| 
					
				 | 
			
			
				@@ -34,7 +34,6 @@ interface MongoFilter { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		| MongoFilter[]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-// WIP 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 interface Document { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	[property: string]: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		| AttributeValue 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -111,7 +110,6 @@ export default class DataModule extends BaseModule { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	public override async shutdown() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		await super.shutdown(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		// TODO: Ensure the following shutdown correctly 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		if (this.redisClient) await this.redisClient.quit(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		if (this.mongoClient) await this.mongoClient.close(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -279,9 +277,6 @@ export default class DataModule extends BaseModule { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		// This will be false if we let Mongo return any restricted properties 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		let canCache = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		// TODO add better comments 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		// TODO add support for nested objects in arrays 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		const unfilteredEntries = Object.entries(schema); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		await Promise.all( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			unfilteredEntries.map(async ([key, value]) => { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -497,7 +492,6 @@ export default class DataModule extends BaseModule { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			// Check if value is a number, and if not, convert the value to a number 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			const castedValue = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				typeof value === "number" ? value : Number(value); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			// TODO possibly allow this via a validate boolean option? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			// We don't allow NaN for numbers, so throw an error 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			if (Number.isNaN(castedValue)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				throw new Error( 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -512,7 +506,6 @@ export default class DataModule extends BaseModule { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				Object.prototype.toString.call(value) === "[object Date]" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					? (value as Date) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					: new Date(value.toString()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			// TODO possibly allow this via a validate boolean option? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			// We don't allow invalid dates, so throw an error 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			if (new Date(castedValue).toString() === "Invalid Date") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				throw new Error( 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -564,8 +557,6 @@ export default class DataModule extends BaseModule { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		containsRestrictedProperties: boolean; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		canCache: boolean; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	}> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		// TODO validate whether restricted property is allowed 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		if (!filter || typeof filter !== "object") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			throw new Error( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				"Invalid filter provided. Filter must be an object." 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -864,8 +855,6 @@ export default class DataModule extends BaseModule { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 						} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 						// Normal array item type 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 						else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							// TODO possibly handle if a user gives some weird value here, like an object or array or $ operator 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 							// Value must not be an array, so if it is, throw an error 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 							if (Array.isArray(value)) throw Error("an array"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -930,7 +919,6 @@ export default class DataModule extends BaseModule { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	 * @param document - The document object 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	 * @param schema - The schema object 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	 * @param projection - The projection, which can be null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	 * @returns 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	private async stripDocument( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		document: Document, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -938,9 +926,6 @@ export default class DataModule extends BaseModule { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		projection: NormalizedProjection, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		allowedRestricted: AllowedRestricted 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	): Promise<Document> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		// TODO possibly do different things with required properties? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		// TODO possibly do different things with properties with default? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		const unfilteredEntries = Object.entries(document); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		// Go through all properties in the document to decide whether to allow it or not, and possibly casts the value to its property type 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		const filteredEntries: Entries<Document> = []; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -964,7 +949,6 @@ export default class DataModule extends BaseModule { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				// Handle nested object 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				if (schema[key].type === Types.Schema) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					// TODO possibly return nothing, or an empty object here instead? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					// If value is falsy, it can't be an object, so just return null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					if (!value) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 						filteredEntries.push([key, null]); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -995,32 +979,27 @@ export default class DataModule extends BaseModule { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 						deeperAllowedRestricted 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					// If the returned stripped document/object has keys, add the current key with that document/object to the memeo 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					// If the returned stripped document/object has keys, add the current key with that document/object to the memo 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					if (Object.keys(strippedDocument).length > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 						filteredEntries.push([key, strippedDocument]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 						return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					// TODO possibly return null or an object here for the key instead? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					// The current key has no values that should be returned, so just return the memo 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					// The current key has no values that should be returned, so just return empty object 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					filteredEntries.push([key, {}]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				// Handle array type 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				if (schema[key].type === Types.Array) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					// TODO possibly return nothing, or an empty array here instead? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					// If value is falsy, return null with the key instead 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					if (!value) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 						filteredEntries.push([key, null]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 						return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					// TODO possibly return nothing, or an empty array here instead? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					// If value isn't a valid array, return null with the key instead 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					if (!Array.isArray(value)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						filteredEntries.push([key, null]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					// If value isn't a valid array, throw error 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					if (!Array.isArray(value)) throw Error("not an array"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					// The type of the array items 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					const itemType = schema[key].item!.type; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1029,12 +1008,9 @@ export default class DataModule extends BaseModule { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 						value.map(async item => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 							// Handle schema objects inside an array 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 							if (itemType === Types.Schema) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-								// TODO possibly return nothing, or an empty object here instead? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-								// If item is falsy, it can't be an object, so just return null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-								if (!item) return null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 								// Item must be an actual object, so if it's not, throw an error 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 								if ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									!item || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 									typeof item !== "object" || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 									item.constructor.name !== "Object" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 								) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1063,9 +1039,8 @@ export default class DataModule extends BaseModule { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 								if (Object.keys(strippedDocument).length > 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 									return strippedDocument; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-								// TODO possibly return object here instead? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-								// The current item has no values that should be returned, so just return null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-								return null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								// The current item has no values that should be returned, so just return empty object 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								return {}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 							} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 							// Nested arrays are not supported 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 							if (itemType === Types.Array) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1078,7 +1053,6 @@ export default class DataModule extends BaseModule { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 									item === null || item === undefined; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 								if (isNullOrUndefined) return null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-								// TODO possibly don't validate casted in getCastedValue? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 								// Cast item 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 								const castedValue = this.getCastedValue( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 									item, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1096,7 +1070,6 @@ export default class DataModule extends BaseModule { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				// Handle normal types 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				// TODO possible don't validate casted in getCastedValue? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				// Cast item 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				const castedValue = this.getCastedValue( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					value, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1110,15 +1083,6 @@ export default class DataModule extends BaseModule { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		return Object.fromEntries(filteredEntries); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	// TODO improve caching 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	// TODO add support for computed fields 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	// TODO parse query - validation 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	// TODO add proper typescript support 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	// TODO add proper jsdoc 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	// TODO add support for enum document attributes 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	// TODO add support for array document attributes 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	// TODO add support for reference document attributes 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	// TODO fix 2nd layer of schema 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	 * find - Get one or more document(s) from a single collection 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	 * 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1160,7 +1124,6 @@ export default class DataModule extends BaseModule { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		// Normalize the projection into something we understand, and which throws an error if we have any path collisions 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		const normalizedProjection = this.normalizeProjection(projection); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		// TODO validate the projection based on the schema here 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		// Parse the projection into a mongo projection, and returns whether this query can be cached or not 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		const parsedProjection = await this.parseFindProjection( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			normalizedProjection, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1211,8 +1174,6 @@ export default class DataModule extends BaseModule { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		if (documents) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			cacheable = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			// TODO, add mongo projection. Make sure to keep in mind caching with queryHash. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			const totalCount = await this.collections?.[ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				collection 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			].collection.countDocuments(mongoFilter); 
			 |