@jskit-ai/crud-core 0.1.30 → 0.1.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.descriptor.mjs +2 -2
- package/package.json +7 -6
- package/src/server/createCrudRepositoryFromResource.js +18 -12
- package/src/server/createHooksToCollectChildren.js +247 -0
- package/src/server/lookupHydration.js +172 -11
- package/src/server/lookupProviders.js +33 -1
- package/src/server/repositoryMethods.js +808 -58
- package/test/createCrudRepositoryFromResource.test.js +1091 -71
- package/test/createHooksToCollectChildren.test.js +251 -0
- package/test/lookupProviders.test.js +32 -0
|
@@ -166,17 +166,263 @@ function resolveCrudRepositoryCall(runtime, knex, repositoryOptions = {}, callOp
|
|
|
166
166
|
});
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
|
|
169
|
+
function normalizeCrudRepositoryHooks(hooks = null, allowedHookKeys = [], { context = "crudRepository" } = {}) {
|
|
170
|
+
if (hooks === null || hooks === undefined) {
|
|
171
|
+
return Object.freeze({});
|
|
172
|
+
}
|
|
173
|
+
if (!hooks || typeof hooks !== "object" || Array.isArray(hooks)) {
|
|
174
|
+
throw new TypeError(`${context} hooks must be an object when provided.`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const supportedHookKeys = (Array.isArray(allowedHookKeys) ? allowedHookKeys : [])
|
|
178
|
+
.map((entry) => normalizeText(entry))
|
|
179
|
+
.filter(Boolean);
|
|
180
|
+
const supportedHookKeySet = new Set(supportedHookKeys);
|
|
181
|
+
const normalizedHooks = {};
|
|
182
|
+
|
|
183
|
+
for (const [rawHookKey, rawHook] of Object.entries(hooks)) {
|
|
184
|
+
const normalizedHookKey = normalizeText(rawHookKey);
|
|
185
|
+
if (!normalizedHookKey) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
if (!supportedHookKeySet.has(normalizedHookKey)) {
|
|
189
|
+
throw new TypeError(
|
|
190
|
+
`${context} does not support hooks.${normalizedHookKey}. Allowed hooks: ${supportedHookKeys.join(", ")}.`
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (rawHook === null || rawHook === undefined) {
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
if (typeof rawHook !== "function") {
|
|
198
|
+
throw new TypeError(`${context} hooks.${normalizedHookKey} must be a function.`);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
normalizedHooks[normalizedHookKey] = rawHook;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return Object.freeze(normalizedHooks);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function resolveOptionalCrudRepositoryHook(
|
|
208
|
+
hooks = {},
|
|
209
|
+
hookKey = "",
|
|
210
|
+
{ context = "crudRepository" } = {}
|
|
211
|
+
) {
|
|
212
|
+
const normalizedHookKey = normalizeText(hookKey);
|
|
213
|
+
if (!normalizedHookKey) {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const directHook = hooks?.[normalizedHookKey];
|
|
218
|
+
if (directHook !== undefined && directHook !== null) {
|
|
219
|
+
if (typeof directHook !== "function") {
|
|
220
|
+
throw new TypeError(`${context} hooks.${normalizedHookKey} must be a function.`);
|
|
221
|
+
}
|
|
222
|
+
return directHook;
|
|
223
|
+
}
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
async function applyCrudRepositoryQueryHook(
|
|
228
|
+
dbQuery,
|
|
229
|
+
hook = null,
|
|
230
|
+
hookContext = {},
|
|
231
|
+
{ context = "crudRepository", hookKey = "modifyQuery" } = {}
|
|
232
|
+
) {
|
|
233
|
+
if (typeof hook !== "function") {
|
|
234
|
+
return {
|
|
235
|
+
queryBuilder: dbQuery
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const directResult = hook(dbQuery, hookContext);
|
|
240
|
+
if (directResult === undefined || directResult === dbQuery) {
|
|
241
|
+
return {
|
|
242
|
+
queryBuilder: dbQuery
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (directResult && typeof directResult.then === "function") {
|
|
247
|
+
const awaitedResult = await directResult;
|
|
248
|
+
if (awaitedResult === undefined || awaitedResult === dbQuery) {
|
|
249
|
+
return {
|
|
250
|
+
queryBuilder: dbQuery
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
throw new TypeError(
|
|
256
|
+
`${context} hooks.${hookKey} must mutate the provided query builder and return undefined or the same builder.`
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function normalizeCrudRepositoryObjectInput(value = {}) {
|
|
261
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
262
|
+
return {};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return value;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async function applyCrudRepositoryPayloadHook(
|
|
269
|
+
payload = {},
|
|
270
|
+
hook = null,
|
|
271
|
+
hookContext = {},
|
|
272
|
+
{ context = "crudRepository", hookKey = "modifyPayload" } = {}
|
|
273
|
+
) {
|
|
274
|
+
const normalizedPayload = normalizeCrudRepositoryObjectInput(payload);
|
|
275
|
+
if (typeof hook !== "function") {
|
|
276
|
+
return normalizedPayload;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const nextPayload = await hook(normalizedPayload, hookContext);
|
|
280
|
+
if (nextPayload === undefined) {
|
|
281
|
+
return normalizedPayload;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (!nextPayload || typeof nextPayload !== "object" || Array.isArray(nextPayload)) {
|
|
285
|
+
throw new TypeError(`${context} hooks.${hookKey} must return an object when it returns a value.`);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return nextPayload;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
async function applyCrudRepositoryRecordsHook(
|
|
292
|
+
items = [],
|
|
293
|
+
hook = null,
|
|
294
|
+
hookContext = {},
|
|
295
|
+
{ context = "crudRepository", hookKey = "afterQuery" } = {}
|
|
296
|
+
) {
|
|
297
|
+
const normalizedItems = Array.isArray(items) ? items : [];
|
|
298
|
+
if (typeof hook !== "function") {
|
|
299
|
+
return normalizedItems;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const nextItems = await hook(normalizedItems, hookContext);
|
|
303
|
+
if (nextItems === undefined) {
|
|
304
|
+
return normalizedItems;
|
|
305
|
+
}
|
|
306
|
+
if (!Array.isArray(nextItems)) {
|
|
307
|
+
throw new TypeError(`${context} hooks.${hookKey} must return an array when it returns a value.`);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return nextItems;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
async function applyCrudRepositoryRecordHook(
|
|
314
|
+
record = null,
|
|
315
|
+
hook = null,
|
|
316
|
+
hookContext = {},
|
|
317
|
+
{ context = "crudRepository", hookKey = "transformReturnedRecord" } = {}
|
|
318
|
+
) {
|
|
319
|
+
if (record === null || record === undefined) {
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
if (!record || typeof record !== "object" || Array.isArray(record)) {
|
|
323
|
+
throw new TypeError(`${context} ${hookKey} record must be an object.`);
|
|
324
|
+
}
|
|
325
|
+
if (typeof hook !== "function") {
|
|
326
|
+
return record;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const nextRecord = await hook(record, hookContext);
|
|
330
|
+
if (nextRecord === undefined) {
|
|
331
|
+
return record;
|
|
332
|
+
}
|
|
333
|
+
if (!nextRecord || typeof nextRecord !== "object" || Array.isArray(nextRecord)) {
|
|
334
|
+
throw new TypeError(`${context} hooks.${hookKey} must return an object when it returns a value.`);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return nextRecord;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
async function applyCrudRepositoryOutputHook(
|
|
341
|
+
output,
|
|
342
|
+
hook = null,
|
|
343
|
+
hookContext = {},
|
|
344
|
+
{ context = "crudRepository", hookKey = "finalizeOutput", validateOutput = null } = {}
|
|
345
|
+
) {
|
|
346
|
+
if (typeof hook !== "function") {
|
|
347
|
+
if (typeof validateOutput === "function") {
|
|
348
|
+
validateOutput(output);
|
|
349
|
+
}
|
|
350
|
+
return output;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const nextOutput = await hook(output, hookContext);
|
|
354
|
+
const resolvedOutput = nextOutput === undefined ? output : nextOutput;
|
|
355
|
+
if (typeof validateOutput === "function") {
|
|
356
|
+
validateOutput(resolvedOutput);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return resolvedOutput;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
async function applyCrudRepositoryAfterWriteHook(
|
|
363
|
+
meta = {},
|
|
364
|
+
hook = null,
|
|
365
|
+
hookContext = {},
|
|
366
|
+
{ context = "crudRepository", hookKey = "afterWrite" } = {}
|
|
367
|
+
) {
|
|
368
|
+
if (typeof hook !== "function") {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
await hook(meta, hookContext);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function enforceCrudRepositoryListControls(dbQuery, { idColumn = "id", limit = DEFAULT_LIST_LIMIT + 1 } = {}) {
|
|
376
|
+
let nextQuery = dbQuery;
|
|
377
|
+
if (typeof nextQuery.clearOrder === "function") {
|
|
378
|
+
nextQuery = nextQuery.clearOrder();
|
|
379
|
+
}
|
|
380
|
+
if (typeof nextQuery.clear === "function") {
|
|
381
|
+
nextQuery = nextQuery.clear("limit");
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
return nextQuery
|
|
385
|
+
.orderBy(idColumn, "asc")
|
|
386
|
+
.limit(limit);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function createCrudRepositoryHookContextBase(runtime, repositoryOptions = {}, callOptions = {}) {
|
|
390
|
+
return {
|
|
391
|
+
runtime,
|
|
392
|
+
repositoryOptions,
|
|
393
|
+
callOptions,
|
|
394
|
+
state: {}
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
async function crudRepositoryList(runtime, knex, query = {}, repositoryOptions = {}, callOptions = {}, hooks = null) {
|
|
170
399
|
const { client, tableName, idColumn, visible } = resolveCrudRepositoryCall(runtime, knex, repositoryOptions, callOptions);
|
|
400
|
+
const methodHooks = normalizeCrudRepositoryHooks(
|
|
401
|
+
hooks,
|
|
402
|
+
["modifyQuery", "afterQuery", "transformReturnedRecord", "finalizeOutput"],
|
|
403
|
+
{
|
|
404
|
+
context: "crudRepositoryList"
|
|
405
|
+
}
|
|
406
|
+
);
|
|
407
|
+
const modifyListQuery = resolveOptionalCrudRepositoryHook(methodHooks, "modifyQuery", {
|
|
408
|
+
context: "crudRepositoryList"
|
|
409
|
+
});
|
|
410
|
+
const afterListQuery = resolveOptionalCrudRepositoryHook(methodHooks, "afterQuery", {
|
|
411
|
+
context: "crudRepositoryList"
|
|
412
|
+
});
|
|
413
|
+
const transformListRecord = resolveOptionalCrudRepositoryHook(methodHooks, "transformReturnedRecord", {
|
|
414
|
+
context: "crudRepositoryList"
|
|
415
|
+
});
|
|
416
|
+
const finalizeListOutput = resolveOptionalCrudRepositoryHook(methodHooks, "finalizeOutput", {
|
|
417
|
+
context: "crudRepositoryList"
|
|
418
|
+
});
|
|
171
419
|
const normalizedLimit = normalizeCrudListLimit(query?.limit, {
|
|
172
420
|
fallback: runtime.list.defaultLimit,
|
|
173
421
|
max: runtime.list.maxLimit
|
|
174
422
|
});
|
|
423
|
+
const hookContextBase = createCrudRepositoryHookContextBase(runtime, repositoryOptions, callOptions);
|
|
175
424
|
let dbQuery = client(tableName)
|
|
176
|
-
.select(...runtime.selectColumns)
|
|
177
|
-
.where(visible)
|
|
178
|
-
.orderBy(idColumn, "asc")
|
|
179
|
-
.limit(normalizedLimit + 1);
|
|
425
|
+
.select(...runtime.selectColumns);
|
|
180
426
|
|
|
181
427
|
dbQuery = applyCrudListQueryFilters(dbQuery, {
|
|
182
428
|
idColumn,
|
|
@@ -187,6 +433,26 @@ async function crudRepositoryList(runtime, knex, query = {}, repositoryOptions =
|
|
|
187
433
|
parentFilterColumns: runtime.mapping.parentFilterColumns
|
|
188
434
|
});
|
|
189
435
|
|
|
436
|
+
const listHookResult = await applyCrudRepositoryQueryHook(
|
|
437
|
+
dbQuery,
|
|
438
|
+
modifyListQuery,
|
|
439
|
+
{
|
|
440
|
+
query,
|
|
441
|
+
...hookContextBase
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
context: "crudRepositoryList",
|
|
445
|
+
hookKey: "modifyQuery"
|
|
446
|
+
}
|
|
447
|
+
);
|
|
448
|
+
dbQuery = listHookResult.queryBuilder;
|
|
449
|
+
|
|
450
|
+
dbQuery = dbQuery.where(visible);
|
|
451
|
+
dbQuery = enforceCrudRepositoryListControls(dbQuery, {
|
|
452
|
+
idColumn,
|
|
453
|
+
limit: normalizedLimit + 1
|
|
454
|
+
});
|
|
455
|
+
|
|
190
456
|
const rows = await dbQuery;
|
|
191
457
|
const hasMore = rows.length > normalizedLimit;
|
|
192
458
|
const pageRows = hasMore ? rows.slice(0, normalizedLimit) : rows;
|
|
@@ -202,7 +468,7 @@ async function crudRepositoryList(runtime, knex, query = {}, repositoryOptions =
|
|
|
202
468
|
}));
|
|
203
469
|
}
|
|
204
470
|
|
|
205
|
-
|
|
471
|
+
let hydratedItems = await hydrateCrudLookupRecords(items, {
|
|
206
472
|
...runtime.lookup,
|
|
207
473
|
context: runtime.context
|
|
208
474
|
}, {
|
|
@@ -212,45 +478,211 @@ async function crudRepositoryList(runtime, knex, query = {}, repositoryOptions =
|
|
|
212
478
|
callOptions
|
|
213
479
|
});
|
|
214
480
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
481
|
+
hydratedItems = await applyCrudRepositoryRecordsHook(
|
|
482
|
+
hydratedItems,
|
|
483
|
+
afterListQuery,
|
|
484
|
+
{
|
|
485
|
+
query,
|
|
486
|
+
...hookContextBase
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
context: "crudRepositoryList",
|
|
490
|
+
hookKey: "afterQuery"
|
|
491
|
+
}
|
|
492
|
+
);
|
|
493
|
+
|
|
494
|
+
const transformedItems = [];
|
|
495
|
+
for (let itemIndex = 0; itemIndex < hydratedItems.length; itemIndex += 1) {
|
|
496
|
+
transformedItems.push(
|
|
497
|
+
await applyCrudRepositoryRecordHook(
|
|
498
|
+
hydratedItems[itemIndex],
|
|
499
|
+
transformListRecord,
|
|
500
|
+
{
|
|
501
|
+
query,
|
|
502
|
+
itemIndex,
|
|
503
|
+
items: hydratedItems,
|
|
504
|
+
...hookContextBase
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
context: "crudRepositoryList",
|
|
508
|
+
hookKey: "transformReturnedRecord"
|
|
509
|
+
}
|
|
510
|
+
)
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
const nextCursor = hasMore && hydratedItems.length > 0 ? String(hydratedItems[hydratedItems.length - 1].id) : null;
|
|
515
|
+
let output = {
|
|
516
|
+
items: transformedItems,
|
|
517
|
+
nextCursor
|
|
218
518
|
};
|
|
519
|
+
|
|
520
|
+
output = await applyCrudRepositoryOutputHook(
|
|
521
|
+
output,
|
|
522
|
+
finalizeListOutput,
|
|
523
|
+
{
|
|
524
|
+
query,
|
|
525
|
+
...hookContextBase
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
context: "crudRepositoryList",
|
|
529
|
+
hookKey: "finalizeOutput",
|
|
530
|
+
validateOutput(nextOutput) {
|
|
531
|
+
if (!nextOutput || typeof nextOutput !== "object" || Array.isArray(nextOutput)) {
|
|
532
|
+
throw new TypeError("crudRepositoryList hooks.finalizeOutput must return an object.");
|
|
533
|
+
}
|
|
534
|
+
if (!Object.hasOwn(nextOutput, "items")) {
|
|
535
|
+
throw new TypeError('crudRepositoryList hooks.finalizeOutput must return required key "items".');
|
|
536
|
+
}
|
|
537
|
+
if (!Object.hasOwn(nextOutput, "nextCursor")) {
|
|
538
|
+
throw new TypeError('crudRepositoryList hooks.finalizeOutput must return required key "nextCursor".');
|
|
539
|
+
}
|
|
540
|
+
if (!Array.isArray(nextOutput.items)) {
|
|
541
|
+
throw new TypeError('crudRepositoryList hooks.finalizeOutput must return "items" as an array.');
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
);
|
|
546
|
+
|
|
547
|
+
return output;
|
|
219
548
|
}
|
|
220
549
|
|
|
221
|
-
async function crudRepositoryFindById(runtime, knex, recordId, repositoryOptions = {}, callOptions = {}) {
|
|
550
|
+
async function crudRepositoryFindById(runtime, knex, recordId, repositoryOptions = {}, callOptions = {}, hooks = null) {
|
|
222
551
|
const { client, tableName, idColumn, visible } = resolveCrudRepositoryCall(runtime, knex, repositoryOptions, callOptions);
|
|
223
|
-
const
|
|
224
|
-
|
|
552
|
+
const methodHooks = normalizeCrudRepositoryHooks(
|
|
553
|
+
hooks,
|
|
554
|
+
["modifyQuery", "afterQuery", "transformReturnedRecord", "finalizeOutput"],
|
|
555
|
+
{
|
|
556
|
+
context: "crudRepositoryFindById"
|
|
557
|
+
}
|
|
558
|
+
);
|
|
559
|
+
const modifyFindByIdQuery = resolveOptionalCrudRepositoryHook(methodHooks, "modifyQuery", {
|
|
560
|
+
context: "crudRepositoryFindById"
|
|
561
|
+
});
|
|
562
|
+
const afterFindByIdQuery = resolveOptionalCrudRepositoryHook(methodHooks, "afterQuery", {
|
|
563
|
+
context: "crudRepositoryFindById"
|
|
564
|
+
});
|
|
565
|
+
const transformFindByIdRecord = resolveOptionalCrudRepositoryHook(methodHooks, "transformReturnedRecord", {
|
|
566
|
+
context: "crudRepositoryFindById"
|
|
567
|
+
});
|
|
568
|
+
const finalizeFindByIdOutput = resolveOptionalCrudRepositoryHook(methodHooks, "finalizeOutput", {
|
|
569
|
+
context: "crudRepositoryFindById"
|
|
570
|
+
});
|
|
571
|
+
const hookContextBase = createCrudRepositoryHookContextBase(runtime, repositoryOptions, callOptions);
|
|
572
|
+
let dbQuery = client(tableName)
|
|
573
|
+
.select(...runtime.selectColumns);
|
|
574
|
+
|
|
575
|
+
const findByIdHookResult = await applyCrudRepositoryQueryHook(
|
|
576
|
+
dbQuery,
|
|
577
|
+
modifyFindByIdQuery,
|
|
578
|
+
{
|
|
579
|
+
recordId,
|
|
580
|
+
...hookContextBase
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
context: "crudRepositoryFindById",
|
|
584
|
+
hookKey: "modifyQuery"
|
|
585
|
+
}
|
|
586
|
+
);
|
|
587
|
+
dbQuery = findByIdHookResult.queryBuilder;
|
|
588
|
+
|
|
589
|
+
dbQuery = dbQuery
|
|
225
590
|
.where(visible)
|
|
226
591
|
.where({
|
|
227
592
|
[idColumn]: Number(recordId)
|
|
228
|
-
})
|
|
229
|
-
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
const row = await dbQuery.first();
|
|
230
596
|
|
|
231
597
|
const mappedRecord = mapRecordRow(row, runtime.mapping.outputKeys, runtime.mapping.columnOverrides);
|
|
232
|
-
|
|
233
|
-
|
|
598
|
+
let records = [];
|
|
599
|
+
if (mappedRecord) {
|
|
600
|
+
const normalizedRecord = await normalizeRepositoryOutputRecord(runtime, mappedRecord, {
|
|
601
|
+
operation: "findById"
|
|
602
|
+
});
|
|
603
|
+
const hydrated = await hydrateCrudLookupRecords([normalizedRecord], {
|
|
604
|
+
...runtime.lookup,
|
|
605
|
+
context: runtime.context
|
|
606
|
+
}, {
|
|
607
|
+
include: callOptions?.include,
|
|
608
|
+
mode: "view",
|
|
609
|
+
repositoryOptions,
|
|
610
|
+
callOptions
|
|
611
|
+
});
|
|
612
|
+
records = hydrated[0] ? [hydrated[0]] : [];
|
|
234
613
|
}
|
|
235
|
-
const normalizedRecord = await normalizeRepositoryOutputRecord(runtime, mappedRecord, {
|
|
236
|
-
operation: "findById"
|
|
237
|
-
});
|
|
238
614
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
615
|
+
records = await applyCrudRepositoryRecordsHook(
|
|
616
|
+
records,
|
|
617
|
+
afterFindByIdQuery,
|
|
618
|
+
{
|
|
619
|
+
recordId,
|
|
620
|
+
...hookContextBase
|
|
621
|
+
},
|
|
622
|
+
{
|
|
623
|
+
context: "crudRepositoryFindById",
|
|
624
|
+
hookKey: "afterQuery"
|
|
625
|
+
}
|
|
626
|
+
);
|
|
248
627
|
|
|
249
|
-
|
|
628
|
+
let output = records[0] || null;
|
|
629
|
+
output = await applyCrudRepositoryRecordHook(
|
|
630
|
+
output,
|
|
631
|
+
transformFindByIdRecord,
|
|
632
|
+
{
|
|
633
|
+
recordId,
|
|
634
|
+
...hookContextBase
|
|
635
|
+
},
|
|
636
|
+
{
|
|
637
|
+
context: "crudRepositoryFindById",
|
|
638
|
+
hookKey: "transformReturnedRecord"
|
|
639
|
+
}
|
|
640
|
+
);
|
|
641
|
+
|
|
642
|
+
return applyCrudRepositoryOutputHook(
|
|
643
|
+
output,
|
|
644
|
+
finalizeFindByIdOutput,
|
|
645
|
+
{
|
|
646
|
+
recordId,
|
|
647
|
+
...hookContextBase
|
|
648
|
+
},
|
|
649
|
+
{
|
|
650
|
+
context: "crudRepositoryFindById",
|
|
651
|
+
hookKey: "finalizeOutput",
|
|
652
|
+
validateOutput(nextOutput) {
|
|
653
|
+
if (nextOutput === null) {
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
if (!nextOutput || typeof nextOutput !== "object" || Array.isArray(nextOutput)) {
|
|
657
|
+
throw new TypeError("crudRepositoryFindById hooks.finalizeOutput must return record object or null.");
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
);
|
|
250
662
|
}
|
|
251
663
|
|
|
252
|
-
async function crudRepositoryListByIds(runtime, knex, ids = [], repositoryOptions = {}, callOptions = {}) {
|
|
664
|
+
async function crudRepositoryListByIds(runtime, knex, ids = [], repositoryOptions = {}, callOptions = {}, hooks = null) {
|
|
253
665
|
const { client, tableName, visible } = resolveCrudRepositoryCall(runtime, knex, repositoryOptions, callOptions);
|
|
666
|
+
const methodHooks = normalizeCrudRepositoryHooks(
|
|
667
|
+
hooks,
|
|
668
|
+
["modifyQuery", "afterQuery", "transformReturnedRecord", "finalizeOutput"],
|
|
669
|
+
{
|
|
670
|
+
context: "crudRepositoryListByIds"
|
|
671
|
+
}
|
|
672
|
+
);
|
|
673
|
+
const modifyListByIdsQuery = resolveOptionalCrudRepositoryHook(methodHooks, "modifyQuery", {
|
|
674
|
+
context: "crudRepositoryListByIds"
|
|
675
|
+
});
|
|
676
|
+
const afterListByIdsQuery = resolveOptionalCrudRepositoryHook(methodHooks, "afterQuery", {
|
|
677
|
+
context: "crudRepositoryListByIds"
|
|
678
|
+
});
|
|
679
|
+
const transformListByIdsRecord = resolveOptionalCrudRepositoryHook(methodHooks, "transformReturnedRecord", {
|
|
680
|
+
context: "crudRepositoryListByIds"
|
|
681
|
+
});
|
|
682
|
+
const finalizeListByIdsOutput = resolveOptionalCrudRepositoryHook(methodHooks, "finalizeOutput", {
|
|
683
|
+
context: "crudRepositoryListByIds"
|
|
684
|
+
});
|
|
685
|
+
const hookContextBase = createCrudRepositoryHookContextBase(runtime, repositoryOptions, callOptions);
|
|
254
686
|
const lookupValueKey = normalizeText(callOptions?.valueKey) || "id";
|
|
255
687
|
if (!runtime.mapping.outputKeys.includes(lookupValueKey)) {
|
|
256
688
|
throw new TypeError(
|
|
@@ -267,11 +699,31 @@ async function crudRepositoryListByIds(runtime, knex, ids = [], repositoryOption
|
|
|
267
699
|
return [];
|
|
268
700
|
}
|
|
269
701
|
|
|
270
|
-
|
|
271
|
-
.select(...runtime.selectColumns)
|
|
702
|
+
let dbQuery = client(tableName)
|
|
703
|
+
.select(...runtime.selectColumns);
|
|
704
|
+
|
|
705
|
+
const listByIdsHookResult = await applyCrudRepositoryQueryHook(
|
|
706
|
+
dbQuery,
|
|
707
|
+
modifyListByIdsQuery,
|
|
708
|
+
{
|
|
709
|
+
ids: normalizedIds,
|
|
710
|
+
lookupValueKey,
|
|
711
|
+
lookupColumn,
|
|
712
|
+
...hookContextBase
|
|
713
|
+
},
|
|
714
|
+
{
|
|
715
|
+
context: "crudRepositoryListByIds",
|
|
716
|
+
hookKey: "modifyQuery"
|
|
717
|
+
}
|
|
718
|
+
);
|
|
719
|
+
dbQuery = listByIdsHookResult.queryBuilder;
|
|
720
|
+
|
|
721
|
+
dbQuery = dbQuery
|
|
272
722
|
.where(visible)
|
|
273
723
|
.whereIn(lookupColumn, normalizedIds);
|
|
274
724
|
|
|
725
|
+
const rows = await dbQuery;
|
|
726
|
+
|
|
275
727
|
const records = [];
|
|
276
728
|
for (const row of rows) {
|
|
277
729
|
const mappedRecord = mapRecordRow(row, runtime.mapping.outputKeys, runtime.mapping.columnOverrides);
|
|
@@ -285,8 +737,7 @@ async function crudRepositoryListByIds(runtime, knex, ids = [], repositoryOption
|
|
|
285
737
|
}
|
|
286
738
|
|
|
287
739
|
const lookupInclude = callOptions?.include === undefined ? "none" : callOptions.include;
|
|
288
|
-
|
|
289
|
-
return hydrateCrudLookupRecords(records, {
|
|
740
|
+
let hydratedRecords = await hydrateCrudLookupRecords(records, {
|
|
290
741
|
...runtime.lookup,
|
|
291
742
|
context: runtime.context
|
|
292
743
|
}, {
|
|
@@ -295,11 +746,116 @@ async function crudRepositoryListByIds(runtime, knex, ids = [], repositoryOption
|
|
|
295
746
|
repositoryOptions,
|
|
296
747
|
callOptions
|
|
297
748
|
});
|
|
749
|
+
|
|
750
|
+
hydratedRecords = await applyCrudRepositoryRecordsHook(
|
|
751
|
+
hydratedRecords,
|
|
752
|
+
afterListByIdsQuery,
|
|
753
|
+
{
|
|
754
|
+
ids: normalizedIds,
|
|
755
|
+
...hookContextBase
|
|
756
|
+
},
|
|
757
|
+
{
|
|
758
|
+
context: "crudRepositoryListByIds",
|
|
759
|
+
hookKey: "afterQuery"
|
|
760
|
+
}
|
|
761
|
+
);
|
|
762
|
+
|
|
763
|
+
const transformedRecords = [];
|
|
764
|
+
for (let itemIndex = 0; itemIndex < hydratedRecords.length; itemIndex += 1) {
|
|
765
|
+
transformedRecords.push(
|
|
766
|
+
await applyCrudRepositoryRecordHook(
|
|
767
|
+
hydratedRecords[itemIndex],
|
|
768
|
+
transformListByIdsRecord,
|
|
769
|
+
{
|
|
770
|
+
ids: normalizedIds,
|
|
771
|
+
itemIndex,
|
|
772
|
+
items: hydratedRecords,
|
|
773
|
+
...hookContextBase
|
|
774
|
+
},
|
|
775
|
+
{
|
|
776
|
+
context: "crudRepositoryListByIds",
|
|
777
|
+
hookKey: "transformReturnedRecord"
|
|
778
|
+
}
|
|
779
|
+
)
|
|
780
|
+
);
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
return applyCrudRepositoryOutputHook(
|
|
784
|
+
transformedRecords,
|
|
785
|
+
finalizeListByIdsOutput,
|
|
786
|
+
{
|
|
787
|
+
ids: normalizedIds,
|
|
788
|
+
...hookContextBase
|
|
789
|
+
},
|
|
790
|
+
{
|
|
791
|
+
context: "crudRepositoryListByIds",
|
|
792
|
+
hookKey: "finalizeOutput",
|
|
793
|
+
validateOutput(nextOutput) {
|
|
794
|
+
if (!Array.isArray(nextOutput)) {
|
|
795
|
+
throw new TypeError("crudRepositoryListByIds hooks.finalizeOutput must return an array.");
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
);
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
async function crudRepositoryListByForeignIds(
|
|
803
|
+
runtime,
|
|
804
|
+
knex,
|
|
805
|
+
ids = [],
|
|
806
|
+
foreignKey = "",
|
|
807
|
+
repositoryOptions = {},
|
|
808
|
+
callOptions = {},
|
|
809
|
+
hooks = null
|
|
810
|
+
) {
|
|
811
|
+
const normalizedForeignKey = normalizeText(foreignKey);
|
|
812
|
+
if (!normalizedForeignKey) {
|
|
813
|
+
throw new TypeError(`${runtime?.context || "crudRepository"} listByForeignIds requires foreignKey.`);
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
return crudRepositoryListByIds(
|
|
817
|
+
runtime,
|
|
818
|
+
knex,
|
|
819
|
+
ids,
|
|
820
|
+
repositoryOptions,
|
|
821
|
+
{
|
|
822
|
+
...callOptions,
|
|
823
|
+
valueKey: normalizedForeignKey
|
|
824
|
+
},
|
|
825
|
+
hooks
|
|
826
|
+
);
|
|
298
827
|
}
|
|
299
828
|
|
|
300
|
-
async function crudRepositoryCreate(runtime, knex, payload = {}, repositoryOptions = {}, callOptions = {}) {
|
|
829
|
+
async function crudRepositoryCreate(runtime, knex, payload = {}, repositoryOptions = {}, callOptions = {}, hooks = null) {
|
|
301
830
|
const { client, tableName } = resolveCrudRepositoryCall(runtime, knex, repositoryOptions, callOptions);
|
|
302
|
-
const
|
|
831
|
+
const methodHooks = normalizeCrudRepositoryHooks(hooks, ["modifyPayload", "modifyQuery", "afterWrite"], {
|
|
832
|
+
context: "crudRepositoryCreate"
|
|
833
|
+
});
|
|
834
|
+
const modifyCreatePayload = resolveOptionalCrudRepositoryHook(methodHooks, "modifyPayload", {
|
|
835
|
+
context: "crudRepositoryCreate"
|
|
836
|
+
});
|
|
837
|
+
const modifyCreateQuery = resolveOptionalCrudRepositoryHook(methodHooks, "modifyQuery", {
|
|
838
|
+
context: "crudRepositoryCreate"
|
|
839
|
+
});
|
|
840
|
+
const afterCreateWrite = resolveOptionalCrudRepositoryHook(methodHooks, "afterWrite", {
|
|
841
|
+
context: "crudRepositoryCreate"
|
|
842
|
+
});
|
|
843
|
+
const hookContextBase = createCrudRepositoryHookContextBase(runtime, repositoryOptions, callOptions);
|
|
844
|
+
let sourcePayload = normalizeCrudRepositoryObjectInput(payload);
|
|
845
|
+
sourcePayload = await applyCrudRepositoryPayloadHook(
|
|
846
|
+
sourcePayload,
|
|
847
|
+
modifyCreatePayload,
|
|
848
|
+
{
|
|
849
|
+
payload: sourcePayload,
|
|
850
|
+
...hookContextBase
|
|
851
|
+
},
|
|
852
|
+
{
|
|
853
|
+
context: "crudRepositoryCreate",
|
|
854
|
+
hookKey: "modifyPayload"
|
|
855
|
+
}
|
|
856
|
+
);
|
|
857
|
+
|
|
858
|
+
const insertPayload = buildWritePayload(sourcePayload, runtime.mapping.writeKeys, runtime.mapping.columnOverrides);
|
|
303
859
|
const timestamp = toInsertDateTime();
|
|
304
860
|
if (runtime.defaults.createdAtColumn && !Object.hasOwn(insertPayload, runtime.defaults.createdAtColumn)) {
|
|
305
861
|
insertPayload[runtime.defaults.createdAtColumn] = timestamp;
|
|
@@ -308,18 +864,83 @@ async function crudRepositoryCreate(runtime, knex, payload = {}, repositoryOptio
|
|
|
308
864
|
insertPayload[runtime.defaults.updatedAtColumn] = timestamp;
|
|
309
865
|
}
|
|
310
866
|
|
|
311
|
-
|
|
312
|
-
|
|
867
|
+
let withOwners = applyVisibilityOwners(insertPayload, callOptions.visibilityContext);
|
|
868
|
+
let createQuery = client(tableName);
|
|
869
|
+
const createHookResult = await applyCrudRepositoryQueryHook(
|
|
870
|
+
createQuery,
|
|
871
|
+
modifyCreateQuery,
|
|
872
|
+
{
|
|
873
|
+
payload: {
|
|
874
|
+
...withOwners
|
|
875
|
+
},
|
|
876
|
+
...hookContextBase
|
|
877
|
+
},
|
|
878
|
+
{
|
|
879
|
+
context: "crudRepositoryCreate",
|
|
880
|
+
hookKey: "modifyQuery"
|
|
881
|
+
}
|
|
882
|
+
);
|
|
883
|
+
createQuery = createHookResult.queryBuilder;
|
|
884
|
+
|
|
885
|
+
const [recordId] = await createQuery.insert(withOwners);
|
|
313
886
|
|
|
314
|
-
|
|
887
|
+
const createdRecord = await crudRepositoryFindById(runtime, knex, recordId, repositoryOptions, {
|
|
315
888
|
...callOptions,
|
|
316
|
-
trx: client
|
|
317
|
-
|
|
889
|
+
trx: client,
|
|
890
|
+
sourceOperation: "create"
|
|
891
|
+
}, null);
|
|
892
|
+
|
|
893
|
+
await applyCrudRepositoryAfterWriteHook(
|
|
894
|
+
{
|
|
895
|
+
operation: "create",
|
|
896
|
+
recordId,
|
|
897
|
+
payload: {
|
|
898
|
+
...withOwners
|
|
899
|
+
},
|
|
900
|
+
record: createdRecord,
|
|
901
|
+
output: createdRecord
|
|
902
|
+
},
|
|
903
|
+
afterCreateWrite,
|
|
904
|
+
hookContextBase,
|
|
905
|
+
{
|
|
906
|
+
context: "crudRepositoryCreate",
|
|
907
|
+
hookKey: "afterWrite"
|
|
908
|
+
}
|
|
909
|
+
);
|
|
910
|
+
|
|
911
|
+
return createdRecord;
|
|
318
912
|
}
|
|
319
913
|
|
|
320
|
-
async function crudRepositoryUpdateById(runtime, knex, recordId, patch = {}, repositoryOptions = {}, callOptions = {}) {
|
|
914
|
+
async function crudRepositoryUpdateById(runtime, knex, recordId, patch = {}, repositoryOptions = {}, callOptions = {}, hooks = null) {
|
|
321
915
|
const { client, tableName, idColumn, visible } = resolveCrudRepositoryCall(runtime, knex, repositoryOptions, callOptions);
|
|
322
|
-
const
|
|
916
|
+
const methodHooks = normalizeCrudRepositoryHooks(hooks, ["modifyPatch", "modifyQuery", "afterWrite"], {
|
|
917
|
+
context: "crudRepositoryUpdateById"
|
|
918
|
+
});
|
|
919
|
+
const modifyUpdatePatch = resolveOptionalCrudRepositoryHook(methodHooks, "modifyPatch", {
|
|
920
|
+
context: "crudRepositoryUpdateById"
|
|
921
|
+
});
|
|
922
|
+
const modifyUpdateByIdQuery = resolveOptionalCrudRepositoryHook(methodHooks, "modifyQuery", {
|
|
923
|
+
context: "crudRepositoryUpdateById"
|
|
924
|
+
});
|
|
925
|
+
const afterUpdateWrite = resolveOptionalCrudRepositoryHook(methodHooks, "afterWrite", {
|
|
926
|
+
context: "crudRepositoryUpdateById"
|
|
927
|
+
});
|
|
928
|
+
const hookContextBase = createCrudRepositoryHookContextBase(runtime, repositoryOptions, callOptions);
|
|
929
|
+
let sourcePatch = normalizeCrudRepositoryObjectInput(patch);
|
|
930
|
+
sourcePatch = await applyCrudRepositoryPayloadHook(
|
|
931
|
+
sourcePatch,
|
|
932
|
+
modifyUpdatePatch,
|
|
933
|
+
{
|
|
934
|
+
recordId,
|
|
935
|
+
patch: sourcePatch,
|
|
936
|
+
...hookContextBase
|
|
937
|
+
},
|
|
938
|
+
{
|
|
939
|
+
context: "crudRepositoryUpdateById",
|
|
940
|
+
hookKey: "modifyPatch"
|
|
941
|
+
}
|
|
942
|
+
);
|
|
943
|
+
let dbPatch = buildWritePayload(sourcePatch, runtime.mapping.writeKeys, runtime.mapping.columnOverrides);
|
|
323
944
|
|
|
324
945
|
if (runtime.defaults.updatedAtColumn) {
|
|
325
946
|
dbPatch[runtime.defaults.updatedAtColumn] = toInsertDateTime();
|
|
@@ -328,46 +949,174 @@ async function crudRepositoryUpdateById(runtime, knex, recordId, patch = {}, rep
|
|
|
328
949
|
if (Object.keys(dbPatch).length < 1) {
|
|
329
950
|
return crudRepositoryFindById(runtime, knex, recordId, repositoryOptions, {
|
|
330
951
|
...callOptions,
|
|
331
|
-
trx: client
|
|
332
|
-
|
|
952
|
+
trx: client,
|
|
953
|
+
sourceOperation: "update"
|
|
954
|
+
}, null);
|
|
333
955
|
}
|
|
334
956
|
|
|
335
|
-
|
|
957
|
+
let updateQuery = client(tableName);
|
|
958
|
+
const updateHookResult = await applyCrudRepositoryQueryHook(
|
|
959
|
+
updateQuery,
|
|
960
|
+
modifyUpdateByIdQuery,
|
|
961
|
+
{
|
|
962
|
+
recordId,
|
|
963
|
+
patch: {
|
|
964
|
+
...dbPatch
|
|
965
|
+
},
|
|
966
|
+
...hookContextBase
|
|
967
|
+
},
|
|
968
|
+
{
|
|
969
|
+
context: "crudRepositoryUpdateById",
|
|
970
|
+
hookKey: "modifyQuery"
|
|
971
|
+
}
|
|
972
|
+
);
|
|
973
|
+
updateQuery = updateHookResult.queryBuilder;
|
|
974
|
+
|
|
975
|
+
updateQuery = updateQuery
|
|
336
976
|
.where(visible)
|
|
337
977
|
.where({
|
|
338
978
|
[idColumn]: Number(recordId)
|
|
339
|
-
})
|
|
340
|
-
.update(dbPatch);
|
|
979
|
+
});
|
|
341
980
|
|
|
342
|
-
|
|
981
|
+
await updateQuery.update(dbPatch);
|
|
982
|
+
|
|
983
|
+
const updatedRecord = await crudRepositoryFindById(runtime, knex, recordId, repositoryOptions, {
|
|
343
984
|
...callOptions,
|
|
344
|
-
trx: client
|
|
345
|
-
|
|
985
|
+
trx: client,
|
|
986
|
+
sourceOperation: "update"
|
|
987
|
+
}, null);
|
|
988
|
+
|
|
989
|
+
await applyCrudRepositoryAfterWriteHook(
|
|
990
|
+
{
|
|
991
|
+
operation: "update",
|
|
992
|
+
recordId,
|
|
993
|
+
patch: {
|
|
994
|
+
...dbPatch
|
|
995
|
+
},
|
|
996
|
+
record: updatedRecord,
|
|
997
|
+
output: updatedRecord
|
|
998
|
+
},
|
|
999
|
+
afterUpdateWrite,
|
|
1000
|
+
hookContextBase,
|
|
1001
|
+
{
|
|
1002
|
+
context: "crudRepositoryUpdateById",
|
|
1003
|
+
hookKey: "afterWrite"
|
|
1004
|
+
}
|
|
1005
|
+
);
|
|
1006
|
+
|
|
1007
|
+
return updatedRecord;
|
|
346
1008
|
}
|
|
347
1009
|
|
|
348
|
-
async function crudRepositoryDeleteById(runtime, knex, recordId, repositoryOptions = {}, callOptions = {}) {
|
|
1010
|
+
async function crudRepositoryDeleteById(runtime, knex, recordId, repositoryOptions = {}, callOptions = {}, hooks = null) {
|
|
349
1011
|
const { client, tableName, idColumn, visible } = resolveCrudRepositoryCall(runtime, knex, repositoryOptions, callOptions);
|
|
1012
|
+
const methodHooks = normalizeCrudRepositoryHooks(hooks, ["modifyQuery", "finalizeOutput", "afterWrite"], {
|
|
1013
|
+
context: "crudRepositoryDeleteById"
|
|
1014
|
+
});
|
|
1015
|
+
const modifyDeleteByIdQuery = resolveOptionalCrudRepositoryHook(methodHooks, "modifyQuery", {
|
|
1016
|
+
context: "crudRepositoryDeleteById"
|
|
1017
|
+
});
|
|
1018
|
+
const finalizeDeleteOutput = resolveOptionalCrudRepositoryHook(methodHooks, "finalizeOutput", {
|
|
1019
|
+
context: "crudRepositoryDeleteById"
|
|
1020
|
+
});
|
|
1021
|
+
const afterDeleteWrite = resolveOptionalCrudRepositoryHook(methodHooks, "afterWrite", {
|
|
1022
|
+
context: "crudRepositoryDeleteById"
|
|
1023
|
+
});
|
|
1024
|
+
const hookContextBase = createCrudRepositoryHookContextBase(runtime, repositoryOptions, callOptions);
|
|
350
1025
|
const existing = await crudRepositoryFindById(runtime, knex, recordId, repositoryOptions, {
|
|
351
1026
|
...callOptions,
|
|
352
1027
|
include: "none",
|
|
353
1028
|
trx: client
|
|
354
|
-
});
|
|
1029
|
+
}, null);
|
|
355
1030
|
|
|
356
1031
|
if (!existing) {
|
|
357
|
-
return
|
|
1032
|
+
return applyCrudRepositoryOutputHook(
|
|
1033
|
+
null,
|
|
1034
|
+
finalizeDeleteOutput,
|
|
1035
|
+
{
|
|
1036
|
+
recordId,
|
|
1037
|
+
...hookContextBase
|
|
1038
|
+
},
|
|
1039
|
+
{
|
|
1040
|
+
context: "crudRepositoryDeleteById",
|
|
1041
|
+
hookKey: "finalizeOutput",
|
|
1042
|
+
validateOutput(nextOutput) {
|
|
1043
|
+
if (nextOutput === null) {
|
|
1044
|
+
return;
|
|
1045
|
+
}
|
|
1046
|
+
if (!nextOutput || typeof nextOutput !== "object" || Array.isArray(nextOutput)) {
|
|
1047
|
+
throw new TypeError("crudRepositoryDeleteById hooks.finalizeOutput must return object or null.");
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
);
|
|
358
1052
|
}
|
|
359
1053
|
|
|
360
|
-
|
|
1054
|
+
let deleteQuery = client(tableName);
|
|
1055
|
+
const deleteHookResult = await applyCrudRepositoryQueryHook(
|
|
1056
|
+
deleteQuery,
|
|
1057
|
+
modifyDeleteByIdQuery,
|
|
1058
|
+
{
|
|
1059
|
+
recordId,
|
|
1060
|
+
existing,
|
|
1061
|
+
...hookContextBase
|
|
1062
|
+
},
|
|
1063
|
+
{
|
|
1064
|
+
context: "crudRepositoryDeleteById",
|
|
1065
|
+
hookKey: "modifyQuery"
|
|
1066
|
+
}
|
|
1067
|
+
);
|
|
1068
|
+
deleteQuery = deleteHookResult.queryBuilder;
|
|
1069
|
+
|
|
1070
|
+
deleteQuery = deleteQuery
|
|
361
1071
|
.where(visible)
|
|
362
1072
|
.where({
|
|
363
1073
|
[idColumn]: Number(recordId)
|
|
364
|
-
})
|
|
365
|
-
.delete();
|
|
1074
|
+
});
|
|
366
1075
|
|
|
367
|
-
|
|
1076
|
+
await deleteQuery.delete();
|
|
1077
|
+
|
|
1078
|
+
let output = {
|
|
368
1079
|
id: existing.id,
|
|
369
1080
|
deleted: true
|
|
370
1081
|
};
|
|
1082
|
+
|
|
1083
|
+
output = await applyCrudRepositoryOutputHook(
|
|
1084
|
+
output,
|
|
1085
|
+
finalizeDeleteOutput,
|
|
1086
|
+
{
|
|
1087
|
+
recordId,
|
|
1088
|
+
...hookContextBase
|
|
1089
|
+
},
|
|
1090
|
+
{
|
|
1091
|
+
context: "crudRepositoryDeleteById",
|
|
1092
|
+
hookKey: "finalizeOutput",
|
|
1093
|
+
validateOutput(nextOutput) {
|
|
1094
|
+
if (nextOutput === null) {
|
|
1095
|
+
return;
|
|
1096
|
+
}
|
|
1097
|
+
if (!nextOutput || typeof nextOutput !== "object" || Array.isArray(nextOutput)) {
|
|
1098
|
+
throw new TypeError("crudRepositoryDeleteById hooks.finalizeOutput must return object or null.");
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
);
|
|
1103
|
+
|
|
1104
|
+
await applyCrudRepositoryAfterWriteHook(
|
|
1105
|
+
{
|
|
1106
|
+
operation: "delete",
|
|
1107
|
+
recordId,
|
|
1108
|
+
existing,
|
|
1109
|
+
output
|
|
1110
|
+
},
|
|
1111
|
+
afterDeleteWrite,
|
|
1112
|
+
hookContextBase,
|
|
1113
|
+
{
|
|
1114
|
+
context: "crudRepositoryDeleteById",
|
|
1115
|
+
hookKey: "afterWrite"
|
|
1116
|
+
}
|
|
1117
|
+
);
|
|
1118
|
+
|
|
1119
|
+
return output;
|
|
371
1120
|
}
|
|
372
1121
|
|
|
373
1122
|
export {
|
|
@@ -375,6 +1124,7 @@ export {
|
|
|
375
1124
|
crudRepositoryList,
|
|
376
1125
|
crudRepositoryFindById,
|
|
377
1126
|
crudRepositoryListByIds,
|
|
1127
|
+
crudRepositoryListByForeignIds,
|
|
378
1128
|
crudRepositoryCreate,
|
|
379
1129
|
crudRepositoryUpdateById,
|
|
380
1130
|
crudRepositoryDeleteById
|