masterrecord 0.3.9 → 0.3.11

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/deleteManager.js CHANGED
@@ -1,60 +1,157 @@
1
- // version 0.0.3
2
- var tools = require('./Tools');
3
- class DeleteManager{
4
- constructor(sqlEngine, entities){
1
+ // version 1.0.0 - FAANG-Level Refactored
2
+ const tools = require('./Tools');
3
+
4
+ // Constants for relationship types
5
+ const RELATIONSHIP_TYPES = {
6
+ HAS_ONE: 'hasOne',
7
+ HAS_MANY: 'hasMany',
8
+ HAS_MANY_THROUGH: 'hasManyThrough'
9
+ };
10
+
11
+ /**
12
+ * Manages cascade deletion of entities and their relationships
13
+ * @class DeleteManager
14
+ */
15
+ class DeleteManager {
16
+ constructor(sqlEngine, entities) {
17
+ if (!sqlEngine) {
18
+ throw new Error('DeleteManager requires a valid SQL engine');
19
+ }
5
20
  this._SQLEngine = sqlEngine;
6
- this._allEntities = entities;
21
+ this._allEntities = entities || [];
7
22
  }
8
23
 
9
- init(currentModel){
10
- var $that = this;
11
- try{
12
- this.cascadeDelete(currentModel);
24
+ /**
25
+ * Initialize deletion for an entity or array of entities
26
+ * @param {Object|Array} currentModel - Entity or entities to delete
27
+ * @throws {Error} If deletion fails
28
+ */
29
+ init(currentModel) {
30
+ // Input validation
31
+ if (!currentModel) {
32
+ throw new Error('DeleteManager.init() requires a valid model');
13
33
  }
14
- catch(error){
15
- throw error;
34
+
35
+ try {
36
+ this.cascadeDelete(currentModel);
37
+ } catch (error) {
38
+ // Add context to error
39
+ const entityName = currentModel.__entity?.__name || 'unknown';
40
+ throw new Error(`Failed to delete ${entityName}: ${error.message}`, { cause: error });
16
41
  }
17
42
  }
18
43
 
19
- cascadeDelete(currentModel){
20
- var $that = this;
21
- if(!Array.isArray(currentModel)){
22
- const entityKeys = Object.keys(currentModel.__entity);
23
- // loop though all entity properties
24
- for (const property of entityKeys) {
25
- // cascade delete
26
- if(currentModel.__entity[property].type === "hasOne" || currentModel.__entity[property].type === "hasMany" || currentModel.__entity[property].type === "hasManyThrough"){
27
- var curModel = currentModel[property];
28
- if(curModel === null){
29
- // check if state is nullable - if so and nothing comes back dont call cascadeDelete
30
- var prp = currentModel.__entity[property];
31
- if(!prp.nullable){
32
- throw "No relationship record found - please set hasOne or hasMany to nullable. "
33
- }
34
- }
35
- else{
36
- $that.cascadeDelete( currentModel[property]);
44
+ /**
45
+ * Recursively cascade delete an entity and its relationships
46
+ * @param {Object|Array} currentModel - Entity or entities to delete
47
+ * @throws {Error} If cascade deletion fails
48
+ */
49
+ cascadeDelete(currentModel) {
50
+ if (!currentModel) {
51
+ return; // Nothing to delete
52
+ }
53
+
54
+ if (!Array.isArray(currentModel)) {
55
+ this._deleteSingleEntity(currentModel);
56
+ } else {
57
+ this._deleteMultipleEntities(currentModel);
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Delete a single entity with cascade
63
+ * @private
64
+ * @param {Object} entity - Entity to delete
65
+ */
66
+ _deleteSingleEntity(entity) {
67
+ // Validate entity structure
68
+ if (!entity.__entity) {
69
+ throw new Error('Entity missing __entity metadata');
70
+ }
71
+
72
+ const entityKeys = Object.keys(entity.__entity);
73
+
74
+ // Loop through all entity properties to find relationships
75
+ for (const property of entityKeys) {
76
+ const propertyConfig = entity.__entity[property];
77
+
78
+ // Check if this is a relationship that needs cascade deletion
79
+ if (this._isRelationshipType(propertyConfig.type)) {
80
+ const relatedModel = entity[property];
81
+
82
+ if (relatedModel === null || relatedModel === undefined) {
83
+ // Check if relationship is required (not nullable)
84
+ if (!propertyConfig.nullable) {
85
+ throw new Error(
86
+ `Cannot delete ${entity.__entity.__name}: ` +
87
+ `required relationship '${property}' is null. ` +
88
+ `Set nullable: true if this is intentional.`
89
+ );
37
90
  }
91
+ } else {
92
+ // Recursively delete related entities
93
+ this.cascadeDelete(relatedModel);
38
94
  }
39
95
  }
40
- this._SQLEngine.delete(currentModel);
41
96
  }
42
- else{
43
97
 
44
- for(let i = 0 ; i < currentModel.length; i++) {
45
- const entityKeys = Object.keys(currentModel[i].__entity);
46
- // loop though all entity properties
47
- for (const property of entityKeys) {
48
- // cascade delete
49
- if(currentModel[i].__entity[property].type === "hasOne" || currentModel[i].__entity[property].type === "hasMany" || currentModel[i].__entity[property].type === "hasManyThrough"){
50
- $that.cascadeDelete( currentModel[i][property]);
98
+ // Delete the entity itself after cascading
99
+ this._SQLEngine.delete(entity);
100
+ }
101
+
102
+ /**
103
+ * Delete multiple entities with cascade
104
+ * @private
105
+ * @param {Array} entities - Array of entities to delete
106
+ */
107
+ _deleteMultipleEntities(entities) {
108
+ if (entities.length === 0) {
109
+ return; // Nothing to delete
110
+ }
111
+
112
+ // Process each entity
113
+ for (let i = 0; i < entities.length; i++) {
114
+ const entity = entities[i];
115
+
116
+ if (!entity) {
117
+ console.warn(`DeleteManager: Skipping null entity at index ${i}`);
118
+ continue;
119
+ }
120
+
121
+ if (!entity.__entity) {
122
+ throw new Error(`Entity at index ${i} missing __entity metadata`);
123
+ }
124
+
125
+ const entityKeys = Object.keys(entity.__entity);
126
+
127
+ // Loop through relationships for cascade
128
+ for (const property of entityKeys) {
129
+ const propertyConfig = entity.__entity[property];
130
+
131
+ if (this._isRelationshipType(propertyConfig.type)) {
132
+ const relatedModel = entity[property];
133
+
134
+ if (relatedModel !== null && relatedModel !== undefined) {
135
+ this.cascadeDelete(relatedModel);
51
136
  }
52
137
  }
53
- this._SQLEngine.delete(currentModel[i]);
54
138
  }
139
+
140
+ // Delete the entity
141
+ this._SQLEngine.delete(entity);
55
142
  }
56
-
143
+ }
57
144
 
145
+ /**
146
+ * Check if a property type is a relationship that requires cascade deletion
147
+ * @private
148
+ * @param {string} type - Property type
149
+ * @returns {boolean} True if relationship type
150
+ */
151
+ _isRelationshipType(type) {
152
+ return type === RELATIONSHIP_TYPES.HAS_ONE ||
153
+ type === RELATIONSHIP_TYPES.HAS_MANY ||
154
+ type === RELATIONSHIP_TYPES.HAS_MANY_THROUGH;
58
155
  }
59
156
  }
60
157