@appweaver/core 1.4.1 → 1.5.1
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/factory/create-model.js +25 -5
- package/package.json +1 -1
- package/prisma/client/internal/class.js +4 -4
- package/prisma/client/internal/prismaNamespace.d.ts +1 -0
- package/prisma/client/internal/prismaNamespace.js +2 -1
- package/prisma/client/internal/prismaNamespaceBrowser.d.ts +1 -0
- package/prisma/client/internal/prismaNamespaceBrowser.js +2 -1
- package/prisma/client/models/ConnectedAccount.d.ts +6 -1
- package/prisma/client/models/File.d.ts +29 -1
- package/resource/resource-loader.js +3 -0
- package/resource/resource-routes.js +0 -1
- package/resource/resource-service.d.ts +35 -8
- package/resource/resource-service.js +110 -23
- package/resource/utils/delete-util.d.ts +120 -0
- package/resource/utils/delete-util.js +385 -0
- package/resource/utils/filter-util.js +11 -5
- package/resource/utils/index.d.ts +1 -0
- package/resource/utils/index.js +1 -0
- package/resource/utils/relation-util.js +19 -6
- package/security/api-key/api-key-auth.js +4 -3
- package/security/oauth2/oauth2-service.js +19 -5
- package/security/resources/api-key/model.js +2 -0
- package/security/resources/connected-account/model.js +3 -1
- package/storage/file-service.d.ts +13 -3
- package/storage/file-service.js +24 -14
- package/storage/resources/file/model.js +5 -1
- package/types/generated.d.ts +1 -0
- package/utils/file-util.d.ts +14 -0
- package/utils/file-util.js +21 -0
- package/utils/model-util.d.ts +24 -0
- package/utils/model-util.js +43 -0
|
@@ -6,6 +6,7 @@ const context_1 = require("../context");
|
|
|
6
6
|
const utils_1 = require("../utils");
|
|
7
7
|
const cache_1 = require("../cache");
|
|
8
8
|
const errors_1 = require("../errors");
|
|
9
|
+
const storage_1 = require("../storage");
|
|
9
10
|
const utils_2 = require("./utils");
|
|
10
11
|
class ResourceService {
|
|
11
12
|
modelName;
|
|
@@ -61,7 +62,7 @@ class ResourceService {
|
|
|
61
62
|
let resource;
|
|
62
63
|
try {
|
|
63
64
|
resource = await this._client.findFirst({
|
|
64
|
-
where: { id, ...restrictions },
|
|
65
|
+
where: { id, ...restrictions, ...(0, utils_1.liveRecordFilter)(this._client.name) },
|
|
65
66
|
include: includeRelations
|
|
66
67
|
});
|
|
67
68
|
}
|
|
@@ -120,7 +121,9 @@ class ResourceService {
|
|
|
120
121
|
const restrictions = await this.readRestrictions('query', filter);
|
|
121
122
|
const textSearch = this.extractTextSearchQuery(filter);
|
|
122
123
|
const mappedFilter = (0, utils_2.mapQueryFilter)(filter, this._client.name);
|
|
123
|
-
const query = {
|
|
124
|
+
const query = {
|
|
125
|
+
AND: [mappedFilter, textSearch, restrictions, ...this.liveFilters()]
|
|
126
|
+
};
|
|
124
127
|
const includeRelations = (0, utils_2.mapRelationInclusions)(this._client.name, 'query');
|
|
125
128
|
const orderBy = (0, utils_2.mapStableSortValues)(sort, this._client.name, 'query');
|
|
126
129
|
// Binding to the mapped query rather than the filter also invalidates a
|
|
@@ -220,7 +223,9 @@ class ResourceService {
|
|
|
220
223
|
const restrictions = await this.readRestrictions('aggregate', filter);
|
|
221
224
|
const textSearch = this.extractTextSearchQuery(filter);
|
|
222
225
|
const mappedFilter = (0, utils_2.mapQueryFilter)(filter, this._client.name);
|
|
223
|
-
const query = {
|
|
226
|
+
const query = {
|
|
227
|
+
AND: [mappedFilter, textSearch, restrictions, ...this.liveFilters()]
|
|
228
|
+
};
|
|
224
229
|
const rangeQuery = (rangeFrom, rangeTo) => ({
|
|
225
230
|
AND: [query, { [dateField]: { gte: rangeFrom, lt: rangeTo } }]
|
|
226
231
|
});
|
|
@@ -290,6 +295,7 @@ class ResourceService {
|
|
|
290
295
|
const sanitizedData = this.sanitizeData('create', createData);
|
|
291
296
|
const connectRelations = (0, utils_2.mapRelationActions)(this._client.name, 'create', sanitizedData);
|
|
292
297
|
const includeRelations = (0, utils_2.mapRelationInclusions)(this._client.name, 'create');
|
|
298
|
+
await (0, utils_2.assertLiveRelationTargets)(this._db.client(), this._client.name, connectRelations);
|
|
293
299
|
let resource;
|
|
294
300
|
try {
|
|
295
301
|
resource = await this._client.create({
|
|
@@ -315,9 +321,9 @@ class ResourceService {
|
|
|
315
321
|
* the read restrictions applied and checked for access, then updated with the
|
|
316
322
|
* data merged with the write restrictions inside a single transaction.
|
|
317
323
|
* Relations missing from the new value are disconnected, or deleted when
|
|
318
|
-
* `orphanRemoval` is configured for them. The resource cache is invalidated
|
|
319
|
-
*
|
|
320
|
-
*
|
|
324
|
+
* `orphanRemoval` is configured for them, the same way a delete does. The resource cache is invalidated and a
|
|
325
|
+
* resource event carrying both the previous and the current state is emitted
|
|
326
|
+
* after a successful update.
|
|
321
327
|
*
|
|
322
328
|
* @param {ResourceId} id The id of the resource to update.
|
|
323
329
|
* @param {Object} data The partial data to update the resource with, including
|
|
@@ -327,7 +333,8 @@ class ResourceService {
|
|
|
327
333
|
* @throws {@link HttpError} 404 if the resource does not exist or is filtered
|
|
328
334
|
* out by the read restrictions, 403 if the access check denies the action, 400
|
|
329
335
|
* if an inline relation payload is missing required fields or the relation
|
|
330
|
-
* does not accept new records,
|
|
336
|
+
* does not accept new records, 409 if a live record references a soft
|
|
337
|
+
* deleted orphan through a restricting relation, and 500 on a database error.
|
|
331
338
|
*/
|
|
332
339
|
async update(id, data) {
|
|
333
340
|
const readRestrictions = await this.readRestrictions('update', {
|
|
@@ -346,13 +353,18 @@ class ResourceService {
|
|
|
346
353
|
const includeRelations = (0, utils_2.mapRelationInclusions)(this._client.name, 'update');
|
|
347
354
|
let updateResource;
|
|
348
355
|
let resource;
|
|
356
|
+
let orphans;
|
|
349
357
|
try {
|
|
350
|
-
[updateResource, resource] = await this._db
|
|
358
|
+
[updateResource, resource, orphans] = await this._db
|
|
351
359
|
.client()
|
|
352
360
|
.$transaction(async (tx) => {
|
|
353
361
|
const txModel = tx[this._client.name];
|
|
354
362
|
const current = await txModel.findFirst({
|
|
355
|
-
where: {
|
|
363
|
+
where: {
|
|
364
|
+
id,
|
|
365
|
+
...readRestrictions,
|
|
366
|
+
...(0, utils_1.liveRecordFilter)(this._client.name)
|
|
367
|
+
},
|
|
356
368
|
include: includeRelations
|
|
357
369
|
});
|
|
358
370
|
if (!current || current.id !== id) {
|
|
@@ -363,12 +375,18 @@ class ResourceService {
|
|
|
363
375
|
throw new errors_1.HttpError(`${this._client.name} update action is forbidden`, 403);
|
|
364
376
|
}
|
|
365
377
|
const setRelations = (0, utils_2.mapRelationActions)(this._client.name, 'update', sanitizedData, current);
|
|
378
|
+
await (0, utils_2.assertLiveRelationTargets)(tx, this._client.name, setRelations);
|
|
379
|
+
// Soft deleted orphans are marked before the update reads the
|
|
380
|
+
// relations back, so the response no longer holds them
|
|
381
|
+
const deleteData = (0, utils_2.softDeleteData)();
|
|
382
|
+
const removed = await (0, utils_2.removeOrphans)(tx, this._client.name, setRelations, deleteData);
|
|
383
|
+
await (0, utils_2.retainDeletedFiles)(tx, removed, deleteData);
|
|
366
384
|
const updated = await txModel.update({
|
|
367
385
|
where: { id },
|
|
368
386
|
include: includeRelations,
|
|
369
387
|
data: { ...sanitizedData, ...setRelations }
|
|
370
388
|
});
|
|
371
|
-
return [current, updated];
|
|
389
|
+
return [current, updated, removed];
|
|
372
390
|
});
|
|
373
391
|
}
|
|
374
392
|
catch (e) {
|
|
@@ -378,6 +396,7 @@ class ResourceService {
|
|
|
378
396
|
throw new errors_1.HttpError(`${this._client.name} update error`, 500, e);
|
|
379
397
|
}
|
|
380
398
|
await this._cacheService.invalidateCache(this._client.name, 'update');
|
|
399
|
+
await this.cleanupDeletedRecords(orphans);
|
|
381
400
|
this._events.emitResourceEvent(this._client.name, 'update', {
|
|
382
401
|
previous: updateResource,
|
|
383
402
|
current: resource
|
|
@@ -387,24 +406,43 @@ class ResourceService {
|
|
|
387
406
|
/**
|
|
388
407
|
* Deletes an existing resource by its id. The current record is loaded with
|
|
389
408
|
* the read restrictions applied and checked for access before it is deleted
|
|
390
|
-
* inside a single transaction.
|
|
391
|
-
*
|
|
409
|
+
* inside a single transaction.
|
|
410
|
+
*
|
|
411
|
+
* A model with `softDelete` enabled marks the record with the `deletedAt`
|
|
412
|
+
* and `deletedById` columns instead, soft deleting its cascade as well.
|
|
413
|
+
*
|
|
414
|
+
* The stored files of the deleted records follow the `onResourceDeleted`, or
|
|
415
|
+
* for soft deleted records the `onResourceSoftDeleted`, option of each file
|
|
416
|
+
* field: kept files are marked deleted in the transaction and no longer
|
|
417
|
+
* served, the others are removed once it commits. The cache of every affected
|
|
418
|
+
* model is invalidated and a resource event is emitted.
|
|
392
419
|
*
|
|
393
420
|
* @param {ResourceId} id The id of the resource to delete.
|
|
394
421
|
* @returns {Promise<Object>} The deleted resource with its virtual fields and
|
|
395
422
|
* relation counts projected.
|
|
396
423
|
* @throws {@link HttpError} 404 if the resource does not exist or is filtered
|
|
397
|
-
* out by the read restrictions, 403 if the access check denies
|
|
398
|
-
* 500 on a
|
|
424
|
+
* out by the read restrictions, 403 if the access check denies it, 409 if a
|
|
425
|
+
* restricting relation still references a soft deleted resource, and 500 on a
|
|
426
|
+
* database error, a restricting relation of a removed resource included.
|
|
399
427
|
*/
|
|
400
428
|
async delete(id) {
|
|
401
429
|
const restrictions = await this.readRestrictions('delete', id);
|
|
430
|
+
const softDelete = (0, common_1.hasSoftDelete)((0, context_1.injectModel)(this._client.name).config);
|
|
431
|
+
const includeRelations = (0, utils_2.mapRelationInclusions)(this._client.name, 'delete');
|
|
402
432
|
let resource;
|
|
433
|
+
let deleted;
|
|
403
434
|
try {
|
|
404
|
-
resource = await this._db.client().$transaction(async (tx) => {
|
|
435
|
+
[resource, deleted] = await this._db.client().$transaction(async (tx) => {
|
|
405
436
|
const txModel = tx[this._client.name];
|
|
437
|
+
// A soft deleted record is read with its relations up front, as a
|
|
438
|
+
// database delete returns them before the cascade removes them
|
|
406
439
|
const current = await txModel.findFirst({
|
|
407
|
-
where: {
|
|
440
|
+
where: {
|
|
441
|
+
id,
|
|
442
|
+
...restrictions,
|
|
443
|
+
...(0, utils_1.liveRecordFilter)(this._client.name)
|
|
444
|
+
},
|
|
445
|
+
include: softDelete ? includeRelations : undefined
|
|
408
446
|
});
|
|
409
447
|
if (!current || current.id !== id) {
|
|
410
448
|
throw new errors_1.HttpError(`${this._client.name} data not found`, 404);
|
|
@@ -413,11 +451,28 @@ class ResourceService {
|
|
|
413
451
|
if (!access) {
|
|
414
452
|
throw new errors_1.HttpError(`${this._client.name} delete action is forbidden`, 403);
|
|
415
453
|
}
|
|
416
|
-
const
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
454
|
+
const data = (0, utils_2.softDeleteData)();
|
|
455
|
+
let result;
|
|
456
|
+
let records;
|
|
457
|
+
if (softDelete) {
|
|
458
|
+
records = await (0, utils_2.softDeleteCascade)(tx, this._client.name, [id], data);
|
|
459
|
+
const updated = await txModel.update({ where: { id }, data });
|
|
460
|
+
result = { ...current, ...updated };
|
|
461
|
+
}
|
|
462
|
+
else {
|
|
463
|
+
records = await (0, utils_2.cascadedRecords)(tx, this._client.name, [id]);
|
|
464
|
+
result = await txModel.delete({
|
|
465
|
+
where: { id },
|
|
466
|
+
include: includeRelations
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
// Merged rather than spread, since a self cascade holds the same model
|
|
470
|
+
(0, utils_2.mergeAffectedRecords)(records, { [this._client.name]: [id] });
|
|
471
|
+
const removed = softDelete
|
|
472
|
+
? { soft: records, hard: {} }
|
|
473
|
+
: { soft: {}, hard: records };
|
|
474
|
+
await (0, utils_2.retainDeletedFiles)(tx, removed, data);
|
|
475
|
+
return [result, removed];
|
|
421
476
|
});
|
|
422
477
|
}
|
|
423
478
|
catch (e) {
|
|
@@ -426,7 +481,7 @@ class ResourceService {
|
|
|
426
481
|
}
|
|
427
482
|
throw new errors_1.HttpError(`${this._client.name} delete error`, 500, e);
|
|
428
483
|
}
|
|
429
|
-
await this.
|
|
484
|
+
await this.cleanupDeletedRecords(deleted);
|
|
430
485
|
this._events.emitResourceEvent(this._client.name, 'delete', {
|
|
431
486
|
current: resource
|
|
432
487
|
});
|
|
@@ -541,7 +596,7 @@ class ResourceService {
|
|
|
541
596
|
* and the `_count` property removed.
|
|
542
597
|
*/
|
|
543
598
|
projectResource(resource) {
|
|
544
|
-
const projectedResource = (0, utils_1.projectVirtualFields)(resource, this._client.name);
|
|
599
|
+
const projectedResource = (0, utils_1.projectVirtualFields)((0, utils_2.hideDeletedRelations)(resource, this._client.name), this._client.name);
|
|
545
600
|
if (!(0, common_1.isPlainObject)(projectedResource['_count'])) {
|
|
546
601
|
return projectedResource;
|
|
547
602
|
}
|
|
@@ -552,6 +607,38 @@ class ResourceService {
|
|
|
552
607
|
delete projectedResource['_count'];
|
|
553
608
|
return projectedResource;
|
|
554
609
|
}
|
|
610
|
+
/**
|
|
611
|
+
* Lists the conditions hiding the soft deleted resources from a query. It is
|
|
612
|
+
* empty for a model that deletes its records, so its query and the cursors
|
|
613
|
+
* bound to it stay the same.
|
|
614
|
+
*
|
|
615
|
+
* @returns {Object[]} The `deletedAt: null` condition, or no condition.
|
|
616
|
+
*/
|
|
617
|
+
liveFilters() {
|
|
618
|
+
const liveFilter = (0, utils_1.liveRecordFilter)(this._client.name);
|
|
619
|
+
return Object.keys(liveFilter).length > 0 ? [liveFilter] : [];
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* Cleans up after records were deleted, once the deleting transaction
|
|
623
|
+
* commits: removes the stored files their fields do not keep, since the
|
|
624
|
+
* storage cannot take part in the transaction, and invalidates the cache of
|
|
625
|
+
* every model they belong to.
|
|
626
|
+
*
|
|
627
|
+
* @param {DeletedRecords} deleted The soft deleted and the removed records.
|
|
628
|
+
*/
|
|
629
|
+
async cleanupDeletedRecords(deleted) {
|
|
630
|
+
const fileService = (0, context_1.inject)(storage_1.FileService, false);
|
|
631
|
+
const groups = [
|
|
632
|
+
[true, deleted.soft],
|
|
633
|
+
[false, deleted.hard]
|
|
634
|
+
];
|
|
635
|
+
for (const [softDeleted, records] of groups) {
|
|
636
|
+
for (const [modelName, ids] of Object.entries(records)) {
|
|
637
|
+
await fileService?.deleteResourcesFiles(modelName, ids, softDeleted);
|
|
638
|
+
await this._cacheService.invalidateCache(modelName, 'delete');
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
555
642
|
/**
|
|
556
643
|
* Prepares a write payload for the database by removing the virtual fields
|
|
557
644
|
* that have no column, filling in default values for the hidden required
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { ResourceId } from '@appweaver/common';
|
|
2
|
+
import type { RelationActions } from './relation-util';
|
|
3
|
+
/** The records of every model affected by a delete, keyed by model name. */
|
|
4
|
+
export type AffectedRecords = Record<string, ResourceId[]>;
|
|
5
|
+
/** The records deleted by one action, split by how they were deleted. */
|
|
6
|
+
export type DeletedRecords = {
|
|
7
|
+
/** Records marked with the soft delete columns */
|
|
8
|
+
soft: AffectedRecords;
|
|
9
|
+
/** Records removed from the database */
|
|
10
|
+
hard: AffectedRecords;
|
|
11
|
+
};
|
|
12
|
+
/** The columns marking a record as soft deleted. */
|
|
13
|
+
export type SoftDeleteData = {
|
|
14
|
+
deletedAt: Date;
|
|
15
|
+
deletedById?: ResourceId | null;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Restricts a mapped relation filter to the related records that are not soft deleted, so a filter never matches
|
|
19
|
+
* through a deleted record, and a null check treats a deleted related record as missing.
|
|
20
|
+
*
|
|
21
|
+
* @param {*} condition - The mapped database condition of the relation field.
|
|
22
|
+
* @param {string} resourceName - The name of the related model.
|
|
23
|
+
* @param {boolean} isArrayType - Whether the relation is a list (to-many) relation.
|
|
24
|
+
* @return {*} The condition restricted to the live related records, or unchanged if the related model does not soft
|
|
25
|
+
* delete its records.
|
|
26
|
+
*/
|
|
27
|
+
export declare function liveRelationFilter(condition: any, resourceName: string, isArrayType: boolean): any;
|
|
28
|
+
/**
|
|
29
|
+
* Builds the inclusion filter of a list relation, so only the related records that are not soft deleted are read.
|
|
30
|
+
*
|
|
31
|
+
* @param {string} [resourceName] - The name of the related model.
|
|
32
|
+
* @return {Object|undefined} The `where` clause of the inclusion, or undefined if the related model does not soft
|
|
33
|
+
* delete its records.
|
|
34
|
+
*/
|
|
35
|
+
export declare function liveInclusionFilter(resourceName?: string): {
|
|
36
|
+
where: Record<string, any>;
|
|
37
|
+
} | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Replaces the soft deleted records in the single relations of a resource with null, recursively. Unlike the list
|
|
40
|
+
* relations, a single relation cannot be filtered when it is read.
|
|
41
|
+
*
|
|
42
|
+
* @param {Object} resource - The resource as returned by the database client.
|
|
43
|
+
* @param {string} resourceName - The name of the model describing the resource.
|
|
44
|
+
* @return {Object} A copy of the resource without the soft deleted related records, or the resource itself if it
|
|
45
|
+
* holds no relations.
|
|
46
|
+
*/
|
|
47
|
+
export declare function hideDeletedRelations<T>(resource: T, resourceName: string): T;
|
|
48
|
+
/**
|
|
49
|
+
* Builds the column values marking a record as soft deleted now by the current user, who is only recorded when the
|
|
50
|
+
* application defines an auth model.
|
|
51
|
+
*
|
|
52
|
+
* @return {SoftDeleteData} The soft delete column values.
|
|
53
|
+
*/
|
|
54
|
+
export declare function softDeleteData(): SoftDeleteData;
|
|
55
|
+
/**
|
|
56
|
+
* Mirrors the referential actions of a database delete for soft deleted records: cascading records are soft deleted
|
|
57
|
+
* with the same column values, level by level, a restricting relation aborts the delete, and references set to null on
|
|
58
|
+
* delete are kept for a manual restore. The records themselves are not updated.
|
|
59
|
+
*
|
|
60
|
+
* @param {Object} tx - The transaction client the delete runs in.
|
|
61
|
+
* @param {string} resourceName - The name of the model of the deleted records.
|
|
62
|
+
* @param {ResourceId[]} ids - The ids of the deleted records.
|
|
63
|
+
* @param {SoftDeleteData} data - The soft delete column values applied to the cascaded records.
|
|
64
|
+
* @return {Promise<AffectedRecords>} The ids of the soft deleted records per model, excluding the records themselves.
|
|
65
|
+
* @throws {HttpError} 409 if a live record references a deleted record through a restricting relation.
|
|
66
|
+
*/
|
|
67
|
+
export declare function softDeleteCascade(tx: any, resourceName: string, ids: ResourceId[], data: SoftDeleteData): Promise<AffectedRecords>;
|
|
68
|
+
/**
|
|
69
|
+
* Collects the records the database cascade removes together with deleted records, so their files and caches can be
|
|
70
|
+
* cleaned up once the delete commits.
|
|
71
|
+
*
|
|
72
|
+
* @param {Object} tx - The transaction client the delete runs in.
|
|
73
|
+
* @param {string} resourceName - The name of the model of the deleted records.
|
|
74
|
+
* @param {ResourceId[]} ids - The ids of the deleted records.
|
|
75
|
+
* @return {Promise<AffectedRecords>} The ids of the cascaded records per model, excluding the records themselves.
|
|
76
|
+
*/
|
|
77
|
+
export declare function cascadedRecords(tx: any, resourceName: string, ids: ResourceId[]): Promise<AffectedRecords>;
|
|
78
|
+
/**
|
|
79
|
+
* Removes the orphans an update maps to a nested `delete` action (`orphanRemoval`). Orphans of a soft deleted model are
|
|
80
|
+
* soft deleted with their cascade and keep their references, so their `delete` action is dropped; the others are left
|
|
81
|
+
* to the `delete` action, collecting the records its cascade removes.
|
|
82
|
+
*
|
|
83
|
+
* @param {Object} tx - The transaction client the update runs in.
|
|
84
|
+
* @param {string} resourceName - The name of the model the relation actions belong to.
|
|
85
|
+
* @param {RelationActions} relationActions - The mapped relation write actions, from which the nested `delete` actions
|
|
86
|
+
* of the soft deleted orphans are removed.
|
|
87
|
+
* @param {SoftDeleteData} data - The soft delete column values applied to the soft deleted orphans.
|
|
88
|
+
* @return {Promise<DeletedRecords>} The ids of the soft deleted and the removed records per model.
|
|
89
|
+
* @throws {HttpError} 409 if a live record references a soft deleted orphan through a restricting relation.
|
|
90
|
+
*/
|
|
91
|
+
export declare function removeOrphans(tx: any, resourceName: string, relationActions: RelationActions, data: SoftDeleteData): Promise<DeletedRecords>;
|
|
92
|
+
/**
|
|
93
|
+
* Marks the file rows of the files the deleted records keep (`onResourceDeleted` / `onResourceSoftDeleted: 'keep'`) as
|
|
94
|
+
* deleted with the values of the delete, so they stay stored, e.g. for audit, but are no longer served.
|
|
95
|
+
*
|
|
96
|
+
* @param {Object} tx - The transaction client the delete runs in.
|
|
97
|
+
* @param {DeletedRecords} deleted - The soft deleted and the removed records.
|
|
98
|
+
* @param {SoftDeleteData} data - The soft delete column values of the delete.
|
|
99
|
+
* @return {Promise<void>} Resolves when the kept files are marked deleted.
|
|
100
|
+
*/
|
|
101
|
+
export declare function retainDeletedFiles(tx: any, deleted: DeletedRecords, data: SoftDeleteData): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Merges the affected records of several deletes into the target, keeping the ids of every model unique.
|
|
104
|
+
*
|
|
105
|
+
* @param {AffectedRecords} target - The affected records merged into.
|
|
106
|
+
* @param {AffectedRecords[]} sources - The affected records to add.
|
|
107
|
+
* @return {AffectedRecords} The target holding the ids of every source.
|
|
108
|
+
*/
|
|
109
|
+
export declare function mergeAffectedRecords(target: AffectedRecords, ...sources: AffectedRecords[]): AffectedRecords;
|
|
110
|
+
/**
|
|
111
|
+
* Rejects the relation write actions pointing at soft deleted records, which the database would otherwise connect or
|
|
112
|
+
* update, since it does not know the record is deleted.
|
|
113
|
+
*
|
|
114
|
+
* @param {Object} client - The database client, or the transaction client the write runs in.
|
|
115
|
+
* @param {string} resourceName - The name of the model the relation actions belong to.
|
|
116
|
+
* @param {RelationActions} relationActions - The mapped relation write actions.
|
|
117
|
+
* @return {Promise<void>} Resolves when no action points at a soft deleted record.
|
|
118
|
+
* @throws {HttpError} 400 if a connect, update or connect-or-create action matches a soft deleted record.
|
|
119
|
+
*/
|
|
120
|
+
export declare function assertLiveRelationTargets(client: any, resourceName: string, relationActions: RelationActions): Promise<void>;
|