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 <[email protected]>
  • Loading branch information
Manuel Ruck committed Sep 23, 2024
1 parent 9cf873d commit 29defaa
Show file tree
Hide file tree
Showing 13 changed files with 207 additions and 96 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@
"[ignore]": {
"editor.defaultFormatter": "foxundermoon.shell-format"
},
"conventionalCommits.scopes": ["push-send-queued"]
"conventionalCommits.scopes": ["push-send-queued"],
"CodeGPT.apiKey": "OpenAI"
}
4 changes: 2 additions & 2 deletions bundestag.io/admin/src/app/list/past/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default async function Page() {
return (
<>
<h1>Past procedures</h1>
{data.map((procedure) => (
{data.procedures.map((procedure) => (
<Entry
key={procedure.id}
title={procedure.title}
Expand All @@ -25,7 +25,7 @@ export default async function Page() {
);
}

async function getData(): Promise<IProcedure[]> {
async function getData(): Promise<{ procedures: IProcedure[]; count: number }> {
const res = await fetch(`${process.env.PROCEDURES_SERVER_URL}/procedures/list/past`, {
headers: {
'Cache-Control': 'no-cache',
Expand Down
4 changes: 2 additions & 2 deletions bundestag.io/admin/src/app/list/upcoming/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default async function Page() {
return (
<>
<h1>Upcoming procedures</h1>
{data.map((procedure) => (
{data.procedures.map((procedure) => (
<Entry
key={procedure.id}
title={procedure.title}
Expand All @@ -25,7 +25,7 @@ export default async function Page() {
);
}

async function getData(): Promise<IProcedure[]> {
async function getData(): Promise<{ procedures: IProcedure[]; count: number }> {
const res = await fetch(`${process.env.PROCEDURES_SERVER_URL}/procedures/list/upcoming`, {
headers: {
'Cache-Control': 'no-cache',
Expand Down
2 changes: 1 addition & 1 deletion services/procedures/bruno/environments/localhost.bru
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
vars {
url: http://localhost:3000
url: http://localhost:3006
}
2 changes: 1 addition & 1 deletion services/procedures/bruno/findAll.bru
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ get {
}

assert {
res.body.procedureId: isString
res.body.procedures[0].procedureId: isString
res.status: eq 200
}
8 changes: 6 additions & 2 deletions services/procedures/bruno/pastProcedures.bru
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ meta {
}

get {
url: {{url}}/procedures/list/past
url: {{url}}/procedures/list/past?limit=2
body: none
auth: none
}

params:query {
limit: 2
}

assert {
res.body[0].procedureId: isString
res.body.count: gt 0
res.status: eq 200
}
9 changes: 7 additions & 2 deletions services/procedures/bruno/upcomingProcedures.bru
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@ meta {
}

get {
url: {{url}}/procedures/list/upcoming
url: {{url}}/procedures/list/upcoming?limit=1&page=2
body: none
auth: none
}

params:query {
limit: 1
page: 2
}

assert {
res.body[0].procedureId: isString
res.body.procedures[0].procedureId: isString
res.status: eq 200
}
2 changes: 1 addition & 1 deletion services/procedures/garden.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ spec:
sourcePath: src
mode: one-way
overrides:
- command: [pnpm, --filter, procedures, run, garden:dev]
- command: [pnpm, --filter, procedures, run, dev]
patchResources:
- name: procedures
kind: Deployment
Expand Down
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,
});
}
}
124 changes: 80 additions & 44 deletions services/procedures/src/procedures/procedures.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,22 @@ 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: [],
},
],
]),
}),
}),
countDocuments: jest.fn().mockResolvedValue(1),
};

const module: TestingModule = await Test.createTestingModule({
Expand All @@ -29,15 +34,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,54 +59,80 @@ 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: [],
},
]),
}),
});

expect(service.fetchUpcomingProcedures()).resolves.toStrictEqual([
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);

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: [],
},
]),
expect(
service.fetchUpcomingProcedures({
page: 1,
limit: 1,
}),
).resolves.toStrictEqual({
procedures: [
{
title: 'test',
id: 1,
type: '',
period: '',
importantDocuments: [],
},
],
count: 1,
});
});

expect(service.fetchPastProcedures()).resolves.toStrictEqual([
it('should return an array of past procedures', async () => {
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);

await expect(
service.fetchPastProcedures({
page: 1,
limit: 1,
}),
).resolves.toStrictEqual({
procedures: [
{
title: 'test',
id: 1,
type: '',
period: '',
importantDocuments: [],
},
],
count: 1,
});
});
});
Loading

0 comments on commit 29defaa

Please sign in to comment.