@wxn0brp/db-core 0.2.11 → 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.
- package/dist/helpers/CollectionManager.d.ts +11 -7
- package/dist/helpers/CollectionManager.js +6 -0
- package/dist/types/options.d.ts +1 -1
- package/dist/types/searchOpts.d.ts +51 -34
- package/dist/types/searchOpts.js +0 -6
- package/dist/types/updater.d.ts +28 -19
- package/dist/types/updater.js +0 -3
- package/dist/types/utils.d.ts +8 -0
- package/dist/utils/action.js +7 -7
- package/dist/utils/hasFieldsAdvanced.js +42 -14
- package/dist/utils/merge.d.ts +2 -1
- package/dist/utils/merge.js +18 -14
- package/dist/utils/updateObject.d.ts +1 -1
- package/dist/utils/updateObject.js +70 -38
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -14,30 +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 &
|
|
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 &
|
|
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 &
|
|
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 &
|
|
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 &
|
|
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 &
|
|
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 &
|
|
41
|
+
updateOneOrAdd<T = Data>(search: Search<T & D>, updater: Updater<T & D>, { add_arg, context, id_gen }: UpdateOneOrAdd<T & D>): Promise<boolean>;
|
|
42
|
+
/**
|
|
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
|
+
*/
|
|
45
|
+
toggleOne<T = Data>(search: Search<T & D>, data?: Arg<T & D>, context?: VContext): Promise<boolean>;
|
|
42
46
|
}
|
|
43
47
|
export default CollectionManager;
|
|
@@ -53,5 +53,11 @@ class CollectionManager {
|
|
|
53
53
|
async updateOneOrAdd(search, updater, { add_arg = {}, context = {}, id_gen = true }) {
|
|
54
54
|
return await this.db.updateOneOrAdd(this.collection, search, updater, { add_arg, context, id_gen });
|
|
55
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Asynchronously removes one entry in a database or adds a new one if it doesn't exist. Usage e.g. for toggling a flag.
|
|
58
|
+
*/
|
|
59
|
+
async toggleOne(search, data = {}, context = {}) {
|
|
60
|
+
return await this.db.toggleOne(this.collection, search, data, context);
|
|
61
|
+
}
|
|
56
62
|
}
|
|
57
63
|
export default CollectionManager;
|
package/dist/types/options.d.ts
CHANGED
|
@@ -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
|
-
|
|
30
|
-
$
|
|
31
|
-
|
|
32
|
-
$
|
|
33
|
-
|
|
34
|
-
$
|
|
35
|
-
|
|
36
|
-
$
|
|
37
|
-
|
|
38
|
-
$
|
|
39
|
-
|
|
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
|
-
|
|
44
|
-
$
|
|
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
|
-
|
|
49
|
-
$
|
|
50
|
-
|
|
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
|
-
|
|
55
|
-
$
|
|
56
|
-
|
|
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
|
-
$
|
|
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> &
|
|
84
|
+
export type SearchOptions<T = any> = PredefinedSearchOperators<T> & DeepPartial<T> & Record<string, any>;
|
package/dist/types/searchOpts.js
CHANGED
package/dist/types/updater.d.ts
CHANGED
|
@@ -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
|
|
9
|
-
|
|
10
|
-
$pushset
|
|
11
|
-
$
|
|
12
|
-
$
|
|
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
|
|
17
|
-
$
|
|
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
|
|
22
|
-
$
|
|
23
|
-
$
|
|
24
|
-
$
|
|
25
|
-
/**
|
|
26
|
-
$
|
|
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> &
|
|
37
|
+
export type UpdaterArg<T = any> = ArrayUpdater<T> & ObjectUpdater<T> & ValueUpdater<T> & DeepPartial<T> & Record<string, any>;
|
package/dist/types/updater.js
CHANGED
package/dist/types/utils.d.ts
CHANGED
|
@@ -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
|
+
};
|
package/dist/utils/action.js
CHANGED
|
@@ -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,
|
|
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 (
|
|
25
|
-
if (totalEntries + entries.length >
|
|
26
|
-
const remaining =
|
|
24
|
+
if (limit !== -1) {
|
|
25
|
+
if (totalEntries + entries.length > limit) {
|
|
26
|
+
const remaining = limit - totalEntries;
|
|
27
27
|
entries = entries.slice(0, remaining);
|
|
28
|
-
totalEntries =
|
|
28
|
+
totalEntries = limit;
|
|
29
29
|
}
|
|
30
30
|
else {
|
|
31
31
|
totalEntries += entries.length;
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
datas.push(...entries);
|
|
35
|
-
if (
|
|
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 =
|
|
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
|
-
|
|
19
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
61
|
-
|
|
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
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
90
|
-
|
|
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
|
+
}
|
package/dist/utils/merge.d.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export declare function
|
|
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>;
|
package/dist/utils/merge.js
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
1
|
-
export function
|
|
2
|
-
|
|
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 (
|
|
6
|
-
if (
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
|
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
|
|
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:
|
|
7
|
+
export default function updateObjectAdvanced(obj: Record<string, any>, field: UpdaterArg): Record<string, any>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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 (
|
|
12
|
-
|
|
11
|
+
if (Object.keys(field).length === 0) {
|
|
12
|
+
return obj;
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
78
|
-
|
|
79
|
-
delete
|
|
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
|
-
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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.
|
|
1
|
+
export const version = "0.3.0-alpha.0";
|