@wxn0brp/vql 0.6.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/apiAbstract.d.ts +15 -0
- package/dist/apiAbstract.js +36 -2
- package/dist/cpu/relation.js +3 -2
- package/dist/cpu/string/index.js +44 -3
- package/dist/cpu/utils.d.ts +1 -0
- package/dist/cpu/utils.js +17 -0
- package/dist/processor.d.ts +13 -1
- package/dist/processor.js +31 -13
- package/dist/types/vql.d.ts +1 -1
- package/dist/valid.js +2 -2
- package/dist/vql.d.ts +1 -1
- package/package.json +6 -6
package/dist/apiAbstract.d.ts
CHANGED
|
@@ -43,4 +43,19 @@ export interface ValtheraResolver {
|
|
|
43
43
|
removeCollection?: ResolverFn<[collection: string], boolean>;
|
|
44
44
|
}
|
|
45
45
|
export declare function createValtheraAdapter(resolver: ValtheraResolver, extendedFind?: boolean): ValtheraCompatible;
|
|
46
|
+
export type Operation = "add" | "find" | "findOne" | "update" | "updateOne" | "updateOneOrAdd" | "remove" | "removeOne" | "removeCollection";
|
|
47
|
+
export declare class AdapterBuilder {
|
|
48
|
+
private handlers;
|
|
49
|
+
private collections;
|
|
50
|
+
register(op: "add", collection: string, fn: ResolverFn<[collection: string, data: any, id_gen?: boolean], any>): any;
|
|
51
|
+
register(op: "find", collection: string, fn: ResolverFn<[collection: string, search: any, context?: any, options?: any, findOpts?: any], any[]>): any;
|
|
52
|
+
register(op: "findOne", collection: string, fn: ResolverFn<[collection: string, search: any, context?: any, findOpts?: any], any | null>): any;
|
|
53
|
+
register(op: "update", collection: string, fn: ResolverFn<[collection: string, search: any, updater: any], boolean>): any;
|
|
54
|
+
register(op: "updateOne", collection: string, fn: ResolverFn<[collection: string, search: any, updater: any], boolean>): any;
|
|
55
|
+
register(op: "updateOneOrAdd", collection: string, fn: ResolverFn<[collection: string, search: any, updater: any, add_arg?: any, context?: any, id_gen?: boolean], boolean>): any;
|
|
56
|
+
register(op: "remove", collection: string, fn: ResolverFn<[collection: string, search: any], boolean>): any;
|
|
57
|
+
register(op: "removeOne", collection: string, fn: ResolverFn<[collection: string, search: any], boolean>): any;
|
|
58
|
+
register(op: "removeCollection", collection: string, fn: ResolverFn<[collection: string], boolean>): any;
|
|
59
|
+
getAdapter(extendedFind?: boolean): ValtheraCompatible;
|
|
60
|
+
}
|
|
46
61
|
export {};
|
package/dist/apiAbstract.js
CHANGED
|
@@ -22,8 +22,6 @@ export function createValtheraAdapter(resolver, extendedFind = false) {
|
|
|
22
22
|
remove: (col, search) => safe(resolver.remove)(col, search),
|
|
23
23
|
removeOne: (col, search) => safe(resolver.removeOne)(col, search),
|
|
24
24
|
removeCollection: (col) => safe(resolver.removeCollection)(col),
|
|
25
|
-
findStream: null,
|
|
26
|
-
transaction: null,
|
|
27
25
|
};
|
|
28
26
|
adapter.c = (collection) => new CollectionManager(adapter, collection);
|
|
29
27
|
if (extendedFind) {
|
|
@@ -45,3 +43,39 @@ export function createValtheraAdapter(resolver, extendedFind = false) {
|
|
|
45
43
|
}
|
|
46
44
|
return adapter;
|
|
47
45
|
}
|
|
46
|
+
export class AdapterBuilder {
|
|
47
|
+
handlers = new Map();
|
|
48
|
+
collections = new Set();
|
|
49
|
+
register(op, collection, fn) {
|
|
50
|
+
this.handlers.set(`${op}:${collection}`, fn);
|
|
51
|
+
this.collections.add(collection);
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
getAdapter(extendedFind = true) {
|
|
55
|
+
const resolve = async (op, col, ...args) => {
|
|
56
|
+
const handler = this.handlers.get(`${op}:${col}`) || this.handlers.get(`${op}:*`) || null;
|
|
57
|
+
if (!handler)
|
|
58
|
+
throw new Error(`Unimplemented method: ${op}:${col}`);
|
|
59
|
+
return handler(...args);
|
|
60
|
+
};
|
|
61
|
+
const adapter = createValtheraAdapter({
|
|
62
|
+
getCollections: async () => Array.from(this.collections),
|
|
63
|
+
issetCollection: async (col) => this.collections.has(col),
|
|
64
|
+
ensureCollection: async (col) => {
|
|
65
|
+
if (!this.collections.has(col))
|
|
66
|
+
this.collections.add(col);
|
|
67
|
+
return true;
|
|
68
|
+
},
|
|
69
|
+
add: (col, data, id_gen) => resolve("add", col, data, id_gen),
|
|
70
|
+
find: (col, search, context, options, findOpts) => resolve("find", col, search, context, options, findOpts),
|
|
71
|
+
findOne: (col, search, context, findOpts) => resolve("findOne", col, search, context, findOpts),
|
|
72
|
+
update: (col, search, up) => resolve("update", col, search, up),
|
|
73
|
+
updateOne: (col, search, up) => resolve("updateOne", col, search, up),
|
|
74
|
+
updateOneOrAdd: (col, search, up, add_data, ctx, id_gen) => resolve("updateOneOrAdd", col, search, up, add_data, ctx, id_gen),
|
|
75
|
+
remove: (col, search) => resolve("remove", col, search),
|
|
76
|
+
removeOne: (col, search) => resolve("removeOne", col, search),
|
|
77
|
+
removeCollection: (col) => resolve("removeCollection", col),
|
|
78
|
+
}, extendedFind);
|
|
79
|
+
return adapter;
|
|
80
|
+
}
|
|
81
|
+
}
|
package/dist/cpu/relation.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { checkRelationPermission } from "../permissions/index.js";
|
|
2
|
-
import { parseSelect } from "./utils.js";
|
|
2
|
+
import { parseObjectSelect, parseSelect } from "./utils.js";
|
|
3
3
|
function standardizeRelationRequest(config, req) {
|
|
4
|
-
|
|
4
|
+
const select = parseObjectSelect(req.select) || [];
|
|
5
|
+
req.select = parseSelect(config, select);
|
|
5
6
|
}
|
|
6
7
|
function checkDBsExist(cpu, req) {
|
|
7
8
|
const db = req.path[0];
|
package/dist/cpu/string/index.js
CHANGED
|
@@ -14,6 +14,7 @@ function parseArgs(input) {
|
|
|
14
14
|
let current = "";
|
|
15
15
|
let inQuotes = false;
|
|
16
16
|
let escape = false;
|
|
17
|
+
let objTree = 0;
|
|
17
18
|
for (let i = 0; i < input.length; i++) {
|
|
18
19
|
const char = input[i];
|
|
19
20
|
if (escape) {
|
|
@@ -23,11 +24,51 @@ function parseArgs(input) {
|
|
|
23
24
|
else if (char === "\\") {
|
|
24
25
|
escape = true;
|
|
25
26
|
}
|
|
26
|
-
else if (char === "
|
|
27
|
-
|
|
27
|
+
else if (!inQuotes && (char === "{" || char === "[")) {
|
|
28
|
+
objTree++;
|
|
29
|
+
current += char;
|
|
28
30
|
}
|
|
29
|
-
else if (!inQuotes && (char === "
|
|
31
|
+
else if (!inQuotes && (char === "}" || char === "]")) {
|
|
32
|
+
objTree--;
|
|
33
|
+
current += char;
|
|
34
|
+
if (objTree === 0) {
|
|
35
|
+
tokens.push(current);
|
|
36
|
+
current = "";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else if (!objTree && (char === "'" || char === '"' || char === "`")) {
|
|
40
|
+
if (inQuotes === char) {
|
|
41
|
+
inQuotes = false;
|
|
42
|
+
tokens.push(`"` + current + `"`);
|
|
43
|
+
current = "";
|
|
44
|
+
}
|
|
45
|
+
else if (typeof inQuotes === "boolean") {
|
|
46
|
+
inQuotes = char;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
current += char;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else if (!inQuotes && (char === " " || char === "=" || char === "<" || char === ">")) {
|
|
30
53
|
if (current !== "") {
|
|
54
|
+
if (char === "<" || char === ">") {
|
|
55
|
+
let type = char === ">" ? "gt" : "lt";
|
|
56
|
+
if (i < input.length - 1 && input[i + 1] === "=") {
|
|
57
|
+
type += "e";
|
|
58
|
+
i++;
|
|
59
|
+
}
|
|
60
|
+
const split = current.split(".");
|
|
61
|
+
if (split.length > 1) {
|
|
62
|
+
const original = split.shift();
|
|
63
|
+
const operation = "$" + type;
|
|
64
|
+
split.unshift(operation);
|
|
65
|
+
split.unshift(original);
|
|
66
|
+
current = split.join(".");
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
current = "$" + type + "." + current;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
31
72
|
tokens.push(current);
|
|
32
73
|
current = "";
|
|
33
74
|
}
|
package/dist/cpu/utils.d.ts
CHANGED
package/dist/cpu/utils.js
CHANGED
|
@@ -11,3 +11,20 @@ export function parseSelect(config, select) {
|
|
|
11
11
|
return keys.filter(k => !!select[k]);
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
|
+
export function parseObjectSelect(obj) {
|
|
15
|
+
if (Array.isArray(obj))
|
|
16
|
+
return obj;
|
|
17
|
+
let result = [];
|
|
18
|
+
function walk(o, path = []) {
|
|
19
|
+
if (o !== null && typeof o === "object") {
|
|
20
|
+
for (const k of Object.keys(o)) {
|
|
21
|
+
walk(o[k], [...path, k]);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
result.push(path);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
walk(obj);
|
|
29
|
+
return result;
|
|
30
|
+
}
|
package/dist/processor.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Relation, ValtheraCompatible } from "@wxn0brp/db-core";
|
|
2
2
|
import { VQLConfig, VQLConfigInterface } from "./config.js";
|
|
3
|
-
import { VQLError, VQLUQ } from "./types/vql.js";
|
|
3
|
+
import { VQL_Query, VQLError, VQLUQ } from "./types/vql.js";
|
|
4
4
|
import { PermValidFn } from "./types/perm.js";
|
|
5
5
|
export declare class VQLProcessor {
|
|
6
6
|
dbInstances: Record<string, ValtheraCompatible>;
|
|
@@ -9,4 +9,16 @@ export declare class VQLProcessor {
|
|
|
9
9
|
config: VQLConfig;
|
|
10
10
|
constructor(dbInstances: Record<string, ValtheraCompatible>, config?: VQLConfig | Partial<VQLConfigInterface>, permValidFn?: PermValidFn);
|
|
11
11
|
execute<T = any>(queryRaw: VQLUQ<T>, user?: any): Promise<T | VQLError>;
|
|
12
|
+
_preProcessQuery(queryRaw: VQLUQ, user: any): {
|
|
13
|
+
err: VQLError;
|
|
14
|
+
query?: undefined;
|
|
15
|
+
} | {
|
|
16
|
+
query: VQL_Query;
|
|
17
|
+
err?: undefined;
|
|
18
|
+
};
|
|
19
|
+
_parseQuery(queryRaw: VQLUQ): {
|
|
20
|
+
query?: VQL_Query;
|
|
21
|
+
err?: VQLError;
|
|
22
|
+
};
|
|
23
|
+
_runQuery(query: VQL_Query, user: any): Promise<any>;
|
|
12
24
|
}
|
package/dist/processor.js
CHANGED
|
@@ -18,6 +18,31 @@ export class VQLProcessor {
|
|
|
18
18
|
this.config = config instanceof VQLConfig ? config : new VQLConfig(config);
|
|
19
19
|
}
|
|
20
20
|
async execute(queryRaw, user = { _id: "null-null-null" }) {
|
|
21
|
+
const result = this._preProcessQuery(queryRaw, user);
|
|
22
|
+
if ("err" in result)
|
|
23
|
+
return result.err;
|
|
24
|
+
return await this._runQuery(result.query, user);
|
|
25
|
+
}
|
|
26
|
+
_preProcessQuery(queryRaw, user) {
|
|
27
|
+
const { query: parsedQuery, err: parseErr } = this._parseQuery(queryRaw);
|
|
28
|
+
if (parseErr) {
|
|
29
|
+
return { err: parseErr };
|
|
30
|
+
}
|
|
31
|
+
const validateRawResult = validateRaw(parsedQuery);
|
|
32
|
+
if (validateRawResult !== true) {
|
|
33
|
+
logger.warn("Raw validation failed:", validateRawResult);
|
|
34
|
+
return { err: validateRawResult };
|
|
35
|
+
}
|
|
36
|
+
const query = replaceVars(parsedQuery, user);
|
|
37
|
+
logger.debug("Executed sheet (expanded query):", query);
|
|
38
|
+
const validateVqlResult = validateVql(query);
|
|
39
|
+
if (validateVqlResult !== true) {
|
|
40
|
+
logger.warn("VQL validation failed:", validateVqlResult);
|
|
41
|
+
return { err: validateVqlResult };
|
|
42
|
+
}
|
|
43
|
+
return { query };
|
|
44
|
+
}
|
|
45
|
+
_parseQuery(queryRaw) {
|
|
21
46
|
if (typeof queryRaw === "string" || "query" in queryRaw) {
|
|
22
47
|
logger.info("Incoming string query");
|
|
23
48
|
const q = typeof queryRaw === "string" ? queryRaw : queryRaw.query;
|
|
@@ -29,7 +54,9 @@ export class VQLProcessor {
|
|
|
29
54
|
}
|
|
30
55
|
catch (e) {
|
|
31
56
|
logger.error("Error parsing string query: ", { error: e, msg: e.message });
|
|
32
|
-
return {
|
|
57
|
+
return {
|
|
58
|
+
err: { err: true, c: 400, msg: `String query parsing error: ${e.message}` }
|
|
59
|
+
};
|
|
33
60
|
}
|
|
34
61
|
if (vars)
|
|
35
62
|
queryRaw = { ...queryRaw, var: vars };
|
|
@@ -39,18 +66,9 @@ export class VQLProcessor {
|
|
|
39
66
|
logger.info("Incoming object query");
|
|
40
67
|
logger.debug("Raw query: ", queryRaw);
|
|
41
68
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return validateRawResult;
|
|
46
|
-
}
|
|
47
|
-
const query = replaceVars(queryRaw, user);
|
|
48
|
-
logger.debug("Executed sheet (expanded query):", query);
|
|
49
|
-
const validateVqlResult = validateVql(query);
|
|
50
|
-
if (validateVqlResult !== true) {
|
|
51
|
-
logger.warn("VQL validation failed:", validateVqlResult);
|
|
52
|
-
return validateVqlResult;
|
|
53
|
-
}
|
|
69
|
+
return { query: queryRaw };
|
|
70
|
+
}
|
|
71
|
+
async _runQuery(query, user) {
|
|
54
72
|
if ("r" in query) {
|
|
55
73
|
return await executeRelation(this, query, user);
|
|
56
74
|
}
|
package/dist/types/vql.d.ts
CHANGED
|
@@ -81,7 +81,7 @@ export interface VQL_Query_Relation {
|
|
|
81
81
|
relations: RelationTypes.Relation;
|
|
82
82
|
many?: boolean;
|
|
83
83
|
options?: DbFindOpts;
|
|
84
|
-
select?: RelationTypes.FieldPath[]
|
|
84
|
+
select?: RelationTypes.FieldPath[] | Record<string, any>;
|
|
85
85
|
};
|
|
86
86
|
}
|
|
87
87
|
export interface VQL_Var {
|
package/dist/valid.js
CHANGED
|
@@ -54,8 +54,8 @@ function validR(query) {
|
|
|
54
54
|
return emptyErr("Relation query 'r.many' must be a boolean.");
|
|
55
55
|
if ("options" in r && !isObj(r.options, false))
|
|
56
56
|
return emptyErr("Relation query 'r.options' must be an object.");
|
|
57
|
-
if ("select" in r &&
|
|
58
|
-
return emptyErr("Relation query 'r.select' must be an array.");
|
|
57
|
+
if ("select" in r && typeof r.select !== "object")
|
|
58
|
+
return emptyErr("Relation query 'r.select' must be an object or an array.");
|
|
59
59
|
return true;
|
|
60
60
|
}
|
|
61
61
|
function validD(query) {
|
package/dist/vql.d.ts
CHANGED
|
@@ -268,7 +268,7 @@ export interface VQL_Query_Relation {
|
|
|
268
268
|
relations: RelationTypes.Relation;
|
|
269
269
|
many?: boolean;
|
|
270
270
|
options?: DbFindOpts;
|
|
271
|
-
select?: RelationTypes.FieldPath[]
|
|
271
|
+
select?: RelationTypes.FieldPath[] | Record<string, any>;
|
|
272
272
|
};
|
|
273
273
|
}
|
|
274
274
|
export interface VQL_Var {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wxn0brp/vql",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"author": "wxn0brP",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,16 +31,16 @@
|
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@types/node": "^24.
|
|
34
|
+
"@types/node": "^24.3.0",
|
|
35
35
|
"@wxn0brp/db": "^0.30.0",
|
|
36
|
-
"@wxn0brp/falcon-frame": "0.0.
|
|
36
|
+
"@wxn0brp/falcon-frame": "0.0.21",
|
|
37
37
|
"@wxn0brp/gate-warden": "^0.4.0",
|
|
38
|
-
"esbuild": "^0.25.
|
|
38
|
+
"esbuild": "^0.25.9",
|
|
39
39
|
"tsc-alias": "^1.8.10",
|
|
40
|
-
"typescript": "^5.
|
|
40
|
+
"typescript": "^5.9.2"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@wxn0brp/lucerna-log": "^0.
|
|
43
|
+
"@wxn0brp/lucerna-log": "^0.2.0"
|
|
44
44
|
},
|
|
45
45
|
"exports": {
|
|
46
46
|
".": {
|