@snowtop/ent 0.2.5 → 0.2.7

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.
Files changed (104) hide show
  1. package/action/action.js +5 -5
  2. package/action/executor.d.ts +1 -1
  3. package/action/executor.js +4 -4
  4. package/action/experimental_action.js +5 -5
  5. package/action/operations.js +17 -7
  6. package/action/orchestrator.d.ts +2 -2
  7. package/action/orchestrator.js +17 -7
  8. package/action/privacy.d.ts +2 -2
  9. package/action/relative_value.js +3 -3
  10. package/auth/auth.d.ts +0 -1
  11. package/auth/auth.js +4 -5
  12. package/core/async_utils.d.ts +1 -0
  13. package/core/async_utils.js +29 -0
  14. package/core/base.d.ts +1 -1
  15. package/core/base.js +5 -5
  16. package/core/cache_utils.d.ts +1 -0
  17. package/core/cache_utils.js +28 -0
  18. package/core/clause.js +76 -67
  19. package/core/config.d.ts +3 -1
  20. package/core/config.js +29 -9
  21. package/core/context.d.ts +3 -2
  22. package/core/context.js +96 -25
  23. package/core/convert.d.ts +0 -1
  24. package/core/convert.js +16 -17
  25. package/core/date.js +1 -2
  26. package/core/db.js +17 -7
  27. package/core/ent.d.ts +4 -2
  28. package/core/ent.js +111 -106
  29. package/core/global_schema.js +6 -7
  30. package/core/loaders/assoc_count_loader.d.ts +2 -2
  31. package/core/loaders/assoc_count_loader.js +18 -8
  32. package/core/loaders/assoc_edge_loader.d.ts +5 -2
  33. package/core/loaders/assoc_edge_loader.js +87 -31
  34. package/core/loaders/index.d.ts +2 -0
  35. package/core/loaders/index.js +8 -1
  36. package/core/loaders/loader.d.ts +33 -0
  37. package/core/loaders/loader.js +159 -3
  38. package/core/loaders/object_loader.d.ts +7 -5
  39. package/core/loaders/object_loader.js +97 -74
  40. package/core/loaders/query_loader.d.ts +2 -2
  41. package/core/loaders/query_loader.js +60 -24
  42. package/core/loaders/raw_count_loader.d.ts +4 -4
  43. package/core/loaders/raw_count_loader.js +34 -24
  44. package/core/logger.js +6 -7
  45. package/core/metrics.d.ts +22 -0
  46. package/core/metrics.js +31 -0
  47. package/core/privacy.d.ts +2 -2
  48. package/core/privacy.js +4 -5
  49. package/core/query/assoc_query.js +17 -7
  50. package/core/query/query.js +17 -7
  51. package/core/query/shared_assoc_test.js +1 -2
  52. package/core/query_impl.js +4 -5
  53. package/core/viewer.d.ts +2 -2
  54. package/graphql/graphql_field_helpers.js +22 -22
  55. package/graphql/mutations/union.js +1 -2
  56. package/graphql/node_resolver.js +7 -7
  57. package/graphql/query/shared_assoc_test.js +1 -2
  58. package/graphql/scalars/date.js +8 -3
  59. package/graphql/scalars/time.d.ts +1 -1
  60. package/imports/dataz/example1/_auth.js +14 -10
  61. package/imports/index.js +18 -9
  62. package/index.d.ts +2 -1
  63. package/index.js +22 -9
  64. package/names/names.js +61 -18
  65. package/package.json +14 -17
  66. package/parse_schema/parse.js +2 -3
  67. package/schema/binary_field.js +3 -3
  68. package/schema/field.js +45 -35
  69. package/schema/json_field.js +7 -7
  70. package/schema/schema.js +12 -12
  71. package/schema/struct_field.js +4 -4
  72. package/schema/union_field.js +3 -3
  73. package/scripts/custom_compiler.js +17 -7
  74. package/scripts/custom_graphql.js +17 -7
  75. package/scripts/fix_action_exports.js +17 -7
  76. package/scripts/move_types.js +17 -7
  77. package/scripts/read_schema.js +17 -7
  78. package/testutils/action/complex_schemas.js +28 -18
  79. package/testutils/builder.d.ts +1 -1
  80. package/testutils/builder.js +7 -7
  81. package/testutils/db/fixture.js +1 -2
  82. package/testutils/db/temp_db.js +54 -44
  83. package/testutils/db/value.js +3 -4
  84. package/testutils/db_mock.js +12 -0
  85. package/testutils/ent-graphql-tests/index.d.ts +3 -3
  86. package/testutils/ent-graphql-tests/index.js +27 -18
  87. package/testutils/fake_data/const.js +2 -2
  88. package/testutils/fake_data/fake_contact.js +20 -10
  89. package/testutils/fake_data/fake_event.js +20 -10
  90. package/testutils/fake_data/fake_tag.js +21 -11
  91. package/testutils/fake_data/fake_user.js +21 -11
  92. package/testutils/fake_data/test_helpers.js +17 -17
  93. package/testutils/fake_data/user_query.js +19 -9
  94. package/testutils/parse_sql.js +151 -43
  95. package/testutils/query.js +2 -3
  96. package/testutils/soft_delete.js +17 -7
  97. package/testutils/test_edge_global_schema.js +17 -7
  98. package/testutils/write.js +20 -11
  99. package/tsc/ast.js +27 -18
  100. package/tsc/compilerOptions.js +22 -13
  101. package/tsc/move_generated.js +18 -9
  102. package/tsc/transform.js +18 -9
  103. package/tsc/transform_action.js +17 -7
  104. package/tsc/transform_schema.js +17 -7
@@ -15,33 +15,59 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
37
  };
28
38
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.ObjectLoaderFactory = exports.ObjectCountLoader = exports.ObjectLoader = void 0;
30
- const dataloader_1 = __importDefault(require("dataloader"));
39
+ exports.ObjectLoaderFactory = exports.ObjectCountLoader = exports.ObjectLoader = exports.mapWithConcurrency = void 0;
40
+ exports.setClauseLoaderConcurrency = setClauseLoaderConcurrency;
31
41
  const ent_1 = require("../ent");
42
+ const async_utils_1 = require("../async_utils");
43
+ Object.defineProperty(exports, "mapWithConcurrency", { enumerable: true, get: function () { return async_utils_1.mapWithConcurrency; } });
32
44
  const clause = __importStar(require("../clause"));
33
45
  const logger_1 = require("../logger");
34
46
  const clause_1 = require("../clause");
35
47
  const loader_1 = require("./loader");
36
48
  const memoizee_1 = __importDefault(require("memoizee"));
49
+ const DEFAULT_CLAUSE_LOADER_CONCURRENCY = 10;
50
+ let clauseLoaderConcurrency = DEFAULT_CLAUSE_LOADER_CONCURRENCY;
51
+ function setClauseLoaderConcurrency(limit) {
52
+ if (!Number.isFinite(limit) || limit < 1) {
53
+ clauseLoaderConcurrency = DEFAULT_CLAUSE_LOADER_CONCURRENCY;
54
+ return;
55
+ }
56
+ clauseLoaderConcurrency = Math.floor(limit);
57
+ }
37
58
  async function loadRowsForIDLoader(options, ids, context) {
38
59
  let col = options.key;
39
- const cls = (0, clause_1.getCombinedClause)(options, clause.DBTypeIn(col, ids, options.keyType || "uuid"));
40
- const rowOptions = {
41
- ...options,
42
- clause: cls,
43
- context,
44
- };
60
+ const typ = options.keyType || "uuid";
61
+ const maxBatchSize = (0, loader_1.getLoaderMaxBatchSize)();
62
+ const batches = [];
63
+ if (maxBatchSize > 0 && ids.length > maxBatchSize) {
64
+ for (let i = 0; i < ids.length; i += maxBatchSize) {
65
+ batches.push(ids.slice(i, i + maxBatchSize));
66
+ }
67
+ }
68
+ else {
69
+ batches.push(ids);
70
+ }
45
71
  let m = new Map();
46
72
  let result = [];
47
73
  for (let i = 0; i < ids.length; i++) {
@@ -49,33 +75,43 @@ async function loadRowsForIDLoader(options, ids, context) {
49
75
  // store the index....
50
76
  m.set(ids[i], i);
51
77
  }
52
- const rows = (await (0, ent_1.loadRows)(rowOptions));
53
- for (const row of rows) {
54
- const id = row[col];
55
- if (id === undefined) {
56
- throw new Error(`need to query for column ${col} when using an object loader because the query may not be sorted and we need the id to maintain sort order`);
57
- }
58
- const idx = m.get(id);
59
- if (idx === undefined) {
60
- throw new Error(`malformed query. got ${id} back but didn't query for it`);
78
+ for (const batch of batches) {
79
+ const cls = (0, clause_1.getCombinedClause)(options, clause.DBTypeIn(col, batch, typ));
80
+ const rowOptions = {
81
+ ...options,
82
+ clause: cls,
83
+ context,
84
+ };
85
+ const rows = (await (0, ent_1.loadRows)(rowOptions));
86
+ for (const row of rows) {
87
+ const id = row[col];
88
+ if (id === undefined) {
89
+ throw new Error(`need to query for column ${col} when using an object loader because the query may not be sorted and we need the id to maintain sort order`);
90
+ }
91
+ const idx = m.get(id);
92
+ if (idx === undefined) {
93
+ throw new Error(`malformed query. got ${id} back but didn't query for it`);
94
+ }
95
+ result[idx] = row;
61
96
  }
62
- result[idx] = row;
63
97
  }
64
98
  return result;
65
99
  }
66
- async function loadRowsForClauseLoader(options, clause) {
100
+ async function loadRowsForClauseLoader(options, clause, context) {
67
101
  const rowOptions = {
68
102
  ...options,
69
103
  // @ts-expect-error clause in LoadRowOptions doesn't take templatized version of Clause
70
104
  clause: (0, clause_1.getCombinedClause)(options, clause, true),
105
+ context,
71
106
  };
72
107
  return (await (0, ent_1.loadRows)(rowOptions));
73
108
  }
74
- async function loadCountForClauseLoader(options, clause) {
109
+ async function loadCountForClauseLoader(options, clause, context) {
75
110
  const rowOptions = {
76
111
  ...options,
77
112
  // @ts-expect-error clause in LoadRowOptions doesn't take templatized version of Clause
78
113
  clause: (0, clause_1.getCombinedClause)(options, clause, true),
114
+ context,
79
115
  };
80
116
  const row = await (0, ent_1.loadRow)({
81
117
  ...rowOptions,
@@ -89,19 +125,19 @@ async function loadCountForClauseLoader(options, clause) {
89
125
  // optional clause...
90
126
  // so ObjectLoaderFactory and createDataLoader need to take a new optional field which is a clause that's always added here
91
127
  // and we need a disableTransform which skips loader completely and uses loadRow...
92
- function createDataLoader(options) {
93
- const loaderOptions = {};
94
- // if query logging is enabled, we should log what's happening with loader
95
- if ((0, logger_1.logEnabled)("query")) {
96
- loaderOptions.cacheMap = new loader_1.CacheMap(options);
97
- }
98
- return new dataloader_1.default(async (ids) => {
128
+ function createDataLoader(options, context) {
129
+ const loaderName = `objectLoader:${options.tableName}:${options.key}`;
130
+ const loaderOptions = {
131
+ maxBatchSize: (0, loader_1.getLoaderMaxBatchSize)(),
132
+ cacheMap: (0, loader_1.createLoaderCacheMap)(options),
133
+ };
134
+ return new loader_1.InstrumentedDataLoader(loaderName, async (ids) => {
99
135
  if (!ids.length) {
100
136
  return [];
101
137
  }
102
- // context not needed because we're creating a loader which has its own cache which is being used here
103
- return loadRowsForIDLoader(options, ids);
104
- }, loaderOptions);
138
+ // pass context along so ContextCache is primed alongside DataLoader caching
139
+ return loadRowsForIDLoader(options, ids, context);
140
+ }, loaderOptions, options.tableName);
105
141
  }
106
142
  class clauseCacheMap {
107
143
  constructor(options, count) {
@@ -130,35 +166,32 @@ class clauseCacheMap {
130
166
  return this.m.clear();
131
167
  }
132
168
  }
133
- function createClauseDataLoder(options) {
134
- return new dataloader_1.default(async (clauses) => {
169
+ function createClauseCacheMap(options, count) {
170
+ return (0, loader_1.createBoundedCacheMap)(new clauseCacheMap(options, count), (key) => key.instanceKey());
171
+ }
172
+ function createClauseDataLoder(options, context) {
173
+ const loaderName = `objectLoader:clause:${options.tableName}`;
174
+ return new loader_1.InstrumentedDataLoader(loaderName, async (clauses) => {
135
175
  if (!clauses.length) {
136
176
  return [];
137
177
  }
138
- const ret = [];
139
- for await (const clause of clauses) {
140
- const data = await loadRowsForClauseLoader(options, clause);
141
- ret.push(data);
142
- }
143
- return ret;
178
+ return (0, async_utils_1.mapWithConcurrency)(clauses, clauseLoaderConcurrency, (clauseItem) => loadRowsForClauseLoader(options, clauseItem, context));
144
179
  }, {
145
- cacheMap: new clauseCacheMap(options),
146
- });
180
+ cacheMap: createClauseCacheMap(options),
181
+ maxBatchSize: (0, loader_1.getLoaderMaxBatchSize)(),
182
+ }, options.tableName, (key) => key.instanceKey());
147
183
  }
148
- function createClauseCountDataLoader(options) {
149
- return new dataloader_1.default(async (clauses) => {
184
+ function createClauseCountDataLoader(options, context) {
185
+ const loaderName = `objectLoader:count:${options.tableName}`;
186
+ return new loader_1.InstrumentedDataLoader(loaderName, async (clauses) => {
150
187
  if (!clauses.length) {
151
188
  return [];
152
189
  }
153
- const ret = [];
154
- for await (const clause of clauses) {
155
- const data = await loadCountForClauseLoader(options, clause);
156
- ret.push(data);
157
- }
158
- return ret;
190
+ return (0, async_utils_1.mapWithConcurrency)(clauses, clauseLoaderConcurrency, (clauseItem) => loadCountForClauseLoader(options, clauseItem, context));
159
191
  }, {
160
- cacheMap: new clauseCacheMap(options, true),
161
- });
192
+ cacheMap: createClauseCacheMap(options, true),
193
+ maxBatchSize: (0, loader_1.getLoaderMaxBatchSize)(),
194
+ }, options.tableName, (key) => `${key.instanceKey()}:count`);
162
195
  }
163
196
  class ObjectLoader {
164
197
  constructor(options, context, toPrime) {
@@ -169,8 +202,8 @@ class ObjectLoader {
169
202
  console.trace();
170
203
  }
171
204
  if (context) {
172
- this.idLoader = createDataLoader(options);
173
- this.clauseLoader = createClauseDataLoder(options);
205
+ this.idLoader = createDataLoader(options, context);
206
+ this.clauseLoader = createClauseDataLoder(options, context);
174
207
  }
175
208
  this.memoizedInitPrime = (0, memoizee_1.default)(this.initPrime.bind(this));
176
209
  }
@@ -225,7 +258,7 @@ class ObjectLoader {
225
258
  if (this.clauseLoader) {
226
259
  return this.clauseLoader.load(key);
227
260
  }
228
- return loadRowsForClauseLoader(this.options, key);
261
+ return loadRowsForClauseLoader(this.options, key, this.context);
229
262
  }
230
263
  clearAll() {
231
264
  this.idLoader && this.idLoader.clearAll();
@@ -252,12 +285,7 @@ class ObjectLoader {
252
285
  // @ts-expect-error TODO?
253
286
  return this.clauseLoader.loadMany(keys);
254
287
  }
255
- const res = [];
256
- for await (const key of keys) {
257
- const rows = await loadRowsForClauseLoader(this.options, key);
258
- res.push(rows);
259
- }
260
- return res;
288
+ return (0, async_utils_1.mapWithConcurrency)(keys, clauseLoaderConcurrency, (key) => loadRowsForClauseLoader(this.options, key, this.context));
261
289
  }
262
290
  prime(data) {
263
291
  // we have this data from somewhere else, prime it in the c
@@ -286,7 +314,7 @@ class ObjectCountLoader {
286
314
  this.options = options;
287
315
  this.context = context;
288
316
  if (context) {
289
- this.loader = createClauseCountDataLoader(options);
317
+ this.loader = createClauseCountDataLoader(options, context);
290
318
  }
291
319
  }
292
320
  getOptions() {
@@ -296,7 +324,7 @@ class ObjectCountLoader {
296
324
  if (this.loader) {
297
325
  return this.loader.load(key);
298
326
  }
299
- return loadCountForClauseLoader(this.options, key);
327
+ return loadCountForClauseLoader(this.options, key, this.context);
300
328
  }
301
329
  clearAll() {
302
330
  this.loader && this.loader.clearAll();
@@ -309,12 +337,7 @@ class ObjectCountLoader {
309
337
  // @ts-expect-error
310
338
  return this.loader.loadMany(keys);
311
339
  }
312
- const res = [];
313
- for await (const key of keys) {
314
- const r = await loadCountForClauseLoader(this.options, key);
315
- res.push(r);
316
- }
317
- return res;
340
+ return (0, async_utils_1.mapWithConcurrency)(keys, clauseLoaderConcurrency, (key) => loadCountForClauseLoader(this.options, key, this.context));
318
341
  }
319
342
  }
320
343
  exports.ObjectCountLoader = ObjectCountLoader;
@@ -5,10 +5,10 @@ import { ObjectLoaderFactory } from "./object_loader";
5
5
  declare class QueryDirectLoader<K extends any> implements Loader<K, Data[]> {
6
6
  private options;
7
7
  private queryOptions?;
8
- context?: Context<import("../base").Viewer<import("../base").Ent<any> | null, import("../base").ID | null>> | undefined;
8
+ context?: Context | undefined;
9
9
  private memoizedInitPrime;
10
10
  private primedLoaders;
11
- constructor(options: QueryOptions, queryOptions?: Partial<Pick<import("../base").QueryableDataOptions, "clause" | "limit" | "orderby" | "disableTransformations">> | undefined, context?: Context<import("../base").Viewer<import("../base").Ent<any> | null, import("../base").ID | null>> | undefined);
11
+ constructor(options: QueryOptions, queryOptions?: EdgeQueryableDataOptions | undefined, context?: Context | undefined);
12
12
  private initPrime;
13
13
  load(id: K): Promise<Data[]>;
14
14
  clearAll(): void;
@@ -15,23 +15,32 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
37
  };
28
38
  Object.defineProperty(exports, "__esModule", { value: true });
29
39
  exports.QueryLoaderFactory = void 0;
30
- const dataloader_1 = __importDefault(require("dataloader"));
31
40
  const memoizee_1 = __importDefault(require("memoizee"));
32
41
  const clause = __importStar(require("../clause"));
33
42
  const ent_1 = require("../ent");
34
- const logger_1 = require("../logger");
43
+ const cache_utils_1 = require("../cache_utils");
35
44
  const loader_1 = require("./loader");
36
45
  function getOrderByLocal(options, queryOptions) {
37
46
  return (options.orderby ??
@@ -42,7 +51,7 @@ function getOrderByLocal(options, queryOptions) {
42
51
  },
43
52
  ]);
44
53
  }
45
- async function simpleCase(options, id, queryOptions) {
54
+ async function simpleCase(options, id, queryOptions, context) {
46
55
  let cls;
47
56
  if (options.groupCol) {
48
57
  cls = clause.Eq(options.groupCol, id);
@@ -65,22 +74,27 @@ async function simpleCase(options, id, queryOptions) {
65
74
  clause: cls,
66
75
  orderby: getOrderByLocal(options, queryOptions),
67
76
  limit: queryOptions?.limit || (0, ent_1.getDefaultLimit)(),
77
+ context,
68
78
  });
69
79
  }
70
- function createLoader(options, queryOptions) {
71
- const loaderOptions = {};
72
- // if query logging is enabled, we should log what's happening with loader
73
- if ((0, logger_1.logEnabled)("query")) {
74
- loaderOptions.cacheMap = new loader_1.CacheMap(options);
75
- }
76
- return new dataloader_1.default(async (keys) => {
80
+ function createLoader(options, queryOptions, context) {
81
+ const loaderName = options.groupCol
82
+ ? `queryLoader:${options.tableName}:${options.groupCol}`
83
+ : options.clause
84
+ ? `queryLoader:${options.tableName}:${options.clause.instanceKey()}`
85
+ : `queryLoader:${options.tableName}`;
86
+ const loaderOptions = {
87
+ maxBatchSize: (0, loader_1.getLoaderMaxBatchSize)(),
88
+ cacheMap: (0, loader_1.createLoaderCacheMap)(options),
89
+ };
90
+ return new loader_1.InstrumentedDataLoader(loaderName, async (keys) => {
77
91
  if (!keys.length) {
78
92
  return [];
79
93
  }
80
94
  // keep query simple if we're only fetching for one id
81
95
  // or can't group because no groupCol...
82
96
  if (keys.length == 1 || !options.groupCol) {
83
- const rows = await simpleCase(options, keys[0], queryOptions);
97
+ const rows = await simpleCase(options, keys[0], queryOptions, context);
84
98
  return [rows];
85
99
  }
86
100
  let m = new Map();
@@ -121,7 +135,7 @@ function createLoader(options, queryOptions) {
121
135
  result[idx].push(row);
122
136
  }
123
137
  return result;
124
- }, loaderOptions);
138
+ }, loaderOptions, options.tableName);
125
139
  }
126
140
  class QueryDirectLoader {
127
141
  constructor(options, queryOptions, context) {
@@ -145,7 +159,7 @@ class QueryDirectLoader {
145
159
  this.primedLoaders = primedLoaders;
146
160
  }
147
161
  async load(id) {
148
- const rows = await simpleCase(this.options, id, this.queryOptions);
162
+ const rows = await simpleCase(this.options, id, this.queryOptions, this.context);
149
163
  if (this.context) {
150
164
  this.memoizedInitPrime();
151
165
  if (this.primedLoaders) {
@@ -171,7 +185,7 @@ class QueryLoader {
171
185
  this.context = context;
172
186
  this.queryOptions = queryOptions;
173
187
  if (context) {
174
- this.loader = createLoader(options, queryOptions);
188
+ this.loader = createLoader(options, queryOptions, context);
175
189
  }
176
190
  this.memoizedInitPrime = (0, memoizee_1.default)(this.initPrime.bind(this));
177
191
  }
@@ -205,7 +219,7 @@ class QueryLoader {
205
219
  }
206
220
  return rows;
207
221
  }
208
- return simpleCase(this.options, id, this.queryOptions);
222
+ return simpleCase(this.options, id, this.queryOptions, this.context);
209
223
  }
210
224
  clearAll() {
211
225
  this.loader && this.loader.clearAll();
@@ -231,10 +245,32 @@ class QueryLoaderFactory {
231
245
  return QueryLoaderFactory.createConfigurableLoader(this.name, this.options, options, context);
232
246
  }
233
247
  static createConfigurableLoader(name, queryOptions, options, context) {
234
- if (options.clause || !context) {
248
+ if (!context) {
235
249
  return new QueryDirectLoader(queryOptions, options, context);
236
250
  }
237
- const key = `${name}:limit:${options.limit}:orderby:${options.orderby}`;
251
+ if (options.clause) {
252
+ const effectiveOrderBy = getOrderByLocal(queryOptions, options);
253
+ const effectiveLimit = options.limit || (0, ent_1.getDefaultLimit)();
254
+ const disableTransformations = options.disableTransformations ?? false;
255
+ const keyParts = [
256
+ name,
257
+ `clause:${options.clause.instanceKey()}`,
258
+ queryOptions.clause
259
+ ? `baseClause:${queryOptions.clause.instanceKey()}`
260
+ : undefined,
261
+ `limit:${effectiveLimit}`,
262
+ `orderby:${(0, cache_utils_1.stableStringify)(effectiveOrderBy)}`,
263
+ `disableTransformations:${disableTransformations}`,
264
+ ];
265
+ const key = keyParts
266
+ .filter((part) => Boolean(part))
267
+ .join(":");
268
+ return (0, loader_1.getCustomLoader)(key, () => new QueryDirectLoader(queryOptions, options, context), context);
269
+ }
270
+ const effectiveOrderBy = getOrderByLocal(queryOptions, options);
271
+ const effectiveLimit = options.limit || (0, ent_1.getDefaultLimit)();
272
+ const disableTransformations = options.disableTransformations ?? false;
273
+ const key = `${name}:limit:${effectiveLimit}:orderby:${(0, cache_utils_1.stableStringify)(effectiveOrderBy)}:disableTransformations:${disableTransformations}`;
238
274
  return (0, loader_1.getCustomLoader)(key, () => new QueryLoader(queryOptions, context, options), context);
239
275
  }
240
276
  }
@@ -1,18 +1,18 @@
1
- import DataLoader from "dataloader";
2
1
  import { ID, Context, Loader, LoaderFactory, SelectBaseDataOptions } from "../base";
3
2
  import * as clause from "../clause";
3
+ import { InstrumentedDataLoader } from "./loader";
4
4
  interface QueryCountOptions {
5
5
  tableName: string;
6
6
  groupCol?: string;
7
7
  groupColType?: string;
8
8
  clause?: clause.Clause;
9
9
  }
10
- export declare function createCountDataLoader<K extends any>(options: QueryCountOptions): DataLoader<K, number, K>;
10
+ export declare function createCountDataLoader<K extends any>(options: QueryCountOptions, context?: Context): InstrumentedDataLoader<K, number>;
11
11
  export declare class RawCountLoader<K extends any> implements Loader<K, number> {
12
12
  private options;
13
- context?: Context<import("../base").Viewer<import("../base").Ent<any> | null, ID | null>> | undefined;
13
+ context?: Context | undefined;
14
14
  private loader;
15
- constructor(options: QueryCountOptions, context?: Context<import("../base").Viewer<import("../base").Ent<any> | null, ID | null>> | undefined);
15
+ constructor(options: QueryCountOptions, context?: Context | undefined);
16
16
  load(id: K): Promise<number>;
17
17
  clearAll(): void;
18
18
  }
@@ -15,22 +15,28 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
28
35
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.RawCountLoaderFactory = exports.RawCountLoader = exports.createCountDataLoader = void 0;
30
- const dataloader_1 = __importDefault(require("dataloader"));
36
+ exports.RawCountLoaderFactory = exports.RawCountLoader = void 0;
37
+ exports.createCountDataLoader = createCountDataLoader;
31
38
  const ent_1 = require("../ent");
32
39
  const clause = __importStar(require("../clause"));
33
- const logger_1 = require("../logger");
34
40
  const loader_1 = require("./loader");
35
41
  async function simpleCase(options, key, context) {
36
42
  let cls;
@@ -55,19 +61,23 @@ async function simpleCase(options, key, context) {
55
61
  });
56
62
  return [parseInt(row?.count, 10) || 0];
57
63
  }
58
- function createCountDataLoader(options) {
59
- const loaderOptions = {};
60
- // if query logging is enabled, we should log what's happening with loader
61
- if ((0, logger_1.logEnabled)("query")) {
62
- loaderOptions.cacheMap = new loader_1.CacheMap(options);
63
- }
64
- return new dataloader_1.default(async (keys) => {
64
+ function createCountDataLoader(options, context) {
65
+ const loaderName = options.groupCol
66
+ ? `rawCountLoader:${options.tableName}:${options.groupCol}`
67
+ : options.clause
68
+ ? `rawCountLoader:${options.tableName}:${options.clause.instanceKey()}`
69
+ : `rawCountLoader:${options.tableName}`;
70
+ const loaderOptions = {
71
+ maxBatchSize: (0, loader_1.getLoaderMaxBatchSize)(),
72
+ cacheMap: (0, loader_1.createLoaderCacheMap)(options),
73
+ };
74
+ return new loader_1.InstrumentedDataLoader(loaderName, async (keys) => {
65
75
  if (!keys.length) {
66
76
  return [];
67
77
  }
68
78
  // keep query simple if we're only fetching for one id
69
79
  if (keys.length == 1 || !options.groupCol) {
70
- return simpleCase(options, keys[0]);
80
+ return simpleCase(options, keys[0], context);
71
81
  }
72
82
  let typ = options.groupColType || "uuid";
73
83
  let cls = clause.DBTypeIn(options.groupCol, keys, typ);
@@ -86,6 +96,7 @@ function createCountDataLoader(options) {
86
96
  fields: ["count(1) as count", options.groupCol],
87
97
  groupby: options.groupCol,
88
98
  clause: cls,
99
+ context,
89
100
  };
90
101
  const rows = await (0, ent_1.loadRows)(rowOptions);
91
102
  for (const row of rows) {
@@ -97,9 +108,8 @@ function createCountDataLoader(options) {
97
108
  result[idx] = parseInt(row.count, 10);
98
109
  }
99
110
  return result;
100
- }, loaderOptions);
111
+ }, loaderOptions, options.tableName);
101
112
  }
102
- exports.createCountDataLoader = createCountDataLoader;
103
113
  // for now this only works for single column counts
104
114
  // e.g. foreign key count
105
115
  class RawCountLoader {
@@ -108,7 +118,7 @@ class RawCountLoader {
108
118
  this.options = options;
109
119
  this.context = context;
110
120
  if (context && options.groupCol) {
111
- this.loader = createCountDataLoader(options);
121
+ this.loader = createCountDataLoader(options, context);
112
122
  }
113
123
  }
114
124
  async load(id) {
package/core/logger.js CHANGED
@@ -1,6 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.logEnabled = exports.logTrace = exports.logIf = exports.log = exports.clearLogLevels = exports.setLogLevels = void 0;
3
+ exports.setLogLevels = setLogLevels;
4
+ exports.clearLogLevels = clearLogLevels;
5
+ exports.log = log;
6
+ exports.logIf = logIf;
7
+ exports.logTrace = logTrace;
8
+ exports.logEnabled = logEnabled;
4
9
  var m = {
5
10
  query: "log",
6
11
  warn: "warn",
@@ -16,11 +21,9 @@ function setLogLevels(levels) {
16
21
  }
17
22
  levels.forEach((level) => logLevels.set(level, true));
18
23
  }
19
- exports.setLogLevels = setLogLevels;
20
24
  function clearLogLevels() {
21
25
  logLevels.clear();
22
26
  }
23
- exports.clearLogLevels = clearLogLevels;
24
27
  function log(level, msg) {
25
28
  if (logLevels.has(level)) {
26
29
  // mostly for sqlite error but fine for any type of error
@@ -32,20 +35,16 @@ function log(level, msg) {
32
35
  console[m[level]](msg);
33
36
  }
34
37
  }
35
- exports.log = log;
36
38
  function logIf(level, logFn) {
37
39
  if (logLevels.has(level)) {
38
40
  console[m[level]](logFn());
39
41
  }
40
42
  }
41
- exports.logIf = logIf;
42
43
  function logTrace() {
43
44
  if (logLevels.has("debug")) {
44
45
  console.trace();
45
46
  }
46
47
  }
47
- exports.logTrace = logTrace;
48
48
  function logEnabled(level) {
49
49
  return logLevels.has(level);
50
50
  }
51
- exports.logEnabled = logEnabled;
@@ -0,0 +1,22 @@
1
+ export type DataLoaderBatchMetrics = {
2
+ loaderName: string;
3
+ batchSize: number;
4
+ };
5
+ export type DataLoaderCacheHitMetrics = {
6
+ tableName: string;
7
+ key: unknown;
8
+ };
9
+ export type QueryCacheHitMetrics = {
10
+ tableName: string;
11
+ key: string;
12
+ };
13
+ export type MetricsHook = {
14
+ onDataLoaderBatch?: (info: DataLoaderBatchMetrics) => void;
15
+ onDataLoaderCacheHit?: (info: DataLoaderCacheHitMetrics) => void;
16
+ onQueryCacheHit?: (info: QueryCacheHitMetrics) => void;
17
+ };
18
+ export declare function setMetricsHook(hooks?: MetricsHook | null): void;
19
+ export declare function getMetricsHook(): MetricsHook;
20
+ export declare function getOnDataLoaderBatch(): ((info: DataLoaderBatchMetrics) => void) | undefined;
21
+ export declare function getOnDataLoaderCacheHit(): ((info: DataLoaderCacheHitMetrics) => void) | undefined;
22
+ export declare function getOnQueryCacheHit(): ((info: QueryCacheHitMetrics) => void) | undefined;