@coderich/autograph 0.13.33 → 0.13.35
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/package.json +1 -1
- package/src/data/Pipeline.js +9 -6
- package/src/data/Resolver.js +2 -2
- package/src/data/Transformer.js +47 -25
- package/src/query/Query.js +15 -58
- package/src/query/QueryBuilder.js +1 -1
- package/src/query/QueryResolver.js +6 -6
- package/src/schema/Schema.js +83 -13
package/package.json
CHANGED
package/src/data/Pipeline.js
CHANGED
|
@@ -62,7 +62,7 @@ module.exports = class Pipeline {
|
|
|
62
62
|
Pipeline.define('$construct', params => Pipeline.resolve(params, 'construct'), { ignoreNull: false });
|
|
63
63
|
Pipeline.define('$restruct', params => Pipeline.resolve(params, 'restruct'), { ignoreNull: false });
|
|
64
64
|
Pipeline.define('$serialize', params => Pipeline.resolve(params, 'serialize'), { ignoreNull: false });
|
|
65
|
-
Pipeline.define('$
|
|
65
|
+
Pipeline.define('$validate', params => Pipeline.resolve(params, 'validate'), { ignoreNull: false });
|
|
66
66
|
|
|
67
67
|
//
|
|
68
68
|
Pipeline.define('$pk', (params) => {
|
|
@@ -114,14 +114,17 @@ module.exports = class Pipeline {
|
|
|
114
114
|
Pipeline.define('ensureFK', ({ query, resolver, field, value }) => {
|
|
115
115
|
const { type, fkField } = field;
|
|
116
116
|
const ids = Util.filterBy(Util.ensureArray(value), (a, b) => `${a}` === `${b}`);
|
|
117
|
+
if (!ids.length) return undefined;
|
|
117
118
|
return resolver.match(type).flags(query.flags).where({ [fkField]: ids }).count().then((count) => {
|
|
118
119
|
if (count !== ids.length) throw Boom.notFound(`${type} Not Found`);
|
|
119
120
|
});
|
|
120
121
|
}, { itemize: false });
|
|
121
122
|
|
|
122
123
|
// Required fields
|
|
123
|
-
Pipeline.define('required', ({ query, model, field, value }) => {
|
|
124
|
-
if ((query.crud === 'create' && value == null) || (query.crud === 'update' && value === null))
|
|
124
|
+
Pipeline.define('required', ({ query, model, field, value, path }) => {
|
|
125
|
+
if ((query.crud === 'create' && value == null) || (query.crud === 'update' && value === null)) {
|
|
126
|
+
throw Boom.badRequest(`${model.name}.${field.name} is required`);
|
|
127
|
+
}
|
|
125
128
|
}, { ignoreNull: false });
|
|
126
129
|
|
|
127
130
|
// A field cannot hold a reference to itself
|
|
@@ -161,9 +164,9 @@ module.exports = class Pipeline {
|
|
|
161
164
|
static resolve(params, pipeline) {
|
|
162
165
|
const transformers = params.field.pipelines[pipeline] || [];
|
|
163
166
|
|
|
164
|
-
return
|
|
165
|
-
return Pipeline[t]({ ...params, value });
|
|
166
|
-
}
|
|
167
|
+
return transformers.reduce((value, t) => {
|
|
168
|
+
return Util.uvl(Pipeline[t]({ ...params, value }), value);
|
|
169
|
+
}, params.value);
|
|
167
170
|
}
|
|
168
171
|
};
|
|
169
172
|
|
package/src/data/Resolver.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
const { graphql } = require('graphql');
|
|
2
2
|
const Boom = require('@hapi/boom');
|
|
3
3
|
const Util = require('@coderich/util');
|
|
4
|
+
const QueryResolver = require('../query/QueryResolver');
|
|
4
5
|
const Emitter = require('./Emitter');
|
|
5
6
|
const Loader = require('./Loader');
|
|
6
7
|
const DataLoader = require('./DataLoader');
|
|
7
8
|
const Transaction = require('./Transaction');
|
|
8
|
-
const QueryResolver = require('../query/QueryResolver');
|
|
9
9
|
|
|
10
10
|
const loaders = {};
|
|
11
11
|
|
|
@@ -291,7 +291,7 @@ module.exports = class Resolver {
|
|
|
291
291
|
const tquery = await $query.transform(false);
|
|
292
292
|
query = tquery.toObject();
|
|
293
293
|
event = this.#createEvent(query);
|
|
294
|
-
if (query.isMutation) await Emitter.emit('validate', event);
|
|
294
|
+
if (query.isMutation) await Promise.all([...query.input.$thunks, Emitter.emit('validate', event)]);
|
|
295
295
|
return thunk(tquery);
|
|
296
296
|
}).then((result) => {
|
|
297
297
|
event.doc ??= result; // Case of create
|
package/src/data/Transformer.js
CHANGED
|
@@ -1,30 +1,36 @@
|
|
|
1
1
|
const Util = require('@coderich/util');
|
|
2
2
|
|
|
3
3
|
module.exports = class Transformer {
|
|
4
|
-
#config;
|
|
5
|
-
#operation;
|
|
6
|
-
#operations = {
|
|
7
|
-
get: {
|
|
8
|
-
get: () => {
|
|
4
|
+
#config = { shape: {}, defaults: {}, args: {}, strictSchema: false, keepUndefined: false };
|
|
9
5
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
6
|
+
#operation = {
|
|
7
|
+
set: (target, prop, startValue, proxy) => {
|
|
8
|
+
if (this.#config.shape[prop]) {
|
|
9
|
+
let previousValue;
|
|
10
|
+
|
|
11
|
+
const result = this.#config.shape[prop].reduce((value, t) => {
|
|
12
|
+
previousValue = value;
|
|
13
|
+
if (typeof t === 'function') return Util.uvl(t({ startValue, value, ...this.#config.args }), value);
|
|
17
14
|
prop = t;
|
|
18
|
-
return
|
|
19
|
-
},
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
return value;
|
|
16
|
+
}, startValue);
|
|
17
|
+
|
|
18
|
+
if (result instanceof Promise) {
|
|
19
|
+
target[prop] = previousValue;
|
|
20
|
+
proxy.$thunks.push(result);
|
|
21
|
+
} else if (result !== undefined || this.#config.keepUndefined) {
|
|
22
|
+
target[prop] = result;
|
|
23
|
+
}
|
|
24
|
+
} else if (!this.#config.strictSchema) {
|
|
25
|
+
target[prop] = startValue;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return true;
|
|
23
29
|
},
|
|
24
30
|
};
|
|
25
31
|
|
|
26
32
|
/**
|
|
27
|
-
* Allowing construction of object before knowing configuration
|
|
33
|
+
* Allowing construction of object before knowing full configuration
|
|
28
34
|
*/
|
|
29
35
|
constructor(config = {}) {
|
|
30
36
|
this.config(config);
|
|
@@ -34,14 +40,30 @@ module.exports = class Transformer {
|
|
|
34
40
|
* Re-assign configuration after instantiation
|
|
35
41
|
*/
|
|
36
42
|
config(config = {}) {
|
|
37
|
-
this.#config
|
|
38
|
-
this
|
|
39
|
-
this.#config.defaults ??= {};
|
|
40
|
-
this.#config.operation ??= 'set';
|
|
41
|
-
this.#operation = this.#operations[this.#config.operation];
|
|
43
|
+
Object.assign(this.#config, config);
|
|
44
|
+
return this;
|
|
42
45
|
}
|
|
43
46
|
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Re-assign args after instantiation
|
|
49
|
+
*/
|
|
50
|
+
args(args = {}) {
|
|
51
|
+
Object.assign(this.#config.args, args);
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
clone(config) {
|
|
56
|
+
return new Transformer({ ...this.#config }).config(config);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
transform(mixed, args = {}) {
|
|
60
|
+
args.thunks ??= [];
|
|
61
|
+
this.args(args);
|
|
62
|
+
|
|
63
|
+
return Util.map(mixed, (data) => {
|
|
64
|
+
const thunks = Object.defineProperty({}, '$thunks', { value: args.thunks });
|
|
65
|
+
const $data = Object.assign({}, this.#config.defaults, data); // eslint-disable-line
|
|
66
|
+
return Object.assign(new Proxy(thunks, this.#operation), $data);
|
|
67
|
+
});
|
|
46
68
|
}
|
|
47
69
|
};
|
package/src/query/Query.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const Util = require('@coderich/util');
|
|
2
|
-
const Pipeline = require('../data/Pipeline');
|
|
3
2
|
const { isGlob, globToRegex, mergeDeep, finalizeWhereClause, JSONParse } = require('../service/AppService');
|
|
4
3
|
|
|
5
4
|
module.exports = class Query {
|
|
@@ -46,34 +45,22 @@ module.exports = class Query {
|
|
|
46
45
|
}
|
|
47
46
|
|
|
48
47
|
/**
|
|
49
|
-
*
|
|
50
|
-
*/
|
|
51
|
-
pipeline(target, data, transformers) {
|
|
52
|
-
data = Util.unflatten(data, { safe: true });
|
|
53
|
-
const crudMap = { create: ['$construct', '$serialize'], update: ['$restruct', '$serialize'] };
|
|
54
|
-
const crudLines = crudMap[this.#query.crud] || [];
|
|
55
|
-
const transformerMap = { where: ['$cast', '$instruct', '$serialize'], sort: [], input: [] };
|
|
56
|
-
if (this.#query.isMutation) transformerMap.input = ['$default', '$cast', '$normalize', '$instruct', ...crudLines, '$finalize'];
|
|
57
|
-
// if (this.#query.crud === 'create') transformerMap.input.unshift('$default'); // Cant because embedded documents on update are really "creates"
|
|
58
|
-
transformers = transformers || transformerMap[target];
|
|
59
|
-
return this.#pipeline(this.#query, target, this.#model, data, transformers.map(el => Pipeline[el]));
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Transform entire query via pipeline. At minimum, pipeline is needed to unflatten the data...
|
|
48
|
+
* Transform entire query for user consumption
|
|
64
49
|
*/
|
|
65
50
|
transform(asClone = true) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
this.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
51
|
+
const args = { query: this.#query, resolver: this.#resolver, context: this.#context };
|
|
52
|
+
|
|
53
|
+
const [input, where, sort] = [
|
|
54
|
+
this.#model.transformers.input.transform(Util.unflatten(this.#query.input, { safe: true }), args),
|
|
55
|
+
this.#query.isNative ? this.#query.where : this.#model.transformers.where.transform(Util.unflatten(this.#query.where ?? {}, { safe: true }), args),
|
|
56
|
+
this.#model.transformers.sort.transform(Util.unflatten(this.#query.sort, { safe: true }), args),
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
if (asClone) return this.clone({ input, where, sort });
|
|
60
|
+
this.#query.input = input;
|
|
61
|
+
this.#query.where = where;
|
|
62
|
+
this.#query.sort = sort;
|
|
63
|
+
return this;
|
|
77
64
|
}
|
|
78
65
|
|
|
79
66
|
/**
|
|
@@ -85,7 +72,7 @@ module.exports = class Query {
|
|
|
85
72
|
const query = this.clone({
|
|
86
73
|
model: this.#model.key,
|
|
87
74
|
select: this.#query.select.map(name => this.#model.fields[name].key),
|
|
88
|
-
input: this.#model.
|
|
75
|
+
input: this.#model.transformers.toDriver.transform(input),
|
|
89
76
|
where: isNative ? where : this.#model.walk(where, node => Object.assign(node, { key: node.field.key })),
|
|
90
77
|
sort: this.#model.walk(sort, node => Object.assign(node, { key: node.field.key })),
|
|
91
78
|
before: (!isCursorPaging || !before) ? undefined : JSONParse(Buffer.from(before, 'base64').toString('ascii')),
|
|
@@ -98,36 +85,6 @@ module.exports = class Query {
|
|
|
98
85
|
return query;
|
|
99
86
|
}
|
|
100
87
|
|
|
101
|
-
/**
|
|
102
|
-
* Recursive pipeline function
|
|
103
|
-
*/
|
|
104
|
-
#pipeline(query, target, model, data, transformers = [], paths = []) {
|
|
105
|
-
return Util.mapPromise(data, (doc, index) => {
|
|
106
|
-
const path = [...paths];
|
|
107
|
-
if (Array.isArray(data)) path.push(index);
|
|
108
|
-
if (target === 'input') doc = mergeDeep(model.pipelineFields.input, doc);
|
|
109
|
-
else if (target === 'where') doc = mergeDeep(model.pipelineFields.where, doc);
|
|
110
|
-
|
|
111
|
-
return Util.pipeline(Object.entries(doc).map(([key, startValue]) => async (prev) => {
|
|
112
|
-
const field = model.fields[key];
|
|
113
|
-
if (!field) return prev;
|
|
114
|
-
|
|
115
|
-
// Transform value
|
|
116
|
-
let $value = await Util.pipeline(transformers.map(t => async (value) => {
|
|
117
|
-
const v = await t({ query, model, field, value, path: path.concat(key), startValue, resolver: this.#resolver, context: this.#context, schema: this.#schema });
|
|
118
|
-
return v === undefined ? value : v;
|
|
119
|
-
}), startValue);
|
|
120
|
-
|
|
121
|
-
// If it's embedded - delegate
|
|
122
|
-
if (field.isEmbedded) $value = await this.#pipeline(query, target, field.model, $value, transformers, path.concat(key));
|
|
123
|
-
|
|
124
|
-
// Assign it back
|
|
125
|
-
if (target === 'input' && $value === undefined) return prev;
|
|
126
|
-
return Object.assign(prev, { [field.name]: $value });
|
|
127
|
-
}), {});
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
|
|
131
88
|
/**
|
|
132
89
|
* Finalize the query for the driver
|
|
133
90
|
*/
|
|
@@ -44,9 +44,9 @@ module.exports = class QueryResolver extends QueryBuilder {
|
|
|
44
44
|
});
|
|
45
45
|
}
|
|
46
46
|
case 'pushOne': {
|
|
47
|
-
return this.#get(query).then(
|
|
47
|
+
return this.#get(query).then((doc) => {
|
|
48
48
|
const [key] = Object.keys(input);
|
|
49
|
-
const values = get(
|
|
49
|
+
const values = get(this.#model.transformers.input.transform(input), key);
|
|
50
50
|
const $input = { [key]: (get(doc, key) || []).concat(...values) };
|
|
51
51
|
return this.#resolver.match(this.#model.name).id(doc.id).save($input);
|
|
52
52
|
});
|
|
@@ -58,9 +58,9 @@ module.exports = class QueryResolver extends QueryBuilder {
|
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
60
|
case 'pullOne': {
|
|
61
|
-
return this.#get(query).then(
|
|
61
|
+
return this.#get(query).then((doc) => {
|
|
62
62
|
const [key] = Object.keys(input);
|
|
63
|
-
const values = get(
|
|
63
|
+
const values = get(this.#model.transformers.input.transform(input), key);
|
|
64
64
|
const $input = { [key]: (get(doc, key) || []).filter(el => values.every(v => `${v}` !== `${el}`)) };
|
|
65
65
|
return this.#resolver.match(this.#model.name).id(doc.id).save($input);
|
|
66
66
|
});
|
|
@@ -72,9 +72,9 @@ module.exports = class QueryResolver extends QueryBuilder {
|
|
|
72
72
|
});
|
|
73
73
|
}
|
|
74
74
|
case 'spliceOne': {
|
|
75
|
-
return this.#get(query).then(
|
|
75
|
+
return this.#get(query).then((doc) => {
|
|
76
76
|
const [key] = Object.keys(input);
|
|
77
|
-
const [find, replace] = get(
|
|
77
|
+
const [find, replace] = get(this.#model.transformers.input.transform(input), key);
|
|
78
78
|
const $input = { [key]: (get(doc, key) || []).map(el => (`${el}` === `${find}` ? replace : el)) };
|
|
79
79
|
return this.#resolver.match(this.#model.name).id(doc.id).save($input);
|
|
80
80
|
});
|
package/src/schema/Schema.js
CHANGED
|
@@ -16,8 +16,8 @@ const scalarKinds = [Kind.SCALAR_TYPE_DEFINITION, Kind.SCALAR_TYPE_EXTENSION];
|
|
|
16
16
|
const fieldKinds = [Kind.FIELD_DEFINITION];
|
|
17
17
|
const modelKinds = [Kind.OBJECT_TYPE_DEFINITION, Kind.OBJECT_TYPE_EXTENSION].concat(interfaceKinds);
|
|
18
18
|
const allowedKinds = modelKinds.concat(fieldKinds).concat(Kind.DOCUMENT, Kind.NON_NULL_TYPE, Kind.NAMED_TYPE, Kind.LIST_TYPE, Kind.DIRECTIVE).concat(scalarKinds).concat(enumKinds);
|
|
19
|
-
const pipelines = ['
|
|
20
|
-
const inputPipelines = ['
|
|
19
|
+
const pipelines = ['validate', 'construct', 'restruct', 'instruct', 'normalize', 'serialize'];
|
|
20
|
+
const inputPipelines = ['validate', 'construct', 'instruct', 'normalize', 'serialize'];
|
|
21
21
|
const scalars = ['ID', 'String', 'Float', 'Int', 'Boolean'];
|
|
22
22
|
|
|
23
23
|
module.exports = class Schema {
|
|
@@ -144,7 +144,11 @@ module.exports = class Schema {
|
|
|
144
144
|
loader: this.#config.dataLoaders?.default,
|
|
145
145
|
generator: this.#config.generators?.default,
|
|
146
146
|
pipelines: pipelines.reduce((prev, key) => Object.assign(prev, { [key]: [] }), {}),
|
|
147
|
-
transformers: {
|
|
147
|
+
transformers: {
|
|
148
|
+
input: new Transformer({ args: { schema: this.#schema, path: [] } }),
|
|
149
|
+
where: new Transformer({ args: { schema: this.#schema, path: [] } }),
|
|
150
|
+
doc: new Transformer({ args: { schema: this.#schema, path: [] } }),
|
|
151
|
+
},
|
|
148
152
|
directives: {},
|
|
149
153
|
toString: () => name,
|
|
150
154
|
};
|
|
@@ -155,7 +159,6 @@ module.exports = class Schema {
|
|
|
155
159
|
name,
|
|
156
160
|
key: name,
|
|
157
161
|
pipelines: pipelines.reduce((prev, key) => Object.assign(prev, { [key]: [] }), {}),
|
|
158
|
-
transformers: { doc: new Transformer() },
|
|
159
162
|
directives: {},
|
|
160
163
|
toString: () => name,
|
|
161
164
|
};
|
|
@@ -180,7 +183,7 @@ module.exports = class Schema {
|
|
|
180
183
|
|
|
181
184
|
// Define (and assign) an Allow pipeline for the enumeration
|
|
182
185
|
Pipeline.define(name, Pipeline.Allow(...values), { configurable: true });
|
|
183
|
-
target.pipelines.
|
|
186
|
+
target.pipelines.validate.push(name);
|
|
184
187
|
}
|
|
185
188
|
|
|
186
189
|
if (node.kind === Kind.NON_NULL_TYPE) {
|
|
@@ -234,8 +237,8 @@ module.exports = class Schema {
|
|
|
234
237
|
target.isConnection = value;
|
|
235
238
|
break;
|
|
236
239
|
}
|
|
237
|
-
case `${directives.field}-validate`: {
|
|
238
|
-
target.pipelines.
|
|
240
|
+
case `${directives.field}-validate`: {
|
|
241
|
+
target.pipelines.validate = target.pipelines.validate.concat(value).filter(Boolean);
|
|
239
242
|
break;
|
|
240
243
|
}
|
|
241
244
|
case `${directives.field}-transform`: { // Deprecated
|
|
@@ -345,11 +348,79 @@ module.exports = class Schema {
|
|
|
345
348
|
where: Object.values($model.fields).filter(f => f.pipelines.instruct.length).reduce((prev, f) => Object.assign(prev, { [f.name]: undefined }), {}),
|
|
346
349
|
};
|
|
347
350
|
|
|
351
|
+
$model.transformers.toDriver = new Transformer({
|
|
352
|
+
shape: Object.values($model.fields).reduce((prev, curr) => {
|
|
353
|
+
const rules = [curr.key]; // Rename key
|
|
354
|
+
if (curr.isEmbedded) rules.unshift(({ value }) => Util.map(value, v => curr.model.transformers.toDriver.transform(v)));
|
|
355
|
+
return Object.assign(prev, { [curr.name]: rules });
|
|
356
|
+
}, {}),
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
$model.transformers.input.config({
|
|
360
|
+
strictSchema: true,
|
|
361
|
+
shape: Object.values($model.fields).reduce((prev, curr) => {
|
|
362
|
+
const args = { model: $model, field: curr };
|
|
363
|
+
|
|
364
|
+
const rules = [
|
|
365
|
+
a => Pipeline.$default({ ...a, ...args, path: a.path.concat(curr.name) }),
|
|
366
|
+
a => Pipeline.$cast({ ...a, ...args, path: a.path.concat(curr.name) }),
|
|
367
|
+
a => Pipeline.$normalize({ ...a, ...args, path: a.path.concat(curr.name) }),
|
|
368
|
+
a => Pipeline.$instruct({ ...a, ...args, path: a.path.concat(curr.name) }),
|
|
369
|
+
(a) => {
|
|
370
|
+
if (a.query.crud === 'create') return Pipeline.$construct({ ...a, ...args, path: a.path.concat(curr.name) });
|
|
371
|
+
if (a.query.crud === 'update') return Pipeline.$restruct({ ...a, ...args, path: a.path.concat(curr.name) });
|
|
372
|
+
return undefined;
|
|
373
|
+
},
|
|
374
|
+
a => Pipeline.$serialize({ ...a, ...args, path: a.path.concat(curr.name) }),
|
|
375
|
+
];
|
|
376
|
+
|
|
377
|
+
if (curr.isEmbedded) {
|
|
378
|
+
rules.push(a => Util.map(a.value, (value, i) => {
|
|
379
|
+
const path = a.path.concat(curr.name);
|
|
380
|
+
if (curr.isArray) path.push(i);
|
|
381
|
+
return curr.model.transformers.input.transform(value, { ...args, thunks: a.thunks, query: a.query, resolver: a.resolver, context: a.context, path });
|
|
382
|
+
}));
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Validate
|
|
386
|
+
rules.push(a => Pipeline.$validate({ ...a, ...args, path: a.path.concat(curr.name) }));
|
|
387
|
+
|
|
388
|
+
return Object.assign(prev, { [curr.name]: rules });
|
|
389
|
+
}, {}),
|
|
390
|
+
defaults: $model.pipelineFields.input,
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
$model.transformers.where.config({
|
|
394
|
+
keepUndefined: true,
|
|
395
|
+
shape: Object.values($model.fields).reduce((prev, curr) => {
|
|
396
|
+
const args = { model: $model, field: curr };
|
|
397
|
+
|
|
398
|
+
const rules = [
|
|
399
|
+
a => Pipeline.$cast({ ...a, ...args, path: a.path.concat(curr.name) }),
|
|
400
|
+
a => Pipeline.$instruct({ ...a, ...args, path: a.path.concat(curr.name) }),
|
|
401
|
+
a => Pipeline.$serialize({ ...a, ...args, path: a.path.concat(curr.name) }),
|
|
402
|
+
];
|
|
403
|
+
|
|
404
|
+
if (curr.isEmbedded) {
|
|
405
|
+
rules.push(a => Util.map(a.value, (value, i) => {
|
|
406
|
+
const path = a.path.concat(curr.name);
|
|
407
|
+
if (curr.isArray) path.push(i);
|
|
408
|
+
return curr.model.transformers.where.transform(value, { ...args, query: a.query, context: a.context, path });
|
|
409
|
+
}));
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
return Object.assign(prev, { [curr.name]: rules });
|
|
413
|
+
}, {}),
|
|
414
|
+
defaults: $model.pipelineFields.where,
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
$model.transformers.sort = $model.transformers.where.clone({ defaults: {} });
|
|
418
|
+
|
|
348
419
|
$model.transformers.doc.config({
|
|
349
420
|
shape: Object.values($model.fields).reduce((prev, curr) => {
|
|
350
421
|
const rules = [curr.name]; // Rename key
|
|
351
|
-
if (curr.isArray) rules.unshift(
|
|
352
|
-
if (curr.isEmbedded) rules.unshift(
|
|
422
|
+
if (curr.isArray) rules.unshift(({ value }) => (value == null ? value : Util.ensureArray(value)));
|
|
423
|
+
if (curr.isEmbedded) rules.unshift(({ value }) => Util.map(value, v => curr.model.transformers.doc.transform(v)));
|
|
353
424
|
return Object.assign(prev, { [curr.key]: rules });
|
|
354
425
|
}, {}),
|
|
355
426
|
});
|
|
@@ -385,7 +456,7 @@ module.exports = class Schema {
|
|
|
385
456
|
|
|
386
457
|
if ($field.isArray) $field.pipelines.normalize.unshift('toArray');
|
|
387
458
|
if ($field.isPrimaryKey) $field.pipelines.serialize.unshift('$pk'); // Will create/convert to FK type always
|
|
388
|
-
if ($field.isRequired && $field.isPersistable && !$field.isVirtual) $field.pipelines.
|
|
459
|
+
if ($field.isRequired && $field.isPersistable && !$field.isVirtual) $field.pipelines.validate.push('required');
|
|
389
460
|
|
|
390
461
|
if ($field.isFKReference) {
|
|
391
462
|
const to = $field.model.key;
|
|
@@ -394,7 +465,7 @@ module.exports = class Schema {
|
|
|
394
465
|
const as = `join_${to}`;
|
|
395
466
|
$field.join = { to, on, from, as };
|
|
396
467
|
$field.pipelines.serialize.unshift('$fk'); // Will convert to FK type IFF defined in payload
|
|
397
|
-
$field.pipelines.
|
|
468
|
+
$field.pipelines.validate.push('ensureFK'); // Absolute Last
|
|
398
469
|
}
|
|
399
470
|
});
|
|
400
471
|
|
|
@@ -540,8 +611,7 @@ module.exports = class Schema {
|
|
|
540
611
|
construct: [AutoGraphPipelineEnum!]
|
|
541
612
|
restruct: [AutoGraphPipelineEnum!]
|
|
542
613
|
serialize: [AutoGraphPipelineEnum!]
|
|
543
|
-
|
|
544
|
-
validate: [AutoGraphPipelineEnum!] # Alias for finalize
|
|
614
|
+
validate: [AutoGraphPipelineEnum!]
|
|
545
615
|
|
|
546
616
|
# TEMP TO APPEASE TRANSITION
|
|
547
617
|
ref: AutoGraphMixed # Specify the modelRef field's name (overrides isEmbedded)
|