feathers-utils 2.0.0 → 2.1.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/index.cjs +103 -57
- package/dist/index.d.ts +8 -1
- package/dist/index.mjs +103 -57
- package/package.json +2 -1
- package/src/hooks/runPerItem.ts +4 -6
- package/src/hooks/setData.ts +4 -5
- package/src/utils/getPaginate.ts +2 -1
- package/src/utils/internal.utils.ts +6 -0
- package/src/utils/mergeQuery/mergeQuery.ts +62 -25
- package/src/utils/mergeQuery/utils.ts +82 -29
package/dist/index.cjs
CHANGED
|
@@ -5,10 +5,11 @@ const _merge = require('lodash/merge.js');
|
|
|
5
5
|
const _isEmpty = require('lodash/isEmpty.js');
|
|
6
6
|
const _get = require('lodash/get.js');
|
|
7
7
|
const _has = require('lodash/has.js');
|
|
8
|
-
const _isEqual = require('lodash/isEqual.js');
|
|
9
8
|
const _set = require('lodash/set.js');
|
|
10
9
|
const _uniqWith = require('lodash/uniqWith.js');
|
|
10
|
+
const fastEquals = require('fast-equals');
|
|
11
11
|
const adapterCommons = require('@feathersjs/adapter-commons');
|
|
12
|
+
const _isEqual = require('lodash/isEqual.js');
|
|
12
13
|
const commons = require('@feathersjs/commons');
|
|
13
14
|
const feathersHooksCommon = require('feathers-hooks-common');
|
|
14
15
|
const _debounce = require('lodash/debounce.js');
|
|
@@ -53,9 +54,10 @@ function mergeArrays(targetArr, sourceArr, handle, prependKey, actionOnEmptyInte
|
|
|
53
54
|
return void 0;
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
const hasOwnProperty = (obj,
|
|
57
|
-
return Object.prototype.hasOwnProperty.call(obj,
|
|
57
|
+
const hasOwnProperty = (obj, ...keys) => {
|
|
58
|
+
return keys.some((x) => Object.prototype.hasOwnProperty.call(obj, x));
|
|
58
59
|
};
|
|
60
|
+
|
|
59
61
|
function handleArray(target, source, key, options) {
|
|
60
62
|
const targetVal = _get(target, key);
|
|
61
63
|
const sourceVal = _get(source, key);
|
|
@@ -120,7 +122,7 @@ function handleCircular(target, source, prependKey, options) {
|
|
|
120
122
|
};
|
|
121
123
|
const targetVal = getTargetVal();
|
|
122
124
|
const sourceVal = getSourceVal();
|
|
123
|
-
if (
|
|
125
|
+
if (fastEquals.deepEqual(targetVal, sourceVal)) {
|
|
124
126
|
return;
|
|
125
127
|
}
|
|
126
128
|
if (defaultHandle === "source") {
|
|
@@ -156,17 +158,17 @@ function handleCircular(target, source, prependKey, options) {
|
|
|
156
158
|
const targetHasIn = hasOwnProperty(targetVal, "$in");
|
|
157
159
|
const $in = targetHasIn ? targetVal["$in"] : sourceVal["$in"];
|
|
158
160
|
const otherVal = isTargetSimple ? targetVal : sourceVal;
|
|
159
|
-
if ($in.length === 1 &&
|
|
161
|
+
if ($in.length === 1 && fastEquals.deepEqual($in[0], otherVal)) {
|
|
160
162
|
_set(target, prependKey, otherVal);
|
|
161
163
|
return;
|
|
162
164
|
} else if (defaultHandle === "combine") {
|
|
163
|
-
if (!$in.some((x) =>
|
|
165
|
+
if (!$in.some((x) => fastEquals.deepEqual(x, otherVal))) {
|
|
164
166
|
$in.push(otherVal);
|
|
165
167
|
}
|
|
166
168
|
_set(target, `${prependKey}.$in`, $in);
|
|
167
169
|
return;
|
|
168
170
|
} else if (defaultHandle === "intersect") {
|
|
169
|
-
if ($in.some((x) =>
|
|
171
|
+
if ($in.some((x) => fastEquals.deepEqual(x, otherVal))) {
|
|
170
172
|
_set(target, prependKey, otherVal);
|
|
171
173
|
} else {
|
|
172
174
|
actionOnEmptyIntersect(target, source, prependKey);
|
|
@@ -183,7 +185,7 @@ function handleCircular(target, source, prependKey, options) {
|
|
|
183
185
|
if (key === "$or") {
|
|
184
186
|
if (defaultHandle === "combine") {
|
|
185
187
|
const newVals = sourceVal.filter(
|
|
186
|
-
(x) => !targetVal.some((y) =>
|
|
188
|
+
(x) => !targetVal.some((y) => fastEquals.deepEqual(x, y))
|
|
187
189
|
);
|
|
188
190
|
targetVal.push(...newVals);
|
|
189
191
|
} else if (defaultHandle === "intersect") {
|
|
@@ -217,7 +219,7 @@ function handleCircular(target, source, prependKey, options) {
|
|
|
217
219
|
return;
|
|
218
220
|
} else if (defaultHandle === "intersect") {
|
|
219
221
|
const newVals = sourceVal.filter(
|
|
220
|
-
(x) => !targetVal.some((y) =>
|
|
222
|
+
(x) => !targetVal.some((y) => fastEquals.deepEqual(x, y))
|
|
221
223
|
);
|
|
222
224
|
targetVal.push(...newVals);
|
|
223
225
|
return;
|
|
@@ -230,7 +232,7 @@ function handleCircular(target, source, prependKey, options) {
|
|
|
230
232
|
return;
|
|
231
233
|
} else if (defaultHandle === "intersect") {
|
|
232
234
|
const $in = targetVal.filter(
|
|
233
|
-
(x) => sourceVal.some((y) =>
|
|
235
|
+
(x) => sourceVal.some((y) => fastEquals.deepEqual(x, y))
|
|
234
236
|
);
|
|
235
237
|
if ($in.length === 0) {
|
|
236
238
|
actionOnEmptyIntersect(target, source, prependKey);
|
|
@@ -257,13 +259,10 @@ function handleCircular(target, source, prependKey, options) {
|
|
|
257
259
|
}
|
|
258
260
|
}
|
|
259
261
|
function makeDefaultOptions$1(options) {
|
|
260
|
-
options
|
|
261
|
-
options.defaultHandle
|
|
262
|
-
options.useLogicalConjunction =
|
|
263
|
-
|
|
264
|
-
"useLogicalConjunction"
|
|
265
|
-
) ? options.useLogicalConjunction : false;
|
|
266
|
-
options.actionOnEmptyIntersect = options.actionOnEmptyIntersect || (() => {
|
|
262
|
+
options ?? (options = {});
|
|
263
|
+
options.defaultHandle ?? (options.defaultHandle = "combine");
|
|
264
|
+
options.useLogicalConjunction ?? (options.useLogicalConjunction = false);
|
|
265
|
+
options.actionOnEmptyIntersect ?? (options.actionOnEmptyIntersect = () => {
|
|
267
266
|
throw new errors.Forbidden("You're not allowed to make this request");
|
|
268
267
|
});
|
|
269
268
|
options.handle = options.handle || {};
|
|
@@ -272,12 +271,14 @@ function makeDefaultOptions$1(options) {
|
|
|
272
271
|
}
|
|
273
272
|
return options;
|
|
274
273
|
}
|
|
275
|
-
function moveProperty(
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
274
|
+
function moveProperty(from, to, ...keys) {
|
|
275
|
+
keys.forEach((key) => {
|
|
276
|
+
if (!hasOwnProperty(from, key)) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
to[key] = from[key];
|
|
280
|
+
delete from[key];
|
|
281
|
+
});
|
|
281
282
|
}
|
|
282
283
|
function getParentProp(target, path) {
|
|
283
284
|
if (path.length <= 1) {
|
|
@@ -311,7 +312,41 @@ function arrayWithoutDuplicates(target) {
|
|
|
311
312
|
if (!target || !Array.isArray(target)) {
|
|
312
313
|
return target;
|
|
313
314
|
}
|
|
314
|
-
return _uniqWith(target,
|
|
315
|
+
return _uniqWith(target, fastEquals.deepEqual);
|
|
316
|
+
}
|
|
317
|
+
function isQueryMoreExplicitThanQuery(target, source) {
|
|
318
|
+
if (!target || !source) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
const targetKeys = Object.keys(target);
|
|
322
|
+
const sourceKeys = Object.keys(source);
|
|
323
|
+
if (!sourceKeys.length) {
|
|
324
|
+
return target;
|
|
325
|
+
}
|
|
326
|
+
if (!targetKeys.length) {
|
|
327
|
+
return source;
|
|
328
|
+
}
|
|
329
|
+
if (targetKeys.every((key) => fastEquals.deepEqual(target[key], source[key]))) {
|
|
330
|
+
return source;
|
|
331
|
+
}
|
|
332
|
+
if (sourceKeys.every((key) => fastEquals.deepEqual(target[key], source[key]))) {
|
|
333
|
+
return target;
|
|
334
|
+
}
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
function areQueriesOverlapping(target, source) {
|
|
338
|
+
if (!target || !source) {
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
const targetKeys = Object.keys(target);
|
|
342
|
+
const sourceKeys = Object.keys(source);
|
|
343
|
+
if (!sourceKeys.length || !targetKeys.length) {
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
if (targetKeys.some((x) => sourceKeys.includes(x)) || sourceKeys.some((x) => targetKeys.includes(x))) {
|
|
347
|
+
return true;
|
|
348
|
+
}
|
|
349
|
+
return false;
|
|
315
350
|
}
|
|
316
351
|
|
|
317
352
|
function filterQuery(query, _options) {
|
|
@@ -337,16 +372,15 @@ function filterQuery(query, _options) {
|
|
|
337
372
|
return adapterCommons.filterQuery(query, options);
|
|
338
373
|
}
|
|
339
374
|
|
|
340
|
-
function mergeQuery(target, source,
|
|
341
|
-
const
|
|
375
|
+
function mergeQuery(target, source, _options) {
|
|
376
|
+
const options = makeDefaultOptions$1(_options);
|
|
342
377
|
const { filters: targetFilters, query: targetQuery } = filterQuery(target, {
|
|
343
|
-
operators:
|
|
344
|
-
filters:
|
|
345
|
-
service:
|
|
378
|
+
operators: options.operators,
|
|
379
|
+
filters: options.filters,
|
|
380
|
+
service: options.service
|
|
346
381
|
});
|
|
347
|
-
moveProperty(targetFilters, targetQuery, "$or");
|
|
348
|
-
|
|
349
|
-
if (target.$limit) {
|
|
382
|
+
moveProperty(targetFilters, targetQuery, "$or", "$and");
|
|
383
|
+
if ("$limit" in target) {
|
|
350
384
|
targetFilters.$limit = target.$limit;
|
|
351
385
|
}
|
|
352
386
|
let {
|
|
@@ -354,27 +388,40 @@ function mergeQuery(target, source, options) {
|
|
|
354
388
|
filters: sourceFilters,
|
|
355
389
|
query: sourceQuery
|
|
356
390
|
} = filterQuery(source, {
|
|
357
|
-
operators:
|
|
358
|
-
filters:
|
|
359
|
-
service:
|
|
391
|
+
operators: options.operators,
|
|
392
|
+
filters: options.filters,
|
|
393
|
+
service: options.service
|
|
360
394
|
});
|
|
361
|
-
moveProperty(sourceFilters, sourceQuery, "$or");
|
|
362
|
-
moveProperty(sourceFilters, sourceQuery, "$and");
|
|
395
|
+
moveProperty(sourceFilters, sourceQuery, "$or", "$and");
|
|
363
396
|
if (source.$limit) {
|
|
364
397
|
sourceFilters.$limit = source.$limit;
|
|
365
398
|
}
|
|
366
|
-
if (target && !
|
|
399
|
+
if (target && !hasOwnProperty(target, "$limit") && hasOwnProperty(targetFilters, "$limit")) {
|
|
367
400
|
delete targetFilters.$limit;
|
|
368
401
|
}
|
|
369
|
-
if (source && !
|
|
402
|
+
if (source && !hasOwnProperty(source, "$limit") && hasOwnProperty(sourceFilters, "$limit")) {
|
|
370
403
|
delete sourceFilters.$limit;
|
|
371
404
|
}
|
|
372
|
-
handleArray(targetFilters, sourceFilters, ["$select"],
|
|
405
|
+
handleArray(targetFilters, sourceFilters, ["$select"], options);
|
|
373
406
|
delete sourceFilters["$select"];
|
|
374
407
|
_merge(targetFilters, sourceFilters);
|
|
375
|
-
|
|
408
|
+
const subsetQuery = isQueryMoreExplicitThanQuery(targetQuery, sourceQuery);
|
|
409
|
+
if (options.defaultHandle === "intersect" && !!subsetQuery && !hasOwnProperty(targetQuery, "$or", "$and") && !hasOwnProperty(sourceQuery, "$or", "$and")) {
|
|
410
|
+
return {
|
|
411
|
+
...targetFilters,
|
|
412
|
+
...subsetQuery
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
if (options.defaultHandle === "intersect" && !areQueriesOverlapping(targetQuery, sourceQuery) && !hasOwnProperty(targetQuery, "$or", "$and") && !hasOwnProperty(sourceQuery, "$or", "$and")) {
|
|
416
|
+
return {
|
|
417
|
+
...targetFilters,
|
|
418
|
+
...targetQuery,
|
|
419
|
+
...sourceQuery
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
if (options.useLogicalConjunction && (options.defaultHandle === "combine" || options.defaultHandle === "intersect") && !_isEmpty(targetQuery)) {
|
|
376
423
|
const logicalOp = options.defaultHandle === "combine" ? "$or" : "$and";
|
|
377
|
-
if (
|
|
424
|
+
if (hasOwnProperty(sourceQuery, logicalOp)) {
|
|
378
425
|
const andOr = sourceQuery[logicalOp];
|
|
379
426
|
delete sourceQuery[logicalOp];
|
|
380
427
|
andOr.push(sourceQuery);
|
|
@@ -386,10 +433,12 @@ function mergeQuery(target, source, options) {
|
|
|
386
433
|
const keys = Object.keys(sourceQuery);
|
|
387
434
|
for (let i = 0, n = keys.length; i < n; i++) {
|
|
388
435
|
const key = keys[i];
|
|
389
|
-
handleCircular(targetQuery, sourceQuery, [key],
|
|
436
|
+
handleCircular(targetQuery, sourceQuery, [key], options);
|
|
390
437
|
}
|
|
391
|
-
|
|
392
|
-
|
|
438
|
+
return {
|
|
439
|
+
...targetFilters,
|
|
440
|
+
...targetQuery
|
|
441
|
+
};
|
|
393
442
|
}
|
|
394
443
|
|
|
395
444
|
const getItemsIsArray = (context, options) => {
|
|
@@ -413,7 +462,7 @@ const getItemsIsArray = (context, options) => {
|
|
|
413
462
|
};
|
|
414
463
|
|
|
415
464
|
const getPaginate = (context) => {
|
|
416
|
-
if (
|
|
465
|
+
if (hasOwnProperty(context.params, "paginate")) {
|
|
417
466
|
return context.params.paginate || void 0;
|
|
418
467
|
}
|
|
419
468
|
if (context.params.paginate === false) {
|
|
@@ -717,12 +766,10 @@ function removeRelated({
|
|
|
717
766
|
|
|
718
767
|
const makeOptions = (options) => {
|
|
719
768
|
options = options || {};
|
|
720
|
-
return
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
options
|
|
725
|
-
);
|
|
769
|
+
return {
|
|
770
|
+
wait: true,
|
|
771
|
+
...options
|
|
772
|
+
};
|
|
726
773
|
};
|
|
727
774
|
const runPerItem = (actionPerItem, _options) => {
|
|
728
775
|
const options = makeOptions(_options);
|
|
@@ -746,11 +793,10 @@ const defaultOptions = {
|
|
|
746
793
|
overwrite: true
|
|
747
794
|
};
|
|
748
795
|
function setData(from, to, _options) {
|
|
749
|
-
const options =
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
);
|
|
796
|
+
const options = {
|
|
797
|
+
...defaultOptions,
|
|
798
|
+
..._options
|
|
799
|
+
};
|
|
754
800
|
return (context) => {
|
|
755
801
|
if (shouldSkip("setData", context)) {
|
|
756
802
|
return context;
|
package/dist/index.d.ts
CHANGED
|
@@ -145,7 +145,14 @@ interface MergeQueryOptions<T> extends FilterQueryOptions<T> {
|
|
|
145
145
|
|
|
146
146
|
declare function mergeArrays<T>(targetArr: T[], sourceArr: T[], handle: Handle, prependKey?: Path, actionOnEmptyIntersect?: ActionOnEmptyIntersect): T[] | undefined;
|
|
147
147
|
|
|
148
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Merges two queries into one.
|
|
150
|
+
* @param target Query to be merged into
|
|
151
|
+
* @param source Query to be merged from
|
|
152
|
+
* @param _options
|
|
153
|
+
* @returns Query
|
|
154
|
+
*/
|
|
155
|
+
declare function mergeQuery<T = any>(target: Query, source: Query, _options?: Partial<MergeQueryOptions<T>>): Query;
|
|
149
156
|
|
|
150
157
|
/**
|
|
151
158
|
* util to get paginate options from context
|
package/dist/index.mjs
CHANGED
|
@@ -3,10 +3,11 @@ import _merge from 'lodash/merge.js';
|
|
|
3
3
|
import _isEmpty from 'lodash/isEmpty.js';
|
|
4
4
|
import _get from 'lodash/get.js';
|
|
5
5
|
import _has from 'lodash/has.js';
|
|
6
|
-
import _isEqual from 'lodash/isEqual.js';
|
|
7
6
|
import _set from 'lodash/set.js';
|
|
8
7
|
import _uniqWith from 'lodash/uniqWith.js';
|
|
8
|
+
import { deepEqual } from 'fast-equals';
|
|
9
9
|
import { filterQuery as filterQuery$1 } from '@feathersjs/adapter-commons';
|
|
10
|
+
import _isEqual from 'lodash/isEqual.js';
|
|
10
11
|
import { _ } from '@feathersjs/commons';
|
|
11
12
|
import { checkContext } from 'feathers-hooks-common';
|
|
12
13
|
import _debounce from 'lodash/debounce.js';
|
|
@@ -51,9 +52,10 @@ function mergeArrays(targetArr, sourceArr, handle, prependKey, actionOnEmptyInte
|
|
|
51
52
|
return void 0;
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
const hasOwnProperty = (obj,
|
|
55
|
-
return Object.prototype.hasOwnProperty.call(obj,
|
|
55
|
+
const hasOwnProperty = (obj, ...keys) => {
|
|
56
|
+
return keys.some((x) => Object.prototype.hasOwnProperty.call(obj, x));
|
|
56
57
|
};
|
|
58
|
+
|
|
57
59
|
function handleArray(target, source, key, options) {
|
|
58
60
|
const targetVal = _get(target, key);
|
|
59
61
|
const sourceVal = _get(source, key);
|
|
@@ -118,7 +120,7 @@ function handleCircular(target, source, prependKey, options) {
|
|
|
118
120
|
};
|
|
119
121
|
const targetVal = getTargetVal();
|
|
120
122
|
const sourceVal = getSourceVal();
|
|
121
|
-
if (
|
|
123
|
+
if (deepEqual(targetVal, sourceVal)) {
|
|
122
124
|
return;
|
|
123
125
|
}
|
|
124
126
|
if (defaultHandle === "source") {
|
|
@@ -154,17 +156,17 @@ function handleCircular(target, source, prependKey, options) {
|
|
|
154
156
|
const targetHasIn = hasOwnProperty(targetVal, "$in");
|
|
155
157
|
const $in = targetHasIn ? targetVal["$in"] : sourceVal["$in"];
|
|
156
158
|
const otherVal = isTargetSimple ? targetVal : sourceVal;
|
|
157
|
-
if ($in.length === 1 &&
|
|
159
|
+
if ($in.length === 1 && deepEqual($in[0], otherVal)) {
|
|
158
160
|
_set(target, prependKey, otherVal);
|
|
159
161
|
return;
|
|
160
162
|
} else if (defaultHandle === "combine") {
|
|
161
|
-
if (!$in.some((x) =>
|
|
163
|
+
if (!$in.some((x) => deepEqual(x, otherVal))) {
|
|
162
164
|
$in.push(otherVal);
|
|
163
165
|
}
|
|
164
166
|
_set(target, `${prependKey}.$in`, $in);
|
|
165
167
|
return;
|
|
166
168
|
} else if (defaultHandle === "intersect") {
|
|
167
|
-
if ($in.some((x) =>
|
|
169
|
+
if ($in.some((x) => deepEqual(x, otherVal))) {
|
|
168
170
|
_set(target, prependKey, otherVal);
|
|
169
171
|
} else {
|
|
170
172
|
actionOnEmptyIntersect(target, source, prependKey);
|
|
@@ -181,7 +183,7 @@ function handleCircular(target, source, prependKey, options) {
|
|
|
181
183
|
if (key === "$or") {
|
|
182
184
|
if (defaultHandle === "combine") {
|
|
183
185
|
const newVals = sourceVal.filter(
|
|
184
|
-
(x) => !targetVal.some((y) =>
|
|
186
|
+
(x) => !targetVal.some((y) => deepEqual(x, y))
|
|
185
187
|
);
|
|
186
188
|
targetVal.push(...newVals);
|
|
187
189
|
} else if (defaultHandle === "intersect") {
|
|
@@ -215,7 +217,7 @@ function handleCircular(target, source, prependKey, options) {
|
|
|
215
217
|
return;
|
|
216
218
|
} else if (defaultHandle === "intersect") {
|
|
217
219
|
const newVals = sourceVal.filter(
|
|
218
|
-
(x) => !targetVal.some((y) =>
|
|
220
|
+
(x) => !targetVal.some((y) => deepEqual(x, y))
|
|
219
221
|
);
|
|
220
222
|
targetVal.push(...newVals);
|
|
221
223
|
return;
|
|
@@ -228,7 +230,7 @@ function handleCircular(target, source, prependKey, options) {
|
|
|
228
230
|
return;
|
|
229
231
|
} else if (defaultHandle === "intersect") {
|
|
230
232
|
const $in = targetVal.filter(
|
|
231
|
-
(x) => sourceVal.some((y) =>
|
|
233
|
+
(x) => sourceVal.some((y) => deepEqual(x, y))
|
|
232
234
|
);
|
|
233
235
|
if ($in.length === 0) {
|
|
234
236
|
actionOnEmptyIntersect(target, source, prependKey);
|
|
@@ -255,13 +257,10 @@ function handleCircular(target, source, prependKey, options) {
|
|
|
255
257
|
}
|
|
256
258
|
}
|
|
257
259
|
function makeDefaultOptions$1(options) {
|
|
258
|
-
options
|
|
259
|
-
options.defaultHandle
|
|
260
|
-
options.useLogicalConjunction =
|
|
261
|
-
|
|
262
|
-
"useLogicalConjunction"
|
|
263
|
-
) ? options.useLogicalConjunction : false;
|
|
264
|
-
options.actionOnEmptyIntersect = options.actionOnEmptyIntersect || (() => {
|
|
260
|
+
options ?? (options = {});
|
|
261
|
+
options.defaultHandle ?? (options.defaultHandle = "combine");
|
|
262
|
+
options.useLogicalConjunction ?? (options.useLogicalConjunction = false);
|
|
263
|
+
options.actionOnEmptyIntersect ?? (options.actionOnEmptyIntersect = () => {
|
|
265
264
|
throw new Forbidden("You're not allowed to make this request");
|
|
266
265
|
});
|
|
267
266
|
options.handle = options.handle || {};
|
|
@@ -270,12 +269,14 @@ function makeDefaultOptions$1(options) {
|
|
|
270
269
|
}
|
|
271
270
|
return options;
|
|
272
271
|
}
|
|
273
|
-
function moveProperty(
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
272
|
+
function moveProperty(from, to, ...keys) {
|
|
273
|
+
keys.forEach((key) => {
|
|
274
|
+
if (!hasOwnProperty(from, key)) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
to[key] = from[key];
|
|
278
|
+
delete from[key];
|
|
279
|
+
});
|
|
279
280
|
}
|
|
280
281
|
function getParentProp(target, path) {
|
|
281
282
|
if (path.length <= 1) {
|
|
@@ -309,7 +310,41 @@ function arrayWithoutDuplicates(target) {
|
|
|
309
310
|
if (!target || !Array.isArray(target)) {
|
|
310
311
|
return target;
|
|
311
312
|
}
|
|
312
|
-
return _uniqWith(target,
|
|
313
|
+
return _uniqWith(target, deepEqual);
|
|
314
|
+
}
|
|
315
|
+
function isQueryMoreExplicitThanQuery(target, source) {
|
|
316
|
+
if (!target || !source) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
const targetKeys = Object.keys(target);
|
|
320
|
+
const sourceKeys = Object.keys(source);
|
|
321
|
+
if (!sourceKeys.length) {
|
|
322
|
+
return target;
|
|
323
|
+
}
|
|
324
|
+
if (!targetKeys.length) {
|
|
325
|
+
return source;
|
|
326
|
+
}
|
|
327
|
+
if (targetKeys.every((key) => deepEqual(target[key], source[key]))) {
|
|
328
|
+
return source;
|
|
329
|
+
}
|
|
330
|
+
if (sourceKeys.every((key) => deepEqual(target[key], source[key]))) {
|
|
331
|
+
return target;
|
|
332
|
+
}
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
function areQueriesOverlapping(target, source) {
|
|
336
|
+
if (!target || !source) {
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
const targetKeys = Object.keys(target);
|
|
340
|
+
const sourceKeys = Object.keys(source);
|
|
341
|
+
if (!sourceKeys.length || !targetKeys.length) {
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
if (targetKeys.some((x) => sourceKeys.includes(x)) || sourceKeys.some((x) => targetKeys.includes(x))) {
|
|
345
|
+
return true;
|
|
346
|
+
}
|
|
347
|
+
return false;
|
|
313
348
|
}
|
|
314
349
|
|
|
315
350
|
function filterQuery(query, _options) {
|
|
@@ -335,16 +370,15 @@ function filterQuery(query, _options) {
|
|
|
335
370
|
return filterQuery$1(query, options);
|
|
336
371
|
}
|
|
337
372
|
|
|
338
|
-
function mergeQuery(target, source,
|
|
339
|
-
const
|
|
373
|
+
function mergeQuery(target, source, _options) {
|
|
374
|
+
const options = makeDefaultOptions$1(_options);
|
|
340
375
|
const { filters: targetFilters, query: targetQuery } = filterQuery(target, {
|
|
341
|
-
operators:
|
|
342
|
-
filters:
|
|
343
|
-
service:
|
|
376
|
+
operators: options.operators,
|
|
377
|
+
filters: options.filters,
|
|
378
|
+
service: options.service
|
|
344
379
|
});
|
|
345
|
-
moveProperty(targetFilters, targetQuery, "$or");
|
|
346
|
-
|
|
347
|
-
if (target.$limit) {
|
|
380
|
+
moveProperty(targetFilters, targetQuery, "$or", "$and");
|
|
381
|
+
if ("$limit" in target) {
|
|
348
382
|
targetFilters.$limit = target.$limit;
|
|
349
383
|
}
|
|
350
384
|
let {
|
|
@@ -352,27 +386,40 @@ function mergeQuery(target, source, options) {
|
|
|
352
386
|
filters: sourceFilters,
|
|
353
387
|
query: sourceQuery
|
|
354
388
|
} = filterQuery(source, {
|
|
355
|
-
operators:
|
|
356
|
-
filters:
|
|
357
|
-
service:
|
|
389
|
+
operators: options.operators,
|
|
390
|
+
filters: options.filters,
|
|
391
|
+
service: options.service
|
|
358
392
|
});
|
|
359
|
-
moveProperty(sourceFilters, sourceQuery, "$or");
|
|
360
|
-
moveProperty(sourceFilters, sourceQuery, "$and");
|
|
393
|
+
moveProperty(sourceFilters, sourceQuery, "$or", "$and");
|
|
361
394
|
if (source.$limit) {
|
|
362
395
|
sourceFilters.$limit = source.$limit;
|
|
363
396
|
}
|
|
364
|
-
if (target && !
|
|
397
|
+
if (target && !hasOwnProperty(target, "$limit") && hasOwnProperty(targetFilters, "$limit")) {
|
|
365
398
|
delete targetFilters.$limit;
|
|
366
399
|
}
|
|
367
|
-
if (source && !
|
|
400
|
+
if (source && !hasOwnProperty(source, "$limit") && hasOwnProperty(sourceFilters, "$limit")) {
|
|
368
401
|
delete sourceFilters.$limit;
|
|
369
402
|
}
|
|
370
|
-
handleArray(targetFilters, sourceFilters, ["$select"],
|
|
403
|
+
handleArray(targetFilters, sourceFilters, ["$select"], options);
|
|
371
404
|
delete sourceFilters["$select"];
|
|
372
405
|
_merge(targetFilters, sourceFilters);
|
|
373
|
-
|
|
406
|
+
const subsetQuery = isQueryMoreExplicitThanQuery(targetQuery, sourceQuery);
|
|
407
|
+
if (options.defaultHandle === "intersect" && !!subsetQuery && !hasOwnProperty(targetQuery, "$or", "$and") && !hasOwnProperty(sourceQuery, "$or", "$and")) {
|
|
408
|
+
return {
|
|
409
|
+
...targetFilters,
|
|
410
|
+
...subsetQuery
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
if (options.defaultHandle === "intersect" && !areQueriesOverlapping(targetQuery, sourceQuery) && !hasOwnProperty(targetQuery, "$or", "$and") && !hasOwnProperty(sourceQuery, "$or", "$and")) {
|
|
414
|
+
return {
|
|
415
|
+
...targetFilters,
|
|
416
|
+
...targetQuery,
|
|
417
|
+
...sourceQuery
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
if (options.useLogicalConjunction && (options.defaultHandle === "combine" || options.defaultHandle === "intersect") && !_isEmpty(targetQuery)) {
|
|
374
421
|
const logicalOp = options.defaultHandle === "combine" ? "$or" : "$and";
|
|
375
|
-
if (
|
|
422
|
+
if (hasOwnProperty(sourceQuery, logicalOp)) {
|
|
376
423
|
const andOr = sourceQuery[logicalOp];
|
|
377
424
|
delete sourceQuery[logicalOp];
|
|
378
425
|
andOr.push(sourceQuery);
|
|
@@ -384,10 +431,12 @@ function mergeQuery(target, source, options) {
|
|
|
384
431
|
const keys = Object.keys(sourceQuery);
|
|
385
432
|
for (let i = 0, n = keys.length; i < n; i++) {
|
|
386
433
|
const key = keys[i];
|
|
387
|
-
handleCircular(targetQuery, sourceQuery, [key],
|
|
434
|
+
handleCircular(targetQuery, sourceQuery, [key], options);
|
|
388
435
|
}
|
|
389
|
-
|
|
390
|
-
|
|
436
|
+
return {
|
|
437
|
+
...targetFilters,
|
|
438
|
+
...targetQuery
|
|
439
|
+
};
|
|
391
440
|
}
|
|
392
441
|
|
|
393
442
|
const getItemsIsArray = (context, options) => {
|
|
@@ -411,7 +460,7 @@ const getItemsIsArray = (context, options) => {
|
|
|
411
460
|
};
|
|
412
461
|
|
|
413
462
|
const getPaginate = (context) => {
|
|
414
|
-
if (
|
|
463
|
+
if (hasOwnProperty(context.params, "paginate")) {
|
|
415
464
|
return context.params.paginate || void 0;
|
|
416
465
|
}
|
|
417
466
|
if (context.params.paginate === false) {
|
|
@@ -715,12 +764,10 @@ function removeRelated({
|
|
|
715
764
|
|
|
716
765
|
const makeOptions = (options) => {
|
|
717
766
|
options = options || {};
|
|
718
|
-
return
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
options
|
|
723
|
-
);
|
|
767
|
+
return {
|
|
768
|
+
wait: true,
|
|
769
|
+
...options
|
|
770
|
+
};
|
|
724
771
|
};
|
|
725
772
|
const runPerItem = (actionPerItem, _options) => {
|
|
726
773
|
const options = makeOptions(_options);
|
|
@@ -744,11 +791,10 @@ const defaultOptions = {
|
|
|
744
791
|
overwrite: true
|
|
745
792
|
};
|
|
746
793
|
function setData(from, to, _options) {
|
|
747
|
-
const options =
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
);
|
|
794
|
+
const options = {
|
|
795
|
+
...defaultOptions,
|
|
796
|
+
..._options
|
|
797
|
+
};
|
|
752
798
|
return (context) => {
|
|
753
799
|
if (shouldSkip("setData", context)) {
|
|
754
800
|
return context;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "feathers-utils",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Some utils for projects using '@feathersjs/feathers'",
|
|
5
5
|
"author": "fratzinger",
|
|
6
6
|
"repository": {
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"@feathersjs/commons": "^5.0.0",
|
|
44
44
|
"@feathersjs/errors": "5.0.0",
|
|
45
45
|
"@feathersjs/feathers": "5.0.0",
|
|
46
|
+
"fast-equals": "^5.0.1",
|
|
46
47
|
"feathers-hooks-common": "^7.0.0",
|
|
47
48
|
"lodash": "^4.17.21"
|
|
48
49
|
},
|
package/src/hooks/runPerItem.ts
CHANGED
|
@@ -11,12 +11,10 @@ const makeOptions = (
|
|
|
11
11
|
options?: HookRunPerItemOptions
|
|
12
12
|
): Required<HookRunPerItemOptions> => {
|
|
13
13
|
options = options || {};
|
|
14
|
-
return
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
options
|
|
19
|
-
);
|
|
14
|
+
return {
|
|
15
|
+
wait: true,
|
|
16
|
+
...options,
|
|
17
|
+
};
|
|
20
18
|
};
|
|
21
19
|
|
|
22
20
|
/**
|
package/src/hooks/setData.ts
CHANGED
|
@@ -27,11 +27,10 @@ export function setData<H extends HookContext = HookContext>(
|
|
|
27
27
|
to: PropertyPath,
|
|
28
28
|
_options?: HookSetDataOptions
|
|
29
29
|
) {
|
|
30
|
-
const options: Required<HookSetDataOptions> =
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
);
|
|
30
|
+
const options: Required<HookSetDataOptions> = {
|
|
31
|
+
...defaultOptions,
|
|
32
|
+
..._options,
|
|
33
|
+
};
|
|
35
34
|
return (context: H) => {
|
|
36
35
|
if (shouldSkip("setData", context)) {
|
|
37
36
|
return context;
|
package/src/utils/getPaginate.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PaginationOptions } from "@feathersjs/adapter-commons";
|
|
2
2
|
import type { HookContext } from "@feathersjs/feathers";
|
|
3
|
+
import { hasOwnProperty } from "./internal.utils";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* util to get paginate options from context
|
|
@@ -10,7 +11,7 @@ import type { HookContext } from "@feathersjs/feathers";
|
|
|
10
11
|
export const getPaginate = <H extends HookContext = HookContext>(
|
|
11
12
|
context: H
|
|
12
13
|
): PaginationOptions | undefined => {
|
|
13
|
-
if (
|
|
14
|
+
if (hasOwnProperty(context.params, "paginate")) {
|
|
14
15
|
return (context.params.paginate as PaginationOptions) || undefined;
|
|
15
16
|
}
|
|
16
17
|
|
|
@@ -2,30 +2,39 @@ import _merge from "lodash/merge.js";
|
|
|
2
2
|
import _isEmpty from "lodash/isEmpty.js";
|
|
3
3
|
import type { Query } from "@feathersjs/feathers";
|
|
4
4
|
import {
|
|
5
|
+
areQueriesOverlapping,
|
|
5
6
|
handleArray,
|
|
6
7
|
handleCircular,
|
|
8
|
+
isQueryMoreExplicitThanQuery,
|
|
7
9
|
makeDefaultOptions,
|
|
8
10
|
moveProperty,
|
|
9
11
|
} from "./utils";
|
|
10
12
|
import type { MergeQueryOptions } from "./types";
|
|
11
13
|
import { filterQuery } from "../filterQuery";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
import { hasOwnProperty } from "../internal.utils";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Merges two queries into one.
|
|
18
|
+
* @param target Query to be merged into
|
|
19
|
+
* @param source Query to be merged from
|
|
20
|
+
* @param _options
|
|
21
|
+
* @returns Query
|
|
22
|
+
*/
|
|
23
|
+
export function mergeQuery<T = any>(
|
|
14
24
|
target: Query,
|
|
15
25
|
source: Query,
|
|
16
|
-
|
|
26
|
+
_options?: Partial<MergeQueryOptions<T>>
|
|
17
27
|
): Query {
|
|
18
|
-
const
|
|
28
|
+
const options = makeDefaultOptions(_options);
|
|
19
29
|
const { filters: targetFilters, query: targetQuery } = filterQuery(target, {
|
|
20
|
-
operators:
|
|
21
|
-
filters:
|
|
22
|
-
service:
|
|
30
|
+
operators: options.operators,
|
|
31
|
+
filters: options.filters,
|
|
32
|
+
service: options.service,
|
|
23
33
|
});
|
|
24
34
|
|
|
25
|
-
moveProperty(targetFilters, targetQuery, "$or");
|
|
26
|
-
moveProperty(targetFilters, targetQuery, "$and");
|
|
35
|
+
moveProperty(targetFilters, targetQuery, "$or", "$and");
|
|
27
36
|
|
|
28
|
-
if (target
|
|
37
|
+
if ("$limit" in target) {
|
|
29
38
|
targetFilters.$limit = target.$limit;
|
|
30
39
|
}
|
|
31
40
|
|
|
@@ -34,13 +43,12 @@ export function mergeQuery<T>(
|
|
|
34
43
|
filters: sourceFilters,
|
|
35
44
|
query: sourceQuery,
|
|
36
45
|
} = filterQuery(source, {
|
|
37
|
-
operators:
|
|
38
|
-
filters:
|
|
39
|
-
service:
|
|
46
|
+
operators: options.operators,
|
|
47
|
+
filters: options.filters,
|
|
48
|
+
service: options.service,
|
|
40
49
|
});
|
|
41
50
|
|
|
42
|
-
moveProperty(sourceFilters, sourceQuery, "$or");
|
|
43
|
-
moveProperty(sourceFilters, sourceQuery, "$and");
|
|
51
|
+
moveProperty(sourceFilters, sourceQuery, "$or", "$and");
|
|
44
52
|
|
|
45
53
|
if (source.$limit) {
|
|
46
54
|
sourceFilters.$limit = source.$limit;
|
|
@@ -50,37 +58,64 @@ export function mergeQuery<T>(
|
|
|
50
58
|
|
|
51
59
|
if (
|
|
52
60
|
target &&
|
|
53
|
-
!
|
|
54
|
-
|
|
61
|
+
!hasOwnProperty(target, "$limit") &&
|
|
62
|
+
hasOwnProperty(targetFilters, "$limit")
|
|
55
63
|
) {
|
|
56
64
|
delete targetFilters.$limit;
|
|
57
65
|
}
|
|
58
66
|
|
|
59
67
|
if (
|
|
60
68
|
source &&
|
|
61
|
-
!
|
|
62
|
-
|
|
69
|
+
!hasOwnProperty(source, "$limit") &&
|
|
70
|
+
hasOwnProperty(sourceFilters, "$limit")
|
|
63
71
|
) {
|
|
64
72
|
delete sourceFilters.$limit;
|
|
65
73
|
}
|
|
66
74
|
|
|
67
|
-
handleArray(targetFilters, sourceFilters, ["$select"],
|
|
75
|
+
handleArray(targetFilters, sourceFilters, ["$select"], options);
|
|
68
76
|
// remaining filters
|
|
69
77
|
delete sourceFilters["$select"];
|
|
70
78
|
_merge(targetFilters, sourceFilters);
|
|
71
79
|
|
|
72
80
|
//#endregion
|
|
73
81
|
|
|
82
|
+
const subsetQuery = isQueryMoreExplicitThanQuery(targetQuery, sourceQuery);
|
|
83
|
+
|
|
84
|
+
if (
|
|
85
|
+
options.defaultHandle === "intersect" &&
|
|
86
|
+
!!subsetQuery &&
|
|
87
|
+
!hasOwnProperty(targetQuery, "$or", "$and") &&
|
|
88
|
+
!hasOwnProperty(sourceQuery, "$or", "$and")
|
|
89
|
+
) {
|
|
90
|
+
return {
|
|
91
|
+
...targetFilters,
|
|
92
|
+
...subsetQuery,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (
|
|
97
|
+
options.defaultHandle === "intersect" &&
|
|
98
|
+
!areQueriesOverlapping(targetQuery, sourceQuery) &&
|
|
99
|
+
!hasOwnProperty(targetQuery, "$or", "$and") &&
|
|
100
|
+
!hasOwnProperty(sourceQuery, "$or", "$and")
|
|
101
|
+
) {
|
|
102
|
+
return {
|
|
103
|
+
...targetFilters,
|
|
104
|
+
...targetQuery,
|
|
105
|
+
...sourceQuery,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
74
109
|
//#region '$or' / '$and'
|
|
75
110
|
|
|
76
111
|
if (
|
|
77
|
-
options
|
|
112
|
+
options.useLogicalConjunction &&
|
|
78
113
|
(options.defaultHandle === "combine" ||
|
|
79
114
|
options.defaultHandle === "intersect") &&
|
|
80
115
|
!_isEmpty(targetQuery)
|
|
81
116
|
) {
|
|
82
117
|
const logicalOp = options.defaultHandle === "combine" ? "$or" : "$and";
|
|
83
|
-
if (
|
|
118
|
+
if (hasOwnProperty(sourceQuery, logicalOp)) {
|
|
84
119
|
// omit '$or'/'$and' and put all other props into '$or'/'$and'
|
|
85
120
|
const andOr = sourceQuery[logicalOp] as unknown[];
|
|
86
121
|
delete sourceQuery[logicalOp];
|
|
@@ -96,9 +131,11 @@ export function mergeQuery<T>(
|
|
|
96
131
|
const keys = Object.keys(sourceQuery);
|
|
97
132
|
for (let i = 0, n = keys.length; i < n; i++) {
|
|
98
133
|
const key = keys[i];
|
|
99
|
-
handleCircular(targetQuery, sourceQuery, [key],
|
|
134
|
+
handleCircular(targetQuery, sourceQuery, [key], options);
|
|
100
135
|
}
|
|
101
|
-
const result = Object.assign({}, targetFilters, targetQuery) as Query;
|
|
102
136
|
|
|
103
|
-
return
|
|
137
|
+
return {
|
|
138
|
+
...targetFilters,
|
|
139
|
+
...targetQuery,
|
|
140
|
+
};
|
|
104
141
|
}
|
|
@@ -2,20 +2,15 @@ import { Forbidden } from "@feathersjs/errors";
|
|
|
2
2
|
import _get from "lodash/get.js";
|
|
3
3
|
import _has from "lodash/has.js";
|
|
4
4
|
import _isEmpty from "lodash/isEmpty.js";
|
|
5
|
-
import _isEqual from "lodash/isEqual.js";
|
|
6
5
|
|
|
7
6
|
import _set from "lodash/set.js";
|
|
8
7
|
import _uniqWith from "lodash/uniqWith.js";
|
|
9
8
|
import type { Path } from "../../typesInternal";
|
|
10
9
|
import { mergeArrays } from "./mergeArrays";
|
|
11
10
|
import type { Handle, MergeQueryOptions } from "./types";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
key: string
|
|
16
|
-
): boolean => {
|
|
17
|
-
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
18
|
-
};
|
|
11
|
+
import { deepEqual as _isEqual } from "fast-equals";
|
|
12
|
+
import type { Query } from "@feathersjs/feathers";
|
|
13
|
+
import { hasOwnProperty } from "../internal.utils";
|
|
19
14
|
|
|
20
15
|
export function handleArray<T>(
|
|
21
16
|
target: Record<string, unknown>,
|
|
@@ -265,19 +260,12 @@ export function handleCircular<T>(
|
|
|
265
260
|
export function makeDefaultOptions<T>(
|
|
266
261
|
options?: Partial<MergeQueryOptions<T>>
|
|
267
262
|
): MergeQueryOptions<T> {
|
|
268
|
-
options
|
|
269
|
-
options.defaultHandle
|
|
270
|
-
options.useLogicalConjunction
|
|
271
|
-
|
|
272
|
-
"
|
|
273
|
-
|
|
274
|
-
? options.useLogicalConjunction
|
|
275
|
-
: false;
|
|
276
|
-
options.actionOnEmptyIntersect =
|
|
277
|
-
options.actionOnEmptyIntersect ||
|
|
278
|
-
(() => {
|
|
279
|
-
throw new Forbidden("You're not allowed to make this request");
|
|
280
|
-
});
|
|
263
|
+
options ??= {} as MergeQueryOptions<T>;
|
|
264
|
+
options.defaultHandle ??= "combine";
|
|
265
|
+
options.useLogicalConjunction ??= false;
|
|
266
|
+
options.actionOnEmptyIntersect ??= () => {
|
|
267
|
+
throw new Forbidden("You're not allowed to make this request");
|
|
268
|
+
};
|
|
281
269
|
options.handle = options.handle || {};
|
|
282
270
|
if (options.defaultHandle === "intersect") {
|
|
283
271
|
options.handle.$select = options.handle.$select || "intersectOrFull";
|
|
@@ -286,15 +274,17 @@ export function makeDefaultOptions<T>(
|
|
|
286
274
|
}
|
|
287
275
|
|
|
288
276
|
export function moveProperty(
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
277
|
+
from: Record<string, any>,
|
|
278
|
+
to: Record<string, any>,
|
|
279
|
+
...keys: string[]
|
|
292
280
|
): void {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
281
|
+
keys.forEach((key) => {
|
|
282
|
+
if (!hasOwnProperty(from, key)) {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
to[key] = from[key];
|
|
286
|
+
delete from[key];
|
|
287
|
+
});
|
|
298
288
|
}
|
|
299
289
|
|
|
300
290
|
export function getParentProp(target: Record<string, unknown>, path: Path) {
|
|
@@ -338,5 +328,68 @@ export function arrayWithoutDuplicates<T>(target: T[]): T[] {
|
|
|
338
328
|
if (!target || !Array.isArray(target)) {
|
|
339
329
|
return target;
|
|
340
330
|
}
|
|
331
|
+
|
|
341
332
|
return _uniqWith(target, _isEqual);
|
|
342
333
|
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Checks if one query is a superset of the target query
|
|
337
|
+
* @param target The target query
|
|
338
|
+
* @param source The source query
|
|
339
|
+
* @returns The query that is the superset of the other query, returns undefined otherwise
|
|
340
|
+
*/
|
|
341
|
+
export function isQueryMoreExplicitThanQuery(
|
|
342
|
+
target: Query,
|
|
343
|
+
source: Query
|
|
344
|
+
): Query | undefined {
|
|
345
|
+
if (!target || !source) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const targetKeys = Object.keys(target);
|
|
350
|
+
const sourceKeys = Object.keys(source);
|
|
351
|
+
|
|
352
|
+
// sourceQuery: {}; targetQuery: { something }
|
|
353
|
+
if (!sourceKeys.length) {
|
|
354
|
+
return target;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// sourceQuery: { something }; targetQuery: {}
|
|
358
|
+
if (!targetKeys.length) {
|
|
359
|
+
return source;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if (targetKeys.every((key) => _isEqual(target[key], source[key]))) {
|
|
363
|
+
// every property of target is exactly in source
|
|
364
|
+
return source;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (sourceKeys.every((key) => _isEqual(target[key], source[key]))) {
|
|
368
|
+
// every property of source is exactly in target
|
|
369
|
+
return target;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
export function areQueriesOverlapping(target: Query, source: Query): boolean {
|
|
376
|
+
if (!target || !source) {
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const targetKeys = Object.keys(target);
|
|
381
|
+
const sourceKeys = Object.keys(source);
|
|
382
|
+
|
|
383
|
+
if (!sourceKeys.length || !targetKeys.length) {
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if (
|
|
388
|
+
targetKeys.some((x) => sourceKeys.includes(x)) ||
|
|
389
|
+
sourceKeys.some((x) => targetKeys.includes(x))
|
|
390
|
+
) {
|
|
391
|
+
return true;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return false;
|
|
395
|
+
}
|