@coderich/autograph 0.13.22 → 0.13.24
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 +7 -5
- package/src/data/Resolver.js +2 -2
- package/src/query/Query.js +3 -3
- package/src/query/QueryBuilder.js +2 -2
- package/src/schema/Schema.js +37 -25
- package/src/service/AppService.js +9 -0
package/package.json
CHANGED
package/src/data/Pipeline.js
CHANGED
|
@@ -74,12 +74,14 @@ module.exports = class Pipeline {
|
|
|
74
74
|
|
|
75
75
|
//
|
|
76
76
|
Pipeline.define('$pk', (params) => {
|
|
77
|
-
const
|
|
77
|
+
const { pkField } = params.model;
|
|
78
|
+
const value = get(params.query.doc, params.path) || params.value?.[pkField] || params.value; // I "think" the get() is for embedded documents
|
|
78
79
|
return Pipeline[params.field.id]({ ...params, value });
|
|
79
80
|
}, { ignoreNull: false });
|
|
80
81
|
|
|
81
82
|
Pipeline.define('$fk', (params) => {
|
|
82
|
-
const
|
|
83
|
+
const { fkField } = params.field;
|
|
84
|
+
const value = params.value?.[fkField] || params.value;
|
|
83
85
|
return Pipeline[params.field.id]({ ...params, value });
|
|
84
86
|
});
|
|
85
87
|
|
|
@@ -116,10 +118,10 @@ module.exports = class Pipeline {
|
|
|
116
118
|
});
|
|
117
119
|
|
|
118
120
|
//
|
|
119
|
-
Pipeline.define('
|
|
120
|
-
const { type } = field;
|
|
121
|
+
Pipeline.define('ensureFK', ({ query, resolver, field, value }) => {
|
|
122
|
+
const { type, fkField } = field;
|
|
121
123
|
const ids = Util.filterBy(Util.ensureArray(value), (a, b) => `${a}` === `${b}`);
|
|
122
|
-
return resolver.match(type).flags(query.flags).where({
|
|
124
|
+
return resolver.match(type).flags(query.flags).where({ [fkField]: ids }).count().then((count) => {
|
|
123
125
|
if (count !== ids.length) throw Boom.notFound(`${type} Not Found`);
|
|
124
126
|
});
|
|
125
127
|
}, { itemize: false });
|
package/src/data/Resolver.js
CHANGED
|
@@ -229,11 +229,11 @@ module.exports = class Resolver {
|
|
|
229
229
|
return (...args) => {
|
|
230
230
|
switch (cmd) {
|
|
231
231
|
case 'save': {
|
|
232
|
-
return queryResolver.save({ ...$doc, ...args[0] });
|
|
232
|
+
return queryResolver.save({ ...$doc, ...args[0] }); // $doc incase it's mutated
|
|
233
233
|
}
|
|
234
234
|
case 'lookup': {
|
|
235
235
|
const field = self.toModel(model).fields[args[0]];
|
|
236
|
-
const where = { [field.linkBy]: $doc[field.linkField.
|
|
236
|
+
const where = field.isVirtual ? { [field.linkBy]: $doc[field.linkField] } : { [field.fkField]: $doc[field] };
|
|
237
237
|
return self.match(field.model).where(where);
|
|
238
238
|
}
|
|
239
239
|
default: {
|
package/src/query/Query.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const Util = require('@coderich/util');
|
|
2
2
|
const Pipeline = require('../data/Pipeline');
|
|
3
|
-
const { isGlob, globToRegex, mergeDeep, finalizeWhereClause } = require('../service/AppService');
|
|
3
|
+
const { isGlob, globToRegex, mergeDeep, finalizeWhereClause, JSONParse } = require('../service/AppService');
|
|
4
4
|
|
|
5
5
|
module.exports = class Query {
|
|
6
6
|
#config;
|
|
@@ -82,8 +82,8 @@ module.exports = class Query {
|
|
|
82
82
|
input: this.#model.walk(input, node => node.value !== undefined && Object.assign(node, { key: node.field.key })),
|
|
83
83
|
where: isNative ? where : this.#model.walk(where, node => Object.assign(node, { key: node.field.key })),
|
|
84
84
|
sort: this.#model.walk(sort, node => Object.assign(node, { key: node.field.key })),
|
|
85
|
-
before: (!isCursorPaging || !before) ? undefined :
|
|
86
|
-
after: (!isCursorPaging || !after) ? undefined :
|
|
85
|
+
before: (!isCursorPaging || !before) ? undefined : JSONParse(Buffer.from(before, 'base64').toString('ascii')),
|
|
86
|
+
after: (!isCursorPaging || !after) ? undefined : JSONParse(Buffer.from(after, 'base64').toString('ascii')),
|
|
87
87
|
$schema: this.#schema.resolvePath,
|
|
88
88
|
});
|
|
89
89
|
|
|
@@ -68,7 +68,7 @@ module.exports = class QueryBuilder {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
info(info) {
|
|
71
|
-
this.select(getGQLSelectFields(this.#query.model, info));
|
|
71
|
+
// this.select(getGQLSelectFields(this.#query.model, info));
|
|
72
72
|
return this;
|
|
73
73
|
}
|
|
74
74
|
|
|
@@ -82,7 +82,7 @@ module.exports = class QueryBuilder {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
where(clause) {
|
|
85
|
-
this.#propCheck('where', 'native', false);
|
|
85
|
+
this.#propCheck('where', 'native', false); // Allow redefine of "where" because we merge it
|
|
86
86
|
const $clause = mergeDeep(this.#query.where || {}, clause);
|
|
87
87
|
this.#query.where = $clause;
|
|
88
88
|
this.#query.args.where = $clause;
|
package/src/schema/Schema.js
CHANGED
|
@@ -59,7 +59,7 @@ module.exports = class Schema {
|
|
|
59
59
|
|
|
60
60
|
if (directive) {
|
|
61
61
|
const arg = directive.arguments.find(({ name }) => name.value === 'decorate');
|
|
62
|
-
const value = arg?.value
|
|
62
|
+
const value = Util.uvl(Schema.#resolveNodeValue(arg?.value), 'default');
|
|
63
63
|
const decorator = this.#config.decorators?.[value];
|
|
64
64
|
|
|
65
65
|
if (decorator) {
|
|
@@ -214,6 +214,10 @@ module.exports = class Schema {
|
|
|
214
214
|
break;
|
|
215
215
|
}
|
|
216
216
|
// Field specific directives
|
|
217
|
+
case `${directives.field}-fk`: {
|
|
218
|
+
target.fkField = value;
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
217
221
|
case `${directives.field}-default`: {
|
|
218
222
|
target.defaultValue = value;
|
|
219
223
|
break;
|
|
@@ -230,9 +234,14 @@ module.exports = class Schema {
|
|
|
230
234
|
target.pipelines.normalize = target.pipelines.normalize.concat(value).filter(Boolean);
|
|
231
235
|
break;
|
|
232
236
|
}
|
|
237
|
+
case `${directives.link}-to`: {
|
|
238
|
+
target.linkTo = value;
|
|
239
|
+
target.isVirtual ??= true;
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
233
242
|
case `${directives.link}-by`: {
|
|
234
243
|
target.linkBy = value;
|
|
235
|
-
target.isVirtual
|
|
244
|
+
target.isVirtual ??= true;
|
|
236
245
|
break;
|
|
237
246
|
}
|
|
238
247
|
// Generic by target directives
|
|
@@ -339,8 +348,10 @@ module.exports = class Schema {
|
|
|
339
348
|
thunks.unshift(($schema) => {
|
|
340
349
|
$field.id ??= $model.id;
|
|
341
350
|
$field.model = $schema.models[$field.type];
|
|
342
|
-
$field.linkBy ??= $field.model?.pkField;
|
|
343
351
|
$field.crud = Util.uvl($field.crud, $field.model?.scope, 'crud');
|
|
352
|
+
$field.linkTo ??= $field.model;
|
|
353
|
+
$field.linkBy ??= $field.linkTo?.pkField; // This defines join logic (below) for both straight+virtual references
|
|
354
|
+
$field.fkField ??= $field.model?.pkField; // This is the fkReference field for straight references
|
|
344
355
|
$field.linkField = $field.isVirtual ? $model.fields[$model.pkField] : $field;
|
|
345
356
|
$field.isFKReference = !$field.isPrimaryKey && $field.model?.isMarkedModel && !$field.model?.isEmbedded;
|
|
346
357
|
$field.isEmbedded = Boolean($field.model && !$field.isFKReference && !$field.isPrimaryKey);
|
|
@@ -354,16 +365,16 @@ module.exports = class Schema {
|
|
|
354
365
|
|
|
355
366
|
if ($field.isArray) $field.pipelines.normalize.unshift('toArray');
|
|
356
367
|
if ($field.isPrimaryKey) $field.pipelines.serialize.unshift('$pk'); // Will create/convert to FK type always
|
|
357
|
-
if ($field.isFKReference) $field.pipelines.serialize.unshift('$fk'); // Will convert to FK type IFF defined in payload
|
|
358
|
-
|
|
359
368
|
if ($field.isRequired && $field.isPersistable && !$field.isVirtual) $field.pipelines.finalize.push('required');
|
|
369
|
+
|
|
360
370
|
if ($field.isFKReference) {
|
|
361
371
|
const to = $field.model.key;
|
|
362
372
|
const on = $field.model.fields[$field.linkBy].key;
|
|
363
373
|
const from = $field.linkField.key;
|
|
364
374
|
const as = `join_${to}`;
|
|
365
375
|
$field.join = { to, on, from, as };
|
|
366
|
-
$field.pipelines.
|
|
376
|
+
$field.pipelines.serialize.unshift('$fk'); // Will convert to FK type IFF defined in payload
|
|
377
|
+
$field.pipelines.finalize.push('ensureFK'); // Absolute Last
|
|
367
378
|
}
|
|
368
379
|
});
|
|
369
380
|
|
|
@@ -446,6 +457,8 @@ module.exports = class Schema {
|
|
|
446
457
|
}
|
|
447
458
|
|
|
448
459
|
static #resolveNodeValue(node) {
|
|
460
|
+
if (node == null) return node;
|
|
461
|
+
|
|
449
462
|
switch (node.kind) {
|
|
450
463
|
case 'NullValue': return null;
|
|
451
464
|
case 'ListValue': return node.values.map(Schema.#resolveNodeValue);
|
|
@@ -493,6 +506,7 @@ module.exports = class Schema {
|
|
|
493
506
|
|
|
494
507
|
directive @${field}(
|
|
495
508
|
id: String # Specify the ID strategy (eg. "toObjectId")
|
|
509
|
+
fk: String # Specify the FK field (default model.pk)
|
|
496
510
|
key: String # Specify db key
|
|
497
511
|
persist: Boolean # Persist this field (default true)
|
|
498
512
|
connection: Boolean # Treat this field as a connection type (default false - rolling this out slowly)
|
|
@@ -589,7 +603,7 @@ module.exports = class Schema {
|
|
|
589
603
|
}
|
|
590
604
|
${connectionFields.length ? `
|
|
591
605
|
extend type ${model} {
|
|
592
|
-
${connectionFields.map(field => `${field}: ${field.model}Connection`)}
|
|
606
|
+
${connectionFields.map(field => `${field}(${Schema.#getConnectionArguments(field.model)}): ${field.model}Connection`)}
|
|
593
607
|
}
|
|
594
608
|
` : ''}
|
|
595
609
|
`;
|
|
@@ -619,16 +633,7 @@ module.exports = class Schema {
|
|
|
619
633
|
node(id: ID!): Node
|
|
620
634
|
${queryModels.map(model => `
|
|
621
635
|
get${model}(id: ID!): ${model}
|
|
622
|
-
find${model}(
|
|
623
|
-
where: ${model}InputWhere
|
|
624
|
-
sortBy: ${model}InputSort
|
|
625
|
-
limit: Int
|
|
626
|
-
skip: Int
|
|
627
|
-
first: Int
|
|
628
|
-
after: String
|
|
629
|
-
last: Int
|
|
630
|
-
before: String
|
|
631
|
-
): ${model}Connection!
|
|
636
|
+
find${model}(${Schema.#getConnectionArguments(model)}): ${model}Connection!
|
|
632
637
|
`)}
|
|
633
638
|
}
|
|
634
639
|
|
|
@@ -713,13 +718,7 @@ module.exports = class Schema {
|
|
|
713
718
|
Query: queryModels.reduce((prev, model) => {
|
|
714
719
|
return Object.assign(prev, {
|
|
715
720
|
[`get${model}`]: (doc, args, context, info) => context[schema.namespace].resolver.match(model).args(args).info(info).one({ required: true }),
|
|
716
|
-
[`find${model}`]: (doc, args, context, info) =>
|
|
717
|
-
return {
|
|
718
|
-
edges: () => context[schema.namespace].resolver.match(model).args(args).info(info).many(),
|
|
719
|
-
count: () => context[schema.namespace].resolver.match(model).args(args).info(info).count(),
|
|
720
|
-
pageInfo: () => context[schema.namespace].resolver.match(model).args(args).info(info).many(),
|
|
721
|
-
};
|
|
722
|
-
},
|
|
721
|
+
[`find${model}`]: (doc, args, context, info) => context[schema.namespace].resolver.match(model).args(args).info(info).resolve(info),
|
|
723
722
|
});
|
|
724
723
|
}, {
|
|
725
724
|
node: (doc, args, context, info) => {
|
|
@@ -746,7 +745,7 @@ module.exports = class Schema {
|
|
|
746
745
|
[model]: Object.values(model.fields).filter(field => field.model?.isEntity).reduce((prev2, field) => {
|
|
747
746
|
return Object.assign(prev2, {
|
|
748
747
|
[field]: (doc, args, context, info) => {
|
|
749
|
-
return
|
|
748
|
+
return doc.$.lookup(field).args(args).info(info).resolve(info);
|
|
750
749
|
},
|
|
751
750
|
});
|
|
752
751
|
}, {}),
|
|
@@ -767,6 +766,19 @@ module.exports = class Schema {
|
|
|
767
766
|
return type;
|
|
768
767
|
}
|
|
769
768
|
|
|
769
|
+
static #getConnectionArguments(model) {
|
|
770
|
+
return `
|
|
771
|
+
where: ${model}InputWhere
|
|
772
|
+
sortBy: ${model}InputSort
|
|
773
|
+
limit: Int
|
|
774
|
+
skip: Int
|
|
775
|
+
first: Int
|
|
776
|
+
after: String
|
|
777
|
+
last: Int
|
|
778
|
+
before: String
|
|
779
|
+
`;
|
|
780
|
+
}
|
|
781
|
+
|
|
770
782
|
static #identifyOnDeletes(models, parentName) {
|
|
771
783
|
return models.reduce((prev, model) => {
|
|
772
784
|
Object.values(model.fields).filter(f => f.onDelete).forEach((field) => {
|
|
@@ -43,3 +43,12 @@ exports.getGQLSelectFields = (model, info) => {
|
|
|
43
43
|
// return value === undefined ? prev : Object.assign(prev, { [key]: value });
|
|
44
44
|
// }, {}));
|
|
45
45
|
// };
|
|
46
|
+
|
|
47
|
+
exports.JSONParse = (mixed) => {
|
|
48
|
+
try {
|
|
49
|
+
const json = JSON.parse(mixed);
|
|
50
|
+
return json;
|
|
51
|
+
} catch (e) {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
};
|