feathers-utils 6.0.0 → 7.0.1

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.
Files changed (59) hide show
  1. package/README.md +3 -4
  2. package/dist/index.cjs +81 -99
  3. package/dist/index.d.cts +35 -33
  4. package/dist/index.d.mts +35 -33
  5. package/dist/index.d.ts +35 -33
  6. package/dist/index.mjs +81 -99
  7. package/package.json +29 -32
  8. package/src/.DS_Store +0 -0
  9. package/src/filters/array.ts +11 -13
  10. package/src/filters/index.ts +2 -2
  11. package/src/filters/object.ts +11 -11
  12. package/src/hooks/.DS_Store +0 -0
  13. package/src/hooks/checkMulti.ts +98 -82
  14. package/src/hooks/createRelated.ts +41 -41
  15. package/src/hooks/forEach.ts +32 -32
  16. package/src/hooks/from-client-for-server/common.ts +1 -1
  17. package/src/hooks/from-client-for-server/index.ts +2 -2
  18. package/src/hooks/from-client-for-server/paramsForServer.ts +32 -32
  19. package/src/hooks/from-client-for-server/paramsFromClient.ts +25 -25
  20. package/src/hooks/index.ts +9 -9
  21. package/src/hooks/onDelete.ts +54 -55
  22. package/src/hooks/parseFields.ts +13 -13
  23. package/src/hooks/removeRelated.ts +22 -20
  24. package/src/hooks/runPerItem.ts +17 -18
  25. package/src/hooks/setData.ts +295 -264
  26. package/src/index.ts +6 -6
  27. package/src/mixins/debounce-mixin/DebouncedStore.ts +29 -29
  28. package/src/mixins/debounce-mixin/debounceMixin.ts +17 -17
  29. package/src/mixins/debounce-mixin/index.ts +3 -3
  30. package/src/mixins/debounce-mixin/types.ts +9 -9
  31. package/src/mixins/debounce-mixin/utils.ts +3 -3
  32. package/src/mixins/index.ts +1 -1
  33. package/src/types.ts +3 -5
  34. package/src/typesInternal.ts +14 -14
  35. package/src/utility-types/index.ts +48 -48
  36. package/src/utils/_utils.internal.ts +5 -5
  37. package/src/utils/defineHooks.ts +8 -8
  38. package/src/utils/deflattenQuery.ts +31 -31
  39. package/src/utils/filterQuery.ts +58 -58
  40. package/src/utils/flattenQuery.ts +54 -54
  41. package/src/utils/getItemsIsArray.ts +148 -149
  42. package/src/utils/getPaginate.ts +31 -31
  43. package/src/utils/index.ts +17 -17
  44. package/src/utils/isMulti.ts +48 -40
  45. package/src/utils/isPaginated.ts +30 -30
  46. package/src/utils/markHookForSkip.ts +177 -178
  47. package/src/utils/mergeQuery/index.ts +3 -3
  48. package/src/utils/mergeQuery/mergeArrays.ts +67 -67
  49. package/src/utils/mergeQuery/mergeQuery.ts +211 -211
  50. package/src/utils/mergeQuery/types.ts +12 -12
  51. package/src/utils/mergeQuery/utils.ts +224 -224
  52. package/src/utils/optimizeBatchPatch.ts +42 -42
  53. package/src/utils/pushSet.ts +57 -57
  54. package/src/utils/setQueryKeySafely.ts +68 -68
  55. package/src/utils/setResultEmpty.ts +125 -123
  56. package/src/utils/shouldSkip.ts +72 -72
  57. package/src/utils/toJSON.ts +4 -4
  58. package/src/utils/validateQueryProperty.ts +10 -10
  59. package/src/hooks/makeSequelizeQuery.ts_ +0 -90
@@ -1,5 +1,5 @@
1
- import type { HookContext } from "@feathersjs/feathers";
2
- import { FROM_CLIENT_FOR_SERVER_DEFAULT_KEY } from "./common";
1
+ import type { HookContext } from '@feathersjs/feathers'
2
+ import { FROM_CLIENT_FOR_SERVER_DEFAULT_KEY } from './common.js'
3
3
 
4
4
  export function defineParamsFromClient(keyToHide: string) {
5
5
  return function paramsFromClient(
@@ -8,9 +8,9 @@ export function defineParamsFromClient(keyToHide: string) {
8
8
  return (context: HookContext): HookContext => {
9
9
  if (
10
10
  !context.params?.query?.[keyToHide] ||
11
- typeof context.params.query[keyToHide] !== "object"
11
+ typeof context.params.query[keyToHide] !== 'object'
12
12
  ) {
13
- return context;
13
+ return context
14
14
  }
15
15
 
16
16
  const params = {
@@ -21,40 +21,40 @@ export function defineParamsFromClient(keyToHide: string) {
21
21
  ...context.params.query[keyToHide],
22
22
  },
23
23
  },
24
- };
24
+ }
25
25
 
26
- const client = params.query[keyToHide];
26
+ const client = params.query[keyToHide]
27
27
 
28
28
  whitelist.forEach((key) => {
29
29
  if (key in client) {
30
- params[key] = client[key];
31
- delete client[key];
30
+ params[key] = client[key]
31
+ delete client[key]
32
32
  }
33
- });
33
+ })
34
34
 
35
35
  if (Object.keys(client).length === 0) {
36
- delete params.query[keyToHide];
36
+ delete params.query[keyToHide]
37
37
  }
38
38
 
39
- context.params = params;
39
+ context.params = params
40
40
 
41
- return context;
42
- };
43
- };
41
+ return context
42
+ }
43
+ }
44
44
  }
45
45
 
46
46
  export const paramsFromClient = defineParamsFromClient(
47
47
  FROM_CLIENT_FOR_SERVER_DEFAULT_KEY,
48
- );
48
+ )
49
49
 
50
50
  if (import.meta.vitest) {
51
- const { it, expect } = import.meta.vitest;
51
+ const { it, expect } = import.meta.vitest
52
52
 
53
- it("should move params to query._$client", () => {
53
+ it('should move params to query._$client', () => {
54
54
  expect(
55
55
  paramsFromClient(
56
- "a",
57
- "b",
56
+ 'a',
57
+ 'b',
58
58
  )({
59
59
  params: {
60
60
  query: {
@@ -74,12 +74,12 @@ if (import.meta.vitest) {
74
74
  c: 3,
75
75
  },
76
76
  },
77
- });
78
- });
77
+ })
78
+ })
79
79
 
80
- it("should move params to query._$client and leave remaining", () => {
80
+ it('should move params to query._$client and leave remaining', () => {
81
81
  expect(
82
- paramsFromClient("a")({
82
+ paramsFromClient('a')({
83
83
  params: {
84
84
  query: {
85
85
  _$client: {
@@ -100,6 +100,6 @@ if (import.meta.vitest) {
100
100
  c: 3,
101
101
  },
102
102
  },
103
- });
104
- });
103
+ })
104
+ })
105
105
  }
@@ -1,9 +1,9 @@
1
- export * from "./checkMulti";
2
- export * from "./createRelated";
3
- export * from "./forEach";
4
- export * from "./onDelete";
5
- export * from "./parseFields";
6
- export * from "./removeRelated";
7
- export * from "./runPerItem";
8
- export * from "./setData";
9
- export * from "./from-client-for-server";
1
+ export * from './checkMulti.js'
2
+ export * from './createRelated.js'
3
+ export * from './forEach.js'
4
+ export * from './onDelete.js'
5
+ export * from './parseFields.js'
6
+ export * from './removeRelated.js'
7
+ export * from './runPerItem.js'
8
+ export * from './setData.js'
9
+ export * from './from-client-for-server/index.js'
@@ -1,14 +1,16 @@
1
- import type { HookContext } from "@feathersjs/feathers";
2
- import { checkContext } from "feathers-hooks-common";
3
- import { getItemsIsArray, shouldSkip } from "../utils";
1
+ import type { HookContext } from '@feathersjs/feathers'
2
+ import { checkContext } from 'feathers-hooks-common'
3
+ import { getItemsIsArray, shouldSkip } from '../utils/index.js'
4
+ import type { KeyOf, MaybeArray } from '../typesInternal.js'
4
5
 
5
- export type OnDeleteAction = "cascade" | "set null";
6
+ export type OnDeleteAction = 'cascade' | 'set null'
6
7
 
7
- export interface OnDeleteOptions {
8
- keyThere: string;
9
- keyHere: string;
10
- onDelete: OnDeleteAction;
11
- blocking?: boolean;
8
+ export interface OnDeleteOptions<Path extends string = string> {
9
+ service: Path
10
+ keyThere: string
11
+ keyHere: string
12
+ onDelete: OnDeleteAction
13
+ blocking?: boolean
12
14
  }
13
15
 
14
16
  /**
@@ -17,62 +19,59 @@ export interface OnDeleteOptions {
17
19
  export function onDelete<
18
20
  S = Record<string, any>,
19
21
  H extends HookContext = HookContext,
20
- >(
21
- service: keyof S,
22
- {
23
- keyThere,
24
- keyHere = "id",
25
- onDelete = "cascade",
26
- blocking = true,
27
- }: OnDeleteOptions,
28
- ) {
29
- if (!service || !keyThere) {
30
- throw "initialize hook 'removeRelated' completely!";
31
- }
32
- if (!["cascade", "set null"].includes(onDelete)) {
33
- throw "onDelete must be 'cascade' or 'set null'";
34
- }
35
-
22
+ >(options: MaybeArray<OnDeleteOptions<KeyOf<S>>>) {
36
23
  return async (context: H) => {
37
- if (shouldSkip("onDelete", context)) {
38
- return context;
24
+ if (shouldSkip('onDelete', context)) {
25
+ return context
39
26
  }
40
27
 
41
- checkContext(context, "after", "remove", "onDelete");
28
+ checkContext(context, 'after', 'remove', 'onDelete')
42
29
 
43
- const { items } = getItemsIsArray(context);
30
+ const { items } = getItemsIsArray(context)
44
31
 
45
- let ids = items.map((x) => x[keyHere]).filter((x) => !!x);
46
- ids = [...new Set(ids)];
32
+ const entries = Array.isArray(options) ? options : [options]
47
33
 
48
- if (!ids || ids.length <= 0) {
49
- return context;
50
- }
34
+ const promises: Promise<any>[] = []
51
35
 
52
- const params = {
53
- query: {
54
- [keyThere]: {
55
- $in: ids,
56
- },
57
- },
58
- paginate: false,
59
- };
36
+ entries.forEach(
37
+ async ({ keyHere, keyThere, onDelete, service, blocking }) => {
38
+ let ids = items.map((x) => x[keyHere]).filter((x) => !!x)
39
+ ids = [...new Set(ids)]
60
40
 
61
- let promise;
41
+ if (!ids || ids.length <= 0) {
42
+ return context
43
+ }
62
44
 
63
- if (onDelete === "cascade") {
64
- promise = context.app.service(service as string).remove(null, params);
65
- } else if (onDelete === "set null") {
66
- const data = { [keyThere]: null };
67
- promise = context.app
68
- .service(service as string)
69
- .patch(null, data, params);
70
- }
45
+ const params = {
46
+ query: {
47
+ [keyThere]: {
48
+ $in: ids,
49
+ },
50
+ },
51
+ paginate: false,
52
+ }
71
53
 
72
- if (blocking) {
73
- await promise;
54
+ let promise: Promise<any> | undefined = undefined
55
+
56
+ if (onDelete === 'cascade') {
57
+ promise = context.app.service(service as string).remove(null, params)
58
+ } else if (onDelete === 'set null') {
59
+ const data = { [keyThere]: null }
60
+ promise = context.app
61
+ .service(service as string)
62
+ .patch(null, data, params)
63
+ }
64
+
65
+ if (blocking && promise) {
66
+ promises.push(promise)
67
+ }
68
+ },
69
+ )
70
+
71
+ if (promises.length) {
72
+ await Promise.all(promises)
74
73
  }
75
74
 
76
- return context;
77
- };
75
+ return context
76
+ }
78
77
  }
@@ -1,29 +1,29 @@
1
- import type { HookContext } from "@feathersjs/feathers";
2
- import { getItemsIsArray } from "../utils/getItemsIsArray";
1
+ import type { HookContext } from '@feathersjs/feathers'
2
+ import { getItemsIsArray } from '../utils/getItemsIsArray.js'
3
3
 
4
4
  /**
5
5
  * Parse fields to date or number
6
6
  * skips undefined fields
7
7
  */
8
8
  export const parseFields =
9
- (type: "date" | "number", options: { fields: string[] }) =>
9
+ (type: 'date' | 'number', options: { fields: string[] }) =>
10
10
  (context: HookContext) => {
11
- const { items } = getItemsIsArray(context);
11
+ const { items } = getItemsIsArray(context)
12
12
 
13
13
  items.forEach((item) => {
14
14
  options.fields.forEach((field) => {
15
15
  // ignore undefined fields
16
16
  if (!(field in item)) {
17
- return;
17
+ return
18
18
  }
19
19
 
20
- if (type === "date") {
21
- item[field] = new Date(item[field]);
22
- } else if (type === "number") {
23
- item[field] = Number(item[field]);
20
+ if (type === 'date') {
21
+ item[field] = new Date(item[field])
22
+ } else if (type === 'number') {
23
+ item[field] = Number(item[field])
24
24
  }
25
- });
26
- });
25
+ })
26
+ })
27
27
 
28
- return context;
29
- };
28
+ return context
29
+ }
@@ -1,16 +1,18 @@
1
- import type { HookContext, Params, Query } from "@feathersjs/feathers";
2
- import { checkContext } from "feathers-hooks-common";
3
- import { getItemsIsArray, shouldSkip } from "../utils";
1
+ import type { HookContext, Params, Query } from '@feathersjs/feathers'
2
+ import { checkContext } from 'feathers-hooks-common'
3
+ import { getItemsIsArray, shouldSkip } from '../utils/index.js'
4
4
 
5
5
  export interface RemoveRelatedOptions<S = Record<string, any>> {
6
- service: keyof S;
7
- keyThere: string;
8
- keyHere: string;
9
- blocking?: boolean;
6
+ service: keyof S
7
+ keyThere: string
8
+ keyHere: string
9
+ blocking?: boolean
10
10
  }
11
11
 
12
12
  /**
13
13
  * hook to remove related items
14
+ *
15
+ * @deprecated use 'onDelete' instead
14
16
  */
15
17
  export function removeRelated<
16
18
  S = Record<string, any>,
@@ -18,26 +20,26 @@ export function removeRelated<
18
20
  >({
19
21
  service,
20
22
  keyThere,
21
- keyHere = "id",
23
+ keyHere = 'id',
22
24
  blocking = true,
23
25
  }: RemoveRelatedOptions<S>) {
24
26
  if (!service || !keyThere) {
25
- throw "initialize hook 'removeRelated' completely!";
27
+ throw "initialize hook 'removeRelated' completely!"
26
28
  }
27
29
  return async (context: H) => {
28
- if (shouldSkip("removeRelated", context)) {
29
- return context;
30
+ if (shouldSkip('removeRelated', context)) {
31
+ return context
30
32
  }
31
33
 
32
- checkContext(context, "after", "remove", "removeRelated");
34
+ checkContext(context, 'after', 'remove', 'removeRelated')
33
35
 
34
- const { items } = getItemsIsArray(context);
36
+ const { items } = getItemsIsArray(context)
35
37
 
36
- let ids = items.map((x) => x[keyHere]).filter((x) => !!x);
37
- ids = [...new Set(ids)];
38
+ let ids = items.map((x) => x[keyHere]).filter((x) => !!x)
39
+ ids = [...new Set(ids)]
38
40
 
39
41
  if (!ids || ids.length <= 0) {
40
- return context;
42
+ return context
41
43
  }
42
44
 
43
45
  // feathers does not accept `paginate: false` for remove, but some adapters need it to work properly
@@ -50,12 +52,12 @@ export function removeRelated<
50
52
  },
51
53
  },
52
54
  paginate: false,
53
- } as Params<Query>);
55
+ } as Params<Query>)
54
56
 
55
57
  if (blocking) {
56
- await promise;
58
+ await promise
57
59
  }
58
60
 
59
- return context;
60
- };
61
+ return context
62
+ }
61
63
  }
@@ -1,47 +1,46 @@
1
- import { shouldSkip, getItemsIsArray } from "../utils";
1
+ import { shouldSkip, getItemsIsArray } from '../utils/index.js'
2
2
 
3
- import type { HookContext } from "@feathersjs/feathers";
4
- import type { Promisable } from "../typesInternal";
3
+ import type { HookContext } from '@feathersjs/feathers'
4
+ import type { Promisable } from '../typesInternal.js'
5
5
 
6
6
  export interface HookRunPerItemOptions {
7
- wait?: boolean;
7
+ wait?: boolean
8
8
  }
9
9
 
10
10
  const makeOptions = (
11
11
  options?: HookRunPerItemOptions,
12
12
  ): Required<HookRunPerItemOptions> => {
13
- options = options || {};
13
+ options = options || {}
14
14
  return {
15
15
  wait: true,
16
16
  ...options,
17
- };
18
- };
17
+ }
18
+ }
19
19
 
20
20
  /**
21
21
  * hook to run a hook for each item in the context
22
22
  * uses `context.result` if it is existent. otherwise uses context.data
23
23
  */
24
24
  export const runPerItem = <H extends HookContext = HookContext, T = any>(
25
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
25
  actionPerItem: (item: T, context: H) => Promisable<any>,
27
26
  _options?: HookRunPerItemOptions,
28
27
  ) => {
29
- const options = makeOptions(_options);
28
+ const options = makeOptions(_options)
30
29
  return async (context: H) => {
31
- if (shouldSkip("runForItems", context)) {
32
- return context;
30
+ if (shouldSkip('runForItems', context)) {
31
+ return context
33
32
  }
34
33
 
35
- const { items } = getItemsIsArray(context);
34
+ const { items } = getItemsIsArray(context)
36
35
 
37
36
  const promises = items.map(async (item: T) => {
38
- await actionPerItem(item, context);
39
- });
37
+ await actionPerItem(item, context)
38
+ })
40
39
 
41
40
  if (options.wait) {
42
- await Promise.all(promises);
41
+ await Promise.all(promises)
43
42
  }
44
43
 
45
- return context;
46
- };
47
- };
44
+ return context
45
+ }
46
+ }