dyna-record 0.1.4 → 0.2.0

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.
Files changed (123) hide show
  1. package/README.md +15 -15
  2. package/dist/src/DynaRecord.d.ts +36 -28
  3. package/dist/src/DynaRecord.d.ts.map +1 -1
  4. package/dist/src/DynaRecord.js +39 -36
  5. package/dist/src/decorators/Table.d.ts.map +1 -1
  6. package/dist/src/decorators/attributes/BooleanAttribute.d.ts.map +1 -1
  7. package/dist/src/decorators/attributes/BooleanAttribute.js +1 -2
  8. package/dist/src/decorators/attributes/DateAttribute.d.ts.map +1 -1
  9. package/dist/src/decorators/attributes/DateAttribute.js +1 -2
  10. package/dist/src/decorators/attributes/EnumAttribute.d.ts +1 -1
  11. package/dist/src/decorators/attributes/EnumAttribute.d.ts.map +1 -1
  12. package/dist/src/decorators/attributes/EnumAttribute.js +2 -3
  13. package/dist/src/decorators/attributes/ForeignKeyAttribute.d.ts +1 -1
  14. package/dist/src/decorators/attributes/ForeignKeyAttribute.d.ts.map +1 -1
  15. package/dist/src/decorators/attributes/ForeignKeyAttribute.js +2 -3
  16. package/dist/src/decorators/attributes/IdAttribute.d.ts +32 -0
  17. package/dist/src/decorators/attributes/IdAttribute.d.ts.map +1 -0
  18. package/dist/src/decorators/attributes/IdAttribute.js +41 -0
  19. package/dist/src/decorators/attributes/NumberAttribute.d.ts.map +1 -1
  20. package/dist/src/decorators/attributes/NumberAttribute.js +1 -2
  21. package/dist/src/decorators/attributes/PartitionKeyAttribute.d.ts +1 -1
  22. package/dist/src/decorators/attributes/PartitionKeyAttribute.d.ts.map +1 -1
  23. package/dist/src/decorators/attributes/PartitionKeyAttribute.js +2 -3
  24. package/dist/src/decorators/attributes/SortKeyAttribute.d.ts +1 -1
  25. package/dist/src/decorators/attributes/SortKeyAttribute.d.ts.map +1 -1
  26. package/dist/src/decorators/attributes/SortKeyAttribute.js +2 -3
  27. package/dist/src/decorators/attributes/StringAttribute.d.ts +1 -1
  28. package/dist/src/decorators/attributes/StringAttribute.d.ts.map +1 -1
  29. package/dist/src/decorators/attributes/StringAttribute.js +2 -3
  30. package/dist/src/decorators/attributes/index.d.ts +1 -0
  31. package/dist/src/decorators/attributes/index.d.ts.map +1 -1
  32. package/dist/src/decorators/attributes/index.js +3 -1
  33. package/dist/src/decorators/attributes/serializers.d.ts +1 -1
  34. package/dist/src/decorators/relationships/BelongsTo.d.ts +1 -1
  35. package/dist/src/decorators/relationships/BelongsTo.d.ts.map +1 -1
  36. package/dist/src/decorators/relationships/BelongsTo.js +2 -3
  37. package/dist/src/decorators/relationships/HasAndBelongsToMany.d.ts +2 -2
  38. package/dist/src/decorators/relationships/HasAndBelongsToMany.d.ts.map +1 -1
  39. package/dist/src/decorators/relationships/HasAndBelongsToMany.js +3 -4
  40. package/dist/src/decorators/relationships/HasMany.d.ts +2 -2
  41. package/dist/src/decorators/relationships/HasMany.d.ts.map +1 -1
  42. package/dist/src/decorators/relationships/HasMany.js +3 -4
  43. package/dist/src/decorators/relationships/HasOne.d.ts +2 -2
  44. package/dist/src/decorators/relationships/HasOne.d.ts.map +1 -1
  45. package/dist/src/decorators/relationships/HasOne.js +3 -4
  46. package/dist/src/decorators/types.d.ts +2 -2
  47. package/dist/src/decorators/types.d.ts.map +1 -1
  48. package/dist/src/dynamo-utils/TransactGetBuilder.d.ts +4 -0
  49. package/dist/src/dynamo-utils/TransactGetBuilder.d.ts.map +1 -1
  50. package/dist/src/dynamo-utils/TransactGetBuilder.js +6 -0
  51. package/dist/src/metadata/EntityMetadata.d.ts +17 -1
  52. package/dist/src/metadata/EntityMetadata.d.ts.map +1 -1
  53. package/dist/src/metadata/EntityMetadata.js +25 -0
  54. package/dist/src/metadata/MetadataStorage.d.ts +6 -0
  55. package/dist/src/metadata/MetadataStorage.d.ts.map +1 -1
  56. package/dist/src/metadata/MetadataStorage.js +9 -0
  57. package/dist/src/metadata/TableMetadata.d.ts.map +1 -1
  58. package/dist/src/metadata/TableMetadata.js +2 -6
  59. package/dist/src/metadata/relationship-metadata/types.d.ts +4 -0
  60. package/dist/src/metadata/relationship-metadata/types.d.ts.map +1 -1
  61. package/dist/src/metadata/types.d.ts +2 -3
  62. package/dist/src/metadata/types.d.ts.map +1 -1
  63. package/dist/src/metadata/utils.d.ts.map +1 -1
  64. package/dist/src/operations/Create/Create.d.ts +95 -16
  65. package/dist/src/operations/Create/Create.d.ts.map +1 -1
  66. package/dist/src/operations/Create/Create.js +180 -29
  67. package/dist/src/operations/Delete/Delete.d.ts +29 -25
  68. package/dist/src/operations/Delete/Delete.d.ts.map +1 -1
  69. package/dist/src/operations/Delete/Delete.js +105 -104
  70. package/dist/src/operations/Delete/types.d.ts +0 -3
  71. package/dist/src/operations/Delete/types.d.ts.map +1 -1
  72. package/dist/src/operations/FindById/FindById.d.ts +7 -28
  73. package/dist/src/operations/FindById/FindById.d.ts.map +1 -1
  74. package/dist/src/operations/FindById/FindById.js +36 -125
  75. package/dist/src/operations/FindById/types.d.ts +8 -9
  76. package/dist/src/operations/FindById/types.d.ts.map +1 -1
  77. package/dist/src/operations/Query/Query.d.ts +2 -1
  78. package/dist/src/operations/Query/Query.d.ts.map +1 -1
  79. package/dist/src/operations/Query/Query.js +17 -4
  80. package/dist/src/operations/Query/types.d.ts +39 -5
  81. package/dist/src/operations/Query/types.d.ts.map +1 -1
  82. package/dist/src/operations/Update/Update.d.ts +185 -24
  83. package/dist/src/operations/Update/Update.d.ts.map +1 -1
  84. package/dist/src/operations/Update/Update.js +402 -72
  85. package/dist/src/operations/Update/UpdateDryRun.d.ts +10 -0
  86. package/dist/src/operations/Update/UpdateDryRun.d.ts.map +1 -0
  87. package/dist/src/operations/Update/UpdateDryRun.js +15 -0
  88. package/dist/src/operations/Update/index.d.ts +1 -0
  89. package/dist/src/operations/Update/index.d.ts.map +1 -1
  90. package/dist/src/operations/Update/index.js +3 -1
  91. package/dist/src/operations/types.d.ts +6 -1
  92. package/dist/src/operations/types.d.ts.map +1 -1
  93. package/dist/src/operations/utils/expressionBuilder.d.ts.map +1 -1
  94. package/dist/src/operations/utils/expressionBuilder.js +1 -4
  95. package/dist/src/operations/utils/index.d.ts +0 -1
  96. package/dist/src/operations/utils/index.d.ts.map +1 -1
  97. package/dist/src/operations/utils/index.js +0 -6
  98. package/dist/src/operations/utils/utils.d.ts +13 -3
  99. package/dist/src/operations/utils/utils.d.ts.map +1 -1
  100. package/dist/src/operations/utils/utils.js +33 -3
  101. package/dist/src/query-utils/Filters.d.ts +1 -1
  102. package/dist/src/query-utils/Filters.d.ts.map +1 -1
  103. package/dist/src/query-utils/Filters.js +7 -15
  104. package/dist/src/query-utils/QueryBuilder.d.ts.map +1 -1
  105. package/dist/src/query-utils/QueryBuilder.js +9 -1
  106. package/dist/src/relationships/JoinTable.d.ts +17 -7
  107. package/dist/src/relationships/JoinTable.d.ts.map +1 -1
  108. package/dist/src/relationships/JoinTable.js +77 -20
  109. package/dist/src/relationships/index.d.ts +0 -1
  110. package/dist/src/relationships/index.d.ts.map +1 -1
  111. package/dist/src/relationships/index.js +1 -3
  112. package/dist/src/types.d.ts +6 -8
  113. package/dist/src/types.d.ts.map +1 -1
  114. package/dist/src/utils.d.ts +10 -32
  115. package/dist/src/utils.d.ts.map +1 -1
  116. package/dist/src/utils.js +13 -59
  117. package/package.json +4 -4
  118. package/dist/src/operations/utils/RelationshipTransactions.d.ts +0 -64
  119. package/dist/src/operations/utils/RelationshipTransactions.d.ts.map +0 -1
  120. package/dist/src/operations/utils/RelationshipTransactions.js +0 -125
  121. package/dist/src/relationships/BelongsToLink.d.ts +0 -51
  122. package/dist/src/relationships/BelongsToLink.d.ts.map +0 -1
  123. package/dist/src/relationships/BelongsToLink.js +0 -57
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/metadata/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,+BAA+B,EAChC,MAAM,GAAG,CAAC;AACX,OAAO,KAAK,UAAU,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C;;GAEG;AACH,eAAO,MAAM,qBAAqB,QAC3B,oBAAoB,+BAG1B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,QAC7B,oBAAoB,iCAG1B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,QAC1B,oBAAoB,8BAG1B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iCAAiC,QACvC,oBAAoB,2CAG1B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oCAAoC,QAC1C,oBAAoB,8CAG1B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,sDAEnC,qBAAqB,KACzB,OAMF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,8BAA8B,sDAEpC,qBAAqB,KACzB,OAMF,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/metadata/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,+BAA+B,EAChC,MAAM,GAAG,CAAC;AACX,OAAO,KAAK,UAAU,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C;;GAEG;AACH,eAAO,MAAM,qBAAqB,QAC3B,oBAAoB,KACxB,GAAG,IAAI,mBAET,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,QAC7B,oBAAoB,KACxB,GAAG,IAAI,qBAET,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,QAC1B,oBAAoB,KACxB,GAAG,IAAI,kBAET,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iCAAiC,QACvC,oBAAoB,KACxB,GAAG,IAAI,+BAET,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oCAAoC,QAC1C,oBAAoB,KACxB,GAAG,IAAI,kCAET,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,GAAI,CAAC,SAAS,UAAU,UACxD,WAAW,CAAC,CAAC,CAAC,OACjB,qBAAqB,KACzB,OAMF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,8BAA8B,GAAI,CAAC,SAAS,UAAU,UACzD,WAAW,CAAC,CAAC,CAAC,OACjB,qBAAqB,KACzB,OAMF,CAAC"}
@@ -2,13 +2,22 @@ import type DynaRecord from "../../DynaRecord";
2
2
  import type { EntityClass } from "../../types";
3
3
  import OperationBase from "../OperationBase";
4
4
  import type { CreateOptions } from "./types";
5
- import { type EntityAttributes } from "../types";
5
+ import { type EntityAttributesOnly } from "../types";
6
6
  /**
7
- * Represents the operation for creating a new entity in the database, including handling its attributes and any related entities' associations. It will handle de-normalizing data to support relationships
7
+ * Represents an operation to create a new entity record in DynamoDB, including all necessary
8
+ * denormalized relationship records. This ensures that "BelongsTo" and "HasMany" relationships
9
+ * are properly maintained at the time of entity creation.
8
10
  *
9
- * It encapsulates the logic required to translate entity attributes to a format suitable for DynamoDB, execute the creation transaction, and manage any relationships defined by the entity, such as "BelongsTo" or "HasMany" links.
11
+ * **What it does:**
12
+ * - Converts the given attributes into a DynamoDB-compatible format.
13
+ * - Inserts a new entity record, ensuring no duplicate primary key conflicts.
14
+ * - For each "BelongsTo" relationship that includes a foreign key:
15
+ * - Verifies the referenced entity exists.
16
+ * - Creates a denormalized link record in the related entity's partition.
17
+ * - If the entity's relationships imply additional denormalized records in its own partition,
18
+ * those are also created after verifying the related entities exist.
10
19
  *
11
- * Only attributes defined on the model can be configured, and will be enforced via types and runtime schema validation.
20
+ * Only attributes defined on the entity model can be set, validated both at compile-time and runtime.
12
21
  *
13
22
  * @template T - The type of the entity being created, extending `DynaRecord`.
14
23
  */
@@ -16,27 +25,97 @@ declare class Create<T extends DynaRecord> extends OperationBase<T> {
16
25
  #private;
17
26
  constructor(Entity: EntityClass<T>);
18
27
  /**
19
- * Create an entity transaction, including relationship transactions (EX: Creating BelongsToLinks for HasMany, checking existence of relationships, etc)
20
- * @param attributes
21
- * @returns
28
+ * Executes the create operation.
29
+ *
30
+ * **What it does:**
31
+ * - Parses and validates the provided attributes against the entity schema.
32
+ * - Generates any required reserved attributes (like `id`, `createdAt`, and `updatedAt`).
33
+ * - Inserts the new entity record into DynamoDB, ensuring it doesn't already exist.
34
+ * - For each defined "BelongsTo" relationship, ensures the related entity exists and creates
35
+ * a corresponding denormalized "link" record.
36
+ * - If the entity's creation implies that related records must also be denormalized into its own
37
+ * partition (due to "BelongsTo" links), retrieves and inserts those link records.
38
+ *
39
+ * @param attributes - Attributes to initialize the new entity. Must be defined on the model and valid per schema constraints.
40
+ * @returns A promise that resolves to the newly created entity with all attributes, including automatically set fields.
41
+ * @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.
22
43
  */
23
- run(attributes: CreateOptions<T>): Promise<EntityAttributes<T>>;
44
+ run(attributes: CreateOptions<T>): Promise<EntityAttributesOnly<T>>;
24
45
  /**
25
- * Builds the entity attributes
26
- * @param attributes
27
- * @returns
46
+ * Builds and returns entity attributes that must be reserved for system usage.
47
+ *
48
+ * **What it does:**
49
+ * - Generates a unique entity ID if the entity's schema does not specify an `id` field.
50
+ * - Sets `createdAt` and `updatedAt` to the current time.
51
+ * - Builds the partition and sort key values based on the entity's class and generated ID.
52
+ *
53
+ * @param entityAttrs - The user-provided entity attributes.
54
+ * @returns The combined attributes including all reserved fields.
55
+ * @private
28
56
  */
29
57
  private buildReservedAttributes;
30
58
  /**
31
- * Build the transaction for the parent entity Create item request
32
- * @param tableItem
59
+ * Adds a "PutItem" transaction for the new entity record.
60
+ *
61
+ * **What it does:**
62
+ * - Ensures the primary key does not already exist, preventing duplication.
63
+ *
64
+ * @param tableItem - The DynamoDB table item for the entity to put.
65
+ * @param id - The unique identifier of the new entity.
66
+ * @private
33
67
  */
34
68
  private buildPutItemTransaction;
35
69
  /**
36
- * Build transaction items for associations
37
- * @param entityData
70
+ * Adds "PutItem" transactions to create denormalized "BelongsTo" link records in the related entity's partitions.
71
+ *
72
+ * **What it does:**
73
+ * - For each "BelongsTo" relationship with a defined foreign key, checks that the related entity exists.
74
+ * - Inserts a "link" item into the related entity's partition to maintain denormalized relationships.
75
+ *
76
+ * @param entityData - The complete set of entity attributes for the new entity.
77
+ * @param tableItem - The main entity's DynamoDB table item.
78
+ * @private
38
79
  */
39
- private buildRelationshipTransactions;
80
+ private buildBelongsToTransactions;
81
+ /**
82
+ * Retrieves the DynamoDB items for all entities that the new entity references via "BelongsTo" relationships.
83
+ *
84
+ * **What it does:**
85
+ * - For each "BelongsTo" relationship, queries DynamoDB for the related entity record.
86
+ * - Returns all found related items as an array.
87
+ * - If no relationships or no foreign keys are present, returns an empty array.
88
+ *
89
+ * @param entityData - The attributes of the entity being created.
90
+ * @returns A promise that resolves to an array of related DynamoDB items.
91
+ * @private
92
+ */
93
+ private getBelongsToTableItems;
94
+ /**
95
+ * Adds a condition check transaction to ensure that the entity referenced by a "BelongsTo" foreign key exists.
96
+ *
97
+ * **What it does:**
98
+ * - Checks the existence of the related entity before creating the link item.
99
+ * - If the related entity does not exist, the transaction will fail, preventing creation of dangling references.
100
+ *
101
+ * @param rel - The "BelongsTo" relationship metadata.
102
+ * @param relationshipId - The foreign key value referencing the related entity.
103
+ * @private
104
+ */
105
+ private buildRelationshipExistsConditionTransaction;
106
+ /**
107
+ * For each related entity referenced by a "BelongsTo" relationship, insert a denormalized copy of that entity
108
+ * into the new entity's partition. This maintains a consistent, denormalized view of relationships.
109
+ *
110
+ * **What it does:**
111
+ * - Adds "PutItem" operations to create link records in the newly created entity's partition.
112
+ * - Ensures these link records don't already exist.
113
+ *
114
+ * @param entityId - The newly created entity's ID.
115
+ * @param belongsToTableItems - The table items representing each related "BelongsTo" entity.
116
+ * @private
117
+ */
118
+ private buildAddBelongsToLinkToSelfTransactions;
40
119
  }
41
120
  export default Create;
42
121
  //# sourceMappingURL=Create.d.ts.map
@@ -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;AAGhE,OAAO,aAAa,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,UAAU,CAAC;AAGlB;;;;;;;;GAQG;AACH,cAAM,MAAM,CAAC,CAAC,SAAS,UAAU,CAAE,SAAQ,aAAa,CAAC,CAAC,CAAC;;gBAG7C,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IAKlC;;;;OAIG;IACU,GAAG,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAiB5E;;;;OAIG;IACH,OAAO,CAAC,uBAAuB;IAsB/B;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAW/B;;;OAGG;YACW,6BAA6B;CAU5C;AAED,eAAe,MAAM,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,MAAM,SAAS,CAAC;AAC7C,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;;;;;;;;;;;;;;;;OAgBG;IACU,GAAG,CACd,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,GAC3B,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;IA4BnC;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,uBAAuB;IA8B/B;;;;;;;;;OASG;IACH,OAAO,CAAC,uBAAuB;IAiB/B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,0BAA0B;IAgClC;;;;;;;;;;;OAWG;YACW,sBAAsB;IAmCpC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,2CAA2C;IAmBnD;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,uCAAuC;CA0BhD;AAED,eAAe,MAAM,CAAC"}
@@ -8,13 +8,22 @@ const dynamo_utils_1 = require("../../dynamo-utils");
8
8
  const utils_1 = require("../../utils");
9
9
  const OperationBase_1 = __importDefault(require("../OperationBase"));
10
10
  const utils_2 = require("../utils");
11
- const metadata_1 = __importDefault(require("../../metadata"));
11
+ const utils_3 = require("../../metadata/utils");
12
12
  /**
13
- * Represents the operation for creating a new entity in the database, including handling its attributes and any related entities' associations. It will handle de-normalizing data to support relationships
13
+ * Represents an operation to create a new entity record in DynamoDB, including all necessary
14
+ * denormalized relationship records. This ensures that "BelongsTo" and "HasMany" relationships
15
+ * are properly maintained at the time of entity creation.
14
16
  *
15
- * It encapsulates the logic required to translate entity attributes to a format suitable for DynamoDB, execute the creation transaction, and manage any relationships defined by the entity, such as "BelongsTo" or "HasMany" links.
17
+ * **What it does:**
18
+ * - Converts the given attributes into a DynamoDB-compatible format.
19
+ * - Inserts a new entity record, ensuring no duplicate primary key conflicts.
20
+ * - For each "BelongsTo" relationship that includes a foreign key:
21
+ * - Verifies the referenced entity exists.
22
+ * - Creates a denormalized link record in the related entity's partition.
23
+ * - If the entity's relationships imply additional denormalized records in its own partition,
24
+ * those are also created after verifying the related entities exist.
16
25
  *
17
- * Only attributes defined on the model can be configured, and will be enforced via types and runtime schema validation.
26
+ * Only attributes defined on the entity model can be set, validated both at compile-time and runtime.
18
27
  *
19
28
  * @template T - The type of the entity being created, extending `DynaRecord`.
20
29
  */
@@ -25,28 +34,55 @@ class Create extends OperationBase_1.default {
25
34
  this.#transactionBuilder = new dynamo_utils_1.TransactWriteBuilder();
26
35
  }
27
36
  /**
28
- * Create an entity transaction, including relationship transactions (EX: Creating BelongsToLinks for HasMany, checking existence of relationships, etc)
29
- * @param attributes
30
- * @returns
37
+ * Executes the create operation.
38
+ *
39
+ * **What it does:**
40
+ * - Parses and validates the provided attributes against the entity schema.
41
+ * - Generates any required reserved attributes (like `id`, `createdAt`, and `updatedAt`).
42
+ * - Inserts the new entity record into DynamoDB, ensuring it doesn't already exist.
43
+ * - For each defined "BelongsTo" relationship, ensures the related entity exists and creates
44
+ * a corresponding denormalized "link" record.
45
+ * - If the entity's creation implies that related records must also be denormalized into its own
46
+ * partition (due to "BelongsTo" links), retrieves and inserts those link records.
47
+ *
48
+ * @param attributes - Attributes to initialize the new entity. Must be defined on the model and valid per schema constraints.
49
+ * @returns A promise that resolves to the newly created entity with all attributes, including automatically set fields.
50
+ * @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.
31
52
  */
32
53
  async run(attributes) {
33
- const entityMeta = metadata_1.default.getEntity(this.EntityClass.name);
34
- const entityAttrs = entityMeta.parseRawEntityDefinedAttributes(attributes);
35
- const reservedAttrs = this.buildReservedAttributes();
54
+ const entityAttrs = this.entityMetadata.parseRawEntityDefinedAttributes(attributes);
55
+ const reservedAttrs = this.buildReservedAttributes(entityAttrs);
36
56
  const entityData = { ...reservedAttrs, ...entityAttrs };
37
57
  const tableItem = (0, utils_1.entityToTableItem)(this.EntityClass, entityData);
38
- this.buildPutItemTransaction(tableItem);
39
- await this.buildRelationshipTransactions(entityData);
58
+ this.buildPutItemTransaction(tableItem, entityData.id);
59
+ this.buildBelongsToTransactions(entityData, tableItem);
60
+ // Attempt to fetch all belongs-to entities to properly create reverse denormalization links
61
+ const belongsToTableItems = await this.getBelongsToTableItems(entityData);
62
+ // If there are any belongs-to relationships, add the inverse link records into the new entity's partition
63
+ if (belongsToTableItems.length > 0) {
64
+ this.buildAddBelongsToLinkToSelfTransactions(reservedAttrs.id, belongsToTableItems);
65
+ }
40
66
  await this.#transactionBuilder.executeTransaction();
41
67
  return (0, utils_1.tableItemToEntity)(this.EntityClass, tableItem);
42
68
  }
43
69
  /**
44
- * Builds the entity attributes
45
- * @param attributes
46
- * @returns
70
+ * Builds and returns entity attributes that must be reserved for system usage.
71
+ *
72
+ * **What it does:**
73
+ * - Generates a unique entity ID if the entity's schema does not specify an `id` field.
74
+ * - Sets `createdAt` and `updatedAt` to the current time.
75
+ * - Builds the partition and sort key values based on the entity's class and generated ID.
76
+ *
77
+ * @param entityAttrs - The user-provided entity attributes.
78
+ * @returns The combined attributes including all reserved fields.
79
+ * @private
47
80
  */
48
- buildReservedAttributes() {
49
- const id = (0, uuid_1.v4)();
81
+ buildReservedAttributes(entityAttrs) {
82
+ const { idField } = this.entityMetadata;
83
+ const id = idField === undefined
84
+ ? (0, uuid_1.v4)()
85
+ : entityAttrs[idField];
50
86
  const createdAt = new Date();
51
87
  const pk = this.tableMetadata.partitionKeyAttribute.name;
52
88
  const sk = this.tableMetadata.sortKeyAttribute.name;
@@ -63,28 +99,143 @@ class Create extends OperationBase_1.default {
63
99
  return { ...keys, ...defaultAttrs };
64
100
  }
65
101
  /**
66
- * Build the transaction for the parent entity Create item request
67
- * @param tableItem
102
+ * Adds a "PutItem" transaction for the new entity record.
103
+ *
104
+ * **What it does:**
105
+ * - Ensures the primary key does not already exist, preventing duplication.
106
+ *
107
+ * @param tableItem - The DynamoDB table item for the entity to put.
108
+ * @param id - The unique identifier of the new entity.
109
+ * @private
68
110
  */
69
- buildPutItemTransaction(tableItem) {
111
+ buildPutItemTransaction(tableItem, id) {
70
112
  const { name: tableName } = this.tableMetadata;
71
113
  const putExpression = {
72
114
  TableName: tableName,
73
115
  Item: tableItem,
74
- ConditionExpression: `attribute_not_exists(${this.partitionKeyAlias})` // Ensure item doesn't already exist
116
+ ConditionExpression: `attribute_not_exists(${this.partitionKeyAlias})`
75
117
  };
76
- this.#transactionBuilder.addPut(putExpression);
118
+ this.#transactionBuilder.addPut(putExpression, `${this.EntityClass.name} with id: ${id} already exists`);
77
119
  }
78
120
  /**
79
- * Build transaction items for associations
80
- * @param entityData
121
+ * Adds "PutItem" transactions to create denormalized "BelongsTo" link records in the related entity's partitions.
122
+ *
123
+ * **What it does:**
124
+ * - For each "BelongsTo" relationship with a defined foreign key, checks that the related entity exists.
125
+ * - Inserts a "link" item into the related entity's partition to maintain denormalized relationships.
126
+ *
127
+ * @param entityData - The complete set of entity attributes for the new entity.
128
+ * @param tableItem - The main entity's DynamoDB table item.
129
+ * @private
81
130
  */
82
- async buildRelationshipTransactions(entityData) {
83
- const relationshipTransactions = new utils_2.RelationshipTransactions({
84
- Entity: this.EntityClass,
85
- transactionBuilder: this.#transactionBuilder
131
+ buildBelongsToTransactions(entityData, tableItem) {
132
+ const tableName = this.tableMetadata.name;
133
+ for (const relMeta of this.entityMetadata.belongsToRelationships) {
134
+ const foreignKey = (0, utils_2.extractForeignKeyFromEntity)(relMeta, entityData);
135
+ if (foreignKey !== undefined) {
136
+ // Ensure referenced entity exists before linking
137
+ this.buildRelationshipExistsConditionTransaction(relMeta, foreignKey);
138
+ const key = (0, utils_2.buildBelongsToLinkKey)(this.EntityClass, entityData.id, relMeta, foreignKey);
139
+ this.#transactionBuilder.addPut({
140
+ TableName: tableName,
141
+ Item: { ...tableItem, ...key },
142
+ ConditionExpression: `attribute_not_exists(${this.partitionKeyAlias})`
143
+ }, `${relMeta.target.name} with id: ${foreignKey} already has an associated ${this.EntityClass.name}`);
144
+ }
145
+ }
146
+ }
147
+ /**
148
+ * Retrieves the DynamoDB items for all entities that the new entity references via "BelongsTo" relationships.
149
+ *
150
+ * **What it does:**
151
+ * - For each "BelongsTo" relationship, queries DynamoDB for the related entity record.
152
+ * - Returns all found related items as an array.
153
+ * - If no relationships or no foreign keys are present, returns an empty array.
154
+ *
155
+ * @param entityData - The attributes of the entity being created.
156
+ * @returns A promise that resolves to an array of related DynamoDB items.
157
+ * @private
158
+ */
159
+ async getBelongsToTableItems(entityData) {
160
+ const { name: tableName } = this.tableMetadata;
161
+ const transactionBuilder = new dynamo_utils_1.TransactGetBuilder();
162
+ const relMetas = this.entityMetadata.relationships;
163
+ const belongsToRelMetas = Object.values(relMetas).filter(relMeta => (0, utils_3.isBelongsToRelationship)(relMeta));
164
+ belongsToRelMetas.forEach(relMeta => {
165
+ const fk = (0, utils_2.extractForeignKeyFromEntity)(relMeta, entityData);
166
+ if (fk !== undefined) {
167
+ transactionBuilder.addGet({
168
+ TableName: tableName,
169
+ Key: {
170
+ [this.partitionKeyAlias]: relMeta.target.partitionKeyValue(fk),
171
+ [this.sortKeyAlias]: relMeta.target.name
172
+ }
173
+ });
174
+ }
175
+ });
176
+ if (transactionBuilder.hasTransactions()) {
177
+ const results = await transactionBuilder.executeTransaction();
178
+ return results.reduce((acc, res) => {
179
+ if (res.Item !== undefined)
180
+ acc.push(res.Item);
181
+ return acc;
182
+ }, []);
183
+ }
184
+ return [];
185
+ }
186
+ /**
187
+ * Adds a condition check transaction to ensure that the entity referenced by a "BelongsTo" foreign key exists.
188
+ *
189
+ * **What it does:**
190
+ * - Checks the existence of the related entity before creating the link item.
191
+ * - If the related entity does not exist, the transaction will fail, preventing creation of dangling references.
192
+ *
193
+ * @param rel - The "BelongsTo" relationship metadata.
194
+ * @param relationshipId - The foreign key value referencing the related entity.
195
+ * @private
196
+ */
197
+ buildRelationshipExistsConditionTransaction(rel, relationshipId) {
198
+ const { name: tableName } = this.tableMetadata;
199
+ const errMsg = `${rel.target.name} with ID '${relationshipId}' does not exist`;
200
+ const conditionCheck = {
201
+ TableName: tableName,
202
+ Key: {
203
+ [this.partitionKeyAlias]: rel.target.partitionKeyValue(relationshipId),
204
+ [this.sortKeyAlias]: rel.target.name
205
+ },
206
+ ConditionExpression: `attribute_exists(${this.partitionKeyAlias})`
207
+ };
208
+ this.#transactionBuilder.addConditionCheck(conditionCheck, errMsg);
209
+ }
210
+ /**
211
+ * For each related entity referenced by a "BelongsTo" relationship, insert a denormalized copy of that entity
212
+ * into the new entity's partition. This maintains a consistent, denormalized view of relationships.
213
+ *
214
+ * **What it does:**
215
+ * - Adds "PutItem" operations to create link records in the newly created entity's partition.
216
+ * - Ensures these link records don't already exist.
217
+ *
218
+ * @param entityId - The newly created entity's ID.
219
+ * @param belongsToTableItems - The table items representing each related "BelongsTo" entity.
220
+ * @private
221
+ */
222
+ buildAddBelongsToLinkToSelfTransactions(entityId, belongsToTableItems) {
223
+ const pk = this.EntityClass.partitionKeyValue(entityId);
224
+ const typeAlias = this.tableMetadata.defaultAttributes.type.alias;
225
+ belongsToTableItems.forEach(tableItem => {
226
+ const relationshipType = tableItem[typeAlias];
227
+ const key = {
228
+ [this.partitionKeyAlias]: pk,
229
+ [this.sortKeyAlias]: relationshipType
230
+ };
231
+ this.#transactionBuilder.addPut({
232
+ TableName: this.tableMetadata.name,
233
+ Item: { ...tableItem, ...key },
234
+ ConditionExpression: `attribute_not_exists(${this.partitionKeyAlias})`
235
+ },
236
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
237
+ `${this.EntityClass.name} already has an associated ${relationshipType}`);
86
238
  });
87
- await relationshipTransactions.build(entityData);
88
239
  }
89
240
  }
90
241
  exports.default = Create;
@@ -1,10 +1,10 @@
1
- import DynaRecord from "../../DynaRecord";
1
+ import type DynaRecord from "../../DynaRecord";
2
2
  import type { EntityClass } from "../../types";
3
3
  import OperationBase from "../OperationBase";
4
4
  /**
5
5
  * Implements the operation for deleting an entity and its related data from the database within the ORM framework.
6
6
  *
7
- * Delete an entity, everything in its partition, BelongsToLinks and nullifies ForeignKeys on attributes that BelongTo it
7
+ * Delete an entity, everything in its partition, denormalized records and nullifies ForeignKeys on attributes that BelongTo it
8
8
  * If the foreign key is non nullable than it will throw a NullConstraintViolationError
9
9
  *
10
10
  * The `Delete` operation supports complex scenarios, such as deleting related entities in "BelongsTo" relationships, nullifying or removing foreign keys to maintain data integrity, and handling many-to-many relationships through join tables.
@@ -18,21 +18,38 @@ declare class Delete<T extends DynaRecord> extends OperationBase<T> {
18
18
  * Delete an item by id
19
19
  * - Deletes the given entity
20
20
  * - Deletes each item in the entity's partition
21
- * - For each item in the entity's partition which is of type 'BelongsToLink' it:
21
+ * - For each item in the entity's partition which is a denormalized record it:
22
22
  * - Will nullify the associated relationship's ForeignKey attribute if the attribute is nullable
23
23
  * @param id
24
24
  */
25
25
  run(id: string): Promise<void>;
26
26
  /**
27
- * Deletes an item
28
- * @param item
27
+ * Prefetch the item being deleted including items in its partition from denormalized associated records
28
+ * @param id
29
+ * @returns - The item and its associated links denormalized
30
+ */
31
+ private preFetch;
32
+ /**
33
+ * Returns true if the linked entity needs to have a foreign key nullified
34
+ * @param relMeta
35
+ * @returns
36
+ */
37
+ private doesEntityNeedForeignKeyNullified;
38
+ /**
39
+ * Delete the entity and denormalized links from BelongsTo relationships
40
+ * @param self
41
+ */
42
+ private buildDeleteSelfTransactions;
43
+ /**
44
+ * Deletes an item when given the table keys
45
+ * @param keys - The key to delete representing the table keys, as opposed to the entities keys
29
46
  */
30
47
  private buildDeleteItemTransaction;
31
48
  /**
32
- * If the item has a JoinTable entry (is part of HasAndBelongsToMany relationship) then delete both JoinTable entries
33
- * @param item - BelongsToLink from HasAndBelongsToMany relationship
49
+ * Deletes an item when given the keys of the entity. Converts the keys to the table alias
50
+ * @param keys - The key to delete representing the entity keys, as opposed to the table keys
34
51
  */
35
- private buildDeleteJoinTableLinkTransaction;
52
+ private buildDeleteEntityTransaction;
36
53
  /**
37
54
  * If the item being deleted has a foreign key reference, nullify the associated relationship's ForeignKey attribute
38
55
  * If the ForeignKey is non nullable than it throws a NullConstraintViolationError
@@ -46,29 +63,16 @@ declare class Delete<T extends DynaRecord> extends OperationBase<T> {
46
63
  */
47
64
  private buildDeleteAssociatedBelongsTransaction;
48
65
  /**
49
- * Deletes associated BelongsToLink for a BelongsTo HasMany relationship
50
- * @param relMeta
51
- * @param entityId
52
- * @param foreignKeyValue
53
- */
54
- private buildDeleteBelongsToHasManyTransaction;
55
- /**
56
- * Deletes associated BelongsToLink for a BelongsTo HasOne relationship
57
- * @param relMeta
58
- * @param foreignKeyValue
59
- */
60
- private buildDeleteBelongsToHasOneTransaction;
61
- /**
62
- * Type guard to check if the item being evaluated is the currentClass
63
- * @param item
64
- * @returns
66
+ * If the item has a JoinTable entry (is part of HasAndBelongsToMany relationship) then delete both JoinTable entries
67
+ * @param item - Denormalized record from HasAndBelongsToMany relationship
65
68
  */
66
- private isEntityClass;
69
+ private buildDeleteJoinTableLinkTransaction;
67
70
  /**
68
71
  * Track validation errors and throw AggregateError after all validations have been run
69
72
  * @param err
70
73
  */
71
74
  private trackValidationError;
75
+ private buildKeyObject;
72
76
  }
73
77
  export default Delete;
74
78
  //# sourceMappingURL=Delete.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Delete.d.ts","sourceRoot":"","sources":["../../../../src/operations/Delete/Delete.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,kBAAkB,CAAC;AAc1C,OAAO,KAAK,EAAE,WAAW,EAAsB,MAAM,aAAa,CAAC;AAEnE,OAAO,aAAa,MAAM,kBAAkB,CAAC;AAI7C;;;;;;;;;GASG;AACH,cAAM,MAAM,CAAC,CAAC,SAAS,UAAU,CAAE,SAAQ,aAAa,CAAC,CAAC,CAAC;;gBAS7C,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IAiBlC;;;;;;;OAOG;IACU,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyC3C;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAmBlC;;;OAGG;IACH,OAAO,CAAC,mCAAmC;IAoB3C;;;;OAIG;IACH,OAAO,CAAC,iCAAiC;IA0CzC;;;;OAIG;IACH,OAAO,CAAC,uCAAuC;IA0B/C;;;;;OAKG;IACH,OAAO,CAAC,sCAAsC;IAkB9C;;;;OAIG;IACH,OAAO,CAAC,qCAAqC;IAiB7C;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAIrB;;;OAGG;IACH,OAAO,CAAC,oBAAoB;CAG7B;AAED,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"Delete.d.ts","sourceRoot":"","sources":["../../../../src/operations/Delete/Delete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAY/C,OAAO,KAAK,EAEV,WAAW,EAEZ,MAAM,aAAa,CAAC;AAErB,OAAO,aAAa,MAAM,kBAAkB,CAAC;AA2B7C;;;;;;;;;GASG;AACH,cAAM,MAAM,CAAC,CAAC,SAAS,UAAU,CAAE,SAAQ,aAAa,CAAC,CAAC,CAAC;;gBAS7C,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IAiBlC;;;;;;;OAOG;IACU,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B3C;;;;OAIG;YACW,QAAQ;IA+BtB;;;;OAIG;IACH,OAAO,CAAC,iCAAiC;IASzC;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IAOnC;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAalC;;;OAGG;IACH,OAAO,CAAC,4BAA4B;IAkBpC;;;;OAIG;YACW,iCAAiC;IA2B/C;;;;OAIG;IACH,OAAO,CAAC,uCAAuC;IA2B/C;;;OAGG;IACH,OAAO,CAAC,mCAAmC;IAiB3C;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,cAAc;CAcvB;AAED,eAAe,MAAM,CAAC"}