Skip to content

Commit

Permalink
feat: modified to filter items based on options in request when nextC…
Browse files Browse the repository at this point in the history
…ursor is invalid (#557)
  • Loading branch information
JadenKim-dev authored Jun 4, 2024
1 parent c4bdc12 commit 9569af9
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 21 deletions.
63 changes: 63 additions & 0 deletions spec/pagination/pagination.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,37 @@ describe('Pagination', () => {
expect(lastOneOfFirstResponse.type).toEqual(0);
expect(firstOneOfNextResponse.type).toEqual(1);
});

it('should return items queried based on request when nextCursor is invalid', async () => {
// readMany
const { body: responseBody } = await request(app.getHttpServer())
.get(`/${PaginationType.CURSOR}`)
.query({
type: 1,
nextCursor: 'invalid',
})
.expect(HttpStatus.OK);

expect(responseBody.data).toHaveLength(20);
expect(responseBody.metadata).toEqual({
nextCursor: expect.any(String),
limit: 20,
total: 50,
});

// search
const { body: searchResponseBody } = await request(app.getHttpServer())
.post(`/${PaginationType.CURSOR}/search`)
.send({ where: [{ type: { operator: '=', operand: 1 } }], nextCursor: 'invalid' })
.expect(HttpStatus.OK);

expect(searchResponseBody.data).toHaveLength(20);
expect(searchResponseBody.metadata).toEqual({
nextCursor: expect.any(String),
limit: 20,
total: 50,
});
});
});

describe('Offset', () => {
Expand Down Expand Up @@ -536,5 +567,37 @@ describe('Pagination', () => {
expect(lastOneOfFirstResponse.type).toEqual(0);
expect(firstOneOfNextResponse.type).toEqual(1);
});

it('should return items queried based on request when nextCursor is invalid', async () => {
// readMany
const { body: readManyResponseBody } = await request(app.getHttpServer())
.get(`/${PaginationType.OFFSET}`)
.query({
nextCursor: 'invalid',
type: 1,
})
.expect(HttpStatus.OK);

expect(readManyResponseBody.metadata).toEqual({
page: 1,
pages: 3,
total: 50,
offset: 20,
nextCursor: expect.any(String),
});

// search
const { body: searchResponseBody } = await request(app.getHttpServer())
.post(`/${PaginationType.OFFSET}/search`)
.send({ where: [{ type: { operator: '=', operand: 1 } }], nextCursor: 'invalid' })
.expect(HttpStatus.OK);
expect(searchResponseBody.metadata).toEqual({
page: 1,
pages: 3,
total: 50,
offset: 20,
nextCursor: expect.any(String),
});
});
});
});
3 changes: 2 additions & 1 deletion src/lib/abstract/abstract.pagination.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ describe('AbstractPaginationRequest', () => {

it('should do nothing when query is invalid', () => {
const paginationRequest = new PaginationRequest();
paginationRequest.setQuery('invalid');
const isQueryValid = paginationRequest.setQuery('invalid');
expect(isQueryValid).toEqual(false);
expect(paginationRequest.isNext).toBeFalsy();
});
});
28 changes: 18 additions & 10 deletions src/lib/abstract/abstract.pagination.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,25 @@ export abstract class AbstractPaginationRequest {
).toString(encoding);
}

setQuery(query: string): void {
try {
const paginationType: PaginationQuery = JSON.parse(Buffer.from(query, encoding).toString());
this._where = paginationType.where;
this._total = paginationType.total;
this._nextCursor = paginationType.nextCursor;

this._isNext = true;
} catch {
//
setQuery(query: string): boolean {
const paginationQuery: PaginationQuery | null = (() => {
try {
return JSON.parse(Buffer.from(query, encoding).toString());
} catch {
return null;
}
})();
if (paginationQuery == null) {
return false;
}

this._where = paginationQuery.where;
this._total = paginationQuery.total;
this._nextCursor = paginationQuery.nextCursor;

this._isNext = true;

return true;
}

protected get total(): number {
Expand Down
2 changes: 1 addition & 1 deletion src/lib/abstract/abstract.request.interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export abstract class RequestAbstractInterceptor {
crudOptions: CrudOptions,
method: Exclude<Method, Method.READ_MANY | Method.READ_ONE | Method.SEARCH>,
): Author | undefined {
const author = crudOptions?.routes?.[method]?.author;
const author = crudOptions.routes?.[method]?.author;

if (!author) {
return;
Expand Down
7 changes: 2 additions & 5 deletions src/lib/dto/request-search.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Sort } from '../interface';
import { QueryFilter, operators } from '../interface/query-operation.interface';

export class RequestSearchDto<T> {
@ApiPropertyOptional({ description: 'select fields', isArray: true, type: [String] })
@ApiPropertyOptional({ description: 'select fields', isArray: true, type: String })
select?: Array<keyof Partial<T>>;

@ApiPropertyOptional({
Expand Down Expand Up @@ -39,12 +39,9 @@ export class RequestSearchDto<T> {
@ApiPropertyOptional({ description: 'withDeleted', type: Boolean })
withDeleted?: boolean;

@ApiPropertyOptional({ description: 'take', type: Number })
@ApiPropertyOptional({ description: 'take', type: Number, example: 20 })
take?: number;

@ApiPropertyOptional({ description: 'Use to search the next page', type: String })
nextCursor?: string;

@ApiPropertyOptional({ description: 'Use to search the next page under the same conditions', type: String })
query?: string;
}
9 changes: 7 additions & 2 deletions src/lib/interceptor/read-many-request.interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@ export function ReadManyRequestInterceptor(crudOptions: CrudOptions, factoryOpti

const query = await (async () => {
if (PaginationHelper.isNextPage(pagination)) {
pagination.setQuery(pagination.query ?? btoa('{}'));
return {};
const isQueryValid = pagination.setQuery(pagination.query);
if (isQueryValid) {
return {};
}
}
const query = await this.validateQuery(req.query);
pagination.setWhere(PaginationHelper.serialize(query));
Expand Down Expand Up @@ -83,6 +85,9 @@ export function ReadManyRequestInterceptor(crudOptions: CrudOptions, factoryOpti
if ('offset' in query) {
delete query.offset;
}
if ('nextCursor' in query) {
delete query.nextCursor;
}

const transformed = plainToInstance(crudOptions.entity as ClassConstructor<EntityType>, query, {
groups: [GROUP.READ_MANY],
Expand Down
6 changes: 4 additions & 2 deletions src/lib/interceptor/search-request.interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,10 @@ export function SearchRequestInterceptor(crudOptions: CrudOptions, factoryOption

const requestSearchDto = await (async () => {
if (isNextPage) {
pagination.setQuery(pagination.query ?? btoa('{}'));
return PaginationHelper.deserialize<RequestSearchDto<EntityType>>(pagination.where);
const isQueryValid = pagination.setQuery(pagination.query);
if (isQueryValid) {
return PaginationHelper.deserialize<RequestSearchDto<EntityType>>(pagination.where);
}
}
const searchBody = await this.validateBody(req.body);
pagination.setWhere(PaginationHelper.serialize((searchBody ?? {}) as FindOptionsWhere<typeof crudOptions.entity>));
Expand Down

0 comments on commit 9569af9

Please sign in to comment.