@impactor/nest 3.0.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -6
- package/index.d.ts +41 -40
- package/package.json +31 -33
- package/src/configs/app.d.ts +7 -4
- package/src/configs/app.js +11 -18
- package/src/configs/app.js.map +1 -1
- package/src/configs/database.js +1 -11
- package/src/configs/database.js.map +1 -1
- package/src/configs/microservice.js +6 -16
- package/src/configs/microservice.js.map +1 -1
- package/src/configs/multi-queue-rabbitmq-server.js +28 -34
- package/src/configs/multi-queue-rabbitmq-server.js.map +1 -1
- package/src/configs/redis-config.js +1 -11
- package/src/configs/redis-config.js.map +1 -1
- package/src/create-app.d.ts +1 -1
- package/src/create-app.js +47 -55
- package/src/create-app.js.map +1 -1
- package/src/create-microservice.d.ts +1 -1
- package/src/create-microservice.js +18 -22
- package/src/create-microservice.js.map +1 -1
- package/src/create-testing-microservice.d.ts +1 -1
- package/src/create-testing-microservice.js +16 -20
- package/src/create-testing-microservice.js.map +1 -1
- package/src/decorators/controller/add-decorators/add-controller-path.d.ts +1 -1
- package/src/decorators/controller/add-decorators/add-controller-path.js +7 -15
- package/src/decorators/controller/add-decorators/add-controller-path.js.map +1 -1
- package/src/decorators/controller/add-decorators/add-controller-tags.d.ts +1 -1
- package/src/decorators/controller/add-decorators/add-controller-tags.js +9 -17
- package/src/decorators/controller/add-decorators/add-controller-tags.js.map +1 -1
- package/src/decorators/controller/add-decorators/add-http-method.d.ts +2 -2
- package/src/decorators/controller/add-decorators/add-http-method.js +13 -20
- package/src/decorators/controller/add-decorators/add-http-method.js.map +1 -1
- package/src/decorators/controller/add-decorators/add-swagger-body.d.ts +2 -2
- package/src/decorators/controller/add-decorators/add-swagger-body.js +7 -17
- package/src/decorators/controller/add-decorators/add-swagger-body.js.map +1 -1
- package/src/decorators/controller/add-decorators/add-swagger-operation.d.ts +2 -2
- package/src/decorators/controller/add-decorators/add-swagger-operation.js +8 -15
- package/src/decorators/controller/add-decorators/add-swagger-operation.js.map +1 -1
- package/src/decorators/controller/add-decorators/add-swagger-params.d.ts +2 -2
- package/src/decorators/controller/add-decorators/add-swagger-params.js +9 -16
- package/src/decorators/controller/add-decorators/add-swagger-params.js.map +1 -1
- package/src/decorators/controller/add-decorators/add-swagger-response.d.ts +2 -2
- package/src/decorators/controller/add-decorators/add-swagger-response.js +10 -20
- package/src/decorators/controller/add-decorators/add-swagger-response.js.map +1 -1
- package/src/decorators/controller/controller.decorator.d.ts +1 -1
- package/src/decorators/controller/controller.decorator.js +12 -13
- package/src/decorators/controller/controller.decorator.js.map +1 -1
- package/src/decorators/controller/controller.factory.d.ts +1 -1
- package/src/decorators/controller/controller.factory.js +59 -67
- package/src/decorators/controller/controller.factory.js.map +1 -1
- package/src/decorators/controller/default-options.d.ts +1 -1
- package/src/decorators/controller/default-options.js +11 -26
- package/src/decorators/controller/default-options.js.map +1 -1
- package/src/decorators/controller/dto/empty.dto.js +2 -12
- package/src/decorators/controller/dto/empty.dto.js.map +1 -1
- package/src/decorators/controller/dto/update-response.dto.js +2 -12
- package/src/decorators/controller/dto/update-response.dto.js.map +1 -1
- package/src/decorators/controller/interceptors/query.interceptor.d.ts +1 -1
- package/src/decorators/controller/interceptors/query.interceptor.js +10 -19
- package/src/decorators/controller/interceptors/query.interceptor.js.map +1 -1
- package/src/decorators/controller/route-handler.d.ts +2 -2
- package/src/decorators/controller/route-handler.js +8 -16
- package/src/decorators/controller/route-handler.js.map +1 -1
- package/src/decorators/controller/route.decorator.d.ts +1 -1
- package/src/decorators/controller/route.decorator.js +11 -11
- package/src/decorators/controller/route.decorator.js.map +1 -1
- package/src/decorators/controller/services/crud-typeorm.service.d.ts +1 -2
- package/src/decorators/controller/services/crud-typeorm.service.js +19 -24
- package/src/decorators/controller/services/crud-typeorm.service.js.map +1 -1
- package/src/decorators/controller/types/index.d.ts +2 -2
- package/src/decorators/controller/types/index.js +1 -4
- package/src/decorators/controller/types/index.js.map +1 -1
- package/src/decorators/controller/utils/merge-options.d.ts +1 -1
- package/src/decorators/controller/utils/merge-options.js +3 -13
- package/src/decorators/controller/utils/merge-options.js.map +1 -1
- package/src/decorators/controller/utils/reflect.d.ts +2 -2
- package/src/decorators/controller/utils/reflect.js +24 -38
- package/src/decorators/controller/utils/reflect.js.map +1 -1
- package/src/decorators/entity.decorator.d.ts +6 -0
- package/src/decorators/entity.decorator.js +73 -0
- package/src/decorators/entity.decorator.js.map +1 -0
- package/src/decorators/prop.decorator.js +79 -38
- package/src/decorators/prop.decorator.js.map +1 -1
- package/src/exceptions/rpc-bad-request.exception.d.ts +1 -1
- package/src/exceptions/rpc-bad-request.exception.js +5 -15
- package/src/exceptions/rpc-bad-request.exception.js.map +1 -1
- package/src/exceptions/rpc-base.exception.js +10 -15
- package/src/exceptions/rpc-base.exception.js.map +1 -1
- package/src/exceptions/rpc-conflict.exception.d.ts +1 -1
- package/src/exceptions/rpc-conflict.exception.js +5 -15
- package/src/exceptions/rpc-conflict.exception.js.map +1 -1
- package/src/exceptions/rpc-internal-server-error.exception.d.ts +1 -1
- package/src/exceptions/rpc-internal-server-error.exception.js +5 -15
- package/src/exceptions/rpc-internal-server-error.exception.js.map +1 -1
- package/src/exceptions/rpc-method-not-allowed.exception.d.ts +1 -1
- package/src/exceptions/rpc-method-not-allowed.exception.js +5 -15
- package/src/exceptions/rpc-method-not-allowed.exception.js.map +1 -1
- package/src/exceptions/rpc-not-found.exception.d.ts +1 -1
- package/src/exceptions/rpc-not-found.exception.js +5 -15
- package/src/exceptions/rpc-not-found.exception.js.map +1 -1
- package/src/exceptions/rpc-not-implemented.exception.d.ts +1 -1
- package/src/exceptions/rpc-not-implemented.exception.js +5 -15
- package/src/exceptions/rpc-not-implemented.exception.js.map +1 -1
- package/src/exceptions/rpc-unauthorized.exception.d.ts +1 -1
- package/src/exceptions/rpc-unauthorized.exception.js +5 -15
- package/src/exceptions/rpc-unauthorized.exception.js.map +1 -1
- package/src/filters/error-to-rpc-exception.filter.js +12 -22
- package/src/filters/error-to-rpc-exception.filter.js.map +1 -1
- package/src/filters/error-to-ws-exception.filter.js +10 -20
- package/src/filters/error-to-ws-exception.filter.js.map +1 -1
- package/src/filters/typeorm-exception.filter.js +9 -19
- package/src/filters/typeorm-exception.filter.js.map +1 -1
- package/src/filters/ws-exception.filter.js +6 -16
- package/src/filters/ws-exception.filter.js.map +1 -1
- package/src/generate-metadata.d.ts +3 -3
- package/src/generate-metadata.js +18 -74
- package/src/generate-metadata.js.map +1 -1
- package/src/guards/auth.guard.js +43 -44
- package/src/guards/auth.guard.js.map +1 -1
- package/src/modules/basic/basic.controller.js +6 -16
- package/src/modules/basic/basic.controller.js.map +1 -1
- package/src/modules/basic/basic.module.js +15 -23
- package/src/modules/basic/basic.module.js.map +1 -1
- package/src/modules/basic/basic.service.js +4 -14
- package/src/modules/basic/basic.service.js.map +1 -1
- package/src/register-entities.d.ts +1 -0
- package/src/register-entities.js +135 -0
- package/src/register-entities.js.map +1 -0
- package/src/utils/logger.js +2 -12
- package/src/utils/logger.js.map +1 -1
- package/src/utils/typeorm-to-swagger.d.ts +3 -0
- package/src/utils/typeorm-to-swagger.js +308 -0
- package/src/utils/typeorm-to-swagger.js.map +1 -0
- package/nx.json +0 -190
- package/src/nest-swagger-metadata.js +0 -553
- package/src/nest-swagger-metadata.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/decorators/controller/default-options.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport { UpdateResponseDto } from './dto/update-response.dto';\nimport type { InitControllerOptions } from './types';\n// todo: add opts.maxTake to limit ?take=\n\n/**\n * the default options for \\@Controller()\n */\nexport const defaultOptions: Partial<InitControllerOptions> = {\n // todo: allow sub routes, such as `/:field`\n routes: [\n {\n httpMethod: 'GET',\n // todo: `retrieve a single ${entity.name || \"record\"}`\n summary: 'retrieve a single record',\n },\n {\n httpMethod: 'GET',\n many: true,\n // todo: change to \"retrieve multiple $entity records\"\n summary: 'retrieve multiple records',\n description:\n 'see <a href=\"https://typeorm.io/docs/working-with-entity-manager/find-options\" target=\"_blank\">TypeOrm find options</a>',\n },\n {\n httpMethod: 'POST',\n summary: 'create a single or multiple records',\n },\n {\n httpMethod: 'PATCH',\n summary: 'update a single record by primary key',\n // todo: this causes an error in swagger UI\n // `swagger-ui-init.js:1597 Uncaught ReferenceError: __name is not defined`\n // https://chat.deepseek.com/a/chat/s/e76e6f76-1a5e-4c49-a63f-6d44ce619906\n // responseModel: UpdateResponseDto,\n },\n {\n httpMethod: 'PATCH',\n summary: 'update multiple records',\n many: true,\n // responseModel: UpdateResponseDto,\n },\n {\n httpMethod: 'PUT',\n summary: 'replace a single record',\n // responseModel: UpdateResponseDto,\n },\n {\n httpMethod: 'PUT',\n summary: 'replace multiple records',\n many: true,\n // responseModel: UpdateResponseDto,\n },\n {\n httpMethod: 'DELETE',\n summary: 'delete a record by primary key',\n // responseModel: UpdateResponseDto,\n },\n {\n httpMethod: 'DELETE',\n summary: 'delete multiple records',\n many: true,\n // responseModel: UpdateResponseDto,\n },\n // todo: add update multiple records\n ],\n // query params should be similar to typeOrm methods, such as findOne({relations, withDeleted, ...})\n // so query params should be ?relations&withDeleted\n // https://orkhan.gitbook.io/typeorm/docs/find-options\n queryParams: [\n {\n name: 'take',\n description: 'limit resource count.',\n example: 50,\n many: true,\n httpMethods: ['GET', 'DELETE', 'PATCH', 'PUT'],\n },\n {\n name: 'skip',\n description: 'skip rows.
|
|
1
|
+
{"version":3,"sources":["../../../../src/decorators/controller/default-options.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport { UpdateResponseDto } from './dto/update-response.dto.js';\nimport type { InitControllerOptions } from './types/index.js';\n// todo: add opts.maxTake to limit ?take=\n\n/**\n * the default options for \\@Controller()\n */\nexport const defaultOptions: Partial<InitControllerOptions> = {\n // todo: allow sub routes, such as `/:field`\n routes: [\n {\n httpMethod: 'GET',\n // todo: `retrieve a single ${entity.name || \"record\"}`\n summary: 'retrieve a single record',\n },\n {\n httpMethod: 'GET',\n many: true,\n // todo: change to \"retrieve multiple $entity records\"\n summary: 'retrieve multiple records',\n description:\n 'see <a href=\"https://typeorm.io/docs/working-with-entity-manager/find-options\" target=\"_blank\">TypeOrm find options</a>',\n },\n {\n httpMethod: 'POST',\n summary: 'create a single or multiple records',\n },\n {\n httpMethod: 'PATCH',\n summary: 'update a single record by primary key',\n // todo: this causes an error in swagger UI\n // `swagger-ui-init.js:1597 Uncaught ReferenceError: __name is not defined`\n // https://chat.deepseek.com/a/chat/s/e76e6f76-1a5e-4c49-a63f-6d44ce619906\n // responseModel: UpdateResponseDto,\n },\n {\n httpMethod: 'PATCH',\n summary: 'update multiple records',\n many: true,\n // responseModel: UpdateResponseDto,\n },\n {\n httpMethod: 'PUT',\n summary: 'replace a single record',\n // responseModel: UpdateResponseDto,\n },\n {\n httpMethod: 'PUT',\n summary: 'replace multiple records',\n many: true,\n // responseModel: UpdateResponseDto,\n },\n {\n httpMethod: 'DELETE',\n summary: 'delete a record by primary key',\n // responseModel: UpdateResponseDto,\n },\n {\n httpMethod: 'DELETE',\n summary: 'delete multiple records',\n many: true,\n // responseModel: UpdateResponseDto,\n },\n // todo: add update multiple records\n ],\n // query params should be similar to typeOrm methods, such as findOne({relations, withDeleted, ...})\n // so query params should be ?relations&withDeleted\n // https://orkhan.gitbook.io/typeorm/docs/find-options\n queryParams: [\n {\n name: 'take',\n description: 'limit resource count.',\n example: 50,\n many: true,\n httpMethods: ['GET', 'DELETE', 'PATCH', 'PUT'],\n },\n {\n name: 'skip',\n description: 'skip rows. example: `2`',\n many: true,\n httpMethods: ['GET', 'DELETE', 'PATCH', 'PUT'],\n },\n {\n name: 'select',\n description: `Selects resource fields.`,\n example: ['name', 'email'],\n required: false,\n httpMethods: ['GET'],\n },\n {\n name: 'relations',\n description:\n 'add joined relational objects, supports nested relations. example: `[\"age\", \"user.profile:name\"]`',\n httpMethods: ['GET'],\n },\n {\n name: 'where',\n description:\n 'add where condition. to use sql statement, start the value with `>`.\\n to search in an array column, put the value in an array. see <a href=\"https://orkhan.gitbook.io/typeorm/docs/find-options#advanced-options\" target=\"_blank\">see advanced options</a>\\n example: `{ name: \"john\", email: \">Like \\'%john@%\\'\" }`',\n // when adding an example here, Swagger adds it to the query by default, causing the query to has properties may not be defined in the entity\n // example: { name: 'john', email: \">Like '%john@%'\" },\n many: true,\n httpMethods: ['GET', 'PATCH', 'PUT', 'DELETE'],\n },\n {\n name: 'order',\n // or 'name,id:DESC'\n // example: { name: 'ASC', id: 'DESC' },\n description: \"example: `{ name: 'ASC', id: 'DESC' }`\",\n many: true,\n httpMethods: ['GET', 'PATCH', 'PUT', 'DELETE'],\n },\n {\n name: 'cache',\n description: 'Enables or disables query result caching',\n type: 'boolean',\n httpMethods: ['GET'],\n },\n {\n name: 'withDeleted',\n // todo:\"default:${route.many ? 'false' : 'true'}\"\n description: `include soft deleted records`,\n type: 'boolean',\n httpMethods: ['GET'],\n },\n {\n name: 'softDelete',\n description:\n 'whether to perform a soft or hard delete, the default is true',\n type: 'boolean',\n httpMethods: ['DELETE'],\n },\n {\n name: 'lock',\n description: 'Enables locking mechanism for query',\n httpMethods: ['GET'],\n many: false,\n example: { mode: 'optimistic', version: 1 },\n },\n ],\n serviceName: 'service',\n primaryKey: 'id',\n};\n"],"names":["defaultOptions","routes","httpMethod","summary","many","description","queryParams","name","example","httpMethods","required","type","mode","version","serviceName","primaryKey"],"mappings":"AAAA,6DAA6D;AAG7D,yCAAyC;AAEzC;;CAEC,GACD,OAAO,MAAMA,iBAAiD;IAC5D,4CAA4C;IAC5CC,QAAQ;QACN;YACEC,YAAY;YACZ,uDAAuD;YACvDC,SAAS;QACX;QACA;YACED,YAAY;YACZE,MAAM;YACN,sDAAsD;YACtDD,SAAS;YACTE,aACE;QACJ;QACA;YACEH,YAAY;YACZC,SAAS;QACX;QACA;YACED,YAAY;YACZC,SAAS;QAKX;QACA;YACED,YAAY;YACZC,SAAS;YACTC,MAAM;QAER;QACA;YACEF,YAAY;YACZC,SAAS;QAEX;QACA;YACED,YAAY;YACZC,SAAS;YACTC,MAAM;QAER;QACA;YACEF,YAAY;YACZC,SAAS;QAEX;QACA;YACED,YAAY;YACZC,SAAS;YACTC,MAAM;QAER;KAED;IACD,oGAAoG;IACpG,mDAAmD;IACnD,sDAAsD;IACtDE,aAAa;QACX;YACEC,MAAM;YACNF,aAAa;YACbG,SAAS;YACTJ,MAAM;YACNK,aAAa;gBAAC;gBAAO;gBAAU;gBAAS;aAAM;QAChD;QACA;YACEF,MAAM;YACNF,aAAa;YACbD,MAAM;YACNK,aAAa;gBAAC;gBAAO;gBAAU;gBAAS;aAAM;QAChD;QACA;YACEF,MAAM;YACNF,aAAa,CAAC,wBAAwB,CAAC;YACvCG,SAAS;gBAAC;gBAAQ;aAAQ;YAC1BE,UAAU;YACVD,aAAa;gBAAC;aAAM;QACtB;QACA;YACEF,MAAM;YACNF,aACE;YACFI,aAAa;gBAAC;aAAM;QACtB;QACA;YACEF,MAAM;YACNF,aACE;YACF,6IAA6I;YAC7I,uDAAuD;YACvDD,MAAM;YACNK,aAAa;gBAAC;gBAAO;gBAAS;gBAAO;aAAS;QAChD;QACA;YACEF,MAAM;YACN,oBAAoB;YACpB,wCAAwC;YACxCF,aAAa;YACbD,MAAM;YACNK,aAAa;gBAAC;gBAAO;gBAAS;gBAAO;aAAS;QAChD;QACA;YACEF,MAAM;YACNF,aAAa;YACbM,MAAM;YACNF,aAAa;gBAAC;aAAM;QACtB;QACA;YACEF,MAAM;YACN,kDAAkD;YAClDF,aAAa,CAAC,4BAA4B,CAAC;YAC3CM,MAAM;YACNF,aAAa;gBAAC;aAAM;QACtB;QACA;YACEF,MAAM;YACNF,aACE;YACFM,MAAM;YACNF,aAAa;gBAAC;aAAS;QACzB;QACA;YACEF,MAAM;YACNF,aAAa;YACbI,aAAa;gBAAC;aAAM;YACpBL,MAAM;YACNI,SAAS;gBAAEI,MAAM;gBAAcC,SAAS;YAAE;QAC5C;KACD;IACDC,aAAa;IACbC,YAAY;AACd,EAAE"}
|
|
@@ -2,17 +2,7 @@
|
|
|
2
2
|
* an empty DTO
|
|
3
3
|
* can be used with routes that don't need to receive any data in its body
|
|
4
4
|
* or when the response is intended to be an empty object
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
value: true
|
|
8
|
-
});
|
|
9
|
-
Object.defineProperty(exports, "EmptyDto", {
|
|
10
|
-
enumerable: true,
|
|
11
|
-
get: function() {
|
|
12
|
-
return EmptyDto;
|
|
13
|
-
}
|
|
14
|
-
});
|
|
15
|
-
let EmptyDto = class EmptyDto {
|
|
16
|
-
};
|
|
5
|
+
*/ export class EmptyDto {
|
|
6
|
+
}
|
|
17
7
|
|
|
18
8
|
//# sourceMappingURL=empty.dto.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/decorators/controller/dto/empty.dto.ts"],"sourcesContent":["/**\n * an empty DTO\n * can be used with routes that don't need to receive any data in its body\n * or when the response is intended to be an empty object\n */\nexport class EmptyDto {}\n"],"names":["EmptyDto"],"mappings":"AAAA;;;;CAIC
|
|
1
|
+
{"version":3,"sources":["../../../../../src/decorators/controller/dto/empty.dto.ts"],"sourcesContent":["/**\n * an empty DTO\n * can be used with routes that don't need to receive any data in its body\n * or when the response is intended to be an empty object\n */\nexport class EmptyDto {}\n"],"names":["EmptyDto"],"mappings":"AAAA;;;;CAIC,GACD,OAAO,MAAMA;AAAU"}
|
|
@@ -1,16 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* a Dto for the response of the update or delete query
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
value: true
|
|
6
|
-
});
|
|
7
|
-
Object.defineProperty(exports, "UpdateResponseDto", {
|
|
8
|
-
enumerable: true,
|
|
9
|
-
get: function() {
|
|
10
|
-
return UpdateResponseDto;
|
|
11
|
-
}
|
|
12
|
-
});
|
|
13
|
-
let UpdateResponseDto = class UpdateResponseDto {
|
|
14
|
-
};
|
|
3
|
+
*/ export class UpdateResponseDto {
|
|
4
|
+
}
|
|
15
5
|
|
|
16
6
|
//# sourceMappingURL=update-response.dto.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/decorators/controller/dto/update-response.dto.ts"],"sourcesContent":["/**\n * a Dto for the response of the update or delete query\n */\nexport class UpdateResponseDto {\n /**\n * the total number of the affecter rows\n */\n affected: number;\n}\n"],"names":["UpdateResponseDto"],"mappings":"AAAA;;CAEC
|
|
1
|
+
{"version":3,"sources":["../../../../../src/decorators/controller/dto/update-response.dto.ts"],"sourcesContent":["/**\n * a Dto for the response of the update or delete query\n */\nexport class UpdateResponseDto {\n /**\n * the total number of the affecter rows\n */\n affected: number;\n}\n"],"names":["UpdateResponseDto"],"mappings":"AAAA;;CAEC,GACD,OAAO,MAAMA;AAKb"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ControllerOptions } from '../types';
|
|
1
|
+
import type { ControllerOptions } from '../types/index.js';
|
|
2
2
|
import { type CallHandler, type ExecutionContext, type NestInterceptor } from '@nestjs/common';
|
|
3
3
|
import { Observable } from 'rxjs';
|
|
4
4
|
export declare class QueryInterceptor implements NestInterceptor {
|
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
Object.defineProperty(exports, "QueryInterceptor", {
|
|
6
|
-
enumerable: true,
|
|
7
|
-
get: function() {
|
|
8
|
-
return QueryInterceptor;
|
|
9
|
-
}
|
|
10
|
-
});
|
|
11
|
-
const _common = require("@nestjs/common");
|
|
12
|
-
const _mergeanything = require("merge-anything");
|
|
13
1
|
function _ts_decorate(decorators, target, key, desc) {
|
|
14
2
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
15
3
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -19,7 +7,13 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
19
7
|
function _ts_metadata(k, v) {
|
|
20
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
21
9
|
}
|
|
22
|
-
|
|
10
|
+
import { Injectable } from "@nestjs/common";
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
import { merge } from "merge-anything";
|
|
13
|
+
export class QueryInterceptor {
|
|
14
|
+
constructor(query){
|
|
15
|
+
this.query = query;
|
|
16
|
+
}
|
|
23
17
|
intercept(context, next) {
|
|
24
18
|
let req = context.switchToHttp().getRequest();
|
|
25
19
|
// trying to parse JSON params
|
|
@@ -39,17 +33,14 @@ let QueryInterceptor = class QueryInterceptor {
|
|
|
39
33
|
}
|
|
40
34
|
// req.query is `Empty <[Object: null prototype] {}>` and not merged, but replaces ths.query
|
|
41
35
|
// https://github.com/mesqueeb/merge-anything/issues/48
|
|
42
|
-
req.query =
|
|
36
|
+
req.query = merge(this.query || {}, {
|
|
43
37
|
...req.query
|
|
44
38
|
});
|
|
45
39
|
return next.handle();
|
|
46
40
|
}
|
|
47
|
-
|
|
48
|
-
this.query = query;
|
|
49
|
-
}
|
|
50
|
-
};
|
|
41
|
+
}
|
|
51
42
|
QueryInterceptor = _ts_decorate([
|
|
52
|
-
|
|
43
|
+
Injectable(),
|
|
53
44
|
_ts_metadata("design:type", Function),
|
|
54
45
|
_ts_metadata("design:paramtypes", [
|
|
55
46
|
Object
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/decorators/controller/interceptors/query.interceptor.ts"],"sourcesContent":["import type { ControllerOptions } from '../types';\nimport {\n type CallHandler,\n type ExecutionContext,\n Injectable,\n type NestInterceptor,\n} from '@nestjs/common';\nimport { Observable } from 'rxjs';\n// @ts-ignore\nimport { merge } from 'merge-anything';\n\n/**\n * merge route query with the current request query.\n *\n * this ensures route.query{} is merged to the existing user routes too,\n * not only the routes that are generated by \\@Controller()\n */\n@Injectable()\nexport class QueryInterceptor implements NestInterceptor {\n constructor(private readonly query: ControllerOptions['query']) {}\n\n intercept(context: ExecutionContext, next: CallHandler): Observable<any> {\n let req = context.switchToHttp().getRequest();\n\n // trying to parse JSON params\n // client-side stringify JSON params using JSON.stringify\n // for example `?where=JSON.stringify({field: \"value\"})`\n for (let key in req.query) {\n if (\n typeof req.query[key] === 'string' &&\n ['[', '{'].includes(req.query[key][0])\n ) {\n try {\n req.query[key] = JSON.parse(req.query[key]);\n } catch {\n // keep the value as string as-is\n }\n }\n }\n\n // req.query is `Empty <[Object: null prototype] {}>` and not merged, but replaces ths.query\n // https://github.com/mesqueeb/merge-anything/issues/48\n req.query = merge(this.query || {}, { ...req.query });\n return next.handle();\n }\n}\n"],"names":["QueryInterceptor","intercept","context","next","req","switchToHttp","getRequest","key","
|
|
1
|
+
{"version":3,"sources":["../../../../../src/decorators/controller/interceptors/query.interceptor.ts"],"sourcesContent":["import type { ControllerOptions } from '../types/index.js';\nimport {\n type CallHandler,\n type ExecutionContext,\n Injectable,\n type NestInterceptor,\n} from '@nestjs/common';\nimport { Observable } from 'rxjs';\n// @ts-ignore\nimport { merge } from 'merge-anything';\n\n/**\n * merge route query with the current request query.\n *\n * this ensures route.query{} is merged to the existing user routes too,\n * not only the routes that are generated by \\@Controller()\n */\n@Injectable()\nexport class QueryInterceptor implements NestInterceptor {\n constructor(private readonly query: ControllerOptions['query']) {}\n\n intercept(context: ExecutionContext, next: CallHandler): Observable<any> {\n let req = context.switchToHttp().getRequest();\n\n // trying to parse JSON params\n // client-side stringify JSON params using JSON.stringify\n // for example `?where=JSON.stringify({field: \"value\"})`\n for (let key in req.query) {\n if (\n typeof req.query[key] === 'string' &&\n ['[', '{'].includes(req.query[key][0])\n ) {\n try {\n req.query[key] = JSON.parse(req.query[key]);\n } catch {\n // keep the value as string as-is\n }\n }\n }\n\n // req.query is `Empty <[Object: null prototype] {}>` and not merged, but replaces ths.query\n // https://github.com/mesqueeb/merge-anything/issues/48\n req.query = merge(this.query || {}, { ...req.query });\n return next.handle();\n }\n}\n"],"names":["Injectable","merge","QueryInterceptor","query","intercept","context","next","req","switchToHttp","getRequest","key","includes","JSON","parse","handle"],"mappings":";;;;;;;;;AACA,SAGEA,UAAU,QAEL,iBAAiB;AAExB,aAAa;AACb,SAASC,KAAK,QAAQ,iBAAiB;AASvC,OAAO,MAAMC;IACX,YAAY,AAAiBC,KAAiC,CAAE;aAAnCA,QAAAA;IAAoC;IAEjEC,UAAUC,OAAyB,EAAEC,IAAiB,EAAmB;QACvE,IAAIC,MAAMF,QAAQG,YAAY,GAAGC,UAAU;QAE3C,8BAA8B;QAC9B,yDAAyD;QACzD,wDAAwD;QACxD,IAAK,IAAIC,OAAOH,IAAIJ,KAAK,CAAE;YACzB,IACE,OAAOI,IAAIJ,KAAK,CAACO,IAAI,KAAK,YAC1B;gBAAC;gBAAK;aAAI,CAACC,QAAQ,CAACJ,IAAIJ,KAAK,CAACO,IAAI,CAAC,EAAE,GACrC;gBACA,IAAI;oBACFH,IAAIJ,KAAK,CAACO,IAAI,GAAGE,KAAKC,KAAK,CAACN,IAAIJ,KAAK,CAACO,IAAI;gBAC5C,EAAE,OAAM;gBACN,iCAAiC;gBACnC;YACF;QACF;QAEA,4FAA4F;QAC5F,uDAAuD;QACvDH,IAAIJ,KAAK,GAAGF,MAAM,IAAI,CAACE,KAAK,IAAI,CAAC,GAAG;YAAE,GAAGI,IAAIJ,KAAK;QAAC;QACnD,OAAOG,KAAKQ,MAAM;IACpB;AACF"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { ControllerFactory } from './controller.factory';
|
|
2
|
-
import type { IRoute } from './types';
|
|
1
|
+
import { ControllerFactory } from './controller.factory.js';
|
|
2
|
+
import type { IRoute } from './types/index.js';
|
|
3
3
|
export declare function routeHandler(route: IRoute, factory: ControllerFactory): (req: Request, query: any, ...params: any) => any;
|
|
@@ -1,15 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Object.defineProperty(exports, "routeHandler", {
|
|
6
|
-
enumerable: true,
|
|
7
|
-
get: function() {
|
|
8
|
-
return routeHandler;
|
|
9
|
-
}
|
|
10
|
-
});
|
|
11
|
-
const _common = require("@nestjs/common");
|
|
12
|
-
function routeHandler(route, factory) {
|
|
1
|
+
import { HttpException } from "@nestjs/common";
|
|
2
|
+
/**
|
|
3
|
+
* returns a route handler that receives the Request object as its first arg
|
|
4
|
+
*/ export function routeHandler(route, factory) {
|
|
13
5
|
let serviceName = factory.options?.serviceName || 'service';
|
|
14
6
|
// don't convert this to arrow function, so `this` here refers to the Controller class
|
|
15
7
|
// don't use factory.controller.prototype[serviceName] as service will be undefined
|
|
@@ -18,12 +10,12 @@ function routeHandler(route, factory) {
|
|
|
18
10
|
// @ts-ignore
|
|
19
11
|
let service = this[serviceName];
|
|
20
12
|
if (!service) {
|
|
21
|
-
throw new
|
|
13
|
+
throw new HttpException(`this.${serviceName} is not defined, please inject the service`, 500);
|
|
22
14
|
}
|
|
23
15
|
if (!service[route.methodName]) {
|
|
24
|
-
throw new
|
|
16
|
+
throw new HttpException(`the method this.${serviceName}.${route.methodName}() is not defined in the service`, 500);
|
|
25
17
|
} else if (typeof service[route.methodName] !== 'function') {
|
|
26
|
-
throw new
|
|
18
|
+
throw new HttpException(`this.${serviceName}.${route.methodName} is not a method`, 500);
|
|
27
19
|
}
|
|
28
20
|
try {
|
|
29
21
|
// todo: send the proper params to each operation
|
|
@@ -36,7 +28,7 @@ function routeHandler(route, factory) {
|
|
|
36
28
|
// todo: get class name using Reflect
|
|
37
29
|
// eslint-disable-next-line no-console
|
|
38
30
|
console.error(`error at ${factory.controller.name}.${route.methodName}()`, error);
|
|
39
|
-
throw new
|
|
31
|
+
throw new HttpException(error?.message || error, 500);
|
|
40
32
|
}
|
|
41
33
|
};
|
|
42
34
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/decorators/controller/route-handler.ts"],"sourcesContent":["import { ControllerFactory } from './controller.factory';\nimport type { IRoute } from './types';\nimport { HttpException } from '@nestjs/common';\n\n/**\n * returns a route handler that receives the Request object as its first arg\n */\nexport function routeHandler(route: IRoute, factory: ControllerFactory) {\n let serviceName = factory.options?.serviceName || 'service';\n // don't convert this to arrow function, so `this` here refers to the Controller class\n // don't use factory.controller.prototype[serviceName] as service will be undefined\n // todo: query type\n return function (req: Request, query: any, ...params: any) {\n // @ts-ignore\n let service = this[serviceName];\n\n if (!service) {\n throw new HttpException(\n `this.${serviceName} is not defined, please inject the service`,\n 500,\n );\n }\n\n if (!service[route.methodName]) {\n throw new HttpException(\n `the method this.${serviceName}.${route.methodName}() is not defined in the service`,\n 500,\n );\n } else if (typeof service[route.methodName] !== 'function') {\n throw new HttpException(\n `this.${serviceName}.${route.methodName} is not a method`,\n 500,\n );\n }\n\n try {\n // todo: send the proper params to each operation\n // getOne(id), postOne(body), patchOne(id,body)\n if (factory.options.maxLimit && query.take > factory.options.maxLimit) {\n query.take = factory.options.maxLimit;\n }\n return service[route.methodName](...params, query, req);\n } catch (error: any) {\n // todo: get class name using Reflect\n // eslint-disable-next-line no-console\n console.error(\n `error at ${factory.controller.name}.${route.methodName}()`,\n error,\n );\n throw new HttpException(error?.message || error, 500);\n }\n };\n}\n"],"names":["routeHandler","route","factory","serviceName","options","req","query","params","service","
|
|
1
|
+
{"version":3,"sources":["../../../../src/decorators/controller/route-handler.ts"],"sourcesContent":["import { ControllerFactory } from './controller.factory.js';\nimport type { IRoute } from './types/index.js';\nimport { HttpException } from '@nestjs/common';\n\n/**\n * returns a route handler that receives the Request object as its first arg\n */\nexport function routeHandler(route: IRoute, factory: ControllerFactory) {\n let serviceName = factory.options?.serviceName || 'service';\n // don't convert this to arrow function, so `this` here refers to the Controller class\n // don't use factory.controller.prototype[serviceName] as service will be undefined\n // todo: query type\n return function (req: Request, query: any, ...params: any) {\n // @ts-ignore\n let service = this[serviceName];\n\n if (!service) {\n throw new HttpException(\n `this.${serviceName} is not defined, please inject the service`,\n 500,\n );\n }\n\n if (!service[route.methodName]) {\n throw new HttpException(\n `the method this.${serviceName}.${route.methodName}() is not defined in the service`,\n 500,\n );\n } else if (typeof service[route.methodName] !== 'function') {\n throw new HttpException(\n `this.${serviceName}.${route.methodName} is not a method`,\n 500,\n );\n }\n\n try {\n // todo: send the proper params to each operation\n // getOne(id), postOne(body), patchOne(id,body)\n if (factory.options.maxLimit && query.take > factory.options.maxLimit) {\n query.take = factory.options.maxLimit;\n }\n return service[route.methodName](...params, query, req);\n } catch (error: any) {\n // todo: get class name using Reflect\n // eslint-disable-next-line no-console\n console.error(\n `error at ${factory.controller.name}.${route.methodName}()`,\n error,\n );\n throw new HttpException(error?.message || error, 500);\n }\n };\n}\n"],"names":["HttpException","routeHandler","route","factory","serviceName","options","req","query","params","service","methodName","maxLimit","take","error","console","controller","name","message"],"mappings":"AAEA,SAASA,aAAa,QAAQ,iBAAiB;AAE/C;;CAEC,GACD,OAAO,SAASC,aAAaC,KAAa,EAAEC,OAA0B;IACpE,IAAIC,cAAcD,QAAQE,OAAO,EAAED,eAAe;IAClD,sFAAsF;IACtF,mFAAmF;IACnF,mBAAmB;IACnB,OAAO,SAAUE,GAAY,EAAEC,KAAU,EAAE,GAAGC,MAAW;QACvD,aAAa;QACb,IAAIC,UAAU,IAAI,CAACL,YAAY;QAE/B,IAAI,CAACK,SAAS;YACZ,MAAM,IAAIT,cACR,CAAC,KAAK,EAAEI,YAAY,0CAA0C,CAAC,EAC/D;QAEJ;QAEA,IAAI,CAACK,OAAO,CAACP,MAAMQ,UAAU,CAAC,EAAE;YAC9B,MAAM,IAAIV,cACR,CAAC,gBAAgB,EAAEI,YAAY,CAAC,EAAEF,MAAMQ,UAAU,CAAC,gCAAgC,CAAC,EACpF;QAEJ,OAAO,IAAI,OAAOD,OAAO,CAACP,MAAMQ,UAAU,CAAC,KAAK,YAAY;YAC1D,MAAM,IAAIV,cACR,CAAC,KAAK,EAAEI,YAAY,CAAC,EAAEF,MAAMQ,UAAU,CAAC,gBAAgB,CAAC,EACzD;QAEJ;QAEA,IAAI;YACF,iDAAiD;YACjD,+CAA+C;YAC/C,IAAIP,QAAQE,OAAO,CAACM,QAAQ,IAAIJ,MAAMK,IAAI,GAAGT,QAAQE,OAAO,CAACM,QAAQ,EAAE;gBACrEJ,MAAMK,IAAI,GAAGT,QAAQE,OAAO,CAACM,QAAQ;YACvC;YACA,OAAOF,OAAO,CAACP,MAAMQ,UAAU,CAAC,IAAIF,QAAQD,OAAOD;QACrD,EAAE,OAAOO,OAAY;YACnB,qCAAqC;YACrC,sCAAsC;YACtCC,QAAQD,KAAK,CACX,CAAC,SAAS,EAAEV,QAAQY,UAAU,CAACC,IAAI,CAAC,CAAC,EAAEd,MAAMQ,UAAU,CAAC,EAAE,CAAC,EAC3DG;YAEF,MAAM,IAAIb,cAAca,OAAOI,WAAWJ,OAAO;QACnD;IACF;AACF"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { InitRoute } from './types';
|
|
1
|
+
import { InitRoute } from './types/index.js';
|
|
2
2
|
export declare function Route(route?: InitRoute): MethodDecorator;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
function Route(route) {
|
|
1
|
+
/**
|
|
2
|
+
* add route options to the method to override the options set by `@Controller()`
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```
|
|
6
|
+
* \@Route({httpMethod: 'GET', many: true})
|
|
7
|
+
* getAllUsers(){
|
|
8
|
+
* return this.service.getAllUsers();
|
|
9
|
+
* }
|
|
10
|
+
* ```
|
|
11
|
+
*/ export function Route(route) {
|
|
12
12
|
return (target, property)=>{
|
|
13
13
|
Reflect.defineMetadata('routeOptions', route, target, property);
|
|
14
14
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/decorators/controller/route.decorator.ts"],"sourcesContent":["import { InitRoute } from './types';\n\n/**\n * add route options to the method to override the options set by `@Controller()`\n *\n * @example\n * ```\n * \\@Route({httpMethod: 'GET', many: true})\n * getAllUsers(){\n * return this.service.getAllUsers();\n * }\n * ```\n */\nexport function Route(route?: InitRoute): MethodDecorator {\n return (target: Object, property: string | symbol) => {\n Reflect.defineMetadata('routeOptions', route, target, property);\n };\n}\n"],"names":["Route","route","target","property","Reflect","defineMetadata"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../../src/decorators/controller/route.decorator.ts"],"sourcesContent":["import { InitRoute } from './types/index.js';\n\n/**\n * add route options to the method to override the options set by `@Controller()`\n *\n * @example\n * ```\n * \\@Route({httpMethod: 'GET', many: true})\n * getAllUsers(){\n * return this.service.getAllUsers();\n * }\n * ```\n */\nexport function Route(route?: InitRoute): MethodDecorator {\n return (target: Object, property: string | symbol) => {\n Reflect.defineMetadata('routeOptions', route, target, property);\n };\n}\n"],"names":["Route","route","target","property","Reflect","defineMetadata"],"mappings":"AAEA;;;;;;;;;;CAUC,GACD,OAAO,SAASA,MAAMC,KAAiB;IACrC,OAAO,CAACC,QAAgBC;QACtBC,QAAQC,cAAc,CAAC,gBAAgBJ,OAAOC,QAAQC;IACxD;AACF"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { type FindManyOptions, type ObjectLiteral, Repository } from 'typeorm';
|
|
2
|
-
import type { DeepPartial } from 'typeorm/common/DeepPartial';
|
|
1
|
+
import { type FindManyOptions, type ObjectLiteral, type DeepPartial, Repository } from 'typeorm';
|
|
3
2
|
export interface IQuery<Entity = any> extends Omit<FindManyOptions<Entity>, 'where' | 'relations'> {
|
|
4
3
|
where?: FindManyOptions['where'] | string;
|
|
5
4
|
relations?: FindManyOptions['relations'] | string;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { NotImplementedException } from "@nestjs/common";
|
|
2
|
+
import { ArrayContains, Raw } from "typeorm";
|
|
3
|
+
import { merge } from "merge-anything";
|
|
4
|
+
/**
|
|
5
|
+
* The CRUD implementation service for TypeORM
|
|
6
|
+
* it adds methods such as `getOne()`, `getMany()`, and `post()` that ue TypeORM repo
|
|
7
|
+
* to work with the data model
|
|
8
|
+
*/ // todo: add pipes, example: `update(@Param('id', ParseUUIDPipe) id: string, body){}`
|
|
9
|
+
export class CrudTypeOrmService {
|
|
10
|
+
constructor(// todo: inject repo using Entity
|
|
11
|
+
// @InjectRepository(Dto) private repo: Repository<Entity>,
|
|
12
|
+
repo){
|
|
13
|
+
this.repo = repo;
|
|
9
14
|
}
|
|
10
|
-
});
|
|
11
|
-
const _common = require("@nestjs/common");
|
|
12
|
-
const _typeorm = require("typeorm");
|
|
13
|
-
const _mergeanything = require("merge-anything");
|
|
14
|
-
let CrudTypeOrmService = class CrudTypeOrmService {
|
|
15
15
|
/**
|
|
16
16
|
* create a TypeORM Query object
|
|
17
17
|
* @param query
|
|
@@ -52,7 +52,7 @@ let CrudTypeOrmService = class CrudTypeOrmService {
|
|
|
52
52
|
// check if the array column contains the value
|
|
53
53
|
// todo: use the entity to check if the field type is an array
|
|
54
54
|
// @ts-ignore
|
|
55
|
-
query.where[key] =
|
|
55
|
+
query.where[key] = ArrayContains(value.map((el)=>el?.trim()));
|
|
56
56
|
} else if (typeof value === 'string') {
|
|
57
57
|
value = value?.trim();
|
|
58
58
|
// if the value starts with ">", consider it as a raw sql statement
|
|
@@ -64,7 +64,7 @@ let CrudTypeOrmService = class CrudTypeOrmService {
|
|
|
64
64
|
// example `{key: "> {field} > 0"}`
|
|
65
65
|
if (value?.startsWith?.('>')) {
|
|
66
66
|
// @ts-ignore
|
|
67
|
-
query.where[key] =
|
|
67
|
+
query.where[key] = Raw((field)=>`${value.slice(1)}`.replaceAll('{field}', field));
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
});
|
|
@@ -118,7 +118,7 @@ let CrudTypeOrmService = class CrudTypeOrmService {
|
|
|
118
118
|
// }
|
|
119
119
|
// }
|
|
120
120
|
getManyByRelation(field, value, query, primaryKeyName = 'id', req) {
|
|
121
|
-
return this.getMany(
|
|
121
|
+
return this.getMany(merge(query || {}, {
|
|
122
122
|
where: {
|
|
123
123
|
[field]: {
|
|
124
124
|
[primaryKeyName]: value
|
|
@@ -161,10 +161,10 @@ let CrudTypeOrmService = class CrudTypeOrmService {
|
|
|
161
161
|
// .then((res) => ({ affected: res.affected }));
|
|
162
162
|
}
|
|
163
163
|
putOne() {
|
|
164
|
-
throw new
|
|
164
|
+
throw new NotImplementedException();
|
|
165
165
|
}
|
|
166
166
|
putMany() {
|
|
167
|
-
throw new
|
|
167
|
+
throw new NotImplementedException();
|
|
168
168
|
}
|
|
169
169
|
deleteOne(primaryKeyOrCondition, query = {}, req) {
|
|
170
170
|
query.where = [
|
|
@@ -222,11 +222,6 @@ let CrudTypeOrmService = class CrudTypeOrmService {
|
|
|
222
222
|
}, {});
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
|
-
|
|
226
|
-
// @InjectRepository(Dto) private repo: Repository<Entity>,
|
|
227
|
-
repo){
|
|
228
|
-
this.repo = repo;
|
|
229
|
-
}
|
|
230
|
-
};
|
|
225
|
+
}
|
|
231
226
|
|
|
232
227
|
//# sourceMappingURL=crud-typeorm.service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/decorators/controller/services/crud-typeorm.service.ts"],"sourcesContent":["import { NotImplementedException } from '@nestjs/common';\nimport {\n ArrayContains,\n DeleteResult,\n type FindManyOptions,\n type ObjectLiteral,\n Raw,\n Repository,\n UpdateResult,\n} from 'typeorm';\nimport type { DeepPartial } from 'typeorm/common/DeepPartial';\n// @ts-ignore\nimport { merge } from 'merge-anything';\n\n/**\n * find options but some props accepts string format that parsed internally into the correct format\n * for example { where: \"age>30,name='john'\" }\n */\nexport interface IQuery<Entity = any> extends Omit<\n FindManyOptions<Entity>,\n 'where' | 'relations'\n> {\n where?: FindManyOptions['where'] | string;\n relations?: FindManyOptions['relations'] | string;\n}\n\n/**\n * The CRUD implementation service for TypeORM\n * it adds methods such as `getOne()`, `getMany()`, and `post()` that ue TypeORM repo\n * to work with the data model\n */\n// todo: add pipes, example: `update(@Param('id', ParseUUIDPipe) id: string, body){}`\nexport class CrudTypeOrmService<Entity extends ObjectLiteral> {\n constructor(\n // todo: inject repo using Entity\n // @InjectRepository(Dto) private repo: Repository<Entity>,\n protected repo: Repository<Entity>,\n ) {}\n\n /**\n * create a TypeORM Query object\n * @param query\n * @param primaryKey the primary key value, for \"*One\" operations\n * @param primaryKeyName the primary key field name, default: \"id\"\n */\n // todo: enforce the return type\n // todo: `T extends FindOneOptions | FindManyOptions | ...`\n createQuery<Entity>(\n query?: IQuery<Entity>,\n primaryKeyValue?: string | number,\n primaryKeyName = 'id', // FindManyOptions already extends FindOneOptions\n ): FindManyOptions<Entity> {\n query = {\n ...query,\n // for \"one\" operations, include deleted records by default\n withDeleted: primaryKeyValue\n ? query?.withDeleted !== false\n : query?.withDeleted,\n // todo: nested relations \"users.profiles\"\n // todo: relation fields \"users:name,email\"\n // todo: relations may be an object rather than an array\n relations: this.toArray(query?.relations),\n select: this.toArray(query?.select),\n order: this.toObject(query?.order, 'ASC'),\n };\n\n if (query.where) {\n // convert query.where to object\n if (\n typeof query.where === 'string' &&\n // json format\n (query.where.startsWith('{') ||\n // query.where can be a string, i.e. \"primaryKey\"\n // if its format is not `key:value, key2` keep it string\n // if it is a single text value, consider it as primaryKey value\n // matches: `a:1, b:2, c` and `a,b` but not `id`\n // todo: deprecate inline k-v syntax, use explicit object\n // eslint-disable-next-line regexp/optimal-quantifier-concatenation\n /(.+:.+(,.+)?)|(.+,.+)/.test(query.where))\n ) {\n query.where = this.toObject(query.where);\n }\n\n // todo: if isObject()\n if (typeof query.where !== 'string' && !Array.isArray(query.where)) {\n Object.keys(query.where!).map((key) => {\n // @ts-ignore\n let value = query.where[key];\n if (Array.isArray(value)) {\n // check if the array column contains the value\n // todo: use the entity to check if the field type is an array\n // @ts-ignore\n query.where[key] = ArrayContains(value.map((el) => el?.trim()));\n } else if (typeof value === 'string') {\n value = value?.trim();\n\n // if the value starts with \">\", consider it as a raw sql statement\n // convert `{key: value}` to `{key: Raw(field=>value)}`\n // to enable sql syntax and find operations\n // such as: `Like '%test%'`\n // todo: check for sql injection of the user's input\n // todo: if it includes a find operation such as `Like` (can be a part of the value)\n // example `{key: \"> {field} > 0\"}`\n if (value?.startsWith?.('>')) {\n // @ts-ignore\n query.where[key] = Raw((field: string) =>\n `${value.slice(1)}`.replaceAll('{field}', field),\n );\n }\n }\n });\n\n // add primaryKey to the condition\n if (primaryKeyValue && primaryKeyName) {\n query.where = {\n [primaryKeyName]: primaryKeyValue,\n ...query.where,\n };\n }\n }\n } else if (primaryKeyValue) {\n query.where = { [primaryKeyName]: primaryKeyValue };\n }\n\n return <FindManyOptions<Entity>>query;\n }\n\n // todo: rename to getOneById() or getOneBy${primaryParam}\n // todo: route.paramKey{name, type:String|Number}\n // todo: types\n // todo: parse query params, and add type ControllerOptions.QueryParams\n getOne(id: any, query?: any, _req?: Request) {\n return this.repo.findOne(this.createQuery(query, id));\n }\n\n // todo: handle operations, example: `{where: {email: \"like %john%\"} }`\n getMany(query?: any, _req?: Request) {\n return this.repo\n .findAndCount(this.createQuery(query))\n .then((res) => ({ data: res[0], count: res[1] }));\n }\n\n /**\n * get records by a relation field\n * @param field the relationship field name\n * @param value\n * @param query\n * @param primaryKeyName\n * @param req\n * @returns\n * @example\n * if the table posts has a relation with users,\n * we can get all posts by the user by `getManyByRelation(\"user\", 1)`\n */\n // todo: merge options.query{}\n // for example the following route should inherit options from @Controller()\n // @Controller(options)\n // class MyController{\n // @Get('/users/:userId/posts')\n // getUserPosts(){\n // return this.service.getManyByRelation(...) // options.query from @Controller() should be merged here\n // }\n // }\n getManyByRelation(\n field: string,\n value: any,\n query?: any,\n primaryKeyName = 'id',\n req?: Request,\n ) {\n return this.getMany(\n merge(query || {}, { where: { [field]: { [primaryKeyName]: value } } }),\n req,\n );\n }\n\n post(body: DeepPartial<Entity>, _query?: any, _req?: Request) {\n // .save() automatically saves the manyToMany relations if cascade=true\n // or this.repo.insert(body).then((res) => (Array.isArray(body) ? res?.raw : res?.raw[0]))\n return this.repo.save(body);\n }\n\n /**\n * update a record by its primary key\n */\n patchOne(\n // todo: add type opts.model\n body: DeepPartial<Entity>,\n primaryKey: string | number | { [key: string]: any } = 'id',\n _req?: Request,\n ) {\n return this.getOne(primaryKey).then((res) => {\n if (!res?.id) throw new Error(`not found`);\n // .save() automatically modifies the ManyToMany relations\n // but requires fetching the items to be modified to add the id of each item\n // otherwise it will create a new item if it doesn't have an id\n return this.repo.save({ ...body, id: res.id });\n });\n }\n\n patchMany(body: DeepPartial<Entity>, query?: any, _req?: Request) {\n return this.repo\n .find(query)\n .then((res) => res.map((el) => ({ ...body, id: el.id })))\n .then((res) => this.repo.save(res));\n\n // .update() doesn't save ManyToMany relation automatically\n // but .save() doesn't have where condition (each item has to specify id)\n // and has no limit option (it relies on the number of the items being updated)\n // use .save() see patchOne(), it meeds merging body[] with existing ids of the items to be updated\n // or create a route to save (insert or update) items `POST /save`\n\n // return this.repo\n // .update(query.where, body)\n // .then((res) => ({ affected: res.affected }));\n }\n\n putOne() {\n throw new NotImplementedException();\n }\n\n putMany() {\n throw new NotImplementedException();\n }\n\n deleteOne(\n primaryKeyOrCondition: string | number | { [key: string]: any },\n query: any = {},\n req?: Request,\n ) {\n query.where = ['string', 'number'].includes(typeof primaryKeyOrCondition)\n ? primaryKeyOrCondition\n : { ...query.where, ...(<{ [key: string]: any }>primaryKeyOrCondition) };\n return this.deleteMany(query, req);\n }\n\n deleteMany(query?: any, _req?: Request) {\n // todo: softDelete() vs softRemove()\n\n let deleteQuery: Promise<DeleteResult | UpdateResult>;\n // repo.delete({}) no longer allowed by TypeORM, in this case we'll use QueryBuilder to provide a fake criteria\n if (query.where) {\n deleteQuery =\n query.softDelete === false\n ? this.repo.delete(query.where)\n : this.repo.softDelete(query.where);\n } else {\n let builder = this.repo.createQueryBuilder();\n deleteQuery =\n query.softDelete === false\n ? builder.delete().where('1 = 1').execute()\n : builder.softDelete().where('1 = 1').execute();\n }\n return deleteQuery.then((res) => ({ affected: res?.affected }));\n }\n\n /**\n * delete all data using `TRUNCATE` instead of `DELETE`\n */\n // todo: add a route to clear (truncate) the data, for instance `DELETE <entity>/clear`\n clear() {\n return this.repo.clear();\n }\n\n /**\n * convert delimited string int array items and remove empty items\n * @example 'a,b,c' => ['a', 'b', 'c']\n */\n toArray(value?: any, delimiter = ',') {\n return typeof value === 'string'\n ? value\n ?.split?.(delimiter)\n // remove empty elements\n ?.filter((el) => el && el.trim() !== '')\n : value;\n }\n\n /**\n * convert JSON string or delimited string into a plain object\n * @example `{\"a\": 1}` => `{a: 1}`\n * @example `a:1, b:2, c` => `{a: 1, b: 2, c: defaultValue}`\n */\n toObject(value?: any, defaultValue: any = true) {\n if (!value) return;\n if (typeof value !== 'string') return value;\n // todo: if isObject(value) return value\n\n try {\n return JSON.parse(value);\n } catch {\n return value?.split?.(',')?.reduce?.(\n (acc, el) => {\n let [key, value = defaultValue] = el.split(':');\n return { ...acc, [key.trim()]: value.trim() };\n },\n <{ [key: string]: any }>{},\n );\n }\n }\n}\n"],"names":["CrudTypeOrmService","createQuery","query","primaryKeyValue","primaryKeyName","withDeleted","relations","toArray","select","order","toObject","where","startsWith","test","Array","isArray","Object","keys","map","key","value","ArrayContains","el","trim","Raw","field","slice","replaceAll","getOne","id","_req","repo","findOne","getMany","findAndCount","then","res","data","count","getManyByRelation","req","merge","post","body","_query","save","patchOne","primaryKey","Error","patchMany","find","putOne","NotImplementedException","putMany","deleteOne","primaryKeyOrCondition","includes","deleteMany","deleteQuery","softDelete","delete","builder","createQueryBuilder","execute","affected","clear","delimiter","split","filter","defaultValue","JSON","parse","reduce","acc"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../src/decorators/controller/services/crud-typeorm.service.ts"],"sourcesContent":["import { NotImplementedException } from '@nestjs/common';\nimport {\n ArrayContains,\n DeleteResult,\n type FindManyOptions,\n type ObjectLiteral,\n type DeepPartial,\n Raw,\n Repository,\n UpdateResult,\n} from 'typeorm';\nimport { merge } from 'merge-anything';\n\n/**\n * find options but some props accepts string format that parsed internally into the correct format\n * for example { where: \"age>30,name='john'\" }\n */\nexport interface IQuery<Entity = any> extends Omit<\n FindManyOptions<Entity>,\n 'where' | 'relations'\n> {\n where?: FindManyOptions['where'] | string;\n relations?: FindManyOptions['relations'] | string;\n}\n\n/**\n * The CRUD implementation service for TypeORM\n * it adds methods such as `getOne()`, `getMany()`, and `post()` that ue TypeORM repo\n * to work with the data model\n */\n// todo: add pipes, example: `update(@Param('id', ParseUUIDPipe) id: string, body){}`\nexport class CrudTypeOrmService<Entity extends ObjectLiteral> {\n constructor(\n // todo: inject repo using Entity\n // @InjectRepository(Dto) private repo: Repository<Entity>,\n protected repo: Repository<Entity>,\n ) {}\n\n /**\n * create a TypeORM Query object\n * @param query\n * @param primaryKey the primary key value, for \"*One\" operations\n * @param primaryKeyName the primary key field name, default: \"id\"\n */\n // todo: enforce the return type\n // todo: `T extends FindOneOptions | FindManyOptions | ...`\n createQuery<Entity>(\n query?: IQuery<Entity>,\n primaryKeyValue?: string | number,\n primaryKeyName = 'id', // FindManyOptions already extends FindOneOptions\n ): FindManyOptions<Entity> {\n query = {\n ...query,\n // for \"one\" operations, include deleted records by default\n withDeleted: primaryKeyValue\n ? query?.withDeleted !== false\n : query?.withDeleted,\n // todo: nested relations \"users.profiles\"\n // todo: relation fields \"users:name,email\"\n // todo: relations may be an object rather than an array\n relations: this.toArray(query?.relations),\n select: this.toArray(query?.select),\n order: this.toObject(query?.order, 'ASC'),\n };\n\n if (query.where) {\n // convert query.where to object\n if (\n typeof query.where === 'string' &&\n // json format\n (query.where.startsWith('{') ||\n // query.where can be a string, i.e. \"primaryKey\"\n // if its format is not `key:value, key2` keep it string\n // if it is a single text value, consider it as primaryKey value\n // matches: `a:1, b:2, c` and `a,b` but not `id`\n // todo: deprecate inline k-v syntax, use explicit object\n // eslint-disable-next-line regexp/optimal-quantifier-concatenation\n /(.+:.+(,.+)?)|(.+,.+)/.test(query.where))\n ) {\n query.where = this.toObject(query.where);\n }\n\n // todo: if isObject()\n if (typeof query.where !== 'string' && !Array.isArray(query.where)) {\n Object.keys(query.where!).map((key) => {\n // @ts-ignore\n let value = query.where[key];\n if (Array.isArray(value)) {\n // check if the array column contains the value\n // todo: use the entity to check if the field type is an array\n // @ts-ignore\n query.where[key] = ArrayContains(value.map((el) => el?.trim()));\n } else if (typeof value === 'string') {\n value = value?.trim();\n\n // if the value starts with \">\", consider it as a raw sql statement\n // convert `{key: value}` to `{key: Raw(field=>value)}`\n // to enable sql syntax and find operations\n // such as: `Like '%test%'`\n // todo: check for sql injection of the user's input\n // todo: if it includes a find operation such as `Like` (can be a part of the value)\n // example `{key: \"> {field} > 0\"}`\n if (value?.startsWith?.('>')) {\n // @ts-ignore\n query.where[key] = Raw((field: string) =>\n `${value.slice(1)}`.replaceAll('{field}', field),\n );\n }\n }\n });\n\n // add primaryKey to the condition\n if (primaryKeyValue && primaryKeyName) {\n query.where = {\n [primaryKeyName]: primaryKeyValue,\n ...query.where,\n };\n }\n }\n } else if (primaryKeyValue) {\n query.where = { [primaryKeyName]: primaryKeyValue };\n }\n\n return <FindManyOptions<Entity>>query;\n }\n\n // todo: rename to getOneById() or getOneBy${primaryParam}\n // todo: route.paramKey{name, type:String|Number}\n // todo: types\n // todo: parse query params, and add type ControllerOptions.QueryParams\n getOne(id: any, query?: any, _req?: Request) {\n return this.repo.findOne(this.createQuery(query, id));\n }\n\n // todo: handle operations, example: `{where: {email: \"like %john%\"} }`\n getMany(query?: any, _req?: Request) {\n return this.repo\n .findAndCount(this.createQuery(query))\n .then((res) => ({ data: res[0], count: res[1] }));\n }\n\n /**\n * get records by a relation field\n * @param field the relationship field name\n * @param value\n * @param query\n * @param primaryKeyName\n * @param req\n * @returns\n * @example\n * if the table posts has a relation with users,\n * we can get all posts by the user by `getManyByRelation(\"user\", 1)`\n */\n // todo: merge options.query{}\n // for example the following route should inherit options from @Controller()\n // @Controller(options)\n // class MyController{\n // @Get('/users/:userId/posts')\n // getUserPosts(){\n // return this.service.getManyByRelation(...) // options.query from @Controller() should be merged here\n // }\n // }\n getManyByRelation(\n field: string,\n value: any,\n query?: any,\n primaryKeyName = 'id',\n req?: Request,\n ) {\n return this.getMany(\n merge(query || {}, { where: { [field]: { [primaryKeyName]: value } } }),\n req,\n );\n }\n\n post(body: DeepPartial<Entity>, _query?: any, _req?: Request) {\n // .save() automatically saves the manyToMany relations if cascade=true\n // or this.repo.insert(body).then((res) => (Array.isArray(body) ? res?.raw : res?.raw[0]))\n return this.repo.save(body);\n }\n\n /**\n * update a record by its primary key\n */\n patchOne(\n // todo: add type opts.model\n body: DeepPartial<Entity>,\n primaryKey: string | number | { [key: string]: any } = 'id',\n _req?: Request,\n ) {\n return this.getOne(primaryKey).then((res) => {\n if (!res?.id) throw new Error(`not found`);\n // .save() automatically modifies the ManyToMany relations\n // but requires fetching the items to be modified to add the id of each item\n // otherwise it will create a new item if it doesn't have an id\n return this.repo.save({ ...body, id: res.id });\n });\n }\n\n patchMany(body: DeepPartial<Entity>, query?: any, _req?: Request) {\n return this.repo\n .find(query)\n .then((res) => res.map((el) => ({ ...body, id: el.id })))\n .then((res) => this.repo.save(res));\n\n // .update() doesn't save ManyToMany relation automatically\n // but .save() doesn't have where condition (each item has to specify id)\n // and has no limit option (it relies on the number of the items being updated)\n // use .save() see patchOne(), it meeds merging body[] with existing ids of the items to be updated\n // or create a route to save (insert or update) items `POST /save`\n\n // return this.repo\n // .update(query.where, body)\n // .then((res) => ({ affected: res.affected }));\n }\n\n putOne() {\n throw new NotImplementedException();\n }\n\n putMany() {\n throw new NotImplementedException();\n }\n\n deleteOne(\n primaryKeyOrCondition: string | number | { [key: string]: any },\n query: any = {},\n req?: Request,\n ) {\n query.where = ['string', 'number'].includes(typeof primaryKeyOrCondition)\n ? primaryKeyOrCondition\n : { ...query.where, ...(<{ [key: string]: any }>primaryKeyOrCondition) };\n return this.deleteMany(query, req);\n }\n\n deleteMany(query?: any, _req?: Request) {\n // todo: softDelete() vs softRemove()\n\n let deleteQuery: Promise<DeleteResult | UpdateResult>;\n // repo.delete({}) no longer allowed by TypeORM, in this case we'll use QueryBuilder to provide a fake criteria\n if (query.where) {\n deleteQuery =\n query.softDelete === false\n ? this.repo.delete(query.where)\n : this.repo.softDelete(query.where);\n } else {\n let builder = this.repo.createQueryBuilder();\n deleteQuery =\n query.softDelete === false\n ? builder.delete().where('1 = 1').execute()\n : builder.softDelete().where('1 = 1').execute();\n }\n return deleteQuery.then((res) => ({ affected: res?.affected }));\n }\n\n /**\n * delete all data using `TRUNCATE` instead of `DELETE`\n */\n // todo: add a route to clear (truncate) the data, for instance `DELETE <entity>/clear`\n clear() {\n return this.repo.clear();\n }\n\n /**\n * convert delimited string int array items and remove empty items\n * @example 'a,b,c' => ['a', 'b', 'c']\n */\n toArray(value?: any, delimiter = ',') {\n return typeof value === 'string'\n ? value\n ?.split?.(delimiter)\n // remove empty elements\n ?.filter((el) => el && el.trim() !== '')\n : value;\n }\n\n /**\n * convert JSON string or delimited string into a plain object\n * @example `{\"a\": 1}` => `{a: 1}`\n * @example `a:1, b:2, c` => `{a: 1, b: 2, c: defaultValue}`\n */\n toObject(value?: any, defaultValue: any = true) {\n if (!value) return;\n if (typeof value !== 'string') return value;\n // todo: if isObject(value) return value\n\n try {\n return JSON.parse(value);\n } catch {\n return value?.split?.(',')?.reduce?.(\n (acc, el) => {\n let [key, value = defaultValue] = el.split(':');\n return { ...acc, [key.trim()]: value.trim() };\n },\n <{ [key: string]: any }>{},\n );\n }\n }\n}\n"],"names":["NotImplementedException","ArrayContains","Raw","merge","CrudTypeOrmService","repo","createQuery","query","primaryKeyValue","primaryKeyName","withDeleted","relations","toArray","select","order","toObject","where","startsWith","test","Array","isArray","Object","keys","map","key","value","el","trim","field","slice","replaceAll","getOne","id","_req","findOne","getMany","findAndCount","then","res","data","count","getManyByRelation","req","post","body","_query","save","patchOne","primaryKey","Error","patchMany","find","putOne","putMany","deleteOne","primaryKeyOrCondition","includes","deleteMany","deleteQuery","softDelete","delete","builder","createQueryBuilder","execute","affected","clear","delimiter","split","filter","defaultValue","JSON","parse","reduce","acc"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { HttpStatus, type NestInterceptor, type Type } from '@nestjs/common';
|
|
2
2
|
import type { ApiOperationOptions, ApiParamOptions } from '@nestjs/swagger';
|
|
3
|
-
import type { ParameterObject } from '@nestjs/swagger/dist/interfaces/open-api-spec.interface';
|
|
4
|
-
import type { SwaggerEnumType } from '@nestjs/swagger/dist/types/swagger-enum.type';
|
|
3
|
+
import type { ParameterObject } from '@nestjs/swagger/dist/interfaces/open-api-spec.interface.js';
|
|
4
|
+
import type { SwaggerEnumType } from '@nestjs/swagger/dist/types/swagger-enum.type.js';
|
|
5
5
|
type MakeRequired<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
|
|
6
6
|
export interface ControllerOptions extends MakeRequired<InitControllerOptions, 'serviceName' | 'routes'> {
|
|
7
7
|
routes: IRoute[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/decorators/controller/types/index.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"sources":["../../../../../src/decorators/controller/types/index.ts"],"sourcesContent":["import { HttpStatus, type NestInterceptor, type Type } from '@nestjs/common';\nimport type { ApiOperationOptions, ApiParamOptions } from '@nestjs/swagger';\nimport type { ParameterObject } from '@nestjs/swagger/dist/interfaces/open-api-spec.interface.js';\nimport type { SwaggerEnumType } from '@nestjs/swagger/dist/types/swagger-enum.type.js';\n\ntype MakeRequired<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;\n\nexport interface ControllerOptions extends MakeRequired<\n InitControllerOptions,\n 'serviceName' | 'routes'\n> {\n routes: IRoute[];\n}\n\nexport interface IRoute extends MakeRequired<\n InitRoute,\n 'methodName' | 'httpMethod' | 'decorators' | 'interceptors'\n> {}\n\n/**\n * the initial Controller options by the user, i.e before adjusted by mergeOptions()\n * all these options can be customized per route\n */\n// todo: add decorators[] that are added to each route.decorators[]\n// todo: errorResponse to set error decorators -> @ApiBadRequestResponse({ type: ErrorResponse })\nexport interface InitControllerOptions {\n /**\n * The URL path of the controller\n */\n path?: string;\n /** routes to be generated and added to the Controller class */\n routes?: InitRoute[];\n queryParams?: QueryParam[];\n /** the service name, default: \"service\" */\n serviceName?: string;\n /** the request model */\n // todo: DTO | Entity\n model?: any;\n /** the success response model, by default the same as model */\n responseModel?: InitControllerOptions['model'];\n /** the general error response model */\n errorResponseModel?: InitControllerOptions['model'];\n /** other response models */\n // todo typeof @ApiResponse()\n responseModels?: Array<{\n status: HttpStatus;\n type: InitControllerOptions['model'];\n }>;\n /** the primary key field name, default: \"id\" */\n primaryKey?: string;\n /** the maximum records count to be fetched */\n maxLimit?: number;\n /** decorators to be added to each route\n * to apply decorators to the controller itself, just annotate them to the controller directly\n */\n decorators?: (MethodDecorator | PropertyDecorator)[];\n interceptors?: (NestInterceptor | Function)[];\n /**\n * the default query object to be merged with each route query.\n *\n * this applies to both the routes that are generated by \\@Controller()\n * or the existing routes.\n * @example\n * ```\n * @Get()\n * getMany(@Query() query){}\n * ```\n * query here is merged with opts.query\n */\n // todo: FindOneOptions | FindManyOptions ...\n query?: { [key: string]: any };\n /**\n * Api tags -> see `@ApiTags()` by @nestjs/swagger\n * if this value is not provided, the value of `@Controller(<path>)` will be used\n * to disable this feature use `null`\n */\n tags?: string | string | null;\n}\n\n/**\n * the initial Route,\n * also accepts `ApiOperationOptions` and `InitControllerOptions` to override its props for each route\n */\n\nexport interface InitRoute\n extends ApiOperationOptions, Omit<InitControllerOptions, 'routes' | 'tags'> {\n /** the http method, default: GET */\n httpMethod?: HttpMethod /*| RequestMethod*/;\n /** default path is \"/\" or \":id\" */\n path?: string;\n /**\n * the name of the generated method, by default it is ${httpMethod}${Many|One}\n * it must be unique within the Controller class to avoid overriding each other\n * @example getMany, deleteOne\n */\n methodName?: string;\n /**\n * whether it get many or one result, to set the proper metadata\n */\n many?: boolean;\n /**\n * the method body\n * by default it is generated based on the route's info,\n * and it calls the corresponding Service's method\n * @example `(req)=>this.service.getMany(req)`\n */\n methodFactory?: () => any;\n /** Swagger summary for this route */\n description?: string;\n pathParams?: ApiParamOptions[];\n /** if disabled, the route method will not be created */\n disabled?: boolean;\n}\n\n// todo: extends ApiQueryMetadata from @nestjs/swagger (not exported)\nexport interface QueryParam extends ParameterOptions {\n name?: string;\n type?: Type<unknown> | Function | [Function] | string;\n isArray?: boolean;\n enum?: SwaggerEnumType;\n enumName?: string;\n /**\n * if this query param should be added only to routes that has many=true\n * i.e operations that returns multiple records\n * such as getMany()\n */\n many?: boolean;\n /**\n * to add the query only to specific http methods\n */\n httpMethods?: HttpMethod[];\n}\ntype ParameterOptions = Omit<ParameterObject, 'in' | 'name'>;\n\n// todo: replace with `RequestMethod` Enum from @nestjs/common\nexport type HttpMethod =\n | 'GET'\n | 'POST'\n | 'PUT'\n | 'DELETE'\n | 'PATCH'\n | 'HEAD'\n | 'OPTIONS';\n\nexport type RouteHandler = (req: Request, query: any, ...params: any[]) => any;\n"],"names":[],"mappings":"AAgJA,WAA+E"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { ControllerOptions, InitControllerOptions } from '../types';
|
|
1
|
+
import { ControllerOptions, InitControllerOptions } from '../types/index.js';
|
|
2
2
|
export declare function mergeOptions(...options: InitControllerOptions[]): ControllerOptions;
|
|
@@ -1,16 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
});
|
|
5
|
-
Object.defineProperty(exports, "mergeOptions", {
|
|
6
|
-
enumerable: true,
|
|
7
|
-
get: function() {
|
|
8
|
-
return mergeOptions;
|
|
9
|
-
}
|
|
10
|
-
});
|
|
11
|
-
const _javascript = require("@impactor/javascript");
|
|
12
|
-
function mergeOptions(...options) {
|
|
13
|
-
let opts = (0, _javascript.merge)(options.map((el)=>(0, _javascript.removeValues)(el, [
|
|
1
|
+
import { merge, removeValues } from "@impactor/javascript";
|
|
2
|
+
export function mergeOptions(...options) {
|
|
3
|
+
let opts = merge(options.map((el)=>removeValues(el, [
|
|
14
4
|
undefined,
|
|
15
5
|
null
|
|
16
6
|
]) || {}), {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/decorators/controller/utils/merge-options.ts"],"sourcesContent":["import { ControllerOptions, InitControllerOptions } from '../types';\nimport { merge, removeValues } from '@impactor/javascript';\n\nexport function mergeOptions(\n ...options: InitControllerOptions[]\n): ControllerOptions {\n let opts = <ControllerOptions>merge(\n options.map((el) => removeValues(el, [undefined, null]) || {}),\n { deep: true },\n );\n\n // todo: merge matched routes (by methodNam, path, and httpMethod) and queryParams (by name)\n // the later override the previous one\n // opts.queryParams?.map((param) => {\n // let existingQueryParam = opts.queryParams!.findIndex(\n // (el) => el.name === param.name,\n // );\n\n // opts.queryParams!.push(\n // existingQueryParam > -1\n // ? {\n // ...opts.queryParams![existingQueryParam],\n // ...param,\n // }\n // : param,\n // );\n // });\n\n return opts;\n}\n"],"names":["
|
|
1
|
+
{"version":3,"sources":["../../../../../src/decorators/controller/utils/merge-options.ts"],"sourcesContent":["import { ControllerOptions, InitControllerOptions } from '../types/index.js';\nimport { merge, removeValues } from '@impactor/javascript';\n\nexport function mergeOptions(\n ...options: InitControllerOptions[]\n): ControllerOptions {\n let opts = <ControllerOptions>merge(\n options.map((el) => removeValues(el, [undefined, null]) || {}),\n { deep: true },\n );\n\n // todo: merge matched routes (by methodNam, path, and httpMethod) and queryParams (by name)\n // the later override the previous one\n // opts.queryParams?.map((param) => {\n // let existingQueryParam = opts.queryParams!.findIndex(\n // (el) => el.name === param.name,\n // );\n\n // opts.queryParams!.push(\n // existingQueryParam > -1\n // ? {\n // ...opts.queryParams![existingQueryParam],\n // ...param,\n // }\n // : param,\n // );\n // });\n\n return opts;\n}\n"],"names":["merge","removeValues","mergeOptions","options","opts","map","el","undefined","deep"],"mappings":"AACA,SAASA,KAAK,EAAEC,YAAY,QAAQ,uBAAuB;AAE3D,OAAO,SAASC,aACd,GAAGC,OAAgC;IAEnC,IAAIC,OAA0BJ,MAC5BG,QAAQE,GAAG,CAAC,CAACC,KAAOL,aAAaK,IAAI;YAACC;YAAW;SAAK,KAAK,CAAC,IAC5D;QAAEC,MAAM;IAAK;IAGf,4FAA4F;IAC5F,sCAAsC;IACtC,qCAAqC;IACrC,0DAA0D;IAC1D,sCAAsC;IACtC,OAAO;IAEP,4BAA4B;IAC5B,8BAA8B;IAC9B,YAAY;IACZ,sDAAsD;IACtD,sBAAsB;IACtB,YAAY;IACZ,iBAAiB;IACjB,OAAO;IACP,MAAM;IAEN,OAAOJ;AACT"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ControllerFactory } from '../controller.factory';
|
|
2
|
-
import { IRoute } from '../types';
|
|
1
|
+
import { ControllerFactory } from '../controller.factory.js';
|
|
2
|
+
import { IRoute } from '../types/index.js';
|
|
3
3
|
export declare function has(property: string, factory: ControllerFactory, route?: IRoute): boolean;
|
|
4
4
|
export declare function get(property: string, factory: ControllerFactory, route?: IRoute): any;
|
|
5
5
|
export declare function set<T extends Object>(property: string, value: T, factory: ControllerFactory, route?: IRoute): void;
|