fix migration, add create swipe route

This commit is contained in:
Pravdin Egor 2023-09-19 23:38:07 +07:00
parent bf38ec5355
commit 06cf4b129f
11 changed files with 175 additions and 21 deletions

View File

@ -8,6 +8,7 @@ export class InitSchema1695130227420 implements MigrationInterface {
"name" varchar NOT NULL, "name" varchar NOT NULL,
"password" varchar NOT NULL, "password" varchar NOT NULL,
email varchar NOT NULL, email varchar NOT NULL,
"createdAt" timestamp NOT NULL DEFAULT now(),
CONSTRAINT "users_pk" PRIMARY KEY (id), CONSTRAINT "users_pk" PRIMARY KEY (id),
CONSTRAINT "users_email_unique" UNIQUE (email) CONSTRAINT "users_email_unique" UNIQUE (email)
); );
@ -18,7 +19,7 @@ export class InitSchema1695130227420 implements MigrationInterface {
"createdAt" timestamp NOT NULL DEFAULT now(), "createdAt" timestamp NOT NULL DEFAULT now(),
"sourceUserId" int4 NULL, "sourceUserId" int4 NULL,
"targetUserId" int4 NULL, "targetUserId" int4 NULL,
CONSTRAINT "PK_bb38af5831e2c084a78e3622ff6" PRIMARY KEY (id) CONSTRAINT "swipes_pk" PRIMARY KEY (id)
); );
ALTER TABLE swipes ADD CONSTRAINT "swipes_target_user_fk" FOREIGN KEY ("targetUserId") REFERENCES users(id); ALTER TABLE swipes ADD CONSTRAINT "swipes_target_user_fk" FOREIGN KEY ("targetUserId") REFERENCES users(id);
@ -26,6 +27,7 @@ export class InitSchema1695130227420 implements MigrationInterface {
CREATE TABLE pairs ( CREATE TABLE pairs (
id serial4 NOT NULL, id serial4 NOT NULL,
"createdAt" timestamp NOT NULL DEFAULT now(),
CONSTRAINT "pairs_pk" PRIMARY KEY (id) CONSTRAINT "pairs_pk" PRIMARY KEY (id)
); );

View File

@ -4,11 +4,17 @@ import { User } from 'src/users/entities/user.entity';
@Entity('pair-members') @Entity('pair-members')
export class PairMember { export class PairMember {
@PrimaryColumn('int', { name: 'pairId' }) @PrimaryColumn({ type: 'int4', name: 'pairId' })
pairId: number;
@PrimaryColumn({ type: 'int', name: 'userId' })
userId: number;
// @PrimaryColumn('int', { name: 'pairId' })
@ManyToOne(() => Pair, (pair) => pair.pairMembers) @ManyToOne(() => Pair, (pair) => pair.pairMembers)
pair: Pair; pair: Pair;
@PrimaryColumn('int', { name: 'userId' }) // @PrimaryColumn('int', { name: 'userId' })
@ManyToOne(() => User) @ManyToOne(() => User)
user: User; user: User;
} }

View File

@ -1,4 +1,9 @@
import { Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm'; import {
CreateDateColumn,
Entity,
OneToMany,
PrimaryGeneratedColumn,
} from 'typeorm';
import { PairMember } from './pair-member.entity'; import { PairMember } from './pair-member.entity';
@Entity('pairs') @Entity('pairs')
@ -8,4 +13,7 @@ export class Pair {
@OneToMany(() => PairMember, (pairMember) => pairMember.pair) @OneToMany(() => PairMember, (pairMember) => pairMember.pair)
pairMembers: PairMember[]; pairMembers: PairMember[];
@CreateDateColumn({ type: 'timestamp' })
createdAt: Date;
} }

View File

@ -30,17 +30,19 @@ export class PairsService {
async (manager) => { async (manager) => {
const pair = this.pairsRepository.create(); const pair = this.pairsRepository.create();
await manager.save(pair); await manager.save(pair);
const pairMembers = this.pairMembersRepository.create([ const pairMembers = this.pairMembersRepository.create([
{ {
pair, pairId: pair.id,
user: { id: userIds[0] }, userId: userIds[0],
}, },
{ {
pair, pairId: pair.id,
user: { id: userIds[1] }, userId: userIds[1],
}, },
]); ]);
await manager.save(pairMembers); await manager.save(pairMembers);
return pair; return pair;
}, },
); );

View File

@ -0,0 +1,12 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsBoolean, IsNumber } from 'class-validator';
export class CreateSwipeDto {
@ApiProperty()
@IsNumber()
userId: number;
@ApiProperty()
@IsBoolean()
liked: boolean;
}

View File

@ -0,0 +1,19 @@
import { ApiProperty } from '@nestjs/swagger';
import { User } from 'src/users/entities/user.entity';
export class CreateSwipeResponseDto {
@ApiProperty()
id: number;
@ApiProperty()
sourceUser: Pick<User, 'id' | 'name' | 'email'>;
@ApiProperty()
targetUser: Pick<User, 'id' | 'name' | 'email'>;
@ApiProperty()
liked: boolean;
@ApiProperty()
createdAt: Date;
}

View File

@ -0,0 +1,38 @@
import {
Body,
Controller,
HttpCode,
Post,
Req,
UseGuards,
} from '@nestjs/common';
import { ApiBody, ApiCreatedResponse, ApiTags } from '@nestjs/swagger';
import { SwipesService } from './swipes.service';
import { CreateSwipeDto } from './dto/create-swipe.dto';
import JwtAuthGuard from 'src/auth/guards/jwt-auth.guard';
import { RequestWithUser } from 'src/auth/interfaces/request-with-user.interface';
import { CreateSwipeResponseDto } from './dto/create-swipe.response.dto';
@ApiTags('swipes')
@Controller('swipes')
export class SwipesController {
constructor(private readonly swipesService: SwipesService) {}
@HttpCode(201)
@Post()
@UseGuards(JwtAuthGuard)
@ApiBody({ type: CreateSwipeDto })
@ApiCreatedResponse({ type: CreateSwipeResponseDto })
async create(
@Req() req: RequestWithUser,
@Body() createData: CreateSwipeDto,
) {
const swipe = await this.swipesService.createSwipe(
req.user.id,
createData.userId,
createData.liked,
);
return swipe;
}
}

View File

@ -4,9 +4,11 @@ import { Swipe } from './entities/swipe.entity';
import { SwipesService } from './swipes.service'; import { SwipesService } from './swipes.service';
import { UsersModule } from 'src/users/users.module'; import { UsersModule } from 'src/users/users.module';
import { PairsModule } from 'src/pairs/pairs.module'; import { PairsModule } from 'src/pairs/pairs.module';
import { SwipesController } from './swipes.controller';
@Module({ @Module({
imports: [TypeOrmModule.forFeature([Swipe]), UsersModule, PairsModule], imports: [TypeOrmModule.forFeature([Swipe]), UsersModule, PairsModule],
providers: [SwipesService], providers: [SwipesService],
controllers: [SwipesController],
}) })
export class SwipesModule {} export class SwipesModule {}

View File

@ -15,37 +15,53 @@ export class SwipesService {
private readonly pairsService: PairsService, private readonly pairsService: PairsService,
) {} ) {}
get select() {
return {
id: true,
createdAt: true,
liked: true,
sourceUser: { id: true, email: true, name: true },
targetUser: { id: true, email: true, name: true },
};
}
async createSwipe( async createSwipe(
sourceUserId: number, sourceUserId: number,
targetUserId: number, targetUserId: number,
liked: boolean, liked: boolean,
) { ) {
const users = await this.usersService.getByIds([ const sourceUser = await this.usersService.getById(sourceUserId);
sourceUserId, const targetUser = await this.usersService.getById(targetUserId);
targetUserId, if (!sourceUser || !targetUser) {
]);
if (users.length !== 2) {
throw new UserIdNotExistsException(); throw new UserIdNotExistsException();
} }
const existedSwipe = await this.getSwipe(sourceUserId, targetUserId, liked);
if (existedSwipe) {
return existedSwipe;
}
const swipe = this.swipesRepository.create({ const swipe = this.swipesRepository.create({
sourceUser: { id: sourceUserId }, sourceUser: { id: sourceUserId },
targetUser: { id: targetUserId }, targetUser: { id: targetUserId },
liked, liked,
}); });
await this.swipesRepository.save(swipe); await this.swipesRepository.save(swipe);
if (liked) { if (liked) {
const answeringLikeSwipe = await this.swipesRepository.findBy({ const answeringLikeSwipe = await this.getSwipe(
sourceUser: { id: targetUserId }, targetUserId,
targetUser: { id: sourceUserId }, sourceUserId,
}); true,
);
if (answeringLikeSwipe) { if (answeringLikeSwipe) {
await this.pairsService.createPair([sourceUserId, targetUserId]); // TODO use transaction? await this.pairsService.createPair([sourceUserId, targetUserId]); // TODO use transaction?
} }
} }
return swipe; return this.getSwipeById(swipe.id);
} }
async getSwipesByUser(sourceUserId: number) { async getSwipesByUser(sourceUserId: number) {
@ -53,6 +69,39 @@ export class SwipesService {
if (!user) { if (!user) {
throw new UserIdNotExistsException(); throw new UserIdNotExistsException();
} }
return this.swipesRepository.findBy({ sourceUser: { id: sourceUserId } }); return this.swipesRepository.find({
where: { sourceUser: { id: sourceUserId } },
select: this.select,
relations: {
sourceUser: true,
targetUser: true,
},
});
}
async getSwipe(sourceUserId: number, targetUserId: number, liked: boolean) {
return this.swipesRepository.findOne({
where: {
sourceUser: { id: sourceUserId },
targetUser: { id: targetUserId },
liked,
},
select: this.select,
relations: {
sourceUser: true,
targetUser: true,
},
});
}
async getSwipeById(id: number) {
return this.swipesRepository.findOne({
where: { id },
select: this.select,
relations: {
sourceUser: true,
targetUser: true,
},
});
} }
} }

View File

@ -1,5 +1,12 @@
import { Exclude } from 'class-transformer';
import { Swipe } from 'src/swipes/entities/swipe.entity'; import { Swipe } from 'src/swipes/entities/swipe.entity';
import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm'; import {
Column,
CreateDateColumn,
Entity,
OneToMany,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity('users') @Entity('users')
export class User { export class User {
@ -10,6 +17,7 @@ export class User {
name: string; name: string;
@Column() @Column()
@Exclude()
password: string; password: string;
@Column({ unique: true }) @Column({ unique: true })
@ -20,4 +28,7 @@ export class User {
@OneToMany(() => Swipe, (swipe) => swipe.targetUser) @OneToMany(() => Swipe, (swipe) => swipe.targetUser)
swiped: Swipe[]; swiped: Swipe[];
@CreateDateColumn({ type: 'timestamp' })
createdAt: Date;
} }

View File

@ -28,7 +28,10 @@ export class UsersService {
} }
async getById(id: number) { async getById(id: number) {
const user = await this.usersRepository.findOneBy({ id }); const user = await this.usersRepository.findOne({
where: { id },
select: { id: true, email: true, name: true, swipes: true, swiped: true },
});
if (!user) { if (!user) {
throw new UserIdNotExistsException(); throw new UserIdNotExistsException();
} }
@ -41,6 +44,8 @@ export class UsersService {
async create(userData: CreateUserDto) { async create(userData: CreateUserDto) {
const user = this.usersRepository.create(userData); const user = this.usersRepository.create(userData);
console.log('user', user);
await this.usersRepository.save(user); await this.usersRepository.save(user);
return user; return user;
} }