@coderich/autograph 0.9.12 → 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.
@@ -0,0 +1,299 @@
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
+ if (data == null) return data;
8
+ const { resolver, model, sort, first, after, last, before } = query.toObject();
9
+ const fields = model.getFields().filter(f => f.getName() !== 'id');
10
+
11
+ const rs = map(data, (doc) => {
12
+ if (doc == null || typeof doc !== 'object') return doc;
13
+
14
+ //
15
+ const cache = new Map();
16
+
17
+ const definition = {
18
+ // $$model: model,
19
+ $$isResultSetItem: true,
20
+
21
+ get id() { return doc.id || doc[model.idKey()]; },
22
+ set id(id) { doc.id = id; }, // Embedded array of documents need to set id
23
+ get $id() { return toGUID(model.getName(), this.id); },
24
+
25
+ get $$cursor() {
26
+ const sortPaths = keyPaths(sort);
27
+ const sortValues = sortPaths.reduce((prv, path) => Object.assign(prv, { [path]: get(this, path) }), {});
28
+ const sortJSON = JSON.stringify(sortValues);
29
+ return Buffer.from(sortJSON).toString('base64');
30
+ },
31
+
32
+ $$save: input => resolver.match(model).id(this.id).save({ ...this, ...input }),
33
+ $$remove: () => resolver.match(model).id(this.id).remove(),
34
+ $$delete: () => resolver.match(model).id(this.id).delete(),
35
+
36
+ get toObject() {
37
+ return () => map(this, obj => Object.entries(obj).reduce((prev, [key, value]) => {
38
+ if (value === undefined) return prev;
39
+ prev[key] = get(value, '$$isResultSet') ? value.toObject() : value;
40
+ return prev;
41
+ }, {}));
42
+ },
43
+
44
+ ...fields.reduce((prev, field) => {
45
+ const key = field.getKey();
46
+ const name = field.getName();
47
+ const $name = `$${name}`;
48
+ const value = doc[key];
49
+
50
+ return {
51
+ ...prev,
52
+
53
+ // Deserialized field attributes
54
+ get [name]() {
55
+ if (cache.has(name)) return cache.get(name);
56
+ let $value = field.deserialize(query, value);
57
+ $value = $value != null && field.isEmbedded() ? new ResultSet(query.model(field.getModelRef()), $value, false) : $value;
58
+ cache.set(name, $value);
59
+ return $value;
60
+ },
61
+ set [name]($value) {
62
+ cache.set(name, $value);
63
+ },
64
+
65
+ // Fully deserialized, hydrated, and resolved field attributes
66
+ get [$name]() {
67
+ return (args = {}) => {
68
+ // Ensure where clause
69
+ args.where = args.where || {};
70
+
71
+ // Cache
72
+ const cacheKey = `${$name}-${hashObject(args)}`;
73
+ if (cache.has(cacheKey)) return cache.get(cacheKey);
74
+
75
+ const promise = new Promise((resolve, reject) => {
76
+ (() => {
77
+ const $value = this[name];
78
+
79
+ if (field.isScalar() || field.isEmbedded()) return Promise.resolve($value);
80
+
81
+ const modelRef = field.getModelRef();
82
+
83
+ if (field.isArray()) {
84
+ if (field.isVirtual()) {
85
+ args.where[[field.getVirtualField()]] = this.id; // Is where[[field.getVirtualField()]] correct?
86
+ return resolver.match(modelRef).merge(args).many();
87
+ }
88
+
89
+ // Not a "required" query + strip out nulls
90
+ args.where.id = $value;
91
+ return resolver.match(modelRef).merge(args).many();
92
+ }
93
+
94
+ if (field.isVirtual()) {
95
+ args.where[[field.getVirtualField()]] = this.id;
96
+ return resolver.match(modelRef).merge(args).one();
97
+ }
98
+
99
+ return resolver.match(modelRef).id($value).one({ required: field.isRequired() });
100
+ })().then((results) => {
101
+ if (results == null) return field.resolve(query, results); // Allow field to determine
102
+ return mapPromise(results, result => field.resolve(query, result)).then(() => results); // Resolve the inside fields but still return "results"!!!!
103
+ }).then((resolved) => {
104
+ resolve(resolved);
105
+ }).catch((e) => {
106
+ reject(e);
107
+ });
108
+ });
109
+
110
+ cache.set(cacheKey, promise);
111
+ return promise;
112
+ };
113
+ },
114
+
115
+ // Field count (let's assume it's a Connection Type - meaning dont try with anything else)
116
+ get [`${$name}:count`]() {
117
+ return (q = {}) => {
118
+ q.where = q.where || {};
119
+ if (field.isVirtual()) q.where[field.getVirtualField()] = this.id;
120
+ else q.where.id = this[name];
121
+ return resolver.match(field.getModelRef()).merge(q).count();
122
+ };
123
+ },
124
+ };
125
+ }, {}),
126
+ };
127
+
128
+ // const definition = fields.reduce((prev, field) => {
129
+ // const key = field.getKey();
130
+ // const name = field.getName();
131
+ // const $name = `$${name}`;
132
+ // const value = doc[key];
133
+
134
+ // return {
135
+ // ...prev,
136
+
137
+ // // Deserialized field attributes
138
+ // get [name]() {
139
+ // if (cache.has(name)) return cache.get(name);
140
+ // let $value = field.deserialize(query, value);
141
+ // $value = $value != null && field.isEmbedded() ? new ResultSet(query.model(field.getModelRef()), $value, false) : $value;
142
+ // cache.set(name, $value);
143
+ // return $value;
144
+ // },
145
+ // set [name]($value) {
146
+ // cache.set(name, $value);
147
+ // },
148
+
149
+ // // Fully deserialized, hydrated, and resolved field attributes
150
+ // get [$name]() {
151
+ // return (args = {}) => {
152
+ // // Ensure where clause
153
+ // args.where = args.where || {};
154
+
155
+ // // Cache
156
+ // const cacheKey = `${$name}-${hashObject(args)}`;
157
+ // if (cache.has(cacheKey)) return cache.get(cacheKey);
158
+
159
+ // const promise = new Promise((resolve, reject) => {
160
+ // (() => {
161
+ // const $value = this[name];
162
+
163
+ // if (field.isScalar() || field.isEmbedded()) return Promise.resolve($value);
164
+
165
+ // const modelRef = field.getModelRef();
166
+
167
+ // if (field.isArray()) {
168
+ // if (field.isVirtual()) {
169
+ // args.where[[field.getVirtualField()]] = this.id; // Is where[[field.getVirtualField()]] correct?
170
+ // return resolver.match(modelRef).merge(args).many();
171
+ // }
172
+
173
+ // // Not a "required" query + strip out nulls
174
+ // args.where.id = $value;
175
+ // return resolver.match(modelRef).merge(args).many();
176
+ // }
177
+
178
+ // if (field.isVirtual()) {
179
+ // args.where[[field.getVirtualField()]] = this.id;
180
+ // return resolver.match(modelRef).merge(args).one();
181
+ // }
182
+
183
+ // return resolver.match(modelRef).id($value).one({ required: field.isRequired() });
184
+ // })().then((results) => {
185
+ // if (results == null) return field.resolve(query, results); // Allow field to determine
186
+ // return mapPromise(results, result => field.resolve(query, result)).then(() => results); // Resolve the inside fields but still return "results"!!!!
187
+ // }).then((resolved) => {
188
+ // resolve(resolved);
189
+ // }).catch((e) => {
190
+ // reject(e);
191
+ // });
192
+ // });
193
+
194
+ // cache.set(cacheKey, promise);
195
+ // return promise;
196
+ // };
197
+ // },
198
+
199
+ // // Field count (let's assume it's a Connection Type - meaning dont try with anything else)
200
+ // get [`${$name}:count`]() {
201
+ // return (q = {}) => {
202
+ // q.where = q.where || {};
203
+ // if (field.isVirtual()) q.where[field.getVirtualField()] = this.id;
204
+ // else q.where.id = this[name];
205
+ // return resolver.match(field.getModelRef()).merge(q).count();
206
+ // };
207
+ // },
208
+ // };
209
+ // }, {
210
+ // get id() { return doc.id || doc[model.idKey()]; },
211
+ // set id(id) { doc.id = id; }, // Embedded array of documents need to set id
212
+
213
+ // get $id() { return toGUID(model.getName(), this.id); },
214
+
215
+ // get $$cursor() {
216
+ // const sortPaths = keyPaths(sort);
217
+ // const sortValues = sortPaths.reduce((prv, path) => Object.assign(prv, { [path]: get(this, path) }), {});
218
+ // const sortJSON = JSON.stringify(sortValues);
219
+ // return Buffer.from(sortJSON).toString('base64');
220
+ // },
221
+
222
+ // $$model: model,
223
+ // $$isResultSetItem: true,
224
+ // $$save: input => resolver.match(model).id(this.id).save({ ...this, ...input }),
225
+ // $$remove: () => resolver.match(model).id(this.id).remove(),
226
+ // $$delete: () => resolver.match(model).id(this.id).delete(),
227
+
228
+ // get toObject() {
229
+ // return () => map(this, obj => Object.entries(obj).reduce((prev, [key, value]) => {
230
+ // if (value === undefined) return prev;
231
+ // prev[key] = get(value, '$$isResultSet') ? value.toObject() : value;
232
+ // return prev;
233
+ // }, {}));
234
+ // },
235
+ // });
236
+
237
+ return definition;
238
+ });
239
+
240
+ let hasNextPage = false;
241
+ let hasPreviousPage = false;
242
+ if (adjustForPagination && rs.length) (({ hasPreviousPage, hasNextPage } = DataService.paginateResultSet(rs, first, after, last, before)));
243
+
244
+ return Object.defineProperties(rs, {
245
+ $$pageInfo: {
246
+ get() {
247
+ const edges = ensureArray(rs);
248
+
249
+ return {
250
+ startCursor: get(edges, '0.$$cursor', ''),
251
+ endCursor: get(edges, `${edges.length - 1}.$$cursor`, ''),
252
+ hasPreviousPage,
253
+ hasNextPage,
254
+ };
255
+ },
256
+ enumerable: false,
257
+ },
258
+ $$isResultSet: {
259
+ value: true,
260
+ enumerable: false,
261
+ },
262
+ toObject: {
263
+ get() {
264
+ return () => map(this, doc => Object.entries(doc).reduce((prev, [key, value]) => {
265
+ if (value === undefined) return prev;
266
+ prev[key] = get(value, '$$isResultSet') ? value.toObject() : value;
267
+ return prev;
268
+ }, {}));
269
+ },
270
+ enumerable: false,
271
+ configurable: true,
272
+ },
273
+ });
274
+
275
+ // const idk = {
276
+ // ...rs,
277
+ // $$isResultSet: true,
278
+ // get $$pageInfo() {
279
+ // const edges = ensureArray(rs);
280
+
281
+ // return {
282
+ // startCursor: get(edges, '0.$$cursor', ''),
283
+ // endCursor: get(edges, `${edges.length - 1}.$$cursor`, ''),
284
+ // hasPreviousPage,
285
+ // hasNextPage,
286
+ // };
287
+ // },
288
+ // get toObject() {
289
+ // return () => map(this, doc => Object.entries(doc).reduce((prev, [key, value]) => {
290
+ // if (value === undefined) return prev;
291
+ // prev[key] = get(value, '$$isResultSet') ? value.toObject() : value;
292
+ // return prev;
293
+ // }, {}));
294
+ // },
295
+ // };
296
+
297
+ // return idk;
298
+ }
299
+ };
@@ -4,6 +4,8 @@ const { map, ensureArray, keyPaths, mapPromise, toGUID, hashObject } = require('
4
4
 
5
5
  module.exports = class ResultSet {
6
6
  constructor(query, data, adjustForPagination = true) {
7
+ if (data == null) return data;
8
+
7
9
  const { resolver, model, sort, first, after, last, before } = query.toObject();
8
10
  const fields = model.getFields().filter(f => f.getName() !== 'id');
9
11
 
@@ -13,80 +15,15 @@ module.exports = class ResultSet {
13
15
  //
14
16
  const cache = new Map();
15
17
 
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) => {
18
+ const definition = fields.reduce((prev, field) => {
83
19
  const key = field.getKey();
84
20
  const name = field.getName();
85
21
  const $name = `$${name}`;
86
22
  const value = doc[key];
87
23
 
88
- // Field attributes
89
- definition[name] = {
24
+ // Deserialized field attributes
25
+ prev[name] = {
26
+ // value,
90
27
  get() {
91
28
  if (cache.has(name)) return cache.get(name);
92
29
  let $value = field.deserialize(query, value);
@@ -101,8 +38,9 @@ module.exports = class ResultSet {
101
38
  configurable: true, // Allows things like delete
102
39
  };
103
40
 
104
- // Hydrated field attributes
105
- definition[`$${name}`] = {
41
+ // Fully deserialized, hydrated, and resolved field attributes
42
+ prev[$name] = {
43
+ // value: () => value,
106
44
  get() {
107
45
  return (args = {}) => {
108
46
  // Ensure where clause
@@ -155,7 +93,7 @@ module.exports = class ResultSet {
155
93
  };
156
94
 
157
95
  // Field count (let's assume it's a Connection Type - meaning dont try with anything else)
158
- definition[`$${name}:count`] = {
96
+ prev[`${$name}:count`] = {
159
97
  get() {
160
98
  return (q = {}) => {
161
99
  q.where = q.where || {};
@@ -166,6 +104,66 @@ module.exports = class ResultSet {
166
104
  },
167
105
  enumerable: false,
168
106
  };
107
+
108
+ return prev;
109
+ }, {
110
+ id: {
111
+ get() { return doc.id || doc[model.idKey()]; },
112
+ set(id) { doc.id = id; }, // Embedded array of documents need to set id
113
+ enumerable: true,
114
+ },
115
+
116
+ $id: {
117
+ get() { return toGUID(model.getName(), this.id); },
118
+ enumerable: false,
119
+ },
120
+
121
+ $$cursor: {
122
+ get() {
123
+ const sortPaths = keyPaths(sort);
124
+ const sortValues = sortPaths.reduce((prv, path) => Object.assign(prv, { [path]: get(this, path) }), {});
125
+ const sortJSON = JSON.stringify(sortValues);
126
+ return Buffer.from(sortJSON).toString('base64');
127
+ },
128
+ enumerable: false,
129
+ },
130
+
131
+ $$model: {
132
+ value: model,
133
+ enumerable: false,
134
+ },
135
+
136
+ $$isResultSetItem: {
137
+ value: true,
138
+ enumerable: false,
139
+ },
140
+
141
+ $$save: {
142
+ get() { return input => resolver.match(model).id(this.id).save({ ...this, ...input }); },
143
+ enumerable: false,
144
+ },
145
+
146
+ $$remove: {
147
+ get() { return () => resolver.match(model).id(this.id).remove(); },
148
+ enumerable: false,
149
+ },
150
+
151
+ $$delete: {
152
+ get() { return () => resolver.match(model).id(this.id).delete(); },
153
+ enumerable: false,
154
+ },
155
+
156
+ toObject: {
157
+ get() {
158
+ return () => map(this, obj => Object.entries(obj).reduce((prev, [key, value]) => {
159
+ if (value === undefined) return prev;
160
+ prev[key] = get(value, '$$isResultSet') ? value.toObject() : value;
161
+ return prev;
162
+ }, {}));
163
+ },
164
+ enumerable: false,
165
+ configurable: true,
166
+ },
169
167
  });
170
168
 
171
169
  // Create and return ResultSetItem
@@ -148,15 +148,15 @@ module.exports = class MongoDriver {
148
148
  }
149
149
 
150
150
  static getAddFields(query) {
151
- const { schema, where } = query;
151
+ const { shape, where } = query;
152
152
 
153
- return Object.entries(schema).reduce((prev, [key, { type }]) => {
154
- const value = where[key];
153
+ return shape.reduce((prev, { from, type }) => {
154
+ const value = where[from];
155
155
  if (value === undefined) return prev;
156
156
  if (!isScalarDataType(type)) return prev;
157
157
  const stype = String((type === 'Float' || type === 'Int' ? 'Number' : type)).toLowerCase();
158
158
  if (String(typeof value) === `${stype}`) return prev;
159
- return Object.assign(prev, { [key]: { $toString: `$${key}` } });
159
+ return Object.assign(prev, { [from]: { $toString: `$${from}` } });
160
160
  }, {});
161
161
  }
162
162
 
@@ -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();
@@ -251,7 +251,7 @@ module.exports = class Query {
251
251
  return {
252
252
  isNative: Boolean(this.props.native),
253
253
  model: model.getKey(),
254
- schema: Query.getSchema(model),
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(el => fn(el));
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
+ };