@coderich/autograph 0.13.38 → 0.13.39

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@coderich/autograph",
3
3
  "main": "index.js",
4
- "version": "0.13.38",
4
+ "version": "0.13.39",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -15,7 +15,7 @@
15
15
  "dev": "coderich-dev"
16
16
  },
17
17
  "dependencies": {
18
- "@coderich/util": "1.0.3",
18
+ "@coderich/util": "1.0.4",
19
19
  "@graphql-tools/merge": "9.0.0",
20
20
  "@graphql-tools/resolvers-composition": "7.0.0",
21
21
  "@hapi/boom": "10.0.1",
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "devDependencies": {
34
34
  "@apollo/server": "4.9.5",
35
- "@coderich/autograph-mongodb": "0.0.2",
35
+ "@coderich/autograph-mongodb": "0.0.4",
36
36
  "@coderich/dev": "0.2.1",
37
37
  "@graphql-tools/schema": "10.0.0",
38
38
  "graphql": "16.8.1",
@@ -24,16 +24,63 @@ module.exports = class Loader {
24
24
  }
25
25
 
26
26
  #resolve(queries) {
27
- return Promise.all(queries.map((query) => {
28
- const dquery = query.toDriver();
29
- const $query = dquery.toObject();
27
+ /**
28
+ * Batch queries can save resources and network round-trip latency. However, we have to be careful to
29
+ * preserve the order and adhere to the DataLoader API. This step simply creates a map of batch
30
+ * queries to run; saving the order ("i") along with useful query information
31
+ */
32
+ const batchesByKey = queries.reduce((prev, query, i) => {
33
+ const $query = query.toDriver().toObject();
34
+ const key = $query.batch ?? '__default__';
35
+ const [values] = key === '__default__' ? [] : Object.values(Util.flatten($query.where, { safe: true }));
36
+ const $values = Util.ensureArray(values).map(value => (value instanceof RegExp ? value : new RegExp(`${value}`, 'i')));
37
+ prev[key] = prev[key] || [];
38
+ prev[key].push({ query, $query, values, $values, i });
39
+ return prev;
40
+ }, {});
30
41
 
31
- return this.#model.source.client.resolve($query).then((data) => {
42
+ return Promise.all(Object.entries(batchesByKey).map(([key, batches]) => {
43
+ switch (key) {
44
+ case '__default__': {
45
+ return batches.map(batch => this.#model.source.client.resolve(batch.$query).then(data => ({ data, ...batch })));
46
+ }
47
+ default: {
48
+ const values = Array.from(new Set(batches.map(batch => batch.values).flat()));
49
+ const $query = { ...batches[0].$query, op: 'findMany', where: { [key]: values } };
50
+ return this.#model.source.client.resolve($query).then((docs) => {
51
+ return batches.map((batch) => {
52
+ const matches = docs.filter((doc) => {
53
+ let match = false;
54
+ Util.pathmap(key, doc, (mixed) => {
55
+ match = match || Util.ensureArray(mixed).some(value => batch.$values.some($value => `${value}`.match($value)));
56
+ return mixed;
57
+ });
58
+ return match;
59
+ });
60
+ const data = batch.$query.op === 'findOne' ? matches[0] : matches;
61
+ return { data, ...batch };
62
+ });
63
+ });
64
+ }
65
+ }
66
+ }).flat()).then((results) => {
67
+ return results.flat().sort((a, b) => a.i - b.i).map(({ query, $query, data }) => {
32
68
  if (data == null) return null; // Explicit return null;
33
69
  if ($query.isCursorPaging && Array.isArray(data)) data = Loader.#paginateResults(data, query.toObject());
34
70
  return this.#resolver.toResultSet(this.#model, data);
35
71
  });
36
- }));
72
+ });
73
+
74
+ // return Promise.all(queries.map((query, i) => {
75
+ // const dquery = query.toDriver();
76
+ // const $query = dquery.toObject();
77
+
78
+ // return this.#model.source.client.resolve($query).then((data) => {
79
+ // if (data == null) return null; // Explicit return null;
80
+ // if ($query.isCursorPaging && Array.isArray(data)) data = Loader.#paginateResults(data, query.toObject());
81
+ // return this.#resolver.toResultSet(this.#model, data);
82
+ // });
83
+ // }));
37
84
  }
38
85
 
39
86
  static #paginateResults(rs, query) {
@@ -1,5 +1,5 @@
1
1
  const Util = require('@coderich/util');
2
- const { isGlob, globToRegex, mergeDeep, finalizeWhereClause, JSONParse } = require('../service/AppService');
2
+ const { isGlob, globToRegex, mergeDeep, JSONParse } = require('../service/AppService');
3
3
 
4
4
  module.exports = class Query {
5
5
  #config;
@@ -89,7 +89,7 @@ module.exports = class Query {
89
89
  * Finalize the query for the driver
90
90
  */
91
91
  #finalize(query) {
92
- const { where = {}, sort = {} } = query;
92
+ const { where = {}, sort = {}, op } = query;
93
93
  const flatSort = Util.flatten(sort, { safe: true });
94
94
  const flatWhere = Util.flatten(where, { safe: true });
95
95
  const $sort = Util.unflatten(Object.keys(flatSort).reduce((prev, key) => Object.assign(prev, { [key]: {} }), {}), { safe: true });
@@ -101,11 +101,11 @@ module.exports = class Query {
101
101
  }, { key: 'key' });
102
102
 
103
103
  // Reconstruct the where clause by pulling out anything that requires a join
104
- query.where = finalizeWhereClause(Util.unflatten(Object.entries(flatWhere).reduce((prev, [key, value]) => {
104
+ query.where = Object.entries(flatWhere).reduce((prev, [key, value]) => {
105
105
  if (this.#model.isJoinPath(key, 'key')) return prev;
106
106
  value = Util.map(value, el => (isGlob(el) ? globToRegex(el) : el));
107
107
  return Object.assign(prev, { [key]: value });
108
- }, {}), { safe: true }));
108
+ }, {});
109
109
 
110
110
  // Determine what join data is needed (derived from where + sort)
111
111
  const joinData = mergeDeep($sort, Util.unflatten(Object.entries(flatWhere).reduce((prev, [key, value]) => {
@@ -113,6 +113,9 @@ module.exports = class Query {
113
113
  return prev;
114
114
  }, {}), { safe: true }));
115
115
 
116
+ // If we have 1 field in where clause this is a candidate for batching
117
+ query.batch = (op === 'findOne' || op === 'findMany') && Object.keys(query.where).length === 1 ? Object.keys(query.where)[0] : '__default__';
118
+
116
119
  // Construct joins
117
120
  query.joins = [];
118
121
 
@@ -17,14 +17,6 @@ exports.hashObject = obj => ObjectHash(obj, { respectType: false, respectFunctio
17
17
  exports.fromGUID = guid => Buffer.from(`${guid}`, 'base64').toString('ascii').split(',');
18
18
  exports.guidToId = (autograph, guid) => (autograph.legacyMode ? guid : exports.uvl(exports.fromGUID(guid)[1], guid));
19
19
 
20
- exports.finalizeWhereClause = (obj, arrayOp = '$in') => {
21
- return Object.entries(Util.flatten(obj, { safe: true })).reduce((prev, [key, value]) => {
22
- const isArray = Array.isArray(value);
23
- if (isArray) return Object.assign(prev, { [key]: { [arrayOp]: value } });
24
- return Object.assign(prev, { [key]: value });
25
- }, {});
26
- };
27
-
28
20
  exports.getGQLReturnType = (info) => {
29
21
  const returnType = `${info.returnType}`;
30
22
  const typeMap = { array: /^\[.+\].?$/, connection: /.+Connection!?$/, number: /^(Int|Float)!?$/, scalar: /.*/ };