@coderich/autograph 0.9.10 → 0.9.13
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 +2 -0
- package/package.json +5 -1
- package/src/.DS_Store +0 -0
- package/src/core/Resolver.js +6 -1
- package/src/core/SchemaDecorator.js +46 -0
- package/src/data/.DS_Store +0 -0
- package/src/data/Model.js +20 -0
- package/src/data/ResultSet.js +200 -146
- package/src/data/ResultSetItem.js +178 -0
- package/src/data/ResultSetNew.js +47 -0
- package/src/data/ResultSetObj.js +299 -0
- package/src/data/{ResultSet2.js → ResultSetOriginal.js} +70 -72
- package/src/driver/MongoDriver.js +8 -4
- package/src/graphql/ast/.DS_Store +0 -0
- package/src/graphql/ast/Model.js +4 -0
- package/src/graphql/ast/Schema.js +2 -3
- package/src/graphql/ast/SchemaDecorator.js +138 -0
- package/src/graphql/ast/TypeDefApi.js +93 -0
- package/src/query/Query.js +1 -19
- package/src/query/QueryResolver.js +5 -1
- package/src/service/app.service.js +18 -1
- package/src/service/event.service.js +1 -0
- package/src/data/ResultSet3.js +0 -186
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
const FS = require('fs');
|
|
2
|
+
const Glob = require('glob');
|
|
3
|
+
const Merge = require('deepmerge');
|
|
4
|
+
const { Kind, print, parse, visit } = require('graphql');
|
|
5
|
+
const { mergeASTArray, makeExecutableSchema } = require('../../service/graphql.service');
|
|
6
|
+
const { deleteKeys } = require('../../service/app.service');
|
|
7
|
+
const frameworkExt = require('../extension/framework');
|
|
8
|
+
const typeExt = require('../extension/type');
|
|
9
|
+
const apiExt = require('../extension/api');
|
|
10
|
+
const TypeDefApi = require('./TypeDefApi');
|
|
11
|
+
const Node = require('./Node');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* SchemaDecorator
|
|
15
|
+
*
|
|
16
|
+
* This class helps facilitate dynamic modification of a schema before it is passed to makeExecutableSchema(). It allows
|
|
17
|
+
* for "intelligent" merging of schemas and exposes an API wrapper for typeDefs.
|
|
18
|
+
*
|
|
19
|
+
* A "schema" is defined by the following object attributes:
|
|
20
|
+
*
|
|
21
|
+
* context <Object> - Globally shared object by all resolvers
|
|
22
|
+
* typeDefs <String|Object> - GQL String or AST Object (also supports a mixed array of both)
|
|
23
|
+
* resolvers <Object> - GraphQL resolvers
|
|
24
|
+
* schemaDirectives <Object> - GraphQL directives
|
|
25
|
+
*
|
|
26
|
+
*/
|
|
27
|
+
module.exports = class SchemaDecorator extends TypeDefApi {
|
|
28
|
+
constructor(schema) {
|
|
29
|
+
super();
|
|
30
|
+
this.schema = { context: {}, typeDefs: [], resolvers: {}, schemaDirectives: {} };
|
|
31
|
+
if (schema) this.mergeSchema(schema);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Synchronously merge a schema
|
|
36
|
+
*/
|
|
37
|
+
mergeSchema(schema, options = {}) {
|
|
38
|
+
// Here we want to normalize the schema into the shape { context, typeDefs, resolvers, schemaDirectives }
|
|
39
|
+
// We do NOT want to modify the schema object because that may cause unwanted side-effects.
|
|
40
|
+
const normalizedSchema = { ...schema };
|
|
41
|
+
if (typeof schema === 'string') normalizedSchema.typeDefs = [schema];
|
|
42
|
+
else if (schema.typeDefs && !Array.isArray(schema.typeDefs)) normalizedSchema.typeDefs = [schema.typeDefs];
|
|
43
|
+
|
|
44
|
+
// For typeDefs we want the AST so that it can be intelligently merged. Here we convert
|
|
45
|
+
// GQL strings to AST objects and also filter out anything that does not parse to AST.
|
|
46
|
+
if (normalizedSchema.typeDefs && normalizedSchema.typeDefs.length) {
|
|
47
|
+
normalizedSchema.typeDefs = deleteKeys(normalizedSchema.typeDefs.map((td) => {
|
|
48
|
+
try {
|
|
49
|
+
const ast = typeof td === 'object' ? td : parse(td);
|
|
50
|
+
return ast.definitions;
|
|
51
|
+
} catch (e) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}), ['loc']).filter(Boolean).flat();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Now we're ready to merge the schema
|
|
58
|
+
const [left, right] = options.passive ? [normalizedSchema, this.schema] : [this.schema, normalizedSchema];
|
|
59
|
+
if (normalizedSchema.typeDefs && normalizedSchema.typeDefs.length) this.schema.typeDefs = mergeASTArray(left.typeDefs.concat(right.typeDefs));
|
|
60
|
+
if (normalizedSchema.context) this.schema.context = Merge(left.context, right.context);
|
|
61
|
+
if (normalizedSchema.resolvers) this.schema.resolvers = Merge(left.resolvers, right.resolvers);
|
|
62
|
+
if (normalizedSchema.schemaDirectives) this.schema.schemaDirectives = Merge(left.schemaDirectives, right.schemaDirectives);
|
|
63
|
+
|
|
64
|
+
// Chaining
|
|
65
|
+
return this;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Asynchronously load files from a given glob pattern and merge each schema
|
|
70
|
+
*/
|
|
71
|
+
mergeSchemaFromFiles(globPattern, options) {
|
|
72
|
+
return new Promise((resolve, reject) => {
|
|
73
|
+
Glob(globPattern, options, (err, files) => {
|
|
74
|
+
if (err) return reject(err);
|
|
75
|
+
|
|
76
|
+
return Promise.all(files.map((file) => {
|
|
77
|
+
return new Promise((res) => {
|
|
78
|
+
if (file.endsWith('.js')) res(require(file)); // eslint-disable-line global-require,import/no-dynamic-require
|
|
79
|
+
else res(FS.readFileSync(file, 'utf8'));
|
|
80
|
+
}).then(schema => this.mergeSchema(schema, options));
|
|
81
|
+
})).then(() => resolve(this)).catch(e => reject(e));
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Traverses the current schema's typeDefs in order to keep the TypeDefApi in sync. This operation
|
|
88
|
+
* only needs to be called when typeDefs have been changed and you want to keep the data model in sync.
|
|
89
|
+
*/
|
|
90
|
+
initialize() {
|
|
91
|
+
return super.initialize(this.schema.typeDefs);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Decorate the schema with Autograph's default api/definitions
|
|
96
|
+
*/
|
|
97
|
+
decorate() {
|
|
98
|
+
this.initialize();
|
|
99
|
+
this.mergeSchema(frameworkExt(this), { passive: true });
|
|
100
|
+
this.mergeSchema(typeExt(this), { passive: true });
|
|
101
|
+
this.initialize();
|
|
102
|
+
this.mergeSchema(apiExt(this), { passive: true });
|
|
103
|
+
this.finalize();
|
|
104
|
+
return this;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* This should be called once before passing to makeExecutableSchema()
|
|
109
|
+
*/
|
|
110
|
+
finalize() {
|
|
111
|
+
const definitions = visit(this.schema.typeDefs, {
|
|
112
|
+
[Kind.FIELD_DEFINITION]: (node) => {
|
|
113
|
+
const scope = new Node(node, 'field').getDirectiveArg('field', 'gqlScope', 'crud');
|
|
114
|
+
if (scope === null || scope.indexOf('r') === -1) return null; // Delete node
|
|
115
|
+
return false; // Stop traversing this node
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
this.schema.typeDefs = { kind: Kind.DOCUMENT, definitions };
|
|
120
|
+
return this;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
makeExecutableSchema() {
|
|
124
|
+
return makeExecutableSchema(this.schema);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
getContext() {
|
|
128
|
+
return this.schema.context;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
toObject() {
|
|
132
|
+
return this.schema;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
toString() {
|
|
136
|
+
return print(this.typeDefs);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
const { Kind, visit } = require('graphql');
|
|
2
|
+
const Model = require('./Model');
|
|
3
|
+
const Node = require('./Node');
|
|
4
|
+
|
|
5
|
+
const operations = ['Query', 'Mutation', 'Subscription'];
|
|
6
|
+
const modelKinds = [Kind.OBJECT_TYPE_DEFINITION, Kind.OBJECT_TYPE_EXTENSION, Kind.INTERFACE_TYPE_DEFINITION, Kind.INTERFACE_TYPE_EXTENSION];
|
|
7
|
+
const inputKinds = [Kind.INPUT_OBJECT_TYPE_DEFINITION, Kind.INPUT_OBJECT_TYPE_EXTENSION];
|
|
8
|
+
const scalarKinds = [Kind.SCALAR_TYPE_DEFINITION, Kind.SCALAR_TYPE_EXTENSION];
|
|
9
|
+
const enumKinds = [Kind.ENUM_TYPE_DEFINITION, Kind.ENUM_TYPE_EXTENSION];
|
|
10
|
+
|
|
11
|
+
module.exports = class TypeDefApi {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.models = [];
|
|
14
|
+
this.scalars = [];
|
|
15
|
+
this.inputs = [];
|
|
16
|
+
this.enums = [];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
initialize(typeDefs) {
|
|
20
|
+
this.models.length = 0;
|
|
21
|
+
this.scalars.length = 0;
|
|
22
|
+
this.inputs.length = 0;
|
|
23
|
+
this.enums.length = 0;
|
|
24
|
+
|
|
25
|
+
visit(typeDefs, {
|
|
26
|
+
enter: (node) => {
|
|
27
|
+
if (modelKinds.indexOf(node.kind) > -1 && operations.indexOf(node.name.value) === -1) {
|
|
28
|
+
this.models.push(new Model(this, node));
|
|
29
|
+
} else if (scalarKinds.indexOf(node.kind) > -1) {
|
|
30
|
+
this.scalars.push(new Node(node));
|
|
31
|
+
} else if (inputKinds.indexOf(node.kind) > -1) {
|
|
32
|
+
this.inputs.push(new Node(node));
|
|
33
|
+
} else if (enumKinds.indexOf(node.kind) > -1) {
|
|
34
|
+
this.enums.push(new Node(node));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return false; // Stop traversing this node
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Models
|
|
45
|
+
getModel(name) {
|
|
46
|
+
return this.models.find(m => m.getName() === name);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
getModels() {
|
|
50
|
+
return this.models;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
getModelNames() {
|
|
54
|
+
return this.getModels().map(model => model.getName());
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
getModelMap() {
|
|
58
|
+
return this.getModels().reduce((prev, model) => Object.assign(prev, { [model.getName()]: model }), {});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
getMarkedModels() {
|
|
62
|
+
return Object.values(this.models).filter(model => model.isMarkedModel());
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
getEntityModels() {
|
|
66
|
+
return Object.values(this.models).filter(model => model.isEntity());
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Definitions
|
|
70
|
+
getInput(name) {
|
|
71
|
+
return this.getInputs().find(input => input.getName() === name);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
getInputs() {
|
|
75
|
+
return this.inputs;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
getScalar(name) {
|
|
79
|
+
return this.getScalars().find(scalar => scalar.getName() === name);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
getScalars() {
|
|
83
|
+
return this.scalars;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
getEnum(name) {
|
|
87
|
+
return this.getEnums().find(el => el.getName() === name);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
getEnums() {
|
|
91
|
+
return this.enums;
|
|
92
|
+
}
|
|
93
|
+
};
|
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('deserialize', false),
|
|
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
|
};
|
|
@@ -36,7 +36,11 @@ module.exports = class QueryResolver {
|
|
|
36
36
|
return createSystemEvent('Mutation', { method: 'create', query }, () => {
|
|
37
37
|
const $input = model.serialize(query, model.appendCreateFields(input));
|
|
38
38
|
query.$input($input);
|
|
39
|
-
|
|
39
|
+
const promise = get(flags, 'novalidate') ? this.resolver.resolve(query) : model.validate(query, $input).then(() => this.resolver.resolve(query));
|
|
40
|
+
return promise.then((doc) => {
|
|
41
|
+
query.doc(doc);
|
|
42
|
+
return doc;
|
|
43
|
+
});
|
|
40
44
|
});
|
|
41
45
|
}
|
|
42
46
|
|
|
@@ -69,6 +69,12 @@ exports.renameObjectKey = (obj, oldKey, newKey) => {
|
|
|
69
69
|
}
|
|
70
70
|
};
|
|
71
71
|
|
|
72
|
+
exports.deleteKeys = (obj, keys) => {
|
|
73
|
+
if (Array.isArray(obj)) obj.map(item => exports.deleteKeys(item, keys));
|
|
74
|
+
else if (obj === Object(obj)) { keys.forEach(key => delete obj[key]); Object.values(obj).forEach(v => exports.deleteKeys(v, keys)); }
|
|
75
|
+
return obj;
|
|
76
|
+
};
|
|
77
|
+
|
|
72
78
|
exports.getDeep = (obj, path, defaultValue) => {
|
|
73
79
|
const [prop, ...rest] = path.split('.');
|
|
74
80
|
const normalize = data => (Array.isArray(data) ? _.flatten(data) : data);
|
|
@@ -84,7 +90,7 @@ exports.map = (mixed, fn) => {
|
|
|
84
90
|
if (mixed == null) return mixed;
|
|
85
91
|
const isArray = Array.isArray(mixed);
|
|
86
92
|
const arr = isArray ? mixed : [mixed];
|
|
87
|
-
const results = arr.map(
|
|
93
|
+
const results = arr.map((...args) => fn(...args));
|
|
88
94
|
return isArray ? results : results[0];
|
|
89
95
|
};
|
|
90
96
|
|
|
@@ -260,3 +266,14 @@ exports.proxyDeep = (obj, handler, proxyMap = new WeakMap(), path = '') => {
|
|
|
260
266
|
|
|
261
267
|
return finalProxy;
|
|
262
268
|
};
|
|
269
|
+
|
|
270
|
+
exports.resolveDataObject = (obj) => {
|
|
271
|
+
return Promise.all(Object.keys(obj).map(async (key) => {
|
|
272
|
+
const value = await obj[key];
|
|
273
|
+
return { key, value };
|
|
274
|
+
})).then((results) => {
|
|
275
|
+
return results.reduce((prev, { key, value }) => {
|
|
276
|
+
return Object.assign(prev, { [key]: value });
|
|
277
|
+
}, {});
|
|
278
|
+
});
|
|
279
|
+
};
|
|
@@ -56,6 +56,7 @@ exports.createSystemEvent = (name, mixed = {}, thunk = () => {}) => {
|
|
|
56
56
|
return middleware().then(thunk);
|
|
57
57
|
}).then((result) => {
|
|
58
58
|
event.result = result;
|
|
59
|
+
if (event.crud === 'create') event.doc = event.query.toObject().doc;
|
|
59
60
|
return systemEvent.emit('system', { type: `post${type}`, data: event }).then((postResult = result) => postResult);
|
|
60
61
|
}).then((result) => {
|
|
61
62
|
if (name === 'Response') return result;
|
package/src/data/ResultSet3.js
DELETED
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
const { get } = require('lodash');
|
|
2
|
-
const DataService = require('./DataService');
|
|
3
|
-
const { map, ensureArray, keyPaths, mapPromise, toGUID, hashObject } = require('../service/app.service');
|
|
4
|
-
|
|
5
|
-
module.exports = class ResultSet {
|
|
6
|
-
constructor(query, data, adjustForPagination = true) {
|
|
7
|
-
const { resolver, model, sort, first, after, last, before } = query.toObject();
|
|
8
|
-
const fields = model.getFields().filter(f => f.getName() !== 'id');
|
|
9
|
-
|
|
10
|
-
const rs = map(data, (doc) => {
|
|
11
|
-
if (doc == null || typeof doc !== 'object') return doc;
|
|
12
|
-
|
|
13
|
-
const cache = new Map();
|
|
14
|
-
|
|
15
|
-
const validKeys = [];
|
|
16
|
-
|
|
17
|
-
const definition = {
|
|
18
|
-
get id() { return doc.id || doc[model.idKey()]; },
|
|
19
|
-
get $id() { return toGUID(model.getName(), this.id); },
|
|
20
|
-
get $$data() { return data; },
|
|
21
|
-
get $$model() { return model; },
|
|
22
|
-
get $$isResultSetItem() { return true; },
|
|
23
|
-
get $$save() { return input => resolver.match(model).id(this.id).save({ ...this, ...input }); },
|
|
24
|
-
get $$remove() { return () => resolver.match(model).id(this.id).remove(); },
|
|
25
|
-
get $$delete() { return () => resolver.match(model).id(this.id).delete(); },
|
|
26
|
-
get $$cursor() {
|
|
27
|
-
return () => {
|
|
28
|
-
const sortPaths = keyPaths(sort);
|
|
29
|
-
const sortValues = sortPaths.reduce((prv, path) => Object.assign(prv, { [path]: get(this, path) }), {});
|
|
30
|
-
const sortJSON = JSON.stringify(sortValues);
|
|
31
|
-
return Buffer.from(sortJSON).toString('base64');
|
|
32
|
-
};
|
|
33
|
-
},
|
|
34
|
-
get toObject() {
|
|
35
|
-
return () => validKeys.reduce((prev, key) => Object.assign(prev, { [key]: this[key] }), {});
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
fields.forEach((field) => {
|
|
40
|
-
const key = field.getKey();
|
|
41
|
-
const name = field.getName();
|
|
42
|
-
const $name = `$${name}`;
|
|
43
|
-
const value = doc[key];
|
|
44
|
-
validKeys.push(name);
|
|
45
|
-
|
|
46
|
-
// Field attributes
|
|
47
|
-
Object.assign(definition, {
|
|
48
|
-
get [name]() {
|
|
49
|
-
let $value = field.deserialize(query, value);
|
|
50
|
-
$value = $value != null && field.isEmbedded() ? new ResultSet(query.model(field.getModelRef()), $value, false) : $value;
|
|
51
|
-
return $value;
|
|
52
|
-
},
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
// Hydrated field attributes
|
|
56
|
-
Object.assign(definition, {
|
|
57
|
-
get [$name]() {
|
|
58
|
-
return (args = {}) => {
|
|
59
|
-
// Ensure where clause
|
|
60
|
-
args.where = args.where || {};
|
|
61
|
-
|
|
62
|
-
return new Promise((resolve, reject) => {
|
|
63
|
-
(() => {
|
|
64
|
-
const $value = this[name];
|
|
65
|
-
|
|
66
|
-
if (field.isScalar() || field.isEmbedded()) return Promise.resolve($value);
|
|
67
|
-
|
|
68
|
-
const modelRef = field.getModelRef();
|
|
69
|
-
|
|
70
|
-
if (field.isArray()) {
|
|
71
|
-
if (field.isVirtual()) {
|
|
72
|
-
args.where[[field.getVirtualField()]] = this.id; // Is where[[field.getVirtualField()]] correct?
|
|
73
|
-
return resolver.match(modelRef).merge(args).many();
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Not a "required" query + strip out nulls
|
|
77
|
-
args.where.id = $value;
|
|
78
|
-
return resolver.match(modelRef).merge(args).many();
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (field.isVirtual()) {
|
|
82
|
-
args.where[[field.getVirtualField()]] = this.id;
|
|
83
|
-
return resolver.match(modelRef).merge(args).one();
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return resolver.match(modelRef).id($value).one({ required: field.isRequired() });
|
|
87
|
-
})().then((results) => {
|
|
88
|
-
if (results == null) return field.resolve(query, results); // Allow field to determine
|
|
89
|
-
return mapPromise(results, result => field.resolve(query, result)).then(() => results); // Resolve the inside fields but still return "results"!!!!
|
|
90
|
-
}).then((resolved) => {
|
|
91
|
-
resolve(resolved);
|
|
92
|
-
}).catch((e) => {
|
|
93
|
-
reject(e);
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
};
|
|
97
|
-
},
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
// Field count (let's assume it's a Connection Type - meaning dont try with anything else)
|
|
101
|
-
Object.assign(definition, {
|
|
102
|
-
get [`${$name}:count`]() {
|
|
103
|
-
return (q = {}) => {
|
|
104
|
-
q.where = q.where || {};
|
|
105
|
-
if (field.isVirtual()) q.where[field.getVirtualField()] = this.id;
|
|
106
|
-
else q.where.id = this[name];
|
|
107
|
-
return resolver.match(field.getModelRef()).merge(q).count();
|
|
108
|
-
};
|
|
109
|
-
},
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
// Create and return ResultSetItem
|
|
114
|
-
const idk = new Proxy(definition, {
|
|
115
|
-
get(target, prop, rec) {
|
|
116
|
-
if (cache.has(prop)) return cache.get(prop);
|
|
117
|
-
const value = Reflect.get(target, prop, rec);
|
|
118
|
-
if (typeof value === 'function') return value.bind(target);
|
|
119
|
-
cache.set(prop, value);
|
|
120
|
-
return value;
|
|
121
|
-
},
|
|
122
|
-
set(target, prop, value) {
|
|
123
|
-
cache.set(prop, value);
|
|
124
|
-
return true;
|
|
125
|
-
},
|
|
126
|
-
ownKeys() {
|
|
127
|
-
return validKeys;
|
|
128
|
-
},
|
|
129
|
-
getOwnPropertyDescriptor(target, prop) {
|
|
130
|
-
if (validKeys.indexOf(prop) === -1) {
|
|
131
|
-
return {
|
|
132
|
-
writable: true,
|
|
133
|
-
enumerable: true,
|
|
134
|
-
configurable: true,
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return {
|
|
139
|
-
writable: false,
|
|
140
|
-
enumerable: false,
|
|
141
|
-
configurable: false,
|
|
142
|
-
};
|
|
143
|
-
},
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
// console.log(idk);
|
|
147
|
-
// // console.log(idk.toObject());
|
|
148
|
-
return idk;
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
let hasNextPage = false;
|
|
152
|
-
let hasPreviousPage = false;
|
|
153
|
-
if (adjustForPagination && rs.length) (({ hasPreviousPage, hasNextPage } = DataService.paginateResultSet(rs, first, after, last, before)));
|
|
154
|
-
|
|
155
|
-
return Object.defineProperties(rs, {
|
|
156
|
-
$$pageInfo: {
|
|
157
|
-
get() {
|
|
158
|
-
const edges = ensureArray(rs);
|
|
159
|
-
|
|
160
|
-
return {
|
|
161
|
-
startCursor: get(edges, '0.$$cursor', ''),
|
|
162
|
-
endCursor: get(edges, `${edges.length - 1}.$$cursor`, ''),
|
|
163
|
-
hasPreviousPage,
|
|
164
|
-
hasNextPage,
|
|
165
|
-
};
|
|
166
|
-
},
|
|
167
|
-
enumerable: false,
|
|
168
|
-
},
|
|
169
|
-
$$isResultSet: {
|
|
170
|
-
value: true,
|
|
171
|
-
enumerable: false,
|
|
172
|
-
},
|
|
173
|
-
toObject: {
|
|
174
|
-
get() {
|
|
175
|
-
return () => map(this, doc => Object.entries(doc).reduce((prev, [key, value]) => {
|
|
176
|
-
if (value === undefined) return prev;
|
|
177
|
-
prev[key] = get(value, '$$isResultSet') ? value.toObject() : value;
|
|
178
|
-
return prev;
|
|
179
|
-
}, {}));
|
|
180
|
-
},
|
|
181
|
-
enumerable: false,
|
|
182
|
-
configurable: true,
|
|
183
|
-
},
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
};
|