Initial commit

This commit is contained in:
david.hon
2023-04-17 10:20:39 +08:00
parent 164373aa05
commit 8c78c2ad98
54 changed files with 23165 additions and 2 deletions

View File

@@ -0,0 +1,39 @@
import { ApiProperty } from '@nestjs/swagger';
import {
IsEmail,
IsNotEmpty,
IsDefined,
IsString,
IsNumber,
IsOptional,
} from 'class-validator';
export class CreateUserDto {
// NOTE: Since the id is autoinc, so no id for user creation
// @ApiProperty({
// type: 'number',
// name: 'id',
// description: 'id of user',
// required: false,
// })
// id: number;
@ApiProperty({
type: String,
name: 'name',
description: 'name of user',
required: true,
})
@IsString()
@IsNotEmpty()
name: string;
@ApiProperty({
type: Number,
name: 'age',
description: 'age of user',
required: false,
})
@IsNumber()
@IsOptional()
age: number;
}

View File

@@ -0,0 +1,4 @@
import { PartialType } from '@nestjs/swagger';
import { CreateUserDto } from './create-user.dto';
export class UpdateUserDto extends PartialType(CreateUserDto) {}

View File

@@ -0,0 +1,54 @@
import { ApiProperty } from '@nestjs/swagger';
import { CreateUserDto } from '../dto/create-user.dto';
import { UpdateUserDto } from '../dto/update-user.dto';
// See: https://cimpleo.com/blog/nestjs-modules-and-swagger-practices/
// export interface IUser {
// id: number;
// name: string;
// }
// export class User implements IUser {
export class User {
@ApiProperty({
type: 'number',
name: 'id',
description: 'id of user',
required: false,
})
id: number;
@ApiProperty({
type: 'string',
name: 'name',
description: 'name of user',
required: false,
})
name: string;
protected constructor() {
this.id = -1;
this.name = '';
}
// Factory methods
public static create(id = 0, name = ''): User {
const user = new User();
user.id = id;
user.name = name;
return user;
}
public static createFromCreateUserDto(
userDto: CreateUserDto | UpdateUserDto,
id?: number,
): User {
const user = new User();
if (id) {
user.id = id;
}
user.name = userDto.name;
return user;
}
}

View File

@@ -0,0 +1,49 @@
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
} from '@nestjs/common';
import { ApiResponse } from '@nestjs/swagger';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { User } from './entities/user.entity';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}
@Get()
@ApiResponse({ type: [User], status: 200 })
async findAll(): Promise<User[]> {
return this.usersService.findAll();
}
@Get(':id')
@ApiResponse({ type: User, status: 200 })
async findOne(@Param('id') id: number): Promise<User> {
return this.usersService.findOne(+id);
}
@Patch(':id')
update(
@Param('id') id: number,
@Body() updateUserDto: UpdateUserDto,
): Promise<User> {
return this.usersService.update(+id, updateUserDto);
}
@Delete(':id')
remove(@Param('id') id: number): Promise<User> {
return this.usersService.remove(+id);
}
}

10
src/users/users.module.ts Normal file
View File

@@ -0,0 +1,10 @@
import { Logger, Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import { UserRepository } from './users.repository';
@Module({
controllers: [UsersController],
providers: [Logger, UsersService, UserRepository],
})
export class UsersModule {}

View File

@@ -0,0 +1,72 @@
import { Injectable, Logger, NotFoundException } from '@nestjs/common';
import { User } from './entities/user.entity';
@Injectable()
export class UserRepository {
constructor(private readonly logger: Logger) {}
private readonly users = new Map<number, User>();
public async findAll(): Promise<User[]> {
return [...this.users.values()];
}
public async get(id: number): Promise<User> {
// const user = this.users.find((user) => user.id === id);
if (!this.users.has(id)) {
throw new NotFoundException('User not found');
}
return this.users.get(id);
}
public async add(user: User): Promise<void> {
const largestId = Math.max(...Array.from(this.users.keys()));
// Can get size from map directly but we simulate reading from external service
// So calling the method instead
// const cnt = await this.count();
// await this.get(cnt - 1)
// .then((lastuser) => {
// id = lastuser.id + 1;
// })
// .catch(() => {
// id = 0;
// });
user.id = largestId < 0 ? 0 : largestId + 1;
this.users.set(user.id, user);
this.logger.log({ message: 'User added', user });
}
public async update(id: number, user: User): Promise<User> {
// Can get size from map directly but we simulate reading from external service
// So calling the method instead
// It will throw exception if not found.
const oldUser = await this.get(id);
this.users.set(id, user);
this.logger.log({ message: 'User updated', from: oldUser, to: user });
return oldUser;
}
public async delete(id: number): Promise<User> {
let deletedUser: User;
await this.get(id)
.then((user) => {
this.users.delete(id);
this.logger.log({ message: 'User deleted', user });
deletedUser = user;
})
.catch(() => {
throw new NotFoundException(
`User not found, No user deleted, id=${id}`,
);
});
return deletedUser;
}
public async count(): Promise<number> {
return this.users.size;
}
}

View File

@@ -0,0 +1,36 @@
import { Injectable, Logger } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { User } from './entities/user.entity';
import { UserRepository } from './users.repository';
@Injectable()
export class UsersService {
constructor(
private readonly logger: Logger,
private readonly userRepository: UserRepository,
) {}
async create(createUserDto: CreateUserDto): Promise<User> {
const user = User.createFromCreateUserDto(createUserDto, -1);
await this.userRepository.add(user);
return user;
}
async findAll(): Promise<User[]> {
return this.userRepository.findAll();
}
async findOne(id: number): Promise<User> {
return this.userRepository.get(id);
}
async update(id: number, updateUserDto: UpdateUserDto): Promise<User> {
const user = User.createFromCreateUserDto(updateUserDto, id);
return this.userRepository.update(id, user);
}
async remove(id: number): Promise<User> {
return this.userRepository.delete(id);
}
}