@wxn0brp/vql 0.8.4 → 0.9.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.
@@ -1,9 +1,12 @@
1
1
  import { checkRequestPermission } from "../permissions/index.js";
2
2
  import { parseSelect } from "./utils.js";
3
+ import { LowAdapter } from "../helpers/lowAdapter.js";
3
4
  export async function executeQuery(cpu, query, user) {
4
5
  if (!query.db || !cpu.dbInstances[query.db])
5
6
  return { err: true, msg: `Invalid query - db "${query.db || "undefined"}" not found`, c: 400 };
6
7
  const db = cpu.dbInstances[query.db];
8
+ if (db instanceof LowAdapter)
9
+ return await db.resolver(query, user);
7
10
  const operation = Object.keys(query.d)[0];
8
11
  if (!cpu.config.noCheckPermissions && !await checkRequestPermission(cpu.config, cpu.permValidFn, user, query)) {
9
12
  return { err: true, msg: "Permission denied", c: 403 };
@@ -1,3 +1,4 @@
1
+ import { VQL_Query_CRUD_Keys } from "../types/vql.js";
1
2
  import { ValtheraCompatible } from "@wxn0brp/db-core";
2
3
  type ResolverFn<TArgs extends any[] = any[], TReturn = any> = (...args: TArgs) => Promise<TReturn>;
3
4
  export interface ValtheraResolverMeta {
@@ -18,47 +19,42 @@ export interface ValtheraResolver {
18
19
  find?: ResolverFn<[
19
20
  collection: string,
20
21
  search: any,
21
- context?: any,
22
22
  options?: any,
23
- findOpts?: any
23
+ findOpts?: any,
24
+ context?: any
24
25
  ], any[]>;
25
26
  findOne?: ResolverFn<[
26
27
  collection: string,
27
28
  search: any,
28
- context?: any,
29
- findOpts?: any
29
+ findOpts?: any,
30
+ context?: any
30
31
  ], any | null>;
31
32
  update?: ResolverFn<[collection: string, search: any, updater: any, context?: any], boolean>;
32
33
  updateOne?: ResolverFn<[collection: string, search: any, updater: any, context?: any], boolean>;
33
- updateOneOrAdd?: ResolverFn<[
34
- collection: string,
35
- search: any,
36
- updater: any,
37
- add_arg?: any,
38
- context?: any,
39
- id_gen?: boolean
40
- ], boolean>;
34
+ updateOneOrAdd?: ResolverFn<[collection: string, search: any, updater: any, opts?: any], boolean>;
35
+ toggleOne?: ResolverFn<[collection: string, search: any, data?: any, context?: any], boolean>;
41
36
  remove?: ResolverFn<[collection: string, search: any, context?: any], boolean>;
42
37
  removeOne?: ResolverFn<[collection: string, search: any, context?: any], boolean>;
43
38
  removeCollection?: ResolverFn<[collection: string], boolean>;
44
39
  }
40
+ export type Operation = Exclude<VQL_Query_CRUD_Keys, "f">;
45
41
  export declare function createValtheraAdapter(resolver: ValtheraResolver, extendedFind?: boolean): ValtheraCompatible;
46
- export type Operation = "add" | "find" | "findOne" | "update" | "updateOne" | "updateOneOrAdd" | "remove" | "removeOne" | "removeCollection";
47
42
  export declare class AdapterBuilder {
48
43
  private catchCb;
49
44
  private handlers;
50
45
  private collections;
51
46
  constructor(catchCb?: (e: any, op: string, args: any[]) => void);
52
47
  register(op: Operation, collection: string, fn: Function): this;
53
- add(collection: string, fn: ResolverFn<[data: any, id_gen?: boolean], any>): this;
54
- find(collection: string, fn: ResolverFn<[search: any, context?: any, options?: any, findOpts?: any], any[]>): this;
55
- findOne(collection: string, fn: ResolverFn<[search: any, context?: any, findOpts?: any], any | null>): this;
56
- update(collection: string, fn: ResolverFn<[collection: string, search: any, updater: any], boolean>): this;
57
- updateOne(collection: string, fn: ResolverFn<[search: any, updater: any], boolean>): this;
58
- updateOneOrAdd(collection: string, fn: ResolverFn<[search: any, updater: any, add_arg?: any, context?: any, id_gen?: boolean], boolean>): this;
59
- remove(collection: string, fn: ResolverFn<[search: any], boolean>): this;
60
- removeOne(collection: string, fn: ResolverFn<[search: any], boolean>): this;
61
- removeCollection(collection: string, fn: ResolverFn<[], boolean>): this;
48
+ add(collection: string, fn: ValtheraResolver["add"]): this;
49
+ find(collection: string, fn: ValtheraResolver["find"]): this;
50
+ findOne(collection: string, fn: ValtheraResolver["findOne"]): this;
51
+ update(collection: string, fn: ValtheraResolver["update"]): this;
52
+ updateOne(collection: string, fn: ValtheraResolver["updateOne"]): this;
53
+ updateOneOrAdd(collection: string, fn: ValtheraResolver["updateOneOrAdd"]): this;
54
+ toggleOne(collection: string, fn: ValtheraResolver["toggleOne"]): this;
55
+ remove(collection: string, fn: ValtheraResolver["remove"]): this;
56
+ removeOne(collection: string, fn: ValtheraResolver["removeOne"]): this;
57
+ removeCollection(collection: string, fn: ValtheraResolver["removeCollection"]): this;
62
58
  getAdapter(extendedFind?: boolean): ValtheraCompatible;
63
59
  }
64
60
  export {};
@@ -4,7 +4,8 @@ const list = [
4
4
  "ensureCollection", "issetCollection", "getCollections", "removeCollection",
5
5
  "add",
6
6
  "find", "findOne",
7
- "update", "updateOne", "updateOneOrAdd",
7
+ "update", "updateOne",
8
+ "updateOneOrAdd", "toggleOne",
8
9
  "remove", "removeOne"
9
10
  ];
10
11
  export function createValtheraAdapter(resolver, extendedFind = false) {
@@ -26,8 +27,8 @@ export function createValtheraAdapter(resolver, extendedFind = false) {
26
27
  let data = await safe(resolver.find)(col, search, options, findOpts, context);
27
28
  if (options?.reverse)
28
29
  data.reverse();
29
- if (options?.max !== -1 && data.length > options?.max)
30
- data = data.slice(0, options?.max);
30
+ if (options?.limit !== -1 && data.length > options?.limit)
31
+ data = data.slice(0, options?.limit);
31
32
  data = data.map(d => updateFindObject(d, findOpts || {}));
32
33
  return data;
33
34
  };
@@ -70,6 +71,9 @@ export class AdapterBuilder {
70
71
  updateOneOrAdd(collection, fn) {
71
72
  return this.register("updateOneOrAdd", collection, fn);
72
73
  }
74
+ toggleOne(collection, fn) {
75
+ return this.register("toggleOne", collection, fn);
76
+ }
73
77
  remove(collection, fn) {
74
78
  return this.register("remove", collection, fn);
75
79
  }
@@ -103,9 +107,8 @@ export class AdapterBuilder {
103
107
  return true;
104
108
  },
105
109
  }, extendedFind);
106
- for (const name of ["add", "find", "findOne", "update", "updateOne", "updateOneOrAdd", "remove", "removeOne", "removeCollection"]) {
110
+ for (const name of list.slice(4))
107
111
  adapter[name] = (...args) => resolve(name, ...args);
108
- }
109
112
  return adapter;
110
113
  }
111
114
  }
@@ -0,0 +1,6 @@
1
+ import { VQL_Query_CRUD } from "../types/vql.js";
2
+ export type LowResolver = (query: VQL_Query_CRUD, user: any) => Promise<any> | any;
3
+ export declare class LowAdapter {
4
+ resolver: LowResolver;
5
+ constructor(resolver: LowResolver);
6
+ }
@@ -0,0 +1,6 @@
1
+ export class LowAdapter {
2
+ resolver;
3
+ constructor(resolver) {
4
+ this.resolver = resolver;
5
+ }
6
+ }
@@ -22,6 +22,7 @@ function replaceVariables(obj, variables) {
22
22
  export function replaceVars(query, user) {
23
23
  query.var = {
24
24
  _me: user?.id || user?._id || user,
25
+ _user: user,
25
26
  _now: Date.now(),
26
27
  _nowShort: Math.floor(Date.now() / 1000),
27
28
  __now: Date.now().toString(),
package/dist/vql.d.ts CHANGED
@@ -9,8 +9,14 @@ export interface VContext {
9
9
  export type KeysMatching<T, V, C = V> = {
10
10
  [K in keyof T]-?: T[K] extends C ? K : never;
11
11
  }[keyof T];
12
- export type PartialOfType<T, V, C = V> = Partial<Record<KeysMatching<T, V, C>, V>>;
13
- export type PartialPickMatching<T, V, C = V> = Partial<Pick<T, KeysMatching<T, V, C>>>;
12
+ /** Helper type for nested path values with type filtering */
13
+ export type NestedValue<T, V, C = V> = {
14
+ [K in keyof T as T[K] extends C ? K : T[K] extends object ? K : never]?: T[K] extends C ? V : T[K] extends object ? NestedValue<T[K], V, C> : never;
15
+ };
16
+ /** Helper type for nested path structure */
17
+ export type DeepPartial<T> = {
18
+ [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
19
+ };
14
20
  /** Logical Operators */
15
21
  export type LogicalOperators<T = any> = {
16
22
  /**
@@ -29,73 +35,110 @@ export type LogicalOperators<T = any> = {
29
35
  */
30
36
  $not?: SearchOptions<T>;
31
37
  };
32
- /** Comparison Operators */
38
+ /** Comparison Operators with nested support */
33
39
  export type ComparisonOperators<T = any> = {
34
- $gt?: PartialOfType<T, number>;
35
- $lt?: PartialOfType<T, number>;
36
- $gte?: PartialOfType<T, number>;
37
- $lte?: PartialOfType<T, number>;
38
- $between?: PartialOfType<T, [
40
+ /** 5 > 4 */
41
+ $gt?: NestedValue<T, number, number>;
42
+ /** 5 < 4 */
43
+ $lt?: NestedValue<T, number, number>;
44
+ /** 5 >= 4 */
45
+ $gte?: NestedValue<T, number, number>;
46
+ /** 5 <= 4 */
47
+ $lte?: NestedValue<T, number, number>;
48
+ /** 5 between [min, max] */
49
+ $between?: NestedValue<T, [
39
50
  number,
40
51
  number
41
52
  ], number>;
42
- $in?: Partial<Record<keyof T, T[keyof T][]>>;
43
- $nin?: Partial<Record<keyof T, T[keyof T][]>>;
44
- $idGt?: PartialOfType<T, string | number>;
45
- $idLt?: PartialOfType<T, string | number>;
46
- $idGte?: PartialOfType<T, string | number>;
47
- $idLte?: PartialOfType<T, string | number>;
53
+ /** 2 in [1, 2, 3] */
54
+ $in?: DeepPartial<T> & {
55
+ [K in keyof T]?: T[K] extends any[] ? T[K] : T[K][];
56
+ };
57
+ /** 5 not in [1, 2, 3] */
58
+ $nin?: DeepPartial<T> & {
59
+ [K in keyof T]?: T[K] extends any[] ? T[K] : T[K][];
60
+ };
61
+ /** id > 4 */
62
+ $idGt?: NestedValue<T, string | number, string | number>;
63
+ /** id < 4 */
64
+ $idLt?: NestedValue<T, string | number, string | number>;
65
+ /** id >= 4 */
66
+ $idGte?: NestedValue<T, string | number, string | number>;
67
+ /** id <= 4 */
68
+ $idLte?: NestedValue<T, string | number, string | number>;
48
69
  };
49
- /** Type and Existence Operators */
70
+ /** Type and Existence Operators with nested support */
50
71
  export type TypeAndExistenceOperators<T = any> = {
51
- $exists?: PartialOfType<T, boolean, any>;
52
- $type?: PartialOfType<T, string>;
72
+ /** "name" in { name: "John" } */
73
+ $exists?: NestedValue<T, boolean>;
74
+ /** "name" == "string" in { name: "John" } */
75
+ $type?: NestedValue<T, string>;
53
76
  };
54
- /** Array Operators */
77
+ /** Array Operators with nested support */
55
78
  export type ArrayOperators<T = any> = {
56
- $arrinc?: PartialPickMatching<T, any[]>;
57
- $arrincall?: PartialPickMatching<T, any[]>;
58
- $size?: PartialOfType<T, number>;
79
+ /** [1, 2, 3] includes 2 */
80
+ $arrinc?: DeepPartial<T>;
81
+ /** [1, 2, 3] array includes all elements e.g. [1, 2] */
82
+ $arrincall?: DeepPartial<T>;
83
+ /** [1, 2, 3] has size 3 */
84
+ $size?: NestedValue<T, number>;
59
85
  };
60
- /** String Operators */
86
+ /** String Operators with nested support */
61
87
  export type StringOperators<T = any> = {
62
- $regex?: PartialOfType<T, RegExp | string, string>;
63
- $startsWith?: PartialOfType<T, string>;
64
- $endsWith?: PartialOfType<T, string>;
88
+ /** "John" matches /oh/ */
89
+ $regex?: NestedValue<T, RegExp | string, string>;
90
+ /** "John" starts with "Jo" */
91
+ $startsWith?: NestedValue<T, string, string>;
92
+ /** "John" ends with "hn" */
93
+ $endsWith?: NestedValue<T, string, string>;
65
94
  };
66
- /** Other Operators */
95
+ /** Other Operators with nested support */
67
96
  export type OtherOperators<T = any> = {
68
- $subset?: Partial<Record<keyof T, T[keyof T]>>;
97
+ /** { $type: "name" } matches { $type: "name" } literally - Ignore $ operators */
98
+ $subset?: DeepPartial<T>;
69
99
  };
70
100
  /** Predefined Search Operators */
71
101
  export type PredefinedSearchOperators<T = any> = LogicalOperators<T> & ComparisonOperators<T> & TypeAndExistenceOperators<T> & ArrayOperators<T> & StringOperators<T> & OtherOperators<T>;
72
102
  /**
73
103
  * SearchOptions can be either a function or an object with predefined operators.
74
104
  */
75
- export type SearchOptions<T = any> = PredefinedSearchOperators<T> & Arg<T>;
105
+ export type SearchOptions<T = any> = PredefinedSearchOperators<T> & DeepPartial<T> & Record<string, any>;
76
106
  /** Arrays */
77
107
  export type ArrayUpdater<T = any> = {
78
- $push?: PartialOfType<T, any>;
79
- /** Pushes items into an array and removes duplicates */
80
- $pushset?: PartialOfType<T, any>;
81
- $pull?: PartialOfType<T, any>;
82
- $pullall?: PartialOfType<T, any>;
108
+ /** [1,2] -> $push 3 -> [1,2,3] */
109
+ $push?: NestedValue<T, any>;
110
+ /** [1,2] -> $pushset 2,3 -> [1,2,3] */
111
+ $pushset?: NestedValue<T, any>;
112
+ /** [1,2,3] -> $pull 2 -> [1,3] */
113
+ $pull?: NestedValue<T, any>;
114
+ /** [1,2,2,3] -> $pullall [2] -> [1,3] */
115
+ $pullall?: NestedValue<T, any>;
83
116
  };
84
117
  /** Objects */
85
118
  export type ObjectUpdater<T = any> = {
86
- $merge?: PartialOfType<T, any>;
87
- $deepMerge?: PartialOfType<T, any>;
119
+ /** { a: 1 } -> $merge { b: 2 } -> { a: 1, b: 2 } */
120
+ $merge?: NestedValue<T, any>;
121
+ /** { a: { x: 1 } } -> $deepMerge { a: { y: 2 } } -> { a: { x: 1, y: 2 } } */
122
+ $deepMerge?: NestedValue<T, any>;
88
123
  };
89
124
  /** Values */
90
125
  export type ValueUpdater<T = any> = {
91
- $inc?: PartialOfType<T, number>;
92
- $dec?: PartialOfType<T, number>;
93
- $unset?: PartialOfType<T, any>;
94
- $rename?: PartialOfType<T, any>;
95
- /** same as { name: value } */
96
- $set?: PartialOfType<T, any>;
126
+ /** { count: 1 } -> $inc 2 -> { count: 3 } */
127
+ $inc?: NestedValue<T, number>;
128
+ /** { count: 5 } -> $dec 2 -> { count: 3 } */
129
+ $dec?: NestedValue<T, number>;
130
+ /** { name: "John" } -> $unset "name" -> {} */
131
+ $unset?: NestedValue<T, any>;
132
+ /** { oldName: "value" } -> $rename "oldName" to "newName" -> { newName: "value" } */
133
+ $rename?: NestedValue<T, any>;
134
+ /**
135
+ * {} -> $set { name: "John" } -> { name: "John" }
136
+ *
137
+ * Note: same as { name: value }
138
+ */
139
+ $set?: NestedValue<T, any>;
97
140
  };
98
- export type UpdaterArg<T = any> = ArrayUpdater<T> & ObjectUpdater<T> & ValueUpdater<T> & Arg<T>;
141
+ export type UpdaterArg<T = any> = ArrayUpdater<T> & ObjectUpdater<T> & ValueUpdater<T> & DeepPartial<T> & Record<string, any>;
99
142
  export type Arg<T = any> = {
100
143
  [K in keyof T]?: any;
101
144
  } & Record<string, any>;
@@ -105,7 +148,7 @@ export type Search<T = any> = SearchOptions<T> | SearchFunc<T>;
105
148
  export type Updater<T = any> = UpdaterArg<T> | UpdaterArg<T>[] | UpdaterFunc<T>;
106
149
  export interface DbFindOpts<T = any> {
107
150
  reverse?: boolean;
108
- max?: number;
151
+ limit?: number;
109
152
  offset?: number;
110
153
  sortBy?: KeysMatching<T, any>;
111
154
  sortAsc?: boolean;
@@ -126,31 +169,35 @@ declare class CollectionManager<D = Data> {
126
169
  /**
127
170
  * Find data in a database.
128
171
  */
129
- find<T = Data>(search?: Search<T & D>, options?: DbFindOpts<T & Data>, findOpts?: FindOpts<T & Data>, context?: VContext): Promise<T[]>;
172
+ find<T = Data>(search?: Search<T & D>, options?: DbFindOpts<T & D>, findOpts?: FindOpts<T & D>, context?: VContext): Promise<T[]>;
130
173
  /**
131
174
  * Find one data entry in a database.
132
175
  */
133
- findOne<T = Data>(search?: Search<T & Data>, findOpts?: FindOpts<T & Data>, context?: VContext): Promise<T>;
176
+ findOne<T = Data>(search?: Search<T & D>, findOpts?: FindOpts<T & D>, context?: VContext): Promise<T>;
134
177
  /**
135
178
  * Update data in a database.
136
179
  */
137
- update<T = Data>(search: Search<T & Data>, updater: Updater<T & Data>, context?: VContext): Promise<boolean>;
180
+ update<T = Data>(search: Search<T & D>, updater: Updater<T & D>, context?: VContext): Promise<boolean>;
138
181
  /**
139
182
  * Update one data entry in a database.
140
183
  */
141
- updateOne<T = Data>(search: Search<T & Data>, updater: Updater<T & Data>, context?: VContext): Promise<boolean>;
184
+ updateOne<T = Data>(search: Search<T & D>, updater: Updater<T & D>, context?: VContext): Promise<boolean>;
142
185
  /**
143
186
  * Remove data from a database.
144
187
  */
145
- remove<T = Data>(search: Search<T & Data>, context?: VContext): Promise<boolean>;
188
+ remove<T = Data>(search: Search<T & D>, context?: VContext): Promise<boolean>;
146
189
  /**
147
190
  * Remove one data entry from a database.
148
191
  */
149
- removeOne<T = Data>(search: Search<T & Data>, context?: VContext): Promise<boolean>;
192
+ removeOne<T = Data>(search: Search<T & D>, context?: VContext): Promise<boolean>;
150
193
  /**
151
194
  * Asynchronously updates one entry in a database or adds a new one if it doesn't exist.
152
195
  */
153
- updateOneOrAdd<T = Data>(search: Search<T & Data>, updater: Updater<T & Data>, { add_arg, context, id_gen }: UpdateOneOrAdd<T & Data>): Promise<boolean>;
196
+ updateOneOrAdd<T = Data>(search: Search<T & D>, updater: Updater<T & D>, { add_arg, context, id_gen }: UpdateOneOrAdd<T & D>): Promise<boolean>;
197
+ /**
198
+ * Asynchronously removes one entry in a database or adds a new one if it doesn't exist. Usage e.g. for toggling a flag.
199
+ */
200
+ toggleOne<T = Data>(search: Search<T & D>, data?: Arg<T & D>, context?: VContext): Promise<boolean>;
154
201
  }
155
202
  export interface ValtheraCompatible {
156
203
  c(collection: string): CollectionManager;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wxn0brp/vql",
3
- "version": "0.8.4",
3
+ "version": "0.9.0",
4
4
  "main": "dist/index.js",
5
5
  "author": "wxn0brP",
6
6
  "license": "MIT",
@@ -27,7 +27,7 @@
27
27
  "query-language"
28
28
  ],
29
29
  "peerDependencies": {
30
- "@wxn0brp/db-core": ">=0.2.11",
30
+ "@wxn0brp/db-core": ">=0.3.0",
31
31
  "@wxn0brp/falcon-frame": ">=0.5.3",
32
32
  "@wxn0brp/gate-warden": ">=0.5.0"
33
33
  },
@@ -45,8 +45,8 @@
45
45
  "devDependencies": {
46
46
  "@types/bun": "*",
47
47
  "@types/node": "*",
48
- "@wxn0brp/db": "^0.40.3",
49
- "@wxn0brp/db-core": "^0.2.11",
48
+ "@wxn0brp/db": "^0.41.0",
49
+ "@wxn0brp/db-core": "^0.3.0",
50
50
  "@wxn0brp/falcon-frame": "^0.5.3",
51
51
  "@wxn0brp/gate-warden": "^0.5.0",
52
52
  "esbuild": "*",