dyna-record 0.4.0 → 0.4.6
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/README.md +44 -0
- package/dist/src/DynaRecord.d.ts +54 -7
- package/dist/src/DynaRecord.d.ts.map +1 -1
- package/dist/src/DynaRecord.js +54 -10
- package/dist/src/metadata/MetadataStorage.d.ts +7 -1
- package/dist/src/metadata/MetadataStorage.d.ts.map +1 -1
- package/dist/src/metadata/MetadataStorage.js +15 -0
- package/dist/src/metadata/TableMetadata.d.ts +9 -1
- package/dist/src/metadata/TableMetadata.d.ts.map +1 -1
- package/dist/src/metadata/TableMetadata.js +13 -0
- package/dist/src/metadata/schemas.d.ts +432 -0
- package/dist/src/metadata/schemas.d.ts.map +1 -0
- package/dist/src/metadata/schemas.js +121 -0
- package/dist/src/operations/Create/Create.d.ts +7 -3
- package/dist/src/operations/Create/Create.d.ts.map +1 -1
- package/dist/src/operations/Create/Create.js +17 -7
- package/dist/src/operations/Create/types.d.ts +12 -0
- package/dist/src/operations/Create/types.d.ts.map +1 -1
- package/dist/src/operations/Update/Update.d.ts +11 -2
- package/dist/src/operations/Update/Update.d.ts.map +1 -1
- package/dist/src/operations/Update/Update.js +26 -11
- package/dist/src/operations/Update/types.d.ts +12 -0
- package/dist/src/operations/Update/types.d.ts.map +1 -1
- package/dist/src/relationships/JoinTable.d.ts +17 -1
- package/dist/src/relationships/JoinTable.d.ts.map +1 -1
- package/dist/src/relationships/JoinTable.js +16 -9
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/operations/Create/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAExD;;GAEG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,UAAU,IAAI,uBAAuB,CAAC,CAAC,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/operations/Create/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,UAAU,IAAI,uBAAuB,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type DynaRecord from "../../DynaRecord";
|
|
2
2
|
import { TransactWriteBuilder } from "../../dynamo-utils";
|
|
3
3
|
import OperationBase from "../OperationBase";
|
|
4
|
-
import type { UpdatedAttributes, UpdateOptions } from "./types";
|
|
4
|
+
import type { UpdatedAttributes, UpdateOptions, UpdateOperationOptions } from "./types";
|
|
5
5
|
import type { EntityClass } from "../../types";
|
|
6
6
|
/**
|
|
7
7
|
* Represents an update operation for a DynaRecord-backed entity, handling both attribute updates and relationship consistency via denormalization.
|
|
@@ -35,10 +35,11 @@ declare class Update<T extends DynaRecord> extends OperationBase<T> {
|
|
|
35
35
|
*
|
|
36
36
|
* @param id - The unique identifier of the entity being updated.
|
|
37
37
|
* @param attributes - Partial set of entity attributes to update. Must be defined on the entity's model.
|
|
38
|
+
* @param options - Optional operation options including referentialIntegrityCheck flag.
|
|
38
39
|
* @returns A promise that resolves to the set of updated attributes as applied to the entity.
|
|
39
40
|
* @throws If the entity does not exist, an error is thrown.
|
|
40
41
|
*/
|
|
41
|
-
run(id: string, attributes: UpdateOptions<DynaRecord
|
|
42
|
+
run(id: string, attributes: UpdateOptions<DynaRecord>, options?: UpdateOperationOptions): Promise<UpdatedAttributes<T>>;
|
|
42
43
|
protected commitTransaction(): Promise<void>;
|
|
43
44
|
/**
|
|
44
45
|
* BelongsToRelationship meta data and foreign key value pair for foreign keys being updated
|
|
@@ -50,6 +51,8 @@ declare class Update<T extends DynaRecord> extends OperationBase<T> {
|
|
|
50
51
|
* Adds condition checks for standalone foreign keys present in the update payload to ensure the referenced records exist.
|
|
51
52
|
*
|
|
52
53
|
* @param attributes - Partial entity attributes supplied to the update call.
|
|
54
|
+
* @param referentialIntegrityCheck - Whether to perform referential integrity checks.
|
|
55
|
+
* @private
|
|
53
56
|
*/
|
|
54
57
|
private addStandaloneForeignKeyConditionChecks;
|
|
55
58
|
/**
|
|
@@ -114,6 +117,8 @@ declare class Update<T extends DynaRecord> extends OperationBase<T> {
|
|
|
114
117
|
* @param entityPreUpdate - The state of the entity before the update.
|
|
115
118
|
* @param updatedEntity - The entity state after proposed updates (partial attributes).
|
|
116
119
|
* @param updateExpression - The DynamoDB update expression representing the attribute updates.
|
|
120
|
+
* @param newBelongsToEntityLookup - Lookup of new belongs-to entities.
|
|
121
|
+
* @param referentialIntegrityCheck - Whether to perform referential integrity checks.
|
|
117
122
|
* @private
|
|
118
123
|
*/
|
|
119
124
|
private buildBelongsToTransactions;
|
|
@@ -141,6 +146,8 @@ declare class Update<T extends DynaRecord> extends OperationBase<T> {
|
|
|
141
146
|
* @param newBelongsToEntityLookup
|
|
142
147
|
* @param persistToSelfCondition
|
|
143
148
|
* @param persistToSelfConditionErrMessage
|
|
149
|
+
* @param referentialIntegrityCheck - Whether to perform referential integrity checks.
|
|
150
|
+
* @private
|
|
144
151
|
*/
|
|
145
152
|
private buildPutBelongsToLinkedRecords;
|
|
146
153
|
/**
|
|
@@ -185,6 +192,8 @@ declare class Update<T extends DynaRecord> extends OperationBase<T> {
|
|
|
185
192
|
* @param newForeignKey
|
|
186
193
|
* @param oldForeignKey
|
|
187
194
|
* @param newBelongsToEntityLookup
|
|
195
|
+
* @param referentialIntegrityCheck - Whether to perform referential integrity checks.
|
|
196
|
+
* @private
|
|
188
197
|
*/
|
|
189
198
|
private updateForeignKeyTransactions;
|
|
190
199
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Update.d.ts","sourceRoot":"","sources":["../../../../src/operations/Update/Update.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAGL,oBAAoB,EACrB,MAAM,oBAAoB,CAAC;AAmB5B,OAAO,aAAa,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"Update.d.ts","sourceRoot":"","sources":["../../../../src/operations/Update/Update.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAGL,oBAAoB,EACrB,MAAM,oBAAoB,CAAC;AAmB5B,OAAO,aAAa,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EACV,iBAAiB,EACjB,aAAa,EACb,sBAAsB,EACvB,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAmB,WAAW,EAAgB,MAAM,aAAa,CAAC;AA4D9E;;;;;;;;;;;;;;;;;GAiBG;AACH,cAAM,MAAM,CAAC,CAAC,SAAS,UAAU,CAAE,SAAQ,aAAa,CAAC,CAAC,CAAC;IACzD,SAAS,CAAC,QAAQ,CAAC,kBAAkB,EAAE,oBAAoB,CAAC;gBAG1D,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EACtB,kBAAkB,CAAC,EAAE,oBAAoB;IAO3C;;;;;;;;;;;;;;OAcG;IACU,GAAG,CACd,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,aAAa,CAAC,UAAU,CAAC,EACrC,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;cAoDhB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIlD;;;;OAIG;IACH,OAAO,CAAC,uCAAuC;IAY/C;;;;;;OAMG;IACH,OAAO,CAAC,sCAAsC;IAoC9C;;;;;;;;;;;;;;;OAeG;YACW,QAAQ;IAsDtB;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB;IA4B7B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,mBAAmB;IAY3B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,0BAA0B;IAyBlC;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,0BAA0B;IA0DlC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,iCAAiC;IAuBzC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,8BAA8B;IAkCtC;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;IAkBlC;;;;;OAKG;IACH,OAAO,CAAC,mCAAmC;IAsB3C;;;;;;;;OAQG;IACH,OAAO,CAAC,sCAAsC;IAqC9C;;;;;;;;;;OAUG;IACH,OAAO,CAAC,6BAA6B;IAuCrC;;;;;;;;;OASG;IACH,OAAO,CAAC,4BAA4B;IAgCpC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,6BAA6B;IAwBrC;;;;;;OAMG;IACH,OAAO,CAAC,gCAAgC;IAgBxC;;;OAGG;IACH,OAAO,CAAC,iCAAiC;CAU1C;AAED,eAAe,MAAM,CAAC"}
|
|
@@ -46,15 +46,17 @@ class Update extends OperationBase_1.default {
|
|
|
46
46
|
*
|
|
47
47
|
* @param id - The unique identifier of the entity being updated.
|
|
48
48
|
* @param attributes - Partial set of entity attributes to update. Must be defined on the entity's model.
|
|
49
|
+
* @param options - Optional operation options including referentialIntegrityCheck flag.
|
|
49
50
|
* @returns A promise that resolves to the set of updated attributes as applied to the entity.
|
|
50
51
|
* @throws If the entity does not exist, an error is thrown.
|
|
51
52
|
*/
|
|
52
|
-
async run(id, attributes) {
|
|
53
|
+
async run(id, attributes, options) {
|
|
54
|
+
const referentialIntegrityCheck = options?.referentialIntegrityCheck ?? true;
|
|
53
55
|
const entityMeta = metadata_1.default.getEntity(this.EntityClass.name);
|
|
54
56
|
const entityAttrs = entityMeta.parseRawEntityDefinedAttributesPartial(attributes);
|
|
55
57
|
const { updatedAttrs, expression } = this.buildUpdateMetadata(entityAttrs);
|
|
56
58
|
this.buildUpdateItemTransaction(id, expression);
|
|
57
|
-
this.addStandaloneForeignKeyConditionChecks(entityAttrs);
|
|
59
|
+
this.addStandaloneForeignKeyConditionChecks(entityAttrs, referentialIntegrityCheck);
|
|
58
60
|
// Only need to prefetch if the entity has relationships
|
|
59
61
|
if (entityMeta.allRelationships.length > 0) {
|
|
60
62
|
const belongsToRelMetaBeingUpdated = this.getBelongsToRelMetaAndKeyForUpdatedKeys(entityAttrs);
|
|
@@ -66,7 +68,7 @@ class Update extends OperationBase_1.default {
|
|
|
66
68
|
id
|
|
67
69
|
};
|
|
68
70
|
this.buildUpdateRelatedEntityLinks(id, preFetch.relatedEntities, expression);
|
|
69
|
-
this.buildBelongsToTransactions(preFetch.entityPreUpdate, updatedEntity, expression, preFetch.newBelongsToEntityLookup);
|
|
71
|
+
this.buildBelongsToTransactions(preFetch.entityPreUpdate, updatedEntity, expression, preFetch.newBelongsToEntityLookup, referentialIntegrityCheck);
|
|
70
72
|
}
|
|
71
73
|
await this.commitTransaction();
|
|
72
74
|
return updatedAttrs;
|
|
@@ -91,8 +93,13 @@ class Update extends OperationBase_1.default {
|
|
|
91
93
|
* Adds condition checks for standalone foreign keys present in the update payload to ensure the referenced records exist.
|
|
92
94
|
*
|
|
93
95
|
* @param attributes - Partial entity attributes supplied to the update call.
|
|
96
|
+
* @param referentialIntegrityCheck - Whether to perform referential integrity checks.
|
|
97
|
+
* @private
|
|
94
98
|
*/
|
|
95
|
-
addStandaloneForeignKeyConditionChecks(attributes) {
|
|
99
|
+
addStandaloneForeignKeyConditionChecks(attributes, referentialIntegrityCheck) {
|
|
100
|
+
if (!referentialIntegrityCheck) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
96
103
|
const standaloneForeignKeys = this.entityMetadata.standaloneForeignKeyAttributes;
|
|
97
104
|
for (const attrMeta of standaloneForeignKeys) {
|
|
98
105
|
const target = attrMeta.foreignKeyTarget;
|
|
@@ -258,9 +265,11 @@ class Update extends OperationBase_1.default {
|
|
|
258
265
|
* @param entityPreUpdate - The state of the entity before the update.
|
|
259
266
|
* @param updatedEntity - The entity state after proposed updates (partial attributes).
|
|
260
267
|
* @param updateExpression - The DynamoDB update expression representing the attribute updates.
|
|
268
|
+
* @param newBelongsToEntityLookup - Lookup of new belongs-to entities.
|
|
269
|
+
* @param referentialIntegrityCheck - Whether to perform referential integrity checks.
|
|
261
270
|
* @private
|
|
262
271
|
*/
|
|
263
|
-
buildBelongsToTransactions(entityPreUpdate, updatedEntity, updateExpression, newBelongsToEntityLookup) {
|
|
272
|
+
buildBelongsToTransactions(entityPreUpdate, updatedEntity, updateExpression, newBelongsToEntityLookup, referentialIntegrityCheck) {
|
|
264
273
|
const entityId = entityPreUpdate.id;
|
|
265
274
|
const relMetas = this.entityMetadata.belongsToOrOwnedByRelationships;
|
|
266
275
|
for (const relMeta of relMetas) {
|
|
@@ -273,13 +282,13 @@ class Update extends OperationBase_1.default {
|
|
|
273
282
|
const isUpdatingForeignKey = oldFk !== undefined && oldFk !== foreignKey;
|
|
274
283
|
const isRemovingForeignKey = isUpdatingForeignKey && foreignKey === null;
|
|
275
284
|
if (isAddingForeignKey) {
|
|
276
|
-
this.buildPutBelongsToLinkedRecords(updatedEntity, relMeta, foreignKey, newBelongsToEntityLookup, "attribute_not_exists", `${this.EntityClass.name} already has an associated ${relMeta.target.name}
|
|
285
|
+
this.buildPutBelongsToLinkedRecords(updatedEntity, relMeta, foreignKey, newBelongsToEntityLookup, "attribute_not_exists", `${this.EntityClass.name} already has an associated ${relMeta.target.name}`, referentialIntegrityCheck);
|
|
277
286
|
}
|
|
278
287
|
else if (isRemovingForeignKey) {
|
|
279
288
|
this.removeForeignKeysTransactions(entityId, relMeta, oldFk);
|
|
280
289
|
}
|
|
281
290
|
else if (isUpdatingForeignKey) {
|
|
282
|
-
this.updateForeignKeyTransactions(updatedEntity, relMeta, foreignKey, oldFk, newBelongsToEntityLookup);
|
|
291
|
+
this.updateForeignKeyTransactions(updatedEntity, relMeta, foreignKey, oldFk, newBelongsToEntityLookup, referentialIntegrityCheck);
|
|
283
292
|
}
|
|
284
293
|
else if (foreignKey !== null) {
|
|
285
294
|
this.buildUpdateBelongsToLinkedRecords(entityId, relMeta, foreignKey, updateExpression);
|
|
@@ -320,10 +329,14 @@ class Update extends OperationBase_1.default {
|
|
|
320
329
|
* @param newBelongsToEntityLookup
|
|
321
330
|
* @param persistToSelfCondition
|
|
322
331
|
* @param persistToSelfConditionErrMessage
|
|
332
|
+
* @param referentialIntegrityCheck - Whether to perform referential integrity checks.
|
|
333
|
+
* @private
|
|
323
334
|
*/
|
|
324
|
-
buildPutBelongsToLinkedRecords(updatedEntity, relMeta, foreignKey, newBelongsToEntityLookup, persistToSelfCondition, persistToSelfConditionErrMessage) {
|
|
335
|
+
buildPutBelongsToLinkedRecords(updatedEntity, relMeta, foreignKey, newBelongsToEntityLookup, persistToSelfCondition, persistToSelfConditionErrMessage, referentialIntegrityCheck = true) {
|
|
325
336
|
// Ensure that the new foreign key is valid and exists
|
|
326
|
-
|
|
337
|
+
if (referentialIntegrityCheck) {
|
|
338
|
+
this.buildEntityExistsCondition(relMeta, foreignKey);
|
|
339
|
+
}
|
|
327
340
|
// Denormalize entity being updated to foreign partition
|
|
328
341
|
this.buildLinkToForeignEntityTransaction(updatedEntity, relMeta, foreignKey);
|
|
329
342
|
if ((0, utils_3.isBelongsToRelationship)(relMeta)) {
|
|
@@ -426,15 +439,17 @@ class Update extends OperationBase_1.default {
|
|
|
426
439
|
* @param newForeignKey
|
|
427
440
|
* @param oldForeignKey
|
|
428
441
|
* @param newBelongsToEntityLookup
|
|
442
|
+
* @param referentialIntegrityCheck - Whether to perform referential integrity checks.
|
|
443
|
+
* @private
|
|
429
444
|
*/
|
|
430
|
-
updateForeignKeyTransactions(updatedEntity, relMeta, newForeignKey, oldForeignKey, newBelongsToEntityLookup) {
|
|
445
|
+
updateForeignKeyTransactions(updatedEntity, relMeta, newForeignKey, oldForeignKey, newBelongsToEntityLookup, referentialIntegrityCheck) {
|
|
431
446
|
// Keys to delete the linked record from the foreign entities partition
|
|
432
447
|
const oldKeysToForeignEntity = (0, utils_2.buildBelongsToLinkKey)(this.EntityClass, updatedEntity.id, relMeta, oldForeignKey);
|
|
433
448
|
this.transactionBuilder.addDelete({
|
|
434
449
|
TableName: this.tableMetadata.name,
|
|
435
450
|
Key: oldKeysToForeignEntity
|
|
436
451
|
});
|
|
437
|
-
this.buildPutBelongsToLinkedRecords(updatedEntity, relMeta, newForeignKey, newBelongsToEntityLookup, "attribute_exists");
|
|
452
|
+
this.buildPutBelongsToLinkedRecords(updatedEntity, relMeta, newForeignKey, newBelongsToEntityLookup, "attribute_exists", undefined, referentialIntegrityCheck);
|
|
438
453
|
}
|
|
439
454
|
/**
|
|
440
455
|
* Builds transactions to update all related entities that exist in the main entity's partition, applying the same attribute updates.
|
|
@@ -28,6 +28,18 @@ type AllowNullForNullable<T> = {
|
|
|
28
28
|
* })
|
|
29
29
|
*/
|
|
30
30
|
export type UpdateOptions<T extends DynaRecord> = Partial<AllowNullForNullable<EntityDefinedAttributes<T>>>;
|
|
31
|
+
/**
|
|
32
|
+
* Options for update operations
|
|
33
|
+
*/
|
|
34
|
+
export interface UpdateOperationOptions {
|
|
35
|
+
/**
|
|
36
|
+
* Whether to perform referential integrity checks for foreign key references.
|
|
37
|
+
* When `true` (default), condition checks are added to verify that referenced entities exist.
|
|
38
|
+
* When `false`, these condition checks are skipped, allowing updates even if foreign key references don't exist.
|
|
39
|
+
* @default true
|
|
40
|
+
*/
|
|
41
|
+
referentialIntegrityCheck?: boolean;
|
|
42
|
+
}
|
|
31
43
|
/**
|
|
32
44
|
* Attributes of an entity that were updated. Including the auto generated updatedAt date
|
|
33
45
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/operations/Update/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAExD;;;;;GAKG;AACH,KAAK,kBAAkB,CAAC,CAAC,IAAI;KAC1B,CAAC,IAAI,MAAM,CAAC,GAAG,SAAS,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK;CACnD,CAAC,MAAM,CAAC,CAAC,CAAC;AAEX;;;;;GAKG;AACH,KAAK,oBAAoB,CAAC,CAAC,IAAI;KAC5B,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,SAAS,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;CACrE,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,UAAU,IAAI,OAAO,CACvD,oBAAoB,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CACjD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,UAAU,IAAI,IAAI,CACxD,OAAO,CAAC,CAAC,CAAC,EACV,WAAW,CACZ,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/operations/Update/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAExD;;;;;GAKG;AACH,KAAK,kBAAkB,CAAC,CAAC,IAAI;KAC1B,CAAC,IAAI,MAAM,CAAC,GAAG,SAAS,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK;CACnD,CAAC,MAAM,CAAC,CAAC,CAAC;AAEX;;;;;GAKG;AACH,KAAK,oBAAoB,CAAC,CAAC,IAAI;KAC5B,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,SAAS,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;CACrE,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,UAAU,IAAI,OAAO,CACvD,oBAAoB,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CACjD,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,UAAU,IAAI,IAAI,CACxD,OAAO,CAAC,CAAC,CAAC,EACV,WAAW,CACZ,CAAC"}
|
|
@@ -10,6 +10,18 @@ type ExcludeKeys = "type1" | "type2";
|
|
|
10
10
|
type ForeignKeyProperties<T> = {
|
|
11
11
|
[P in Exclude<keyof T, ExcludeKeys>]: T[P] extends ForeignKey ? string : never;
|
|
12
12
|
};
|
|
13
|
+
/**
|
|
14
|
+
* Options for JoinTable operations
|
|
15
|
+
*/
|
|
16
|
+
interface JoinTableOptions {
|
|
17
|
+
/**
|
|
18
|
+
* Whether to perform referential integrity checks for foreign key references.
|
|
19
|
+
* When `true` (default), condition checks are added to verify that referenced entities exist.
|
|
20
|
+
* When `false`, these condition checks are skipped, allowing updates even if foreign key references don't exist.
|
|
21
|
+
* @default true
|
|
22
|
+
*/
|
|
23
|
+
referentialIntegrityCheck?: boolean;
|
|
24
|
+
}
|
|
13
25
|
/**
|
|
14
26
|
* Abstract class representing a join table for HasAndBelongsToMany relationships.
|
|
15
27
|
* This class should be extended for specific join table implementations.
|
|
@@ -33,8 +45,9 @@ declare abstract class JoinTable<T extends DynaRecord, K extends DynaRecord> {
|
|
|
33
45
|
* Adds denormalized copy of the related entity to each associated Entity's partition
|
|
34
46
|
* @param this
|
|
35
47
|
* @param keys
|
|
48
|
+
* @param options - Optional operation options including referentialIntegrityCheck flag
|
|
36
49
|
*/
|
|
37
|
-
static create<ThisClass extends JoinTable<T, K>, T extends DynaRecord, K extends DynaRecord>(this: new (type1: EntityClass<T>, type2: EntityClass<K>) => ThisClass, keys: ForeignKeyProperties<ThisClass
|
|
50
|
+
static create<ThisClass extends JoinTable<T, K>, T extends DynaRecord, K extends DynaRecord>(this: new (type1: EntityClass<T>, type2: EntityClass<K>) => ThisClass, keys: ForeignKeyProperties<ThisClass>, options?: JoinTableOptions): Promise<void>;
|
|
38
51
|
/**
|
|
39
52
|
* Delete a JoinTable entry
|
|
40
53
|
* Deletes denormalized records from each associated Entity's partition
|
|
@@ -51,6 +64,9 @@ declare abstract class JoinTable<T extends DynaRecord, K extends DynaRecord> {
|
|
|
51
64
|
* @param keys
|
|
52
65
|
* @param parentEntityMeta
|
|
53
66
|
* @param linkedEntityMeta
|
|
67
|
+
* @param linkedRecord
|
|
68
|
+
* @param referentialIntegrityCheck - Whether to perform referential integrity checks.
|
|
69
|
+
* @private
|
|
54
70
|
*/
|
|
55
71
|
private static denormalizeLinkRecord;
|
|
56
72
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JoinTable.d.ts","sourceRoot":"","sources":["../../../src/relationships/JoinTable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,eAAe,CAAC;AAW5C,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAmB,MAAM,UAAU,CAAC;AAEzE;;GAEG;AACH,KAAK,WAAW,GAAG,OAAO,GAAG,OAAO,CAAC;AAOrC;;GAEG;AACH,KAAK,oBAAoB,CAAC,CAAC,IAAI;KAC5B,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,UAAU,GACzD,MAAM,GACN,KAAK;CACV,CAAC;
|
|
1
|
+
{"version":3,"file":"JoinTable.d.ts","sourceRoot":"","sources":["../../../src/relationships/JoinTable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,eAAe,CAAC;AAW5C,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAmB,MAAM,UAAU,CAAC;AAEzE;;GAEG;AACH,KAAK,WAAW,GAAG,OAAO,GAAG,OAAO,CAAC;AAOrC;;GAEG;AACH,KAAK,oBAAoB,CAAC,CAAC,IAAI;KAC5B,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,UAAU,GACzD,MAAM,GACN,KAAK;CACV,CAAC;AAYF;;GAEG;AACH,UAAU,gBAAgB;IACxB;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;AAWD;;;;;;;;;;;;;GAaG;AACH,uBAAe,SAAS,CAAC,CAAC,SAAS,UAAU,EAAE,CAAC,SAAS,UAAU;IAE/D,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK;gBADL,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,EACrB,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC;IAGxC;;;;;;OAMG;WACiB,MAAM,CACxB,SAAS,SAAS,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EACjC,CAAC,SAAS,UAAU,EACpB,CAAC,SAAS,UAAU,EAEpB,IAAI,EAAE,KAAK,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,SAAS,EACrE,IAAI,EAAE,oBAAoB,CAAC,SAAS,CAAC,EACrC,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,IAAI,CAAC;IA6BhB;;;;;OAKG;WACiB,MAAM,CACxB,SAAS,SAAS,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EACjC,CAAC,SAAS,UAAU,EACpB,CAAC,SAAS,UAAU,EAEpB,IAAI,EAAE,KAAK,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,SAAS,EACrE,IAAI,EAAE,oBAAoB,CAAC,SAAS,CAAC,GACpC,OAAO,CAAC,IAAI,CAAC;mBAWK,QAAQ;IAmD7B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,MAAM,CAAC,qBAAqB;IA8CpC;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAcpC;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM,CAAC,UAAU;IA0BzB,OAAO,CAAC,MAAM,CAAC,YAAY;IAoB3B,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAoB/B,OAAO,CAAC,MAAM,CAAC,4BAA4B;CA6B5C;AAED,eAAe,SAAS,CAAC"}
|
|
@@ -33,14 +33,16 @@ class JoinTable {
|
|
|
33
33
|
* Adds denormalized copy of the related entity to each associated Entity's partition
|
|
34
34
|
* @param this
|
|
35
35
|
* @param keys
|
|
36
|
+
* @param options - Optional operation options including referentialIntegrityCheck flag
|
|
36
37
|
*/
|
|
37
|
-
static async create(keys) {
|
|
38
|
+
static async create(keys, options) {
|
|
39
|
+
const referentialIntegrityCheck = options?.referentialIntegrityCheck ?? true;
|
|
38
40
|
const transactionBuilder = new TransactWriteBuilder_1.default();
|
|
39
41
|
const [rel1, rel2] = metadata_1.default.getJoinTable(this.name);
|
|
40
42
|
const transactionProps = JoinTable.transactionProps(keys, rel2, rel1);
|
|
41
43
|
const lookupTableItem = await JoinTable.preFetch(transactionProps);
|
|
42
|
-
JoinTable.denormalizeLinkRecord(transactionBuilder, keys, rel1, rel2, lookupTableItem[transactionProps.ids.linkedEntityId]);
|
|
43
|
-
JoinTable.denormalizeLinkRecord(transactionBuilder, keys, rel2, rel1, lookupTableItem[transactionProps.ids.parentId]);
|
|
44
|
+
JoinTable.denormalizeLinkRecord(transactionBuilder, keys, rel1, rel2, lookupTableItem[transactionProps.ids.linkedEntityId], referentialIntegrityCheck);
|
|
45
|
+
JoinTable.denormalizeLinkRecord(transactionBuilder, keys, rel2, rel1, lookupTableItem[transactionProps.ids.parentId], referentialIntegrityCheck);
|
|
44
46
|
await transactionBuilder.executeTransaction();
|
|
45
47
|
}
|
|
46
48
|
/**
|
|
@@ -90,8 +92,11 @@ class JoinTable {
|
|
|
90
92
|
* @param keys
|
|
91
93
|
* @param parentEntityMeta
|
|
92
94
|
* @param linkedEntityMeta
|
|
95
|
+
* @param linkedRecord
|
|
96
|
+
* @param referentialIntegrityCheck - Whether to perform referential integrity checks.
|
|
97
|
+
* @private
|
|
93
98
|
*/
|
|
94
|
-
static denormalizeLinkRecord(transactionBuilder, keys, parentEntityMeta, linkedEntityMeta, linkedRecord) {
|
|
99
|
+
static denormalizeLinkRecord(transactionBuilder, keys, parentEntityMeta, linkedEntityMeta, linkedRecord, referentialIntegrityCheck) {
|
|
95
100
|
const { tableProps, entities, ids } = this.transactionProps(keys, parentEntityMeta, linkedEntityMeta);
|
|
96
101
|
const { name: tableName } = tableProps;
|
|
97
102
|
const { alias: partitionKeyAlias } = tableProps.partitionKeyAttribute;
|
|
@@ -105,11 +110,13 @@ class JoinTable {
|
|
|
105
110
|
},
|
|
106
111
|
ConditionExpression: `attribute_not_exists(${partitionKeyAlias})` // Ensure item doesn't already exist
|
|
107
112
|
}, `${parentEntity.name} with ID ${linkedEntityId} is already linked to ${linkedEntity.name} with ID ${parentId}`);
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
+
if (referentialIntegrityCheck) {
|
|
114
|
+
transactionBuilder.addConditionCheck({
|
|
115
|
+
TableName: tableName,
|
|
116
|
+
Key: this.buildForeignEntityKey(tableProps, parentEntity, linkedEntityId),
|
|
117
|
+
ConditionExpression: `attribute_exists(${partitionKeyAlias})`
|
|
118
|
+
}, `${parentEntity.name} with ID ${linkedEntityId} does not exist`);
|
|
119
|
+
}
|
|
113
120
|
}
|
|
114
121
|
/**
|
|
115
122
|
* Builds the key to the foreign entity
|