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
package/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# feathers-utils
|
|
2
2
|
|
|
3
|
-

|
|
4
|
-

|
|
5
|
-

|
|
6
|
-

|
|
7
|
-

|
|
3
|
+
[](https://www.npmjs.com/package/feathers-utils)
|
|
4
|
+
[](https://github.com/fratzinger/feathers-utils/actions/workflows/node.js.yml?query=branch%3Amain)
|
|
5
|
+
[](https://codeclimate.com/github/fratzinger/feathers-utils)
|
|
6
|
+
[](https://codeclimate.com/github/fratzinger/feathers-utils)
|
|
7
|
+
[](https://libraries.io/npm/feathers-utils)
|
|
8
|
+
[](https://www.npmjs.com/package/feathers-utils)
|
|
9
9
|
[](https://github.com/fratzinger/feathers-utils/blob/main/LICENSE.md)
|
|
10
10
|
|
|
11
11
|
|
|
@@ -19,8 +19,12 @@ npm i feathers-utils
|
|
|
19
19
|
|
|
20
20
|
### Hooks
|
|
21
21
|
|
|
22
|
-
- `
|
|
23
|
-
- `
|
|
22
|
+
- `checkMulti`: throws if the request is **multi** data, but the service has `allowsMulti(method)` returns `false`
|
|
23
|
+
- `createRelated`: simply create related items from a hook.
|
|
24
|
+
- `onDelete`: simply remove/set null related items from a hook.
|
|
25
|
+
- `removeRelated`: simple remove related items from a hook. Basically `cascade` at feathers level.
|
|
26
|
+
- `runPerItem`: run a function for every item. Meant for `multi:true`.
|
|
27
|
+
- `setData`: map properties from `context` to `data`. Something like `userId: context.params.user.id`
|
|
24
28
|
|
|
25
29
|
### Mixins
|
|
26
30
|
|
|
@@ -28,11 +32,14 @@ npm i feathers-utils
|
|
|
28
32
|
|
|
29
33
|
### Utils
|
|
30
34
|
|
|
31
|
-
- `addHook`: add hooks to specific services
|
|
32
35
|
- `filterQuery`
|
|
36
|
+
- `getItemsIsArray(context)`: returns `{ items: any[], isArray: boolean }`
|
|
37
|
+
- `getPaginate`
|
|
33
38
|
- `isMulti(context) => Boolean`: returns true, if `find`, `create/patch/remove`: multi
|
|
39
|
+
- `isPaginated`
|
|
34
40
|
- `markHookForSkip`: add hookName to `context.params.skipHooks` - also see `shouldSkip`
|
|
35
41
|
- `mergeQuery`: deeply merges queries
|
|
36
42
|
- `mergeArrays`: merges arrays with intersection options
|
|
37
43
|
- `pushSet`: if existing array: *push*, else *set*
|
|
44
|
+
- `setResultEmpty`
|
|
38
45
|
- `shouldSkip`: checks `context.params.skipHooks` for `'all' | '${hookName}' | '${type}:${hookName}'` - also see `markHookForSkip`
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { validateQueryProperty } from "../utils/validateQueryProperty";
|
|
2
|
+
export const filterArray = () => (arr, { operators }) => {
|
|
3
|
+
if (arr && !Array.isArray(arr)) {
|
|
4
|
+
throw new Error("Invalid query parameter $and. It has to be an array");
|
|
5
|
+
}
|
|
6
|
+
if (Array.isArray(arr)) {
|
|
7
|
+
return arr.map((current) => validateQueryProperty(current, operators));
|
|
8
|
+
}
|
|
9
|
+
return arr;
|
|
10
|
+
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare function checkMulti():
|
|
1
|
+
import type { ReturnSyncHook } from "../types";
|
|
2
|
+
export declare function checkMulti(): ReturnSyncHook;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { HookContext } from "@feathersjs/feathers";
|
|
2
|
+
import type { CreateRelatedOptions } from "../types";
|
|
3
|
+
export declare function createRelated<S = Record<string, any>>({ service, multi, data, createItemsInDataArraySeparately }: CreateRelatedOptions<S>): (context: HookContext) => Promise<HookContext>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { checkContext } from "feathers-hooks-common";
|
|
2
|
+
import { getItemsIsArray } from "../utils/getItemsIsArray";
|
|
3
|
+
export function createRelated({ service, multi = true, data, createItemsInDataArraySeparately = true }) {
|
|
4
|
+
if (!service || !data) {
|
|
5
|
+
throw "initialize hook 'createRelated' completely!";
|
|
6
|
+
}
|
|
7
|
+
return async (context) => {
|
|
8
|
+
// @ts-expect-error wait for feathers-hooks-common to update
|
|
9
|
+
checkContext(context, "after", undefined, "createRelated");
|
|
10
|
+
const { items } = getItemsIsArray(context);
|
|
11
|
+
let dataToCreate = (await Promise.all(items.map(async (item) => data(item, context)))).filter(x => !!x);
|
|
12
|
+
if (createItemsInDataArraySeparately) {
|
|
13
|
+
dataToCreate = dataToCreate.flat();
|
|
14
|
+
}
|
|
15
|
+
if (!dataToCreate || dataToCreate.length <= 0) {
|
|
16
|
+
return context;
|
|
17
|
+
}
|
|
18
|
+
if (multi) {
|
|
19
|
+
await context.app.service(service).create(dataToCreate);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
await Promise.all(dataToCreate.map(async (item) => context.app.service(service).create(item)));
|
|
23
|
+
}
|
|
24
|
+
return context;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { HookContext } from "@feathersjs/feathers";
|
|
2
|
+
import type { OnDeleteOptions } from "../types";
|
|
3
|
+
export declare function onDelete<S = Record<string, any>>(service: keyof S, { keyThere, keyHere, onDelete, blocking }: OnDeleteOptions): (context: HookContext) => Promise<HookContext>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { checkContext } from "feathers-hooks-common";
|
|
2
|
+
import { getItemsIsArray } from "../utils/getItemsIsArray";
|
|
3
|
+
export function onDelete(service, { keyThere, keyHere = "id", onDelete = "cascade", blocking = true }) {
|
|
4
|
+
if (!service || !keyThere) {
|
|
5
|
+
throw "initialize hook 'removeRelated' completely!";
|
|
6
|
+
}
|
|
7
|
+
if (!["cascade", "set null"].includes(onDelete)) {
|
|
8
|
+
throw "onDelete must be 'cascade' or 'set null'";
|
|
9
|
+
}
|
|
10
|
+
return async (context) => {
|
|
11
|
+
// @ts-expect-error wait for feathers-hooks-common to update
|
|
12
|
+
checkContext(context, "after", "remove", "onDelete");
|
|
13
|
+
const { items } = getItemsIsArray(context);
|
|
14
|
+
let ids = items.map(x => x[keyHere]).filter(x => !!x);
|
|
15
|
+
ids = [...new Set(ids)];
|
|
16
|
+
if (!ids || ids.length <= 0) {
|
|
17
|
+
return context;
|
|
18
|
+
}
|
|
19
|
+
const params = {
|
|
20
|
+
query: {
|
|
21
|
+
[keyThere]: {
|
|
22
|
+
$in: ids
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
paginate: false
|
|
26
|
+
};
|
|
27
|
+
let promise;
|
|
28
|
+
if (onDelete === "cascade") {
|
|
29
|
+
promise = context.app.service(service).remove(null, params);
|
|
30
|
+
}
|
|
31
|
+
else if (onDelete === "set null") {
|
|
32
|
+
const data = { [keyThere]: null };
|
|
33
|
+
promise = context.app.service(service).patch(null, data, params);
|
|
34
|
+
}
|
|
35
|
+
if (blocking) {
|
|
36
|
+
await promise;
|
|
37
|
+
}
|
|
38
|
+
return context;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { HookContext } from "@feathersjs/feathers";
|
|
2
|
+
import type { RemoveRelatedOptions } from "../types";
|
|
3
|
+
export declare function removeRelated<S = Record<string, any>>({ service, keyThere, keyHere, blocking }: RemoveRelatedOptions<S>): (context: HookContext) => Promise<HookContext>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { checkContext } from "feathers-hooks-common";
|
|
2
|
+
import { getItemsIsArray } from "../utils/getItemsIsArray";
|
|
3
|
+
export function removeRelated({ service, keyThere, keyHere = "id", blocking = true }) {
|
|
4
|
+
if (!service || !keyThere) {
|
|
5
|
+
throw "initialize hook 'removeRelated' completely!";
|
|
6
|
+
}
|
|
7
|
+
return async (context) => {
|
|
8
|
+
// @ts-expect-error wait for feathers-hooks-common to update
|
|
9
|
+
checkContext(context, "after", "remove", "removeRelated");
|
|
10
|
+
const { items } = getItemsIsArray(context);
|
|
11
|
+
let ids = items.map(x => x[keyHere]).filter(x => !!x);
|
|
12
|
+
ids = [...new Set(ids)];
|
|
13
|
+
if (!ids || ids.length <= 0) {
|
|
14
|
+
return context;
|
|
15
|
+
}
|
|
16
|
+
// feathers does not accept `paginate: false` for remove, but some adapters need it to work properly
|
|
17
|
+
const promise = context.app.service(service).remove(null, {
|
|
18
|
+
query: {
|
|
19
|
+
[keyThere]: {
|
|
20
|
+
$in: ids
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
paginate: false
|
|
24
|
+
});
|
|
25
|
+
if (blocking) {
|
|
26
|
+
await promise;
|
|
27
|
+
}
|
|
28
|
+
return context;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { HookRunPerItemOptions } from "../types";
|
|
1
|
+
import type { HookRunPerItemOptions, ReturnAsyncHook, Promisable } from "../types";
|
|
2
2
|
import type { HookContext } from "@feathersjs/feathers";
|
|
3
|
-
|
|
4
|
-
export declare const runPerItem: (actionPerItem: (item: any, context: HookContext) => Promisable<any>, options: HookRunPerItemOptions) => (context: HookContext) => Promise<HookContext>;
|
|
3
|
+
export declare const runPerItem: (actionPerItem: (item: any, context: HookContext) => Promisable<any>, _options?: HookRunPerItemOptions) => ReturnAsyncHook;
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { getItems } from "feathers-hooks-common";
|
|
2
1
|
import { shouldSkip } from "../utils/shouldSkip";
|
|
2
|
+
import { getItemsIsArray } from "../utils/getItemsIsArray";
|
|
3
3
|
const makeOptions = (options) => {
|
|
4
4
|
options = options || {};
|
|
5
5
|
return Object.assign({
|
|
6
6
|
wait: true
|
|
7
7
|
}, options);
|
|
8
8
|
};
|
|
9
|
-
export const runPerItem = (
|
|
10
|
-
|
|
9
|
+
export const runPerItem = (
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
|
+
actionPerItem, _options) => {
|
|
12
|
+
const options = makeOptions(_options);
|
|
11
13
|
return async (context) => {
|
|
12
14
|
if (shouldSkip("runForItems", context)) {
|
|
13
15
|
return context;
|
|
14
16
|
}
|
|
15
|
-
|
|
16
|
-
let items = getItems(context);
|
|
17
|
-
items = (Array.isArray(items)) ? items : [items];
|
|
17
|
+
const { items } = getItemsIsArray(context);
|
|
18
18
|
const promises = items.map(async (item) => {
|
|
19
19
|
await actionPerItem(item, context);
|
|
20
20
|
});
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { HookContext } from "@feathersjs/feathers";
|
|
2
|
-
import type { HookSetDataOptions } from "../types";
|
|
3
1
|
import type { PropertyPath } from "lodash";
|
|
4
|
-
|
|
2
|
+
import type { HookSetDataOptions, ReturnSyncHook } from "../types";
|
|
3
|
+
export declare function setData(from: PropertyPath, to: PropertyPath, _options?: HookSetDataOptions): ReturnSyncHook;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import _get from "lodash/get";
|
|
2
|
-
import _set from "lodash/set";
|
|
3
|
-
import _has from "lodash/has";
|
|
4
|
-
import { getItems } from "feathers-hooks-common";
|
|
1
|
+
import _get from "lodash/get.js";
|
|
2
|
+
import _set from "lodash/set.js";
|
|
3
|
+
import _has from "lodash/has.js";
|
|
5
4
|
import { Forbidden } from "@feathersjs/errors";
|
|
5
|
+
import { getItemsIsArray } from "../utils/getItemsIsArray";
|
|
6
6
|
const defaultOptions = {
|
|
7
7
|
allowUndefined: false,
|
|
8
8
|
overwrite: true
|
|
@@ -10,9 +10,7 @@ const defaultOptions = {
|
|
|
10
10
|
export function setData(from, to, _options) {
|
|
11
11
|
const options = Object.assign({}, defaultOptions, _options);
|
|
12
12
|
return (context) => {
|
|
13
|
-
|
|
14
|
-
let items = getItems(context);
|
|
15
|
-
items = (Array.isArray(items)) ? items : [items];
|
|
13
|
+
const { items } = getItemsIsArray(context);
|
|
16
14
|
if (!_has(context, from)) {
|
|
17
15
|
if (!context.params?.provider || options.allowUndefined === true) {
|
|
18
16
|
return context;
|
|
@@ -24,7 +22,14 @@ export function setData(from, to, _options) {
|
|
|
24
22
|
}
|
|
25
23
|
const val = _get(context, from);
|
|
26
24
|
items.forEach((item) => {
|
|
27
|
-
|
|
25
|
+
let overwrite;
|
|
26
|
+
if (typeof options.overwrite === "function") {
|
|
27
|
+
overwrite = options.overwrite(item, context);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
overwrite = options.overwrite;
|
|
31
|
+
}
|
|
32
|
+
if (!overwrite && _has(item, to)) {
|
|
28
33
|
return;
|
|
29
34
|
}
|
|
30
35
|
_set(item, to, val);
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -4,10 +4,12 @@ import { runPerItem } from "./hooks/runPerItem";
|
|
|
4
4
|
export declare const hooks: {
|
|
5
5
|
checkMulti: typeof checkMulti;
|
|
6
6
|
setData: typeof setData;
|
|
7
|
-
runPerItem: (actionPerItem: (item: any, context: import("@feathersjs/feathers/lib").HookContext<import("@feathersjs/feathers/lib").Application<any, any>, any>) => any,
|
|
7
|
+
runPerItem: (actionPerItem: (item: any, context: import("@feathersjs/feathers/lib").HookContext<import("@feathersjs/feathers/lib").Application<any, any>, any>) => any, _options?: import("./types").HookRunPerItemOptions | undefined) => import("./types").ReturnAsyncHook;
|
|
8
8
|
};
|
|
9
9
|
export { checkMulti };
|
|
10
|
+
export { createRelated } from "./hooks/createRelated";
|
|
10
11
|
export { setData };
|
|
12
|
+
export { removeRelated } from "./hooks/removeRelated";
|
|
11
13
|
export { runPerItem };
|
|
12
14
|
import { debounceMixin, DebouncedService, DebouncedStore } from "./mixins/debounce-mixin";
|
|
13
15
|
export declare const mixins: {
|
|
@@ -25,6 +27,10 @@ export { mergeArrays } from "./utils/mergeQuery/mergeArrays";
|
|
|
25
27
|
export { pushSet } from "./utils/pushSet";
|
|
26
28
|
export { setResultEmpty } from "./utils/setResultEmpty";
|
|
27
29
|
export { markHookForSkip } from "./utils/markHookForSkip";
|
|
28
|
-
export { shouldSkip } from "./utils/shouldSkip";
|
|
29
30
|
export { filterQuery } from "./utils/filterQuery";
|
|
31
|
+
export { getItemsIsArray } from "./utils/getItemsIsArray";
|
|
32
|
+
export { onDelete } from "./hooks/onDelete";
|
|
33
|
+
export { shouldSkip } from "./utils/shouldSkip";
|
|
34
|
+
export { validateQueryProperty } from "./utils/validateQueryProperty";
|
|
35
|
+
export { filterArray } from "./filters/array";
|
|
30
36
|
export * from "./types";
|
package/dist/esm/index.js
CHANGED
|
@@ -8,7 +8,9 @@ export const hooks = {
|
|
|
8
8
|
runPerItem
|
|
9
9
|
};
|
|
10
10
|
export { checkMulti };
|
|
11
|
+
export { createRelated } from "./hooks/createRelated";
|
|
11
12
|
export { setData };
|
|
13
|
+
export { removeRelated } from "./hooks/removeRelated";
|
|
12
14
|
export { runPerItem };
|
|
13
15
|
import { debounceMixin, DebouncedStore } from "./mixins/debounce-mixin";
|
|
14
16
|
export const mixins = {
|
|
@@ -25,6 +27,11 @@ export { mergeArrays } from "./utils/mergeQuery/mergeArrays";
|
|
|
25
27
|
export { pushSet } from "./utils/pushSet";
|
|
26
28
|
export { setResultEmpty } from "./utils/setResultEmpty";
|
|
27
29
|
export { markHookForSkip } from "./utils/markHookForSkip";
|
|
28
|
-
export { shouldSkip } from "./utils/shouldSkip";
|
|
29
30
|
export { filterQuery } from "./utils/filterQuery";
|
|
31
|
+
export { getItemsIsArray } from "./utils/getItemsIsArray";
|
|
32
|
+
export { onDelete } from "./hooks/onDelete";
|
|
33
|
+
export { shouldSkip } from "./utils/shouldSkip";
|
|
34
|
+
export { validateQueryProperty } from "./utils/validateQueryProperty";
|
|
35
|
+
// query filters
|
|
36
|
+
export { filterArray } from "./filters/array";
|
|
30
37
|
export * from "./types";
|
|
@@ -7,7 +7,7 @@ export declare class DebouncedStore {
|
|
|
7
7
|
private _options;
|
|
8
8
|
private _isRunningById;
|
|
9
9
|
_queueById: Record<string, DebouncedFunc<((id: Id, action: DebouncedFunctionApp) => void | Promise<void>)>>;
|
|
10
|
-
add: (id: Id, action: (app?: Application
|
|
10
|
+
add: (id: Id, action: (app?: Application) => void | Promise<void>) => void | Promise<void> | undefined;
|
|
11
11
|
constructor(app: Application, options?: Partial<DebouncedStoreOptions>);
|
|
12
12
|
private unbounced;
|
|
13
13
|
private debounceById;
|
|
@@ -2,7 +2,7 @@ import { DebouncedStore } from "./DebouncedStore";
|
|
|
2
2
|
import type { Application, FeathersService } from "@feathersjs/feathers";
|
|
3
3
|
import type { InitDebounceMixinOptions } from "../../types";
|
|
4
4
|
export declare type DebouncedService = FeathersService & {
|
|
5
|
-
debouncedStore
|
|
5
|
+
debouncedStore: DebouncedStore;
|
|
6
6
|
};
|
|
7
7
|
export declare function debounceMixin(options?: Partial<InitDebounceMixinOptions>): ((app: Application) => void);
|
|
8
8
|
export { DebouncedStore };
|
package/dist/esm/types.d.ts
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
import type { Application } from "@feathersjs/feathers";
|
|
2
|
-
import type {
|
|
1
|
+
import type { Application, HookContext } from "@feathersjs/feathers";
|
|
2
|
+
import type { AdapterBase, FilterQueryOptions as PlainFilterQueryOptions } from "@feathersjs/adapter-commons";
|
|
3
3
|
export declare type Path = Array<string | number>;
|
|
4
|
+
export declare type MaybeArray<T> = T | T[];
|
|
5
|
+
export declare type Promisable<T> = T | Promise<T>;
|
|
4
6
|
export declare type HookType = "before" | "after" | "error";
|
|
5
7
|
export declare type ServiceMethodName = "find" | "get" | "create" | "update" | "patch" | "remove";
|
|
8
|
+
export declare type ReturnSyncHook = (context: HookContext) => HookContext;
|
|
9
|
+
export declare type ReturnAsyncHook = (context: HookContext) => Promise<HookContext>;
|
|
6
10
|
export declare type Handle = "target" | "source" | "combine" | "intersect" | "intersectOrFull";
|
|
7
11
|
export declare type FirstLast = "first" | "last";
|
|
12
|
+
export declare type Predicate<T = any> = (item: T) => boolean;
|
|
13
|
+
export declare type PredicateWithContext<T = any> = (item: T, context: HookContext) => boolean;
|
|
8
14
|
export interface HookSetDataOptions {
|
|
9
15
|
allowUndefined?: boolean;
|
|
10
|
-
overwrite?: boolean;
|
|
16
|
+
overwrite?: boolean | PredicateWithContext;
|
|
11
17
|
}
|
|
12
18
|
export interface AddHookOptions {
|
|
13
19
|
types: HookType[];
|
|
@@ -19,6 +25,25 @@ export interface AddHookOptions {
|
|
|
19
25
|
export interface HookRunPerItemOptions {
|
|
20
26
|
wait?: boolean;
|
|
21
27
|
}
|
|
28
|
+
export interface RemoveRelatedOptions<S = Record<string, any>> {
|
|
29
|
+
service: keyof S;
|
|
30
|
+
keyThere: string;
|
|
31
|
+
keyHere: string;
|
|
32
|
+
blocking?: boolean;
|
|
33
|
+
}
|
|
34
|
+
export interface CreateRelatedOptions<S = Record<string, any>> {
|
|
35
|
+
service: keyof S;
|
|
36
|
+
multi?: boolean;
|
|
37
|
+
data: (item: any, context: HookContext) => Promisable<Record<string, any>>;
|
|
38
|
+
createItemsInDataArraySeparately?: boolean;
|
|
39
|
+
}
|
|
40
|
+
export declare type OnDeleteAction = "cascade" | "set null";
|
|
41
|
+
export interface OnDeleteOptions {
|
|
42
|
+
keyThere: string;
|
|
43
|
+
keyHere: string;
|
|
44
|
+
onDelete: OnDeleteAction;
|
|
45
|
+
blocking?: boolean;
|
|
46
|
+
}
|
|
22
47
|
export interface InitDebounceMixinOptions {
|
|
23
48
|
default: Partial<DebouncedStoreOptions>;
|
|
24
49
|
blacklist: string[];
|
|
@@ -44,17 +69,11 @@ export interface MergeQueryOptions<T> extends FilterQueryOptions<T> {
|
|
|
44
69
|
};
|
|
45
70
|
}
|
|
46
71
|
export interface FilterQueryOptions<T> {
|
|
47
|
-
service?:
|
|
48
|
-
operators?:
|
|
49
|
-
filters?:
|
|
50
|
-
}
|
|
51
|
-
export interface
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
export interface FilterQueryResult {
|
|
56
|
-
filters: Record<string, unknown>;
|
|
57
|
-
query: Record<string, unknown>;
|
|
58
|
-
paginate?: unknown;
|
|
59
|
-
[key: string]: unknown;
|
|
72
|
+
service?: AdapterBase<T>;
|
|
73
|
+
operators?: PlainFilterQueryOptions["operators"];
|
|
74
|
+
filters?: PlainFilterQueryOptions["filters"];
|
|
75
|
+
}
|
|
76
|
+
export interface GetItemsIsArrayOptions<T = any> {
|
|
77
|
+
items: T[];
|
|
78
|
+
isArray: boolean;
|
|
60
79
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { FilterQueryOptions, FilterQueryResult } from "../types";
|
|
2
1
|
import type { Query } from "@feathersjs/feathers";
|
|
3
|
-
|
|
2
|
+
import type { FilterQueryOptions } from "../types";
|
|
3
|
+
export declare function filterQuery<T>(query: Query, _options?: FilterQueryOptions<T>): any;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { filterQuery as plainFilterQuery } from "@feathersjs/adapter-commons";
|
|
2
|
-
export function filterQuery(query,
|
|
1
|
+
import { filterQuery as plainFilterQuery, } from "@feathersjs/adapter-commons";
|
|
2
|
+
export function filterQuery(query, _options) {
|
|
3
3
|
query = query || {};
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
_options = _options || {};
|
|
5
|
+
const { service, ...options } = _options;
|
|
6
|
+
if (service) {
|
|
7
7
|
const operators = options.operators
|
|
8
8
|
? options.operators
|
|
9
|
-
: service.options?.
|
|
9
|
+
: service.options?.operators;
|
|
10
10
|
const filters = options.filters
|
|
11
11
|
? options.filters
|
|
12
12
|
: service.options?.filters;
|
|
@@ -17,7 +17,9 @@ export function filterQuery(query, options) {
|
|
|
17
17
|
if (filters) {
|
|
18
18
|
optionsForFilterQuery.filters = filters;
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
// @ts-expect-error service has no filterQuery method
|
|
21
|
+
if (service && "filterQuery" in service && typeof service.filterQuery === "function") {
|
|
22
|
+
// @ts-expect-error service has no filterQuery method
|
|
21
23
|
return service.filterQuery({ query }, optionsForFilterQuery);
|
|
22
24
|
}
|
|
23
25
|
else {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2
|
+
export const getItemsIsArray = (context) => {
|
|
3
|
+
let itemOrItems = context.type === "before"
|
|
4
|
+
? context.data
|
|
5
|
+
: context.result;
|
|
6
|
+
itemOrItems = itemOrItems && context.method === "find"
|
|
7
|
+
? (itemOrItems.data || itemOrItems)
|
|
8
|
+
: itemOrItems;
|
|
9
|
+
const isArray = Array.isArray(itemOrItems);
|
|
10
|
+
return {
|
|
11
|
+
items: (isArray)
|
|
12
|
+
? itemOrItems
|
|
13
|
+
: (itemOrItems != null)
|
|
14
|
+
? [itemOrItems]
|
|
15
|
+
: [],
|
|
16
|
+
isArray
|
|
17
|
+
};
|
|
18
|
+
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { HookContext } from "@feathersjs/feathers";
|
|
1
|
+
import type { HookContext } from "@feathersjs/feathers";
|
|
2
2
|
export declare const isPaginated: (context: HookContext) => boolean;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { HookContext } from "@feathersjs/feathers";
|
|
2
|
-
import type { HookType } from "
|
|
3
|
-
export declare function markHookForSkip<T>(hookName: string, type: "all" | HookType
|
|
2
|
+
import type { HookType, MaybeArray } from "../types";
|
|
3
|
+
export declare function markHookForSkip<T>(hookName: string, type: "all" | MaybeArray<HookType>, context?: Partial<HookContext<T>>): Partial<HookContext<T>>;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import _get from "lodash/get";
|
|
2
|
-
import _has from "lodash/has";
|
|
3
|
-
import _isEmpty from "lodash/isEmpty";
|
|
4
|
-
import _isEqual from "lodash/isEqual";
|
|
5
|
-
import _merge from "lodash/merge";
|
|
6
|
-
import _set from "lodash/set";
|
|
7
|
-
import _uniqWith from "lodash/uniqWith";
|
|
1
|
+
import _get from "lodash/get.js";
|
|
2
|
+
import _has from "lodash/has.js";
|
|
3
|
+
import _isEmpty from "lodash/isEmpty.js";
|
|
4
|
+
import _isEqual from "lodash/isEqual.js";
|
|
5
|
+
import _merge from "lodash/merge.js";
|
|
6
|
+
import _set from "lodash/set.js";
|
|
7
|
+
import _uniqWith from "lodash/uniqWith.js";
|
|
8
8
|
import { mergeArrays } from "./mergeArrays";
|
|
9
9
|
import { filterQuery } from "../filterQuery";
|
|
10
10
|
import { Forbidden } from "@feathersjs/errors";
|
|
@@ -227,12 +227,21 @@ function makeDefaultOptions(options) {
|
|
|
227
227
|
}
|
|
228
228
|
return options;
|
|
229
229
|
}
|
|
230
|
+
function moveProperty(source, target, key) {
|
|
231
|
+
if (!Object.prototype.hasOwnProperty.call(source, key)) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
target[key] = source[key];
|
|
235
|
+
delete source[key];
|
|
236
|
+
}
|
|
230
237
|
export function mergeQuery(target, source, options) {
|
|
231
238
|
const fullOptions = makeDefaultOptions(options);
|
|
232
239
|
const { filters: targetFilters, query: targetQuery } = filterQuery(target, {
|
|
233
240
|
operators: fullOptions.operators,
|
|
234
241
|
service: fullOptions.service
|
|
235
242
|
});
|
|
243
|
+
moveProperty(targetFilters, targetQuery, "$or");
|
|
244
|
+
moveProperty(targetFilters, targetQuery, "$and");
|
|
236
245
|
if (target.$limit) {
|
|
237
246
|
targetFilters.$limit = target.$limit;
|
|
238
247
|
}
|
|
@@ -242,6 +251,8 @@ export function mergeQuery(target, source, options) {
|
|
|
242
251
|
operators: fullOptions.operators,
|
|
243
252
|
service: fullOptions.service
|
|
244
253
|
});
|
|
254
|
+
moveProperty(sourceFilters, sourceQuery, "$or");
|
|
255
|
+
moveProperty(sourceFilters, sourceQuery, "$and");
|
|
245
256
|
if (source.$limit) {
|
|
246
257
|
sourceFilters.$limit = source.$limit;
|
|
247
258
|
}
|
|
@@ -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[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import _isEqual from "lodash/isEqual";
|
|
2
|
-
import _get from "lodash/get";
|
|
3
|
-
import _set from "lodash/set";
|
|
1
|
+
import _isEqual from "lodash/isEqual.js";
|
|
2
|
+
import _get from "lodash/get.js";
|
|
3
|
+
import _set from "lodash/set.js";
|
|
4
4
|
export const pushSet = (obj, path, val, options) => {
|
|
5
5
|
options = options || {};
|
|
6
6
|
let arr = _get(obj, path);
|
|
@@ -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,20 @@
|
|
|
1
|
+
import { _ } from "@feathersjs/commons";
|
|
2
|
+
import { BadRequest } from "@feathersjs/errors";
|
|
3
|
+
const isPlainObject = (value) => _.isObject(value) && value.constructor === {}.constructor;
|
|
4
|
+
export const validateQueryProperty = (query, operators = []) => {
|
|
5
|
+
if (!isPlainObject(query)) {
|
|
6
|
+
return query;
|
|
7
|
+
}
|
|
8
|
+
for (const key of Object.keys(query)) {
|
|
9
|
+
if (key.startsWith("$") && !operators.includes(key)) {
|
|
10
|
+
throw new BadRequest(`Invalid query parameter ${key}`, query);
|
|
11
|
+
}
|
|
12
|
+
const value = query[key];
|
|
13
|
+
if (isPlainObject(value)) {
|
|
14
|
+
query[key] = validateQueryProperty(value, operators);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
...query
|
|
19
|
+
};
|
|
20
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.filterArray = void 0;
|
|
4
|
+
const validateQueryProperty_1 = require("../utils/validateQueryProperty");
|
|
5
|
+
const filterArray = () => (arr, { operators }) => {
|
|
6
|
+
if (arr && !Array.isArray(arr)) {
|
|
7
|
+
throw new Error("Invalid query parameter $and. It has to be an array");
|
|
8
|
+
}
|
|
9
|
+
if (Array.isArray(arr)) {
|
|
10
|
+
return arr.map((current) => (0, validateQueryProperty_1.validateQueryProperty)(current, operators));
|
|
11
|
+
}
|
|
12
|
+
return arr;
|
|
13
|
+
};
|
|
14
|
+
exports.filterArray = filterArray;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare function checkMulti():
|
|
1
|
+
import type { ReturnSyncHook } from "../types";
|
|
2
|
+
export declare function checkMulti(): ReturnSyncHook;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { HookContext } from "@feathersjs/feathers";
|
|
2
|
+
import type { CreateRelatedOptions } from "../types";
|
|
3
|
+
export declare function createRelated<S = Record<string, any>>({ service, multi, data, createItemsInDataArraySeparately }: CreateRelatedOptions<S>): (context: HookContext) => Promise<HookContext>;
|