@wxn0brp/vql 0.6.3 → 0.7.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/README.md CHANGED
@@ -5,12 +5,13 @@ VQL is a query language and processing framework designed for managing and inter
5
5
  [![npm version](https://img.shields.io/npm/v/@wxn0brp/vql)](https://www.npmjs.com/package/@wxn0brp/vql)
6
6
  [![License](https://img.shields.io/npm/l/@wxn0brp/vql)](./LICENSE)
7
7
  [![Downloads](https://img.shields.io/npm/dm/@wxn0brp/vql)](https://www.npmjs.com/package/@wxn0brp/vql)
8
+ ![CI](https://img.shields.io/github/actions/workflow/status/wxn0brP/VQL/build.yml?branch=master)
9
+ ![bundle size](https://img.shields.io/bundlephobia/minzip/@wxn0brp/vql)
8
10
 
9
11
  ## Features
10
12
 
11
13
  - **Query Execution**: Supports CRUD operations and advanced query capabilities.
12
14
  - **Permission Management**: Fine-grained access control using Gate Warden.
13
- - **GUI**: A web-based interface for managing ACL rules and database structures.
14
15
  - **Extensibility**: Easily extendable with pre-defined sheets and custom configurations.
15
16
 
16
17
  ## Example Usage
@@ -35,7 +36,7 @@ const query = {
35
36
  d: {
36
37
  find: {
37
38
  collection: "users",
38
- search: { age: { $gt: 18 } },
39
+ search: { $gt: { age: 18 } },
39
40
  fields: { name: 1, age: 1 },
40
41
  },
41
42
  },
@@ -45,17 +45,20 @@ export interface ValtheraResolver {
45
45
  export declare function createValtheraAdapter(resolver: ValtheraResolver, extendedFind?: boolean): ValtheraCompatible;
46
46
  export type Operation = "add" | "find" | "findOne" | "update" | "updateOne" | "updateOneOrAdd" | "remove" | "removeOne" | "removeCollection";
47
47
  export declare class AdapterBuilder {
48
+ private catchCb;
48
49
  private handlers;
49
50
  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;
51
+ constructor(catchCb?: (e: any, op: string, args: any[]) => void);
52
+ 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;
59
62
  getAdapter(extendedFind?: boolean): ValtheraCompatible;
60
63
  }
61
64
  export {};
@@ -1,5 +1,12 @@
1
1
  import CollectionManager from "@wxn0brp/db-core/helpers/CollectionManager";
2
2
  import updateFindObject from "@wxn0brp/db-core/utils/updateFindObject";
3
+ const list = [
4
+ "ensureCollection", "issetCollection", "getCollections", "removeCollection",
5
+ "add",
6
+ "find", "findOne",
7
+ "update", "updateOne", "updateOneOrAdd",
8
+ "remove", "removeOne"
9
+ ];
3
10
  export function createValtheraAdapter(resolver, extendedFind = false) {
4
11
  const safe = (fn) => {
5
12
  if (!fn)
@@ -9,24 +16,14 @@ export function createValtheraAdapter(resolver, extendedFind = false) {
9
16
  const adapter = {
10
17
  // @ts-ignore
11
18
  meta: resolver.meta ?? { type: "api", version: "0.0.1" },
12
- c: null,
13
- getCollections: () => safe(resolver.getCollections)(),
14
- issetCollection: (c) => safe(resolver.issetCollection)(c),
15
- ensureCollection: (c) => safe(resolver.ensureCollection)(c),
16
- add: (col, data, id_gen) => safe(resolver.add)(col, data, id_gen),
17
- find: (col, search, context, options, findOpts) => safe(resolver.find)(col, search, context, options, findOpts),
18
- findOne: (col, search, context, findOpts) => safe(resolver.findOne)(col, search, context, findOpts),
19
- update: (col, search, up) => safe(resolver.update)(col, search, up),
20
- updateOne: (col, search, up) => safe(resolver.updateOne)(col, search, up),
21
- updateOneOrAdd: (col, search, up, add_data, ctx, id_gen) => safe(resolver.updateOneOrAdd)(col, search, up, add_data, ctx, id_gen),
22
- remove: (col, search) => safe(resolver.remove)(col, search),
23
- removeOne: (col, search) => safe(resolver.removeOne)(col, search),
24
- removeCollection: (col) => safe(resolver.removeCollection)(col),
25
19
  };
26
20
  adapter.c = (collection) => new CollectionManager(adapter, collection);
21
+ for (const name of list) {
22
+ adapter[name] = (...args) => safe(resolver[name])(...args);
23
+ }
27
24
  if (extendedFind) {
28
- adapter.find = async (col, search, context, options, findOpts) => {
29
- let data = await safe(resolver.find)(col, search, context, options, findOpts);
25
+ adapter.find = async (col, search, options, findOpts, context) => {
26
+ let data = await safe(resolver.find)(col, search, options, findOpts, context);
30
27
  if (options?.reverse)
31
28
  data.reverse();
32
29
  if (options?.max !== -1 && data.length > options?.max)
@@ -44,19 +41,58 @@ export function createValtheraAdapter(resolver, extendedFind = false) {
44
41
  return adapter;
45
42
  }
46
43
  export class AdapterBuilder {
44
+ catchCb;
47
45
  handlers = new Map();
48
46
  collections = new Set();
47
+ constructor(catchCb = (e) => { console.log(e); }) {
48
+ this.catchCb = catchCb;
49
+ }
49
50
  register(op, collection, fn) {
50
51
  this.handlers.set(`${op}:${collection}`, fn);
51
52
  this.collections.add(collection);
52
53
  return this;
53
54
  }
55
+ add(collection, fn) {
56
+ return this.register("add", collection, fn);
57
+ }
58
+ find(collection, fn) {
59
+ return this.register("find", collection, fn);
60
+ }
61
+ findOne(collection, fn) {
62
+ return this.register("findOne", collection, fn);
63
+ }
64
+ update(collection, fn) {
65
+ return this.register("update", collection, fn);
66
+ }
67
+ updateOne(collection, fn) {
68
+ return this.register("updateOne", collection, fn);
69
+ }
70
+ updateOneOrAdd(collection, fn) {
71
+ return this.register("updateOneOrAdd", collection, fn);
72
+ }
73
+ remove(collection, fn) {
74
+ return this.register("remove", collection, fn);
75
+ }
76
+ removeOne(collection, fn) {
77
+ return this.register("removeOne", collection, fn);
78
+ }
79
+ removeCollection(collection, fn) {
80
+ return this.register("removeCollection", collection, fn);
81
+ }
54
82
  getAdapter(extendedFind = true) {
55
- const resolve = async (op, col, ...args) => {
83
+ const resolve = async (op, ...args) => {
84
+ const col = args.shift();
56
85
  const handler = this.handlers.get(`${op}:${col}`) || this.handlers.get(`${op}:*`) || null;
57
86
  if (!handler)
58
87
  throw new Error(`Unimplemented method: ${op}:${col}`);
59
- return handler(...args);
88
+ if (col === "*")
89
+ args.unshift(col);
90
+ try {
91
+ return await handler(...args);
92
+ }
93
+ catch (e) {
94
+ this.catchCb(e, op, args);
95
+ }
60
96
  };
61
97
  const adapter = createValtheraAdapter({
62
98
  getCollections: async () => Array.from(this.collections),
@@ -66,16 +102,10 @@ export class AdapterBuilder {
66
102
  this.collections.add(col);
67
103
  return true;
68
104
  },
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
105
  }, extendedFind);
106
+ for (const name of ["add", "find", "findOne", "update", "updateOne", "updateOneOrAdd", "remove", "removeOne", "removeCollection"]) {
107
+ adapter[name] = (...args) => resolve(name, ...args);
108
+ }
79
109
  return adapter;
80
110
  }
81
111
  }
@@ -13,14 +13,14 @@ export async function executeQuery(cpu, query, user) {
13
13
  const select = parseSelect(cpu.config, params.fields || params.select || {});
14
14
  if (select && typeof select === "object" && Object.keys(select).length !== 0)
15
15
  params.searchOpts = { ...params.searchOpts, select };
16
- return db.find(params.collection, params.search, {}, params.options || {}, params.searchOpts);
16
+ return db.find(params.collection, params.search, params.options || {}, params.searchOpts);
17
17
  }
18
18
  else if (operation === "findOne" || operation === "f") {
19
19
  const params = query.d[operation];
20
20
  const select = parseSelect(cpu.config, params.fields || params.select || {});
21
21
  if (select && typeof select === "object" && Object.keys(select).length !== 0)
22
22
  params.searchOpts = { ...params.searchOpts, select };
23
- return db.findOne(params.collection, params.search, {}, params.searchOpts);
23
+ return db.findOne(params.collection, params.search, params.searchOpts);
24
24
  }
25
25
  else if (operation === "add") {
26
26
  const params = query.d[operation];
@@ -44,7 +44,12 @@ export async function executeQuery(cpu, query, user) {
44
44
  }
45
45
  else if (operation === "updateOneOrAdd") {
46
46
  const params = query.d[operation];
47
- return db.updateOneOrAdd(params.collection, params.search, params.updater, params.add_arg || {}, {}, params.id_gen ?? true);
47
+ const opts = {};
48
+ if (params.add_arg)
49
+ opts.add_arg = params.add_arg;
50
+ if (params.id_gen)
51
+ opts.id_gen = params.id_gen;
52
+ return db.updateOneOrAdd(params.collection, params.search, params.updater, opts);
48
53
  }
49
54
  else if (operation === "removeCollection") {
50
55
  const params = query.d[operation];
package/dist/gw.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export function createGwValidFn(gw) {
2
- return async (path, perm, user) => {
3
- return gw.hasAccess(user.id, path, perm);
2
+ return async (args) => {
3
+ return gw.hasAccess(args.user.id, args.field, args.p);
4
4
  };
5
5
  }
@@ -3,30 +3,35 @@ import { extractPathsFromData, hashKey } from "./utils.js";
3
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
- const checkPermissionRecursively = async (entityId, fallbackLevels = []) => {
6
+ const checkPermissionRecursively = async (entityId, originalPath, 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 permValidFn(entityId, PermCRUD.READ, user);
9
+ const result = await permValidFn({
10
+ field: entityId,
11
+ path: originalPath,
12
+ p: PermCRUD.READ,
13
+ user
14
+ });
10
15
  if (result.granted) {
11
16
  return true;
12
17
  }
13
18
  // If the result is "entity-404", check the next fallback level
14
19
  if (!config.strictACL && result.via === "entity-404" && fallbackLevels.length > 0) {
15
20
  const nextFallbackEntityId = await hashKey(config, fallbackLevels.slice(0, -1));
16
- return checkPermissionRecursively(nextFallbackEntityId, fallbackLevels.slice(0, -2));
21
+ return checkPermissionRecursively(nextFallbackEntityId, fallbackLevels.slice(0, -2), fallbackLevels.slice(0, -2));
17
22
  }
18
23
  // If no fallback levels are left or the result is not "entity-404", deny access
19
24
  return false;
20
25
  };
21
26
  // Check permission for the relation field in the parent collection
22
- if (!await checkPermissionRecursively(await hashKey(config, path), path)) {
27
+ if (!await checkPermissionRecursively(await hashKey(config, path), path, path)) {
23
28
  return false;
24
29
  }
25
30
  // Check permissions for search fields
26
31
  const searchPaths = extractPathsFromData(search || {});
27
32
  for (const searchPath of searchPaths) {
28
33
  const key = [...path, ...searchPath.path, searchPath.key];
29
- if (!await checkPermissionRecursively(await hashKey(config, key), key)) {
34
+ if (!await checkPermissionRecursively(await hashKey(config, key), key, key)) {
30
35
  return false;
31
36
  }
32
37
  }
@@ -34,7 +39,7 @@ export async function checkRelationPermission(config, permValidFn, user, query)
34
39
  if (select) {
35
40
  for (const fieldPath of select) {
36
41
  const key = [...path, fieldPath];
37
- if (!await checkPermissionRecursively(await hashKey(config, key), key)) {
42
+ if (!await checkPermissionRecursively(await hashKey(config, key), key, key)) {
38
43
  return false;
39
44
  }
40
45
  }
@@ -41,14 +41,15 @@ export async function extractPaths(config, query) {
41
41
  permPaths.paths.push({ c: PermCRUD.COLLECTION });
42
42
  break;
43
43
  }
44
- permPaths.paths = permPaths.paths.map(path => {
44
+ permPaths.paths = (await Promise.all(permPaths.paths.map(async (path) => {
45
45
  if (!path.filed)
46
46
  return path;
47
- return path.filed.map(filed => {
47
+ return await Promise.all(path.filed.map(async (filed) => {
48
48
  const processedPath = [query.db, collection, ...processFieldPath(filed)];
49
- return { filed: hashKey(config, processedPath), path: processedPath, p: path.p };
50
- });
51
- }).flat();
49
+ const hashedKey = await hashKey(config, processedPath);
50
+ return { filed: hashedKey, path: processedPath, p: path.p };
51
+ }));
52
+ }))).flat();
52
53
  return permPaths;
53
54
  }
54
55
  export function processFieldPath(pathObj) {
@@ -84,17 +85,22 @@ export async function checkRequestPermission(config, permValidFn, user, query) {
84
85
  return false;
85
86
  const permPaths = await extractPaths(config, query);
86
87
  // Helper function to recursively check permissions
87
- const checkPermissionRecursively = async (entityId, requiredPerm, fallbackLevels = []) => {
88
+ const checkPermissionRecursively = async (entityId, originalPath, requiredPerm, fallbackLevels = []) => {
88
89
  // Check if the user has access to the current entity
89
90
  // const result = await gw.hasAccess(user.id, entityId, requiredPerm);
90
- const result = await permValidFn(entityId, requiredPerm, user);
91
+ const result = await permValidFn({
92
+ field: entityId,
93
+ path: originalPath,
94
+ p: requiredPerm,
95
+ user
96
+ });
91
97
  if (result.granted) {
92
98
  return true;
93
99
  }
94
100
  // If the result is "entity-404", check the next fallback level
95
101
  if (!config.strictACL && result.via === "entity-404" && fallbackLevels.length > 0) {
96
102
  const nextFallbackEntityId = await hashKey(config, fallbackLevels.slice(0, -1));
97
- return checkPermissionRecursively(nextFallbackEntityId, requiredPerm, fallbackLevels.slice(0, -2));
103
+ return checkPermissionRecursively(nextFallbackEntityId, fallbackLevels.slice(0, -2), requiredPerm, fallbackLevels.slice(0, -2));
98
104
  }
99
105
  // If no fallback levels are left or the result is not "entity-404", deny access
100
106
  return false;
@@ -105,10 +111,12 @@ export async function checkRequestPermission(config, permValidFn, user, query) {
105
111
  let entityId;
106
112
  let requiredPerm;
107
113
  let fallbackLevels = [];
114
+ let originalPath = [];
108
115
  if ("c" in path) {
109
116
  // Collection-level permission: hash the combination of db and collection
110
117
  entityId = await hashKey(config, [query.db, permPaths.c]);
111
118
  requiredPerm = path.c;
119
+ originalPath = [query.db, permPaths.c];
112
120
  // Fallback to database level if needed
113
121
  fallbackLevels = [query.db];
114
122
  }
@@ -116,11 +124,12 @@ export async function checkRequestPermission(config, permValidFn, user, query) {
116
124
  // Field-level permission: use the hashed field path
117
125
  entityId = path.filed;
118
126
  requiredPerm = path.p;
127
+ originalPath = path.path;
119
128
  // Fallback to collection and then database level if needed
120
129
  fallbackLevels = path.path;
121
130
  }
122
131
  // Check permissions recursively
123
- const result = await checkPermissionRecursively(entityId, requiredPerm, fallbackLevels);
132
+ const result = await checkPermissionRecursively(entityId, originalPath, requiredPerm, fallbackLevels);
124
133
  results.push(result);
125
134
  }
126
135
  // All permissions must be granted
@@ -0,0 +1,9 @@
1
+ import { PathMatcher, PermissionResolver } from "../types/resolver.js";
2
+ import { PermValidFn } from "../types/perm.js";
3
+ import { GateWarden } from "@wxn0brp/gate-warden";
4
+ export declare class PermissionResolverEngine {
5
+ private resolvers;
6
+ addResolver(matcher: PathMatcher, resolver: PermissionResolver): void;
7
+ create(): PermValidFn;
8
+ createWithGw(gw: GateWarden): PermValidFn;
9
+ }
@@ -0,0 +1,46 @@
1
+ export class PermissionResolverEngine {
2
+ resolvers = [];
3
+ addResolver(matcher, resolver) {
4
+ this.resolvers.push({ matcher, resolver });
5
+ }
6
+ create() {
7
+ return async (args) => {
8
+ const originalPath = args.path.join("/");
9
+ for (const { matcher, resolver } of this.resolvers) {
10
+ let isMatch = false;
11
+ if (typeof matcher === "string") {
12
+ isMatch = originalPath === matcher;
13
+ }
14
+ else if (matcher instanceof RegExp) {
15
+ isMatch = matcher.test(originalPath);
16
+ }
17
+ else if (typeof matcher === "function") {
18
+ isMatch = await matcher(originalPath, args.path);
19
+ }
20
+ if (isMatch) {
21
+ try {
22
+ const resolverGranted = await resolver(args);
23
+ return { granted: resolverGranted, via: `resolver` };
24
+ }
25
+ catch (error) {
26
+ console.error(`[Resolver Engine] Error in custom resolver for path ${originalPath}:`, error);
27
+ return { granted: false, via: `resolver-error` };
28
+ }
29
+ }
30
+ }
31
+ return { granted: false, via: `no-resolver-match` };
32
+ };
33
+ }
34
+ createWithGw(gw) {
35
+ const resolver = this.create();
36
+ return async (args) => {
37
+ const resolverResult = await resolver(args);
38
+ if (resolverResult.granted)
39
+ return resolverResult;
40
+ if (!resolverResult.granted && resolverResult.via !== `no-resolver-match`)
41
+ return resolverResult;
42
+ const gwResult = await gw.hasAccess(args.user.id, args.field, args.p);
43
+ return { granted: gwResult.granted, via: `gate-warden` };
44
+ };
45
+ }
46
+ }
@@ -9,4 +9,13 @@ export interface ValidFnResult {
9
9
  granted: boolean;
10
10
  via?: string;
11
11
  }
12
- export type PermValidFn = (path: string, perm: number, user: any) => Promise<ValidFnResult>;
12
+ export interface PermValidFnArgs {
13
+ /** sha256/json */
14
+ field: string;
15
+ /** original path */
16
+ path: string[];
17
+ /** permission */
18
+ p: number;
19
+ user: any;
20
+ }
21
+ export type PermValidFn = (args: PermValidFnArgs) => Promise<ValidFnResult>;
@@ -0,0 +1,14 @@
1
+ import { PermValidFnArgs } from "./perm.js";
2
+ export interface GWUser {
3
+ _id: string;
4
+ }
5
+ export type PathMatcher = string | RegExp | ((path: string, pathSegments: string[]) => Promise<boolean>);
6
+ export type PermissionResolver = (args: PermValidFnArgs) => Promise<boolean>;
7
+ export interface ResolverEntry {
8
+ matcher: PathMatcher;
9
+ resolver: PermissionResolver;
10
+ }
11
+ export interface ResolverValidFnResult {
12
+ granted: boolean;
13
+ via: string;
14
+ }
@@ -0,0 +1 @@
1
+ export {};
package/dist/vql.d.ts CHANGED
@@ -119,11 +119,11 @@ declare class CollectionManager<D = Data> {
119
119
  /**
120
120
  * Find data in a database.
121
121
  */
122
- find<T = Data>(search?: Search<T & D>, context?: VContext, options?: DbFindOpts<T & Data>, findOpts?: FindOpts<T & Data>): Promise<T[]>;
122
+ find<T = Data>(search?: Search<T & D>, options?: DbFindOpts<T & Data>, findOpts?: FindOpts<T & Data>, context?: VContext): Promise<T[]>;
123
123
  /**
124
124
  * Find one data entry in a database.
125
125
  */
126
- findOne<T = Data>(search?: Search<T & Data>, context?: VContext, findOpts?: FindOpts<T & Data>): Promise<T>;
126
+ findOne<T = Data>(search?: Search<T & Data>, findOpts?: FindOpts<T & Data>, context?: VContext): Promise<T>;
127
127
  /**
128
128
  * Update data in a database.
129
129
  */
@@ -143,7 +143,7 @@ declare class CollectionManager<D = Data> {
143
143
  /**
144
144
  * Asynchronously updates one entry in a database or adds a new one if it doesn't exist.
145
145
  */
146
- updateOneOrAdd<T = Data>(search: Search<T & Data>, updater: Updater<T & Data>, add_arg?: Arg<T & Data>, context?: VContext, id_gen?: boolean): Promise<boolean>;
146
+ updateOneOrAdd<T = Data>(search: Search<T & Data>, updater: Updater<T & Data>, { add_arg, context, id_gen }: UpdateOneOrAdd<T & Data>): Promise<boolean>;
147
147
  }
148
148
  export interface ValtheraCompatible {
149
149
  c(collection: string): CollectionManager;
@@ -151,14 +151,19 @@ export interface ValtheraCompatible {
151
151
  ensureCollection(collection: string): Promise<boolean>;
152
152
  issetCollection(collection: string): Promise<boolean>;
153
153
  add<T = Data>(collection: string, data: Arg<T>, id_gen?: boolean): Promise<T>;
154
- find<T = Data>(collection: string, search: Search<T>, context?: VContext, options?: DbFindOpts<T>, findOpts?: FindOpts<T>): Promise<T[]>;
155
- findOne<T = Data>(collection: string, search: Search<T>, context?: VContext, findOpts?: FindOpts<T>): Promise<T | null>;
154
+ find<T = Data>(collection: string, search?: Search<T>, options?: DbFindOpts<T>, findOpts?: FindOpts<T>, context?: VContext): Promise<T[]>;
155
+ findOne<T = Data>(collection: string, search?: Search<T>, findOpts?: FindOpts<T>, context?: VContext): Promise<T | null>;
156
156
  update<T = Data>(collection: string, search: Search<T>, updater: Updater<T>, context?: VContext): Promise<boolean>;
157
157
  updateOne<T = Data>(collection: string, search: Search<T>, updater: Updater<T>, context?: VContext): Promise<boolean>;
158
158
  remove<T = Data>(collection: string, search: Search<T>, context?: VContext): Promise<boolean>;
159
159
  removeOne<T = Data>(collection: string, search: Search<T>, context?: VContext): Promise<boolean>;
160
160
  removeCollection(collection: string): Promise<boolean>;
161
- updateOneOrAdd<T = Data>(collection: string, search: Search<T>, updater: Updater<T>, add_arg?: Arg<T>, context?: VContext, id_gen?: boolean): Promise<boolean>;
161
+ updateOneOrAdd<T = Data>(collection: string, search: Search<T>, updater: Updater<T>, opts?: UpdateOneOrAdd<T>): Promise<boolean>;
162
+ }
163
+ export interface UpdateOneOrAdd<T> {
164
+ add_arg?: Arg<T>;
165
+ id_gen?: boolean;
166
+ context?: VContext;
162
167
  }
163
168
  declare namespace RelationTypes {
164
169
  type Path = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wxn0brp/vql",
3
- "version": "0.6.3",
3
+ "version": "0.7.0",
4
4
  "main": "dist/index.js",
5
5
  "author": "wxn0brP",
6
6
  "license": "MIT",
@@ -15,8 +15,8 @@
15
15
  "dist"
16
16
  ],
17
17
  "peerDependencies": {
18
- "@wxn0brp/db-core": ">=0.1.4",
19
- "@wxn0brp/falcon-frame": ">=0.0.20",
18
+ "@wxn0brp/db-core": ">=0.2.2",
19
+ "@wxn0brp/falcon-frame": ">=0.1.0",
20
20
  "@wxn0brp/gate-warden": ">=0.4.0"
21
21
  },
22
22
  "peerDependenciesMeta": {
@@ -31,13 +31,13 @@
31
31
  }
32
32
  },
33
33
  "devDependencies": {
34
- "@types/node": "^24.3.0",
35
- "@wxn0brp/db": "^0.30.0",
36
- "@wxn0brp/falcon-frame": "0.0.21",
34
+ "@types/node": "*",
35
+ "@wxn0brp/db": "^0.40.0",
36
+ "@wxn0brp/falcon-frame": "0.1.0",
37
37
  "@wxn0brp/gate-warden": "^0.4.0",
38
- "esbuild": "^0.25.9",
39
- "tsc-alias": "^1.8.10",
40
- "typescript": "^5.9.2"
38
+ "esbuild": "^0.25.10",
39
+ "tsc-alias": "*",
40
+ "typescript": "*"
41
41
  },
42
42
  "dependencies": {
43
43
  "@wxn0brp/lucerna-log": "^0.2.0"