@feathersjs/schema 5.0.0-pre.18 → 5.0.0-pre.21

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/CHANGELOG.md CHANGED
@@ -3,6 +3,54 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [5.0.0-pre.21](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.20...v5.0.0-pre.21) (2022-05-23)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **schema:** Add Combine helper to allow merging schema types that use ([#2637](https://github.com/feathersjs/feathers/issues/2637)) ([06d03e9](https://github.com/feathersjs/feathers/commit/06d03e91abb1347576c2351c12322d01c58473e5))
12
+ * **typescript:** Make additional types generic to work with extended types ([#2625](https://github.com/feathersjs/feathers/issues/2625)) ([269fdec](https://github.com/feathersjs/feathers/commit/269fdecc5961092dc8608b3cbe16f433c80bfa96))
13
+
14
+
15
+ ### Features
16
+
17
+ * **schema:** Add resolveAll hook ([#2643](https://github.com/feathersjs/feathers/issues/2643)) ([85527d7](https://github.com/feathersjs/feathers/commit/85527d71cb78852880696e5d96abdcdf24593934))
18
+ * **schema:** Add resolver for safe external data dispatching ([#2641](https://github.com/feathersjs/feathers/issues/2641)) ([72b980e](https://github.com/feathersjs/feathers/commit/72b980e05631136d30c8f1468dee45ec6a8d2503))
19
+ * **schema:** Add schema resolver converter functionality ([#2640](https://github.com/feathersjs/feathers/issues/2640)) ([26d9e05](https://github.com/feathersjs/feathers/commit/26d9e05327d6e0144466cd57d6fcc11ac7ecb06a))
20
+
21
+
22
+
23
+
24
+
25
+ # [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)
26
+
27
+
28
+ ### Bug Fixes
29
+
30
+ * **dependencies:** Lock monorepo package version numbers ([#2623](https://github.com/feathersjs/feathers/issues/2623)) ([5640c10](https://github.com/feathersjs/feathers/commit/5640c1020cc139994e695d658c08bad3494db507))
31
+
32
+
33
+ ### Features
34
+
35
+ * **schema:** Add querySyntax helper to create full query schemas ([#2621](https://github.com/feathersjs/feathers/issues/2621)) ([2bbb103](https://github.com/feathersjs/feathers/commit/2bbb103b2f3e30fb0fff935f92ad3276a1a67e41))
36
+
37
+
38
+
39
+
40
+
41
+ # [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)
42
+
43
+
44
+ ### Features
45
+
46
+ * **schema:** Allow hooks to run resolvers in sequence ([#2609](https://github.com/feathersjs/feathers/issues/2609)) ([d85c507](https://github.com/feathersjs/feathers/commit/d85c507c76d07e48fc8e7e28ff7de0ef435e0ef8))
47
+ * **typescript:** Improve adapter typings ([#2605](https://github.com/feathersjs/feathers/issues/2605)) ([3b2ca0a](https://github.com/feathersjs/feathers/commit/3b2ca0a6a8e03e8390272c4d7e930b4bffdaacf5))
48
+ * **typescript:** Improve params and query typeability ([#2600](https://github.com/feathersjs/feathers/issues/2600)) ([df28b76](https://github.com/feathersjs/feathers/commit/df28b7619161f1df5e700326f52cca1a92dc5d28))
49
+
50
+
51
+
52
+
53
+
6
54
  # [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)
7
55
 
8
56
 
@@ -0,0 +1,2 @@
1
+ export * from './resolve';
2
+ export * from './validate';
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./resolve"), exports);
18
+ __exportStar(require("./validate"), exports);
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4CAA0B;AAC1B,6CAA2B"}
@@ -0,0 +1,14 @@
1
+ import { HookContext, NextFunction } from '@feathersjs/feathers';
2
+ import { Resolver } from '../resolver';
3
+ export declare const DISPATCH: unique symbol;
4
+ export declare const resolveQuery: <T, H extends HookContext<import("@feathersjs/feathers").Application<any, any>, any>>(...resolvers: Resolver<T, H>[]) => (context: H, next?: NextFunction) => Promise<any>;
5
+ export declare const resolveData: <T, H extends HookContext<import("@feathersjs/feathers").Application<any, any>, any>>(...resolvers: Resolver<T, H>[]) => (context: H, next?: NextFunction) => Promise<any>;
6
+ export declare const resolveResult: <T, H extends HookContext<import("@feathersjs/feathers").Application<any, any>, any>>(...resolvers: Resolver<T, H>[]) => (context: H, next?: NextFunction) => Promise<void>;
7
+ export declare const resolveDispatch: <T, H extends HookContext<import("@feathersjs/feathers").Application<any, any>, any>>(...resolvers: Resolver<T, H>[]) => (context: H, next?: NextFunction) => Promise<void>;
8
+ export declare type ResolveAllSettings<H extends HookContext> = {
9
+ data?: Resolver<any, H> | Resolver<any, H>[];
10
+ query?: Resolver<any, H> | Resolver<any, H>[];
11
+ result?: Resolver<any, H> | Resolver<any, H>[];
12
+ dispatch?: Resolver<any, H> | Resolver<any, H>[];
13
+ };
14
+ export declare const resolveAll: <H extends HookContext<import("@feathersjs/feathers").Application<any, any>, any>>(map: ResolveAllSettings<H>) => (this: any, context: H, next?: import("@feathersjs/hooks").AsyncMiddleware<H>) => Promise<any>;
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveAll = exports.resolveDispatch = exports.resolveResult = exports.resolveData = exports.resolveQuery = exports.DISPATCH = void 0;
4
+ const hooks_1 = require("@feathersjs/hooks");
5
+ const getContext = (context) => {
6
+ return {
7
+ ...context,
8
+ params: {
9
+ ...context.params,
10
+ query: {}
11
+ }
12
+ };
13
+ };
14
+ const getData = (context) => {
15
+ const isPaginated = context.method === 'find' && context.result.data;
16
+ const data = isPaginated ? context.result.data : context.result;
17
+ return { isPaginated, data };
18
+ };
19
+ const runResolvers = async (resolvers, data, ctx, status) => {
20
+ let current = data;
21
+ for (const resolver of resolvers) {
22
+ current = await resolver.resolve(current, ctx, status);
23
+ }
24
+ return current;
25
+ };
26
+ exports.DISPATCH = Symbol('@feathersjs/schema/dispatch');
27
+ const resolveQuery = (...resolvers) => async (context, next) => {
28
+ var _a;
29
+ const ctx = getContext(context);
30
+ const data = ((_a = context === null || context === void 0 ? void 0 : context.params) === null || _a === void 0 ? void 0 : _a.query) || {};
31
+ const query = await runResolvers(resolvers, data, ctx);
32
+ context.params = {
33
+ ...context.params,
34
+ query
35
+ };
36
+ if (typeof next === 'function') {
37
+ return next();
38
+ }
39
+ };
40
+ exports.resolveQuery = resolveQuery;
41
+ const resolveData = (...resolvers) => async (context, next) => {
42
+ if (context.method === 'create' || context.method === 'patch' || context.method === 'update') {
43
+ const ctx = getContext(context);
44
+ const data = context.data;
45
+ const status = {
46
+ originalContext: context
47
+ };
48
+ if (Array.isArray(data)) {
49
+ context.data = await Promise.all(data.map(current => runResolvers(resolvers, current, ctx, status)));
50
+ }
51
+ else {
52
+ context.data = await runResolvers(resolvers, data, ctx, status);
53
+ }
54
+ }
55
+ if (typeof next === 'function') {
56
+ return next();
57
+ }
58
+ };
59
+ exports.resolveData = resolveData;
60
+ const resolveResult = (...resolvers) => async (context, next) => {
61
+ var _a;
62
+ if (typeof next === 'function') {
63
+ const { $resolve: properties, ...query } = ((_a = context.params) === null || _a === void 0 ? void 0 : _a.query) || {};
64
+ const resolve = {
65
+ originalContext: context,
66
+ ...context.params.resolve,
67
+ properties
68
+ };
69
+ context.params = {
70
+ ...context.params,
71
+ resolve,
72
+ query
73
+ };
74
+ await next();
75
+ }
76
+ const ctx = getContext(context);
77
+ const status = context.params.resolve;
78
+ const { isPaginated, data } = getData(context);
79
+ const result = Array.isArray(data) ?
80
+ await Promise.all(data.map(async (current) => runResolvers(resolvers, current, ctx, status))) :
81
+ await runResolvers(resolvers, data, ctx, status);
82
+ if (isPaginated) {
83
+ context.result.data = result;
84
+ }
85
+ else {
86
+ context.result = result;
87
+ }
88
+ };
89
+ exports.resolveResult = resolveResult;
90
+ const resolveDispatch = (...resolvers) => async (context, next) => {
91
+ if (typeof next === 'function') {
92
+ await next();
93
+ }
94
+ const ctx = getContext(context);
95
+ const status = context.params.resolve;
96
+ const { isPaginated, data } = getData(context);
97
+ const resolveDispatch = async (current) => {
98
+ const resolved = await runResolvers(resolvers, current, ctx, status);
99
+ return Object.keys(resolved).reduce((res, key) => {
100
+ const value = current[key];
101
+ const hasDispatch = typeof value === 'object' && value !== null && value[exports.DISPATCH] !== undefined;
102
+ res[key] = hasDispatch ? value[exports.DISPATCH] : value;
103
+ return res;
104
+ }, {});
105
+ };
106
+ const result = await (Array.isArray(data) ? Promise.all(data.map(resolveDispatch)) : resolveDispatch(data));
107
+ const dispatch = isPaginated ? {
108
+ ...context.result,
109
+ data: result
110
+ } : result;
111
+ context.dispatch = dispatch;
112
+ Object.defineProperty(context.result, exports.DISPATCH, {
113
+ value: dispatch,
114
+ enumerable: false,
115
+ configurable: false
116
+ });
117
+ };
118
+ exports.resolveDispatch = resolveDispatch;
119
+ const getResolvers = (map, name) => {
120
+ const value = map[name];
121
+ return Array.isArray(value) ? value : (value !== undefined ? [value] : []);
122
+ };
123
+ const resolveAll = (map) => (0, hooks_1.compose)([
124
+ (0, exports.resolveDispatch)(...getResolvers(map, 'dispatch')),
125
+ (0, exports.resolveResult)(...getResolvers(map, 'result')),
126
+ (0, exports.resolveQuery)(...getResolvers(map, 'query')),
127
+ (0, exports.resolveData)(...getResolvers(map, 'data'))
128
+ ]);
129
+ exports.resolveAll = resolveAll;
130
+ //# sourceMappingURL=resolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/hooks/resolve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { HookContext, NextFunction } from '@feathersjs/feathers';
2
+ import { Schema } from '../schema';
3
+ export declare const validateQuery: <H extends HookContext<import("@feathersjs/feathers").Application<any, any>, any>>(schema: Schema<any>) => (context: H, next?: NextFunction) => Promise<any>;
4
+ export declare const validateData: <H extends HookContext<import("@feathersjs/feathers").Application<any, any>, any>>(schema: Schema<any>) => (context: H, next?: NextFunction) => Promise<any>;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateData = exports.validateQuery = void 0;
4
+ const lib_1 = require("../../../errors/lib");
5
+ const validateQuery = (schema) => async (context, next) => {
6
+ var _a;
7
+ const data = ((_a = context === null || context === void 0 ? void 0 : context.params) === null || _a === void 0 ? void 0 : _a.query) || {};
8
+ try {
9
+ const query = await schema.validate(data);
10
+ context.params = {
11
+ ...context.params,
12
+ query
13
+ };
14
+ if (typeof next === 'function') {
15
+ return next();
16
+ }
17
+ }
18
+ catch (error) {
19
+ throw (error.ajv ? new lib_1.BadRequest(error.message, error.errors) : error);
20
+ }
21
+ };
22
+ exports.validateQuery = validateQuery;
23
+ const validateData = (schema) => async (context, next) => {
24
+ const data = context.data;
25
+ try {
26
+ if (Array.isArray(data)) {
27
+ context.data = await Promise.all(data.map(current => schema.validate(current)));
28
+ }
29
+ else {
30
+ context.data = await schema.validate(data);
31
+ }
32
+ }
33
+ catch (error) {
34
+ throw (error.ajv ? new lib_1.BadRequest(error.message, error.errors) : error);
35
+ }
36
+ if (typeof next === 'function') {
37
+ return next();
38
+ }
39
+ };
40
+ exports.validateData = validateData;
41
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/hooks/validate.ts"],"names":[],"mappings":";;;AACA,6CAAiD;AAG1C,MAAM,aAAa,GAAG,CAAyB,MAAmB,EAAE,EAAE,CAC3E,KAAK,EAAE,OAAU,EAAE,IAAmB,EAAE,EAAE;;IACxC,MAAM,IAAI,GAAG,CAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,MAAM,0CAAE,KAAK,KAAI,EAAE,CAAC;IAE1C,IAAI;QACF,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAE1C,OAAO,CAAC,MAAM,GAAG;YACf,GAAG,OAAO,CAAC,MAAM;YACjB,KAAK;SACN,CAAA;QAED,IAAI,OAAO,IAAI,KAAK,UAAU,EAAE;YAC9B,OAAO,IAAI,EAAE,CAAC;SACf;KACF;IAAC,OAAO,KAAU,EAAE;QACnB,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,gBAAU,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;KACzE;AACH,CAAC,CAAC;AAlBS,QAAA,aAAa,iBAkBtB;AAEK,MAAM,YAAY,GAAG,CAAyB,MAAmB,EAAE,EAAE,CAC5E,KAAK,EAAE,OAAU,EAAE,IAAmB,EAAE,EAAE;IACxC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAE1B,IAAI;QACF,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;YACvB,OAAO,CAAC,IAAI,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAClD,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CACzB,CAAC,CAAC;SACJ;aAAM;YACL,OAAO,CAAC,IAAI,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;SAC5C;KACF;IAAC,OAAO,KAAU,EAAE;QACnB,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,gBAAU,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;KACzE;IAED,IAAI,OAAO,IAAI,KAAK,UAAU,EAAE;QAC9B,OAAO,IAAI,EAAE,CAAC;KACf;AACH,CAAC,CAAC;AAnBW,QAAA,YAAY,gBAmBvB"}
package/lib/index.d.ts CHANGED
@@ -6,6 +6,9 @@ export * from './query';
6
6
  export declare type Infer<S extends {
7
7
  _type: any;
8
8
  }> = S['_type'];
9
+ export declare type Combine<S extends {
10
+ _type: any;
11
+ }, U> = Pick<Infer<S>, Exclude<keyof Infer<S>, keyof U>> & U;
9
12
  declare module '@feathersjs/feathers/lib/declarations' {
10
13
  interface Params {
11
14
  resolve?: ResolverStatus<any, HookContext>;
package/lib/query.d.ts CHANGED
@@ -1,5 +1,29 @@
1
1
  import { JSONSchema } from 'json-schema-to-ts';
2
- export declare const queryProperty: <T extends JSONSchema>(definition: T) => {
2
+ export declare type PropertyQuery<D extends JSONSchema> = {
3
+ anyOf: [
4
+ D,
5
+ {
6
+ type: 'object';
7
+ additionalProperties: false;
8
+ properties: {
9
+ $gt: D;
10
+ $gte: D;
11
+ $lt: D;
12
+ $lte: D;
13
+ $ne: D;
14
+ $in: {
15
+ type: 'array';
16
+ items: D;
17
+ };
18
+ $nin: {
19
+ type: 'array';
20
+ items: D;
21
+ };
22
+ };
23
+ }
24
+ ];
25
+ };
26
+ export declare const queryProperty: <T extends import("json-schema-to-ts").JSONSchema7>(definition: T) => {
3
27
  readonly anyOf: readonly [T, {
4
28
  readonly type: "object";
5
29
  readonly additionalProperties: false;
@@ -20,3 +44,32 @@ export declare const queryProperty: <T extends JSONSchema>(definition: T) => {
20
44
  };
21
45
  }];
22
46
  };
47
+ export declare const queryProperties: <T extends {
48
+ [key: string]: import("json-schema-to-ts").JSONSchema7;
49
+ }>(definition: T) => { [K in keyof T]: PropertyQuery<T[K]>; };
50
+ export declare const querySyntax: <T extends {
51
+ [key: string]: import("json-schema-to-ts").JSONSchema7;
52
+ }>(definition: T) => {
53
+ readonly $limit: {
54
+ readonly type: "number";
55
+ readonly minimum: 0;
56
+ };
57
+ readonly $skip: {
58
+ readonly type: "number";
59
+ readonly minimum: 0;
60
+ };
61
+ readonly $sort: {
62
+ readonly type: "object";
63
+ readonly properties: { [K in keyof T]: {
64
+ readonly type: 'number';
65
+ readonly enum: [1, -1];
66
+ }; };
67
+ };
68
+ readonly $select: {
69
+ readonly type: "array";
70
+ readonly items: {
71
+ readonly type: "string";
72
+ readonly enum: (keyof T)[];
73
+ };
74
+ };
75
+ } & { [K_1 in keyof T]: PropertyQuery<T[K_1]>; };
package/lib/query.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.queryProperty = void 0;
3
+ exports.querySyntax = exports.queryProperties = exports.queryProperty = void 0;
4
4
  const queryProperty = (definition) => ({
5
5
  anyOf: [
6
6
  definition,
@@ -26,4 +26,38 @@ const queryProperty = (definition) => ({
26
26
  ]
27
27
  });
28
28
  exports.queryProperty = queryProperty;
29
+ const queryProperties = (definition) => Object.keys(definition).reduce((res, key) => {
30
+ res[key] = (0, exports.queryProperty)(definition[key]);
31
+ return res;
32
+ }, {});
33
+ exports.queryProperties = queryProperties;
34
+ const querySyntax = (definition) => ({
35
+ $limit: {
36
+ type: 'number',
37
+ minimum: 0
38
+ },
39
+ $skip: {
40
+ type: 'number',
41
+ minimum: 0
42
+ },
43
+ $sort: {
44
+ type: 'object',
45
+ properties: Object.keys(definition).reduce((res, key) => {
46
+ res[key] = {
47
+ type: 'number',
48
+ enum: [1, -1]
49
+ };
50
+ return res;
51
+ }, {})
52
+ },
53
+ $select: {
54
+ type: 'array',
55
+ items: {
56
+ type: 'string',
57
+ enum: Object.keys(definition)
58
+ }
59
+ },
60
+ ...(0, exports.queryProperties)(definition)
61
+ });
62
+ exports.querySyntax = querySyntax;
29
63
  //# sourceMappingURL=query.js.map
package/lib/query.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":";;;AAEO,MAAM,aAAa,GAAG,CAAwB,UAAa,EAAE,EAAE,CAAC,CAAC;IACtE,KAAK,EAAE;QACL,UAAU;QACV;YACE,IAAI,EAAE,QAAQ;YACd,oBAAoB,EAAE,KAAK;YAC3B,UAAU,EAAE;gBACV,GAAG,EAAE,UAAU;gBACf,IAAI,EAAE,UAAU;gBAChB,GAAG,EAAE,UAAU;gBACf,IAAI,EAAE,UAAU;gBAChB,GAAG,EAAE,UAAU;gBACf,GAAG,EAAE;oBACH,IAAI,EAAE,OAAO;oBACb,KAAK,EAAE,UAAU;iBAClB;gBACD,IAAI,EAAE;oBACJ,IAAI,EAAE,OAAO;oBACb,KAAK,EAAE,UAAU;iBAClB;aACF;SACF;KACF;CACQ,CAAA,CAAC;AAvBC,QAAA,aAAa,iBAuBd"}
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":";;;AA2BO,MAAM,aAAa,GAAG,CAAwB,UAAa,EAAE,EAAE,CAAC,CAAC;IACtE,KAAK,EAAE;QACL,UAAU;QACV;YACE,IAAI,EAAE,QAAQ;YACd,oBAAoB,EAAE,KAAK;YAC3B,UAAU,EAAE;gBACV,GAAG,EAAE,UAAU;gBACf,IAAI,EAAE,UAAU;gBAChB,GAAG,EAAE,UAAU;gBACf,IAAI,EAAE,UAAU;gBAChB,GAAG,EAAE,UAAU;gBACf,GAAG,EAAE;oBACH,IAAI,EAAE,OAAO;oBACb,KAAK,EAAE,UAAU;iBAClB;gBACD,IAAI,EAAE;oBACJ,IAAI,EAAE,OAAO;oBACb,KAAK,EAAE,UAAU;iBAClB;aACF;SACF;KACF;CACQ,CAAA,CAAC;AAvBC,QAAA,aAAa,iBAuBd;AAEL,MAAM,eAAe,GAAG,CAA2C,UAAa,EAAE,EAAE,CACzF,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IACzC,GAAW,CAAC,GAAG,CAAC,GAAG,IAAA,qBAAa,EAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAA;IAElD,OAAO,GAAG,CAAA;AACZ,CAAC,EAAE,EAA6C,CAAC,CAAA;AALtC,QAAA,eAAe,mBAKuB;AAE5C,MAAM,WAAW,GAAG,CAA2C,UAAa,EAAE,EAAE,CAAC,CAAC;IACvF,MAAM,EAAE;QACN,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,CAAC;KACX;IACD,KAAK,EAAE;QACL,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,CAAC;KACX;IACD,KAAK,EAAE;QACL,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YACrD,GAAW,CAAC,GAAG,CAAC,GAAG;gBAClB,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;aACd,CAAA;YAED,OAAO,GAAG,CAAA;QACZ,CAAC,EAAE,EAA6E,CAAC;KAClF;IACD,OAAO,EAAE;QACP,IAAI,EAAE,OAAO;QACb,KAAK,EAAE;YACL,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAuB;SACpD;KACF;IACD,GAAG,IAAA,uBAAe,EAAC,UAAU,CAAC;CACrB,CAAA,CAAA;AA5BE,QAAA,WAAW,eA4Bb"}
package/lib/resolver.d.ts CHANGED
@@ -3,10 +3,12 @@ export declare type PropertyResolver<T, V, C> = (value: V | undefined, obj: T, c
3
3
  export declare type PropertyResolverMap<T, C> = {
4
4
  [key in keyof T]?: PropertyResolver<T, T[key], C>;
5
5
  };
6
+ export declare type ResolverConverter<T, C> = (obj: any, context: C, status: ResolverStatus<T, C>) => Promise<T | undefined>;
6
7
  export interface ResolverConfig<T, C> {
7
8
  schema?: Schema<T>;
8
9
  validate?: 'before' | 'after' | false;
9
10
  properties: PropertyResolverMap<T, C>;
11
+ converter?: ResolverConverter<T, C>;
10
12
  }
11
13
  export interface ResolverStatus<T, C> {
12
14
  path: string[];
@@ -19,6 +21,7 @@ export declare class Resolver<T, C> {
19
21
  readonly _type: T;
20
22
  constructor(options: ResolverConfig<T, C>);
21
23
  resolveProperty<D, K extends keyof T>(name: K, data: D, context: C, status?: Partial<ResolverStatus<T, C>>): Promise<T[K]>;
24
+ convert<D>(data: D, context: C, status?: Partial<ResolverStatus<T, C>>): Promise<T | D>;
22
25
  resolve<D>(_data: D, context: C, status?: Partial<ResolverStatus<T, C>>): Promise<T>;
23
26
  }
24
27
  export declare function resolve<T, C>(options: ResolverConfig<T, C>): Resolver<T, C>;
package/lib/resolver.js CHANGED
@@ -21,9 +21,17 @@ class Resolver {
21
21
  };
22
22
  return resolver(value, data, context, resolverStatus);
23
23
  }
24
+ async convert(data, context, status) {
25
+ if (this.options.converter) {
26
+ const { path = [], stack = [] } = status || {};
27
+ return this.options.converter(data, context, { ...status, path, stack });
28
+ }
29
+ return data;
30
+ }
24
31
  async resolve(_data, context, status) {
25
32
  const { properties: resolvers, schema, validate } = this.options;
26
- const data = schema && validate === 'before' ? await schema.validate(_data) : _data;
33
+ const payload = await this.convert(_data, context, status);
34
+ const data = schema && validate === 'before' ? await schema.validate(payload) : payload;
27
35
  const propertyList = (Array.isArray(status === null || status === void 0 ? void 0 : status.properties)
28
36
  ? status === null || status === void 0 ? void 0 : status.properties
29
37
  // By default get all data and resolver keys but remove duplicates
@@ -56,7 +64,7 @@ class Resolver {
56
64
  }));
57
65
  if (hasErrors) {
58
66
  const propertyName = (status === null || status === void 0 ? void 0 : status.properties) ? ` ${status.properties.join('.')}` : '';
59
- throw new errors_1.BadRequest('Error resolving data' + propertyName, errors);
67
+ throw new errors_1.BadRequest('Error resolving data' + (propertyName ? ` ${propertyName}` : ''), errors);
60
68
  }
61
69
  return schema && validate === 'after'
62
70
  ? await schema.validate(result)
@@ -1 +1 @@
1
- {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"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"}
package/lib/schema.d.ts CHANGED
@@ -5,6 +5,10 @@ export { Ajv };
5
5
  export declare type JSONSchemaDefinition = JSONSchema & {
6
6
  $id: string;
7
7
  $async?: boolean;
8
+ properties?: {
9
+ [key: string]: JSONSchema;
10
+ };
11
+ required?: readonly string[];
8
12
  };
9
13
  export interface Schema<T> {
10
14
  validate<X = T>(...args: Parameters<ValidateFunction<X>>): Promise<X>;
@@ -15,6 +19,8 @@ export declare class SchemaWrapper<S extends JSONSchemaDefinition> implements Sc
15
19
  validator: AsyncValidateFunction;
16
20
  readonly _type: FromSchema<S>;
17
21
  constructor(definition: S, ajv?: Ajv);
22
+ get properties(): S["properties"];
23
+ get required(): S["required"];
18
24
  validate<T = FromSchema<S>>(...args: Parameters<ValidateFunction<T>>): Promise<T>;
19
25
  toJSON(): S;
20
26
  }
package/lib/schema.js CHANGED
@@ -19,6 +19,12 @@ class SchemaWrapper {
19
19
  ...this.definition
20
20
  });
21
21
  }
22
+ get properties() {
23
+ return this.definition.properties;
24
+ }
25
+ get required() {
26
+ return this.definition.required;
27
+ }
22
28
  async validate(...args) {
23
29
  try {
24
30
  const validated = await this.validator(...args);
package/lib/schema.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":";;;;;;AAAA,8CAAmE;AAQ1D,cARF,aAAG,CAQE;AANZ,+CAAgD;AAEnC,QAAA,WAAW,GAAG,IAAI,aAAG,CAAC;IACjC,WAAW,EAAE,IAAI;CAClB,CAAC,CAAC;AAUH,MAAa,aAAa;IAKxB,YAAoB,UAAa,EAAE,MAAW,mBAAW;QAArC,eAAU,GAAV,UAAU,CAAG;QAC/B,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;YAChC,MAAM,EAAE,IAAI;YACZ,GAAI,IAAI,CAAC,UAAkB;SAC5B,CAA0B,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,QAAQ,CAAsB,GAAG,IAAqC;QAC1E,IAAI;YACF,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAM,CAAC;YAErD,OAAO,SAAS,CAAC;SAClB;QAAC,OAAO,KAAU,EAAE;YACnB,MAAM,IAAI,mBAAU,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;SACnD;IACH,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;CACF;AA1BD,sCA0BC;AAED,SAAgB,MAAM,CAAmC,UAAa,EAAE,MAAW,mBAAW;IAC5F,OAAO,IAAI,aAAa,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;AAC5C,CAAC;AAFD,wBAEC"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":";;;;;;AAAA,8CAAmE;AAQ1D,cARF,aAAG,CAQE;AANZ,+CAAgD;AAEnC,QAAA,WAAW,GAAG,IAAI,aAAG,CAAC;IACjC,WAAW,EAAE,IAAI;CAClB,CAAC,CAAC;AAeH,MAAa,aAAa;IAKxB,YAAoB,UAAa,EAAE,MAAW,mBAAW;QAArC,eAAU,GAAV,UAAU,CAAG;QAC/B,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;YAChC,MAAM,EAAE,IAAI;YACZ,GAAI,IAAI,CAAC,UAAkB;SAC5B,CAA0B,CAAC;IAC9B,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,UAAU,CAAC,UAA6B,CAAC;IACvD,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,UAAU,CAAC,QAAyB,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,QAAQ,CAAsB,GAAG,IAAqC;QAC1E,IAAI;YACF,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAM,CAAC;YAErD,OAAO,SAAS,CAAC;SAClB;QAAC,OAAO,KAAU,EAAE;YACnB,MAAM,IAAI,mBAAU,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;SACnD;IACH,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;CACF;AAlCD,sCAkCC;AAED,SAAgB,MAAM,CAAmC,UAAa,EAAE,MAAW,mBAAW;IAC5F,OAAO,IAAI,aAAa,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;AAC5C,CAAC;AAFD,wBAEC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@feathersjs/schema",
3
3
  "description": "A common data schema definition format",
4
- "version": "5.0.0-pre.18",
4
+ "version": "5.0.0-pre.21",
5
5
  "homepage": "https://feathersjs.com",
6
6
  "main": "lib/",
7
7
  "types": "lib/",
@@ -53,21 +53,22 @@
53
53
  "access": "public"
54
54
  },
55
55
  "dependencies": {
56
- "@feathersjs/errors": "^5.0.0-pre.18",
57
- "@feathersjs/feathers": "^5.0.0-pre.18",
56
+ "@feathersjs/errors": "^5.0.0-pre.21",
57
+ "@feathersjs/feathers": "^5.0.0-pre.21",
58
+ "@feathersjs/hooks": "^0.7.4",
58
59
  "@types/json-schema": "^7.0.11",
59
60
  "ajv": "^8.11.0",
60
61
  "json-schema": "^0.4.0",
61
- "json-schema-to-ts": "^1.6.5"
62
+ "json-schema-to-ts": "^2.3.0"
62
63
  },
63
64
  "devDependencies": {
64
- "@feathersjs/memory": "^5.0.0-pre.18",
65
- "@types/mocha": "^9.1.0",
66
- "@types/node": "^17.0.23",
65
+ "@feathersjs/memory": "^5.0.0-pre.21",
66
+ "@types/mocha": "^9.1.1",
67
+ "@types/node": "^17.0.31",
67
68
  "ajv-formats": "^2.1.1",
68
- "mocha": "^9.2.2",
69
+ "mocha": "^10.0.0",
69
70
  "shx": "^0.3.4",
70
- "typescript": "^4.6.3"
71
+ "typescript": "^4.6.4"
71
72
  },
72
- "gitHead": "c0b7b67d872dcd6b6d94e4587f21332c8a519b50"
73
+ "gitHead": "ac3baed231f72370a80a06c5944538915479b96e"
73
74
  }
@@ -0,0 +1,2 @@
1
+ export * from './resolve';
2
+ export * from './validate';
@@ -0,0 +1,170 @@
1
+ import { HookContext, NextFunction } from '@feathersjs/feathers';
2
+ import { compose } from '@feathersjs/hooks';
3
+ import { Resolver, ResolverStatus } from '../resolver';
4
+
5
+ const getContext = <H extends HookContext> (context: H) => {
6
+ return {
7
+ ...context,
8
+ params: {
9
+ ...context.params,
10
+ query: {}
11
+ }
12
+ }
13
+ }
14
+
15
+ const getData = <H extends HookContext> (context: H) => {
16
+ const isPaginated = context.method === 'find' && context.result.data;
17
+ const data = isPaginated ? context.result.data : context.result;
18
+
19
+ return { isPaginated, data };
20
+ }
21
+
22
+ const runResolvers = async <T, H extends HookContext> (
23
+ resolvers: Resolver<T, H>[],
24
+ data: any,
25
+ ctx: H,
26
+ status?: Partial<ResolverStatus<T, H>>
27
+ ) => {
28
+ let current: any = data;
29
+
30
+ for (const resolver of resolvers) {
31
+ current = await resolver.resolve(current, ctx, status);
32
+ }
33
+
34
+ return current as T;
35
+ }
36
+
37
+ export const DISPATCH = Symbol('@feathersjs/schema/dispatch');
38
+
39
+ export const resolveQuery = <T, H extends HookContext> (...resolvers: Resolver<T, H>[]) =>
40
+ async (context: H, next?: NextFunction) => {
41
+ const ctx = getContext(context);
42
+ const data = context?.params?.query || {};
43
+ const query = await runResolvers(resolvers, data, ctx);
44
+
45
+ context.params = {
46
+ ...context.params,
47
+ query
48
+ }
49
+
50
+ if (typeof next === 'function') {
51
+ return next();
52
+ }
53
+ };
54
+
55
+ export const resolveData = <T, H extends HookContext> (...resolvers: Resolver<T, H>[]) =>
56
+ async (context: H, next?: NextFunction) => {
57
+ if (context.method === 'create' || context.method === 'patch' || context.method === 'update') {
58
+ const ctx = getContext(context);
59
+ const data = context.data;
60
+
61
+ const status = {
62
+ originalContext: context
63
+ };
64
+
65
+ if (Array.isArray(data)) {
66
+ context.data = await Promise.all(data.map(current =>
67
+ runResolvers(resolvers, current, ctx, status)
68
+ ));
69
+ } else {
70
+ context.data = await runResolvers(resolvers, data, ctx, status);
71
+ }
72
+ }
73
+
74
+ if (typeof next === 'function') {
75
+ return next();
76
+ }
77
+ };
78
+
79
+ export const resolveResult = <T, H extends HookContext> (...resolvers: Resolver<T, H>[]) =>
80
+ async (context: H, next?: NextFunction) => {
81
+ if (typeof next === 'function') {
82
+ const { $resolve: properties, ...query } = context.params?.query || {};
83
+ const resolve = {
84
+ originalContext: context,
85
+ ...context.params.resolve,
86
+ properties
87
+ };
88
+
89
+ context.params = {
90
+ ...context.params,
91
+ resolve,
92
+ query
93
+ }
94
+
95
+ await next();
96
+ }
97
+
98
+ const ctx = getContext(context);
99
+ const status = context.params.resolve;
100
+ const { isPaginated, data } = getData(context);
101
+
102
+ const result = Array.isArray(data) ?
103
+ await Promise.all(data.map(async current => runResolvers(resolvers, current, ctx, status))) :
104
+ await runResolvers(resolvers, data, ctx, status);
105
+
106
+ if (isPaginated) {
107
+ context.result.data = result;
108
+ } else {
109
+ context.result = result;
110
+ }
111
+ };
112
+
113
+ export const resolveDispatch = <T, H extends HookContext> (...resolvers: Resolver<T, H>[]) =>
114
+ async (context: H, next?: NextFunction) => {
115
+ if (typeof next === 'function') {
116
+ await next();
117
+ }
118
+
119
+ const ctx = getContext(context);
120
+ const status = context.params.resolve;
121
+ const { isPaginated, data } = getData(context);
122
+ const resolveDispatch = async (current: any) => {
123
+ const resolved = await runResolvers(resolvers, current, ctx, status)
124
+
125
+ return Object.keys(resolved).reduce((res, key) => {
126
+ const value = current[key];
127
+ const hasDispatch = typeof value === 'object' && value !== null && value[DISPATCH] !== undefined;
128
+
129
+ res[key] = hasDispatch ? value[DISPATCH] : value;
130
+
131
+ return res
132
+ }, {} as any)
133
+ }
134
+
135
+ const result = await (Array.isArray(data) ? Promise.all(data.map(resolveDispatch)) : resolveDispatch(data));
136
+ const dispatch = isPaginated ? {
137
+ ...context.result,
138
+ data: result
139
+ } : result;
140
+
141
+ context.dispatch = dispatch;
142
+ Object.defineProperty(context.result, DISPATCH, {
143
+ value: dispatch,
144
+ enumerable: false,
145
+ configurable: false
146
+ });
147
+ };
148
+
149
+ export type ResolveAllSettings<H extends HookContext> = {
150
+ data?: Resolver<any, H>|Resolver<any, H>[]
151
+ query?: Resolver<any, H>|Resolver<any, H>[]
152
+ result?: Resolver<any, H>|Resolver<any, H>[]
153
+ dispatch?: Resolver<any, H>|Resolver<any, H>[]
154
+ }
155
+
156
+ const getResolvers = <H extends HookContext> (
157
+ map: ResolveAllSettings<H>,
158
+ name: keyof ResolveAllSettings<H>
159
+ ) => {
160
+ const value = map[name];
161
+
162
+ return Array.isArray(value) ? value : (value !== undefined ? [ value ] : []);
163
+ }
164
+
165
+ export const resolveAll = <H extends HookContext> (map: ResolveAllSettings<H>) => compose([
166
+ resolveDispatch(...getResolvers(map, 'dispatch')),
167
+ resolveResult(...getResolvers(map, 'result')),
168
+ resolveQuery(...getResolvers(map, 'query')),
169
+ resolveData(...getResolvers(map, 'data'))
170
+ ])
@@ -0,0 +1,44 @@
1
+ import { HookContext, NextFunction } from '@feathersjs/feathers';
2
+ import { BadRequest } from '../../../errors/lib';
3
+ import { Schema } from '../schema';
4
+
5
+ export const validateQuery = <H extends HookContext> (schema: Schema<any>) =>
6
+ async (context: H, next?: NextFunction) => {
7
+ const data = context?.params?.query || {};
8
+
9
+ try {
10
+ const query = await schema.validate(data);
11
+
12
+ context.params = {
13
+ ...context.params,
14
+ query
15
+ }
16
+
17
+ if (typeof next === 'function') {
18
+ return next();
19
+ }
20
+ } catch (error: any) {
21
+ throw (error.ajv ? new BadRequest(error.message, error.errors) : error);
22
+ }
23
+ };
24
+
25
+ export const validateData = <H extends HookContext> (schema: Schema<any>) =>
26
+ async (context: H, next?: NextFunction) => {
27
+ const data = context.data;
28
+
29
+ try {
30
+ if (Array.isArray(data)) {
31
+ context.data = await Promise.all(data.map(current =>
32
+ schema.validate(current)
33
+ ));
34
+ } else {
35
+ context.data = await schema.validate(data);
36
+ }
37
+ } catch (error: any) {
38
+ throw (error.ajv ? new BadRequest(error.message, error.errors) : error);
39
+ }
40
+
41
+ if (typeof next === 'function') {
42
+ return next();
43
+ }
44
+ };
package/src/index.ts CHANGED
@@ -7,6 +7,8 @@ export * from './query';
7
7
 
8
8
  export type Infer<S extends { _type: any }> = S['_type'];
9
9
 
10
+ export type Combine<S extends { _type: any }, U> = Pick<Infer<S>, Exclude<keyof Infer<S>, keyof U>> & U;
11
+
10
12
  declare module '@feathersjs/feathers/lib/declarations' {
11
13
  interface Params {
12
14
  resolve?: ResolverStatus<any, HookContext>;
package/src/query.ts CHANGED
@@ -1,5 +1,30 @@
1
1
  import { JSONSchema } from 'json-schema-to-ts';
2
2
 
3
+ export type PropertyQuery<D extends JSONSchema> = {
4
+ anyOf: [
5
+ D,
6
+ {
7
+ type: 'object',
8
+ additionalProperties: false,
9
+ properties: {
10
+ $gt: D,
11
+ $gte: D,
12
+ $lt: D,
13
+ $lte: D,
14
+ $ne: D,
15
+ $in: {
16
+ type: 'array',
17
+ items: D
18
+ },
19
+ $nin: {
20
+ type: 'array',
21
+ items: D
22
+ }
23
+ }
24
+ }
25
+ ]
26
+ }
27
+
3
28
  export const queryProperty = <T extends JSONSchema> (definition: T) => ({
4
29
  anyOf: [
5
30
  definition,
@@ -24,3 +49,40 @@ export const queryProperty = <T extends JSONSchema> (definition: T) => ({
24
49
  }
25
50
  ]
26
51
  } as const);
52
+
53
+ export const queryProperties = <T extends { [key: string]: JSONSchema }> (definition: T) =>
54
+ Object.keys(definition).reduce((res, key) => {
55
+ (res as any)[key] = queryProperty(definition[key])
56
+
57
+ return res
58
+ }, {} as { [K in keyof T]: PropertyQuery<T[K]> })
59
+
60
+ export const querySyntax = <T extends { [key: string]: JSONSchema }> (definition: T) => ({
61
+ $limit: {
62
+ type: 'number',
63
+ minimum: 0
64
+ },
65
+ $skip: {
66
+ type: 'number',
67
+ minimum: 0
68
+ },
69
+ $sort: {
70
+ type: 'object',
71
+ properties: Object.keys(definition).reduce((res, key) => {
72
+ (res as any)[key] = {
73
+ type: 'number',
74
+ enum: [1, -1]
75
+ }
76
+
77
+ return res
78
+ }, {} as { [K in keyof T]: { readonly type: 'number', readonly enum: [1, -1] } })
79
+ },
80
+ $select: {
81
+ type: 'array',
82
+ items: {
83
+ type: 'string',
84
+ enum: Object.keys(definition) as any as (keyof T)[]
85
+ }
86
+ },
87
+ ...queryProperties(definition)
88
+ } as const)
package/src/resolver.ts CHANGED
@@ -12,17 +12,21 @@ export type PropertyResolverMap<T, C> = {
12
12
  [key in keyof T]?: PropertyResolver<T, T[key], C>
13
13
  }
14
14
 
15
+ export type ResolverConverter<T, C> = (obj: any, context: C, status: ResolverStatus<T, C>)
16
+ => Promise<T|undefined>
17
+
15
18
  export interface ResolverConfig<T, C> {
16
19
  schema?: Schema<T>,
17
20
  validate?: 'before'|'after'|false,
18
21
  properties: PropertyResolverMap<T, C>
22
+ converter?: ResolverConverter<T, C>
19
23
  }
20
24
 
21
25
  export interface ResolverStatus<T, C> {
22
- path: string[];
23
- originalContext?: C;
24
- properties?: string[];
25
- stack: PropertyResolver<T, any, C>[];
26
+ path: string[]
27
+ originalContext?: C
28
+ properties?: string[]
29
+ stack: PropertyResolver<T, any, C>[]
26
30
  }
27
31
 
28
32
  export class Resolver<T, C> {
@@ -55,9 +59,20 @@ export class Resolver<T, C> {
55
59
  return resolver(value, data as any, context, resolverStatus);
56
60
  }
57
61
 
62
+ async convert <D> (data: D, context: C, status?: Partial<ResolverStatus<T, C>>) {
63
+ if (this.options.converter) {
64
+ const { path = [], stack = [] } = status || {}
65
+
66
+ return this.options.converter(data, context, { ...status, path, stack })
67
+ }
68
+
69
+ return data
70
+ }
71
+
58
72
  async resolve<D> (_data: D, context: C, status?: Partial<ResolverStatus<T, C>>): Promise<T> {
59
73
  const { properties: resolvers, schema, validate } = this.options;
60
- const data = schema && validate === 'before' ? await schema.validate(_data) : _data;
74
+ const payload = await this.convert(_data, context, status);
75
+ const data = schema && validate === 'before' ? await schema.validate(payload) : payload;
61
76
  const propertyList = (Array.isArray(status?.properties)
62
77
  ? status?.properties
63
78
  // By default get all data and resolver keys but remove duplicates
@@ -96,7 +111,7 @@ export class Resolver<T, C> {
96
111
  if (hasErrors) {
97
112
  const propertyName = status?.properties ? ` ${status.properties.join('.')}` : '';
98
113
 
99
- throw new BadRequest('Error resolving data' + propertyName, errors);
114
+ throw new BadRequest('Error resolving data' + (propertyName ? ` ${propertyName}` : ''), errors);
100
115
  }
101
116
 
102
117
  return schema && validate === 'after'
package/src/schema.ts CHANGED
@@ -8,7 +8,12 @@ export const DEFAULT_AJV = new Ajv({
8
8
 
9
9
  export { Ajv };
10
10
 
11
- export type JSONSchemaDefinition = JSONSchema & { $id: string, $async?: boolean };
11
+ export type JSONSchemaDefinition = JSONSchema & {
12
+ $id: string,
13
+ $async?: boolean,
14
+ properties?: { [key: string]: JSONSchema }
15
+ required?: readonly string[]
16
+ };
12
17
 
13
18
  export interface Schema<T> {
14
19
  validate <X = T> (...args: Parameters<ValidateFunction<X>>): Promise<X>;
@@ -27,6 +32,14 @@ export class SchemaWrapper<S extends JSONSchemaDefinition> implements Schema<Fro
27
32
  }) as AsyncValidateFunction;
28
33
  }
29
34
 
35
+ get properties () {
36
+ return this.definition.properties as S['properties'];
37
+ }
38
+
39
+ get required () {
40
+ return this.definition.required as S['required'];
41
+ }
42
+
30
43
  async validate <T = FromSchema<S>> (...args: Parameters<ValidateFunction<T>>) {
31
44
  try {
32
45
  const validated = await this.validator(...args) as T;
package/lib/hooks.d.ts DELETED
@@ -1,8 +0,0 @@
1
- import { HookContext, NextFunction } from '@feathersjs/feathers';
2
- import { Resolver } from './resolver';
3
- import { Schema } from './schema';
4
- export declare const resolveQuery: <T>(resolver: Resolver<T, HookContext<import("@feathersjs/feathers").Application<any, any>, any>>) => (context: HookContext, next?: NextFunction) => Promise<any>;
5
- export declare const resolveData: <T>(resolver: Resolver<T, HookContext<import("@feathersjs/feathers").Application<any, any>, any>>) => (context: HookContext, next?: NextFunction) => Promise<any>;
6
- export declare const resolveResult: <T>(resolver: Resolver<T, HookContext<import("@feathersjs/feathers").Application<any, any>, any>>) => (context: HookContext, next?: NextFunction) => Promise<void>;
7
- export declare const validateQuery: (schema: Schema<any>) => (context: HookContext, next?: NextFunction) => Promise<any>;
8
- export declare const validateData: (schema: Schema<any>) => (context: HookContext, next?: NextFunction) => Promise<any>;
package/lib/hooks.js DELETED
@@ -1,114 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateData = exports.validateQuery = exports.resolveResult = exports.resolveData = exports.resolveQuery = void 0;
4
- const lib_1 = require("../../errors/lib");
5
- const getContext = (context) => {
6
- return {
7
- ...context,
8
- params: {
9
- ...context.params,
10
- query: {}
11
- }
12
- };
13
- };
14
- const resolveQuery = (resolver) => async (context, next) => {
15
- var _a;
16
- const ctx = getContext(context);
17
- const data = ((_a = context === null || context === void 0 ? void 0 : context.params) === null || _a === void 0 ? void 0 : _a.query) || {};
18
- const query = await resolver.resolve(data, ctx, {
19
- originalContext: context
20
- });
21
- context.params = {
22
- ...context.params,
23
- query
24
- };
25
- if (typeof next === 'function') {
26
- return next();
27
- }
28
- };
29
- exports.resolveQuery = resolveQuery;
30
- const resolveData = (resolver) => async (context, next) => {
31
- const ctx = getContext(context);
32
- const data = context.data;
33
- const status = {
34
- originalContext: context
35
- };
36
- if (Array.isArray(data)) {
37
- context.data = await Promise.all(data.map(current => resolver.resolve(current, ctx, status)));
38
- }
39
- else {
40
- context.data = await resolver.resolve(data, ctx, status);
41
- }
42
- if (typeof next === 'function') {
43
- return next();
44
- }
45
- };
46
- exports.resolveData = resolveData;
47
- const resolveResult = (resolver) => async (context, next) => {
48
- var _a;
49
- if (typeof next === 'function') {
50
- const { $resolve: properties, ...query } = ((_a = context.params) === null || _a === void 0 ? void 0 : _a.query) || {};
51
- const resolve = {
52
- originalContext: context,
53
- ...context.params.resolve,
54
- properties
55
- };
56
- context.params = {
57
- ...context.params,
58
- resolve,
59
- query
60
- };
61
- await next();
62
- }
63
- const ctx = getContext(context);
64
- const status = context.params.resolve;
65
- const isPaginated = context.method === 'find' && context.result.data;
66
- const data = isPaginated ? context.result.data : context.result;
67
- const result = Array.isArray(data) ?
68
- await Promise.all(data.map(async (current) => resolver.resolve(current, ctx, status))) :
69
- await resolver.resolve(data, ctx, status);
70
- if (isPaginated) {
71
- context.result.data = result;
72
- }
73
- else {
74
- context.result = result;
75
- }
76
- };
77
- exports.resolveResult = resolveResult;
78
- const validateQuery = (schema) => async (context, next) => {
79
- var _a;
80
- const data = ((_a = context === null || context === void 0 ? void 0 : context.params) === null || _a === void 0 ? void 0 : _a.query) || {};
81
- try {
82
- const query = await schema.validate(data);
83
- context.params = {
84
- ...context.params,
85
- query
86
- };
87
- if (typeof next === 'function') {
88
- return next();
89
- }
90
- }
91
- catch (error) {
92
- throw (error.ajv ? new lib_1.BadRequest(error.message, error.errors) : error);
93
- }
94
- };
95
- exports.validateQuery = validateQuery;
96
- const validateData = (schema) => async (context, next) => {
97
- const data = context.data;
98
- try {
99
- if (Array.isArray(data)) {
100
- context.data = await Promise.all(data.map(current => schema.validate(current)));
101
- }
102
- else {
103
- context.data = await schema.validate(data);
104
- }
105
- }
106
- catch (error) {
107
- throw (error.ajv ? new lib_1.BadRequest(error.message, error.errors) : error);
108
- }
109
- if (typeof next === 'function') {
110
- return next();
111
- }
112
- };
113
- exports.validateData = validateData;
114
- //# sourceMappingURL=hooks.js.map
package/lib/hooks.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"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"}
package/src/hooks.ts DELETED
@@ -1,130 +0,0 @@
1
- import { HookContext, NextFunction } from '@feathersjs/feathers';
2
- import { BadRequest } from '../../errors/lib';
3
- import { Resolver } from './resolver';
4
- import { Schema } from './schema';
5
-
6
- const getContext = (context: HookContext) => {
7
- return {
8
- ...context,
9
- params: {
10
- ...context.params,
11
- query: {}
12
- }
13
- }
14
- }
15
-
16
- export const resolveQuery = <T> (resolver: Resolver<T, HookContext>) =>
17
- async (context: HookContext, next?: NextFunction) => {
18
- const ctx = getContext(context);
19
- const data = context?.params?.query || {};
20
- const query = await resolver.resolve(data, ctx, {
21
- originalContext: context
22
- });
23
-
24
- context.params = {
25
- ...context.params,
26
- query
27
- }
28
-
29
- if (typeof next === 'function') {
30
- return next();
31
- }
32
- };
33
-
34
- export const resolveData = <T> (resolver: Resolver<T, HookContext>) =>
35
- async (context: HookContext, next?: NextFunction) => {
36
- const ctx = getContext(context);
37
- const data = context.data;
38
- const status = {
39
- originalContext: context
40
- };
41
-
42
- if (Array.isArray(data)) {
43
- context.data = await Promise.all(data.map(current =>
44
- resolver.resolve(current, ctx, status)
45
- ));
46
- } else {
47
- context.data = await resolver.resolve(data, ctx, status);
48
- }
49
-
50
- if (typeof next === 'function') {
51
- return next();
52
- }
53
- };
54
-
55
- export const resolveResult = <T> (resolver: Resolver<T, HookContext>) =>
56
- async (context: HookContext, next?: NextFunction) => {
57
- if (typeof next === 'function') {
58
- const { $resolve: properties, ...query } = context.params?.query || {};
59
- const resolve = {
60
- originalContext: context,
61
- ...context.params.resolve,
62
- properties
63
- };
64
-
65
- context.params = {
66
- ...context.params,
67
- resolve,
68
- query
69
- }
70
-
71
- await next();
72
- }
73
-
74
- const ctx = getContext(context);
75
- const status = context.params.resolve;
76
-
77
- const isPaginated = context.method === 'find' && context.result.data;
78
- const data = isPaginated ? context.result.data : context.result;
79
-
80
- const result = Array.isArray(data) ?
81
- await Promise.all(data.map(async current => resolver.resolve(current, ctx, status))) :
82
- await resolver.resolve(data, ctx, status);
83
-
84
- if (isPaginated) {
85
- context.result.data = result;
86
- } else {
87
- context.result = result;
88
- }
89
- };
90
-
91
- export const validateQuery = (schema: Schema<any>) =>
92
- async (context: HookContext, next?: NextFunction) => {
93
- const data = context?.params?.query || {};
94
-
95
- try {
96
- const query = await schema.validate(data);
97
-
98
- context.params = {
99
- ...context.params,
100
- query
101
- }
102
-
103
- if (typeof next === 'function') {
104
- return next();
105
- }
106
- } catch (error: any) {
107
- throw (error.ajv ? new BadRequest(error.message, error.errors) : error);
108
- }
109
- };
110
-
111
- export const validateData = (schema: Schema<any>) =>
112
- async (context: HookContext, next?: NextFunction) => {
113
- const data = context.data;
114
-
115
- try {
116
- if (Array.isArray(data)) {
117
- context.data = await Promise.all(data.map(current =>
118
- schema.validate(current)
119
- ));
120
- } else {
121
- context.data = await schema.validate(data);
122
- }
123
- } catch (error: any) {
124
- throw (error.ajv ? new BadRequest(error.message, error.errors) : error);
125
- }
126
-
127
- if (typeof next === 'function') {
128
- return next();
129
- }
130
- };