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.
@@ -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>): Promise<UpdatedAttributes<T>>;
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,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAChE,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;;;;;;;;;;;;;OAaG;IACU,GAAG,CACd,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,aAAa,CAAC,UAAU,CAAC,GACpC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;cA6ChB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIlD;;;;OAIG;IACH,OAAO,CAAC,uCAAuC;IAY/C;;;;OAIG;IACH,OAAO,CAAC,sCAAsC;IAgC9C;;;;;;;;;;;;;;;OAeG;YACW,QAAQ;IAsDtB;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB;IA4B7B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,mBAAmB;IAY3B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,0BAA0B;IAyBlC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,0BAA0B;IAuDlC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,iCAAiC;IAuBzC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,8BAA8B;IA+BtC;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;IAkBlC;;;;;OAKG;IACH,OAAO,CAAC,mCAAmC;IAsB3C;;;;;;;;OAQG;IACH,OAAO,CAAC,sCAAsC;IAqC9C;;;;;;;;;;OAUG;IACH,OAAO,CAAC,6BAA6B;IAuCrC;;;;;;;OAOG;IACH,OAAO,CAAC,4BAA4B;IA6BpC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,6BAA6B;IAwBrC;;;;;;OAMG;IACH,OAAO,CAAC,gCAAgC;IAgBxC;;;OAGG;IACH,OAAO,CAAC,iCAAiC;CAU1C;AAED,eAAe,MAAM,CAAC"}
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
- this.buildEntityExistsCondition(relMeta, foreignKey);
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>): Promise<void>;
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;AAqBF;;;;;;;;;;;;;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;;;;;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;IAyBhB;;;;;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;;;;;;;;OAQG;IACH,OAAO,CAAC,MAAM,CAAC,qBAAqB;IA2CpC;;;;;;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"}
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
- transactionBuilder.addConditionCheck({
109
- TableName: tableName,
110
- Key: this.buildForeignEntityKey(tableProps, parentEntity, linkedEntityId),
111
- ConditionExpression: `attribute_exists(${partitionKeyAlias})`
112
- }, `${parentEntity.name} with ID ${linkedEntityId} does not exist`);
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dyna-record",
3
- "version": "0.4.0",
3
+ "version": "0.4.6",
4
4
  "description": "Typescript Data Modeler and ORM for Dynamo",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",