@coderich/autograph 0.13.21 → 0.13.22
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 +2 -2
- package/src/data/Emitter.js +26 -9
- package/src/data/Resolver.js +16 -32
- package/src/query/Query.js +4 -3
- package/src/query/QueryResolver.js +1 -1
- package/src/service/AppService.js +6 -7
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.22",
|
|
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": "1.0.
|
|
18
|
+
"@coderich/util": "1.0.3",
|
|
19
19
|
"@graphql-tools/merge": "9.0.0",
|
|
20
20
|
"@graphql-tools/resolvers-composition": "7.0.0",
|
|
21
21
|
"@hapi/boom": "10.0.1",
|
package/src/data/Emitter.js
CHANGED
|
@@ -12,20 +12,21 @@ class Emitter extends EventEmitter {
|
|
|
12
12
|
emit(event, data) {
|
|
13
13
|
// Here we pull out functions with "next" vs those without
|
|
14
14
|
const [basicFuncs, nextFuncs] = this.rawListeners(event).reduce((prev, wrapper) => {
|
|
15
|
-
const listener = wrapper
|
|
15
|
+
const { listener = wrapper } = wrapper;
|
|
16
16
|
const isBasic = listener.length < 2;
|
|
17
|
+
wrapper.priority = listener.priority ?? 0;
|
|
17
18
|
return prev[isBasic ? 0 : 1].push(wrapper) && prev;
|
|
18
19
|
}, [[], []]);
|
|
19
20
|
|
|
20
21
|
return new Promise((resolve, reject) => {
|
|
21
22
|
// Basic functions run first; if they return a value they abort the flow of execution
|
|
22
|
-
basicFuncs.forEach((fn) => {
|
|
23
|
+
basicFuncs.sort(Emitter.sort).forEach((fn) => {
|
|
23
24
|
const value = fn(data);
|
|
24
25
|
if (value !== undefined && !(value instanceof Promise)) throw new AbortEarlyError(value);
|
|
25
26
|
});
|
|
26
27
|
|
|
27
28
|
// Next functions are async and control the timing of the next phase
|
|
28
|
-
Promise.all(nextFuncs.map((fn) => {
|
|
29
|
+
Promise.all(nextFuncs.sort(Emitter.sort).map((fn) => {
|
|
29
30
|
return new Promise((next) => {
|
|
30
31
|
Promise.resolve(fn(data, next));
|
|
31
32
|
}).then((result) => {
|
|
@@ -38,35 +39,45 @@ class Emitter extends EventEmitter {
|
|
|
38
39
|
});
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
on(event, listener, priority = 0) {
|
|
43
|
+
listener.priority = priority;
|
|
44
|
+
return super.on(event, listener);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
prependListener(event, listener, priority = 0) {
|
|
48
|
+
listener.priority = priority;
|
|
49
|
+
return super.prependListener(event, listener);
|
|
50
|
+
}
|
|
51
|
+
|
|
41
52
|
/**
|
|
42
53
|
* Syntactic sugar to listen on query keys
|
|
43
54
|
*/
|
|
44
55
|
onKeys(...args) {
|
|
45
|
-
return this.#createWrapper(...args,
|
|
56
|
+
return this.#createWrapper('key', false, ...args,);
|
|
46
57
|
}
|
|
47
58
|
|
|
48
59
|
/**
|
|
49
60
|
* Syntactic sugar to listen once on query keys
|
|
50
61
|
*/
|
|
51
62
|
onceKeys(...args) {
|
|
52
|
-
return this.#createWrapper(
|
|
63
|
+
return this.#createWrapper('key', true, ...args);
|
|
53
64
|
}
|
|
54
65
|
|
|
55
66
|
/**
|
|
56
67
|
* Syntactic sugar to listen on query models
|
|
57
68
|
*/
|
|
58
69
|
onModels(...args) {
|
|
59
|
-
return this.#createWrapper(
|
|
70
|
+
return this.#createWrapper('model', false, ...args);
|
|
60
71
|
}
|
|
61
72
|
|
|
62
73
|
/**
|
|
63
74
|
* Syntactic sugar to listen once on query models
|
|
64
75
|
*/
|
|
65
76
|
onceModels(...args) {
|
|
66
|
-
return this.#createWrapper(
|
|
77
|
+
return this.#createWrapper('model', true, ...args);
|
|
67
78
|
}
|
|
68
79
|
|
|
69
|
-
#createWrapper(eventName, arr, listener,
|
|
80
|
+
#createWrapper(prop, once, eventName, arr, listener, priority) {
|
|
70
81
|
arr = Util.ensureArray(arr);
|
|
71
82
|
|
|
72
83
|
const wrapper = listener.length < 2 ? (event) => {
|
|
@@ -83,7 +94,13 @@ class Emitter extends EventEmitter {
|
|
|
83
94
|
return next();
|
|
84
95
|
};
|
|
85
96
|
|
|
86
|
-
return this.on(eventName, wrapper);
|
|
97
|
+
return this.on(eventName, wrapper, priority);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
static sort(a, b) {
|
|
101
|
+
if (a.priority > b.priority) return -1;
|
|
102
|
+
if (a.priority < b.priority) return 1;
|
|
103
|
+
return 0;
|
|
87
104
|
}
|
|
88
105
|
}
|
|
89
106
|
|
package/src/data/Resolver.js
CHANGED
|
@@ -189,19 +189,11 @@ module.exports = class Resolver {
|
|
|
189
189
|
*/
|
|
190
190
|
async resolve(query) {
|
|
191
191
|
let thunk;
|
|
192
|
-
const
|
|
193
|
-
const oquery = Object.defineProperties(tquery.toObject(), {
|
|
194
|
-
changeset: {
|
|
195
|
-
get: function get() {
|
|
196
|
-
return oquery.crud === 'update' ? Util.changeset(this.doc, this.input) : undefined;
|
|
197
|
-
},
|
|
198
|
-
},
|
|
199
|
-
});
|
|
200
|
-
const model = this.#schema.models[oquery.model];
|
|
192
|
+
const { model, doc, crud, isMutation, flags } = query.toObject();
|
|
201
193
|
const currSession = this.#sessions.slice(-1).pop();
|
|
202
194
|
|
|
203
|
-
if (
|
|
204
|
-
thunk =
|
|
195
|
+
if (isMutation) {
|
|
196
|
+
thunk = tquery => this.#schema.models[model].source.client.resolve(tquery.toDriver().toObject()).then((results) => {
|
|
205
197
|
// We clear the cache immediately (regardless if we're in transaction or not)
|
|
206
198
|
this.clear(model);
|
|
207
199
|
|
|
@@ -209,16 +201,16 @@ module.exports = class Resolver {
|
|
|
209
201
|
currSession?.thunks.push(...this.#sessions.map(s => () => s.parent.clear(model)));
|
|
210
202
|
|
|
211
203
|
// Return results
|
|
212
|
-
return
|
|
204
|
+
return crud === 'delete' ? doc : results;
|
|
213
205
|
});
|
|
214
206
|
} else {
|
|
215
|
-
thunk =
|
|
207
|
+
thunk = tquery => this.#dataLoaders[model].resolve(tquery);
|
|
216
208
|
}
|
|
217
209
|
|
|
218
|
-
return this.#createSystemEvent(
|
|
219
|
-
return thunk().then((result) => {
|
|
220
|
-
if (
|
|
221
|
-
return
|
|
210
|
+
return this.#createSystemEvent(query, (tquery) => {
|
|
211
|
+
return thunk(tquery).then((result) => {
|
|
212
|
+
if (flags?.required && (result == null || result?.length === 0)) throw Boom.notFound();
|
|
213
|
+
return crud === 'delete' ? result : this.toResultSet(model, result);
|
|
222
214
|
});
|
|
223
215
|
});
|
|
224
216
|
}
|
|
@@ -274,8 +266,8 @@ module.exports = class Resolver {
|
|
|
274
266
|
}, {});
|
|
275
267
|
}
|
|
276
268
|
|
|
277
|
-
#createSystemEvent(
|
|
278
|
-
const query =
|
|
269
|
+
#createSystemEvent($query, thunk = () => {}) {
|
|
270
|
+
const query = $query.toObject();
|
|
279
271
|
const type = query.isMutation ? 'Mutation' : 'Query';
|
|
280
272
|
const event = { schema: this.#schema, context: this.#context, resolver: this, query };
|
|
281
273
|
|
|
@@ -287,23 +279,15 @@ module.exports = class Resolver {
|
|
|
287
279
|
event.input = event.args?.input;
|
|
288
280
|
|
|
289
281
|
return Emitter.emit(`pre${type}`, event).then(async (resultEarly) => {
|
|
290
|
-
if (resultEarly !== undefined) return resultEarly;
|
|
291
|
-
if (Util.isEqual(
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
return thunk().then((result) => {
|
|
282
|
+
if (resultEarly !== undefined) return resultEarly; // Nothing to validate/transform
|
|
283
|
+
// if (query.crud === 'update' && Util.isEqual({ added: {}, updated: {}, deleted: {} }, Util.changeset(query.doc, query.input))) return query.doc;
|
|
284
|
+
const tquery = await $query.transform();
|
|
285
|
+
// await Emitter.emit('validate', event); // We need to re-connect tquery to event
|
|
286
|
+
return thunk(tquery).then((result) => {
|
|
295
287
|
event.result = result; // backwards compat
|
|
296
288
|
query.result = result;
|
|
297
289
|
return Emitter.emit(`post${type}`, event);
|
|
298
290
|
});
|
|
299
|
-
}).then((result = query.result) => {
|
|
300
|
-
event.result = result; // backwards compat
|
|
301
|
-
query.result = result;
|
|
302
|
-
return Emitter.emit('preResponse', event);
|
|
303
|
-
}).then((result = query.result) => {
|
|
304
|
-
event.result = result; // backwards compat
|
|
305
|
-
query.result = result;
|
|
306
|
-
return Emitter.emit('postResponse', event);
|
|
307
291
|
}).then((result = query.result) => result).catch((e) => {
|
|
308
292
|
const { data = {} } = e;
|
|
309
293
|
throw Boom.boomify(e, { data: { ...event, ...data } });
|
package/src/query/Query.js
CHANGED
|
@@ -49,11 +49,12 @@ module.exports = class Query {
|
|
|
49
49
|
* Run a portion of the pipeline against a data set
|
|
50
50
|
*/
|
|
51
51
|
pipeline(target, data, transformers) {
|
|
52
|
-
data = Util.unflatten(data);
|
|
52
|
+
data = Util.unflatten(data, { safe: true });
|
|
53
53
|
const crudMap = { create: ['$construct', '$serialize'], update: ['$restruct', '$serialize'] };
|
|
54
54
|
const crudLines = crudMap[this.#query.crud] || [];
|
|
55
55
|
const transformerMap = { where: ['$cast', '$instruct', '$serialize'], sort: [], input: [] };
|
|
56
|
-
if (this.#query.isMutation) transformerMap.input = ['$default', '$cast', '$normalize', '$instruct', ...crudLines];
|
|
56
|
+
if (this.#query.isMutation) transformerMap.input = ['$default', '$cast', '$normalize', '$instruct', ...crudLines, '$finalize'];
|
|
57
|
+
// if (this.#query.crud === 'create') transformerMap.input.unshift('$default'); // Cant because embedded documents on update are really "creates"
|
|
57
58
|
transformers = transformers || transformerMap[target];
|
|
58
59
|
return this.#pipeline(this.#query, target, this.#model, data, transformers.map(el => Pipeline[el]));
|
|
59
60
|
}
|
|
@@ -128,7 +129,7 @@ module.exports = class Query {
|
|
|
128
129
|
const { where = {}, sort = {} } = query;
|
|
129
130
|
const flatSort = Util.flatten(sort, { safe: true });
|
|
130
131
|
const flatWhere = Util.flatten(where, { safe: true });
|
|
131
|
-
const $sort = Util.unflatten(Object.keys(flatSort).reduce((prev, key) => Object.assign(prev, { [key]: {} }), {}));
|
|
132
|
+
const $sort = Util.unflatten(Object.keys(flatSort).reduce((prev, key) => Object.assign(prev, { [key]: {} }), {}), { safe: true });
|
|
132
133
|
|
|
133
134
|
//
|
|
134
135
|
query.sort = this.#model.walk(sort, (node) => {
|
|
@@ -34,7 +34,7 @@ module.exports = class QueryResolver extends QueryBuilder {
|
|
|
34
34
|
}
|
|
35
35
|
case 'updateOne': {
|
|
36
36
|
return this.#get(query).then((doc) => {
|
|
37
|
-
const merged = mergeDeep({}, Util.unflatten(doc), Util.unflatten(input));
|
|
37
|
+
const merged = mergeDeep({}, Util.unflatten(doc, { safe: true }), Util.unflatten(input, { safe: true }));
|
|
38
38
|
return this.#resolver.resolve(query.clone({ doc, input: merged }));
|
|
39
39
|
});
|
|
40
40
|
}
|
|
@@ -11,8 +11,7 @@ exports.isGlob = str => PicoMatch.scan(str).isGlob;
|
|
|
11
11
|
exports.globToRegex = (glob, options = {}) => PicoMatch.makeRe(glob, { nocase: true, ...options, expandRange: (a, b) => `(${FillRange(a, b, { toRegex: true })})` });
|
|
12
12
|
|
|
13
13
|
const smartMerge = (target, source, options) => source;
|
|
14
|
-
exports.
|
|
15
|
-
exports.isLeafValue = value => Array.isArray(value) || value instanceof Date || ObjectId.isValid(value) || exports.isScalarValue(value);
|
|
14
|
+
exports.isLeafValue = value => Array.isArray(value) || value instanceof Date || ObjectId.isValid(value) || Util.isScalarValue(value);
|
|
16
15
|
exports.mergeDeep = (...args) => DeepMerge.all(args, { isMergeableObject: obj => (Util.isPlainObjectOrArray(obj)), arrayMerge: smartMerge });
|
|
17
16
|
exports.hashObject = obj => ObjectHash(obj, { respectType: false, respectFunctionNames: false, respectFunctionProperties: false, unorderedArrays: true, ignoreUnknown: true, replacer: r => (ObjectId.isValid(r) ? `${r}` : r) });
|
|
18
17
|
exports.fromGUID = guid => Buffer.from(`${guid}`, 'base64').toString('ascii').split(',');
|
|
@@ -39,8 +38,8 @@ exports.getGQLSelectFields = (model, info) => {
|
|
|
39
38
|
return Object.keys(node || fields);
|
|
40
39
|
};
|
|
41
40
|
|
|
42
|
-
exports.removeUndefinedDeep = (obj) => {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
};
|
|
41
|
+
// exports.removeUndefinedDeep = (obj) => {
|
|
42
|
+
// return Util.unflatten(Object.entries(Util.flatten(obj)).reduce((prev, [key, value]) => {
|
|
43
|
+
// return value === undefined ? prev : Object.assign(prev, { [key]: value });
|
|
44
|
+
// }, {}));
|
|
45
|
+
// };
|