diff --git a/domain.d.ts b/domain.d.ts index d7f6d68..a80d309 100644 --- a/domain.d.ts +++ b/domain.d.ts @@ -47,6 +47,7 @@ type FilterWithSet = { type: ExpressionType["Filter"], set: string, filter: Filter, + field: string, }; type Expression = @@ -65,9 +66,9 @@ type StringNode = BaseNode & { value: string; }; -type MapString = BaseNode & { +type MapNode = BaseNode & { valueType: NodeValueType["Map"]; - value: { [key: string]: Node["uuid"]; }; + value: { [key: string]: BaseNode["uuid"]; }; }; type ExpressionNode = BaseNode & { diff --git a/package-lock.json b/package-lock.json index f5a462c..61da84b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,12 @@ "name": "refdb", "version": "1.0.0", "license": "ISC", + "dependencies": { + "dot-prop": "^8.0.2" + }, "devDependencies": { "@types/node": "^20.10.6", - "typescript": "4.9.3" + "typescript": "5.3.3" } }, "node_modules/@types/node": { @@ -22,17 +25,42 @@ "undici-types": "~5.26.4" } }, + "node_modules/dot-prop": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-8.0.2.tgz", + "integrity": "sha512-xaBe6ZT4DHPkg0k4Ytbvn5xoxgpG0jOS1dYxSOwAHPuNLjP3/OzN0gH55SrLqpx8cBfSaVt91lXYkApjb+nYdQ==", + "dependencies": { + "type-fest": "^3.8.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/typescript": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", - "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/undici-types": { @@ -52,10 +80,23 @@ "undici-types": "~5.26.4" } }, + "dot-prop": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-8.0.2.tgz", + "integrity": "sha512-xaBe6ZT4DHPkg0k4Ytbvn5xoxgpG0jOS1dYxSOwAHPuNLjP3/OzN0gH55SrLqpx8cBfSaVt91lXYkApjb+nYdQ==", + "requires": { + "type-fest": "^3.8.0" + } + }, + "type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==" + }, "typescript": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", - "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true }, "undici-types": { diff --git a/package.json b/package.json index 0ed77c6..055ce05 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,9 @@ "license": "ISC", "devDependencies": { "@types/node": "^20.10.6", - "typescript": "4.9.3" + "typescript": "5.3.3" + }, + "dependencies": { + "dot-prop": "^8.0.2" } -} +} \ No newline at end of file diff --git a/src/DataBase.ts b/src/DataBase.ts index 8000fab..494f85b 100644 --- a/src/DataBase.ts +++ b/src/DataBase.ts @@ -1,4 +1,6 @@ +import { getProperty } from 'dot-prop'; import * as crypto from 'node:crypto'; +import { filter } from './filter/filter'; const NOT_DEFINED_SET = "NOT_DEFINED"; @@ -73,9 +75,12 @@ export class DataBase { if (cache != null) { return cache; } + const result = this.calculateExpression(node); + this.expressionCacheMap.set(node.uuid, result); + return result; } - private calculateExpression(node: ExpressionNode) { + private calculateExpression(node: ExpressionNode): ExpressionResult { switch (node.value.type) { case "count": { if (node.value.hasOwnProperty("set")) { @@ -92,9 +97,33 @@ export class DataBase { break; } case "filter": { - + switch (typeof node.value.filter.value) { + case "number": { + if (node.value.hasOwnProperty("set")) { + const { set, field, filter: filterObj } = node.value as FilterWithSet; + const setValues = this.getSet(set); + return setValues.filter((it) => { + const candidate = getProperty(it, field) as PrimitiveValue; + return filter( + filterObj.predicate, + candidate, + filterObj.value + ); + }) as ExpressionResult; + } + if (node.value.hasOwnProperty("expression")) { + const exprNode: ExpressionNode = this.nodeMap.get((node.value as FilterWithExpression).expression); + const expressionValue = this.getExpression(exprNode.id); + if (expressionValue instanceof Array) { + return expressionValue.length; + } + } + } + } + break; } } + return null as ExpressionResult; } } diff --git a/src/filter/filter.ts b/src/filter/filter.ts new file mode 100644 index 0000000..f31fd0d --- /dev/null +++ b/src/filter/filter.ts @@ -0,0 +1,28 @@ + + +export function filter( + filterType: Filter["predicate"], + candidate: Filter["value"], + expect: Filter["value"], +): boolean { + switch (filterType) { + case "equal": { + return candidate === expect; + } + case "greatThat": { + return candidate > expect; + } + case "greatThatEqual": { + return candidate >= expect; + } + case "lessThat": { + return candidate < expect; + } + case "lessThatEqual": { + return candidate <= expect; + } + case "include": { + return (candidate as string).toUpperCase().includes((expect as string).toUpperCase()); + } + } +} \ No newline at end of file diff --git a/src/graph/WeightedGraph.ts b/src/graph/WeightedGraph.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/index.ts b/src/index.ts index 84d75b9..c0b3c8f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -32,14 +32,17 @@ for (const user of users) { const ageExp = db.addNode({ set: "users_exp", valueType: "expression", + id: "userExp_gt_13", value: { type: "filter", set: "user", + field: "age", filter: { predicate: "greatThat", value: 13 } } -}); +} as ExpressionNode); -console.log(db.getSet("user")); \ No newline at end of file +console.log(db.getSet("user")); +console.log(db.getExpression("userExp_gt_13")); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index d1115d3..b03beaf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,22 +1,24 @@ { "compilerOptions": { - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "ES2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ "lib": [ - "es6" + "es6", + "es7", ], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - "module": "commonjs", /* Specify what module code is generated. */ + "module": "ES6", /* Specify what module code is generated. */ "rootDir": "./src", /* Specify the root folder within your source files. */ "resolveJsonModule": true, /* Enable importing .json files. */ "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ "outDir": "./dist", /* Specify an output folder for all emitted files. */ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ - "strict": false, /* Enable all strict type-checking options. */ + "strict": true, /* Enable all strict type-checking options. */ "noImplicitAny": false, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ + "skipLibCheck": false, /* Skip type checking all .d.ts files. */ + "moduleResolution": "Node", }, "include": [ - "./src/**.ts", + "./src/**/*.ts", "./domain.d.ts" ], "exclude": [