@coderich/autograph 0.13.34 → 0.13.36
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 +6 -3
- package/src/data/Resolver.js +2 -2
- package/src/data/Transformer.js +30 -26
- package/src/query/Query.js +15 -59
- package/src/query/QueryBuilder.js +1 -1
- package/src/query/QueryResolver.js +6 -6
- package/src/schema/Schema.js +72 -23
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
|
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,39 +1,34 @@
|
|
|
1
1
|
const Util = require('@coderich/util');
|
|
2
2
|
|
|
3
|
-
// { query, path: path.concat(key), context: this.#context }
|
|
4
|
-
|
|
5
3
|
module.exports = class Transformer {
|
|
6
|
-
#config = {
|
|
7
|
-
args: {},
|
|
8
|
-
shape: {},
|
|
9
|
-
defaults: {},
|
|
10
|
-
operation: 'set',
|
|
11
|
-
};
|
|
4
|
+
#config = { shape: {}, defaults: {}, args: {}, strictSchema: false, keepUndefined: false };
|
|
12
5
|
|
|
13
|
-
#
|
|
14
|
-
|
|
15
|
-
|
|
6
|
+
#operation = {
|
|
7
|
+
set: (target, prop, startValue, proxy) => {
|
|
8
|
+
if (this.#config.shape[prop]) {
|
|
9
|
+
let previousValue;
|
|
16
10
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
set: {
|
|
20
|
-
set: (target, prop, startValue) => {
|
|
21
|
-
const transforms = this.#config.shape[prop] ?? [];
|
|
22
|
-
|
|
23
|
-
const result = transforms.reduce((value, t) => {
|
|
11
|
+
const result = this.#config.shape[prop].reduce((value, t) => {
|
|
12
|
+
previousValue = value;
|
|
24
13
|
if (typeof t === 'function') return Util.uvl(t({ startValue, value, ...this.#config.args }), value);
|
|
25
14
|
prop = t;
|
|
26
15
|
return value;
|
|
27
16
|
}, startValue);
|
|
28
17
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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;
|
|
32
29
|
},
|
|
33
30
|
};
|
|
34
31
|
|
|
35
|
-
#operation;
|
|
36
|
-
|
|
37
32
|
/**
|
|
38
33
|
* Allowing construction of object before knowing full configuration
|
|
39
34
|
*/
|
|
@@ -46,7 +41,6 @@ module.exports = class Transformer {
|
|
|
46
41
|
*/
|
|
47
42
|
config(config = {}) {
|
|
48
43
|
Object.assign(this.#config, config);
|
|
49
|
-
this.#operation = this.#operations[this.#config.operation];
|
|
50
44
|
return this;
|
|
51
45
|
}
|
|
52
46
|
|
|
@@ -58,8 +52,18 @@ module.exports = class Transformer {
|
|
|
58
52
|
return this;
|
|
59
53
|
}
|
|
60
54
|
|
|
61
|
-
|
|
55
|
+
clone(config) {
|
|
56
|
+
return new Transformer({ ...this.#config }).config(config);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
transform(mixed, args = {}) {
|
|
60
|
+
args.thunks ??= [];
|
|
62
61
|
this.args(args);
|
|
63
|
-
|
|
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
|
+
});
|
|
64
68
|
}
|
|
65
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,35 +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
|
-
this.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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;
|
|
78
64
|
}
|
|
79
65
|
|
|
80
66
|
/**
|
|
@@ -86,7 +72,7 @@ module.exports = class Query {
|
|
|
86
72
|
const query = this.clone({
|
|
87
73
|
model: this.#model.key,
|
|
88
74
|
select: this.#query.select.map(name => this.#model.fields[name].key),
|
|
89
|
-
input: this.#model.
|
|
75
|
+
input: this.#model.transformers.toDriver.transform(input),
|
|
90
76
|
where: isNative ? where : this.#model.walk(where, node => Object.assign(node, { key: node.field.key })),
|
|
91
77
|
sort: this.#model.walk(sort, node => Object.assign(node, { key: node.field.key })),
|
|
92
78
|
before: (!isCursorPaging || !before) ? undefined : JSONParse(Buffer.from(before, 'base64').toString('ascii')),
|
|
@@ -99,36 +85,6 @@ module.exports = class Query {
|
|
|
99
85
|
return query;
|
|
100
86
|
}
|
|
101
87
|
|
|
102
|
-
/**
|
|
103
|
-
* Recursive pipeline function
|
|
104
|
-
*/
|
|
105
|
-
#pipeline(query, target, model, data, transformers = [], paths = []) {
|
|
106
|
-
return Util.mapPromise(data, (doc, index) => {
|
|
107
|
-
const path = [...paths];
|
|
108
|
-
if (Array.isArray(data)) path.push(index);
|
|
109
|
-
if (target === 'input') doc = mergeDeep(model.pipelineFields.input, doc);
|
|
110
|
-
else if (target === 'where') doc = mergeDeep(model.pipelineFields.where, doc);
|
|
111
|
-
|
|
112
|
-
return Util.pipeline(Object.entries(doc).map(([key, startValue]) => async (prev) => {
|
|
113
|
-
const field = model.fields[key];
|
|
114
|
-
if (!field) return prev;
|
|
115
|
-
|
|
116
|
-
// Transform value
|
|
117
|
-
let $value = await Util.pipeline(transformers.map(t => async (value) => {
|
|
118
|
-
const v = await t({ query, model, field, value, path: path.concat(key), startValue, resolver: this.#resolver, context: this.#context, schema: this.#schema });
|
|
119
|
-
return v === undefined ? value : v;
|
|
120
|
-
}), startValue);
|
|
121
|
-
|
|
122
|
-
// If it's embedded - delegate
|
|
123
|
-
if (field.isEmbedded) $value = await this.#pipeline(query, target, field.model, $value, transformers, path.concat(key));
|
|
124
|
-
|
|
125
|
-
// Assign it back
|
|
126
|
-
if (target === 'input' && $value === undefined) return prev;
|
|
127
|
-
return Object.assign(prev, { [field.name]: $value });
|
|
128
|
-
}), {});
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
|
|
132
88
|
/**
|
|
133
89
|
* Finalize the query for the driver
|
|
134
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 {
|
|
@@ -145,8 +145,9 @@ module.exports = class Schema {
|
|
|
145
145
|
generator: this.#config.generators?.default,
|
|
146
146
|
pipelines: pipelines.reduce((prev, key) => Object.assign(prev, { [key]: [] }), {}),
|
|
147
147
|
transformers: {
|
|
148
|
-
input: new Transformer(),
|
|
149
|
-
|
|
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: [] } }),
|
|
150
151
|
},
|
|
151
152
|
directives: {},
|
|
152
153
|
toString: () => name,
|
|
@@ -158,9 +159,6 @@ module.exports = class Schema {
|
|
|
158
159
|
name,
|
|
159
160
|
key: name,
|
|
160
161
|
pipelines: pipelines.reduce((prev, key) => Object.assign(prev, { [key]: [] }), {}),
|
|
161
|
-
transformers: {
|
|
162
|
-
input: new Transformer({ args: { model, field, schema: this.#schema } }),
|
|
163
|
-
},
|
|
164
162
|
directives: {},
|
|
165
163
|
toString: () => name,
|
|
166
164
|
};
|
|
@@ -185,7 +183,7 @@ module.exports = class Schema {
|
|
|
185
183
|
|
|
186
184
|
// Define (and assign) an Allow pipeline for the enumeration
|
|
187
185
|
Pipeline.define(name, Pipeline.Allow(...values), { configurable: true });
|
|
188
|
-
target.pipelines.
|
|
186
|
+
target.pipelines.validate.push(name);
|
|
189
187
|
}
|
|
190
188
|
|
|
191
189
|
if (node.kind === Kind.NON_NULL_TYPE) {
|
|
@@ -239,8 +237,8 @@ module.exports = class Schema {
|
|
|
239
237
|
target.isConnection = value;
|
|
240
238
|
break;
|
|
241
239
|
}
|
|
242
|
-
case `${directives.field}-validate`: {
|
|
243
|
-
target.pipelines.
|
|
240
|
+
case `${directives.field}-validate`: {
|
|
241
|
+
target.pipelines.validate = target.pipelines.validate.concat(value).filter(Boolean);
|
|
244
242
|
break;
|
|
245
243
|
}
|
|
246
244
|
case `${directives.field}-transform`: { // Deprecated
|
|
@@ -350,22 +348,74 @@ module.exports = class Schema {
|
|
|
350
348
|
where: Object.values($model.fields).filter(f => f.pipelines.instruct.length).reduce((prev, f) => Object.assign(prev, { [f.name]: undefined }), {}),
|
|
351
349
|
};
|
|
352
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
|
+
|
|
353
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,
|
|
354
395
|
shape: Object.values($model.fields).reduce((prev, curr) => {
|
|
396
|
+
const args = { model: $model, field: curr };
|
|
397
|
+
|
|
355
398
|
const rules = [
|
|
356
|
-
a => Pipeline.$
|
|
357
|
-
a => Pipeline.$
|
|
358
|
-
a => Pipeline.$
|
|
359
|
-
a => Pipeline.$instruct({ ...a, field: curr }),
|
|
360
|
-
// a => Pipeline.$finalize({ ...a, field: curr }),
|
|
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) }),
|
|
361
402
|
];
|
|
362
|
-
|
|
363
|
-
if (curr.isEmbedded)
|
|
364
|
-
|
|
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
|
+
|
|
365
412
|
return Object.assign(prev, { [curr.name]: rules });
|
|
366
413
|
}, {}),
|
|
414
|
+
defaults: $model.pipelineFields.where,
|
|
367
415
|
});
|
|
368
416
|
|
|
417
|
+
$model.transformers.sort = $model.transformers.where.clone({ defaults: {} });
|
|
418
|
+
|
|
369
419
|
$model.transformers.doc.config({
|
|
370
420
|
shape: Object.values($model.fields).reduce((prev, curr) => {
|
|
371
421
|
const rules = [curr.name]; // Rename key
|
|
@@ -390,7 +440,7 @@ module.exports = class Schema {
|
|
|
390
440
|
$field.linkBy ??= $field.linkTo?.pkField; // This defines join logic (below) for both straight+virtual references
|
|
391
441
|
$field.fkField ??= $field.model?.pkField; // This is the fkReference field for straight references
|
|
392
442
|
$field.linkField = $field.isVirtual ? $model.fields[$model.pkField] : $field;
|
|
393
|
-
$field.isFKReference = !$field.isPrimaryKey && $field.model?.isMarkedModel && !$field.model?.isEmbedded;
|
|
443
|
+
$field.isFKReference = $field.fkField && !$field.isPrimaryKey && $field.model?.isMarkedModel && !$field.model?.isEmbedded;
|
|
394
444
|
$field.isEmbedded = Boolean($field.model && !$field.isFKReference && !$field.isPrimaryKey);
|
|
395
445
|
$field.isScalar = scalars.includes($field.type);
|
|
396
446
|
$field.generator ??= $model.generator;
|
|
@@ -406,7 +456,7 @@ module.exports = class Schema {
|
|
|
406
456
|
|
|
407
457
|
if ($field.isArray) $field.pipelines.normalize.unshift('toArray');
|
|
408
458
|
if ($field.isPrimaryKey) $field.pipelines.serialize.unshift('$pk'); // Will create/convert to FK type always
|
|
409
|
-
if ($field.isRequired && $field.isPersistable && !$field.isVirtual) $field.pipelines.
|
|
459
|
+
if ($field.isRequired && $field.isPersistable && !$field.isVirtual) $field.pipelines.validate.push('required');
|
|
410
460
|
|
|
411
461
|
if ($field.isFKReference) {
|
|
412
462
|
const to = $field.model.key;
|
|
@@ -415,7 +465,7 @@ module.exports = class Schema {
|
|
|
415
465
|
const as = `join_${to}`;
|
|
416
466
|
$field.join = { to, on, from, as };
|
|
417
467
|
$field.pipelines.serialize.unshift('$fk'); // Will convert to FK type IFF defined in payload
|
|
418
|
-
$field.pipelines.
|
|
468
|
+
$field.pipelines.validate.push('ensureFK'); // Absolute Last
|
|
419
469
|
}
|
|
420
470
|
});
|
|
421
471
|
|
|
@@ -561,8 +611,7 @@ module.exports = class Schema {
|
|
|
561
611
|
construct: [AutoGraphPipelineEnum!]
|
|
562
612
|
restruct: [AutoGraphPipelineEnum!]
|
|
563
613
|
serialize: [AutoGraphPipelineEnum!]
|
|
564
|
-
|
|
565
|
-
validate: [AutoGraphPipelineEnum!] # Alias for finalize
|
|
614
|
+
validate: [AutoGraphPipelineEnum!]
|
|
566
615
|
|
|
567
616
|
# TEMP TO APPEASE TRANSITION
|
|
568
617
|
ref: AutoGraphMixed # Specify the modelRef field's name (overrides isEmbedded)
|