@coderich/autograph 0.13.10 → 0.13.12
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 +3 -3
- package/src/data/Emitter.js +2 -1
- package/src/data/Resolver.js +8 -1
- package/src/schema/Schema.js +75 -20
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.12",
|
|
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.11",
|
|
19
19
|
"@graphql-tools/merge": "9.0.0",
|
|
20
20
|
"@graphql-tools/resolvers-composition": "7.0.0",
|
|
21
21
|
"@hapi/boom": "10.0.1",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"@coderich/dev": "0.1.0",
|
|
37
37
|
"@graphql-tools/schema": "10.0.0",
|
|
38
38
|
"graphql": "16.6.0",
|
|
39
|
-
"mongodb": "5.
|
|
39
|
+
"mongodb": "5.9.2",
|
|
40
40
|
"mongodb-memory-server": "8.13.0",
|
|
41
41
|
"validator": "13.9.0"
|
|
42
42
|
},
|
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
|
@@ -76,12 +76,15 @@ module.exports = class Resolver {
|
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Execute a user-defined loader (curry in context)
|
|
81
|
+
*/
|
|
79
82
|
loader(name) {
|
|
80
83
|
const context = this.#context;
|
|
81
84
|
|
|
82
85
|
return new Proxy(loaders[name], {
|
|
83
86
|
get(loader, fn, proxy) {
|
|
84
|
-
if (fn
|
|
87
|
+
if (fn.startsWith('load')) return args => loader[fn](args, context);
|
|
85
88
|
return Reflect.get(loader, fn, proxy);
|
|
86
89
|
},
|
|
87
90
|
});
|
|
@@ -276,6 +279,10 @@ module.exports = class Resolver {
|
|
|
276
279
|
const type = query.isMutation ? 'Mutation' : 'Query';
|
|
277
280
|
const event = { schema: this.#schema, context: this.#context, resolver: this, query };
|
|
278
281
|
|
|
282
|
+
// Backwards compat
|
|
283
|
+
query.match = { ...query.where };
|
|
284
|
+
query.toObject = () => query;
|
|
285
|
+
|
|
279
286
|
return Emitter.emit(`pre${type}`, event).then(async (resultEarly) => {
|
|
280
287
|
if (resultEarly !== undefined) return resultEarly;
|
|
281
288
|
if (Util.isEqual(query.changeset, { added: {}, updated: {}, deleted: {} })) return query.doc;
|
package/src/schema/Schema.js
CHANGED
|
@@ -9,11 +9,13 @@ 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
|
+
const scalarKinds = [Kind.SCALAR_TYPE_DEFINITION, Kind.SCALAR_TYPE_EXTENSION];
|
|
12
13
|
const modelKinds = [Kind.OBJECT_TYPE_DEFINITION, Kind.OBJECT_TYPE_EXTENSION, Kind.INTERFACE_TYPE_DEFINITION, Kind.INTERFACE_TYPE_EXTENSION];
|
|
13
|
-
const
|
|
14
|
+
const fieldKinds = [Kind.FIELD_DEFINITION].concat(scalarKinds);
|
|
15
|
+
const allowedKinds = modelKinds.concat(fieldKinds).concat(Kind.DOCUMENT, Kind.NON_NULL_TYPE, Kind.NAMED_TYPE, Kind.LIST_TYPE, Kind.DIRECTIVE);
|
|
14
16
|
const pipelines = ['finalize', 'construct', 'restruct', 'instruct', 'normalize', 'serialize'];
|
|
15
17
|
const inputPipelines = ['finalize', 'construct', 'instruct', 'normalize', 'serialize'];
|
|
16
|
-
const scalars = ['ID', 'String', 'Float', 'Int', 'Boolean'];
|
|
18
|
+
// const scalars = ['ID', 'String', 'Float', 'Int', 'Boolean'];
|
|
17
19
|
|
|
18
20
|
module.exports = class Schema {
|
|
19
21
|
#config;
|
|
@@ -29,9 +31,19 @@ module.exports = class Schema {
|
|
|
29
31
|
this.#config.directives.field ??= 'field';
|
|
30
32
|
this.#config.directives.link ??= 'link';
|
|
31
33
|
this.#config.directives.index ??= 'index';
|
|
32
|
-
|
|
34
|
+
this.#typeDefs = Schema.#framework(this.#config.directives);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* ****** DEPRECATE! ****** */
|
|
38
|
+
getModels() {
|
|
39
|
+
return this.#schema.models;
|
|
33
40
|
}
|
|
34
41
|
|
|
42
|
+
getModel(name) {
|
|
43
|
+
return this.#schema.models[`${name}`];
|
|
44
|
+
}
|
|
45
|
+
/* ***************** */
|
|
46
|
+
|
|
35
47
|
/**
|
|
36
48
|
* Decorate each marked @model with config-driven field decorators
|
|
37
49
|
*/
|
|
@@ -106,38 +118,41 @@ module.exports = class Schema {
|
|
|
106
118
|
let model, field, isField, isList;
|
|
107
119
|
const thunks = [];
|
|
108
120
|
|
|
121
|
+
// Deprecate
|
|
122
|
+
this.#schema.getModel = name => this.#schema.models[`${name}`];
|
|
123
|
+
|
|
109
124
|
// Parse AST
|
|
110
125
|
visit(this.#typeDefs, {
|
|
111
126
|
enter: (node) => {
|
|
112
127
|
const name = node.name?.value;
|
|
113
|
-
if (!allowedKinds.includes(node.kind)) return false;
|
|
128
|
+
if (!allowedKinds.includes(node.kind) || operations.includes(name)) return false;
|
|
114
129
|
|
|
115
|
-
if (modelKinds.includes(node.kind)
|
|
130
|
+
if (modelKinds.includes(node.kind)) {
|
|
116
131
|
// this.#schema.types[name] = schema.getType(name);
|
|
117
132
|
|
|
118
133
|
model = this.#schema.models[name] = {
|
|
119
134
|
name,
|
|
120
135
|
key: name,
|
|
121
136
|
fields: {},
|
|
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)
|
|
122
139
|
idField: 'id',
|
|
123
|
-
crud: 'crud',
|
|
124
|
-
scope: 'crud',
|
|
125
140
|
isPersistable: true,
|
|
126
141
|
source: this.#config.dataSources?.default,
|
|
127
142
|
loader: this.#config.dataLoaders?.default,
|
|
128
143
|
directives: {},
|
|
129
144
|
toString: () => name,
|
|
130
145
|
};
|
|
131
|
-
} else if (node.kind
|
|
146
|
+
} else if (fieldKinds.includes(node.kind)) {
|
|
132
147
|
isField = true;
|
|
133
|
-
field =
|
|
148
|
+
field = {
|
|
134
149
|
name,
|
|
135
150
|
key: name,
|
|
136
|
-
crud: 'crud',
|
|
137
151
|
pipelines: pipelines.reduce((prev, key) => Object.assign(prev, { [key]: [] }), {}),
|
|
138
152
|
directives: {},
|
|
139
153
|
toString: () => name,
|
|
140
154
|
};
|
|
155
|
+
if (model) model.fields[name] = field;
|
|
141
156
|
} else if (node.kind === Kind.NON_NULL_TYPE) {
|
|
142
157
|
field[isList ? 'isArrayRequired' : 'isRequired'] = true;
|
|
143
158
|
} else if (node.kind === Kind.NAMED_TYPE) {
|
|
@@ -154,8 +169,8 @@ module.exports = class Schema {
|
|
|
154
169
|
|
|
155
170
|
node.arguments.forEach((arg) => {
|
|
156
171
|
const key = arg.name.value;
|
|
157
|
-
const { value: val, values } = arg.value;
|
|
158
|
-
const value =
|
|
172
|
+
const { value: val, values = { value: val }, kind } = arg.value;
|
|
173
|
+
const value = kind === 'NullValue' ? null : Util.map(values, n => n.value);
|
|
159
174
|
target.directives[name][key] = value;
|
|
160
175
|
|
|
161
176
|
if (name === directives.index) this.#schema.indexes[this.#schema.indexes.length - 1][key] = value;
|
|
@@ -214,7 +229,6 @@ module.exports = class Schema {
|
|
|
214
229
|
case 'model-gqlScope': { model.crud = value; break; }
|
|
215
230
|
case 'model-fieldScope': { model.scope = value; break; }
|
|
216
231
|
case 'field-gqlScope': { field.crud = value; break; }
|
|
217
|
-
case 'field-fieldScope': { field.scope = value; break; }
|
|
218
232
|
|
|
219
233
|
// Pipelines
|
|
220
234
|
default: {
|
|
@@ -230,7 +244,7 @@ module.exports = class Schema {
|
|
|
230
244
|
return undefined; // Continue
|
|
231
245
|
},
|
|
232
246
|
leave: (node) => {
|
|
233
|
-
if (modelKinds.includes(node.kind)
|
|
247
|
+
if (modelKinds.includes(node.kind)) {
|
|
234
248
|
const $model = model;
|
|
235
249
|
// const idField = $model.fields[$model.idField];
|
|
236
250
|
// $model.primaryKey = Util.nvl(idField?.key, idField?.name, 'id');
|
|
@@ -295,11 +309,12 @@ module.exports = class Schema {
|
|
|
295
309
|
// Field resolution comes first (unshift)
|
|
296
310
|
thunks.unshift(($schema) => {
|
|
297
311
|
$field.model = $schema.models[$field.type];
|
|
298
|
-
$field.
|
|
312
|
+
$field.crud = Util.uvl($field.crud, $field.model?.scope, 'crud');
|
|
313
|
+
$field.linkBy ??= $field.model?.idField;
|
|
299
314
|
$field.linkField = $field.isVirtual ? $model.fields[$model.idField] : $field;
|
|
300
315
|
$field.isFKReference = !$field.isPrimaryKey && $field.model?.isMarkedModel && !$field.model?.isEmbedded;
|
|
316
|
+
// $field.isScalar = Boolean(!$field.model || scalars.includes($field.type));
|
|
301
317
|
$field.isEmbedded = Boolean($field.model && !$field.isFKReference && !$field.isPrimaryKey);
|
|
302
|
-
$field.isScalar = Boolean(!$field.model || scalars.includes($field.type));
|
|
303
318
|
|
|
304
319
|
if ($field.isArray) $field.pipelines.normalize.unshift('toArray');
|
|
305
320
|
if ($field.isPrimaryKey) $field.pipelines.serialize.unshift('$pk'); // Will create/convert to FK type always
|
|
@@ -431,7 +446,6 @@ module.exports = class Schema {
|
|
|
431
446
|
ref: AutoGraphMixed # Specify the modelRef field's name (overrides isEmbedded)
|
|
432
447
|
gqlScope: AutoGraphMixed # Dictate how GraphQL API behaves
|
|
433
448
|
dalScope: AutoGraphMixed # Dictate how the DAL behaves
|
|
434
|
-
fieldScope: AutoGraphMixed # Dictate how a FIELD may use me
|
|
435
449
|
destruct: [AutoGraphPipelineEnum!]
|
|
436
450
|
transform: [AutoGraphPipelineEnum!]
|
|
437
451
|
deserialize: [AutoGraphPipelineEnum!]
|
|
@@ -453,9 +467,9 @@ module.exports = class Schema {
|
|
|
453
467
|
|
|
454
468
|
static #api(schema) {
|
|
455
469
|
// These models are for creating types
|
|
456
|
-
const readModels = Object.values(schema.models).filter(model => model.crud?.includes('r'));
|
|
457
|
-
const createModels = Object.values(schema.models).filter(model => model.crud?.includes('c'));
|
|
458
|
-
const updateModels = Object.values(schema.models).filter(model => model.crud?.includes('u'));
|
|
470
|
+
const readModels = Object.values(schema.models).filter(model => [model.crud, model.scope].join()?.includes('r'));
|
|
471
|
+
const createModels = Object.values(schema.models).filter(model => [model.crud, model.scope].join()?.includes('c'));
|
|
472
|
+
const updateModels = Object.values(schema.models).filter(model => [model.crud, model.scope].join()?.includes('u'));
|
|
459
473
|
|
|
460
474
|
// These are for defining schema queries/mutations
|
|
461
475
|
const entityModels = Object.values(schema.models).filter(model => model.isEntity);
|
|
@@ -573,6 +587,47 @@ module.exports = class Schema {
|
|
|
573
587
|
): ${model}SubscriptionPayload!
|
|
574
588
|
`)}
|
|
575
589
|
}
|
|
590
|
+
|
|
591
|
+
${subscriptionModels.map((model) => {
|
|
592
|
+
const fields = Object.values(model.fields).filter(field => field.crud?.includes('r'));
|
|
593
|
+
|
|
594
|
+
return `
|
|
595
|
+
input ${model}SubscriptionInputFilter {
|
|
596
|
+
when: [SubscriptionWhenEnum!]! = [preEvent, postEvent]
|
|
597
|
+
where: ${model}SubscriptionInputWhere! = {}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
input ${model}SubscriptionInputWhere {
|
|
601
|
+
${fields.map(field => `${field}: ${field.model?.isEntity ? `${field.model}InputWhere` : 'AutoGraphMixed'}`)}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
type ${model}SubscriptionPayload {
|
|
605
|
+
event: ${model}SubscriptionPayloadEvent
|
|
606
|
+
query: ${model}SubscriptionQuery
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
type ${model}SubscriptionPayloadEvent {
|
|
610
|
+
crud: SubscriptionCrudEnum!
|
|
611
|
+
data: ${model}SubscriptionPayloadEventData!
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
type ${model}SubscriptionPayloadEventData {
|
|
615
|
+
${fields.map(field => `${field}: ${Schema.#getGQLType(field)}`)}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
interface ${model}SubscriptionQuery {
|
|
619
|
+
${fields.map(field => `${field}: ${Schema.#getGQLType(field)}`)}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
type ${model}Create implements ${model}SubscriptionQuery {
|
|
623
|
+
${fields.map(field => `${field}: ${Schema.#getGQLType(field)}`)}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
type ${model}Update implements ${model}SubscriptionQuery {
|
|
627
|
+
${fields.map(field => `${field}: ${Schema.#getGQLType(field)}`)}
|
|
628
|
+
}
|
|
629
|
+
`;
|
|
630
|
+
})}
|
|
576
631
|
` : ''}
|
|
577
632
|
`,
|
|
578
633
|
resolvers: {
|