@coderich/autograph 0.9.12 → 0.10.0
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/CHANGELOG.md +5 -0
- package/package.json +7 -8
- package/src/.DS_Store +0 -0
- package/src/core/Resolver.js +3 -1
- package/src/core/ServerResolver.js +7 -93
- package/src/data/.DS_Store +0 -0
- package/src/data/DataLoader.js +28 -26
- package/src/data/Model.js +22 -10
- package/src/data/stream/DataHydrator.js +58 -0
- package/src/data/stream/ResultSet.js +34 -0
- package/src/data/stream/ResultSetItem.js +158 -0
- package/src/data/stream/ResultSetItemProxy.js +161 -0
- package/src/driver/MongoDriver.js +42 -18
- package/src/graphql/ast/Field.js +1 -2
- package/src/graphql/ast/Node.js +0 -7
- package/src/graphql/ast/SchemaDecorator.js +5 -2
- package/src/graphql/extension/api.js +1 -16
- package/src/graphql/extension/framework.js +0 -1
- package/src/query/Query.js +1 -19
- package/src/query/QueryBuilder.js +3 -2
- package/src/query/QueryResolver.js +6 -7
- package/src/service/decorator.service.js +21 -288
- package/src/service/graphql.service.js +1 -1
- package/src/data/ResultSet2.js +0 -210
- package/src/data/ResultSet3.js +0 -186
- package/src/graphql/core/.DS_Store +0 -0
- package/src/graphql/core/Field.js +0 -20
- package/src/graphql/core/GraphQL.js +0 -21
- package/src/graphql/core/Model.js +0 -23
- package/src/graphql/core/Node.js +0 -34
- package/src/graphql/core/Schema.js +0 -63
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
const { get } = require('lodash');
|
|
2
|
+
const ResultSet = require('./ResultSet');
|
|
3
|
+
const { map, keyPaths, mapPromise, toGUID, hashObject } = require('../../service/app.service');
|
|
4
|
+
|
|
5
|
+
module.exports = class ResultSetItem {
|
|
6
|
+
constructor(query, doc) {
|
|
7
|
+
if (doc == null) return doc;
|
|
8
|
+
|
|
9
|
+
const cache = new Map();
|
|
10
|
+
const { resolver, model, sort } = query.toObject();
|
|
11
|
+
const fields = model.getFields().filter(f => f.getName() !== 'id');
|
|
12
|
+
|
|
13
|
+
const proxy = new Proxy(doc, {
|
|
14
|
+
get(target, prop, rec) {
|
|
15
|
+
const value = Reflect.get(target, prop, rec);
|
|
16
|
+
if (typeof value === 'function') return value.bind(target);
|
|
17
|
+
|
|
18
|
+
if (cache.has(prop)) return cache.get(prop);
|
|
19
|
+
|
|
20
|
+
const field = fields.find(f => `${f}` === prop);
|
|
21
|
+
|
|
22
|
+
if (field) {
|
|
23
|
+
let $value = field.deserialize(query, value);
|
|
24
|
+
|
|
25
|
+
if ($value != null && field.isEmbedded()) {
|
|
26
|
+
const newQuery = query.model(field.getModelRef());
|
|
27
|
+
$value = new ResultSet(newQuery, map($value, v => new ResultSetItem(newQuery, v)), false);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
cache.set(prop, $value);
|
|
31
|
+
return $value;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return value;
|
|
35
|
+
},
|
|
36
|
+
set(target, prop, value, receiver) {
|
|
37
|
+
cache.set(prop, value);
|
|
38
|
+
return Reflect.set(target, prop, value);
|
|
39
|
+
},
|
|
40
|
+
deleteProperty(target, prop) {
|
|
41
|
+
cache.delete(prop);
|
|
42
|
+
return Reflect.delete(target, prop);
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const definition = fields.reduce((prev, field) => {
|
|
47
|
+
const name = field.getName();
|
|
48
|
+
const $name = `$${name}`;
|
|
49
|
+
|
|
50
|
+
// Hydrated field attributes
|
|
51
|
+
prev[`$${name}`] = {
|
|
52
|
+
get() {
|
|
53
|
+
return (args = {}) => {
|
|
54
|
+
// Ensure where clause
|
|
55
|
+
args.where = args.where || {};
|
|
56
|
+
|
|
57
|
+
// Cache
|
|
58
|
+
const cacheKey = `${$name}-${hashObject(args)}`;
|
|
59
|
+
if (cache.has(cacheKey)) return cache.get(cacheKey);
|
|
60
|
+
|
|
61
|
+
const promise = new Promise((resolve, reject) => {
|
|
62
|
+
(() => {
|
|
63
|
+
const $value = this[name];
|
|
64
|
+
|
|
65
|
+
if (field.isScalar() || field.isEmbedded()) return Promise.resolve($value);
|
|
66
|
+
|
|
67
|
+
const modelRef = field.getModelRef();
|
|
68
|
+
|
|
69
|
+
if (field.isArray()) {
|
|
70
|
+
if (field.isVirtual()) {
|
|
71
|
+
args.where[[field.getVirtualField()]] = this.id; // Is where[[field.getVirtualField()]] correct?
|
|
72
|
+
return resolver.match(modelRef).merge(args).many();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Not a "required" query + strip out nulls
|
|
76
|
+
args.where.id = $value;
|
|
77
|
+
return resolver.match(modelRef).merge(args).many();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (field.isVirtual()) {
|
|
81
|
+
args.where[[field.getVirtualField()]] = this.id;
|
|
82
|
+
return resolver.match(modelRef).merge(args).one();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return resolver.match(modelRef).id($value).one({ required: field.isRequired() });
|
|
86
|
+
})().then((results) => {
|
|
87
|
+
if (results == null) return field.resolve(query, results); // Allow field to determine
|
|
88
|
+
return mapPromise(results, result => field.resolve(query, result)).then(() => results); // Resolve the inside fields but still return "results"!!!!
|
|
89
|
+
}).then((resolved) => {
|
|
90
|
+
resolve(resolved);
|
|
91
|
+
}).catch((e) => {
|
|
92
|
+
reject(e);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
cache.set(cacheKey, promise);
|
|
97
|
+
return promise;
|
|
98
|
+
};
|
|
99
|
+
},
|
|
100
|
+
enumerable: false,
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// Field count (let's assume it's a Connection Type - meaning dont try with anything else)
|
|
104
|
+
prev[`$${name}:count`] = {
|
|
105
|
+
get() {
|
|
106
|
+
return (q = {}) => {
|
|
107
|
+
q.where = q.where || {};
|
|
108
|
+
if (field.isVirtual()) q.where[field.getVirtualField()] = this.id;
|
|
109
|
+
else q.where.id = this[name];
|
|
110
|
+
return resolver.match(field.getModelRef()).merge(q).count();
|
|
111
|
+
};
|
|
112
|
+
},
|
|
113
|
+
enumerable: false,
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
return prev;
|
|
117
|
+
}, {
|
|
118
|
+
$id: {
|
|
119
|
+
get() { return toGUID(model.getName(), this.id); },
|
|
120
|
+
enumerable: false,
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
$$cursor: {
|
|
124
|
+
get() {
|
|
125
|
+
const sortPaths = keyPaths(sort);
|
|
126
|
+
const sortValues = sortPaths.reduce((prv, path) => Object.assign(prv, { [path]: get(this, path) }), {});
|
|
127
|
+
const sortJSON = JSON.stringify(sortValues);
|
|
128
|
+
return Buffer.from(sortJSON).toString('base64');
|
|
129
|
+
},
|
|
130
|
+
enumerable: false,
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
$$model: {
|
|
134
|
+
value: model,
|
|
135
|
+
enumerable: false,
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
$$isResultSetItem: {
|
|
139
|
+
value: true,
|
|
140
|
+
enumerable: false,
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
$$save: {
|
|
144
|
+
get() { return input => resolver.match(model).id(this.id).save({ ...this, ...input }); },
|
|
145
|
+
enumerable: false,
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
$$remove: {
|
|
149
|
+
get() { return () => resolver.match(model).id(this.id).remove(); },
|
|
150
|
+
enumerable: false,
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
$$delete: {
|
|
154
|
+
get() { return () => resolver.match(model).id(this.id).delete(); },
|
|
155
|
+
enumerable: false,
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
return Object.defineProperties(proxy, definition);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
@@ -3,16 +3,15 @@ const { MongoClient, ObjectID } = require('mongodb');
|
|
|
3
3
|
const { proxyDeep, toKeyObj, globToRegex, proxyPromise, isScalarDataType, promiseRetry } = require('../service/app.service');
|
|
4
4
|
|
|
5
5
|
module.exports = class MongoDriver {
|
|
6
|
-
constructor(config
|
|
6
|
+
constructor(config) {
|
|
7
7
|
this.config = config;
|
|
8
|
-
this.schema = schema;
|
|
9
8
|
this.connection = this.connect();
|
|
10
9
|
this.getDirectives = () => get(config, 'directives', {});
|
|
11
10
|
}
|
|
12
11
|
|
|
13
12
|
connect() {
|
|
14
13
|
const { uri, options = {} } = this.config;
|
|
15
|
-
options.ignoreUndefined =
|
|
14
|
+
options.ignoreUndefined = false;
|
|
16
15
|
return MongoClient.connect(uri, options);
|
|
17
16
|
}
|
|
18
17
|
|
|
@@ -25,7 +24,8 @@ module.exports = class MongoDriver {
|
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
query(collection, method, ...args) {
|
|
28
|
-
if (has(args[args.length - 1], 'debug')) console.log(collection, method, JSON.stringify(args));
|
|
27
|
+
if (has(args[args.length - 1], 'debug')) console.log(collection, method, JSON.stringify(args, null, 2));
|
|
28
|
+
if (method === 'aggregate') args.splice(2);
|
|
29
29
|
return this.raw(collection)[method](...args);
|
|
30
30
|
}
|
|
31
31
|
|
|
@@ -36,18 +36,21 @@ module.exports = class MongoDriver {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
findOne(query) {
|
|
39
|
-
return this.findMany(Object.assign(query, { first: 1 })).then(
|
|
39
|
+
return this.findMany(Object.assign(query, { first: 1 })).then((stream) => {
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
stream.on('data', resolve);
|
|
42
|
+
stream.on('error', reject);
|
|
43
|
+
stream.on('end', resolve);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
40
46
|
}
|
|
41
47
|
|
|
42
48
|
findMany(query) {
|
|
43
|
-
const { model, options = {},
|
|
49
|
+
const { model, options = {}, flags } = query;
|
|
44
50
|
Object.assign(options, this.config.query || {});
|
|
45
51
|
|
|
46
52
|
return this.query(model, 'aggregate', MongoDriver.aggregateQuery(query), options, flags).then((cursor) => {
|
|
47
|
-
return cursor.
|
|
48
|
-
if (last) return results.splice(-last);
|
|
49
|
-
return results;
|
|
50
|
-
});
|
|
53
|
+
return cursor.stream();
|
|
51
54
|
});
|
|
52
55
|
}
|
|
53
56
|
|
|
@@ -63,7 +66,7 @@ module.exports = class MongoDriver {
|
|
|
63
66
|
}
|
|
64
67
|
|
|
65
68
|
createOne({ model, input, options, flags }) {
|
|
66
|
-
return this.query(model, 'insertOne', input, options, flags).then(result => Object.assign(input, {
|
|
69
|
+
return this.query(model, 'insertOne', input, options, flags).then(result => Object.assign(input, { id: result.insertedId }));
|
|
67
70
|
}
|
|
68
71
|
|
|
69
72
|
updateOne({ model, where, $doc, options, flags }) {
|
|
@@ -76,7 +79,7 @@ module.exports = class MongoDriver {
|
|
|
76
79
|
}
|
|
77
80
|
|
|
78
81
|
deleteOne({ model, where, options, flags }) {
|
|
79
|
-
return this.query(model, 'deleteOne', where, options, flags);
|
|
82
|
+
return this.query(model, 'deleteOne', where, options, flags).then(() => true);
|
|
80
83
|
}
|
|
81
84
|
|
|
82
85
|
dropModel(model) {
|
|
@@ -148,20 +151,38 @@ module.exports = class MongoDriver {
|
|
|
148
151
|
}
|
|
149
152
|
|
|
150
153
|
static getAddFields(query) {
|
|
151
|
-
const {
|
|
154
|
+
const { shape, where } = query;
|
|
152
155
|
|
|
153
|
-
return
|
|
154
|
-
const value = where[
|
|
156
|
+
return shape.reduce((prev, { from, type }) => {
|
|
157
|
+
const value = where[from];
|
|
155
158
|
if (value === undefined) return prev;
|
|
156
159
|
if (!isScalarDataType(type)) return prev;
|
|
157
160
|
const stype = String((type === 'Float' || type === 'Int' ? 'Number' : type)).toLowerCase();
|
|
158
161
|
if (String(typeof value) === `${stype}`) return prev;
|
|
159
|
-
return Object.assign(prev, { [
|
|
162
|
+
return Object.assign(prev, { [from]: { $toString: `$${from}` } });
|
|
160
163
|
}, {});
|
|
161
164
|
}
|
|
162
165
|
|
|
166
|
+
static getProjectFields(parentShape, currentShape = { _id: 0, id: '$_id' }, isEmbedded, isEmbeddedArray, path = []) {
|
|
167
|
+
return parentShape.reduce((project, value) => {
|
|
168
|
+
const { from, to, shape: subShape, isArray } = value;
|
|
169
|
+
const $key = isEmbedded && isEmbeddedArray ? `$$embedded.${from}` : `$${path.concat(from).join('.')}`;
|
|
170
|
+
|
|
171
|
+
if (subShape) {
|
|
172
|
+
const $project = MongoDriver.getProjectFields(subShape, {}, true, isArray, path.concat(from));
|
|
173
|
+
Object.assign(project, { [to]: isArray ? { $map: { input: $key, as: 'embedded', in: $project } } : $project });
|
|
174
|
+
} else if (isEmbedded) {
|
|
175
|
+
Object.assign(project, { [to]: $key });
|
|
176
|
+
} else {
|
|
177
|
+
Object.assign(project, { [to]: from === to ? 1 : $key });
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return project;
|
|
181
|
+
}, currentShape);
|
|
182
|
+
}
|
|
183
|
+
|
|
163
184
|
static aggregateQuery(query, count = false) {
|
|
164
|
-
const { where: $match, sort, skip, limit, joins } = query;
|
|
185
|
+
const { where: $match, sort = {}, skip, limit, joins, shape, after, before, first } = query;
|
|
165
186
|
const $aggregate = [{ $match }];
|
|
166
187
|
|
|
167
188
|
// Used for $regex matching
|
|
@@ -190,10 +211,13 @@ module.exports = class MongoDriver {
|
|
|
190
211
|
if (limit) $aggregate.push({ $limit: limit });
|
|
191
212
|
|
|
192
213
|
// Pagination
|
|
193
|
-
const { after, before, first } = query;
|
|
194
214
|
if (after) $aggregate.push({ $match: { $or: Object.entries(after).reduce((prev, [key, value]) => prev.concat({ [key]: { [sort[key] === 1 ? '$gte' : '$lte']: value } }), []) } });
|
|
195
215
|
if (before) $aggregate.push({ $match: { $or: Object.entries(before).reduce((prev, [key, value]) => prev.concat({ [key]: { [sort[key] === 1 ? '$lte' : '$gte']: value } }), []) } });
|
|
196
216
|
if (first) $aggregate.push({ $limit: first });
|
|
217
|
+
|
|
218
|
+
// Projection
|
|
219
|
+
const $project = MongoDriver.getProjectFields(shape);
|
|
220
|
+
$aggregate.push({ $project });
|
|
197
221
|
}
|
|
198
222
|
|
|
199
223
|
return $aggregate;
|
package/src/graphql/ast/Field.js
CHANGED
|
@@ -145,12 +145,11 @@ module.exports = class Field extends Node {
|
|
|
145
145
|
// GQL Schema Methods
|
|
146
146
|
getGQLType(suffix, options = {}) {
|
|
147
147
|
let type = this.getType();
|
|
148
|
-
// if (suffix === 'InputUpdate' && this.isSpliceable()) suffix = 'InputSplice';
|
|
149
148
|
const modelType = `${type}${suffix}`;
|
|
150
149
|
if (suffix && !this.isScalar()) type = this.isEmbedded() ? modelType : 'ID';
|
|
151
150
|
type = this.isArray() ? `[${type}${this.isArrayElementRequired() ? '!' : ''}]` : type;
|
|
152
151
|
if (!suffix && this.isRequired()) type += '!';
|
|
153
|
-
if (
|
|
152
|
+
if (suffix === 'InputCreate' && this.isRequired() && !this.isDefaulted()) type += '!';
|
|
154
153
|
return type;
|
|
155
154
|
}
|
|
156
155
|
|
package/src/graphql/ast/Node.js
CHANGED
|
@@ -208,13 +208,6 @@ module.exports = class Node {
|
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
/**
|
|
212
|
-
* Is this API embedded in another document
|
|
213
|
-
*/
|
|
214
|
-
isEmbeddedApi() {
|
|
215
|
-
return this.isEmbedded() && Boolean(this.getDirectiveArg('field', 'embedApi'));
|
|
216
|
-
}
|
|
217
|
-
|
|
218
211
|
/**
|
|
219
212
|
* Can the field be changed after it's set
|
|
220
213
|
*/
|
|
@@ -35,6 +35,9 @@ module.exports = class SchemaDecorator extends TypeDefApi {
|
|
|
35
35
|
* Synchronously merge a schema
|
|
36
36
|
*/
|
|
37
37
|
mergeSchema(schema, options = {}) {
|
|
38
|
+
// Ensure this is a schema of sorts otherwise skip it
|
|
39
|
+
if (typeof schema !== 'string' && ['context', 'typeDefs', 'resolvers', 'schemaDirectives'].every(key => !schema[key])) return this;
|
|
40
|
+
|
|
38
41
|
// Here we want to normalize the schema into the shape { context, typeDefs, resolvers, schemaDirectives }
|
|
39
42
|
// We do NOT want to modify the schema object because that may cause unwanted side-effects.
|
|
40
43
|
const normalizedSchema = { ...schema };
|
|
@@ -96,8 +99,8 @@ module.exports = class SchemaDecorator extends TypeDefApi {
|
|
|
96
99
|
*/
|
|
97
100
|
decorate() {
|
|
98
101
|
this.initialize();
|
|
99
|
-
this.mergeSchema(frameworkExt(this));
|
|
100
|
-
this.mergeSchema(typeExt(this));
|
|
102
|
+
this.mergeSchema(frameworkExt(this), { passive: true });
|
|
103
|
+
this.mergeSchema(typeExt(this), { passive: true });
|
|
101
104
|
this.initialize();
|
|
102
105
|
this.mergeSchema(apiExt(this), { passive: true });
|
|
103
106
|
this.finalize();
|
|
@@ -3,7 +3,7 @@ const { Kind } = require('graphql');
|
|
|
3
3
|
const ServerResolver = require('../../core/ServerResolver');
|
|
4
4
|
const { ucFirst, fromGUID } = require('../../service/app.service');
|
|
5
5
|
const { findGQLModels } = require('../../service/schema.service');
|
|
6
|
-
const { makeCreateAPI, makeReadAPI, makeUpdateAPI, makeDeleteAPI, makeSubscriptionAPI,
|
|
6
|
+
const { makeCreateAPI, makeReadAPI, makeUpdateAPI, makeDeleteAPI, makeSubscriptionAPI, makeQueryResolver, makeMutationResolver } = require('../../service/decorator.service');
|
|
7
7
|
|
|
8
8
|
const interfaceKinds = [Kind.INTERFACE_TYPE_DEFINITION, Kind.INTERFACE_TYPE_EXTENSION];
|
|
9
9
|
|
|
@@ -25,8 +25,6 @@ module.exports = (schema) => {
|
|
|
25
25
|
const createModels = findGQLModels('c', markedModels, allModels);
|
|
26
26
|
const readModels = findGQLModels('r', markedModels, allModels);
|
|
27
27
|
const updateModels = findGQLModels('u', markedModels, allModels);
|
|
28
|
-
const deleteModels = findGQLModels('d', markedModels, allModels);
|
|
29
|
-
const spliceModels = [...new Set([...createModels, ...updateModels, ...deleteModels])];
|
|
30
28
|
|
|
31
29
|
return ({
|
|
32
30
|
typeDefs: [
|
|
@@ -40,7 +38,6 @@ module.exports = (schema) => {
|
|
|
40
38
|
input ${model.getName()}InputUpdate {
|
|
41
39
|
${model.getFields().filter(field => field.hasGQLScope('u') && !field.isVirtual()).map(field => `${field.getName()}: ${field.getGQLType('InputUpdate')}`)}
|
|
42
40
|
}
|
|
43
|
-
# ${makeInputSplice(model)}
|
|
44
41
|
`),
|
|
45
42
|
|
|
46
43
|
...readModels.map(model => `
|
|
@@ -50,19 +47,14 @@ module.exports = (schema) => {
|
|
|
50
47
|
input ${model.getName()}InputSort {
|
|
51
48
|
${getGQLWhereFields(model).map(field => `${field.getName()}: ${field.getModelRef() ? `${ucFirst(field.getDataRef())}InputSort` : 'SortOrderEnum'}`)}
|
|
52
49
|
}
|
|
53
|
-
`),
|
|
54
|
-
|
|
55
|
-
...readModels.map(model => `
|
|
56
50
|
extend ${interfaceKinds.indexOf(model.getKind()) > -1 ? 'interface' : 'type'} ${model.getName()} {
|
|
57
51
|
${model.getFields().filter(field => field.hasGQLScope('r')).map(field => `${field.getName()}${field.getExtendArgs()}: ${field.getPayloadType()}`)}
|
|
58
52
|
}
|
|
59
|
-
|
|
60
53
|
type ${model.getName()}Connection {
|
|
61
54
|
pageInfo: PageInfo!
|
|
62
55
|
edges: [${model.getName()}Edge]
|
|
63
56
|
count: Int!
|
|
64
57
|
}
|
|
65
|
-
|
|
66
58
|
type ${model.getName()}Edge {
|
|
67
59
|
node: ${model.getName()}
|
|
68
60
|
cursor: String!
|
|
@@ -105,13 +97,6 @@ module.exports = (schema) => {
|
|
|
105
97
|
${model.getFields().filter(field => field.hasGQLScope('r')).map(field => `${field.getName()}: ${field.getPayloadType()}`)}
|
|
106
98
|
}
|
|
107
99
|
`),
|
|
108
|
-
|
|
109
|
-
...spliceModels.map(model => `
|
|
110
|
-
#input ${model.getName()}InputSplice {
|
|
111
|
-
# with: ${model}InputWhere
|
|
112
|
-
# put: ${model}InputUpdate
|
|
113
|
-
#}
|
|
114
|
-
`),
|
|
115
100
|
].concat([
|
|
116
101
|
`type PageInfo {
|
|
117
102
|
startCursor: String!
|
|
@@ -40,7 +40,6 @@ module.exports = (schema) => {
|
|
|
40
40
|
fieldScope: AutoGraphMixed # Dictate how a FIELD may use me
|
|
41
41
|
persist: Boolean # Persist this field (default true)
|
|
42
42
|
default: AutoGraphMixed # Define a default value
|
|
43
|
-
embedApi: Boolean # Should we also create an embedded API from this (default false)
|
|
44
43
|
connection: Boolean # Treat this field as a connection type (default false - rolling this out slowly)
|
|
45
44
|
|
|
46
45
|
noRepeat: Boolean
|
package/src/query/Query.js
CHANGED
|
@@ -251,7 +251,7 @@ module.exports = class Query {
|
|
|
251
251
|
return {
|
|
252
252
|
isNative: Boolean(this.props.native),
|
|
253
253
|
model: model.getKey(),
|
|
254
|
-
|
|
254
|
+
shape: model.getShape(),
|
|
255
255
|
method: this.props.method,
|
|
256
256
|
select: this.props.$select,
|
|
257
257
|
joins: this.props.joins,
|
|
@@ -292,22 +292,4 @@ module.exports = class Query {
|
|
|
292
292
|
options: this.props.options,
|
|
293
293
|
};
|
|
294
294
|
}
|
|
295
|
-
|
|
296
|
-
static getSchema(model, name = false) {
|
|
297
|
-
return model.getSelectFields().reduce((prev, field) => {
|
|
298
|
-
const key = name ? field.getName() : field.getKey();
|
|
299
|
-
// const modelRef = field.getModelRef();
|
|
300
|
-
// const isEmbedded = field.isEmbedded();
|
|
301
|
-
|
|
302
|
-
return Object.assign(prev, {
|
|
303
|
-
[key]: {
|
|
304
|
-
field,
|
|
305
|
-
alias: name ? field.getKey() : field.getName(),
|
|
306
|
-
type: field.getDataType(),
|
|
307
|
-
isArray: field.isArray(),
|
|
308
|
-
// schema: isEmbedded ? Query.getSchema(modelRef, name) : null,
|
|
309
|
-
},
|
|
310
|
-
});
|
|
311
|
-
}, {});
|
|
312
|
-
}
|
|
313
295
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const Query = require('./Query');
|
|
2
2
|
const QueryResolver = require('./QueryResolver');
|
|
3
|
-
const { unravelObject } = require('../service/app.service');
|
|
3
|
+
const { toKeyObj, unravelObject } = require('../service/app.service');
|
|
4
4
|
|
|
5
5
|
/*
|
|
6
6
|
* QueryBuilder
|
|
@@ -14,7 +14,8 @@ module.exports = class QueryBuilder {
|
|
|
14
14
|
|
|
15
15
|
// Chainable commands
|
|
16
16
|
this.id = (id) => { this.query.id(id); return this; };
|
|
17
|
-
this.select = (select) => { this.query.select(select); return this; };
|
|
17
|
+
// this.select = (select) => { this.query.select(select); return this; };
|
|
18
|
+
this.select = (select) => { this.query.select(Object.entries(toKeyObj(select)).reduce((prev, [key, value]) => Object.assign(prev, { [key.replace(/edges.node./g, '')]: !!value }), {})); return this; };
|
|
18
19
|
this.where = (where) => { this.query.where(where); return this; };
|
|
19
20
|
this.match = (match) => { this.query.match(match); return this; };
|
|
20
21
|
this.native = (native) => { this.query.native(native); return this; };
|
|
@@ -33,14 +33,13 @@ module.exports = class QueryResolver {
|
|
|
33
33
|
const { model, input, flags } = query.toObject();
|
|
34
34
|
model.appendDefaultFields(query, input);
|
|
35
35
|
|
|
36
|
-
return createSystemEvent('Mutation', { method: 'create', query }, () => {
|
|
36
|
+
return createSystemEvent('Mutation', { method: 'create', query }, async () => {
|
|
37
37
|
const $input = model.serialize(query, model.appendCreateFields(input));
|
|
38
38
|
query.$input($input);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
});
|
|
39
|
+
if (!get(flags, 'novalidate')) await model.validate(query, $input);
|
|
40
|
+
const doc = await this.resolver.resolve(query);
|
|
41
|
+
query.doc(doc);
|
|
42
|
+
return doc;
|
|
44
43
|
});
|
|
45
44
|
}
|
|
46
45
|
|
|
@@ -174,7 +173,7 @@ module.exports = class QueryResolver {
|
|
|
174
173
|
return this.findMany(query.method('findMany'));
|
|
175
174
|
}
|
|
176
175
|
|
|
177
|
-
|
|
176
|
+
resolve() {
|
|
178
177
|
const { model, method, flags } = this.query.toObject();
|
|
179
178
|
|
|
180
179
|
return this[method](this.query).then((data) => {
|