feathers-utils 5.0.2 → 5.2.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.
Files changed (39) hide show
  1. package/README.md +4 -0
  2. package/dist/index.cjs +181 -26
  3. package/dist/index.d.cts +20 -5
  4. package/dist/index.d.mts +20 -5
  5. package/dist/index.d.ts +20 -5
  6. package/dist/index.mjs +175 -23
  7. package/package.json +18 -20
  8. package/src/filters/object.ts +2 -2
  9. package/src/hooks/checkMulti.ts +151 -0
  10. package/src/hooks/from-client-for-server/common.ts +1 -0
  11. package/src/hooks/from-client-for-server/index.ts +2 -0
  12. package/src/hooks/from-client-for-server/paramsForServer.ts +100 -0
  13. package/src/hooks/from-client-for-server/paramsFromClient.ts +105 -0
  14. package/src/hooks/index.ts +1 -0
  15. package/src/hooks/setData.ts +509 -0
  16. package/src/mixins/debounce-mixin/DebouncedStore.ts +1 -9
  17. package/src/mixins/debounce-mixin/debounceMixin.ts +2 -1
  18. package/src/mixins/debounce-mixin/utils.ts +10 -0
  19. package/src/types.ts +1 -0
  20. package/src/utils/_utils.internal.ts +16 -0
  21. package/src/utils/deflattenQuery.ts +109 -0
  22. package/src/utils/filterQuery.ts +112 -40
  23. package/src/utils/flattenQuery.ts +198 -0
  24. package/src/utils/getItemsIsArray.ts +279 -0
  25. package/src/utils/getPaginate.ts +74 -1
  26. package/src/utils/index.ts +2 -0
  27. package/src/utils/isMulti.ts +51 -0
  28. package/src/utils/isPaginated.ts +72 -0
  29. package/src/utils/markHookForSkip.ts +411 -0
  30. package/src/utils/mergeQuery/mergeArrays.ts +68 -0
  31. package/src/utils/mergeQuery/mergeQuery.ts +464 -3
  32. package/src/utils/mergeQuery/types.ts +0 -1
  33. package/src/utils/mergeQuery/utils.ts +93 -5
  34. package/src/utils/pushSet.ts +67 -1
  35. package/src/utils/setQueryKeySafely.ts +169 -4
  36. package/src/utils/setResultEmpty.ts +260 -0
  37. package/src/utils/shouldSkip.ts +121 -0
  38. package/src/utils/validateQueryProperty.ts +3 -6
  39. package/src/utils/internal.utils.ts +0 -9
@@ -41,3 +41,282 @@ export const getItemsIsArray = <T = any, H extends HookContext = HookContext>(
41
41
  isArray,
42
42
  };
43
43
  };
44
+
45
+ if (import.meta.vitest) {
46
+ const { describe, it, assert } = import.meta.vitest;
47
+
48
+ const assertBefore = (context, items, isArray) => {
49
+ const arrays: (GetItemsIsArrayFrom | undefined)[] = [
50
+ undefined,
51
+ "data",
52
+ "automatic",
53
+ ];
54
+
55
+ for (const from of arrays) {
56
+ const { items: items2, isArray: isArray2 } = getItemsIsArray(context, {
57
+ from,
58
+ });
59
+ assert.deepStrictEqual(items2, items, `from: ${from}`);
60
+ assert.deepStrictEqual(isArray2, isArray, `from: ${from}`);
61
+ }
62
+ };
63
+
64
+ const assertAfter = (context, items, isArray) => {
65
+ const arrays: (GetItemsIsArrayFrom | undefined)[] = [
66
+ undefined,
67
+ "result",
68
+ "automatic",
69
+ ];
70
+
71
+ for (const from of arrays) {
72
+ const { items: items2, isArray: isArray2 } = getItemsIsArray(context, {
73
+ from,
74
+ });
75
+ assert.deepStrictEqual(items2, items, `from: ${from}`);
76
+ assert.deepStrictEqual(isArray2, isArray, `from: ${from}`);
77
+ }
78
+ };
79
+
80
+ describe("before", function () {
81
+ it("find:before", async function () {
82
+ const context = {
83
+ type: "before",
84
+ method: "find",
85
+ params: {
86
+ query: {},
87
+ },
88
+ } as any as HookContext;
89
+
90
+ assertBefore(context, [], false);
91
+ });
92
+
93
+ it("get:before", async function () {
94
+ const context = {
95
+ type: "before",
96
+ method: "get",
97
+ id: 1,
98
+ params: {
99
+ query: {},
100
+ },
101
+ } as any as HookContext;
102
+
103
+ assertBefore(context, [], false);
104
+ });
105
+
106
+ it("create:before single", async function () {
107
+ const context = {
108
+ type: "before",
109
+ method: "create",
110
+ data: { test: true },
111
+ params: {
112
+ query: {},
113
+ },
114
+ } as any as HookContext;
115
+
116
+ assertBefore(context, [{ test: true }], false);
117
+ });
118
+
119
+ it("create:before multi", async function () {
120
+ const context = {
121
+ type: "before",
122
+ method: "create",
123
+ data: [{ test: true }, { test: true }],
124
+ params: {
125
+ query: {},
126
+ },
127
+ } as any as HookContext;
128
+
129
+ assertBefore(context, [{ test: true }, { test: true }], true);
130
+ });
131
+
132
+ it("update:before single", async function () {
133
+ const context = {
134
+ type: "before",
135
+ method: "update",
136
+ id: 1,
137
+ data: { test: true },
138
+ params: {
139
+ query: {},
140
+ },
141
+ } as any as HookContext;
142
+
143
+ assertBefore(context, [{ test: true }], false);
144
+ });
145
+
146
+ it("patch:before single", async function () {
147
+ const context = {
148
+ type: "before",
149
+ method: "patch",
150
+ id: 1,
151
+ data: { test: true },
152
+ params: {
153
+ query: {},
154
+ },
155
+ } as any as HookContext;
156
+
157
+ assertBefore(context, [{ test: true }], false);
158
+ });
159
+
160
+ it("patch:before multi", async function () {
161
+ const context = {
162
+ type: "before",
163
+ method: "patch",
164
+ id: null,
165
+ data: { test: true },
166
+ params: {
167
+ query: {},
168
+ },
169
+ } as any as HookContext;
170
+
171
+ assertBefore(context, [{ test: true }], false);
172
+ });
173
+
174
+ it("remove:before single", async function () {
175
+ const context = {
176
+ type: "before",
177
+ method: "remove",
178
+ id: 1,
179
+ params: {
180
+ query: {},
181
+ },
182
+ } as any as HookContext;
183
+
184
+ assertBefore(context, [], false);
185
+ });
186
+
187
+ it("remove:before multi", async function () {
188
+ const context = {
189
+ type: "before",
190
+ method: "remove",
191
+ id: null,
192
+ params: {
193
+ query: {},
194
+ },
195
+ } as any as HookContext;
196
+
197
+ assertBefore(context, [], false);
198
+ });
199
+ });
200
+
201
+ describe("after", function () {
202
+ it("find:after paginate:true", function () {
203
+ const context = {
204
+ type: "after",
205
+ method: "find",
206
+ result: {
207
+ total: 1,
208
+ skip: 0,
209
+ limit: 10,
210
+ data: [{ test: true }],
211
+ },
212
+ params: {
213
+ query: {},
214
+ },
215
+ } as any as HookContext;
216
+
217
+ assertAfter(context, [{ test: true }], true);
218
+ });
219
+
220
+ it("find:after paginate:false", function () {
221
+ const context = {
222
+ type: "after",
223
+ method: "find",
224
+ result: [{ test: true }],
225
+ params: {
226
+ query: {},
227
+ },
228
+ } as any as HookContext;
229
+
230
+ assertAfter(context, [{ test: true }], true);
231
+ });
232
+
233
+ it("get:after", function () {
234
+ const context = {
235
+ type: "after",
236
+ method: "get",
237
+ id: 1,
238
+ result: { test: true },
239
+ params: {
240
+ query: {},
241
+ },
242
+ } as any as HookContext;
243
+
244
+ assertAfter(context, [{ test: true }], false);
245
+ });
246
+
247
+ it("update:after", function () {
248
+ const context = {
249
+ type: "after",
250
+ method: "update",
251
+ id: 1,
252
+ data: { test: "yes" },
253
+ result: { test: true },
254
+ params: {
255
+ query: {},
256
+ },
257
+ } as any as HookContext;
258
+
259
+ assertAfter(context, [{ test: true }], false);
260
+ });
261
+
262
+ it("patch:after single", function () {
263
+ const context = {
264
+ type: "after",
265
+ method: "patch",
266
+ id: 1,
267
+ data: { test: "yes" },
268
+ result: { test: true },
269
+ params: {
270
+ query: {},
271
+ },
272
+ } as any as HookContext;
273
+
274
+ assertAfter(context, [{ test: true }], false);
275
+ });
276
+
277
+ it("patch:after multi", function () {
278
+ const context = {
279
+ type: "after",
280
+ method: "patch",
281
+ id: null,
282
+ data: { test: "yes" },
283
+ result: [{ test: true }, { test: true }],
284
+ params: {
285
+ query: {},
286
+ },
287
+ } as any as HookContext;
288
+
289
+ assertAfter(context, [{ test: true }, { test: true }], true);
290
+ });
291
+
292
+ it("remove:after single", function () {
293
+ const context = {
294
+ type: "after",
295
+ method: "remove",
296
+ id: 1,
297
+ data: { test: "yes" },
298
+ result: { test: true },
299
+ params: {
300
+ query: {},
301
+ },
302
+ } as any as HookContext;
303
+
304
+ assertAfter(context, [{ test: true }], false);
305
+ });
306
+
307
+ it("remove:after multi", function () {
308
+ const context = {
309
+ type: "after",
310
+ method: "remove",
311
+ id: null,
312
+ data: { test: "yes" },
313
+ result: [{ test: true }, { test: true }],
314
+ params: {
315
+ query: {},
316
+ },
317
+ } as any as HookContext;
318
+
319
+ assertAfter(context, [{ test: true }, { test: true }], true);
320
+ });
321
+ });
322
+ }
@@ -1,6 +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
+ import { hasOwnProperty } from "./_utils.internal";
4
4
 
5
5
  /**
6
6
  * util to get paginate options from context
@@ -27,3 +27,76 @@ export const getPaginate = <H extends HookContext = HookContext>(
27
27
 
28
28
  return options.paginate || undefined;
29
29
  };
30
+
31
+ if (import.meta.vitest) {
32
+ const { it, assert } = import.meta.vitest;
33
+
34
+ it("returns service.options.paginate", function () {
35
+ const serviceOptions = {
36
+ paginate: {
37
+ default: 10,
38
+ max: 50,
39
+ },
40
+ };
41
+
42
+ const paginate = getPaginate({
43
+ params: {},
44
+ service: {
45
+ options: serviceOptions,
46
+ },
47
+ } as HookContext);
48
+
49
+ assert.deepStrictEqual(paginate, { default: 10, max: 50 });
50
+ });
51
+
52
+ it("returns undefined for params.paginate: false", function () {
53
+ const serviceOptions = {
54
+ paginate: {
55
+ default: 10,
56
+ max: 50,
57
+ },
58
+ };
59
+
60
+ const paginate = getPaginate({
61
+ params: { paginate: false },
62
+ service: {
63
+ options: serviceOptions,
64
+ },
65
+ } as HookContext);
66
+
67
+ assert.deepStrictEqual(paginate, undefined);
68
+ });
69
+
70
+ it("returns context.adapter.paginate over service.options.paginate", function () {
71
+ const serviceOptions = {
72
+ paginate: {
73
+ default: 10,
74
+ max: 50,
75
+ },
76
+ };
77
+
78
+ const paginate = getPaginate({
79
+ params: { adapter: { paginate: { default: 20, max: 100 } } },
80
+ service: {
81
+ options: serviceOptions,
82
+ },
83
+ } as HookContext);
84
+
85
+ assert.deepStrictEqual(paginate, { default: 20, max: 100 });
86
+ });
87
+
88
+ it("returns undefined for no paginate", function () {
89
+ const serviceOptions = {
90
+ paginate: false,
91
+ };
92
+
93
+ const paginate = getPaginate({
94
+ params: {},
95
+ service: {
96
+ options: serviceOptions,
97
+ },
98
+ } as HookContext);
99
+
100
+ assert.deepStrictEqual(paginate, undefined);
101
+ });
102
+ }
@@ -13,3 +13,5 @@ export * from "./shouldSkip";
13
13
  export * from "./toJSON";
14
14
  export * from "./validateQueryProperty";
15
15
  export * from "./optimizeBatchPatch";
16
+ export * from "./flattenQuery";
17
+ export * from "./deflattenQuery";
@@ -25,3 +25,54 @@ export const isMulti = <H extends HookContext = HookContext>(
25
25
  }
26
26
  return false;
27
27
  };
28
+
29
+ if (import.meta.vitest) {
30
+ const { it, assert } = import.meta.vitest;
31
+
32
+ it("returns true", function () {
33
+ const makeContext = (type: string, method: string) => {
34
+ const context = {
35
+ method,
36
+ type,
37
+ } as HookContext;
38
+ if (method === "create") {
39
+ type === "before" ? (context.data = []) : (context.result = []);
40
+ }
41
+ return context;
42
+ };
43
+ ["before", "after"].forEach((type) => {
44
+ ["find", "create", "patch", "remove"].forEach((method) => {
45
+ const context = makeContext(type, method);
46
+ assert.strictEqual(
47
+ isMulti(context),
48
+ true,
49
+ `'${type}:${method}': returns true`,
50
+ );
51
+ });
52
+ });
53
+ });
54
+
55
+ it("returns false", function () {
56
+ const makeContext = (type: string, method: string) => {
57
+ const context = {
58
+ method,
59
+ type,
60
+ id: 0,
61
+ } as HookContext;
62
+ if (method === "create") {
63
+ type === "before" ? (context.data = {}) : (context.result = {});
64
+ }
65
+ return context;
66
+ };
67
+ ["before", "after"].forEach((type) => {
68
+ ["get", "create", "update", "patch", "remove"].forEach((method) => {
69
+ const context = makeContext(type, method);
70
+ assert.strictEqual(
71
+ isMulti(context),
72
+ false,
73
+ `'${type}:${method}': returns false`,
74
+ );
75
+ });
76
+ });
77
+ });
78
+ }
@@ -15,3 +15,75 @@ export const isPaginated = <H extends HookContext = HookContext>(
15
15
 
16
16
  return !!paginate;
17
17
  };
18
+
19
+ if (import.meta.vitest) {
20
+ const { it, assert } = import.meta.vitest;
21
+
22
+ it("returns true for service.options.paginate", function () {
23
+ const serviceOptions = {
24
+ paginate: {
25
+ default: 10,
26
+ max: 50,
27
+ },
28
+ };
29
+
30
+ const paginate = isPaginated({
31
+ params: {},
32
+ service: {
33
+ options: serviceOptions,
34
+ },
35
+ method: "find",
36
+ } as HookContext);
37
+
38
+ assert.deepStrictEqual(paginate, true);
39
+ });
40
+
41
+ it("returns false for params.paginate: false", function () {
42
+ const serviceOptions = {
43
+ paginate: {
44
+ default: 10,
45
+ max: 50,
46
+ },
47
+ };
48
+
49
+ const paginate = isPaginated({
50
+ params: { paginate: false },
51
+ service: {
52
+ options: serviceOptions,
53
+ },
54
+ } as HookContext);
55
+
56
+ assert.deepStrictEqual(paginate, false);
57
+ });
58
+
59
+ it("returns true for context.adapter.paginate", function () {
60
+ const serviceOptions = {
61
+ paginate: false,
62
+ };
63
+
64
+ const paginate = isPaginated({
65
+ params: { adapter: { paginate: { default: 20, max: 100 } } },
66
+ service: {
67
+ options: serviceOptions,
68
+ },
69
+ method: "find",
70
+ } as HookContext);
71
+
72
+ assert.deepStrictEqual(paginate, true);
73
+ });
74
+
75
+ it("returns false for no paginate", function () {
76
+ const serviceOptions = {
77
+ paginate: false,
78
+ };
79
+
80
+ const paginate = isPaginated({
81
+ params: {},
82
+ service: {
83
+ options: serviceOptions,
84
+ },
85
+ } as HookContext);
86
+
87
+ assert.deepStrictEqual(paginate, false);
88
+ });
89
+ }