@coderich/autograph 0.13.15 → 0.13.17
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 +2 -2
- package/src/schema/Schema.js +54 -29
- package/src/service/AppService.js +1 -3
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coderich/autograph",
|
|
3
3
|
"main": "index.js",
|
|
4
|
-
"version": "0.13.
|
|
4
|
+
"version": "0.13.17",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"dev": "coderich-dev"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@coderich/util": "0.1.
|
|
18
|
+
"@coderich/util": "0.1.13",
|
|
19
19
|
"@graphql-tools/merge": "9.0.0",
|
|
20
20
|
"@graphql-tools/resolvers-composition": "7.0.0",
|
|
21
21
|
"@hapi/boom": "10.0.1",
|
package/src/schema/Schema.js
CHANGED
|
@@ -3,17 +3,18 @@
|
|
|
3
3
|
const Util = require('@coderich/util');
|
|
4
4
|
const { Kind, parse, visit } = require('graphql');
|
|
5
5
|
const { mergeTypeDefs, mergeFields } = require('@graphql-tools/merge');
|
|
6
|
-
const { isLeafValue,
|
|
6
|
+
const { isLeafValue, mergeDeep, fromGUID } = require('../service/AppService');
|
|
7
7
|
const Pipeline = require('../data/Pipeline');
|
|
8
8
|
const Emitter = require('../data/Emitter');
|
|
9
9
|
|
|
10
10
|
const operations = ['Query', 'Mutation', 'Subscription'];
|
|
11
11
|
const interfaceKinds = [Kind.INTERFACE_TYPE_DEFINITION, Kind.INTERFACE_TYPE_EXTENSION];
|
|
12
12
|
// const unionKinds = [Kind.UNION_TYPE_DEFINITION, Kind.UNION_TYPE_EXTENSION];
|
|
13
|
-
const
|
|
14
|
-
const
|
|
13
|
+
const enumKinds = [Kind.ENUM_TYPE_DEFINITION, Kind.ENUM_TYPE_EXTENSION];
|
|
14
|
+
const scalarKinds = [Kind.SCALAR_TYPE_DEFINITION, Kind.SCALAR_TYPE_EXTENSION];
|
|
15
|
+
const fieldKinds = [Kind.FIELD_DEFINITION];
|
|
15
16
|
const modelKinds = [Kind.OBJECT_TYPE_DEFINITION, Kind.OBJECT_TYPE_EXTENSION].concat(interfaceKinds);
|
|
16
|
-
const allowedKinds = modelKinds.concat(fieldKinds).concat(Kind.DOCUMENT, Kind.NON_NULL_TYPE, Kind.NAMED_TYPE, Kind.LIST_TYPE, Kind.DIRECTIVE).concat(scalarKinds);
|
|
17
|
+
const allowedKinds = modelKinds.concat(fieldKinds).concat(Kind.DOCUMENT, Kind.NON_NULL_TYPE, Kind.NAMED_TYPE, Kind.LIST_TYPE, Kind.DIRECTIVE).concat(scalarKinds).concat(enumKinds);
|
|
17
18
|
const pipelines = ['finalize', 'construct', 'restruct', 'instruct', 'normalize', 'serialize'];
|
|
18
19
|
const inputPipelines = ['finalize', 'construct', 'instruct', 'normalize', 'serialize'];
|
|
19
20
|
const scalars = ['ID', 'String', 'Float', 'Int', 'Boolean'];
|
|
@@ -114,8 +115,8 @@ module.exports = class Schema {
|
|
|
114
115
|
if (this.#schema) return this.#schema;
|
|
115
116
|
|
|
116
117
|
const { directives, namespace } = this.#config;
|
|
117
|
-
this.#schema = {
|
|
118
|
-
let model, field,
|
|
118
|
+
this.#schema = { models: {}, enums: {}, scalars: {}, indexes: [], namespace };
|
|
119
|
+
let target, model, field, isList;
|
|
119
120
|
const thunks = [];
|
|
120
121
|
|
|
121
122
|
// Deprecate
|
|
@@ -128,9 +129,7 @@ module.exports = class Schema {
|
|
|
128
129
|
if (!allowedKinds.includes(node.kind) || operations.includes(name)) return false;
|
|
129
130
|
|
|
130
131
|
if (modelKinds.includes(node.kind)) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
model = this.#schema.models[name] = {
|
|
132
|
+
target = model = this.#schema.models[name] = {
|
|
134
133
|
name,
|
|
135
134
|
key: name,
|
|
136
135
|
fields: {},
|
|
@@ -140,32 +139,50 @@ module.exports = class Schema {
|
|
|
140
139
|
isPersistable: true,
|
|
141
140
|
source: this.#config.dataSources?.default,
|
|
142
141
|
loader: this.#config.dataLoaders?.default,
|
|
142
|
+
pipelines: pipelines.reduce((prev, key) => Object.assign(prev, { [key]: [] }), {}),
|
|
143
143
|
directives: {},
|
|
144
144
|
toString: () => name,
|
|
145
145
|
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (fieldKinds.includes(node.kind)) {
|
|
149
|
+
target = field = model.fields[name] = {
|
|
149
150
|
name,
|
|
150
151
|
key: name,
|
|
151
152
|
pipelines: pipelines.reduce((prev, key) => Object.assign(prev, { [key]: [] }), {}),
|
|
152
153
|
directives: {},
|
|
153
154
|
toString: () => name,
|
|
154
155
|
};
|
|
155
|
-
if (model) model.fields[name] = field;
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
if (scalarKinds.includes(node.kind)) {
|
|
159
|
-
scalars.push(
|
|
160
|
-
|
|
161
|
-
|
|
159
|
+
scalars.push(name);
|
|
160
|
+
target = this.#schema.scalars[name] = {
|
|
161
|
+
directives: {},
|
|
162
|
+
pipelines: pipelines.reduce((prev, key) => Object.assign(prev, { [key]: [] }), {}),
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (enumKinds.includes(node.kind)) {
|
|
167
|
+
target = this.#schema.enums[name] = {
|
|
168
|
+
directives: {},
|
|
169
|
+
pipelines: pipelines.reduce((prev, key) => Object.assign(prev, { [key]: [] }), {}),
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// Define (and assign) an Allow pipeline for the enumeration
|
|
173
|
+
const values = Schema.#resolveNodeValue(node);
|
|
174
|
+
Pipeline.define(name, Pipeline.Allow(...values), { configurable: true });
|
|
175
|
+
target.pipelines.finalize.push(name);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (node.kind === Kind.NON_NULL_TYPE) {
|
|
179
|
+
target[isList ? 'isArrayRequired' : 'isRequired'] = true;
|
|
162
180
|
} else if (node.kind === Kind.NAMED_TYPE) {
|
|
163
|
-
|
|
181
|
+
target.type = node.name.value;
|
|
164
182
|
} else if (node.kind === Kind.LIST_TYPE) {
|
|
165
|
-
|
|
183
|
+
target.isArray = true;
|
|
166
184
|
isList = true;
|
|
167
185
|
} else if (node.kind === Kind.DIRECTIVE) {
|
|
168
|
-
const target = isField ? field : model;
|
|
169
186
|
target.directives[name] = target.directives[name] || {};
|
|
170
187
|
|
|
171
188
|
if (name === directives.model) model.isMarkedModel = true;
|
|
@@ -198,11 +215,11 @@ module.exports = class Schema {
|
|
|
198
215
|
}
|
|
199
216
|
// Field specific directives
|
|
200
217
|
case `${directives.field}-default`: {
|
|
201
|
-
|
|
218
|
+
target.defaultValue = value;
|
|
202
219
|
break;
|
|
203
220
|
}
|
|
204
221
|
case `${directives.field}-connection`: {
|
|
205
|
-
|
|
222
|
+
target.isConnection = value;
|
|
206
223
|
break;
|
|
207
224
|
}
|
|
208
225
|
case `${directives.field}-validate`: { // Alias for finalize
|
|
@@ -210,8 +227,8 @@ module.exports = class Schema {
|
|
|
210
227
|
break;
|
|
211
228
|
}
|
|
212
229
|
case `${directives.link}-by`: {
|
|
213
|
-
|
|
214
|
-
|
|
230
|
+
target.linkBy = value;
|
|
231
|
+
target.isVirtual = true;
|
|
215
232
|
break;
|
|
216
233
|
}
|
|
217
234
|
// Generic by target directives
|
|
@@ -231,7 +248,7 @@ module.exports = class Schema {
|
|
|
231
248
|
// Backwards compat (deprecated)
|
|
232
249
|
case 'model-gqlScope': { model.crud = value; break; }
|
|
233
250
|
case 'model-fieldScope': { model.scope = value; break; }
|
|
234
|
-
case 'field-gqlScope': {
|
|
251
|
+
case 'field-gqlScope': { target.crud = value; break; }
|
|
235
252
|
|
|
236
253
|
// Pipelines
|
|
237
254
|
default: {
|
|
@@ -269,7 +286,7 @@ module.exports = class Schema {
|
|
|
269
286
|
};
|
|
270
287
|
|
|
271
288
|
$model.walk = (data, fn, opts = {}) => {
|
|
272
|
-
if (data == null || !isPlainObject(data)) return data;
|
|
289
|
+
if (data == null || !Util.isPlainObject(data)) return data;
|
|
273
290
|
|
|
274
291
|
// Options
|
|
275
292
|
opts.key = opts.key ?? 'name';
|
|
@@ -291,7 +308,7 @@ module.exports = class Schema {
|
|
|
291
308
|
|
|
292
309
|
// Recursive walk
|
|
293
310
|
if (!$field.model?.isEmbedded) run = [];
|
|
294
|
-
const $value = opts.itemize && $field.model &&
|
|
311
|
+
const $value = opts.itemize && $field.model && Util.isPlainObjectOrArray($node.value) ? Util.map($node.value, el => $field.model.walk(el, fn, { ...opts, path, run })) : $node.value;
|
|
295
312
|
return Object.assign(prev, { [$node.key]: $value });
|
|
296
313
|
}, {});
|
|
297
314
|
};
|
|
@@ -319,6 +336,12 @@ module.exports = class Schema {
|
|
|
319
336
|
$field.isEmbedded = Boolean($field.model && !$field.isFKReference && !$field.isPrimaryKey);
|
|
320
337
|
$field.isScalar = scalars.includes($field.type);
|
|
321
338
|
|
|
339
|
+
// Merge Enums and Scalar type definitions
|
|
340
|
+
const enumer = this.#schema.enums[$field.type];
|
|
341
|
+
const scalar = this.#schema.scalars[$field.type];
|
|
342
|
+
if (enumer) Object.entries(enumer.pipelines).forEach(([key, values]) => $field.pipelines[key].push(...values));
|
|
343
|
+
if (scalar) Object.entries(scalar.pipelines).forEach(([key, values]) => $field.pipelines[key].push(...values));
|
|
344
|
+
|
|
322
345
|
if ($field.isArray) $field.pipelines.normalize.unshift('toArray');
|
|
323
346
|
if ($field.isPrimaryKey) $field.pipelines.serialize.unshift('$pk'); // Will create/convert to FK type always
|
|
324
347
|
if ($field.isFKReference) $field.pipelines.serialize.unshift('$fk'); // Will convert to FK type IFF defined in payload
|
|
@@ -334,11 +357,11 @@ module.exports = class Schema {
|
|
|
334
357
|
}
|
|
335
358
|
});
|
|
336
359
|
|
|
337
|
-
|
|
360
|
+
target = model;
|
|
338
361
|
} else if (node.kind === Kind.LIST_TYPE) {
|
|
339
362
|
isList = false;
|
|
340
|
-
} else if (scalarKinds.includes(node.kind)) {
|
|
341
|
-
|
|
363
|
+
} else if (scalarKinds.concat(enumKinds).includes(node.kind)) {
|
|
364
|
+
target = model;
|
|
342
365
|
}
|
|
343
366
|
},
|
|
344
367
|
});
|
|
@@ -416,6 +439,8 @@ module.exports = class Schema {
|
|
|
416
439
|
switch (node.kind) {
|
|
417
440
|
case 'NullValue': return null;
|
|
418
441
|
case 'ListValue': return node.values.map(Schema.#resolveNodeValue);
|
|
442
|
+
case 'EnumValueDefinition': return node.name.value;
|
|
443
|
+
case 'EnumTypeDefinition': return node.values.map(Schema.#resolveNodeValue);
|
|
419
444
|
case 'ObjectValue': return node.fields.reduce((prev, field) => Object.assign(prev, { [field.name.value]: Schema.#resolveNodeValue(field.value) }), {});
|
|
420
445
|
default: return node.value ?? node;
|
|
421
446
|
}
|
|
@@ -13,9 +13,7 @@ exports.globToRegex = (glob, options = {}) => PicoMatch.makeRe(glob, { nocase: t
|
|
|
13
13
|
const smartMerge = (target, source, options) => source;
|
|
14
14
|
exports.isScalarValue = value => typeof value !== 'object' && typeof value !== 'function';
|
|
15
15
|
exports.isLeafValue = value => Array.isArray(value) || value instanceof Date || ObjectId.isValid(value) || exports.isScalarValue(value);
|
|
16
|
-
exports.
|
|
17
|
-
exports.isPlainObject = obj => exports.isBasicObject(obj) && !Array.isArray(obj);
|
|
18
|
-
exports.mergeDeep = (...args) => DeepMerge.all(args, { isMergeableObject: obj => (exports.isPlainObject(obj) || Array.isArray(obj)), arrayMerge: smartMerge });
|
|
16
|
+
exports.mergeDeep = (...args) => DeepMerge.all(args, { isMergeableObject: obj => (Util.isPlainObjectOrArray(obj)), arrayMerge: smartMerge });
|
|
19
17
|
exports.hashObject = obj => ObjectHash(obj, { respectType: false, respectFunctionNames: false, respectFunctionProperties: false, unorderedArrays: true, ignoreUnknown: true, replacer: r => (ObjectId.isValid(r) ? `${r}` : r) });
|
|
20
18
|
exports.fromGUID = guid => Buffer.from(`${guid}`, 'base64').toString('ascii').split(',');
|
|
21
19
|
exports.guidToId = (autograph, guid) => (autograph.legacyMode ? guid : exports.uvl(exports.fromGUID(guid)[1], guid));
|