@coderich/autograph 0.9.12 → 0.9.15
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 -5
- package/src/.DS_Store +0 -0
- package/src/core/Resolver.js +2 -1
- package/src/data/Field.js +1 -26
- package/src/data/Model.js +20 -0
- package/src/data/ResultSet.js +188 -147
- package/src/data/Type.js +0 -14
- package/src/driver/MongoDriver.js +6 -5
- package/src/graphql/.DS_Store +0 -0
- package/src/graphql/ast/SchemaDecorator.js +2 -2
- package/src/graphql/extension/api.js +1 -1
- package/src/graphql/extension/framework.js +0 -1
- package/src/query/Query.js +1 -19
- package/src/service/app.service.js +12 -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
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coderich/autograph",
|
|
3
3
|
"author": "Richard Livolsi (coderich)",
|
|
4
|
-
"version": "0.9.
|
|
4
|
+
"version": "0.9.15",
|
|
5
5
|
"description": "AutoGraph",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"graphql",
|
|
@@ -30,7 +30,6 @@
|
|
|
30
30
|
"ratchet": "ratchet"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@graphql-tools/schema": "^8.3.14",
|
|
34
33
|
"@hapi/boom": "^9.1.0",
|
|
35
34
|
"axios": "^0.21.4",
|
|
36
35
|
"dataloader": "^2.0.0",
|
|
@@ -55,9 +54,6 @@
|
|
|
55
54
|
"redis": "^2.8.0",
|
|
56
55
|
"redis-mock": "^0.47.0"
|
|
57
56
|
},
|
|
58
|
-
"peerDependencies": {
|
|
59
|
-
"graphql": ">15"
|
|
60
|
-
},
|
|
61
57
|
"repository": {
|
|
62
58
|
"type": "git",
|
|
63
59
|
"url": "git@github.com:coderich/autograph.git"
|
package/src/.DS_Store
CHANGED
|
Binary file
|
package/src/core/Resolver.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const { isEmpty } = require('lodash');
|
|
1
2
|
const Model = require('../data/Model');
|
|
2
3
|
const Query = require('../query/Query');
|
|
3
4
|
const ResultSet = require('../data/ResultSet');
|
|
@@ -89,7 +90,7 @@ module.exports = class Resolver {
|
|
|
89
90
|
// This is needed in SF tests...
|
|
90
91
|
const key = model.idKey();
|
|
91
92
|
const { where, method } = query.toDriver();
|
|
92
|
-
if (Object.prototype.hasOwnProperty.call(where, key) && where[key]
|
|
93
|
+
if (Object.prototype.hasOwnProperty.call(where, key) && isEmpty(where[key])) return Promise.resolve(method === 'findMany' ? [] : null);
|
|
93
94
|
|
|
94
95
|
//
|
|
95
96
|
return this.loaders.get(`${model}`).load(query);
|
package/src/data/Field.js
CHANGED
|
@@ -2,7 +2,7 @@ const Type = require('./Type');
|
|
|
2
2
|
const Field = require('../graphql/ast/Field');
|
|
3
3
|
const Rule = require('../core/Rule');
|
|
4
4
|
const Transformer = require('../core/Transformer');
|
|
5
|
-
const { map, uvl, isPlainObject, ensureArray
|
|
5
|
+
const { map, uvl, isPlainObject, ensureArray } = require('../service/app.service');
|
|
6
6
|
|
|
7
7
|
module.exports = class extends Field {
|
|
8
8
|
constructor(model, field) {
|
|
@@ -63,17 +63,6 @@ module.exports = class extends Field {
|
|
|
63
63
|
return transformers.concat(this.type.getDeserializers());
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
getResolvers() {
|
|
67
|
-
const resolvers = [];
|
|
68
|
-
|
|
69
|
-
Object.entries(this.getDirectiveArgs('field', {})).forEach(([key, value]) => {
|
|
70
|
-
if (!Array.isArray(value)) value = [value];
|
|
71
|
-
if (key === 'resolve') resolvers.push(...value.map(t => Transformer.getInstances()[t]));
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
return resolvers.concat(this.type.getResolvers());
|
|
75
|
-
}
|
|
76
|
-
|
|
77
66
|
validate(query, value) {
|
|
78
67
|
const modelRef = this.getModelRef();
|
|
79
68
|
const rules = [...this.getRules()];
|
|
@@ -124,20 +113,6 @@ module.exports = class extends Field {
|
|
|
124
113
|
return this.transform(query, value, 'deserialize');
|
|
125
114
|
}
|
|
126
115
|
|
|
127
|
-
/**
|
|
128
|
-
* Applies any user-defined @field(resolve: [...methods]) in series
|
|
129
|
-
* This is ONLY run when resolving a value via the $<name> attribute
|
|
130
|
-
*/
|
|
131
|
-
resolve(query, value) {
|
|
132
|
-
const resolvers = [...this.getResolvers()];
|
|
133
|
-
|
|
134
|
-
return promiseChain(resolvers.map(fn => (chain) => {
|
|
135
|
-
return Promise.resolve(fn(this, uvl(this.cast(chain.pop()), value), query));
|
|
136
|
-
})).then((results) => {
|
|
137
|
-
return uvl(this.cast(results.pop()), value);
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
|
|
141
116
|
tform(query, value) {
|
|
142
117
|
// Determine transformers
|
|
143
118
|
const transformers = this.getTransformers();
|
package/src/data/Model.js
CHANGED
|
@@ -160,4 +160,24 @@ module.exports = class extends Model {
|
|
|
160
160
|
}, {});
|
|
161
161
|
});
|
|
162
162
|
}
|
|
163
|
+
|
|
164
|
+
getShape(serdes = 'deserialize', recursive = true) {
|
|
165
|
+
return this.getSelectFields().map((field) => {
|
|
166
|
+
const [from, to] = serdes === 'serialize' ? [field.getName(), field.getKey()] : [field.getKey(), field.getName()];
|
|
167
|
+
const shape = recursive && field.isEmbedded() ? field.getModelRef().getShape(serdes, recursive) : null;
|
|
168
|
+
return { from, to, type: field.getDataType(), isArray: field.isArray(), shape };
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
shape(data, serdes = (() => { throw new Error('No Sir Sir SerDes!'); }), shape) {
|
|
173
|
+
shape = shape || this.getShape(serdes);
|
|
174
|
+
|
|
175
|
+
return map(data, (doc) => {
|
|
176
|
+
return shape.reduce((prev, { from, to, shape: subShape }) => {
|
|
177
|
+
const value = doc[from];
|
|
178
|
+
if (value === undefined) return prev;
|
|
179
|
+
return Object.assign(prev, { [to]: subShape ? this.shape(value, serdes, subShape) : value });
|
|
180
|
+
}, {});
|
|
181
|
+
});
|
|
182
|
+
}
|
|
163
183
|
};
|
package/src/data/ResultSet.js
CHANGED
|
@@ -1,170 +1,51 @@
|
|
|
1
1
|
const { get } = require('lodash');
|
|
2
2
|
const DataService = require('./DataService');
|
|
3
|
-
const { map, ensureArray, keyPaths,
|
|
3
|
+
const { map, ensureArray, keyPaths, toGUID } = require('../service/app.service');
|
|
4
|
+
|
|
5
|
+
const modelCache = new WeakMap();
|
|
4
6
|
|
|
5
7
|
module.exports = class ResultSet {
|
|
6
8
|
constructor(query, data, adjustForPagination = true) {
|
|
7
9
|
if (data == null) return data;
|
|
10
|
+
|
|
8
11
|
const { resolver, model, sort, first, after, last, before } = query.toObject();
|
|
9
|
-
const fields = model.getFields().filter(f => f.getName() !== 'id');
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
if (doc == null || typeof doc !== 'object') return doc;
|
|
13
|
+
ResultSet.ensureModelCache(model);
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
const cache = new Map();
|
|
16
|
-
|
|
17
|
-
const definition = fields.reduce((prev, field) => {
|
|
18
|
-
const key = field.getKey();
|
|
19
|
-
const name = field.getName();
|
|
20
|
-
const $name = `$${name}`;
|
|
21
|
-
const value = doc[key];
|
|
22
|
-
|
|
23
|
-
// Field attributes
|
|
24
|
-
prev[name] = {
|
|
25
|
-
get() {
|
|
26
|
-
if (cache.has(name)) return cache.get(name);
|
|
27
|
-
let $value = field.deserialize(query, value);
|
|
28
|
-
$value = $value != null && field.isEmbedded() ? new ResultSet(query.model(field.getModelRef()), $value, false) : $value;
|
|
29
|
-
cache.set(name, $value);
|
|
30
|
-
return $value;
|
|
31
|
-
},
|
|
32
|
-
set($value) {
|
|
33
|
-
cache.set(name, $value);
|
|
34
|
-
},
|
|
35
|
-
enumerable: true,
|
|
36
|
-
configurable: true, // Allows things like delete
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
// Hydrated field attributes
|
|
40
|
-
prev[`$${name}`] = {
|
|
41
|
-
get() {
|
|
42
|
-
return (args = {}) => {
|
|
43
|
-
// Ensure where clause
|
|
44
|
-
args.where = args.where || {};
|
|
45
|
-
|
|
46
|
-
// Cache
|
|
47
|
-
const cacheKey = `${$name}-${hashObject(args)}`;
|
|
48
|
-
if (cache.has(cacheKey)) return cache.get(cacheKey);
|
|
49
|
-
|
|
50
|
-
const promise = new Promise((resolve, reject) => {
|
|
51
|
-
(() => {
|
|
52
|
-
const $value = this[name];
|
|
53
|
-
|
|
54
|
-
if (field.isScalar() || field.isEmbedded()) return Promise.resolve($value);
|
|
55
|
-
|
|
56
|
-
const modelRef = field.getModelRef();
|
|
57
|
-
|
|
58
|
-
if (field.isArray()) {
|
|
59
|
-
if (field.isVirtual()) {
|
|
60
|
-
args.where[[field.getVirtualField()]] = this.id; // Is where[[field.getVirtualField()]] correct?
|
|
61
|
-
return resolver.match(modelRef).merge(args).many();
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Not a "required" query + strip out nulls
|
|
65
|
-
args.where.id = $value;
|
|
66
|
-
return resolver.match(modelRef).merge(args).many();
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (field.isVirtual()) {
|
|
70
|
-
args.where[[field.getVirtualField()]] = this.id;
|
|
71
|
-
return resolver.match(modelRef).merge(args).one();
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return resolver.match(modelRef).id($value).one({ required: field.isRequired() });
|
|
75
|
-
})().then((results) => {
|
|
76
|
-
if (results == null) return field.resolve(query, results); // Allow field to determine
|
|
77
|
-
return mapPromise(results, result => field.resolve(query, result)).then(() => results); // Resolve the inside fields but still return "results"!!!!
|
|
78
|
-
}).then((resolved) => {
|
|
79
|
-
resolve(resolved);
|
|
80
|
-
}).catch((e) => {
|
|
81
|
-
reject(e);
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
cache.set(cacheKey, promise);
|
|
86
|
-
return promise;
|
|
87
|
-
};
|
|
88
|
-
},
|
|
89
|
-
enumerable: false,
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
// Field count (let's assume it's a Connection Type - meaning dont try with anything else)
|
|
93
|
-
prev[`$${name}:count`] = {
|
|
94
|
-
get() {
|
|
95
|
-
return (q = {}) => {
|
|
96
|
-
q.where = q.where || {};
|
|
97
|
-
if (field.isVirtual()) q.where[field.getVirtualField()] = this.id;
|
|
98
|
-
else q.where.id = this[name];
|
|
99
|
-
return resolver.match(field.getModelRef()).merge(q).count();
|
|
100
|
-
};
|
|
101
|
-
},
|
|
102
|
-
enumerable: false,
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
return prev;
|
|
106
|
-
}, {
|
|
107
|
-
id: {
|
|
108
|
-
get() { return doc.id || doc[model.idKey()]; },
|
|
109
|
-
set(id) { doc.id = id; }, // Embedded array of documents need to set id
|
|
110
|
-
enumerable: true,
|
|
111
|
-
},
|
|
15
|
+
const { template, fieldDefs } = modelCache.get(model);
|
|
112
16
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
enumerable: false,
|
|
116
|
-
},
|
|
17
|
+
const rs = map(data, (doc) => {
|
|
18
|
+
if (doc == null || typeof doc !== 'object') return doc;
|
|
117
19
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
20
|
+
const instance = Object.create(template, {
|
|
21
|
+
$$services: {
|
|
22
|
+
value: {
|
|
23
|
+
cache: new Map(),
|
|
24
|
+
data: doc,
|
|
25
|
+
resolver,
|
|
26
|
+
query,
|
|
27
|
+
sort,
|
|
124
28
|
},
|
|
125
29
|
enumerable: false,
|
|
126
30
|
},
|
|
31
|
+
});
|
|
127
32
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
33
|
+
return new Proxy(instance, {
|
|
34
|
+
ownKeys(target) {
|
|
35
|
+
return Reflect.ownKeys(target).concat('id', fieldDefs.map(d => d.name));
|
|
131
36
|
},
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
value: true,
|
|
135
|
-
enumerable: false,
|
|
37
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
38
|
+
return (prop === 'id' || fieldDefs.find(el => el.name === prop)) ? { enumerable: true, configurable: true } : Reflect.getOwnPropertyDescriptor(target, prop);
|
|
136
39
|
},
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
get() { return input => resolver.match(model).id(this.id).save({ ...this, ...input }); },
|
|
140
|
-
enumerable: false,
|
|
40
|
+
getPrototypeOf() {
|
|
41
|
+
return { $$services: instance.$$services };
|
|
141
42
|
},
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
},
|
|
147
|
-
|
|
148
|
-
$$delete: {
|
|
149
|
-
get() { return () => resolver.match(model).id(this.id).delete(); },
|
|
150
|
-
enumerable: false,
|
|
151
|
-
},
|
|
152
|
-
|
|
153
|
-
toObject: {
|
|
154
|
-
get() {
|
|
155
|
-
return () => map(this, obj => Object.entries(obj).reduce((prev, [key, value]) => {
|
|
156
|
-
if (value === undefined) return prev;
|
|
157
|
-
prev[key] = get(value, '$$isResultSet') ? value.toObject() : value;
|
|
158
|
-
return prev;
|
|
159
|
-
}, {}));
|
|
160
|
-
},
|
|
161
|
-
enumerable: false,
|
|
162
|
-
configurable: true,
|
|
43
|
+
deleteProperty(target, prop) {
|
|
44
|
+
const { key = prop } = fieldDefs.find(d => d.name === prop);
|
|
45
|
+
delete instance[prop];
|
|
46
|
+
delete instance.$$services.data[key];
|
|
163
47
|
},
|
|
164
48
|
});
|
|
165
|
-
|
|
166
|
-
// Create and return ResultSetItem
|
|
167
|
-
return Object.defineProperties({}, definition);
|
|
168
49
|
});
|
|
169
50
|
|
|
170
51
|
let hasNextPage = false;
|
|
@@ -202,4 +83,164 @@ module.exports = class ResultSet {
|
|
|
202
83
|
},
|
|
203
84
|
});
|
|
204
85
|
}
|
|
86
|
+
|
|
87
|
+
static ensureModelCache(model) {
|
|
88
|
+
if (!modelCache.has(model)) {
|
|
89
|
+
const fields = model.getFields().filter(f => f.getName() !== 'id');
|
|
90
|
+
|
|
91
|
+
const fieldDefs = fields.map(field => ({
|
|
92
|
+
field,
|
|
93
|
+
key: field.getKey(),
|
|
94
|
+
name: field.getName(),
|
|
95
|
+
isArray: field.isArray(),
|
|
96
|
+
isScalar: field.isScalar(),
|
|
97
|
+
isVirtual: field.isVirtual(),
|
|
98
|
+
isRequired: field.isRequired(),
|
|
99
|
+
isEmbedded: field.isEmbedded(),
|
|
100
|
+
modelRef: field.getModelRef(),
|
|
101
|
+
virtualField: field.getVirtualField(),
|
|
102
|
+
// deserialize: field.deserialize.bind(field),
|
|
103
|
+
// fieldResolve: field.resolve.bind(field),
|
|
104
|
+
get useDefaultResolver() { return Boolean(this.isScalar || this.isEmbedded); },
|
|
105
|
+
}));
|
|
106
|
+
|
|
107
|
+
const template = ResultSet.makeModelTemplate(model, fieldDefs);
|
|
108
|
+
|
|
109
|
+
modelCache.set(model, { template, fieldDefs });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
static makeModelTemplate(model, fieldDefs) {
|
|
114
|
+
const definition = fieldDefs.reduce((prev, fieldDef) => {
|
|
115
|
+
const { field, key, name, isArray, isVirtual, isRequired, isEmbedded, modelRef, virtualField, useDefaultResolver } = fieldDef;
|
|
116
|
+
const $name = `$${name}`;
|
|
117
|
+
|
|
118
|
+
// Deserialized field attributes
|
|
119
|
+
prev[name] = {
|
|
120
|
+
get() {
|
|
121
|
+
if (this.$$services.cache.has(name)) return this.$$services.cache.get(name);
|
|
122
|
+
let $value = field.deserialize(this.$$services.query, this.$$services.data[key]);
|
|
123
|
+
if ($value != null && isEmbedded) $value = new ResultSet(this.$$services.query.model(modelRef), $value, false);
|
|
124
|
+
this.$$services.cache.set(name, $value);
|
|
125
|
+
return $value;
|
|
126
|
+
},
|
|
127
|
+
set($value) {
|
|
128
|
+
this.$$services.cache.set(name, $value);
|
|
129
|
+
},
|
|
130
|
+
enumerable: true,
|
|
131
|
+
configurable: true, // Allows things like delete
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// Fully deserialized, hydrated, and resolved field attributes
|
|
135
|
+
prev[$name] = {
|
|
136
|
+
get() {
|
|
137
|
+
return (args = {}) => {
|
|
138
|
+
// Grab deserialized value
|
|
139
|
+
const $value = this[name];
|
|
140
|
+
|
|
141
|
+
// Default resolver return immediately!
|
|
142
|
+
if (useDefaultResolver) return $value;
|
|
143
|
+
|
|
144
|
+
// Ensure where clause for DB lookup
|
|
145
|
+
args.where = args.where || {};
|
|
146
|
+
|
|
147
|
+
if (isArray) {
|
|
148
|
+
if (isVirtual) {
|
|
149
|
+
args.where[[virtualField]] = this.id; // Is where[[virtualField]] correct?
|
|
150
|
+
return this.$$services.resolver.match(modelRef).merge(args).many();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Not a "required" query + strip out nulls
|
|
154
|
+
args.where.id = $value;
|
|
155
|
+
return this.$$services.resolver.match(modelRef).merge(args).many();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (isVirtual) {
|
|
159
|
+
args.where[[virtualField]] = this.id;
|
|
160
|
+
return this.$$services.resolver.match(modelRef).merge(args).one();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return this.$$services.resolver.match(modelRef).id($value).one({ required: isRequired });
|
|
164
|
+
};
|
|
165
|
+
},
|
|
166
|
+
enumerable: false,
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// Field count (let's assume it's a Connection Type - meaning dont try with anything else)
|
|
170
|
+
prev[`${$name}:count`] = {
|
|
171
|
+
get() {
|
|
172
|
+
return (q = {}) => {
|
|
173
|
+
q.where = q.where || {};
|
|
174
|
+
if (isVirtual) q.where[virtualField] = this.id;
|
|
175
|
+
else q.where.id = this[name];
|
|
176
|
+
return this.$$services.resolver.match(modelRef).merge(q).count();
|
|
177
|
+
};
|
|
178
|
+
},
|
|
179
|
+
enumerable: false,
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
return prev;
|
|
183
|
+
}, {
|
|
184
|
+
id: {
|
|
185
|
+
get() { return this.$$services.data.id || this.$$services.data[model.idKey()]; },
|
|
186
|
+
set(id) { this.$$services.data.id = id; }, // Embedded array of documents need to set id
|
|
187
|
+
enumerable: true,
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
$id: {
|
|
191
|
+
get() { return toGUID(model.getName(), this.id); },
|
|
192
|
+
enumerable: false,
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
$$cursor: {
|
|
196
|
+
get() {
|
|
197
|
+
const sortPaths = keyPaths(this.$$services.sort);
|
|
198
|
+
const sortValues = sortPaths.reduce((prv, path) => Object.assign(prv, { [path]: get(this, path) }), {});
|
|
199
|
+
const sortJSON = JSON.stringify(sortValues);
|
|
200
|
+
return Buffer.from(sortJSON).toString('base64');
|
|
201
|
+
},
|
|
202
|
+
enumerable: false,
|
|
203
|
+
},
|
|
204
|
+
|
|
205
|
+
$$model: {
|
|
206
|
+
value: model,
|
|
207
|
+
enumerable: false,
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
$$isResultSetItem: {
|
|
211
|
+
value: true,
|
|
212
|
+
enumerable: false,
|
|
213
|
+
},
|
|
214
|
+
|
|
215
|
+
$$save: {
|
|
216
|
+
get() { return input => this.$$services.resolver.match(model).id(this.id).save({ ...this, ...input }); },
|
|
217
|
+
enumerable: false,
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
$$remove: {
|
|
221
|
+
get() { return () => this.$$services.resolver.match(model).id(this.id).remove(); },
|
|
222
|
+
enumerable: false,
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
$$delete: {
|
|
226
|
+
get() { return () => this.$$services.resolver.match(model).id(this.id).delete(); },
|
|
227
|
+
enumerable: false,
|
|
228
|
+
},
|
|
229
|
+
|
|
230
|
+
toObject: {
|
|
231
|
+
get() {
|
|
232
|
+
return () => map(this, obj => Object.entries(obj).reduce((prev, [key, value]) => {
|
|
233
|
+
if (value === undefined) return prev;
|
|
234
|
+
prev[key] = get(value, '$$isResultSet') ? value.toObject() : value;
|
|
235
|
+
return prev;
|
|
236
|
+
}, {}));
|
|
237
|
+
},
|
|
238
|
+
enumerable: false,
|
|
239
|
+
configurable: true,
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// return Object.defineProperties({}, definition);
|
|
244
|
+
return Object.create(null, definition);
|
|
245
|
+
}
|
|
205
246
|
};
|
package/src/data/Type.js
CHANGED
|
@@ -69,18 +69,4 @@ module.exports = class extends Type {
|
|
|
69
69
|
|
|
70
70
|
return transformers;
|
|
71
71
|
}
|
|
72
|
-
|
|
73
|
-
getResolvers() {
|
|
74
|
-
const resolvers = [];
|
|
75
|
-
const scalarType = this.field.getScalarRef();
|
|
76
|
-
|
|
77
|
-
if (scalarType) {
|
|
78
|
-
Object.entries(scalarType.getDirectiveArgs('field', {})).forEach(([key, value]) => {
|
|
79
|
-
if (!Array.isArray(value)) value = [value];
|
|
80
|
-
if (key === 'resolve') resolvers.push(...value.map(t => Transformer.getInstances()[t]));
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return resolvers;
|
|
85
|
-
}
|
|
86
72
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const Util = require('util');
|
|
1
2
|
const { get, has } = require('lodash');
|
|
2
3
|
const { MongoClient, ObjectID } = require('mongodb');
|
|
3
4
|
const { proxyDeep, toKeyObj, globToRegex, proxyPromise, isScalarDataType, promiseRetry } = require('../service/app.service');
|
|
@@ -25,7 +26,7 @@ module.exports = class MongoDriver {
|
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
query(collection, method, ...args) {
|
|
28
|
-
if (has(args[args.length - 1], 'debug')) console.log(collection, method,
|
|
29
|
+
if (has(args[args.length - 1], 'debug')) console.log(collection, method, Util.inspect(args, { depth: null, showHidden: false, colors: true }));
|
|
29
30
|
return this.raw(collection)[method](...args);
|
|
30
31
|
}
|
|
31
32
|
|
|
@@ -148,15 +149,15 @@ module.exports = class MongoDriver {
|
|
|
148
149
|
}
|
|
149
150
|
|
|
150
151
|
static getAddFields(query) {
|
|
151
|
-
const {
|
|
152
|
+
const { shape, where } = query;
|
|
152
153
|
|
|
153
|
-
return
|
|
154
|
-
const value = where[
|
|
154
|
+
return shape.reduce((prev, { from, type }) => {
|
|
155
|
+
const value = where[from];
|
|
155
156
|
if (value === undefined) return prev;
|
|
156
157
|
if (!isScalarDataType(type)) return prev;
|
|
157
158
|
const stype = String((type === 'Float' || type === 'Int' ? 'Number' : type)).toLowerCase();
|
|
158
159
|
if (String(typeof value) === `${stype}`) return prev;
|
|
159
|
-
return Object.assign(prev, { [
|
|
160
|
+
return Object.assign(prev, { [from]: { $toString: `$${from}` } });
|
|
160
161
|
}, {});
|
|
161
162
|
}
|
|
162
163
|
|
package/src/graphql/.DS_Store
CHANGED
|
Binary file
|
|
@@ -96,8 +96,8 @@ module.exports = class SchemaDecorator extends TypeDefApi {
|
|
|
96
96
|
*/
|
|
97
97
|
decorate() {
|
|
98
98
|
this.initialize();
|
|
99
|
-
this.mergeSchema(frameworkExt(this));
|
|
100
|
-
this.mergeSchema(typeExt(this));
|
|
99
|
+
this.mergeSchema(frameworkExt(this), { passive: true });
|
|
100
|
+
this.mergeSchema(typeExt(this), { passive: true });
|
|
101
101
|
this.initialize();
|
|
102
102
|
this.mergeSchema(apiExt(this), { passive: true });
|
|
103
103
|
this.finalize();
|
|
@@ -90,7 +90,7 @@ module.exports = (schema) => {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
type ${model.getName()}SubscriptionPayloadEventData {
|
|
93
|
-
${
|
|
93
|
+
${model.getFields().filter(field => field.hasGQLScope('r')).map(field => `${field.getName()}: ${field.getSubscriptionType()}`)}
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
interface ${model.getName()}SubscriptionQuery {
|
|
@@ -49,7 +49,6 @@ module.exports = (schema) => {
|
|
|
49
49
|
onDelete: AutoGraphOnDeleteEnum
|
|
50
50
|
|
|
51
51
|
enforce: [AutoGraphEnforceEnum!] #
|
|
52
|
-
resolve: [AutoGraphTransformEnum!] # Transforms when resolving
|
|
53
52
|
transform: [AutoGraphTransformEnum!] # Transforms when serialize + deserialize
|
|
54
53
|
serialize: [AutoGraphTransformEnum!] # Transforms when serialize
|
|
55
54
|
deserialize: [AutoGraphTransformEnum!] # Transforms when deserialize
|
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
|
};
|
|
@@ -90,7 +90,7 @@ exports.map = (mixed, fn) => {
|
|
|
90
90
|
if (mixed == null) return mixed;
|
|
91
91
|
const isArray = Array.isArray(mixed);
|
|
92
92
|
const arr = isArray ? mixed : [mixed];
|
|
93
|
-
const results = arr.map(
|
|
93
|
+
const results = arr.map((...args) => fn(...args));
|
|
94
94
|
return isArray ? results : results[0];
|
|
95
95
|
};
|
|
96
96
|
|
|
@@ -266,3 +266,14 @@ exports.proxyDeep = (obj, handler, proxyMap = new WeakMap(), path = '') => {
|
|
|
266
266
|
|
|
267
267
|
return finalProxy;
|
|
268
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
|
+
};
|
package/src/data/ResultSet2.js
DELETED
|
@@ -1,210 +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
|
-
//
|
|
14
|
-
const cache = new Map();
|
|
15
|
-
|
|
16
|
-
// Base definition all results have
|
|
17
|
-
const definition = {
|
|
18
|
-
id: {
|
|
19
|
-
get() { return doc.id || doc[model.idKey()]; },
|
|
20
|
-
set(id) { doc.id = id; }, // Embedded array of documents need to set id
|
|
21
|
-
enumerable: true,
|
|
22
|
-
},
|
|
23
|
-
|
|
24
|
-
$id: {
|
|
25
|
-
get() { return toGUID(model.getName(), this.id); },
|
|
26
|
-
enumerable: false,
|
|
27
|
-
},
|
|
28
|
-
|
|
29
|
-
$$cursor: {
|
|
30
|
-
get() {
|
|
31
|
-
const sortPaths = keyPaths(sort);
|
|
32
|
-
const sortValues = sortPaths.reduce((prv, path) => Object.assign(prv, { [path]: get(this, path) }), {});
|
|
33
|
-
const sortJSON = JSON.stringify(sortValues);
|
|
34
|
-
return Buffer.from(sortJSON).toString('base64');
|
|
35
|
-
},
|
|
36
|
-
enumerable: false,
|
|
37
|
-
},
|
|
38
|
-
|
|
39
|
-
$$model: {
|
|
40
|
-
value: model,
|
|
41
|
-
enumerable: false,
|
|
42
|
-
},
|
|
43
|
-
|
|
44
|
-
$$data: {
|
|
45
|
-
value: data,
|
|
46
|
-
enumerable: false,
|
|
47
|
-
},
|
|
48
|
-
|
|
49
|
-
$$isResultSetItem: {
|
|
50
|
-
value: true,
|
|
51
|
-
enumerable: false,
|
|
52
|
-
},
|
|
53
|
-
|
|
54
|
-
$$save: {
|
|
55
|
-
get() { return input => resolver.match(model).id(this.id).save({ ...this, ...input }); },
|
|
56
|
-
enumerable: false,
|
|
57
|
-
},
|
|
58
|
-
|
|
59
|
-
$$remove: {
|
|
60
|
-
get() { return () => resolver.match(model).id(this.id).remove(); },
|
|
61
|
-
enumerable: false,
|
|
62
|
-
},
|
|
63
|
-
|
|
64
|
-
$$delete: {
|
|
65
|
-
get() { return () => resolver.match(model).id(this.id).delete(); },
|
|
66
|
-
enumerable: false,
|
|
67
|
-
},
|
|
68
|
-
|
|
69
|
-
toObject: {
|
|
70
|
-
get() {
|
|
71
|
-
return () => map(this, obj => Object.entries(obj).reduce((prev, [key, value]) => {
|
|
72
|
-
if (value === undefined) return prev;
|
|
73
|
-
prev[key] = get(value, '$$isResultSet') ? value.toObject() : value;
|
|
74
|
-
return prev;
|
|
75
|
-
}, {}));
|
|
76
|
-
},
|
|
77
|
-
enumerable: false,
|
|
78
|
-
configurable: true,
|
|
79
|
-
},
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
fields.forEach((field) => {
|
|
83
|
-
const key = field.getKey();
|
|
84
|
-
const name = field.getName();
|
|
85
|
-
const $name = `$${name}`;
|
|
86
|
-
const value = doc[key];
|
|
87
|
-
|
|
88
|
-
// Field attributes
|
|
89
|
-
definition[name] = {
|
|
90
|
-
get() {
|
|
91
|
-
if (cache.has(name)) return cache.get(name);
|
|
92
|
-
let $value = field.deserialize(query, value);
|
|
93
|
-
$value = $value != null && field.isEmbedded() ? new ResultSet(query.model(field.getModelRef()), $value, false) : $value;
|
|
94
|
-
cache.set(name, $value);
|
|
95
|
-
return $value;
|
|
96
|
-
},
|
|
97
|
-
set($value) {
|
|
98
|
-
cache.set(name, $value);
|
|
99
|
-
},
|
|
100
|
-
enumerable: true,
|
|
101
|
-
configurable: true, // Allows things like delete
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
// Hydrated field attributes
|
|
105
|
-
definition[`$${name}`] = {
|
|
106
|
-
get() {
|
|
107
|
-
return (args = {}) => {
|
|
108
|
-
// Ensure where clause
|
|
109
|
-
args.where = args.where || {};
|
|
110
|
-
|
|
111
|
-
// Cache
|
|
112
|
-
const cacheKey = `${$name}-${hashObject(args)}`;
|
|
113
|
-
if (cache.has(cacheKey)) return cache.get(cacheKey);
|
|
114
|
-
|
|
115
|
-
const promise = new Promise((resolve, reject) => {
|
|
116
|
-
(() => {
|
|
117
|
-
const $value = this[name];
|
|
118
|
-
|
|
119
|
-
if (field.isScalar() || field.isEmbedded()) return Promise.resolve($value);
|
|
120
|
-
|
|
121
|
-
const modelRef = field.getModelRef();
|
|
122
|
-
|
|
123
|
-
if (field.isArray()) {
|
|
124
|
-
if (field.isVirtual()) {
|
|
125
|
-
args.where[[field.getVirtualField()]] = this.id; // Is where[[field.getVirtualField()]] correct?
|
|
126
|
-
return resolver.match(modelRef).merge(args).many();
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Not a "required" query + strip out nulls
|
|
130
|
-
args.where.id = $value;
|
|
131
|
-
return resolver.match(modelRef).merge(args).many();
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (field.isVirtual()) {
|
|
135
|
-
args.where[[field.getVirtualField()]] = this.id;
|
|
136
|
-
return resolver.match(modelRef).merge(args).one();
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return resolver.match(modelRef).id($value).one({ required: field.isRequired() });
|
|
140
|
-
})().then((results) => {
|
|
141
|
-
if (results == null) return field.resolve(query, results); // Allow field to determine
|
|
142
|
-
return mapPromise(results, result => field.resolve(query, result)).then(() => results); // Resolve the inside fields but still return "results"!!!!
|
|
143
|
-
}).then((resolved) => {
|
|
144
|
-
resolve(resolved);
|
|
145
|
-
}).catch((e) => {
|
|
146
|
-
reject(e);
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
cache.set(cacheKey, promise);
|
|
151
|
-
return promise;
|
|
152
|
-
};
|
|
153
|
-
},
|
|
154
|
-
enumerable: false,
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
// Field count (let's assume it's a Connection Type - meaning dont try with anything else)
|
|
158
|
-
definition[`$${name}:count`] = {
|
|
159
|
-
get() {
|
|
160
|
-
return (q = {}) => {
|
|
161
|
-
q.where = q.where || {};
|
|
162
|
-
if (field.isVirtual()) q.where[field.getVirtualField()] = this.id;
|
|
163
|
-
else q.where.id = this[name];
|
|
164
|
-
return resolver.match(field.getModelRef()).merge(q).count();
|
|
165
|
-
};
|
|
166
|
-
},
|
|
167
|
-
enumerable: false,
|
|
168
|
-
};
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
// Create and return ResultSetItem
|
|
172
|
-
return Object.defineProperties({}, definition);
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
let hasNextPage = false;
|
|
176
|
-
let hasPreviousPage = false;
|
|
177
|
-
if (adjustForPagination && rs.length) (({ hasPreviousPage, hasNextPage } = DataService.paginateResultSet(rs, first, after, last, before)));
|
|
178
|
-
|
|
179
|
-
return Object.defineProperties(rs, {
|
|
180
|
-
$$pageInfo: {
|
|
181
|
-
get() {
|
|
182
|
-
const edges = ensureArray(rs);
|
|
183
|
-
|
|
184
|
-
return {
|
|
185
|
-
startCursor: get(edges, '0.$$cursor', ''),
|
|
186
|
-
endCursor: get(edges, `${edges.length - 1}.$$cursor`, ''),
|
|
187
|
-
hasPreviousPage,
|
|
188
|
-
hasNextPage,
|
|
189
|
-
};
|
|
190
|
-
},
|
|
191
|
-
enumerable: false,
|
|
192
|
-
},
|
|
193
|
-
$$isResultSet: {
|
|
194
|
-
value: true,
|
|
195
|
-
enumerable: false,
|
|
196
|
-
},
|
|
197
|
-
toObject: {
|
|
198
|
-
get() {
|
|
199
|
-
return () => map(this, doc => Object.entries(doc).reduce((prev, [key, value]) => {
|
|
200
|
-
if (value === undefined) return prev;
|
|
201
|
-
prev[key] = get(value, '$$isResultSet') ? value.toObject() : value;
|
|
202
|
-
return prev;
|
|
203
|
-
}, {}));
|
|
204
|
-
},
|
|
205
|
-
enumerable: false,
|
|
206
|
-
configurable: true,
|
|
207
|
-
},
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
};
|
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
|
-
};
|
|
Binary file
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
const { Kind, visit } = require('graphql');
|
|
2
|
-
const Node = require('./Node');
|
|
3
|
-
|
|
4
|
-
module.exports = class Field extends Node {
|
|
5
|
-
constructor(ast) {
|
|
6
|
-
super(ast);
|
|
7
|
-
// this.fields = {};
|
|
8
|
-
// if (ast) this.appendAST(ast);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
appendAST(ast) {
|
|
12
|
-
// visit(ast, {
|
|
13
|
-
// [Kind.FIELD_DEFINITION]: (node) => {
|
|
14
|
-
// const name = node.name.value;
|
|
15
|
-
// if (this.fields[name]) this.fields[name].appendAST(node);
|
|
16
|
-
// else this.fields[name] = new Field(node);
|
|
17
|
-
// },
|
|
18
|
-
// });
|
|
19
|
-
}
|
|
20
|
-
};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
const { graphql, execute, validate } = require('graphql');
|
|
2
|
-
const Schema = require('./Schema');
|
|
3
|
-
|
|
4
|
-
module.exports = class GraphQL {
|
|
5
|
-
constructor(schema) {
|
|
6
|
-
this.schema = (schema instanceof Schema ? schema : new Schema(schema)).makeExecutableSchema();
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
exec(source, variableValues) {
|
|
10
|
-
const { schema } = this.schema;
|
|
11
|
-
return graphql({ schema, source, variableValues, contextValue: schema.context });
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
execute(source, variableValues) {
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
validate(source, variableValues) {
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
const { Kind, visit } = require('graphql');
|
|
2
|
-
const Field = require('./Field');
|
|
3
|
-
const Node = require('./Node');
|
|
4
|
-
|
|
5
|
-
module.exports = class Model extends Node {
|
|
6
|
-
constructor(ast) {
|
|
7
|
-
super(ast);
|
|
8
|
-
this.fields = {};
|
|
9
|
-
if (ast) this.appendAST(ast);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
appendAST(ast) {
|
|
13
|
-
visit(ast, {
|
|
14
|
-
[Kind.FIELD_DEFINITION]: (node) => {
|
|
15
|
-
const name = node.name.value;
|
|
16
|
-
if (this.fields[name]) this.fields[name].appendAST(node);
|
|
17
|
-
else this.fields[name] = new Field(node);
|
|
18
|
-
},
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
return this;
|
|
22
|
-
}
|
|
23
|
-
};
|
package/src/graphql/core/Node.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
const { Kind } = require('graphql');
|
|
2
|
-
|
|
3
|
-
module.exports = class Node {
|
|
4
|
-
constructor(ast) {
|
|
5
|
-
this.ast = ast;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
getKind() {
|
|
9
|
-
return this.ast.kind;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
getName() {
|
|
13
|
-
return this.ast.name.value;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
getValue(ast = this.ast) {
|
|
17
|
-
const { value = {} } = ast;
|
|
18
|
-
|
|
19
|
-
switch (value.kind) {
|
|
20
|
-
case Kind.NULL: return null;
|
|
21
|
-
case Kind.LIST: return value.values.map(el => this.getValue({ value: el }));
|
|
22
|
-
case Kind.OBJECT: {
|
|
23
|
-
return value.fields.reduce((prev, field) => {
|
|
24
|
-
const node = new Node(field);
|
|
25
|
-
return Object.assign(prev, { [node.getName()]: node.getValue() });
|
|
26
|
-
}, {});
|
|
27
|
-
}
|
|
28
|
-
default: {
|
|
29
|
-
if (ast.values) return ast.values.map(v => v.name.value);
|
|
30
|
-
return value.value;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
};
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
const FS = require('fs');
|
|
2
|
-
const Glob = require('glob');
|
|
3
|
-
const Merge = require('deepmerge');
|
|
4
|
-
const { Kind, parse, visit, printSchema, buildSchema } = require('graphql');
|
|
5
|
-
const { makeExecutableSchema } = require('graphql-tools');
|
|
6
|
-
const Model = require('./Model');
|
|
7
|
-
|
|
8
|
-
const modelKinds = [Kind.OBJECT_TYPE_DEFINITION, Kind.OBJECT_TYPE_EXTENSION, Kind.INTERFACE_TYPE_DEFINITION, Kind.INTERFACE_TYPE_EXTENSION];
|
|
9
|
-
|
|
10
|
-
module.exports = class Schema {
|
|
11
|
-
constructor(schema) {
|
|
12
|
-
this.models = {};
|
|
13
|
-
this.schema = { typeDefs: [], context: {}, resolvers: {}, schemaDirectives: {} };
|
|
14
|
-
if (schema) this.appendSchema(schema);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
appendSchema(schema) {
|
|
18
|
-
// Normalize schema
|
|
19
|
-
if (typeof schema === 'string') schema = { typeDefs: [schema] };
|
|
20
|
-
else if (schema.typeDefs && !Array.isArray(schema.typeDefs)) schema.typeDefs = [schema.typeDefs];
|
|
21
|
-
|
|
22
|
-
// Merge schema
|
|
23
|
-
this.schema = Merge(this.schema, schema);
|
|
24
|
-
|
|
25
|
-
// Visit AST to maintain model definitions
|
|
26
|
-
if (schema.typeDefs) {
|
|
27
|
-
visit(parse(schema.typeDefs.join('\n')), {
|
|
28
|
-
enter: (node) => {
|
|
29
|
-
if (modelKinds.indexOf(node.kind) > -1) {
|
|
30
|
-
const name = node.name.value;
|
|
31
|
-
if (this.models[name]) this.models[name].appendAST(node);
|
|
32
|
-
else this.models[name] = new Model(node);
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return this;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
appendSchemaFromFile(file) {
|
|
42
|
-
if (file.endsWith('.js')) this.appendSchema(require(file)); // eslint-disable-line global-require,import/no-dynamic-require
|
|
43
|
-
else this.appendSchema(FS.readFileSync(file, 'utf8'));
|
|
44
|
-
return this;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
appendSchemaFromDirectory(dir, options) {
|
|
48
|
-
Glob.sync(`${dir}/**/*.{js,gql,graphql}`, options).forEach(file => this.appendSchemaFromFile(file));
|
|
49
|
-
return this;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
makeExecutableSchema() {
|
|
53
|
-
return makeExecutableSchema(this.schema);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
printSchema() {
|
|
57
|
-
return printSchema(buildSchema(this.toString()));
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
toString() {
|
|
61
|
-
return this.schema.typeDefs.join('\n');
|
|
62
|
-
}
|
|
63
|
-
};
|