diff --git a/package-lock.json b/package-lock.json index a10e84f..b8fe28d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,8 @@ "@nestjs/core": "^11.0.1", "@nestjs/platform-express": "^11.0.1", "@nestjs/typeorm": "^11.0.0", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.0", "pg": "^8.16.3", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1", @@ -3031,6 +3033,12 @@ "@types/superagent": "^8.1.0" } }, + "node_modules/@types/validator": { + "version": "13.15.3", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.3.tgz", + "integrity": "sha512-7bcUmDyS6PN3EuD9SlGGOxM77F8WLVsrwkxyWxKnxzmXoequ6c7741QBrANq6htVRGOITJ7z72mTP6Z4XyuG+Q==", + "license": "MIT" + }, "node_modules/@types/yargs": { "version": "17.0.34", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.34.tgz", @@ -4525,6 +4533,23 @@ "dev": true, "license": "MIT" }, + "node_modules/class-transformer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==", + "license": "MIT" + }, + "node_modules/class-validator": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.2.tgz", + "integrity": "sha512-3kMVRF2io8N8pY1IFIXlho9r8IPUUIfHe2hYVtiebvAzU2XeQFXTv+XI4WX+TnXmtwXMDcjngcpkiPM0O9PvLw==", + "license": "MIT", + "dependencies": { + "@types/validator": "^13.11.8", + "libphonenumber-js": "^1.11.1", + "validator": "^13.9.0" + } + }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -7503,6 +7528,12 @@ "node": ">= 0.8.0" } }, + "node_modules/libphonenumber-js": { + "version": "1.12.25", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.25.tgz", + "integrity": "sha512-u90tUu/SEF8b+RaDKCoW7ZNFDakyBtFlX1ex3J+VH+ElWes/UaitJLt/w4jGu8uAE41lltV/s+kMVtywcMEg7g==", + "license": "MIT" + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -10516,6 +10547,15 @@ "node": ">=10.12.0" } }, + "node_modules/validator": { + "version": "13.15.20", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.20.tgz", + "integrity": "sha512-KxPOq3V2LmfQPP4eqf3Mq/zrT0Dqp2Vmx2Bn285LwVahLc+CsxOM0crBHczm8ijlcjZ0Q5Xd6LW3z3odTPnlrw==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/package.json b/package.json index 8005858..87aa445 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,8 @@ "@nestjs/core": "^11.0.1", "@nestjs/platform-express": "^11.0.1", "@nestjs/typeorm": "^11.0.0", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.0", "pg": "^8.16.3", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1", diff --git a/src/app.module.ts b/src/app.module.ts index aa115bf..b33031f 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -3,20 +3,21 @@ import { AppController } from './app.controller'; import { AppService } from './app.service'; import { TypeOrmModule } from '@nestjs/typeorm'; import { ConfigModule, ConfigService } from '@nestjs/config'; - +import { UserModule } from './user/user.module'; +import { User } from './entity/user'; const moduleTypeOrm = TypeOrmModule.forRootAsync({ imports: [ConfigModule], inject: [ConfigService], useFactory: (configService: ConfigService) => { return { - type: 'postgres', + type: 'postgres', host: configService.get('DATABASE_HOST'), port: parseInt(configService.get('DATABASE_PORT') as string,10), username: configService.get('DATABASE_USER'), password: configService.get('DATABASE_PASS'), database: configService.get('DATABASE_NAME'), - entities: [], + entities: [User], // synchronize: true, }; }, @@ -26,10 +27,10 @@ const moduleTypeOrm = TypeOrmModule.forRootAsync({ @Module({ imports: [ ConfigModule.forRoot(), - moduleTypeOrm + moduleTypeOrm, + UserModule ], controllers: [AppController], providers: [AppService], }) -export class AppModule { -} +export class AppModule {} diff --git a/src/user/dto/create-user.dto.ts b/src/user/dto/create-user.dto.ts new file mode 100644 index 0000000..eec4673 --- /dev/null +++ b/src/user/dto/create-user.dto.ts @@ -0,0 +1,14 @@ +import { IsString, IsEmail, MinLength } from 'class-validator'; + +export class CreateUserDto { + @IsString() + @MinLength(3) + username: string; + + @IsEmail() + email: string; + + @IsString() + @MinLength(6) + password: string; +} diff --git a/src/user/dto/update-user.dto.ts b/src/user/dto/update-user.dto.ts new file mode 100644 index 0000000..62b3a6f --- /dev/null +++ b/src/user/dto/update-user.dto.ts @@ -0,0 +1,17 @@ +import { IsString, IsEmail, MinLength, IsOptional } from 'class-validator'; + +export class UpdateUserDto { + @IsOptional() + @IsString() + @MinLength(3) + username?: string; + + @IsOptional() + @IsEmail() + email?: string; + + @IsOptional() + @IsString() + @MinLength(6) + password?: string; +} diff --git a/src/user/user.controller.ts b/src/user/user.controller.ts new file mode 100644 index 0000000..613b91e --- /dev/null +++ b/src/user/user.controller.ts @@ -0,0 +1,47 @@ +import { + Controller, + Get, + Post, + Body, + Patch, + Param, + Delete, + ValidationPipe, +} from '@nestjs/common'; +import { UserService } from './user.service'; +import { CreateUserDto } from './dto/create-user.dto'; +import { UpdateUserDto } from './dto/update-user.dto'; +import { User } from '../entity/user'; + +@Controller('users') +export class UserController { + constructor(private readonly userService: UserService) {} + + @Post() + create(@Body(new ValidationPipe()) createUserDto: CreateUserDto): Promise { + return this.userService.create(createUserDto); + } + + @Get() + findAll(): Promise { + return this.userService.findAll(); + } + + @Get(':id') + findOne(@Param('id') id: string): Promise { + return this.userService.findOne(+id); + } + + @Patch(':id') + update( + @Param('id') id: string, + @Body(new ValidationPipe()) updateUserDto: UpdateUserDto, + ): Promise { + return this.userService.update(+id, updateUserDto); + } + + @Delete(':id') + remove(@Param('id') id: string): Promise { + return this.userService.remove(+id); + } +} diff --git a/src/user/user.module.ts b/src/user/user.module.ts new file mode 100644 index 0000000..1e2ac8c --- /dev/null +++ b/src/user/user.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { UserService } from './user.service'; +import { UserController } from './user.controller'; +import { User } from '../entity/user'; + +@Module({ + imports: [TypeOrmModule.forFeature([User])], + providers: [UserService], + controllers: [UserController], +}) +export class UserModule {} diff --git a/src/user/user.service.ts b/src/user/user.service.ts new file mode 100644 index 0000000..0f442c9 --- /dev/null +++ b/src/user/user.service.ts @@ -0,0 +1,34 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { User } from '../entity/user'; + +@Injectable() +export class UserService { + constructor( + @InjectRepository(User) + private usersRepository: Repository, + ) {} + + findAll(): Promise { + return this.usersRepository.find(); + } + + findOne(id: number): Promise { + return this.usersRepository.findOneBy({ id }); + } + + async create(user: Partial): Promise { + const newUser = this.usersRepository.create(user); + return this.usersRepository.save(newUser); + } + + async update(id: number, user: Partial): Promise { + await this.usersRepository.update(id, user); + return this.usersRepository.findOneBy({ id }); + } + + async remove(id: number): Promise { + await this.usersRepository.delete(id); + } +}