@impactor/nest 3.0.0 → 3.0.2

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 CHANGED
@@ -2,6 +2,13 @@ utils for NestJs
2
2
 
3
3
  ## Decorators
4
4
 
5
+ ## @Controller()
6
+
7
+ Quickly generate all API endpoints and Crud operations of a controller without a single line of code.
8
+ It also generate Swagger decorators for all routes.
9
+
10
+ [Read more...](./README.controller.md)
11
+
5
12
  ## @Prop()
6
13
 
7
14
  a param decorator that extracts a field from the request
@@ -30,20 +37,96 @@ and add the suitable Swagger's docs.
30
37
 
31
38
  ```
32
39
 
33
- ## @Controller()
40
+ ## Exceptions
34
41
 
35
- Quickly generate all API endpoints and Crud operations of a controller without a single line of code.
36
- It also generate Swagger decorators for all routes.
42
+ RPC exceptions equivalent to the corresponding HTTP exceptions, such as:
37
43
 
38
- [Read more...](./README.controller.md)
44
+ - `RpcBadRequestException` -> `HttpBadRequestException`
45
+ - `RpcConflictException` -> `HttpConflictException`
46
+ - `RpcInternalServerErrorException` -> `HttpInternalServerErrorException`
47
+ - `RpcMethodNotAllowedException` -> `HttpMethodNotAllowedException`
48
+ - `RpcNotFoundException` -> `HttpNotFoundException`
49
+ - `RpcNotImplementedException` -> `HttpNotImplementedException`
50
+ - `RpcUnauthorizedException` -> `HttpUnauthorizedException`
51
+
52
+ Use these exceptions in microservices instead of the HTTP exceptions Nest provides, so you can handle RPC exception correctly.
53
+
54
+ usage:
55
+
56
+ inside microservices:
57
+
58
+ ```ts
59
+ export function doAction() {
60
+ // if a bad request is received
61
+ throw new RpcBadRequestException(); // correct
62
+ throw new HttpBadRequestException(); // wrong
63
+ }
64
+ ```
65
+
66
+ if you returned an instance of HttpException, Nest will handle it just like any other http, causes the exception not propagated to the microservice that requested the action and your response will be lost.
67
+
68
+ Using RPC exceptions instead, with the RPC exception filter we provide, you can handle this type of exceptions correctly.
39
69
 
40
70
  ## Exception Filters
41
71
 
42
- - RCP: convert Error to RpcException
72
+ - RPC: convert Error to RpcException
43
73
  - WS: convert Error to WsException
44
- - TypeORM
74
+ - TypeORM: detect TypeORM exceptions and handle them.
75
+
76
+ ## Guards
77
+
78
+ ### Auth guard
79
+
80
+ - `JwtAuthGuard`: inspects the JWT token and guard your routes based on this token.
81
+
82
+ it also checks the specified roles to determine weather to pass the guard or not.
83
+
84
+ Thi guard also provides the following decorators:
85
+
86
+ - `@Public()` and `@Private()`: to allow or disallow un-authenticated users to use the route. You can use it in the class-level or route-level.
87
+ - `@Roles()`: if provided, the guard checks the user roles before allowing him to use the route. you need to provide the user role when creating `req.user` object.
88
+
89
+ ### example
90
+
91
+ ```ts
92
+ // app.module.ts
93
+ import { JwtAuthGuard } from "@impactor/nest"
94
+
95
+ @Module({
96
+ imports: [...],
97
+ providers: [
98
+ AppService,
99
+ {
100
+ provide: APP_GUARD,
101
+ useClass: JwtAuthGuard, //<---
102
+ },
103
+ ],
104
+ });
105
+ ```
106
+
107
+ ```ts
108
+ // users.controller.ts
109
+ import { Public, Private } from "@impactor/nest";
110
+
111
+ @Controller()
112
+ @Private() //<--- lock all routes
113
+ export class UsersController {
114
+ @Pot()
115
+ addUser() {}
116
+
117
+ @Get()
118
+ @Public() //<--- allow this route
119
+ getUserById() {}
120
+
121
+ @Get()
122
+ @Roles("admin", "moderators") //<--- limit access to admins and moderators only
123
+ getAllUsers() {}
124
+ }
125
+ ```
45
126
 
46
127
  ## Features
47
128
 
48
129
  - `BasicModule`
130
+ - `createApp()`: create a Nest app [learn more](./README.createApp.md)
49
131
  - `createMicroservice()`: create a microservice
132
+ - `generate-metadata`: generate Swagger metadata
package/index.d.ts CHANGED
@@ -38,3 +38,4 @@ export * from './src/decorators/controller/route-handler';
38
38
  export * from './src/decorators/controller/services/crud-typeorm.service';
39
39
  export * from './src/decorators/controller/types';
40
40
  export * from './src/decorators/controller/utils/merge-options';
41
+ export * from './src/decorators/entity.decorator';
package/package.json CHANGED
@@ -1,11 +1,13 @@
1
1
  {
2
2
  "name": "@impactor/nest",
3
- "version": "3.0.0",
3
+ "version": "3.0.2",
4
4
  "type": "module",
5
5
  "description": "utils for NestJs. Automatically generate APIs and crud operators for NestJs apps",
6
6
  "private": false,
7
7
  "publishConfig": {
8
- "access": "public"
8
+ "access": "public",
9
+ "directory": "dist",
10
+ "linkDirectory": false
9
11
  },
10
12
  "nx": {
11
13
  "projectType": "library",
@@ -55,11 +57,11 @@
55
57
  "typeorm": "^0.3.28",
56
58
  "winston": "^3.19.0",
57
59
  "@fastify/multipart": "^9.3.0",
58
- "@impactor/javascript": "3.0.2",
59
- "@impactor/nodejs": "3.0.2",
60
60
  "@nestjs/passport": "^11.0.5",
61
61
  "merge-anything": "^6.0.6",
62
- "reflect-metadata": "^0.2.2"
62
+ "reflect-metadata": "^0.2.2",
63
+ "@impactor/javascript": "^3.0.2",
64
+ "@impactor/nodejs": "^3.0.2"
63
65
  },
64
66
  "devDependencies": {
65
67
  "@types/amqplib": "^0.10.8",
@@ -12,9 +12,11 @@ export interface IAppConfig extends NestApplicationOptions {
12
12
  prefix?: string | IPrefix;
13
13
  versioning?: VersioningOptions;
14
14
  swagger?: Partial<Omit<OpenAPIObject, 'paths'>>;
15
+ swaggerPath?: string;
15
16
  multipart?: boolean;
16
17
  validationPipe?: ValidationPipeOptions;
17
18
  package?: string | Record<string, unknown>;
19
+ registerEntities?: boolean | Function[];
18
20
  onServerRun?: (app: IApp) => void | Promise<void>;
19
21
  onServerError?: (error: Error, app: IApp) => void | Promise<void>;
20
22
  }
@@ -37,6 +37,7 @@ const appConfig = {
37
37
  }
38
38
  }
39
39
  },
40
+ swaggerPath: '',
40
41
  versioning: {
41
42
  defaultVersion: [
42
43
  '1.0'
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/configs/app.ts"],"sourcesContent":["import { logger } from '../utils/logger';\nimport {\n ValidationPipeOptions,\n type VersioningOptions,\n VersioningType,\n} from '@nestjs/common';\nimport type {\n GlobalPrefixOptions,\n NestApplicationOptions,\n} from '@nestjs/common/interfaces';\nimport { NestExpressApplication } from '@nestjs/platform-express';\nimport { NestFastifyApplication } from '@nestjs/platform-fastify/interfaces';\nimport { OpenAPIObject } from '@nestjs/swagger';\n\nexport type IApp = NestFastifyApplication | NestExpressApplication;\nexport interface IPrefix extends GlobalPrefixOptions {\n prefix: string;\n}\n\n// todo: adaptor: fastify | express = fastify\nexport interface IAppConfig extends NestApplicationOptions {\n /**\n * The port that the app will listen to\n * if not provided, `app.listen()` is not called\n */\n port?: string | number;\n /** the global prefix for every HTTP route path. see Nest.setGlobalPrefix() */\n prefix?: string | IPrefix;\n versioning?: VersioningOptions;\n /**\n * Swagger API spec.\n * https://spec.openapis.org/oas\n */\n swagger?: Partial<Omit<OpenAPIObject, 'paths'>>;\n /** whether to enable parsing multiPart */\n multipart?: boolean;\n /**\n * validation pipe options\n */\n validationPipe?: ValidationPipeOptions;\n /**\n * package.json absolute path or object, or the path of the project root dir\n * used to extract info for Swagger docs, such as title, description, and version.\n */\n // todo: import IPackage interface from @impactor/javascript (move from @impactor/nx-manager)\n package?: string | Record<string, unknown>;\n /**\n * a hook that executed when the server runs and listens to the specified port\n * get the server by app.getHttpServer()\n */\n onServerRun?: (app: IApp) => void | Promise<void>;\n onServerError?: (error: Error, app: IApp) => void | Promise<void>;\n}\n\n/**\n * the default app configs\n */\nexport const appConfig: IAppConfig = {\n port: process.env.PORT,\n prefix: { prefix: 'api', exclude: ['sitemap.xml', 'robots.txt'] },\n // or use `DocumentBuilder` from \"@nestjs/swagger\"\n swagger: {\n openapi: '3.1.0',\n info: { title: 'API', version: '1.0' },\n components: {\n securitySchemes: {\n // add `@ApiBearerAuth()` to controllers which you need to check their bearer auth header\n bearer: {\n scheme: 'bearer',\n bearerFormat: 'JWT',\n type: 'http',\n },\n },\n },\n },\n versioning: {\n defaultVersion: ['1.0'],\n type: VersioningType.URI,\n },\n // cors: {\n // // todo: add APP_URL or localhost by default\n // origin: '*',\n // methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',\n // allowedHeaders: '*',\n // },\n onServerRun: async (app) => {\n logger.log(`running at ${await app.getUrl()}`);\n logger.log(`Env: ${process.env.NODE_ENV}`);\n if (process.env.DB_NAME) {\n logger.log(\n `database: ${process.env.DB_NAME}@${process.env.DB_HOST || 'localhost'}`,\n );\n }\n },\n onServerError: (error, _app) => {\n logger.error(`Server failed to run`);\n throw error;\n },\n};\n"],"names":["appConfig","port","process","env","PORT","prefix","exclude","swagger","openapi","info","title","version","components","securitySchemes","bearer","scheme","bearerFormat","type","versioning","defaultVersion","VersioningType","URI","onServerRun","app","logger","log","getUrl","NODE_ENV","DB_NAME","DB_HOST","onServerError","error","_app"],"mappings":";;;;+BAyDaA;;;eAAAA;;;wBAzDU;wBAKhB;AAoDA,MAAMA,YAAwB;IACnCC,MAAMC,QAAQC,GAAG,CAACC,IAAI;IACtBC,QAAQ;QAAEA,QAAQ;QAAOC,SAAS;YAAC;YAAe;SAAa;IAAC;IAChE,kDAAkD;IAClDC,SAAS;QACPC,SAAS;QACTC,MAAM;YAAEC,OAAO;YAAOC,SAAS;QAAM;QACrCC,YAAY;YACVC,iBAAiB;gBACf,yFAAyF;gBACzFC,QAAQ;oBACNC,QAAQ;oBACRC,cAAc;oBACdC,MAAM;gBACR;YACF;QACF;IACF;IACAC,YAAY;QACVC,gBAAgB;YAAC;SAAM;QACvBF,MAAMG,sBAAc,CAACC,GAAG;IAC1B;IACA,UAAU;IACV,iDAAiD;IACjD,iBAAiB;IACjB,+CAA+C;IAC/C,yBAAyB;IACzB,KAAK;IACLC,aAAa,OAAOC;QAClBC,cAAM,CAACC,GAAG,CAAC,CAAC,WAAW,EAAE,MAAMF,IAAIG,MAAM,IAAI;QAC7CF,cAAM,CAACC,GAAG,CAAC,CAAC,KAAK,EAAEvB,QAAQC,GAAG,CAACwB,QAAQ,EAAE;QACzC,IAAIzB,QAAQC,GAAG,CAACyB,OAAO,EAAE;YACvBJ,cAAM,CAACC,GAAG,CACR,CAAC,UAAU,EAAEvB,QAAQC,GAAG,CAACyB,OAAO,CAAC,CAAC,EAAE1B,QAAQC,GAAG,CAAC0B,OAAO,IAAI,aAAa;QAE5E;IACF;IACAC,eAAe,CAACC,OAAOC;QACrBR,cAAM,CAACO,KAAK,CAAC,CAAC,oBAAoB,CAAC;QACnC,MAAMA;IACR;AACF"}
1
+ {"version":3,"sources":["../../../src/configs/app.ts"],"sourcesContent":["import { logger } from '../utils/logger';\nimport {\n ValidationPipeOptions,\n type VersioningOptions,\n VersioningType,\n} from '@nestjs/common';\nimport type {\n GlobalPrefixOptions,\n NestApplicationOptions,\n} from '@nestjs/common/interfaces';\nimport { NestExpressApplication } from '@nestjs/platform-express';\nimport { NestFastifyApplication } from '@nestjs/platform-fastify/interfaces';\nimport { OpenAPIObject } from '@nestjs/swagger';\n\nexport type IApp = NestFastifyApplication | NestExpressApplication;\nexport interface IPrefix extends GlobalPrefixOptions {\n prefix: string;\n}\n\n// todo: adaptor: fastify | express = fastify\nexport interface IAppConfig extends NestApplicationOptions {\n /**\n * The port that the app will listen to\n * if not provided, `app.listen()` is not called\n */\n port?: string | number;\n /** the global prefix for every HTTP route path. see Nest.setGlobalPrefix() */\n prefix?: string | IPrefix;\n versioning?: VersioningOptions;\n /**\n * Swagger API spec.\n * https://spec.openapis.org/oas\n */\n swagger?: Partial<Omit<OpenAPIObject, 'paths'>>;\n /**\n * The path to the Swagger UI page\n * @default ''\n */\n swaggerPath?: string;\n /** whether to enable parsing multiPart */\n multipart?: boolean;\n /**\n * validation pipe options\n */\n validationPipe?: ValidationPipeOptions;\n /**\n * package.json absolute path or object, or the path of the project root dir\n * used to extract info for Swagger docs, such as title, description, and version.\n */\n // todo: import IPackage interface from @impactor/javascript (move from @impactor/nx-manager)\n package?: string | Record<string, unknown>;\n /**\n * weather to register entities to automatically generate Swagger and class-validator decorators\n * You can specify list of models to be registered\n */\n registerEntities?: boolean | Function[];\n /**\n * a hook that executed when the server runs and listens to the specified port\n * get the server by app.getHttpServer()\n */\n onServerRun?: (app: IApp) => void | Promise<void>;\n onServerError?: (error: Error, app: IApp) => void | Promise<void>;\n}\n\n/**\n * the default app configs\n */\nexport const appConfig: IAppConfig = {\n port: process.env.PORT,\n prefix: { prefix: 'api', exclude: ['sitemap.xml', 'robots.txt'] },\n // or use `DocumentBuilder` from \"@nestjs/swagger\"\n swagger: {\n openapi: '3.1.0',\n info: { title: 'API', version: '1.0' },\n components: {\n securitySchemes: {\n // add `@ApiBearerAuth()` to controllers which you need to check their bearer auth header\n bearer: {\n scheme: 'bearer',\n bearerFormat: 'JWT',\n type: 'http',\n },\n },\n },\n },\n swaggerPath: '',\n versioning: {\n defaultVersion: ['1.0'],\n type: VersioningType.URI,\n },\n // cors: {\n // // todo: add APP_URL or localhost by default\n // origin: '*',\n // methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',\n // allowedHeaders: '*',\n // },\n onServerRun: async (app) => {\n logger.log(`running at ${await app.getUrl()}`);\n logger.log(`Env: ${process.env.NODE_ENV}`);\n if (process.env.DB_NAME) {\n logger.log(\n `database: ${process.env.DB_NAME}@${process.env.DB_HOST || 'localhost'}`,\n );\n }\n },\n onServerError: (error, _app) => {\n logger.error(`Server failed to run`);\n throw error;\n },\n};\n"],"names":["appConfig","port","process","env","PORT","prefix","exclude","swagger","openapi","info","title","version","components","securitySchemes","bearer","scheme","bearerFormat","type","swaggerPath","versioning","defaultVersion","VersioningType","URI","onServerRun","app","logger","log","getUrl","NODE_ENV","DB_NAME","DB_HOST","onServerError","error","_app"],"mappings":";;;;+BAmEaA;;;eAAAA;;;wBAnEU;wBAKhB;AA8DA,MAAMA,YAAwB;IACnCC,MAAMC,QAAQC,GAAG,CAACC,IAAI;IACtBC,QAAQ;QAAEA,QAAQ;QAAOC,SAAS;YAAC;YAAe;SAAa;IAAC;IAChE,kDAAkD;IAClDC,SAAS;QACPC,SAAS;QACTC,MAAM;YAAEC,OAAO;YAAOC,SAAS;QAAM;QACrCC,YAAY;YACVC,iBAAiB;gBACf,yFAAyF;gBACzFC,QAAQ;oBACNC,QAAQ;oBACRC,cAAc;oBACdC,MAAM;gBACR;YACF;QACF;IACF;IACAC,aAAa;IACbC,YAAY;QACVC,gBAAgB;YAAC;SAAM;QACvBH,MAAMI,sBAAc,CAACC,GAAG;IAC1B;IACA,UAAU;IACV,iDAAiD;IACjD,iBAAiB;IACjB,+CAA+C;IAC/C,yBAAyB;IACzB,KAAK;IACLC,aAAa,OAAOC;QAClBC,cAAM,CAACC,GAAG,CAAC,CAAC,WAAW,EAAE,MAAMF,IAAIG,MAAM,IAAI;QAC7CF,cAAM,CAACC,GAAG,CAAC,CAAC,KAAK,EAAExB,QAAQC,GAAG,CAACyB,QAAQ,EAAE;QACzC,IAAI1B,QAAQC,GAAG,CAAC0B,OAAO,EAAE;YACvBJ,cAAM,CAACC,GAAG,CACR,CAAC,UAAU,EAAExB,QAAQC,GAAG,CAAC0B,OAAO,CAAC,CAAC,EAAE3B,QAAQC,GAAG,CAAC2B,OAAO,IAAI,aAAa;QAE5E;IACF;IACAC,eAAe,CAACC,OAAOC;QACrBR,cAAM,CAACO,KAAK,CAAC,CAAC,oBAAoB,CAAC;QACnC,MAAMA;IACR;AACF"}
package/src/create-app.js CHANGED
@@ -18,6 +18,7 @@ const _javascript = require("@impactor/javascript");
18
18
  const _nodejs = require("@impactor/nodejs");
19
19
  const _generatemetadata = require("./generate-metadata");
20
20
  const _logger = require("./utils/logger");
21
+ const _registerentities = require("./register-entities");
21
22
  function _interop_require_default(obj) {
22
23
  return obj && obj.__esModule ? obj : {
23
24
  default: obj
@@ -62,6 +63,14 @@ function createApp(module, options) {
62
63
  forbidNonWhitelisted: true,
63
64
  ...opts.validationPipe
64
65
  }));
66
+ // this must be before registering Swagger
67
+ if (opts.registerEntities !== false) {
68
+ if (Array.isArray(opts.registerEntities)) {
69
+ (0, _registerentities.registerEntities)(opts.registerEntities);
70
+ } else {
71
+ (0, _registerentities.registerEntities)();
72
+ }
73
+ }
65
74
  // swagger docs
66
75
  // navigate to localhost:PORT to see API docs
67
76
  // navigate to localhost:PORT/-json to download the API json file
@@ -87,7 +96,7 @@ function createApp(module, options) {
87
96
  });
88
97
  if (opts.swagger) {
89
98
  let document = _swagger.SwaggerModule.createDocument(app, opts.swagger);
90
- _swagger.SwaggerModule.setup('', app, document);
99
+ _swagger.SwaggerModule.setup(opts.swaggerPath || '', app, document);
91
100
  }
92
101
  }
93
102
  // todo: import `FastifyMulterModule` from '@nest-lab/fastify-multer' in the module
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/create-app.ts"],"sourcesContent":["import { NestFactory } from '@nestjs/core';\nimport { OpenAPIObject, SwaggerModule } from '@nestjs/swagger';\nimport {\n FastifyAdapter,\n type NestFastifyApplication,\n} from '@nestjs/platform-fastify';\nimport multiPart from '@fastify/multipart';\nimport { type IAppConfig, appConfig } from './configs/app';\nimport { ValidationPipe } from '@nestjs/common';\nimport { merge } from '@impactor/javascript';\nimport { isDirSync, readSync } from '@impactor/nodejs';\nimport {\n generateSwaggerMetadata,\n loadSwaggerMetadata,\n} from './generate-metadata';\nimport { logger } from './utils/logger';\n\n// todo: add type to `module`\nexport function createApp(module: any, options?: IAppConfig) {\n // todo: options.adapter = fastify | express\n return NestFactory.create<NestFastifyApplication>(\n module,\n new FastifyAdapter(),\n options,\n ).then(async (app) => {\n let pkg = (\n typeof options?.package === 'string'\n ? isDirSync(options.package)\n ? // todo: use IPackage interface\n readSync(`${options.package}/package.json`)\n : readSync(options.package)\n : options?.package || {}\n ) as Record<string, string>;\n\n let opts = merge(\n [\n appConfig,\n {\n swagger: {\n info: {\n title: pkg.name,\n description:\n pkg.description || `${pkg.name ? `${pkg.name} ` : ''}API`,\n version: `v${pkg.version || '1.0'}`,\n },\n },\n },\n options,\n ],\n {\n deep: true,\n },\n ) as IAppConfig;\n\n if (opts?.prefix) {\n if (typeof opts.prefix === 'string') {\n app.setGlobalPrefix(opts.prefix);\n } else {\n let { prefix, ...prefixOptions } = opts.prefix;\n app.setGlobalPrefix(prefix, prefixOptions);\n }\n }\n\n if (opts.versioning) {\n app.enableVersioning(opts.versioning);\n }\n\n app.useGlobalPipes(\n new ValidationPipe({\n // apply class-transformer decorators, such as @Transform()\n transform: true,\n // Strip out any properties that are not defined in your DTO.\n whitelist: true,\n // Instead of silently removing unknown fields, it throws a 400 error.\n forbidNonWhitelisted: true,\n ...opts.validationPipe,\n }),\n );\n\n // swagger docs\n // navigate to localhost:PORT to see API docs\n // navigate to localhost:PORT/-json to download the API json file\n if (opts.swagger) {\n // emit swagger metadata\n // this file will be generated in runtime\n // todo: when emitting swagger metadata using generateSwaggerMetadata(),\n // the TSDocs comments are no longer read by nest,\n // and we must manually add @ApiProperty() to all properties\n let metadataPath = generateSwaggerMetadata({\n // @ts-ignore `import.meta` requires `module: nodeNext`\n outputDir: import.meta.dirname,\n // fixes: src/nest-swagger-metadata.ts:2:1 - error TS2742:\n // The inferred type of 'default' cannot be named without a reference to '../node_modules/@impactor/utils/src/dto/order.dto'.\n // This is likely not portable. A type annotation is necessary.\n transform: (content) =>\n content.replaceAll('../node_modules/@impactor/', '@impactor/'),\n });\n\n // todo: the file by default is related to CWD(),\n // change cwd of the target \"serve\" in nx.json to \"{projectRoot}/dist\"\n await loadSwaggerMetadata(metadataPath)\n .then(() => logger.debug('Swagger metadata loaded'))\n // ignore if the metadata file hasn't generated\n .catch((error) => {\n logger.warn(`Failed to load Swagger metadata`, error);\n });\n\n if (opts.swagger) {\n let document = SwaggerModule.createDocument(\n app,\n opts.swagger as OpenAPIObject,\n );\n SwaggerModule.setup('', app, document);\n }\n }\n\n // todo: import `FastifyMulterModule` from '@nest-lab/fastify-multer' in the module\n // that wants to receive files, instead of registering 'multipart' globally\n if (opts.multipart !== false) {\n await app.register(multiPart);\n }\n\n return opts.port\n ? app\n // if the server runs inside a container, it should bound to '0.0.0.0' instead of 'localhost' (the default)\n // so it can listen to the external requests i.e. from the browser\n .listen(opts.port, '0.0.0.0')\n .then((_server) => opts.onServerRun?.(app))\n .catch((error) => opts.onServerError?.(error, app))\n .then(() => app)\n : app;\n });\n}\n"],"names":["createApp","module","options","NestFactory","create","FastifyAdapter","then","app","pkg","package","isDirSync","readSync","opts","merge","appConfig","swagger","info","title","name","description","version","deep","prefix","setGlobalPrefix","prefixOptions","versioning","enableVersioning","useGlobalPipes","ValidationPipe","transform","whitelist","forbidNonWhitelisted","validationPipe","metadataPath","generateSwaggerMetadata","outputDir","content","replaceAll","loadSwaggerMetadata","logger","debug","catch","error","warn","document","SwaggerModule","createDocument","setup","multipart","register","multiPart","port","listen","_server","onServerRun","onServerError"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/create-app.ts"],"sourcesContent":["import { NestFactory } from '@nestjs/core';\nimport { OpenAPIObject, SwaggerModule } from '@nestjs/swagger';\nimport {\n FastifyAdapter,\n type NestFastifyApplication,\n} from '@nestjs/platform-fastify';\nimport multiPart from '@fastify/multipart';\nimport { type IAppConfig, appConfig } from './configs/app';\nimport { ValidationPipe } from '@nestjs/common';\nimport { merge } from '@impactor/javascript';\nimport { isDirSync, readSync } from '@impactor/nodejs';\nimport {\n generateSwaggerMetadata,\n loadSwaggerMetadata,\n} from './generate-metadata';\nimport { logger } from './utils/logger';\nimport { registerEntities } from './register-entities';\n\n// todo: add type to `module`\nexport function createApp(module: any, options?: IAppConfig) {\n // todo: options.adapter = fastify | express\n return NestFactory.create<NestFastifyApplication>(\n module,\n new FastifyAdapter(),\n options,\n ).then(async (app) => {\n let pkg = (\n typeof options?.package === 'string'\n ? isDirSync(options.package)\n ? // todo: use IPackage interface\n readSync(`${options.package}/package.json`)\n : readSync(options.package)\n : options?.package || {}\n ) as Record<string, string>;\n\n let opts = merge(\n [\n appConfig,\n {\n swagger: {\n info: {\n title: pkg.name,\n description:\n pkg.description || `${pkg.name ? `${pkg.name} ` : ''}API`,\n version: `v${pkg.version || '1.0'}`,\n },\n },\n },\n options,\n ],\n {\n deep: true,\n },\n ) as IAppConfig;\n\n if (opts?.prefix) {\n if (typeof opts.prefix === 'string') {\n app.setGlobalPrefix(opts.prefix);\n } else {\n let { prefix, ...prefixOptions } = opts.prefix;\n app.setGlobalPrefix(prefix, prefixOptions);\n }\n }\n\n if (opts.versioning) {\n app.enableVersioning(opts.versioning);\n }\n\n app.useGlobalPipes(\n new ValidationPipe({\n // apply class-transformer decorators, such as @Transform()\n transform: true,\n // Strip out any properties that are not defined in your DTO.\n whitelist: true,\n // Instead of silently removing unknown fields, it throws a 400 error.\n forbidNonWhitelisted: true,\n ...opts.validationPipe,\n }),\n );\n\n // this must be before registering Swagger\n if (opts.registerEntities !== false) {\n if (Array.isArray(opts.registerEntities)) {\n registerEntities(opts.registerEntities);\n } else {\n registerEntities();\n }\n }\n\n // swagger docs\n // navigate to localhost:PORT to see API docs\n // navigate to localhost:PORT/-json to download the API json file\n if (opts.swagger) {\n // emit swagger metadata\n // this file will be generated in runtime\n // todo: when emitting swagger metadata using generateSwaggerMetadata(),\n // the TSDocs comments are no longer read by nest,\n // and we must manually add @ApiProperty() to all properties\n let metadataPath = generateSwaggerMetadata({\n // @ts-ignore `import.meta` requires `module: nodeNext`\n outputDir: import.meta.dirname,\n // fixes: src/nest-swagger-metadata.ts:2:1 - error TS2742:\n // The inferred type of 'default' cannot be named without a reference to '../node_modules/@impactor/utils/src/dto/order.dto'.\n // This is likely not portable. A type annotation is necessary.\n transform: (content) =>\n content.replaceAll('../node_modules/@impactor/', '@impactor/'),\n });\n\n // todo: the file by default is related to CWD(),\n // change cwd of the target \"serve\" in nx.json to \"{projectRoot}/dist\"\n await loadSwaggerMetadata(metadataPath)\n .then(() => logger.debug('Swagger metadata loaded'))\n // ignore if the metadata file hasn't generated\n .catch((error) => {\n logger.warn(`Failed to load Swagger metadata`, error);\n });\n\n if (opts.swagger) {\n let document = SwaggerModule.createDocument(\n app,\n opts.swagger as OpenAPIObject,\n );\n SwaggerModule.setup(opts.swaggerPath || '', app, document);\n }\n }\n\n // todo: import `FastifyMulterModule` from '@nest-lab/fastify-multer' in the module\n // that wants to receive files, instead of registering 'multipart' globally\n if (opts.multipart !== false) {\n await app.register(multiPart);\n }\n\n return opts.port\n ? app\n // if the server runs inside a container, it should bound to '0.0.0.0' instead of 'localhost' (the default)\n // so it can listen to the external requests i.e. from the browser\n .listen(opts.port, '0.0.0.0')\n .then((_server) => opts.onServerRun?.(app))\n .catch((error) => opts.onServerError?.(error, app))\n .then(() => app)\n : app;\n });\n}\n"],"names":["createApp","module","options","NestFactory","create","FastifyAdapter","then","app","pkg","package","isDirSync","readSync","opts","merge","appConfig","swagger","info","title","name","description","version","deep","prefix","setGlobalPrefix","prefixOptions","versioning","enableVersioning","useGlobalPipes","ValidationPipe","transform","whitelist","forbidNonWhitelisted","validationPipe","registerEntities","Array","isArray","metadataPath","generateSwaggerMetadata","outputDir","content","replaceAll","loadSwaggerMetadata","logger","debug","catch","error","warn","document","SwaggerModule","createDocument","setup","swaggerPath","multipart","register","multiPart","port","listen","_server","onServerRun","onServerError"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { EntityOptions } from 'typeorm';
2
+ export interface IEntityOptions extends EntityOptions {
3
+ name?: string;
4
+ }
5
+ export declare function Entity(name?: string, options?: EntityOptions): ClassDecorator;
6
+ export declare function Hide(): PropertyDecorator;
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get Entity () {
13
+ return Entity;
14
+ },
15
+ get Hide () {
16
+ return Hide;
17
+ }
18
+ });
19
+ const _registerentities = require("../register-entities");
20
+ const _typeorm = require("typeorm");
21
+ const _StringUtils = require("typeorm/util/StringUtils");
22
+ function Entity(name, options) {
23
+ return (target)=>{
24
+ new EntityFactory(target, {
25
+ name,
26
+ ...options
27
+ });
28
+ };
29
+ }
30
+ let EntityFactory = class EntityFactory {
31
+ /**
32
+ * decorate the class with TypeORM `@Entity()`
33
+ */ addEntity() {
34
+ // TypeORM's `@Entity()` adds the class to storage.tables
35
+ if (!this.storage.tables.some((el)=>el.target === this.model)) {
36
+ Reflect.decorate([
37
+ (0, _typeorm.Entity)(this.options?.name || // todo: generate plural names
38
+ (0, _StringUtils.snakeCase)(this.model.name.replace(/(Entity|DTO|Model)$/i, '') + 's'), this.options)
39
+ ], this.model);
40
+ }
41
+ }
42
+ /**
43
+ * add Swagger decorators to all the model fields
44
+ */ addSwaggerDecorators() {
45
+ // todo: also get the class that this.model extends, if any.
46
+ (0, _registerentities.registerEntities)([
47
+ this.model
48
+ ]);
49
+ }
50
+ constructor(model, options){
51
+ this.model = model;
52
+ this.options = options;
53
+ /**
54
+ * contains all TypeORM metadata for all entities
55
+ */ this.storage = (0, _typeorm.getMetadataArgsStorage)();
56
+ this.addEntity();
57
+ this.addSwaggerDecorators();
58
+ }
59
+ };
60
+ function Hide() {
61
+ return (target, key)=>{
62
+ Reflect.defineMetadata('swagger/apiModelProperties', false, target, key);
63
+ };
64
+ }
65
+
66
+ //# sourceMappingURL=entity.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/decorators/entity.decorator.ts"],"sourcesContent":["import { registerEntities } from '../register-entities';\nimport {\n Entity as TypeORMEntity,\n EntityOptions,\n getMetadataArgsStorage,\n} from 'typeorm';\nimport { MetadataArgsStorage } from 'typeorm/metadata-args/MetadataArgsStorage';\nimport { snakeCase } from 'typeorm/util/StringUtils';\n\nexport interface IEntityOptions extends EntityOptions {\n name?: string;\n}\n\n/**\n * Define a class as a TypeORM entity\n * - add Swagger decorators to all columns\n *\n * note: currently, this decorator ignores `@ApiHideProperty()`\n * use `@Hide()` instead\n * https://github.com/nestjs/swagger/issues/3711\n */\n// todo: add basic columns such as id, created_at, updated_at\n// this has a downside, that TS cannot detect props that are defined dynamically\n// i.e. `Model.id` will cause a TS error\n// todo: add class validator decorators from column definition\n// for instance `@Column(type: 'varchar', length: 200)` -> `@IsString() @MaxLength(200)`\n// note that we cannot access uninitialized classes properties,\n// so `this.model[col.propertyName]` is always undefined,\n// also Reflect methods cannot be used to decorate those properties as they are not existing\n// otherwise use a property decorator to work with each property separately\n// todo: create `@Column()` decorator to apply these steps on property-level\n// this has a downside: it'll use the property name rather than the final column name,\n// because TypeORM may rename the column using a naming strategy\n// so, we need to access the naming strategy to apply it on each prop\nexport function Entity(name?: string, options?: EntityOptions): ClassDecorator {\n return (target: Function) => {\n new EntityFactory(target, { name, ...options });\n };\n}\n\nclass EntityFactory {\n /**\n * contains all TypeORM metadata for all entities\n */\n private storage: MetadataArgsStorage = getMetadataArgsStorage();\n\n constructor(\n private model: Function,\n private options?: IEntityOptions,\n ) {\n this.addEntity();\n this.addSwaggerDecorators();\n }\n\n /**\n * decorate the class with TypeORM `@Entity()`\n */\n addEntity() {\n // TypeORM's `@Entity()` adds the class to storage.tables\n if (!this.storage.tables.some((el) => el.target === this.model)) {\n Reflect.decorate(\n [\n TypeORMEntity(\n this.options?.name ||\n // todo: generate plural names\n snakeCase(\n this.model.name.replace(/(Entity|DTO|Model)$/i, '') + 's',\n ),\n this.options,\n ),\n ],\n this.model,\n );\n }\n }\n\n /**\n * add Swagger decorators to all the model fields\n */\n addSwaggerDecorators() {\n // todo: also get the class that this.model extends, if any.\n registerEntities([this.model]);\n }\n}\n\n/**\n * add `@Hide()` to properties that you don't want to hide in Swagger\n * Using `@ApiHideProperty()` from `@nestjs/swagger` is not supported\n * `@ApiHideProperty()` doesn't add a metadata -> use `@Hide()`\n * https://github.com/nestjs/swagger/blob/master/lib/decorators/api-hide-property.decorator.ts\n */\nexport function Hide(): PropertyDecorator {\n return (target: Object, key: string | symbol) => {\n Reflect.defineMetadata('swagger/apiModelProperties', false, target, key);\n };\n}\n"],"names":["Entity","Hide","name","options","target","EntityFactory","addEntity","storage","tables","some","el","model","Reflect","decorate","TypeORMEntity","snakeCase","replace","addSwaggerDecorators","registerEntities","getMetadataArgsStorage","key","defineMetadata"],"mappings":";;;;;;;;;;;QAkCgBA;eAAAA;;QAyDAC;eAAAA;;;kCA3FiB;yBAK1B;6BAEmB;AA2BnB,SAASD,OAAOE,IAAa,EAAEC,OAAuB;IAC3D,OAAO,CAACC;QACN,IAAIC,cAAcD,QAAQ;YAAEF;YAAM,GAAGC,OAAO;QAAC;IAC/C;AACF;AAEA,IAAA,AAAME,gBAAN,MAAMA;IAcJ;;GAEC,GACDC,YAAY;QACV,yDAAyD;QACzD,IAAI,CAAC,IAAI,CAACC,OAAO,CAACC,MAAM,CAACC,IAAI,CAAC,CAACC,KAAOA,GAAGN,MAAM,KAAK,IAAI,CAACO,KAAK,GAAG;YAC/DC,QAAQC,QAAQ,CACd;gBACEC,IAAAA,eAAa,EACX,IAAI,CAACX,OAAO,EAAED,QACZ,8BAA8B;gBAC9Ba,IAAAA,sBAAS,EACP,IAAI,CAACJ,KAAK,CAACT,IAAI,CAACc,OAAO,CAAC,wBAAwB,MAAM,MAE1D,IAAI,CAACb,OAAO;aAEf,EACD,IAAI,CAACQ,KAAK;QAEd;IACF;IAEA;;GAEC,GACDM,uBAAuB;QACrB,4DAA4D;QAC5DC,IAAAA,kCAAgB,EAAC;YAAC,IAAI,CAACP,KAAK;SAAC;IAC/B;IApCA,YACE,AAAQA,KAAe,EACvB,AAAQR,OAAwB,CAChC;aAFQQ,QAAAA;aACAR,UAAAA;QAPV;;GAEC,QACOI,UAA+BY,IAAAA,+BAAsB;QAM3D,IAAI,CAACb,SAAS;QACd,IAAI,CAACW,oBAAoB;IAC3B;AA+BF;AAQO,SAAShB;IACd,OAAO,CAACG,QAAgBgB;QACtBR,QAAQS,cAAc,CAAC,8BAA8B,OAAOjB,QAAQgB;IACtE;AACF"}
@@ -51,14 +51,18 @@ function _interop_require_wildcard(obj, nodeInterop) {
51
51
  }
52
52
  const _default = async ()=>{
53
53
  const t = {
54
+ ["../../../apps/edu-backend/src/types/approve-status.enum"]: await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../../apps/edu-backend/src/types/approve-status.enum"))),
54
55
  ["../../../apps/edu-backend/src/api/users/entities/user.entity"]: await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../../apps/edu-backend/src/api/users/entities/user.entity"))),
55
56
  ["../../../apps/edu-backend/src/types/schedule"]: await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../../apps/edu-backend/src/types/schedule"))),
56
57
  ["../../../apps/edu-backend/src/api/cards/entities/card.entity"]: await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../../apps/edu-backend/src/api/cards/entities/card.entity"))),
57
58
  ["../../../apps/edu-backend/src/api/card-templates/entities/card-template.entity"]: await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../../apps/edu-backend/src/api/card-templates/entities/card-template.entity"))),
58
59
  ["../../../apps/edu-backend/src/api/notes/entities/note.entity"]: await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../../apps/edu-backend/src/api/notes/entities/note.entity"))),
60
+ ["../../../apps/edu-backend/src/api/schedule/entities/schedule.entity"]: await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../../apps/edu-backend/src/api/schedule/entities/schedule.entity"))),
61
+ ["../../../apps/edu-backend/src/api/review-history/entities/review-history.entity"]: await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../../apps/edu-backend/src/api/review-history/entities/review-history.entity"))),
59
62
  ["../../../apps/edu-backend/src/api/note-types/entities/note-type.entity"]: await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../../apps/edu-backend/src/api/note-types/entities/note-type.entity"))),
60
63
  ["../../../apps/edu-backend/src/api/note-fields/entities/note-field.entity"]: await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../../apps/edu-backend/src/api/note-fields/entities/note-field.entity"))),
61
- ["../../../apps/edu-backend/src/types/countries.enum"]: await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../../apps/edu-backend/src/types/countries.enum")))
64
+ ["../../../apps/edu-backend/src/types/countries.enum"]: await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../../apps/edu-backend/src/types/countries.enum"))),
65
+ ["../../../apps/edu-backend/src/api/collections/entities/collection.entity"]: await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../../apps/edu-backend/src/api/collections/entities/collection.entity")))
62
66
  };
63
67
  return {
64
68
  "@nestjs/swagger": {
@@ -67,6 +71,20 @@ const _default = async ()=>{
67
71
  Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../../apps/edu-backend/src/utils/basic.entity"))),
68
72
  {
69
73
  "BasicEntity": {
74
+ id: {
75
+ required: true,
76
+ type: ()=>String
77
+ },
78
+ _version: {
79
+ required: true,
80
+ type: ()=>Number,
81
+ description: "the version number of the updated row",
82
+ example: 1
83
+ },
84
+ approve_status: {
85
+ required: true,
86
+ enum: t["../../../apps/edu-backend/src/types/approve-status.enum"].ApproveStatus
87
+ },
70
88
  tags: {
71
89
  required: true,
72
90
  type: ()=>[
@@ -164,7 +182,7 @@ const _default = async ()=>{
164
182
  difficulty: {
165
183
  required: false,
166
184
  type: ()=>Number,
167
- description: "FSRS difficulty value.\nControls how quickly stability grows or decays. *",
185
+ description: "FSRS difficulty value.\nControls how quickly stability grows or decays.",
168
186
  minimum: 0
169
187
  },
170
188
  elapsed_days: {
@@ -222,6 +240,16 @@ const _default = async ()=>{
222
240
  note: {
223
241
  required: true,
224
242
  type: ()=>t["../../../apps/edu-backend/src/api/notes/entities/note.entity"].Note
243
+ },
244
+ schedule: {
245
+ required: true,
246
+ type: ()=>t["../../../apps/edu-backend/src/api/schedule/entities/schedule.entity"].Schedule
247
+ },
248
+ reviewHistory: {
249
+ required: true,
250
+ type: ()=>[
251
+ t["../../../apps/edu-backend/src/api/review-history/entities/review-history.entity"].ReviewHistory
252
+ ]
225
253
  }
226
254
  }
227
255
  }
@@ -256,6 +284,12 @@ const _default = async ()=>{
256
284
  type: {
257
285
  required: true,
258
286
  type: ()=>t["../../../apps/edu-backend/src/api/note-types/entities/note-type.entity"].NoteType
287
+ },
288
+ cards: {
289
+ required: true,
290
+ type: ()=>[
291
+ t["../../../apps/edu-backend/src/api/cards/entities/card.entity"].Card
292
+ ]
259
293
  }
260
294
  }
261
295
  }
@@ -348,13 +382,13 @@ const _default = async ()=>{
348
382
  firstName: {
349
383
  required: true,
350
384
  type: ()=>String,
351
- example: "Ali",
385
+ minLength: 2,
352
386
  maxLength: 100
353
387
  },
354
388
  lastName: {
355
389
  required: true,
356
390
  type: ()=>String,
357
- example: "Mostafa",
391
+ minLength: 2,
358
392
  maxLength: 100
359
393
  },
360
394
  gender: {
@@ -368,40 +402,46 @@ const _default = async ()=>{
368
402
  city: {
369
403
  required: true,
370
404
  type: ()=>String,
371
- example: "Cairo",
372
405
  maxLength: 100
373
406
  },
374
407
  email: {
375
408
  required: true,
376
409
  type: ()=>String,
377
- example: "ali.mostafa@gmail.com",
378
410
  format: "email"
379
411
  },
380
412
  mobile: {
381
413
  required: true,
382
414
  type: ()=>String,
383
- description: "the mobile number including the country code",
384
- example: "+14844731795",
385
415
  format: "mobile-phone",
386
416
  pattern: "/^\\+/"
387
417
  },
388
418
  password: {
389
419
  required: true,
390
420
  type: ()=>String,
391
- example: "P@sSwrd",
392
421
  minLength: 8
422
+ },
423
+ role: {
424
+ required: true,
425
+ type: ()=>String,
426
+ enum: t["../../../apps/edu-backend/src/api/users/entities/user.entity"].UserRole
427
+ },
428
+ collections: {
429
+ required: true,
430
+ type: ()=>[
431
+ t["../../../apps/edu-backend/src/api/collections/entities/collection.entity"].Collection
432
+ ]
393
433
  }
394
434
  }
395
435
  }
396
436
  ],
397
437
  [
398
- Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../../apps/edu-backend/node_modules/@impactor/nest-crud/src/dto/empty.dto"))),
438
+ Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../../apps/edu-backend/node_modules/@impactor/nest/src/decorators/controller/dto/empty.dto"))),
399
439
  {
400
440
  "EmptyDto": {}
401
441
  }
402
442
  ],
403
443
  [
404
- Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../../apps/edu-backend/node_modules/@impactor/nest-crud/src/dto/update-response.dto"))),
444
+ Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../../apps/edu-backend/node_modules/@impactor/nest/src/decorators/controller/dto/update-response.dto"))),
405
445
  {
406
446
  "UpdateResponseDto": {
407
447
  affected: {
@@ -468,6 +508,12 @@ const _default = async ()=>{
468
508
  ]
469
509
  ],
470
510
  "controllers": [
511
+ [
512
+ Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../../apps/edu-backend/node_modules/@impactor/nest/src/modules/basic/basic.controller"))),
513
+ {
514
+ "BasicController": {}
515
+ }
516
+ ],
471
517
  [
472
518
  Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../../apps/edu-backend/src/api/auth/auth.controller"))),
473
519
  {
@@ -538,12 +584,6 @@ const _default = async ()=>{
538
584
  "subscribe": {}
539
585
  }
540
586
  }
541
- ],
542
- [
543
- Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../../apps/edu-backend/node_modules/@impactor/nest/src/modules/basic/basic.controller"))),
544
- {
545
- "BasicController": {}
546
- }
547
587
  ]
548
588
  ]
549
589
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/nest-swagger-metadata.js"],"sourcesContent":["/* eslint-disable */\nexport default async () => {\n const t = {\n [\"../../../apps/edu-backend/src/api/users/entities/user.entity\"]: await import(\"../../../apps/edu-backend/src/api/users/entities/user.entity\"),\n [\"../../../apps/edu-backend/src/types/schedule\"]: await import(\"../../../apps/edu-backend/src/types/schedule\"),\n [\"../../../apps/edu-backend/src/api/cards/entities/card.entity\"]: await import(\"../../../apps/edu-backend/src/api/cards/entities/card.entity\"),\n [\"../../../apps/edu-backend/src/api/card-templates/entities/card-template.entity\"]: await import(\"../../../apps/edu-backend/src/api/card-templates/entities/card-template.entity\"),\n [\"../../../apps/edu-backend/src/api/notes/entities/note.entity\"]: await import(\"../../../apps/edu-backend/src/api/notes/entities/note.entity\"),\n [\"../../../apps/edu-backend/src/api/note-types/entities/note-type.entity\"]: await import(\"../../../apps/edu-backend/src/api/note-types/entities/note-type.entity\"),\n [\"../../../apps/edu-backend/src/api/note-fields/entities/note-field.entity\"]: await import(\"../../../apps/edu-backend/src/api/note-fields/entities/note-field.entity\"),\n [\"../../../apps/edu-backend/src/types/countries.enum\"]: await import(\"../../../apps/edu-backend/src/types/countries.enum\")\n };\n return { \"@nestjs/swagger\": { \"models\": [[import(\"../../../apps/edu-backend/src/utils/basic.entity\"), { \"BasicEntity\": { tags: { required: true, type: () => [String], maxLength: 50, maxItems: 20 }, created_by: { required: true, type: () => t[\"../../../apps/edu-backend/src/api/users/entities/user.entity\"].UserEntity } }, \"EntityWithCount\": { data: { required: true }, count: { required: true, type: () => Number } } }], [import(\"../../../apps/edu-backend/src/api/review-history/entities/review-history.entity\"), { \"ReviewHistory\": { rating: { required: true, type: () => Number, description: \"FSRS rating for this review (0 = Again, 1 = Hard, 2 = Good, 3 = Easy)\", minimum: 0 }, state: { required: true, description: \"Current FSRS state of the card\", enum: t[\"../../../apps/edu-backend/src/types/schedule\"].State }, stability: { required: false, type: () => Number, description: \"Stability value controlling retention (can use scaled bigint for performance)\", minimum: 0 }, difficulty: { required: false, type: () => Number, description: \"Difficulty value controlling growth/decay of stability\", minimum: 0 }, elapsed_days: { required: false, type: () => Number, description: \"Days elapsed since last review\", deprecated: true, minimum: 0 }, last_elapsed_days: { required: false, type: () => Number, description: \"Last elapsed days (from previous review)\", deprecated: true, minimum: 0 }, scheduled_days: { required: false, type: () => Number, description: \"Number of scheduled days for this review (can be -1 before scheduling)\" }, learning_steps: { required: false, type: () => Number, description: \"Learning step index (for cards in learning phase)\", minimum: 0 }, card: { required: true, type: () => t[\"../../../apps/edu-backend/src/api/cards/entities/card.entity\"].Card, description: \"Card associated with this review\" } } }], [import(\"../../../apps/edu-backend/src/api/schedule/entities/schedule.entity\"), { \"Schedule\": { stability: { required: false, type: () => Number, description: \"FSRS stability value.\\nRepresents memory retention strength.\", minimum: 0 }, difficulty: { required: false, type: () => Number, description: \"FSRS difficulty value.\\nControls how quickly stability grows or decays. *\", minimum: 0 }, elapsed_days: { required: false, type: () => Number, description: \"Number of days elapsed since the previous review.\\nProvided by FSRS during scheduling.\", deprecated: true, minimum: 0 }, scheduled_days: { required: false, type: () => Number, description: \"Number of days the card was scheduled for at the time of the last review.\", minimum: 0 }, reps: { required: false, type: () => Number, description: \"Total number of successful reviews for the card.\", minimum: 0 }, lapses: { required: false, type: () => Number, description: \"Number of times the card was forgotten, i.e. \\\"Again\\\"\", minimum: 0 }, learning_steps: { required: false, type: () => Number, description: \"Current learning step index.\\nUsed mainly during the learning / relearning phases.\", minimum: 0 }, state: { required: false, description: \"Current FSRS state of the card\\n(New, Learning, Review, Relearning).\", enum: t[\"../../../apps/edu-backend/src/types/schedule\"].State }, card: { required: true, type: () => t[\"../../../apps/edu-backend/src/api/cards/entities/card.entity\"].Card, description: \"The card this schedule belongs to.\" } } }], [import(\"../../../apps/edu-backend/src/api/cards/entities/card.entity\"), { \"Card\": { template: { required: true, type: () => t[\"../../../apps/edu-backend/src/api/card-templates/entities/card-template.entity\"].CardTemplate }, note: { required: true, type: () => t[\"../../../apps/edu-backend/src/api/notes/entities/note.entity\"].Note } } }], [import(\"../../../apps/edu-backend/src/api/card-templates/entities/card-template.entity\"), { \"CardTemplate\": { title: { required: true, type: () => String, maxLength: 200 }, front: { required: true, type: () => String }, back: { required: true, type: () => String }, css: { required: true, type: () => String, description: \"the CSS style, without `<style>`\" }, js: { required: true, type: () => String, description: \"A javascript code to be executed when the card is rendered, including `<script>`\" }, type: { required: true, type: () => t[\"../../../apps/edu-backend/src/api/note-types/entities/note-type.entity\"].NoteType } } }], [import(\"../../../apps/edu-backend/src/api/note-entry/entities/note-entry.entity\"), { \"NoteEntry\": { value: { required: true, type: () => String }, field: { required: true, type: () => t[\"../../../apps/edu-backend/src/api/note-fields/entities/note-field.entity\"].NoteField }, note: { required: true, type: () => t[\"../../../apps/edu-backend/src/api/notes/entities/note.entity\"].Note } } }], [import(\"../../../apps/edu-backend/src/api/note-fields/entities/note-field.entity\"), { \"NoteField\": { title: { required: true, type: () => String, maxLength: 200 }, type: { required: true, description: \"The field type mainly used in UI to create a form field.\\nit also can be used to perform proper queries,\\nfor instance, filtering a number field where its value > a specific number\", enum: t[\"../../../apps/edu-backend/src/api/note-fields/entities/note-field.entity\"].FieldType }, noteType: { required: true, type: () => t[\"../../../apps/edu-backend/src/api/note-types/entities/note-type.entity\"].NoteType } } }], [import(\"../../../apps/edu-backend/src/api/note-types/entities/note-type.entity\"), { \"NoteType\": { title: { required: true, type: () => String }, description: { required: true, type: () => String } } }], [import(\"../../../apps/edu-backend/src/api/notes/entities/note.entity\"), { \"Note\": { type: { required: true, type: () => t[\"../../../apps/edu-backend/src/api/note-types/entities/note-type.entity\"].NoteType } } }], [import(\"../../../apps/edu-backend/src/api/collections/entities/collection.entity\"), { \"Collection\": { title: { required: true, type: () => String }, description: { required: true, type: () => String } } }], [import(\"../../../apps/edu-backend/src/api/users/entities/user.entity\"), { \"UserEntity\": { firstName: { required: true, type: () => String, example: \"Ali\", maxLength: 100 }, lastName: { required: true, type: () => String, example: \"Mostafa\", maxLength: 100 }, gender: { required: true, enum: t[\"../../../apps/edu-backend/src/api/users/entities/user.entity\"].Gender }, country: { required: true, enum: t[\"../../../apps/edu-backend/src/types/countries.enum\"].Country }, city: { required: true, type: () => String, example: \"Cairo\", maxLength: 100 }, email: { required: true, type: () => String, example: \"ali.mostafa@gmail.com\", format: \"email\" }, mobile: { required: true, type: () => String, description: \"the mobile number including the country code\", example: \"+14844731795\", format: \"mobile-phone\", pattern: \"/^\\\\+/\" }, password: { required: true, type: () => String, example: \"P@sSwrd\", minLength: 8 } } }], [import(\"../../../apps/edu-backend/node_modules/@impactor/nest-crud/src/dto/empty.dto\"), { \"EmptyDto\": {} }], [import(\"../../../apps/edu-backend/node_modules/@impactor/nest-crud/src/dto/update-response.dto\"), { \"UpdateResponseDto\": { affected: { required: true, type: () => Number, description: \"the total number of the affecter rows\" } } }], [import(\"../../../apps/edu-backend/src/api/auth/entities/token.entity\"), { \"Token\": { tokenId: { required: true, type: () => String, description: \"a random UUID hash that stored in payload.tokenId,\\nwhen the JWT token is validated, the tokenId is extracted from it,\\nand then checked if it existing here, to revoke a token just remove its corresponding tokenId from here.\\nAvoid storing the token itself here, so no one can use it without permission\" } } }], [import(\"../../../apps/edu-backend/src/api/auth/dto/auth-response.dto\"), { \"AuthResponseDto\": { access_token: { required: true, type: () => String } } }], [import(\"../../../apps/edu-backend/src/api/auth/dto/login.dto\"), { \"LoginDto\": {} }], [import(\"../../../apps/edu-backend/src/types/errors-response.dto\"), { \"ErrorResponse\": { message: { required: true, type: () => String, description: \"the error message\", example: \"duplicate key value violates unique constraint\" }, request: { required: false, type: () => String, description: \"the endpoint that caused the error\", example: \"GET /example\" }, code: { required: false, type: () => String, description: \"the error code\", example: \"DB_ERR\" } } }]], \"controllers\": [[import(\"../../../apps/edu-backend/src/api/auth/auth.controller\"), { \"AuthController\": { \"login\": { type: Object }, \"register\": { type: Object }, \"getTokens\": {}, \"getToken\": { type: Object } } }], [import(\"../../../apps/edu-backend/src/api/users/users.controller\"), { \"UsersController\": { \"me\": { summary: \"get the current loggedIn user\", type: Object }, \"updateOwnData\": { summary: \"update the user's own data\", type: Object } } }], [import(\"../../../apps/edu-backend/src/api/schedule/schedule.controller\"), { \"ScheduleController\": { \"getCardSchedule\": { type: Object }, \"review\": { type: Object }, \"next\": { type: Object }, \"getRetrievability\": { type: Number }, \"undo\": { type: Object }, \"forget\": { type: Object }, \"reschedule\": { type: Object } } }], [import(\"../../../apps/edu-backend/src/api/collections/collections.controller\"), { \"CollectionsController\": { \"addNote\": {}, \"getCollectionNotes\": {}, \"getCollectionSubscribers\": {}, \"subscribe\": {} } }], [import(\"../../../apps/edu-backend/node_modules/@impactor/nest/src/modules/basic/basic.controller\"), { \"BasicController\": {} }]] } };\n};"],"names":["t","tags","required","type","String","maxLength","maxItems","created_by","UserEntity","data","count","Number","rating","description","minimum","state","enum","State","stability","difficulty","elapsed_days","deprecated","last_elapsed_days","scheduled_days","learning_steps","card","Card","reps","lapses","template","CardTemplate","note","Note","title","front","back","css","js","NoteType","value","field","NoteField","FieldType","noteType","firstName","example","lastName","gender","Gender","country","Country","city","email","format","mobile","pattern","password","minLength","affected","tokenId","access_token","message","request","code","Object","summary"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/nest-swagger-metadata.js"],"sourcesContent":["/* eslint-disable */\nexport default async () => {\n const t = {\n [\"../../../apps/edu-backend/src/types/approve-status.enum\"]: await import(\"../../../apps/edu-backend/src/types/approve-status.enum\"),\n [\"../../../apps/edu-backend/src/api/users/entities/user.entity\"]: await import(\"../../../apps/edu-backend/src/api/users/entities/user.entity\"),\n [\"../../../apps/edu-backend/src/types/schedule\"]: await import(\"../../../apps/edu-backend/src/types/schedule\"),\n [\"../../../apps/edu-backend/src/api/cards/entities/card.entity\"]: await import(\"../../../apps/edu-backend/src/api/cards/entities/card.entity\"),\n [\"../../../apps/edu-backend/src/api/card-templates/entities/card-template.entity\"]: await import(\"../../../apps/edu-backend/src/api/card-templates/entities/card-template.entity\"),\n [\"../../../apps/edu-backend/src/api/notes/entities/note.entity\"]: await import(\"../../../apps/edu-backend/src/api/notes/entities/note.entity\"),\n [\"../../../apps/edu-backend/src/api/schedule/entities/schedule.entity\"]: await import(\"../../../apps/edu-backend/src/api/schedule/entities/schedule.entity\"),\n [\"../../../apps/edu-backend/src/api/review-history/entities/review-history.entity\"]: await import(\"../../../apps/edu-backend/src/api/review-history/entities/review-history.entity\"),\n [\"../../../apps/edu-backend/src/api/note-types/entities/note-type.entity\"]: await import(\"../../../apps/edu-backend/src/api/note-types/entities/note-type.entity\"),\n [\"../../../apps/edu-backend/src/api/note-fields/entities/note-field.entity\"]: await import(\"../../../apps/edu-backend/src/api/note-fields/entities/note-field.entity\"),\n [\"../../../apps/edu-backend/src/types/countries.enum\"]: await import(\"../../../apps/edu-backend/src/types/countries.enum\"),\n [\"../../../apps/edu-backend/src/api/collections/entities/collection.entity\"]: await import(\"../../../apps/edu-backend/src/api/collections/entities/collection.entity\")\n };\n return { \"@nestjs/swagger\": { \"models\": [[import(\"../../../apps/edu-backend/src/utils/basic.entity\"), { \"BasicEntity\": { id: { required: true, type: () => String }, _version: { required: true, type: () => Number, description: \"the version number of the updated row\", example: 1 }, approve_status: { required: true, enum: t[\"../../../apps/edu-backend/src/types/approve-status.enum\"].ApproveStatus }, tags: { required: true, type: () => [String], maxLength: 50, maxItems: 20 }, created_by: { required: true, type: () => t[\"../../../apps/edu-backend/src/api/users/entities/user.entity\"].UserEntity } }, \"EntityWithCount\": { data: { required: true }, count: { required: true, type: () => Number } } }], [import(\"../../../apps/edu-backend/src/api/review-history/entities/review-history.entity\"), { \"ReviewHistory\": { rating: { required: true, type: () => Number, description: \"FSRS rating for this review (0 = Again, 1 = Hard, 2 = Good, 3 = Easy)\", minimum: 0 }, state: { required: true, description: \"Current FSRS state of the card\", enum: t[\"../../../apps/edu-backend/src/types/schedule\"].State }, stability: { required: false, type: () => Number, description: \"Stability value controlling retention (can use scaled bigint for performance)\", minimum: 0 }, difficulty: { required: false, type: () => Number, description: \"Difficulty value controlling growth/decay of stability\", minimum: 0 }, elapsed_days: { required: false, type: () => Number, description: \"Days elapsed since last review\", deprecated: true, minimum: 0 }, last_elapsed_days: { required: false, type: () => Number, description: \"Last elapsed days (from previous review)\", deprecated: true, minimum: 0 }, scheduled_days: { required: false, type: () => Number, description: \"Number of scheduled days for this review (can be -1 before scheduling)\" }, learning_steps: { required: false, type: () => Number, description: \"Learning step index (for cards in learning phase)\", minimum: 0 }, card: { required: true, type: () => t[\"../../../apps/edu-backend/src/api/cards/entities/card.entity\"].Card, description: \"Card associated with this review\" } } }], [import(\"../../../apps/edu-backend/src/api/schedule/entities/schedule.entity\"), { \"Schedule\": { stability: { required: false, type: () => Number, description: \"FSRS stability value.\\nRepresents memory retention strength.\", minimum: 0 }, difficulty: { required: false, type: () => Number, description: \"FSRS difficulty value.\\nControls how quickly stability grows or decays.\", minimum: 0 }, elapsed_days: { required: false, type: () => Number, description: \"Number of days elapsed since the previous review.\\nProvided by FSRS during scheduling.\", deprecated: true, minimum: 0 }, scheduled_days: { required: false, type: () => Number, description: \"Number of days the card was scheduled for at the time of the last review.\", minimum: 0 }, reps: { required: false, type: () => Number, description: \"Total number of successful reviews for the card.\", minimum: 0 }, lapses: { required: false, type: () => Number, description: \"Number of times the card was forgotten, i.e. \\\"Again\\\"\", minimum: 0 }, learning_steps: { required: false, type: () => Number, description: \"Current learning step index.\\nUsed mainly during the learning / relearning phases.\", minimum: 0 }, state: { required: false, description: \"Current FSRS state of the card\\n(New, Learning, Review, Relearning).\", enum: t[\"../../../apps/edu-backend/src/types/schedule\"].State }, card: { required: true, type: () => t[\"../../../apps/edu-backend/src/api/cards/entities/card.entity\"].Card, description: \"The card this schedule belongs to.\" } } }], [import(\"../../../apps/edu-backend/src/api/cards/entities/card.entity\"), { \"Card\": { template: { required: true, type: () => t[\"../../../apps/edu-backend/src/api/card-templates/entities/card-template.entity\"].CardTemplate }, note: { required: true, type: () => t[\"../../../apps/edu-backend/src/api/notes/entities/note.entity\"].Note }, schedule: { required: true, type: () => t[\"../../../apps/edu-backend/src/api/schedule/entities/schedule.entity\"].Schedule }, reviewHistory: { required: true, type: () => [t[\"../../../apps/edu-backend/src/api/review-history/entities/review-history.entity\"].ReviewHistory] } } }], [import(\"../../../apps/edu-backend/src/api/card-templates/entities/card-template.entity\"), { \"CardTemplate\": { title: { required: true, type: () => String, maxLength: 200 }, front: { required: true, type: () => String }, back: { required: true, type: () => String }, css: { required: true, type: () => String, description: \"the CSS style, without `<style>`\" }, js: { required: true, type: () => String, description: \"A javascript code to be executed when the card is rendered, including `<script>`\" }, type: { required: true, type: () => t[\"../../../apps/edu-backend/src/api/note-types/entities/note-type.entity\"].NoteType }, cards: { required: true, type: () => [t[\"../../../apps/edu-backend/src/api/cards/entities/card.entity\"].Card] } } }], [import(\"../../../apps/edu-backend/src/api/note-entry/entities/note-entry.entity\"), { \"NoteEntry\": { value: { required: true, type: () => String }, field: { required: true, type: () => t[\"../../../apps/edu-backend/src/api/note-fields/entities/note-field.entity\"].NoteField }, note: { required: true, type: () => t[\"../../../apps/edu-backend/src/api/notes/entities/note.entity\"].Note } } }], [import(\"../../../apps/edu-backend/src/api/note-fields/entities/note-field.entity\"), { \"NoteField\": { title: { required: true, type: () => String, maxLength: 200 }, type: { required: true, description: \"The field type mainly used in UI to create a form field.\\nit also can be used to perform proper queries,\\nfor instance, filtering a number field where its value > a specific number\", enum: t[\"../../../apps/edu-backend/src/api/note-fields/entities/note-field.entity\"].FieldType }, noteType: { required: true, type: () => t[\"../../../apps/edu-backend/src/api/note-types/entities/note-type.entity\"].NoteType } } }], [import(\"../../../apps/edu-backend/src/api/note-types/entities/note-type.entity\"), { \"NoteType\": { title: { required: true, type: () => String }, description: { required: true, type: () => String } } }], [import(\"../../../apps/edu-backend/src/api/notes/entities/note.entity\"), { \"Note\": { type: { required: true, type: () => t[\"../../../apps/edu-backend/src/api/note-types/entities/note-type.entity\"].NoteType } } }], [import(\"../../../apps/edu-backend/src/api/collections/entities/collection.entity\"), { \"Collection\": { title: { required: true, type: () => String }, description: { required: true, type: () => String } } }], [import(\"../../../apps/edu-backend/src/api/users/entities/user.entity\"), { \"UserEntity\": { firstName: { required: true, type: () => String, minLength: 2, maxLength: 100 }, lastName: { required: true, type: () => String, minLength: 2, maxLength: 100 }, gender: { required: true, enum: t[\"../../../apps/edu-backend/src/api/users/entities/user.entity\"].Gender }, country: { required: true, enum: t[\"../../../apps/edu-backend/src/types/countries.enum\"].Country }, city: { required: true, type: () => String, maxLength: 100 }, email: { required: true, type: () => String, format: \"email\" }, mobile: { required: true, type: () => String, format: \"mobile-phone\", pattern: \"/^\\\\+/\" }, password: { required: true, type: () => String, minLength: 8 }, role: { required: true, type: () => String, enum: t[\"../../../apps/edu-backend/src/api/users/entities/user.entity\"].UserRole }, collections: { required: true, type: () => [t[\"../../../apps/edu-backend/src/api/collections/entities/collection.entity\"].Collection] } } }], [import(\"../../../apps/edu-backend/node_modules/@impactor/nest/src/decorators/controller/dto/empty.dto\"), { \"EmptyDto\": {} }], [import(\"../../../apps/edu-backend/node_modules/@impactor/nest/src/decorators/controller/dto/update-response.dto\"), { \"UpdateResponseDto\": { affected: { required: true, type: () => Number, description: \"the total number of the affecter rows\" } } }], [import(\"../../../apps/edu-backend/src/api/auth/entities/token.entity\"), { \"Token\": { tokenId: { required: true, type: () => String, description: \"a random UUID hash that stored in payload.tokenId,\\nwhen the JWT token is validated, the tokenId is extracted from it,\\nand then checked if it existing here, to revoke a token just remove its corresponding tokenId from here.\\nAvoid storing the token itself here, so no one can use it without permission\" } } }], [import(\"../../../apps/edu-backend/src/api/auth/dto/auth-response.dto\"), { \"AuthResponseDto\": { access_token: { required: true, type: () => String } } }], [import(\"../../../apps/edu-backend/src/api/auth/dto/login.dto\"), { \"LoginDto\": {} }], [import(\"../../../apps/edu-backend/src/types/errors-response.dto\"), { \"ErrorResponse\": { message: { required: true, type: () => String, description: \"the error message\", example: \"duplicate key value violates unique constraint\" }, request: { required: false, type: () => String, description: \"the endpoint that caused the error\", example: \"GET /example\" }, code: { required: false, type: () => String, description: \"the error code\", example: \"DB_ERR\" } } }]], \"controllers\": [[import(\"../../../apps/edu-backend/node_modules/@impactor/nest/src/modules/basic/basic.controller\"), { \"BasicController\": {} }], [import(\"../../../apps/edu-backend/src/api/auth/auth.controller\"), { \"AuthController\": { \"login\": { type: Object }, \"register\": { type: Object }, \"getTokens\": {}, \"getToken\": { type: Object } } }], [import(\"../../../apps/edu-backend/src/api/users/users.controller\"), { \"UsersController\": { \"me\": { summary: \"get the current loggedIn user\", type: Object }, \"updateOwnData\": { summary: \"update the user's own data\", type: Object } } }], [import(\"../../../apps/edu-backend/src/api/schedule/schedule.controller\"), { \"ScheduleController\": { \"getCardSchedule\": { type: Object }, \"review\": { type: Object }, \"next\": { type: Object }, \"getRetrievability\": { type: Number }, \"undo\": { type: Object }, \"forget\": { type: Object }, \"reschedule\": { type: Object } } }], [import(\"../../../apps/edu-backend/src/api/collections/collections.controller\"), { \"CollectionsController\": { \"addNote\": {}, \"getCollectionNotes\": {}, \"getCollectionSubscribers\": {}, \"subscribe\": {} } }]] } };\n};"],"names":["t","id","required","type","String","_version","Number","description","example","approve_status","enum","ApproveStatus","tags","maxLength","maxItems","created_by","UserEntity","data","count","rating","minimum","state","State","stability","difficulty","elapsed_days","deprecated","last_elapsed_days","scheduled_days","learning_steps","card","Card","reps","lapses","template","CardTemplate","note","Note","schedule","Schedule","reviewHistory","ReviewHistory","title","front","back","css","js","NoteType","cards","value","field","NoteField","FieldType","noteType","firstName","minLength","lastName","gender","Gender","country","Country","city","email","format","mobile","pattern","password","role","UserRole","collections","Collection","affected","tokenId","access_token","message","request","code","Object","summary"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function registerEntities(models?: Function[]): void;
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "registerEntities", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return registerEntities;
9
+ }
10
+ });
11
+ const _typeormtoswagger = require("./utils/typeorm-to-swagger");
12
+ const _swagger = require("@nestjs/swagger");
13
+ const _typeorm = require("typeorm");
14
+ function registerEntities(models) {
15
+ let storage = (0, _typeorm.getMetadataArgsStorage)(), // todo: handle when col.target is string
16
+ cols = storage.columns.filter((el)=>typeof el.target === 'function'), relations = storage.relations.filter((el)=>typeof el.target === 'function' && el.relationType.endsWith('to-one')), joinColumns = storage.joinColumns;
17
+ if (Array.isArray(models)) {
18
+ cols = cols.filter((el)=>models.includes(el.target));
19
+ relations = relations.filter((el)=>models.includes(el.target));
20
+ }
21
+ for (let col of cols){
22
+ // existing props, i.e. options that the consumer already specified in `@ApiProperty()`
23
+ let props = Reflect.getMetadata('swagger/apiModelProperties', col.target.prototype, col.propertyName), // if the column is auto generated
24
+ // this is similar to `storage.generations.filter()`
25
+ // this also contains the generation strategy, such as "uuid"
26
+ isGenerated = [
27
+ 'createDate',
28
+ 'updateDate',
29
+ 'deleteDate',
30
+ 'version',
31
+ 'treeChildrenCount',
32
+ 'treeLevel',
33
+ 'objectId'
34
+ ].includes(col.mode) || !!storage.findGenerated(col.target, col.propertyName);
35
+ Reflect.decorate([
36
+ (0, _swagger.ApiProperty)({
37
+ readOnly: isGenerated,
38
+ // try using the column type as "format",
39
+ // unless `typeORMToSwagger()` returned the correct one
40
+ // todo: if `format` cannot detected, try to infer it from the column name
41
+ // for instance:
42
+ // - email -> format: email
43
+ // - password -> format: password
44
+ // - image -> format: binary
45
+ format: col.options.type,
46
+ ...col.options.type ? (0, _typeormtoswagger.typeORMToSwagger)(col.options.type) : {},
47
+ enumName: col.options.enumName,
48
+ default: col.options.default,
49
+ required: !!col.options.nullable,
50
+ nullable: col.options.nullable,
51
+ ...col.options.enum ? {
52
+ enum: col.options.enum
53
+ } : {},
54
+ ...col.options.length ? {
55
+ maxLength: +col.options.length
56
+ } : {},
57
+ ...props
58
+ })
59
+ ], col.target.prototype, col.propertyName, Reflect.getOwnPropertyDescriptor(col.target.prototype, col.propertyName));
60
+ }
61
+ for (let rel of relations){
62
+ let props = Reflect.getMetadata('swagger/apiModelProperties', rel.target.prototype, rel.propertyName);
63
+ // todo: get the reference column name, mostly the primary key of the other table
64
+ // for instance if `posts.user` -> `user.id`, then FK name is "id"
65
+ let foreignKey = joinColumns.find((el)=>el.propertyName === rel.propertyName)?.foreignKeyConstraintName || // todo: this should be the PK of the other table,
66
+ // but currently we are unable to get the other table
67
+ 'id';
68
+ if (rel.relationType.endsWith('to-one')) {
69
+ // todo: in one-to-one, we may want to display this field in the join column only
70
+ // for instance, for this relation `user.info <-> info.user`,
71
+ // we may need to inset `user.info.id`, not `info.user.id`
72
+ Reflect.decorate([
73
+ (0, _swagger.ApiProperty)({
74
+ // todo: `type: rel.type` -> gives `string`
75
+ // or get `design:type` metadata -> gives `{}`
76
+ // i.e. `Reflect.getMetadata('design:type',(<Function>rel.target).prototype, rel.propertyName)`
77
+ type: 'object',
78
+ // todo: properties{} should refer to the other table definition
79
+ // for `post.user`, it should be `user{}` props
80
+ properties: {
81
+ // todo: get foreign column name (by default the PK of the other table), type (string/number), and format (uuid)
82
+ [foreignKey]: {
83
+ type: 'string'
84
+ }
85
+ },
86
+ required: !!rel.options.nullable,
87
+ nullable: rel.options.nullable,
88
+ ...props
89
+ })
90
+ ], rel.target.prototype, rel.propertyName, Reflect.getOwnPropertyDescriptor(rel.target.prototype, rel.propertyName));
91
+ } else {
92
+ // `*-to-many` relations should appear in GET operations only
93
+ // we don't need to insert them when creating or updating the record
94
+ // we insert them from the other side
95
+ // for instance, for this relation `posts.user <-> user.posts`,
96
+ // we often refer to the user when inserting a new post, not the other way around
97
+ // todo: we need to specify the relation definition, i.e. the shape of the other table
98
+ // todo: in `many-to-many`, we can allow inserting relations from the joining side
99
+ // todo: these fields don't display in Swagger UI even after applying `@ApiProperty()` on them
100
+ (0, _swagger.ApiProperty)({
101
+ readOnly: true,
102
+ isArray: true,
103
+ type: 'array',
104
+ items: {
105
+ type: 'object',
106
+ properties: {
107
+ [foreignKey]: {
108
+ type: 'string'
109
+ }
110
+ }
111
+ },
112
+ ...props
113
+ });
114
+ }
115
+ }
116
+ }
117
+
118
+ //# sourceMappingURL=register-entities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/register-entities.ts"],"sourcesContent":["import { typeORMToSwagger } from './utils/typeorm-to-swagger';\nimport { ApiProperty } from '@nestjs/swagger';\nimport { getMetadataArgsStorage } from 'typeorm';\n\n/**\n * Register models and add Swagger and class-validator decorators\n * call this function before `SwaggerModule.createDocument()`\n *\n * This function extracts info from each column to generate best Swagger model and best validations as much as possible.\n *\n * add `@Hide()` to properties that you want to hide from Swagger\n * `@ApiHideProperty()` doesn't work.\n *\n * to skip processing a property by this function add `@Skip()`\n *\n * to apply this function on a specific model, decorate it with `@Entity()`\n * or use `registerEntities([model])`\n *\n * existing options in `@ApiProperty()` will be merged into options generated by this function\n *\n * `ManyToMany` and `OneToMany` relations are ignored by default, you need to add `@ApiProperty()` to include them\n * `OneToOne` and `ManyToOne` relation is included but with a different name, after suffixing the primary key name\n *\n * @param models list of models to apply this function to\n */\nexport function registerEntities(models?: Function[]) {\n let storage = getMetadataArgsStorage(),\n // todo: handle when col.target is string\n cols = storage.columns.filter((el) => typeof el.target === 'function'),\n relations = storage.relations.filter(\n (el) =>\n typeof el.target === 'function' && el.relationType.endsWith('to-one'),\n ),\n joinColumns = storage.joinColumns;\n\n if (Array.isArray(models)) {\n cols = cols.filter((el) => models.includes(el.target as Function));\n relations = relations.filter((el) =>\n models.includes(el.target as Function),\n );\n }\n\n for (let col of cols) {\n // existing props, i.e. options that the consumer already specified in `@ApiProperty()`\n let props = Reflect.getMetadata(\n 'swagger/apiModelProperties',\n (col.target as Function).prototype,\n col.propertyName,\n ),\n // if the column is auto generated\n // this is similar to `storage.generations.filter()`\n // this also contains the generation strategy, such as \"uuid\"\n isGenerated =\n [\n 'createDate',\n 'updateDate',\n 'deleteDate',\n 'version',\n 'treeChildrenCount',\n 'treeLevel',\n 'objectId',\n ].includes(col.mode) ||\n !!storage.findGenerated(col.target, col.propertyName);\n\n Reflect.decorate(\n [\n ApiProperty({\n readOnly: isGenerated,\n // try using the column type as \"format\",\n // unless `typeORMToSwagger()` returned the correct one\n // todo: if `format` cannot detected, try to infer it from the column name\n // for instance:\n // - email -> format: email\n // - password -> format: password\n // - image -> format: binary\n format: col.options.type,\n ...(col.options.type ? typeORMToSwagger(col.options.type) : {}),\n enumName: col.options.enumName,\n default: col.options.default,\n required: !!col.options.nullable,\n nullable: col.options.nullable,\n ...(col.options.enum ? { enum: col.options.enum } : {}),\n ...(col.options.length ? { maxLength: +col.options.length } : {}),\n ...props,\n }),\n ],\n (col.target as Function).prototype,\n col.propertyName,\n Reflect.getOwnPropertyDescriptor(\n (col.target as Function).prototype,\n col.propertyName,\n ),\n );\n }\n\n for (let rel of relations) {\n let props = Reflect.getMetadata(\n 'swagger/apiModelProperties',\n (rel.target as Function).prototype,\n rel.propertyName,\n );\n // todo: get the reference column name, mostly the primary key of the other table\n // for instance if `posts.user` -> `user.id`, then FK name is \"id\"\n let foreignKey =\n joinColumns.find((el) => el.propertyName === rel.propertyName)\n ?.foreignKeyConstraintName ||\n // todo: this should be the PK of the other table,\n // but currently we are unable to get the other table\n 'id';\n\n if (rel.relationType.endsWith('to-one')) {\n // todo: in one-to-one, we may want to display this field in the join column only\n // for instance, for this relation `user.info <-> info.user`,\n // we may need to inset `user.info.id`, not `info.user.id`\n Reflect.decorate(\n [\n ApiProperty({\n // todo: `type: rel.type` -> gives `string`\n // or get `design:type` metadata -> gives `{}`\n // i.e. `Reflect.getMetadata('design:type',(<Function>rel.target).prototype, rel.propertyName)`\n type: 'object',\n // todo: properties{} should refer to the other table definition\n // for `post.user`, it should be `user{}` props\n properties: {\n // todo: get foreign column name (by default the PK of the other table), type (string/number), and format (uuid)\n [foreignKey]: { type: 'string' },\n },\n required: !!rel.options.nullable,\n nullable: rel.options.nullable,\n ...props,\n }),\n ],\n (rel.target as Function).prototype,\n rel.propertyName,\n Reflect.getOwnPropertyDescriptor(\n (rel.target as Function).prototype,\n rel.propertyName,\n ),\n );\n } else {\n // `*-to-many` relations should appear in GET operations only\n // we don't need to insert them when creating or updating the record\n // we insert them from the other side\n // for instance, for this relation `posts.user <-> user.posts`,\n // we often refer to the user when inserting a new post, not the other way around\n // todo: we need to specify the relation definition, i.e. the shape of the other table\n // todo: in `many-to-many`, we can allow inserting relations from the joining side\n // todo: these fields don't display in Swagger UI even after applying `@ApiProperty()` on them\n ApiProperty({\n readOnly: true,\n isArray: true,\n type: 'array',\n items: {\n type: 'object',\n properties: {\n [foreignKey]: { type: 'string' },\n },\n // required: [foreignKey],\n },\n ...props,\n });\n }\n }\n}\n"],"names":["registerEntities","models","storage","getMetadataArgsStorage","cols","columns","filter","el","target","relations","relationType","endsWith","joinColumns","Array","isArray","includes","col","props","Reflect","getMetadata","prototype","propertyName","isGenerated","mode","findGenerated","decorate","ApiProperty","readOnly","format","options","type","typeORMToSwagger","enumName","default","required","nullable","enum","length","maxLength","getOwnPropertyDescriptor","rel","foreignKey","find","foreignKeyConstraintName","properties","items"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { ApiPropertyOptions } from '@nestjs/swagger';
2
+ import { ColumnType } from 'typeorm/driver/types/ColumnTypes';
3
+ export declare function typeORMToSwagger(type: ColumnType): ApiPropertyOptions;
@@ -0,0 +1,315 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "typeORMToSwagger", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return typeORMToSwagger;
9
+ }
10
+ });
11
+ function typeORMToSwagger(type) {
12
+ // the column type as string
13
+ // it may be a BooleanConstructor | DateConstructor | ....
14
+ let value = (typeof type === 'string' ? type : type.name).toLowerCase();
15
+ // numbers
16
+ if ([
17
+ 'numeric',
18
+ 'number',
19
+ 'int',
20
+ 'int2',
21
+ 'int4',
22
+ 'int8',
23
+ 'int64',
24
+ 'integer',
25
+ 'tinyint',
26
+ 'smallint',
27
+ 'mediumint',
28
+ 'bigint',
29
+ 'unsigned big int',
30
+ 'rowid',
31
+ 'urowid',
32
+ 'float',
33
+ 'float4',
34
+ 'float8',
35
+ 'float64',
36
+ 'money',
37
+ 'smallmoney',
38
+ 'decimal',
39
+ 'smalldecimal',
40
+ 'dec',
41
+ 'double',
42
+ 'double precision',
43
+ 'fixed',
44
+ 'real'
45
+ ].includes(value)) {
46
+ // todo: set the best 'format' for each type
47
+ return {
48
+ type: 'number'
49
+ };
50
+ }
51
+ // booleans
52
+ if ([
53
+ 'boolean',
54
+ 'bool',
55
+ 'bit',
56
+ 'bit varying',
57
+ 'varbit'
58
+ ].includes(value)) {
59
+ return {
60
+ type: 'boolean'
61
+ };
62
+ }
63
+ // arrays / collections
64
+ if ([
65
+ 'array',
66
+ 'simple-array',
67
+ 'set',
68
+ 'cube',
69
+ 'ltree'
70
+ ].includes(value)) {
71
+ return {
72
+ type: 'array'
73
+ };
74
+ }
75
+ // files
76
+ if ([
77
+ 'blob',
78
+ 'longblob',
79
+ 'mediumblob',
80
+ 'tinyblob',
81
+ 'bytea',
82
+ 'bytes',
83
+ 'image',
84
+ 'rowversion',
85
+ 'raw',
86
+ 'long raw',
87
+ 'bfile',
88
+ 'binary',
89
+ 'varbinary'
90
+ ].includes(value)) {
91
+ // todo: openAPI v3 changed 'file' to 'string' with format 'binary' | 'byte'
92
+ // https://swagger.io/docs/specification/v3_0/data-models/data-types/#files
93
+ return {
94
+ type: 'string',
95
+ format: 'binary'
96
+ };
97
+ }
98
+ // date
99
+ if ([
100
+ 'date'
101
+ ].includes(value)) {
102
+ return {
103
+ type: 'string',
104
+ format: 'date'
105
+ };
106
+ }
107
+ if ([
108
+ 'year'
109
+ ].includes(value)) {
110
+ return {
111
+ type: 'integer',
112
+ format: 'int32',
113
+ example: new Date().getFullYear()
114
+ };
115
+ }
116
+ // time
117
+ if ([
118
+ 'time',
119
+ 'timetz'
120
+ ].includes(value)) {
121
+ return {
122
+ type: 'string',
123
+ format: 'time'
124
+ };
125
+ }
126
+ // date-time
127
+ if ([
128
+ 'timestamp',
129
+ 'timestamptz',
130
+ 'timestamp without time zone',
131
+ 'timestamp with time zone',
132
+ 'timestamp with local time zone',
133
+ 'datetime',
134
+ 'datetime2',
135
+ 'datetimeoffset',
136
+ 'smalldatetime',
137
+ 'seconddate'
138
+ ].includes(value)) {
139
+ return {
140
+ type: 'string',
141
+ format: 'date-time'
142
+ };
143
+ }
144
+ // intervals and durations
145
+ if ([
146
+ 'interval',
147
+ 'interval year to month',
148
+ 'interval day to second'
149
+ ].includes(value)) {
150
+ return {
151
+ type: 'string',
152
+ format: 'duration',
153
+ example: 'P1Y2M3DT4H5M6S'
154
+ };
155
+ }
156
+ // strings
157
+ if ([
158
+ 'text',
159
+ 'tinytext',
160
+ 'shorttext',
161
+ 'mediumtext',
162
+ 'longtext',
163
+ 'ntext',
164
+ 'citext',
165
+ 'string',
166
+ 'character varying',
167
+ 'varying character',
168
+ 'char varying',
169
+ 'varchar2',
170
+ 'nvarchar',
171
+ 'nvarchar2',
172
+ 'national varchar',
173
+ 'character',
174
+ 'native character',
175
+ 'varchar',
176
+ 'char',
177
+ 'nchar',
178
+ 'national char',
179
+ 'alphanum',
180
+ 'jsonpath',
181
+ 'xml',
182
+ 'long',
183
+ 'clob',
184
+ 'nclob',
185
+ // ranges
186
+ // this can also represented as object `{start, end}`
187
+ 'int4range',
188
+ 'int8range',
189
+ 'numrange',
190
+ 'tsrange',
191
+ 'tstzrange',
192
+ 'daterange',
193
+ 'int4multirange',
194
+ 'int8multirange',
195
+ 'nummultirange',
196
+ 'tsmultirange',
197
+ 'tstzmultirange',
198
+ 'datemultirange',
199
+ // enums
200
+ 'enum',
201
+ 'simple-enum',
202
+ // network
203
+ 'cidr',
204
+ 'inet',
205
+ 'inet4',
206
+ 'inet6',
207
+ 'macaddr',
208
+ 'macaddr8',
209
+ // full-text search types
210
+ 'tsvector',
211
+ 'tsquery',
212
+ // identifiers
213
+ 'rowid',
214
+ 'urowid',
215
+ 'hierarchyid',
216
+ 'sql_variant'
217
+ ].includes(value)) {
218
+ return {
219
+ type: 'string'
220
+ };
221
+ }
222
+ if ([
223
+ 'uuid',
224
+ // most databases generates a 128-bit GUID, the same as a UUID
225
+ // so, it is safe to represent it in Swagger UI as a UUID string
226
+ 'uniqueidentifier'
227
+ ].includes(value)) {
228
+ return {
229
+ type: 'string',
230
+ format: 'uuid'
231
+ };
232
+ }
233
+ // vectors
234
+ if ([
235
+ 'vector',
236
+ 'halfvec',
237
+ 'half_vector',
238
+ 'real_vector'
239
+ ].includes(value)) {
240
+ return {
241
+ type: 'array',
242
+ items: {
243
+ type: 'number'
244
+ }
245
+ };
246
+ }
247
+ // JSON
248
+ if ([
249
+ 'json',
250
+ 'jsonb',
251
+ 'simple-json',
252
+ 'hstore'
253
+ ].includes(value)) {
254
+ return {
255
+ type: 'object',
256
+ items: {
257
+ type: 'number'
258
+ },
259
+ // in hstore, keys must ve string
260
+ additionalProperties: value === 'hstore' ? {
261
+ type: 'string'
262
+ } : true
263
+ };
264
+ }
265
+ // geometry types
266
+ if ([
267
+ 'geometry',
268
+ 'geography',
269
+ 'st_geometry',
270
+ 'st_point',
271
+ 'point',
272
+ 'line',
273
+ 'polygon',
274
+ 'circle',
275
+ 'multipolygon',
276
+ 'linestring',
277
+ 'multilinestring',
278
+ 'multipoint',
279
+ 'geometrycollection',
280
+ 'lseg',
281
+ 'box',
282
+ 'path'
283
+ ].includes(value)) {
284
+ return {
285
+ // they're saved as JSON objects
286
+ type: 'object',
287
+ properties: {
288
+ type: {
289
+ type: 'string',
290
+ example: 'Point'
291
+ },
292
+ coordinates: {
293
+ type: 'array',
294
+ items: {
295
+ type: 'number'
296
+ },
297
+ example: [
298
+ 125.6,
299
+ 10.1
300
+ ]
301
+ }
302
+ },
303
+ required: [
304
+ 'type',
305
+ 'coordinates'
306
+ ],
307
+ description: 'GeoJSON object representing geometry or geography'
308
+ };
309
+ }
310
+ return {
311
+ type: 'null'
312
+ };
313
+ }
314
+
315
+ //# sourceMappingURL=typeorm-to-swagger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/utils/typeorm-to-swagger.ts"],"sourcesContent":["import { ApiPropertyOptions } from '@nestjs/swagger';\nimport { ColumnType } from 'typeorm/driver/types/ColumnTypes';\n\n/**\n * extract openAPI type and format from TypeORM column type\n * @example `typeORMToSwaggerType(\"file\")` // { type: 'string', format: 'binary' }\n */\nexport function typeORMToSwagger(type: ColumnType): ApiPropertyOptions {\n // the column type as string\n // it may be a BooleanConstructor | DateConstructor | ....\n let value = (typeof type === 'string' ? type : type.name).toLowerCase();\n\n // numbers\n if (\n [\n 'numeric',\n 'number',\n 'int',\n 'int2',\n 'int4',\n 'int8',\n 'int64',\n 'integer',\n 'tinyint',\n 'smallint',\n 'mediumint',\n 'bigint',\n 'unsigned big int',\n 'rowid',\n 'urowid',\n 'float',\n 'float4',\n 'float8',\n 'float64',\n 'money',\n 'smallmoney',\n 'decimal',\n 'smalldecimal',\n 'dec',\n 'double',\n 'double precision',\n 'fixed',\n 'real',\n ].includes(value)\n ) {\n // todo: set the best 'format' for each type\n return { type: 'number' };\n }\n\n // booleans\n if (['boolean', 'bool', 'bit', 'bit varying', 'varbit'].includes(value)) {\n return { type: 'boolean' };\n }\n\n // arrays / collections\n if (['array', 'simple-array', 'set', 'cube', 'ltree'].includes(value)) {\n return { type: 'array' };\n }\n\n // files\n if (\n [\n 'blob',\n 'longblob',\n 'mediumblob',\n 'tinyblob',\n 'bytea',\n 'bytes',\n 'image',\n 'rowversion',\n 'raw',\n 'long raw',\n 'bfile',\n 'binary',\n 'varbinary',\n ].includes(value)\n ) {\n // todo: openAPI v3 changed 'file' to 'string' with format 'binary' | 'byte'\n // https://swagger.io/docs/specification/v3_0/data-models/data-types/#files\n return { type: 'string', format: 'binary' };\n }\n\n // date\n if (['date'].includes(value)) {\n return { type: 'string', format: 'date' };\n }\n\n if (['year'].includes(value)) {\n return {\n type: 'integer',\n format: 'int32',\n example: new Date().getFullYear(),\n };\n }\n\n // time\n if (['time', 'timetz'].includes(value)) {\n return { type: 'string', format: 'time' };\n }\n\n // date-time\n if (\n [\n 'timestamp',\n 'timestamptz',\n 'timestamp without time zone',\n 'timestamp with time zone',\n 'timestamp with local time zone',\n 'datetime',\n 'datetime2',\n 'datetimeoffset',\n 'smalldatetime',\n 'seconddate',\n ].includes(value)\n ) {\n return { type: 'string', format: 'date-time' };\n }\n\n // intervals and durations\n if (\n ['interval', 'interval year to month', 'interval day to second'].includes(\n value,\n )\n ) {\n return { type: 'string', format: 'duration', example: 'P1Y2M3DT4H5M6S' };\n }\n\n // strings\n if (\n [\n 'text',\n 'tinytext',\n 'shorttext',\n 'mediumtext',\n 'longtext',\n 'ntext',\n 'citext',\n 'string',\n 'character varying',\n 'varying character',\n 'char varying',\n 'varchar2',\n 'nvarchar',\n 'nvarchar2',\n 'national varchar',\n 'character',\n 'native character',\n 'varchar',\n 'char',\n 'nchar',\n 'national char',\n 'alphanum',\n 'jsonpath',\n 'xml',\n 'long',\n 'clob',\n 'nclob',\n // ranges\n // this can also represented as object `{start, end}`\n 'int4range',\n 'int8range',\n 'numrange',\n 'tsrange',\n 'tstzrange',\n 'daterange',\n 'int4multirange',\n 'int8multirange',\n 'nummultirange',\n 'tsmultirange',\n 'tstzmultirange',\n 'datemultirange',\n\n // enums\n 'enum',\n 'simple-enum',\n // network\n 'cidr',\n 'inet',\n 'inet4',\n 'inet6',\n 'macaddr',\n 'macaddr8',\n // full-text search types\n 'tsvector',\n 'tsquery',\n // identifiers\n 'rowid',\n 'urowid',\n 'hierarchyid',\n 'sql_variant',\n ].includes(value)\n ) {\n return { type: 'string' };\n }\n\n if (\n [\n 'uuid',\n // most databases generates a 128-bit GUID, the same as a UUID\n // so, it is safe to represent it in Swagger UI as a UUID string\n 'uniqueidentifier',\n ].includes(value)\n ) {\n return { type: 'string', format: 'uuid' };\n }\n\n // vectors\n if (['vector', 'halfvec', 'half_vector', 'real_vector'].includes(value)) {\n return {\n type: 'array',\n items: { type: 'number' },\n };\n }\n\n // JSON\n if (['json', 'jsonb', 'simple-json', 'hstore'].includes(value)) {\n return {\n type: 'object',\n items: { type: 'number' },\n // in hstore, keys must ve string\n additionalProperties: value === 'hstore' ? { type: 'string' } : true,\n };\n }\n\n // geometry types\n if (\n [\n 'geometry',\n 'geography',\n 'st_geometry',\n 'st_point',\n 'point',\n 'line',\n 'polygon',\n 'circle',\n 'multipolygon',\n 'linestring',\n 'multilinestring',\n 'multipoint',\n 'geometrycollection',\n 'lseg',\n 'box',\n 'path',\n ].includes(value)\n ) {\n return {\n // they're saved as JSON objects\n type: 'object',\n properties: {\n type: { type: 'string', example: 'Point' },\n coordinates: {\n type: 'array',\n items: { type: 'number' },\n example: [125.6, 10.1],\n },\n },\n required: ['type', 'coordinates'],\n description: 'GeoJSON object representing geometry or geography',\n };\n }\n\n return { type: 'null' };\n}\n"],"names":["typeORMToSwagger","type","value","name","toLowerCase","includes","format","example","Date","getFullYear","items","additionalProperties","properties","coordinates","required","description"],"mappings":"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"}