@coderich/autograph 0.13.11 → 0.13.13
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/Emitter.js +2 -1
- package/src/data/Resolver.js +4 -0
- package/src/schema/Schema.js +98 -26
package/package.json
CHANGED
package/src/data/Emitter.js
CHANGED
|
@@ -78,8 +78,9 @@ class Emitter extends EventEmitter {
|
|
|
78
78
|
} : (event, next) => {
|
|
79
79
|
if (arr.includes(`${event.query[prop]}`)) {
|
|
80
80
|
if (once) this.removeListener(eventName, wrapper);
|
|
81
|
-
next(listener(event, next));
|
|
81
|
+
return next(listener(event, next));
|
|
82
82
|
}
|
|
83
|
+
return next();
|
|
83
84
|
};
|
|
84
85
|
|
|
85
86
|
return this.on(eventName, wrapper);
|
package/src/data/Resolver.js
CHANGED
|
@@ -279,6 +279,10 @@ module.exports = class Resolver {
|
|
|
279
279
|
const type = query.isMutation ? 'Mutation' : 'Query';
|
|
280
280
|
const event = { schema: this.#schema, context: this.#context, resolver: this, query };
|
|
281
281
|
|
|
282
|
+
// Backwards compat
|
|
283
|
+
query.match = { ...query.where };
|
|
284
|
+
query.toObject = () => query;
|
|
285
|
+
|
|
282
286
|
return Emitter.emit(`pre${type}`, event).then(async (resultEarly) => {
|
|
283
287
|
if (resultEarly !== undefined) return resultEarly;
|
|
284
288
|
if (Util.isEqual(query.changeset, { added: {}, updated: {}, deleted: {} })) return query.doc;
|
package/src/schema/Schema.js
CHANGED
|
@@ -8,9 +8,12 @@ const Pipeline = require('../data/Pipeline');
|
|
|
8
8
|
const Emitter = require('../data/Emitter');
|
|
9
9
|
|
|
10
10
|
const operations = ['Query', 'Mutation', 'Subscription'];
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
const
|
|
11
|
+
const interfaceKinds = [Kind.INTERFACE_TYPE_DEFINITION, Kind.INTERFACE_TYPE_EXTENSION];
|
|
12
|
+
// const unionKinds = [Kind.UNION_TYPE_DEFINITION, Kind.UNION_TYPE_EXTENSION];
|
|
13
|
+
const scalarKinds = [Kind.SCALAR_TYPE_DEFINITION, Kind.SCALAR_TYPE_EXTENSION, Kind.ENUM_TYPE_DEFINITION, Kind.ENUM_TYPE_EXTENSION];
|
|
14
|
+
const fieldKinds = [Kind.FIELD_DEFINITION].concat(scalarKinds);
|
|
15
|
+
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);
|
|
14
17
|
const pipelines = ['finalize', 'construct', 'restruct', 'instruct', 'normalize', 'serialize'];
|
|
15
18
|
const inputPipelines = ['finalize', 'construct', 'instruct', 'normalize', 'serialize'];
|
|
16
19
|
const scalars = ['ID', 'String', 'Float', 'Int', 'Boolean'];
|
|
@@ -110,7 +113,6 @@ module.exports = class Schema {
|
|
|
110
113
|
parse() {
|
|
111
114
|
if (this.#schema) return this.#schema;
|
|
112
115
|
|
|
113
|
-
// const schema = buildASTSchema(this.#typeDefs);
|
|
114
116
|
const { directives, namespace } = this.#config;
|
|
115
117
|
this.#schema = { types: {}, models: {}, indexes: [], namespace };
|
|
116
118
|
let model, field, isField, isList;
|
|
@@ -119,21 +121,21 @@ module.exports = class Schema {
|
|
|
119
121
|
// Deprecate
|
|
120
122
|
this.#schema.getModel = name => this.#schema.models[`${name}`];
|
|
121
123
|
|
|
122
|
-
// Parse AST
|
|
124
|
+
// Parse AST (build/defined this.#schema)
|
|
123
125
|
visit(this.#typeDefs, {
|
|
124
126
|
enter: (node) => {
|
|
125
127
|
const name = node.name?.value;
|
|
126
|
-
if (!allowedKinds.includes(node.kind)) return false;
|
|
128
|
+
if (!allowedKinds.includes(node.kind) || operations.includes(name)) return false;
|
|
127
129
|
|
|
128
|
-
if (modelKinds.includes(node.kind)
|
|
130
|
+
if (modelKinds.includes(node.kind)) {
|
|
129
131
|
// this.#schema.types[name] = schema.getType(name);
|
|
130
132
|
|
|
131
133
|
model = this.#schema.models[name] = {
|
|
132
134
|
name,
|
|
133
135
|
key: name,
|
|
134
136
|
fields: {},
|
|
135
|
-
crud: 'crud',
|
|
136
|
-
scope: 'crud',
|
|
137
|
+
crud: 'crud', // For use when creating API Queries and Mutations
|
|
138
|
+
scope: 'crud', // For use when defining types (how it's field.model reference can be used)
|
|
137
139
|
idField: 'id',
|
|
138
140
|
isPersistable: true,
|
|
139
141
|
source: this.#config.dataSources?.default,
|
|
@@ -141,16 +143,20 @@ module.exports = class Schema {
|
|
|
141
143
|
directives: {},
|
|
142
144
|
toString: () => name,
|
|
143
145
|
};
|
|
144
|
-
} else if (node.kind
|
|
146
|
+
} else if (fieldKinds.includes(node.kind)) {
|
|
145
147
|
isField = true;
|
|
146
|
-
field =
|
|
148
|
+
field = {
|
|
147
149
|
name,
|
|
148
150
|
key: name,
|
|
149
|
-
crud: 'crud',
|
|
150
151
|
pipelines: pipelines.reduce((prev, key) => Object.assign(prev, { [key]: [] }), {}),
|
|
151
152
|
directives: {},
|
|
152
153
|
toString: () => name,
|
|
153
154
|
};
|
|
155
|
+
if (model) model.fields[name] = field;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (scalarKinds.includes(node.kind)) {
|
|
159
|
+
scalars.push(node.name.value);
|
|
154
160
|
} else if (node.kind === Kind.NON_NULL_TYPE) {
|
|
155
161
|
field[isList ? 'isArrayRequired' : 'isRequired'] = true;
|
|
156
162
|
} else if (node.kind === Kind.NAMED_TYPE) {
|
|
@@ -167,8 +173,7 @@ module.exports = class Schema {
|
|
|
167
173
|
|
|
168
174
|
node.arguments.forEach((arg) => {
|
|
169
175
|
const key = arg.name.value;
|
|
170
|
-
const
|
|
171
|
-
const value = values ? values.map(n => n.value) : val;
|
|
176
|
+
const value = Schema.#resolveNodeValue(arg.value);
|
|
172
177
|
target.directives[name][key] = value;
|
|
173
178
|
|
|
174
179
|
if (name === directives.index) this.#schema.indexes[this.#schema.indexes.length - 1][key] = value;
|
|
@@ -227,7 +232,6 @@ module.exports = class Schema {
|
|
|
227
232
|
case 'model-gqlScope': { model.crud = value; break; }
|
|
228
233
|
case 'model-fieldScope': { model.scope = value; break; }
|
|
229
234
|
case 'field-gqlScope': { field.crud = value; break; }
|
|
230
|
-
case 'field-fieldScope': { field.scope = value; break; }
|
|
231
235
|
|
|
232
236
|
// Pipelines
|
|
233
237
|
default: {
|
|
@@ -243,7 +247,7 @@ module.exports = class Schema {
|
|
|
243
247
|
return undefined; // Continue
|
|
244
248
|
},
|
|
245
249
|
leave: (node) => {
|
|
246
|
-
if (modelKinds.includes(node.kind)
|
|
250
|
+
if (modelKinds.includes(node.kind)) {
|
|
247
251
|
const $model = model;
|
|
248
252
|
// const idField = $model.fields[$model.idField];
|
|
249
253
|
// $model.primaryKey = Util.nvl(idField?.key, idField?.name, 'id');
|
|
@@ -308,11 +312,12 @@ module.exports = class Schema {
|
|
|
308
312
|
// Field resolution comes first (unshift)
|
|
309
313
|
thunks.unshift(($schema) => {
|
|
310
314
|
$field.model = $schema.models[$field.type];
|
|
311
|
-
$field.
|
|
315
|
+
$field.crud = Util.uvl($field.crud, $field.model?.scope, 'crud');
|
|
316
|
+
$field.linkBy ??= $field.model?.idField;
|
|
312
317
|
$field.linkField = $field.isVirtual ? $model.fields[$model.idField] : $field;
|
|
313
318
|
$field.isFKReference = !$field.isPrimaryKey && $field.model?.isMarkedModel && !$field.model?.isEmbedded;
|
|
314
319
|
$field.isEmbedded = Boolean($field.model && !$field.isFKReference && !$field.isPrimaryKey);
|
|
315
|
-
$field.isScalar =
|
|
320
|
+
$field.isScalar = scalars.includes($field.type);
|
|
316
321
|
|
|
317
322
|
if ($field.isArray) $field.pipelines.normalize.unshift('toArray');
|
|
318
323
|
if ($field.isPrimaryKey) $field.pipelines.serialize.unshift('$pk'); // Will create/convert to FK type always
|
|
@@ -360,6 +365,23 @@ module.exports = class Schema {
|
|
|
360
365
|
return fieldKeys.reduce((parent, key) => Object.values(parent.fields || parent.model.fields).find(el => el[prop] === key) || parent, $model);
|
|
361
366
|
};
|
|
362
367
|
|
|
368
|
+
// Mutate typeDefs
|
|
369
|
+
let $model;
|
|
370
|
+
this.#typeDefs = visit(this.#typeDefs, {
|
|
371
|
+
enter: (node) => {
|
|
372
|
+
const name = node.name?.value;
|
|
373
|
+
if (!allowedKinds.includes(node.kind) || operations.includes(name)) return false;
|
|
374
|
+
|
|
375
|
+
if (modelKinds.includes(node.kind)) {
|
|
376
|
+
$model = this.#schema.models[name];
|
|
377
|
+
} else if (fieldKinds.includes(node.kind)) {
|
|
378
|
+
if (!Util.uvl($model?.fields[name]?.crud, 'crud')?.includes('r')) return null;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return undefined;
|
|
382
|
+
},
|
|
383
|
+
});
|
|
384
|
+
|
|
363
385
|
// Return schema
|
|
364
386
|
return this.#schema;
|
|
365
387
|
}
|
|
@@ -388,6 +410,15 @@ module.exports = class Schema {
|
|
|
388
410
|
return this.#config.makeExecutableSchema(this.toObject());
|
|
389
411
|
}
|
|
390
412
|
|
|
413
|
+
static #resolveNodeValue(node) {
|
|
414
|
+
switch (node.kind) {
|
|
415
|
+
case 'NullValue': return null;
|
|
416
|
+
case 'ListValue': return node.values.map(Schema.#resolveNodeValue);
|
|
417
|
+
case 'ObjectValue': return node.fields.reduce((prev, field) => Object.assign(prev, { [field.name.value]: Schema.#resolveNodeValue(field.value) }), {});
|
|
418
|
+
default: return node.value ?? node;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
391
422
|
static #framework(directives) {
|
|
392
423
|
const { model, field, link, index } = directives;
|
|
393
424
|
|
|
@@ -444,7 +475,6 @@ module.exports = class Schema {
|
|
|
444
475
|
ref: AutoGraphMixed # Specify the modelRef field's name (overrides isEmbedded)
|
|
445
476
|
gqlScope: AutoGraphMixed # Dictate how GraphQL API behaves
|
|
446
477
|
dalScope: AutoGraphMixed # Dictate how the DAL behaves
|
|
447
|
-
fieldScope: AutoGraphMixed # Dictate how a FIELD may use me
|
|
448
478
|
destruct: [AutoGraphPipelineEnum!]
|
|
449
479
|
transform: [AutoGraphPipelineEnum!]
|
|
450
480
|
deserialize: [AutoGraphPipelineEnum!]
|
|
@@ -466,9 +496,9 @@ module.exports = class Schema {
|
|
|
466
496
|
|
|
467
497
|
static #api(schema) {
|
|
468
498
|
// These models are for creating types
|
|
469
|
-
const readModels = Object.values(schema.models).filter(model => model.crud?.includes('r'));
|
|
470
|
-
const createModels = Object.values(schema.models).filter(model => model.crud?.includes('c'));
|
|
471
|
-
const updateModels = Object.values(schema.models).filter(model => model.crud?.includes('u'));
|
|
499
|
+
const readModels = Object.values(schema.models).filter(model => [model.crud, model.scope].join()?.includes('r'));
|
|
500
|
+
const createModels = Object.values(schema.models).filter(model => [model.crud, model.scope].join()?.includes('c'));
|
|
501
|
+
const updateModels = Object.values(schema.models).filter(model => [model.crud, model.scope].join()?.includes('u'));
|
|
472
502
|
|
|
473
503
|
// These are for defining schema queries/mutations
|
|
474
504
|
const entityModels = Object.values(schema.models).filter(model => model.isEntity);
|
|
@@ -479,6 +509,7 @@ module.exports = class Schema {
|
|
|
479
509
|
return {
|
|
480
510
|
typeDefs: `
|
|
481
511
|
scalar AutoGraphMixed
|
|
512
|
+
scalar AutoGraphDateTime
|
|
482
513
|
|
|
483
514
|
interface Node { id: ID! }
|
|
484
515
|
|
|
@@ -505,10 +536,10 @@ module.exports = class Schema {
|
|
|
505
536
|
|
|
506
537
|
return `
|
|
507
538
|
input ${model}InputWhere {
|
|
508
|
-
${fields.map(field => `${field}: ${field.model
|
|
539
|
+
${fields.map(field => `${field}: ${field.model ? `${field.model}InputWhere` : 'AutoGraphMixed'}`)}
|
|
509
540
|
}
|
|
510
541
|
input ${model}InputSort {
|
|
511
|
-
${fields.map(field => `${field}: ${field.model
|
|
542
|
+
${fields.map(field => `${field}: ${field.model ? `${field.model}InputSort` : 'SortOrderEnum'}`)}
|
|
512
543
|
}
|
|
513
544
|
type ${model}Connection {
|
|
514
545
|
count: Int!
|
|
@@ -586,6 +617,47 @@ module.exports = class Schema {
|
|
|
586
617
|
): ${model}SubscriptionPayload!
|
|
587
618
|
`)}
|
|
588
619
|
}
|
|
620
|
+
|
|
621
|
+
${subscriptionModels.map((model) => {
|
|
622
|
+
const fields = Object.values(model.fields).filter(field => field.crud?.includes('r'));
|
|
623
|
+
|
|
624
|
+
return `
|
|
625
|
+
input ${model}SubscriptionInputFilter {
|
|
626
|
+
when: [SubscriptionWhenEnum!]! = [preEvent, postEvent]
|
|
627
|
+
where: ${model}SubscriptionInputWhere! = {}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
input ${model}SubscriptionInputWhere {
|
|
631
|
+
${fields.map(field => `${field}: ${field.model ? `${field.model}InputWhere` : 'AutoGraphMixed'}`)}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
type ${model}SubscriptionPayload {
|
|
635
|
+
event: ${model}SubscriptionPayloadEvent
|
|
636
|
+
query: ${model}SubscriptionQuery
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
type ${model}SubscriptionPayloadEvent {
|
|
640
|
+
crud: SubscriptionCrudEnum!
|
|
641
|
+
data: ${model}SubscriptionPayloadEventData!
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
type ${model}SubscriptionPayloadEventData {
|
|
645
|
+
${fields.map(field => `${field}: ${Schema.#getGQLType(field)}`)}
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
interface ${model}SubscriptionQuery {
|
|
649
|
+
${fields.map(field => `${field}: ${Schema.#getGQLType(field)}`)}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
type ${model}Create implements ${model}SubscriptionQuery {
|
|
653
|
+
${fields.map(field => `${field}: ${Schema.#getGQLType(field)}`)}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
type ${model}Update implements ${model}SubscriptionQuery {
|
|
657
|
+
${fields.map(field => `${field}: ${Schema.#getGQLType(field)}`)}
|
|
658
|
+
}
|
|
659
|
+
`;
|
|
660
|
+
})}
|
|
589
661
|
` : ''}
|
|
590
662
|
`,
|
|
591
663
|
resolvers: {
|
|
@@ -649,12 +721,12 @@ module.exports = class Schema {
|
|
|
649
721
|
|
|
650
722
|
static #getGQLType(field, suffix) {
|
|
651
723
|
let { type } = field;
|
|
652
|
-
const { isEmbedded, isRequired, isScalar, isArray, isArrayRequired, defaultValue } = field;
|
|
724
|
+
const { isEmbedded, isRequired, isScalar, isArray, isArrayRequired, isPrimaryKey, defaultValue } = field;
|
|
653
725
|
const modelType = `${type}${suffix}`;
|
|
654
726
|
if (suffix && !isScalar) type = isEmbedded ? modelType : 'ID';
|
|
655
727
|
type = isArray ? `[${type}${isArrayRequired ? '!' : ''}]` : type;
|
|
656
728
|
if (!suffix && isRequired) type += '!';
|
|
657
|
-
if (suffix === 'InputCreate' && isRequired && defaultValue
|
|
729
|
+
if (suffix === 'InputCreate' && !isPrimaryKey && isRequired && defaultValue == null) type += '!';
|
|
658
730
|
return type;
|
|
659
731
|
}
|
|
660
732
|
|