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

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.
@@ -1,8 +1,8 @@
1
- import { HookContext, NextFunction } from '@feathersjs/feathers';
2
- import { compose } from '@feathersjs/hooks';
3
- import { Resolver, ResolverStatus } from '../resolver';
1
+ import { HookContext, NextFunction } from '@feathersjs/feathers'
2
+ import { compose } from '@feathersjs/hooks'
3
+ import { Resolver, ResolverStatus } from '../resolver'
4
4
 
5
- const getContext = <H extends HookContext> (context: H) => {
5
+ const getContext = <H extends HookContext>(context: H) => {
6
6
  return {
7
7
  ...context,
8
8
  params: {
@@ -12,35 +12,56 @@ const getContext = <H extends HookContext> (context: H) => {
12
12
  }
13
13
  }
14
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;
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
18
 
19
- return { isPaginated, data };
19
+ return { isPaginated, data }
20
20
  }
21
21
 
22
- const runResolvers = async <T, H extends HookContext> (
22
+ const runResolvers = async <T, H extends HookContext>(
23
23
  resolvers: Resolver<T, H>[],
24
24
  data: any,
25
25
  ctx: H,
26
26
  status?: Partial<ResolverStatus<T, H>>
27
27
  ) => {
28
- let current: any = data;
28
+ let current: any = data
29
29
 
30
30
  for (const resolver of resolvers) {
31
- current = await resolver.resolve(current, ctx, status);
31
+ if (resolver && typeof resolver.resolve === 'function') {
32
+ current = await resolver.resolve(current, ctx, status)
33
+ }
32
34
  }
33
35
 
34
- return current as T;
36
+ return current as T
37
+ }
38
+
39
+ export type ResolverSetting<H extends HookContext> = Resolver<any, H> | Resolver<any, H>[]
40
+
41
+ export type DataResolvers<H extends HookContext> = {
42
+ create: Resolver<any, H>
43
+ patch: Resolver<any, H>
44
+ update: Resolver<any, H>
45
+ }
46
+
47
+ export type ResolveAllSettings<H extends HookContext> = {
48
+ data?: DataResolvers<H>
49
+ query?: Resolver<any, H>
50
+ result?: Resolver<any, H>
51
+ dispatch?: Resolver<any, H>
35
52
  }
36
53
 
37
- export const DISPATCH = Symbol('@feathersjs/schema/dispatch');
54
+ export const DISPATCH = Symbol('@feathersjs/schema/dispatch')
38
55
 
39
- export const resolveQuery = <T, H extends HookContext> (...resolvers: Resolver<T, H>[]) =>
56
+ export const getDispatch = (value: any) =>
57
+ typeof value === 'object' && value !== null && value[DISPATCH] !== undefined ? value[DISPATCH] : value
58
+
59
+ export const resolveQuery =
60
+ <T, H extends HookContext>(...resolvers: Resolver<T, H>[]) =>
40
61
  async (context: H, next?: NextFunction) => {
41
- const ctx = getContext(context);
42
- const data = context?.params?.query || {};
43
- const query = await runResolvers(resolvers, data, ctx);
62
+ const ctx = getContext(context)
63
+ const data = context?.params?.query || {}
64
+ const query = await runResolvers(resolvers, data, ctx)
44
65
 
45
66
  context.params = {
46
67
  ...context.params,
@@ -48,43 +69,44 @@ export const resolveQuery = <T, H extends HookContext> (...resolvers: Resolver<T
48
69
  }
49
70
 
50
71
  if (typeof next === 'function') {
51
- return next();
72
+ return next()
52
73
  }
53
- };
74
+ }
54
75
 
55
- export const resolveData = <T, H extends HookContext> (...resolvers: Resolver<T, H>[]) =>
76
+ export const resolveData =
77
+ <H extends HookContext>(settings: DataResolvers<H> | Resolver<any, H>) =>
56
78
  async (context: H, next?: NextFunction) => {
57
79
  if (context.method === 'create' || context.method === 'patch' || context.method === 'update') {
58
- const ctx = getContext(context);
59
- const data = context.data;
80
+ const resolvers = settings instanceof Resolver ? [settings] : [settings[context.method]]
81
+ const ctx = getContext(context)
82
+ const data = context.data
60
83
 
61
84
  const status = {
62
85
  originalContext: context
63
- };
86
+ }
64
87
 
65
88
  if (Array.isArray(data)) {
66
- context.data = await Promise.all(data.map(current =>
67
- runResolvers(resolvers, current, ctx, status)
68
- ));
89
+ context.data = await Promise.all(data.map((current) => runResolvers(resolvers, current, ctx, status)))
69
90
  } else {
70
- context.data = await runResolvers(resolvers, data, ctx, status);
91
+ context.data = await runResolvers(resolvers, data, ctx, status)
71
92
  }
72
93
  }
73
94
 
74
95
  if (typeof next === 'function') {
75
- return next();
96
+ return next()
76
97
  }
77
- };
98
+ }
78
99
 
79
- export const resolveResult = <T, H extends HookContext> (...resolvers: Resolver<T, H>[]) =>
100
+ export const resolveResult =
101
+ <T, H extends HookContext>(...resolvers: Resolver<T, H>[]) =>
80
102
  async (context: H, next?: NextFunction) => {
81
103
  if (typeof next === 'function') {
82
- const { $resolve: properties, ...query } = context.params?.query || {};
104
+ const { $resolve: properties, ...query } = context.params?.query || {}
83
105
  const resolve = {
84
106
  originalContext: context,
85
107
  ...context.params.resolve,
86
108
  properties
87
- };
109
+ }
88
110
 
89
111
  context.params = {
90
112
  ...context.params,
@@ -92,79 +114,78 @@ export const resolveResult = <T, H extends HookContext> (...resolvers: Resolver<
92
114
  query
93
115
  }
94
116
 
95
- await next();
117
+ await next()
96
118
  }
97
119
 
98
- const ctx = getContext(context);
99
- const status = context.params.resolve;
100
- const { isPaginated, data } = getData(context);
120
+ const ctx = getContext(context)
121
+ const status = context.params.resolve
122
+ const { isPaginated, data } = getData(context)
101
123
 
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);
124
+ const result = Array.isArray(data)
125
+ ? await Promise.all(data.map(async (current) => runResolvers(resolvers, current, ctx, status)))
126
+ : await runResolvers(resolvers, data, ctx, status)
105
127
 
106
128
  if (isPaginated) {
107
- context.result.data = result;
129
+ context.result.data = result
108
130
  } else {
109
- context.result = result;
131
+ context.result = result
110
132
  }
111
- };
133
+ }
112
134
 
113
- export const resolveDispatch = <T, H extends HookContext> (...resolvers: Resolver<T, H>[]) =>
135
+ export const resolveDispatch =
136
+ <T, H extends HookContext>(...resolvers: Resolver<T, H>[]) =>
114
137
  async (context: H, next?: NextFunction) => {
115
138
  if (typeof next === 'function') {
116
- await next();
139
+ await next()
117
140
  }
118
141
 
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)
142
+ const ctx = getContext(context)
143
+ const status = context.params.resolve
144
+ const { isPaginated, data } = getData(context)
145
+ const resolveAndGetDispatch = async (current: any) => {
146
+ const resolved: any = await runResolvers(resolvers, current, ctx, status)
124
147
 
125
148
  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;
149
+ res[key] = getDispatch(resolved[key])
130
150
 
131
151
  return res
132
152
  }, {} as any)
133
153
  }
134
154
 
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;
155
+ const result = await (Array.isArray(data)
156
+ ? Promise.all(data.map(resolveAndGetDispatch))
157
+ : resolveAndGetDispatch(data))
158
+ const dispatch = isPaginated
159
+ ? {
160
+ ...context.result,
161
+ data: result
162
+ }
163
+ : result
164
+
165
+ context.dispatch = dispatch
142
166
  Object.defineProperty(context.result, DISPATCH, {
143
167
  value: dispatch,
144
168
  enumerable: false,
145
169
  configurable: false
146
- });
147
- };
170
+ })
171
+ }
148
172
 
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
- }
173
+ export const resolveAll = <H extends HookContext>(map: ResolveAllSettings<H>) => {
174
+ const middleware = []
155
175
 
156
- const getResolvers = <H extends HookContext> (
157
- map: ResolveAllSettings<H>,
158
- name: keyof ResolveAllSettings<H>
159
- ) => {
160
- const value = map[name];
176
+ middleware.push(resolveDispatch(map.dispatch))
161
177
 
162
- return Array.isArray(value) ? value : (value !== undefined ? [ value ] : []);
163
- }
178
+ if (map.result) {
179
+ middleware.push(resolveResult(map.result))
180
+ }
181
+
182
+ if (map.query) {
183
+ middleware.push(resolveQuery(map.query))
184
+ }
164
185
 
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
- ])
186
+ if (map.data) {
187
+ middleware.push(resolveData(map.data))
188
+ }
189
+
190
+ return compose(middleware)
191
+ }
@@ -1,13 +1,14 @@
1
- import { HookContext, NextFunction } from '@feathersjs/feathers';
2
- import { BadRequest } from '../../../errors/lib';
3
- import { Schema } from '../schema';
1
+ import { HookContext, NextFunction } from '@feathersjs/feathers'
2
+ import { BadRequest } from '../../../errors/lib'
3
+ import { Schema } from '../schema'
4
4
 
5
- export const validateQuery = <H extends HookContext> (schema: Schema<any>) =>
5
+ export const validateQuery =
6
+ <H extends HookContext>(schema: Schema<any>) =>
6
7
  async (context: H, next?: NextFunction) => {
7
- const data = context?.params?.query || {};
8
+ const data = context?.params?.query || {}
8
9
 
9
10
  try {
10
- const query = await schema.validate(data);
11
+ const query = await schema.validate(data)
11
12
 
12
13
  context.params = {
13
14
  ...context.params,
@@ -15,30 +16,29 @@ export const validateQuery = <H extends HookContext> (schema: Schema<any>) =>
15
16
  }
16
17
 
17
18
  if (typeof next === 'function') {
18
- return next();
19
+ return next()
19
20
  }
20
21
  } catch (error: any) {
21
- throw (error.ajv ? new BadRequest(error.message, error.errors) : error);
22
+ throw error.ajv ? new BadRequest(error.message, error.errors) : error
22
23
  }
23
- };
24
+ }
24
25
 
25
- export const validateData = <H extends HookContext> (schema: Schema<any>) =>
26
+ export const validateData =
27
+ <H extends HookContext>(schema: Schema<any>) =>
26
28
  async (context: H, next?: NextFunction) => {
27
- const data = context.data;
29
+ const data = context.data
28
30
 
29
31
  try {
30
32
  if (Array.isArray(data)) {
31
- context.data = await Promise.all(data.map(current =>
32
- schema.validate(current)
33
- ));
33
+ context.data = await Promise.all(data.map((current) => schema.validate(current)))
34
34
  } else {
35
- context.data = await schema.validate(data);
35
+ context.data = await schema.validate(data)
36
36
  }
37
37
  } catch (error: any) {
38
- throw (error.ajv ? new BadRequest(error.message, error.errors) : error);
38
+ throw error.ajv ? new BadRequest(error.message, error.errors) : error
39
39
  }
40
40
 
41
41
  if (typeof next === 'function') {
42
- return next();
42
+ return next()
43
43
  }
44
- };
44
+ }
package/src/index.ts CHANGED
@@ -1,16 +1,16 @@
1
- import { ResolverStatus } from './resolver';
1
+ import { ResolverStatus } from './resolver'
2
2
 
3
- export * from './schema';
4
- export * from './resolver';
5
- export * from './hooks';
6
- export * from './query';
3
+ export * from './schema'
4
+ export * from './resolver'
5
+ export * from './hooks'
6
+ export * from './query'
7
7
 
8
- export type Infer<S extends { _type: any }> = S['_type'];
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;
10
+ export type Combine<S extends { _type: any }, U> = Pick<Infer<S>, Exclude<keyof Infer<S>, keyof U>> & U
11
11
 
12
12
  declare module '@feathersjs/feathers/lib/declarations' {
13
13
  interface Params {
14
- resolve?: ResolverStatus<any, HookContext>;
14
+ resolve?: ResolverStatus<any, HookContext>
15
15
  }
16
16
  }
package/src/query.ts CHANGED
@@ -1,23 +1,24 @@
1
- import { JSONSchema } from 'json-schema-to-ts';
1
+ import { _ } from '@feathersjs/commons'
2
+ import { JSONSchema } from 'json-schema-to-ts'
2
3
 
3
4
  export type PropertyQuery<D extends JSONSchema> = {
4
5
  anyOf: [
5
6
  D,
6
7
  {
7
- type: 'object',
8
- additionalProperties: false,
8
+ type: 'object'
9
+ additionalProperties: false
9
10
  properties: {
10
- $gt: D,
11
- $gte: D,
12
- $lt: D,
13
- $lte: D,
14
- $ne: D,
11
+ $gt: D
12
+ $gte: D
13
+ $lt: D
14
+ $lte: D
15
+ $ne: D
15
16
  $in: {
16
- type: 'array',
17
+ type: 'array'
17
18
  items: D
18
- },
19
+ }
19
20
  $nin: {
20
- type: 'array',
21
+ type: 'array'
21
22
  items: D
22
23
  }
23
24
  }
@@ -25,64 +26,72 @@ export type PropertyQuery<D extends JSONSchema> = {
25
26
  ]
26
27
  }
27
28
 
28
- export const queryProperty = <T extends JSONSchema> (definition: T) => ({
29
- anyOf: [
30
- definition,
31
- {
32
- type: 'object',
33
- additionalProperties: false,
34
- properties: {
35
- $gt: definition,
36
- $gte: definition,
37
- $lt: definition,
38
- $lte: definition,
39
- $ne: definition,
40
- $in: {
41
- type: 'array',
42
- items: definition
43
- },
44
- $nin: {
45
- type: 'array',
46
- items: definition
29
+ export const queryProperty = <T extends JSONSchema>(def: T) => {
30
+ const definition = _.omit(def, 'default')
31
+ return {
32
+ anyOf: [
33
+ definition,
34
+ {
35
+ type: 'object',
36
+ additionalProperties: false,
37
+ properties: {
38
+ $gt: definition,
39
+ $gte: definition,
40
+ $lt: definition,
41
+ $lte: definition,
42
+ $ne: definition,
43
+ $in: {
44
+ type: 'array',
45
+ items: definition
46
+ },
47
+ $nin: {
48
+ type: 'array',
49
+ items: definition
50
+ }
47
51
  }
48
52
  }
49
- }
50
- ]
51
- } as const);
53
+ ]
54
+ } as const
55
+ }
52
56
 
53
- export const queryProperties = <T extends { [key: string]: JSONSchema }> (definition: T) =>
57
+ export const queryProperties = <T extends { [key: string]: JSONSchema }>(definition: T) =>
54
58
  Object.keys(definition).reduce((res, key) => {
55
- (res as any)[key] = queryProperty(definition[key])
59
+ const result = res as any
60
+
61
+ result[key] = queryProperty(definition[key])
56
62
 
57
- return res
63
+ return result
58
64
  }, {} as { [K in keyof T]: PropertyQuery<T[K]> })
59
65
 
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
- }
66
+ export const querySyntax = <T extends { [key: string]: any }>(definition: T) =>
67
+ ({
68
+ $limit: {
69
+ type: 'number',
70
+ minimum: 0
71
+ },
72
+ $skip: {
73
+ type: 'number',
74
+ minimum: 0
75
+ },
76
+ $sort: {
77
+ type: 'object',
78
+ properties: Object.keys(definition).reduce((res, key) => {
79
+ const result = res as any
76
80
 
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)
81
+ result[key] = {
82
+ type: 'number',
83
+ enum: [1, -1]
84
+ }
85
+
86
+ return result
87
+ }, {} as { [K in keyof T]: { readonly type: 'number'; readonly enum: [1, -1] } })
88
+ },
89
+ $select: {
90
+ type: 'array',
91
+ items: {
92
+ type: 'string',
93
+ enum: Object.keys(definition) as any as (keyof T)[]
94
+ }
95
+ },
96
+ ...queryProperties(definition)
97
+ } as const)