Skip to content

Commit

Permalink
feat: implement find many and count reply repository method
Browse files Browse the repository at this point in the history
  • Loading branch information
skgndi12 committed Mar 11, 2024
1 parent 138a683 commit 048a4e6
Show file tree
Hide file tree
Showing 3 changed files with 212 additions and 2 deletions.
4 changes: 2 additions & 2 deletions api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
"build": "rimraf ./build && tsc --project tsconfig.prod.json && tsc-alias --project tsconfig.json",
"start:dev": "NODE_ENV=development ts-node -r tsconfig-paths/register src/main.ts",
"start:watch": "NODE_ENV=development nodemon",
"test": "jest",
"test:cov": "jest --coverage --coverageDirectory='coverage'",
"test": "jest --runInBand",
"test:cov": "jest --coverage --coverageDirectory='coverage' --runInBand",
"migrate-create:down": "prisma migrate diff --from-schema-datamodel prisma/schema.prisma --to-migrations prisma/migrations --shadow-database-url $DATABASE_URL --script > prisma/migrations/down.sql",
"migrate-create:up": "prisma migrate dev --create-only",
"migrate-apply:rollback": "prisma db execute --schema prisma/schema.prisma",
Expand Down
42 changes: 42 additions & 0 deletions api/src/infrastructure/repositories/postgresql/reply.repository.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { Prisma } from '@prisma/client';

import { Reply } from '@src/core/entities/review.entity';
import {
CreateReplyParams,
FindManyAndCountResponse,
FindRepliesParams,
ReplyRepository
} from '@src/core/ports/reply.repository';
import { AppErrorCode, CustomError } from '@src/error/errors';
Expand Down Expand Up @@ -72,4 +76,42 @@ export class PostgresqlReplyRepository implements Partial<ReplyRepository> {
});
}
};

public findManyAndCount = async (
params: FindRepliesParams,
txClient?: ExtendedPrismaTransactionClient
): Promise<FindManyAndCountResponse> => {
try {
const client = txClient ?? this.client;
const args: Prisma.ReplyFindManyArgs = {
skip: (params.pageOffset - 1) * params.pageSize,
take: params.pageSize,
where: { reviewId: params.reviewId },
orderBy: {
createdAt: params.direction
}
};

const replyResults = await client.reply.findMany({
skip: args.skip,
take: args.take,
where: args.where,
orderBy: args.orderBy
});
const replyCount = await client.reply.count({ where: args.where });
const replies = replyResults.map((reply) => reply.convertToEntity());

return {
replies,
replyCount
};
} catch (error: unknown) {
throw new CustomError({
code: AppErrorCode.INTERNAL_ERROR,
cause: error,
message: 'failed to find replies and count',
context: { params }
});
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ import seedrandom from 'seedrandom';
import { Logger } from 'winston';

import { Reply } from '@src/core/entities/review.entity';
import { User } from '@src/core/entities/user.entity';
import {
generateUserNickname,
generateUserTag
} from '@src/core/nickname.generator';
import {
CreateReplyParams,
FindRepliesParams
} from '@src/core/ports/reply.repository';
import { AccessLevelEnum, IdpEnum } from '@src/core/types';
import { AppErrorCode, CustomError } from '@src/error/errors';
import { generatePrismaClient } from '@src/infrastructure/prisma/prisma.client';
import { ExtendedPrismaClient } from '@src/infrastructure/prisma/types';
Expand Down Expand Up @@ -158,4 +161,169 @@ describe('Test reply repository', () => {
}
});
});

describe('Test find many and count', () => {
const users: User[] = [];
const userCount = 2;
let reviewId: number;
const replyCount = 20;
const replies: Reply[] = [];
const content = 'randomContent';

beforeAll(async () => {
const currentDate = new Date();

for (let i = 1; i <= userCount; i++) {
const userId = randomUUID();

users.push(
new User(
userId,
generateUserNickname(userId),
generateUserTag(userId),
new IdpEnum(Idp.GOOGLE),
`${userId}@gmail.com`,
new AccessLevelEnum(AccessLevel.USER),
currentDate,
currentDate
)
);
}

for (const user of users) {
await prismaClient.user.create({
data: {
id: user.id,
nickname: user.nickname,
tag: user.tag,
idp: user.idp.get(),
email: user.email,
accessLevel: user.accessLevel.get(),
createdAt: user.createdAt,
updatedAt: user.updatedAt
}
});
}

reviewId = generateRandomNumber(users[0].id);
await prismaClient.review.create({
data: {
id: reviewId,
userId: users[0].id,
title: 'randomTitle',
movieName: 'randomMovieName',
content,
createdAt: currentDate,
updatedAt: currentDate
}
});

for (let i = 1; i <= replyCount; i++) {
const createdAt = new Date(currentDate.getTime() + i * 1000);

if (i <= 10) {
replies.push(
new Reply(i, reviewId, users[0].id, content, createdAt, createdAt)
);
} else {
replies.push(
new Reply(i, reviewId, users[1].id, content, createdAt, createdAt)
);
}
}

for (const reply of replies) {
await prismaClient.reply.create({
data: {
id: reply.id,
reviewId: reply.reviewId,
userId: reply.userId,
content: reply.content,
createdAt: reply.createdAt,
updatedAt: reply.updatedAt
}
});
}
});

afterAll(async () => {
await prismaClient.review.delete({ where: { id: reviewId } });
const userIds = users.map((user) => user.id);
await prismaClient.user.deleteMany({
where: { id: { in: userIds } }
});
});

it('should success when pagination is valid and sorting in descending order', async () => {
const params: FindRepliesParams = {
reviewId,
pageOffset: 1,
pageSize: 10,
direction: 'desc'
};
const repliesSorted = replies.sort(
(a, b) => b.createdAt.getTime() - a.createdAt.getTime()
);
const start = (params.pageOffset - 1) * params.pageSize;
const end = start + params.pageSize;
const repliesSpliced = repliesSorted.slice(start, end);

const actualResult = await replyRepository.findManyAndCount(params);

expect(actualResult.replyCount).toEqual(replyCount);
expect(JSON.stringify(actualResult.replies)).toEqual(
JSON.stringify(repliesSpliced)
);
});

it('should success when pagination is valid and sorting in ascending order', async () => {
const params: FindRepliesParams = {
reviewId,
pageOffset: 2,
pageSize: 10,
direction: 'asc'
};
const repliesSorted = replies.sort(
(a, b) => a.createdAt.getTime() - b.createdAt.getTime()
);
const start = (params.pageOffset - 1) * params.pageSize;
const end = start + params.pageSize;
const repliesSpliced = repliesSorted.slice(start, end);

const actualResult = await replyRepository.findManyAndCount(params);

expect(actualResult.replyCount).toEqual(replyCount);
expect(JSON.stringify(actualResult.replies)).toEqual(
JSON.stringify(repliesSpliced)
);
});

it('should return an empty array when the page offset exceeds the available data size range', async () => {
const params: FindRepliesParams = {
reviewId: reviewId,
pageOffset: 10,
pageSize: 10,
direction: 'asc'
};

const actualResult = await replyRepository.findManyAndCount(params);

expect(actualResult.replyCount).toEqual(replyCount);
expect(JSON.stringify(actualResult.replies)).toEqual(JSON.stringify([]));
});

it('should return an empty array when no data is found for the given review ID', async () => {
const params: FindRepliesParams = {
reviewId: reviewId + 1,
pageOffset: 1,
pageSize: 10,
direction: 'asc'
};

const actualResult = await replyRepository.findManyAndCount(params);

expect(actualResult.replyCount).toEqual(0);
expect(JSON.stringify(actualResult.replies)).toEqual(JSON.stringify([]));
});
});
});

0 comments on commit 048a4e6

Please sign in to comment.