@wxn0brp/db-core 0.2.12 → 0.3.0-alpha.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.
@@ -14,34 +14,34 @@ declare class CollectionManager<D = Data> {
14
14
  /**
15
15
  * Find data in a database.
16
16
  */
17
- find<T = Data>(search?: Search<T & D>, options?: DbFindOpts<T & Data>, findOpts?: FindOpts<T & Data>, context?: VContext): Promise<T[]>;
17
+ find<T = Data>(search?: Search<T & D>, options?: DbFindOpts<T & D>, findOpts?: FindOpts<T & D>, context?: VContext): Promise<T[]>;
18
18
  /**
19
19
  * Find one data entry in a database.
20
20
  */
21
- findOne<T = Data>(search?: Search<T & Data>, findOpts?: FindOpts<T & Data>, context?: VContext): Promise<T>;
21
+ findOne<T = Data>(search?: Search<T & D>, findOpts?: FindOpts<T & D>, context?: VContext): Promise<T>;
22
22
  /**
23
23
  * Update data in a database.
24
24
  */
25
- update<T = Data>(search: Search<T & Data>, updater: Updater<T & Data>, context?: VContext): Promise<boolean>;
25
+ update<T = Data>(search: Search<T & D>, updater: Updater<T & D>, context?: VContext): Promise<boolean>;
26
26
  /**
27
27
  * Update one data entry in a database.
28
28
  */
29
- updateOne<T = Data>(search: Search<T & Data>, updater: Updater<T & Data>, context?: VContext): Promise<boolean>;
29
+ updateOne<T = Data>(search: Search<T & D>, updater: Updater<T & D>, context?: VContext): Promise<boolean>;
30
30
  /**
31
31
  * Remove data from a database.
32
32
  */
33
- remove<T = Data>(search: Search<T & Data>, context?: VContext): Promise<boolean>;
33
+ remove<T = Data>(search: Search<T & D>, context?: VContext): Promise<boolean>;
34
34
  /**
35
35
  * Remove one data entry from a database.
36
36
  */
37
- removeOne<T = Data>(search: Search<T & Data>, context?: VContext): Promise<boolean>;
37
+ removeOne<T = Data>(search: Search<T & D>, context?: VContext): Promise<boolean>;
38
38
  /**
39
39
  * Asynchronously updates one entry in a database or adds a new one if it doesn't exist.
40
40
  */
41
- updateOneOrAdd<T = Data>(search: Search<T & Data>, updater: Updater<T & Data>, { add_arg, context, id_gen }: UpdateOneOrAdd<T & Data>): Promise<boolean>;
41
+ updateOneOrAdd<T = Data>(search: Search<T & D>, updater: Updater<T & D>, { add_arg, context, id_gen }: UpdateOneOrAdd<T & D>): Promise<boolean>;
42
42
  /**
43
43
  * Asynchronously removes one entry in a database or adds a new one if it doesn't exist. Usage e.g. for toggling a flag.
44
44
  */
45
- toggleOne<T = Data>(search: Search<T & Data>, data?: Arg<T & Data>, context?: VContext): Promise<boolean>;
45
+ toggleOne<T = Data>(search: Search<T & D>, data?: Arg<T & D>, context?: VContext): Promise<boolean>;
46
46
  }
47
47
  export default CollectionManager;
@@ -9,7 +9,7 @@ export interface DbOpts {
9
9
  }
10
10
  export interface DbFindOpts<T = any> {
11
11
  reverse?: boolean;
12
- max?: number;
12
+ limit?: number;
13
13
  offset?: number;
14
14
  sortBy?: KeysMatching<T, any>;
15
15
  sortAsc?: boolean;
@@ -1,11 +1,4 @@
1
- /**
2
- * Predefined Search Options Quick Reference
3
- *
4
- * This module defines the types and structures for search operators used
5
- * to validate and query data objects.
6
- */
7
- import { Arg } from "./arg.js";
8
- import { PartialOfType, PartialPickMatching } from "./utils.js";
1
+ import { DeepPartial, NestedValue } from "./utils.js";
9
2
  /** Logical Operators */
10
3
  export type LogicalOperators<T = any> = {
11
4
  /**
@@ -24,44 +17,68 @@ export type LogicalOperators<T = any> = {
24
17
  */
25
18
  $not?: SearchOptions<T>;
26
19
  };
27
- /** Comparison Operators */
20
+ /** Comparison Operators with nested support */
28
21
  export type ComparisonOperators<T = any> = {
29
- $gt?: PartialOfType<T, number>;
30
- $lt?: PartialOfType<T, number>;
31
- $gte?: PartialOfType<T, number>;
32
- $lte?: PartialOfType<T, number>;
33
- $between?: PartialOfType<T, [number, number], number>;
34
- $in?: Partial<Record<keyof T, T[keyof T][]>>;
35
- $nin?: Partial<Record<keyof T, T[keyof T][]>>;
36
- $idGt?: PartialOfType<T, string | number>;
37
- $idLt?: PartialOfType<T, string | number>;
38
- $idGte?: PartialOfType<T, string | number>;
39
- $idLte?: PartialOfType<T, string | number>;
22
+ /** 5 > 4 */
23
+ $gt?: NestedValue<T, number, number>;
24
+ /** 5 < 4 */
25
+ $lt?: NestedValue<T, number, number>;
26
+ /** 5 >= 4 */
27
+ $gte?: NestedValue<T, number, number>;
28
+ /** 5 <= 4 */
29
+ $lte?: NestedValue<T, number, number>;
30
+ /** 5 between [min, max] */
31
+ $between?: NestedValue<T, [number, number], number>;
32
+ /** 2 in [1, 2, 3] */
33
+ $in?: DeepPartial<T> & {
34
+ [K in keyof T]?: T[K] extends any[] ? T[K] : T[K][];
35
+ };
36
+ /** 5 not in [1, 2, 3] */
37
+ $nin?: DeepPartial<T> & {
38
+ [K in keyof T]?: T[K] extends any[] ? T[K] : T[K][];
39
+ };
40
+ /** id > 4 */
41
+ $idGt?: NestedValue<T, string | number, string | number>;
42
+ /** id < 4 */
43
+ $idLt?: NestedValue<T, string | number, string | number>;
44
+ /** id >= 4 */
45
+ $idGte?: NestedValue<T, string | number, string | number>;
46
+ /** id <= 4 */
47
+ $idLte?: NestedValue<T, string | number, string | number>;
40
48
  };
41
- /** Type and Existence Operators */
49
+ /** Type and Existence Operators with nested support */
42
50
  export type TypeAndExistenceOperators<T = any> = {
43
- $exists?: PartialOfType<T, boolean, any>;
44
- $type?: PartialOfType<T, string>;
51
+ /** "name" in { name: "John" } */
52
+ $exists?: NestedValue<T, boolean>;
53
+ /** "name" == "string" in { name: "John" } */
54
+ $type?: NestedValue<T, string>;
45
55
  };
46
- /** Array Operators */
56
+ /** Array Operators with nested support */
47
57
  export type ArrayOperators<T = any> = {
48
- $arrinc?: PartialPickMatching<T, any[]>;
49
- $arrincall?: PartialPickMatching<T, any[]>;
50
- $size?: PartialOfType<T, number>;
58
+ /** [1, 2, 3] includes 2 */
59
+ $arrinc?: DeepPartial<T>;
60
+ /** [1, 2, 3] array includes all elements e.g. [1, 2] */
61
+ $arrincall?: DeepPartial<T>;
62
+ /** [1, 2, 3] has size 3 */
63
+ $size?: NestedValue<T, number>;
51
64
  };
52
- /** String Operators */
65
+ /** String Operators with nested support */
53
66
  export type StringOperators<T = any> = {
54
- $regex?: PartialOfType<T, RegExp | string, string>;
55
- $startsWith?: PartialOfType<T, string>;
56
- $endsWith?: PartialOfType<T, string>;
67
+ /** "John" matches /oh/ */
68
+ $regex?: NestedValue<T, RegExp | string, string>;
69
+ /** "John" starts with "Jo" */
70
+ $startsWith?: NestedValue<T, string, string>;
71
+ /** "John" ends with "hn" */
72
+ $endsWith?: NestedValue<T, string, string>;
57
73
  };
58
- /** Other Operators */
74
+ /** Other Operators with nested support */
59
75
  export type OtherOperators<T = any> = {
60
- $subset?: Partial<Record<keyof T, T[keyof T]>>;
76
+ /** { $type: "name" } matches { $type: "name" } literally - Ignore $ operators */
77
+ $subset?: DeepPartial<T>;
61
78
  };
62
79
  /** Predefined Search Operators */
63
80
  export type PredefinedSearchOperators<T = any> = LogicalOperators<T> & ComparisonOperators<T> & TypeAndExistenceOperators<T> & ArrayOperators<T> & StringOperators<T> & OtherOperators<T>;
64
81
  /**
65
82
  * SearchOptions can be either a function or an object with predefined operators.
66
83
  */
67
- export type SearchOptions<T = any> = PredefinedSearchOperators<T> & Arg<T>;
84
+ export type SearchOptions<T = any> = PredefinedSearchOperators<T> & DeepPartial<T> & Record<string, any>;
@@ -1,7 +1 @@
1
- /**
2
- * Predefined Search Options Quick Reference
3
- *
4
- * This module defines the types and structures for search operators used
5
- * to validate and query data objects.
6
- */
7
1
  export {};
@@ -1,28 +1,37 @@
1
- /**
2
- * Predefined type for updating data.
3
- */
4
- import { Arg } from "./arg.js";
5
- import { PartialOfType } from "./utils.js";
1
+ import { DeepPartial, NestedValue } from "./utils.js";
6
2
  /** Arrays */
7
3
  export type ArrayUpdater<T = any> = {
8
- $push?: PartialOfType<T, any>;
9
- /** Pushes items into an array and removes duplicates */
10
- $pushset?: PartialOfType<T, any>;
11
- $pull?: PartialOfType<T, any>;
12
- $pullall?: PartialOfType<T, any>;
4
+ /** [1,2] -> $push 3 -> [1,2,3] */
5
+ $push?: NestedValue<T, any>;
6
+ /** [1,2] -> $pushset 2,3 -> [1,2,3] */
7
+ $pushset?: NestedValue<T, any>;
8
+ /** [1,2,3] -> $pull 2 -> [1,3] */
9
+ $pull?: NestedValue<T, any>;
10
+ /** [1,2,2,3] -> $pullall [2] -> [1,3] */
11
+ $pullall?: NestedValue<T, any>;
13
12
  };
14
13
  /** Objects */
15
14
  export type ObjectUpdater<T = any> = {
16
- $merge?: PartialOfType<T, any>;
17
- $deepMerge?: PartialOfType<T, any>;
15
+ /** { a: 1 } -> $merge { b: 2 } -> { a: 1, b: 2 } */
16
+ $merge?: NestedValue<T, any>;
17
+ /** { a: { x: 1 } } -> $deepMerge { a: { y: 2 } } -> { a: { x: 1, y: 2 } } */
18
+ $deepMerge?: NestedValue<T, any>;
18
19
  };
19
20
  /** Values */
20
21
  export type ValueUpdater<T = any> = {
21
- $inc?: PartialOfType<T, number>;
22
- $dec?: PartialOfType<T, number>;
23
- $unset?: PartialOfType<T, any>;
24
- $rename?: PartialOfType<T, any>;
25
- /** same as { name: value } */
26
- $set?: PartialOfType<T, any>;
22
+ /** { count: 1 } -> $inc 2 -> { count: 3 } */
23
+ $inc?: NestedValue<T, number>;
24
+ /** { count: 5 } -> $dec 2 -> { count: 3 } */
25
+ $dec?: NestedValue<T, number>;
26
+ /** { name: "John" } -> $unset "name" -> {} */
27
+ $unset?: NestedValue<T, any>;
28
+ /** { oldName: "value" } -> $rename "oldName" to "newName" -> { newName: "value" } */
29
+ $rename?: NestedValue<T, any>;
30
+ /**
31
+ * {} -> $set { name: "John" } -> { name: "John" }
32
+ *
33
+ * Note: same as { name: value }
34
+ */
35
+ $set?: NestedValue<T, any>;
27
36
  };
28
- export type UpdaterArg<T = any> = ArrayUpdater<T> & ObjectUpdater<T> & ValueUpdater<T> & Arg<T>;
37
+ export type UpdaterArg<T = any> = ArrayUpdater<T> & ObjectUpdater<T> & ValueUpdater<T> & DeepPartial<T> & Record<string, any>;
@@ -1,4 +1 @@
1
- /**
2
- * Predefined type for updating data.
3
- */
4
1
  export {};
@@ -3,3 +3,11 @@ export type KeysMatching<T, V, C = V> = {
3
3
  }[keyof T];
4
4
  export type PartialOfType<T, V, C = V> = Partial<Record<KeysMatching<T, V, C>, V>>;
5
5
  export type PartialPickMatching<T, V, C = V> = Partial<Pick<T, KeysMatching<T, V, C>>>;
6
+ /** Helper type for nested path values with type filtering */
7
+ export type NestedValue<T, V, C = V> = {
8
+ [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;
9
+ };
10
+ /** Helper type for nested path structure */
11
+ export type DeepPartial<T> = {
12
+ [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
13
+ };
@@ -1,7 +1,7 @@
1
1
  import { compareSafe } from "./compare.js";
2
2
  export async function findUtil(query, fileCpu, files) {
3
3
  const { search, context = {}, dbFindOpts = {}, findOpts = {} } = query;
4
- const { reverse = false, max = -1, offset = 0, sortBy, sortAsc = true } = dbFindOpts;
4
+ const { reverse = false, offset = 0, limit = -1, sortBy, sortAsc = true } = dbFindOpts;
5
5
  if (reverse && !sortBy)
6
6
  files.reverse();
7
7
  let datas = [];
@@ -21,18 +21,18 @@ export async function findUtil(query, fileCpu, files) {
21
21
  entries = entries.slice(remainingSkip);
22
22
  skippedEntries = offset;
23
23
  }
24
- if (max !== -1) {
25
- if (totalEntries + entries.length > max) {
26
- const remaining = max - totalEntries;
24
+ if (limit !== -1) {
25
+ if (totalEntries + entries.length > limit) {
26
+ const remaining = limit - totalEntries;
27
27
  entries = entries.slice(0, remaining);
28
- totalEntries = max;
28
+ totalEntries = limit;
29
29
  }
30
30
  else {
31
31
  totalEntries += entries.length;
32
32
  }
33
33
  }
34
34
  datas.push(...entries);
35
- if (max !== -1 && totalEntries >= max)
35
+ if (limit !== -1 && totalEntries >= limit)
36
36
  break;
37
37
  }
38
38
  else {
@@ -43,7 +43,7 @@ export async function findUtil(query, fileCpu, files) {
43
43
  const dir = sortAsc ? 1 : -1;
44
44
  datas.sort((a, b) => compareSafe(a[sortBy], b[sortBy]) * dir);
45
45
  const start = offset;
46
- const end = max !== -1 ? offset + max : undefined;
46
+ const end = limit !== -1 ? offset + limit : undefined;
47
47
  datas = datas.slice(start, end);
48
48
  }
49
49
  return datas;
@@ -15,14 +15,19 @@ export default function hasFieldsAdvanced(obj, fields) {
15
15
  if ("$or" in fields) {
16
16
  return fields["$or"].some((subFields) => hasFieldsAdvanced(obj, subFields));
17
17
  }
18
- // Check various conditions
19
- if (!checkConditions(obj, fields))
18
+ const $fields = {};
19
+ const subsetFields = {};
20
+ Object.keys(fields).forEach(key => {
21
+ if (key.startsWith("$"))
22
+ $fields[key.toLowerCase()] = fields[key];
23
+ else
24
+ subsetFields[key] = fields[key];
25
+ });
26
+ if (!checkConditions(obj, $fields))
20
27
  return false;
21
- const fieldsSubset = { ...fields };
22
- Object.keys(fieldsSubset).filter(key => key.startsWith("$")).forEach(key => delete fieldsSubset[key]);
23
- if (!Object.keys(fieldsSubset).length)
28
+ if (!Object.keys(subsetFields).length)
24
29
  return true;
25
- return hasFields(obj, fieldsSubset);
30
+ return hasFields(obj, subsetFields);
26
31
  }
27
32
  function checkConditions(obj, fields) {
28
33
  return (mainCheck(obj, fields) &&
@@ -57,15 +62,15 @@ function mainCheck(obj, fields) {
57
62
  return false;
58
63
  }
59
64
  },
60
- startsWith: (data, value) => typeof data === "string" && data.startsWith(value),
61
- endsWith: (data, value) => typeof data === "string" && data.endsWith(value),
65
+ startswith: (data, value) => typeof data === "string" && data.startsWith(value),
66
+ endswith: (data, value) => typeof data === "string" && data.endsWith(value),
62
67
  between: (data, [min, max]) => typeof data === "number" && data >= min && data <= max,
63
68
  arrinc: (data, values) => Array.isArray(data) && values.some((val) => data.includes(val)),
64
69
  arrincall: (data, values) => Array.isArray(data) && values.every((val) => data.includes(val)),
65
- idGt: (data, value) => compareIds(data, value) > 0,
66
- idLt: (data, value) => compareIds(data, value) < 0,
67
- idGte: (data, value) => compareIds(data, value) >= 0,
68
- idLte: (data, value) => compareIds(data, value) <= 0,
70
+ idgt: (data, value) => compareIds(data, value) > 0,
71
+ idlt: (data, value) => compareIds(data, value) < 0,
72
+ idgte: (data, value) => compareIds(data, value) >= 0,
73
+ idlte: (data, value) => compareIds(data, value) <= 0,
69
74
  });
70
75
  }
71
76
  function checkNot(obj, fields) {
@@ -86,10 +91,33 @@ function _for(fields, obj, opts) {
86
91
  const field = "$" + fieldRaw;
87
92
  if (field in fields) {
88
93
  for (const [key, value] of Object.entries(fields[field])) {
89
- if (!fieldFn(obj?.[key], value, key))
90
- return false;
94
+ const targetValue = obj?.[key];
95
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
96
+ if (!deepCheck(value, targetValue, fieldFn))
97
+ return false;
98
+ }
99
+ else {
100
+ if (!fieldFn(targetValue, value, key))
101
+ return false;
102
+ }
91
103
  }
92
104
  }
93
105
  }
94
106
  return true;
95
107
  }
108
+ function deepCheck(valueObj, targetObj, fieldFn) {
109
+ if (typeof targetObj !== "object" || targetObj === null)
110
+ return false;
111
+ for (const [k, v] of Object.entries(valueObj)) {
112
+ const targetValue = targetObj[k];
113
+ if (typeof v === "object" && v !== null && !Array.isArray(v)) {
114
+ if (!deepCheck(v, targetValue, fieldFn))
115
+ return false;
116
+ }
117
+ else {
118
+ if (!fieldFn(targetValue, v, k))
119
+ return false;
120
+ }
121
+ }
122
+ return true;
123
+ }
@@ -1 +1,2 @@
1
- export declare function deepMerge(target: any, source: any): any;
1
+ export declare function _deepMerge(target: Record<string, any>, ...sources: Record<string, any>[]): Record<string, any>;
2
+ export declare function deepMerge(target: Record<string, any>, ...sources: Record<string, any>[]): Record<string, any>;
@@ -1,22 +1,26 @@
1
- export function deepMerge(target, source) {
2
- const output = { ...target };
1
+ export function _deepMerge(target, ...sources) {
2
+ if (!sources.length)
3
+ return target;
4
+ const source = sources.shift();
5
+ if (!target)
6
+ target = {};
3
7
  if (isObject(target) && isObject(source)) {
4
8
  for (const key in source) {
5
- if (Object.prototype.hasOwnProperty.call(source, key)) {
6
- if (isObject(source[key])) {
7
- if (!target[key]) {
8
- output[key] = {};
9
- }
10
- output[key] = deepMerge(target[key], source[key]);
11
- }
12
- else {
13
- output[key] = source[key];
14
- }
9
+ if (isObject(source[key])) {
10
+ if (!target[key])
11
+ Object.assign(target, { [key]: {} });
12
+ _deepMerge(target[key], source[key]);
13
+ }
14
+ else {
15
+ Object.assign(target, { [key]: source[key] });
15
16
  }
16
17
  }
17
18
  }
18
- return output;
19
+ return _deepMerge(target, ...sources);
20
+ }
21
+ export function deepMerge(target, ...sources) {
22
+ return _deepMerge(structuredClone(target), ...sources.map(s => structuredClone(s)));
19
23
  }
20
24
  function isObject(item) {
21
- return item !== null && typeof item === "object" && !Array.isArray(item);
25
+ return (item && typeof item === "object" && !Array.isArray(item));
22
26
  }
@@ -4,4 +4,4 @@ import { UpdaterArg } from "../types/updater.js";
4
4
  * @param obj - The object to update.
5
5
  * @param field - An object containing new values to update in the target object.
6
6
  */
7
- export default function updateObjectAdvanced(obj: Object, field: UpdaterArg): Object;
7
+ export default function updateObjectAdvanced(obj: Record<string, any>, field: UpdaterArg): Record<string, any>;
@@ -1,4 +1,4 @@
1
- import { deepMerge } from "./merge.js";
1
+ import { _deepMerge } from "./merge.js";
2
2
  /**
3
3
  * Updates an object with new values.
4
4
  * @param obj - The object to update.
@@ -8,18 +8,30 @@ export default function updateObjectAdvanced(obj, field) {
8
8
  if (typeof field !== "object" || field === null) {
9
9
  throw new Error("Fields must be an object or object array");
10
10
  }
11
- if (typeof field !== "object" || field === null) {
12
- throw new Error("Fields must be an object or object array");
11
+ if (Object.keys(field).length === 0) {
12
+ return obj;
13
13
  }
14
- updateAdvanced(obj, field);
15
- const fieldsSubset = { ...field };
16
- Object.keys(fieldsSubset).filter(key => key.startsWith("$")).forEach(key => delete fieldsSubset[key]);
17
- updateObject(obj, fieldsSubset);
18
- return obj;
14
+ const newObj = structuredClone(obj);
15
+ const $fields = {};
16
+ const subsetFields = {};
17
+ Object.keys(field).forEach(key => {
18
+ if (key.startsWith("$"))
19
+ $fields[key.toLowerCase()] = field[key];
20
+ else
21
+ subsetFields[key] = field[key];
22
+ });
23
+ mainUpdate(newObj, $fields);
24
+ const mergedObj = deepMerge(newObj, $fields);
25
+ updateObject(mergedObj, subsetFields);
26
+ return mergedObj;
19
27
  }
20
- function updateAdvanced(obj, fields) {
21
- mainUpdate(obj, fields);
22
- updateUnset(obj, fields);
28
+ function deepMerge(obj, fields) {
29
+ if (!("$deepmerge" in fields))
30
+ return obj;
31
+ if (Object.keys(obj).length === 0)
32
+ return fields.$deepmerge;
33
+ _deepMerge(obj, fields.$deepmerge);
34
+ return obj;
23
35
  }
24
36
  function mainUpdate(obj, fields) {
25
37
  _for(fields, obj, {
@@ -30,7 +42,14 @@ function mainUpdate(obj, fields) {
30
42
  }
31
43
  return [updater];
32
44
  },
33
- pushSet: (item, updater) => {
45
+ pushall: (item, updater) => {
46
+ if (Array.isArray(item)) {
47
+ item.push(...updater);
48
+ return item;
49
+ }
50
+ return updater;
51
+ },
52
+ pushset: (item, updater) => {
34
53
  if (Array.isArray(item)) {
35
54
  item.push(updater);
36
55
  return [...new Set(item)];
@@ -47,47 +66,39 @@ function mainUpdate(obj, fields) {
47
66
  },
48
67
  merge: (item, updater) => {
49
68
  if (typeof item === "object" && typeof updater === "object") {
50
- return { ...item, ...updater };
51
- }
52
- return updater;
53
- },
54
- deepMerge: (item, updater) => {
55
- if (typeof item === "object" && typeof updater === "object") {
56
- return deepMerge(item, updater);
69
+ Object.assign(item, updater);
70
+ return item;
57
71
  }
58
72
  return updater;
59
73
  },
60
- inc: (item, updater, key) => {
74
+ inc: (item, updater, key, deepObj) => {
61
75
  if (typeof item === "number" && typeof updater === "number") {
62
76
  return item + updater;
63
77
  }
64
- if (!(key in obj))
78
+ if (!(key in deepObj))
65
79
  return updater;
66
80
  throw new Error(`Cannot increment non-numeric value at key: ${key}`);
67
81
  },
68
- dec: (item, updater, key) => {
82
+ dec: (item, updater, key, deepObj) => {
69
83
  if (typeof item === "number" && typeof updater === "number") {
70
84
  return item - updater;
71
85
  }
72
- if (!(key in obj))
86
+ if (!(key in deepObj))
73
87
  return -updater;
74
88
  throw new Error(`Cannot decrement non-numeric value at key: ${key}`);
75
89
  },
76
- rename: (_, newKey, oldKey) => {
77
- if (oldKey in obj) {
78
- obj[newKey] = obj[oldKey];
79
- delete obj[oldKey];
90
+ rename: (_, newKey, oldKey, deepObj) => {
91
+ if (oldKey in deepObj) {
92
+ deepObj[newKey] = deepObj[oldKey];
93
+ delete deepObj[oldKey];
80
94
  }
81
95
  },
82
- set: (_, value) => value
83
- });
84
- }
85
- function updateUnset(obj, fields) {
86
- if ("$unset" in fields) {
87
- for (const key of Object.keys(fields["$unset"])) {
88
- delete obj[key];
96
+ set: (_, value) => value,
97
+ unset: (_, __, key, deepObj) => {
98
+ if (key in deepObj)
99
+ delete deepObj[key];
89
100
  }
90
- }
101
+ });
91
102
  }
92
103
  /**
93
104
  * Updates an object with new values.
@@ -107,10 +118,31 @@ function _for(fields, obj, opts) {
107
118
  const field = "$" + fieldRaw;
108
119
  if (field in fields) {
109
120
  for (const [key, value] of Object.entries(fields[field])) {
110
- const res = fieldFn(obj?.[key], value, key);
111
- if (res !== undefined)
112
- obj[key] = res;
121
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
122
+ if (!obj[key])
123
+ obj[key] = {};
124
+ deepUpdateCheck(value, obj[key], fieldFn);
125
+ }
126
+ else {
127
+ const res = fieldFn(obj?.[key], value, key, obj);
128
+ if (res !== undefined)
129
+ obj[key] = res;
130
+ }
113
131
  }
114
132
  }
115
133
  }
116
134
  }
135
+ function deepUpdateCheck(valueObj, targetObj, fieldFn) {
136
+ for (const [k, v] of Object.entries(valueObj)) {
137
+ if (typeof v === "object" && v !== null && !Array.isArray(v)) {
138
+ if (!targetObj[k])
139
+ targetObj[k] = {};
140
+ deepUpdateCheck(v, targetObj[k], fieldFn);
141
+ }
142
+ else {
143
+ const res = fieldFn(targetObj[k], v, k, targetObj);
144
+ if (res !== undefined)
145
+ targetObj[k] = res;
146
+ }
147
+ }
148
+ }
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = "0.2.12";
1
+ export const version = "0.3.0-alpha.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wxn0brp/db-core",
3
- "version": "0.2.12",
3
+ "version": "0.3.0-alpha.0",
4
4
  "types": "dist/index.d.ts",
5
5
  "main": "dist/index.js",
6
6
  "author": "wxn0brP",