@wxn0brp/vql 0.6.0-alpha.0 → 0.6.0-beta.0
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/cpu/relation.d.ts +2 -2
- package/dist/cpu/relation.js +1 -1
- package/dist/cpu/request.d.ts +2 -2
- package/dist/cpu/request.js +1 -1
- package/dist/cpu/string/index.d.ts +2 -2
- package/dist/gw.d.ts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/permissions/relation.d.ts +3 -3
- package/dist/permissions/relation.js +7 -7
- package/dist/permissions/request.d.ts +5 -5
- package/dist/permissions/request.js +7 -7
- package/dist/permissions/utils.d.ts +2 -1
- package/dist/permissions/utils.js +15 -3
- package/dist/processor.d.ts +5 -6
- package/dist/processor.js +7 -11
- package/dist/sheet.d.ts +2 -0
- package/dist/sheet.js +34 -0
- package/dist/types/perm.d.ts +1 -1
- package/dist/types/vql.d.ts +51 -84
- package/dist/valid.d.ts +3 -3
- package/dist/valid.js +110 -25
- package/dist/vql.d.ts +51 -83
- package/package.json +1 -2
- package/dist/sheet/index.d.ts +0 -2
- package/dist/sheet/index.js +0 -70
- package/dist/sheet/load.d.ts +0 -3
- package/dist/sheet/load.js +0 -22
package/dist/cpu/relation.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { VQLProcessor } from "../processor.js";
|
|
2
|
-
import {
|
|
3
|
-
export declare function executeRelation(cpu: VQLProcessor, query:
|
|
2
|
+
import { VQL_Query_Relation } from "../types/vql.js";
|
|
3
|
+
export declare function executeRelation(cpu: VQLProcessor, query: VQL_Query_Relation, user: any): Promise<any>;
|
package/dist/cpu/relation.js
CHANGED
|
@@ -21,7 +21,7 @@ export async function executeRelation(cpu, query, user) {
|
|
|
21
21
|
const checkDb = checkDBsExist(cpu, query.r);
|
|
22
22
|
if (checkDb.err)
|
|
23
23
|
return checkDb;
|
|
24
|
-
if (!cpu.config.noCheckPermissions && !await checkRelationPermission(cpu.config, cpu.
|
|
24
|
+
if (!cpu.config.noCheckPermissions && !await checkRelationPermission(cpu.config, cpu.permValidFn, user, query)) {
|
|
25
25
|
return { err: true, msg: "Permission denied", c: 403 };
|
|
26
26
|
}
|
|
27
27
|
const req = query.r;
|
package/dist/cpu/request.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { VQLProcessor } from "../processor.js";
|
|
2
|
-
import {
|
|
3
|
-
export declare function executeQuery(cpu: VQLProcessor, query:
|
|
2
|
+
import { VQL_Query_CRUD } from "../types/vql.js";
|
|
3
|
+
export declare function executeQuery(cpu: VQLProcessor, query: VQL_Query_CRUD, user: any): Promise<any>;
|
package/dist/cpu/request.js
CHANGED
|
@@ -5,7 +5,7 @@ export async function executeQuery(cpu, query, user) {
|
|
|
5
5
|
return { err: true, msg: `Invalid query - db "${query.db || "undefined"}" not found`, c: 400 };
|
|
6
6
|
const db = cpu.dbInstances[query.db];
|
|
7
7
|
const operation = Object.keys(query.d)[0];
|
|
8
|
-
if (!cpu.config.noCheckPermissions && !await checkRequestPermission(cpu.config, cpu.
|
|
8
|
+
if (!cpu.config.noCheckPermissions && !await checkRequestPermission(cpu.config, cpu.permValidFn, user, query)) {
|
|
9
9
|
return { err: true, msg: "Permission denied", c: 403 };
|
|
10
10
|
}
|
|
11
11
|
if (operation === "find") {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare function parseVQLS(query: string):
|
|
1
|
+
import { VQL_Query } from "../../types/vql.js";
|
|
2
|
+
export declare function parseVQLS(query: string): VQL_Query;
|
package/dist/gw.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { GateWarden } from "@wxn0brp/gate-warden";
|
|
2
|
-
import {
|
|
3
|
-
export declare function createGwValidFn(gw: GateWarden):
|
|
2
|
+
import { PermValidFn } from "./types/perm.js";
|
|
3
|
+
export declare function createGwValidFn(gw: GateWarden): PermValidFn;
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,6 @@ import { createValtheraAdapter } from "./apiAbstract.js";
|
|
|
4
4
|
import logger from "./logger.js";
|
|
5
5
|
import { LogLevel } from "@wxn0brp/lucerna-log";
|
|
6
6
|
import { FF_VQL } from "./falconFrame.js";
|
|
7
|
+
import { createGwValidFn } from "./gw.js";
|
|
7
8
|
export default VQLProcessor;
|
|
8
|
-
export { createValtheraAdapter, VQLConfig, logger as VQLLogger, LogLevel as VQLLogLevel, FF_VQL };
|
|
9
|
-
export * as VQLSheet from "./sheet/load.js";
|
|
9
|
+
export { VQLProcessor, createValtheraAdapter, VQLConfig, logger as VQLLogger, LogLevel as VQLLogLevel, FF_VQL, createGwValidFn };
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,6 @@ import { createValtheraAdapter } from "./apiAbstract.js";
|
|
|
4
4
|
import logger from "./logger.js";
|
|
5
5
|
import { LogLevel } from "@wxn0brp/lucerna-log";
|
|
6
6
|
import { FF_VQL } from "./falconFrame.js";
|
|
7
|
+
import { createGwValidFn } from "./gw.js";
|
|
7
8
|
export default VQLProcessor;
|
|
8
|
-
export { createValtheraAdapter, VQLConfig, logger as VQLLogger, LogLevel as VQLLogLevel, FF_VQL };
|
|
9
|
-
export * as VQLSheet from "./sheet/load.js";
|
|
9
|
+
export { VQLProcessor, createValtheraAdapter, VQLConfig, logger as VQLLogger, LogLevel as VQLLogLevel, FF_VQL, createGwValidFn };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { PermValidFn } from "../types/perm.js";
|
|
2
|
+
import { VQL_Query_Relation } from "../types/vql.js";
|
|
3
3
|
import { VQLConfig } from "../config.js";
|
|
4
|
-
export declare function checkRelationPermission(config: VQLConfig,
|
|
4
|
+
export declare function checkRelationPermission(config: VQLConfig, permValidFn: PermValidFn, user: any, query: VQL_Query_Relation): Promise<boolean>;
|
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
import { PermCRUD } from "../types/perm.js";
|
|
2
2
|
import { extractPathsFromData, hashKey } from "./utils.js";
|
|
3
|
-
export async function checkRelationPermission(config,
|
|
3
|
+
export async function checkRelationPermission(config, permValidFn, user, query) {
|
|
4
4
|
const { path, search, relations, select } = query.r;
|
|
5
5
|
// Helper function to recursively check permissions with fallback mechanism
|
|
6
6
|
const checkPermissionRecursively = async (entityId, fallbackLevels = []) => {
|
|
7
7
|
// Check if the user has access to the current entity
|
|
8
8
|
// const result = await gw.hasAccess(user.id, entityId, PermCRUD.READ);
|
|
9
|
-
const result = await
|
|
9
|
+
const result = await permValidFn(entityId, PermCRUD.READ, user);
|
|
10
10
|
if (result.granted) {
|
|
11
11
|
return true;
|
|
12
12
|
}
|
|
13
13
|
// If the result is "entity-404", check the next fallback level
|
|
14
14
|
if (!config.strictACL && result.via === "entity-404" && fallbackLevels.length > 0) {
|
|
15
|
-
const nextFallbackEntityId = hashKey(config, fallbackLevels.slice(0, -1));
|
|
15
|
+
const nextFallbackEntityId = await hashKey(config, fallbackLevels.slice(0, -1));
|
|
16
16
|
return checkPermissionRecursively(nextFallbackEntityId, fallbackLevels.slice(0, -2));
|
|
17
17
|
}
|
|
18
18
|
// If no fallback levels are left or the result is not "entity-404", deny access
|
|
19
19
|
return false;
|
|
20
20
|
};
|
|
21
21
|
// Check permission for the relation field in the parent collection
|
|
22
|
-
if (!await checkPermissionRecursively(hashKey(config, path), path)) {
|
|
22
|
+
if (!await checkPermissionRecursively(await hashKey(config, path), path)) {
|
|
23
23
|
return false;
|
|
24
24
|
}
|
|
25
25
|
// Check permissions for search fields
|
|
26
26
|
const searchPaths = extractPathsFromData(search || {});
|
|
27
27
|
for (const searchPath of searchPaths) {
|
|
28
28
|
const key = [...path, ...searchPath.path, searchPath.key];
|
|
29
|
-
if (!await checkPermissionRecursively(hashKey(config, key), key)) {
|
|
29
|
+
if (!await checkPermissionRecursively(await hashKey(config, key), key)) {
|
|
30
30
|
return false;
|
|
31
31
|
}
|
|
32
32
|
}
|
|
@@ -34,7 +34,7 @@ export async function checkRelationPermission(config, validFn, user, query) {
|
|
|
34
34
|
if (select) {
|
|
35
35
|
for (const fieldPath of select) {
|
|
36
36
|
const key = [...path, fieldPath];
|
|
37
|
-
if (!await checkPermissionRecursively(hashKey(config, key), key)) {
|
|
37
|
+
if (!await checkPermissionRecursively(await hashKey(config, key), key)) {
|
|
38
38
|
return false;
|
|
39
39
|
}
|
|
40
40
|
}
|
|
@@ -43,7 +43,7 @@ export async function checkRelationPermission(config, validFn, user, query) {
|
|
|
43
43
|
if (relations) {
|
|
44
44
|
for (const relationKey in relations) {
|
|
45
45
|
const r = relations[relationKey];
|
|
46
|
-
if (!await checkRelationPermission(config,
|
|
46
|
+
if (!await checkRelationPermission(config, permValidFn, user, { r })) {
|
|
47
47
|
return false;
|
|
48
48
|
}
|
|
49
49
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { PermCRUD, ValidFn } from "../types/perm.js";
|
|
2
|
-
import { VQLRequest } from "../types/vql.js";
|
|
3
1
|
import { VQLConfig } from "../config.js";
|
|
4
|
-
|
|
2
|
+
import { PermCRUD, PermValidFn } from "../types/perm.js";
|
|
3
|
+
import { VQL_Query_CRUD } from "../types/vql.js";
|
|
4
|
+
export declare function extractPaths(config: VQLConfig, query: VQL_Query_CRUD): Promise<{
|
|
5
5
|
db: string;
|
|
6
6
|
c: string;
|
|
7
7
|
paths: {
|
|
@@ -10,9 +10,9 @@ export declare function extractPaths(config: VQLConfig, query: VQLRequest): {
|
|
|
10
10
|
c?: PermCRUD;
|
|
11
11
|
path?: string[];
|
|
12
12
|
}[];
|
|
13
|
-
}
|
|
13
|
+
}>;
|
|
14
14
|
export declare function processFieldPath(pathObj: {
|
|
15
15
|
path: string[];
|
|
16
16
|
key: string;
|
|
17
17
|
}): string[];
|
|
18
|
-
export declare function checkRequestPermission(config: VQLConfig,
|
|
18
|
+
export declare function checkRequestPermission(config: VQLConfig, permValidFn: PermValidFn, user: any, query: VQL_Query_CRUD): Promise<boolean>;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { PermCRUD } from "../types/perm.js";
|
|
2
2
|
import { extractPathsFromData, hashKey } from "./utils.js";
|
|
3
|
-
export function extractPaths(config, query) {
|
|
3
|
+
export async function extractPaths(config, query) {
|
|
4
4
|
const operation = Object.keys(query.d)[0];
|
|
5
5
|
const collection = query.d[operation].collection;
|
|
6
6
|
const permPaths = {
|
|
7
|
-
db: hashKey(config, query.db),
|
|
7
|
+
db: await hashKey(config, query.db),
|
|
8
8
|
c: collection,
|
|
9
9
|
paths: []
|
|
10
10
|
};
|
|
@@ -79,21 +79,21 @@ export function processFieldPath(pathObj) {
|
|
|
79
79
|
}
|
|
80
80
|
return processedPath;
|
|
81
81
|
}
|
|
82
|
-
export async function checkRequestPermission(config,
|
|
82
|
+
export async function checkRequestPermission(config, permValidFn, user, query) {
|
|
83
83
|
if (!query)
|
|
84
84
|
return false;
|
|
85
|
-
const permPaths = extractPaths(config, query);
|
|
85
|
+
const permPaths = await extractPaths(config, query);
|
|
86
86
|
// Helper function to recursively check permissions
|
|
87
87
|
const checkPermissionRecursively = async (entityId, requiredPerm, fallbackLevels = []) => {
|
|
88
88
|
// Check if the user has access to the current entity
|
|
89
89
|
// const result = await gw.hasAccess(user.id, entityId, requiredPerm);
|
|
90
|
-
const result = await
|
|
90
|
+
const result = await permValidFn(entityId, requiredPerm, user);
|
|
91
91
|
if (result.granted) {
|
|
92
92
|
return true;
|
|
93
93
|
}
|
|
94
94
|
// If the result is "entity-404", check the next fallback level
|
|
95
95
|
if (!config.strictACL && result.via === "entity-404" && fallbackLevels.length > 0) {
|
|
96
|
-
const nextFallbackEntityId = hashKey(config, fallbackLevels.slice(0, -1));
|
|
96
|
+
const nextFallbackEntityId = await hashKey(config, fallbackLevels.slice(0, -1));
|
|
97
97
|
return checkPermissionRecursively(nextFallbackEntityId, requiredPerm, fallbackLevels.slice(0, -2));
|
|
98
98
|
}
|
|
99
99
|
// If no fallback levels are left or the result is not "entity-404", deny access
|
|
@@ -107,7 +107,7 @@ export async function checkRequestPermission(config, validFn, user, query) {
|
|
|
107
107
|
let fallbackLevels = [];
|
|
108
108
|
if ("c" in path) {
|
|
109
109
|
// Collection-level permission: hash the combination of db and collection
|
|
110
|
-
entityId = hashKey(config, [query.db, permPaths.c]);
|
|
110
|
+
entityId = await hashKey(config, [query.db, permPaths.c]);
|
|
111
111
|
requiredPerm = path.c;
|
|
112
112
|
// Fallback to database level if needed
|
|
113
113
|
fallbackLevels = [query.db];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { VQLConfig } from "../config.js";
|
|
2
|
-
export declare function
|
|
2
|
+
export declare function getHash(json: string): Promise<string>;
|
|
3
|
+
export declare function hashKey(config: VQLConfig, path: any): Promise<string>;
|
|
3
4
|
export declare function extractPathsFromData(data: any, stack?: string[]): {
|
|
4
5
|
path: string[];
|
|
5
6
|
key: string;
|
|
@@ -1,8 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
export function
|
|
1
|
+
let cryptoRef = null;
|
|
2
|
+
export async function getHash(json) {
|
|
3
|
+
if (typeof window !== "undefined" && window.crypto?.subtle) {
|
|
4
|
+
const buffer = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(json));
|
|
5
|
+
return [...new Uint8Array(buffer)].map(b => b.toString(16).padStart(2, "0")).join("");
|
|
6
|
+
}
|
|
7
|
+
else {
|
|
8
|
+
if (!cryptoRef) {
|
|
9
|
+
cryptoRef = await import("crypto");
|
|
10
|
+
}
|
|
11
|
+
return cryptoRef.createHash("sha256").update(json).digest("hex");
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export async function hashKey(config, path) {
|
|
3
15
|
const json = JSON.stringify(path);
|
|
4
16
|
if (config.hidePath)
|
|
5
|
-
return
|
|
17
|
+
return await getHash(json);
|
|
6
18
|
else
|
|
7
19
|
return json;
|
|
8
20
|
}
|
package/dist/processor.d.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { Relation, ValtheraCompatible } from "@wxn0brp/db-core";
|
|
2
2
|
import { VQLConfig, VQLConfigInterface } from "./config.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { VQLError, VQLUQ } from "./types/vql.js";
|
|
4
|
+
import { PermValidFn } from "./types/perm.js";
|
|
5
5
|
export declare class VQLProcessor {
|
|
6
6
|
dbInstances: Record<string, ValtheraCompatible>;
|
|
7
|
-
|
|
7
|
+
permValidFn: PermValidFn;
|
|
8
8
|
relation: Relation;
|
|
9
|
-
preDefinedSheets: Map<string, VQL>;
|
|
10
9
|
config: VQLConfig;
|
|
11
|
-
constructor(dbInstances: Record<string, ValtheraCompatible>, config?: VQLConfig | Partial<VQLConfigInterface>,
|
|
12
|
-
execute<T = any>(queryRaw:
|
|
10
|
+
constructor(dbInstances: Record<string, ValtheraCompatible>, config?: VQLConfig | Partial<VQLConfigInterface>, permValidFn?: PermValidFn);
|
|
11
|
+
execute<T = any>(queryRaw: VQLUQ<T>, user?: any): Promise<T | VQLError>;
|
|
13
12
|
}
|
package/dist/processor.js
CHANGED
|
@@ -3,27 +3,25 @@ import { VQLConfig } from "./config.js";
|
|
|
3
3
|
import { executeRelation } from "./cpu/relation.js";
|
|
4
4
|
import { executeQuery } from "./cpu/request.js";
|
|
5
5
|
import logger from "./logger.js";
|
|
6
|
-
import {
|
|
6
|
+
import { replaceVars } from "./sheet.js";
|
|
7
7
|
import { validateRaw, validateVql } from "./valid.js";
|
|
8
8
|
import { parseVQLS } from "./cpu/string/index.js";
|
|
9
9
|
export class VQLProcessor {
|
|
10
10
|
dbInstances;
|
|
11
|
-
|
|
11
|
+
permValidFn;
|
|
12
12
|
relation;
|
|
13
|
-
preDefinedSheets = new Map();
|
|
14
13
|
config;
|
|
15
|
-
constructor(dbInstances, config = new VQLConfig(),
|
|
14
|
+
constructor(dbInstances, config = new VQLConfig(), permValidFn = async () => ({ granted: true, via: "" })) {
|
|
16
15
|
this.dbInstances = dbInstances;
|
|
17
|
-
this.
|
|
16
|
+
this.permValidFn = permValidFn;
|
|
18
17
|
this.relation = new Relation(dbInstances);
|
|
19
18
|
this.config = config instanceof VQLConfig ? config : new VQLConfig(config);
|
|
20
19
|
}
|
|
21
|
-
async execute(queryRaw, user = {}) {
|
|
20
|
+
async execute(queryRaw, user = { _id: "null-null-null" }) {
|
|
22
21
|
if (typeof queryRaw === "string" || "query" in queryRaw) {
|
|
23
22
|
logger.info("Incoming string query");
|
|
24
23
|
const q = typeof queryRaw === "string" ? queryRaw : queryRaw.query;
|
|
25
24
|
const vars = typeof queryRaw === "string" ? null : queryRaw.var;
|
|
26
|
-
const ref = typeof queryRaw === "string" ? null : queryRaw.ref;
|
|
27
25
|
logger.debug(q);
|
|
28
26
|
try {
|
|
29
27
|
queryRaw = parseVQLS(q);
|
|
@@ -31,12 +29,10 @@ export class VQLProcessor {
|
|
|
31
29
|
}
|
|
32
30
|
catch (e) {
|
|
33
31
|
logger.error("Error parsing string query: ", { error: e, msg: e.message });
|
|
34
|
-
return { err: true,
|
|
32
|
+
return { err: true, c: 400, msg: `String query parsing error: ${e.message}` };
|
|
35
33
|
}
|
|
36
34
|
if (vars)
|
|
37
35
|
queryRaw = { ...queryRaw, var: vars };
|
|
38
|
-
if (ref)
|
|
39
|
-
queryRaw = { ...queryRaw, ref };
|
|
40
36
|
logger.debug("Final string query: ", queryRaw);
|
|
41
37
|
}
|
|
42
38
|
else {
|
|
@@ -48,7 +44,7 @@ export class VQLProcessor {
|
|
|
48
44
|
logger.warn("Raw validation failed:", validateRawResult);
|
|
49
45
|
return validateRawResult;
|
|
50
46
|
}
|
|
51
|
-
const query =
|
|
47
|
+
const query = replaceVars(queryRaw, user);
|
|
52
48
|
logger.debug("Executed sheet (expanded query):", query);
|
|
53
49
|
const validateVqlResult = validateVql(query);
|
|
54
50
|
if (validateVqlResult !== true) {
|
package/dist/sheet.d.ts
ADDED
package/dist/sheet.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
function replaceVariables(obj, variables) {
|
|
2
|
+
if (typeof obj === "object" && !Array.isArray(obj) && obj !== null && "__" in obj) {
|
|
3
|
+
const varKey = obj.__;
|
|
4
|
+
return variables[varKey] ?? obj;
|
|
5
|
+
}
|
|
6
|
+
if (typeof obj === "string") {
|
|
7
|
+
if (obj.startsWith("$"))
|
|
8
|
+
return variables[obj.slice(1)] ?? obj;
|
|
9
|
+
return obj;
|
|
10
|
+
}
|
|
11
|
+
if (Array.isArray(obj))
|
|
12
|
+
return obj.map((item) => replaceVariables(item, variables));
|
|
13
|
+
if (typeof obj === "object" && obj !== null) {
|
|
14
|
+
const newObj = {};
|
|
15
|
+
for (const key in obj) {
|
|
16
|
+
newObj[key] = replaceVariables(obj[key], variables);
|
|
17
|
+
}
|
|
18
|
+
return newObj;
|
|
19
|
+
}
|
|
20
|
+
return obj;
|
|
21
|
+
}
|
|
22
|
+
export function replaceVars(query, user) {
|
|
23
|
+
query.var = {
|
|
24
|
+
_me: user?.id || user?._id || user,
|
|
25
|
+
_now: Date.now(),
|
|
26
|
+
_nowShort: Math.floor(Date.now() / 1000),
|
|
27
|
+
__now: Date.now().toString(),
|
|
28
|
+
__nowShort: Math.floor(Date.now() / 1000).toString(),
|
|
29
|
+
...(query.var || {})
|
|
30
|
+
};
|
|
31
|
+
query = replaceVariables(query, query.var);
|
|
32
|
+
delete query.var;
|
|
33
|
+
return query;
|
|
34
|
+
}
|
package/dist/types/perm.d.ts
CHANGED
package/dist/types/vql.d.ts
CHANGED
|
@@ -2,106 +2,79 @@ import { RelationTypes } from "@wxn0brp/db";
|
|
|
2
2
|
import { Search, Arg } from "@wxn0brp/db-core/types/arg";
|
|
3
3
|
import { DbFindOpts, FindOpts } from "@wxn0brp/db-core/types/options";
|
|
4
4
|
import { UpdaterArg } from "@wxn0brp/db-core/types/updater";
|
|
5
|
-
export interface
|
|
6
|
-
find: VQLFind<T>;
|
|
7
|
-
findOne: VQLFindOne<T>;
|
|
8
|
-
f: VQLFindOne<T>;
|
|
9
|
-
add: VQLAdd<T>;
|
|
10
|
-
update: VQLUpdate<T>;
|
|
11
|
-
updateOne: VQLUpdateOne<T>;
|
|
12
|
-
remove: VQLRemove<T>;
|
|
13
|
-
removeOne: VQLRemoveOne<T>;
|
|
14
|
-
updateOneOrAdd: VQLUpdateOneOrAdd<T>;
|
|
15
|
-
removeCollection: VQLCollectionOperation;
|
|
16
|
-
ensureCollection: VQLCollectionOperation;
|
|
17
|
-
issetCollection: VQLCollectionOperation;
|
|
18
|
-
getCollections: {};
|
|
19
|
-
}
|
|
20
|
-
export type VQLQueryData<T = any> = {
|
|
21
|
-
find: VQLFind<T>;
|
|
22
|
-
} | {
|
|
23
|
-
findOne: VQLFindOne<T>;
|
|
24
|
-
} | {
|
|
25
|
-
f: VQLFindOne<T>;
|
|
26
|
-
} | {
|
|
27
|
-
add: VQLAdd<T>;
|
|
28
|
-
} | {
|
|
29
|
-
update: VQLUpdate<T>;
|
|
30
|
-
} | {
|
|
31
|
-
updateOne: VQLUpdateOne<T>;
|
|
32
|
-
} | {
|
|
33
|
-
remove: VQLRemove<T>;
|
|
34
|
-
} | {
|
|
35
|
-
removeOne: VQLRemoveOne<T>;
|
|
36
|
-
} | {
|
|
37
|
-
updateOneOrAdd: VQLUpdateOneOrAdd<T>;
|
|
38
|
-
} | {
|
|
39
|
-
removeCollection: VQLCollectionOperation;
|
|
40
|
-
} | {
|
|
41
|
-
ensureCollection: VQLCollectionOperation;
|
|
42
|
-
} | {
|
|
43
|
-
issetCollection: VQLCollectionOperation;
|
|
44
|
-
} | {
|
|
45
|
-
getCollections: {};
|
|
46
|
-
};
|
|
47
|
-
export interface VQLRequest<T = any> {
|
|
48
|
-
db: string;
|
|
49
|
-
d: VQLQueryData<T>;
|
|
50
|
-
}
|
|
51
|
-
export interface VQLFind<T = any> {
|
|
5
|
+
export interface VQL_OP_Find<T = any> {
|
|
52
6
|
collection: string;
|
|
53
7
|
search?: Search<T>;
|
|
54
8
|
limit?: number;
|
|
55
|
-
fields?:
|
|
56
|
-
select?:
|
|
57
|
-
relations?: VQLRelations;
|
|
9
|
+
fields?: VQL_Fields;
|
|
10
|
+
select?: VQL_Fields;
|
|
58
11
|
options?: DbFindOpts<T>;
|
|
59
12
|
searchOpts?: FindOpts<T>;
|
|
60
13
|
}
|
|
61
|
-
export interface
|
|
14
|
+
export interface VQL_OP_FindOne<T = any> {
|
|
62
15
|
collection: string;
|
|
63
16
|
search: Search<T>;
|
|
64
|
-
fields?:
|
|
65
|
-
select?:
|
|
66
|
-
relations?: VQLRelations;
|
|
17
|
+
fields?: VQL_Fields;
|
|
18
|
+
select?: VQL_Fields;
|
|
67
19
|
searchOpts?: FindOpts<T>;
|
|
68
20
|
}
|
|
69
|
-
export interface
|
|
21
|
+
export interface VQL_OP_Add<T = any> {
|
|
70
22
|
collection: string;
|
|
71
23
|
data: Arg<T>;
|
|
72
24
|
id_gen?: boolean;
|
|
73
25
|
}
|
|
74
|
-
export interface
|
|
75
|
-
collection: string;
|
|
76
|
-
search: Search<T>;
|
|
77
|
-
updater: UpdaterArg<T>;
|
|
78
|
-
}
|
|
79
|
-
export interface VQLUpdateOne<T = any> {
|
|
26
|
+
export interface VQL_OP_Update<T = any> {
|
|
80
27
|
collection: string;
|
|
81
28
|
search: Search<T>;
|
|
82
29
|
updater: UpdaterArg<T>;
|
|
83
30
|
}
|
|
84
|
-
export interface
|
|
31
|
+
export interface VQL_OP_Remove<T = any> {
|
|
85
32
|
collection: string;
|
|
86
33
|
search: Search<T>;
|
|
87
34
|
}
|
|
88
|
-
export interface
|
|
89
|
-
collection: string;
|
|
90
|
-
search: Search<T>;
|
|
91
|
-
}
|
|
92
|
-
export interface VQLUpdateOneOrAdd<T = any> {
|
|
35
|
+
export interface VQL_OP_UpdateOneOrAdd<T = any> {
|
|
93
36
|
collection: string;
|
|
94
37
|
search: Search<T>;
|
|
95
38
|
updater: UpdaterArg<T>;
|
|
96
39
|
add_arg?: Arg<T>;
|
|
97
40
|
id_gen?: boolean;
|
|
98
41
|
}
|
|
99
|
-
export interface
|
|
42
|
+
export interface VQL_OP_CollectionOperation {
|
|
100
43
|
collection: string;
|
|
101
44
|
}
|
|
102
|
-
export type
|
|
103
|
-
export type
|
|
104
|
-
|
|
45
|
+
export type VQL_Fields = Record<string, boolean | number> | string[];
|
|
46
|
+
export type VQL_Query_CRUD_Data<T = any> = {
|
|
47
|
+
find: VQL_OP_Find<T>;
|
|
48
|
+
} | {
|
|
49
|
+
findOne: VQL_OP_FindOne<T>;
|
|
50
|
+
} | {
|
|
51
|
+
f: VQL_OP_FindOne<T>;
|
|
52
|
+
} | {
|
|
53
|
+
add: VQL_OP_Add<T>;
|
|
54
|
+
} | {
|
|
55
|
+
update: VQL_OP_Update<T>;
|
|
56
|
+
} | {
|
|
57
|
+
updateOne: VQL_OP_Update<T>;
|
|
58
|
+
} | {
|
|
59
|
+
remove: VQL_OP_Remove<T>;
|
|
60
|
+
} | {
|
|
61
|
+
removeOne: VQL_OP_Remove<T>;
|
|
62
|
+
} | {
|
|
63
|
+
updateOneOrAdd: VQL_OP_UpdateOneOrAdd<T>;
|
|
64
|
+
} | {
|
|
65
|
+
removeCollection: VQL_OP_CollectionOperation;
|
|
66
|
+
} | {
|
|
67
|
+
ensureCollection: VQL_OP_CollectionOperation;
|
|
68
|
+
} | {
|
|
69
|
+
issetCollection: VQL_OP_CollectionOperation;
|
|
70
|
+
} | {
|
|
71
|
+
getCollections: {};
|
|
72
|
+
};
|
|
73
|
+
export interface VQL_Query_CRUD<T = any> {
|
|
74
|
+
db: string;
|
|
75
|
+
d: VQL_Query_CRUD_Data<T>;
|
|
76
|
+
}
|
|
77
|
+
export interface VQL_Query_Relation {
|
|
105
78
|
r: {
|
|
106
79
|
path: RelationTypes.Path;
|
|
107
80
|
search: Search;
|
|
@@ -111,25 +84,19 @@ export interface RelationQuery {
|
|
|
111
84
|
select?: RelationTypes.FieldPath[];
|
|
112
85
|
};
|
|
113
86
|
}
|
|
114
|
-
export interface
|
|
115
|
-
ref?: string;
|
|
87
|
+
export interface VQL_Var {
|
|
116
88
|
var?: {
|
|
117
89
|
[k: string]: any;
|
|
118
90
|
};
|
|
119
91
|
}
|
|
120
|
-
|
|
121
|
-
type
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
92
|
+
/** VQL Query */
|
|
93
|
+
export type VQL_Query<T = any> = (VQL_Query_CRUD<T> | VQL_Query_Relation) & VQL_Var;
|
|
94
|
+
/** VQL Universal Query */
|
|
95
|
+
export type VQLUQ<T = any> = VQL_Query<T> | string | {
|
|
96
|
+
query: string;
|
|
97
|
+
} & VQL_Var;
|
|
126
98
|
export interface VQLError {
|
|
127
99
|
err: true;
|
|
128
100
|
msg: string;
|
|
129
101
|
c: number;
|
|
130
|
-
why?: string;
|
|
131
102
|
}
|
|
132
|
-
export type VqlQueryRaw<T = any> = VQLR<T> | string | {
|
|
133
|
-
query: string;
|
|
134
|
-
} & VQLRef;
|
|
135
|
-
export {};
|
package/dist/valid.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare function validateRaw(query:
|
|
3
|
-
export declare function validateVql(query:
|
|
1
|
+
import { VQL_Query, VQLError } from "./types/vql.js";
|
|
2
|
+
export declare function validateRaw(query: VQL_Query): true | VQLError;
|
|
3
|
+
export declare function validateVql(query: VQL_Query): true | VQLError;
|
package/dist/valid.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
function emptyErr() {
|
|
1
|
+
function emptyErr(msg = "Bad query") {
|
|
2
2
|
return {
|
|
3
3
|
err: true,
|
|
4
|
-
msg
|
|
4
|
+
msg,
|
|
5
5
|
c: 400
|
|
6
6
|
};
|
|
7
7
|
}
|
|
@@ -10,51 +10,136 @@ function isObj(obj, one = true) {
|
|
|
10
10
|
}
|
|
11
11
|
export function validateRaw(query) {
|
|
12
12
|
if (("r" in query && isObj(query.r)) ||
|
|
13
|
-
("db" in query && typeof query.db === "string" && isObj(query.d))
|
|
14
|
-
("ref" in query && isObj(query.ref)))
|
|
13
|
+
("db" in query && typeof query.db === "string" && isObj(query.d)))
|
|
15
14
|
return true;
|
|
16
|
-
return emptyErr();
|
|
15
|
+
return emptyErr("Invalid VQL query structure. Must contain 'r' or 'db' and 'd'.");
|
|
16
|
+
}
|
|
17
|
+
function validateRelations(relations) {
|
|
18
|
+
if (!isObj(relations, false))
|
|
19
|
+
return emptyErr("The 'relations' property must be an object.");
|
|
20
|
+
for (const key in relations) {
|
|
21
|
+
const relation = relations[key];
|
|
22
|
+
if (!isObj(relation))
|
|
23
|
+
return emptyErr(`Relation '${key}' must be an object.`);
|
|
24
|
+
if (!("path" in relation) || !Array.isArray(relation.path) || relation.path.length !== 2)
|
|
25
|
+
return emptyErr(`Relation '${key}' must have a 'path' property with an array of two strings.`);
|
|
26
|
+
if ("search" in relation && !isObj(relation.search, false))
|
|
27
|
+
return emptyErr(`Relation '${key}' has an invalid 'search' property; it must be an object.`);
|
|
28
|
+
if ("many" in relation && typeof relation.many !== "boolean")
|
|
29
|
+
return emptyErr(`Relation '${key}' has an invalid 'many' property; it must be a boolean.`);
|
|
30
|
+
if ("options" in relation && !isObj(relation.options, false))
|
|
31
|
+
return emptyErr(`Relation '${key}' has an invalid 'options' property; it must be an object.`);
|
|
32
|
+
if ("select" in relation && !Array.isArray(relation.select))
|
|
33
|
+
return emptyErr(`Relation '${key}' has an invalid 'select' property; it must be an array.`);
|
|
34
|
+
if ("relations" in relation) {
|
|
35
|
+
const nestedResult = validateRelations(relation.relations);
|
|
36
|
+
if (nestedResult !== true)
|
|
37
|
+
return nestedResult;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return true;
|
|
17
41
|
}
|
|
18
42
|
function validR(query) {
|
|
19
43
|
const { r } = query;
|
|
20
44
|
if (!("path" in r) || !Array.isArray(r.path) || r.path.length !== 2)
|
|
21
|
-
return emptyErr();
|
|
45
|
+
return emptyErr("Relation query 'r' must have a 'path' property with an array of two strings.");
|
|
22
46
|
if (!isObj(r.search, false))
|
|
23
|
-
return emptyErr();
|
|
47
|
+
return emptyErr("Relation query 'r.search' must be an object.");
|
|
48
|
+
if (!isObj(r.relations, false))
|
|
49
|
+
return emptyErr("Relation query 'r' must have a 'relations' object.");
|
|
50
|
+
const relationsValidation = validateRelations(r.relations);
|
|
51
|
+
if (relationsValidation !== true)
|
|
52
|
+
return relationsValidation;
|
|
53
|
+
if ("many" in r && typeof r.many !== "boolean")
|
|
54
|
+
return emptyErr("Relation query 'r.many' must be a boolean.");
|
|
55
|
+
if ("options" in r && !isObj(r.options, false))
|
|
56
|
+
return emptyErr("Relation query 'r.options' must be an object.");
|
|
57
|
+
if ("select" in r && !Array.isArray(r.select))
|
|
58
|
+
return emptyErr("Relation query 'r.select' must be an array.");
|
|
24
59
|
return true;
|
|
25
60
|
}
|
|
26
61
|
function validD(query) {
|
|
27
62
|
const { d } = query;
|
|
28
63
|
const key = Object.keys(d)[0];
|
|
29
|
-
|
|
64
|
+
const value = d[key]; // Cast for common property
|
|
65
|
+
if (key === "getCollections") {
|
|
66
|
+
if (Object.keys(value).length > 0)
|
|
67
|
+
return emptyErr("'getCollections' should be an empty object.");
|
|
30
68
|
return true;
|
|
31
|
-
|
|
69
|
+
}
|
|
32
70
|
if (typeof value.collection !== "string" || value.collection.trim() === "")
|
|
33
|
-
return emptyErr();
|
|
34
|
-
if (key === "issetCollection" || key === "ensureCollection")
|
|
71
|
+
return emptyErr(`CRUD operation '${key}' must specify a non-empty 'collection' string.`);
|
|
72
|
+
if (key === "issetCollection" || key === "ensureCollection" || key === "removeCollection") {
|
|
35
73
|
return true;
|
|
74
|
+
}
|
|
36
75
|
if (key === "add") {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
76
|
+
const op = d.add;
|
|
77
|
+
if (!isObj(op.data))
|
|
78
|
+
return emptyErr("'add' operation requires a 'data' object.");
|
|
79
|
+
if ("id_gen" in op && typeof op.id_gen !== "boolean")
|
|
80
|
+
return emptyErr("'add' operation 'id_gen' property must be a boolean.");
|
|
81
|
+
return true;
|
|
41
82
|
}
|
|
42
|
-
if ("
|
|
43
|
-
|
|
44
|
-
|
|
83
|
+
if (key === "find") {
|
|
84
|
+
const op = d.find;
|
|
85
|
+
if ("search" in op && !isObj(op.search, false))
|
|
86
|
+
return emptyErr("'find' operation 'search' property must be an object.");
|
|
87
|
+
if ("limit" in op && typeof op.limit !== "number")
|
|
88
|
+
return emptyErr("'find' operation 'limit' property must be a number.");
|
|
89
|
+
if ("fields" in op && !isObj(op.fields, false) && !Array.isArray(op.fields))
|
|
90
|
+
return emptyErr("'find' operation 'fields' property must be an object or an array.");
|
|
91
|
+
if ("select" in op && !isObj(op.select, false) && !Array.isArray(op.select))
|
|
92
|
+
return emptyErr("'find' operation 'select' property must be an object or an array.");
|
|
93
|
+
if ("options" in op && !isObj(op.options, false))
|
|
94
|
+
return emptyErr("'find' operation 'options' property must be an object.");
|
|
95
|
+
if ("searchOpts" in op && !isObj(op.searchOpts, false))
|
|
96
|
+
return emptyErr("'find' operation 'searchOpts' property must be an object.");
|
|
45
97
|
return true;
|
|
46
|
-
if (key === "update" || key === "updateOne" || key === "updateOneOrAdd") {
|
|
47
|
-
if (!isObj(value.updater, false))
|
|
48
|
-
return emptyErr();
|
|
49
|
-
else
|
|
50
|
-
return true;
|
|
51
98
|
}
|
|
52
|
-
|
|
99
|
+
if (key === "findOne" || key === "f") {
|
|
100
|
+
const op = d.findOne || d.f;
|
|
101
|
+
if (!isObj(op.search, false))
|
|
102
|
+
return emptyErr(`'${key}' operation requires a 'search' object.`);
|
|
103
|
+
if ("fields" in op && !isObj(op.fields, false) && !Array.isArray(op.fields))
|
|
104
|
+
return emptyErr(`'${key}' operation 'fields' property must be an object or an array.`);
|
|
105
|
+
if ("select" in op && !isObj(op.select, false) && !Array.isArray(op.select))
|
|
106
|
+
return emptyErr(`'${key}' operation 'select' property must be an object or an array.`);
|
|
107
|
+
if ("searchOpts" in op && !isObj(op.searchOpts, false))
|
|
108
|
+
return emptyErr(`'${key}' operation 'searchOpts' property must be an object.`);
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
if (key === "remove" || key === "removeOne") {
|
|
112
|
+
const op = d.remove || d.removeOne;
|
|
113
|
+
if (!isObj(op.search, false))
|
|
114
|
+
return emptyErr(`'${key}' operation requires a 'search' object.`);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
if (key === "update" || key === "updateOne") {
|
|
118
|
+
const op = d.update || d.updateOne;
|
|
119
|
+
if (!isObj(op.search, false))
|
|
120
|
+
return emptyErr(`'${key}' operation requires a 'search' object.`);
|
|
121
|
+
if (!isObj(op.updater, false))
|
|
122
|
+
return emptyErr(`'${key}' operation requires an 'updater' object.`);
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
if (key === "updateOneOrAdd") {
|
|
126
|
+
const op = d.updateOneOrAdd;
|
|
127
|
+
if (!isObj(op.search, false))
|
|
128
|
+
return emptyErr("'updateOneOrAdd' operation requires a 'search' object.");
|
|
129
|
+
if (!isObj(op.updater, false))
|
|
130
|
+
return emptyErr("'updateOneOrAdd' operation requires an 'updater' object.");
|
|
131
|
+
if ("add_arg" in op && !isObj(op.add_arg, false))
|
|
132
|
+
return emptyErr("'updateOneOrAdd' operation 'add_arg' property must be an object.");
|
|
133
|
+
if ("id_gen" in op && typeof op.id_gen !== "boolean")
|
|
134
|
+
return emptyErr("'updateOneOrAdd' operation 'id_gen' property must be a boolean.");
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
return emptyErr(`Unknown or invalid CRUD operation: '${key}'`);
|
|
53
138
|
}
|
|
54
139
|
export function validateVql(query) {
|
|
55
140
|
if ("r" in query && isObj(query.r))
|
|
56
141
|
return validR(query);
|
|
57
142
|
if ("d" in query && isObj(query.d))
|
|
58
143
|
return validD(query);
|
|
59
|
-
return emptyErr();
|
|
144
|
+
return emptyErr("Query must contain a valid 'r' (relation) or 'd' (database) property.");
|
|
60
145
|
}
|
package/dist/vql.d.ts
CHANGED
|
@@ -189,106 +189,79 @@ declare namespace RelationTypes {
|
|
|
189
189
|
};
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
|
-
export interface
|
|
193
|
-
find: VQLFind<T>;
|
|
194
|
-
findOne: VQLFindOne<T>;
|
|
195
|
-
f: VQLFindOne<T>;
|
|
196
|
-
add: VQLAdd<T>;
|
|
197
|
-
update: VQLUpdate<T>;
|
|
198
|
-
updateOne: VQLUpdateOne<T>;
|
|
199
|
-
remove: VQLRemove<T>;
|
|
200
|
-
removeOne: VQLRemoveOne<T>;
|
|
201
|
-
updateOneOrAdd: VQLUpdateOneOrAdd<T>;
|
|
202
|
-
removeCollection: VQLCollectionOperation;
|
|
203
|
-
ensureCollection: VQLCollectionOperation;
|
|
204
|
-
issetCollection: VQLCollectionOperation;
|
|
205
|
-
getCollections: {};
|
|
206
|
-
}
|
|
207
|
-
export type VQLQueryData<T = any> = {
|
|
208
|
-
find: VQLFind<T>;
|
|
209
|
-
} | {
|
|
210
|
-
findOne: VQLFindOne<T>;
|
|
211
|
-
} | {
|
|
212
|
-
f: VQLFindOne<T>;
|
|
213
|
-
} | {
|
|
214
|
-
add: VQLAdd<T>;
|
|
215
|
-
} | {
|
|
216
|
-
update: VQLUpdate<T>;
|
|
217
|
-
} | {
|
|
218
|
-
updateOne: VQLUpdateOne<T>;
|
|
219
|
-
} | {
|
|
220
|
-
remove: VQLRemove<T>;
|
|
221
|
-
} | {
|
|
222
|
-
removeOne: VQLRemoveOne<T>;
|
|
223
|
-
} | {
|
|
224
|
-
updateOneOrAdd: VQLUpdateOneOrAdd<T>;
|
|
225
|
-
} | {
|
|
226
|
-
removeCollection: VQLCollectionOperation;
|
|
227
|
-
} | {
|
|
228
|
-
ensureCollection: VQLCollectionOperation;
|
|
229
|
-
} | {
|
|
230
|
-
issetCollection: VQLCollectionOperation;
|
|
231
|
-
} | {
|
|
232
|
-
getCollections: {};
|
|
233
|
-
};
|
|
234
|
-
export interface VQLRequest<T = any> {
|
|
235
|
-
db: string;
|
|
236
|
-
d: VQLQueryData<T>;
|
|
237
|
-
}
|
|
238
|
-
export interface VQLFind<T = any> {
|
|
192
|
+
export interface VQL_OP_Find<T = any> {
|
|
239
193
|
collection: string;
|
|
240
194
|
search?: Search<T>;
|
|
241
195
|
limit?: number;
|
|
242
|
-
fields?:
|
|
243
|
-
select?:
|
|
244
|
-
relations?: VQLRelations;
|
|
196
|
+
fields?: VQL_Fields;
|
|
197
|
+
select?: VQL_Fields;
|
|
245
198
|
options?: DbFindOpts<T>;
|
|
246
199
|
searchOpts?: FindOpts<T>;
|
|
247
200
|
}
|
|
248
|
-
export interface
|
|
201
|
+
export interface VQL_OP_FindOne<T = any> {
|
|
249
202
|
collection: string;
|
|
250
203
|
search: Search<T>;
|
|
251
|
-
fields?:
|
|
252
|
-
select?:
|
|
253
|
-
relations?: VQLRelations;
|
|
204
|
+
fields?: VQL_Fields;
|
|
205
|
+
select?: VQL_Fields;
|
|
254
206
|
searchOpts?: FindOpts<T>;
|
|
255
207
|
}
|
|
256
|
-
export interface
|
|
208
|
+
export interface VQL_OP_Add<T = any> {
|
|
257
209
|
collection: string;
|
|
258
210
|
data: Arg<T>;
|
|
259
211
|
id_gen?: boolean;
|
|
260
212
|
}
|
|
261
|
-
export interface
|
|
262
|
-
collection: string;
|
|
263
|
-
search: Search<T>;
|
|
264
|
-
updater: UpdaterArg<T>;
|
|
265
|
-
}
|
|
266
|
-
export interface VQLUpdateOne<T = any> {
|
|
213
|
+
export interface VQL_OP_Update<T = any> {
|
|
267
214
|
collection: string;
|
|
268
215
|
search: Search<T>;
|
|
269
216
|
updater: UpdaterArg<T>;
|
|
270
217
|
}
|
|
271
|
-
export interface
|
|
218
|
+
export interface VQL_OP_Remove<T = any> {
|
|
272
219
|
collection: string;
|
|
273
220
|
search: Search<T>;
|
|
274
221
|
}
|
|
275
|
-
export interface
|
|
276
|
-
collection: string;
|
|
277
|
-
search: Search<T>;
|
|
278
|
-
}
|
|
279
|
-
export interface VQLUpdateOneOrAdd<T = any> {
|
|
222
|
+
export interface VQL_OP_UpdateOneOrAdd<T = any> {
|
|
280
223
|
collection: string;
|
|
281
224
|
search: Search<T>;
|
|
282
225
|
updater: UpdaterArg<T>;
|
|
283
226
|
add_arg?: Arg<T>;
|
|
284
227
|
id_gen?: boolean;
|
|
285
228
|
}
|
|
286
|
-
export interface
|
|
229
|
+
export interface VQL_OP_CollectionOperation {
|
|
287
230
|
collection: string;
|
|
288
231
|
}
|
|
289
|
-
export type
|
|
290
|
-
export type
|
|
291
|
-
|
|
232
|
+
export type VQL_Fields = Record<string, boolean | number> | string[];
|
|
233
|
+
export type VQL_Query_CRUD_Data<T = any> = {
|
|
234
|
+
find: VQL_OP_Find<T>;
|
|
235
|
+
} | {
|
|
236
|
+
findOne: VQL_OP_FindOne<T>;
|
|
237
|
+
} | {
|
|
238
|
+
f: VQL_OP_FindOne<T>;
|
|
239
|
+
} | {
|
|
240
|
+
add: VQL_OP_Add<T>;
|
|
241
|
+
} | {
|
|
242
|
+
update: VQL_OP_Update<T>;
|
|
243
|
+
} | {
|
|
244
|
+
updateOne: VQL_OP_Update<T>;
|
|
245
|
+
} | {
|
|
246
|
+
remove: VQL_OP_Remove<T>;
|
|
247
|
+
} | {
|
|
248
|
+
removeOne: VQL_OP_Remove<T>;
|
|
249
|
+
} | {
|
|
250
|
+
updateOneOrAdd: VQL_OP_UpdateOneOrAdd<T>;
|
|
251
|
+
} | {
|
|
252
|
+
removeCollection: VQL_OP_CollectionOperation;
|
|
253
|
+
} | {
|
|
254
|
+
ensureCollection: VQL_OP_CollectionOperation;
|
|
255
|
+
} | {
|
|
256
|
+
issetCollection: VQL_OP_CollectionOperation;
|
|
257
|
+
} | {
|
|
258
|
+
getCollections: {};
|
|
259
|
+
};
|
|
260
|
+
export interface VQL_Query_CRUD<T = any> {
|
|
261
|
+
db: string;
|
|
262
|
+
d: VQL_Query_CRUD_Data<T>;
|
|
263
|
+
}
|
|
264
|
+
export interface VQL_Query_Relation {
|
|
292
265
|
r: {
|
|
293
266
|
path: RelationTypes.Path;
|
|
294
267
|
search: Search;
|
|
@@ -298,26 +271,21 @@ export interface RelationQuery {
|
|
|
298
271
|
select?: RelationTypes.FieldPath[];
|
|
299
272
|
};
|
|
300
273
|
}
|
|
301
|
-
export interface
|
|
302
|
-
ref?: string;
|
|
274
|
+
export interface VQL_Var {
|
|
303
275
|
var?: {
|
|
304
276
|
[k: string]: any;
|
|
305
277
|
};
|
|
306
278
|
}
|
|
307
|
-
|
|
308
|
-
export type
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
279
|
+
/** VQL Query */
|
|
280
|
+
export type VQL_Query<T = any> = (VQL_Query_CRUD<T> | VQL_Query_Relation) & VQL_Var;
|
|
281
|
+
/** VQL Universal Query */
|
|
282
|
+
export type VQLUQ<T = any> = VQL_Query<T> | string | {
|
|
283
|
+
query: string;
|
|
284
|
+
} & VQL_Var;
|
|
313
285
|
export interface VQLError {
|
|
314
286
|
err: true;
|
|
315
287
|
msg: string;
|
|
316
288
|
c: number;
|
|
317
|
-
why?: string;
|
|
318
289
|
}
|
|
319
|
-
export type VqlQueryRaw<T = any> = VQLR<T> | string | {
|
|
320
|
-
query: string;
|
|
321
|
-
} & VQLRef;
|
|
322
290
|
|
|
323
291
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wxn0brp/vql",
|
|
3
|
-
"version": "0.6.0-
|
|
3
|
+
"version": "0.6.0-beta.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"author": "wxn0brP",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,7 +35,6 @@
|
|
|
35
35
|
"@wxn0brp/db": "^0.30.0",
|
|
36
36
|
"@wxn0brp/falcon-frame": "0.0.20",
|
|
37
37
|
"@wxn0brp/gate-warden": "^0.4.0",
|
|
38
|
-
"dotenv": "^17.2.0",
|
|
39
38
|
"esbuild": "^0.25.8",
|
|
40
39
|
"tsc-alias": "^1.8.10",
|
|
41
40
|
"typescript": "^5.7.3"
|
package/dist/sheet/index.d.ts
DELETED
package/dist/sheet/index.js
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { deepMerge } from "../merge.js";
|
|
2
|
-
function trimPath(path) {
|
|
3
|
-
return path && path.length > 2 ? path.slice(0, 2) : path;
|
|
4
|
-
}
|
|
5
|
-
function relationFix(relations) {
|
|
6
|
-
for (const key in relations) {
|
|
7
|
-
const value = relations[key];
|
|
8
|
-
value.path = trimPath(value.path);
|
|
9
|
-
if (value.relations) {
|
|
10
|
-
relationFix(value.relations);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
function pathFix(vql) {
|
|
15
|
-
if ("d" in vql) {
|
|
16
|
-
const key = Object.keys(vql.d)[0];
|
|
17
|
-
const value = vql.d[key];
|
|
18
|
-
value.path = trimPath(value.path);
|
|
19
|
-
}
|
|
20
|
-
else if ("r" in vql) {
|
|
21
|
-
const value = vql.r;
|
|
22
|
-
value.path = trimPath(value.path);
|
|
23
|
-
if (value.relations) {
|
|
24
|
-
relationFix(value.relations);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
function replaceVariables(obj, variables) {
|
|
29
|
-
if (typeof obj === "object" && !Array.isArray(obj) && obj !== null && "__" in obj) {
|
|
30
|
-
const varKey = obj.__;
|
|
31
|
-
return variables[varKey] ?? obj;
|
|
32
|
-
}
|
|
33
|
-
if (typeof obj === "string") {
|
|
34
|
-
if (obj.startsWith("$"))
|
|
35
|
-
return variables[obj.slice(1)] ?? obj;
|
|
36
|
-
return obj;
|
|
37
|
-
}
|
|
38
|
-
if (Array.isArray(obj))
|
|
39
|
-
return obj.map((item) => replaceVariables(item, variables));
|
|
40
|
-
if (typeof obj === "object" && obj !== null) {
|
|
41
|
-
const newObj = {};
|
|
42
|
-
for (const key in obj) {
|
|
43
|
-
newObj[key] = replaceVariables(obj[key], variables);
|
|
44
|
-
}
|
|
45
|
-
return newObj;
|
|
46
|
-
}
|
|
47
|
-
return obj;
|
|
48
|
-
}
|
|
49
|
-
export function executeSheetAndReplaceVars(query, preDefinedSheets, user) {
|
|
50
|
-
if ("ref" in query) {
|
|
51
|
-
if (preDefinedSheets.has(query.ref)) {
|
|
52
|
-
const ref = preDefinedSheets.get(query.ref);
|
|
53
|
-
const merge = deepMerge(query, ref);
|
|
54
|
-
pathFix(merge);
|
|
55
|
-
query = merge;
|
|
56
|
-
}
|
|
57
|
-
delete query.ref;
|
|
58
|
-
}
|
|
59
|
-
query.var = {
|
|
60
|
-
_me: user?.id || user?._id || user,
|
|
61
|
-
_now: Date.now(),
|
|
62
|
-
_nowShort: Math.floor(Date.now() / 1000),
|
|
63
|
-
__now: Date.now().toString(),
|
|
64
|
-
__nowShort: Math.floor(Date.now() / 1000).toString(),
|
|
65
|
-
...(query.var || {})
|
|
66
|
-
};
|
|
67
|
-
query = replaceVariables(query, query.var);
|
|
68
|
-
delete query.var;
|
|
69
|
-
return query;
|
|
70
|
-
}
|
package/dist/sheet/load.d.ts
DELETED
package/dist/sheet/load.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { existsSync, readdirSync, readFileSync } from "fs";
|
|
2
|
-
function loadSheet(map, file) {
|
|
3
|
-
if (!existsSync(file)) {
|
|
4
|
-
throw new Error(`Sheet ${file} not found`);
|
|
5
|
-
}
|
|
6
|
-
const sheet = JSON.parse(readFileSync(file, "utf-8"));
|
|
7
|
-
for (const key in sheet) {
|
|
8
|
-
map.set(key, sheet[key]);
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
export function loadSheetsFromDir(dir) {
|
|
12
|
-
const map = new Map();
|
|
13
|
-
for (const file of readdirSync(dir)) {
|
|
14
|
-
loadSheet(map, `${dir}/${file}`);
|
|
15
|
-
}
|
|
16
|
-
return map;
|
|
17
|
-
}
|
|
18
|
-
export function loadSheetFromFile(file) {
|
|
19
|
-
const map = new Map();
|
|
20
|
-
loadSheet(map, file);
|
|
21
|
-
return map;
|
|
22
|
-
}
|