@coderich/autograph 0.13.45 → 0.13.47
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/Transformer.js +7 -1
- package/src/query/QueryBuilder.js +1 -0
- package/src/query/QueryResolver.js +17 -13
- package/src/schema/Schema.js +29 -17
package/package.json
CHANGED
package/src/data/Transformer.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
const Util = require('@coderich/util');
|
|
2
2
|
|
|
3
3
|
module.exports = class Transformer {
|
|
4
|
-
#config = {
|
|
4
|
+
#config = {
|
|
5
|
+
args: {}, // Arguments passed to each thunk
|
|
6
|
+
shape: {}, // The final shape
|
|
7
|
+
defaults: {}, // Default values applied at beginning of transformation
|
|
8
|
+
strictSchema: false, // If true, will strip away unknown attributes
|
|
9
|
+
keepUndefined: false, // If true, will preserve undefined values
|
|
10
|
+
};
|
|
5
11
|
|
|
6
12
|
#operation = {
|
|
7
13
|
set: (target, prop, startValue, proxy) => {
|
|
@@ -221,6 +221,7 @@ module.exports = class QueryBuilder {
|
|
|
221
221
|
const suffix = id || limit === 1 || (crud === 'create' && args.length < 2) ? 'One' : 'Many';
|
|
222
222
|
let input = suffix === 'One' ? args[0] : args;
|
|
223
223
|
if (input === undefined) input = {};
|
|
224
|
+
input.id = id;
|
|
224
225
|
this.#query.args.input = input;
|
|
225
226
|
return this.terminate(Object.assign(this.#query, {
|
|
226
227
|
op: `${crud}${suffix}`,
|
|
@@ -34,6 +34,10 @@ module.exports = class QueryResolver extends QueryBuilder {
|
|
|
34
34
|
}
|
|
35
35
|
case 'updateOne': {
|
|
36
36
|
return this.#get(query).then((doc) => {
|
|
37
|
+
// const $input = this.#model.walk(doc, (node) => {
|
|
38
|
+
// if (node.field.defaultValue !== undefined || ['instruct', 'restruct', 'serialize'].some(el => node.field.pipelines[el]?.length)) return node;
|
|
39
|
+
// return false;
|
|
40
|
+
// });
|
|
37
41
|
const merged = mergeDeep({}, doc, Util.unflatten(input, { safe: true }));
|
|
38
42
|
return this.#resolver.resolve(query.clone({ doc, input: merged }));
|
|
39
43
|
});
|
|
@@ -60,7 +64,7 @@ module.exports = class QueryResolver extends QueryBuilder {
|
|
|
60
64
|
case 'pullOne': {
|
|
61
65
|
return this.#get(query).then((doc) => {
|
|
62
66
|
const [key] = Object.keys(input);
|
|
63
|
-
const values = get(this.#model.transformers.input.transform(input), key);
|
|
67
|
+
const values = get(this.#model.transformers.input.transform(input), key, []);
|
|
64
68
|
const $input = { [key]: (get(doc, key) || []).filter(el => values.every(v => `${v}` !== `${el}`)) };
|
|
65
69
|
return this.#resolver.match(this.#model.name).id(doc.id).save($input);
|
|
66
70
|
});
|
|
@@ -81,7 +85,7 @@ module.exports = class QueryResolver extends QueryBuilder {
|
|
|
81
85
|
}
|
|
82
86
|
case 'deleteOne': {
|
|
83
87
|
return this.#get(query).then((doc) => {
|
|
84
|
-
return this.#resolveReferentialIntegrity(
|
|
88
|
+
return this.#resolveReferentialIntegrity(doc).then(() => {
|
|
85
89
|
return this.#resolver.resolve(query.clone({ doc })).then(() => doc);
|
|
86
90
|
});
|
|
87
91
|
});
|
|
@@ -105,21 +109,21 @@ module.exports = class QueryResolver extends QueryBuilder {
|
|
|
105
109
|
return this.#resolver.resolve(query.clone({ op: 'findMany', key: `find${this.#model.name}`, crud: 'read', isMutation: false }));
|
|
106
110
|
}
|
|
107
111
|
|
|
108
|
-
#resolveReferentialIntegrity(
|
|
109
|
-
const { id } =
|
|
112
|
+
#resolveReferentialIntegrity(doc) {
|
|
113
|
+
const { id } = doc;
|
|
110
114
|
const txn = this.#resolver.transaction(false);
|
|
111
115
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
const
|
|
116
|
+
return txn.run(Util.promiseChain(this.#model.referentialIntegrity.map(({ model, field, path }) => () => {
|
|
117
|
+
const { onDelete, isArray } = field;
|
|
118
|
+
const $path = path.join('.');
|
|
119
|
+
const where = field.isVirtual ? { [field.model.pkField]: get(doc, field.linkBy) } : { [$path]: id };
|
|
116
120
|
|
|
117
|
-
switch (
|
|
118
|
-
case 'cascade': return isArray ? txn.match(model).where(
|
|
119
|
-
case 'nullify': return txn.match(model).where(
|
|
120
|
-
case 'restrict': return txn.match(model).where(
|
|
121
|
+
switch (onDelete) {
|
|
122
|
+
case 'cascade': return isArray ? txn.match(model).where(where).pull($path, id) : txn.match(model).where(where).remove();
|
|
123
|
+
case 'nullify': return txn.match(model).where(where).save({ [$path]: null });
|
|
124
|
+
case 'restrict': return txn.match(model).where(where).count().then(count => (count ? Promise.reject(new Error('Restricted')) : count));
|
|
121
125
|
case 'defer': return Promise.resolve(); // Used for embedded models (could be improved)
|
|
122
|
-
default: throw new Error(`Unknown onDelete operator: '${
|
|
126
|
+
default: throw new Error(`Unknown onDelete operator: '${onDelete}'`);
|
|
123
127
|
}
|
|
124
128
|
})));
|
|
125
129
|
}
|
package/src/schema/Schema.js
CHANGED
|
@@ -129,6 +129,7 @@ module.exports = class Schema {
|
|
|
129
129
|
visit(this.#typeDefs, {
|
|
130
130
|
enter: (node) => {
|
|
131
131
|
const name = node.name?.value;
|
|
132
|
+
|
|
132
133
|
if (!allowedKinds.includes(node.kind) || operations.includes(name)) return false;
|
|
133
134
|
|
|
134
135
|
if (modelKinds.includes(node.kind)) {
|
|
@@ -424,8 +425,9 @@ module.exports = class Schema {
|
|
|
424
425
|
curr.name, // Rename key
|
|
425
426
|
a => Pipeline.$deserialize({ ...a, ...args, path: a.path.concat(curr.name) }),
|
|
426
427
|
];
|
|
428
|
+
|
|
427
429
|
if (curr.isArray) rules.unshift(({ value }) => (value == null ? value : Util.ensureArray(value)));
|
|
428
|
-
|
|
430
|
+
|
|
429
431
|
if (curr.isEmbedded) {
|
|
430
432
|
rules.unshift(a => Util.map(a.value, (value, i) => {
|
|
431
433
|
const path = a.path.concat(curr.name);
|
|
@@ -433,6 +435,7 @@ module.exports = class Schema {
|
|
|
433
435
|
return curr.model.transformers.doc.transform(value, { ...args, query: a.query, context: a.context, path });
|
|
434
436
|
}));
|
|
435
437
|
}
|
|
438
|
+
|
|
436
439
|
return Object.assign(prev, { [curr.key]: rules });
|
|
437
440
|
}, {}),
|
|
438
441
|
defaults: Object.values($model.fields).reduce((prev, curr) => {
|
|
@@ -450,6 +453,7 @@ module.exports = class Schema {
|
|
|
450
453
|
|
|
451
454
|
// Field resolution comes first (unshift)
|
|
452
455
|
thunks.unshift(($schema) => {
|
|
456
|
+
$field.parent = $model;
|
|
453
457
|
$field.model = $schema.models[$field.type];
|
|
454
458
|
$field.crud = Util.uvl($field.crud, $field.model?.scope, 'crud');
|
|
455
459
|
$field.linkTo ??= $field.model;
|
|
@@ -514,8 +518,12 @@ module.exports = class Schema {
|
|
|
514
518
|
});
|
|
515
519
|
|
|
516
520
|
// Resolve referential integrity
|
|
521
|
+
const onDeleteFields = Array.from(new Set(Object.values(this.#schema.models).reduce((prev, curr) => {
|
|
522
|
+
return prev.concat(Object.values(curr.fields).filter(el => el.onDelete)).flat();
|
|
523
|
+
}, [])));
|
|
524
|
+
|
|
517
525
|
Object.values(this.#schema.models).forEach(($model) => {
|
|
518
|
-
$model.referentialIntegrity = Schema.#identifyOnDeletes(Object.values(this.#schema.models), $model
|
|
526
|
+
$model.referentialIntegrity = Schema.#identifyOnDeletes(Object.values(this.#schema.models).filter(m => m.isEntity), onDeleteFields.filter(f => `${f.model}` === `${$model}`));
|
|
519
527
|
});
|
|
520
528
|
|
|
521
529
|
// Helper methods
|
|
@@ -894,21 +902,25 @@ module.exports = class Schema {
|
|
|
894
902
|
`;
|
|
895
903
|
}
|
|
896
904
|
|
|
897
|
-
static #
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
}
|
|
904
|
-
// else {
|
|
905
|
-
// prev.push(...Schema.#identifyOnDeletes(models, model.name).map(od => Object.assign(od, { fieldRef: field.name, isArray: field.isArray, op: field.onDelete })));
|
|
906
|
-
// }
|
|
907
|
-
}
|
|
908
|
-
});
|
|
905
|
+
static #findPathToField(model, field, path = []) {
|
|
906
|
+
const { target, embeds } = Object.values(model.fields).reduce((prev, curr) => {
|
|
907
|
+
if (curr === field) prev.target = curr;
|
|
908
|
+
else if (curr.isEmbedded) prev.embeds.push(curr);
|
|
909
|
+
return prev;
|
|
910
|
+
}, { embeds: [] });
|
|
909
911
|
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
912
|
+
if (target) return path.concat(target.name);
|
|
913
|
+
if (embeds.length) return embeds.map(f => Schema.#findPathToField(f.model, field, path.concat(f.name))).filter(Boolean)[0];
|
|
914
|
+
return undefined;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
static #identifyOnDeletes(models, fields) {
|
|
918
|
+
return models.map((model) => {
|
|
919
|
+
return fields.map((field) => {
|
|
920
|
+
const path = Schema.#findPathToField(model, field);
|
|
921
|
+
if (!path) return null;
|
|
922
|
+
return { model, field, path };
|
|
923
|
+
});
|
|
924
|
+
}).flat().filter(Boolean);
|
|
913
925
|
}
|
|
914
926
|
};
|