feathers-utils 4.1.0 → 4.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.
package/dist/index.cjs CHANGED
@@ -607,6 +607,30 @@ const validateQueryProperty = (query, operators = []) => {
607
607
  };
608
608
  };
609
609
 
610
+ function optimizeBatchPatch(items, options) {
611
+ const map = [];
612
+ const id = options?.id ?? "id";
613
+ for (const [id2, data] of items) {
614
+ const index = map.findIndex((item) => fastEquals.deepEqual(item.data, data));
615
+ if (index === -1) {
616
+ map.push({ ids: [id2], data });
617
+ } else {
618
+ map[index].ids.push(id2);
619
+ }
620
+ }
621
+ return map.map(({ ids, data }) => {
622
+ return ids.length === 1 ? [ids[0], data, void 0] : [
623
+ null,
624
+ data,
625
+ {
626
+ query: {
627
+ [id]: { $in: ids }
628
+ }
629
+ }
630
+ ];
631
+ });
632
+ }
633
+
610
634
  function checkMulti() {
611
635
  return (context) => {
612
636
  if (shouldSkip("checkMulti", context)) {
@@ -986,6 +1010,7 @@ exports.markHookForSkip = markHookForSkip;
986
1010
  exports.mergeArrays = mergeArrays;
987
1011
  exports.mergeQuery = mergeQuery;
988
1012
  exports.onDelete = onDelete;
1013
+ exports.optimizeBatchPatch = optimizeBatchPatch;
989
1014
  exports.parseFields = parseFields;
990
1015
  exports.pushSet = pushSet;
991
1016
  exports.removeRelated = removeRelated;
package/dist/index.d.cts CHANGED
@@ -234,6 +234,12 @@ declare const toJSON: (context: HookContext) => HookContext<_feathersjs_feathers
234
234
  */
235
235
  declare const validateQueryProperty: (query: any, operators?: string[]) => Query;
236
236
 
237
+ type OptimizeBatchPatchOptions = {
238
+ id?: string;
239
+ };
240
+ type OptimizeBatchPatchResultItem<T = Record<string, unknown>, P = Params> = [Id, T, P | undefined];
241
+ declare function optimizeBatchPatch<T extends Record<string, unknown>, P extends Params>(items: Map<Id, T>, options?: OptimizeBatchPatchOptions): OptimizeBatchPatchResultItem<T, P>[];
242
+
237
243
  declare const filterArray: <T extends string[]>(...keys: T) => { [key in T[number]]: (value: any, options: FilterQueryOptions) => any; };
238
244
 
239
245
  declare const filterObject: <T extends string[]>(...keys: T) => { [key in T[number]]: (value: any, options: FilterQueryOptions) => any; };
@@ -284,4 +290,4 @@ type InferRemoveResultFromPath<App extends Application, Path extends string, IdO
284
290
  type InferDataFromPath<App extends Application, Path extends string, Method extends "create" | "update" | "patch"> = Method extends "create" ? InferCreateDataFromPath<App, Path> : Method extends "update" ? InferUpdateDataFromPath<App, Path> : Method extends "patch" ? InferPatchDataFromPath<App, Path> : never;
285
291
  type InferResultFromPath<App extends Application, Path extends string, Method extends "get" | "find" | "create" | "update" | "patch" | "remove"> = Method extends "get" ? InferGetResultFromPath<App, Path> : Method extends "find" ? InferFindResultFromPath<App, Path> : Method extends "create" ? InferCreateResultFromPath<App, Path> : Method extends "update" ? InferUpdateResultFromPath<App, Path> : Method extends "patch" ? InferPatchResultFromPath<App, Path> : Method extends "remove" ? InferRemoveResultFromPath<App, Path> : never;
286
292
 
287
- export { type ActionOnEmptyIntersect, type CreateRelatedOptions, type DebouncedFunctionApp, type DebouncedService, DebouncedStore, type DebouncedStoreOptions, type FirstLast, type GetItemsIsArrayFrom, type GetItemsIsArrayOptions, type GetItemsIsArrayResult, type GetService, type Handle, type HookForEachOptions, type HookRunPerItemOptions, type HookSetDataOptions, type InferCreateData, type InferCreateDataFromPath, type InferCreateDataSingle, type InferCreateDataSingleFromPath, type InferCreateResult, type InferCreateResultFromPath, type InferCreateResultSingle, type InferCreateResultSingleFromPath, type InferDataFromPath, type InferFindResult, type InferFindResultFromPath, type InferGetResult, type InferGetResultFromPath, type InferPatchData, type InferPatchDataFromPath, type InferPatchResult, type InferPatchResultFromPath, type InferRemoveResult, type InferRemoveResultFromPath, type InferResultFromPath, type InferUpdateData, type InferUpdateDataFromPath, type InferUpdateResult, type InferUpdateResultFromPath, type InitDebounceMixinOptions, type MergeQueryOptions, type OnDeleteAction, type OnDeleteOptions, type Predicate, type PredicateWithContext, type PushSetOptions, type RemoveRelatedOptions, type SetQueryKeySafelyOptions, type ShouldSkipOptions, checkMulti, createRelated, debounceMixin, defineHooks, filterArray, filterObject, filterQuery, forEach, getItemsIsArray, getPaginate, isMulti, isPaginated, makeDefaultOptions, markHookForSkip, mergeArrays, mergeQuery, onDelete, parseFields, pushSet, removeRelated, runPerItem, setData, setQueryKeySafely, setResultEmpty, shouldSkip, toJSON, validateQueryProperty };
293
+ export { type ActionOnEmptyIntersect, type CreateRelatedOptions, type DebouncedFunctionApp, type DebouncedService, DebouncedStore, type DebouncedStoreOptions, type FirstLast, type GetItemsIsArrayFrom, type GetItemsIsArrayOptions, type GetItemsIsArrayResult, type GetService, type Handle, type HookForEachOptions, type HookRunPerItemOptions, type HookSetDataOptions, type InferCreateData, type InferCreateDataFromPath, type InferCreateDataSingle, type InferCreateDataSingleFromPath, type InferCreateResult, type InferCreateResultFromPath, type InferCreateResultSingle, type InferCreateResultSingleFromPath, type InferDataFromPath, type InferFindResult, type InferFindResultFromPath, type InferGetResult, type InferGetResultFromPath, type InferPatchData, type InferPatchDataFromPath, type InferPatchResult, type InferPatchResultFromPath, type InferRemoveResult, type InferRemoveResultFromPath, type InferResultFromPath, type InferUpdateData, type InferUpdateDataFromPath, type InferUpdateResult, type InferUpdateResultFromPath, type InitDebounceMixinOptions, type MergeQueryOptions, type OnDeleteAction, type OnDeleteOptions, type OptimizeBatchPatchOptions, type OptimizeBatchPatchResultItem, type Predicate, type PredicateWithContext, type PushSetOptions, type RemoveRelatedOptions, type SetQueryKeySafelyOptions, type ShouldSkipOptions, checkMulti, createRelated, debounceMixin, defineHooks, filterArray, filterObject, filterQuery, forEach, getItemsIsArray, getPaginate, isMulti, isPaginated, makeDefaultOptions, markHookForSkip, mergeArrays, mergeQuery, onDelete, optimizeBatchPatch, parseFields, pushSet, removeRelated, runPerItem, setData, setQueryKeySafely, setResultEmpty, shouldSkip, toJSON, validateQueryProperty };
package/dist/index.d.mts CHANGED
@@ -234,6 +234,12 @@ declare const toJSON: (context: HookContext) => HookContext<_feathersjs_feathers
234
234
  */
235
235
  declare const validateQueryProperty: (query: any, operators?: string[]) => Query;
236
236
 
237
+ type OptimizeBatchPatchOptions = {
238
+ id?: string;
239
+ };
240
+ type OptimizeBatchPatchResultItem<T = Record<string, unknown>, P = Params> = [Id, T, P | undefined];
241
+ declare function optimizeBatchPatch<T extends Record<string, unknown>, P extends Params>(items: Map<Id, T>, options?: OptimizeBatchPatchOptions): OptimizeBatchPatchResultItem<T, P>[];
242
+
237
243
  declare const filterArray: <T extends string[]>(...keys: T) => { [key in T[number]]: (value: any, options: FilterQueryOptions) => any; };
238
244
 
239
245
  declare const filterObject: <T extends string[]>(...keys: T) => { [key in T[number]]: (value: any, options: FilterQueryOptions) => any; };
@@ -284,4 +290,4 @@ type InferRemoveResultFromPath<App extends Application, Path extends string, IdO
284
290
  type InferDataFromPath<App extends Application, Path extends string, Method extends "create" | "update" | "patch"> = Method extends "create" ? InferCreateDataFromPath<App, Path> : Method extends "update" ? InferUpdateDataFromPath<App, Path> : Method extends "patch" ? InferPatchDataFromPath<App, Path> : never;
285
291
  type InferResultFromPath<App extends Application, Path extends string, Method extends "get" | "find" | "create" | "update" | "patch" | "remove"> = Method extends "get" ? InferGetResultFromPath<App, Path> : Method extends "find" ? InferFindResultFromPath<App, Path> : Method extends "create" ? InferCreateResultFromPath<App, Path> : Method extends "update" ? InferUpdateResultFromPath<App, Path> : Method extends "patch" ? InferPatchResultFromPath<App, Path> : Method extends "remove" ? InferRemoveResultFromPath<App, Path> : never;
286
292
 
287
- export { type ActionOnEmptyIntersect, type CreateRelatedOptions, type DebouncedFunctionApp, type DebouncedService, DebouncedStore, type DebouncedStoreOptions, type FirstLast, type GetItemsIsArrayFrom, type GetItemsIsArrayOptions, type GetItemsIsArrayResult, type GetService, type Handle, type HookForEachOptions, type HookRunPerItemOptions, type HookSetDataOptions, type InferCreateData, type InferCreateDataFromPath, type InferCreateDataSingle, type InferCreateDataSingleFromPath, type InferCreateResult, type InferCreateResultFromPath, type InferCreateResultSingle, type InferCreateResultSingleFromPath, type InferDataFromPath, type InferFindResult, type InferFindResultFromPath, type InferGetResult, type InferGetResultFromPath, type InferPatchData, type InferPatchDataFromPath, type InferPatchResult, type InferPatchResultFromPath, type InferRemoveResult, type InferRemoveResultFromPath, type InferResultFromPath, type InferUpdateData, type InferUpdateDataFromPath, type InferUpdateResult, type InferUpdateResultFromPath, type InitDebounceMixinOptions, type MergeQueryOptions, type OnDeleteAction, type OnDeleteOptions, type Predicate, type PredicateWithContext, type PushSetOptions, type RemoveRelatedOptions, type SetQueryKeySafelyOptions, type ShouldSkipOptions, checkMulti, createRelated, debounceMixin, defineHooks, filterArray, filterObject, filterQuery, forEach, getItemsIsArray, getPaginate, isMulti, isPaginated, makeDefaultOptions, markHookForSkip, mergeArrays, mergeQuery, onDelete, parseFields, pushSet, removeRelated, runPerItem, setData, setQueryKeySafely, setResultEmpty, shouldSkip, toJSON, validateQueryProperty };
293
+ export { type ActionOnEmptyIntersect, type CreateRelatedOptions, type DebouncedFunctionApp, type DebouncedService, DebouncedStore, type DebouncedStoreOptions, type FirstLast, type GetItemsIsArrayFrom, type GetItemsIsArrayOptions, type GetItemsIsArrayResult, type GetService, type Handle, type HookForEachOptions, type HookRunPerItemOptions, type HookSetDataOptions, type InferCreateData, type InferCreateDataFromPath, type InferCreateDataSingle, type InferCreateDataSingleFromPath, type InferCreateResult, type InferCreateResultFromPath, type InferCreateResultSingle, type InferCreateResultSingleFromPath, type InferDataFromPath, type InferFindResult, type InferFindResultFromPath, type InferGetResult, type InferGetResultFromPath, type InferPatchData, type InferPatchDataFromPath, type InferPatchResult, type InferPatchResultFromPath, type InferRemoveResult, type InferRemoveResultFromPath, type InferResultFromPath, type InferUpdateData, type InferUpdateDataFromPath, type InferUpdateResult, type InferUpdateResultFromPath, type InitDebounceMixinOptions, type MergeQueryOptions, type OnDeleteAction, type OnDeleteOptions, type OptimizeBatchPatchOptions, type OptimizeBatchPatchResultItem, type Predicate, type PredicateWithContext, type PushSetOptions, type RemoveRelatedOptions, type SetQueryKeySafelyOptions, type ShouldSkipOptions, checkMulti, createRelated, debounceMixin, defineHooks, filterArray, filterObject, filterQuery, forEach, getItemsIsArray, getPaginate, isMulti, isPaginated, makeDefaultOptions, markHookForSkip, mergeArrays, mergeQuery, onDelete, optimizeBatchPatch, parseFields, pushSet, removeRelated, runPerItem, setData, setQueryKeySafely, setResultEmpty, shouldSkip, toJSON, validateQueryProperty };
package/dist/index.d.ts CHANGED
@@ -234,6 +234,12 @@ declare const toJSON: (context: HookContext) => HookContext<_feathersjs_feathers
234
234
  */
235
235
  declare const validateQueryProperty: (query: any, operators?: string[]) => Query;
236
236
 
237
+ type OptimizeBatchPatchOptions = {
238
+ id?: string;
239
+ };
240
+ type OptimizeBatchPatchResultItem<T = Record<string, unknown>, P = Params> = [Id, T, P | undefined];
241
+ declare function optimizeBatchPatch<T extends Record<string, unknown>, P extends Params>(items: Map<Id, T>, options?: OptimizeBatchPatchOptions): OptimizeBatchPatchResultItem<T, P>[];
242
+
237
243
  declare const filterArray: <T extends string[]>(...keys: T) => { [key in T[number]]: (value: any, options: FilterQueryOptions) => any; };
238
244
 
239
245
  declare const filterObject: <T extends string[]>(...keys: T) => { [key in T[number]]: (value: any, options: FilterQueryOptions) => any; };
@@ -284,4 +290,4 @@ type InferRemoveResultFromPath<App extends Application, Path extends string, IdO
284
290
  type InferDataFromPath<App extends Application, Path extends string, Method extends "create" | "update" | "patch"> = Method extends "create" ? InferCreateDataFromPath<App, Path> : Method extends "update" ? InferUpdateDataFromPath<App, Path> : Method extends "patch" ? InferPatchDataFromPath<App, Path> : never;
285
291
  type InferResultFromPath<App extends Application, Path extends string, Method extends "get" | "find" | "create" | "update" | "patch" | "remove"> = Method extends "get" ? InferGetResultFromPath<App, Path> : Method extends "find" ? InferFindResultFromPath<App, Path> : Method extends "create" ? InferCreateResultFromPath<App, Path> : Method extends "update" ? InferUpdateResultFromPath<App, Path> : Method extends "patch" ? InferPatchResultFromPath<App, Path> : Method extends "remove" ? InferRemoveResultFromPath<App, Path> : never;
286
292
 
287
- export { type ActionOnEmptyIntersect, type CreateRelatedOptions, type DebouncedFunctionApp, type DebouncedService, DebouncedStore, type DebouncedStoreOptions, type FirstLast, type GetItemsIsArrayFrom, type GetItemsIsArrayOptions, type GetItemsIsArrayResult, type GetService, type Handle, type HookForEachOptions, type HookRunPerItemOptions, type HookSetDataOptions, type InferCreateData, type InferCreateDataFromPath, type InferCreateDataSingle, type InferCreateDataSingleFromPath, type InferCreateResult, type InferCreateResultFromPath, type InferCreateResultSingle, type InferCreateResultSingleFromPath, type InferDataFromPath, type InferFindResult, type InferFindResultFromPath, type InferGetResult, type InferGetResultFromPath, type InferPatchData, type InferPatchDataFromPath, type InferPatchResult, type InferPatchResultFromPath, type InferRemoveResult, type InferRemoveResultFromPath, type InferResultFromPath, type InferUpdateData, type InferUpdateDataFromPath, type InferUpdateResult, type InferUpdateResultFromPath, type InitDebounceMixinOptions, type MergeQueryOptions, type OnDeleteAction, type OnDeleteOptions, type Predicate, type PredicateWithContext, type PushSetOptions, type RemoveRelatedOptions, type SetQueryKeySafelyOptions, type ShouldSkipOptions, checkMulti, createRelated, debounceMixin, defineHooks, filterArray, filterObject, filterQuery, forEach, getItemsIsArray, getPaginate, isMulti, isPaginated, makeDefaultOptions, markHookForSkip, mergeArrays, mergeQuery, onDelete, parseFields, pushSet, removeRelated, runPerItem, setData, setQueryKeySafely, setResultEmpty, shouldSkip, toJSON, validateQueryProperty };
293
+ export { type ActionOnEmptyIntersect, type CreateRelatedOptions, type DebouncedFunctionApp, type DebouncedService, DebouncedStore, type DebouncedStoreOptions, type FirstLast, type GetItemsIsArrayFrom, type GetItemsIsArrayOptions, type GetItemsIsArrayResult, type GetService, type Handle, type HookForEachOptions, type HookRunPerItemOptions, type HookSetDataOptions, type InferCreateData, type InferCreateDataFromPath, type InferCreateDataSingle, type InferCreateDataSingleFromPath, type InferCreateResult, type InferCreateResultFromPath, type InferCreateResultSingle, type InferCreateResultSingleFromPath, type InferDataFromPath, type InferFindResult, type InferFindResultFromPath, type InferGetResult, type InferGetResultFromPath, type InferPatchData, type InferPatchDataFromPath, type InferPatchResult, type InferPatchResultFromPath, type InferRemoveResult, type InferRemoveResultFromPath, type InferResultFromPath, type InferUpdateData, type InferUpdateDataFromPath, type InferUpdateResult, type InferUpdateResultFromPath, type InitDebounceMixinOptions, type MergeQueryOptions, type OnDeleteAction, type OnDeleteOptions, type OptimizeBatchPatchOptions, type OptimizeBatchPatchResultItem, type Predicate, type PredicateWithContext, type PushSetOptions, type RemoveRelatedOptions, type SetQueryKeySafelyOptions, type ShouldSkipOptions, checkMulti, createRelated, debounceMixin, defineHooks, filterArray, filterObject, filterQuery, forEach, getItemsIsArray, getPaginate, isMulti, isPaginated, makeDefaultOptions, markHookForSkip, mergeArrays, mergeQuery, onDelete, optimizeBatchPatch, parseFields, pushSet, removeRelated, runPerItem, setData, setQueryKeySafely, setResultEmpty, shouldSkip, toJSON, validateQueryProperty };
package/dist/index.mjs CHANGED
@@ -593,6 +593,30 @@ const validateQueryProperty = (query, operators = []) => {
593
593
  };
594
594
  };
595
595
 
596
+ function optimizeBatchPatch(items, options) {
597
+ const map = [];
598
+ const id = options?.id ?? "id";
599
+ for (const [id2, data] of items) {
600
+ const index = map.findIndex((item) => deepEqual(item.data, data));
601
+ if (index === -1) {
602
+ map.push({ ids: [id2], data });
603
+ } else {
604
+ map[index].ids.push(id2);
605
+ }
606
+ }
607
+ return map.map(({ ids, data }) => {
608
+ return ids.length === 1 ? [ids[0], data, void 0] : [
609
+ null,
610
+ data,
611
+ {
612
+ query: {
613
+ [id]: { $in: ids }
614
+ }
615
+ }
616
+ ];
617
+ });
618
+ }
619
+
596
620
  function checkMulti() {
597
621
  return (context) => {
598
622
  if (shouldSkip("checkMulti", context)) {
@@ -954,4 +978,4 @@ const filterObject = (...keys) => {
954
978
  return result;
955
979
  };
956
980
 
957
- export { DebouncedStore, checkMulti, createRelated, debounceMixin, defineHooks, filterArray, filterObject, filterQuery, forEach, getItemsIsArray, getPaginate, isMulti, isPaginated, makeDefaultOptions, markHookForSkip, mergeArrays, mergeQuery, onDelete, parseFields, pushSet, removeRelated, runPerItem, setData, setQueryKeySafely, setResultEmpty, shouldSkip, toJSON, validateQueryProperty };
981
+ export { DebouncedStore, checkMulti, createRelated, debounceMixin, defineHooks, filterArray, filterObject, filterQuery, forEach, getItemsIsArray, getPaginate, isMulti, isPaginated, makeDefaultOptions, markHookForSkip, mergeArrays, mergeQuery, onDelete, optimizeBatchPatch, parseFields, pushSet, removeRelated, runPerItem, setData, setQueryKeySafely, setResultEmpty, shouldSkip, toJSON, validateQueryProperty };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feathers-utils",
3
- "version": "4.1.0",
3
+ "version": "4.2.0",
4
4
  "description": "Some utils for projects using '@feathersjs/feathers'",
5
5
  "author": "fratzinger",
6
6
  "repository": {
@@ -12,3 +12,4 @@ export * from "./setResultEmpty";
12
12
  export * from "./shouldSkip";
13
13
  export * from "./toJSON";
14
14
  export * from "./validateQueryProperty";
15
+ export * from "./optimizeBatchPatch";
@@ -0,0 +1,66 @@
1
+ import type { Id, Params } from "@feathersjs/feathers";
2
+ import { deepEqual } from "fast-equals";
3
+
4
+ export type OptimizeBatchPatchOptions = {
5
+ id?: string;
6
+ };
7
+
8
+ export type OptimizeBatchPatchResultItem<
9
+ T = Record<string, unknown>,
10
+ P = Params,
11
+ > = [Id, T, P | undefined];
12
+
13
+ export function optimizeBatchPatch<
14
+ T extends Record<string, unknown>,
15
+ P extends Params,
16
+ >(
17
+ items: Map<Id, T>,
18
+ options?: OptimizeBatchPatchOptions,
19
+ ): OptimizeBatchPatchResultItem<T, P>[] {
20
+ const map: { ids: Id[]; data: T }[] = [];
21
+
22
+ const id = options?.id ?? "id";
23
+
24
+ for (const [id, data] of items) {
25
+ const index = map.findIndex((item) => deepEqual(item.data, data));
26
+
27
+ if (index === -1) {
28
+ map.push({ ids: [id], data });
29
+ } else {
30
+ map[index].ids.push(id);
31
+ }
32
+ }
33
+
34
+ return map.map(({ ids, data }) => {
35
+ return ids.length === 1
36
+ ? ([ids[0], data, undefined] as OptimizeBatchPatchResultItem<T, P>)
37
+ : ([
38
+ null,
39
+ data,
40
+ {
41
+ query: {
42
+ [id]: { $in: ids },
43
+ },
44
+ },
45
+ ] as OptimizeBatchPatchResultItem<T, P>);
46
+ });
47
+ }
48
+
49
+ if (import.meta.vitest) {
50
+ const { it, expect } = import.meta.vitest;
51
+ it("optimizeBatchPatch", () => {
52
+ const items = new Map<Id, Record<string, unknown>>([
53
+ ["1", { name: "John" }],
54
+ ["2", { name: "Jane" }],
55
+ ["3", { name: "John" }],
56
+ ["4", { name: "Jane" }],
57
+ [5, { name: "Jack" }],
58
+ ]);
59
+
60
+ expect(optimizeBatchPatch(items)).toEqual([
61
+ [null, { name: "John" }, { query: { id: { $in: ["1", "3"] } } }],
62
+ [null, { name: "Jane" }, { query: { id: { $in: ["2", "4"] } } }],
63
+ [5, { name: "Jack" }, undefined],
64
+ ]);
65
+ });
66
+ }