From c6dd6ea56a4f15a4ea09e102f1ee584d01798751 Mon Sep 17 00:00:00 2001 From: Nikita Kudinov Date: Sun, 4 Feb 2024 20:06:50 +0300 Subject: [PATCH] refactor: create entity classes with automap properties --- src/api/api.module.ts | 4 +- src/api/controllers/auth.controller.ts | 8 +- src/api/controllers/centrifugo.controller.ts | 2 +- src/api/controllers/packs.controller.ts | 22 ++--- src/api/controllers/trades.controller.ts | 27 +++--- src/api/controllers/users.controller.ts | 30 +++---- .../accepted-trade.output.dto.ts | 2 + .../cancelled-trade.output.dto.ts | 2 + src/api/dtos/packs/opened-pack.output.dto.ts | 6 ++ .../packs/pack-with-pokemons.output.dto.ts | 2 + src/api/dtos/packs/pack.output.dto.ts | 6 ++ .../pending-trade.output.dto.ts | 2 + src/api/dtos/pokemons/pokemon.output.dto.ts | 7 ++ .../rejected-trade.output.dto.ts | 2 + src/api/dtos/trades/trade.output.dto.ts | 10 ++- .../quick-sold-user-item.output.dto.ts | 2 + .../dtos/user-items/user-item.output.dto.ts | 4 + src/api/dtos/users/user.output.dto.ts | 4 + src/api/profiles/pack.profile.ts | 66 ++------------- src/api/profiles/pokemon.profile.ts | 33 +------- src/api/profiles/trade.profile.ts | 83 ++++--------------- src/api/profiles/user-item.profile.ts | 47 ++--------- src/api/profiles/user.profile.ts | 29 +------ .../strategies/access-token-auth.strategy.ts | 2 +- src/api/strategies/local-auth.strategy.ts | 2 +- .../strategies/refresh-token-auth.strategy.ts | 2 +- src/core/entities/opened-pack.entity.ts | 23 +++++ src/core/entities/pack-to-pokemon.entity.ts | 10 +++ src/core/entities/pack.entity.ts | 27 ++++++ src/core/entities/pokemon.entity.ts | 18 ++++ .../entities/quick-sold-user-item.entity.ts | 7 ++ .../entities/trade-to-user-item.entity.ts | 40 +++++++++ src/core/entities/trade.entity.ts | 61 ++++++++++++++ src/core/entities/user-item.entity.ts | 26 ++++++ .../entities/user-refresh-token.entity.ts | 16 ++++ src/core/entities/user.entity.ts | 29 +++++++ .../repositories/opened-packs.repository.ts | 2 +- src/core/repositories/packs.repository.ts | 3 +- src/core/repositories/pokemons.repository.ts | 2 +- .../quick-sold-user-items.repository.ts | 3 +- .../trades-to-user-items.repository.ts | 4 +- src/core/repositories/trades.repository.ts | 5 +- .../repositories/user-items.repository.ts | 3 +- .../user-refresh-tokens.repository.ts | 2 +- src/core/repositories/users.repository.ts | 3 +- src/core/services/auth.service.ts | 35 +++----- src/core/services/packs.service.ts | 4 +- src/core/services/pending-trades.service.ts | 3 +- src/core/services/user-items.service.ts | 4 +- src/core/services/users.service.ts | 2 +- src/infra/centrifugo/centrifugo.service.ts | 3 +- .../repositories/opened-pack.repository.ts | 3 +- .../postgres/repositories/packs.repository.ts | 4 +- .../repositories/pokemons.repository.ts | 3 +- .../quick-sold-user-items.repository.ts | 12 ++- .../trades-to-user-items.repository.ts | 14 ++-- .../repositories/trades.repository.ts | 12 ++- .../repositories/user-items.repository.ts | 8 +- .../user-refresh-tokens.repository.ts | 50 +++++++---- .../postgres/repositories/users.repository.ts | 20 ++++- .../postgres/tables/opened-packs.table.ts | 19 +---- .../tables/packs-to-pokemons.table.ts | 9 +- src/infra/postgres/tables/packs.table.ts | 6 +- src/infra/postgres/tables/pokemons.table.ts | 3 - .../tables/quick-sold-user-items.table.ts | 9 +- .../tables/trades-to-user-items.table.ts | 36 +------- src/infra/postgres/tables/trades.table.ts | 46 +--------- src/infra/postgres/tables/user-items.table.ts | 19 +---- .../tables/user-refresh-tokens.table.ts | 9 +- src/infra/postgres/tables/users.table.ts | 4 - tests/e2e/modules/auth/login.post.test.ts | 2 +- 71 files changed, 539 insertions(+), 490 deletions(-) create mode 100644 src/core/entities/opened-pack.entity.ts create mode 100644 src/core/entities/pack-to-pokemon.entity.ts create mode 100644 src/core/entities/pack.entity.ts create mode 100644 src/core/entities/pokemon.entity.ts create mode 100644 src/core/entities/quick-sold-user-item.entity.ts create mode 100644 src/core/entities/trade-to-user-item.entity.ts create mode 100644 src/core/entities/trade.entity.ts create mode 100644 src/core/entities/user-item.entity.ts create mode 100644 src/core/entities/user-refresh-token.entity.ts create mode 100644 src/core/entities/user.entity.ts diff --git a/src/api/api.module.ts b/src/api/api.module.ts index ccab7da..0fae7df 100644 --- a/src/api/api.module.ts +++ b/src/api/api.module.ts @@ -19,12 +19,12 @@ import { UserItemProfile } from './profiles/user-item.profile'; import { TradesController } from './controllers/trades.controller'; import { TradesModule } from 'src/infra/ioc/core-modules/trades.module'; import { TradeProfile } from './profiles/trade.profile'; -import { pojos } from '@automapper/pojos'; import { EventEmitterModule } from '@nestjs/event-emitter'; import { CentrifugoModule } from 'src/infra/centrifugo/centrifugo.module'; import { CentrifugoController } from './controllers/centrifugo.controller'; import { RefreshTokenAuthStrategy } from './strategies/refresh-token-auth.strategy'; import { CronJobsModule } from 'src/infra/cron-jobs/cron-jobs.module'; +import { classes } from '@automapper/classes'; @Module({ imports: [ @@ -32,7 +32,7 @@ import { CronJobsModule } from 'src/infra/cron-jobs/cron-jobs.module'; global: true, }), AutomapperModule.forRoot({ - strategyInitializer: pojos(), + strategyInitializer: classes(), }), PassportModule, diff --git a/src/api/controllers/auth.controller.ts b/src/api/controllers/auth.controller.ts index baf5bb0..bc37fbb 100644 --- a/src/api/controllers/auth.controller.ts +++ b/src/api/controllers/auth.controller.ts @@ -7,7 +7,7 @@ import { LoginUserInputDTO } from '../dtos/auth/login-user.input.dto'; import { RegisterUserInputDTO } from '../dtos/auth/register-user.input.dto'; import { RegisterUserOutputDTO } from '../dtos/auth/register-user.output.dto'; import { ApiCreatedResponse, ApiOkResponse, ApiSecurity, ApiTags } from '@nestjs/swagger'; -import { UserEntity } from 'src/infra/postgres/tables'; +import { UserEntity } from 'src/core/entities/user.entity'; import { InjectMapper } from '@automapper/nestjs'; import { Mapper } from '@automapper/core'; import { UserOutputDTO } from '../dtos/users/user.output.dto'; @@ -36,7 +36,7 @@ export class AuthController { const { accessToken, refreshToken } = await this.authService.loginUser(user); return { - user: this.mapper.map(user, 'UserEntity', 'UserOutputDTO'), + user: this.mapper.map(user, UserEntity, UserOutputDTO), accessToken, refreshToken, }; @@ -50,7 +50,7 @@ export class AuthController { const { user, accessToken, refreshToken } = await this.authService.registerUser(dto); return { - user: this.mapper.map(user, 'UserEntity', 'UserOutputDTO'), + user: this.mapper.map(user, UserEntity, UserOutputDTO), accessToken, refreshToken, }; @@ -82,7 +82,7 @@ export class AuthController { } = await this.authService.refreshTokens(user, oldRefreshToken); return { - user: this.mapper.map(user, 'UserEntity', 'UserOutputDTO'), + user: this.mapper.map(user, UserEntity, UserOutputDTO), accessToken, refreshToken: newRefreshToken, }; diff --git a/src/api/controllers/centrifugo.controller.ts b/src/api/controllers/centrifugo.controller.ts index 6aa9fdb..c5960c1 100644 --- a/src/api/controllers/centrifugo.controller.ts +++ b/src/api/controllers/centrifugo.controller.ts @@ -1,7 +1,7 @@ import { Controller, HttpCode, HttpStatus, Post, UseGuards } from '@nestjs/common'; import { CentrifugoService } from 'src/infra/centrifugo/centrifugo.service'; import { User } from '../decorators/user.decorator'; -import { UserEntity } from 'src/infra/postgres/tables'; +import { UserEntity } from 'src/core/entities/user.entity'; import { AccessTokenAuthGuard } from '../guards/access-token-auth.guard'; import { ApiCreatedResponse, ApiSecurity, ApiTags } from '@nestjs/swagger'; import { GenerateCentrifugoConnectionTokenOutputDTO } from '../dtos/centrifugo/generate-centrifugo-connection-token.output.dto'; diff --git a/src/api/controllers/packs.controller.ts b/src/api/controllers/packs.controller.ts index 56d6285..1a8a3ce 100644 --- a/src/api/controllers/packs.controller.ts +++ b/src/api/controllers/packs.controller.ts @@ -11,7 +11,9 @@ import { PackWithPokemonsOutputDTO } from '../dtos/packs/pack-with-pokemons.outp import { OpenedPackOutputDTO } from '../dtos/packs/opened-pack.output.dto'; import { PaginationInputDTO } from '../dtos/pagination.input.dto'; import { mapPaginatedArray } from 'src/common/helpers/map-paginated-array.helper'; -import { OpenedPackEntity, PackEntity, UserEntity } from 'src/infra/postgres/tables'; +import { OpenedPackEntity } from 'src/core/entities/opened-pack.entity'; +import { PackEntity} from 'src/core/entities/pack.entity'; +import { UserEntity } from 'src/core/entities/user.entity'; import { GetPacksInputDTO } from '../dtos/packs/get-packs.input.dto'; import { ApiOkResponseWithPagination } from '../decorators/api-ok-response-with-pagination.decorator'; @@ -35,11 +37,11 @@ export class PacksController { ): Promise> { const packs = await this.packsService.getPacksWithPagination(dto, paginationDTO); - return mapPaginatedArray( + return mapPaginatedArray( this.mapper, packs, - 'PackEntity', - 'PackOutputDTO', + PackEntity, + PackOutputDTO, ) } @@ -53,10 +55,10 @@ export class PacksController { ): Promise { const pack = await this.packsService.getPackById(id); - return this.mapper.map( + return this.mapper.map( pack, - 'PackEntity', - 'PackOutputDTO', + PackEntity, + PackWithPokemonsOutputDTO, ); } @@ -72,10 +74,10 @@ export class PacksController { ): Promise { const openedPack = await this.packsService.openPackById(user, id); - return this.mapper.map( + return this.mapper.map( openedPack, - 'OpenedPackEntity', - 'OpenedPackOutputDTO' + OpenedPackEntity, + OpenedPackOutputDTO, ); } } diff --git a/src/api/controllers/trades.controller.ts b/src/api/controllers/trades.controller.ts index dca96c1..67a02e2 100644 --- a/src/api/controllers/trades.controller.ts +++ b/src/api/controllers/trades.controller.ts @@ -4,7 +4,8 @@ import { Body, Controller, Param, ParseUUIDPipe, Post, UseGuards } from '@nestjs import { ApiCreatedResponse, ApiSecurity, ApiTags } from '@nestjs/swagger'; import { UUIDv4 } from 'src/common/types'; import { PendingTradesService } from 'src/core/services/pending-trades.service'; -import { AcceptedTradeEntity, CancelledTradeEntity, PendingTradeEntity, RejectedTradeEntity, UserEntity } from 'src/infra/postgres/tables'; +import { AcceptedTradeEntity, CancelledTradeEntity, PendingTradeEntity, RejectedTradeEntity} from 'src/core/entities/trade.entity'; +import { UserEntity } from 'src/core/entities/user.entity'; import { User } from '../decorators/user.decorator'; import { AcceptedTradeOutputDTO } from '../dtos/accepted-trades/accepted-trade.output.dto'; import { CancelledTradeOuputDTO } from '../dtos/cancelled-trades/cancelled-trade.output.dto'; @@ -33,10 +34,10 @@ export class TradesController { ): Promise { const pendingTrade = await this.pendingTradesService.createPendingTrade(user, dto); - return this.mapper.map( + return this.mapper.map( pendingTrade, - 'PendingTradeEntity', - 'PendingTradeOutputDTO', + PendingTradeEntity, + PendingTradeOutputDTO, ); } @@ -50,10 +51,10 @@ export class TradesController { ) { const cancelledTrade = await this.pendingTradesService.cancelPendingTradeById(user, id) - return this.mapper.map( + return this.mapper.map( cancelledTrade, - 'CancelledTradeEntity', - 'CancelledTradeOuputDTO', + CancelledTradeEntity, + CancelledTradeOuputDTO, ); } @@ -67,10 +68,10 @@ export class TradesController { ) { const acceptedTrade = await this.pendingTradesService.acceptPendingTradeById(user, id); - return this.mapper.map( + return this.mapper.map( acceptedTrade, - 'AcceptedTradeEntity', - 'AcceptedTradeOutputDTO', + AcceptedTradeEntity, + AcceptedTradeOutputDTO, ); } @@ -84,10 +85,10 @@ export class TradesController { ) { const rejectedTrade = await this.pendingTradesService.rejectPendingTradeById(user, id); - return this.mapper.map( + return this.mapper.map( rejectedTrade, - 'RejectedTradeEntity', - 'RejectedTradeOutputDTO' + RejectedTradeEntity, + RejectedTradeOutputDTO, ); } } diff --git a/src/api/controllers/users.controller.ts b/src/api/controllers/users.controller.ts index be40bf8..5b05abe 100644 --- a/src/api/controllers/users.controller.ts +++ b/src/api/controllers/users.controller.ts @@ -14,7 +14,9 @@ import { GetUsersInputDTO } from '../dtos/users/get-users.input.dto'; import { UserItemsService } from 'src/core/services/user-items.service'; import { UserItemOutputDTO } from '../dtos/user-items/user-item.output.dto'; import { QuickSoldUserItemOutputDTO } from '../dtos/user-items/quick-sold-user-item.output.dto'; -import { QuickSoldUserItemEntity, UserEntity, UserItemEntity } from 'src/infra/postgres/tables'; +import { QuickSoldUserItemEntity } from 'src/core/entities/quick-sold-user-item.entity'; +import { UserEntity } from 'src/core/entities/user.entity'; +import { UserItemEntity } from 'src/core/entities/user-item.entity'; @ApiTags('Users') @Controller('users') @@ -37,13 +39,7 @@ export class UsersController { ): Promise> { const users = await this.usersService.getUsersWithPagination(dto, paginationDTO); - this.mapper.mapArray - return mapPaginatedArray( - this.mapper, - users, - 'UserEntity', - 'UserOutputDTO', - ) + return mapPaginatedArray(this.mapper, users, UserEntity, UserOutputDTO); } @ApiOkResponse({ type: UserOutputDTO }) @@ -51,11 +47,7 @@ export class UsersController { @Get('me') @UseGuards(AccessTokenAuthGuard) public async getMe(@User() user: UserEntity): Promise { - return this.mapper.map( - user, - 'UserEntity', - 'UserOutputDTO', - ); + return this.mapper.map(user, UserEntity, UserOutputDTO); } @ApiOkResponseWithPagination({ type: UserItemOutputDTO }) @@ -68,11 +60,11 @@ export class UsersController { ): Promise> { const userItemsWithPagination = await this.userItemsService.getUserItemsWithPaginationByUser(user, paginationDto); - return mapPaginatedArray( + return mapPaginatedArray( this.mapper, userItemsWithPagination, - 'UserItemEntity', - 'UserItemOutputDTO', + UserItemEntity, + UserItemOutputDTO, ); } @@ -86,10 +78,10 @@ export class UsersController { ): Promise { const quickSoldUserItem = await this.userItemsService.quickSellUserItemById(user, id); - return this.mapper.map( + return this.mapper.map( quickSoldUserItem, - 'QuickSoldUserItemEntity', - 'QuickSoldUserItemOutputDTO', + QuickSoldUserItemEntity, + QuickSoldUserItemOutputDTO, ); } } diff --git a/src/api/dtos/accepted-trades/accepted-trade.output.dto.ts b/src/api/dtos/accepted-trades/accepted-trade.output.dto.ts index 68a74b9..5f1449f 100644 --- a/src/api/dtos/accepted-trades/accepted-trade.output.dto.ts +++ b/src/api/dtos/accepted-trades/accepted-trade.output.dto.ts @@ -1,9 +1,11 @@ import { ApiProperty, OmitType } from '@nestjs/swagger'; import { TradeOutputDTO } from '../trades/trade.output.dto'; +import { AutoMap } from '@automapper/classes'; export class AcceptedTradeOutputDTO extends OmitType(TradeOutputDTO, [ 'status', ]) { @ApiProperty() + @AutoMap() status: 'ACCEPTED'; } diff --git a/src/api/dtos/cancelled-trades/cancelled-trade.output.dto.ts b/src/api/dtos/cancelled-trades/cancelled-trade.output.dto.ts index 49d2158..ab98d73 100644 --- a/src/api/dtos/cancelled-trades/cancelled-trade.output.dto.ts +++ b/src/api/dtos/cancelled-trades/cancelled-trade.output.dto.ts @@ -1,9 +1,11 @@ import { ApiProperty, OmitType } from '@nestjs/swagger'; import { TradeOutputDTO } from '../trades/trade.output.dto'; +import { AutoMap } from '@automapper/classes'; export class CancelledTradeOuputDTO extends OmitType(TradeOutputDTO, [ 'status', ]) { @ApiProperty() + @AutoMap() status: 'CANCELLED'; } diff --git a/src/api/dtos/packs/opened-pack.output.dto.ts b/src/api/dtos/packs/opened-pack.output.dto.ts index d64e463..079b7ab 100644 --- a/src/api/dtos/packs/opened-pack.output.dto.ts +++ b/src/api/dtos/packs/opened-pack.output.dto.ts @@ -3,20 +3,26 @@ import { UUIDv4 } from 'src/common/types'; import { PokemonOutputDTO } from '../pokemons/pokemon.output.dto'; import { UserOutputDTO } from '../users/user.output.dto'; import { PackOutputDTO } from './pack.output.dto'; +import { AutoMap } from '@automapper/classes'; export class OpenedPackOutputDTO { @ApiProperty() + @AutoMap() public readonly id: UUIDv4; @ApiProperty() + @AutoMap() public readonly openedAt: Date; @ApiProperty({ type: UserOutputDTO }) + @AutoMap(() => UserOutputDTO) public readonly user: UserOutputDTO; @ApiProperty({ type: PackOutputDTO }) + @AutoMap(() => PackOutputDTO) public readonly pack: PackOutputDTO; @ApiProperty({ type: PokemonOutputDTO }) + @AutoMap(() => PokemonOutputDTO) public readonly pokemon: PokemonOutputDTO; } diff --git a/src/api/dtos/packs/pack-with-pokemons.output.dto.ts b/src/api/dtos/packs/pack-with-pokemons.output.dto.ts index 0d0b417..62b1269 100644 --- a/src/api/dtos/packs/pack-with-pokemons.output.dto.ts +++ b/src/api/dtos/packs/pack-with-pokemons.output.dto.ts @@ -1,8 +1,10 @@ import { ApiProperty } from '@nestjs/swagger'; import { PokemonOutputDTO } from '../pokemons/pokemon.output.dto'; import { PackOutputDTO } from './pack.output.dto'; +import { AutoMap } from '@automapper/classes'; export class PackWithPokemonsOutputDTO extends PackOutputDTO { @ApiProperty({ type: PokemonOutputDTO, isArray: true }) + @AutoMap(() => [PokemonOutputDTO]) public readonly pokemons: Array; } diff --git a/src/api/dtos/packs/pack.output.dto.ts b/src/api/dtos/packs/pack.output.dto.ts index f059b3e..516fbc7 100644 --- a/src/api/dtos/packs/pack.output.dto.ts +++ b/src/api/dtos/packs/pack.output.dto.ts @@ -1,20 +1,26 @@ +import { AutoMap } from "@automapper/classes"; import { ApiProperty } from "@nestjs/swagger"; import { UUIDv4 } from "src/common/types"; export class PackOutputDTO { @ApiProperty() + @AutoMap() public readonly id: UUIDv4; @ApiProperty() + @AutoMap() public readonly name: string; @ApiProperty() + @AutoMap() public readonly description: string; @ApiProperty() + @AutoMap() public readonly price: number; // NOTE: URL @ApiProperty() + @AutoMap() public readonly image: string; } diff --git a/src/api/dtos/pending-trades/pending-trade.output.dto.ts b/src/api/dtos/pending-trades/pending-trade.output.dto.ts index d6bd319..3910cf4 100644 --- a/src/api/dtos/pending-trades/pending-trade.output.dto.ts +++ b/src/api/dtos/pending-trades/pending-trade.output.dto.ts @@ -1,9 +1,11 @@ import { ApiProperty, OmitType } from '@nestjs/swagger'; import { TradeOutputDTO } from '../trades/trade.output.dto'; +import { AutoMap } from '@automapper/classes'; export class PendingTradeOutputDTO extends OmitType(TradeOutputDTO, [ 'status', ]) { @ApiProperty() + @AutoMap() status: 'PENDING'; } diff --git a/src/api/dtos/pokemons/pokemon.output.dto.ts b/src/api/dtos/pokemons/pokemon.output.dto.ts index 1339024..88a46fc 100644 --- a/src/api/dtos/pokemons/pokemon.output.dto.ts +++ b/src/api/dtos/pokemons/pokemon.output.dto.ts @@ -1,21 +1,28 @@ +import { AutoMap } from '@automapper/classes'; import { ApiProperty } from '@nestjs/swagger'; export class PokemonOutputDTO { @ApiProperty() + @AutoMap() public readonly id: number; @ApiProperty() + @AutoMap() public readonly name: string; @ApiProperty() + @AutoMap() public readonly worth: number; @ApiProperty() + @AutoMap() public readonly height: number; @ApiProperty() + @AutoMap() public readonly weight: number; @ApiProperty() + @AutoMap() public readonly image: string; } diff --git a/src/api/dtos/rejected-trades/rejected-trade.output.dto.ts b/src/api/dtos/rejected-trades/rejected-trade.output.dto.ts index 3cde3e2..7aee46e 100644 --- a/src/api/dtos/rejected-trades/rejected-trade.output.dto.ts +++ b/src/api/dtos/rejected-trades/rejected-trade.output.dto.ts @@ -1,9 +1,11 @@ import { ApiProperty, OmitType } from '@nestjs/swagger'; import { TradeOutputDTO } from '../trades/trade.output.dto'; +import { AutoMap } from '@automapper/classes'; export class RejectedTradeOutputDTO extends OmitType(TradeOutputDTO, [ 'status', ]) { @ApiProperty() + @AutoMap() status: 'REJECTED'; } diff --git a/src/api/dtos/trades/trade.output.dto.ts b/src/api/dtos/trades/trade.output.dto.ts index ccb6259..18e28f7 100644 --- a/src/api/dtos/trades/trade.output.dto.ts +++ b/src/api/dtos/trades/trade.output.dto.ts @@ -1,27 +1,35 @@ import { ApiProperty } from '@nestjs/swagger'; import { UUIDv4 } from 'src/common/types'; -import { TradeStatus } from 'src/infra/postgres/tables/trades.table'; +import { TradeStatus } from 'src/core/entities/trade.entity'; import { UserOutputDTO } from '../users/user.output.dto'; +import { AutoMap } from '@automapper/classes'; export class TradeOutputDTO { @ApiProperty() + @AutoMap() public readonly id: UUIDv4; @ApiProperty() + @AutoMap() public readonly createdAt: Date; @ApiProperty() + @AutoMap() public readonly updatedAt: Date; @ApiProperty() + @AutoMap() public readonly status: TradeStatus; @ApiProperty() + @AutoMap() public readonly statusedAt: Date; @ApiProperty({ type: UserOutputDTO }) + @AutoMap(() => UserOutputDTO) public readonly sender: UserOutputDTO; @ApiProperty({ type: UserOutputDTO }) + @AutoMap(() => UserOutputDTO) public readonly receiver: UserOutputDTO; } diff --git a/src/api/dtos/user-items/quick-sold-user-item.output.dto.ts b/src/api/dtos/user-items/quick-sold-user-item.output.dto.ts index cf4fe9d..de82f1c 100644 --- a/src/api/dtos/user-items/quick-sold-user-item.output.dto.ts +++ b/src/api/dtos/user-items/quick-sold-user-item.output.dto.ts @@ -1,7 +1,9 @@ import { ApiProperty } from '@nestjs/swagger'; import { UserItemOutputDTO } from './user-item.output.dto'; +import { AutoMap } from '@automapper/classes'; export class QuickSoldUserItemOutputDTO extends UserItemOutputDTO { @ApiProperty() + @AutoMap() public readonly soldAt: Date; } diff --git a/src/api/dtos/user-items/user-item.output.dto.ts b/src/api/dtos/user-items/user-item.output.dto.ts index d74f185..c8f8aee 100644 --- a/src/api/dtos/user-items/user-item.output.dto.ts +++ b/src/api/dtos/user-items/user-item.output.dto.ts @@ -1,14 +1,18 @@ import { ApiProperty } from '@nestjs/swagger'; import { UUIDv4 } from 'src/common/types'; import { PokemonOutputDTO } from '../pokemons/pokemon.output.dto'; +import { AutoMap } from '@automapper/classes'; export class UserItemOutputDTO { @ApiProperty() + @AutoMap() public readonly id: UUIDv4; @ApiProperty() + @AutoMap() public readonly receivedAt: Date; @ApiProperty({ type: PokemonOutputDTO }) + @AutoMap(() => PokemonOutputDTO) public readonly pokemon: PokemonOutputDTO; } diff --git a/src/api/dtos/users/user.output.dto.ts b/src/api/dtos/users/user.output.dto.ts index 6aad0d3..f00dd01 100644 --- a/src/api/dtos/users/user.output.dto.ts +++ b/src/api/dtos/users/user.output.dto.ts @@ -1,13 +1,17 @@ import { UUIDv4 } from 'src/common/types'; import { ApiProperty } from '@nestjs/swagger'; +import { AutoMap } from '@automapper/classes'; export class UserOutputDTO { @ApiProperty() + @AutoMap() public readonly id: UUIDv4; @ApiProperty() + @AutoMap() public readonly name: string; @ApiProperty() + @AutoMap() public readonly balance: number; } diff --git a/src/api/profiles/pack.profile.ts b/src/api/profiles/pack.profile.ts index fa6a009..f888f4b 100644 --- a/src/api/profiles/pack.profile.ts +++ b/src/api/profiles/pack.profile.ts @@ -2,78 +2,28 @@ import { AutomapperProfile, InjectMapper } from '@automapper/nestjs'; import { Injectable } from '@nestjs/common'; import { Mapper, createMap } from '@automapper/core'; import { PackOutputDTO } from '../dtos/packs/pack.output.dto'; -import { PackWithPokemonsOutputDTO } from '../dtos/packs/pack-with-pokemons.output.dto'; import { OpenedPackOutputDTO } from '../dtos/packs/opened-pack.output.dto'; -import { PojosMetadataMap } from '@automapper/pojos'; -import { OpenedPackEntity, PackEntity, PackToPokemonEntity } from 'src/infra/postgres/tables'; +import { OpenedPackEntity} from 'src/core/entities/opened-pack.entity'; +import { PackEntity } from 'src/core/entities/pack.entity'; @Injectable() export class PackProfile extends AutomapperProfile { public constructor(@InjectMapper() mapper: Mapper) { super(mapper); - this.createMetadataEntities(); - this.createMetadataDTOs(); } public override get profile() { return (mapper: Mapper) => { - createMap( + createMap( mapper, - 'PackEntity', - 'PackOutputDTO', + PackEntity, + PackOutputDTO, ); - createMap( + createMap( mapper, - 'OpenedPackEntity', - 'OpenedPackOutputDTO', + OpenedPackEntity, + OpenedPackOutputDTO, ); }; } - - private createMetadataEntities(): void { - PojosMetadataMap.create('PackToPokemonEntity', { - pack: 'PackEntity', - pokemon: 'PokemonEntity', - }); - - PojosMetadataMap.create('PackEntity', { - id: String, - name: String, - description: String, - price: String, - image: String, - }); - - PojosMetadataMap.create('OpenedPackEntity', { - id: String, - openedAt: Date, - user: 'UserEntity', - pack: 'PackEntity', - pokemon: 'PokemonEntity', - }); - } - - private createMetadataDTOs(): void { - const packOutputDTOProperties = { - id: String, - name: String, - description: String, - price: String, - image: String, - } - - PojosMetadataMap.create('PackOutputDTO', packOutputDTOProperties); - PojosMetadataMap.create('PackWithPokemonsOutputDTO', { - ...packOutputDTOProperties, - pokemons: ['PokemonOutputDTO'], - }); - - PojosMetadataMap.create('OpenedPackOutputDTO', { - id: String, - openedAt: Date, - user: 'UserOutputDTO', - pack: 'PackOutputDTO', - pokemon: 'PokemonOutputDTO', - }); - } } diff --git a/src/api/profiles/pokemon.profile.ts b/src/api/profiles/pokemon.profile.ts index a1c6e8f..6a0cdbc 100644 --- a/src/api/profiles/pokemon.profile.ts +++ b/src/api/profiles/pokemon.profile.ts @@ -1,47 +1,22 @@ import { Mapper, createMap, MappingProfile } from '@automapper/core'; import { AutomapperProfile, InjectMapper } from '@automapper/nestjs'; -import { PojosMetadataMap } from '@automapper/pojos'; import { Injectable } from '@nestjs/common'; import { PokemonOutputDTO } from '../dtos/pokemons/pokemon.output.dto'; -import { PokemonEntity } from 'src/infra/postgres/tables'; +import { PokemonEntity } from 'src/core/entities/pokemon.entity'; @Injectable() export class PokemonProfile extends AutomapperProfile { public constructor(@InjectMapper() mapper: Mapper) { super(mapper); - this.createMetadataEntities(); - this.createMetadataDTOs(); } public override get profile(): MappingProfile { return (mapper: Mapper) => { - createMap( + createMap( mapper, - 'PokemonEntity', - 'PokemonOutputDTO', + PokemonEntity, + PokemonOutputDTO, ); }; } - - private createMetadataEntities(): void { - PojosMetadataMap.create('PokemonEntity', { - id: Number, - name: String, - worth: Number, - height: Number, - weight: Number, - image: String, - }); - } - - private createMetadataDTOs(): void { - PojosMetadataMap.create('PokemonOutputDTO', { - id: Number, - name: String, - worth: Number, - height: Number, - weight: Number, - image: String, - }); - } } diff --git a/src/api/profiles/trade.profile.ts b/src/api/profiles/trade.profile.ts index 6c4b7f4..90f4abd 100644 --- a/src/api/profiles/trade.profile.ts +++ b/src/api/profiles/trade.profile.ts @@ -1,6 +1,5 @@ import { createMap, Mapper, MappingProfile } from '@automapper/core'; import { AutomapperProfile, InjectMapper } from '@automapper/nestjs'; -import { PojosMetadataMap } from '@automapper/pojos'; import { Injectable } from '@nestjs/common'; import { AcceptedTradeEntity, @@ -8,9 +7,7 @@ import { PendingTradeEntity, RejectedTradeEntity, TradeEntity, - TradeToReceiverItemEntity, - TradeToSenderItemEntity, -} from 'src/infra/postgres/tables'; +} from 'src/core/entities/trade.entity'; import { AcceptedTradeOutputDTO } from '../dtos/accepted-trades/accepted-trade.output.dto'; import { CancelledTradeOuputDTO } from '../dtos/cancelled-trades/cancelled-trade.output.dto'; import { PendingTradeOutputDTO } from '../dtos/pending-trades/pending-trade.output.dto'; @@ -21,83 +18,35 @@ import { TradeOutputDTO } from '../dtos/trades/trade.output.dto'; export class TradeProfile extends AutomapperProfile { public constructor(@InjectMapper() mapper: Mapper) { super(mapper); - this.createMetadataEntities(); - this.createMetadataDTOs(); } public override get profile(): MappingProfile { return (mapper: Mapper) => { - createMap( + createMap( mapper, - 'TradeEntity', - 'TradeOutputDTO', + TradeEntity, + TradeOutputDTO, ); - createMap( + createMap( mapper, - 'PendingTradeEntity', - 'PendingTradeOutputDTO', + PendingTradeEntity, + PendingTradeOutputDTO, ); - createMap( + createMap( mapper, - 'CancelledTradeEntity', - 'CancelledTradeOuputDTO', + CancelledTradeEntity, + CancelledTradeOuputDTO, ); - createMap( + createMap( mapper, - 'AcceptedTradeEntity', - 'AcceptedTradeOutputDTO', + AcceptedTradeEntity, + AcceptedTradeOutputDTO, ); - createMap( + createMap( mapper, - 'RejectedTradeEntity', - 'RejectedTradeOutputDTO', + RejectedTradeEntity, + RejectedTradeOutputDTO, ); }; } - - private createMetadataEntities(): void { - PojosMetadataMap.create('TradeToSenderItemEntity', { - trade: 'TradeEntity', - senderItem: 'UserItemEntity', - }); - - PojosMetadataMap.create('TradeToReceiverItemEntity', { - trade: 'TradeEntity', - receiverItem: 'UserItemEntity', - }); - - const tradeEntityProperties = { - id: String, - createdAt: Date, - updatedAt: Date, - status: String, - statusedAt: Date, - sender: 'UserEntity', - receiver: 'UserEntity', - }; - PojosMetadataMap.create('TradeEntity', tradeEntityProperties); - - PojosMetadataMap.create('PendingTradeEntity', tradeEntityProperties); - PojosMetadataMap.create('CancelledTradeEntity', tradeEntityProperties); - PojosMetadataMap.create('AcceptedTradeEntity', tradeEntityProperties); - PojosMetadataMap.create('RejectedTradeEntity', tradeEntityProperties); - } - - private createMetadataDTOs(): void { - const tradeOutputDTOProperties = { - id: String, - createdAt: Date, - updatedAt: Date, - status: String, - statusedAt: Date, - sender: 'UserOutputDTO', - receiver: 'UserOutputDTO', - }; - PojosMetadataMap.create('TradeOutputDTO', tradeOutputDTOProperties); - - PojosMetadataMap.create('PendingTradeOutputDTO', tradeOutputDTOProperties); - PojosMetadataMap.create('CancelledTradeOutputDTO', tradeOutputDTOProperties); - PojosMetadataMap.create('AcceptedTradeOutputDTO', tradeOutputDTOProperties); - PojosMetadataMap.create('RejectedTradeOutputDTO', tradeOutputDTOProperties); - } } diff --git a/src/api/profiles/user-item.profile.ts b/src/api/profiles/user-item.profile.ts index 217638f..f2e7f5b 100644 --- a/src/api/profiles/user-item.profile.ts +++ b/src/api/profiles/user-item.profile.ts @@ -3,58 +3,27 @@ import { AutomapperProfile, InjectMapper } from '@automapper/nestjs'; import { Injectable } from '@nestjs/common'; import { UserItemOutputDTO } from '../dtos/user-items/user-item.output.dto'; import { QuickSoldUserItemOutputDTO } from '../dtos/user-items/quick-sold-user-item.output.dto'; -import { PojosMetadataMap } from '@automapper/pojos'; -import { QuickSoldUserItemEntity, UserItemEntity } from 'src/infra/postgres/tables'; +import { UserItemEntity } from 'src/core/entities/user-item.entity'; +import { QuickSoldUserItemEntity } from 'src/core/entities/quick-sold-user-item.entity'; @Injectable() export class UserItemProfile extends AutomapperProfile { public constructor(@InjectMapper() mapper: Mapper) { super(mapper); - this.createMetadataEntities(); - this.createMetadataDTOs(); } public override get profile(): MappingProfile { return (mapper: Mapper) => { - createMap( + createMap( mapper, - 'UserItemEntity', - 'UserItemOutputDTO', + UserItemEntity, + UserItemOutputDTO, ); - createMap( + createMap( mapper, - 'QuickSoldUserItemEntity', - 'QuickSoldUserItemOutputDTO', + QuickSoldUserItemEntity, + QuickSoldUserItemOutputDTO, ); }; } - - private createMetadataEntities(): void { - const userItemEntityProperties = { - id: String, - receivedAt: Date, - user: 'UserEntity', - pokemon: 'PokemonEntity', - }; - - PojosMetadataMap.create('UserItemEntity', userItemEntityProperties); - PojosMetadataMap.create('QuickSoldUserItemEntity', { - ...userItemEntityProperties, - soldAt: Date, - }); - } - - private createMetadataDTOs(): void { - const userItemOutputDTOProperties = { - id: String, - receivedAt: Date, - pokemon: 'PokemonOutputDTO', - }; - - PojosMetadataMap.create('UserItemOutputDTO', userItemOutputDTOProperties); - PojosMetadataMap.create('QuickSoldUserItemOutputDTO', { - ...userItemOutputDTOProperties, - soldAt: Date, - }) - } } diff --git a/src/api/profiles/user.profile.ts b/src/api/profiles/user.profile.ts index 642cd52..2def88c 100644 --- a/src/api/profiles/user.profile.ts +++ b/src/api/profiles/user.profile.ts @@ -2,42 +2,17 @@ import { AutomapperProfile, InjectMapper } from '@automapper/nestjs'; import { Injectable } from '@nestjs/common'; import { Mapper, createMap, MappingProfile } from '@automapper/core'; import { UserOutputDTO } from '../dtos/users/user.output.dto'; -import { PojosMetadataMap } from '@automapper/pojos'; -import { UserEntity } from 'src/infra/postgres/tables'; +import { UserEntity } from 'src/core/entities/user.entity'; @Injectable() export class UserProfile extends AutomapperProfile { public constructor(@InjectMapper() mapper: Mapper) { super(mapper); - this.createMetadataEntities(); - this.createMetadataDTOs(); } public override get profile(): MappingProfile { return (mapper: Mapper) => { - createMap( - mapper, - 'UserEntity', - 'UserOutputDTO', - ); + createMap(mapper, UserEntity, UserOutputDTO); }; } - - private createMetadataEntities(): void { - PojosMetadataMap.create('UserEntity', { - id: String, - createdAt: Date, - updatedAt: Date, - name: String, - balance: Number, - }); - } - - private createMetadataDTOs(): void { - PojosMetadataMap.create('UserOutputDTO', { - id: String, - name: String, - balance: Number, - }); - } } diff --git a/src/api/strategies/access-token-auth.strategy.ts b/src/api/strategies/access-token-auth.strategy.ts index e1e5fb9..a1ba60b 100644 --- a/src/api/strategies/access-token-auth.strategy.ts +++ b/src/api/strategies/access-token-auth.strategy.ts @@ -7,7 +7,7 @@ import { Nullable } from 'src/common/types'; import { UserTokenPayload } from '../types'; import { IUsersRepository } from 'src/core/repositories/users.repository'; import { EnvVariables } from 'src/infra/config/env.config'; -import { UserEntity } from 'src/infra/postgres/tables'; +import { UserEntity } from 'src/core/entities/user.entity'; @Injectable() export class AccessTokenAuthStrategy extends PassportStrategy(Strategy, 'access-token') { diff --git a/src/api/strategies/local-auth.strategy.ts b/src/api/strategies/local-auth.strategy.ts index 7c9cee4..81f1cfa 100644 --- a/src/api/strategies/local-auth.strategy.ts +++ b/src/api/strategies/local-auth.strategy.ts @@ -3,7 +3,7 @@ import { PassportStrategy } from '@nestjs/passport'; import { Strategy } from 'passport-local'; import * as bcrypt from 'bcrypt'; import { IUsersRepository } from 'src/core/repositories/users.repository'; -import { UserEntity } from 'src/infra/postgres/tables'; +import { UserEntity } from 'src/core/entities/user.entity'; import { Nullable } from 'src/common/types'; import { AppAuthException } from 'src/core/exceptions'; diff --git a/src/api/strategies/refresh-token-auth.strategy.ts b/src/api/strategies/refresh-token-auth.strategy.ts index fa861c1..31d6cf9 100644 --- a/src/api/strategies/refresh-token-auth.strategy.ts +++ b/src/api/strategies/refresh-token-auth.strategy.ts @@ -7,7 +7,7 @@ import { Nullable, } from 'src/common/types'; import { UserTokenPayload } from '../types'; import { IUsersRepository } from 'src/core/repositories/users.repository'; import { EnvVariables } from 'src/infra/config/env.config'; -import { UserEntity } from 'src/infra/postgres/tables'; +import { UserEntity } from 'src/core/entities/user.entity'; @Injectable() export class RefreshTokenAuthStrategy extends PassportStrategy(Strategy, 'refresh-token') { diff --git a/src/core/entities/opened-pack.entity.ts b/src/core/entities/opened-pack.entity.ts new file mode 100644 index 0000000..4f762d4 --- /dev/null +++ b/src/core/entities/opened-pack.entity.ts @@ -0,0 +1,23 @@ +import { UUIDv4 } from 'src/common/types'; +import { UserEntity } from './user.entity'; +import { PokemonEntity } from './pokemon.entity'; +import { PackEntity } from './pack.entity'; +import { AutoMap } from '@automapper/classes'; + +export class OpenedPackEntity { + @AutoMap() + public readonly id: UUIDv4; + @AutoMap() + public readonly openedAt: Date; + @AutoMap(() => UserEntity) + public readonly user: UserEntity; + @AutoMap(() => PackEntity) + public readonly pack: PackEntity; + @AutoMap(() => PokemonEntity) + public readonly pokemon: PokemonEntity; +} + +export type CreateOpenedPackEntityValues = Omit; diff --git a/src/core/entities/pack-to-pokemon.entity.ts b/src/core/entities/pack-to-pokemon.entity.ts new file mode 100644 index 0000000..829204e --- /dev/null +++ b/src/core/entities/pack-to-pokemon.entity.ts @@ -0,0 +1,10 @@ +import { AutoMap } from "@automapper/classes"; +import { PackEntity } from "./pack.entity"; +import { PokemonEntity } from "./pokemon.entity"; + +export class PackToPokemonEntity { + @AutoMap(() => PackEntity) + public readonly pack: PackEntity; + @AutoMap(() => PokemonEntity) + public readonly pokemon: PokemonEntity; +} diff --git a/src/core/entities/pack.entity.ts b/src/core/entities/pack.entity.ts new file mode 100644 index 0000000..435fbcd --- /dev/null +++ b/src/core/entities/pack.entity.ts @@ -0,0 +1,27 @@ +import { AutoMap } from '@automapper/classes'; +import { UUIDv4 } from 'src/common/types'; + +export class PackEntity { + @AutoMap() + public readonly id: UUIDv4; + @AutoMap() + public readonly createdAt: Date; + @AutoMap() + public readonly updatedAt: Date; + @AutoMap() + public readonly name: string; + @AutoMap() + public readonly description: string; + @AutoMap() + public readonly price: number; + @AutoMap() + public readonly image: string; +} + +export type CreatePackEntityValues = Omit; + +export type UpdatePackEntityValues = Partial; diff --git a/src/core/entities/pokemon.entity.ts b/src/core/entities/pokemon.entity.ts new file mode 100644 index 0000000..dde7dd1 --- /dev/null +++ b/src/core/entities/pokemon.entity.ts @@ -0,0 +1,18 @@ +import { AutoMap } from '@automapper/classes'; + +export class PokemonEntity { + @AutoMap() + public readonly id: number; + @AutoMap() + public readonly name: string; + @AutoMap() + public readonly worth: number; + @AutoMap() + public readonly height: number; + @AutoMap() + public readonly weight: number; + @AutoMap() + public readonly image: string; +} + +export type CreatePokemonEntityValues = PokemonEntity; diff --git a/src/core/entities/quick-sold-user-item.entity.ts b/src/core/entities/quick-sold-user-item.entity.ts new file mode 100644 index 0000000..b9999e7 --- /dev/null +++ b/src/core/entities/quick-sold-user-item.entity.ts @@ -0,0 +1,7 @@ +import { AutoMap } from '@automapper/classes'; +import { UserItemEntity } from './user-item.entity'; + +export class QuickSoldUserItemEntity extends UserItemEntity { + @AutoMap() + public readonly soldAt: Date; +} diff --git a/src/core/entities/trade-to-user-item.entity.ts b/src/core/entities/trade-to-user-item.entity.ts new file mode 100644 index 0000000..c5debcc --- /dev/null +++ b/src/core/entities/trade-to-user-item.entity.ts @@ -0,0 +1,40 @@ +import { UserItemEntity } from './user-item.entity'; +import { TradeEntity } from './trade.entity'; +import { AutoMap } from '@automapper/classes'; + +export const userTypeEnumValues = ['SENDER', 'RECEIVER'] as const; +export type TradeToUserItemUserType = typeof userTypeEnumValues[number]; + +class _TradeToUserItemEntity { + @AutoMap(() => TradeEntity) + public readonly trade: TradeEntity; + @AutoMap() + public readonly userType: TradeToUserItemUserType; +} + +export class TradeToUserItemEntity extends _TradeToUserItemEntity { + @AutoMap(() => UserItemEntity) + public readonly userItem: UserItemEntity; +} + +export class TradeToSenderItemEntity extends _TradeToUserItemEntity { + @AutoMap() + public readonly userType: 'SENDER'; + @AutoMap(() => UserItemEntity) + public readonly senderItem: UserItemEntity; +} + +export class TradeToReceiverItemEntity extends _TradeToUserItemEntity { + @AutoMap() + public readonly userType: 'RECEIVER'; + @AutoMap(() => UserItemEntity) + public readonly receiverItem: UserItemEntity; +} + +export type CreateTradeToUserItemEntityValues = TradeToUserItemEntity; +export type CreateTradeToSenderItemEntityValues = Omit & { + senderItem: UserItemEntity, +}; +export type CreateTradeToReceiverItemEntityValues = Omit & { + receiverItem: UserItemEntity, +}; diff --git a/src/core/entities/trade.entity.ts b/src/core/entities/trade.entity.ts new file mode 100644 index 0000000..92ddfec --- /dev/null +++ b/src/core/entities/trade.entity.ts @@ -0,0 +1,61 @@ +import { UUIDv4 } from 'src/common/types'; +import { UserEntity } from './user.entity'; +import { UserItemEntity } from './user-item.entity'; +import { AutoMap } from '@automapper/classes'; + +export const tradeStatusEnumValues = [ + 'PENDING', + 'CANCELLED', + 'ACCEPTED', + 'REJECTED', +] as const; + +export type TradeStatus = typeof tradeStatusEnumValues[number]; + +export class TradeEntity { + @AutoMap() + public readonly id: UUIDv4; + @AutoMap() + public readonly createdAt: Date; + @AutoMap() + public readonly updatedAt: Date; + @AutoMap() + public readonly status: TradeStatus; + @AutoMap(() => UserEntity) + public readonly sender: UserEntity; + @AutoMap(() => UserEntity) + public readonly receiver: UserEntity; + @AutoMap() + public readonly statusedAt: Date; +} + +export class PendingTradeEntity extends TradeEntity { + @AutoMap() + public readonly status: 'PENDING'; +} + +export class CancelledTradeEntity extends TradeEntity { + @AutoMap() + public readonly status: 'CANCELLED'; +} + +export class AcceptedTradeEntity extends TradeEntity { + @AutoMap() + public readonly status: 'ACCEPTED'; +} + +export class RejectedTradeEntity extends TradeEntity { + @AutoMap() + public readonly status: 'REJECTED'; +} + +export type CreatePendingTradeEntityValues = Omit & { + senderItems: Array, + receiverItems: Array, +} diff --git a/src/core/entities/user-item.entity.ts b/src/core/entities/user-item.entity.ts new file mode 100644 index 0000000..6523eda --- /dev/null +++ b/src/core/entities/user-item.entity.ts @@ -0,0 +1,26 @@ +import { UUIDv4 } from 'src/common/types'; +import { UserEntity } from './user.entity'; +import { PokemonEntity } from './pokemon.entity'; +import { AutoMap } from '@automapper/classes'; + +export class UserItemEntity { + @AutoMap() + public readonly id: UUIDv4; + @AutoMap() + public readonly receivedAt: Date; + @AutoMap(() => UserEntity) + public readonly user: UserEntity; + @AutoMap(() => PokemonEntity) + public readonly pokemon: PokemonEntity; +} + +export type CreateUserItemEntityValues = Omit; +export type UpdateUserItemEntityValues = Partial< + & CreateUserItemEntityValues + & Pick +>; diff --git a/src/core/entities/user-refresh-token.entity.ts b/src/core/entities/user-refresh-token.entity.ts new file mode 100644 index 0000000..371cb0b --- /dev/null +++ b/src/core/entities/user-refresh-token.entity.ts @@ -0,0 +1,16 @@ +import { AutoMap } from '@automapper/classes'; +import { UserEntity } from './user.entity'; +import { JWT } from 'src/common/types'; + +export class UserRefreshTokenEntity { + @AutoMap(() => UserEntity) + public readonly user: UserEntity; + @AutoMap() + public readonly hashedRefreshToken: string; + @AutoMap() + public readonly expiresAt: Date; +} + +export type CreateUserRefreshTokenEntityValues = Omit & { + refreshToken: JWT; +}; diff --git a/src/core/entities/user.entity.ts b/src/core/entities/user.entity.ts new file mode 100644 index 0000000..b4a1d04 --- /dev/null +++ b/src/core/entities/user.entity.ts @@ -0,0 +1,29 @@ +import { AutoMap } from '@automapper/classes'; +import { UUIDv4 } from 'src/common/types'; + +export class UserEntity { + @AutoMap() + public readonly id: UUIDv4; + @AutoMap() + public readonly createdAt: Date; + @AutoMap() + public readonly updatedAt: Date; + @AutoMap() + public readonly name: string; + @AutoMap() + public readonly hashedPassword: string; + @AutoMap() + public readonly balance: number; +} + +export type CreateUserEntityValues = Omit +& Required<{ password: string }> +& Partial>; + +export type UpdateUserEntityValues = Partial; diff --git a/src/core/repositories/opened-packs.repository.ts b/src/core/repositories/opened-packs.repository.ts index 04321f5..b43bd21 100644 --- a/src/core/repositories/opened-packs.repository.ts +++ b/src/core/repositories/opened-packs.repository.ts @@ -1,4 +1,4 @@ -import { CreateOpenedPackEntityValues, OpenedPackEntity } from 'src/infra/postgres/tables'; +import { CreateOpenedPackEntityValues, OpenedPackEntity } from '../entities/opened-pack.entity'; export abstract class IOpenedPacksRepository { public abstract createOpenedPack( diff --git a/src/core/repositories/packs.repository.ts b/src/core/repositories/packs.repository.ts index f8d161f..47ef81d 100644 --- a/src/core/repositories/packs.repository.ts +++ b/src/core/repositories/packs.repository.ts @@ -1,5 +1,6 @@ import { PaginatedArray, UUIDv4 } from 'src/common/types'; -import { PackEntity, PokemonEntity } from 'src/infra/postgres/tables'; +import { PokemonEntity } from '../entities/pokemon.entity'; +import { PackEntity } from '../entities/pack.entity'; import { FindEntitiesWithPaginationOptions, FindEntityByIdOptions, FindEntityOptions } from '../types'; export type FindPacksWhere = Partial<{ diff --git a/src/core/repositories/pokemons.repository.ts b/src/core/repositories/pokemons.repository.ts index 6188d9f..c65358f 100644 --- a/src/core/repositories/pokemons.repository.ts +++ b/src/core/repositories/pokemons.repository.ts @@ -1,4 +1,4 @@ -import { CreatePokemonEntityValues, PokemonEntity } from 'src/infra/postgres/tables'; +import { CreatePokemonEntityValues, PokemonEntity } from '../entities/pokemon.entity'; export abstract class IPokemonsRepository { public abstract createPokemons( diff --git a/src/core/repositories/quick-sold-user-items.repository.ts b/src/core/repositories/quick-sold-user-items.repository.ts index 6d6d815..aa82412 100644 --- a/src/core/repositories/quick-sold-user-items.repository.ts +++ b/src/core/repositories/quick-sold-user-items.repository.ts @@ -1,4 +1,5 @@ -import { QuickSoldUserItemEntity, UserItemEntity } from 'src/infra/postgres/tables'; +import { UserItemEntity } from '../entities/user-item.entity'; +import { QuickSoldUserItemEntity } from '../entities/quick-sold-user-item.entity'; export abstract class IQuickSoldUserItemsRepository { public abstract createQuickSoldUserItem( diff --git a/src/core/repositories/trades-to-user-items.repository.ts b/src/core/repositories/trades-to-user-items.repository.ts index 407fbe0..c25b37d 100644 --- a/src/core/repositories/trades-to-user-items.repository.ts +++ b/src/core/repositories/trades-to-user-items.repository.ts @@ -1,5 +1,5 @@ import { UUIDv4 } from 'src/common/types'; -import { FindEntitiesOptions } from 'src/core/types'; +import { FindEntitiesOptions } from '../types'; import { CreateTradeToReceiverItemEntityValues, CreateTradeToSenderItemEntityValues, @@ -7,7 +7,7 @@ import { TradeToSenderItemEntity, TradeToUserItemEntity, TradeToUserItemUserType, -} from 'src/infra/postgres/tables'; +} from '../entities/trade-to-user-item.entity'; export type FindTradesToUserItemsWhere = Partial<{ tradeId: UUIDv4, diff --git a/src/core/repositories/trades.repository.ts b/src/core/repositories/trades.repository.ts index ed11f64..ae98897 100644 --- a/src/core/repositories/trades.repository.ts +++ b/src/core/repositories/trades.repository.ts @@ -3,12 +3,11 @@ import { TradeStatus, PendingTradeEntity, CreatePendingTradeEntityValues, - TradeToSenderItemEntity, - TradeToReceiverItemEntity, CancelledTradeEntity, AcceptedTradeEntity, RejectedTradeEntity, -} from 'src/infra/postgres/tables'; +} from '../entities/trade.entity'; +import { TradeToSenderItemEntity, TradeToReceiverItemEntity, } from '../entities/trade-to-user-item.entity' import { UUIDv4 } from 'src/common/types'; import { FindEntityByIdOptions, FindEntityOptions } from '../types'; diff --git a/src/core/repositories/user-items.repository.ts b/src/core/repositories/user-items.repository.ts index 27bfeb1..87e5256 100644 --- a/src/core/repositories/user-items.repository.ts +++ b/src/core/repositories/user-items.repository.ts @@ -1,5 +1,6 @@ import { PaginatedArray, UUIDv4 } from 'src/common/types'; -import { CreateUserItemEntityValues, UpdateUserItemEntityValues, UserEntity, UserItemEntity } from 'src/infra/postgres/tables'; +import { UserEntity } from '../entities/user.entity'; +import { CreateUserItemEntityValues, UpdateUserItemEntityValues, UserItemEntity } from '../entities/user-item.entity'; import { FindEntitiesOptions, FindEntityOptions, diff --git a/src/core/repositories/user-refresh-tokens.repository.ts b/src/core/repositories/user-refresh-tokens.repository.ts index a9ee6a6..063b291 100644 --- a/src/core/repositories/user-refresh-tokens.repository.ts +++ b/src/core/repositories/user-refresh-tokens.repository.ts @@ -1,5 +1,5 @@ import { JWT, UUIDv4 } from 'src/common/types'; -import { CreateUserRefreshTokenEntityValues, UserRefreshTokenEntity } from 'src/infra/postgres/tables'; +import { CreateUserRefreshTokenEntityValues, UserRefreshTokenEntity } from '../entities/user-refresh-token.entity'; import { FindEntityOptions } from '../types'; export type FindUserRefreshTokensWhere = Partial<{ diff --git a/src/core/repositories/users.repository.ts b/src/core/repositories/users.repository.ts index 8099f6a..c62e231 100644 --- a/src/core/repositories/users.repository.ts +++ b/src/core/repositories/users.repository.ts @@ -1,6 +1,7 @@ import { PaginatedArray, UUIDv4 } from 'src/common/types'; -import { CreateUserEntityValues, UpdateUserEntityValues, UserEntity } from 'src/infra/postgres/tables'; +import { CreateUserEntityValues, UpdateUserEntityValues } from '../entities/user.entity'; import { FindEntitiesOptions, FindEntitiesWithPaginationOptions, FindEntityByIdOptions, FindEntityOptions } from '../types'; +import { UserEntity } from '../entities/user.entity'; export type FindUsersWhere = Partial<{ id: UUIDv4, diff --git a/src/core/services/auth.service.ts b/src/core/services/auth.service.ts index e2a65a3..0c32562 100644 --- a/src/core/services/auth.service.ts +++ b/src/core/services/auth.service.ts @@ -2,15 +2,12 @@ import { Injectable } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { RegisterUserInputDTO } from 'src/api/dtos/auth/register-user.input.dto'; import { JWT } from 'src/common/types'; -import { UserEntity } from 'src/infra/postgres/tables'; +import { UserEntity } from '../entities/user.entity'; import { IUserRefreshTokensRepository } from '../repositories/user-refresh-tokens.repository'; import ms from 'ms'; import { addMilliseconds } from 'date-fns'; import { ConfigService } from '@nestjs/config'; import { EnvVariables } from 'src/infra/config/env.config'; -import { hashUserPassword } from 'src/common/helpers/hash-user-password.helper'; -import { hashRefreshToken } from 'src/common/helpers/hash-refresh-token.helper'; -import { DatabaseError } from 'pg'; import { IUsersRepository } from '../repositories/users.repository'; import { AppConflictException, AppValidationException } from '../exceptions'; @@ -47,21 +44,11 @@ export class AuthService { })) as JWT; const expiresAt = addMilliseconds(new Date(), ms(expiresIn)); - try { - await this.userRefreshTokensRepository.createUserRefreshToken({ - user, - hashedRefreshToken: hashRefreshToken(refreshToken), - expiresAt, - }); - } catch (error) { - // NOTE: If multiple refresh tokens got generated at the same time (have the same `iat` and `exp`) - // Then the database will throw an unique constraint error (because of the primary key) - // If that happens that means that we already have the refresh token in the database - // so we can simple ignore that - if (!(error instanceof DatabaseError) || error.code !== '23505') { - throw error; - } - } + await this.userRefreshTokensRepository.createUserRefreshToken({ + user, + refreshToken, + expiresAt, + }); return refreshToken; } @@ -86,17 +73,19 @@ export class AuthService { public async registerUser( dto: RegisterUserInputDTO ): Promise<{ user: UserEntity } & AuthTokens> { - if (dto.password !== dto.confirmPassword) { + const { username, password, confirmPassword } = dto; + + if (password !== confirmPassword) { throw new AppValidationException('Passwords does not match'); } - if (await this.usersRepository.userExists({ name: dto.username })) { + if (await this.usersRepository.userExists({ name: username })) { throw new AppConflictException('User with this name already exists'); } const user = await this.usersRepository.createUser({ - name: dto.username, - hashedPassword: await hashUserPassword(dto.password), + name: username, + password, }); const tokens = await this.generateTokens(user); diff --git a/src/core/services/packs.service.ts b/src/core/services/packs.service.ts index d0e6d75..4165c1f 100644 --- a/src/core/services/packs.service.ts +++ b/src/core/services/packs.service.ts @@ -2,7 +2,9 @@ import { Injectable } from '@nestjs/common'; import { PaginatedArray, UUIDv4 } from 'src/common/types'; import { IPacksRepository } from '../repositories/packs.repository'; import { Database, Transaction } from 'src/infra/postgres/types'; -import { OpenedPackEntity, PackEntity, UserEntity } from 'src/infra/postgres/tables'; +import { OpenedPackEntity } from '../entities/opened-pack.entity'; +import { PackEntity } from '../entities/pack.entity'; +import { UserEntity } from '../entities/user.entity'; import { GetPacksInputDTO } from 'src/api/dtos/packs/get-packs.input.dto'; import { PaginationInputDTO } from 'src/api/dtos/pagination.input.dto'; import { IUsersRepository } from '../repositories/users.repository'; diff --git a/src/core/services/pending-trades.service.ts b/src/core/services/pending-trades.service.ts index 3c22bbb..639b5df 100644 --- a/src/core/services/pending-trades.service.ts +++ b/src/core/services/pending-trades.service.ts @@ -2,7 +2,8 @@ import { Injectable } from '@nestjs/common'; import { CreatePendingTradeInputDTO } from 'src/api/dtos/pending-trades/create-pending-trade.input.dto'; import { UUIDv4 } from 'src/common/types'; import { Database, Transaction } from 'src/infra/postgres/types'; -import { AcceptedTradeEntity, CancelledTradeEntity, PendingTradeEntity, RejectedTradeEntity, UserEntity } from 'src/infra/postgres/tables'; +import { AcceptedTradeEntity, CancelledTradeEntity, PendingTradeEntity, RejectedTradeEntity } from '../entities/trade.entity'; +import { UserEntity } from '../entities/user.entity'; import { ITradesRepository } from '../repositories/trades.repository'; import { ITradesToUserItemsRepository } from '../repositories/trades-to-user-items.repository'; import { EventEmitter2 } from '@nestjs/event-emitter'; diff --git a/src/core/services/user-items.service.ts b/src/core/services/user-items.service.ts index 23ee18b..2f9a208 100644 --- a/src/core/services/user-items.service.ts +++ b/src/core/services/user-items.service.ts @@ -2,7 +2,9 @@ import { Injectable } from '@nestjs/common'; import { PaginationInputDTO } from 'src/api/dtos/pagination.input.dto'; import { PaginatedArray, UUIDv4 } from 'src/common/types'; import { Database, Transaction } from 'src/infra/postgres/types'; -import { QuickSoldUserItemEntity, UserEntity, UserItemEntity } from 'src/infra/postgres/tables'; +import { QuickSoldUserItemEntity } from '../entities/quick-sold-user-item.entity'; +import { UserEntity } from '../entities/user.entity'; +import { UserItemEntity } from '../entities/user-item.entity'; import { IQuickSoldUserItemsRepository } from '../repositories/quick-sold-user-items.repository'; import { IUserItemsRepository } from '../repositories/user-items.repository'; import { IUsersRepository } from '../repositories/users.repository'; diff --git a/src/core/services/users.service.ts b/src/core/services/users.service.ts index 0ed258f..767b6ea 100644 --- a/src/core/services/users.service.ts +++ b/src/core/services/users.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common'; import { IUsersRepository } from '../repositories/users.repository'; import { PaginatedArray } from 'src/common/types'; import { GetUsersInputDTO } from 'src/api/dtos/users/get-users.input.dto'; -import { UserEntity } from 'src/infra/postgres/tables'; +import { UserEntity } from '../entities/user.entity'; import { PaginationInputDTO } from 'src/api/dtos/pagination.input.dto'; @Injectable() diff --git a/src/infra/centrifugo/centrifugo.service.ts b/src/infra/centrifugo/centrifugo.service.ts index 311f881..f8ff543 100644 --- a/src/infra/centrifugo/centrifugo.service.ts +++ b/src/infra/centrifugo/centrifugo.service.ts @@ -1,6 +1,7 @@ import { Injectable, Logger } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; -import { AcceptedTradeEntity, PendingTradeEntity, UserEntity } from '../postgres/tables'; +import { AcceptedTradeEntity, PendingTradeEntity } from 'src/core/entities/trade.entity'; +import { UserEntity } from 'src/core/entities/user.entity'; import { CentClient } from 'cent.js'; import { PENDING_TRADE_ACCEPTED_EVENT, PENDING_TRADE_CREATED_EVENT } from 'src/core/events'; import { ConfigService } from '@nestjs/config'; diff --git a/src/infra/postgres/repositories/opened-pack.repository.ts b/src/infra/postgres/repositories/opened-pack.repository.ts index 2b62e89..8317962 100644 --- a/src/infra/postgres/repositories/opened-pack.repository.ts +++ b/src/infra/postgres/repositories/opened-pack.repository.ts @@ -1,7 +1,8 @@ import { Injectable } from '@nestjs/common'; import { Database, Transaction } from 'src/infra/postgres/types'; import { InjectDatabase } from 'src/infra/ioc/decorators/inject-database.decorator'; -import { CreateOpenedPackEntityValues, OpenedPackEntity, openedPacksTable } from 'src/infra/postgres/tables'; +import { openedPacksTable } from 'src/infra/postgres/tables'; +import { CreateOpenedPackEntityValues, OpenedPackEntity } from 'src/core/entities/opened-pack.entity'; import { IOpenedPacksRepository } from 'src/core/repositories/opened-packs.repository'; @Injectable() diff --git a/src/infra/postgres/repositories/packs.repository.ts b/src/infra/postgres/repositories/packs.repository.ts index 61bffa3..11b6a5d 100644 --- a/src/infra/postgres/repositories/packs.repository.ts +++ b/src/infra/postgres/repositories/packs.repository.ts @@ -1,6 +1,8 @@ import { Injectable } from '@nestjs/common'; import { Optional, PaginatedArray } from 'src/common/types'; -import { PackEntity, packsTable, packsToPokemonsTable, PokemonEntity, pokemonsTable } from 'src/infra/postgres/tables'; +import { packsTable, packsToPokemonsTable, pokemonsTable } from 'src/infra/postgres/tables'; +import { PackEntity } from 'src/core/entities/pack.entity'; +import { PokemonEntity } from 'src/core/entities/pokemon.entity'; import { and, eq, getTableColumns, inArray, like, SQL, sql } from 'drizzle-orm'; import { Database } from 'src/infra/postgres/types'; import { InjectDatabase } from 'src/infra/ioc/decorators/inject-database.decorator'; diff --git a/src/infra/postgres/repositories/pokemons.repository.ts b/src/infra/postgres/repositories/pokemons.repository.ts index 2f6945f..32d1e11 100644 --- a/src/infra/postgres/repositories/pokemons.repository.ts +++ b/src/infra/postgres/repositories/pokemons.repository.ts @@ -1,7 +1,8 @@ import { Injectable } from '@nestjs/common'; import { Database, Transaction } from 'src/infra/postgres/types'; import { InjectDatabase } from 'src/infra/ioc/decorators/inject-database.decorator'; -import { CreatePokemonEntityValues, PokemonEntity, pokemonsTable } from 'src/infra/postgres/tables'; +import { pokemonsTable } from 'src/infra/postgres/tables'; +import { CreatePokemonEntityValues, PokemonEntity } from 'src/core/entities/pokemon.entity'; import { IPokemonsRepository } from 'src/core/repositories/pokemons.repository'; @Injectable() diff --git a/src/infra/postgres/repositories/quick-sold-user-items.repository.ts b/src/infra/postgres/repositories/quick-sold-user-items.repository.ts index d926475..659dd4f 100644 --- a/src/infra/postgres/repositories/quick-sold-user-items.repository.ts +++ b/src/infra/postgres/repositories/quick-sold-user-items.repository.ts @@ -1,7 +1,9 @@ import { Injectable } from '@nestjs/common'; import { Database, Transaction } from 'src/infra/postgres/types'; import { InjectDatabase } from 'src/infra/ioc/decorators/inject-database.decorator'; -import { QuickSoldUserItemEntity, quickSoldUserItemsTable, UserItemEntity } from 'src/infra/postgres/tables'; +import { quickSoldUserItemsTable } from 'src/infra/postgres/tables'; +import { QuickSoldUserItemEntity } from 'src/core/entities/quick-sold-user-item.entity'; +import { UserItemEntity } from 'src/core/entities/user-item.entity'; import { IUserItemsRepository } from 'src/core/repositories/user-items.repository'; import { IQuickSoldUserItemsRepository } from 'src/core/repositories/quick-sold-user-items.repository'; @@ -23,8 +25,12 @@ export class QuickSoldUserItemsRepository implements IQuickSoldUserItemsReposito const [quickSoldUserItem] = await Promise.all([ (tx ?? this.db) .insert(quickSoldUserItemsTable) - .values(userItem) - .returning() + .values({ + ...userItem, + userId: userItem.user.id, + pokemonId: userItem.pokemon.id, + }) + .returning() .then(([quickSoldUserItem]) => ({ ...quickSoldUserItem!, user, diff --git a/src/infra/postgres/repositories/trades-to-user-items.repository.ts b/src/infra/postgres/repositories/trades-to-user-items.repository.ts index 6a9c824..d611a10 100644 --- a/src/infra/postgres/repositories/trades-to-user-items.repository.ts +++ b/src/infra/postgres/repositories/trades-to-user-items.repository.ts @@ -7,18 +7,20 @@ import { FindEntitiesOptions } from 'src/core/types'; import { InjectDatabase } from 'src/infra/ioc/decorators/inject-database.decorator'; import { Database, Transaction } from 'src/infra/postgres/types'; import { - CreateTradeToReceiverItemEntityValues, - CreateTradeToSenderItemEntityValues, - CreateTradeToUserItemEntityValues, pokemonsTable, tradesTable, tradesToUserItemsTable, - TradeToReceiverItemEntity, - TradeToSenderItemEntity, - TradeToUserItemEntity, userItemsTable, usersTable, } from 'src/infra/postgres/tables'; +import { + TradeToReceiverItemEntity, + TradeToSenderItemEntity, + TradeToUserItemEntity, + CreateTradeToReceiverItemEntityValues, + CreateTradeToSenderItemEntityValues, + CreateTradeToUserItemEntityValues, +} from 'src/core/entities/trade-to-user-item.entity'; import { mapTradesRowToEntity } from './trades.repository'; import { mapUserItemsRowToEntity } from './user-items.repository'; import { FindTradesToReceiverItemsWhere, FindTradesToSenderItemsWhere, FindTradesToUserItemsWhere, ITradesToUserItemsRepository } from 'src/core/repositories/trades-to-user-items.repository'; diff --git a/src/infra/postgres/repositories/trades.repository.ts b/src/infra/postgres/repositories/trades.repository.ts index 992c162..c47c11e 100644 --- a/src/infra/postgres/repositories/trades.repository.ts +++ b/src/infra/postgres/repositories/trades.repository.ts @@ -3,15 +3,19 @@ import { Database, Transaction } from 'src/infra/postgres/types'; import { tradesTable, usersTable, +} from 'src/infra/postgres/tables'; +import { TradeEntity, PendingTradeEntity, - CreatePendingTradeEntityValues, - TradeToSenderItemEntity, - TradeToReceiverItemEntity, CancelledTradeEntity, AcceptedTradeEntity, RejectedTradeEntity, -} from 'src/infra/postgres/tables'; + CreatePendingTradeEntityValues, +} from 'src/core/entities/trade.entity' +import { + TradeToSenderItemEntity, + TradeToReceiverItemEntity, +} from 'src/core/entities/trade-to-user-item.entity' import { InjectDatabase } from 'src/infra/ioc/decorators/inject-database.decorator'; import { and, eq, inArray, sql, SQL } from 'drizzle-orm'; import { Optional } from 'src/common/types'; diff --git a/src/infra/postgres/repositories/user-items.repository.ts b/src/infra/postgres/repositories/user-items.repository.ts index d5194f2..507244f 100644 --- a/src/infra/postgres/repositories/user-items.repository.ts +++ b/src/infra/postgres/repositories/user-items.repository.ts @@ -2,7 +2,9 @@ import { Injectable } from '@nestjs/common'; import { Database, Transaction } from 'src/infra/postgres/types'; import { InjectDatabase } from 'src/infra/ioc/decorators/inject-database.decorator'; import { Optional, PaginatedArray, UUIDv4 } from 'src/common/types'; -import { CreateUserItemEntityValues, pokemonsTable, UpdateUserItemEntityValues, UserEntity, UserItemEntity, userItemsTable, usersTable } from 'src/infra/postgres/tables'; +import { pokemonsTable, userItemsTable, usersTable } from 'src/infra/postgres/tables'; +import { UserItemEntity, CreateUserItemEntityValues, UpdateUserItemEntityValues} from 'src/core/entities/user-item.entity'; +import { UserEntity } from 'src/core/entities/user.entity'; import { and, eq, inArray, like, SQL } from 'drizzle-orm'; import { mapArrayToPaginatedArray } from 'src/common/helpers/map-array-to-paginated-array.helper'; import { zip } from 'lodash'; @@ -202,12 +204,12 @@ export class UserItemsRepository implements IUserItemsRepository { ): Promise> { if (!fromUserItems.length) return []; - const set = new Set(fromUserItems.map(({ userId }) => userId)); + const set = new Set(fromUserItems.map(({ user }) => user.id)); if (set.size > 1) { throw new AppConflictException('All of the items must have the same user'); } - const fromUserId = fromUserItems[0]!.userId; + const fromUserId = fromUserItems[0]!.user.id; if (fromUserId === toUser.id) { throw new AppConflictException('You cannot transfer items to yourself'); } diff --git a/src/infra/postgres/repositories/user-refresh-tokens.repository.ts b/src/infra/postgres/repositories/user-refresh-tokens.repository.ts index cf37ab4..fc42261 100644 --- a/src/infra/postgres/repositories/user-refresh-tokens.repository.ts +++ b/src/infra/postgres/repositories/user-refresh-tokens.repository.ts @@ -1,13 +1,15 @@ import { Injectable } from '@nestjs/common'; import { SQL, and, eq, gt, sql } from 'drizzle-orm'; -import { Optional } from 'src/common/types'; +import { Nullable, Optional } from 'src/common/types'; import { InjectDatabase } from 'src/infra/ioc/decorators/inject-database.decorator'; import { Database, Transaction } from 'src/infra/postgres/types'; -import { CreateUserRefreshTokenEntityValues, UserRefreshTokenEntity, userRefreshTokensTable, usersTable } from 'src/infra/postgres/tables'; +import { userRefreshTokensTable, usersTable } from 'src/infra/postgres/tables'; +import { CreateUserRefreshTokenEntityValues, UserRefreshTokenEntity } from 'src/core/entities/user-refresh-token.entity'; import { hashRefreshToken } from 'src/common/helpers/hash-refresh-token.helper'; import { AppEntityNotFoundException } from 'src/core/exceptions'; import { FindEntitiesOptions, FindEntityOptions } from 'src/core/types'; import { FindUserRefreshTokensWhere, IUserRefreshTokensRepository } from 'src/core/repositories/user-refresh-tokens.repository'; +import { DatabaseError } from 'pg'; export const mapUserRefreshTokensRowToEntity = ( row: Record<'user_refresh_tokens' | 'users', any>, @@ -71,19 +73,37 @@ export class UserRefreshTokensRepository implements IUserRefreshTokensRepository values: CreateUserRefreshTokenEntityValues, tx?: Transaction, ): Promise { - const { user } = values; + const { user, refreshToken } = values; - return (tx ?? this.db) - .insert(userRefreshTokensTable) - .values({ - ...values, - userId: user.id, - }) - .returning() - .then(([userRefreshToken]) => ({ - ...userRefreshToken!, - user, - })); + try { + return await (tx ?? this.db) + .insert(userRefreshTokensTable) + .values({ + ...values, + userId: user.id, + hashedRefreshToken: hashRefreshToken(refreshToken) + }) + .returning() + .then(([userRefreshToken]) => ({ + ...userRefreshToken!, + user, + })); + } catch (error) { + // NOTE: If multiple refresh tokens got generated at the same time (have the same `iat` and `exp`) + // Then the database will throw an unique constraint error (because of the primary key) + // If that happens that means that we already have the refresh token in the database + // so we can simply fetch it from the database + if (error instanceof DatabaseError && error.code !== '23505') { + return this.findUserRefreshToken({ + where: { + userId: user.id, + refreshToken, + }, + }); + } else { + throw error; + } + } } public async deleteUserRefreshToken( @@ -93,7 +113,7 @@ export class UserRefreshTokensRepository implements IUserRefreshTokensRepository return (tx ?? this.db) .delete(userRefreshTokensTable) .where(and( - eq(userRefreshTokensTable.userId, userRefreshToken.userId), + eq(userRefreshTokensTable.userId, userRefreshToken.user.id), eq(userRefreshTokensTable.hashedRefreshToken, userRefreshToken.hashedRefreshToken), )) .returning() diff --git a/src/infra/postgres/repositories/users.repository.ts b/src/infra/postgres/repositories/users.repository.ts index 0fe60c4..4a8830c 100644 --- a/src/infra/postgres/repositories/users.repository.ts +++ b/src/infra/postgres/repositories/users.repository.ts @@ -2,12 +2,14 @@ import { Injectable } from '@nestjs/common'; import { Database, Transaction } from 'src/infra/postgres/types'; import { InjectDatabase } from 'src/infra/ioc/decorators/inject-database.decorator'; import { Nullable, Optional, PaginatedArray } from 'src/common/types'; -import { CreateUserEntityValues, UpdateUserEntityValues, UserEntity, usersTable } from 'src/infra/postgres/tables'; +import { usersTable } from 'src/infra/postgres/tables'; +import { CreateUserEntityValues, UpdateUserEntityValues, UserEntity } from 'src/core/entities/user.entity'; import { and, eq, inArray, like, SQL } from 'drizzle-orm'; import { mapArrayToPaginatedArray } from 'src/common/helpers/map-array-to-paginated-array.helper'; import { AppEntityNotFoundException } from 'src/core/exceptions'; import { FindEntitiesOptions, FindEntitiesWithPaginationOptions, FindEntityByIdOptions, FindEntityOptions } from 'src/core/types'; import { FindUsersWhere, IUsersRepository } from 'src/core/repositories/users.repository'; +import { hashUserPassword } from 'src/common/helpers/hash-user-password.helper'; @Injectable() export class UsersRepository implements IUsersRepository { @@ -124,9 +126,14 @@ export class UsersRepository implements IUsersRepository { values: CreateUserEntityValues, tx?: Transaction, ): Promise { + const { password } = values; + return (tx ?? this.db) .insert(usersTable) - .values(values) + .values({ + ...values, + hashedPassword: await hashUserPassword(password), + }) .returning() .then(([user]) => user!); } @@ -136,9 +143,16 @@ export class UsersRepository implements IUsersRepository { values: UpdateUserEntityValues, tx?: Transaction, ): Promise { + const { password } = values; + return (tx ?? this.db) .update(usersTable) - .set(values) + .set({ + ...values, + ...(password !== undefined + ? { hashedPassword: await hashUserPassword(password) } + : {}) + }) .where(eq(usersTable.id, user.id)) .returning() .then(([updatedUser]) => updatedUser!); diff --git a/src/infra/postgres/tables/opened-packs.table.ts b/src/infra/postgres/tables/opened-packs.table.ts index ed8b40c..00f633d 100644 --- a/src/infra/postgres/tables/opened-packs.table.ts +++ b/src/infra/postgres/tables/opened-packs.table.ts @@ -1,8 +1,8 @@ import { uuid, pgTable, integer, timestamp } from 'drizzle-orm/pg-core'; import { baseIdColumn } from '../base-columns'; -import { UserEntity, usersTable } from './users.table'; -import { PackEntity, packsTable } from './packs.table'; -import { PokemonEntity, pokemonsTable } from './pokemons.table'; +import { usersTable } from './users.table'; +import { packsTable } from './packs.table'; +import { pokemonsTable } from './pokemons.table'; import { UUIDv4 } from 'src/common/types'; import { relations } from 'drizzle-orm'; @@ -37,15 +37,4 @@ export const openedPacksTableRelations = relations(openedPacksTable, ({ one }) = fields: [openedPacksTable.pokemonId], references: [pokemonsTable.id], }), -})) - -export type OpenedPackEntity = typeof openedPacksTable.$inferSelect & { - user: UserEntity, - pack: PackEntity, - pokemon: PokemonEntity, -} -export type CreateOpenedPackEntityValues = Omit & { - user: UserEntity, - pack: PackEntity, - pokemon: PokemonEntity, -} +})); diff --git a/src/infra/postgres/tables/packs-to-pokemons.table.ts b/src/infra/postgres/tables/packs-to-pokemons.table.ts index b499a47..131e930 100644 --- a/src/infra/postgres/tables/packs-to-pokemons.table.ts +++ b/src/infra/postgres/tables/packs-to-pokemons.table.ts @@ -1,8 +1,8 @@ import { relations } from 'drizzle-orm'; import { uuid, integer, pgTable, index, primaryKey } from 'drizzle-orm/pg-core'; import { UUIDv4 } from 'src/common/types'; -import { PackEntity, packsTable } from './packs.table'; -import { PokemonEntity, pokemonsTable } from './pokemons.table'; +import { packsTable } from './packs.table'; +import { pokemonsTable } from './pokemons.table'; export const packsToPokemonsTable = pgTable('packs_to_pokemons', { packId: uuid('pack_id') @@ -28,8 +28,3 @@ export const packsToPokemonsTableRelations = relations(packsToPokemonsTable, ({ references: [pokemonsTable.id], }), })); - -export type PackToPokemonEntity = typeof packsToPokemonsTable.$inferSelect & { - pack: PackEntity, - pokemon: PokemonEntity, -} diff --git a/src/infra/postgres/tables/packs.table.ts b/src/infra/postgres/tables/packs.table.ts index 6038553..5b271d8 100644 --- a/src/infra/postgres/tables/packs.table.ts +++ b/src/infra/postgres/tables/packs.table.ts @@ -17,8 +17,4 @@ export const packsTable = pgTable('packs', { export const packsTableRelations = relations(packsTable, ({ many }) => ({ packsToPokemons: many(packsToPokemonsTable), -})) - -export type PackEntity = typeof packsTable.$inferSelect; -export type CreatePackEntityValues = Omit; -export type UpdatePackEntityValues = Partial; +})); diff --git a/src/infra/postgres/tables/pokemons.table.ts b/src/infra/postgres/tables/pokemons.table.ts index 6055b55..81a6402 100644 --- a/src/infra/postgres/tables/pokemons.table.ts +++ b/src/infra/postgres/tables/pokemons.table.ts @@ -21,6 +21,3 @@ export const pokemonsTable = pgTable('pokemons', { export const pokemonsTableRelations = relations(pokemonsTable, ({ many }) => ({ packsToPokemons: many(packsToPokemonsTable), })); - -export type PokemonEntity = typeof pokemonsTable.$inferSelect; -export type CreatePokemonEntityValues = typeof pokemonsTable.$inferInsert; diff --git a/src/infra/postgres/tables/quick-sold-user-items.table.ts b/src/infra/postgres/tables/quick-sold-user-items.table.ts index 600834b..62f275b 100644 --- a/src/infra/postgres/tables/quick-sold-user-items.table.ts +++ b/src/infra/postgres/tables/quick-sold-user-items.table.ts @@ -1,9 +1,9 @@ import { relations } from 'drizzle-orm'; import { uuid, pgTable, timestamp } from 'drizzle-orm/pg-core'; import { UUIDv4 } from 'src/common/types'; -import { PokemonEntity, pokemonsTable } from './pokemons.table'; +import { pokemonsTable } from './pokemons.table'; import { userItemsTableColumns } from './user-items.table'; -import { UserEntity, usersTable } from './users.table'; +import { usersTable } from './users.table'; export const quickSoldUserItemsTable = pgTable('quick_sold_user_items', { ...userItemsTableColumns, @@ -30,8 +30,3 @@ export const quickSoldUserItemsTableRelations = relations(quickSoldUserItemsTabl references: [pokemonsTable.id], }), })); - -export type QuickSoldUserItemEntity = typeof quickSoldUserItemsTable.$inferSelect & { - user: UserEntity, - pokemon: PokemonEntity, -}; diff --git a/src/infra/postgres/tables/trades-to-user-items.table.ts b/src/infra/postgres/tables/trades-to-user-items.table.ts index 3737972..74f7360 100644 --- a/src/infra/postgres/tables/trades-to-user-items.table.ts +++ b/src/infra/postgres/tables/trades-to-user-items.table.ts @@ -1,13 +1,11 @@ import { relations } from 'drizzle-orm'; import { index, pgEnum, pgTable, primaryKey, uuid } from 'drizzle-orm/pg-core'; import { UUIDv4 } from 'src/common/types'; -import { TradeEntity, tradesTable } from './trades.table'; -import { UserItemEntity, userItemsTable } from './user-items.table'; +import { tradesTable } from './trades.table'; +import { userItemsTable } from './user-items.table'; +import { userTypeEnumValues } from 'src/core/entities/trade-to-user-item.entity'; -export const userTypeEnum = pgEnum('trades_to_user_items_user_type', [ - 'SENDER', - 'RECEIVER', -]); +export const userTypeEnum = pgEnum('trades_to_user_items_user_type', userTypeEnumValues); export const tradesToUserItemsTable = pgTable('trades_to_user_items', { tradeId: uuid('trade_id') @@ -37,29 +35,3 @@ export const tradesToUserItemsTableRelations = relations(tradesToUserItemsTable, references: [userItemsTable.id], }), })); - -export type TradeToUserItemUserType = typeof userTypeEnum.enumValues[number]; - -export type TradeToUserItemEntity = typeof tradesToUserItemsTable.$inferSelect & { - trade: TradeEntity, - userItem: UserItemEntity, -} -export type TradeToSenderItemEntity = Omit & { - userType: 'SENDER', - senderItem: UserItemEntity, -} -export type TradeToReceiverItemEntity = Omit & { - userType: 'RECEIVER', - receiverItem: UserItemEntity, -} - -export type CreateTradeToUserItemEntityValues = Omit & { - trade: TradeEntity, - userItem: UserItemEntity, -} -export type CreateTradeToSenderItemEntityValues = Omit & { - senderItem: UserItemEntity, -}; -export type CreateTradeToReceiverItemEntityValues = Omit & { - receiverItem: UserItemEntity, -}; diff --git a/src/infra/postgres/tables/trades.table.ts b/src/infra/postgres/tables/trades.table.ts index 0ab5e17..e39a661 100644 --- a/src/infra/postgres/tables/trades.table.ts +++ b/src/infra/postgres/tables/trades.table.ts @@ -2,16 +2,10 @@ import { relations } from 'drizzle-orm'; import { uuid, pgTable, timestamp, index, pgEnum } from 'drizzle-orm/pg-core'; import { UUIDv4 } from 'src/common/types'; import { baseColumns } from '../base-columns'; -import { UserItemEntity } from './user-items.table'; -import { UserEntity, usersTable } from './users.table'; -import { tradesToUserItemsTable } from './trades-to-user-items.table'; +import { usersTable } from './users.table'; +import { tradeStatusEnumValues } from 'src/core/entities/trade.entity'; -export const statusEnum = pgEnum('trades_status', [ - 'PENDING', - 'CANCELLED', - 'ACCEPTED', - 'REJECTED', -]); +export const statusEnum = pgEnum('trades_status', tradeStatusEnumValues); export const tradesTable = pgTable('trades', { ...baseColumns, @@ -31,7 +25,7 @@ export const tradesTable = pgTable('trades', { statusIdx: index().on(table.status), })); -export const tradesTableRelations = relations(tradesTable, ({ one, many }) => ({ +export const tradesTableRelations = relations(tradesTable, ({ one }) => ({ sender: one(usersTable, { fields: [tradesTable.senderId], references: [usersTable.id], @@ -41,35 +35,3 @@ export const tradesTableRelations = relations(tradesTable, ({ one, many }) => ({ references: [usersTable.id], }), })) - -export type TradeStatus = typeof statusEnum.enumValues[number]; - -export type TradeEntity = typeof tradesTable.$inferSelect & { - sender: UserEntity, - receiver: UserEntity, -}; - -export type PendingTradeEntity = Omit & { - status: 'PENDING' -}; -export type CancelledTradeEntity = Omit & { - status: 'CANCELLED', -}; -export type AcceptedTradeEntity = Omit & { - status: 'ACCEPTED', -}; -export type RejectedTradeEntity = Omit & { - status: 'REJECTED', -}; - -export type CreatePendingTradeEntityValues = Omit< - typeof tradesTable.$inferInsert, - | 'status' - | 'statusedAt' - | 'senderId' - | 'receiverId'> & { - sender: UserEntity, - senderItems: Array, - receiver: UserEntity, - receiverItems: Array, -}; diff --git a/src/infra/postgres/tables/user-items.table.ts b/src/infra/postgres/tables/user-items.table.ts index 4d517c6..4a811dc 100644 --- a/src/infra/postgres/tables/user-items.table.ts +++ b/src/infra/postgres/tables/user-items.table.ts @@ -1,10 +1,9 @@ import { uuid, integer, pgTable, timestamp } from 'drizzle-orm/pg-core'; import { baseIdColumn } from '../base-columns'; -import { UserEntity, usersTable } from './users.table'; -import { PokemonEntity, pokemonsTable } from './pokemons.table'; +import { usersTable } from './users.table'; +import { pokemonsTable } from './pokemons.table'; import { UUIDv4 } from 'src/common/types'; import { relations } from 'drizzle-orm'; -import { tradesToUserItemsTable } from './trades-to-user-items.table'; export const userItemsTableColumns = { ...baseIdColumn, @@ -22,7 +21,7 @@ export const userItemsTableColumns = { export const userItemsTable = pgTable('user_items', userItemsTableColumns); -export const userItemsTableRelations = relations(userItemsTable, ({ one, many }) => ({ +export const userItemsTableRelations = relations(userItemsTable, ({ one }) => ({ user: one(usersTable, { fields: [userItemsTable.userId], references: [usersTable.id], @@ -32,15 +31,3 @@ export const userItemsTableRelations = relations(userItemsTable, ({ one, many }) references: [pokemonsTable.id], }), })); - -export type UserItemEntity = typeof userItemsTable.$inferSelect & { - user: UserEntity, - pokemon: PokemonEntity, -} -export type CreateUserItemEntityValues = Omit & { - user: UserEntity, - pokemon: PokemonEntity, -} -export type UpdateUserItemEntityValues = Partial; diff --git a/src/infra/postgres/tables/user-refresh-tokens.table.ts b/src/infra/postgres/tables/user-refresh-tokens.table.ts index b17c5a0..999af73 100644 --- a/src/infra/postgres/tables/user-refresh-tokens.table.ts +++ b/src/infra/postgres/tables/user-refresh-tokens.table.ts @@ -1,6 +1,6 @@ import { index, pgTable, primaryKey, text, timestamp, uuid } from 'drizzle-orm/pg-core'; import { UUIDv4 } from 'src/common/types'; -import { UserEntity, usersTable } from './users.table'; +import { usersTable } from './users.table'; import { relations } from 'drizzle-orm'; // TODO: Create trigger in sql migration @@ -25,10 +25,3 @@ export const userRefreshTokensTableRelations = relations(userRefreshTokensTable, references: [usersTable.id], }), })); - -export type UserRefreshTokenEntity = typeof userRefreshTokensTable.$inferSelect & { - user: UserEntity, -}; -export type CreateUserRefreshTokenEntityValues = Omit & { - user: UserEntity, -}; diff --git a/src/infra/postgres/tables/users.table.ts b/src/infra/postgres/tables/users.table.ts index edf6db3..b67b8b9 100644 --- a/src/infra/postgres/tables/users.table.ts +++ b/src/infra/postgres/tables/users.table.ts @@ -22,7 +22,3 @@ export const usersTableRelations = relations(usersTable, ({ many }) => ({ openedPacks: many(openedPacksTable), quickSoldItems: many(quickSoldUserItemsTable), })) - -export type UserEntity = typeof usersTable.$inferSelect; -export type CreateUserEntityValues = Omit; -export type UpdateUserEntityValues = Partial; diff --git a/tests/e2e/modules/auth/login.post.test.ts b/tests/e2e/modules/auth/login.post.test.ts index ebad52f..d7f93cf 100644 --- a/tests/e2e/modules/auth/login.post.test.ts +++ b/tests/e2e/modules/auth/login.post.test.ts @@ -1,7 +1,7 @@ import request from 'supertest'; import { INestApplication } from '@nestjs/common'; import { AuthService } from 'src/core/services/auth.service'; -import { UserEntity } from 'src/infra/postgres/tables'; +import { UserEntity } from 'src/core/entities/user.entity'; import { buildTestApp } from '../../build-test-app.helper'; const API_ENDPOINT = '/auth/login';