masterrecord 0.3.9 → 0.3.10
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/.eslintrc.js +290 -0
- package/.prettierrc.js +109 -0
- package/CHANGES.md +170 -0
- package/Migrations/cli.js +4 -2
- package/Migrations/migrations.js +13 -10
- package/Migrations/pathUtils.js +76 -0
- package/Migrations/pathUtils.test.js +53 -0
- package/context.js +1087 -410
- package/deleteManager.js +137 -40
- package/insertManager.js +358 -200
- package/package.json +1 -1
- package/readme.md +180 -3
package/deleteManager.js
CHANGED
|
@@ -1,60 +1,157 @@
|
|
|
1
|
-
// version 0.0
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
15
|
-
|
|
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
|