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,
"password" varchar NOT NULL,
email varchar NOT NULL,
"createdAt" timestamp NOT NULL DEFAULT now(),
CONSTRAINT "users_pk" PRIMARY KEY (id),
CONSTRAINT "users_email_unique" UNIQUE (email)
);
@ -18,7 +19,7 @@ export class InitSchema1695130227420 implements MigrationInterface {
"createdAt" timestamp NOT NULL DEFAULT now(),
"sourceUserId" 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);
@ -26,6 +27,7 @@ export class InitSchema1695130227420 implements MigrationInterface {
CREATE TABLE pairs (
id serial4 NOT NULL,
"createdAt" timestamp NOT NULL DEFAULT now(),
CONSTRAINT "pairs_pk" PRIMARY KEY (id)
);

View File

@ -4,11 +4,17 @@ import { User } from 'src/users/entities/user.entity';
@Entity('pair-members')
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)
pair: Pair;
@PrimaryColumn('int', { name: 'userId' })
// @PrimaryColumn('int', { name: 'userId' })
@ManyToOne(() => 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';
@Entity('pairs')
@ -8,4 +13,7 @@ export class Pair {
@OneToMany(() => PairMember, (pairMember) => pairMember.pair)
pairMembers: PairMember[];
@CreateDateColumn({ type: 'timestamp' })
createdAt: Date;
}

View File

@ -30,17 +30,19 @@ export class PairsService {
async (manager) => {
const pair = this.pairsRepository.create();
await manager.save(pair);
const pairMembers = this.pairMembersRepository.create([
{
pair,
user: { id: userIds[0] },
pairId: pair.id,
userId: userIds[0],
},
{
pair,
user: { id: userIds[1] },
pairId: pair.id,
userId: userIds[1],
},
]);
await manager.save(pairMembers);
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 { UsersModule } from 'src/users/users.module';
import { PairsModule } from 'src/pairs/pairs.module';
import { SwipesController } from './swipes.controller';
@Module({
imports: [TypeOrmModule.forFeature([Swipe]), UsersModule, PairsModule],
providers: [SwipesService],
controllers: [SwipesController],
})
export class SwipesModule {}

View File

@ -15,37 +15,53 @@ export class SwipesService {
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(
sourceUserId: number,
targetUserId: number,
liked: boolean,
) {
const users = await this.usersService.getByIds([
sourceUserId,
targetUserId,
]);
if (users.length !== 2) {
const sourceUser = await this.usersService.getById(sourceUserId);
const targetUser = await this.usersService.getById(targetUserId);
if (!sourceUser || !targetUser) {
throw new UserIdNotExistsException();
}
const existedSwipe = await this.getSwipe(sourceUserId, targetUserId, liked);
if (existedSwipe) {
return existedSwipe;
}
const swipe = this.swipesRepository.create({
sourceUser: { id: sourceUserId },
targetUser: { id: targetUserId },
liked,
});
await this.swipesRepository.save(swipe);
if (liked) {
const answeringLikeSwipe = await this.swipesRepository.findBy({
sourceUser: { id: targetUserId },
targetUser: { id: sourceUserId },
});
const answeringLikeSwipe = await this.getSwipe(
targetUserId,
sourceUserId,
true,
);
if (answeringLikeSwipe) {
await this.pairsService.createPair([sourceUserId, targetUserId]); // TODO use transaction?
}
}
return swipe;
return this.getSwipeById(swipe.id);
}
async getSwipesByUser(sourceUserId: number) {
@ -53,6 +69,39 @@ export class SwipesService {
if (!user) {
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 { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
import {
Column,
CreateDateColumn,
Entity,
OneToMany,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity('users')
export class User {
@ -10,6 +17,7 @@ export class User {
name: string;
@Column()
@Exclude()
password: string;
@Column({ unique: true })
@ -20,4 +28,7 @@ export class User {
@OneToMany(() => Swipe, (swipe) => swipe.targetUser)
swiped: Swipe[];
@CreateDateColumn({ type: 'timestamp' })
createdAt: Date;
}

View File

@ -28,7 +28,10 @@ export class UsersService {
}
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) {
throw new UserIdNotExistsException();
}
@ -41,6 +44,8 @@ export class UsersService {
async create(userData: CreateUserDto) {
const user = this.usersRepository.create(userData);
console.log('user', user);
await this.usersRepository.save(user);
return user;
}