dyna-record 0.4.0 → 0.4.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/README.md +44 -0
- package/dist/src/DynaRecord.d.ts +39 -7
- package/dist/src/DynaRecord.d.ts.map +1 -1
- package/dist/src/DynaRecord.js +36 -10
- 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
package/README.md
CHANGED
|
@@ -357,6 +357,25 @@ const grade: Grade = await Grade.create({
|
|
|
357
357
|
});
|
|
358
358
|
```
|
|
359
359
|
|
|
360
|
+
#### Skipping Referential Integrity Checks
|
|
361
|
+
|
|
362
|
+
By default, when creating entities with foreign key references, dyna-record performs condition checks to ensure that referenced entities exist. This prevents creating entities with invalid foreign key references. However, in high-contention or high-throughput systems where the same foreign key may be referenced in parallel operations, these condition checks can fail due to transaction conflicts. In scenarios such as bulk imports or when you've already verified the references, you may want to skip these checks to prevent such failures.
|
|
363
|
+
|
|
364
|
+
To skip referential integrity checks, pass an options object as the second parameter with `referentialIntegrityCheck: false`:
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
const grade: Grade = await Grade.create(
|
|
368
|
+
{
|
|
369
|
+
gradeValue: "A+",
|
|
370
|
+
assignmentId: "123",
|
|
371
|
+
studentId: "456"
|
|
372
|
+
},
|
|
373
|
+
{ referentialIntegrityCheck: false }
|
|
374
|
+
);
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
**Note:** When `referentialIntegrityCheck` is set to `false`, the condition checks that verify foreign key references exist are skipped. This means you can create entities even if the referenced entities don't exist, which may lead to data integrity issues. Use this option with caution.
|
|
378
|
+
|
|
360
379
|
#### Error handling
|
|
361
380
|
|
|
362
381
|
The method is designed to throw errors under various conditions, such as transaction cancellation due to failed conditional checks. For instance, if you attempt to create a `Grade` for an `Assignment` that already has one, the method throws a [TransactionWriteFailedError](https://dyna-record.com/classes/TransactionWriteFailedError.html).
|
|
@@ -549,6 +568,31 @@ const updatedInstance = await petInstance.update({
|
|
|
549
568
|
});
|
|
550
569
|
```
|
|
551
570
|
|
|
571
|
+
#### Skipping Referential Integrity Checks
|
|
572
|
+
|
|
573
|
+
By default, when updating entities with foreign key references, dyna-record performs condition checks to ensure that referenced entities exist. This prevents updating entities with invalid foreign key references. However, in high-contention or high-throughput systems where the same foreign key may be referenced in parallel operations, these condition checks can fail due to transaction conflicts. In scenarios such as bulk updates or when you've already verified the references, you may want to skip these checks to prevent such failures.
|
|
574
|
+
|
|
575
|
+
To skip referential integrity checks, pass an options object as the third parameter with `referentialIntegrityCheck: false`:
|
|
576
|
+
|
|
577
|
+
```typescript
|
|
578
|
+
await PaymentMethod.update(
|
|
579
|
+
"123",
|
|
580
|
+
{ customerId: "456" },
|
|
581
|
+
{ referentialIntegrityCheck: false }
|
|
582
|
+
);
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
For instance methods:
|
|
586
|
+
|
|
587
|
+
```typescript
|
|
588
|
+
const updatedInstance = await paymentMethodInstance.update(
|
|
589
|
+
{ customerId: "456" },
|
|
590
|
+
{ referentialIntegrityCheck: false }
|
|
591
|
+
);
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
**Note:** When `referentialIntegrityCheck` is set to `false`, the condition checks that verify foreign key references exist are skipped. This means you can update entities even if the referenced entities don't exist, which may lead to data integrity issues. Use this option with caution.
|
|
595
|
+
|
|
552
596
|
### Delete
|
|
553
597
|
|
|
554
598
|
[Docs](https://dyna-record.com/classes/default.html#delete)
|
package/dist/src/DynaRecord.d.ts
CHANGED
|
@@ -181,24 +181,36 @@ declare abstract class DynaRecord implements DynaRecordBase {
|
|
|
181
181
|
*/
|
|
182
182
|
static query<T extends DynaRecord>(this: EntityClass<T>, key: IndexKeyConditions<T>, options: OptionsWithIndex): Promise<QueryResults<T>>;
|
|
183
183
|
/**
|
|
184
|
-
* Create an entity. If foreign keys are included in the attributes then links will be
|
|
184
|
+
* Create an entity. If foreign keys are included in the attributes then links will be denormalized accordingly
|
|
185
185
|
* @param attributes - Attributes of the model to create
|
|
186
|
+
* @param options - Optional operation options including referentialIntegrityCheck flag
|
|
186
187
|
* @returns The new Entity
|
|
187
188
|
*
|
|
189
|
+
* @example Basic usage
|
|
188
190
|
* ```typescript
|
|
189
191
|
* const newUser = await User.create({ name: "Alice", email: "alice@example.com", profileId: "123" });
|
|
190
192
|
* ```
|
|
193
|
+
*
|
|
194
|
+
* @example With referential integrity check disabled
|
|
195
|
+
* ```typescript
|
|
196
|
+
* const newUser = await User.create(
|
|
197
|
+
* { name: "Alice", email: "alice@example.com", profileId: "123" },
|
|
198
|
+
* { referentialIntegrityCheck: false }
|
|
199
|
+
* );
|
|
200
|
+
* ```
|
|
191
201
|
*/
|
|
192
|
-
static create<T extends DynaRecord>(this: EntityClass<T>, attributes: CreateOptions<T
|
|
202
|
+
static create<T extends DynaRecord>(this: EntityClass<T>, attributes: CreateOptions<T>, options?: {
|
|
203
|
+
referentialIntegrityCheck?: boolean;
|
|
204
|
+
}): Promise<ReturnType<Create<T>["run"]>>;
|
|
193
205
|
/**
|
|
194
|
-
* Update an entity. If foreign keys are included in the
|
|
206
|
+
* Update an entity. If foreign keys are included in the attributes then:
|
|
195
207
|
* - Manages associated relationship links as needed
|
|
196
208
|
* - If the entity already had a foreign key relationship, then denormalized records will be deleted from each partition
|
|
197
209
|
* - If the foreign key is not nullable then a {@link NullConstraintViolationError} is thrown.
|
|
198
210
|
* - Validation errors will be thrown if the attribute being removed is not nullable
|
|
199
211
|
* @param id - The id of the entity to update
|
|
200
212
|
* @param attributes - Attributes to update
|
|
201
|
-
*
|
|
213
|
+
* @param options - Optional operation options including referentialIntegrityCheck flag
|
|
202
214
|
*
|
|
203
215
|
* @example Updating an entity.
|
|
204
216
|
* ```typescript
|
|
@@ -209,12 +221,22 @@ declare abstract class DynaRecord implements DynaRecordBase {
|
|
|
209
221
|
* ```typescript
|
|
210
222
|
* await User.update("userId", { email: "newemail@example.com", someKey: null });
|
|
211
223
|
* ```
|
|
224
|
+
*
|
|
225
|
+
* @example With referential integrity check disabled
|
|
226
|
+
* ```typescript
|
|
227
|
+
* await User.update(
|
|
228
|
+
* "userId",
|
|
229
|
+
* { email: "newemail@example.com", profileId: 789 },
|
|
230
|
+
* { referentialIntegrityCheck: false }
|
|
231
|
+
* );
|
|
232
|
+
* ```
|
|
212
233
|
*/
|
|
213
|
-
static update<T extends DynaRecord>(this: EntityClass<T>, id: string, attributes: UpdateOptions<T
|
|
234
|
+
static update<T extends DynaRecord>(this: EntityClass<T>, id: string, attributes: UpdateOptions<T>, options?: {
|
|
235
|
+
referentialIntegrityCheck?: boolean;
|
|
236
|
+
}): Promise<void>;
|
|
214
237
|
/**
|
|
215
238
|
* Same as the static `update` method but on an instance. Returns the full updated instance
|
|
216
239
|
*
|
|
217
|
-
*
|
|
218
240
|
* @example Updating an entity.
|
|
219
241
|
* ```typescript
|
|
220
242
|
* const updatedInstance = await instance.update({ email: "newemail@example.com", profileId: 789 });
|
|
@@ -224,8 +246,18 @@ declare abstract class DynaRecord implements DynaRecordBase {
|
|
|
224
246
|
* ```typescript
|
|
225
247
|
* const updatedInstance = await instance.update({ email: "newemail@example.com", someKey: null });
|
|
226
248
|
* ```
|
|
249
|
+
*
|
|
250
|
+
* @example With referential integrity check disabled
|
|
251
|
+
* ```typescript
|
|
252
|
+
* const updatedInstance = await instance.update(
|
|
253
|
+
* { email: "newemail@example.com", profileId: 789 },
|
|
254
|
+
* { referentialIntegrityCheck: false }
|
|
255
|
+
* );
|
|
256
|
+
* ```
|
|
227
257
|
*/
|
|
228
|
-
update<T extends this>(attributes: UpdateOptions<T
|
|
258
|
+
update<T extends this>(attributes: UpdateOptions<T>, options?: {
|
|
259
|
+
referentialIntegrityCheck?: boolean;
|
|
260
|
+
}): Promise<EntityAttributesInstance<T>>;
|
|
229
261
|
/**
|
|
230
262
|
* Delete an entity by ID
|
|
231
263
|
* - Delete all denormalized records
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DynaRecord.d.ts","sourceRoot":"","sources":["../../src/DynaRecord.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,mBAAmB,EAExB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,MAAM,EACN,KAAK,aAAa,EAElB,KAAK,aAAa,EAGlB,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EAEtB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGtE,UAAU,cAAc;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,uBAAe,UAAW,YAAW,cAAc;IACjD;;OAEG;IACH,SACgB,EAAE,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,SACgB,IAAI,EAAE,MAAM,CAAC;IAE7B;;OAEG;IACH,SACgB,SAAS,EAAE,IAAI,CAAC;IAEhC;;OAEG;IACH,SACgB,SAAS,EAAE,IAAI,CAAC;IAEhC;;;;;;;;;;;;;;;;;;;;;;OAsBG;WAEiB,QAAQ,CAAC,CAAC,SAAS,UAAU,EAC/C,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EACpB,EAAE,EAAE,MAAM,EACV,OAAO,CAAC,EAAE,SAAS,GAClB,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,CAAC;WAG7B,QAAQ,CAC1B,CAAC,SAAS,UAAU,EACpB,GAAG,SAAS,oBAAoB,CAAC,CAAC,CAAC,GAAG,EAAE,EAExC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EACpB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,eAAe,CAAC,CAAC,EAAE,GAAG,CAAC,GAC/B,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAgBjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmCG;WACiB,KAAK,CAAC,CAAC,SAAS,UAAU,EAC5C,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EACpB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAE3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAqDG;WACiB,KAAK,CAAC,CAAC,SAAS,UAAU,EAC5C,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EACpB,GAAG,EAAE,mBAAmB,CAAC,CAAC,CAAC,EAC3B,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAE3B;;;;;;;;;;;;;;;OAeG;WACiB,KAAK,CAAC,CAAC,SAAS,UAAU,EAC5C,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EACpB,GAAG,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC1B,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAW3B
|
|
1
|
+
{"version":3,"file":"DynaRecord.d.ts","sourceRoot":"","sources":["../../src/DynaRecord.ts"],"names":[],"mappings":"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"}
|
package/dist/src/DynaRecord.js
CHANGED
|
@@ -145,27 +145,37 @@ let DynaRecord = (() => {
|
|
|
145
145
|
return await op.run(key, options);
|
|
146
146
|
}
|
|
147
147
|
/**
|
|
148
|
-
* Create an entity. If foreign keys are included in the attributes then links will be
|
|
148
|
+
* Create an entity. If foreign keys are included in the attributes then links will be denormalized accordingly
|
|
149
149
|
* @param attributes - Attributes of the model to create
|
|
150
|
+
* @param options - Optional operation options including referentialIntegrityCheck flag
|
|
150
151
|
* @returns The new Entity
|
|
151
152
|
*
|
|
153
|
+
* @example Basic usage
|
|
152
154
|
* ```typescript
|
|
153
155
|
* const newUser = await User.create({ name: "Alice", email: "alice@example.com", profileId: "123" });
|
|
154
156
|
* ```
|
|
157
|
+
*
|
|
158
|
+
* @example With referential integrity check disabled
|
|
159
|
+
* ```typescript
|
|
160
|
+
* const newUser = await User.create(
|
|
161
|
+
* { name: "Alice", email: "alice@example.com", profileId: "123" },
|
|
162
|
+
* { referentialIntegrityCheck: false }
|
|
163
|
+
* );
|
|
164
|
+
* ```
|
|
155
165
|
*/
|
|
156
|
-
static async create(attributes) {
|
|
166
|
+
static async create(attributes, options) {
|
|
157
167
|
const op = new operations_1.Create(this);
|
|
158
|
-
return await op.run(attributes);
|
|
168
|
+
return await op.run(attributes, options);
|
|
159
169
|
}
|
|
160
170
|
/**
|
|
161
|
-
* Update an entity. If foreign keys are included in the
|
|
171
|
+
* Update an entity. If foreign keys are included in the attributes then:
|
|
162
172
|
* - Manages associated relationship links as needed
|
|
163
173
|
* - If the entity already had a foreign key relationship, then denormalized records will be deleted from each partition
|
|
164
174
|
* - If the foreign key is not nullable then a {@link NullConstraintViolationError} is thrown.
|
|
165
175
|
* - Validation errors will be thrown if the attribute being removed is not nullable
|
|
166
176
|
* @param id - The id of the entity to update
|
|
167
177
|
* @param attributes - Attributes to update
|
|
168
|
-
*
|
|
178
|
+
* @param options - Optional operation options including referentialIntegrityCheck flag
|
|
169
179
|
*
|
|
170
180
|
* @example Updating an entity.
|
|
171
181
|
* ```typescript
|
|
@@ -176,15 +186,23 @@ let DynaRecord = (() => {
|
|
|
176
186
|
* ```typescript
|
|
177
187
|
* await User.update("userId", { email: "newemail@example.com", someKey: null });
|
|
178
188
|
* ```
|
|
189
|
+
*
|
|
190
|
+
* @example With referential integrity check disabled
|
|
191
|
+
* ```typescript
|
|
192
|
+
* await User.update(
|
|
193
|
+
* "userId",
|
|
194
|
+
* { email: "newemail@example.com", profileId: 789 },
|
|
195
|
+
* { referentialIntegrityCheck: false }
|
|
196
|
+
* );
|
|
197
|
+
* ```
|
|
179
198
|
*/
|
|
180
|
-
static async update(id, attributes) {
|
|
199
|
+
static async update(id, attributes, options) {
|
|
181
200
|
const op = new operations_1.Update(this);
|
|
182
|
-
await op.run(id, attributes);
|
|
201
|
+
await op.run(id, attributes, options);
|
|
183
202
|
}
|
|
184
203
|
/**
|
|
185
204
|
* Same as the static `update` method but on an instance. Returns the full updated instance
|
|
186
205
|
*
|
|
187
|
-
*
|
|
188
206
|
* @example Updating an entity.
|
|
189
207
|
* ```typescript
|
|
190
208
|
* const updatedInstance = await instance.update({ email: "newemail@example.com", profileId: 789 });
|
|
@@ -194,11 +212,19 @@ let DynaRecord = (() => {
|
|
|
194
212
|
* ```typescript
|
|
195
213
|
* const updatedInstance = await instance.update({ email: "newemail@example.com", someKey: null });
|
|
196
214
|
* ```
|
|
215
|
+
*
|
|
216
|
+
* @example With referential integrity check disabled
|
|
217
|
+
* ```typescript
|
|
218
|
+
* const updatedInstance = await instance.update(
|
|
219
|
+
* { email: "newemail@example.com", profileId: 789 },
|
|
220
|
+
* { referentialIntegrityCheck: false }
|
|
221
|
+
* );
|
|
222
|
+
* ```
|
|
197
223
|
*/
|
|
198
|
-
async update(attributes) {
|
|
224
|
+
async update(attributes, options) {
|
|
199
225
|
const InstanceClass = this.constructor;
|
|
200
226
|
const op = new operations_1.Update(InstanceClass);
|
|
201
|
-
const updatedAttributes = await op.run(this.id, attributes);
|
|
227
|
+
const updatedAttributes = await op.run(this.id, attributes, options);
|
|
202
228
|
const clone = structuredClone(this);
|
|
203
229
|
// Update the current instance with new attributes
|
|
204
230
|
Object.assign(clone, updatedAttributes);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type DynaRecord from "../../DynaRecord";
|
|
2
2
|
import type { EntityClass } from "../../types";
|
|
3
3
|
import OperationBase from "../OperationBase";
|
|
4
|
-
import type { CreateOptions } from "./types";
|
|
4
|
+
import type { CreateOptions, CreateOperationOptions } from "./types";
|
|
5
5
|
import { type EntityAttributesOnly } from "../types";
|
|
6
6
|
/**
|
|
7
7
|
* Represents an operation to create a new entity record in DynamoDB, including all necessary
|
|
@@ -37,11 +37,12 @@ declare class Create<T extends DynaRecord> extends OperationBase<T> {
|
|
|
37
37
|
* partition (due to "BelongsTo" links), retrieves and inserts those link records.
|
|
38
38
|
*
|
|
39
39
|
* @param attributes - Attributes to initialize the new entity. Must be defined on the model and valid per schema constraints.
|
|
40
|
+
* @param options - Optional operation options including referentialIntegrityCheck flag.
|
|
40
41
|
* @returns A promise that resolves to the newly created entity with all attributes, including automatically set fields.
|
|
41
42
|
* @throws If the entity already exists, a uniqueness violation error is raised.
|
|
42
|
-
* @throws If a required foreign key does not correspond to an existing entity, an error is raised.
|
|
43
|
+
* @throws If a required foreign key does not correspond to an existing entity, an error is raised (unless referentialIntegrityCheck is false).
|
|
43
44
|
*/
|
|
44
|
-
run(attributes: CreateOptions<T
|
|
45
|
+
run(attributes: CreateOptions<T>, options?: CreateOperationOptions): Promise<EntityAttributesOnly<T>>;
|
|
45
46
|
/**
|
|
46
47
|
* Builds and returns entity attributes that must be reserved for system usage.
|
|
47
48
|
*
|
|
@@ -75,6 +76,7 @@ declare class Create<T extends DynaRecord> extends OperationBase<T> {
|
|
|
75
76
|
*
|
|
76
77
|
* @param entityData - The complete set of entity attributes for the new entity.
|
|
77
78
|
* @param tableItem - The main entity's DynamoDB table item.
|
|
79
|
+
* @param referentialIntegrityCheck - Whether to perform referential integrity checks.
|
|
78
80
|
* @private
|
|
79
81
|
*/
|
|
80
82
|
private buildBelongsToTransactions;
|
|
@@ -83,6 +85,8 @@ declare class Create<T extends DynaRecord> extends OperationBase<T> {
|
|
|
83
85
|
* Ensures referenced entities exist even when denormalised access patterns are not defined.
|
|
84
86
|
*
|
|
85
87
|
* @param entityData - Attributes being persisted for the new entity.
|
|
88
|
+
* @param referentialIntegrityCheck - Whether to perform referential integrity checks.
|
|
89
|
+
* @private
|
|
86
90
|
*/
|
|
87
91
|
private buildStandaloneForeignKeyConditionChecks;
|
|
88
92
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Create.d.ts","sourceRoot":"","sources":["../../../../src/operations/Create/Create.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAE/C,OAAO,KAAK,EAAmB,WAAW,EAAE,MAAM,aAAa,CAAC;AAOhE,OAAO,aAAa,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"Create.d.ts","sourceRoot":"","sources":["../../../../src/operations/Create/Create.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAE/C,OAAO,KAAK,EAAmB,WAAW,EAAE,MAAM,aAAa,CAAC;AAOhE,OAAO,aAAa,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,UAAU,CAAC;AAIlB;;;;;;;;;;;;;;;;;GAiBG;AACH,cAAM,MAAM,CAAC,CAAC,SAAS,UAAU,CAAE,SAAQ,aAAa,CAAC,CAAC,CAAC;;gBAG7C,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IAKlC;;;;;;;;;;;;;;;;;OAiBG;IACU,GAAG,CACd,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,EAC5B,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;IAuCnC;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,uBAAuB;IA8B/B;;;;;;;;;OASG;IACH,OAAO,CAAC,uBAAuB;IAiB/B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,0BAA0B;IAqClC;;;;;;;OAOG;IACH,OAAO,CAAC,wCAAwC;IAkChD;;;;;;;;;;;OAWG;YACW,sBAAsB;IAmCpC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,2CAA2C;IAmBnD;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,uCAAuC;CA0BhD;AAED,eAAe,MAAM,CAAC"}
|
|
@@ -46,18 +46,20 @@ class Create extends OperationBase_1.default {
|
|
|
46
46
|
* partition (due to "BelongsTo" links), retrieves and inserts those link records.
|
|
47
47
|
*
|
|
48
48
|
* @param attributes - Attributes to initialize the new entity. Must be defined on the model and valid per schema constraints.
|
|
49
|
+
* @param options - Optional operation options including referentialIntegrityCheck flag.
|
|
49
50
|
* @returns A promise that resolves to the newly created entity with all attributes, including automatically set fields.
|
|
50
51
|
* @throws If the entity already exists, a uniqueness violation error is raised.
|
|
51
|
-
* @throws If a required foreign key does not correspond to an existing entity, an error is raised.
|
|
52
|
+
* @throws If a required foreign key does not correspond to an existing entity, an error is raised (unless referentialIntegrityCheck is false).
|
|
52
53
|
*/
|
|
53
|
-
async run(attributes) {
|
|
54
|
+
async run(attributes, options) {
|
|
55
|
+
const referentialIntegrityCheck = options?.referentialIntegrityCheck ?? true;
|
|
54
56
|
const entityAttrs = this.entityMetadata.parseRawEntityDefinedAttributes(attributes);
|
|
55
57
|
const reservedAttrs = this.buildReservedAttributes(entityAttrs);
|
|
56
58
|
const entityData = { ...reservedAttrs, ...entityAttrs };
|
|
57
59
|
const tableItem = (0, utils_1.entityToTableItem)(this.EntityClass, entityData);
|
|
58
60
|
this.buildPutItemTransaction(tableItem, entityData.id);
|
|
59
|
-
this.buildBelongsToTransactions(entityData, tableItem);
|
|
60
|
-
this.buildStandaloneForeignKeyConditionChecks(entityData);
|
|
61
|
+
this.buildBelongsToTransactions(entityData, tableItem, referentialIntegrityCheck);
|
|
62
|
+
this.buildStandaloneForeignKeyConditionChecks(entityData, referentialIntegrityCheck);
|
|
61
63
|
// Attempt to fetch all belongs-to entities to properly create reverse denormalization links
|
|
62
64
|
const belongsToTableItems = await this.getBelongsToTableItems(entityData);
|
|
63
65
|
// If there are any belongs-to relationships, add the inverse link records into the new entity's partition
|
|
@@ -127,16 +129,19 @@ class Create extends OperationBase_1.default {
|
|
|
127
129
|
*
|
|
128
130
|
* @param entityData - The complete set of entity attributes for the new entity.
|
|
129
131
|
* @param tableItem - The main entity's DynamoDB table item.
|
|
132
|
+
* @param referentialIntegrityCheck - Whether to perform referential integrity checks.
|
|
130
133
|
* @private
|
|
131
134
|
*/
|
|
132
|
-
buildBelongsToTransactions(entityData, tableItem) {
|
|
135
|
+
buildBelongsToTransactions(entityData, tableItem, referentialIntegrityCheck) {
|
|
133
136
|
const tableName = this.tableMetadata.name;
|
|
134
137
|
const relMetadata = this.entityMetadata.belongsToOrOwnedByRelationships;
|
|
135
138
|
for (const relMeta of relMetadata) {
|
|
136
139
|
const foreignKey = (0, utils_2.extractForeignKeyFromEntity)(relMeta, entityData);
|
|
137
140
|
if (foreignKey !== undefined) {
|
|
138
141
|
// Ensure referenced entity exists before linking
|
|
139
|
-
|
|
142
|
+
if (referentialIntegrityCheck) {
|
|
143
|
+
this.buildRelationshipExistsConditionTransaction(relMeta, foreignKey);
|
|
144
|
+
}
|
|
140
145
|
const key = (0, utils_2.buildBelongsToLinkKey)(this.EntityClass, entityData.id, relMeta, foreignKey);
|
|
141
146
|
this.#transactionBuilder.addPut({
|
|
142
147
|
TableName: tableName,
|
|
@@ -151,8 +156,13 @@ class Create extends OperationBase_1.default {
|
|
|
151
156
|
* Ensures referenced entities exist even when denormalised access patterns are not defined.
|
|
152
157
|
*
|
|
153
158
|
* @param entityData - Attributes being persisted for the new entity.
|
|
159
|
+
* @param referentialIntegrityCheck - Whether to perform referential integrity checks.
|
|
160
|
+
* @private
|
|
154
161
|
*/
|
|
155
|
-
buildStandaloneForeignKeyConditionChecks(entityData) {
|
|
162
|
+
buildStandaloneForeignKeyConditionChecks(entityData, referentialIntegrityCheck) {
|
|
163
|
+
if (!referentialIntegrityCheck) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
156
166
|
const standaloneForeignKeys = this.entityMetadata.standaloneForeignKeyAttributes;
|
|
157
167
|
for (const attrMeta of standaloneForeignKeys) {
|
|
158
168
|
const target = attrMeta.foreignKeyTarget;
|
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import type DynaRecord from "../../DynaRecord";
|
|
2
2
|
import type { EntityDefinedAttributes } from "../types";
|
|
3
|
+
/**
|
|
4
|
+
* Options for create operations
|
|
5
|
+
*/
|
|
6
|
+
export interface CreateOperationOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Whether to perform referential integrity checks for foreign key references.
|
|
9
|
+
* When `true` (default), condition checks are added to verify that referenced entities exist.
|
|
10
|
+
* When `false`, these condition checks are skipped, allowing creation even if foreign key references don't exist.
|
|
11
|
+
* @default true
|
|
12
|
+
*/
|
|
13
|
+
referentialIntegrityCheck?: boolean;
|
|
14
|
+
}
|
|
3
15
|
/**
|
|
4
16
|
* Entity attribute fields that can be set on create. Excludes that are managed by dyna-record
|
|
5
17
|
*/
|
|
@@ -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
|