| 
					
				 | 
			
			
				@@ -2,6 +2,7 @@ import config from "config"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // import { createClient, RedisClientType } from "redis"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import mongoose, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	Connection, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	isObjectIdOrHexString, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	MongooseDefaultQueryMiddleware, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	MongooseDistinctQueryMiddleware, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	MongooseQueryOrDocumentMiddleware 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -12,7 +13,7 @@ import path from "path"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import JobContext from "../JobContext"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import BaseModule, { ModuleStatus } from "../BaseModule"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import { UniqueMethods } from "../types/Modules"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import { Models } from "../types/Models"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { AnyModel, Models } from "../types/Models"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import { Schemas } from "../types/Schemas"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import documentVersionPlugin from "../schemas/plugins/documentVersion"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import getDataPlugin from "../schemas/plugins/getData"; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -185,6 +186,13 @@ export default class DataModule extends BaseModule { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	 * createMongoConnection - Create mongo connection 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	private async _createMongoConnection() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		mongoose.set({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			runValidators: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			sanitizeFilter: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			strict: "throw", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			strictQuery: "throw" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		const { user, password, host, port, database } = config.get<{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			user: string; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			password: string; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -197,11 +205,6 @@ export default class DataModule extends BaseModule { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		this._mongoConnection = await mongoose 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			.createConnection(mongoUrl) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			.asPromise(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		this._mongoConnection.set("runValidators", true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		this._mongoConnection.set("sanitizeFilter", true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		this._mongoConnection.set("strict", "throw"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		this._mongoConnection.set("strictQuery", "throw"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	/** 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -442,45 +445,174 @@ export default class DataModule extends BaseModule { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		await Promise.all( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			Object.entries(this._models).map(async ([modelName, model]) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				await Promise.all( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					["findById"].map(async method => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						this._jobConfig[`${modelName}.${method}`] = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							method: async (context, payload) => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-								Object.getPrototypeOf(this)[`_${method}`]( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-									context, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-									{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-										...payload, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-										model: modelName 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-									} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-								) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					["create", "findById", "updateById", "deleteById"].map( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						async method => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							this._jobConfig[`${modelName}.${method}`] = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								method: async (context, payload) => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									Object.getPrototypeOf(this)[`_${method}`]( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										context, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+											...payload, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+											modelName, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+											model 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				await Promise.all( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					Object.keys(model.schema.statics).map(async name => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						this._jobConfig[`${modelName}.${name}`] = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							method: async (...args) => model[name](...args) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				const jobConfig = model.schema.get("jobConfig"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					typeof jobConfig === "object" && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					Object.keys(jobConfig).length > 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					await Promise.all( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						Object.entries(jobConfig).map( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							async ([name, options]) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								if (options === "disabled") { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									if (this._jobConfig[`${modelName}.${name}`]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										delete this._jobConfig[ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+											`${modelName}.${name}` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								let api = this._jobApiDefault; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								let method; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								const configOptions = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									this._jobConfig[`${modelName}.${name}`]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								if (typeof configOptions === "object") { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									if (typeof configOptions.api === "boolean") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										api = configOptions.api; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									if ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										typeof configOptions.method === 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										"function" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										method = configOptions.method; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								} else if (typeof configOptions === "function") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									method = configOptions; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								else if (typeof configOptions === "boolean") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									api = configOptions; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								if ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									typeof options === "object" && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									typeof options.api === "boolean" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									api = options.api; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								else if (typeof options === "boolean") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									api = options; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								if ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									typeof options === "object" && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									typeof options.method === "function" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									method = async (...args) => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										options.method.apply(model, args); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								else if (typeof options === "function") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									method = async (...args) => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										options.apply(model, args); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								if (typeof method !== "function") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									throw new Error( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+										`Job "${name}" has no function method defined` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								this._jobConfig[`${modelName}.${name}`] = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									api, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									method 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	private async _findById( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		context: JobContext, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		payload: { model: keyof Models; _id: Types.ObjectId } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		payload: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			modelName: keyof Models; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			model: AnyModel; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			_id: Types.ObjectId; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		// await context.assertPermission( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		// 	`data.${payload.model}.findById.${payload._id}` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		// ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		const { modelName, model, _id } = payload ?? {}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		const model = await context.getModel(payload.model); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		await context.assertPermission(`data.${modelName}.findById.${_id}`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		const query = model.findById(payload._id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		const query = model.findById(_id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		return query.exec(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	private async _create( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		context: JobContext, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		payload: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			modelName: keyof Models; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			model: AnyModel; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			query: Record<string, any[]>; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		const { modelName, model, query } = payload ?? {}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		await context.assertPermission(`data.${modelName}.create`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (typeof query !== "object") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			throw new Error("Query is not an object"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (Object.keys(query).length === 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			throw new Error("Empty query object provided"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (model.schema.path("createdBy")) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			query.createdBy = (await context.getUser())._id; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return model.create(query); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	private async _updateById( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		context: JobContext, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		payload: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			modelName: keyof Models; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			model: AnyModel; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			_id: Types.ObjectId; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			query: Record<string, any[]>; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		const { modelName, model, _id, query } = payload ?? {}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		await context.assertPermission(`data.${modelName}.updateById.${_id}`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (!isObjectIdOrHexString(_id)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			throw new Error("_id is not an ObjectId"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (typeof query !== "object") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			throw new Error("Query is not an object"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (Object.keys(query).length === 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			throw new Error("Empty query object provided"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return model.updateOne({ _id }, { $set: query }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	private async _deleteById( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		context: JobContext, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		payload: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			modelName: keyof Models; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			model: AnyModel; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			_id: Types.ObjectId; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		const { modelName, model, _id } = payload ?? {}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		await context.assertPermission(`data.${modelName}.deleteById.${_id}`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (!isObjectIdOrHexString(_id)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			throw new Error("_id is not an ObjectId"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return model.deleteOne({ _id }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 export type DataModuleJobs = { 
			 |