UNPKG

nestjs-paginate

Version:

Pagination and filtering helper method for TypeORM repositories or query builders using Nest.js framework.

321 lines 16.3 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); const common_1 = require("@nestjs/common"); const swagger_1 = require("@nestjs/swagger"); const paginate_1 = require("../paginate"); const testing_1 = require("@nestjs/testing"); const api_paginated_swagger_docs_decorator_1 = require("./api-paginated-swagger-docs.decorator"); const api_paginated_query_decorator_1 = require("./api-paginated-query.decorator"); const api_ok_paginated_response_decorator_1 = require("./api-ok-paginated-response.decorator"); const fs = require("node:fs"); const path = require("node:path"); const BASE_PAGINATION_CONFIG = { sortableColumns: ['id'], }; const FULL_CONFIG = Object.assign(Object.assign({}, BASE_PAGINATION_CONFIG), { defaultSortBy: [['id', 'DESC']], defaultLimit: 20, maxLimit: 100, filterableColumns: { id: true, name: [paginate_1.FilterOperator.EQ, paginate_1.FilterSuffix.NOT], }, searchableColumns: ['name'], select: ['id', 'name'] }); class TestDto { } // eslint-disable-next-line @typescript-eslint/ban-types async function getSwaggerDefinitionForEndpoint(entityType, config) { class TestController { test() { // } testReferenced() { // } testPost() { // } } __decorate([ (0, api_paginated_swagger_docs_decorator_1.PaginatedSwaggerDocs)(entityType, config), (0, common_1.Get)('/test'), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", void 0) ], TestController.prototype, "test", null); __decorate([ (0, api_paginated_query_decorator_1.ApiPaginationQuery)(config), (0, api_paginated_swagger_docs_decorator_1.PaginatedSwaggerDocs)('TestDto', config), (0, common_1.Get)('/test-referenced'), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", void 0) ], TestController.prototype, "testReferenced", null); __decorate([ (0, api_paginated_query_decorator_1.ApiPaginationQuery)(config), (0, api_ok_paginated_response_decorator_1.ApiOkPaginatedResponse)(entityType, config), (0, common_1.Post)('/test'), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", void 0) ], TestController.prototype, "testPost", null); const fakeAppModule = await testing_1.Test.createTestingModule({ controllers: [TestController], }).compile(); const fakeApp = fakeAppModule.createNestApplication(); return swagger_1.SwaggerModule.createDocument(fakeApp, new swagger_1.DocumentBuilder().build()); } describe('PaginatedEndpoint decorator', () => { it('post and get definition should be the same', async () => { const openApiDefinition = await getSwaggerDefinitionForEndpoint(TestDto, BASE_PAGINATION_CONFIG); const testGetParams = openApiDefinition.paths['/test'].get.parameters; expect(openApiDefinition.paths['/test-referenced'].get.parameters).toStrictEqual(testGetParams); expect(openApiDefinition.paths['/test'].post.parameters).toStrictEqual(testGetParams); }); it.each(['/test', '/test-referenced'])('should annotate endpoint with OpenApi documentation with limited config', async (endpoint) => { const openApiDefinition = await getSwaggerDefinitionForEndpoint(TestDto, BASE_PAGINATION_CONFIG); const params = openApiDefinition.paths[endpoint].get.parameters; expect(params).toStrictEqual([ { name: 'page', required: false, in: 'query', description: 'Page number to retrieve. If you provide invalid value the default page number will applied\n\n**Example:** 1\n\n\n**Default Value:** 1\n\n', schema: { type: 'number', }, }, { name: 'limit', required: false, in: 'query', description: 'Number of records per page.\n\n\n**Example:** 20\n\n\n\n**Default Value:** 20\n\n\n\n**Max Value:** 100\n\n\nIf provided value is greater than max value, max value will be applied.\n', schema: { type: 'number', }, }, { name: 'sortBy', required: false, in: 'query', description: 'Parameter to sort by.\nTo sort by multiple fields, just provide query param multiple types. The order in url defines an order of sorting\n\n**Format:** {fieldName}:{DIRECTION}\n\n\n**Example:** sortBy=id:DESC\n\n\n**Default Value:** No default sorting specified, the result order is not guaranteed if not provided\n\n**Available Fields**\n- id\n', schema: { type: 'array', items: { type: 'string', enum: ['id:ASC', 'id:DESC'], }, }, }, ]); expect(openApiDefinition.paths[endpoint].get.responses).toEqual({ '200': { description: '', content: { 'application/json': { schema: { allOf: [ { $ref: '#/components/schemas/PaginatedDocumented', }, { properties: { data: { type: 'array', items: { $ref: '#/components/schemas/TestDto', }, }, meta: { properties: { select: { type: 'array', items: { type: 'string', }, }, filter: { type: 'object', properties: {}, }, }, }, }, }, ], }, }, }, }, }); }); it.each(['/test', '/test-referenced'])('should annotate endpoint with OpenApi documentation with full config', async (endpoint) => { const openApiDefinition = await getSwaggerDefinitionForEndpoint(TestDto, FULL_CONFIG); const params = openApiDefinition.paths[endpoint].get.parameters; expect(params).toStrictEqual([ { name: 'page', required: false, in: 'query', description: 'Page number to retrieve. If you provide invalid value the default page number will applied\n\n**Example:** 1\n\n\n**Default Value:** 1\n\n', schema: { type: 'number', }, }, { name: 'limit', required: false, in: 'query', description: 'Number of records per page.\n\n\n**Example:** 20\n\n\n\n**Default Value:** 20\n\n\n\n**Max Value:** 100\n\n\nIf provided value is greater than max value, max value will be applied.\n', schema: { type: 'number', }, }, { name: 'filter.id', required: false, in: 'query', description: 'Filter by id query param.\n\n**Format:** filter.id={$not}:OPERATION:VALUE\n\n\n\n**Example:** filter.id=$btw:John Doe&filter.id=$contains:John Doe\n\n**Available Operations**\n- $eq\n\n- $gt\n\n- $gte\n\n- $in\n\n- $null\n\n- $lt\n\n- $lte\n\n- $btw\n\n- $ilike\n\n- $sw\n\n- $contains\n\n- $not\n\n- $and\n\n- $or', schema: { type: 'array', items: { type: 'string', }, }, }, { name: 'filter.name', required: false, in: 'query', description: 'Filter by name query param.\n\n**Format:** filter.name={$not}:OPERATION:VALUE\n\n\n\n**Example:** filter.name=$eq:John Doe\n\n**Available Operations**\n- $eq\n\n- $not\n\n- $and\n\n- $or', schema: { type: 'array', items: { type: 'string', }, }, }, { name: 'sortBy', required: false, in: 'query', description: 'Parameter to sort by.\nTo sort by multiple fields, just provide query param multiple types. The order in url defines an order of sorting\n\n**Format:** {fieldName}:{DIRECTION}\n\n\n**Example:** sortBy=id:DESC\n\n\n**Default Value:** id:DESC\n\n**Available Fields**\n- id\n', schema: { type: 'array', items: { type: 'string', enum: ['id:ASC', 'id:DESC'], }, }, }, { name: 'search', required: false, in: 'query', description: 'Search term to filter result values\n\n**Example:** John\n\n\n**Default Value:** No default value\n\n', schema: { type: 'string', }, }, { name: 'searchBy', required: false, in: 'query', description: 'List of fields to search by term to filter result values\n\n**Example:** name\n\n\n**Default Value:** By default all fields mentioned below will be used to search by term\n\n**Available Fields**\n- name\n', schema: { type: 'array', items: { type: 'string', }, }, }, { name: 'select', required: false, in: 'query', description: 'List of fields to select.\n\n**Example:** id,name\n\n\n**Default Value:** By default all fields returns. If you want to select only some fields, provide them in query param\n\n', schema: { type: 'string', }, }, ]); expect(openApiDefinition.paths[endpoint].get.responses).toEqual({ '200': { description: '', content: { 'application/json': { schema: { allOf: [ { $ref: '#/components/schemas/PaginatedDocumented', }, { properties: { data: { type: 'array', items: { $ref: '#/components/schemas/TestDto', }, }, meta: { properties: { select: { type: 'array', items: { type: 'string', enum: ['id', 'name'], }, }, filter: { type: 'object', properties: { id: { oneOf: [ { type: 'string', }, { type: 'array', items: { type: 'string', }, }, ], }, name: { oneOf: [ { type: 'string', }, { type: 'array', items: { type: 'string', }, }, ], }, }, }, }, }, }, }, ], }, }, }, }, }); }); it('should match a base config, snapshot test for all config', async () => { const openApiDefinition = await getSwaggerDefinitionForEndpoint(TestDto, FULL_CONFIG); const fullOpenApiDefinition = JSON.parse(fs.readFileSync(path.join(__dirname, 'resources/full-openapi-definition.json')).toString('utf-8')); expect(openApiDefinition).toStrictEqual(fullOpenApiDefinition); }); }); //# sourceMappingURL=pagination-docs.spec.js.map