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/src/hooks/setData.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import _get from "lodash/get";
|
|
2
|
-
import _set from "lodash/set";
|
|
3
|
-
import _has from "lodash/has";
|
|
4
|
-
|
|
5
|
-
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";
|
|
6
4
|
|
|
7
5
|
import { Forbidden } from "@feathersjs/errors";
|
|
6
|
+
import { getItemsIsArray } from "../utils/getItemsIsArray";
|
|
8
7
|
|
|
9
8
|
import type { HookContext } from "@feathersjs/feathers";
|
|
9
|
+
import type { PropertyPath } from "lodash";
|
|
10
10
|
|
|
11
11
|
import type {
|
|
12
|
-
HookSetDataOptions
|
|
12
|
+
HookSetDataOptions,
|
|
13
|
+
ReturnSyncHook
|
|
13
14
|
} from "../types";
|
|
14
|
-
import type { PropertyPath } from "lodash";
|
|
15
15
|
|
|
16
16
|
const defaultOptions: Required<HookSetDataOptions> = {
|
|
17
17
|
allowUndefined: false,
|
|
@@ -22,13 +22,11 @@ export function setData(
|
|
|
22
22
|
from: PropertyPath,
|
|
23
23
|
to: PropertyPath,
|
|
24
24
|
_options?: HookSetDataOptions
|
|
25
|
-
):
|
|
25
|
+
): ReturnSyncHook {
|
|
26
26
|
const options: Required<HookSetDataOptions> = Object.assign({}, defaultOptions, _options);
|
|
27
27
|
return (context: HookContext): HookContext => {
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
let items = getItems(context);
|
|
31
|
-
items = (Array.isArray(items)) ? items : [items];
|
|
29
|
+
const { items } = getItemsIsArray(context);
|
|
32
30
|
|
|
33
31
|
if (!_has(context, from)) {
|
|
34
32
|
if (!context.params?.provider || options.allowUndefined === true) {
|
|
@@ -45,7 +43,14 @@ export function setData(
|
|
|
45
43
|
const val = _get(context, from);
|
|
46
44
|
|
|
47
45
|
items.forEach((item: Record<string, unknown>) => {
|
|
48
|
-
|
|
46
|
+
let overwrite: boolean;
|
|
47
|
+
if (typeof options.overwrite === "function") {
|
|
48
|
+
overwrite = options.overwrite(item, context);
|
|
49
|
+
} else {
|
|
50
|
+
overwrite = options.overwrite;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!overwrite && _has(item, to)) { return; }
|
|
49
54
|
|
|
50
55
|
_set(item, to, val);
|
|
51
56
|
});
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// hooks
|
|
2
2
|
import { checkMulti } from "./hooks/checkMulti";
|
|
3
3
|
import { setData } from "./hooks/setData";
|
|
4
|
+
|
|
4
5
|
import { runPerItem } from "./hooks/runPerItem";
|
|
5
6
|
|
|
6
7
|
export const hooks = {
|
|
@@ -10,7 +11,9 @@ export const hooks = {
|
|
|
10
11
|
};
|
|
11
12
|
|
|
12
13
|
export { checkMulti };
|
|
14
|
+
export { createRelated } from "./hooks/createRelated";
|
|
13
15
|
export { setData };
|
|
16
|
+
export { removeRelated } from "./hooks/removeRelated";
|
|
14
17
|
export { runPerItem };
|
|
15
18
|
|
|
16
19
|
import { debounceMixin, DebouncedService, DebouncedStore } from "./mixins/debounce-mixin";
|
|
@@ -33,8 +36,15 @@ export { pushSet } from "./utils/pushSet";
|
|
|
33
36
|
export { setResultEmpty } from "./utils/setResultEmpty";
|
|
34
37
|
|
|
35
38
|
export { markHookForSkip } from "./utils/markHookForSkip";
|
|
39
|
+
export { filterQuery } from "./utils/filterQuery";
|
|
40
|
+
export { getItemsIsArray } from "./utils/getItemsIsArray";
|
|
41
|
+
export { onDelete } from "./hooks/onDelete";
|
|
36
42
|
export { shouldSkip } from "./utils/shouldSkip";
|
|
37
43
|
|
|
38
|
-
export {
|
|
44
|
+
export { validateQueryProperty } from "./utils/validateQueryProperty";
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
// query filters
|
|
48
|
+
export { filterArray } from "./filters/array";
|
|
39
49
|
|
|
40
50
|
export * from "./types";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import _debounce from "lodash/debounce";
|
|
1
|
+
import _debounce from "lodash/debounce.js";
|
|
2
2
|
|
|
3
3
|
import type { DebouncedFunc } from "lodash";
|
|
4
4
|
import type { Application, Id } from "@feathersjs/feathers";
|
|
@@ -18,58 +18,58 @@ export const makeDefaultOptions = (): DebouncedStoreOptions => {
|
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
export class DebouncedStore {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
21
|
+
private _app: Application;
|
|
22
|
+
private _options: DebouncedStoreOptions;
|
|
23
|
+
private _isRunningById: Record<string, unknown>;
|
|
24
|
+
_queueById: Record<string, DebouncedFunc<((id: Id, action: DebouncedFunctionApp) => void | Promise<void>)>>;
|
|
25
|
+
//_waitingById: Record<string, WaitingObject>;
|
|
26
|
+
add;
|
|
27
|
+
constructor(app: Application, options?: Partial<DebouncedStoreOptions>) {
|
|
28
|
+
this._app = app;
|
|
29
|
+
this._options = Object.assign(makeDefaultOptions(), options);
|
|
30
|
+
this._queueById = {};
|
|
31
|
+
this._isRunningById = {};
|
|
32
|
+
//this._waitingById = {};
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
private async unbounced(id: Id, action: DebouncedFunctionApp): Promise<void> {
|
|
46
|
-
if (this._queueById[id] === undefined) {
|
|
47
|
-
return;
|
|
34
|
+
this.add = this.debounceById(
|
|
35
|
+
this.unbounced,
|
|
36
|
+
this._options.wait,
|
|
37
|
+
{
|
|
38
|
+
leading: this._options.leading,
|
|
39
|
+
maxWait: this._options.maxWait,
|
|
40
|
+
trailing: this._options.trailing
|
|
48
41
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private async unbounced(id: Id, action: DebouncedFunctionApp): Promise<void> {
|
|
46
|
+
if (this._queueById[id] === undefined) {
|
|
47
|
+
return;
|
|
53
48
|
}
|
|
49
|
+
delete this._queueById[id];
|
|
50
|
+
this._isRunningById[id] = true;
|
|
51
|
+
await action(this._app);
|
|
52
|
+
delete this._isRunningById[id];
|
|
53
|
+
}
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return this._queueById[id](id, action);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
this._queueById[id] = _debounce((id, action) => {
|
|
66
|
-
this.unbounced(id, action);
|
|
67
|
-
}, wait, { ...options, leading: false }); // leading required for return promise
|
|
55
|
+
private debounceById(
|
|
56
|
+
func: ((id: Id, action: DebouncedFunctionApp) => Promise<void>),
|
|
57
|
+
wait: number,
|
|
58
|
+
options?: Partial<DebouncedStoreOptions>
|
|
59
|
+
) {
|
|
60
|
+
return (id: Id, action: ((app?: Application) => void | Promise<void>)) => {
|
|
61
|
+
if (typeof this._queueById[id] === "function") {
|
|
68
62
|
return this._queueById[id](id, action);
|
|
69
|
-
}
|
|
70
|
-
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
this._queueById[id] = _debounce((id, action) => {
|
|
66
|
+
this.unbounced(id, action);
|
|
67
|
+
}, wait, { ...options, leading: false }); // leading required for return promise
|
|
68
|
+
return this._queueById[id](id, action);
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
cancel(id: Id): void {
|
|
73
|
+
delete this._queueById[id];
|
|
74
|
+
}
|
|
75
75
|
}
|
|
@@ -11,14 +11,17 @@ import type {
|
|
|
11
11
|
} from "../../types";
|
|
12
12
|
|
|
13
13
|
export type DebouncedService = FeathersService & {
|
|
14
|
-
debouncedStore
|
|
14
|
+
debouncedStore: DebouncedStore;
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
export function debounceMixin(
|
|
17
|
+
export function debounceMixin(
|
|
18
|
+
options?: Partial<InitDebounceMixinOptions>
|
|
19
|
+
): ((app: Application) => void) {
|
|
18
20
|
return (app: Application): void => {
|
|
19
21
|
options = options || {};
|
|
20
22
|
const defaultOptions = Object.assign(makeDefaultOptions(), options?.default);
|
|
21
|
-
|
|
23
|
+
|
|
24
|
+
app.mixins.push((service: any, path) => {
|
|
22
25
|
// if path is on blacklist, don't add debouncedStore to service
|
|
23
26
|
if (options?.blacklist && options.blacklist.includes(path)) return;
|
|
24
27
|
// if service already has registered something on `debouncedStore`
|
package/src/types.ts
CHANGED
|
@@ -1,18 +1,31 @@
|
|
|
1
|
-
import type { Application } from "@feathersjs/feathers";
|
|
2
|
-
import type {
|
|
1
|
+
import type { Application, HookContext } from "@feathersjs/feathers";
|
|
2
|
+
import type {
|
|
3
|
+
AdapterBase,
|
|
4
|
+
FilterQueryOptions as PlainFilterQueryOptions
|
|
5
|
+
} from "@feathersjs/adapter-commons";
|
|
3
6
|
|
|
4
7
|
export type Path = Array<string|number>;
|
|
8
|
+
export type MaybeArray<T> = T | T[]
|
|
9
|
+
export type Promisable<T> = T | Promise<T>
|
|
10
|
+
|
|
5
11
|
export type HookType = "before" | "after" | "error";
|
|
6
12
|
export type ServiceMethodName = "find" | "get" | "create" | "update" | "patch" | "remove";
|
|
13
|
+
export type ReturnSyncHook = (context: HookContext) => HookContext
|
|
14
|
+
export type ReturnAsyncHook = (context: HookContext) => Promise<HookContext>
|
|
7
15
|
|
|
8
16
|
export type Handle = "target" | "source" | "combine" | "intersect"| "intersectOrFull";
|
|
9
17
|
export type FirstLast = "first" | "last";
|
|
10
18
|
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
export type Predicate<T = any> = (item: T) => boolean
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
|
+
export type PredicateWithContext<T = any> = (item: T, context: HookContext) => boolean
|
|
23
|
+
|
|
11
24
|
//#region hooks
|
|
12
25
|
|
|
13
26
|
export interface HookSetDataOptions {
|
|
14
27
|
allowUndefined?: boolean
|
|
15
|
-
overwrite?: boolean
|
|
28
|
+
overwrite?: boolean | PredicateWithContext
|
|
16
29
|
}
|
|
17
30
|
|
|
18
31
|
export interface AddHookOptions {
|
|
@@ -27,6 +40,29 @@ export interface HookRunPerItemOptions {
|
|
|
27
40
|
wait?: boolean
|
|
28
41
|
}
|
|
29
42
|
|
|
43
|
+
export interface RemoveRelatedOptions<S = Record<string, any>> {
|
|
44
|
+
service: keyof S
|
|
45
|
+
keyThere: string
|
|
46
|
+
keyHere: string
|
|
47
|
+
blocking?: boolean
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface CreateRelatedOptions<S = Record<string, any>> {
|
|
51
|
+
service: keyof S
|
|
52
|
+
multi?: boolean
|
|
53
|
+
data: (item: any, context: HookContext) => Promisable<Record<string, any>>
|
|
54
|
+
createItemsInDataArraySeparately?: boolean
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type OnDeleteAction = "cascade" | "set null";
|
|
58
|
+
|
|
59
|
+
export interface OnDeleteOptions {
|
|
60
|
+
keyThere: string
|
|
61
|
+
keyHere: string
|
|
62
|
+
onDelete: OnDeleteAction
|
|
63
|
+
blocking?: boolean
|
|
64
|
+
}
|
|
65
|
+
|
|
30
66
|
//#endregion
|
|
31
67
|
|
|
32
68
|
//#region mixins
|
|
@@ -70,21 +106,15 @@ export interface MergeQueryOptions<T> extends FilterQueryOptions<T> {
|
|
|
70
106
|
}
|
|
71
107
|
|
|
72
108
|
export interface FilterQueryOptions<T> {
|
|
73
|
-
service?:
|
|
74
|
-
operators?:
|
|
75
|
-
filters?:
|
|
109
|
+
service?: AdapterBase<T>
|
|
110
|
+
operators?: PlainFilterQueryOptions["operators"],
|
|
111
|
+
filters?: PlainFilterQueryOptions["filters"],
|
|
76
112
|
}
|
|
77
113
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
export interface FilterQueryResult {
|
|
84
|
-
filters: Record<string, unknown>
|
|
85
|
-
query: Record<string, unknown>
|
|
86
|
-
paginate?: unknown
|
|
87
|
-
[key: string]: unknown
|
|
114
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
115
|
+
export interface GetItemsIsArrayOptions<T = any> {
|
|
116
|
+
items: T[]
|
|
117
|
+
isArray: boolean
|
|
88
118
|
}
|
|
89
119
|
|
|
90
120
|
//#endregion
|
package/src/utils/filterQuery.ts
CHANGED
|
@@ -1,34 +1,35 @@
|
|
|
1
1
|
import {
|
|
2
|
-
filterQuery as plainFilterQuery
|
|
2
|
+
filterQuery as plainFilterQuery,
|
|
3
3
|
} from "@feathersjs/adapter-commons";
|
|
4
4
|
|
|
5
5
|
import type {
|
|
6
|
-
FilterQueryOptions,
|
|
7
|
-
|
|
8
|
-
PlainFilterQueryOptions
|
|
9
|
-
} from "../types";
|
|
6
|
+
FilterQueryOptions as PlainFilterQueryOptions,
|
|
7
|
+
} from "@feathersjs/adapter-commons";
|
|
10
8
|
|
|
11
9
|
import type { Query } from "@feathersjs/feathers";
|
|
10
|
+
import type { FilterQueryOptions } from "../types";
|
|
12
11
|
|
|
13
|
-
export function filterQuery<T>(query: Query,
|
|
12
|
+
export function filterQuery<T>(query: Query, _options?: FilterQueryOptions<T>) {
|
|
14
13
|
query = query || {};
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
_options = _options || {};
|
|
15
|
+
const { service, ...options } = _options;
|
|
16
|
+
if (service) {
|
|
18
17
|
const operators = options.operators
|
|
19
18
|
? options.operators
|
|
20
|
-
: service.options?.
|
|
19
|
+
: service.options?.operators;
|
|
21
20
|
const filters = options.filters
|
|
22
21
|
? options.filters
|
|
23
22
|
: service.options?.filters;
|
|
24
23
|
const optionsForFilterQuery: PlainFilterQueryOptions = {};
|
|
25
24
|
if (operators) { optionsForFilterQuery.operators = operators; }
|
|
26
25
|
if (filters) { optionsForFilterQuery.filters = filters; }
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
// @ts-expect-error service has no filterQuery method
|
|
27
|
+
if (service && "filterQuery" in service && typeof service.filterQuery === "function") {
|
|
28
|
+
// @ts-expect-error service has no filterQuery method
|
|
29
|
+
return service.filterQuery({ query }, optionsForFilterQuery);
|
|
29
30
|
} else {
|
|
30
|
-
return plainFilterQuery(query, optionsForFilterQuery)
|
|
31
|
+
return plainFilterQuery(query, optionsForFilterQuery);
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
|
-
return plainFilterQuery(query, options)
|
|
34
|
+
return plainFilterQuery(query, options);
|
|
34
35
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { HookContext } from "@feathersjs/feathers";
|
|
2
|
+
import type { GetItemsIsArrayOptions } from "..";
|
|
3
|
+
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5
|
+
export const getItemsIsArray = <T = any>(
|
|
6
|
+
context: HookContext
|
|
7
|
+
): GetItemsIsArrayOptions<T> => {
|
|
8
|
+
let itemOrItems = context.type === "before"
|
|
9
|
+
? context.data
|
|
10
|
+
: context.result;
|
|
11
|
+
itemOrItems = itemOrItems && context.method === "find"
|
|
12
|
+
? (itemOrItems.data || itemOrItems)
|
|
13
|
+
: itemOrItems;
|
|
14
|
+
const isArray = Array.isArray(itemOrItems);
|
|
15
|
+
return {
|
|
16
|
+
items: (isArray)
|
|
17
|
+
? itemOrItems
|
|
18
|
+
: (itemOrItems != null)
|
|
19
|
+
? [itemOrItems]
|
|
20
|
+
: [],
|
|
21
|
+
isArray
|
|
22
|
+
};
|
|
23
|
+
};
|
package/src/utils/getPaginate.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HookContext } from "@feathersjs/feathers";
|
|
1
|
+
import type { HookContext } from "@feathersjs/feathers";
|
|
2
2
|
|
|
3
3
|
// TODO: seems like this does no longer exist in feathers
|
|
4
4
|
interface PaginationOptions {
|
|
@@ -6,7 +6,6 @@ interface PaginationOptions {
|
|
|
6
6
|
max: number;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
|
|
10
9
|
export const getPaginate = (
|
|
11
10
|
context: HookContext
|
|
12
11
|
): PaginationOptions | undefined => {
|
package/src/utils/isMulti.ts
CHANGED
package/src/utils/isPaginated.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { pushSet } from "./pushSet";
|
|
2
2
|
|
|
3
3
|
import type { HookContext } from "@feathersjs/feathers";
|
|
4
|
-
import type { HookType } from "
|
|
4
|
+
import type { HookType, MaybeArray } from "../types";
|
|
5
5
|
|
|
6
6
|
export function markHookForSkip<T>(
|
|
7
7
|
hookName: string,
|
|
8
|
-
type: "all" | HookType
|
|
8
|
+
type: "all" | MaybeArray<HookType>,
|
|
9
9
|
context?: Partial<HookContext<T>>
|
|
10
10
|
): Partial<HookContext<T>> {
|
|
11
11
|
context = context || {};
|
|
@@ -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
|
|
|
9
9
|
import { mergeArrays } from "./mergeArrays";
|
|
10
10
|
import { filterQuery } from "../filterQuery";
|
|
@@ -249,6 +249,12 @@ function makeDefaultOptions<T>(options?: Partial<MergeQueryOptions<T>>): MergeQu
|
|
|
249
249
|
return options as MergeQueryOptions<T>;
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
+
function moveProperty(source: Record<string, any>, target: Record<string, any>, key: string): void {
|
|
253
|
+
if (!Object.prototype.hasOwnProperty.call(source, key)) { return; }
|
|
254
|
+
target[key] = source[key];
|
|
255
|
+
delete source[key];
|
|
256
|
+
}
|
|
257
|
+
|
|
252
258
|
export function mergeQuery<T>(target: Query, source: Query, options?: Partial<MergeQueryOptions<T>>): Query {
|
|
253
259
|
const fullOptions = makeDefaultOptions(options);
|
|
254
260
|
const {
|
|
@@ -259,9 +265,12 @@ export function mergeQuery<T>(target: Query, source: Query, options?: Partial<Me
|
|
|
259
265
|
service: fullOptions.service
|
|
260
266
|
});
|
|
261
267
|
|
|
268
|
+
moveProperty(targetFilters, targetQuery, "$or");
|
|
269
|
+
moveProperty(targetFilters, targetQuery, "$and");
|
|
270
|
+
|
|
262
271
|
if (target.$limit) { targetFilters.$limit = target.$limit; }
|
|
263
272
|
|
|
264
|
-
let {
|
|
273
|
+
let {
|
|
265
274
|
// eslint-disable-next-line prefer-const
|
|
266
275
|
filters: sourceFilters,
|
|
267
276
|
query: sourceQuery
|
|
@@ -270,6 +279,9 @@ export function mergeQuery<T>(target: Query, source: Query, options?: Partial<Me
|
|
|
270
279
|
service: fullOptions.service
|
|
271
280
|
});
|
|
272
281
|
|
|
282
|
+
moveProperty(sourceFilters, sourceQuery, "$or");
|
|
283
|
+
moveProperty(sourceFilters, sourceQuery, "$and");
|
|
284
|
+
|
|
273
285
|
if (source.$limit) { sourceFilters.$limit = source.$limit; }
|
|
274
286
|
|
|
275
287
|
//#region filters
|
package/src/utils/pushSet.ts
CHANGED
package/src/utils/shouldSkip.ts
CHANGED
|
@@ -5,7 +5,10 @@ import { GeneralError } from "@feathersjs/errors";
|
|
|
5
5
|
|
|
6
6
|
import type { HookContext } from "@feathersjs/feathers";
|
|
7
7
|
|
|
8
|
-
export const shouldSkip = (
|
|
8
|
+
export const shouldSkip = (
|
|
9
|
+
hookName: string,
|
|
10
|
+
context: HookContext
|
|
11
|
+
): boolean => {
|
|
9
12
|
if (!context.params || !context.params.skipHooks) {
|
|
10
13
|
return false;
|
|
11
14
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { _ } from "@feathersjs/commons";
|
|
2
|
+
import { BadRequest } from "@feathersjs/errors";
|
|
3
|
+
import type { Query } from "@feathersjs/feathers";
|
|
4
|
+
|
|
5
|
+
const isPlainObject = (value: any) => _.isObject(value) && value.constructor === {}.constructor;
|
|
6
|
+
|
|
7
|
+
export const validateQueryProperty = (query: any, operators: string[] = []): Query => {
|
|
8
|
+
if (!isPlainObject(query)) {
|
|
9
|
+
return query;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
for (const key of Object.keys(query)) {
|
|
13
|
+
if (key.startsWith("$") && !operators.includes(key)) {
|
|
14
|
+
throw new BadRequest(`Invalid query parameter ${key}`, query);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const value = query[key];
|
|
18
|
+
|
|
19
|
+
if (isPlainObject(value)) {
|
|
20
|
+
query[key] = validateQueryProperty(value, operators);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
...query
|
|
26
|
+
};
|
|
27
|
+
};
|
package/.eslintignore
DELETED
package/.eslintrc.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
root: true,
|
|
3
|
-
env: {
|
|
4
|
-
node: true,
|
|
5
|
-
mocha: true
|
|
6
|
-
},
|
|
7
|
-
parser: "@typescript-eslint/parser",
|
|
8
|
-
plugins: [
|
|
9
|
-
"security",
|
|
10
|
-
"@typescript-eslint"
|
|
11
|
-
],
|
|
12
|
-
extends: [
|
|
13
|
-
"eslint:recommended",
|
|
14
|
-
"plugin:security/recommended",
|
|
15
|
-
"plugin:@typescript-eslint/recommended"
|
|
16
|
-
],
|
|
17
|
-
rules: {
|
|
18
|
-
"quotes": ["warn", "double", "avoid-escape"],
|
|
19
|
-
"indent": ["warn", 2, { "SwitchCase": 1 }],
|
|
20
|
-
"semi": ["warn", "always"],
|
|
21
|
-
"@typescript-eslint/no-unused-vars": "warn",
|
|
22
|
-
"no-console": "off",
|
|
23
|
-
"camelcase": "warn",
|
|
24
|
-
"require-atomic-updates": "off",
|
|
25
|
-
"prefer-destructuring": ["warn", {
|
|
26
|
-
"array": false,
|
|
27
|
-
"object": true
|
|
28
|
-
}, {
|
|
29
|
-
"enforceForRenamedProperties": false
|
|
30
|
-
}],
|
|
31
|
-
"security/detect-object-injection": "off",
|
|
32
|
-
"object-curly-spacing": ["warn", "always"],
|
|
33
|
-
"prefer-const": ["warn"]
|
|
34
|
-
},
|
|
35
|
-
overrides: [
|
|
36
|
-
{
|
|
37
|
-
"files": ["test/**/*.ts"],
|
|
38
|
-
"rules": {
|
|
39
|
-
"@typescript-eslint/ban-ts-comment": ["off"]
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
]
|
|
43
|
-
};
|
|
44
|
-
|
package/.gitlab-ci.yml
DELETED
package/.mocharc.js
DELETED
package/.nycrc.json
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "@istanbuljs/nyc-config-typescript",
|
|
3
|
-
"cache": false,
|
|
4
|
-
"check-coverage": false,
|
|
5
|
-
"include": [
|
|
6
|
-
"src/**/*.js",
|
|
7
|
-
"src/**/*.ts"
|
|
8
|
-
],
|
|
9
|
-
"exclude": [
|
|
10
|
-
"src/types.ts",
|
|
11
|
-
"src/index.ts"
|
|
12
|
-
],
|
|
13
|
-
"reporter": [
|
|
14
|
-
"html",
|
|
15
|
-
"text",
|
|
16
|
-
"text-summary",
|
|
17
|
-
"lcov"
|
|
18
|
-
],
|
|
19
|
-
"sourceMap": true,
|
|
20
|
-
"all": true,
|
|
21
|
-
"instrument": true
|
|
22
|
-
}
|
package/index.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
exports.mergeQuery = require("./src/mergeQuery");
|
|
2
|
-
exports.mergeArrays = require("./src/mergeQuery/mergeArrays");
|
|
3
|
-
exports.shouldSkip = require("./src/shouldSkip");
|
|
4
|
-
exports.pushSet = require("./src/pushSet");
|
|
5
|
-
exports.isMulti = require("./src/isMulti");
|
|
6
|
-
|
|
7
|
-
exports.hooks = {
|
|
8
|
-
checkMulti: require("./src/hooks/checkMulti")
|
|
9
|
-
};
|