feathers-utils 1.12.0 → 1.13.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.
@@ -0,0 +1,8 @@
1
+ import type { ReturnAsyncHook, Promisable } from "../types";
2
+ import type { HookContext } from "@feathersjs/feathers";
3
+ import type { GetItemsIsArrayOptions } from "../utils/getItemsIsArray";
4
+ export interface HookForEachOptions {
5
+ wait?: "sequential" | "parallel" | false;
6
+ items?: GetItemsIsArrayOptions["from"];
7
+ }
8
+ export declare const forEach: (actionPerItem: (item: any, context: HookContext) => Promisable<any>, _options?: HookForEachOptions) => ReturnAsyncHook;
@@ -0,0 +1,31 @@
1
+ import { shouldSkip } from "../utils/shouldSkip";
2
+ import { getItemsIsArray } from "../utils/getItemsIsArray";
3
+ export const forEach = (
4
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5
+ actionPerItem, _options) => {
6
+ const options = {
7
+ wait: "parallel",
8
+ items: "automatic",
9
+ ..._options
10
+ };
11
+ return async (context) => {
12
+ if (shouldSkip("runForItems", context)) {
13
+ return context;
14
+ }
15
+ const { items } = getItemsIsArray(context, { from: options.items });
16
+ const promises = [];
17
+ for (const item of items) {
18
+ const promise = actionPerItem(item, context);
19
+ if (options.wait === "sequential") {
20
+ await promise;
21
+ }
22
+ else {
23
+ promises.push(promise);
24
+ }
25
+ }
26
+ if (options.wait === "parallel") {
27
+ await Promise.all(promises);
28
+ }
29
+ return context;
30
+ };
31
+ };
@@ -0,0 +1,8 @@
1
+ import type { HookContext } from "@feathersjs/feathers";
2
+ /**
3
+ * Parse fields to date or number
4
+ * skips undefined fields
5
+ */
6
+ export declare const parseFields: (type: "date" | "number", options: {
7
+ fields: string[];
8
+ }) => (context: HookContext) => HookContext<any, import("@feathersjs/feathers").Service<any>>;
@@ -0,0 +1,23 @@
1
+ import { getItemsIsArray } from "../utils/getItemsIsArray";
2
+ /**
3
+ * Parse fields to date or number
4
+ * skips undefined fields
5
+ */
6
+ export const parseFields = (type, options) => (context) => {
7
+ const { items } = getItemsIsArray(context);
8
+ items.forEach(item => {
9
+ options.fields.forEach(field => {
10
+ // ignore undefined fields
11
+ if (!(field in item)) {
12
+ return;
13
+ }
14
+ if (type === "date") {
15
+ item[field] = new Date(item[field]);
16
+ }
17
+ else if (type === "number") {
18
+ item[field] = Number(item[field]);
19
+ }
20
+ });
21
+ });
22
+ return context;
23
+ };
@@ -11,6 +11,8 @@ export { createRelated } from "./hooks/createRelated";
11
11
  export { setData };
12
12
  export { removeRelated } from "./hooks/removeRelated";
13
13
  export { runPerItem };
14
+ export * from "./hooks/forEach";
15
+ export * from "./hooks/parseFields";
14
16
  import { debounceMixin, DebouncedStore } from "./mixins/debounce-mixin";
15
17
  export declare const mixins: {
16
18
  debounceMixin: typeof debounceMixin;
package/dist/esm/index.js CHANGED
@@ -12,6 +12,8 @@ export { createRelated } from "./hooks/createRelated";
12
12
  export { setData };
13
13
  export { removeRelated } from "./hooks/removeRelated";
14
14
  export { runPerItem };
15
+ export * from "./hooks/forEach";
16
+ export * from "./hooks/parseFields";
15
17
  import { debounceMixin, DebouncedStore } from "./mixins/debounce-mixin";
16
18
  export const mixins = {
17
19
  debounceMixin,
@@ -82,7 +82,7 @@ export interface FilterQueryResult {
82
82
  paginate?: unknown;
83
83
  [key: string]: unknown;
84
84
  }
85
- export interface GetItemsIsArrayOptions<T = any> {
85
+ export interface GetItemsIsArrayResult<T = any> {
86
86
  items: T[];
87
87
  isArray: boolean;
88
88
  }
@@ -1,3 +1,6 @@
1
1
  import type { HookContext } from "@feathersjs/feathers";
2
- import type { GetItemsIsArrayOptions } from "..";
3
- export declare const getItemsIsArray: <T = any>(context: HookContext) => GetItemsIsArrayOptions<T>;
2
+ import type { GetItemsIsArrayResult } from "..";
3
+ export declare type GetItemsIsArrayOptions = {
4
+ from: "data" | "result" | "automatic";
5
+ };
6
+ export declare const getItemsIsArray: <T = any>(context: HookContext, options?: GetItemsIsArrayOptions) => GetItemsIsArrayResult<T>;
@@ -1,11 +1,21 @@
1
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;
2
+ export const getItemsIsArray = (context, options) => {
3
+ const { from = "automatic" } = options || {};
4
+ let itemOrItems;
5
+ if (from === "automatic") {
6
+ itemOrItems = context.type === "before"
7
+ ? context.data
8
+ : context.result;
9
+ itemOrItems = itemOrItems && context.method === "find"
10
+ ? (itemOrItems.data || itemOrItems)
11
+ : itemOrItems;
12
+ }
13
+ else if (from === "data") {
14
+ itemOrItems = context.data;
15
+ }
16
+ else if (from === "result") {
17
+ itemOrItems = context.result;
18
+ }
9
19
  const isArray = Array.isArray(itemOrItems);
10
20
  return {
11
21
  items: (isArray)
@@ -0,0 +1,8 @@
1
+ import type { ReturnAsyncHook, Promisable } from "../types";
2
+ import type { HookContext } from "@feathersjs/feathers";
3
+ import type { GetItemsIsArrayOptions } from "../utils/getItemsIsArray";
4
+ export interface HookForEachOptions {
5
+ wait?: "sequential" | "parallel" | false;
6
+ items?: GetItemsIsArrayOptions["from"];
7
+ }
8
+ export declare const forEach: (actionPerItem: (item: any, context: HookContext) => Promisable<any>, _options?: HookForEachOptions) => ReturnAsyncHook;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.forEach = void 0;
13
+ const shouldSkip_1 = require("../utils/shouldSkip");
14
+ const getItemsIsArray_1 = require("../utils/getItemsIsArray");
15
+ const forEach = (
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
+ actionPerItem, _options) => {
18
+ const options = Object.assign({ wait: "parallel", items: "automatic" }, _options);
19
+ return (context) => __awaiter(void 0, void 0, void 0, function* () {
20
+ if ((0, shouldSkip_1.shouldSkip)("runForItems", context)) {
21
+ return context;
22
+ }
23
+ const { items } = (0, getItemsIsArray_1.getItemsIsArray)(context, { from: options.items });
24
+ const promises = [];
25
+ for (const item of items) {
26
+ const promise = actionPerItem(item, context);
27
+ if (options.wait === "sequential") {
28
+ yield promise;
29
+ }
30
+ else {
31
+ promises.push(promise);
32
+ }
33
+ }
34
+ if (options.wait === "parallel") {
35
+ yield Promise.all(promises);
36
+ }
37
+ return context;
38
+ });
39
+ };
40
+ exports.forEach = forEach;
@@ -0,0 +1,8 @@
1
+ import type { HookContext } from "@feathersjs/feathers";
2
+ /**
3
+ * Parse fields to date or number
4
+ * skips undefined fields
5
+ */
6
+ export declare const parseFields: (type: "date" | "number", options: {
7
+ fields: string[];
8
+ }) => (context: HookContext) => HookContext<any, import("@feathersjs/feathers").Service<any>>;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseFields = void 0;
4
+ const getItemsIsArray_1 = require("../utils/getItemsIsArray");
5
+ /**
6
+ * Parse fields to date or number
7
+ * skips undefined fields
8
+ */
9
+ const parseFields = (type, options) => (context) => {
10
+ const { items } = (0, getItemsIsArray_1.getItemsIsArray)(context);
11
+ items.forEach(item => {
12
+ options.fields.forEach(field => {
13
+ // ignore undefined fields
14
+ if (!(field in item)) {
15
+ return;
16
+ }
17
+ if (type === "date") {
18
+ item[field] = new Date(item[field]);
19
+ }
20
+ else if (type === "number") {
21
+ item[field] = Number(item[field]);
22
+ }
23
+ });
24
+ });
25
+ return context;
26
+ };
27
+ exports.parseFields = parseFields;
package/dist/index.d.ts CHANGED
@@ -11,6 +11,8 @@ export { createRelated } from "./hooks/createRelated";
11
11
  export { setData };
12
12
  export { removeRelated } from "./hooks/removeRelated";
13
13
  export { runPerItem };
14
+ export * from "./hooks/forEach";
15
+ export * from "./hooks/parseFields";
14
16
  import { debounceMixin, DebouncedStore } from "./mixins/debounce-mixin";
15
17
  export declare const mixins: {
16
18
  debounceMixin: typeof debounceMixin;
package/dist/index.js CHANGED
@@ -31,6 +31,8 @@ var createRelated_1 = require("./hooks/createRelated");
31
31
  Object.defineProperty(exports, "createRelated", { enumerable: true, get: function () { return createRelated_1.createRelated; } });
32
32
  var removeRelated_1 = require("./hooks/removeRelated");
33
33
  Object.defineProperty(exports, "removeRelated", { enumerable: true, get: function () { return removeRelated_1.removeRelated; } });
34
+ __exportStar(require("./hooks/forEach"), exports);
35
+ __exportStar(require("./hooks/parseFields"), exports);
34
36
  const debounce_mixin_1 = require("./mixins/debounce-mixin");
35
37
  Object.defineProperty(exports, "debounceMixin", { enumerable: true, get: function () { return debounce_mixin_1.debounceMixin; } });
36
38
  Object.defineProperty(exports, "DebouncedStore", { enumerable: true, get: function () { return debounce_mixin_1.DebouncedStore; } });
package/dist/types.d.ts CHANGED
@@ -82,7 +82,7 @@ export interface FilterQueryResult {
82
82
  paginate?: unknown;
83
83
  [key: string]: unknown;
84
84
  }
85
- export interface GetItemsIsArrayOptions<T = any> {
85
+ export interface GetItemsIsArrayResult<T = any> {
86
86
  items: T[];
87
87
  isArray: boolean;
88
88
  }
@@ -1,3 +1,6 @@
1
1
  import type { HookContext } from "@feathersjs/feathers";
2
- import type { GetItemsIsArrayOptions } from "..";
3
- export declare const getItemsIsArray: <T = any>(context: HookContext) => GetItemsIsArrayOptions<T>;
2
+ import type { GetItemsIsArrayResult } from "..";
3
+ export declare type GetItemsIsArrayOptions = {
4
+ from: "data" | "result" | "automatic";
5
+ };
6
+ export declare const getItemsIsArray: <T = any>(context: HookContext, options?: GetItemsIsArrayOptions) => GetItemsIsArrayResult<T>;
@@ -2,13 +2,23 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getItemsIsArray = void 0;
4
4
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
5
- const getItemsIsArray = (context) => {
6
- let itemOrItems = context.type === "before"
7
- ? context.data
8
- : context.result;
9
- itemOrItems = itemOrItems && context.method === "find"
10
- ? (itemOrItems.data || itemOrItems)
11
- : itemOrItems;
5
+ const getItemsIsArray = (context, options) => {
6
+ const { from = "automatic" } = options || {};
7
+ let itemOrItems;
8
+ if (from === "automatic") {
9
+ itemOrItems = context.type === "before"
10
+ ? context.data
11
+ : context.result;
12
+ itemOrItems = itemOrItems && context.method === "find"
13
+ ? (itemOrItems.data || itemOrItems)
14
+ : itemOrItems;
15
+ }
16
+ else if (from === "data") {
17
+ itemOrItems = context.data;
18
+ }
19
+ else if (from === "result") {
20
+ itemOrItems = context.result;
21
+ }
12
22
  const isArray = Array.isArray(itemOrItems);
13
23
  return {
14
24
  items: (isArray)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feathers-utils",
3
- "version": "1.12.0",
3
+ "version": "1.13.0",
4
4
  "description": "Some utils for projects using '@feathersjs/feathers'",
5
5
  "author": "fratzinger",
6
6
  "repository": {
@@ -0,0 +1,47 @@
1
+ import { shouldSkip } from "../utils/shouldSkip";
2
+
3
+ import type { ReturnAsyncHook, Promisable } from "../types";
4
+ import type { HookContext } from "@feathersjs/feathers";
5
+ import type { GetItemsIsArrayOptions } from "../utils/getItemsIsArray";
6
+ import { getItemsIsArray } from "../utils/getItemsIsArray";
7
+
8
+ export interface HookForEachOptions {
9
+ wait?: "sequential" | "parallel" | false
10
+ items?: GetItemsIsArrayOptions["from"]
11
+ }
12
+
13
+ export const forEach = (
14
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
15
+ actionPerItem: (item: any, context: HookContext) => Promisable<any>,
16
+ _options?: HookForEachOptions
17
+ ): ReturnAsyncHook => {
18
+ const options: Required<HookForEachOptions> = {
19
+ wait: "parallel",
20
+ items: "automatic",
21
+ ..._options
22
+ };
23
+
24
+ return async (context: HookContext): Promise<HookContext> => {
25
+ if (shouldSkip("runForItems", context)) { return context; }
26
+
27
+ const { items } = getItemsIsArray(context, { from: options.items });
28
+
29
+ const promises: Promise<any>[] = [];
30
+
31
+ for (const item of items) {
32
+ const promise = actionPerItem(item, context);
33
+
34
+ if (options.wait === "sequential") {
35
+ await promise;
36
+ } else {
37
+ promises.push(promise);
38
+ }
39
+ }
40
+
41
+ if (options.wait === "parallel") {
42
+ await Promise.all(promises);
43
+ }
44
+
45
+ return context;
46
+ };
47
+ };
@@ -0,0 +1,27 @@
1
+ import type { HookContext } from "@feathersjs/feathers";
2
+ import { getItemsIsArray } from "../utils/getItemsIsArray";
3
+
4
+ /**
5
+ * Parse fields to date or number
6
+ * skips undefined fields
7
+ */
8
+ export const parseFields = (type: "date" | "number", options: { fields: string[] }) => (context: HookContext) => {
9
+ const { items } = getItemsIsArray(context);
10
+
11
+ items.forEach(item => {
12
+ options.fields.forEach(field => {
13
+ // ignore undefined fields
14
+ if (!(field in item)) {
15
+ return;
16
+ }
17
+
18
+ if (type === "date") {
19
+ item[field] = new Date(item[field]);
20
+ } else if (type === "number") {
21
+ item[field] = Number(item[field]);
22
+ }
23
+ });
24
+ });
25
+
26
+ return context;
27
+ };
package/src/index.ts CHANGED
@@ -15,6 +15,8 @@ export { createRelated } from "./hooks/createRelated";
15
15
  export { setData };
16
16
  export { removeRelated } from "./hooks/removeRelated";
17
17
  export { runPerItem };
18
+ export * from "./hooks/forEach";
19
+ export * from "./hooks/parseFields";
18
20
 
19
21
  import { debounceMixin, DebouncedStore } from "./mixins/debounce-mixin";
20
22
 
package/src/types.ts CHANGED
@@ -120,7 +120,7 @@ export interface FilterQueryResult {
120
120
  }
121
121
 
122
122
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
123
- export interface GetItemsIsArrayOptions<T = any> {
123
+ export interface GetItemsIsArrayResult<T = any> {
124
124
  items: T[]
125
125
  isArray: boolean
126
126
  }
@@ -1,16 +1,34 @@
1
1
  import type { HookContext } from "@feathersjs/feathers";
2
- import type { GetItemsIsArrayOptions } from "..";
2
+ import type { GetItemsIsArrayResult } from "..";
3
+
4
+ export type GetItemsIsArrayOptions = {
5
+ from: "data" | "result" | "automatic"
6
+ }
3
7
 
4
8
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
5
9
  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;
10
+ context: HookContext,
11
+ options?: GetItemsIsArrayOptions
12
+ ): GetItemsIsArrayResult<T> => {
13
+ const {
14
+ from = "automatic"
15
+ } = options || {};
16
+
17
+ let itemOrItems;
18
+
19
+ if (from === "automatic") {
20
+ itemOrItems = context.type === "before"
21
+ ? context.data
22
+ : context.result;
23
+ itemOrItems = itemOrItems && context.method === "find"
24
+ ? (itemOrItems.data || itemOrItems)
25
+ : itemOrItems;
26
+ } else if (from === "data") {
27
+ itemOrItems = context.data;
28
+ } else if (from === "result") {
29
+ itemOrItems = context.result;
30
+ }
31
+
14
32
  const isArray = Array.isArray(itemOrItems);
15
33
  return {
16
34
  items: (isArray)