diff --git a/README.md b/README.md
index 8ad1d41..5390021 100644
--- a/README.md
+++ b/README.md
@@ -60,7 +60,6 @@ You can use `npx nx list` to get a list of installed plugins. Then, run `npx nx
| resolver(interface-adapters) | Handles GraphQL queries and mutations by converting them into calls to the application layer.
Responsible for input validation and response formatting specific to GraphQL. |
| dto(interface-adapters) | Define DTOs for GraphQL schema. |
| infrastructure | Implements the technical capabilities needed to support the higher layers of the application.
Handles database connections, external service integrations, and other technical concerns.
Contains concrete implementations of repository interfaces defined in the domain layer. |
-
| mongoose(infrastructure) | Implements the repository interfaces defined in the domain layer using Mongoose as the ODM (Object Document Mapper).
Includes Mongoose Schema definitions, database connection management, and concrete implementations of repository interfaces (e.g., MongooseUsersRepository).
Adding validation in the Mongoose schema ensures that any data persisted to the database adheres to the required constraints. This helps maintain data integrity and prevents invalid or duplicate entries at the database level. |
| service(application) | As the core of the application layer, it mainly interacts with the domain layer and interface-adapter layer.
If you migrate to a non-NestJS architecture in the future (e.g. other frameworks or microservices), the application tier code can be left unaffected. |
| use-case(application) | Define business use cases and encapsulate business logic.
Implementing validation in the use-case layer allows you to enforce business logic and provide immediate feedback to users or calling services. This is where you can handle complex validation rules and provide detailed error messages.|
diff --git a/libs/auth/application/src/lib/auth.service.spec.ts b/libs/auth/application/src/lib/auth.service.spec.ts
index 5611b93..844c893 100644
--- a/libs/auth/application/src/lib/auth.service.spec.ts
+++ b/libs/auth/application/src/lib/auth.service.spec.ts
@@ -1,7 +1,6 @@
import { UnauthorizedException } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { AwsCognitoService } from '@shared/infrastructure-aws-cognito';
-import { UsersService } from '@users/application';
import { JwtService } from '@nestjs/jwt';
import { AuthService } from './auth.service';
@@ -9,7 +8,6 @@ import { AuthService } from './auth.service';
describe('AuthService', () => {
let service: AuthService;
let awsCognitoService: jest.Mocked;
- let usersService: jest.Mocked;
let jwtService: jest.Mocked;
beforeEach(async () => {
@@ -22,12 +20,6 @@ describe('AuthService', () => {
signIn: jest.fn(),
},
},
- {
- provide: UsersService,
- useValue: {
- findByEmail: jest.fn(),
- },
- },
{
provide: JwtService,
useValue: {
@@ -39,7 +31,6 @@ describe('AuthService', () => {
service = module.get(AuthService);
awsCognitoService = module.get(AwsCognitoService);
- usersService = module.get(UsersService);
jwtService = module.get(JwtService);
});
@@ -50,8 +41,6 @@ describe('AuthService', () => {
describe('signIn', () => {
const email = 'test@example.com';
const password = 'password123';
- const userId = '123';
- const user = { id: userId, email, firstName: null, lastName: null };
// it('should throw UnauthorizedException when AWS Cognito sign in fails', async () => {
// const error = new Error('Invalid credentials');
@@ -65,7 +54,6 @@ describe('AuthService', () => {
it('should throw UnauthorizedException when JWT signing fails', async () => {
const error = new Error('JWT signing failed');
awsCognitoService.signIn.mockResolvedValue(undefined);
- usersService.findByEmail.mockResolvedValue(user);
jwtService.signAsync.mockRejectedValue(error);
await expect(service.signIn(email, password)).rejects.toThrow(
diff --git a/libs/tasks/application/src/index.ts b/libs/tasks/application/src/index.ts
index e9187da..05a5430 100644
--- a/libs/tasks/application/src/index.ts
+++ b/libs/tasks/application/src/index.ts
@@ -1 +1,2 @@
-export * from './lib/tasks-application';
+export * from './lib/tasks.service';
+export * from './lib/user-tasks.service';
\ No newline at end of file
diff --git a/libs/tasks/application/src/lib/tasks-application.spec.ts b/libs/tasks/application/src/lib/tasks-application.spec.ts
deleted file mode 100644
index 2640f80..0000000
--- a/libs/tasks/application/src/lib/tasks-application.spec.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { tasksApplication } from './tasks-application';
-
-describe('tasksApplication', () => {
- it('should work', () => {
- expect(tasksApplication()).toEqual('tasks-application');
- });
-});
diff --git a/libs/tasks/application/src/lib/tasks-application.ts b/libs/tasks/application/src/lib/tasks-application.ts
deleted file mode 100644
index 75e4849..0000000
--- a/libs/tasks/application/src/lib/tasks-application.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export function tasksApplication(): string {
- return 'tasks-application';
-}
diff --git a/libs/tasks/application/src/lib/tasks.service.spec.ts b/libs/tasks/application/src/lib/tasks.service.spec.ts
new file mode 100644
index 0000000..95996af
--- /dev/null
+++ b/libs/tasks/application/src/lib/tasks.service.spec.ts
@@ -0,0 +1,26 @@
+import { Test, TestingModule } from '@nestjs/testing';
+
+import { TasksService } from './tasks.service';
+
+describe('TasksService', () => {
+ let service: TasksService;
+
+ beforeEach(async () => {
+ const module: TestingModule = await Test.createTestingModule({
+ providers: [TasksService],
+ }).compile();
+
+ service = module.get(TasksService);
+ });
+
+ it('should be defined', () => {
+ expect(service).toBeDefined();
+ });
+
+ describe('findAll', () => {
+ it('should return an array of tasks', async () => {
+ const result = await service.findAll();
+ expect(Array.isArray(result)).toBe(true);
+ });
+ });
+});
diff --git a/libs/tasks/application/src/lib/tasks.service.ts b/libs/tasks/application/src/lib/tasks.service.ts
new file mode 100644
index 0000000..4ae8c08
--- /dev/null
+++ b/libs/tasks/application/src/lib/tasks.service.ts
@@ -0,0 +1,10 @@
+import { Injectable } from '@nestjs/common';
+import { Task } from '@tasks/domain';
+
+@Injectable()
+export class TasksService {
+ async findAll(): Promise {
+ // TODO: Implement this
+ return [];
+ }
+}
diff --git a/libs/tasks/application/src/lib/user-tasks.service.spec.ts b/libs/tasks/application/src/lib/user-tasks.service.spec.ts
new file mode 100644
index 0000000..b43230e
--- /dev/null
+++ b/libs/tasks/application/src/lib/user-tasks.service.spec.ts
@@ -0,0 +1,39 @@
+import { Test, TestingModule } from '@nestjs/testing';
+import { UserTasksService } from './user-tasks.service';
+
+describe('UserTasksService', () => {
+ let service: UserTasksService;
+
+ beforeEach(async () => {
+ const module: TestingModule = await Test.createTestingModule({
+ providers: [UserTasksService],
+ }).compile();
+
+ service = module.get(UserTasksService);
+ });
+
+ it('should be defined', () => {
+ expect(service).toBeDefined();
+ });
+
+ describe('findMany', () => {
+ it('should return user tasks', async () => {
+ const result = await service.findMany('userId', { from: new Date(), to: new Date() });
+ expect(result).toEqual([]);
+ });
+ });
+
+ describe('createSome', () => {
+ it('should create user tasks', async () => {
+ const result = await service.createSome('userId', [{ id: '1', createdAt: new Date() }]);
+ expect(result).toEqual('success');
+ });
+ });
+
+ describe('updateSome', () => {
+ it('should update user tasks', async () => {
+ const result = await service.updateSome('userId', [{ id: '1', updatedAt: new Date() }]);
+ expect(result).toEqual('success');
+ });
+ });
+});
diff --git a/libs/tasks/application/src/lib/user-tasks.service.ts b/libs/tasks/application/src/lib/user-tasks.service.ts
new file mode 100644
index 0000000..d46d5ed
--- /dev/null
+++ b/libs/tasks/application/src/lib/user-tasks.service.ts
@@ -0,0 +1,29 @@
+import { Injectable } from '@nestjs/common';
+import { UserTask } from '@tasks/domain';
+
+@Injectable()
+export class UserTasksService {
+ async findMany(
+ userId: string,
+ range?: { from: Date; to: Date },
+ ): Promise {
+ // TODO: Implement this
+ return [];
+ }
+
+ async createSome(
+ userId: string,
+ tasks: { id: string; createdAt: Date }[],
+ ): Promise {
+ // TODO: Implement this
+ return 'success';
+ }
+
+ async updateSome(
+ userId: string,
+ userTasks: { id: string; updatedAt: Date }[],
+ ): Promise {
+ // TODO: Implement this
+ return 'success';
+ }
+}
diff --git a/libs/tasks/domain/src/index.ts b/libs/tasks/domain/src/index.ts
index 810dfe0..99ae8ff 100644
--- a/libs/tasks/domain/src/index.ts
+++ b/libs/tasks/domain/src/index.ts
@@ -1 +1,4 @@
-export * from './lib/tasks-domain';
+export * from './lib/entities/task.entity';
+export * from './lib/entities/user-task.entity';
+
+export * from './lib/tasks.repository';
diff --git a/libs/tasks/domain/src/lib/entities/task.entity.spec.ts b/libs/tasks/domain/src/lib/entities/task.entity.spec.ts
new file mode 100644
index 0000000..f86601b
--- /dev/null
+++ b/libs/tasks/domain/src/lib/entities/task.entity.spec.ts
@@ -0,0 +1,39 @@
+import { Task } from './task.entity';
+
+describe('Task', () => {
+ it('should create a task with all properties', () => {
+ const task = new Task(
+ 'test-id',
+ 'Test Title',
+ 'Test Description',
+ ['category1', 'category2']
+ );
+
+ expect(task.id).toBe('test-id');
+ expect(task.title).toBe('Test Title');
+ expect(task.description).toBe('Test Description');
+ expect(task.categories).toEqual(['category1', 'category2']);
+ });
+
+ it('should allow null description', () => {
+ const task = new Task(
+ 'test-id',
+ 'Test Title',
+ null,
+ ['category1']
+ );
+
+ expect(task.description).toBeNull();
+ });
+
+ it('should create a task with empty categories array', () => {
+ const task = new Task(
+ 'test-id',
+ 'Test Title',
+ 'Test Description',
+ []
+ );
+
+ expect(task.categories).toEqual([]);
+ });
+});
diff --git a/libs/tasks/domain/src/lib/entities/task.entity.ts b/libs/tasks/domain/src/lib/entities/task.entity.ts
new file mode 100644
index 0000000..430a6d5
--- /dev/null
+++ b/libs/tasks/domain/src/lib/entities/task.entity.ts
@@ -0,0 +1,8 @@
+export class Task {
+ constructor(
+ public readonly id: string,
+ public readonly title: string,
+ public readonly description: string | null,
+ public readonly categories: string[],
+ ) {}
+}
diff --git a/libs/tasks/domain/src/lib/entities/user-task.entity.spec.ts b/libs/tasks/domain/src/lib/entities/user-task.entity.spec.ts
new file mode 100644
index 0000000..c02282d
--- /dev/null
+++ b/libs/tasks/domain/src/lib/entities/user-task.entity.spec.ts
@@ -0,0 +1,30 @@
+import { User } from '@users/domain';
+import { Task } from './task.entity';
+import { UserTask } from './user-task.entity';
+
+describe('UserTask', () => {
+ it('should create a user task instance', () => {
+ const task = new Task('task-1', 'Test Task', 'Description', ['category1']);
+ const user = new User('user-1', 'test@example.com', null, null);
+ const now = new Date();
+
+ const userTask = new UserTask(
+ 'user-task-1',
+ now,
+ null,
+ 'task-1',
+ task,
+ 'user-1',
+ user,
+ );
+
+ expect(userTask).toBeDefined();
+ expect(userTask.id).toBe('user-task-1');
+ expect(userTask.createdAt).toBe(now);
+ expect(userTask.updatedAt).toBeNull();
+ expect(userTask.taskId).toBe('task-1');
+ expect(userTask.task).toBe(task);
+ expect(userTask.userId).toBe('user-1');
+ expect(userTask.user).toBe(user);
+ });
+});
diff --git a/libs/tasks/domain/src/lib/entities/user-task.entity.ts b/libs/tasks/domain/src/lib/entities/user-task.entity.ts
new file mode 100644
index 0000000..de62bf6
--- /dev/null
+++ b/libs/tasks/domain/src/lib/entities/user-task.entity.ts
@@ -0,0 +1,15 @@
+import { User } from '@users/domain';
+
+import { Task } from './task.entity';
+
+export class UserTask {
+ constructor(
+ public readonly id: string,
+ public readonly createdAt: Date,
+ public readonly updatedAt: Date | null,
+ public readonly taskId: string,
+ public readonly task: Task | null,
+ public readonly userId: string,
+ public readonly user: User | null,
+ ) {}
+}
diff --git a/libs/tasks/domain/src/lib/tasks-domain.spec.ts b/libs/tasks/domain/src/lib/tasks-domain.spec.ts
deleted file mode 100644
index f6e92b2..0000000
--- a/libs/tasks/domain/src/lib/tasks-domain.spec.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { tasksDomain } from './tasks-domain';
-
-describe('tasksDomain', () => {
- it('should work', () => {
- expect(tasksDomain()).toEqual('tasks-domain');
- });
-});
diff --git a/libs/tasks/domain/src/lib/tasks-domain.ts b/libs/tasks/domain/src/lib/tasks-domain.ts
deleted file mode 100644
index f474aea..0000000
--- a/libs/tasks/domain/src/lib/tasks-domain.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export function tasksDomain(): string {
- return 'tasks-domain';
-}
diff --git a/libs/tasks/domain/src/lib/tasks.repository.spec.ts b/libs/tasks/domain/src/lib/tasks.repository.spec.ts
new file mode 100644
index 0000000..f7ec9c6
--- /dev/null
+++ b/libs/tasks/domain/src/lib/tasks.repository.spec.ts
@@ -0,0 +1,24 @@
+import { Task } from './entities/task.entity';
+import { TasksRepository } from './tasks.repository';
+
+class MockTasksRepository implements TasksRepository {
+ async findAll(): Promise {
+ return [];
+ }
+}
+
+describe('TasksRepository', () => {
+ let repository: TasksRepository;
+
+ beforeEach(() => {
+ repository = new MockTasksRepository();
+ });
+
+ describe('findAll', () => {
+ it('should return all tasks', async () => {
+ const tasks = await repository.findAll();
+ expect(Array.isArray(tasks)).toBe(true);
+ expect(tasks.every((task) => task instanceof Task)).toBe(true);
+ });
+ });
+});
diff --git a/libs/tasks/domain/src/lib/tasks.repository.ts b/libs/tasks/domain/src/lib/tasks.repository.ts
new file mode 100644
index 0000000..b45463f
--- /dev/null
+++ b/libs/tasks/domain/src/lib/tasks.repository.ts
@@ -0,0 +1,7 @@
+import { Task } from './entities/task.entity';
+
+export interface TasksRepository {
+ findAll(): Promise;
+}
+
+export const TASKS_REPOSITORY = Symbol('TASKS_REPOSITORY');
diff --git a/libs/tasks/domain/src/lib/user-tasks.repository.spec.ts b/libs/tasks/domain/src/lib/user-tasks.repository.spec.ts
new file mode 100644
index 0000000..af85c02
--- /dev/null
+++ b/libs/tasks/domain/src/lib/user-tasks.repository.spec.ts
@@ -0,0 +1,71 @@
+import { Task } from './entities/task.entity';
+import { UserTasksRepository } from './user-tasks.repository';
+
+class MockUserTasksRepository implements UserTasksRepository {
+ async findAll(userId: string): Promise {
+ return [];
+ }
+
+ async createSome(
+ userId: string,
+ tasks: { id: string; createdAt: Date }[],
+ ): Promise {
+ return;
+ }
+
+ async updateSome(
+ userId: string,
+ tasks: { id: string; updatedAt: Date }[],
+ ): Promise {
+ return;
+ }
+}
+
+describe('UserTasksRepository', () => {
+ let repository: UserTasksRepository;
+
+ beforeEach(() => {
+ repository = new MockUserTasksRepository();
+ });
+
+ describe('findAll', () => {
+ it('should return all tasks for a given user', async () => {
+ const tasks = await repository.findAll('user-1');
+ expect(Array.isArray(tasks)).toBe(true);
+ expect(tasks.every((task) => task instanceof Task)).toBe(true);
+ });
+
+ it('should return tasks within date range when provided', async () => {
+ const range = {
+ from: new Date('2023-01-01'),
+ to: new Date('2023-12-31'),
+ };
+ const tasks = await repository.findAll('user-1', range);
+ expect(Array.isArray(tasks)).toBe(true);
+ });
+ });
+
+ describe('createSome', () => {
+ it('should create multiple tasks for a user', async () => {
+ const tasksToCreate = [
+ { id: 'task-1', createdAt: new Date() },
+ { id: 'task-2', createdAt: new Date() },
+ ];
+ await expect(
+ repository.createSome('user-1', tasksToCreate),
+ ).resolves.not.toThrow();
+ });
+ });
+
+ describe('updateSome', () => {
+ it('should update multiple existing tasks', async () => {
+ const tasksToUpdate = [
+ { id: 'task-1', updatedAt: new Date() },
+ { id: 'task-2', updatedAt: new Date() },
+ ];
+ await expect(
+ repository.updateSome('user-1', tasksToUpdate),
+ ).resolves.not.toThrow();
+ });
+ });
+});
diff --git a/libs/tasks/domain/src/lib/user-tasks.repository.ts b/libs/tasks/domain/src/lib/user-tasks.repository.ts
new file mode 100644
index 0000000..cede650
--- /dev/null
+++ b/libs/tasks/domain/src/lib/user-tasks.repository.ts
@@ -0,0 +1,27 @@
+import { Task } from './entities/task.entity';
+
+export interface UserTasksRepository {
+ findAll(userId: string, range?: { from: Date; to: Date }): Promise;
+
+ /**
+ * Creates tasks for a specific user
+ * @throws {TaskValidationError} If the tasks are invalid
+ * @throws {UserNotFoundError} If user doesn't exist
+ */
+ createSome(
+ userId: string,
+ tasks: { id: string; createdAt: Date }[],
+ ): Promise;
+
+ /**
+ * Updates existing user tasks
+ * @throws {TaskNotFoundError} If any task doesn't exist
+ * @throws {UserNotFoundError} If user doesn't exist
+ */
+ updateSome(
+ userId: string,
+ userTasks: { id: string; updatedAt: Date }[],
+ ): Promise;
+}
+
+export const USER_TASKS_REPOSITORY = Symbol('USER_TASKS_REPOSITORY');
diff --git a/libs/tasks/interface-adapters/src/index.ts b/libs/tasks/interface-adapters/src/index.ts
index a6214aa..c92ed5c 100644
--- a/libs/tasks/interface-adapters/src/index.ts
+++ b/libs/tasks/interface-adapters/src/index.ts
@@ -1 +1 @@
-export * from './lib/tasks-interface-adapters';
+export * from './lib/tasks.module';
\ No newline at end of file
diff --git a/libs/tasks/interface-adapters/src/lib/dto/base-task.dto.ts b/libs/tasks/interface-adapters/src/lib/dto/base-task.dto.ts
new file mode 100644
index 0000000..1b40310
--- /dev/null
+++ b/libs/tasks/interface-adapters/src/lib/dto/base-task.dto.ts
@@ -0,0 +1,14 @@
+import { Field, InputType } from "@nestjs/graphql";
+import { IsNotEmpty, IsUUID } from "class-validator";
+
+@InputType({ isAbstract: true })
+export abstract class BaseTaskDto {
+ @Field(() => String)
+ @IsNotEmpty()
+ @IsUUID()
+ id: string;
+
+ constructor(id: string) {
+ this.id = id;
+ }
+}
\ No newline at end of file
diff --git a/libs/tasks/interface-adapters/src/lib/dto/create-user-task.dto.spec.ts b/libs/tasks/interface-adapters/src/lib/dto/create-user-task.dto.spec.ts
new file mode 100644
index 0000000..099aa9b
--- /dev/null
+++ b/libs/tasks/interface-adapters/src/lib/dto/create-user-task.dto.spec.ts
@@ -0,0 +1,14 @@
+import { CreateUserTaskDto } from './create-user-task.dto';
+
+describe('CreateUserTaskDto', () => {
+ it('should create a CreateUserTaskDto instance', () => {
+ const id = '123';
+ const createdAt = new Date();
+
+ const dto = new CreateUserTaskDto(id, createdAt);
+
+ expect(dto).toBeDefined();
+ expect(dto.id).toBe(id);
+ expect(dto.createdAt).toBe(createdAt);
+ });
+});
diff --git a/libs/tasks/interface-adapters/src/lib/dto/create-user-task.dto.ts b/libs/tasks/interface-adapters/src/lib/dto/create-user-task.dto.ts
new file mode 100644
index 0000000..50d6380
--- /dev/null
+++ b/libs/tasks/interface-adapters/src/lib/dto/create-user-task.dto.ts
@@ -0,0 +1,16 @@
+import { Field, InputType } from '@nestjs/graphql';
+import { IsNotEmpty, IsUUID } from 'class-validator';
+
+import { BaseTaskDto } from './base-task.dto';
+
+@InputType({ description: 'Input type for creating a new user task' })
+export class CreateUserTaskDto extends BaseTaskDto {
+ @Field(() => Date)
+ @IsNotEmpty()
+ createdAt: Date = new Date();
+
+ constructor(id: string, createdAt: Date) {
+ super(id);
+ this.createdAt = createdAt;
+ }
+}
diff --git a/libs/tasks/interface-adapters/src/lib/dto/task.dto.spec.ts b/libs/tasks/interface-adapters/src/lib/dto/task.dto.spec.ts
new file mode 100644
index 0000000..cd748dc
--- /dev/null
+++ b/libs/tasks/interface-adapters/src/lib/dto/task.dto.spec.ts
@@ -0,0 +1,29 @@
+import { TaskDto } from './task.dto';
+
+describe('TaskDto', () => {
+ it('should create a TaskDto instance', () => {
+ const id = '123';
+ const title = 'Test Task';
+ const description = 'Test Description';
+ const categories = ['category1', 'category2'];
+
+ const dto = new TaskDto(id, title, description, categories);
+
+ expect(dto).toBeDefined();
+ expect(dto.id).toBe(id);
+ expect(dto.title).toBe(title);
+ expect(dto.description).toBe(description);
+ expect(dto.categories).toEqual(categories);
+ });
+
+ it('should allow null description', () => {
+ const id = '123';
+ const title = 'Test Task';
+ const description = null;
+ const categories = ['category1'];
+
+ const dto = new TaskDto(id, title, description, categories);
+
+ expect(dto.description).toBeNull();
+ });
+});
diff --git a/libs/tasks/interface-adapters/src/lib/dto/task.dto.ts b/libs/tasks/interface-adapters/src/lib/dto/task.dto.ts
new file mode 100644
index 0000000..ce0b735
--- /dev/null
+++ b/libs/tasks/interface-adapters/src/lib/dto/task.dto.ts
@@ -0,0 +1,51 @@
+import { Field, ID, ObjectType } from '@nestjs/graphql';
+import {
+ IsArray,
+ IsNotEmpty,
+ IsOptional,
+ IsString,
+ IsUUID,
+ MaxLength,
+ MinLength,
+} from 'class-validator';
+
+@ObjectType()
+export class TaskDto {
+ @Field(() => ID)
+ @IsNotEmpty()
+ @IsUUID()
+ id: string;
+
+ @Field()
+ @IsNotEmpty()
+ @IsString()
+ @MinLength(1)
+ @MaxLength(255)
+ title: string;
+
+ @Field(() => String, { nullable: true })
+ @IsOptional()
+ @IsString()
+ @MaxLength(1000)
+ description: string | null;
+
+ @Field(() => [String])
+ @IsNotEmpty()
+ @IsArray()
+ @IsString({ each: true })
+ @MinLength(1, { each: true })
+ @MaxLength(255, { each: true })
+ categories: string[];
+
+ constructor(
+ id: string,
+ title: string,
+ description: string | null,
+ categories: string[],
+ ) {
+ this.id = id;
+ this.title = title;
+ this.description = description;
+ this.categories = categories;
+ }
+}
diff --git a/libs/tasks/interface-adapters/src/lib/dto/update-user-task.dto.spec.ts b/libs/tasks/interface-adapters/src/lib/dto/update-user-task.dto.spec.ts
new file mode 100644
index 0000000..2019dd1
--- /dev/null
+++ b/libs/tasks/interface-adapters/src/lib/dto/update-user-task.dto.spec.ts
@@ -0,0 +1,14 @@
+import { UpdateUserTaskDto } from './update-user-task.dto';
+
+describe('UpdateUserTaskDto', () => {
+ it('should create an UpdateUserTaskDto instance', () => {
+ const id = '123';
+ const updatedAt = new Date();
+
+ const dto = new UpdateUserTaskDto(id, updatedAt);
+
+ expect(dto).toBeDefined();
+ expect(dto.id).toBe(id);
+ expect(dto.updatedAt).toBe(updatedAt);
+ });
+});
diff --git a/libs/tasks/interface-adapters/src/lib/dto/update-user-task.dto.ts b/libs/tasks/interface-adapters/src/lib/dto/update-user-task.dto.ts
new file mode 100644
index 0000000..000ad81
--- /dev/null
+++ b/libs/tasks/interface-adapters/src/lib/dto/update-user-task.dto.ts
@@ -0,0 +1,16 @@
+import { Field, InputType } from '@nestjs/graphql';
+import { IsNotEmpty } from 'class-validator';
+
+import { BaseTaskDto } from './base-task.dto';
+
+@InputType({ description: 'Input type for updating a user task' })
+export class UpdateUserTaskDto extends BaseTaskDto {
+ @Field(() => Date)
+ @IsNotEmpty()
+ updatedAt: Date = new Date();
+
+ constructor(id: string, updatedAt: Date) {
+ super(id);
+ this.updatedAt = updatedAt;
+ }
+}
diff --git a/libs/tasks/interface-adapters/src/lib/dto/user-task.dto.spec.ts b/libs/tasks/interface-adapters/src/lib/dto/user-task.dto.spec.ts
new file mode 100644
index 0000000..a5b1066
--- /dev/null
+++ b/libs/tasks/interface-adapters/src/lib/dto/user-task.dto.spec.ts
@@ -0,0 +1,61 @@
+import { UserTaskDto } from './user-task.dto';
+import { TaskDto } from './task.dto';
+import { UserDto } from '@users/interface-adapters';
+
+describe('UserTaskDto', () => {
+ it('should create a UserTaskDto instance', () => {
+ const id = '123';
+ const createdAt = new Date();
+ const updatedAt = new Date();
+ const taskId = '456';
+ const task = new TaskDto('456', 'Test Task', 'Test Description', []);
+ const userId = '789';
+ const user = new UserDto('789', 'test@example.com', null, null);
+
+ const userTaskDto = new UserTaskDto(
+ id,
+ createdAt,
+ updatedAt,
+ taskId,
+ task,
+ userId,
+ user,
+ );
+
+ expect(userTaskDto.id).toBe(id);
+ expect(userTaskDto.createdAt).toBe(createdAt);
+ expect(userTaskDto.updatedAt).toBe(updatedAt);
+ expect(userTaskDto.taskId).toBe(taskId);
+ expect(userTaskDto.task).toBe(task);
+ expect(userTaskDto.userId).toBe(userId);
+ expect(userTaskDto.user).toBe(user);
+ });
+
+ it('should create a UserTaskDto instance with null values', () => {
+ const id = '123';
+ const createdAt = new Date();
+ const updatedAt = null;
+ const taskId = '456';
+ const task = null;
+ const userId = '789';
+ const user = null;
+
+ const userTaskDto = new UserTaskDto(
+ id,
+ createdAt,
+ updatedAt,
+ taskId,
+ task,
+ userId,
+ user,
+ );
+
+ expect(userTaskDto.id).toBe(id);
+ expect(userTaskDto.createdAt).toBe(createdAt);
+ expect(userTaskDto.updatedAt).toBeNull();
+ expect(userTaskDto.taskId).toBe(taskId);
+ expect(userTaskDto.task).toBeNull();
+ expect(userTaskDto.userId).toBe(userId);
+ expect(userTaskDto.user).toBeNull();
+ });
+});
diff --git a/libs/tasks/interface-adapters/src/lib/dto/user-task.dto.ts b/libs/tasks/interface-adapters/src/lib/dto/user-task.dto.ts
new file mode 100644
index 0000000..790e834
--- /dev/null
+++ b/libs/tasks/interface-adapters/src/lib/dto/user-task.dto.ts
@@ -0,0 +1,59 @@
+import { Field, ID, ObjectType } from '@nestjs/graphql';
+import { UserDto } from '@users/interface-adapters';
+import { IsDate, IsNotEmpty, IsOptional, IsUUID } from 'class-validator';
+
+import { TaskDto } from './task.dto';
+
+@ObjectType()
+export class UserTaskDto {
+ @Field(() => ID)
+ @IsNotEmpty()
+ @IsUUID()
+ id: string;
+
+ @Field(() => Date)
+ @IsNotEmpty()
+ @IsDate()
+ createdAt: Date;
+
+ @Field(() => Date, { nullable: true })
+ @IsOptional()
+ @IsDate()
+ updatedAt: Date | null;
+
+ @Field(() => String)
+ @IsNotEmpty()
+ @IsUUID()
+ taskId: string;
+
+ @Field(() => TaskDto, { nullable: true })
+ @IsOptional()
+ task: TaskDto | null;
+
+ @Field(() => String)
+ @IsNotEmpty()
+ @IsUUID()
+ userId: string;
+
+ @Field(() => UserDto, { nullable: true })
+ @IsOptional()
+ user: UserDto | null;
+
+ constructor(
+ id: string,
+ createdAt: Date,
+ updatedAt: Date | null,
+ taskId: string,
+ task: TaskDto | null,
+ userId: string,
+ user: UserDto | null,
+ ) {
+ this.id = id;
+ this.createdAt = createdAt;
+ this.updatedAt = updatedAt;
+ this.taskId = taskId;
+ this.task = task;
+ this.userId = userId;
+ this.user = user;
+ }
+}
diff --git a/libs/tasks/interface-adapters/src/lib/resolver/tasks.resolver.spec.ts b/libs/tasks/interface-adapters/src/lib/resolver/tasks.resolver.spec.ts
new file mode 100644
index 0000000..d066f08
--- /dev/null
+++ b/libs/tasks/interface-adapters/src/lib/resolver/tasks.resolver.spec.ts
@@ -0,0 +1,37 @@
+import { Test, TestingModule } from '@nestjs/testing';
+import { TasksService } from '@tasks/application';
+
+import { TasksResolver } from './tasks.resolver';
+
+describe('TasksResolver', () => {
+ let resolver: TasksResolver;
+ let service: TasksService;
+
+ beforeEach(async () => {
+ const module: TestingModule = await Test.createTestingModule({
+ providers: [
+ TasksResolver,
+ {
+ provide: TasksService,
+ useValue: {
+ findAll: jest.fn().mockResolvedValue([]),
+ },
+ },
+ ],
+ }).compile();
+
+ resolver = module.get(TasksResolver);
+ service = module.get(TasksService);
+ });
+
+ it('should be defined', () => {
+ expect(resolver).toBeDefined();
+ });
+
+ describe('findAllTasks', () => {
+ it('should return all tasks', async () => {
+ const result = await resolver.getTasks();
+ expect(result).toEqual([]);
+ });
+ });
+});
diff --git a/libs/tasks/interface-adapters/src/lib/resolver/tasks.resolver.ts b/libs/tasks/interface-adapters/src/lib/resolver/tasks.resolver.ts
new file mode 100644
index 0000000..d25f1a0
--- /dev/null
+++ b/libs/tasks/interface-adapters/src/lib/resolver/tasks.resolver.ts
@@ -0,0 +1,16 @@
+import { Query, Resolver } from '@nestjs/graphql';
+import { TasksService } from '@tasks/application';
+
+import { TaskDto } from '../dto/task.dto';
+import { Injectable } from '@nestjs/common';
+
+@Injectable()
+@Resolver(() => [TaskDto])
+export class TasksResolver {
+ constructor(private tasksService: TasksService) {}
+
+ @Query(() => [TaskDto])
+ async getTasks(): Promise {
+ return this.tasksService.findAll();
+ }
+}
diff --git a/libs/tasks/interface-adapters/src/lib/resolver/user-tasks.resolver.spec.ts b/libs/tasks/interface-adapters/src/lib/resolver/user-tasks.resolver.spec.ts
new file mode 100644
index 0000000..15c44a3
--- /dev/null
+++ b/libs/tasks/interface-adapters/src/lib/resolver/user-tasks.resolver.spec.ts
@@ -0,0 +1,62 @@
+import { Test, TestingModule } from '@nestjs/testing';
+import { UserTasksService } from '@tasks/application';
+
+import { UserTasksResolver } from './user-tasks.resolver';
+
+describe('UserTasksResolver', () => {
+ let resolver: UserTasksResolver;
+ let service: UserTasksService;
+
+ beforeEach(async () => {
+ const module: TestingModule = await Test.createTestingModule({
+ providers: [
+ UserTasksResolver,
+ {
+ provide: UserTasksService,
+ useValue: {
+ findMany: jest.fn().mockResolvedValue([]),
+ createSome: jest.fn().mockResolvedValue({ created: true }),
+ updateSome: jest.fn().mockResolvedValue({ updated: true }),
+ },
+ },
+ ],
+ }).compile();
+
+ resolver = module.get(UserTasksResolver);
+ service = module.get(UserTasksService);
+ });
+
+ it('should be defined', () => {
+ expect(resolver).toBeDefined();
+ });
+
+ describe('findUserTasks', () => {
+ it('should return user tasks for given userId and range', async () => {
+ const userId = 'test-user-id';
+ const range = { from: new Date(), to: new Date() };
+ const result = await resolver.getUserTasks(userId, range);
+ expect(service.findMany).toHaveBeenCalledWith(userId, range);
+ expect(result).toEqual([]);
+ });
+ });
+
+ describe('createUserTasks', () => {
+ it('should create user tasks', async () => {
+ const userId = 'test-user-id';
+ const tasks = [{ id: 'task-1', createdAt: new Date() }];
+ const result = await resolver.createUserTasks(userId, tasks);
+ expect(service.createSome).toHaveBeenCalledWith(userId, tasks);
+ expect(result).toBeDefined();
+ });
+ });
+
+ describe('updateUserTasks', () => {
+ it('should update user tasks', async () => {
+ const userId = 'test-user-id';
+ const userTasks = [{ id: 'user-task-1', updatedAt: new Date() }];
+ const result = await resolver.updateUserTasks(userId, userTasks);
+ expect(service.updateSome).toHaveBeenCalledWith(userId, userTasks);
+ expect(result).toBeDefined();
+ });
+ });
+});
diff --git a/libs/tasks/interface-adapters/src/lib/resolver/user-tasks.resolver.ts b/libs/tasks/interface-adapters/src/lib/resolver/user-tasks.resolver.ts
new file mode 100644
index 0000000..35f281c
--- /dev/null
+++ b/libs/tasks/interface-adapters/src/lib/resolver/user-tasks.resolver.ts
@@ -0,0 +1,62 @@
+import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
+import { UserTasksService } from '@tasks/application';
+
+import { CreateUserTaskDto } from '../dto/create-user-task.dto';
+import { UpdateUserTaskDto } from '../dto/update-user-task.dto';
+import { UserTaskDto } from '../dto/user-task.dto';
+import {
+ BadRequestException,
+ Injectable,
+ InternalServerErrorException,
+ Logger,
+} from '@nestjs/common';
+
+@Injectable()
+@Resolver(() => [UserTaskDto])
+export class UserTasksResolver {
+ private readonly logger = new Logger(UserTasksResolver.name);
+ constructor(private userTasksService: UserTasksService) {}
+
+ @Query(() => [UserTaskDto])
+ async getUserTasks(
+ @Args('userId', {
+ description: 'The ID of the user to find tasks for',
+ })
+ userId: string,
+ @Args('range', {
+ description: 'Date range for task filtering',
+ })
+ range: { from: Date; to: Date },
+ ): Promise {
+ try {
+ if (!userId?.trim()) {
+ throw new BadRequestException('Invalid userId'); // TODO: using error codes
+ }
+
+ if (range.from > range.to) {
+ throw new BadRequestException('Invalid date range'); // TODO: using error codes
+ }
+
+ return this.userTasksService.findMany(userId, range);
+ } catch (error) {
+ this.logger.error('FindUserTasks error:', error);
+ throw new InternalServerErrorException('Failed to fetch user tasks'); // TODO: using error codes
+ }
+ }
+
+ @Mutation(() => String)
+ async createUserTasks(
+ @Args('userId') userId: string,
+ @Args('tasks') tasks: CreateUserTaskDto[],
+ ): Promise {
+ return this.userTasksService.createSome(userId, tasks);
+ }
+
+ @Mutation(() => String)
+ async updateUserTasks(
+ @Args('userId') userId: string,
+ @Args('userTasks') userTasks: UpdateUserTaskDto[],
+ ): Promise {
+ return this.userTasksService.updateSome(userId, userTasks);
+ }
+}
diff --git a/libs/tasks/interface-adapters/src/lib/tasks-interface-adapters.spec.ts b/libs/tasks/interface-adapters/src/lib/tasks-interface-adapters.spec.ts
deleted file mode 100644
index a33f1f3..0000000
--- a/libs/tasks/interface-adapters/src/lib/tasks-interface-adapters.spec.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { tasksInterfaceAdapters } from './tasks-interface-adapters';
-
-describe('tasksInterfaceAdapters', () => {
- it('should work', () => {
- expect(tasksInterfaceAdapters()).toEqual('tasks-interface-adapters');
- });
-});
diff --git a/libs/tasks/interface-adapters/src/lib/tasks-interface-adapters.ts b/libs/tasks/interface-adapters/src/lib/tasks-interface-adapters.ts
deleted file mode 100644
index 91f284e..0000000
--- a/libs/tasks/interface-adapters/src/lib/tasks-interface-adapters.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export function tasksInterfaceAdapters(): string {
- return 'tasks-interface-adapters';
-}
diff --git a/libs/tasks/interface-adapters/src/lib/tasks.module.ts b/libs/tasks/interface-adapters/src/lib/tasks.module.ts
new file mode 100644
index 0000000..0a59729
--- /dev/null
+++ b/libs/tasks/interface-adapters/src/lib/tasks.module.ts
@@ -0,0 +1,12 @@
+import { Module } from '@nestjs/common';
+import { TasksService, UserTasksService } from '@tasks/application';
+
+import { TasksResolver } from './resolver/tasks.resolver';
+import { UserTasksResolver } from './resolver/user-tasks.resolver';
+
+@Module({
+ imports: [],
+ providers: [TasksResolver, TasksService, UserTasksResolver, UserTasksService],
+ exports: [TasksService, UserTasksService],
+})
+export class TasksModule {}
diff --git a/libs/users/application/src/lib/use-cases/get-user-by-email.use-case.spec.ts b/libs/users/application/src/lib/use-cases/get-user-by-email.use-case.spec.ts
index 85c753e..d575708 100644
--- a/libs/users/application/src/lib/use-cases/get-user-by-email.use-case.spec.ts
+++ b/libs/users/application/src/lib/use-cases/get-user-by-email.use-case.spec.ts
@@ -7,8 +7,8 @@ describe('GetUserByEmailUseCase', () => {
beforeEach(() => {
usersRepository = {
- findById: jest.fn(),
- findByEmail: jest.fn(),
+ findOneById: jest.fn(),
+ findOneByEmail: jest.fn(),
};
getUserByEmailUseCase = new GetUserByEmailUseCase(usersRepository);
});
@@ -21,21 +21,25 @@ describe('GetUserByEmailUseCase', () => {
firstName: 'John',
lastName: 'Doe',
};
- (usersRepository.findByEmail as jest.Mock).mockResolvedValue(mockUser);
+ (usersRepository.findOneByEmail as jest.Mock).mockResolvedValue(mockUser);
const result = await getUserByEmailUseCase.execute('test@example.com');
expect(result).toEqual(mockUser);
- expect(usersRepository.findByEmail).toHaveBeenCalledWith("test@example.com");
+ expect(usersRepository.findOneByEmail).toHaveBeenCalledWith(
+ 'test@example.com',
+ );
});
it('should return null when user not found', async () => {
- (usersRepository.findByEmail as jest.Mock).mockResolvedValue(null);
+ (usersRepository.findOneByEmail as jest.Mock).mockResolvedValue(null);
const result = await getUserByEmailUseCase.execute('test@example.com');
expect(result).toBeNull();
- expect(usersRepository.findByEmail).toHaveBeenCalledWith("test@example.com");
+ expect(usersRepository.findOneByEmail).toHaveBeenCalledWith(
+ 'test@example.com',
+ );
});
});
});
diff --git a/libs/users/application/src/lib/use-cases/get-user-by-email.use-case.ts b/libs/users/application/src/lib/use-cases/get-user-by-email.use-case.ts
index 5c01524..d98366a 100644
--- a/libs/users/application/src/lib/use-cases/get-user-by-email.use-case.ts
+++ b/libs/users/application/src/lib/use-cases/get-user-by-email.use-case.ts
@@ -9,6 +9,6 @@ export class GetUserByEmailUseCase {
) {}
async execute(email: string): Promise {
- return this.usersRepository.findByEmail(email);
+ return this.usersRepository.findOneByEmail(email);
}
}
diff --git a/libs/users/application/src/lib/use-cases/get-user-by-id.use-case.spec.ts b/libs/users/application/src/lib/use-cases/get-user-by-id.use-case.spec.ts
index e57326e..a167ff8 100644
--- a/libs/users/application/src/lib/use-cases/get-user-by-id.use-case.spec.ts
+++ b/libs/users/application/src/lib/use-cases/get-user-by-id.use-case.spec.ts
@@ -7,8 +7,8 @@ describe('GetUserByIdUseCase', () => {
beforeEach(() => {
usersRepository = {
- findById: jest.fn(),
- findByEmail: jest.fn(),
+ findOneById: jest.fn(),
+ findOneByEmail: jest.fn(),
};
getUserByIdUseCase = new GetUserByIdUseCase(usersRepository);
});
@@ -21,21 +21,21 @@ describe('GetUserByIdUseCase', () => {
firstName: 'John',
lastName: 'Doe',
};
- (usersRepository.findById as jest.Mock).mockResolvedValue(mockUser);
+ (usersRepository.findOneById as jest.Mock).mockResolvedValue(mockUser);
const result = await getUserByIdUseCase.execute('1');
expect(result).toEqual(mockUser);
- expect(usersRepository.findById).toHaveBeenCalledWith('1');
+ expect(usersRepository.findOneById).toHaveBeenCalledWith('1');
});
it('should return null when user not found', async () => {
- (usersRepository.findById as jest.Mock).mockResolvedValue(null);
+ (usersRepository.findOneById as jest.Mock).mockResolvedValue(null);
const result = await getUserByIdUseCase.execute('1');
expect(result).toBeNull();
- expect(usersRepository.findById).toHaveBeenCalledWith('1');
+ expect(usersRepository.findOneById).toHaveBeenCalledWith('1');
});
});
});
diff --git a/libs/users/application/src/lib/use-cases/get-user-by-id.use-case.ts b/libs/users/application/src/lib/use-cases/get-user-by-id.use-case.ts
index aa6ba98..ec72ca8 100644
--- a/libs/users/application/src/lib/use-cases/get-user-by-id.use-case.ts
+++ b/libs/users/application/src/lib/use-cases/get-user-by-id.use-case.ts
@@ -9,6 +9,6 @@ export class GetUserByIdUseCase {
) {}
async execute(id: string): Promise {
- return await this.usersRepository.findById(id);
+ return await this.usersRepository.findOneById(id);
}
}
diff --git a/libs/users/application/src/lib/users.service.spec.ts b/libs/users/application/src/lib/users.service.spec.ts
index adb98d5..3c66f07 100644
--- a/libs/users/application/src/lib/users.service.spec.ts
+++ b/libs/users/application/src/lib/users.service.spec.ts
@@ -42,7 +42,7 @@ describe('UsersService', () => {
};
(getUserByIdUseCase.execute as jest.Mock).mockResolvedValue(mockUser);
- const result = await service.findById('1');
+ const result = await service.findOneById('1');
expect(result).toEqual(mockUser);
expect(getUserByIdUseCase.execute).toHaveBeenCalledWith('1');
@@ -51,7 +51,7 @@ describe('UsersService', () => {
it('should return null when user not found', async () => {
(getUserByIdUseCase.execute as jest.Mock).mockResolvedValue(null);
- const result = await service.findById('1');
+ const result = await service.findOneById('1');
expect(result).toBeNull();
expect(getUserByIdUseCase.execute).toHaveBeenCalledWith('1');
@@ -68,7 +68,7 @@ describe('UsersService', () => {
};
(getUserByEmailUseCase.execute as jest.Mock).mockResolvedValue(mockUser);
- const result = await service.findByEmail('test@example.com');
+ const result = await service.findOneByEmail('test@example.com');
expect(result).toEqual(mockUser);
expect(getUserByEmailUseCase.execute).toHaveBeenCalledWith('test@example.com');
@@ -77,7 +77,7 @@ describe('UsersService', () => {
it('should return null when user not found', async () => {
(getUserByEmailUseCase.execute as jest.Mock).mockResolvedValue(null);
- const result = await service.findByEmail('test@example.com');
+ const result = await service.findOneByEmail('test@example.com');
expect(result).toBeNull();
expect(getUserByEmailUseCase.execute).toHaveBeenCalledWith('test@example.com');
diff --git a/libs/users/application/src/lib/users.service.ts b/libs/users/application/src/lib/users.service.ts
index 87d2b50..c8a0897 100644
--- a/libs/users/application/src/lib/users.service.ts
+++ b/libs/users/application/src/lib/users.service.ts
@@ -11,11 +11,11 @@ export class UsersService {
private readonly getUserByEmailUseCase: GetUserByEmailUseCase,
) {}
- async findById(id: string): Promise {
+ async findOneById(id: string): Promise {
return this.getUserByIdUseCase.execute(id);
}
- async findByEmail(email: string): Promise {
+ async findOneByEmail(email: string): Promise {
return this.getUserByEmailUseCase.execute(email);
}
}
diff --git a/libs/users/domain/src/lib/users.repository.spec.ts b/libs/users/domain/src/lib/users.repository.spec.ts
index d560e1e..242ab4e 100644
--- a/libs/users/domain/src/lib/users.repository.spec.ts
+++ b/libs/users/domain/src/lib/users.repository.spec.ts
@@ -12,11 +12,11 @@ class MockUsersRepository implements UsersRepository {
},
];
- async findById(id: string): Promise {
+ async findOneById(id: string): Promise {
return this.users.find((user) => user.id === id) || null;
}
- async findByEmail(email: string): Promise {
+ async findOneByEmail(email: string): Promise {
return this.users.find((user) => user.email === email) || null;
}
}
@@ -28,23 +28,23 @@ describe('UsersRepository', () => {
usersRepository = new MockUsersRepository();
});
- test('findById should return a user by id', async () => {
- const user = await usersRepository.findById('1');
+ test('findOneById should return a user by id', async () => {
+ const user = await usersRepository.findOneById('1');
expect(user).toEqual({
id: '1',
email: 'john@example.com',
firstName: 'John',
- lastName: 'Doe'
+ lastName: 'Doe',
});
});
- test('findById should return null if user not found', async () => {
- const user = await usersRepository.findById('3');
+ test('findOneById should return null if user not found', async () => {
+ const user = await usersRepository.findOneById('3');
expect(user).toBeNull();
});
- test('findByEmail should return a user by email', async () => {
- const user = await usersRepository.findByEmail('jane@example.com');
+ test('findOneByEmail should return a user by email', async () => {
+ const user = await usersRepository.findOneByEmail('jane@example.com');
expect(user).toEqual({
id: '2',
email: 'jane@example.com',
@@ -53,8 +53,8 @@ describe('UsersRepository', () => {
});
});
- test('findByEmail should return null if user not found', async () => {
- const user = await usersRepository.findByEmail('nonexistent@example.com');
+ test('findOneByEmail should return null if user not found', async () => {
+ const user = await usersRepository.findOneByEmail('nonexistent@example.com');
expect(user).toBeNull();
});
});
diff --git a/libs/users/domain/src/lib/users.repository.ts b/libs/users/domain/src/lib/users.repository.ts
index 593a649..90f45a8 100644
--- a/libs/users/domain/src/lib/users.repository.ts
+++ b/libs/users/domain/src/lib/users.repository.ts
@@ -1,8 +1,8 @@
import { User } from './user.entity';
export interface UsersRepository {
- findById(id: string): Promise;
- findByEmail(email: string): Promise;
+ findOneById(id: string): Promise;
+ findOneByEmail(email: string): Promise;
}
export const USERS_REPOSITORY = Symbol('USERS_REPOSITORY');
\ No newline at end of file
diff --git a/libs/users/infrastructure/mongoose/src/lib/mongoose-users.repository.spec.ts b/libs/users/infrastructure/mongoose/src/lib/mongoose-users.repository.spec.ts
deleted file mode 100644
index 0a4bc93..0000000
--- a/libs/users/infrastructure/mongoose/src/lib/mongoose-users.repository.spec.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import { Test, TestingModule } from '@nestjs/testing';
-import { getModelToken } from '@nestjs/mongoose';
-import { Model } from 'mongoose';
-import { MongooseUsersRepository } from './mongoose-users.repository';
-import { UserDocument } from './user.schema';
-import { User } from '@users/domain';
-
-describe('MongooseUsersRepository', () => {
- let repository: MongooseUsersRepository;
- let userModel: Model;
-
- beforeEach(async () => {
- const module: TestingModule = await Test.createTestingModule({
- providers: [
- MongooseUsersRepository,
- {
- provide: getModelToken(UserDocument.name),
- useValue: {
- findById: jest.fn(),
- },
- },
- ],
- }).compile();
-
- repository = module.get(MongooseUsersRepository);
- userModel = module.get>(
- getModelToken(UserDocument.name),
- );
- });
-
- it('should return a user when found', async () => {
- const mockUser = {
- id: '507f1f77bcf86cd799439011',
- email: 'john@example.com',
- firstName: 'John',
- lastName: 'Doe',
- };
-
- jest.spyOn(userModel, 'findById').mockReturnValue({
- exec: jest.fn().mockResolvedValue(mockUser),
- } as any);
-
- const user = await repository.findById(mockUser.id);
- expect(user).toBeInstanceOf(User);
- expect(user?.id).toBe(mockUser.id);
- expect(user?.email).toBe(mockUser.email);
- expect(user?.firstName).toBe(mockUser.firstName);
- expect(user?.lastName).toBe(mockUser.lastName);
- });
-
- it('should return null when user is not found', async () => {
- jest.spyOn(userModel, 'findById').mockReturnValue({
- exec: jest.fn().mockResolvedValue(null),
- } as any);
-
- const user = await repository.findById('507f1f77bcf86cd799439011');
- expect(user).toBeNull();
- });
-});
diff --git a/libs/users/infrastructure/mongoose/src/lib/mongoose-users.repository.ts b/libs/users/infrastructure/mongoose/src/lib/mongoose-users.repository.ts
index c61f9a8..51f143e 100644
--- a/libs/users/infrastructure/mongoose/src/lib/mongoose-users.repository.ts
+++ b/libs/users/infrastructure/mongoose/src/lib/mongoose-users.repository.ts
@@ -11,9 +11,9 @@ export class MongooseUsersRepository implements UsersRepository {
@InjectModel(UserDocument.name) private userModel: Model,
) {}
- async findById(id: string): Promise {
+ async findOneById(id: string): Promise {
const _id = new Types.ObjectId(id);
- const userDocument = await this.userModel.findById(_id).exec();
+ const userDocument = await this.userModel.findOne(_id).exec();
if (!userDocument) {
return null;
@@ -26,7 +26,7 @@ export class MongooseUsersRepository implements UsersRepository {
);
}
- async findByEmail(email: string): Promise {
+ async findOneByEmail(email: string): Promise {
const userDocument = await this.userModel.findOne({ email }).exec();
if (!userDocument) {
diff --git a/libs/users/interface-adapters/src/lib/resolver/users.resolver.spec.ts b/libs/users/interface-adapters/src/lib/resolver/users.resolver.spec.ts
index 1b71a8c..da6aed2 100644
--- a/libs/users/interface-adapters/src/lib/resolver/users.resolver.spec.ts
+++ b/libs/users/interface-adapters/src/lib/resolver/users.resolver.spec.ts
@@ -14,7 +14,7 @@ describe('UsersResolver', () => {
{
provide: UsersService,
useValue: {
- findById: jest.fn(),
+ findOneById: jest.fn(),
},
},
],
diff --git a/libs/users/interface-adapters/src/lib/resolver/users.resolver.ts b/libs/users/interface-adapters/src/lib/resolver/users.resolver.ts
index 5e665db..ca099db 100644
--- a/libs/users/interface-adapters/src/lib/resolver/users.resolver.ts
+++ b/libs/users/interface-adapters/src/lib/resolver/users.resolver.ts
@@ -10,7 +10,7 @@ export class UsersResolver {
@Query(() => UserDto, { nullable: true })
async getUser(@Args({ name: 'id', type: () => ID }) id: string): Promise {
- const user: User| null = await this.usersService.findById(id);
+ const user: User| null = await this.usersService.findOneById(id);
if (!user) {
return null;