@technicity/data-service-generator 0.22.2 → 0.23.0-next.0

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 (66) hide show
  1. package/dist/src/generation/generate.d.ts +21 -0
  2. package/dist/src/generation/generate.js +2349 -0
  3. package/dist/src/index.d.ts +4 -0
  4. package/dist/src/index.js +11 -0
  5. package/dist/src/lib/CustomError.d.ts +3 -0
  6. package/dist/src/lib/CustomError.js +10 -0
  7. package/dist/src/lib/capitalizeFirstLetter.d.ts +1 -0
  8. package/dist/src/lib/capitalizeFirstLetter.js +6 -0
  9. package/dist/src/lib/getDuplicates.d.ts +1 -0
  10. package/dist/src/lib/getDuplicates.js +9 -0
  11. package/dist/src/lib/isNotNullOrUndefined.d.ts +1 -0
  12. package/dist/src/lib/isNotNullOrUndefined.js +7 -0
  13. package/dist/src/runtime/Cache.d.ts +28 -0
  14. package/dist/src/runtime/Cache.js +142 -0
  15. package/dist/src/runtime/IRuntime.d.ts +209 -0
  16. package/dist/src/runtime/IRuntime.js +12 -0
  17. package/dist/src/runtime/RuntimeMySQL.d.ts +26 -0
  18. package/dist/src/runtime/RuntimeMySQL.js +132 -0
  19. package/dist/src/runtime/RuntimePostgreSQL.d.ts +30 -0
  20. package/dist/src/runtime/RuntimePostgreSQL.js +73 -0
  21. package/dist/src/runtime/RuntimeSQLite.d.ts +42 -0
  22. package/dist/src/runtime/RuntimeSQLite.js +150 -0
  23. package/dist/src/runtime/Stats.d.ts +8 -0
  24. package/dist/src/runtime/Stats.js +31 -0
  25. package/dist/src/runtime/lib/MySQL.d.ts +13 -0
  26. package/dist/src/runtime/lib/MySQL.js +116 -0
  27. package/dist/src/runtime/lib/PostgreSQL.d.ts +14 -0
  28. package/dist/src/runtime/lib/PostgreSQL.js +110 -0
  29. package/dist/src/runtime/lib/SDKBadWhereError.d.ts +4 -0
  30. package/dist/src/runtime/lib/SDKBadWhereError.js +10 -0
  31. package/dist/src/runtime/lib/SDKNotFoundError.d.ts +4 -0
  32. package/dist/src/runtime/lib/SDKNotFoundError.js +10 -0
  33. package/dist/src/runtime/lib/addNullFallbacks.d.ts +1 -0
  34. package/dist/src/runtime/lib/addNullFallbacks.js +32 -0
  35. package/dist/src/runtime/lib/addNullFallbacks.test.d.ts +1 -0
  36. package/dist/src/runtime/lib/addNullFallbacks.test.js +206 -0
  37. package/dist/src/runtime/lib/cursor.d.ts +2 -0
  38. package/dist/src/runtime/lib/cursor.js +10 -0
  39. package/dist/src/runtime/lib/getDateTimeStringMySQL.d.ts +1 -0
  40. package/dist/src/runtime/lib/getDateTimeStringMySQL.js +7 -0
  41. package/dist/src/runtime/lib/getOrderBy.d.ts +5 -0
  42. package/dist/src/runtime/lib/getOrderBy.js +52 -0
  43. package/dist/src/runtime/lib/getSqlAst.d.ts +2 -0
  44. package/dist/src/runtime/lib/getSqlAst.js +245 -0
  45. package/dist/src/runtime/lib/getWhere.d.ts +2 -0
  46. package/dist/src/runtime/lib/getWhere.js +20 -0
  47. package/dist/src/runtime/lib/shared.d.ts +13 -0
  48. package/dist/src/runtime/lib/shared.js +1118 -0
  49. package/dist/src/runtime/lib/stringifyWhere.d.ts +18 -0
  50. package/dist/src/runtime/lib/stringifyWhere.js +257 -0
  51. package/dist/src/runtime/lib/stringifyWhere.test.d.ts +1 -0
  52. package/dist/src/runtime/lib/stringifyWhere.test.js +245 -0
  53. package/dist/src/runtime/lib/utility.d.ts +5 -0
  54. package/dist/src/runtime/lib/utility.js +14 -0
  55. package/dist/src/traverseFieldArgs.d.ts +2 -0
  56. package/dist/src/traverseFieldArgs.js +17 -0
  57. package/dist/src/traverseFieldArgs.test.d.ts +1 -0
  58. package/dist/src/traverseFieldArgs.test.js +56 -0
  59. package/dist/test/addWhereValidTrue.d.ts +1 -0
  60. package/dist/test/addWhereValidTrue.js +39 -0
  61. package/dist/test/globalSetup.d.ts +13 -0
  62. package/dist/test/globalSetup.js +436 -0
  63. package/dist/test/postgres/__generated__/sdk-ts/artifacts.d.ts +8425 -0
  64. package/dist/test/postgres/__generated__/sdk-ts/artifacts.js +10469 -0
  65. package/dist/test/postgres/__generated__/sdk-ts/index.js +12162 -0
  66. package/package.json +5 -1
@@ -0,0 +1,1118 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
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
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.MiddlewareHandler = void 0;
30
+ exports.resolve = resolve;
31
+ exports.postProcess = postProcess;
32
+ exports.whereNeedsProcessing = whereNeedsProcessing;
33
+ exports._prepareWhere = _prepareWhere;
34
+ // @ts-ignore
35
+ // import * as queryAST from "join-monster/dist/query-ast-to-sql-ast";
36
+ // @ts-ignore
37
+ // import arrToConnection from "join-monster/dist/array-to-connection";
38
+ // @ts-ignore
39
+ const batch_planner_1 = __importDefault(require("join-monster/dist/batch-planner"));
40
+ // @ts-ignore
41
+ const util_1 = require("join-monster/dist/util");
42
+ const async_hooks_1 = require("async_hooks");
43
+ const _ = __importStar(require("lodash/fp"));
44
+ const uuid_1 = require("uuid");
45
+ const getSqlAst_1 = require("./getSqlAst");
46
+ const IRuntime_1 = require("../IRuntime");
47
+ const getWhere_1 = require("./getWhere");
48
+ const getDateTimeStringMySQL_1 = require("./getDateTimeStringMySQL");
49
+ const cursor_1 = require("./cursor");
50
+ const addNullFallbacks_1 = require("./addNullFallbacks");
51
+ const SDKNotFoundError_1 = require("./SDKNotFoundError");
52
+ const SDKBadWhereError_1 = require("./SDKBadWhereError");
53
+ const stringifyWhere_1 = require("./stringifyWhere");
54
+ const getOrderBy_1 = require("./getOrderBy");
55
+ const Stats_1 = require("../Stats");
56
+ async function resolve(input, dbCall, formatQuery, beginTransaction, dialect, middlewareHandler, context, cache) {
57
+ // https://github.com/prisma/prisma/blob/822198e5ba21535364d20c86901b8c3778ebf6a3/packages/client/src/runtime/getPrismaClient.ts#L1087
58
+ let index = -1;
59
+ if (middlewareHandler.length() > 0) {
60
+ const resource = new async_hooks_1.AsyncResource("sdk-request");
61
+ const params = input;
62
+ const consumer = async (paramsMaybeMutated) => {
63
+ const nextMiddleware = middlewareHandler.get(++index);
64
+ if (nextMiddleware != null) {
65
+ return nextMiddleware(paramsMaybeMutated, consumer);
66
+ }
67
+ const paramsChanged = { ...input, ...params };
68
+ const onHandler = input.onHandler;
69
+ const asyncLocalStorage = input.asyncLocalStorage;
70
+ const shouldRunOnHandler = typeof onHandler === "function" &&
71
+ asyncLocalStorage != null &&
72
+ asyncLocalStorage?.getStore()?.isInOnHandler !== true;
73
+ const beforeValue = shouldRunOnHandler && input.passBeforeValueToAfterCallback
74
+ ? await _resolve({
75
+ ...paramsChanged,
76
+ action: paramsChanged.action === "updateMany" ||
77
+ paramsChanged.action === "deleteMany"
78
+ ? "findMany"
79
+ : "findUnique",
80
+ fields: undefined
81
+ }, dbCall, formatQuery, beginTransaction, dialect, context, cache)
82
+ : null;
83
+ const p = _resolve(paramsChanged, dbCall, formatQuery, beginTransaction, dialect, context, cache);
84
+ if (shouldRunOnHandler) {
85
+ return p.then((output) => asyncLocalStorage
86
+ .run({ isInOnHandler: true }, async () => onHandler(input.sdk, { ...input.args, data: input.data }, output, beforeValue, context))
87
+ .then(() => output)
88
+ .catch((error) => {
89
+ input.eventTarget.dispatchEvent(new IRuntime_1.EventOnHandlerError("error", {
90
+ error,
91
+ resource: input.resource,
92
+ action: input.action
93
+ }));
94
+ return output;
95
+ }));
96
+ }
97
+ return p;
98
+ };
99
+ return resource.runInAsyncScope(() => consumer(params));
100
+ }
101
+ const onHandler = input.onHandler;
102
+ const asyncLocalStorage = input.asyncLocalStorage;
103
+ const shouldRunOnHandler = typeof onHandler === "function" &&
104
+ asyncLocalStorage != null &&
105
+ asyncLocalStorage?.getStore()?.isInOnHandler !== true;
106
+ const beforeValue = shouldRunOnHandler && input.passBeforeValueToAfterCallback
107
+ ? await _resolve({
108
+ ...input,
109
+ action: input.action === "updateMany" || input.action === "deleteMany"
110
+ ? "findMany"
111
+ : "findUnique",
112
+ fields: undefined
113
+ }, dbCall, formatQuery, beginTransaction, dialect, context, cache)
114
+ : null;
115
+ const p = _resolve(input, dbCall, formatQuery, beginTransaction, dialect, context, cache);
116
+ if (shouldRunOnHandler) {
117
+ return p.then((output) => asyncLocalStorage
118
+ .run({ isInOnHandler: true }, async () => onHandler(input.sdk, { ...input.args, data: input.data }, output, beforeValue, context))
119
+ .then(() => output)
120
+ .catch((error) => {
121
+ input.eventTarget.dispatchEvent(new IRuntime_1.EventOnHandlerError("error", {
122
+ error,
123
+ resource: input.resource,
124
+ action: input.action
125
+ }));
126
+ return output;
127
+ }));
128
+ }
129
+ return p;
130
+ }
131
+ function _resolve(input, dbCall, formatQuery, beginTransaction, dialect, context, cache) {
132
+ switch (input.action) {
133
+ case "findMany":
134
+ return cache && !input.skipCache
135
+ ? getCached(input, dbCall, formatQuery, dialect, cache)
136
+ : getData(input, dbCall, formatQuery, dialect);
137
+ case "findUnique":
138
+ case "findManyPaginated":
139
+ return getData(input, dbCall, formatQuery, dialect);
140
+ case "create":
141
+ return create(input, dbCall, formatQuery, beginTransaction, dialect, context);
142
+ case "update":
143
+ return update(input, dbCall, formatQuery, dialect, cache);
144
+ case "updateMany":
145
+ return updateMany(input, dbCall, formatQuery, dialect, cache);
146
+ case "delete":
147
+ return deleteOne(input, dbCall, formatQuery, dialect, cache);
148
+ case "deleteMany":
149
+ return deleteMany(input, dbCall, formatQuery, dialect, cache);
150
+ default:
151
+ throw new Error("Invalid action: " + input.action);
152
+ }
153
+ }
154
+ class MiddlewareHandler {
155
+ constructor() {
156
+ this._middlewares = [];
157
+ }
158
+ register(middleware) {
159
+ this._middlewares.push(middleware);
160
+ }
161
+ get(id) {
162
+ return this._middlewares[id];
163
+ }
164
+ has(id) {
165
+ return !!this._middlewares[id];
166
+ }
167
+ length() {
168
+ return this._middlewares.length;
169
+ }
170
+ }
171
+ exports.MiddlewareHandler = MiddlewareHandler;
172
+ async function getData(input, dbCall, formatQuery, dialect) {
173
+ const context = {};
174
+ const action = input.action;
175
+ const primaryKey = input.artifacts[input.resource].primaryKey;
176
+ let paginationType;
177
+ let limit = undefined;
178
+ let offset = undefined;
179
+ let rowWithMatchingCursor = undefined;
180
+ if (action === "findManyPaginated") {
181
+ if (input.args?.$paginate == null) {
182
+ throw new Error("$paginate required but not supplied");
183
+ }
184
+ if (typeof input?.args?.$paginate?.limit === "number") {
185
+ paginationType = "limit-offset";
186
+ limit = input.args.$paginate.limit;
187
+ offset = input.args.$paginate.offset;
188
+ }
189
+ else if (typeof input?.args?.$paginate?.first === "number" ||
190
+ typeof input?.args?.$paginate?.last === "number") {
191
+ paginationType = "cursor";
192
+ limit = (typeof input?.args?.$paginate?.first === "number"
193
+ ? input?.args?.$paginate?.first
194
+ : input?.args?.$paginate?.last);
195
+ // + 1 to peek if there is more data
196
+ limit += 1;
197
+ if (input.args.$paginate.after != null ||
198
+ input.args.$paginate.before != null) {
199
+ const cursor = input.args.$paginate.after != null
200
+ ? input.args.$paginate.after
201
+ : input.args.$paginate.before;
202
+ rowWithMatchingCursor = await dbCall(formatQuery("SELECT * FROM ?? WHERE ?? = ?", [
203
+ input.resource,
204
+ primaryKey,
205
+ (0, cursor_1.decodeCursor)(cursor)
206
+ ])).then((xs) => xs[0]);
207
+ if (rowWithMatchingCursor == null) {
208
+ throw new Error(`Invalid cursor: ${cursor}`);
209
+ }
210
+ }
211
+ }
212
+ else {
213
+ throw new Error(`Invalid $paginate: ${input?.args?.$paginate}`);
214
+ }
215
+ }
216
+ else if (action === "findMany") {
217
+ if (typeof input?.args?.$limit === "number") {
218
+ limit = input?.args?.$limit;
219
+ }
220
+ }
221
+ // we need to read the query AST and build a new "SQL AST" from which the SQL and
222
+ // const sqlAST = queryAST.queryASTToSqlAST(resolveInfo, options, context);
223
+ const fields = input.fields ??
224
+ getScalarFields(input.resource, input.artifacts).reduce((acc, x) => {
225
+ acc[x] = true;
226
+ return acc;
227
+ }, {});
228
+ const orderByListPaginatedRootResult = action === "findManyPaginated" ? (0, getOrderBy_1.getOrderBy)(input.args, primaryKey) : undefined;
229
+ const grabMany = action === "findMany" ||
230
+ action === "findManyPaginated" ||
231
+ action === "updateMany" ||
232
+ action === "deleteMany";
233
+ const escapeId = (0, stringifyWhere_1.getEscapeId)(dialect);
234
+ const sqlAST = (0, getSqlAst_1.getSqlAst)({
235
+ ...input,
236
+ table: input.resource,
237
+ fieldName: "data",
238
+ fields,
239
+ getWhere: getWhere_1.getWhere,
240
+ orderBy: orderByListPaginatedRootResult?.orderBy,
241
+ rowWithMatchingCursor,
242
+ dialect,
243
+ grabMany,
244
+ escapeId
245
+ });
246
+ const options = {
247
+ dialect: dialect === "postgresql" ? "pg" : dialect === "sqlite" ? "mysql" : dialect
248
+ };
249
+ let { sql, shapeDefinition } = await (0, util_1.compileSqlAST)(sqlAST, context, options);
250
+ if (!sql) {
251
+ // return {};
252
+ throw new Error("No SQL");
253
+ }
254
+ // TODO - remove if limit support added for mysql dialect
255
+ if (action === "findMany" || action === "findManyPaginated") {
256
+ if (typeof limit === "number") {
257
+ const escape = (0, stringifyWhere_1.getEscape)(dialect);
258
+ sql += ` LIMIT ${escape(limit)}`;
259
+ if (typeof offset === "number") {
260
+ sql += ` OFFSET ${escape(offset)}`;
261
+ }
262
+ }
263
+ }
264
+ // call their function for querying the DB, handle the different cases, do some validation, return a promise of the object
265
+ let data = await (0, util_1.handleUserDbCall)(dbCall, sql, sqlAST, shapeDefinition);
266
+ // if they are paginating, we'll get back an array which is essentially a "slice" of the whole data.
267
+ // this function goes through the data tree and converts the arrays to Connection Objects
268
+ // data = arrToConnection(data, sqlAST);
269
+ // so far we handled the first "batch". up until now, additional batches were ignored
270
+ // this function recursively scanss the sqlAST and runs remaining batches
271
+ await (0, batch_planner_1.default)(sqlAST, data, dbCall, context, options);
272
+ (0, addNullFallbacks_1.addNullFallbacks)(sqlAST, data);
273
+ // We only need to remove extra keys if input.fields isn't
274
+ // specified, since otherwise there wouldn't be extra keys
275
+ const shouldRemoveExtraKeys = input.fields != null;
276
+ if (action !== "findManyPaginated") {
277
+ // Remove additional keys that are added for batches and joins
278
+ // Do later for `listPaginated`, since the `id` is needed for
279
+ // creating the cursor
280
+ postProcess(data, fields, shouldRemoveExtraKeys);
281
+ if (dialect === "sqlite") {
282
+ typeCastSqlite(data, fields, input.resource, input.artifacts);
283
+ }
284
+ }
285
+ // check for batch data
286
+ if (Array.isArray(data)) {
287
+ // TODO - not sure why this code exists in original
288
+ // source code of join-monster; doesn't make sense to me.
289
+ // const childrenToCheck = sqlAST.children.filter(
290
+ // (child: any) => child.sqlBatch
291
+ // );
292
+ // data = data.filter((d) => {
293
+ // for (const child of childrenToCheck) {
294
+ // if (d[child.fieldName] == null) {
295
+ // return false;
296
+ // }
297
+ // }
298
+ // return true;
299
+ // });
300
+ if (action === "findManyPaginated") {
301
+ const argsTotalCount = input.args && _.cloneDeep(input.args);
302
+ if (argsTotalCount != null) {
303
+ if (argsTotalCount.$paginate != null) {
304
+ // We don't want the where clause to include cursor-related stuff
305
+ delete argsTotalCount.$paginate.after;
306
+ delete argsTotalCount.$paginate.before;
307
+ // We don't need offset
308
+ delete argsTotalCount.$paginate.offset;
309
+ }
310
+ }
311
+ const sqlASTTotalCount = (0, getSqlAst_1.getSqlAst)({
312
+ ...input,
313
+ table: input.resource,
314
+ fieldName: "data",
315
+ args: argsTotalCount,
316
+ // Because we're going to manually set children anyway
317
+ fields: {},
318
+ getWhere: getWhere_1.getWhere,
319
+ // We don't want the where clause to include cursor-related stuff
320
+ rowWithMatchingCursor: null,
321
+ dialect,
322
+ grabMany: true,
323
+ escapeId
324
+ });
325
+ // Because orderBy doesn't matter for total count.
326
+ // getOrderBy adds an element if paginating, so deleting args.$orderBy
327
+ // isn't sufficient.
328
+ delete sqlASTTotalCount.orderBy;
329
+ const totalCount = await getTotalCount(sqlASTTotalCount, dbCall, context, options);
330
+ if (paginationType === "cursor") {
331
+ data = wrapListPaginationCursor(data, input.args, orderByListPaginatedRootResult.flip, (xs) => {
332
+ postProcess(xs, fields, shouldRemoveExtraKeys);
333
+ if (dialect === "sqlite") {
334
+ typeCastSqlite(data, fields, input.resource, input.artifacts);
335
+ }
336
+ }, input.artifacts[input.resource].primaryKey, totalCount);
337
+ }
338
+ else {
339
+ postProcess(data, fields, shouldRemoveExtraKeys);
340
+ if (dialect === "sqlite") {
341
+ typeCastSqlite(data, fields, input.resource, input.artifacts);
342
+ }
343
+ data = wrapListPaginationLimitOffset(data, totalCount);
344
+ }
345
+ }
346
+ return data;
347
+ }
348
+ if (data == null && !grabMany) {
349
+ throw new SDKNotFoundError_1.SDKNotFoundError();
350
+ }
351
+ return data;
352
+ }
353
+ async function getCached(input, dbCall, formatQuery, dialect, cache) {
354
+ const done = (0, Stats_1.timer)();
355
+ const { stats } = cache;
356
+ const { request, cached } = await cache.from(input);
357
+ let results;
358
+ if (cached) {
359
+ if (stats)
360
+ done(stats.updateStats, "get_redis");
361
+ results = cached;
362
+ }
363
+ else {
364
+ const remove = ensureUuidSelect(input);
365
+ results = await getData(input, dbCall, formatQuery, dialect);
366
+ if (!Array.isArray(results)) {
367
+ if ("results" in results)
368
+ results = results.results;
369
+ else {
370
+ throw new Error("Bad result returned by getData in SDK.");
371
+ }
372
+ }
373
+ for (const result of results)
374
+ for (const path of remove) {
375
+ let data = result;
376
+ for (const key of path)
377
+ data = data[key];
378
+ // delete data.uuid;
379
+ }
380
+ cache.insert(request, results);
381
+ if (stats)
382
+ done(stats.updateStats, "get_mysql");
383
+ }
384
+ if (stats)
385
+ done(stats.updateStats, "get");
386
+ return results;
387
+ }
388
+ function ensureUuidSelect(input) {
389
+ const { resource, artifacts } = input;
390
+ const remove = [];
391
+ ensure(resource, input.fields);
392
+ function ensure(type, input, path = []) {
393
+ const { scalarFields, relationFields } = artifacts[type];
394
+ if (!scalarFields.includes("uuid"))
395
+ return;
396
+ const fields = input || {};
397
+ if (!Object.keys(fields).includes("uuid")) {
398
+ remove.push(path);
399
+ fields["uuid"] = true;
400
+ }
401
+ const entries = Object.entries(fields);
402
+ for (const [k, v] of entries)
403
+ if (typeof v === "object") {
404
+ const table = relationFields[k]?.table;
405
+ if (table != null) {
406
+ ensure(table, v.$fields, path.concat(k));
407
+ }
408
+ }
409
+ }
410
+ return remove;
411
+ }
412
+ function wrapListPaginationLimitOffset(data, totalCount) {
413
+ return { paginationInfo: { totalCount }, results: data };
414
+ }
415
+ // Not recursive at the moment; only supported at the root.
416
+ // TODO - remove if support for pagination for mysql dialect
417
+ // is added (I doubt it)
418
+ function wrapListPaginationCursor(data, args, flip, cb, primaryKey, totalCount) {
419
+ const limit = flip ? args.$paginate.last : args.$paginate.first;
420
+ const hasMoreResults = data.length === limit + 1;
421
+ if (hasMoreResults) {
422
+ // because we peeked
423
+ data = data.slice(0, -1);
424
+ }
425
+ if (flip) {
426
+ data = data.reverse();
427
+ }
428
+ const hasPreviousPage = flip ? hasMoreResults : false;
429
+ const hasNextPage = flip ? false : hasMoreResults;
430
+ const startKey = data?.[0]?.[primaryKey];
431
+ const endKey = data?.[data.length - 1]?.[primaryKey];
432
+ const startCursor = startKey == null ? null : (0, cursor_1.encodeCursor)(startKey);
433
+ const endCursor = endKey == null ? null : (0, cursor_1.encodeCursor)(endKey);
434
+ cb(data);
435
+ return {
436
+ paginationInfo: {
437
+ hasPreviousPage,
438
+ hasNextPage,
439
+ startCursor,
440
+ endCursor,
441
+ totalCount
442
+ },
443
+ results: data
444
+ };
445
+ }
446
+ async function getTotalCount(sqlASTTotalCount, dbCall, context, options) {
447
+ // Replace field selection with `COUNT(*)`
448
+ const fieldNameTotalCount = "totalCount";
449
+ sqlASTTotalCount.children = [
450
+ {
451
+ type: "expression",
452
+ sqlExpr: () => "COUNT(*)",
453
+ fieldName: fieldNameTotalCount,
454
+ as: fieldNameTotalCount
455
+ }
456
+ ];
457
+ const { sql: sqlTotalCount } = await (0, util_1.compileSqlAST)(sqlASTTotalCount, context, options);
458
+ const totalCount = await dbCall(sqlTotalCount).then((xs) => xs[0][fieldNameTotalCount]);
459
+ return totalCount;
460
+ }
461
+ const runCreateTreeMySQL = async (table, referencedKey, referencedKeyValue, columns, values, dbCall, formatQuery) => {
462
+ let allColumns = columns;
463
+ if (typeof referencedKey === "string") {
464
+ allColumns = allColumns.slice().map((xs) => xs.concat(referencedKey));
465
+ }
466
+ let allValues = values;
467
+ if (referencedKeyValue != null) {
468
+ allValues = allValues.slice().map((xs) => xs.concat(referencedKeyValue));
469
+ }
470
+ return Promise.all(allColumns.map((cs, i) => dbCall(formatQuery(`INSERT INTO ?? (??) VALUES (?)`, [table, cs, allValues[i]])).then((x) => x.insertId)));
471
+ };
472
+ const runCreateTreePostgreSQL = async (table, referencedKey, referencedKeyValue, columns, values, dbCall, formatQuery, artifacts) => {
473
+ if (artifacts == null) {
474
+ throw new Error("artifacts required for PostgreSQL runCreateTree");
475
+ }
476
+ const primaryKey = artifacts[table]?.primaryKey ?? "id";
477
+ let allColumns = columns;
478
+ if (typeof referencedKey === "string") {
479
+ allColumns = allColumns.slice().map((xs) => xs.concat(referencedKey));
480
+ }
481
+ let allValues = values;
482
+ if (referencedKeyValue != null) {
483
+ allValues = allValues.slice().map((xs) => xs.concat(referencedKeyValue));
484
+ }
485
+ return Promise.all(allColumns.map((cs, i) => dbCall(formatQuery(`INSERT INTO ?? (??) VALUES (?) RETURNING ??`, [
486
+ table,
487
+ cs,
488
+ allValues[i],
489
+ primaryKey
490
+ ])).then((rows) => rows[0]?.[primaryKey])));
491
+ };
492
+ async function create(input, dbCall, formatQuery, beginTransaction, dialect, context) {
493
+ async function _create() {
494
+ // Shallow clone, as we're going to mutate later
495
+ let data = { ...input.data };
496
+ const tableArtifacts = input.artifacts[input.resource];
497
+ // Top-level only
498
+ if (hasMappedFields(input.artifacts, input.resource, data)) {
499
+ await mapMappedFields(tableArtifacts, data, dbCall, formatQuery);
500
+ }
501
+ const hasChildren = Object.keys(data).some((k) => {
502
+ const oneToManyRelation = tableArtifacts.relationFields[k];
503
+ if (oneToManyRelation == null) {
504
+ return false;
505
+ }
506
+ if (oneToManyRelation.type === "one-to-many__many-to-one" &&
507
+ oneToManyRelation.kind === "one-to-many") {
508
+ return true;
509
+ }
510
+ });
511
+ if (hasChildren) {
512
+ const { dbCall: dbCallTransaction, commit } = await beginTransaction();
513
+ const runCreateTreeSQL = dialect === "postgresql" ? runCreateTreePostgreSQL : runCreateTreeMySQL;
514
+ const id = await runCreateTree(getCreateTree([data], input.resource, null, context?.specialCaseUuidColumn, dialect, input.artifacts), null, runCreateTreeSQL, dbCallTransaction, formatQuery, dialect, input.artifacts).then((xs) => xs[0]);
515
+ await commit();
516
+ return id;
517
+ }
518
+ else {
519
+ data = processCreateData(data, tableArtifacts, dialect, context?.specialCaseUuidColumn);
520
+ const columns = Object.keys(data);
521
+ const values = Object.values(data);
522
+ if (dialect === "postgresql") {
523
+ const primaryKey = tableArtifacts.primaryKey;
524
+ const inserted = await dbCall(formatQuery(`INSERT INTO ?? (??) VALUES (?) RETURNING ??`, [
525
+ input.resource,
526
+ columns,
527
+ values,
528
+ primaryKey
529
+ ]));
530
+ return inserted[0]?.[primaryKey];
531
+ }
532
+ const inserted = await dbCall(formatQuery(`INSERT INTO ?? (??) VALUES (?)`, [
533
+ input.resource,
534
+ columns,
535
+ values
536
+ ]));
537
+ return inserted.insertId;
538
+ }
539
+ }
540
+ const id = await _create();
541
+ return getData({ ...input, args: { $where: { id } } }, dbCall, formatQuery, dialect);
542
+ }
543
+ function processCreateData(data, tableArtifacts, dialect, specialCaseUuidColumn) {
544
+ let out = { ...data };
545
+ if ((dialect === "mysql" || dialect === "postgresql") &&
546
+ tableArtifacts.dateTimeFieldsCount > 0) {
547
+ for (let k in tableArtifacts.dateTimeFields) {
548
+ if (out[k] != null) {
549
+ out[k] = (0, getDateTimeStringMySQL_1.getDateTimeStringMySQL)(out[k]);
550
+ }
551
+ }
552
+ }
553
+ // Delete keys with value of undefined
554
+ for (let k in out) {
555
+ if (out[k] === void 0) {
556
+ delete out[k];
557
+ }
558
+ }
559
+ const scalarFieldSet = new Set(tableArtifacts.scalarFields);
560
+ if (specialCaseUuidColumn &&
561
+ scalarFieldSet.has("uuid") &&
562
+ !Object.prototype.hasOwnProperty.call(out, "uuid")) {
563
+ out["uuid"] = (0, uuid_1.v4)();
564
+ }
565
+ return out;
566
+ }
567
+ async function runCreateTree(tree, referencedKeyValue, runCreateTreeSQL, dbCall, formatQuery, dialect, artifacts) {
568
+ const ids = await runCreateTreeSQL(tree.table, tree.referencedKey, referencedKeyValue, tree.columns, tree.values, dbCall, formatQuery, artifacts);
569
+ if (tree.children?.length > 0) {
570
+ await Promise.all(ids.flatMap((id, i) => tree.children[i].map((c) => runCreateTree(c, id, runCreateTreeSQL, dbCall, formatQuery, dialect, artifacts))));
571
+ }
572
+ return ids;
573
+ }
574
+ function getCreateTree(data, table, referencedKey, specialCaseUuidColumn, dialect, artifacts) {
575
+ const tableArtifacts = artifacts[table];
576
+ const scalarFieldSet = new Set(tableArtifacts.scalarFields);
577
+ let out = {
578
+ table,
579
+ referencedKey,
580
+ columns: [],
581
+ values: [],
582
+ children: []
583
+ };
584
+ for (let i = 0; i < data.length; i++) {
585
+ let d = data[i];
586
+ if (Object.keys(d).length === 0) {
587
+ continue;
588
+ }
589
+ d = processCreateData(d, tableArtifacts, dialect, specialCaseUuidColumn);
590
+ out.columns[i] = [];
591
+ out.values[i] = [];
592
+ out.children[i] = [];
593
+ for (let k in d) {
594
+ if (scalarFieldSet.has(k)) {
595
+ out.columns[i].push(k);
596
+ const v = d[k];
597
+ out.values[i].push(v);
598
+ continue;
599
+ }
600
+ const oneToManyRelation = tableArtifacts.relationFields[k];
601
+ if (oneToManyRelation == null ||
602
+ oneToManyRelation.type !== "one-to-many__many-to-one" ||
603
+ oneToManyRelation.kind !== "one-to-many") {
604
+ continue;
605
+ }
606
+ if (!Array.isArray(d[k]?.$create)) {
607
+ throw new Error("Invalid data: " + k);
608
+ }
609
+ out.children[i].push(getCreateTree(d[k].$create, oneToManyRelation.table, oneToManyRelation.relation.referencedKey, specialCaseUuidColumn, dialect, artifacts));
610
+ }
611
+ }
612
+ return out;
613
+ }
614
+ async function update(input, dbCall, formatQuery, dialect, cache) {
615
+ async function _update() {
616
+ const escapeId = (0, stringifyWhere_1.getEscapeId)(dialect);
617
+ const tableArtifacts = input.artifacts[input.resource];
618
+ const where = (0, getWhere_1.getWhere)(escapeId(input.resource), input.args, dialect);
619
+ if (where == null) {
620
+ throw new Error("Null where");
621
+ }
622
+ const current = await dbCall(formatQuery("SELECT * FROM ?? WHERE " + where, [input.resource])).then((xs) => xs[0]);
623
+ if (current == null) {
624
+ throw new SDKNotFoundError_1.SDKNotFoundError();
625
+ }
626
+ if (cache && current.uuid)
627
+ cache.purge(current.uuid);
628
+ // Shallow clone, as we're going to mutate later
629
+ const data = { ...input.data };
630
+ if (hasMappedFields(input.artifacts, input.resource, data)) {
631
+ await mapMappedFields(tableArtifacts, data, dbCall, formatQuery);
632
+ }
633
+ if ((dialect === "mysql" || dialect === "postgresql") &&
634
+ tableArtifacts.dateTimeFieldsCount > 0) {
635
+ for (let k in tableArtifacts.dateTimeFields) {
636
+ if (data[k] != null) {
637
+ data[k] = (0, getDateTimeStringMySQL_1.getDateTimeStringMySQL)(data[k]);
638
+ }
639
+ }
640
+ }
641
+ // Delete keys with value of undefined
642
+ for (let k in data) {
643
+ if (data[k] === void 0) {
644
+ delete data[k];
645
+ }
646
+ }
647
+ // Nothing to update
648
+ if (Object.keys(data).length === 0) {
649
+ return true;
650
+ }
651
+ await dbCall(getUpdateQuery(input.resource, data, where, dialect, formatQuery));
652
+ return true;
653
+ }
654
+ await _update();
655
+ return getData(input, dbCall, formatQuery, dialect);
656
+ }
657
+ function getUpdateQuery(table, data, where, dialect, formatQuery) {
658
+ // Assumes `data` is not empty
659
+ const escapeId = (0, stringifyWhere_1.getEscapeId)(dialect);
660
+ const escape = (0, stringifyWhere_1.getEscape)(dialect);
661
+ let q = "UPDATE ?? ";
662
+ let values = [table];
663
+ let opsStrs = [];
664
+ let dataRegular = {};
665
+ for (let k in data) {
666
+ const v = data[k];
667
+ if (typeof v === "object" && v != null && Object.keys(v).length === 1) {
668
+ const _entries = Object.entries(v)?.[0];
669
+ const op = _entries?.[0];
670
+ const vv = _entries?.[1];
671
+ if (op === "$prepend") {
672
+ opsStrs.push(`${escapeId(k)} = CASE WHEN ${escapeId(k)} IS NULL THEN NULL ELSE ${stringifyConcat(escape(vv), escapeId(k), dialect)} END`);
673
+ continue;
674
+ }
675
+ if (op === "$append") {
676
+ opsStrs.push(`${escapeId(k)} = CASE WHEN ${escapeId(k)} IS NULL THEN NULL ELSE ${stringifyConcat(escapeId(k), escape(vv), dialect)} END`);
677
+ continue;
678
+ }
679
+ if (op === "$increment") {
680
+ opsStrs.push(`${escapeId(k)} = ${escapeId(k)} + ${escape(vv)}`);
681
+ continue;
682
+ }
683
+ if (op === "$decrement") {
684
+ opsStrs.push(`${escapeId(k)} = ${escapeId(k)} - ${escape(vv)}`);
685
+ continue;
686
+ }
687
+ dataRegular[k] = v;
688
+ }
689
+ dataRegular[k] = v;
690
+ }
691
+ if (opsStrs.length > 0) {
692
+ q += `SET ${opsStrs.join(", ")}`;
693
+ }
694
+ const columns = Object.keys(dataRegular);
695
+ if (columns.length > 0) {
696
+ if (opsStrs.length > 0) {
697
+ q += ", ";
698
+ }
699
+ else {
700
+ q += "SET ";
701
+ }
702
+ q += columns.map((x) => `${escapeId(x)} = ?`).join(", ");
703
+ for (let k in dataRegular) {
704
+ values.push(dataRegular[k]);
705
+ }
706
+ }
707
+ q += ` WHERE ${where}`;
708
+ return formatQuery(q, values);
709
+ }
710
+ function stringifyConcat(operand1, operand2, dialect) {
711
+ if (dialect === "mysql") {
712
+ return `CONCAT(${operand1}, ${operand2})`;
713
+ }
714
+ // sqlite and postgresql use || for string concatenation
715
+ return `(${operand1} || ${operand2})`;
716
+ }
717
+ async function updateMany(input, dbCall, formatQuery, dialect, cache) {
718
+ async function _updateMany() {
719
+ const escapeId = (0, stringifyWhere_1.getEscapeId)(dialect);
720
+ const tableArtifacts = input.artifacts[input.resource];
721
+ const where = (0, getWhere_1.getWhere)(escapeId(input.resource), input.args, dialect);
722
+ if (where == null) {
723
+ throw new Error("Null where");
724
+ }
725
+ if (cache)
726
+ try {
727
+ const query = formatQuery(`SELECT uuid FROM ?? WHERE ${where}`, [
728
+ input.resource
729
+ ]);
730
+ const matches = await dbCall(query);
731
+ const uuids = matches.map((x) => x.uuid);
732
+ cache.purge(...uuids);
733
+ }
734
+ catch (err) { }
735
+ // Shallow clone, as we're going to mutate later
736
+ const data = { ...input.data };
737
+ if (hasMappedFields(input.artifacts, input.resource, data)) {
738
+ await mapMappedFields(tableArtifacts, data, dbCall, formatQuery);
739
+ }
740
+ if ((dialect === "mysql" || dialect === "postgresql") &&
741
+ tableArtifacts.dateTimeFieldsCount > 0) {
742
+ for (let k in tableArtifacts.dateTimeFields) {
743
+ if (data[k] != null) {
744
+ data[k] = (0, getDateTimeStringMySQL_1.getDateTimeStringMySQL)(data[k]);
745
+ }
746
+ }
747
+ }
748
+ // Delete keys with value of undefined
749
+ for (let k in data) {
750
+ if (data[k] === void 0) {
751
+ delete data[k];
752
+ }
753
+ }
754
+ // Nothing to update
755
+ if (Object.keys(data).length === 0) {
756
+ return [];
757
+ }
758
+ await dbCall(getUpdateQuery(input.resource, data, where, dialect, formatQuery));
759
+ return true;
760
+ }
761
+ await _updateMany();
762
+ return getData(input, dbCall, formatQuery, dialect);
763
+ }
764
+ async function deleteOne(input, dbCall, formatQuery, dialect, cache) {
765
+ const _findOne = Object.entries(input.args.$where)[0];
766
+ const findOne = { key: _findOne[0], value: _findOne[1] };
767
+ const current = await dbCall(formatQuery("SELECT * FROM ?? WHERE ?? = ?", [
768
+ input.resource,
769
+ findOne.key,
770
+ findOne.value
771
+ ])).then((xs) => xs[0]);
772
+ if (current == null) {
773
+ throw new SDKNotFoundError_1.SDKNotFoundError();
774
+ }
775
+ if (cache && current.uuid)
776
+ cache.purge(current.uuid);
777
+ await dbCall(formatQuery("DELETE FROM ?? WHERE ?? = ?", [
778
+ input.resource,
779
+ findOne.key,
780
+ findOne.value
781
+ ]));
782
+ return true;
783
+ }
784
+ async function deleteMany(input, dbCall, formatQuery, dialect, cache) {
785
+ const escapeId = (0, stringifyWhere_1.getEscapeId)(dialect);
786
+ const where = (0, getWhere_1.getWhere)(escapeId(input.resource), input.args, dialect);
787
+ if (where == null) {
788
+ throw new Error("Null where");
789
+ }
790
+ if (cache)
791
+ try {
792
+ const query = formatQuery(`SELECT uuid FROM ?? WHERE ${where}`, [
793
+ input.resource
794
+ ]);
795
+ const matches = await dbCall(query);
796
+ const uuids = matches.map((x) => x.uuid);
797
+ cache.purge(...uuids);
798
+ }
799
+ catch (err) { }
800
+ const sql = "DELETE FROM ?? WHERE " + where;
801
+ const values = [input.resource];
802
+ await dbCall(formatQuery(sql, values));
803
+ return true;
804
+ }
805
+ function getScalarFields(table, artifacts) {
806
+ return artifacts[table].scalarFields;
807
+ }
808
+ function hasMappedFields(artifacts, table, data) {
809
+ const mappedFields = artifacts[table].mappedFields;
810
+ if (mappedFields == null) {
811
+ return false;
812
+ }
813
+ const keys = new Set(Object.keys(mappedFields));
814
+ const dataKeys = Object.keys(data);
815
+ return dataKeys.some((k) => keys.has(k));
816
+ }
817
+ async function mapMappedFields(artifactsForTable, data, dbCall, formatQuery) {
818
+ for (let k in data) {
819
+ const v = data[k];
820
+ if (artifactsForTable.mappedFields == null) {
821
+ continue;
822
+ }
823
+ const mappedField = artifactsForTable.mappedFields[k];
824
+ if (mappedField == null) {
825
+ continue;
826
+ }
827
+ if (Object.prototype.hasOwnProperty.call(data, mappedField.foreignKey)) {
828
+ throw new Error("Must not supply both UUID and ID: " + mappedField.foreignKey);
829
+ }
830
+ if (v === null) {
831
+ data[mappedField.foreignKey] = v;
832
+ delete data[k];
833
+ }
834
+ else if (v === void 0) {
835
+ delete data[k];
836
+ }
837
+ else if (Array.isArray(v)) {
838
+ data[mappedField.foreignKey] = await Promise.all(v.map(async (w) => {
839
+ const result = await dbCall(formatQuery("SELECT ?? FROM ?? WHERE ?? = ?", [
840
+ mappedField.referencedKey,
841
+ mappedField.referencedTable,
842
+ mappedField.name,
843
+ w
844
+ ])).then((xs) => xs[0]?.[mappedField.referencedKey]);
845
+ if (result == null) {
846
+ throw new SDKNotFoundError_1.SDKNotFoundError();
847
+ }
848
+ return result;
849
+ }));
850
+ delete data[k];
851
+ }
852
+ else {
853
+ const result = await dbCall(formatQuery("SELECT ?? FROM ?? WHERE ?? = ?", [
854
+ mappedField.referencedKey,
855
+ mappedField.referencedTable,
856
+ mappedField.name,
857
+ v
858
+ ])).then((xs) => xs[0]?.[mappedField.referencedKey]);
859
+ if (result == null) {
860
+ throw new SDKNotFoundError_1.SDKNotFoundError();
861
+ }
862
+ data[mappedField.foreignKey] = result;
863
+ delete data[k];
864
+ }
865
+ }
866
+ }
867
+ // 1. Remove additional keys added to data for batches and joins
868
+ function postProcess(data, fields, shouldRemoveExtraKeys) {
869
+ if (shouldRemoveExtraKeys) {
870
+ removeExtraKeys(data, fields);
871
+ }
872
+ }
873
+ function removeExtraKeys(data, fields) {
874
+ if (data == null || (Array.isArray(data) && data[0] == null)) {
875
+ return;
876
+ }
877
+ let fieldKeys = Object.keys(fields);
878
+ const dataKeys = Array.isArray(data) ? Object.keys(data[0]) : Object.keys(data);
879
+ const extraDataKeys = _.difference(dataKeys, fieldKeys);
880
+ for (let k of extraDataKeys) {
881
+ if (Array.isArray(data)) {
882
+ for (let d of data) {
883
+ delete d[k];
884
+ }
885
+ }
886
+ else {
887
+ delete data[k];
888
+ }
889
+ }
890
+ const entries = Object.entries(fields);
891
+ for (let [k, v] of entries) {
892
+ if (typeof v === "object" && v.$fields != null) {
893
+ if (Array.isArray(data)) {
894
+ for (let d of data) {
895
+ removeExtraKeys(d[k], v.$fields);
896
+ }
897
+ }
898
+ else {
899
+ removeExtraKeys(data[k], v.$fields);
900
+ }
901
+ }
902
+ }
903
+ }
904
+ const getTypeCastMap = _.memoize(function getTypeCastMap(artifacts) {
905
+ const typeCastMap = new Map();
906
+ for (let table in artifacts) {
907
+ let booleanColumns = new Set();
908
+ for (let field of artifacts[table].fields) {
909
+ if (field.kind === "scalar" && field.type === "boolean") {
910
+ booleanColumns.add(field.name);
911
+ }
912
+ }
913
+ typeCastMap.set(table, { boolean: booleanColumns });
914
+ }
915
+ return typeCastMap;
916
+ });
917
+ function typeCastSqlite(data, fields, table, artifacts) {
918
+ if (data == null || (Array.isArray(data) && data[0] == null)) {
919
+ return;
920
+ }
921
+ const typeCastMap = getTypeCastMap(artifacts);
922
+ const booleanColumns = typeCastMap.get(table)?.boolean;
923
+ if (booleanColumns == null) {
924
+ throw new Error(`Failed to resolve typeCastMap for table \`${table}\``);
925
+ }
926
+ if (booleanColumns.size > 0) {
927
+ const keys = Object.keys(fields);
928
+ for (let k of keys) {
929
+ if (booleanColumns.has(k)) {
930
+ if (Array.isArray(data)) {
931
+ for (let d of data) {
932
+ d[k] = !!d[k];
933
+ }
934
+ }
935
+ else {
936
+ data[k] = !!data[k];
937
+ }
938
+ }
939
+ }
940
+ }
941
+ const tableArtifacts = artifacts[table];
942
+ const entries = Object.entries(fields);
943
+ for (let [k, v] of entries) {
944
+ if (typeof v === "object") {
945
+ const relationFields = tableArtifacts.relationFields[k];
946
+ if (relationFields == null) {
947
+ throw new Error(`Failed to resolve relationFields for field \`${k}\``);
948
+ }
949
+ const fields = v.$fields ??
950
+ tableArtifacts.scalarFields.reduce((acc, x) => {
951
+ acc[x] = true;
952
+ return acc;
953
+ }, {});
954
+ if (Array.isArray(data)) {
955
+ for (let d of data) {
956
+ typeCastSqlite(d[k], fields, relationFields.table, artifacts);
957
+ }
958
+ }
959
+ else {
960
+ typeCastSqlite(data[k], fields, relationFields.table, artifacts);
961
+ }
962
+ }
963
+ }
964
+ }
965
+ function whereNeedsProcessing(where) {
966
+ return JSON.stringify(where).includes("Uuid");
967
+ }
968
+ async function _prepareWhere(artifacts, table, data, dbCall, formatQuery) {
969
+ const mappedFields = artifacts[table].mappedFields;
970
+ let out = {};
971
+ await traverseWhere(data, async (where, ptr, parentPtr, root) => {
972
+ const path = ptr.split("/").slice(1);
973
+ const opIndex = path.length - 1;
974
+ if (ops.includes(path[opIndex])) {
975
+ const newPath = path.slice();
976
+ const index = newPath.length - 2;
977
+ const key = newPath[index];
978
+ const mappedField = mappedFields?.[key];
979
+ if (mappedField != null) {
980
+ newPath[index] = mappedField.foreignKey;
981
+ if (Array.isArray(where)) {
982
+ const newVal = await Promise.all(where.map((v) => dbCall(formatQuery("SELECT ?? FROM ?? WHERE ?? = ?", [
983
+ mappedField.referencedKey,
984
+ mappedField.referencedTable,
985
+ mappedField.name,
986
+ v
987
+ ])).then((xs) => xs[0]?.[mappedField.referencedKey])));
988
+ if (newVal.some((x) => x == null)) {
989
+ const index = newVal.findIndex((x) => x == null);
990
+ if (index === -1) {
991
+ throw new SDKBadWhereError_1.SDKBadWhereError();
992
+ }
993
+ else {
994
+ const v = where[index];
995
+ throw new SDKBadWhereError_1.SDKBadWhereError(getPrepareWhereNotFoundMessage(mappedField, v));
996
+ }
997
+ }
998
+ out = _.set(newPath, newVal, out);
999
+ }
1000
+ else {
1001
+ const newVal = await dbCall(formatQuery("SELECT ?? FROM ?? WHERE ?? = ?", [
1002
+ mappedField.referencedKey,
1003
+ mappedField.referencedTable,
1004
+ mappedField.name,
1005
+ where
1006
+ ])).then((xs) => xs[0]?.[mappedField.referencedKey]);
1007
+ if (newVal == null) {
1008
+ throw new SDKBadWhereError_1.SDKBadWhereError(getPrepareWhereNotFoundMessage(mappedField, where));
1009
+ }
1010
+ out = _.set(newPath, newVal, out);
1011
+ }
1012
+ out = _.unset(path.slice(0, path.length - 1), out);
1013
+ return;
1014
+ }
1015
+ }
1016
+ else {
1017
+ const key = path[path.length - 1];
1018
+ const mappedField = mappedFields?.[key];
1019
+ if (mappedField != null) {
1020
+ const newPath = path
1021
+ .slice(0, path.length - 1)
1022
+ .concat(mappedField.foreignKey);
1023
+ if (Array.isArray(where)) {
1024
+ const newVal = await Promise.all(where.map((v) => dbCall(formatQuery("SELECT ?? FROM ?? WHERE ?? = ?", [
1025
+ mappedField.referencedKey,
1026
+ mappedField.referencedTable,
1027
+ mappedField.name,
1028
+ v
1029
+ ])).then((xs) => xs[0]?.[mappedField.referencedKey])));
1030
+ if (newVal.some((x) => x == null)) {
1031
+ const index = newVal.findIndex((x) => x == null);
1032
+ if (index === -1) {
1033
+ throw new SDKBadWhereError_1.SDKBadWhereError();
1034
+ }
1035
+ else {
1036
+ const v = where[index];
1037
+ throw new SDKBadWhereError_1.SDKBadWhereError(getPrepareWhereNotFoundMessage(mappedField, v));
1038
+ }
1039
+ }
1040
+ out = _.set(newPath, newVal, out);
1041
+ }
1042
+ else {
1043
+ const newVal = await dbCall(formatQuery("SELECT ?? FROM ?? WHERE ?? = ?", [
1044
+ mappedField.referencedKey,
1045
+ mappedField.referencedTable,
1046
+ mappedField.name,
1047
+ where
1048
+ ])).then((xs) => xs[0]?.[mappedField.referencedKey]);
1049
+ if (newVal == null) {
1050
+ throw new SDKBadWhereError_1.SDKBadWhereError(getPrepareWhereNotFoundMessage(mappedField, where));
1051
+ }
1052
+ out = _.set(newPath, newVal, out);
1053
+ }
1054
+ out = _.unset(path, out);
1055
+ }
1056
+ else {
1057
+ out = path.length > 0 ? _.set(path, where, out) : where;
1058
+ }
1059
+ }
1060
+ });
1061
+ return out;
1062
+ }
1063
+ function getPrepareWhereNotFoundMessage(mappedField, value) {
1064
+ return `Not found: unable to map \`${mappedField.referencedTable}\`.\`${mappedField.name}\` to \`${mappedField.referencedTable}\`.\`${mappedField.referencedKey}\` for the value \`${value}\`.`;
1065
+ }
1066
+ const ops = [
1067
+ "$eq",
1068
+ "$neq",
1069
+ "$gt",
1070
+ "$gte",
1071
+ "$lt",
1072
+ "$lte",
1073
+ "$in",
1074
+ "$nin",
1075
+ "$like",
1076
+ "$nlike",
1077
+ "$btwn",
1078
+ "$nbtwn"
1079
+ ];
1080
+ async function traverseWhere(where, cb) {
1081
+ return await _traverseWhere(cb, where, "", where);
1082
+ }
1083
+ const _traverseWhere = async function (cb, where, ptr, root, parentPtr) {
1084
+ await cb(where, ptr, parentPtr, root);
1085
+ if (where && typeof where == "object" && !Array.isArray(where)) {
1086
+ for (let key in where) {
1087
+ const sch = where[key];
1088
+ if (key === "$and" || key == "$or") {
1089
+ await Promise.all(sch.map(async (s, i) => {
1090
+ await _traverseWhere(cb, s, ptr + "/" + key + "/" + i, root, ptr
1091
+ // key,
1092
+ // where,
1093
+ // parentPtr,
1094
+ // i
1095
+ );
1096
+ }));
1097
+ }
1098
+ else if (typeof sch === "object") {
1099
+ for (let prop in sch) {
1100
+ await _traverseWhere(cb, sch[prop], ptr + "/" + key + "/" + escapePtr(prop), root, ptr
1101
+ // key,
1102
+ // where,
1103
+ // prop
1104
+ );
1105
+ }
1106
+ }
1107
+ else {
1108
+ await _traverseWhere(cb, sch, ptr + "/" + key, root, ptr
1109
+ // key,
1110
+ // where
1111
+ );
1112
+ }
1113
+ }
1114
+ }
1115
+ };
1116
+ function escapePtr(str) {
1117
+ return str.replace(/~/g, "~0").replace(/\//g, "~1");
1118
+ }