@snowtop/ent 0.2.6 → 0.2.8

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 (73) hide show
  1. package/action/executor.js +4 -4
  2. package/action/operations.js +3 -0
  3. package/action/orchestrator.js +10 -12
  4. package/action/topological_sort.d.ts +9 -0
  5. package/action/topological_sort.js +46 -0
  6. package/core/async_utils.d.ts +1 -0
  7. package/core/async_utils.js +29 -0
  8. package/core/base.d.ts +12 -5
  9. package/core/clause.d.ts +3 -5
  10. package/core/clause.js +32 -0
  11. package/core/config.d.ts +28 -2
  12. package/core/config.js +14 -1
  13. package/core/context.d.ts +3 -1
  14. package/core/context.js +90 -26
  15. package/core/db.d.ts +12 -2
  16. package/core/db.js +102 -7
  17. package/core/dev_schema.d.ts +9 -0
  18. package/core/dev_schema.js +306 -0
  19. package/core/ent.d.ts +5 -7
  20. package/core/ent.js +33 -48
  21. package/core/extensions.d.ts +25 -0
  22. package/core/extensions.js +220 -0
  23. package/core/loaders/assoc_count_loader.js +3 -6
  24. package/core/loaders/assoc_edge_loader.d.ts +3 -0
  25. package/core/loaders/assoc_edge_loader.js +48 -19
  26. package/core/loaders/index.d.ts +2 -1
  27. package/core/loaders/index.js +5 -1
  28. package/core/loaders/loader.d.ts +31 -0
  29. package/core/loaders/loader.js +141 -2
  30. package/core/loaders/object_loader.d.ts +2 -2
  31. package/core/loaders/object_loader.js +39 -57
  32. package/core/loaders/query_loader.d.ts +2 -5
  33. package/core/loaders/query_loader.js +45 -24
  34. package/core/loaders/raw_count_loader.d.ts +2 -2
  35. package/core/loaders/raw_count_loader.js +12 -14
  36. package/core/memoize.d.ts +1 -0
  37. package/core/memoize.js +15 -0
  38. package/core/metrics.d.ts +22 -0
  39. package/core/metrics.js +31 -0
  40. package/core/query/custom_clause_query.js +5 -1
  41. package/core/query/query.d.ts +1 -1
  42. package/core/query/query.js +10 -7
  43. package/core/query_expression.d.ts +6 -0
  44. package/core/query_expression.js +2 -0
  45. package/core/query_impl.d.ts +19 -3
  46. package/core/query_impl.js +148 -35
  47. package/index.d.ts +7 -2
  48. package/index.js +12 -2
  49. package/package.json +1 -7
  50. package/parse_schema/parse.d.ts +2 -12
  51. package/parse_schema/parse.js +22 -41
  52. package/schema/index.d.ts +1 -1
  53. package/schema/schema.d.ts +20 -1
  54. package/scripts/custom_graphql.js +12 -5
  55. package/scripts/fix_action_exports.js +1 -1
  56. package/scripts/migrate_v0.1.js +2 -5
  57. package/scripts/move_types.js +1 -1
  58. package/scripts/read_schema.js +2 -5
  59. package/testutils/builder.js +1 -2
  60. package/testutils/parse_sql.js +1 -1
  61. package/tsc/compilerOptions.d.ts +2 -2
  62. package/tsc/compilerOptions.js +12 -18
  63. package/tsc/move_generated.js +2 -2
  64. package/tsc/transform.d.ts +1 -1
  65. package/tsc/transform.js +16 -2
  66. package/tsc/transform_action.d.ts +1 -1
  67. package/tsc/transform_action.js +1 -1
  68. package/tsc/transform_ent.d.ts +1 -1
  69. package/tsc/transform_ent.js +1 -1
  70. package/tsc/transform_schema.d.ts +1 -1
  71. package/tsc/transform_schema.js +2 -2
  72. /package/core/{loaders/cache_utils.d.ts → cache_utils.d.ts} +0 -0
  73. /package/core/{loaders/cache_utils.js → cache_utils.js} +0 -0
package/core/ent.js CHANGED
@@ -32,9 +32,6 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
35
  Object.defineProperty(exports, "__esModule", { value: true });
39
36
  exports.assocEdgeLoader = exports.AssocEdgeData = exports.AssocEdge = void 0;
40
37
  exports.rowIsError = rowIsError;
@@ -71,6 +68,7 @@ exports.editRow = editRow;
71
68
  exports.editRowSync = editRowSync;
72
69
  exports.deleteRows = deleteRows;
73
70
  exports.deleteRowsSync = deleteRowsSync;
71
+ exports.decodeCursorPayload = decodeCursorPayload;
74
72
  exports.getCursor = getCursor;
75
73
  exports.loadEdgeData = loadEdgeData;
76
74
  exports.loadEdgeDatas = loadEdgeDatas;
@@ -90,7 +88,7 @@ exports.applyPrivacyPolicyForRows = applyPrivacyPolicyForRows;
90
88
  exports.getEdgeTypeInGroup = getEdgeTypeInGroup;
91
89
  const db_1 = __importStar(require("./db"));
92
90
  const privacy_1 = require("./privacy");
93
- const dataloader_1 = __importDefault(require("dataloader"));
91
+ const async_utils_1 = require("./async_utils");
94
92
  const clause = __importStar(require("./clause"));
95
93
  const global_schema_1 = require("./global_schema");
96
94
  const loader_1 = require("./loaders/loader");
@@ -125,15 +123,13 @@ class entCacheMap {
125
123
  }
126
124
  }
127
125
  function createAssocEdgeConfigLoader(options) {
126
+ const loaderName = `assocEdgeConfigLoader:${options.tableName}`;
128
127
  const loaderOptions = {
129
128
  maxBatchSize: (0, loader_1.getLoaderMaxBatchSize)(),
129
+ cacheMap: (0, loader_1.createLoaderCacheMap)(options),
130
130
  };
131
- // if query logging is enabled, we should log what's happening with loader
132
- if ((0, logger_1.logEnabled)("query")) {
133
- loaderOptions.cacheMap = new loader_1.CacheMap(options);
134
- }
135
131
  // something here brokwn with strict:true
136
- return new dataloader_1.default(async (ids) => {
132
+ return new loader_1.InstrumentedDataLoader(loaderName, async (ids) => {
137
133
  if (!ids.length) {
138
134
  return [];
139
135
  }
@@ -155,7 +151,7 @@ function createAssocEdgeConfigLoader(options) {
155
151
  }
156
152
  }
157
153
  return ids.map((id) => rowMap.get(id) ?? null);
158
- }, loaderOptions);
154
+ }, loaderOptions, options.tableName);
159
155
  }
160
156
  // used to wrap errors that would eventually be thrown in ents
161
157
  // not an Error because DataLoader automatically rejects that
@@ -177,48 +173,23 @@ function setEntLoaderPrivacyConcurrencyLimit(limit) {
177
173
  function getEntLoaderPrivacyConcurrencyLimit() {
178
174
  return entLoaderPrivacyConcurrencyLimit;
179
175
  }
180
- async function mapWithConcurrency(items, limit, mapper) {
181
- if (!items.length) {
182
- return [];
183
- }
184
- const results = new Array(items.length);
185
- const concurrency = limit === Infinity
186
- ? items.length
187
- : Number.isFinite(limit) && limit > 0
188
- ? Math.floor(limit)
189
- : 1;
190
- let nextIndex = 0;
191
- const workers = new Array(Math.min(concurrency, items.length))
192
- .fill(null)
193
- .map(async () => {
194
- while (true) {
195
- const currentIndex = nextIndex;
196
- if (currentIndex >= items.length) {
197
- return;
198
- }
199
- nextIndex += 1;
200
- results[currentIndex] = await mapper(items[currentIndex], currentIndex);
201
- }
202
- });
203
- await Promise.all(workers);
204
- return results;
205
- }
206
176
  function createEntLoader(viewer, options, map) {
177
+ const loaderName = `entLoader:${options.loaderFactory.name}`;
178
+ const tableName = options.loaderFactory.options?.tableName;
207
179
  // share the cache across loaders even if we create a new instance
208
180
  const loaderOptions = {
209
181
  maxBatchSize: (0, loader_1.getLoaderMaxBatchSize)(),
210
182
  };
211
- loaderOptions.cacheMap = map;
212
- return new dataloader_1.default(async (ids) => {
183
+ loaderOptions.cacheMap = (0, loader_1.createBoundedCacheMap)(map);
184
+ return new loader_1.InstrumentedDataLoader(loaderName, async (ids) => {
213
185
  if (!ids.length) {
214
186
  return [];
215
187
  }
216
- const tableName = options.loaderFactory.options?.tableName;
217
188
  const loader = options.loaderFactory.createLoader(viewer.context);
218
189
  const rows = await loader.loadMany(ids);
219
190
  // this is a loader which should return the same order based on passed-in ids
220
191
  // so let's depend on that...
221
- return mapWithConcurrency(rows, getEntLoaderPrivacyConcurrencyLimit(), async (row, idx) => {
192
+ return (0, async_utils_1.mapWithConcurrency)(rows, getEntLoaderPrivacyConcurrencyLimit(), async (row, idx) => {
222
193
  // db error
223
194
  if (rowIsError(row)) {
224
195
  if (row instanceof Error) {
@@ -239,7 +210,7 @@ function createEntLoader(viewer, options, map) {
239
210
  }
240
211
  return r;
241
212
  });
242
- }, loaderOptions);
213
+ }, loaderOptions, tableName);
243
214
  }
244
215
  class EntLoader {
245
216
  constructor(viewer, options) {
@@ -637,13 +608,13 @@ async function loadRow(options) {
637
608
  return row;
638
609
  }
639
610
  }
640
- const query = (0, query_impl_1.buildQuery)(options);
641
- logQuery(query, options.clause.logValues());
611
+ const queryData = (0, query_impl_1.buildQueryData)(options);
612
+ logQuery(queryData.query, queryData.logValues);
642
613
  const pool = db_1.default.getInstance().getPool();
643
- const res = await pool.query(query, options.clause.values());
614
+ const res = await pool.query(queryData.query, queryData.values);
644
615
  if (res.rowCount != 1) {
645
616
  if (res.rowCount > 1) {
646
- (0, logger_1.log)("error", "got more than one row for query " + query);
617
+ (0, logger_1.log)("error", "got more than one row for query " + queryData.query);
647
618
  }
648
619
  return null;
649
620
  }
@@ -682,8 +653,8 @@ async function loadRows(options) {
682
653
  return rows;
683
654
  }
684
655
  }
685
- const query = (0, query_impl_1.buildQuery)(options);
686
- const r = await performRawQuery(query, options.clause.values(), options.clause.logValues());
656
+ const queryData = (0, query_impl_1.buildQueryData)(options);
657
+ const r = await performRawQuery(queryData.query, queryData.values, queryData.logValues);
687
658
  if (cache) {
688
659
  // put the rows in the cache...
689
660
  cache.primeCache(options, r);
@@ -692,6 +663,12 @@ async function loadRows(options) {
692
663
  }
693
664
  // this is used for queries when we select multiple ids at once
694
665
  function buildGroupQuery(options) {
666
+ if (options.fields.some((field) => typeof field === "object" && "expression" in field)) {
667
+ throw new Error("group queries do not support computed select expressions");
668
+ }
669
+ if (options.orderby && (0, query_impl_1.orderByHasExpressions)(options.orderby)) {
670
+ throw new Error("group queries do not support computed order expressions");
671
+ }
695
672
  const fields = [...options.fields, "row_number()"];
696
673
  let cls = clause.In(options.groupColumn, ...options.values);
697
674
  if (options.clause) {
@@ -930,6 +907,14 @@ class AssocEdge {
930
907
  }
931
908
  }
932
909
  exports.AssocEdge = AssocEdge;
910
+ // UTF-8-safe cursor encoding (btoa only supports Latin-1 code units).
911
+ function encodeCursorPayload(json) {
912
+ return Buffer.from(json, "utf8").toString("base64");
913
+ }
914
+ // Inverse of encodeCursorPayload; exported for pagination decode in query.ts
915
+ function decodeCursorPayload(encoded) {
916
+ return Buffer.from(encoded, "base64").toString("utf8");
917
+ }
933
918
  // TODO eventually update this for sortCol time unique keys
934
919
  function getCursor(opts) {
935
920
  const { row, cursorKeys, rowKeys } = opts;
@@ -947,7 +932,7 @@ function getCursor(opts) {
947
932
  const rowKey = rowKeys?.[i] || cursorKey;
948
933
  parts.push([cursorKey, convert(row[rowKey])]);
949
934
  }
950
- return btoa(JSON.stringify(parts));
935
+ return encodeCursorPayload(JSON.stringify(parts));
951
936
  }
952
937
  class AssocEdgeData {
953
938
  constructor(data) {
@@ -0,0 +1,25 @@
1
+ import { type Pool } from "pg";
2
+ import type { RuntimeDBExtension } from "./config";
3
+ import type { ResolvedDevSchema } from "./dev_schema";
4
+ export interface InstalledDBExtension {
5
+ name: string;
6
+ version: string;
7
+ installSchema?: string;
8
+ }
9
+ export interface ExtensionTypeParser {
10
+ name: string;
11
+ parse(value: string | null): unknown;
12
+ }
13
+ export interface ExtensionRuntimeHandler {
14
+ name: string;
15
+ runtimeSchemas?: string[];
16
+ types?: ExtensionTypeParser[];
17
+ validate?(installed: InstalledDBExtension, extension: RuntimeDBExtension): void | Promise<void>;
18
+ }
19
+ export declare function registerExtensionRuntime(handler: ExtensionRuntimeHandler): void;
20
+ export declare function clearExtensionRuntimes(): void;
21
+ export declare function normalizeExtensions(extensions: RuntimeDBExtension[]): RuntimeDBExtension[];
22
+ export declare function resolveExtensions(cfg?: RuntimeDBExtension[]): RuntimeDBExtension[];
23
+ export declare function getExtensionSearchPathSchemas(extensions: RuntimeDBExtension[]): string[];
24
+ export declare function buildExtensionSearchPath(resolvedDevSchema: ResolvedDevSchema, extensions: RuntimeDBExtension[]): string | undefined;
25
+ export declare function initializeExtensions(pool: Pick<Pool, "query">, extensions: RuntimeDBExtension[]): Promise<void>;
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerExtensionRuntime = registerExtensionRuntime;
4
+ exports.clearExtensionRuntimes = clearExtensionRuntimes;
5
+ exports.normalizeExtensions = normalizeExtensions;
6
+ exports.resolveExtensions = resolveExtensions;
7
+ exports.getExtensionSearchPathSchemas = getExtensionSearchPathSchemas;
8
+ exports.buildExtensionSearchPath = buildExtensionSearchPath;
9
+ exports.initializeExtensions = initializeExtensions;
10
+ const pg_1 = require("pg");
11
+ const TEXT_ARRAY_OID = 1009;
12
+ const runtimeHandlers = new Map();
13
+ const registeredTypeOIDs = new Set();
14
+ function normalizeProvisionedBy(extension) {
15
+ if (extension.provisionedBy === "ent" ||
16
+ extension.provisionedBy === "external") {
17
+ return extension.provisionedBy;
18
+ }
19
+ if (extension.provisionedBy) {
20
+ throw new Error(`invalid provisionedBy ${extension.provisionedBy} for db extension ${extension.name}`);
21
+ }
22
+ return "ent";
23
+ }
24
+ function normalizeRuntimeHandler(handler) {
25
+ const typeHandlers = new Map();
26
+ for (const typeHandler of handler.types || []) {
27
+ typeHandlers.set(typeHandler.name, typeHandler);
28
+ }
29
+ return {
30
+ ...handler,
31
+ runtimeSchemas: [...new Set(handler.runtimeSchemas || [])],
32
+ types: [...typeHandlers.values()],
33
+ };
34
+ }
35
+ function mergeRuntimeHandlers(lhs, rhs) {
36
+ const mergedTypes = new Map();
37
+ for (const typeHandler of lhs.types || []) {
38
+ mergedTypes.set(typeHandler.name, typeHandler);
39
+ }
40
+ for (const typeHandler of rhs.types || []) {
41
+ mergedTypes.set(typeHandler.name, typeHandler);
42
+ }
43
+ return {
44
+ name: rhs.name,
45
+ runtimeSchemas: [
46
+ ...new Set([
47
+ ...(lhs.runtimeSchemas || []),
48
+ ...(rhs.runtimeSchemas || []),
49
+ ]),
50
+ ],
51
+ types: [...mergedTypes.values()],
52
+ validate: rhs.validate || lhs.validate,
53
+ };
54
+ }
55
+ function getRegisteredRuntimeHandlers() {
56
+ return [...runtimeHandlers.values()].sort((lhs, rhs) => lhs.name.localeCompare(rhs.name));
57
+ }
58
+ function registerExtensionRuntime(handler) {
59
+ const normalized = normalizeRuntimeHandler(handler);
60
+ const existing = runtimeHandlers.get(normalized.name);
61
+ runtimeHandlers.set(normalized.name, existing ? mergeRuntimeHandlers(existing, normalized) : normalized);
62
+ }
63
+ function clearExtensionRuntimes() {
64
+ runtimeHandlers.clear();
65
+ registeredTypeOIDs.clear();
66
+ }
67
+ function normalizeExtensions(extensions) {
68
+ return [...extensions]
69
+ .map((extension) => ({
70
+ ...extension,
71
+ provisionedBy: normalizeProvisionedBy(extension),
72
+ runtimeSchemas: extension.runtimeSchemas || [],
73
+ dropCascade: extension.dropCascade === true,
74
+ }))
75
+ .sort((lhs, rhs) => lhs.name.localeCompare(rhs.name));
76
+ }
77
+ function resolveExtensions(cfg) {
78
+ return normalizeExtensions(cfg || []);
79
+ }
80
+ function getExtensionSearchPathSchemas(extensions) {
81
+ const normalizedExtensions = normalizeExtensions(extensions);
82
+ const configuredExtensions = new Map(normalizedExtensions.map((extension) => [extension.name, extension]));
83
+ const seen = new Set();
84
+ const schemas = [];
85
+ function addSchemas(runtimeSchemas) {
86
+ for (const schema of runtimeSchemas) {
87
+ if (!schema || seen.has(schema)) {
88
+ continue;
89
+ }
90
+ seen.add(schema);
91
+ schemas.push(schema);
92
+ }
93
+ }
94
+ for (const extension of normalizedExtensions) {
95
+ addSchemas(extension.runtimeSchemas || []);
96
+ }
97
+ for (const handler of getRegisteredRuntimeHandlers()) {
98
+ const configured = configuredExtensions.get(handler.name);
99
+ addSchemas(configured
100
+ ? configured.runtimeSchemas || []
101
+ : handler.runtimeSchemas || []);
102
+ }
103
+ return schemas;
104
+ }
105
+ function buildExtensionSearchPath(resolvedDevSchema, extensions) {
106
+ const schemas = [];
107
+ if (resolvedDevSchema.enabled && resolvedDevSchema.schemaName) {
108
+ schemas.push(resolvedDevSchema.schemaName);
109
+ }
110
+ for (const schema of getExtensionSearchPathSchemas(extensions)) {
111
+ if (!schemas.includes(schema)) {
112
+ schemas.push(schema);
113
+ }
114
+ }
115
+ if (resolvedDevSchema.enabled &&
116
+ resolvedDevSchema.includePublic &&
117
+ !schemas.includes("public")) {
118
+ schemas.push("public");
119
+ }
120
+ if (!resolvedDevSchema.enabled &&
121
+ schemas.length > 0 &&
122
+ !schemas.includes("public")) {
123
+ schemas.push("public");
124
+ }
125
+ if (schemas.length === 0) {
126
+ return undefined;
127
+ }
128
+ return schemas.join(",");
129
+ }
130
+ async function getInstalledExtensions(pool, extensions) {
131
+ if (extensions.length === 0) {
132
+ return new Map();
133
+ }
134
+ const res = await pool.query(`
135
+ SELECT
136
+ extname,
137
+ extversion,
138
+ extnamespace::regnamespace::text AS install_schema
139
+ FROM pg_extension
140
+ WHERE extname = ANY($1::text[])
141
+ `, [extensions.map((extension) => extension.name)]);
142
+ const installed = new Map();
143
+ for (const row of res.rows) {
144
+ installed.set(row.extname, {
145
+ name: row.extname,
146
+ version: row.extversion,
147
+ installSchema: row.install_schema,
148
+ });
149
+ }
150
+ return installed;
151
+ }
152
+ function registerArrayParser(arrayOID, parse) {
153
+ if (!arrayOID || registeredTypeOIDs.has(arrayOID)) {
154
+ return;
155
+ }
156
+ const parseTextArray = pg_1.types.getTypeParser(TEXT_ARRAY_OID);
157
+ pg_1.types.setTypeParser(arrayOID, (value) => {
158
+ if (value === null) {
159
+ return null;
160
+ }
161
+ const parsed = parseTextArray(value);
162
+ return parsed.map((entry) => parse(entry));
163
+ });
164
+ registeredTypeOIDs.add(arrayOID);
165
+ }
166
+ async function initializeRegisteredTypeParsers(pool, configuredExtensions) {
167
+ const registeredTypes = new Map();
168
+ for (const handler of getRegisteredRuntimeHandlers()) {
169
+ for (const typeHandler of handler.types || []) {
170
+ registeredTypes.set(typeHandler.name, {
171
+ extensionName: handler.name,
172
+ parse: typeHandler.parse,
173
+ });
174
+ }
175
+ }
176
+ if (registeredTypes.size === 0) {
177
+ return;
178
+ }
179
+ const res = await pool.query(`
180
+ SELECT oid, typname, typarray
181
+ FROM pg_type
182
+ WHERE typname = ANY($1::text[])
183
+ `, [[...registeredTypes.keys()]]);
184
+ const rowsByType = new Map(res.rows.map((row) => [row.typname, row]));
185
+ for (const [typeName, typeHandler] of registeredTypes.entries()) {
186
+ const row = rowsByType.get(typeName);
187
+ if (!row) {
188
+ if (configuredExtensions.has(typeHandler.extensionName)) {
189
+ throw new Error(`required pg type "${typeName}" for db extension "${typeHandler.extensionName}" was not found`);
190
+ }
191
+ continue;
192
+ }
193
+ if (!registeredTypeOIDs.has(row.oid)) {
194
+ pg_1.types.setTypeParser(row.oid, typeHandler.parse);
195
+ registeredTypeOIDs.add(row.oid);
196
+ }
197
+ registerArrayParser(row.typarray, typeHandler.parse);
198
+ }
199
+ }
200
+ async function initializeExtensions(pool, extensions) {
201
+ const normalizedExtensions = normalizeExtensions(extensions);
202
+ const configuredExtensions = new Map(normalizedExtensions.map((extension) => [extension.name, extension]));
203
+ const installedExtensions = await getInstalledExtensions(pool, normalizedExtensions);
204
+ for (const extension of normalizedExtensions) {
205
+ const installed = installedExtensions.get(extension.name);
206
+ if (!installed) {
207
+ throw new Error(`required db extension "${extension.name}" is not installed`);
208
+ }
209
+ if (extension.version && extension.version !== installed.version) {
210
+ throw new Error(`required db extension "${extension.name}" version "${extension.version}" but found "${installed.version}"`);
211
+ }
212
+ if (extension.installSchema &&
213
+ extension.installSchema !== installed.installSchema) {
214
+ throw new Error(`required db extension "${extension.name}" install schema "${extension.installSchema}" but found "${installed.installSchema}"`);
215
+ }
216
+ const handler = runtimeHandlers.get(extension.name);
217
+ await handler?.validate?.(installed, extension);
218
+ }
219
+ await initializeRegisteredTypeParsers(pool, configuredExtensions);
220
+ }
@@ -32,23 +32,20 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
35
  Object.defineProperty(exports, "__esModule", { value: true });
39
36
  exports.AssocEdgeCountLoaderFactory = exports.AssocEdgeCountLoader = void 0;
40
37
  const ent_1 = require("../ent");
41
38
  const clause = __importStar(require("../clause"));
42
39
  const loader_1 = require("./loader");
43
40
  const raw_count_loader_1 = require("./raw_count_loader");
44
- const memoizee_1 = __importDefault(require("memoizee"));
41
+ const memoize_1 = require("../memoize");
45
42
  class AssocEdgeCountLoader {
46
43
  constructor(edgeType, context, options) {
47
44
  this.edgeType = edgeType;
48
45
  this.context = context;
49
46
  this.options = options;
50
47
  if (context) {
51
- this.loaderFn = (0, memoizee_1.default)(this.getLoader);
48
+ this.loaderFn = (0, memoize_1.memoizeNoArgs)(this.getLoader.bind(this));
52
49
  }
53
50
  }
54
51
  async getLoader() {
@@ -63,7 +60,7 @@ class AssocEdgeCountLoader {
63
60
  tableName: edgeData.edgeTable,
64
61
  groupCol: "id1",
65
62
  clause: cls,
66
- });
63
+ }, this.context);
67
64
  return this.loader;
68
65
  }
69
66
  async load(id) {
@@ -23,7 +23,10 @@ export declare class AssocDirectEdgeLoader<T extends AssocEdge> implements Loade
23
23
  private edgeCtr;
24
24
  private options?;
25
25
  context?: Context | undefined;
26
+ private loader;
27
+ private loaderFn;
26
28
  constructor(edgeType: string, edgeCtr: AssocEdgeConstructor<T>, options?: EdgeQueryableDataOptions | undefined, context?: Context | undefined);
29
+ private getLoader;
27
30
  load(id: ID): Promise<T[]>;
28
31
  loadTwoWay(id: ID): Promise<T[]>;
29
32
  loadEdgeForID2(id: ID, id2: ID): Promise<T | undefined>;
@@ -32,17 +32,12 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
35
  Object.defineProperty(exports, "__esModule", { value: true });
39
36
  exports.AssocEdgeLoaderFactory = exports.AssocDirectEdgeLoader = exports.AssocEdgeLoader = void 0;
40
- const dataloader_1 = __importDefault(require("dataloader"));
41
- const memoizee_1 = __importDefault(require("memoizee"));
42
37
  const clause = __importStar(require("../clause"));
43
38
  const ent_1 = require("../ent");
44
- const logger_1 = require("../logger");
45
- const cache_utils_1 = require("./cache_utils");
39
+ const memoize_1 = require("../memoize");
40
+ const query_impl_1 = require("../query_impl");
46
41
  const loader_1 = require("./loader");
47
42
  function getDefaultOrderBy() {
48
43
  return [
@@ -60,16 +55,15 @@ function getEffectiveOptions(options) {
60
55
  disableTransformations: options.disableTransformations ?? false,
61
56
  };
62
57
  }
63
- function createLoader(options, edgeType, edgeCtr, edgeData) {
58
+ function createLoader(options, edgeType, edgeCtr, edgeData, context) {
59
+ const loaderName = `assocEdgeLoader:${edgeType}`;
64
60
  const loaderOptions = {
65
61
  maxBatchSize: (0, loader_1.getLoaderMaxBatchSize)(),
66
- };
67
- if ((0, logger_1.logEnabled)("query")) {
68
- loaderOptions.cacheMap = new loader_1.CacheMap({
62
+ cacheMap: (0, loader_1.createLoaderCacheMap)({
69
63
  tableName: edgeData.edgeTable,
70
- });
71
- }
72
- return new dataloader_1.default(async (keys) => {
64
+ }),
65
+ };
66
+ return new loader_1.InstrumentedDataLoader(loaderName, async (keys) => {
73
67
  if (keys.length === 1) {
74
68
  // 1 key, just be simple and move on
75
69
  // same as AssocDirectEdgeLoader
@@ -77,6 +71,7 @@ function createLoader(options, edgeType, edgeCtr, edgeData) {
77
71
  id1: keys[0],
78
72
  edgeType: edgeType,
79
73
  queryOptions: options,
74
+ context,
80
75
  ctr: edgeCtr,
81
76
  });
82
77
  return [r];
@@ -115,7 +110,7 @@ function createLoader(options, edgeType, edgeCtr, edgeData) {
115
110
  result[idx].push(new edgeCtr(row));
116
111
  }
117
112
  return result;
118
- }, loaderOptions);
113
+ }, loaderOptions, edgeData.edgeTable);
119
114
  }
120
115
  class AssocEdgeLoader {
121
116
  constructor(edgeType, edgeCtr, options, context) {
@@ -123,14 +118,14 @@ class AssocEdgeLoader {
123
118
  this.edgeCtr = edgeCtr;
124
119
  this.options = options;
125
120
  this.context = context;
126
- this.loaderFn = (0, memoizee_1.default)(this.getLoader);
121
+ this.loaderFn = (0, memoize_1.memoizeNoArgs)(this.getLoader.bind(this));
127
122
  }
128
123
  async getLoader() {
129
124
  const edgeData = await (0, ent_1.loadEdgeData)(this.edgeType);
130
125
  if (!edgeData) {
131
126
  throw new Error(`error loading edge data for ${this.edgeType}`);
132
127
  }
133
- this.loader = createLoader(this.options, this.edgeType, this.edgeCtr, edgeData);
128
+ this.loader = createLoader(this.options, this.edgeType, this.edgeCtr, edgeData, this.context);
134
129
  return this.loader;
135
130
  }
136
131
  async load(id) {
@@ -168,8 +163,40 @@ class AssocDirectEdgeLoader {
168
163
  this.edgeCtr = edgeCtr;
169
164
  this.options = options;
170
165
  this.context = context;
166
+ if (this.context) {
167
+ this.loaderFn = (0, memoize_1.memoizeNoArgs)(this.getLoader.bind(this));
168
+ }
169
+ }
170
+ async getLoader() {
171
+ if (this.loader) {
172
+ return this.loader;
173
+ }
174
+ const edgeData = await (0, ent_1.loadEdgeData)(this.edgeType);
175
+ if (!edgeData) {
176
+ throw new Error(`error loading edge data for ${this.edgeType}`);
177
+ }
178
+ const loaderName = `assocDirectEdgeLoader:${this.edgeType}`;
179
+ this.loader = new loader_1.InstrumentedDataLoader(loaderName, async (keys) => {
180
+ return Promise.all(keys.map((id) => (0, ent_1.loadCustomEdges)({
181
+ id1: id,
182
+ edgeType: this.edgeType,
183
+ context: this.context,
184
+ queryOptions: this.options,
185
+ ctr: this.edgeCtr,
186
+ })));
187
+ }, {
188
+ maxBatchSize: (0, loader_1.getLoaderMaxBatchSize)(),
189
+ cacheMap: (0, loader_1.createLoaderCacheMap)({
190
+ tableName: edgeData.edgeTable,
191
+ }),
192
+ }, edgeData.edgeTable);
193
+ return this.loader;
171
194
  }
172
195
  async load(id) {
196
+ if (this.loaderFn) {
197
+ const loader = await this.loaderFn();
198
+ return loader.load(id);
199
+ }
173
200
  return (0, ent_1.loadCustomEdges)({
174
201
  id1: id,
175
202
  edgeType: this.edgeType,
@@ -197,7 +224,9 @@ class AssocDirectEdgeLoader {
197
224
  ctr: this.edgeCtr,
198
225
  });
199
226
  }
200
- clearAll() { }
227
+ clearAll() {
228
+ this.loader && this.loader.clearAll();
229
+ }
201
230
  }
202
231
  exports.AssocDirectEdgeLoader = AssocDirectEdgeLoader;
203
232
  class AssocEdgeLoaderFactory {
@@ -232,7 +261,7 @@ class AssocEdgeLoaderFactory {
232
261
  return new AssocDirectEdgeLoader(this.edgeType, edgeCtr, options, context);
233
262
  }
234
263
  const effectiveOptions = getEffectiveOptions(options);
235
- const key = `${this.name}:limit:${effectiveOptions.limit}:orderby:${(0, cache_utils_1.stableStringify)(effectiveOptions.orderby)}:disableTransformations:${effectiveOptions.disableTransformations}`;
264
+ const key = `${this.name}:limit:${effectiveOptions.limit}:orderby:${(0, query_impl_1.getOrderByKey)(effectiveOptions.orderby ?? getDefaultOrderBy())}:disableTransformations:${effectiveOptions.disableTransformations}`;
236
265
  return (0, loader_1.getCustomLoader)(key, () => new AssocEdgeLoader(this.edgeType, ctr, effectiveOptions, context), context);
237
266
  }
238
267
  }
@@ -3,4 +3,5 @@ export { RawCountLoader, RawCountLoaderFactory } from "./raw_count_loader";
3
3
  export { AssocEdgeCountLoader, AssocEdgeCountLoaderFactory, } from "./assoc_count_loader";
4
4
  export { AssocDirectEdgeLoader, AssocEdgeLoader, AssocEdgeLoaderFactory, } from "./assoc_edge_loader";
5
5
  export { QueryLoaderFactory } from "./query_loader";
6
- export { getLoaderMaxBatchSize, setLoaderMaxBatchSize } from "./loader";
6
+ export { getLoaderCacheMaxEntries, getLoaderMaxBatchSize, setLoaderCacheMaxEntries, setLoaderMaxBatchSize, } from "./loader";
7
+ export { setClauseLoaderConcurrency } from "./object_loader";
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.setLoaderMaxBatchSize = exports.getLoaderMaxBatchSize = exports.QueryLoaderFactory = exports.AssocEdgeLoaderFactory = exports.AssocEdgeLoader = exports.AssocDirectEdgeLoader = exports.AssocEdgeCountLoaderFactory = exports.AssocEdgeCountLoader = exports.RawCountLoaderFactory = exports.RawCountLoader = exports.ObjectLoaderFactory = exports.ObjectLoader = void 0;
3
+ exports.setClauseLoaderConcurrency = exports.setLoaderMaxBatchSize = exports.setLoaderCacheMaxEntries = exports.getLoaderMaxBatchSize = exports.getLoaderCacheMaxEntries = exports.QueryLoaderFactory = exports.AssocEdgeLoaderFactory = exports.AssocEdgeLoader = exports.AssocDirectEdgeLoader = exports.AssocEdgeCountLoaderFactory = exports.AssocEdgeCountLoader = exports.RawCountLoaderFactory = exports.RawCountLoader = exports.ObjectLoaderFactory = exports.ObjectLoader = void 0;
4
4
  var object_loader_1 = require("./object_loader");
5
5
  Object.defineProperty(exports, "ObjectLoader", { enumerable: true, get: function () { return object_loader_1.ObjectLoader; } });
6
6
  Object.defineProperty(exports, "ObjectLoaderFactory", { enumerable: true, get: function () { return object_loader_1.ObjectLoaderFactory; } });
@@ -17,5 +17,9 @@ Object.defineProperty(exports, "AssocEdgeLoaderFactory", { enumerable: true, get
17
17
  var query_loader_1 = require("./query_loader");
18
18
  Object.defineProperty(exports, "QueryLoaderFactory", { enumerable: true, get: function () { return query_loader_1.QueryLoaderFactory; } });
19
19
  var loader_1 = require("./loader");
20
+ Object.defineProperty(exports, "getLoaderCacheMaxEntries", { enumerable: true, get: function () { return loader_1.getLoaderCacheMaxEntries; } });
20
21
  Object.defineProperty(exports, "getLoaderMaxBatchSize", { enumerable: true, get: function () { return loader_1.getLoaderMaxBatchSize; } });
22
+ Object.defineProperty(exports, "setLoaderCacheMaxEntries", { enumerable: true, get: function () { return loader_1.setLoaderCacheMaxEntries; } });
21
23
  Object.defineProperty(exports, "setLoaderMaxBatchSize", { enumerable: true, get: function () { return loader_1.setLoaderMaxBatchSize; } });
24
+ var object_loader_2 = require("./object_loader");
25
+ Object.defineProperty(exports, "setClauseLoaderConcurrency", { enumerable: true, get: function () { return object_loader_2.setClauseLoaderConcurrency; } });