feathers-utils 2.0.0-0 → 2.0.0-2
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 +16 -9
- package/dist/esm/filters/array.d.ts +2 -0
- package/dist/esm/filters/array.js +10 -0
- package/dist/esm/hooks/checkMulti.d.ts +2 -2
- package/dist/esm/hooks/createRelated.d.ts +3 -0
- package/dist/esm/hooks/createRelated.js +26 -0
- package/dist/esm/hooks/onDelete.d.ts +3 -0
- package/dist/esm/hooks/onDelete.js +40 -0
- package/dist/esm/hooks/removeRelated.d.ts +3 -0
- package/dist/esm/hooks/removeRelated.js +30 -0
- package/dist/esm/hooks/runPerItem.d.ts +2 -3
- package/dist/esm/hooks/runPerItem.js +6 -6
- package/dist/esm/hooks/setData.d.ts +2 -3
- package/dist/esm/hooks/setData.js +13 -8
- package/dist/esm/index.d.ts +8 -2
- package/dist/esm/index.js +8 -1
- package/dist/esm/mixins/debounce-mixin/DebouncedStore.d.ts +1 -1
- package/dist/esm/mixins/debounce-mixin/DebouncedStore.js +1 -1
- package/dist/esm/mixins/debounce-mixin/index.d.ts +1 -1
- package/dist/esm/types.d.ts +35 -16
- package/dist/esm/utils/filterQuery.d.ts +2 -2
- package/dist/esm/utils/filterQuery.js +9 -7
- package/dist/esm/utils/getItemsIsArray.d.ts +3 -0
- package/dist/esm/utils/getItemsIsArray.js +18 -0
- package/dist/esm/utils/getPaginate.d.ts +1 -1
- package/dist/esm/utils/isPaginated.d.ts +1 -1
- package/dist/esm/utils/markHookForSkip.d.ts +2 -2
- package/dist/esm/utils/mergeQuery/index.js +18 -7
- package/dist/esm/utils/pushSet.d.ts +1 -1
- package/dist/esm/utils/pushSet.js +3 -3
- package/dist/esm/utils/setResultEmpty.d.ts +1 -1
- package/dist/esm/utils/validateQueryProperty.d.ts +2 -0
- package/dist/esm/utils/validateQueryProperty.js +20 -0
- package/dist/filters/array.d.ts +2 -0
- package/dist/filters/array.js +14 -0
- package/dist/hooks/checkMulti.d.ts +2 -2
- package/dist/hooks/createRelated.d.ts +3 -0
- package/dist/hooks/createRelated.js +39 -0
- package/dist/hooks/onDelete.d.ts +3 -0
- package/dist/hooks/onDelete.js +53 -0
- package/dist/hooks/removeRelated.d.ts +3 -0
- package/dist/hooks/removeRelated.js +43 -0
- package/dist/hooks/runPerItem.d.ts +2 -3
- package/dist/hooks/runPerItem.js +6 -6
- package/dist/hooks/setData.d.ts +2 -3
- package/dist/hooks/setData.js +17 -12
- package/dist/index.d.ts +8 -2
- package/dist/index.js +21 -4
- package/dist/mixins/debounce-mixin/DebouncedStore.d.ts +1 -1
- package/dist/mixins/debounce-mixin/DebouncedStore.js +2 -2
- package/dist/mixins/debounce-mixin/index.d.ts +1 -1
- package/dist/types.d.ts +35 -16
- package/dist/utils/filterQuery.d.ts +2 -2
- package/dist/utils/filterQuery.js +19 -6
- package/dist/utils/getItemsIsArray.d.ts +3 -0
- package/dist/utils/getItemsIsArray.js +22 -0
- package/dist/utils/getPaginate.d.ts +1 -1
- package/dist/utils/isPaginated.d.ts +1 -1
- package/dist/utils/markHookForSkip.d.ts +2 -2
- package/dist/utils/mergeQuery/index.js +53 -42
- package/dist/utils/pushSet.d.ts +1 -1
- package/dist/utils/pushSet.js +6 -6
- package/dist/utils/setResultEmpty.d.ts +1 -1
- package/dist/utils/validateQueryProperty.d.ts +2 -0
- package/dist/utils/validateQueryProperty.js +22 -0
- package/package.json +33 -19
- package/src/filters/array.ts +14 -0
- package/src/hooks/checkMulti.ts +3 -1
- package/src/hooks/createRelated.ts +45 -0
- package/src/hooks/onDelete.ts +56 -0
- package/src/hooks/removeRelated.ts +42 -0
- package/src/hooks/runPerItem.ts +9 -12
- package/src/hooks/setData.ts +17 -12
- package/src/index.ts +11 -1
- package/src/mixins/debounce-mixin/DebouncedStore.ts +49 -49
- package/src/mixins/debounce-mixin/index.ts +6 -3
- package/src/types.ts +46 -16
- package/src/utils/filterQuery.ts +15 -14
- package/src/utils/getItemsIsArray.ts +23 -0
- package/src/utils/getPaginate.ts +1 -2
- package/src/utils/isMulti.ts +3 -1
- package/src/utils/isPaginated.ts +1 -1
- package/src/utils/markHookForSkip.ts +2 -2
- package/src/utils/mergeQuery/index.ts +20 -8
- package/src/utils/pushSet.ts +3 -3
- package/src/utils/setResultEmpty.ts +1 -1
- package/src/utils/shouldSkip.ts +4 -1
- package/src/utils/validateQueryProperty.ts +27 -0
- package/.eslintignore +0 -3
- package/.eslintrc.js +0 -44
- package/.gitlab-ci.yml +0 -11
- package/.mocharc.js +0 -11
- package/.nycrc.json +0 -22
- package/index.js +0 -9
- package/tsconfig-esm.json +0 -9
- package/tsconfig.json +0 -16
- package/tsconfig.test.json +0 -13
|
@@ -4,13 +4,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.mergeQuery = void 0;
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
7
|
+
const get_js_1 = __importDefault(require("lodash/get.js"));
|
|
8
|
+
const has_js_1 = __importDefault(require("lodash/has.js"));
|
|
9
|
+
const isEmpty_js_1 = __importDefault(require("lodash/isEmpty.js"));
|
|
10
|
+
const isEqual_js_1 = __importDefault(require("lodash/isEqual.js"));
|
|
11
|
+
const merge_js_1 = __importDefault(require("lodash/merge.js"));
|
|
12
|
+
const set_js_1 = __importDefault(require("lodash/set.js"));
|
|
13
|
+
const uniqWith_js_1 = __importDefault(require("lodash/uniqWith.js"));
|
|
14
14
|
const mergeArrays_1 = require("./mergeArrays");
|
|
15
15
|
const filterQuery_1 = require("../filterQuery");
|
|
16
16
|
const errors_1 = require("@feathersjs/errors");
|
|
@@ -18,14 +18,14 @@ const hasOwnProperty = (obj, key) => {
|
|
|
18
18
|
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
19
19
|
};
|
|
20
20
|
function handleArray(target, source, key, options) {
|
|
21
|
-
const targetVal = (0,
|
|
22
|
-
const sourceVal = (0,
|
|
21
|
+
const targetVal = (0, get_js_1.default)(target, key);
|
|
22
|
+
const sourceVal = (0, get_js_1.default)(source, key);
|
|
23
23
|
if (!sourceVal && !targetVal) {
|
|
24
24
|
return;
|
|
25
25
|
}
|
|
26
|
-
const handle = (0,
|
|
26
|
+
const handle = (0, get_js_1.default)(options, ["handle", ...key], options.defaultHandle);
|
|
27
27
|
const arr = (0, mergeArrays_1.mergeArrays)(targetVal, sourceVal, handle, key, options.actionOnEmptyIntersect);
|
|
28
|
-
(0,
|
|
28
|
+
(0, set_js_1.default)(target, key, arr);
|
|
29
29
|
}
|
|
30
30
|
function handleCircular(target, source, prependKey, options) {
|
|
31
31
|
if (target === null || target === void 0 ? void 0 : target.$or) {
|
|
@@ -52,11 +52,11 @@ function handleCircular(target, source, prependKey, options) {
|
|
|
52
52
|
delete source.$and;
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
|
-
if (!(0,
|
|
55
|
+
if (!(0, has_js_1.default)(source, prependKey)) {
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
|
-
if (!(0,
|
|
59
|
-
(0,
|
|
58
|
+
if (!(0, has_js_1.default)(target, prependKey)) {
|
|
59
|
+
(0, set_js_1.default)(target, prependKey, (0, get_js_1.default)(source, prependKey));
|
|
60
60
|
return;
|
|
61
61
|
}
|
|
62
62
|
const { defaultHandle, actionOnEmptyIntersect } = options;
|
|
@@ -64,22 +64,22 @@ function handleCircular(target, source, prependKey, options) {
|
|
|
64
64
|
return;
|
|
65
65
|
}
|
|
66
66
|
const getTargetVal = () => {
|
|
67
|
-
return (prependKey.length > 0) ? (0,
|
|
67
|
+
return (prependKey.length > 0) ? (0, get_js_1.default)(target, prependKey) : target;
|
|
68
68
|
};
|
|
69
69
|
const getSourceVal = () => {
|
|
70
|
-
return (prependKey.length > 0) ? (0,
|
|
70
|
+
return (prependKey.length > 0) ? (0, get_js_1.default)(source, prependKey) : source;
|
|
71
71
|
};
|
|
72
72
|
const targetVal = getTargetVal();
|
|
73
73
|
const sourceVal = getSourceVal();
|
|
74
|
-
if ((0,
|
|
74
|
+
if ((0, isEqual_js_1.default)(targetVal, sourceVal)) {
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
77
|
if (defaultHandle === "source") {
|
|
78
|
-
(0,
|
|
78
|
+
(0, set_js_1.default)(target, prependKey, sourceVal);
|
|
79
79
|
return;
|
|
80
80
|
}
|
|
81
81
|
if (targetVal === null || sourceVal === null) {
|
|
82
|
-
(0,
|
|
82
|
+
(0, set_js_1.default)(target, prependKey, sourceVal);
|
|
83
83
|
return;
|
|
84
84
|
}
|
|
85
85
|
const typeOfTargetVal = typeof targetVal;
|
|
@@ -87,7 +87,7 @@ function handleCircular(target, source, prependKey, options) {
|
|
|
87
87
|
if (defaultHandle === "intersect") {
|
|
88
88
|
actionOnEmptyIntersect(target, source, prependKey);
|
|
89
89
|
}
|
|
90
|
-
(0,
|
|
90
|
+
(0, set_js_1.default)(target, prependKey, sourceVal);
|
|
91
91
|
return;
|
|
92
92
|
}
|
|
93
93
|
const typeOfSourceVal = typeof sourceVal;
|
|
@@ -96,7 +96,7 @@ function handleCircular(target, source, prependKey, options) {
|
|
|
96
96
|
if (isTargetSimple || isSourceSimple) {
|
|
97
97
|
if (isTargetSimple && isSourceSimple) {
|
|
98
98
|
if (defaultHandle === "combine") {
|
|
99
|
-
(0,
|
|
99
|
+
(0, set_js_1.default)(target, prependKey, { $in: [...new Set([targetVal, sourceVal])] });
|
|
100
100
|
return;
|
|
101
101
|
}
|
|
102
102
|
else if (defaultHandle === "intersect") {
|
|
@@ -110,20 +110,20 @@ function handleCircular(target, source, prependKey, options) {
|
|
|
110
110
|
const targetHasIn = hasOwnProperty(targetVal, "$in");
|
|
111
111
|
const $in = (targetHasIn) ? targetVal["$in"] : sourceVal["$in"];
|
|
112
112
|
const otherVal = (isTargetSimple) ? targetVal : sourceVal;
|
|
113
|
-
if ($in.length === 1 && (0,
|
|
114
|
-
(0,
|
|
113
|
+
if ($in.length === 1 && (0, isEqual_js_1.default)($in[0], otherVal)) {
|
|
114
|
+
(0, set_js_1.default)(target, prependKey, otherVal);
|
|
115
115
|
return;
|
|
116
116
|
}
|
|
117
117
|
else if (defaultHandle === "combine") {
|
|
118
|
-
if (!$in.some((x) => (0,
|
|
118
|
+
if (!$in.some((x) => (0, isEqual_js_1.default)(x, otherVal))) {
|
|
119
119
|
$in.push(otherVal);
|
|
120
120
|
}
|
|
121
|
-
(0,
|
|
121
|
+
(0, set_js_1.default)(target, `${prependKey}.$in`, $in);
|
|
122
122
|
return;
|
|
123
123
|
}
|
|
124
124
|
else if (defaultHandle === "intersect") {
|
|
125
|
-
if ($in.some((x) => (0,
|
|
126
|
-
(0,
|
|
125
|
+
if ($in.some((x) => (0, isEqual_js_1.default)(x, otherVal))) {
|
|
126
|
+
(0, set_js_1.default)(target, prependKey, otherVal);
|
|
127
127
|
}
|
|
128
128
|
else {
|
|
129
129
|
actionOnEmptyIntersect(target, source, prependKey);
|
|
@@ -139,7 +139,7 @@ function handleCircular(target, source, prependKey, options) {
|
|
|
139
139
|
const key = prependKey[prependKey.length - 1];
|
|
140
140
|
if (key === "$or") {
|
|
141
141
|
if (defaultHandle === "combine") {
|
|
142
|
-
const newVals = sourceVal.filter((x) => !targetVal.some((y) => (0,
|
|
142
|
+
const newVals = sourceVal.filter((x) => !targetVal.some((y) => (0, isEqual_js_1.default)(x, y)));
|
|
143
143
|
targetVal.push(...newVals);
|
|
144
144
|
}
|
|
145
145
|
else if (defaultHandle === "intersect") {
|
|
@@ -176,7 +176,7 @@ function handleCircular(target, source, prependKey, options) {
|
|
|
176
176
|
return;
|
|
177
177
|
}
|
|
178
178
|
else if (defaultHandle === "intersect") {
|
|
179
|
-
const newVals = sourceVal.filter((x) => !targetVal.some((y) => (0,
|
|
179
|
+
const newVals = sourceVal.filter((x) => !targetVal.some((y) => (0, isEqual_js_1.default)(x, y)));
|
|
180
180
|
targetVal.push(...newVals);
|
|
181
181
|
return;
|
|
182
182
|
}
|
|
@@ -185,29 +185,29 @@ function handleCircular(target, source, prependKey, options) {
|
|
|
185
185
|
if (defaultHandle === "combine") {
|
|
186
186
|
let $in = targetVal.concat(sourceVal);
|
|
187
187
|
$in = [...new Set($in)];
|
|
188
|
-
(0,
|
|
188
|
+
(0, set_js_1.default)(target, prependKey, $in);
|
|
189
189
|
return;
|
|
190
190
|
}
|
|
191
191
|
else if (defaultHandle === "intersect") {
|
|
192
|
-
const $in = targetVal.filter((x) => sourceVal.some((y) => (0,
|
|
192
|
+
const $in = targetVal.filter((x) => sourceVal.some((y) => (0, isEqual_js_1.default)(x, y)));
|
|
193
193
|
if ($in.length === 0) {
|
|
194
194
|
actionOnEmptyIntersect(target, source, prependKey);
|
|
195
195
|
}
|
|
196
196
|
else if ($in.length === 1) {
|
|
197
|
-
(0,
|
|
197
|
+
(0, set_js_1.default)(target, prependKey.slice(0, -1), $in[0]);
|
|
198
198
|
return;
|
|
199
199
|
}
|
|
200
200
|
else {
|
|
201
|
-
(0,
|
|
201
|
+
(0, set_js_1.default)(target, prependKey, $in);
|
|
202
202
|
}
|
|
203
203
|
}
|
|
204
204
|
return;
|
|
205
205
|
}
|
|
206
|
-
(0,
|
|
206
|
+
(0, set_js_1.default)(target, prependKey, sourceVal);
|
|
207
207
|
return;
|
|
208
208
|
}
|
|
209
209
|
if (typeOfTargetVal !== "object" || typeOfSourceVal !== "object") {
|
|
210
|
-
(0,
|
|
210
|
+
(0, set_js_1.default)(target, prependKey, sourceVal);
|
|
211
211
|
return;
|
|
212
212
|
}
|
|
213
213
|
// both are objects
|
|
@@ -233,12 +233,21 @@ function makeDefaultOptions(options) {
|
|
|
233
233
|
}
|
|
234
234
|
return options;
|
|
235
235
|
}
|
|
236
|
+
function moveProperty(source, target, key) {
|
|
237
|
+
if (!Object.prototype.hasOwnProperty.call(source, key)) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
target[key] = source[key];
|
|
241
|
+
delete source[key];
|
|
242
|
+
}
|
|
236
243
|
function mergeQuery(target, source, options) {
|
|
237
244
|
const fullOptions = makeDefaultOptions(options);
|
|
238
245
|
const { filters: targetFilters, query: targetQuery } = (0, filterQuery_1.filterQuery)(target, {
|
|
239
246
|
operators: fullOptions.operators,
|
|
240
247
|
service: fullOptions.service
|
|
241
248
|
});
|
|
249
|
+
moveProperty(targetFilters, targetQuery, "$or");
|
|
250
|
+
moveProperty(targetFilters, targetQuery, "$and");
|
|
242
251
|
if (target.$limit) {
|
|
243
252
|
targetFilters.$limit = target.$limit;
|
|
244
253
|
}
|
|
@@ -248,6 +257,8 @@ function mergeQuery(target, source, options) {
|
|
|
248
257
|
operators: fullOptions.operators,
|
|
249
258
|
service: fullOptions.service
|
|
250
259
|
});
|
|
260
|
+
moveProperty(sourceFilters, sourceQuery, "$or");
|
|
261
|
+
moveProperty(sourceFilters, sourceQuery, "$and");
|
|
251
262
|
if (source.$limit) {
|
|
252
263
|
sourceFilters.$limit = source.$limit;
|
|
253
264
|
}
|
|
@@ -265,13 +276,13 @@ function mergeQuery(target, source, options) {
|
|
|
265
276
|
handleArray(targetFilters, sourceFilters, ["$select"], fullOptions);
|
|
266
277
|
// remaining filters
|
|
267
278
|
delete sourceFilters["$select"];
|
|
268
|
-
(0,
|
|
279
|
+
(0, merge_js_1.default)(targetFilters, sourceFilters);
|
|
269
280
|
//#endregion
|
|
270
281
|
//#region '$or' / '$and'
|
|
271
282
|
if ((options === null || options === void 0 ? void 0 : options.useLogicalConjunction) &&
|
|
272
283
|
(options.defaultHandle === "combine" ||
|
|
273
284
|
options.defaultHandle === "intersect") &&
|
|
274
|
-
!(0,
|
|
285
|
+
!(0, isEmpty_js_1.default)(targetQuery)) {
|
|
275
286
|
const logicalOp = (options.defaultHandle === "combine")
|
|
276
287
|
? "$or"
|
|
277
288
|
: "$and";
|
|
@@ -301,13 +312,13 @@ function getParentProp(target, path) {
|
|
|
301
312
|
return target;
|
|
302
313
|
}
|
|
303
314
|
const pathOneUp = path.slice(0, -1);
|
|
304
|
-
return (0,
|
|
315
|
+
return (0, get_js_1.default)(target, pathOneUp);
|
|
305
316
|
}
|
|
306
317
|
function cleanOr(target) {
|
|
307
318
|
if (!target || !Array.isArray(target) || target.length <= 0) {
|
|
308
319
|
return target;
|
|
309
320
|
}
|
|
310
|
-
if (target.some(x => (0,
|
|
321
|
+
if (target.some(x => (0, isEmpty_js_1.default)(x))) {
|
|
311
322
|
return undefined;
|
|
312
323
|
}
|
|
313
324
|
else {
|
|
@@ -318,11 +329,11 @@ function cleanAnd(target) {
|
|
|
318
329
|
if (!target || !Array.isArray(target) || target.length <= 0) {
|
|
319
330
|
return target;
|
|
320
331
|
}
|
|
321
|
-
if (target.every(x => (0,
|
|
332
|
+
if (target.every(x => (0, isEmpty_js_1.default)(x))) {
|
|
322
333
|
return undefined;
|
|
323
334
|
}
|
|
324
335
|
else {
|
|
325
|
-
target = target.filter(x => !(0,
|
|
336
|
+
target = target.filter(x => !(0, isEmpty_js_1.default)(x));
|
|
326
337
|
return arrayWithoutDuplicates(target);
|
|
327
338
|
}
|
|
328
339
|
}
|
|
@@ -330,5 +341,5 @@ function arrayWithoutDuplicates(target) {
|
|
|
330
341
|
if (!target || !Array.isArray(target)) {
|
|
331
342
|
return target;
|
|
332
343
|
}
|
|
333
|
-
return (0,
|
|
344
|
+
return (0, uniqWith_js_1.default)(target, isEqual_js_1.default);
|
|
334
345
|
}
|
package/dist/utils/pushSet.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { Path, PushSetOptions } from "../types";
|
|
2
|
-
export declare const pushSet: (obj: Record<string, unknown>, path: string | Path, val: unknown, options?: PushSetOptions
|
|
2
|
+
export declare const pushSet: (obj: Record<string, unknown>, path: string | Path, val: unknown, options?: PushSetOptions) => unknown[];
|
package/dist/utils/pushSet.js
CHANGED
|
@@ -4,19 +4,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.pushSet = void 0;
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
7
|
+
const isEqual_js_1 = __importDefault(require("lodash/isEqual.js"));
|
|
8
|
+
const get_js_1 = __importDefault(require("lodash/get.js"));
|
|
9
|
+
const set_js_1 = __importDefault(require("lodash/set.js"));
|
|
10
10
|
const pushSet = (obj, path, val, options) => {
|
|
11
11
|
options = options || {};
|
|
12
|
-
let arr = (0,
|
|
12
|
+
let arr = (0, get_js_1.default)(obj, path);
|
|
13
13
|
if (!arr || !Array.isArray(arr)) {
|
|
14
14
|
arr = [val];
|
|
15
|
-
(0,
|
|
15
|
+
(0, set_js_1.default)(obj, path, arr);
|
|
16
16
|
return arr;
|
|
17
17
|
}
|
|
18
18
|
else {
|
|
19
|
-
if (options.unique && arr.some(x => (0,
|
|
19
|
+
if (options.unique && arr.some(x => (0, isEqual_js_1.default)(x, val))) {
|
|
20
20
|
return arr;
|
|
21
21
|
}
|
|
22
22
|
arr.push(val);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { HookContext } from "@feathersjs/feathers";
|
|
1
|
+
import type { HookContext } from "@feathersjs/feathers";
|
|
2
2
|
export declare const setResultEmpty: (context: HookContext) => HookContext;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateQueryProperty = void 0;
|
|
4
|
+
const commons_1 = require("@feathersjs/commons");
|
|
5
|
+
const errors_1 = require("@feathersjs/errors");
|
|
6
|
+
const isPlainObject = (value) => commons_1._.isObject(value) && value.constructor === {}.constructor;
|
|
7
|
+
const validateQueryProperty = (query, operators = []) => {
|
|
8
|
+
if (!isPlainObject(query)) {
|
|
9
|
+
return query;
|
|
10
|
+
}
|
|
11
|
+
for (const key of Object.keys(query)) {
|
|
12
|
+
if (key.startsWith("$") && !operators.includes(key)) {
|
|
13
|
+
throw new errors_1.BadRequest(`Invalid query parameter ${key}`, query);
|
|
14
|
+
}
|
|
15
|
+
const value = query[key];
|
|
16
|
+
if (isPlainObject(value)) {
|
|
17
|
+
query[key] = (0, exports.validateQueryProperty)(value, operators);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return Object.assign({}, query);
|
|
21
|
+
};
|
|
22
|
+
exports.validateQueryProperty = validateQueryProperty;
|
package/package.json
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "feathers-utils",
|
|
3
|
-
"version": "2.0.0-
|
|
3
|
+
"version": "2.0.0-2",
|
|
4
4
|
"description": "Some utils for projects using '@feathersjs/feathers'",
|
|
5
5
|
"author": "fratzinger",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "https://github.com/fratzinger/feathers-utils"
|
|
9
9
|
},
|
|
10
|
+
"engines": {
|
|
11
|
+
"node": ">= 14"
|
|
12
|
+
},
|
|
10
13
|
"homepage": "https://github.com/fratzinger/feathers-utils",
|
|
11
14
|
"license": "MIT",
|
|
12
15
|
"main": "dist/",
|
|
@@ -21,6 +24,14 @@
|
|
|
21
24
|
"directories": {
|
|
22
25
|
"dist": "dist"
|
|
23
26
|
},
|
|
27
|
+
"files": [
|
|
28
|
+
"CHANGELOG.md",
|
|
29
|
+
"LICENSE",
|
|
30
|
+
"README.md",
|
|
31
|
+
"src/**",
|
|
32
|
+
"lib/**",
|
|
33
|
+
"dist/**"
|
|
34
|
+
],
|
|
24
35
|
"scripts": {
|
|
25
36
|
"build": "shx rm -rf dist/ && npm run tsc",
|
|
26
37
|
"tsc": "tsc -p tsconfig.json && tsc -p tsconfig-esm.json",
|
|
@@ -31,29 +42,32 @@
|
|
|
31
42
|
"lint": "eslint . --ext .js,.jsx,.ts,.tsx"
|
|
32
43
|
},
|
|
33
44
|
"dependencies": {
|
|
34
|
-
"@feathersjs/adapter-commons": "5.0.0-pre.
|
|
35
|
-
"@feathersjs/errors": "5.0.0-pre.
|
|
36
|
-
"@feathersjs/feathers": "5.0.0-pre.
|
|
37
|
-
"feathers-hooks-common": "^
|
|
45
|
+
"@feathersjs/adapter-commons": "5.0.0-pre.29",
|
|
46
|
+
"@feathersjs/errors": "5.0.0-pre.29",
|
|
47
|
+
"@feathersjs/feathers": "5.0.0-pre.29",
|
|
48
|
+
"feathers-hooks-common": "^6.1.5",
|
|
38
49
|
"lodash": "^4.17.21",
|
|
39
|
-
"type-fest": "^2.
|
|
50
|
+
"type-fest": "^2.19.0"
|
|
40
51
|
},
|
|
41
52
|
"devDependencies": {
|
|
42
|
-
"@
|
|
43
|
-
"@
|
|
44
|
-
"@types/
|
|
45
|
-
"@types/
|
|
46
|
-
"@
|
|
47
|
-
"@typescript-eslint/
|
|
53
|
+
"@feathersjs/memory": "^5.0.0-pre.20",
|
|
54
|
+
"@istanbuljs/nyc-config-typescript": "^1.0.2",
|
|
55
|
+
"@types/lodash": "^4.14.185",
|
|
56
|
+
"@types/mocha": "^9.1.1",
|
|
57
|
+
"@types/node": "^18.7.18",
|
|
58
|
+
"@typescript-eslint/eslint-plugin": "^5.37.0",
|
|
59
|
+
"@typescript-eslint/parser": "^5.37.0",
|
|
48
60
|
"cross-env": "^7.0.3",
|
|
49
|
-
"eslint": "^
|
|
50
|
-
"eslint-
|
|
61
|
+
"eslint": "^8.23.1",
|
|
62
|
+
"eslint-import-resolver-typescript": "^3.5.1",
|
|
63
|
+
"eslint-plugin-import": "^2.26.0",
|
|
64
|
+
"eslint-plugin-security": "^1.5.0",
|
|
51
65
|
"feathers-memory": "^4.1.0",
|
|
52
|
-
"mocha": "^
|
|
53
|
-
"np": "^7.
|
|
66
|
+
"mocha": "^10.0.0",
|
|
67
|
+
"np": "^7.6.2",
|
|
54
68
|
"nyc": "^15.1.0",
|
|
55
|
-
"shx": "^0.3.
|
|
56
|
-
"ts-node": "^9.1
|
|
57
|
-
"typescript": "^4.
|
|
69
|
+
"shx": "^0.3.4",
|
|
70
|
+
"ts-node": "^10.9.1",
|
|
71
|
+
"typescript": "^4.8.3"
|
|
58
72
|
}
|
|
59
73
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { FilterQueryOptions } from "@feathersjs/adapter-commons";
|
|
2
|
+
import { validateQueryProperty } from "../utils/validateQueryProperty";
|
|
3
|
+
|
|
4
|
+
export const filterArray = () => (arr: any, { operators }: FilterQueryOptions) => {
|
|
5
|
+
if (arr && !Array.isArray(arr)) {
|
|
6
|
+
throw new Error("Invalid query parameter $and. It has to be an array");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
if (Array.isArray(arr)) {
|
|
10
|
+
return arr.map((current) => validateQueryProperty(current, operators));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return arr;
|
|
14
|
+
};
|
package/src/hooks/checkMulti.ts
CHANGED
|
@@ -3,8 +3,10 @@ import { shouldSkip } from "../utils/shouldSkip";
|
|
|
3
3
|
import { isMulti } from "../utils/isMulti";
|
|
4
4
|
|
|
5
5
|
import type { HookContext } from "@feathersjs/feathers";
|
|
6
|
+
import type { ReturnSyncHook } from "../types";
|
|
6
7
|
|
|
7
|
-
export function checkMulti(
|
|
8
|
+
export function checkMulti(
|
|
9
|
+
): ReturnSyncHook {
|
|
8
10
|
return (context: HookContext): HookContext => {
|
|
9
11
|
if (shouldSkip("checkMulti", context)) { return context; }
|
|
10
12
|
const { service, method } = context;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { HookContext } from "@feathersjs/feathers";
|
|
2
|
+
import { checkContext } from "feathers-hooks-common";
|
|
3
|
+
import type { CreateRelatedOptions } from "../types";
|
|
4
|
+
import { getItemsIsArray } from "../utils/getItemsIsArray";
|
|
5
|
+
|
|
6
|
+
export function createRelated<S = Record<string, any>>({
|
|
7
|
+
service,
|
|
8
|
+
multi = true,
|
|
9
|
+
data,
|
|
10
|
+
createItemsInDataArraySeparately = true
|
|
11
|
+
}: CreateRelatedOptions<S>) {
|
|
12
|
+
if (!service || !data) {
|
|
13
|
+
throw "initialize hook 'createRelated' completely!";
|
|
14
|
+
}
|
|
15
|
+
return async (context: HookContext): Promise<HookContext> => {
|
|
16
|
+
// @ts-expect-error wait for feathers-hooks-common to update
|
|
17
|
+
checkContext(context, "after", undefined, "createRelated");
|
|
18
|
+
|
|
19
|
+
const { items } = getItemsIsArray(context);
|
|
20
|
+
|
|
21
|
+
let dataToCreate = (await Promise.all(
|
|
22
|
+
items.map(async item => data(item, context))
|
|
23
|
+
)).filter(x => !!x);
|
|
24
|
+
|
|
25
|
+
if (createItemsInDataArraySeparately) {
|
|
26
|
+
dataToCreate = dataToCreate.flat();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!dataToCreate || dataToCreate.length <= 0) {
|
|
30
|
+
return context;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (multi) {
|
|
34
|
+
await context.app.service(service as string).create(dataToCreate);
|
|
35
|
+
} else {
|
|
36
|
+
await Promise.all(
|
|
37
|
+
dataToCreate.map(async item =>
|
|
38
|
+
context.app.service(service as string).create(item)
|
|
39
|
+
)
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return context;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { HookContext } from "@feathersjs/feathers";
|
|
2
|
+
import { checkContext } from "feathers-hooks-common";
|
|
3
|
+
import type { OnDeleteOptions } from "../types";
|
|
4
|
+
import { getItemsIsArray } from "../utils/getItemsIsArray";
|
|
5
|
+
|
|
6
|
+
export function onDelete<S = Record<string, any>>(
|
|
7
|
+
service: keyof S,
|
|
8
|
+
{
|
|
9
|
+
keyThere,
|
|
10
|
+
keyHere = "id",
|
|
11
|
+
onDelete = "cascade",
|
|
12
|
+
blocking = true
|
|
13
|
+
}: OnDeleteOptions) {
|
|
14
|
+
if (!service || !keyThere) {
|
|
15
|
+
throw "initialize hook 'removeRelated' completely!";
|
|
16
|
+
}
|
|
17
|
+
if (!["cascade", "set null"].includes(onDelete)) {
|
|
18
|
+
throw "onDelete must be 'cascade' or 'set null'";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return async (context: HookContext): Promise<HookContext> => {
|
|
22
|
+
// @ts-expect-error wait for feathers-hooks-common to update
|
|
23
|
+
checkContext(context, "after", "remove", "onDelete");
|
|
24
|
+
|
|
25
|
+
const { items } = getItemsIsArray(context);
|
|
26
|
+
|
|
27
|
+
let ids = items.map(x => x[keyHere]).filter(x => !!x);
|
|
28
|
+
ids = [...new Set(ids)];
|
|
29
|
+
|
|
30
|
+
if (!ids || ids.length <= 0) { return context; }
|
|
31
|
+
|
|
32
|
+
const params = {
|
|
33
|
+
query: {
|
|
34
|
+
[keyThere]: {
|
|
35
|
+
$in: ids
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
paginate: false
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
let promise;
|
|
42
|
+
|
|
43
|
+
if (onDelete === "cascade") {
|
|
44
|
+
promise = context.app.service(service as string).remove(null, params);
|
|
45
|
+
} else if (onDelete === "set null") {
|
|
46
|
+
const data = { [keyThere]: null };
|
|
47
|
+
promise = context.app.service(service as string).patch(null, data, params);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (blocking) {
|
|
51
|
+
await promise;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return context;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { HookContext, Params, Query } from "@feathersjs/feathers";
|
|
2
|
+
import { checkContext } from "feathers-hooks-common";
|
|
3
|
+
import type { RemoveRelatedOptions } from "../types";
|
|
4
|
+
import { getItemsIsArray } from "../utils/getItemsIsArray";
|
|
5
|
+
|
|
6
|
+
export function removeRelated<S = Record<string, any>>({
|
|
7
|
+
service,
|
|
8
|
+
keyThere,
|
|
9
|
+
keyHere = "id",
|
|
10
|
+
blocking = true
|
|
11
|
+
}: RemoveRelatedOptions<S>) {
|
|
12
|
+
if (!service || !keyThere) {
|
|
13
|
+
throw "initialize hook 'removeRelated' completely!";
|
|
14
|
+
}
|
|
15
|
+
return async (context: HookContext): Promise<HookContext> => {
|
|
16
|
+
// @ts-expect-error wait for feathers-hooks-common to update
|
|
17
|
+
checkContext(context, "after", "remove", "removeRelated");
|
|
18
|
+
|
|
19
|
+
const { items } = getItemsIsArray(context);
|
|
20
|
+
|
|
21
|
+
let ids = items.map(x => x[keyHere]).filter(x => !!x);
|
|
22
|
+
ids = [...new Set(ids)];
|
|
23
|
+
|
|
24
|
+
if (!ids || ids.length <= 0) { return context; }
|
|
25
|
+
|
|
26
|
+
// feathers does not accept `paginate: false` for remove, but some adapters need it to work properly
|
|
27
|
+
const promise: Promise<any> = context.app.service(service as string).remove(null, {
|
|
28
|
+
query: {
|
|
29
|
+
[keyThere]: {
|
|
30
|
+
$in: ids
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
paginate: false
|
|
34
|
+
} as Params<Query>);
|
|
35
|
+
|
|
36
|
+
if (blocking) {
|
|
37
|
+
await promise;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return context;
|
|
41
|
+
};
|
|
42
|
+
}
|
package/src/hooks/runPerItem.ts
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import { getItems } from "feathers-hooks-common";
|
|
2
|
-
|
|
3
1
|
import { shouldSkip } from "../utils/shouldSkip";
|
|
4
2
|
|
|
5
|
-
import type { HookRunPerItemOptions } from "../types";
|
|
3
|
+
import type { HookRunPerItemOptions, ReturnAsyncHook, Promisable } from "../types";
|
|
6
4
|
import type { HookContext } from "@feathersjs/feathers";
|
|
7
|
-
import
|
|
5
|
+
import { getItemsIsArray } from "../utils/getItemsIsArray";
|
|
8
6
|
|
|
9
7
|
const makeOptions = (
|
|
10
|
-
options
|
|
8
|
+
options?: HookRunPerItemOptions
|
|
11
9
|
): Required<HookRunPerItemOptions> => {
|
|
12
10
|
options = options || {};
|
|
13
11
|
return Object.assign({
|
|
@@ -16,16 +14,15 @@ const makeOptions = (
|
|
|
16
14
|
};
|
|
17
15
|
|
|
18
16
|
export const runPerItem = (
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19
18
|
actionPerItem: (item: any, context: HookContext) => Promisable<any>,
|
|
20
|
-
|
|
21
|
-
):
|
|
22
|
-
options = makeOptions(
|
|
19
|
+
_options?: HookRunPerItemOptions
|
|
20
|
+
): ReturnAsyncHook => {
|
|
21
|
+
const options = makeOptions(_options);
|
|
23
22
|
return async (context: HookContext): Promise<HookContext> => {
|
|
24
23
|
if (shouldSkip("runForItems", context)) { return context; }
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
let items = getItems(context);
|
|
28
|
-
items = (Array.isArray(items)) ? items : [items];
|
|
24
|
+
|
|
25
|
+
const { items } = getItemsIsArray(context);
|
|
29
26
|
|
|
30
27
|
const promises = items.map(async (item: unknown) => {
|
|
31
28
|
await actionPerItem(item, context);
|