@technicity/data-service-generator 0.10.0-next.0 → 0.11.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.
- package/dist/generation/generate.js +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +4 -3
- package/dist/runtime/RuntimeKSQL.d.ts +1 -1
- package/dist/runtime/RuntimeKSQL.js +11 -13
- package/dist/runtime/RuntimeMSSQL.d.ts +14 -18
- package/dist/runtime/RuntimeMSSQL.js +43 -48
- package/dist/runtime/RuntimeMySQL.d.ts +12 -10
- package/dist/runtime/RuntimeMySQL.js +84 -46
- package/dist/runtime/lib/MSSQL.d.ts +13 -0
- package/dist/runtime/lib/MSSQL.js +73 -0
- package/dist/runtime/lib/SDKBadWhereError.d.ts +4 -0
- package/dist/runtime/lib/SDKBadWhereError.js +10 -0
- package/dist/runtime/lib/SDKNotFoundError.d.ts +4 -0
- package/dist/runtime/lib/SDKNotFoundError.js +10 -0
- package/dist/runtime/lib/getDateTimeStringMySQL.d.ts +1 -0
- package/dist/runtime/lib/getDateTimeStringMySQL.js +8 -0
- package/dist/runtime/lib/getSqlAst.js +2 -2
- package/dist/runtime/lib/getWhere.d.ts +0 -17
- package/dist/runtime/lib/getWhere.js +4 -228
- package/dist/runtime/lib/shared.d.ts +13 -22
- package/dist/runtime/lib/shared.js +787 -16
- package/dist/runtime/lib/stringifyWhere.d.ts +18 -0
- package/dist/runtime/lib/stringifyWhere.js +228 -0
- package/dist/runtime/lib/typeCastMSSQL.js +1 -1
- package/package.json +4 -1
- package/dist/runtime/Runtime.d.ts +0 -23
- package/dist/runtime/Runtime.js +0 -29
- package/dist/runtime/lib/create.d.ts +0 -12
- package/dist/runtime/lib/create.js +0 -175
- package/dist/runtime/lib/delete.d.ts +0 -5
- package/dist/runtime/lib/delete.js +0 -43
- package/dist/runtime/lib/error.d.ts +0 -9
- package/dist/runtime/lib/error.js +0 -22
- package/dist/runtime/lib/getData.d.ts +0 -4
- package/dist/runtime/lib/getData.js +0 -227
- package/dist/runtime/lib/prepareWhere.d.ts +0 -2
- package/dist/runtime/lib/prepareWhere.js +0 -158
- package/dist/runtime/lib/resolve.d.ts +0 -10
- package/dist/runtime/lib/resolve.js +0 -66
- package/dist/runtime/lib/update.d.ts +0 -4
- package/dist/runtime/lib/update.js +0 -143
|
@@ -1,20 +1,299 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports._prepareWhere = exports.whereNeedsProcessing = exports.postProcess = exports.MiddlewareHandler = exports.resolve = void 0;
|
|
4
|
+
// @ts-ignore
|
|
5
|
+
// import * as queryAST from "join-monster/dist/query-ast-to-sql-ast";
|
|
6
|
+
// @ts-ignore
|
|
7
|
+
// import arrToConnection from "join-monster/dist/array-to-connection";
|
|
8
|
+
// @ts-ignore
|
|
9
|
+
const batch_planner_1 = require("join-monster/dist/batch-planner");
|
|
4
10
|
// @ts-ignore
|
|
5
11
|
const util_1 = require("join-monster/dist/util");
|
|
12
|
+
const async_hooks_1 = require("async_hooks");
|
|
6
13
|
const _ = require("lodash/fp");
|
|
7
|
-
const
|
|
14
|
+
const uuid_1 = require("uuid");
|
|
15
|
+
const getSqlAst_1 = require("./getSqlAst");
|
|
16
|
+
const getWhere_1 = require("./getWhere");
|
|
17
|
+
const getDateTimeStringMySQL_1 = require("./getDateTimeStringMySQL");
|
|
8
18
|
const cursor_1 = require("./cursor");
|
|
9
19
|
const runTransforms_1 = require("./runTransforms");
|
|
20
|
+
const addNullFallbacks_1 = require("./addNullFallbacks");
|
|
21
|
+
const SDKNotFoundError_1 = require("./SDKNotFoundError");
|
|
22
|
+
const SDKBadWhereError_1 = require("./SDKBadWhereError");
|
|
23
|
+
const stringifyWhere_1 = require("./stringifyWhere");
|
|
24
|
+
const getOrderBy_1 = require("./getOrderBy");
|
|
25
|
+
async function resolve(input, dbCall, formatQuery, beginTransaction, dialect, middlewareHandler, context, cache) {
|
|
26
|
+
// https://github.com/prisma/prisma/blob/822198e5ba21535364d20c86901b8c3778ebf6a3/packages/client/src/runtime/getPrismaClient.ts#L1087
|
|
27
|
+
let index = -1;
|
|
28
|
+
if (middlewareHandler.length() > 0) {
|
|
29
|
+
const resource = new async_hooks_1.AsyncResource("sdk-request");
|
|
30
|
+
const params = input;
|
|
31
|
+
const consumer = (paramsMaybeMutated) => {
|
|
32
|
+
const nextMiddleware = middlewareHandler.get(++index);
|
|
33
|
+
if (nextMiddleware != null) {
|
|
34
|
+
return nextMiddleware(paramsMaybeMutated, consumer);
|
|
35
|
+
}
|
|
36
|
+
const paramsChanged = { ...input, ...params };
|
|
37
|
+
return _resolve(paramsChanged, dbCall, formatQuery, beginTransaction, dialect, context, cache);
|
|
38
|
+
};
|
|
39
|
+
return resource.runInAsyncScope(() => consumer(params));
|
|
40
|
+
}
|
|
41
|
+
return _resolve(input, dbCall, formatQuery, beginTransaction, dialect, context, cache);
|
|
42
|
+
}
|
|
43
|
+
exports.resolve = resolve;
|
|
44
|
+
function _resolve(input, dbCall, formatQuery, beginTransaction, dialect, context, cache) {
|
|
45
|
+
switch (input.action) {
|
|
46
|
+
case "findUnique":
|
|
47
|
+
case "findMany":
|
|
48
|
+
case "findManyPaginated":
|
|
49
|
+
return cache ?
|
|
50
|
+
getCached(input, dbCall, formatQuery, dialect, cache) :
|
|
51
|
+
getData(input, dbCall, formatQuery, dialect);
|
|
52
|
+
case "create":
|
|
53
|
+
return create(input, dbCall, formatQuery, beginTransaction, dialect, context);
|
|
54
|
+
case "update":
|
|
55
|
+
return update(input, dbCall, formatQuery, dialect, cache);
|
|
56
|
+
case "updateMany":
|
|
57
|
+
return updateMany(input, dbCall, formatQuery, dialect, cache);
|
|
58
|
+
case "delete":
|
|
59
|
+
return deleteOne(input, dbCall, formatQuery, dialect, cache);
|
|
60
|
+
case "deleteMany":
|
|
61
|
+
return deleteMany(input, dbCall, formatQuery, dialect, cache);
|
|
62
|
+
default:
|
|
63
|
+
throw new Error("Invalid action: " + input.action);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
class MiddlewareHandler {
|
|
67
|
+
constructor() {
|
|
68
|
+
this._middlewares = [];
|
|
69
|
+
}
|
|
70
|
+
register(middleware) {
|
|
71
|
+
this._middlewares.push(middleware);
|
|
72
|
+
}
|
|
73
|
+
get(id) {
|
|
74
|
+
return this._middlewares[id];
|
|
75
|
+
}
|
|
76
|
+
has(id) {
|
|
77
|
+
return !!this._middlewares[id];
|
|
78
|
+
}
|
|
79
|
+
length() {
|
|
80
|
+
return this._middlewares.length;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
exports.MiddlewareHandler = MiddlewareHandler;
|
|
84
|
+
async function getData(input, dbCall, formatQuery, dialect) {
|
|
85
|
+
const context = {};
|
|
86
|
+
const action = input.action;
|
|
87
|
+
const primaryKey = input.artifacts[input.resource].primaryKey;
|
|
88
|
+
let paginationType;
|
|
89
|
+
let limit = undefined;
|
|
90
|
+
let offset = undefined;
|
|
91
|
+
let rowWithMatchingCursor = undefined;
|
|
92
|
+
if (action === "findManyPaginated") {
|
|
93
|
+
if (input.args?.$paginate == null) {
|
|
94
|
+
throw new Error("$paginate required but not supplied");
|
|
95
|
+
}
|
|
96
|
+
if (typeof input?.args?.$paginate?.limit === "number") {
|
|
97
|
+
paginationType = "limit-offset";
|
|
98
|
+
limit = input.args.$paginate.limit;
|
|
99
|
+
offset = input.args.$paginate.offset;
|
|
100
|
+
}
|
|
101
|
+
else if (typeof input?.args?.$paginate?.first === "number" ||
|
|
102
|
+
typeof input?.args?.$paginate?.last === "number") {
|
|
103
|
+
paginationType = "cursor";
|
|
104
|
+
limit = (typeof input?.args?.$paginate?.first === "number"
|
|
105
|
+
? input?.args?.$paginate?.first
|
|
106
|
+
: input?.args?.$paginate?.last);
|
|
107
|
+
// + 1 to peek if there is more data
|
|
108
|
+
limit += 1;
|
|
109
|
+
if (input.args.$paginate.after != null ||
|
|
110
|
+
input.args.$paginate.before != null) {
|
|
111
|
+
const cursor = input.args.$paginate.after != null
|
|
112
|
+
? input.args.$paginate.after
|
|
113
|
+
: input.args.$paginate.before;
|
|
114
|
+
rowWithMatchingCursor = await dbCall(formatQuery("SELECT * FROM ?? WHERE ?? = ?", [
|
|
115
|
+
input.resource,
|
|
116
|
+
primaryKey,
|
|
117
|
+
(0, cursor_1.decodeCursor)(cursor),
|
|
118
|
+
])).then((xs) => xs[0]);
|
|
119
|
+
if (rowWithMatchingCursor == null) {
|
|
120
|
+
throw new Error(`Invalid cursor: ${cursor}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
throw new Error(`Invalid $paginate: ${input?.args?.$paginate}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else if (action === "findMany") {
|
|
129
|
+
if (typeof input?.args?.$limit === "number") {
|
|
130
|
+
limit = input?.args?.$limit;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// we need to read the query AST and build a new "SQL AST" from which the SQL and
|
|
134
|
+
// const sqlAST = queryAST.queryASTToSqlAST(resolveInfo, options, context);
|
|
135
|
+
const fields = input.fields ?? getScalarFields(input.resource, input.artifacts);
|
|
136
|
+
const orderByListPaginatedRootResult =
|
|
137
|
+
// MSSQL's OFFSET and FETCH requires ORDER BY, so we need to provide a fallback
|
|
138
|
+
dialect === "mssql" && paginationType === "limit-offset"
|
|
139
|
+
? {
|
|
140
|
+
orderBy: (0, getOrderBy_1.getOrderBy)(input.args, primaryKey)?.orderBy ?? [
|
|
141
|
+
{ column: primaryKey, direction: "asc" },
|
|
142
|
+
],
|
|
143
|
+
flip: false,
|
|
144
|
+
}
|
|
145
|
+
: action === "findManyPaginated"
|
|
146
|
+
? (0, getOrderBy_1.getOrderBy)(input.args, primaryKey)
|
|
147
|
+
: undefined;
|
|
148
|
+
const grabMany = action === "findMany" ||
|
|
149
|
+
action === "findManyPaginated" ||
|
|
150
|
+
action === "updateMany" ||
|
|
151
|
+
action === "deleteMany";
|
|
152
|
+
const sqlAST = (0, getSqlAst_1.getSqlAst)({
|
|
153
|
+
...input,
|
|
154
|
+
table: input.resource,
|
|
155
|
+
fieldName: "data",
|
|
156
|
+
fields,
|
|
157
|
+
getWhere: getWhere_1.getWhere,
|
|
158
|
+
orderBy: orderByListPaginatedRootResult?.orderBy,
|
|
159
|
+
rowWithMatchingCursor,
|
|
160
|
+
dialect,
|
|
161
|
+
grabMany,
|
|
162
|
+
});
|
|
163
|
+
const options = { dialect };
|
|
164
|
+
let { sql, shapeDefinition } = await (0, util_1.compileSqlAST)(sqlAST, context, options);
|
|
165
|
+
if (!sql) {
|
|
166
|
+
// return {};
|
|
167
|
+
throw new Error("No SQL");
|
|
168
|
+
}
|
|
169
|
+
// TODO - remove if limit support added for mysql dialect
|
|
170
|
+
if (action === "findMany" || action === "findManyPaginated") {
|
|
171
|
+
if (typeof limit === "number") {
|
|
172
|
+
const escape = (0, stringifyWhere_1.getEscape)(dialect);
|
|
173
|
+
if (dialect === "mssql") {
|
|
174
|
+
if (typeof offset === "number") {
|
|
175
|
+
sql += ` OFFSET ${escape(offset)} ROWS FETCH NEXT ${escape(limit)} ROWS ONLY`;
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
sql = sql.replace("SELECT", `SELECT TOP ${escape(limit)}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
sql += ` LIMIT ${escape(limit)}`;
|
|
183
|
+
if (typeof offset === "number") {
|
|
184
|
+
sql += ` OFFSET ${escape(offset)}`;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// call their function for querying the DB, handle the different cases, do some validation, return a promise of the object
|
|
190
|
+
let data = await (0, util_1.handleUserDbCall)(dbCall, sql, sqlAST, shapeDefinition);
|
|
191
|
+
// if they are paginating, we'll get back an array which is essentially a "slice" of the whole data.
|
|
192
|
+
// this function goes through the data tree and converts the arrays to Connection Objects
|
|
193
|
+
// data = arrToConnection(data, sqlAST);
|
|
194
|
+
// so far we handled the first "batch". up until now, additional batches were ignored
|
|
195
|
+
// this function recursively scanss the sqlAST and runs remaining batches
|
|
196
|
+
await (0, batch_planner_1.default)(sqlAST, data, dbCall, context, options);
|
|
197
|
+
(0, addNullFallbacks_1.addNullFallbacks)(sqlAST, data);
|
|
198
|
+
// We only need to remove extra keys if input.fields isn't
|
|
199
|
+
// specified, since otherwise there wouldn't be extra keys
|
|
200
|
+
const shouldRemoveExtraKeys = input.fields != null;
|
|
201
|
+
if (action !== "findManyPaginated") {
|
|
202
|
+
// Remove additional keys that are added for batches and joins
|
|
203
|
+
// Do later for `listPaginated`, since the `id` is needed for
|
|
204
|
+
// creating the cursor
|
|
205
|
+
postProcess(data, fields, shouldRemoveExtraKeys);
|
|
206
|
+
}
|
|
207
|
+
// check for batch data
|
|
208
|
+
if (Array.isArray(data)) {
|
|
209
|
+
// TODO - not sure why this code exists in original
|
|
210
|
+
// source code of join-monster; doesn't make sense to me.
|
|
211
|
+
// const childrenToCheck = sqlAST.children.filter(
|
|
212
|
+
// (child: any) => child.sqlBatch
|
|
213
|
+
// );
|
|
214
|
+
// data = data.filter((d) => {
|
|
215
|
+
// for (const child of childrenToCheck) {
|
|
216
|
+
// if (d[child.fieldName] == null) {
|
|
217
|
+
// return false;
|
|
218
|
+
// }
|
|
219
|
+
// }
|
|
220
|
+
// return true;
|
|
221
|
+
// });
|
|
222
|
+
if (action === "findManyPaginated") {
|
|
223
|
+
const argsTotalCount = input.args && _.cloneDeep(input.args);
|
|
224
|
+
if (argsTotalCount != null) {
|
|
225
|
+
if (argsTotalCount.$paginate != null) {
|
|
226
|
+
// We don't want the where clause to include cursor-related stuff
|
|
227
|
+
delete argsTotalCount.$paginate.after;
|
|
228
|
+
delete argsTotalCount.$paginate.before;
|
|
229
|
+
// We don't need offset
|
|
230
|
+
delete argsTotalCount.$paginate.offset;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
const sqlASTTotalCount = (0, getSqlAst_1.getSqlAst)({
|
|
234
|
+
...input,
|
|
235
|
+
table: input.resource,
|
|
236
|
+
fieldName: "data",
|
|
237
|
+
args: argsTotalCount,
|
|
238
|
+
// Because we're going to manually set children anyway
|
|
239
|
+
fields: [],
|
|
240
|
+
getWhere: getWhere_1.getWhere,
|
|
241
|
+
// We don't want the where clause to include cursor-related stuff
|
|
242
|
+
rowWithMatchingCursor: null,
|
|
243
|
+
dialect,
|
|
244
|
+
grabMany: true,
|
|
245
|
+
});
|
|
246
|
+
// Because orderBy doesn't matter for total count.
|
|
247
|
+
// getOrderBy adds an element if paginating, so deleting args.$orderBy
|
|
248
|
+
// isn't sufficient.
|
|
249
|
+
delete sqlASTTotalCount.orderBy;
|
|
250
|
+
const totalCount = await getTotalCount(sqlASTTotalCount, dbCall, context, options);
|
|
251
|
+
if (paginationType === "cursor") {
|
|
252
|
+
data = wrapListPaginationCursor(data, input.args, orderByListPaginatedRootResult.flip, (xs) => {
|
|
253
|
+
postProcess(xs, fields, shouldRemoveExtraKeys);
|
|
254
|
+
}, input.artifacts[input.resource].primaryKey, totalCount);
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
postProcess(data, fields, shouldRemoveExtraKeys);
|
|
258
|
+
data = wrapListPaginationLimitOffset(data, totalCount);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return data;
|
|
262
|
+
}
|
|
263
|
+
if (data == null && !grabMany) {
|
|
264
|
+
throw new SDKNotFoundError_1.SDKNotFoundError();
|
|
265
|
+
}
|
|
266
|
+
return data;
|
|
267
|
+
}
|
|
268
|
+
async function getCached(input, dbCall, formatQuery, dialect, cache) {
|
|
269
|
+
const { request, cached } = await cache.from(input);
|
|
270
|
+
if (cached)
|
|
271
|
+
return cached;
|
|
272
|
+
ensureUuidSelect(input);
|
|
273
|
+
const results = await getData(input, dbCall, formatQuery, dialect);
|
|
274
|
+
cache.insert(request, results);
|
|
275
|
+
return results;
|
|
276
|
+
}
|
|
277
|
+
function ensureUuidSelect(input) {
|
|
278
|
+
const { resource, artifacts } = input;
|
|
279
|
+
ensure(resource, input);
|
|
280
|
+
function ensure(type, input) {
|
|
281
|
+
const { scalarFields, relationFields } = artifacts[type];
|
|
282
|
+
if (!scalarFields.includes("uuid"))
|
|
283
|
+
return;
|
|
284
|
+
const fields = input.fields || [];
|
|
285
|
+
if (!fields.includes("uuid"))
|
|
286
|
+
fields.unshift("uuid");
|
|
287
|
+
for (const field of fields)
|
|
288
|
+
if (typeof field == "object") {
|
|
289
|
+
const { table } = relationFields[field.name];
|
|
290
|
+
ensure(table, field);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
10
294
|
function wrapListPaginationLimitOffset(data, totalCount) {
|
|
11
295
|
return { paginationInfo: { totalCount }, results: data };
|
|
12
296
|
}
|
|
13
|
-
exports.wrapListPaginationLimitOffset = wrapListPaginationLimitOffset;
|
|
14
|
-
function getDateTimeStringMySQL(dateTimeString) {
|
|
15
|
-
return dateTimeString.replace("T", " ").slice(0, 19);
|
|
16
|
-
}
|
|
17
|
-
exports.getDateTimeStringMySQL = getDateTimeStringMySQL;
|
|
18
297
|
// Not recursive at the moment; only supported at the root.
|
|
19
298
|
// TODO - remove if support for pagination for mysql dialect
|
|
20
299
|
// is added (I doubt it)
|
|
@@ -46,7 +325,6 @@ function wrapListPaginationCursor(data, args, flip, cb, primaryKey, totalCount)
|
|
|
46
325
|
results: data,
|
|
47
326
|
};
|
|
48
327
|
}
|
|
49
|
-
exports.wrapListPaginationCursor = wrapListPaginationCursor;
|
|
50
328
|
async function getTotalCount(sqlASTTotalCount, dbCall, context, options) {
|
|
51
329
|
// Replace field selection with `COUNT(*)`
|
|
52
330
|
const fieldNameTotalCount = "totalCount";
|
|
@@ -62,13 +340,352 @@ async function getTotalCount(sqlASTTotalCount, dbCall, context, options) {
|
|
|
62
340
|
const totalCount = await dbCall(sqlTotalCount).then((xs) => xs[0][fieldNameTotalCount]);
|
|
63
341
|
return totalCount;
|
|
64
342
|
}
|
|
65
|
-
|
|
343
|
+
const runCreateTreeMySQL = async (table, referencedKey, referencedKeyValue, columns, values, dbCall, formatQuery) => {
|
|
344
|
+
let allColumns = columns;
|
|
345
|
+
if (typeof referencedKey === "string") {
|
|
346
|
+
allColumns = allColumns.slice().map((xs) => xs.concat(referencedKey));
|
|
347
|
+
}
|
|
348
|
+
let allValues = values;
|
|
349
|
+
if (referencedKeyValue != null) {
|
|
350
|
+
allValues = allValues.slice().map((xs) => xs.concat(referencedKeyValue));
|
|
351
|
+
}
|
|
352
|
+
return Promise.all(allColumns.map((cs, i) => dbCall(formatQuery(`INSERT INTO ?? (??) VALUES (?)`, [table, cs, allValues[i]])).then((x) => x.insertId)));
|
|
353
|
+
};
|
|
354
|
+
// This doesn't use bulk inserts because:
|
|
355
|
+
// 1. columns aren't necessarily uniform
|
|
356
|
+
// 2. We don't want to do backflips to get all the inserted IDs
|
|
357
|
+
const runCreateTreeMSSQL = async (table, referencedKey, referencedKeyValue, columns, values, dbCall, formatQuery) => {
|
|
358
|
+
let allColumns = columns;
|
|
359
|
+
if (typeof referencedKey === "string") {
|
|
360
|
+
allColumns = allColumns.slice().map((xs) => xs.concat(referencedKey));
|
|
361
|
+
}
|
|
362
|
+
let allValues = values;
|
|
363
|
+
if (referencedKeyValue != null) {
|
|
364
|
+
allValues = allValues.slice().map((xs) => xs.concat(referencedKeyValue));
|
|
365
|
+
}
|
|
366
|
+
// https://github.com/tediousjs/node-mssql/issues/302
|
|
367
|
+
// return Promise.all(
|
|
368
|
+
// allColumns.map((cs, i) =>
|
|
369
|
+
// dbCall(
|
|
370
|
+
// formatQuery(
|
|
371
|
+
// `INSERT INTO ?? (??) VALUES (?) SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY]`,
|
|
372
|
+
// [table, cs, allValues[i]]
|
|
373
|
+
// )
|
|
374
|
+
// ).then((xs) => xs[0]["SCOPE_IDENTITY"])
|
|
375
|
+
// )
|
|
376
|
+
// );
|
|
377
|
+
let out = [];
|
|
378
|
+
let i = 0;
|
|
379
|
+
for (let cs of allColumns) {
|
|
380
|
+
out.push(await dbCall(formatQuery(`INSERT INTO ?? (??) VALUES (?) SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY]`, [table, cs, allValues[i]])).then((xs) => xs[0]["SCOPE_IDENTITY"]));
|
|
381
|
+
i += 1;
|
|
382
|
+
}
|
|
383
|
+
return out;
|
|
384
|
+
};
|
|
385
|
+
async function create(input, dbCall, formatQuery, beginTransaction, dialect, context) {
|
|
386
|
+
async function _create() {
|
|
387
|
+
// Shallow clone, as we're going to mutate later
|
|
388
|
+
let data = { ...input.data };
|
|
389
|
+
const tableArtifacts = input.artifacts[input.resource];
|
|
390
|
+
// Top-level only
|
|
391
|
+
if (hasMappedFields(input.artifacts, input.resource, data)) {
|
|
392
|
+
await mapMappedFields(tableArtifacts, data, dbCall, formatQuery);
|
|
393
|
+
}
|
|
394
|
+
const hasChildren = Object.keys(data).some((k) => {
|
|
395
|
+
const oneToManyRelation = tableArtifacts.relationFields[k];
|
|
396
|
+
if (oneToManyRelation == null) {
|
|
397
|
+
return false;
|
|
398
|
+
}
|
|
399
|
+
if (oneToManyRelation.type === "one-to-many__many-to-one" &&
|
|
400
|
+
oneToManyRelation.kind === "one-to-many") {
|
|
401
|
+
return true;
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
if (hasChildren) {
|
|
405
|
+
const { dbCall: dbCallTransaction, commit } = await beginTransaction();
|
|
406
|
+
const id = await runCreateTree(getCreateTree([data], input.resource, null, context?.specialCaseUuidColumn, dialect, input.artifacts), null, dialect === "mssql" ? runCreateTreeMSSQL : runCreateTreeMySQL, dbCallTransaction, formatQuery, dialect).then((xs) => xs[0]);
|
|
407
|
+
await commit();
|
|
408
|
+
return id;
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
data = processCreateData(data, tableArtifacts, dialect, context?.specialCaseUuidColumn);
|
|
412
|
+
if (dialect === "mysql") {
|
|
413
|
+
const inserted = await dbCall(formatQuery("INSERT INTO ?? SET ?", [input.resource, data]));
|
|
414
|
+
return inserted.insertId;
|
|
415
|
+
}
|
|
416
|
+
else {
|
|
417
|
+
const columns = Object.keys(data);
|
|
418
|
+
const values = Object.values(data);
|
|
419
|
+
const inserted = await dbCall(formatQuery(`INSERT INTO ?? (??) VALUES (?) SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY]`, [input.resource, columns, values]));
|
|
420
|
+
return inserted[0]["SCOPE_IDENTITY"];
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
const id = await _create();
|
|
425
|
+
return getData({ ...input, args: { $where: { id } } }, dbCall, formatQuery, dialect);
|
|
426
|
+
}
|
|
427
|
+
function processCreateData(data, tableArtifacts, dialect, specialCaseUuidColumn) {
|
|
428
|
+
let out = { ...data };
|
|
429
|
+
if (dialect === "mysql" && tableArtifacts.dateTimeFieldsCount > 0) {
|
|
430
|
+
for (let k in tableArtifacts.dateTimeFields) {
|
|
431
|
+
if (out[k] != null) {
|
|
432
|
+
out[k] = (0, getDateTimeStringMySQL_1.getDateTimeStringMySQL)(out[k]);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
// Delete keys with value of undefined
|
|
437
|
+
for (let k in out) {
|
|
438
|
+
if (out[k] === void 0) {
|
|
439
|
+
delete out[k];
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
const scalarFieldSet = new Set(tableArtifacts.scalarFields);
|
|
443
|
+
if (specialCaseUuidColumn &&
|
|
444
|
+
scalarFieldSet.has("uuid") &&
|
|
445
|
+
!Object.prototype.hasOwnProperty.call(out, "uuid")) {
|
|
446
|
+
out["uuid"] = (0, uuid_1.v4)();
|
|
447
|
+
}
|
|
448
|
+
return out;
|
|
449
|
+
}
|
|
450
|
+
async function runCreateTree(tree, referencedKeyValue, runCreateTreeSQL, dbCall, formatQuery, dialect) {
|
|
451
|
+
const ids = await runCreateTreeSQL(tree.table, tree.referencedKey, referencedKeyValue, tree.columns, tree.values, dbCall, formatQuery);
|
|
452
|
+
if (tree.children?.length > 0) {
|
|
453
|
+
// https://github.com/tediousjs/node-mssql/issues/302
|
|
454
|
+
if (dialect === "mssql") {
|
|
455
|
+
const idIndexes = Array(ids.length)
|
|
456
|
+
.fill(null)
|
|
457
|
+
.map((_, i) => i);
|
|
458
|
+
for (let i of idIndexes) {
|
|
459
|
+
for (let c of tree.children[i]) {
|
|
460
|
+
await runCreateTree(c, ids[i], runCreateTreeSQL, dbCall, formatQuery, dialect);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
else {
|
|
465
|
+
await Promise.all(ids.flatMap((id, i) => tree.children[i].map((c) => runCreateTree(c, id, runCreateTreeSQL, dbCall, formatQuery, dialect))));
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return ids;
|
|
469
|
+
}
|
|
470
|
+
function getCreateTree(data, table, referencedKey, specialCaseUuidColumn, dialect, artifacts) {
|
|
471
|
+
const tableArtifacts = artifacts[table];
|
|
472
|
+
const scalarFieldSet = new Set(tableArtifacts.scalarFields);
|
|
473
|
+
let out = {
|
|
474
|
+
table,
|
|
475
|
+
referencedKey,
|
|
476
|
+
columns: [],
|
|
477
|
+
values: [],
|
|
478
|
+
children: [],
|
|
479
|
+
};
|
|
480
|
+
for (let i = 0; i < data.length; i++) {
|
|
481
|
+
let d = data[i];
|
|
482
|
+
if (Object.keys(d).length === 0) {
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
d = processCreateData(d, tableArtifacts, dialect, specialCaseUuidColumn);
|
|
486
|
+
out.columns[i] = [];
|
|
487
|
+
out.values[i] = [];
|
|
488
|
+
out.children[i] = [];
|
|
489
|
+
for (let k in d) {
|
|
490
|
+
if (scalarFieldSet.has(k)) {
|
|
491
|
+
out.columns[i].push(k);
|
|
492
|
+
const v = d[k];
|
|
493
|
+
out.values[i].push(v);
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
496
|
+
const oneToManyRelation = tableArtifacts.relationFields[k];
|
|
497
|
+
if (oneToManyRelation == null ||
|
|
498
|
+
oneToManyRelation.type !== "one-to-many__many-to-one" ||
|
|
499
|
+
oneToManyRelation.kind !== "one-to-many") {
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
502
|
+
if (!Array.isArray(d[k]?.$create)) {
|
|
503
|
+
throw new Error("Invalid data: " + k);
|
|
504
|
+
}
|
|
505
|
+
out.children[i].push(getCreateTree(d[k].$create, oneToManyRelation.table, oneToManyRelation.relation.referencedKey, specialCaseUuidColumn, dialect, artifacts));
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
return out;
|
|
509
|
+
}
|
|
510
|
+
async function update(input, dbCall, formatQuery, dialect, cache) {
|
|
511
|
+
async function _update() {
|
|
512
|
+
const escapeId = (0, stringifyWhere_1.getEscapeId)(dialect);
|
|
513
|
+
const tableArtifacts = input.artifacts[input.resource];
|
|
514
|
+
const where = (0, getWhere_1.getWhere)(escapeId(input.resource), input.args, dialect);
|
|
515
|
+
if (where == null) {
|
|
516
|
+
throw new Error("Null where");
|
|
517
|
+
}
|
|
518
|
+
const current = await dbCall(formatQuery("SELECT * FROM ?? WHERE " + where, [input.resource])).then((xs) => xs[0]);
|
|
519
|
+
if (current == null) {
|
|
520
|
+
throw new SDKNotFoundError_1.SDKNotFoundError();
|
|
521
|
+
}
|
|
522
|
+
if (cache && current.uuid)
|
|
523
|
+
cache.purge(current.uuid);
|
|
524
|
+
// Shallow clone, as we're going to mutate later
|
|
525
|
+
const data = { ...input.data };
|
|
526
|
+
if (hasMappedFields(input.artifacts, input.resource, data)) {
|
|
527
|
+
await mapMappedFields(tableArtifacts, data, dbCall, formatQuery);
|
|
528
|
+
}
|
|
529
|
+
if (dialect === "mysql" && tableArtifacts.dateTimeFieldsCount > 0) {
|
|
530
|
+
for (let k in tableArtifacts.dateTimeFields) {
|
|
531
|
+
if (data[k] != null) {
|
|
532
|
+
data[k] = (0, getDateTimeStringMySQL_1.getDateTimeStringMySQL)(data[k]);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
// Delete keys with value of undefined
|
|
537
|
+
for (let k in data) {
|
|
538
|
+
if (data[k] === void 0) {
|
|
539
|
+
delete data[k];
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
// Nothing to update
|
|
543
|
+
if (Object.keys(data).length === 0) {
|
|
544
|
+
return true;
|
|
545
|
+
}
|
|
546
|
+
await dbCall(getUpdateQuery(input.resource, data, where, dialect, formatQuery));
|
|
547
|
+
return true;
|
|
548
|
+
}
|
|
549
|
+
await _update();
|
|
550
|
+
return getData(input, dbCall, formatQuery, dialect);
|
|
551
|
+
}
|
|
552
|
+
function getUpdateQuery(table, data, where, dialect, formatQuery) {
|
|
553
|
+
// Assumes `data` is not empty
|
|
554
|
+
const escapeId = (0, stringifyWhere_1.getEscapeId)(dialect);
|
|
555
|
+
const escape = (0, stringifyWhere_1.getEscape)(dialect);
|
|
556
|
+
let q = "UPDATE ?? ";
|
|
557
|
+
let values = [table];
|
|
558
|
+
let opsStrs = [];
|
|
559
|
+
let dataRegular = {};
|
|
560
|
+
for (let k in data) {
|
|
561
|
+
const v = data[k];
|
|
562
|
+
if (typeof v === "object" && v != null && Object.keys(v).length === 1) {
|
|
563
|
+
const _entries = Object.entries(v)?.[0];
|
|
564
|
+
const op = _entries?.[0];
|
|
565
|
+
const vv = _entries?.[1];
|
|
566
|
+
if (op === "$prepend") {
|
|
567
|
+
opsStrs.push(`${table}.${escapeId(k)} = CASE WHEN ${table}.${escapeId(k)} IS NULL THEN NULL ELSE CONCAT(${escape(vv)}, ${table}.${escapeId(k)}) END`);
|
|
568
|
+
continue;
|
|
569
|
+
}
|
|
570
|
+
if (op === "$append") {
|
|
571
|
+
opsStrs.push(`${table}.${escapeId(k)} = CASE WHEN ${table}.${escapeId(k)} IS NULL THEN NULL ELSE CONCAT(${table}.${escapeId(k)}, ${escape(vv)}) END`);
|
|
572
|
+
continue;
|
|
573
|
+
}
|
|
574
|
+
if (op === "$increment") {
|
|
575
|
+
opsStrs.push(`${table}.${escapeId(k)} = ${table}.${escapeId(k)} + ${escape(vv)}`);
|
|
576
|
+
continue;
|
|
577
|
+
}
|
|
578
|
+
if (op === "$decrement") {
|
|
579
|
+
opsStrs.push(`${table}.${escapeId(k)} = ${table}.${escapeId(k)} - ${escape(vv)}`);
|
|
580
|
+
continue;
|
|
581
|
+
}
|
|
582
|
+
dataRegular[k] = v;
|
|
583
|
+
}
|
|
584
|
+
dataRegular[k] = v;
|
|
585
|
+
}
|
|
586
|
+
if (opsStrs.length > 0) {
|
|
587
|
+
q += `SET ${opsStrs.join(", ")}`;
|
|
588
|
+
}
|
|
589
|
+
if (Object.keys(dataRegular).length > 0) {
|
|
590
|
+
if (opsStrs.length > 0) {
|
|
591
|
+
q += ", ?";
|
|
592
|
+
}
|
|
593
|
+
else {
|
|
594
|
+
q += "SET ?";
|
|
595
|
+
}
|
|
596
|
+
values.push(dataRegular);
|
|
597
|
+
}
|
|
598
|
+
q += ` WHERE ${where}`;
|
|
599
|
+
return formatQuery(q, values);
|
|
600
|
+
}
|
|
601
|
+
async function updateMany(input, dbCall, formatQuery, dialect, cache) {
|
|
602
|
+
async function _updateMany() {
|
|
603
|
+
const escapeId = (0, stringifyWhere_1.getEscapeId)(dialect);
|
|
604
|
+
const tableArtifacts = input.artifacts[input.resource];
|
|
605
|
+
const where = (0, getWhere_1.getWhere)(escapeId(input.resource), input.args, dialect);
|
|
606
|
+
if (where == null) {
|
|
607
|
+
throw new Error("Null where");
|
|
608
|
+
}
|
|
609
|
+
if (cache)
|
|
610
|
+
try {
|
|
611
|
+
const query = formatQuery(`SELECT uuid FROM ?? WHERE ${where}`, [input.resource]);
|
|
612
|
+
const matches = await dbCall(query);
|
|
613
|
+
const uuids = matches.map((x) => x.uuid);
|
|
614
|
+
cache.purge(...uuids);
|
|
615
|
+
}
|
|
616
|
+
catch (err) { }
|
|
617
|
+
// Shallow clone, as we're going to mutate later
|
|
618
|
+
const data = { ...input.data };
|
|
619
|
+
if (hasMappedFields(input.artifacts, input.resource, data)) {
|
|
620
|
+
await mapMappedFields(tableArtifacts, data, dbCall, formatQuery);
|
|
621
|
+
}
|
|
622
|
+
if (dialect === "mysql" && tableArtifacts.dateTimeFieldsCount > 0) {
|
|
623
|
+
for (let k in tableArtifacts.dateTimeFields) {
|
|
624
|
+
if (data[k] != null) {
|
|
625
|
+
data[k] = (0, getDateTimeStringMySQL_1.getDateTimeStringMySQL)(data[k]);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
// Delete keys with value of undefined
|
|
630
|
+
for (let k in data) {
|
|
631
|
+
if (data[k] === void 0) {
|
|
632
|
+
delete data[k];
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
// Nothing to update
|
|
636
|
+
if (Object.keys(data).length === 0) {
|
|
637
|
+
return [];
|
|
638
|
+
}
|
|
639
|
+
await dbCall(getUpdateQuery(input.resource, data, where, dialect, formatQuery));
|
|
640
|
+
return true;
|
|
641
|
+
}
|
|
642
|
+
await _updateMany();
|
|
643
|
+
return getData(input, dbCall, formatQuery, dialect);
|
|
644
|
+
}
|
|
645
|
+
async function deleteOne(input, dbCall, formatQuery, dialect, cache) {
|
|
646
|
+
const _findOne = Object.entries(input.args.$where)[0];
|
|
647
|
+
const findOne = { key: _findOne[0], value: _findOne[1] };
|
|
648
|
+
const current = await dbCall(formatQuery("SELECT * FROM ?? WHERE ?? = ?", [
|
|
649
|
+
input.resource,
|
|
650
|
+
findOne.key,
|
|
651
|
+
findOne.value,
|
|
652
|
+
])).then((xs) => xs[0]);
|
|
653
|
+
if (current == null) {
|
|
654
|
+
throw new SDKNotFoundError_1.SDKNotFoundError();
|
|
655
|
+
}
|
|
656
|
+
if (cache && current.uuid)
|
|
657
|
+
cache.purge(current.uuid);
|
|
658
|
+
await dbCall(formatQuery("DELETE FROM ?? WHERE ?? = ?", [
|
|
659
|
+
input.resource,
|
|
660
|
+
findOne.key,
|
|
661
|
+
findOne.value,
|
|
662
|
+
]));
|
|
663
|
+
return true;
|
|
664
|
+
}
|
|
665
|
+
async function deleteMany(input, dbCall, formatQuery, dialect, cache) {
|
|
666
|
+
const escapeId = (0, stringifyWhere_1.getEscapeId)(dialect);
|
|
667
|
+
const where = (0, getWhere_1.getWhere)(escapeId(input.resource), input.args, dialect);
|
|
668
|
+
if (where == null) {
|
|
669
|
+
throw new Error("Null where");
|
|
670
|
+
}
|
|
671
|
+
if (cache)
|
|
672
|
+
try {
|
|
673
|
+
const query = formatQuery(`SELECT uuid FROM ?? WHERE ${where}`, [input.resource]);
|
|
674
|
+
const matches = await dbCall(query);
|
|
675
|
+
const uuids = matches.map((x) => x.uuid);
|
|
676
|
+
cache.purge(...uuids);
|
|
677
|
+
}
|
|
678
|
+
catch (err) { }
|
|
679
|
+
const sql = "DELETE FROM ?? WHERE " + where;
|
|
680
|
+
const values = [input.resource];
|
|
681
|
+
await dbCall(formatQuery(sql, values));
|
|
682
|
+
return true;
|
|
683
|
+
}
|
|
66
684
|
function getScalarFields(table, artifacts) {
|
|
67
685
|
return artifacts[table].scalarFields;
|
|
68
686
|
}
|
|
69
|
-
exports.getScalarFields = getScalarFields;
|
|
70
687
|
function hasMappedFields(artifacts, table, data) {
|
|
71
|
-
const
|
|
688
|
+
const mappedFields = artifacts[table].mappedFields;
|
|
72
689
|
if (mappedFields == null) {
|
|
73
690
|
return false;
|
|
74
691
|
}
|
|
@@ -76,7 +693,6 @@ function hasMappedFields(artifacts, table, data) {
|
|
|
76
693
|
const dataKeys = Object.keys(data);
|
|
77
694
|
return dataKeys.some((k) => keys.has(k));
|
|
78
695
|
}
|
|
79
|
-
exports.hasMappedFields = hasMappedFields;
|
|
80
696
|
async function mapMappedFields(artifactsForTable, data, dbCall, formatQuery) {
|
|
81
697
|
for (let k in data) {
|
|
82
698
|
const v = data[k];
|
|
@@ -106,7 +722,7 @@ async function mapMappedFields(artifactsForTable, data, dbCall, formatQuery) {
|
|
|
106
722
|
w,
|
|
107
723
|
])).then((xs) => xs[0]?.[mappedField.referencedKey]);
|
|
108
724
|
if (result == null) {
|
|
109
|
-
throw new
|
|
725
|
+
throw new SDKNotFoundError_1.SDKNotFoundError();
|
|
110
726
|
}
|
|
111
727
|
return result;
|
|
112
728
|
}));
|
|
@@ -120,14 +736,13 @@ async function mapMappedFields(artifactsForTable, data, dbCall, formatQuery) {
|
|
|
120
736
|
v,
|
|
121
737
|
])).then((xs) => xs[0]?.[mappedField.referencedKey]);
|
|
122
738
|
if (result == null) {
|
|
123
|
-
throw new
|
|
739
|
+
throw new SDKNotFoundError_1.SDKNotFoundError();
|
|
124
740
|
}
|
|
125
741
|
data[mappedField.foreignKey] = result;
|
|
126
742
|
delete data[k];
|
|
127
743
|
}
|
|
128
744
|
}
|
|
129
745
|
}
|
|
130
|
-
exports.mapMappedFields = mapMappedFields;
|
|
131
746
|
// 1. Remove additional keys added to data for batches and joins
|
|
132
747
|
// 2. Execute `transform` functions if they exist
|
|
133
748
|
function postProcess(data, fields, shouldRemoveExtraKeys) {
|
|
@@ -141,7 +756,7 @@ function removeExtraKeys(data, fields) {
|
|
|
141
756
|
if (data == null || (Array.isArray(data) && data[0] == null)) {
|
|
142
757
|
return;
|
|
143
758
|
}
|
|
144
|
-
|
|
759
|
+
let fieldKeys = [];
|
|
145
760
|
for (let x of fields) {
|
|
146
761
|
if (typeof x === "string") {
|
|
147
762
|
fieldKeys.push(x);
|
|
@@ -178,3 +793,159 @@ function removeExtraKeys(data, fields) {
|
|
|
178
793
|
}
|
|
179
794
|
}
|
|
180
795
|
}
|
|
796
|
+
function whereNeedsProcessing(where) {
|
|
797
|
+
return JSON.stringify(where).includes("Uuid");
|
|
798
|
+
}
|
|
799
|
+
exports.whereNeedsProcessing = whereNeedsProcessing;
|
|
800
|
+
async function _prepareWhere(artifacts, table, data, dbCall, formatQuery) {
|
|
801
|
+
const mappedFields = artifacts[table].mappedFields;
|
|
802
|
+
let out = {};
|
|
803
|
+
await traverseWhere(data, async (where, ptr, parentPtr, root) => {
|
|
804
|
+
const path = ptr.split("/").slice(1);
|
|
805
|
+
const opIndex = path.length - 1;
|
|
806
|
+
if (ops.includes(path[opIndex])) {
|
|
807
|
+
const newPath = path.slice();
|
|
808
|
+
const index = newPath.length - 2;
|
|
809
|
+
const key = newPath[index];
|
|
810
|
+
const mappedField = mappedFields?.[key];
|
|
811
|
+
if (mappedField != null) {
|
|
812
|
+
newPath[index] = mappedField.foreignKey;
|
|
813
|
+
if (Array.isArray(where)) {
|
|
814
|
+
const newVal = await Promise.all(where.map((v) => dbCall(formatQuery("SELECT ?? FROM ?? WHERE ?? = ?", [
|
|
815
|
+
mappedField.referencedKey,
|
|
816
|
+
mappedField.referencedTable,
|
|
817
|
+
mappedField.name,
|
|
818
|
+
v,
|
|
819
|
+
])).then((xs) => xs[0]?.[mappedField.referencedKey])));
|
|
820
|
+
if (newVal.some((x) => x == null)) {
|
|
821
|
+
const index = newVal.findIndex((x) => x == null);
|
|
822
|
+
if (index === -1) {
|
|
823
|
+
throw new SDKBadWhereError_1.SDKBadWhereError();
|
|
824
|
+
}
|
|
825
|
+
else {
|
|
826
|
+
const v = where[index];
|
|
827
|
+
throw new SDKBadWhereError_1.SDKBadWhereError(getPrepareWhereNotFoundMessage(mappedField, v));
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
out = _.set(newPath, newVal, out);
|
|
831
|
+
}
|
|
832
|
+
else {
|
|
833
|
+
const newVal = await dbCall(formatQuery("SELECT ?? FROM ?? WHERE ?? = ?", [
|
|
834
|
+
mappedField.referencedKey,
|
|
835
|
+
mappedField.referencedTable,
|
|
836
|
+
mappedField.name,
|
|
837
|
+
where,
|
|
838
|
+
])).then((xs) => xs[0]?.[mappedField.referencedKey]);
|
|
839
|
+
if (newVal == null) {
|
|
840
|
+
throw new SDKBadWhereError_1.SDKBadWhereError(getPrepareWhereNotFoundMessage(mappedField, where));
|
|
841
|
+
}
|
|
842
|
+
out = _.set(newPath, newVal, out);
|
|
843
|
+
}
|
|
844
|
+
out = _.unset(path.slice(0, path.length - 1), out);
|
|
845
|
+
return;
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
else {
|
|
849
|
+
const key = path[path.length - 1];
|
|
850
|
+
const mappedField = mappedFields?.[key];
|
|
851
|
+
if (mappedField != null) {
|
|
852
|
+
const newPath = path
|
|
853
|
+
.slice(0, path.length - 1)
|
|
854
|
+
.concat(mappedField.foreignKey);
|
|
855
|
+
if (Array.isArray(where)) {
|
|
856
|
+
const newVal = await Promise.all(where.map((v) => dbCall(formatQuery("SELECT ?? FROM ?? WHERE ?? = ?", [
|
|
857
|
+
mappedField.referencedKey,
|
|
858
|
+
mappedField.referencedTable,
|
|
859
|
+
mappedField.name,
|
|
860
|
+
v,
|
|
861
|
+
])).then((xs) => xs[0]?.[mappedField.referencedKey])));
|
|
862
|
+
if (newVal.some((x) => x == null)) {
|
|
863
|
+
const index = newVal.findIndex((x) => x == null);
|
|
864
|
+
if (index === -1) {
|
|
865
|
+
throw new SDKBadWhereError_1.SDKBadWhereError();
|
|
866
|
+
}
|
|
867
|
+
else {
|
|
868
|
+
const v = where[index];
|
|
869
|
+
throw new SDKBadWhereError_1.SDKBadWhereError(getPrepareWhereNotFoundMessage(mappedField, v));
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
out = _.set(newPath, newVal, out);
|
|
873
|
+
}
|
|
874
|
+
else {
|
|
875
|
+
const newVal = await dbCall(formatQuery("SELECT ?? FROM ?? WHERE ?? = ?", [
|
|
876
|
+
mappedField.referencedKey,
|
|
877
|
+
mappedField.referencedTable,
|
|
878
|
+
mappedField.name,
|
|
879
|
+
where,
|
|
880
|
+
])).then((xs) => xs[0]?.[mappedField.referencedKey]);
|
|
881
|
+
if (newVal == null) {
|
|
882
|
+
throw new SDKBadWhereError_1.SDKBadWhereError(getPrepareWhereNotFoundMessage(mappedField, where));
|
|
883
|
+
}
|
|
884
|
+
out = _.set(newPath, newVal, out);
|
|
885
|
+
}
|
|
886
|
+
out = _.unset(path, out);
|
|
887
|
+
}
|
|
888
|
+
else {
|
|
889
|
+
out = path.length > 0 ? _.set(path, where, out) : where;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
});
|
|
893
|
+
return out;
|
|
894
|
+
}
|
|
895
|
+
exports._prepareWhere = _prepareWhere;
|
|
896
|
+
function getPrepareWhereNotFoundMessage(mappedField, value) {
|
|
897
|
+
return `Not found: unable to map \`${mappedField.referencedTable}\`.\`${mappedField.name}\` to \`${mappedField.referencedTable}\`.\`${mappedField.referencedKey}\` for the value \`${value}\`.`;
|
|
898
|
+
}
|
|
899
|
+
const ops = [
|
|
900
|
+
"$eq",
|
|
901
|
+
"$neq",
|
|
902
|
+
"$gt",
|
|
903
|
+
"$gte",
|
|
904
|
+
"$lt",
|
|
905
|
+
"$lte",
|
|
906
|
+
"$in",
|
|
907
|
+
"$nin",
|
|
908
|
+
"$like",
|
|
909
|
+
"$nlike",
|
|
910
|
+
"$btwn",
|
|
911
|
+
"$nbtwn",
|
|
912
|
+
];
|
|
913
|
+
async function traverseWhere(where, cb) {
|
|
914
|
+
return await _traverseWhere(cb, where, "", where);
|
|
915
|
+
}
|
|
916
|
+
const _traverseWhere = async function (cb, where, ptr, root, parentPtr) {
|
|
917
|
+
await cb(where, ptr, parentPtr, root);
|
|
918
|
+
if (where && typeof where == "object" && !Array.isArray(where)) {
|
|
919
|
+
for (let key in where) {
|
|
920
|
+
const sch = where[key];
|
|
921
|
+
if (key === "$and" || key == "$or") {
|
|
922
|
+
await Promise.all(sch.map(async (s, i) => {
|
|
923
|
+
await _traverseWhere(cb, s, ptr + "/" + key + "/" + i, root, ptr
|
|
924
|
+
// key,
|
|
925
|
+
// where,
|
|
926
|
+
// parentPtr,
|
|
927
|
+
// i
|
|
928
|
+
);
|
|
929
|
+
}));
|
|
930
|
+
}
|
|
931
|
+
else if (typeof sch === "object") {
|
|
932
|
+
for (let prop in sch) {
|
|
933
|
+
await _traverseWhere(cb, sch[prop], ptr + "/" + key + "/" + escapePtr(prop), root, ptr
|
|
934
|
+
// key,
|
|
935
|
+
// where,
|
|
936
|
+
// prop
|
|
937
|
+
);
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
else {
|
|
941
|
+
await _traverseWhere(cb, sch, ptr + "/" + key, root, ptr
|
|
942
|
+
// key,
|
|
943
|
+
// where
|
|
944
|
+
);
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
};
|
|
949
|
+
function escapePtr(str) {
|
|
950
|
+
return str.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
951
|
+
}
|