Sfoglia il codice sorgente

refactor: DataModule support for in find

Kristian Vos 2 anni fa
parent
commit
5e83017cbe

+ 1 - 0
backend/src/LogBook.ts

@@ -1,3 +1,4 @@
+// @ts-nocheck
 import config from "config";
 
 export type Log = {

+ 18 - 0
backend/src/main.ts

@@ -147,6 +147,24 @@ setTimeout(async () => {
 	// 	})
 	// 	.then(console.log)
 	// 	.catch(console.error);
+
+	// logBook.log("Find for testing with $in");
+	// await moduleManager
+	// 	.runJob("data", "find", {
+	// 		collection: "abc",
+	// 		filter: {
+	// 			name: {
+	// 				$in: ["Test123", "Test321"]
+	// 			}
+	// 		},
+	// 		// projection: {
+	// 		// 	// songs: true,
+	// 		// 	// someNumbers: false
+	// 		// },
+	// 		limit: 1
+	// 	})
+	// 	.then(console.log)
+	// 	.catch(console.error);
 }, 0);
 
 const rl = readline.createInterface({

+ 46 - 21
backend/src/modules/DataModule.spec.ts

@@ -32,28 +32,28 @@ describe("Data Module", function () {
 
 	beforeEach(async function () {
 		testData.abc = await async.map(Array(10), async () => {
-			const result =
-				await dataModule.collections?.abc.collection.insertOne({
-					_id: new ObjectId(),
-					name: `Test${Math.round(Math.random() * 1000)}`,
-					autofill: {
-						enabled: !!Math.round(Math.random())
-					},
-					someNumbers: Array.from({
-						length: Math.max(1, Math.round(Math.random() * 50))
-					}).map(() => Math.round(Math.random() * 10000)),
-					songs: Array.from({
-						length: Math.max(1, Math.round(Math.random() * 10))
-					}).map(() => ({
-						_id: new ObjectId()
-					})),
-					createdAt: Date.now(),
-					updatedAt: Date.now(),
-					testData: true
-				});
-			return dataModule.collections?.abc.collection.findOne({
-				_id: result?.insertedId
+			const doc = {
+				name: `Test${Math.round(Math.random() * 1000)}`,
+				autofill: {
+					enabled: !!Math.round(Math.random())
+				},
+				someNumbers: Array.from({
+					length: Math.max(1, Math.round(Math.random() * 50))
+				}).map(() => Math.round(Math.random() * 10000)),
+				songs: Array.from({
+					length: Math.max(1, Math.round(Math.random() * 10))
+				}).map(() => ({
+					_id: new ObjectId()
+				})),
+				createdAt: new Date(),
+				updatedAt: new Date(),
+				testData: true
+			};
+			const res = await dataModule.collections?.abc.collection.insertOne({
+				...doc,
+				testData: true
 			});
+			return { _id: res.insertedId, ...doc };
 		});
 	});
 
@@ -200,6 +200,31 @@ describe("Data Module", function () {
 				`Key "randomProperty" does not exist in the schema.`
 			);
 		});
+
+		it(`filter with simple $in`, async function () {
+			const [document] = testData.abc;
+
+			const resultDocument = await dataModule.find(jobContext, {
+				collection: "abc",
+				filter: { name: { $in: [document.name, "RandomName"] } },
+				limit: 1,
+				useCache: false
+			});
+
+			resultDocument.should.be.an("object");
+			resultDocument._id.should.deep.equal(document._id);
+		});
+
+		it(`filter with simple $in 2`, async function () {
+			const jobPromise = dataModule.find(jobContext, {
+				collection: "abc",
+				filter: { name: { $in: ["RandomName", "RandomName2"] } },
+				limit: 1,
+				useCache: false
+			});
+
+			await jobPromise.should.eventually.be.null;
+		});
 	});
 
 	describe("normalize projection", function () {

+ 50 - 58
backend/src/modules/DataModule.ts

@@ -726,65 +726,57 @@ export default class DataModule extends BaseModule {
 							itemType
 						);
 					}
+				} else if (
+					operators &&
+					typeof value === "object" &&
+					value &&
+					Object.keys(value).length === 1 &&
+					Object.keys(value)[0] &&
+					Object.keys(value)[0][0] === "$"
+				) {
+					// This entire if statement is for handling value operators like $in
+					const operator = Object.keys(value)[0];
+
+					// Operator isn't found, so throw an error
+					if (allowedValueOperators.indexOf(operator) === -1)
+						throw new Error(
+							`Invalid filter provided. Operator "${key}" is not allowed.`
+						);
+
+					// Handle the $in value operator
+					if (operator === "$in") {
+						// TODO handle nested paths for key here
+						mongoFilter[key] = {
+							$in: []
+						};
+
+						// Loop through all $in array items, check if they're not null/undefined, cast them, and return a new array
+						if (value.$in.length > 0)
+							mongoFilter[key].$in = await async.map(
+								value.$in,
+								async (_value: any) => {
+									const isNullOrUndefined =
+										_value === null || _value === undefined;
+									if (isNullOrUndefined)
+										throw new Error(
+											`Value for key ${key} using $in is undefuned/null, which is not allowed.`
+										);
+
+									const schemaType = schema[key].type;
+
+									const castedValue = this.getCastedValue(
+										_value,
+										schemaType
+									);
+
+									return castedValue;
+								}
+							);
+					} else
+						throw new Error(
+							`Unhandled operator "${operator}", this should never happen!`
+						);
 				}
-				// else if (
-				// 	operators &&
-				// 	typeof value === "object" &&
-				// 	value &&
-				// 	Object.keys(value).length === 1 &&
-				// 	Object.keys(value)[0] &&
-				// 	Object.keys(value)[0][0] === "$"
-				// ) {
-				// 	// This entire if statement is for handling value operators
-
-				// 	const operator = Object.keys(value)[0];
-
-				// 	// Operator isn't found, so throw an error
-				// 	if (allowedValueOperators.indexOf(operator) === -1)
-				// 		throw new Error(
-				// 			`Invalid filter provided. Operator "${key}" is not allowed.`
-				// 		);
-
-				// 	// Handle the $in value operator
-				// 	if (operator === "$in") {
-				// 		mongoFilter[key] = {
-				// 			$in: []
-				// 		};
-
-				// 		if (value.$in.length > 0)
-				// 			mongoFilter[key].$in = await async.map(
-				// 				value.$in,
-				// 				async (_value: any) => {
-				// 					// if (
-				// 					// 	typeof schema[key].type === "function"
-				// 					// ) {
-				// 					// 	//
-				// 					// 	// const Type = schema[key].type;
-				// 					// 	// const castValue = new Type(_value);
-				// 					// 	// if (schema[key].validate)
-				// 					// 	// 	await schema[key]
-				// 					// 	// 		.validate(castValue)
-				// 					// 	// 		.catch(err => {
-				// 					// 	// 			throw new Error(
-				// 					// 	// 				`Invalid value for ${key}, ${err}`
-				// 					// 	// 			);
-				// 					// 	// 		});
-				// 					// 	return _value;
-				// 					// }
-				// 					// throw new Error(
-				// 					// 	`Invalid schema type for ${key}`
-				// 					// );
-				// 					console.log(_value);
-
-				// 					return _value;
-				// 				}
-				// 			);
-				// 	}
-				// else
-				// 	throw new Error(
-				// 		`Unhandled operator "${operator}", this should never happen!`
-				// 	);
-				// }
 				// Handle normal types
 				else {
 					const isNullOrUndefined =