Files
genieacs/test/db.ts
T
Zaid Humaimidi c3954c277f Refactor db and local-cache code
Separated cwmp and ui code into distinct files to enhance clarity and
maintainability with varied internal data representations.
2023-09-29 14:55:44 -07:00

170 lines
5.2 KiB
TypeScript

import ava from "ava";
import { EJSON } from "bson";
import { Filter } from "mongodb";
import { stringify, parse } from "../lib/common/expression/parser";
import { convertOldPrecondition } from "../lib/db/util";
import { toMongoQuery } from "../lib/db/synth";
ava("convertOldPrecondition", (t) => {
const tests = [
[{}, "true"],
[{ test: "test" }, 'test = "test"'],
[{ test: { $eq: "test" } }, 'test = "test"'],
[{ test: { $ne: "test" } }, 'test <> "test" OR test IS NULL'],
[{ test: { $gte: "test" } }, 'test >= "test"'],
[{ "Tags.test": true }, "Tags.test IS NOT NULL"],
[{ "Tags.test": false }, "Tags.test IS NULL"],
[{ "Tags.test": { $exists: true } }, "Tags.test IS NOT NULL"],
[{ "Tags.test": { $exists: false } }, "Tags.test IS NULL"],
[{ "Tags.test": { $ne: true } }, "Tags.test IS NULL"],
[{ "Tags.test": { $ne: false } }, "Tags.test IS NOT NULL"],
[{ "Tags.test": { $eq: true } }, "Tags.test IS NOT NULL"],
[{ "Tags.test": { $eq: false } }, "Tags.test IS NULL"],
[{ _tags: "test" }, "Tags.test IS NOT NULL"],
[{ _tags: { $ne: "test" } }, "Tags.test IS NULL"],
[{ _tags: { $eq: "test" } }, "Tags.test IS NOT NULL"],
[
{ $and: [{ test: "test" }, { test: { $ne: "test" } }] },
'test = "test" AND (test <> "test" OR test IS NULL)',
],
[{ test: "test", test2: "test2" }, 'test = "test" AND test2 = "test2"'],
[
{ $or: [{ test: "test" }, { test: { $ne: "test" } }] },
'test = "test" OR (test <> "test" OR test IS NULL)',
],
[
{ test: { $gte: "test1", $ne: "test2" } },
'test >= "test1" AND (test <> "test2" OR test IS NULL)',
],
[
{ test: "test", test2: { $ne: "test2" } },
'test = "test" AND (test2 <> "test2" OR test2 IS NULL)',
],
];
const shouldFailTests = [
[{ test: { $gee: "test" } }, "Operator $gee not supported"],
[{ test: [] }, "Invalid type"],
[{ "Tags.test": { $gt: true } }, "Invalid tag query"],
[{ _tags: [] }, "Invalid type"],
[{ _tags: { $gt: "test" } }, "Invalid tag query"],
[{ $nor: [] }, "Operator $nor not supported"],
];
t.plan(tests.length + 2 * shouldFailTests.length);
for (const test of tests) {
t.is(
stringify(convertOldPrecondition(test[0] as Record<string, unknown>)),
test[1]
);
}
for (const test of shouldFailTests) {
const func = (): void => {
convertOldPrecondition(test[0] as Record<string, unknown>);
};
const error = t.throws(func, { instanceOf: Error });
t.is(error.message, test[1]);
}
});
ava("toMongoQuery", async (t) => {
const queries: [string, Filter<unknown> | false][] = [
["true", {}],
["Tags.tag1 = true", { _tags: { $eq: "tag1" } }],
["Tags.tag1 <> false", { _tags: { $eq: "tag1" } }],
["Tags.tag1 IS NULL", { _tags: { $ne: "tag1" } }],
["Tags.tag1 = 123", false],
["Param1 = 'value1'", { "Param1._value": { $eq: "value1" } }],
[
"Param1 <> 'value1'",
{
"Param1._value": { $ne: "value1" },
$and: [{ "Param1._value": { $ne: null } }],
},
],
[
"Param1 <> 1657844103524",
{
"Param1._value": { $ne: 1657844103524 },
$and: [
{
"Param1._value": { $ne: { $date: "2022-07-15T00:15:03.524Z" } },
},
{ "Param1._value": { $ne: null } },
],
},
],
[
"Param1 = 1657844103524",
{
$or: [
{ "Param1._value": { $eq: { $date: "2022-07-15T00:15:03.524Z" } } },
{ "Param1._value": { $eq: 1657844103524 } },
],
},
],
["Param1 > 'value'", { "Param1._value": { $gt: "value" } }],
["Param1 IS NOT NULL", { "Param1._value": { $ne: null } }],
[
"Param1 LIKE 'value'",
{
"Param1._value": {
$regularExpression: { options: "s", pattern: "^value$" },
},
},
],
[
"LOWER(Param1) LIKE 'value'",
{
"Param1._value": {
$regularExpression: { options: "is", pattern: "^value$" },
},
},
],
[
"Param1 <> 'value2' OR NOT (Param2 = 'value1' OR Param1 < 'value2')",
{
$or: [
{
"Param2._value": { $ne: null },
$and: [{ "Param2._value": { $ne: "value1" } }],
"Param1._value": { $eq: "value2" },
},
{
"Param1._value": { $ne: "value2" },
$and: [{ "Param1._value": { $ne: null } }],
},
],
},
],
[
"Param1 <> 'value2' OR Param1 IS NULL",
{ "Param1._value": { $ne: "value2" } },
],
];
for (const [expStr, expect] of queries) {
const exp = parse(expStr);
let query = toMongoQuery(exp, "devices");
if (query) query = EJSON.serialize(query);
t.deepEqual(query, expect);
}
const failQueries: [any, string][] = [
["Param1 = Param2", "Right-hand operand must be a literal value"],
["Param1 LIKE Param2", "Right-hand operand of 'LIKE' must be a string"],
["NOW() = 1", "Left-hand operand must be a parameter"],
["param{param2} = 1", "Left-hand operand must be a parameter"],
];
for (const [expStr, err] of failQueries) {
const exp = parse(expStr);
t.throws(() => toMongoQuery(exp, "devices"), {
message: err,
});
}
});