Skip to content

Commit

Permalink
feat: ✨ add @tasks/infrastructure-mongoose
Browse files Browse the repository at this point in the history
  • Loading branch information
zhumeisongsong committed Dec 13, 2024
1 parent a5dd726 commit c612fd0
Show file tree
Hide file tree
Showing 17 changed files with 283 additions and 22 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"cSpell.words": [
"compodoc",
"maxlength",
"nestjs",
"pnpx",
"supergraph"
Expand Down
7 changes: 7 additions & 0 deletions libs/tasks/infrastructure/mongoose/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# tasks-infrastructure-mongoose

This library was generated with [Nx](https://nx.dev).

## Running unit tests

Run `nx test tasks-infrastructure-mongoose` to execute the unit tests via [Jest](https://jestjs.io).
3 changes: 3 additions & 0 deletions libs/tasks/infrastructure/mongoose/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const baseConfig = require('../../../../eslint.config.js');

module.exports = [...baseConfig];
10 changes: 10 additions & 0 deletions libs/tasks/infrastructure/mongoose/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export default {
displayName: 'tasks-infrastructure-mongoose',
preset: '../../../../jest.preset.js',
testEnvironment: 'node',
transform: {
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../../../../coverage/libs/users/infrastructure/mongoose',
};
9 changes: 9 additions & 0 deletions libs/tasks/infrastructure/mongoose/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "tasks-infrastructure-mongoose",
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/users/infrastructure/mongoose/src",
"projectType": "library",
"tags": [],
"// targets": "to see all targets run: nx show project tasks-infrastructure-mongoose --web",
"targets": {}
}
2 changes: 2 additions & 0 deletions libs/tasks/infrastructure/mongoose/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './lib/mongoose-tasks.repository';
export * from './lib/task.schema';
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { Test, TestingModule } from '@nestjs/testing';
import { getModelToken } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Task } from '@tasks/domain';

import { TaskDocument } from './task.schema';
import { MongooseTasksRepository } from './mongoose-tasks.repository';

describe('MongooseTasksRepository', () => {
let repository: MongooseTasksRepository;
let taskModel: Model<TaskDocument>;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
MongooseTasksRepository,
{
provide: getModelToken(TaskDocument.name),
useValue: {
find: jest.fn(),
},
},
],
}).compile();

repository = module.get<MongooseTasksRepository>(MongooseTasksRepository);
taskModel = module.get<Model<TaskDocument>>(getModelToken(TaskDocument.name));
});

it('should be defined', () => {
expect(repository).toBeDefined();
});

describe('findAll', () => {
it('should return empty array when no tasks exist', async () => {
jest.spyOn(taskModel, 'find').mockReturnValue({
exec: jest.fn().mockResolvedValue(null),
} as any);

const result = await repository.findAll();
expect(result).toEqual([]);
});

it('should return array of Tasks when found', async () => {
const mockTasks = [
{
id: '123',
title: 'Test Task',
description: 'Test Description',
categories: ['test'],
},
{
id: '456',
title: 'Another Task',
description: null,
categories: ['test', 'another'],
},
];

jest.spyOn(taskModel, 'find').mockReturnValue({
exec: jest.fn().mockResolvedValue(mockTasks),
} as any);

const result = await repository.findAll();
expect(result).toHaveLength(2);
expect(result[0]).toBeInstanceOf(Task);
expect(result[0].id).toBe(mockTasks[0].id);
expect(result[0].title).toBe(mockTasks[0].title);
expect(result[0].description).toBe(mockTasks[0].description);
expect(result[0].categories).toEqual(mockTasks[0].categories);

expect(result[1]).toBeInstanceOf(Task);
expect(result[1].id).toBe(mockTasks[1].id);
expect(result[1].title).toBe(mockTasks[1].title);
expect(result[1].description).toBe(mockTasks[1].description);
expect(result[1].categories).toEqual(mockTasks[1].categories);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Task, TasksRepository } from '@tasks/domain';
import { Model } from 'mongoose';

import { TaskDocument } from './task.schema';

@Injectable()
export class MongooseTasksRepository implements TasksRepository {
constructor(
@InjectModel(TaskDocument.name) private taskModel: Model<TaskDocument>,
) {}

async findAll(): Promise<Task[]> {
const tasks = await this.taskModel.find().exec();

if (!tasks) {
return [];
}

return tasks.map((task) =>
Task.create(task.id, task.title, task.description, task.categories),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,4 @@ describe('TaskDocument', () => {
it('should be defined', () => {
expect(taskModel).toBeDefined();
});

it('should create a task with required fields', () => {
const task = new taskModel({
title: 'Test Task',
categories: ['test'],
});
expect(task.title).toBe('Test Task');
expect(task.categories).toEqual(['test']);
expect(task.description).toBeNull();
});

it('should create a task with all fields', () => {
const task = new taskModel({
title: 'Test Task',
description: 'Test Description',
categories: ['test', 'example'],
});
expect(task.title).toBe('Test Task');
expect(task.description).toBe('Test Description');
expect(task.categories).toEqual(['test', 'example']);
});
});
22 changes: 22 additions & 0 deletions libs/tasks/infrastructure/mongoose/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"extends": "../../../../tsconfig.base.json",
"compilerOptions": {
"module": "commonjs",
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noPropertyAccessFromIndexSignature": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}
11 changes: 11 additions & 0 deletions libs/tasks/infrastructure/mongoose/tsconfig.lib.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "commonjs",
"outDir": "../../../../dist/out-tsc",
"declaration": true,
"types": ["node"]
},
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
"include": ["src/**/*.ts"]
}
14 changes: 14 additions & 0 deletions libs/tasks/infrastructure/mongoose/tsconfig.spec.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"include": [
"jest.config.ts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}
2 changes: 1 addition & 1 deletion libs/users/infrastructure/mongoose/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from './lib/mongoose-users.repository';
export * from './lib/user.schema';
export * from './lib/user.schema';
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { Test, TestingModule } from '@nestjs/testing';
import { getModelToken } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User } from '@users/domain';

import { UserDocument } from './user.schema';
import { MongooseUsersRepository } from './mongoose-users.repository';

describe('MongooseUsersRepository', () => {
let repository: MongooseUsersRepository;
let userModel: Model<UserDocument>;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
MongooseUsersRepository,
{
provide: getModelToken(UserDocument.name),
useValue: {
findOne: jest.fn(),
},
},
],
}).compile();

repository = module.get<MongooseUsersRepository>(MongooseUsersRepository);
userModel = module.get<Model<UserDocument>>(getModelToken(UserDocument.name));
});

it('should be defined', () => {
expect(repository).toBeDefined();
});

describe('findOneById', () => {
it('should return null when user is not found', async () => {
jest.spyOn(userModel, 'findOne').mockReturnValue({
exec: jest.fn().mockResolvedValue(null),
} as any);

const result = await repository.findOneById('non-existent-id');
expect(result).toBeNull();
});

it('should return User when found', async () => {
const mockUser = {
id: '123',
email: '[email protected]',
firstName: 'John',
lastName: 'Doe',
};

jest.spyOn(userModel, 'findOne').mockReturnValue({
exec: jest.fn().mockResolvedValue(mockUser),
} as any);

const result = await repository.findOneById('123');
expect(result).toBeInstanceOf(User);
expect(result?.id).toBe(mockUser.id);
expect(result?.email).toBe(mockUser.email);
expect(result?.firstName).toBe(mockUser.firstName);
expect(result?.lastName).toBe(mockUser.lastName);
});
});

describe('findOneByEmail', () => {
it('should return null when user is not found', async () => {
jest.spyOn(userModel, 'findOne').mockReturnValue({
exec: jest.fn().mockResolvedValue(null),
} as any);

const result = await repository.findOneByEmail('[email protected]');
expect(result).toBeNull();
});

it('should return User when found', async () => {
const mockUser = {
id: '123',
email: '[email protected]',
firstName: 'John',
lastName: 'Doe',
};

jest.spyOn(userModel, 'findOne').mockReturnValue({
exec: jest.fn().mockResolvedValue(mockUser),
} as any);

const result = await repository.findOneByEmail('[email protected]');
expect(result).toBeInstanceOf(User);
expect(result?.id).toBe(mockUser.id);
expect(result?.email).toBe(mockUser.email);
expect(result?.firstName).toBe(mockUser.firstName);
expect(result?.lastName).toBe(mockUser.lastName);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export class MongooseUsersRepository implements UsersRepository {
if (!userDocument) {
return null;
}

return new User(
userDocument.id,
userDocument.email,
Expand Down
3 changes: 3 additions & 0 deletions tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
],
"@tasks/application": ["libs/tasks/application/src/index.ts"],
"@tasks/domain": ["libs/tasks/domain/src/index.ts"],
"@tasks/infrastructure-mongoose": [
"libs/tasks/infrastructure/mongoose/src/index.ts"
],
"@tasks/interface-adapters": [
"libs/tasks/interface-adapters/src/index.ts"
],
Expand Down

0 comments on commit c612fd0

Please sign in to comment.