Skip to content

Commit

Permalink
Merge pull request #268 from jiho-kr/feature/pagination-response-meta…
Browse files Browse the repository at this point in the history
…data
  • Loading branch information
jiho-kr authored Aug 16, 2023
2 parents 2af262a + d64fe25 commit d1c5456
Show file tree
Hide file tree
Showing 17 changed files with 53 additions and 62 deletions.
2 changes: 1 addition & 1 deletion spec/base/base.controller.read-one.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('BaseController', () => {
app = moduleFixture.createNestApplication();

service = moduleFixture.get<BaseService>(BaseService);
await Promise.all(['name1', 'name2'].map((name: string) => service.repository.save(service.repository.create({ name }))));
await service.repository.save(['name1', 'name2'].map((name: string) => service.repository.create({ name })));

await app.init();
});
Expand Down
2 changes: 1 addition & 1 deletion spec/base/base.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('BaseController', () => {

controller = moduleFixture.get<BaseController>(BaseController);
service = moduleFixture.get<BaseService>(BaseService);
await Promise.all(['name1', 'name2'].map((name: string) => service.repository.save(service.repository.create({ name }))));
await service.repository.save(['name1', 'name2'].map((name: string) => service.repository.create({ name })));

await app.init();
});
Expand Down
7 changes: 2 additions & 5 deletions spec/custom-entity/custom-entity.controller.read-many.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,9 @@ describe('CustomEntity - ReadMany', () => {
app = moduleFixture.createNestApplication();

service = moduleFixture.get<CustomEntityService>(CustomEntityService);
await Promise.all(
Array.from({ length: 100 }, (_, index) => index).map((number) =>
service.repository.save(service.repository.create({ uuid: `${number}`, name: `name-${number}` })),
),
await service.repository.save(
Array.from({ length: 100 }, (_, index) => index).map((number) => ({ uuid: `${number}`, name: `name-${number}` })),
);

await app.init();
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('CustomEntity - ReadOne', () => {
app = moduleFixture.createNestApplication();

service = moduleFixture.get<CustomEntityService>(CustomEntityService);
await Promise.all(['name1', 'name2'].map((name: string) => service.repository.save(service.repository.create({ name }))));
await service.repository.save(['name1', 'name2'].map((name: string) => service.repository.create({ name })));

await app.init();
});
Expand Down
6 changes: 2 additions & 4 deletions spec/custom-entity/custom-entity.controller.search.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,8 @@ describe('CustomEntity - Search', () => {
app = moduleFixture.createNestApplication();

service = moduleFixture.get<CustomEntityService>(CustomEntityService);
await Promise.all(
Array.from({ length: 100 }, (_, index) => index).map((number) =>
service.repository.save(service.repository.create({ uuid: `${number}`, name: `name-${number}` })),
),
await service.repository.save(
Array.from({ length: 100 }, (_, index) => index).map((number) => ({ uuid: `${number}`, name: `name-${number}` })),
);

await service.repository.save(service.repository.create({ uuid: 'test' }));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('MultiplePrimaryKey - ReadOne', () => {
app = moduleFixture.createNestApplication();

service = moduleFixture.get<MultiplePrimaryKeyService>(MultiplePrimaryKeyService);
await Promise.all(['name1', 'name2'].map((name: string) => service.repository.save(service.repository.create({ name }))));
await service.repository.save(['name1', 'name2'].map((name: string) => service.repository.create({ name })));

await app.init();
});
Expand Down
12 changes: 2 additions & 10 deletions spec/pagination/pagination.interceptor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,7 @@ describe('Pagination with interceptor', () => {
app = moduleFixture.createNestApplication();

const service: BaseService = moduleFixture.get<BaseService>(BaseService);
await Promise.all(
Array.from({ length: 100 }, (_, index) => index).map((number) =>
service.repository.save(service.repository.create({ name: `name-${number}` })),
),
);
await service.repository.save(Array.from({ length: 100 }, (_, index) => index).map((number) => ({ name: `name-${number}` })));
await app.init();
});

Expand Down Expand Up @@ -141,11 +137,7 @@ describe('Pagination with interceptor', () => {
app = moduleFixture.createNestApplication();

const service: BaseService = moduleFixture.get<BaseService>(BaseService);
await Promise.all(
Array.from({ length: 100 }, (_, index) => index).map((number) =>
service.repository.save(service.repository.create({ name: `name-${number}` })),
),
);
await service.repository.save(Array.from({ length: 100 }, (_, index) => index).map((number) => ({ name: `name-${number}` })));
await app.init();
});

Expand Down
6 changes: 2 additions & 4 deletions spec/pagination/pagination.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,8 @@ describe('Pagination', () => {

beforeEach(async () => {
await service.repository.delete({});
await Promise.all(
Array.from({ length: totalCount }, (_, index) => index).map((number) =>
service.repository.save(service.repository.create({ name: `name-${number}` })),
),
await service.repository.save(
Array.from({ length: totalCount }, (_, index) => index).map((number) => ({ name: `name-${number}` })),
);
});

Expand Down
7 changes: 1 addition & 6 deletions spec/read-many/read-many.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,7 @@ describe('ReadMany - Options', () => {
app = moduleFixture.createNestApplication();

service = moduleFixture.get<BaseService>(BaseService);
await Promise.all(
Array.from({ length: 100 }, (_, index) => index).map((number) =>
service.repository.save(service.repository.create({ name: `name-${number}` })),
),
);

await service.repository.save(Array.from({ length: 100 }, (_, index) => index).map((number) => ({ name: `name-${number}` })));
await app.init();
});

Expand Down
2 changes: 1 addition & 1 deletion spec/response-interceptor/response-interceptor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('Response Interceptor', () => {
app = moduleFixture.createNestApplication();

service = moduleFixture.get<BaseService>(BaseService);
await Promise.all(['name1', 'name2'].map((name: string) => service.repository.save(service.repository.create({ name }))));
await service.repository.save(['name1', 'name2'].map((name: string) => service.repository.create({ name })));

await app.init();
});
Expand Down
10 changes: 4 additions & 6 deletions spec/search/search-cursor-pagination.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,14 @@ describe('Search Cursor Pagination', () => {
* - when index is [0-24], it has [50-26]
* - when index is [25-49], is has null
*/
await Promise.all(
await service.repository.save(
Array.from({ length: 25 }, (_, index) => index).map((no: number) =>
service.repository.save(
service.repository.create({ col1: `col${no % 2 === 0 ? '0' : '1'}_${no}`, col2: no, col3: 50 - no }),
),
service.repository.create({ col1: `col${no % 2 === 0 ? '0' : '1'}_${no}`, col2: no, col3: 50 - no }),
),
);
await Promise.all(
await service.repository.save(
Array.from({ length: 25 }, (_, index) => index + 25).map((no: number) =>
service.repository.save(service.repository.create({ col1: `col${no % 2 === 0 ? '0' : '1'}_${no}`, col2: no })),
service.repository.create({ col1: `col${no % 2 === 0 ? '0' : '1'}_${no}`, col2: no }),
),
);
expect(await TestEntity.count()).toEqual(50);
Expand Down
10 changes: 4 additions & 6 deletions spec/search/search-query-operator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,14 @@ describe('Search Query Operator', () => {
* - when index is [0-4], it has [10-6]
* - when index is [5-9], is has null
*/
await Promise.all(
await service.repository.save(
Array.from({ length: 5 }, (_, index) => index).map((no: number) =>
service.repository.save(
service.repository.create({ col1: `col${no % 2 === 0 ? '0' : '1'}_${no}`, col2: no, col3: 10 - no }),
),
service.repository.create({ col1: `col${no % 2 === 0 ? '0' : '1'}_${no}`, col2: no, col3: 10 - no }),
),
);
await Promise.all(
await service.repository.save(
Array.from({ length: 5 }, (_, index) => index + 5).map((no: number) =>
service.repository.save(service.repository.create({ col1: `col${no % 2 === 0 ? '0' : '1'}_${no}`, col2: no })),
service.repository.create({ col1: `col${no % 2 === 0 ? '0' : '1'}_${no}`, col2: no }),
),
);

Expand Down
4 changes: 4 additions & 0 deletions src/lib/abstract/abstract.pagination.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { AbstractPaginationRequest } from './abstract.pagination';
import { PaginationResponse } from '../interface';

describe('AbstractPaginationRequest', () => {
class PaginationRequest extends AbstractPaginationRequest {
nextTotal(_dataLength?: number | undefined): number {
throw new Error('Method not implemented.');
}
metadata<T>(_take: number, _dataLength: number, _total: number, _nextCursor: string): PaginationResponse<T>['metadata'] {
throw new Error('Method not implemented.');
}
}
it('should do nothing when where is undefined', () => {
const paginationRequest = new PaginationRequest();
Expand Down
3 changes: 2 additions & 1 deletion src/lib/abstract/abstract.pagination.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Expose } from 'class-transformer';
import { IsString, IsOptional } from 'class-validator';

import { PaginationType } from '../interface';
import { PaginationResponse, PaginationType } from '../interface';

interface PaginationQuery {
where: string;
Expand Down Expand Up @@ -74,4 +74,5 @@ export abstract class AbstractPaginationRequest {
}

abstract nextTotal(dataLength?: number): number;
abstract metadata<T>(take: number, dataLength: number, total: number, nextCursor: string): PaginationResponse<T>['metadata'];
}
10 changes: 9 additions & 1 deletion src/lib/dto/pagination-cursor.dto.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import { AbstractPaginationRequest } from '../abstract';
import { PaginationType } from '../interface';
import { CursorPaginationResponse, PaginationType } from '../interface';

export class PaginationCursorDto extends AbstractPaginationRequest {
type: PaginationType.CURSOR = PaginationType.CURSOR;

nextTotal(dataLength: number): number {
return this.total - dataLength;
}

metadata<T>(take: number, _dataLength: number, total: number, nextCursor: string): CursorPaginationResponse<T>['metadata'] {
return {
limit: take,
total,
nextCursor: this.makeQuery(total, nextCursor),
};
}
}
12 changes: 11 additions & 1 deletion src/lib/dto/pagination-offset.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Expose, Transform, Type } from 'class-transformer';
import { IsNumber, IsOptional, IsPositive, Max } from 'class-validator';

import { AbstractPaginationRequest } from '../abstract';
import { PaginationType } from '../interface';
import { OffsetPaginationResponse, PaginationType } from '../interface';

export class PaginationOffsetDto extends AbstractPaginationRequest {
type: PaginationType.OFFSET = PaginationType.OFFSET;
Expand All @@ -24,4 +24,14 @@ export class PaginationOffsetDto extends AbstractPaginationRequest {
nextTotal(): number {
return this.total;
}

metadata<T>(take: number, dataLength: number, total: number, nextCursor: string): OffsetPaginationResponse<T>['metadata'] {
return {
page: this.offset ? Math.floor(this.offset / take) + 1 : 1,
pages: total ? Math.ceil(total / take) : 1,
offset: (this.offset ?? 0) + dataLength,
total,
nextCursor: this.makeQuery(total, nextCursor),
};
}
}
18 changes: 5 additions & 13 deletions src/lib/request/read-many.request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,32 +111,24 @@ export class CrudReadManyRequest<T> {
}

toResponse(data: T[], total: number): PaginationResponse<T> {
const take = this.findOptions.take;
const dataLength = data.length;
const nextCursor = PaginationHelper.serialize(
_.pick(
data.at(-1),
this.primaryKeys.map(({ name }) => name),
) as FindOptionsWhere<T>,
);

if (this.pagination.type === PaginationType.OFFSET) {
return {
data,
metadata: {
page: this.pagination.offset ? Math.floor(this.pagination.offset / this.findOptions.take) + 1 : 1,
pages: total ? Math.ceil(total / this.findOptions.take) : 1,
offset: (this.pagination.offset ?? 0) + data.length,
total,
nextCursor: this.pagination.makeQuery(total, nextCursor),
},
metadata: this.pagination.metadata(take, dataLength, total, nextCursor),
};
}

return {
data,
metadata: {
limit: this.findOptions.take,
total,
nextCursor: this.pagination.makeQuery(total, nextCursor),
},
metadata: this.pagination.metadata(take, dataLength, total, nextCursor),
};
}
}

0 comments on commit d1c5456

Please sign in to comment.