@coderich/autograph 0.13.106 → 0.13.108
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/query/QueryResolver.js +23 -17
- package/src/schema/Schema.js +31 -34
package/package.json
CHANGED
|
@@ -67,13 +67,11 @@ module.exports = class QueryResolver extends QueryBuilder {
|
|
|
67
67
|
}
|
|
68
68
|
case 'pullOne': {
|
|
69
69
|
return this.#get(query).then((doc) => {
|
|
70
|
-
const [
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (arr == null) return arr;
|
|
76
|
-
return arr.filter(el => values.every(v => `${v}` !== `${el}`));
|
|
70
|
+
const [[path, inputs]] = Object.entries(input);
|
|
71
|
+
const [key] = path.split('.');
|
|
72
|
+
const $doc = Util.pathmap(path, doc, (mixed) => { // Pathmap because nested arrays
|
|
73
|
+
if (mixed == null) return mixed;
|
|
74
|
+
return mixed.filter(el => inputs.every(v => `${v}` !== `${el}`));
|
|
77
75
|
});
|
|
78
76
|
return this.#resolver.match(this.#model.name).id(doc.id).save({ [key]: get($doc, key) });
|
|
79
77
|
});
|
|
@@ -86,12 +84,21 @@ module.exports = class QueryResolver extends QueryBuilder {
|
|
|
86
84
|
}
|
|
87
85
|
case 'spliceOne': {
|
|
88
86
|
return this.#get(query).then((doc) => {
|
|
89
|
-
const [
|
|
90
|
-
const
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
87
|
+
const [[path, [find, replace]]] = Object.entries(input);
|
|
88
|
+
const [key] = path.split('.');
|
|
89
|
+
const $doc = Util.pathmap(path, doc, (mixed) => { // Pathmap because nested arrays
|
|
90
|
+
if (mixed == null) return mixed;
|
|
91
|
+
if (Array.isArray(mixed)) return mixed.map(el => (`${el}` === `${find}` ? replace : el));
|
|
92
|
+
if (`${mixed}` === `${find}`) return replace;
|
|
93
|
+
return mixed;
|
|
94
|
+
});
|
|
95
|
+
return this.#resolver.match(this.#model.name).id(doc.id).save({ [key]: get($doc, key) });
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
case 'spliceMany': {
|
|
99
|
+
const [[key, values]] = Object.entries(input);
|
|
100
|
+
return this.#find(query).then((docs) => {
|
|
101
|
+
return Promise.all(docs.map(doc => this.#resolver.match(this.#model.name).id(doc.id).splice(key, ...values)));
|
|
95
102
|
});
|
|
96
103
|
}
|
|
97
104
|
case 'deleteOne': {
|
|
@@ -123,17 +130,16 @@ module.exports = class QueryResolver extends QueryBuilder {
|
|
|
123
130
|
#resolveReferentialIntegrity(doc) {
|
|
124
131
|
const txn = this.#resolver;
|
|
125
132
|
|
|
126
|
-
return Util.promiseChain(this.#model.referentialIntegrity.map(({ model, field, path }) => () => {
|
|
127
|
-
const { onDelete,
|
|
133
|
+
return Util.promiseChain(this.#model.referentialIntegrity.map(({ model, field, isArray, path }) => () => {
|
|
134
|
+
const { onDelete, fkField } = field;
|
|
128
135
|
const id = doc[fkField];
|
|
129
136
|
const $path = path.join('.');
|
|
130
137
|
const where = field.isVirtual ? { [field.model.pkField]: get(doc, field.linkBy) } : { [$path]: id };
|
|
131
138
|
|
|
132
139
|
switch (onDelete) {
|
|
133
140
|
case 'cascade': return isArray ? txn.match(model).where(where).pull($path, id) : txn.match(model).where(where).remove();
|
|
134
|
-
case 'nullify': return txn.match(model).where(where).save({ [$path]: null });
|
|
141
|
+
case 'nullify': return isArray ? txn.match(model).where(where).splice($path, id, null) : txn.match(model).where(where).save({ [$path]: null });
|
|
135
142
|
case 'restrict': return txn.match(model).where(where).count().then(count => (count ? Promise.reject(new Error('Restricted')) : count));
|
|
136
|
-
case 'defer': return Promise.resolve(); // Used for embedded models (could be improved)
|
|
137
143
|
default: throw new Error(`Unknown onDelete operator: '${onDelete}'`);
|
|
138
144
|
}
|
|
139
145
|
}));
|
package/src/schema/Schema.js
CHANGED
|
@@ -142,6 +142,7 @@ module.exports = class Schema {
|
|
|
142
142
|
crud: 'crud', // For use when creating API Queries and Mutations
|
|
143
143
|
scope: 'crud', // For use when defining types (how it's field.model reference can be used)
|
|
144
144
|
pkField: 'id',
|
|
145
|
+
isEmbedded: true,
|
|
145
146
|
isPersistable: true,
|
|
146
147
|
source: this.#config.dataSources?.default,
|
|
147
148
|
loader: this.#config.dataLoaders?.default,
|
|
@@ -156,6 +157,7 @@ module.exports = class Schema {
|
|
|
156
157
|
},
|
|
157
158
|
directives: {},
|
|
158
159
|
ignorePaths: [],
|
|
160
|
+
referentialIntegrity: [],
|
|
159
161
|
toString: () => name,
|
|
160
162
|
};
|
|
161
163
|
}
|
|
@@ -202,8 +204,12 @@ module.exports = class Schema {
|
|
|
202
204
|
} else if (node.kind === Kind.DIRECTIVE) {
|
|
203
205
|
target.directives[name] = target.directives[name] || {};
|
|
204
206
|
|
|
205
|
-
if (name === directives.model)
|
|
206
|
-
|
|
207
|
+
if (name === directives.model) {
|
|
208
|
+
model.isMarkedModel = true;
|
|
209
|
+
model.isEmbedded = false;
|
|
210
|
+
} else if (name === directives.index) {
|
|
211
|
+
this.#schema.indexes.push({ model });
|
|
212
|
+
}
|
|
207
213
|
|
|
208
214
|
node.arguments.forEach((arg) => {
|
|
209
215
|
const key = arg.name.value;
|
|
@@ -521,6 +527,9 @@ module.exports = class Schema {
|
|
|
521
527
|
$field.isScalar = scalars.includes($field.type);
|
|
522
528
|
$field.generator ??= $model.generator;
|
|
523
529
|
|
|
530
|
+
// Referential Integrity Setup
|
|
531
|
+
if ($field.onDelete) $field.model.referentialIntegrity.push(...this.#findModelPathsToField($model, $field));
|
|
532
|
+
|
|
524
533
|
// Merge Enums and Scalar type definitions
|
|
525
534
|
const enumer = this.#schema.enums[$field.type];
|
|
526
535
|
const scalar = this.#schema.scalars[$field.type];
|
|
@@ -573,15 +582,6 @@ module.exports = class Schema {
|
|
|
573
582
|
return { key, name, type, on };
|
|
574
583
|
});
|
|
575
584
|
|
|
576
|
-
// Resolve referential integrity
|
|
577
|
-
const onDeleteFields = Array.from(new Set(Object.values(this.#schema.models).reduce((prev, curr) => {
|
|
578
|
-
return prev.concat(Object.values(curr.fields).filter(el => el.onDelete)).flat();
|
|
579
|
-
}, [])));
|
|
580
|
-
|
|
581
|
-
Object.values(this.#schema.models).forEach(($model) => {
|
|
582
|
-
$model.referentialIntegrity = Schema.#identifyOnDeletes(Object.values(this.#schema.models).filter(m => m.isEntity), onDeleteFields.filter(f => `${f.model}` === `${$model}`));
|
|
583
|
-
});
|
|
584
|
-
|
|
585
585
|
// Helper methods
|
|
586
586
|
const resolvePathCache = {};
|
|
587
587
|
this.#schema.resolvePath = (path, prop = 'key') => {
|
|
@@ -611,6 +611,8 @@ module.exports = class Schema {
|
|
|
611
611
|
},
|
|
612
612
|
});
|
|
613
613
|
|
|
614
|
+
// console.log(this.#schema.models.Person.referentialIntegrity);
|
|
615
|
+
|
|
614
616
|
// Return schema
|
|
615
617
|
return this.#schema;
|
|
616
618
|
}
|
|
@@ -639,6 +641,23 @@ module.exports = class Schema {
|
|
|
639
641
|
return this.#config.makeExecutableSchema(this.toObject());
|
|
640
642
|
}
|
|
641
643
|
|
|
644
|
+
#findModelPathsToField(model, field) {
|
|
645
|
+
if (!model.isEmbedded) return [{ model, field, path: [`${field}`], isArray: field.isArray }];
|
|
646
|
+
|
|
647
|
+
const arr = [];
|
|
648
|
+
|
|
649
|
+
Object.values(this.#schema.models).forEach((m) => {
|
|
650
|
+
Util.traverse(Object.values(m.fields), (f, info) => {
|
|
651
|
+
const path = info.path.concat(f.name);
|
|
652
|
+
if (f.isEmbedded) return { value: Object.values(f.model.fields), info: { path, isArray: info.isArray || f.isArray } };
|
|
653
|
+
if (f.type === model.name) arr.push({ model: m, field, path: path.concat(`${field}`), isArray: info.isArray || field.isArray || f.isArray });
|
|
654
|
+
return null;
|
|
655
|
+
}, { path: [], isArray: false });
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
return arr;
|
|
659
|
+
}
|
|
660
|
+
|
|
642
661
|
static #resolveNodeValue(node) {
|
|
643
662
|
if (node == null) return node;
|
|
644
663
|
|
|
@@ -661,7 +680,7 @@ module.exports = class Schema {
|
|
|
661
680
|
|
|
662
681
|
enum AutoGraphIndexEnum { unique }
|
|
663
682
|
enum AutoGraphAuthzEnum { private protected public } # DELETE WHEN MIGRATED
|
|
664
|
-
enum AutoGraphOnDeleteEnum { cascade nullify restrict
|
|
683
|
+
enum AutoGraphOnDeleteEnum { cascade nullify restrict }
|
|
665
684
|
enum AutoGraphPipelineEnum { ${Object.keys(Pipeline).filter(k => !k.startsWith('$')).join(' ')} }
|
|
666
685
|
|
|
667
686
|
directive @${model}(
|
|
@@ -961,26 +980,4 @@ module.exports = class Schema {
|
|
|
961
980
|
before: String
|
|
962
981
|
`;
|
|
963
982
|
}
|
|
964
|
-
|
|
965
|
-
static #findPathToField(model, field, path = []) {
|
|
966
|
-
const { target, embeds } = Object.values(model.fields).reduce((prev, curr) => {
|
|
967
|
-
if (curr === field) prev.target = curr;
|
|
968
|
-
else if (curr.isEmbedded) prev.embeds.push(curr);
|
|
969
|
-
return prev;
|
|
970
|
-
}, { embeds: [] });
|
|
971
|
-
|
|
972
|
-
if (target) return path.concat(target.name);
|
|
973
|
-
if (embeds.length) return embeds.map(f => Schema.#findPathToField(f.model, field, path.concat(f.name))).filter(Boolean)[0];
|
|
974
|
-
return undefined;
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
static #identifyOnDeletes(models, fields) {
|
|
978
|
-
return models.map((model) => {
|
|
979
|
-
return fields.map((field) => {
|
|
980
|
-
const path = Schema.#findPathToField(model, field);
|
|
981
|
-
if (!path) return null;
|
|
982
|
-
return { model, field, path };
|
|
983
|
-
});
|
|
984
|
-
}).flat().filter(Boolean);
|
|
985
|
-
}
|
|
986
983
|
};
|