@coderich/autograph 0.12.0 → 0.13.1
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/index.js +4 -6
- package/package.json +30 -44
- package/src/data/DataLoader.js +77 -70
- package/src/data/Emitter.js +89 -0
- package/src/data/Loader.js +33 -0
- package/src/data/Pipeline.js +84 -101
- package/src/data/Resolver.js +304 -0
- package/src/data/Transaction.js +49 -0
- package/src/query/Query.js +159 -335
- package/src/query/QueryBuilder.js +228 -114
- package/src/query/QueryResolver.js +110 -205
- package/src/query/QueryResolverTransaction.js +16 -0
- package/src/schema/Schema.js +602 -0
- package/src/service/AppService.js +38 -0
- package/src/service/ErrorService.js +7 -0
- package/CHANGELOG.md +0 -41
- package/LICENSE +0 -21
- package/README.md +0 -76
- package/src/.DS_Store +0 -0
- package/src/core/.DS_Store +0 -0
- package/src/core/Boom.js +0 -9
- package/src/core/EventEmitter.js +0 -95
- package/src/core/Resolver.js +0 -124
- package/src/core/Schema.js +0 -55
- package/src/core/ServerResolver.js +0 -15
- package/src/data/.DS_Store +0 -0
- package/src/data/DataService.js +0 -120
- package/src/data/DataTransaction.js +0 -161
- package/src/data/Field.js +0 -83
- package/src/data/Model.js +0 -214
- package/src/data/TreeMap.js +0 -78
- package/src/data/Type.js +0 -50
- package/src/driver/.DS_Store +0 -0
- package/src/driver/MongoDriver.js +0 -227
- package/src/driver/index.js +0 -11
- package/src/graphql/.DS_Store +0 -0
- package/src/graphql/ast/.DS_Store +0 -0
- package/src/graphql/ast/Field.js +0 -206
- package/src/graphql/ast/Model.js +0 -145
- package/src/graphql/ast/Node.js +0 -291
- package/src/graphql/ast/Schema.js +0 -133
- package/src/graphql/ast/Type.js +0 -26
- package/src/graphql/ast/TypeDefApi.js +0 -93
- package/src/graphql/extension/.DS_Store +0 -0
- package/src/graphql/extension/api.js +0 -193
- package/src/graphql/extension/framework.js +0 -71
- package/src/graphql/extension/type.js +0 -34
- package/src/query/.DS_Store +0 -0
- package/src/query/QueryBuilderTransaction.js +0 -26
- package/src/query/QueryService.js +0 -111
- package/src/service/.DS_Store +0 -0
- package/src/service/app.service.js +0 -319
- package/src/service/decorator.service.js +0 -114
- package/src/service/event.service.js +0 -66
- package/src/service/graphql.service.js +0 -92
- package/src/service/schema.service.js +0 -95
|
@@ -1,221 +1,126 @@
|
|
|
1
|
-
const
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
1
|
+
const get = require('lodash.get');
|
|
2
|
+
const Util = require('@coderich/util');
|
|
3
|
+
const QueryBuilder = require('./QueryBuilder');
|
|
4
|
+
const { mergeDeep } = require('../service/AppService');
|
|
5
|
+
|
|
6
|
+
module.exports = class QueryResolver extends QueryBuilder {
|
|
7
|
+
#model;
|
|
8
|
+
#schema;
|
|
9
|
+
#config;
|
|
10
|
+
#context;
|
|
11
|
+
#resolver;
|
|
12
|
+
|
|
13
|
+
constructor(config) {
|
|
14
|
+
const { schema, context, resolver, query } = config;
|
|
15
|
+
super(config);
|
|
16
|
+
this.#config = config;
|
|
17
|
+
this.#schema = schema;
|
|
18
|
+
this.#context = context;
|
|
19
|
+
this.#resolver = resolver;
|
|
20
|
+
this.#model = schema.models[query.model];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
terminate() {
|
|
24
|
+
const query = super.terminate();
|
|
25
|
+
const { op, input } = query.toObject();
|
|
26
|
+
|
|
27
|
+
// Resolve
|
|
28
|
+
switch (op) {
|
|
29
|
+
case 'findOne': case 'findMany': case 'count': case 'createOne': {
|
|
30
|
+
return this.#resolver.resolve(query);
|
|
22
31
|
}
|
|
23
|
-
case '
|
|
24
|
-
return
|
|
32
|
+
case 'createMany': {
|
|
33
|
+
return this.#resolver.transaction(false).run(Promise.all(input.map(el => this.#resolver.match(this.#model.name).save(el))));
|
|
25
34
|
}
|
|
26
|
-
case '
|
|
27
|
-
return
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
pageInfo: () => new QueryResolver(this.query.clone().method('findMany')).resolve(),
|
|
35
|
+
case 'updateOne': {
|
|
36
|
+
return this.#get(query).then((doc) => {
|
|
37
|
+
const merged = mergeDeep({}, Util.unflatten(doc), Util.unflatten(input));
|
|
38
|
+
return this.#resolver.resolve(query.clone({ doc, input: merged }));
|
|
31
39
|
});
|
|
32
40
|
}
|
|
33
|
-
case '
|
|
34
|
-
return
|
|
41
|
+
case 'updateMany': {
|
|
42
|
+
return this.#find(query).then((docs) => {
|
|
43
|
+
return this.#resolver.transaction(false).run(Promise.all(docs.map(doc => this.#resolver.match(this.#model.name).id(doc.id).save(input))));
|
|
44
|
+
});
|
|
35
45
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
findMany(query) {
|
|
46
|
-
return createSystemEvent('Query', { query }, async () => {
|
|
47
|
-
return this.resolver.resolve(query);
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
count(query) {
|
|
52
|
-
return createSystemEvent('Query', { query }, async () => {
|
|
53
|
-
return this.resolver.resolve(query);
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
createOne(query) {
|
|
58
|
-
const { model, input } = query.toObject();
|
|
59
|
-
const inputShape = model.getShape('create', 'input');
|
|
60
|
-
const docShape = model.getShape('create', 'doc');
|
|
61
|
-
const doc = model.shapeObject(inputShape, {}, query); // We use input shape here
|
|
62
|
-
const merged = mergeDeep(doc, input);
|
|
63
|
-
|
|
64
|
-
return createSystemEvent('Mutation', { query: query.doc(doc).merged(merged) }, async () => {
|
|
65
|
-
const payload = model.shapeObject(inputShape, merged, query);
|
|
66
|
-
await model.validateObject(inputShape, payload, query.payload(payload));
|
|
67
|
-
return this.resolver.resolve(query.$input(model.shapeObject(docShape, payload, query)));
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
createMany(query) {
|
|
72
|
-
const { model, input, transaction } = query.toObject();
|
|
73
|
-
const txn = this.resolver.transaction(transaction);
|
|
74
|
-
input.forEach(arg => txn.match(model).save(arg));
|
|
75
|
-
return txn.run();
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async updateOne(query) {
|
|
79
|
-
const { model, match, input } = query.toObject();
|
|
80
|
-
const inputShape = model.getShape('update', 'input');
|
|
81
|
-
const docShape = model.getShape('update', 'doc');
|
|
82
|
-
|
|
83
|
-
return this.resolver.match(model).match(match).one({ required: true }).then((doc) => {
|
|
84
|
-
const merged = mergeDeep(doc, input);
|
|
85
|
-
|
|
86
|
-
return createSystemEvent('Mutation', { query: query.doc(doc).merged(merged) }, async () => {
|
|
87
|
-
const payload = model.shapeObject(inputShape, merged, query);
|
|
88
|
-
await model.validateObject(inputShape, payload, query.payload(payload));
|
|
89
|
-
return this.resolver.resolve(query.$doc(model.shapeObject(docShape, payload, query)));
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
updateMany(query) {
|
|
95
|
-
const { model, input, match, transaction, flags } = query.toObject();
|
|
96
|
-
|
|
97
|
-
return this.resolver.match(model).match(match).many(flags).then((docs) => {
|
|
98
|
-
const txn = this.resolver.transaction(transaction);
|
|
99
|
-
docs.forEach(doc => txn.match(model).id(doc.id).save(input, flags));
|
|
100
|
-
return txn.run();
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
deleteOne(query) {
|
|
105
|
-
const { model, id } = query.toObject();
|
|
106
|
-
|
|
107
|
-
return this.resolver.match(model).id(id).one({ required: true }).then(async (doc) => {
|
|
108
|
-
return createSystemEvent('Mutation', { query: query.doc(doc) }, () => {
|
|
109
|
-
return QueryService.resolveReferentialIntegrity(query).then(() => {
|
|
110
|
-
return this.resolver.resolve(query).then(() => doc);
|
|
46
|
+
case 'pushOne': {
|
|
47
|
+
return this.#get(query).then(async (doc) => {
|
|
48
|
+
const [key] = Object.keys(input);
|
|
49
|
+
const values = get(await query.pipeline('input', input), key);
|
|
50
|
+
const $input = { [key]: (get(doc, key) || []).concat(...values) };
|
|
51
|
+
return this.#resolver.match(this.#model.name).id(doc.id).save($input);
|
|
111
52
|
});
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
return txn.run();
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
spliceOne(query) {
|
|
162
|
-
const { args } = query.toObject();
|
|
163
|
-
const [key, ...values] = args;
|
|
164
|
-
return this.splice(query.args([key, ...values]));
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
spliceMany(query) {
|
|
168
|
-
const { model, match, transaction, args, flags } = query.toObject();
|
|
169
|
-
const [key, ...values] = args;
|
|
170
|
-
|
|
171
|
-
return this.resolver.match(model).match(match).flags(flags).many().then((docs) => {
|
|
172
|
-
const txn = this.resolver.transaction(transaction);
|
|
173
|
-
docs.forEach(doc => txn.match(model).id(doc.id).splice(key, ...values));
|
|
174
|
-
return txn.run();
|
|
175
|
-
});
|
|
53
|
+
}
|
|
54
|
+
case 'pushMany': {
|
|
55
|
+
const [[key, values]] = Object.entries(input[0]);
|
|
56
|
+
return this.#find(query).then((docs) => {
|
|
57
|
+
return this.#resolver.transaction(false).run(Promise.all(docs.map(doc => this.#resolver.match(this.#model.name).id(doc.id).push(key, values))));
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
case 'pullOne': {
|
|
61
|
+
return this.#get(query).then(async (doc) => {
|
|
62
|
+
const [key] = Object.keys(input);
|
|
63
|
+
const values = get(await query.pipeline('input', input), key);
|
|
64
|
+
const $input = { [key]: (get(doc, key) || []).filter(el => values.every(v => `${v}` !== `${el}`)) };
|
|
65
|
+
return this.#resolver.match(this.#model.name).id(doc.id).save($input);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
case 'pullMany': {
|
|
69
|
+
const [[key, values]] = Object.entries(input[0]);
|
|
70
|
+
return this.#find(query).then((docs) => {
|
|
71
|
+
return this.#resolver.transaction(false).run(Promise.all(docs.map(doc => this.#resolver.match(this.#model.name).id(doc.id).pull(key, values))));
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
case 'spliceOne': {
|
|
75
|
+
return this.#get(query).then(async (doc) => {
|
|
76
|
+
const [key] = Object.keys(input);
|
|
77
|
+
const [find, replace] = get(await query.pipeline('input', input), key);
|
|
78
|
+
const $input = { [key]: (get(doc, key) || []).map(el => (`${el}` === `${find}` ? replace : el)) };
|
|
79
|
+
return this.#resolver.match(this.#model.name).id(doc.id).save($input);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
case 'deleteOne': {
|
|
83
|
+
return this.#get(query).then((doc) => {
|
|
84
|
+
return this.#resolveReferentialIntegrity(query).then(() => {
|
|
85
|
+
return this.#resolver.resolve(query).then(() => doc);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
case 'deleteMany': {
|
|
90
|
+
return this.#find(query).then((docs) => {
|
|
91
|
+
return this.#resolver.transaction(false).run(Promise.all(docs.map(doc => this.#resolver.match(this.#model.name).id(doc.id).delete())));
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
default: {
|
|
95
|
+
throw new Error(`Unknown operation "${op}"`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
176
98
|
}
|
|
177
99
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const docShape = model.getShape('update', 'doc');
|
|
181
|
-
const inputShape = model.getShape('update', 'input');
|
|
182
|
-
const spliceShape = model.getShape('update', 'splice');
|
|
183
|
-
const [key, from, to] = args;
|
|
184
|
-
|
|
185
|
-
// Can only splice arrays
|
|
186
|
-
const field = model.getField(key);
|
|
187
|
-
const isArray = field.isArray();
|
|
188
|
-
if (!isArray) throw Boom.badRequest(`Cannot splice field '${model}.${field}'`);
|
|
189
|
-
|
|
190
|
-
return this.resolver.match(model).match(match).one({ required: true }).then(async (doc) => {
|
|
191
|
-
const array = get(doc, key) || [];
|
|
192
|
-
const $to = model.shapeObject(spliceShape, { [key]: to }, query)[key] || to;
|
|
193
|
-
const $from = model.shapeObject(spliceShape, { [key]: from }, query)[key] || from;
|
|
194
|
-
set(doc, key, DataService.spliceEmbeddedArray(array, $from, $to));
|
|
195
|
-
|
|
196
|
-
return createSystemEvent('Mutation', { query: query.method('updateOne').doc(doc).merged(doc) }, async () => {
|
|
197
|
-
const payload = model.shapeObject(inputShape, doc, query);
|
|
198
|
-
await model.validateObject(inputShape, payload, query.payload(payload));
|
|
199
|
-
return this.resolver.resolve(query.$doc(model.shapeObject(docShape, payload, query)));
|
|
200
|
-
});
|
|
201
|
-
});
|
|
100
|
+
#get(query) {
|
|
101
|
+
return this.#resolver.match(this.#model.name).id(query.toObject().id).one({ required: true });
|
|
202
102
|
}
|
|
203
103
|
|
|
204
|
-
|
|
205
|
-
return this.
|
|
104
|
+
#find(query) {
|
|
105
|
+
return this.#resolver.resolve(query.clone({ op: 'findMany', key: `find${this.#model.name}`, crud: 'read', isMutation: false }));
|
|
206
106
|
}
|
|
207
107
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
108
|
+
#resolveReferentialIntegrity(query) {
|
|
109
|
+
const { id } = query.toObject();
|
|
110
|
+
const txn = this.#resolver.transaction(false);
|
|
211
111
|
|
|
212
|
-
|
|
213
|
-
|
|
112
|
+
// if (this.#model.name === 'Person') console.log(this.#model.referentialIntegrity);
|
|
113
|
+
return txn.run(Util.promiseChain(this.#model.referentialIntegrity.map(({ model, field, fieldRef, isArray, op }) => () => {
|
|
114
|
+
const fieldStr = fieldRef ? `${field}.${fieldRef}` : `${field.name}`;
|
|
115
|
+
const $where = { [fieldStr]: id };
|
|
214
116
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
117
|
+
switch (op) {
|
|
118
|
+
case 'cascade': return isArray ? txn.match(model).where($where).pull(fieldStr, id) : txn.match(model).where($where).remove();
|
|
119
|
+
case 'nullify': return txn.match(model).where($where).save({ [fieldStr]: null });
|
|
120
|
+
case 'restrict': return txn.match(model).where($where).count().then(count => (count ? Promise.reject(new Error('Restricted')) : count));
|
|
121
|
+
case 'defer': return Promise.resolve(); // Used for embedded models (could be improved)
|
|
122
|
+
default: throw new Error(`Unknown onDelete operator: '${op}'`);
|
|
123
|
+
}
|
|
124
|
+
})));
|
|
220
125
|
}
|
|
221
126
|
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const QueryResolver = require('./QueryResolver');
|
|
2
|
+
|
|
3
|
+
module.exports = class QueryResolverTransaction extends QueryResolver {
|
|
4
|
+
#config;
|
|
5
|
+
|
|
6
|
+
constructor(config) {
|
|
7
|
+
super(config);
|
|
8
|
+
this.#config = config;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
terminate() {
|
|
12
|
+
return this.#config.transaction.then((transaction) => {
|
|
13
|
+
return super.terminate(super.options(transaction));
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
};
|