@rapidrest/service-core 1.0.0-beta.1
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/LICENSE +23 -0
- package/README.md +16 -0
- package/dist/lib/ApiErrors.js +41 -0
- package/dist/lib/ApiErrors.js.map +1 -0
- package/dist/lib/BackgroundService.js +16 -0
- package/dist/lib/BackgroundService.js.map +1 -0
- package/dist/lib/BackgroundServiceManager.js +135 -0
- package/dist/lib/BackgroundServiceManager.js.map +1 -0
- package/dist/lib/BulkError.js +24 -0
- package/dist/lib/BulkError.js.map +1 -0
- package/dist/lib/EventListenerManager.js +161 -0
- package/dist/lib/EventListenerManager.js.map +1 -0
- package/dist/lib/NetUtils.js +103 -0
- package/dist/lib/NetUtils.js.map +1 -0
- package/dist/lib/NotificationUtils.js +34 -0
- package/dist/lib/NotificationUtils.js.map +1 -0
- package/dist/lib/ObjectFactory.js +90 -0
- package/dist/lib/ObjectFactory.js.map +1 -0
- package/dist/lib/OpenApiSpec.js +748 -0
- package/dist/lib/OpenApiSpec.js.map +1 -0
- package/dist/lib/Server.js +549 -0
- package/dist/lib/Server.js.map +1 -0
- package/dist/lib/Types.js +2 -0
- package/dist/lib/Types.js.map +1 -0
- package/dist/lib/auth/AuthMiddleware.js +229 -0
- package/dist/lib/auth/AuthMiddleware.js.map +1 -0
- package/dist/lib/auth/AuthStrategy.js +2 -0
- package/dist/lib/auth/AuthStrategy.js.map +1 -0
- package/dist/lib/auth/BasicStrategy.js +106 -0
- package/dist/lib/auth/BasicStrategy.js.map +1 -0
- package/dist/lib/auth/JWTStrategy.js +161 -0
- package/dist/lib/auth/JWTStrategy.js.map +1 -0
- package/dist/lib/auth/index.js +5 -0
- package/dist/lib/auth/index.js.map +1 -0
- package/dist/lib/database/ConnectionKinds.js +14 -0
- package/dist/lib/database/ConnectionKinds.js.map +1 -0
- package/dist/lib/database/ConnectionManager.js +161 -0
- package/dist/lib/database/ConnectionManager.js.map +1 -0
- package/dist/lib/database/MongoConnection.js +86 -0
- package/dist/lib/database/MongoConnection.js.map +1 -0
- package/dist/lib/database/MongoRepository.js +136 -0
- package/dist/lib/database/MongoRepository.js.map +1 -0
- package/dist/lib/database/MongoSchemaSync.js +136 -0
- package/dist/lib/database/MongoSchemaSync.js.map +1 -0
- package/dist/lib/database/NamingUtils.js +52 -0
- package/dist/lib/database/NamingUtils.js.map +1 -0
- package/dist/lib/database/TypeOrmSupport.js +146 -0
- package/dist/lib/database/TypeOrmSupport.js.map +1 -0
- package/dist/lib/database/index.js +7 -0
- package/dist/lib/database/index.js.map +1 -0
- package/dist/lib/decorators/DatabaseDecorators.js +52 -0
- package/dist/lib/decorators/DatabaseDecorators.js.map +1 -0
- package/dist/lib/decorators/DocDecorators.js +120 -0
- package/dist/lib/decorators/DocDecorators.js.map +1 -0
- package/dist/lib/decorators/EventDecorators.js +24 -0
- package/dist/lib/decorators/EventDecorators.js.map +1 -0
- package/dist/lib/decorators/ModelDecorators.js +173 -0
- package/dist/lib/decorators/ModelDecorators.js.map +1 -0
- package/dist/lib/decorators/PersistenceDecorators.js +177 -0
- package/dist/lib/decorators/PersistenceDecorators.js.map +1 -0
- package/dist/lib/decorators/RouteDecorators.js +324 -0
- package/dist/lib/decorators/RouteDecorators.js.map +1 -0
- package/dist/lib/decorators/index.js +7 -0
- package/dist/lib/decorators/index.js.map +1 -0
- package/dist/lib/http/Adapters.js +230 -0
- package/dist/lib/http/Adapters.js.map +1 -0
- package/dist/lib/http/Router.js +403 -0
- package/dist/lib/http/Router.js.map +1 -0
- package/dist/lib/http/WebSocket.js +82 -0
- package/dist/lib/http/WebSocket.js.map +1 -0
- package/dist/lib/http/index.js +4 -0
- package/dist/lib/http/index.js.map +1 -0
- package/dist/lib/http/types.js +5 -0
- package/dist/lib/http/types.js.map +1 -0
- package/dist/lib/index.js +18 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/models/BaseEntity.js +83 -0
- package/dist/lib/models/BaseEntity.js.map +1 -0
- package/dist/lib/models/BaseMongoEntity.js +40 -0
- package/dist/lib/models/BaseMongoEntity.js.map +1 -0
- package/dist/lib/models/ModelUtils.js +645 -0
- package/dist/lib/models/ModelUtils.js.map +1 -0
- package/dist/lib/models/RecoverableBaseEntity.js +39 -0
- package/dist/lib/models/RecoverableBaseEntity.js.map +1 -0
- package/dist/lib/models/RecoverableBaseMongoEntity.js +40 -0
- package/dist/lib/models/RecoverableBaseMongoEntity.js.map +1 -0
- package/dist/lib/models/RepoUtils.js +717 -0
- package/dist/lib/models/RepoUtils.js.map +1 -0
- package/dist/lib/models/SimpleEntity.js +42 -0
- package/dist/lib/models/SimpleEntity.js.map +1 -0
- package/dist/lib/models/SimpleMongoEntity.js +38 -0
- package/dist/lib/models/SimpleMongoEntity.js.map +1 -0
- package/dist/lib/models/StatusExtraData.js +15 -0
- package/dist/lib/models/StatusExtraData.js.map +1 -0
- package/dist/lib/models/index.js +10 -0
- package/dist/lib/models/index.js.map +1 -0
- package/dist/lib/routes/AdminRoute.js +268 -0
- package/dist/lib/routes/AdminRoute.js.map +1 -0
- package/dist/lib/routes/MetricsRoute.js +86 -0
- package/dist/lib/routes/MetricsRoute.js.map +1 -0
- package/dist/lib/routes/ModelRoute.js +481 -0
- package/dist/lib/routes/ModelRoute.js.map +1 -0
- package/dist/lib/routes/OpenAPIRoute.js +115 -0
- package/dist/lib/routes/OpenAPIRoute.js.map +1 -0
- package/dist/lib/routes/RouteUtils.js +445 -0
- package/dist/lib/routes/RouteUtils.js.map +1 -0
- package/dist/lib/routes/StatusRoute.js +55 -0
- package/dist/lib/routes/StatusRoute.js.map +1 -0
- package/dist/lib/routes/index.js +7 -0
- package/dist/lib/routes/index.js.map +1 -0
- package/dist/lib/security/ACLRouteMongo.js +194 -0
- package/dist/lib/security/ACLRouteMongo.js.map +1 -0
- package/dist/lib/security/ACLRouteSQL.js +193 -0
- package/dist/lib/security/ACLRouteSQL.js.map +1 -0
- package/dist/lib/security/ACLUtils.js +457 -0
- package/dist/lib/security/ACLUtils.js.map +1 -0
- package/dist/lib/security/AccessControlList.js +18 -0
- package/dist/lib/security/AccessControlList.js.map +1 -0
- package/dist/lib/security/AccessControlListMongo.js +155 -0
- package/dist/lib/security/AccessControlListMongo.js.map +1 -0
- package/dist/lib/security/AccessControlListSQL.js +149 -0
- package/dist/lib/security/AccessControlListSQL.js.map +1 -0
- package/dist/lib/security/index.js +3 -0
- package/dist/lib/security/index.js.map +1 -0
- package/dist/lib/test/index.js +3 -0
- package/dist/lib/test/index.js.map +1 -0
- package/dist/lib/test/request.js +99 -0
- package/dist/lib/test/request.js.map +1 -0
- package/dist/lib/test/requestws.js +173 -0
- package/dist/lib/test/requestws.js.map +1 -0
- package/dist/types/ApiErrors.d.ts +38 -0
- package/dist/types/BackgroundService.d.ts +30 -0
- package/dist/types/BackgroundServiceManager.d.ts +66 -0
- package/dist/types/BulkError.d.ts +11 -0
- package/dist/types/EventListenerManager.d.ts +36 -0
- package/dist/types/NetUtils.d.ts +29 -0
- package/dist/types/NotificationUtils.d.ts +25 -0
- package/dist/types/ObjectFactory.d.ts +17 -0
- package/dist/types/OpenApiSpec.d.ts +114 -0
- package/dist/types/Server.d.ts +180 -0
- package/dist/types/Types.d.ts +8 -0
- package/dist/types/auth/AuthMiddleware.d.ts +42 -0
- package/dist/types/auth/AuthStrategy.d.ts +32 -0
- package/dist/types/auth/BasicStrategy.d.ts +33 -0
- package/dist/types/auth/JWTStrategy.d.ts +61 -0
- package/dist/types/auth/index.d.ts +4 -0
- package/dist/types/database/ConnectionKinds.d.ts +7 -0
- package/dist/types/database/ConnectionManager.d.ts +35 -0
- package/dist/types/database/MongoConnection.d.ts +54 -0
- package/dist/types/database/MongoRepository.d.ts +92 -0
- package/dist/types/database/MongoSchemaSync.d.ts +41 -0
- package/dist/types/database/NamingUtils.d.ts +24 -0
- package/dist/types/database/TypeOrmSupport.d.ts +20 -0
- package/dist/types/database/index.d.ts +6 -0
- package/dist/types/decorators/DatabaseDecorators.d.ts +18 -0
- package/dist/types/decorators/DocDecorators.d.ts +69 -0
- package/dist/types/decorators/EventDecorators.d.ts +12 -0
- package/dist/types/decorators/ModelDecorators.d.ts +80 -0
- package/dist/types/decorators/PersistenceDecorators.d.ts +117 -0
- package/dist/types/decorators/RouteDecorators.d.ts +172 -0
- package/dist/types/decorators/index.d.ts +6 -0
- package/dist/types/http/Adapters.d.ts +68 -0
- package/dist/types/http/Router.d.ts +99 -0
- package/dist/types/http/WebSocket.d.ts +56 -0
- package/dist/types/http/index.d.ts +6 -0
- package/dist/types/http/types.d.ts +54 -0
- package/dist/types/index.d.ts +17 -0
- package/dist/types/models/BaseEntity.d.ts +29 -0
- package/dist/types/models/BaseMongoEntity.d.ts +13 -0
- package/dist/types/models/ModelUtils.d.ts +166 -0
- package/dist/types/models/RecoverableBaseEntity.d.ts +16 -0
- package/dist/types/models/RecoverableBaseMongoEntity.d.ts +16 -0
- package/dist/types/models/RepoUtils.d.ts +154 -0
- package/dist/types/models/SimpleEntity.d.ts +14 -0
- package/dist/types/models/SimpleMongoEntity.d.ts +15 -0
- package/dist/types/models/StatusExtraData.d.ts +6 -0
- package/dist/types/models/index.d.ts +9 -0
- package/dist/types/routes/AdminRoute.d.ts +47 -0
- package/dist/types/routes/MetricsRoute.d.ts +15 -0
- package/dist/types/routes/ModelRoute.d.ts +226 -0
- package/dist/types/routes/OpenAPIRoute.d.ts +17 -0
- package/dist/types/routes/RouteUtils.d.ts +55 -0
- package/dist/types/routes/StatusRoute.d.ts +11 -0
- package/dist/types/routes/index.d.ts +6 -0
- package/dist/types/security/ACLRouteMongo.d.ts +19 -0
- package/dist/types/security/ACLRouteSQL.d.ts +19 -0
- package/dist/types/security/ACLUtils.d.ts +94 -0
- package/dist/types/security/AccessControlList.d.ts +103 -0
- package/dist/types/security/AccessControlListMongo.d.ts +24 -0
- package/dist/types/security/AccessControlListSQL.d.ts +24 -0
- package/dist/types/security/index.d.ts +2 -0
- package/dist/types/test/index.d.ts +2 -0
- package/dist/types/test/request.d.ts +24 -0
- package/dist/types/test/requestws.d.ts +21 -0
- package/docs/Makefile +20 -0
- package/docs/conf.py +58 -0
- package/docs/index.rst +17 -0
- package/docs/make.bat +35 -0
- package/docs/reference/@rapidrest/namespaces/DatabaseDecorators/README.md +13 -0
- package/docs/reference/@rapidrest/namespaces/DatabaseDecorators/functions/MongoRepository.md +25 -0
- package/docs/reference/@rapidrest/namespaces/DatabaseDecorators/functions/RedisConnection.md +25 -0
- package/docs/reference/@rapidrest/namespaces/DatabaseDecorators/functions/Repository.md +25 -0
- package/docs/reference/@rapidrest/namespaces/DocDecorators/README.md +23 -0
- package/docs/reference/@rapidrest/namespaces/DocDecorators/functions/Default.md +25 -0
- package/docs/reference/@rapidrest/namespaces/DocDecorators/functions/Description.md +25 -0
- package/docs/reference/@rapidrest/namespaces/DocDecorators/functions/Document.md +25 -0
- package/docs/reference/@rapidrest/namespaces/DocDecorators/functions/Example.md +25 -0
- package/docs/reference/@rapidrest/namespaces/DocDecorators/functions/Format.md +25 -0
- package/docs/reference/@rapidrest/namespaces/DocDecorators/functions/Returns.md +28 -0
- package/docs/reference/@rapidrest/namespaces/DocDecorators/functions/Summary.md +25 -0
- package/docs/reference/@rapidrest/namespaces/DocDecorators/functions/Tags.md +25 -0
- package/docs/reference/@rapidrest/namespaces/DocDecorators/functions/TypeInfo.md +28 -0
- package/docs/reference/@rapidrest/namespaces/DocDecorators/interfaces/DocumentsData.md +57 -0
- package/docs/reference/@rapidrest/namespaces/EventDecorators/README.md +12 -0
- package/docs/reference/@rapidrest/namespaces/EventDecorators/functions/EventListener.md +17 -0
- package/docs/reference/@rapidrest/namespaces/EventDecorators/functions/OnEvent.md +26 -0
- package/docs/reference/@rapidrest/namespaces/ModelDecorators/README.md +26 -0
- package/docs/reference/@rapidrest/namespaces/ModelDecorators/functions/Cache.md +25 -0
- package/docs/reference/@rapidrest/namespaces/ModelDecorators/functions/ChildEntity.md +18 -0
- package/docs/reference/@rapidrest/namespaces/ModelDecorators/functions/DataStore.md +25 -0
- package/docs/reference/@rapidrest/namespaces/ModelDecorators/functions/Identifier.md +27 -0
- package/docs/reference/@rapidrest/namespaces/ModelDecorators/functions/Protect.md +35 -0
- package/docs/reference/@rapidrest/namespaces/ModelDecorators/functions/Reference.md +25 -0
- package/docs/reference/@rapidrest/namespaces/ModelDecorators/functions/Shard.md +27 -0
- package/docs/reference/@rapidrest/namespaces/ModelDecorators/functions/TrackChanges.md +26 -0
- package/docs/reference/@rapidrest/namespaces/ModelDecorators/interfaces/PendingTypeOrmColumn.md +45 -0
- package/docs/reference/@rapidrest/namespaces/ModelDecorators/variables/pendingTypeOrmColumns.md +14 -0
- package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/README.md +25 -0
- package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/functions/Column.md +25 -0
- package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/functions/Entity.md +26 -0
- package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/functions/Index.md +119 -0
- package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/functions/PrimaryColumn.md +25 -0
- package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/functions/Unique.md +68 -0
- package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/functions/getColumnMetadata.md +26 -0
- package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/functions/getEntityName.md +26 -0
- package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/functions/getIndexMetadata.md +27 -0
- package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/interfaces/ColumnInfo.md +41 -0
- package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/interfaces/ColumnOptions.md +51 -0
- package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/interfaces/IndexInfo.md +41 -0
- package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/interfaces/IndexOptions.md +51 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/README.md +36 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/After.md +26 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Auth.md +33 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/AuthResult.md +31 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Before.md +25 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/ContentType.md +25 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Delete.md +25 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Get.md +25 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Head.md +25 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Header.md +25 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Method.md +31 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Model.md +25 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Options.md +25 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Param.md +26 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Patch.md +25 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Post.md +25 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Protect.md +31 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Put.md +25 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Query.md +26 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Request.md +31 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/RequiresRole.md +26 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Response.md +31 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Route.md +25 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Socket.md +33 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/User.md +31 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Validate.md +25 -0
- package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/WebSocket.md +25 -0
- package/docs/reference/README.md +20 -0
- package/docs/reference/classes/ACLUtils.md +251 -0
- package/docs/reference/classes/AdminRoute.md +51 -0
- package/docs/reference/classes/AuthMiddleware.md +131 -0
- package/docs/reference/classes/BackgroundService.md +117 -0
- package/docs/reference/classes/BackgroundServiceManager.md +172 -0
- package/docs/reference/classes/BaseEntity.md +82 -0
- package/docs/reference/classes/BaseMongoEntity.md +107 -0
- package/docs/reference/classes/BasicStrategy.md +89 -0
- package/docs/reference/classes/BasicStrategyOptions.md +91 -0
- package/docs/reference/classes/BulkError.md +271 -0
- package/docs/reference/classes/ConnectionManager.md +75 -0
- package/docs/reference/classes/EventListenerManager.md +88 -0
- package/docs/reference/classes/JWTStrategy.md +77 -0
- package/docs/reference/classes/JWTStrategyOptions.md +97 -0
- package/docs/reference/classes/MetricsRoute.md +27 -0
- package/docs/reference/classes/ModelRoute.md +527 -0
- package/docs/reference/classes/ModelUtils.md +448 -0
- package/docs/reference/classes/MongoConnection.md +218 -0
- package/docs/reference/classes/MongoRepository.md +354 -0
- package/docs/reference/classes/MongoSchemaSync.md +67 -0
- package/docs/reference/classes/NetUtils.md +90 -0
- package/docs/reference/classes/NotificationUtils.md +77 -0
- package/docs/reference/classes/ObjectFactory.md +336 -0
- package/docs/reference/classes/OpenAPIRoute.md +77 -0
- package/docs/reference/classes/OpenApiSpec.md +892 -0
- package/docs/reference/classes/RecoverableBaseEntity.md +114 -0
- package/docs/reference/classes/RecoverableBaseMongoEntity.md +124 -0
- package/docs/reference/classes/RedisTransport.md +2202 -0
- package/docs/reference/classes/RepoUtils.md +486 -0
- package/docs/reference/classes/RouteUtils.md +191 -0
- package/docs/reference/classes/Server.md +408 -0
- package/docs/reference/classes/SimpleEntity.md +48 -0
- package/docs/reference/classes/SimpleMongoEntity.md +66 -0
- package/docs/reference/classes/StatusExtraData.md +57 -0
- package/docs/reference/classes/StatusRoute.md +26 -0
- package/docs/reference/enumerations/ACLAction.md +63 -0
- package/docs/reference/enumerations/ApiErrorMessages.md +123 -0
- package/docs/reference/enumerations/ApiErrors.md +123 -0
- package/docs/reference/functions/isSqlDataSource.md +26 -0
- package/docs/reference/functions/resolveCollectionName.md +33 -0
- package/docs/reference/functions/snakeCase.md +28 -0
- package/docs/reference/globals.md +91 -0
- package/docs/reference/interfaces/ACLRecord.md +96 -0
- package/docs/reference/interfaces/AccessControlList.md +76 -0
- package/docs/reference/interfaces/AuthResult.md +55 -0
- package/docs/reference/interfaces/AuthStrategy.md +57 -0
- package/docs/reference/interfaces/CreateRequestOptions.md +121 -0
- package/docs/reference/interfaces/DeleteRequestOptions.md +147 -0
- package/docs/reference/interfaces/FindRequestOptions.md +133 -0
- package/docs/reference/interfaces/JWTAuthResult.md +84 -0
- package/docs/reference/interfaces/RepoCreateOptions.md +95 -0
- package/docs/reference/interfaces/RepoDeleteOptions.md +115 -0
- package/docs/reference/interfaces/RepoFindOptions.md +135 -0
- package/docs/reference/interfaces/RepoOperationOptions.md +69 -0
- package/docs/reference/interfaces/RepoUpdateOptions.md +111 -0
- package/docs/reference/interfaces/RequestOptions.md +112 -0
- package/docs/reference/interfaces/TruncateRequestOptions.md +175 -0
- package/docs/reference/interfaces/UpdateRequestOptions.md +149 -0
- package/docs/reference/type-aliases/OneOrMany.md +19 -0
- package/docs/reference/type-aliases/OneOrNull.md +19 -0
- package/docs/reference/type-aliases/PartialBaseEntity.md +17 -0
- package/docs/reference/type-aliases/PartialSimpleEntity.md +17 -0
- package/docs/reference/type-aliases/UpdateObject.md +19 -0
- package/package.json +125 -0
|
@@ -0,0 +1,645 @@
|
|
|
1
|
+
import { MongoRepository } from "../database/MongoRepository.js";
|
|
2
|
+
import { ApiError, ClassLoader, Logger, StringUtils } from "@rapidrest/core";
|
|
3
|
+
import "reflect-metadata";
|
|
4
|
+
import { isEmpty } from "lodash";
|
|
5
|
+
import { RecoverableBaseEntity } from "./RecoverableBaseEntity.js";
|
|
6
|
+
import { ApiErrorMessages, ApiErrors } from "../ApiErrors.js";
|
|
7
|
+
const logger = Logger();
|
|
8
|
+
// Apparently calling JSON.stringify on RegExp returns an empty set. So the recommended way to
|
|
9
|
+
// overcome this is by adding a `toJSON` method that uses the `toString` instead which will
|
|
10
|
+
// give us what we want.
|
|
11
|
+
RegExp.prototype.toJSON = RegExp.prototype.toString;
|
|
12
|
+
/**
|
|
13
|
+
* Utility class for working with data model classes.
|
|
14
|
+
*
|
|
15
|
+
* @author Jean-Philippe Steinmetz
|
|
16
|
+
*/
|
|
17
|
+
export class ModelUtils {
|
|
18
|
+
/**
|
|
19
|
+
* Provides the `typeorm` module to use when building SQL queries. This is called automatically when a SQL
|
|
20
|
+
* datastore connection is established.
|
|
21
|
+
*
|
|
22
|
+
* @param module The `typeorm` module.
|
|
23
|
+
*/
|
|
24
|
+
static setTypeOrm(module) {
|
|
25
|
+
ModelUtils.typeOrm = module;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Returns the `typeorm` module, throwing an error if it has not been provided.
|
|
29
|
+
*/
|
|
30
|
+
static get orm() {
|
|
31
|
+
if (!ModelUtils.typeOrm) {
|
|
32
|
+
throw new Error("SQL query construction requires the optional peer dependency 'typeorm' but no SQL datastore has been initialized.");
|
|
33
|
+
}
|
|
34
|
+
return ModelUtils.typeOrm;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Retrieves a list of all of the specified class's properties that have the @Identifier decorator applied.
|
|
38
|
+
*
|
|
39
|
+
* @param modelClass The class definition to search for identifiers from.
|
|
40
|
+
* @returns The list of all property names that have the @Identifier decorator applied.
|
|
41
|
+
*/
|
|
42
|
+
static getIdPropertyNames(modelClass) {
|
|
43
|
+
const results = [];
|
|
44
|
+
// The props don't show up correctly on the class def. So instantiate a dummy object that we can read the props
|
|
45
|
+
// from and look for identifiers.
|
|
46
|
+
let proto = Object.getPrototypeOf(new modelClass());
|
|
47
|
+
while (proto) {
|
|
48
|
+
const props = Object.getOwnPropertyNames(proto);
|
|
49
|
+
for (const prop of props) {
|
|
50
|
+
const isIdentifier = Reflect.getMetadata("rrst:isIdentifier", proto, prop);
|
|
51
|
+
if (isIdentifier) {
|
|
52
|
+
results.push(prop);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
proto = Object.getPrototypeOf(proto);
|
|
56
|
+
}
|
|
57
|
+
return results;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Builds a query object for use with `find` functions of the given repository for retrieving objects matching the
|
|
61
|
+
* specified unique identifier.
|
|
62
|
+
*
|
|
63
|
+
* @param repo The repository to build the query for.
|
|
64
|
+
* @param modelClass The class definition of the data model to build a search query for.
|
|
65
|
+
* @param id The unique identifier to search for.
|
|
66
|
+
* @param version The version number of the document to search for.
|
|
67
|
+
* @param productUid The optional product uid that is associated with the uid (when a compound key is used).
|
|
68
|
+
* @returns An object that can be passed to a TypeORM `find` function.
|
|
69
|
+
*/
|
|
70
|
+
static buildIdSearchQuery(repo, modelClass, id, version, productUid) {
|
|
71
|
+
if (repo instanceof MongoRepository) {
|
|
72
|
+
return ModelUtils.buildIdSearchQueryMongo(modelClass, id, version, productUid);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
return ModelUtils.buildIdSearchQuerySQL(modelClass, id, version, productUid);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Builds a TypeORM compatible query object for use in `find` functions for retrieving objects matching the
|
|
80
|
+
* specified unique identifier.
|
|
81
|
+
*
|
|
82
|
+
* @param modelClass The class definition of the data model to build a search query for.
|
|
83
|
+
* @param id The unique identifier to search for.
|
|
84
|
+
* @param version The version number of the document to search for.
|
|
85
|
+
* @param productUid The optional product uid that is associated with the uid (when a compound key is used).
|
|
86
|
+
* @returns An object that can be passed to a TypeORM `find` function.
|
|
87
|
+
*/
|
|
88
|
+
static buildIdSearchQuerySQL(modelClass, id, version, productUid) {
|
|
89
|
+
const props = ModelUtils.getIdPropertyNames(modelClass);
|
|
90
|
+
// Create the where in SQL syntax. We only care about one of the identifier field's matching.
|
|
91
|
+
// e.g. WHERE idField1 = :idField1 OR idField2 = :idField2 ...
|
|
92
|
+
const where = [];
|
|
93
|
+
for (const prop of props) {
|
|
94
|
+
// If productUid is an id, skip it because it's used as a compound key
|
|
95
|
+
if (prop === "productUid")
|
|
96
|
+
continue;
|
|
97
|
+
const q = { [prop]: Array.isArray(id) ? ModelUtils.orm.In(id) : id };
|
|
98
|
+
if (props.includes("productUid")) {
|
|
99
|
+
q.productUid = productUid;
|
|
100
|
+
}
|
|
101
|
+
if (version !== undefined) {
|
|
102
|
+
q.version = version;
|
|
103
|
+
}
|
|
104
|
+
where.push(q);
|
|
105
|
+
}
|
|
106
|
+
return { where };
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Builds a MongoDB compatible query object for use in `find` functions for retrieving objects matching the
|
|
110
|
+
* specified unique identifier.
|
|
111
|
+
*
|
|
112
|
+
* @param modelClass The class definition of the data model to build a search query for.
|
|
113
|
+
* @param id The unique identifier to search for.
|
|
114
|
+
* @param version The version number of the document to search for.
|
|
115
|
+
* @param productUid The optional product uid that is associated with the uid (when a compound key is used).
|
|
116
|
+
* @returns An object that can be passed to a MongoDB `find` function.
|
|
117
|
+
*/
|
|
118
|
+
static buildIdSearchQueryMongo(modelClass, id, version, productUid) {
|
|
119
|
+
const props = ModelUtils.getIdPropertyNames(modelClass);
|
|
120
|
+
// We want to performa case-insensitive search. So convert all strings to regex.
|
|
121
|
+
if (Array.isArray(id)) {
|
|
122
|
+
for (let i = 0; i < id.length; i++) {
|
|
123
|
+
if (typeof id[i] === "string") {
|
|
124
|
+
id[i] = new RegExp("^" + id[i].replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "$", "i");
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else if (typeof id === "string") {
|
|
129
|
+
id = new RegExp("^" + id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "$", "i");
|
|
130
|
+
}
|
|
131
|
+
// Create the where in SQL syntax. We only care about one of the identifier field's matching.
|
|
132
|
+
// e.g. WHERE idField1 = :idField1 OR idField2 = :idField2 ...
|
|
133
|
+
const query = [];
|
|
134
|
+
for (const prop of props) {
|
|
135
|
+
// If productUid is an id, skip it because it's used as a compound key
|
|
136
|
+
if (prop === "productUid")
|
|
137
|
+
continue;
|
|
138
|
+
const q = { [prop]: Array.isArray(id) ? { $in: id } : id };
|
|
139
|
+
if (productUid && props.includes("productUid")) {
|
|
140
|
+
q.productUid = productUid;
|
|
141
|
+
}
|
|
142
|
+
if (version !== undefined) {
|
|
143
|
+
q.version = version;
|
|
144
|
+
}
|
|
145
|
+
query.push(q);
|
|
146
|
+
}
|
|
147
|
+
return { $or: query };
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Given a string containing a parameter value and/or a comparison operation return a TypeORM compatible find value.
|
|
151
|
+
* e.g.
|
|
152
|
+
* Given the string "myvalue" will return an Eq("myvalue") object.
|
|
153
|
+
* Given the string "Like(myvalue)" will return an Like("myvalue") object.
|
|
154
|
+
*
|
|
155
|
+
* @param param
|
|
156
|
+
*/
|
|
157
|
+
static getQueryParamValue(param) {
|
|
158
|
+
if (typeof param === "string") {
|
|
159
|
+
const { Equal, MoreThan, MoreThanOrEqual, In, ILike, LessThan, LessThanOrEqual, Not, Between } = ModelUtils.orm;
|
|
160
|
+
// The value of each param can optionally have the operation included. If no operator is included Eq is
|
|
161
|
+
// always assumed.
|
|
162
|
+
// e.g. ?param1=eq(value)¶m2=not(value)¶m3=gt(value)
|
|
163
|
+
const matches = param.match(new RegExp(/^([a-zA-Z]+)\((.*)\)$/, "i"));
|
|
164
|
+
if (matches) {
|
|
165
|
+
const opName = matches[1].toLowerCase();
|
|
166
|
+
let value = matches[2];
|
|
167
|
+
try {
|
|
168
|
+
// Attempt to parse the value to a native type
|
|
169
|
+
value = JSON.parse(matches[2]);
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
// If an error occurred it's because the value is a string or date, not another type.
|
|
173
|
+
value = new Date(matches[2]);
|
|
174
|
+
if (isNaN(value)) {
|
|
175
|
+
value = matches[2];
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
switch (opName) {
|
|
179
|
+
case "eq":
|
|
180
|
+
return Equal(value);
|
|
181
|
+
case "gt":
|
|
182
|
+
return MoreThan(value);
|
|
183
|
+
case "gte":
|
|
184
|
+
return MoreThanOrEqual(value);
|
|
185
|
+
case "in": {
|
|
186
|
+
const args = value.split(",");
|
|
187
|
+
return In(args);
|
|
188
|
+
}
|
|
189
|
+
case "like":
|
|
190
|
+
return ILike(value);
|
|
191
|
+
case "lt":
|
|
192
|
+
return LessThan(value);
|
|
193
|
+
case "lte":
|
|
194
|
+
return LessThanOrEqual(value);
|
|
195
|
+
case "ne":
|
|
196
|
+
case "not":
|
|
197
|
+
return Not(value);
|
|
198
|
+
case "range": {
|
|
199
|
+
const args = value.split(",");
|
|
200
|
+
if (args.length !== 2) {
|
|
201
|
+
const msg = StringUtils.findAndReplace(ApiErrorMessages.SEARCH_INVALID_RANGE, {
|
|
202
|
+
value,
|
|
203
|
+
length: args.length,
|
|
204
|
+
});
|
|
205
|
+
throw new ApiError(ApiErrors.SEARCH_INVALID_RANGE, 400, msg);
|
|
206
|
+
}
|
|
207
|
+
try {
|
|
208
|
+
// Attempt to parse the range values to native types
|
|
209
|
+
return Between(JSON.parse(args[0]), JSON.parse(args[1]));
|
|
210
|
+
}
|
|
211
|
+
catch (err) {
|
|
212
|
+
return Between(args[0], args[1]);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
default:
|
|
216
|
+
return Equal(value);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
try {
|
|
221
|
+
// Attempt to parse the value to a native type
|
|
222
|
+
return Equal(JSON.parse(param));
|
|
223
|
+
}
|
|
224
|
+
catch (err) {
|
|
225
|
+
// If an error occurred it's because the value is a string, not another type.
|
|
226
|
+
const date = new Date(param);
|
|
227
|
+
return Equal(!isNaN(date.valueOf()) ? date : param);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
return param;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Given a string containing a parameter value and/or a comparison operation return a MongoDB compatible find value.
|
|
237
|
+
* e.g.
|
|
238
|
+
* Given the string "myvalue" will return an `"myvalue"` object.
|
|
239
|
+
* Given the string "not(myvalue)" will return an `{ $not: "myvalue" }` object.
|
|
240
|
+
*
|
|
241
|
+
* @param param
|
|
242
|
+
*/
|
|
243
|
+
static getQueryParamValueMongo(param) {
|
|
244
|
+
if (typeof param === "string") {
|
|
245
|
+
// The value of each param can optionally have the operation included. If no operator is included Eq is
|
|
246
|
+
// always assumed.
|
|
247
|
+
// e.g. ?param1=eq(value)¶m2=not(value)¶m3=gt(value)
|
|
248
|
+
const matches = param.match(new RegExp(/^([a-zA-Z]+)\((.*)\)$/, "i"));
|
|
249
|
+
if (matches) {
|
|
250
|
+
const opName = matches[1].toLowerCase();
|
|
251
|
+
let value = matches[2];
|
|
252
|
+
try {
|
|
253
|
+
// Attempt to parse the value to a native type
|
|
254
|
+
value = JSON.parse(matches[2]);
|
|
255
|
+
}
|
|
256
|
+
catch (err) {
|
|
257
|
+
// If an error occurred it's because the value is a string or date, not another type.
|
|
258
|
+
value = new Date(matches[2]);
|
|
259
|
+
if (isNaN(value)) {
|
|
260
|
+
value = matches[2];
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
switch (opName) {
|
|
264
|
+
case "eq":
|
|
265
|
+
return value;
|
|
266
|
+
case "gt":
|
|
267
|
+
return { $gt: value };
|
|
268
|
+
case "gte":
|
|
269
|
+
return { $gte: value };
|
|
270
|
+
case "in": {
|
|
271
|
+
const args = value.split(",");
|
|
272
|
+
return { $in: args };
|
|
273
|
+
}
|
|
274
|
+
case "nin": {
|
|
275
|
+
const args = value.split(",");
|
|
276
|
+
return { $nin: args };
|
|
277
|
+
}
|
|
278
|
+
case "like":
|
|
279
|
+
return { $regex: value, $options: "i" };
|
|
280
|
+
case "lt":
|
|
281
|
+
return { $lt: value };
|
|
282
|
+
case "lte":
|
|
283
|
+
return { $lte: value };
|
|
284
|
+
case "ne":
|
|
285
|
+
return { $ne: value };
|
|
286
|
+
case "not":
|
|
287
|
+
return { $not: value };
|
|
288
|
+
case "range": {
|
|
289
|
+
const args = value.split(",");
|
|
290
|
+
if (args.length !== 2) {
|
|
291
|
+
const msg = StringUtils.findAndReplace(ApiErrorMessages.SEARCH_INVALID_RANGE, {
|
|
292
|
+
value,
|
|
293
|
+
length: args.length,
|
|
294
|
+
});
|
|
295
|
+
throw new ApiError(ApiErrors.SEARCH_INVALID_RANGE, 400, msg);
|
|
296
|
+
}
|
|
297
|
+
try {
|
|
298
|
+
// Attempt to parse the range values to native types
|
|
299
|
+
return { $gte: JSON.parse(args[0]), $lte: JSON.parse(args[1]) };
|
|
300
|
+
}
|
|
301
|
+
catch (err) {
|
|
302
|
+
return { $gte: args[0], $lte: args[1] };
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
default:
|
|
306
|
+
return value;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
try {
|
|
311
|
+
// Attempt to parse the value to a native type
|
|
312
|
+
return JSON.parse(param);
|
|
313
|
+
}
|
|
314
|
+
catch (err) {
|
|
315
|
+
// If an error occurred it's because the value is a string or date, not another type.
|
|
316
|
+
const date = new Date(param);
|
|
317
|
+
return !isNaN(date.valueOf()) ? date : param;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
return param;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Builds a query object for the given criteria and repository. Query params can have a value containing a
|
|
327
|
+
* conditional operator to apply for the search. The operator is encoded with the format `op(value)`. The following
|
|
328
|
+
* operators are supported:
|
|
329
|
+
* * `eq` - Returns matches whose parameter exactly matches of the given value. e.g. `param = value`
|
|
330
|
+
* * `gt` - Returns matches whose parameter is greater than the given value. e.g. `param > value`
|
|
331
|
+
* * `gte` - Returns matches whose parameter is greater than or equal to the given value. e.g. `param >= value`
|
|
332
|
+
* * `in` - Returns matches whose parameter includes one of the given values. e.g. `param in ('value1', 'value2', 'value3', ...)`
|
|
333
|
+
* * `like` - Returns matches whose parameter is lexographically similar to the given value. `param like value`
|
|
334
|
+
* * `lt` - Returns matches whose parameter is less than the given value. e.g. `param < value`
|
|
335
|
+
* * `lte` - Returns matches whose parameter is less than or equal to than the given value. e.g. `param < value`
|
|
336
|
+
* * `not` - Returns matches whose parameter is not equal to the given value. e.g. `param not value`
|
|
337
|
+
* * `range` - Returns matches whose parameter is greater than or equal to first given value and less than or equal to the second. e.g. `param between(1,100)`
|
|
338
|
+
*
|
|
339
|
+
* When no operator is provided the comparison will always be evaluated as `eq`.
|
|
340
|
+
*
|
|
341
|
+
* NOTE: The result of this function is only compatible with the `aggregate()` function when MongoDB is used.
|
|
342
|
+
*
|
|
343
|
+
* @param modelClass The class definition of the data model to build a search query for.
|
|
344
|
+
* @param repo The repository to build a search query for.
|
|
345
|
+
* @param {any} params The URI parameters for the endpoint that was requested.
|
|
346
|
+
* @param {any} queryParams The URI query parameters that were included in the request.
|
|
347
|
+
* @param {bool} exactMatch Set to true to create a query where parameters are to be matched exactly, otherwise set to false to use a 'contains' search.
|
|
348
|
+
* @param {any} user The user that is performing the request.
|
|
349
|
+
* @returns {object} The TypeORM compatible query object.
|
|
350
|
+
*/
|
|
351
|
+
static buildSearchQuery(modelClass, repo, params, queryParams, exactMatch = false, user) {
|
|
352
|
+
// By default we don't want to return deleted recoverable objects unless explicitly requested
|
|
353
|
+
if (new modelClass() instanceof RecoverableBaseEntity) {
|
|
354
|
+
queryParams = {
|
|
355
|
+
...queryParams,
|
|
356
|
+
deleted: queryParams && "deleted" in queryParams ? queryParams.deleted : false,
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
if (repo instanceof MongoRepository) {
|
|
360
|
+
return ModelUtils.buildSearchQueryMongo(modelClass, params, queryParams, exactMatch, user);
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
return ModelUtils.buildSearchQuerySQL(modelClass, params, queryParams, exactMatch, user);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Builds a TypeORM compatible query object for the given criteria. Query params can have a value containing a
|
|
368
|
+
* conditional operator to apply for the search. The operator is encoded with the format `op(value)`. The following
|
|
369
|
+
* operators are supported:
|
|
370
|
+
* * `eq` - Returns matches whose parameter exactly matches of the given value. e.g. `param = value`
|
|
371
|
+
* * `gt` - Returns matches whose parameter is greater than the given value. e.g. `param > value`
|
|
372
|
+
* * `gte` - Returns matches whose parameter is greater than or equal to the given value. e.g. `param >= value`
|
|
373
|
+
* * `in` - Returns matches whose parameter includes one of the given values. e.g. `param in ('value1', 'value2', 'value3', ...)`
|
|
374
|
+
* * `like` - Returns matches whose parameter is lexographically similar to the given value. `param like value`
|
|
375
|
+
* * `lt` - Returns matches whose parameter is less than the given value. e.g. `param < value`
|
|
376
|
+
* * `lte` - Returns matches whose parameter is less than or equal to than the given value. e.g. `param < value`
|
|
377
|
+
* * `not` - Returns matches whose parameter is not equal to the given value. e.g. `param not value`
|
|
378
|
+
* * `range` - Returns matches whose parameter is greater than or equal to first given value and less than or equal to the second. e.g. `param between(1,100)`
|
|
379
|
+
*
|
|
380
|
+
* When no operator is provided the comparison will always be evaluated as `eq`.
|
|
381
|
+
*
|
|
382
|
+
* @param modelClass The class definition of the data model to build a search query for.
|
|
383
|
+
* @param {any} params The URI parameters for the endpoint that was requested.
|
|
384
|
+
* @param {any} queryParams The URI query parameters that were included in the request.
|
|
385
|
+
* @param {bool} exactMatch Set to true to create a query where parameters are to be matched exactly, otherwise set to false to use a 'contains' search.
|
|
386
|
+
* @param {any} user The user that is performing the request.
|
|
387
|
+
* @returns {object} The TypeORM compatible query object.
|
|
388
|
+
*/
|
|
389
|
+
static buildSearchQuerySQL(modelClass, params, queryParams, exactMatch = false, user) {
|
|
390
|
+
const query = {};
|
|
391
|
+
query.where = [];
|
|
392
|
+
// Add the URL parameters
|
|
393
|
+
for (const key in params) {
|
|
394
|
+
// If the value is 'me' that's a special keyword to reference the user ID.
|
|
395
|
+
if (params[key] === "me") {
|
|
396
|
+
if (!user) {
|
|
397
|
+
throw new ApiError(ApiErrors.SEARCH_INVALID_ME_REFERENCE, 403, ApiErrorMessages.SEARCH_INVALID_ME_REFERENCE);
|
|
398
|
+
}
|
|
399
|
+
query.where[key] = user.uid;
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
402
|
+
query.where[key] = params[key];
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
// Query parameters can be a single value or multiple. In the case of multiple we want to perform an OR
|
|
406
|
+
// operation for each value. But to do that we need to build a separate object for each value containing all
|
|
407
|
+
// the parameters as well.
|
|
408
|
+
// So first let's find out how many queries in total we are going to need.
|
|
409
|
+
let numQueries = 1;
|
|
410
|
+
for (const key in queryParams) {
|
|
411
|
+
const value = queryParams[key];
|
|
412
|
+
if (Array.isArray(value)) {
|
|
413
|
+
if (value.length > numQueries) {
|
|
414
|
+
numQueries = value.length;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
// logger?.debug(`Query params: ${JSON.stringify(queryParams)}`);
|
|
419
|
+
// Now go through each query paramater. If the parameter is a single value, add it to each query object. If it's an array,
|
|
420
|
+
// add only one value to each query object.
|
|
421
|
+
for (let key in queryParams) {
|
|
422
|
+
// Ignore reserved query parameters
|
|
423
|
+
if (key.match(new RegExp("(jwt_|oauth_|auth_|cache).*", "i"))) {
|
|
424
|
+
continue;
|
|
425
|
+
}
|
|
426
|
+
// Limit, page and sort are reserved for specifying query limits
|
|
427
|
+
if (key.match(new RegExp("(limit|page|sort).*", "i"))) {
|
|
428
|
+
let value = queryParams[key];
|
|
429
|
+
if (key === "limit") {
|
|
430
|
+
key = "take";
|
|
431
|
+
query[key] = Number(value);
|
|
432
|
+
}
|
|
433
|
+
else if (key === "page") {
|
|
434
|
+
query[key] = Number(value);
|
|
435
|
+
}
|
|
436
|
+
else if (key === "sort") {
|
|
437
|
+
key = "order";
|
|
438
|
+
if (typeof value === "string") {
|
|
439
|
+
if (value.match(new RegExp(/^\{.*\}$/, "i"))) {
|
|
440
|
+
value = JSON.parse(value);
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
let newValue = value;
|
|
444
|
+
newValue = {};
|
|
445
|
+
newValue[value] = "ASC";
|
|
446
|
+
value = newValue;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
query[key] = value;
|
|
450
|
+
}
|
|
451
|
+
continue;
|
|
452
|
+
}
|
|
453
|
+
if (Array.isArray(queryParams[key])) {
|
|
454
|
+
// Add each value in the array to each corresponding query
|
|
455
|
+
let i = 0;
|
|
456
|
+
for (const value of queryParams[key]) {
|
|
457
|
+
if (!query.where[i]) {
|
|
458
|
+
query.where[i] = {};
|
|
459
|
+
}
|
|
460
|
+
query.where[i][key] = ModelUtils.getQueryParamValue(value);
|
|
461
|
+
i++;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
else {
|
|
465
|
+
// Add the parameter to every query
|
|
466
|
+
for (let i = 0; i < numQueries; i++) {
|
|
467
|
+
if (!query.where[i]) {
|
|
468
|
+
query.where[i] = {};
|
|
469
|
+
}
|
|
470
|
+
query.where[i][key] = ModelUtils.getQueryParamValue(queryParams[key]);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
if (query.where.length === 0) {
|
|
475
|
+
delete query.where;
|
|
476
|
+
}
|
|
477
|
+
if (query.take) {
|
|
478
|
+
query.take = Math.min(query.take, 1000);
|
|
479
|
+
}
|
|
480
|
+
else {
|
|
481
|
+
query.take = 100;
|
|
482
|
+
}
|
|
483
|
+
query.page = query.page ? query.page : 0;
|
|
484
|
+
return query;
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Builds a MongoDB compatible query object for the given criteria. Query params can have a value containing a
|
|
488
|
+
* conditional operator to apply for the search. The operator is encoded with the format `op(value)`. The following
|
|
489
|
+
* operators are supported:
|
|
490
|
+
* * `eq` - Returns matches whose parameter exactly matches of the given value. e.g. `param = value`
|
|
491
|
+
* * `gt` - Returns matches whose parameter is greater than the given value. e.g. `param > value`
|
|
492
|
+
* * `gte` - Returns matches whose parameter is greater than or equal to the given value. e.g. `param >= value`
|
|
493
|
+
* * `in` - Returns matches whose parameter includes one of the given values. e.g. `param in ('value1', 'value2', 'value3', ...)`
|
|
494
|
+
* * `like` - Returns matches whose parameter is lexographically similar to the given value. `param like value`
|
|
495
|
+
* * `lt` - Returns matches whose parameter is less than the given value. e.g. `param < value`
|
|
496
|
+
* * `lte` - Returns matches whose parameter is less than or equal to than the given value. e.g. `param < value`
|
|
497
|
+
* * `not` - Returns matches whose parameter is not equal to the given value. e.g. `param not value`
|
|
498
|
+
* * `range` - Returns matches whose parameter is greater than or equal to first given value and less than or equal to the second. e.g. `param between(1,100)`
|
|
499
|
+
*
|
|
500
|
+
* When no operator is provided the comparison will always be evaluated as `eq`.
|
|
501
|
+
*
|
|
502
|
+
* NOTE: The result of this function is only compatible with the `aggregate()` function.
|
|
503
|
+
*
|
|
504
|
+
* @param modelClass The class definition of the data model to build a search query for.
|
|
505
|
+
* @param {any} params The URI parameters for the endpoint that was requested.
|
|
506
|
+
* @param {any} queryParams The URI query parameters that were included in the request.
|
|
507
|
+
* @param {bool} exactMatch Set to true to create a query where parameters are to be matched exactly, otherwise set to false to use a 'contains' search.
|
|
508
|
+
* @param {any} user The user that is performing the request.
|
|
509
|
+
* @returns {object} The TypeORM compatible query object.
|
|
510
|
+
*/
|
|
511
|
+
static buildSearchQueryMongo(modelClass, params, queryParams, exactMatch = false, user) {
|
|
512
|
+
const queries = [{}];
|
|
513
|
+
let sort = undefined;
|
|
514
|
+
// Add the URL parameters
|
|
515
|
+
for (const key in params) {
|
|
516
|
+
// If the value is 'me' that's a special keyword to reference the user ID.
|
|
517
|
+
if (params[key] === "me") {
|
|
518
|
+
if (!user) {
|
|
519
|
+
throw new ApiError(ApiErrors.SEARCH_INVALID_ME_REFERENCE, 403, ApiErrorMessages.SEARCH_INVALID_ME_REFERENCE);
|
|
520
|
+
}
|
|
521
|
+
queries[0][key] = user.uid;
|
|
522
|
+
}
|
|
523
|
+
else {
|
|
524
|
+
queries[0][key] = params[key];
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
// logger?.debug(`Query params: ${JSON.stringify(queryParams)}`);
|
|
528
|
+
for (const key in queryParams) {
|
|
529
|
+
// Ignore reserved query parameters
|
|
530
|
+
if (key.match(new RegExp("(jwt_|oauth_|auth_).*", "i"))) {
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
// Limit, page and sort are reserved for specifying query limits
|
|
534
|
+
if (key.match(new RegExp("(limit|page|sort).*", "i"))) {
|
|
535
|
+
let value = queryParams[key];
|
|
536
|
+
if (key === "sort") {
|
|
537
|
+
if (typeof value === "string") {
|
|
538
|
+
if (value.match(new RegExp(/^\{.*\}$/, "i"))) {
|
|
539
|
+
value = JSON.parse(value);
|
|
540
|
+
}
|
|
541
|
+
else {
|
|
542
|
+
let newValue = value;
|
|
543
|
+
newValue = {};
|
|
544
|
+
newValue[value] = 1;
|
|
545
|
+
value = newValue;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
let resolvedSort = {
|
|
549
|
+
...sort,
|
|
550
|
+
...value,
|
|
551
|
+
};
|
|
552
|
+
sort = sort || {};
|
|
553
|
+
// Format sort for mongo: https://www.mongodb.com/docs/manual/reference/operator/aggregation/sort/#mongodb-pipeline-pipe.-sort
|
|
554
|
+
Object.keys(resolvedSort).forEach((key) => {
|
|
555
|
+
let value = resolvedSort[key];
|
|
556
|
+
if (!value)
|
|
557
|
+
return;
|
|
558
|
+
if (typeof value === "number") {
|
|
559
|
+
sort[key] = value;
|
|
560
|
+
}
|
|
561
|
+
else if (value.toUpperCase() === "ASC") {
|
|
562
|
+
sort[key] = 1;
|
|
563
|
+
}
|
|
564
|
+
else if (value.toUpperCase() === "DESC") {
|
|
565
|
+
sort[key] = -1;
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
if (key === "$or") {
|
|
572
|
+
// Array of OR queries
|
|
573
|
+
let orResults = [];
|
|
574
|
+
for (const query of queryParams[key]) {
|
|
575
|
+
const subQueryOrResult = this.buildSearchQueryMongo(modelClass, undefined, query, exactMatch, user);
|
|
576
|
+
const validSubQueryResult = subQueryOrResult && subQueryOrResult.length > 0 && subQueryOrResult[0]["$match"];
|
|
577
|
+
validSubQueryResult && orResults.push(validSubQueryResult);
|
|
578
|
+
}
|
|
579
|
+
queries[0] = { $or: orResults };
|
|
580
|
+
continue;
|
|
581
|
+
}
|
|
582
|
+
if (Array.isArray(queryParams[key])) {
|
|
583
|
+
// Add each value in the array to each corresponding query
|
|
584
|
+
const conditions = [];
|
|
585
|
+
for (let i = 0; i < queryParams[key].length; i++) {
|
|
586
|
+
const value = ModelUtils.getQueryParamValueMongo(queryParams[key][i]);
|
|
587
|
+
if (!queries[i]) {
|
|
588
|
+
queries[i] = {
|
|
589
|
+
...queries[0],
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
queries[i][key] = value;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
else {
|
|
596
|
+
const value = ModelUtils.getQueryParamValueMongo(queryParams[key]);
|
|
597
|
+
for (let i = 0; i < queries.length; i++) {
|
|
598
|
+
queries[i][key] = value;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
let result = [];
|
|
603
|
+
if (queries.length > 0) {
|
|
604
|
+
result.push({ $match: queries.length === 1 ? queries[0] : { $or: queries } });
|
|
605
|
+
}
|
|
606
|
+
// Determine if the model class is versioned or not. We provide a different
|
|
607
|
+
// aggregation query if it is.
|
|
608
|
+
if (modelClass && modelClass.trackChanges !== undefined) {
|
|
609
|
+
result.push({ $sort: { version: -1 } });
|
|
610
|
+
result.push({ $group: { _id: "$uid", doc: { $first: "$$ROOT" } } });
|
|
611
|
+
result.push({ $replaceRoot: { newRoot: "$doc" } });
|
|
612
|
+
}
|
|
613
|
+
// Add the sort if specified
|
|
614
|
+
if (sort && !isEmpty(sort)) {
|
|
615
|
+
result.push({ $sort: sort });
|
|
616
|
+
}
|
|
617
|
+
return result;
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* Loads all model schema files from the specified path and returns a map containing all the definitions.
|
|
621
|
+
*
|
|
622
|
+
* @param src The path to the model files to load.
|
|
623
|
+
* @returns A map containing of all loaded model names to their class definitions.
|
|
624
|
+
*/
|
|
625
|
+
static async loadModels(src, result = new Map()) {
|
|
626
|
+
return await new Promise(async (resolve, reject) => {
|
|
627
|
+
try {
|
|
628
|
+
const classLoader = new ClassLoader(src);
|
|
629
|
+
await classLoader.load();
|
|
630
|
+
// Go through each class and determine which ones implements the `@Model` decorator.
|
|
631
|
+
classLoader.getClasses().forEach((clazz, name) => {
|
|
632
|
+
const isModel = Reflect.getMetadata("rrst:datastore", clazz) !== undefined;
|
|
633
|
+
if (isModel) {
|
|
634
|
+
result.set(name, clazz);
|
|
635
|
+
}
|
|
636
|
+
});
|
|
637
|
+
resolve(result);
|
|
638
|
+
}
|
|
639
|
+
catch (error) {
|
|
640
|
+
reject(error);
|
|
641
|
+
}
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
//# sourceMappingURL=ModelUtils.js.map
|