Skip to content

Commit

Permalink
feat(procedure): 🚀 add pagination
Browse files Browse the repository at this point in the history
Signed-off-by: Manuel Ruck <git@manuelruck.de>
  • Loading branch information
Manuel Ruck authored and ManAnRuck committed Sep 22, 2024
1 parent 9cf873d commit 8c64dec
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 60 deletions.
14 changes: 14 additions & 0 deletions services/procedures/src/decorators/pagination.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { createParamDecorator, ExecutionContext } from '@nestjs/common';

export const Pagination = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
const { page = 1, limit = 10 } = request.query;

// Ensure valid pagination values
const validPage = Math.max(1, parseInt(page));
const validLimit = Math.min(Math.max(1, parseInt(limit)), 100); // Max limit of 100

return { page: validPage, limit: validLimit };
},
);
27 changes: 21 additions & 6 deletions services/procedures/src/procedures/procedures.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe('ProceduresController', () => {
jest.Mocked<Partial<ProceduresService>>
> = {
findAll: jest.fn(
() =>
({}: { page: number; limit: number }) =>
({
title: 'test',
id: 1,
Expand All @@ -21,7 +21,7 @@ describe('ProceduresController', () => {
}) as unknown as Promise<IProcedure & { _id: any }>,
),
fetchUpcomingProcedures: jest.fn(
() =>
({}: { page: number; limit: number }) =>
({
title: 'test',
id: 1,
Expand All @@ -32,7 +32,7 @@ describe('ProceduresController', () => {
}) as any,
),
fetchPastProcedures: jest.fn(
() =>
({}: { page: number; limit: number }) =>
({
title: 'test',
id: 1,
Expand Down Expand Up @@ -60,7 +60,12 @@ describe('ProceduresController', () => {
});

it('should return an array of procedures', async () => {
expect(controller.findAll()).toStrictEqual({
expect(
controller.findAll({
page: 1,
limit: 1,
}),
).toStrictEqual({
title: 'test',
id: 1,
procedureId: '123456',
Expand All @@ -71,7 +76,12 @@ describe('ProceduresController', () => {
});

it('should return an array of upcoming procedures', async () => {
expect(controller.upcomingProcedures()).toStrictEqual({
expect(
controller.upcomingProcedures({
page: 1,
limit: 1,
}),
).toStrictEqual({
title: 'test',
id: 1,
procedureId: '123456',
Expand All @@ -82,7 +92,12 @@ describe('ProceduresController', () => {
});

it('should return an array of past procedures', async () => {
expect(controller.pastProcedures()).toStrictEqual({
expect(
controller.pastProcedures({
page: 1,
limit: 1,
}),
).toStrictEqual({
title: 'test',
id: 1,
procedureId: '123456',
Expand Down
24 changes: 18 additions & 6 deletions services/procedures/src/procedures/procedures.controller.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
import { Controller, Get } from '@nestjs/common';
import { ProceduresService } from './procedures.service';
import { Pagination } from '../decorators/pagination';

@Controller('procedures')
export class ProceduresController {
constructor(private readonly proceduresService: ProceduresService) {}
@Get()
findAll() {
return this.proceduresService.findAll();
findAll(@Pagination() pagination: { page: number; limit: number }) {
return this.proceduresService.findAll({
page: pagination.page,
limit: pagination.limit,
});
}

@Get('list/upcoming')
upcomingProcedures() {
return this.proceduresService.fetchUpcomingProcedures();
upcomingProcedures(
@Pagination() pagination: { page: number; limit: number },
) {
return this.proceduresService.fetchUpcomingProcedures({
page: pagination.page,
limit: pagination.limit,
});
}

@Get('list/past')
pastProcedures() {
return this.proceduresService.fetchPastProcedures();
pastProcedures(@Pagination() pagination: { page: number; limit: number }) {
return this.proceduresService.fetchPastProcedures({
page: pagination.page,
limit: pagination.limit,
});
}
}
113 changes: 71 additions & 42 deletions services/procedures/src/procedures/procedures.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,21 @@ describe('ProceduresService', () => {

beforeEach(async () => {
procedureModel = {
find: jest.fn().mockReturnValue([
[
{
title: 'test',
id: 1,
type: '',
period: '',
importantDocuments: [],
},
],
]),
find: jest.fn().mockReturnValue({
skip: jest.fn().mockReturnValue({
limit: jest.fn().mockResolvedValue([
[
{
title: 'test',
id: 1,
type: '',
period: '',
importantDocuments: [],
},
],
]),
}),
}),
};

const module: TestingModule = await Test.createTestingModule({
Expand All @@ -29,15 +33,20 @@ describe('ProceduresService', () => {
}).compile();

service = module.get<ProceduresService>(ProceduresService);
// jest.clearAllMocks();
jest.clearAllMocks();
});

it('should be defined', () => {
expect(service).toBeDefined();
});

it('should return an array of procedures', () => {
expect(service.findAll()).resolves.toStrictEqual([
expect(
service.findAll({
page: 1,
limit: 1,
}),
).resolves.toStrictEqual([
{
title: 'test',
id: 1,
Expand All @@ -49,21 +58,31 @@ describe('ProceduresService', () => {
});

it('should return an array of upcoming procedures', () => {
(procedureModel.find as jest.Mock).mockReturnValueOnce({
sort: jest.fn().mockReturnValueOnce({
limit: jest.fn().mockResolvedValue([
{
title: 'test',
id: 1,
type: '',
period: '',
importantDocuments: [],
},
]),
}),
});
const mockResult = [
{
title: 'test',
id: 1,
type: '',
period: '',
importantDocuments: [],
},
];

// Mock the chain of .find().sort().skip().limit()
const mockLimit = jest.fn().mockResolvedValue(mockResult);
const mockSkip = jest.fn().mockReturnValue({ limit: mockLimit });
const mockSort = jest.fn().mockReturnValue({ skip: mockSkip });
const mockFind = jest.fn().mockReturnValue({ sort: mockSort });

// Assign the mock to procedureModel.find
(procedureModel.find as jest.Mock).mockImplementation(mockFind);

expect(service.fetchUpcomingProcedures()).resolves.toStrictEqual([
expect(
service.fetchUpcomingProcedures({
page: 1,
limit: 1,
}),
).resolves.toStrictEqual([
{
title: 'test',
id: 1,
Expand All @@ -74,22 +93,32 @@ describe('ProceduresService', () => {
]);
});

it('should return an array of past procedures', () => {
(procedureModel.find as jest.Mock).mockReturnValueOnce({
sort: jest.fn().mockReturnValueOnce({
limit: jest.fn().mockResolvedValue([
{
title: 'test',
id: 1,
type: '',
period: '',
importantDocuments: [],
},
]),
}),
});
it('should return an array of past procedures', async () => {
const mockResult = [
{
title: 'test',
id: 1,
type: '',
period: '',
importantDocuments: [],
},
];

expect(service.fetchPastProcedures()).resolves.toStrictEqual([
// Mock the chain of .find().sort().skip().limit()
const mockLimit = jest.fn().mockResolvedValue(mockResult);
const mockSkip = jest.fn().mockReturnValue({ limit: mockLimit });
const mockSort = jest.fn().mockReturnValue({ skip: mockSkip });
const mockFind = jest.fn().mockReturnValue({ sort: mockSort });

// Assign the mock to procedureModel.find
(procedureModel.find as jest.Mock).mockImplementation(mockFind);

await expect(
service.fetchPastProcedures({
page: 1,
limit: 1,
}),
).resolves.toStrictEqual([
{
title: 'test',
id: 1,
Expand Down
23 changes: 17 additions & 6 deletions services/procedures/src/procedures/procedures.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,21 @@ export class ProceduresService {
@InjectModel('Procedure') private procedureModel: typeof ProcedureModel,
) {}

async findAll() {
const procedures = await this.procedureModel.find();
async findAll({ page, limit }: { page: number; limit: number }) {
const procedures = await this.procedureModel
.find()
.skip((page - 1) * limit)
.limit(limit);
return procedures[0];
}

async fetchUpcomingProcedures() {
async fetchUpcomingProcedures({
page,
limit,
}: {
page: number;
limit: number;
}) {
return await this.procedureModel
.find({
$or: [
Expand All @@ -29,10 +38,11 @@ export class ProceduresService {
],
})
.sort({ voteDate: 1, voteEnd: 1, votes: -1 })
.limit(100);
.skip((page - 1) * limit)
.limit(limit);
}

async fetchPastProcedures() {
async fetchPastProcedures({ page, limit }: { page: number; limit: number }) {
return await this.procedureModel
.find({
$or: [
Expand All @@ -41,6 +51,7 @@ export class ProceduresService {
],
})
.sort({ voteDate: -1, voteEnd: -1, votes: -1 })
.limit(100);
.skip((page - 1) * limit)
.limit(limit);
}
}

0 comments on commit 8c64dec

Please sign in to comment.