From 5d6023daa5d03ba075ec71fe28841b812f6510d6 Mon Sep 17 00:00:00 2001 From: zhumeisongsong Date: Mon, 25 Nov 2024 16:06:12 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E2=9C=A8=20update=20user=20module?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/use-cases/get-user.use-case.spec.ts | 7 +++- .../application/src/lib/users.service.spec.ts | 8 +++- .../application/src/lib/users.service.ts | 4 ++ libs/users/domain/src/lib/user.entity.spec.ts | 40 +++++++++++++++---- libs/users/domain/src/lib/user.entity.ts | 5 ++- .../domain/src/lib/users.repository.spec.ts | 28 +++++++++++-- libs/users/domain/src/lib/users.repository.ts | 1 + .../src/lib/mongoose-users.repository.spec.ts | 11 ++++- .../src/lib/dto/user.dto.spec.ts | 11 +++-- .../src/lib/dto/user.dto.ts | 14 +++++-- .../src/lib/resolver/users.resolver.spec.ts | 1 - .../src/lib/resolver/users.resolver.ts | 6 ++- 12 files changed, 111 insertions(+), 25 deletions(-) diff --git a/libs/users/application/src/lib/use-cases/get-user.use-case.spec.ts b/libs/users/application/src/lib/use-cases/get-user.use-case.spec.ts index 7debc7a..01860e4 100644 --- a/libs/users/application/src/lib/use-cases/get-user.use-case.spec.ts +++ b/libs/users/application/src/lib/use-cases/get-user.use-case.spec.ts @@ -8,13 +8,18 @@ describe('GetUserUseCase', () => { beforeEach(() => { usersRepository = { findById: jest.fn(), + findByEmail: jest.fn() }; getUserUseCase = new GetUserUseCase(usersRepository); }); describe('execute', () => { it('should return user when found', async () => { - const mockUser = { id: '1', name: 'John Doe' }; + const mockUser = { id: '1', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com' + }; (usersRepository.findById as jest.Mock).mockResolvedValue(mockUser); const result = await getUserUseCase.execute('1'); diff --git a/libs/users/application/src/lib/users.service.spec.ts b/libs/users/application/src/lib/users.service.spec.ts index c3879e0..92183a5 100644 --- a/libs/users/application/src/lib/users.service.spec.ts +++ b/libs/users/application/src/lib/users.service.spec.ts @@ -30,7 +30,13 @@ describe('UsersService', () => { describe('findById', () => { it('should return a user if found', async () => { - const user: User = { id: '1', name: 'John Doe' }; + const user: User = { + id: '1', + firstName: 'John', + lastName: 'Doe', + email: 'john@example.com', + password: 'password123', + }; jest.spyOn(getUserUseCase, 'execute').mockResolvedValue(user); const result = await service.findById('1'); diff --git a/libs/users/application/src/lib/users.service.ts b/libs/users/application/src/lib/users.service.ts index 8583406..63ebb89 100644 --- a/libs/users/application/src/lib/users.service.ts +++ b/libs/users/application/src/lib/users.service.ts @@ -10,4 +10,8 @@ export class UsersService { async findById(id: string): Promise { return this.getUserUseCase.execute(id); } + + async findByEmail(email: string): Promise { + return this.getUserUseCase.execute(email); + } } diff --git a/libs/users/domain/src/lib/user.entity.spec.ts b/libs/users/domain/src/lib/user.entity.spec.ts index 4274304..582d9c7 100644 --- a/libs/users/domain/src/lib/user.entity.spec.ts +++ b/libs/users/domain/src/lib/user.entity.spec.ts @@ -1,15 +1,39 @@ import { User } from './user.entity'; describe('User Entity', () => { - it('should create a user with id and name', () => { - const user = new User('1', 'John Doe'); - expect(user.id).toBe('1'); - expect(user.name).toBe('John Doe'); + it('should create a user with all required properties', () => { + const user = new User( + 'test-id', + 'John', + 'Doe', + 'john@example.com', + 'password123', + ); + + expect(user.id).toBe('test-id'); + expect(user.firstName).toBe('John'); + expect(user.lastName).toBe('Doe'); + expect(user.email).toBe('john@example.com'); + expect(user.password).toBe('password123'); }); - it('should allow updating the name', () => { - const user = new User('1', 'John Doe'); - user.name = 'Jane Doe'; - expect(user.name).toBe('Jane Doe'); + it('should have all properties as defined in the constructor', () => { + const userData = { + id: 'user-123', + firstName: 'Jane', + lastName: 'Smith', + email: 'jane@example.com', + password: 'securepass', + }; + + const user = new User( + userData.id, + userData.firstName, + userData.lastName, + userData.email, + userData.password, + ); + + expect(user).toEqual(userData); }); }); diff --git a/libs/users/domain/src/lib/user.entity.ts b/libs/users/domain/src/lib/user.entity.ts index 202554e..f7f8b40 100644 --- a/libs/users/domain/src/lib/user.entity.ts +++ b/libs/users/domain/src/lib/user.entity.ts @@ -1,6 +1,9 @@ export class User { constructor( public readonly id: string, - public name: string, + public firstName: string, + public lastName: string, + public email: string, + public password: string, ) {} } diff --git a/libs/users/domain/src/lib/users.repository.spec.ts b/libs/users/domain/src/lib/users.repository.spec.ts index 93f4ec3..6bc69d8 100644 --- a/libs/users/domain/src/lib/users.repository.spec.ts +++ b/libs/users/domain/src/lib/users.repository.spec.ts @@ -3,13 +3,29 @@ import { User } from './user.entity'; class MockUsersRepository implements UsersRepository { private users: User[] = [ - { id: '1', name: 'John Doe' }, - { id: '2', name: 'Jane Doe' }, + { + id: '1', + firstName: 'John', + lastName: 'Doe', + email: 'john@example.com', + password: 'password123' + }, + { + id: '2', + firstName: 'Jane', + lastName: 'Smith', + email: 'jane@example.com', + password: 'password456' + } ]; async findById(id: string): Promise { return this.users.find((user) => user.id === id) || null; } + + async findByEmail(email: string): Promise { + return this.users.find((user) => user.email === email) || null; + } } describe('UsersRepository', () => { @@ -21,7 +37,13 @@ describe('UsersRepository', () => { test('findById should return a user by id', async () => { const user = await usersRepository.findById('1'); - expect(user).toEqual({ id: '1', name: 'John Doe' }); + expect(user).toEqual({ + id: '1', + firstName: 'John', + lastName: 'Doe', + email: 'john@example.com', + password: 'password123' + }); }); test('findById should return null if user not found', async () => { diff --git a/libs/users/domain/src/lib/users.repository.ts b/libs/users/domain/src/lib/users.repository.ts index 4af6be0..593a649 100644 --- a/libs/users/domain/src/lib/users.repository.ts +++ b/libs/users/domain/src/lib/users.repository.ts @@ -2,6 +2,7 @@ import { User } from './user.entity'; export interface UsersRepository { findById(id: string): Promise; + findByEmail(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 index ae36827..572c38a 100644 --- a/libs/users/infrastructure/mongoose/src/lib/mongoose-users.repository.spec.ts +++ b/libs/users/infrastructure/mongoose/src/lib/mongoose-users.repository.spec.ts @@ -29,7 +29,11 @@ describe('MongooseUsersRepository', () => { it('should return a user when found', async () => { const mockUser = { id: '507f1f77bcf86cd799439011', - name: 'Test User', + firstName: 'John', + lastName: 'Doe', + email: 'john@example.com', + password: 'password123', + name: 'John Doe' }; jest.spyOn(userModel, 'findById').mockReturnValue({ @@ -39,7 +43,10 @@ describe('MongooseUsersRepository', () => { const user = await repository.findById(mockUser.id); expect(user).toBeInstanceOf(User); expect(user?.id).toBe(mockUser.id); - expect(user?.name).toBe(mockUser.name); + expect(user?.firstName).toBe(mockUser.firstName); + expect(user?.lastName).toBe(mockUser.lastName); + expect(user?.email).toBe(mockUser.email); + expect(user?.password).toBe(mockUser.password); }); it('should return null when user is not found', async () => { diff --git a/libs/users/interface-adapters/src/lib/dto/user.dto.spec.ts b/libs/users/interface-adapters/src/lib/dto/user.dto.spec.ts index aa7e379..5ab10ca 100644 --- a/libs/users/interface-adapters/src/lib/dto/user.dto.spec.ts +++ b/libs/users/interface-adapters/src/lib/dto/user.dto.spec.ts @@ -3,11 +3,16 @@ import { UserDto } from './user.dto'; describe('UserDto', () => { it('should create a new UserDto instance', () => { const id = '123'; - const name = 'Test User'; - const userDto = new UserDto(id, name); + const firstName = 'Test'; + const lastName = 'User'; + const email = 'test@example.com'; + + const userDto = new UserDto(id, firstName, lastName, email); expect(userDto).toBeDefined(); expect(userDto.id).toBe(id); - expect(userDto.name).toBe(name); + expect(userDto.firstName).toBe(firstName); + expect(userDto.lastName).toBe(lastName); + expect(userDto.email).toBe(email); }); }); diff --git a/libs/users/interface-adapters/src/lib/dto/user.dto.ts b/libs/users/interface-adapters/src/lib/dto/user.dto.ts index 764738c..ddd6478 100644 --- a/libs/users/interface-adapters/src/lib/dto/user.dto.ts +++ b/libs/users/interface-adapters/src/lib/dto/user.dto.ts @@ -6,10 +6,18 @@ export class UserDto { id: string; @Field() - name: string; + firstName: string; - constructor(id: string, name: string) { + @Field() + lastName: string; + + @Field() + email: string; + + constructor(id: string, firstName: string, lastName: string, email: string) { this.id = id; - this.name = name; + this.firstName = firstName; + this.lastName = lastName; + this.email = email; } } 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 1bbf9ec..1b71a8c 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 @@ -1,6 +1,5 @@ import { Test, TestingModule } from '@nestjs/testing'; import { UsersService } from '@users/application'; -import { User } from '@users/domain'; import { UsersResolver } from './users.resolver'; 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 5619dc7..3cc9934 100644 --- a/libs/users/interface-adapters/src/lib/resolver/users.resolver.ts +++ b/libs/users/interface-adapters/src/lib/resolver/users.resolver.ts @@ -8,13 +8,15 @@ export class UsersResolver { constructor(private usersService: UsersService) {} @Query(() => UserDto, { nullable: true }) - async getUser(@Args({ name: 'id', type: () => ID }) id: string): Promise { + async getUser( + @Args({ name: 'id', type: () => ID }) id: string, + ): Promise { const user = await this.usersService.findById(id); if (!user) { return null; } - return new UserDto(user.id, user.name); + return new UserDto(user.id, user.firstName, user.lastName, user.email); } } From ef3f8ca7aca62d11aaf6ab89895042693ab73699 Mon Sep 17 00:00:00 2001 From: zhumeisongsong Date: Mon, 25 Nov 2024 16:20:43 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E2=9C=A8=20Update=20UserDocument?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/lib/mongoose-users.repository.ts | 22 +++++++++++++++++-- .../mongoose/src/lib/user.schema.ts | 13 +++++++++-- 2 files changed, 31 insertions(+), 4 deletions(-) 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 9da4285..ea81393 100644 --- a/libs/users/infrastructure/mongoose/src/lib/mongoose-users.repository.ts +++ b/libs/users/infrastructure/mongoose/src/lib/mongoose-users.repository.ts @@ -12,13 +12,31 @@ export class MongooseUsersRepository implements UsersRepository { ) {} async findById(id: string): Promise { - const _id = new Types.ObjectId(id); const userDocument = await this.userModel.findById(_id).exec(); if (!userDocument) { return null; } - return new User(userDocument.id, userDocument.name); + return new User( + userDocument.id, + userDocument.lastName, + userDocument.firstName, + userDocument.email, + userDocument.password, + ); + } + + async findByEmail(email: string): Promise { + const userDocument = await this.userModel.findOne({ email }).exec(); + return userDocument + ? new User( + userDocument.id, + userDocument.lastName, + userDocument.firstName, + userDocument.email, + userDocument.password, + ) + : null; } } diff --git a/libs/users/infrastructure/mongoose/src/lib/user.schema.ts b/libs/users/infrastructure/mongoose/src/lib/user.schema.ts index ff6527f..fe7cdac 100644 --- a/libs/users/infrastructure/mongoose/src/lib/user.schema.ts +++ b/libs/users/infrastructure/mongoose/src/lib/user.schema.ts @@ -4,7 +4,16 @@ import { Document } from 'mongoose'; @Schema() export class UserDocument extends Document { @Prop({ required: true }) - name!: string; + email!: string; + + @Prop({ required: false }) + firstName!: string; + + @Prop({ required: false }) + lastName!: string; + + @Prop({ required: true, nullable: true }) + password!: string; } -export const UserSchema = SchemaFactory.createForClass(UserDocument); \ No newline at end of file +export const UserSchema = SchemaFactory.createForClass(UserDocument);