@fjell/lib-sequelize 4.4.1 → 4.4.2
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/dist/cjs/EventCoordinator.cjs +20 -1
- package/dist/cjs/KeyMaster.cjs +62 -24
- package/dist/cjs/Operations.cjs +2 -2
- package/dist/cjs/QueryBuilder.cjs +123 -21
- package/dist/cjs/RowProcessor.cjs +1 -1
- package/dist/cjs/ops/create.cjs +137 -6
- package/dist/cjs/ops/get.cjs +44 -8
- package/dist/cjs/ops/remove.cjs +48 -9
- package/dist/cjs/ops/update.cjs +4 -2
- package/dist/cjs/util/relationshipUtils.cjs +117 -0
- package/dist/es/EventCoordinator.js +20 -2
- package/dist/es/KeyMaster.js +62 -24
- package/dist/es/Operations.js +2 -2
- package/dist/es/QueryBuilder.js +123 -21
- package/dist/es/RowProcessor.js +1 -1
- package/dist/es/ops/create.js +137 -6
- package/dist/es/ops/get.js +44 -8
- package/dist/es/ops/remove.js +48 -9
- package/dist/es/ops/update.js +5 -3
- package/dist/es/util/relationshipUtils.js +112 -0
- package/dist/index.cjs +536 -67
- package/dist/index.cjs.map +1 -1
- package/dist/types/EventCoordinator.d.ts +1 -0
- package/dist/types/KeyMaster.d.ts +2 -1
- package/dist/types/QueryBuilder.d.ts +1 -0
- package/dist/types/ops/create.d.ts +1 -1
- package/dist/types/util/relationshipUtils.d.ts +21 -0
- package/package.json +7 -7
|
@@ -22,6 +22,24 @@ const populateEvents = (item)=>{
|
|
|
22
22
|
item.events = events;
|
|
23
23
|
return item;
|
|
24
24
|
};
|
|
25
|
+
const extractEvents = (item)=>{
|
|
26
|
+
logger.default('Extracting Events to database fields', {
|
|
27
|
+
item
|
|
28
|
+
});
|
|
29
|
+
if (item.events) {
|
|
30
|
+
var _item_events_created, _item_events_updated, _item_events_deleted;
|
|
31
|
+
if ((_item_events_created = item.events.created) === null || _item_events_created === void 0 ? void 0 : _item_events_created.at) {
|
|
32
|
+
item.createdAt = item.events.created.at;
|
|
33
|
+
}
|
|
34
|
+
if ((_item_events_updated = item.events.updated) === null || _item_events_updated === void 0 ? void 0 : _item_events_updated.at) {
|
|
35
|
+
item.updatedAt = item.events.updated.at;
|
|
36
|
+
}
|
|
37
|
+
if ((_item_events_deleted = item.events.deleted) === null || _item_events_deleted === void 0 ? void 0 : _item_events_deleted.at) {
|
|
38
|
+
item.deletedAt = item.events.deleted.at;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return item;
|
|
42
|
+
};
|
|
25
43
|
const removeEvents = (item)=>{
|
|
26
44
|
logger.default('Removing Events', {
|
|
27
45
|
item
|
|
@@ -30,6 +48,7 @@ const removeEvents = (item)=>{
|
|
|
30
48
|
return item;
|
|
31
49
|
};
|
|
32
50
|
|
|
51
|
+
exports.extractEvents = extractEvents;
|
|
33
52
|
exports.populateEvents = populateEvents;
|
|
34
53
|
exports.removeEvents = removeEvents;
|
|
35
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
54
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRXZlbnRDb29yZGluYXRvci5janMiLCJzb3VyY2VzIjpbXSwic291cmNlc0NvbnRlbnQiOltdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7In0=
|
package/dist/cjs/KeyMaster.cjs
CHANGED
|
@@ -3,8 +3,43 @@
|
|
|
3
3
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
4
|
|
|
5
5
|
const logger$1 = require('./logger.cjs');
|
|
6
|
+
const relationshipUtils = require('./util/relationshipUtils.cjs');
|
|
6
7
|
|
|
7
8
|
const logger = logger$1.default.get('sequelize', 'KeyMaster');
|
|
9
|
+
// Helper function to extract location key value from item
|
|
10
|
+
const extractLocationKeyValue = (model, item, locatorType, kta)=>{
|
|
11
|
+
logger.default('Extracting location key value', {
|
|
12
|
+
locatorType,
|
|
13
|
+
kta
|
|
14
|
+
});
|
|
15
|
+
const relationshipInfo = relationshipUtils.buildRelationshipPath(model, locatorType, kta, true);
|
|
16
|
+
if (!relationshipInfo.found) {
|
|
17
|
+
throw new Error(`Location key '${locatorType}' cannot be resolved on model '${model.name}' or through its relationships.`);
|
|
18
|
+
}
|
|
19
|
+
if (relationshipInfo.isDirect) {
|
|
20
|
+
// Direct foreign key field
|
|
21
|
+
const foreignKeyField = `${locatorType}Id`;
|
|
22
|
+
const value = item[foreignKeyField];
|
|
23
|
+
if (typeof value === 'undefined' || value === null) {
|
|
24
|
+
throw new Error(`Direct foreign key field '${foreignKeyField}' is missing or null in item`);
|
|
25
|
+
}
|
|
26
|
+
return value;
|
|
27
|
+
} else {
|
|
28
|
+
// Need to traverse relationship
|
|
29
|
+
// Try to get the value from the loaded relationship object
|
|
30
|
+
const relationshipObject = item[locatorType];
|
|
31
|
+
if (relationshipObject && typeof relationshipObject.id !== 'undefined') {
|
|
32
|
+
return relationshipObject.id;
|
|
33
|
+
}
|
|
34
|
+
// If the relationship object isn't loaded, we might need to look at the foreign key field
|
|
35
|
+
// This handles cases where we have the foreign key but not the full object
|
|
36
|
+
const foreignKeyField = `${locatorType}Id`;
|
|
37
|
+
if (typeof item[foreignKeyField] !== 'undefined' && item[foreignKeyField] !== null) {
|
|
38
|
+
return item[foreignKeyField];
|
|
39
|
+
}
|
|
40
|
+
throw new Error(`Unable to extract location key for '${locatorType}'. Neither the relationship object nor direct foreign key is available.`);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
8
43
|
const removeKey = (item)=>{
|
|
9
44
|
logger.default('Removing Key', {
|
|
10
45
|
item
|
|
@@ -39,11 +74,13 @@ const removeKey = (item)=>{
|
|
|
39
74
|
// }
|
|
40
75
|
// return item;
|
|
41
76
|
// }
|
|
42
|
-
const addKey = (item, keyTypes)=>{
|
|
77
|
+
const addKey = (model, item, keyTypes)=>{
|
|
43
78
|
logger.default('Adding Key', {
|
|
44
79
|
item
|
|
45
80
|
});
|
|
46
81
|
const key = {};
|
|
82
|
+
const modelClass = model.constructor;
|
|
83
|
+
const primaryKeyAttr = modelClass.primaryKeyAttribute;
|
|
47
84
|
if (Array.isArray(keyTypes) && keyTypes.length > 1) {
|
|
48
85
|
const type = [
|
|
49
86
|
...keyTypes
|
|
@@ -51,33 +88,34 @@ const addKey = (item, keyTypes)=>{
|
|
|
51
88
|
const pkType = type.shift();
|
|
52
89
|
Object.assign(key, {
|
|
53
90
|
kt: pkType,
|
|
54
|
-
pk: item
|
|
91
|
+
pk: item[primaryKeyAttr]
|
|
55
92
|
});
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
} else if (type.length === 5) {
|
|
75
|
-
throw new Error('Not implemented');
|
|
93
|
+
// Build location keys for composite key
|
|
94
|
+
const locationKeys = [];
|
|
95
|
+
for (const locatorType of type){
|
|
96
|
+
try {
|
|
97
|
+
const lk = extractLocationKeyValue(modelClass, item, locatorType, keyTypes);
|
|
98
|
+
locationKeys.push({
|
|
99
|
+
kt: locatorType,
|
|
100
|
+
lk
|
|
101
|
+
});
|
|
102
|
+
} catch (error) {
|
|
103
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
104
|
+
logger.error(`Failed to extract location key for '${locatorType}'`, {
|
|
105
|
+
error: errorMessage,
|
|
106
|
+
item,
|
|
107
|
+
keyTypes
|
|
108
|
+
});
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
76
111
|
}
|
|
112
|
+
Object.assign(key, {
|
|
113
|
+
loc: locationKeys
|
|
114
|
+
});
|
|
77
115
|
} else {
|
|
78
116
|
Object.assign(key, {
|
|
79
117
|
kt: keyTypes[0],
|
|
80
|
-
pk: item
|
|
118
|
+
pk: item[primaryKeyAttr]
|
|
81
119
|
});
|
|
82
120
|
}
|
|
83
121
|
Object.assign(item, {
|
|
@@ -88,4 +126,4 @@ const addKey = (item, keyTypes)=>{
|
|
|
88
126
|
|
|
89
127
|
exports.addKey = addKey;
|
|
90
128
|
exports.removeKey = removeKey;
|
|
91
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
129
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiS2V5TWFzdGVyLmNqcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzsifQ==
|
package/dist/cjs/Operations.cjs
CHANGED
|
@@ -14,12 +14,12 @@ const createOperations = (models, definition, registry)=>{
|
|
|
14
14
|
const operations = {};
|
|
15
15
|
operations.all = all.getAllOperation(models, definition, registry);
|
|
16
16
|
operations.one = one.getOneOperation(models, definition, registry);
|
|
17
|
-
operations.create = create.getCreateOperation();
|
|
17
|
+
operations.create = create.getCreateOperation(models, definition, registry);
|
|
18
18
|
operations.update = update.getUpdateOperation(models, definition, registry);
|
|
19
19
|
operations.get = get.getGetOperation(models, definition, registry);
|
|
20
20
|
operations.remove = remove.getRemoveOperation(models, definition);
|
|
21
21
|
operations.find = find.getFindOperation(models, definition, registry);
|
|
22
|
-
operations.upsert = ()=>{
|
|
22
|
+
operations.upsert = async ()=>{
|
|
23
23
|
throw new Error('Not implemented');
|
|
24
24
|
};
|
|
25
25
|
return operations;
|
|
@@ -84,7 +84,8 @@ const addReferenceQueries = (options, references, model)=>{
|
|
|
84
84
|
return options;
|
|
85
85
|
};
|
|
86
86
|
const addCompoundCondition = (options, compoundCondition, model)=>{
|
|
87
|
-
|
|
87
|
+
// Ensure options.where exists
|
|
88
|
+
options.where = options.where || {};
|
|
88
89
|
let compoundOp;
|
|
89
90
|
const compoundType = compoundCondition.compoundType;
|
|
90
91
|
if (compoundType === "AND") {
|
|
@@ -100,36 +101,135 @@ const addCompoundCondition = (options, compoundCondition, model)=>{
|
|
|
100
101
|
throw new Error('Nest Compound conditions not supported');
|
|
101
102
|
}
|
|
102
103
|
});
|
|
103
|
-
where
|
|
104
|
-
options.where
|
|
104
|
+
// Merge with existing where conditions instead of replacing
|
|
105
|
+
if (Object.keys(options.where).length > 0) {
|
|
106
|
+
// If there are existing conditions, wrap everything in an AND
|
|
107
|
+
options.where = {
|
|
108
|
+
[sequelize.Op.and]: [
|
|
109
|
+
options.where,
|
|
110
|
+
{
|
|
111
|
+
[compoundOp]: conditions
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
};
|
|
115
|
+
} else {
|
|
116
|
+
// If no existing conditions, just set the compound condition
|
|
117
|
+
options.where[compoundOp] = conditions;
|
|
118
|
+
}
|
|
105
119
|
return options;
|
|
106
120
|
};
|
|
107
|
-
const
|
|
108
|
-
|
|
121
|
+
const getSequelizeOperator = (operator)=>{
|
|
122
|
+
if (operator === '==') {
|
|
123
|
+
return sequelize.Op.eq;
|
|
124
|
+
} else if (operator === '<') {
|
|
125
|
+
return sequelize.Op.lt;
|
|
126
|
+
} else if (operator === '>') {
|
|
127
|
+
return sequelize.Op.gt;
|
|
128
|
+
} else if (operator === '<=') {
|
|
129
|
+
return sequelize.Op.lte;
|
|
130
|
+
} else if (operator === '>=') {
|
|
131
|
+
return sequelize.Op.gte;
|
|
132
|
+
} else if (operator === 'in') {
|
|
133
|
+
return sequelize.Op.in;
|
|
134
|
+
} else {
|
|
135
|
+
throw new Error(`Operator ${operator} not supported`);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
const addAssociationCondition = (conditions, condition, model)=>{
|
|
139
|
+
const [associationName, attributeName] = condition.column.split('.', 2);
|
|
140
|
+
// Check if the association exists on the model
|
|
141
|
+
if (!model.associations || !model.associations[associationName]) {
|
|
142
|
+
throw new Error(`Association ${associationName} not found on model ${model.name}`);
|
|
143
|
+
}
|
|
144
|
+
const association = model.associations[associationName];
|
|
145
|
+
const associatedModel = association.target;
|
|
146
|
+
// Check if the attribute exists on the associated model
|
|
147
|
+
if (!associatedModel.getAttributes()[attributeName]) {
|
|
148
|
+
throw new Error(`Attribute ${attributeName} not found on associated model ${associatedModel.name} for association ${associationName}`);
|
|
149
|
+
}
|
|
150
|
+
// Use Sequelize's $association.attribute$ syntax for querying associated models
|
|
151
|
+
const sequelizeAssociationColumn = `$${associationName}.${attributeName}$`;
|
|
152
|
+
const conditionOp = getSequelizeOperator(condition.operator);
|
|
153
|
+
conditions[sequelizeAssociationColumn] = {
|
|
154
|
+
[conditionOp]: condition.value
|
|
155
|
+
};
|
|
156
|
+
return conditions;
|
|
157
|
+
};
|
|
158
|
+
const addAttributeCondition = (conditions, condition, model)=>{
|
|
109
159
|
const conditionColumn = condition.column;
|
|
110
160
|
if (!model.getAttributes()[conditionColumn]) {
|
|
111
161
|
throw new Error(`Condition column ${conditionColumn} not found on model ${model.name}`);
|
|
112
162
|
}
|
|
113
|
-
|
|
114
|
-
conditionOp = sequelize.Op.eq;
|
|
115
|
-
} else if (condition.operator === '<') {
|
|
116
|
-
conditionOp = sequelize.Op.lt;
|
|
117
|
-
} else if (condition.operator === '>') {
|
|
118
|
-
conditionOp = sequelize.Op.gt;
|
|
119
|
-
} else if (condition.operator === '<=') {
|
|
120
|
-
conditionOp = sequelize.Op.lte;
|
|
121
|
-
} else if (condition.operator === '>=') {
|
|
122
|
-
conditionOp = sequelize.Op.gte;
|
|
123
|
-
} else if (condition.operator === 'in') {
|
|
124
|
-
conditionOp = sequelize.Op.in;
|
|
125
|
-
} else {
|
|
126
|
-
throw new Error(`Operator ${condition.operator} not supported`);
|
|
127
|
-
}
|
|
163
|
+
const conditionOp = getSequelizeOperator(condition.operator);
|
|
128
164
|
conditions[conditionColumn] = {
|
|
129
165
|
[conditionOp]: condition.value
|
|
130
166
|
};
|
|
131
167
|
return conditions;
|
|
132
168
|
};
|
|
169
|
+
const addCondition = (conditions, condition, model)=>{
|
|
170
|
+
const conditionColumn = condition.column;
|
|
171
|
+
// Check if this is an association query (contains a dot)
|
|
172
|
+
if (conditionColumn.includes('.')) {
|
|
173
|
+
return addAssociationCondition(conditions, condition, model);
|
|
174
|
+
}
|
|
175
|
+
// Handle regular column queries
|
|
176
|
+
return addAttributeCondition(conditions, condition, model);
|
|
177
|
+
};
|
|
178
|
+
const collectAssociationsFromConditions = (conditions)=>{
|
|
179
|
+
const associations = new Set();
|
|
180
|
+
const processObject = (obj)=>{
|
|
181
|
+
if (typeof obj === 'object' && obj !== null) {
|
|
182
|
+
// Check string keys
|
|
183
|
+
Object.keys(obj).forEach((key)=>{
|
|
184
|
+
// Check if this is an association reference ($association.attribute$)
|
|
185
|
+
if (typeof key === 'string' && key.startsWith('$') && key.endsWith('$') && key.includes('.')) {
|
|
186
|
+
const associationName = key.substring(1, key.indexOf('.'));
|
|
187
|
+
associations.add(associationName);
|
|
188
|
+
}
|
|
189
|
+
// Recursively process nested objects
|
|
190
|
+
if (typeof obj[key] === 'object') {
|
|
191
|
+
processObject(obj[key]);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
// Also check Symbol keys (for compound conditions like Op.and, Op.or)
|
|
195
|
+
Object.getOwnPropertySymbols(obj).forEach((symbol)=>{
|
|
196
|
+
if (typeof obj[symbol] === 'object') {
|
|
197
|
+
processObject(obj[symbol]);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
// Handle arrays (for compound conditions that might be arrays)
|
|
202
|
+
if (Array.isArray(obj)) {
|
|
203
|
+
obj.forEach((item)=>{
|
|
204
|
+
if (typeof item === 'object') {
|
|
205
|
+
processObject(item);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
processObject(conditions);
|
|
211
|
+
return associations;
|
|
212
|
+
};
|
|
213
|
+
const addAssociationIncludes = (options, model)=>{
|
|
214
|
+
// Collect all association names used in conditions
|
|
215
|
+
const referencedAssociations = collectAssociationsFromConditions(options.where);
|
|
216
|
+
if (referencedAssociations.size > 0) {
|
|
217
|
+
options.include = options.include || [];
|
|
218
|
+
// Add each referenced association to the include array
|
|
219
|
+
referencedAssociations.forEach((associationName)=>{
|
|
220
|
+
// Check if this association is already included
|
|
221
|
+
const alreadyIncluded = options.include.some((inc)=>typeof inc === 'string' && inc === associationName || typeof inc === 'object' && inc.association === associationName);
|
|
222
|
+
if (!alreadyIncluded && model.associations && model.associations[associationName]) {
|
|
223
|
+
options.include.push({
|
|
224
|
+
model: model.associations[associationName].target,
|
|
225
|
+
as: associationName,
|
|
226
|
+
required: false // Use LEFT JOIN so records without associations are still returned
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
return options;
|
|
232
|
+
};
|
|
133
233
|
const buildQuery = (itemQuery, model)=>{
|
|
134
234
|
logger.default('build', {
|
|
135
235
|
itemQuery
|
|
@@ -179,10 +279,12 @@ const buildQuery = (itemQuery, model)=>{
|
|
|
179
279
|
];
|
|
180
280
|
});
|
|
181
281
|
}
|
|
282
|
+
// Add includes for any associations referenced in conditions
|
|
283
|
+
options = addAssociationIncludes(options, model);
|
|
182
284
|
return options;
|
|
183
285
|
};
|
|
184
286
|
|
|
185
287
|
exports.addCompoundCondition = addCompoundCondition;
|
|
186
288
|
exports.addCondition = addCondition;
|
|
187
289
|
exports.buildQuery = buildQuery;
|
|
188
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
290
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUXVlcnlCdWlsZGVyLmNqcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OyJ9
|
|
@@ -18,7 +18,7 @@ const processRow = async (row, keyTypes, referenceDefinitions, aggregationDefini
|
|
|
18
18
|
plain: true
|
|
19
19
|
});
|
|
20
20
|
logger.default('Adding Key to Item with Key Types: %s', general.stringifyJSON(keyTypes));
|
|
21
|
-
item = KeyMaster.addKey(item, keyTypes);
|
|
21
|
+
item = KeyMaster.addKey(row, item, keyTypes);
|
|
22
22
|
item = EventCoordinator.populateEvents(item);
|
|
23
23
|
logger.default('Key Added to Item: %s', general.stringifyJSON(item.key));
|
|
24
24
|
if (referenceDefinitions && referenceDefinitions.length > 0) {
|
package/dist/cjs/ops/create.cjs
CHANGED
|
@@ -2,22 +2,153 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
4
|
|
|
5
|
+
const core = require('@fjell/core');
|
|
5
6
|
const logger$1 = require('../logger.cjs');
|
|
7
|
+
const RowProcessor = require('../RowProcessor.cjs');
|
|
8
|
+
const EventCoordinator = require('../EventCoordinator.cjs');
|
|
9
|
+
const relationshipUtils = require('../util/relationshipUtils.cjs');
|
|
6
10
|
|
|
7
11
|
const logger = logger$1.default.get('sequelize', 'ops', 'create');
|
|
8
|
-
|
|
9
|
-
models,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
// Helper function to validate hierarchical chain exists
|
|
13
|
+
async function validateHierarchicalChain(models, locKey, kta) {
|
|
14
|
+
// Find the direct parent model that contains this locator
|
|
15
|
+
const locatorIndex = kta.indexOf(locKey.kt);
|
|
16
|
+
if (locatorIndex === -1) {
|
|
17
|
+
throw new Error(`Locator type '${locKey.kt}' not found in kta array`);
|
|
18
|
+
}
|
|
19
|
+
// Get the model for this locator
|
|
20
|
+
const locatorModel = models[locatorIndex] || models[0]; // Fallback to primary model
|
|
21
|
+
// Build a query to validate the chain exists
|
|
22
|
+
const chainResult = relationshipUtils.buildRelationshipChain(locatorModel, kta, locatorIndex, kta.length - 1);
|
|
23
|
+
if (!chainResult.success) {
|
|
24
|
+
// If we can't build a chain, just validate the record exists
|
|
25
|
+
const record = await locatorModel.findByPk(locKey.lk);
|
|
26
|
+
if (!record) {
|
|
27
|
+
throw new Error(`Referenced ${locKey.kt} with id ${locKey.lk} does not exist`);
|
|
28
|
+
}
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
// Validate that the chain exists
|
|
32
|
+
const queryOptions = {
|
|
33
|
+
where: {
|
|
34
|
+
id: locKey.lk
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
if (chainResult.includes && chainResult.includes.length > 0) {
|
|
38
|
+
queryOptions.include = chainResult.includes;
|
|
39
|
+
}
|
|
40
|
+
const record = await locatorModel.findOne(queryOptions);
|
|
41
|
+
if (!record) {
|
|
42
|
+
throw new Error(`Referenced ${locKey.kt} with id ${locKey.lk} does not exist or chain is invalid`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const getCreateOperation = (models, definition, registry)=>{
|
|
12
46
|
const create = async (item, options)=>{
|
|
13
47
|
logger.default('Create', {
|
|
14
48
|
item,
|
|
15
49
|
options
|
|
16
50
|
});
|
|
17
|
-
|
|
51
|
+
const { coordinate, options: { references, aggregations } } = definition;
|
|
52
|
+
const { kta } = coordinate;
|
|
53
|
+
// Get the primary model (first model in array)
|
|
54
|
+
const model = models[0];
|
|
55
|
+
const modelAttributes = model.getAttributes();
|
|
56
|
+
// Validate that all item attributes exist on the model
|
|
57
|
+
let itemData = {
|
|
58
|
+
...item
|
|
59
|
+
};
|
|
60
|
+
// TODO: We need the opposite of processRow, something to step down from fjell to database.
|
|
61
|
+
itemData = EventCoordinator.extractEvents(itemData);
|
|
62
|
+
itemData = EventCoordinator.removeEvents(itemData);
|
|
63
|
+
for (const key of Object.keys(itemData)){
|
|
64
|
+
if (!modelAttributes[key]) {
|
|
65
|
+
throw new Error(`Attribute '${key}' does not exist on model ${model.name}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Handle key options
|
|
69
|
+
// If a key is supplied, assume its contents are to be assigned to the appropriate ids.
|
|
70
|
+
// For most cases this will be null as key generation is often through autoIncrement.
|
|
71
|
+
// If this is a CItem then the locations will be present.
|
|
72
|
+
if (options === null || options === void 0 ? void 0 : options.key) {
|
|
73
|
+
const key = options.key;
|
|
74
|
+
if (core.isPriKey(key)) {
|
|
75
|
+
// Set the primary key
|
|
76
|
+
itemData.id = key.pk;
|
|
77
|
+
} else if (core.isComKey(key)) {
|
|
78
|
+
// Set primary key
|
|
79
|
+
itemData.id = key.pk;
|
|
80
|
+
// Process location keys - only set direct foreign keys, validate hierarchical chains
|
|
81
|
+
const comKey = key;
|
|
82
|
+
const directLocations = [];
|
|
83
|
+
const hierarchicalLocations = [];
|
|
84
|
+
// Categorize location keys as direct or hierarchical
|
|
85
|
+
for (const locKey of comKey.loc){
|
|
86
|
+
const relationshipInfo = relationshipUtils.buildRelationshipPath(model, locKey.kt, kta, true);
|
|
87
|
+
if (!relationshipInfo.found) {
|
|
88
|
+
const errorMessage = `Composite key locator '${locKey.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
|
|
89
|
+
logger.error(errorMessage, {
|
|
90
|
+
key: comKey,
|
|
91
|
+
kta
|
|
92
|
+
});
|
|
93
|
+
throw new Error(errorMessage);
|
|
94
|
+
}
|
|
95
|
+
if (relationshipInfo.isDirect) {
|
|
96
|
+
directLocations.push(locKey);
|
|
97
|
+
} else {
|
|
98
|
+
hierarchicalLocations.push(locKey);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Set direct foreign keys
|
|
102
|
+
for (const locKey of directLocations){
|
|
103
|
+
const foreignKeyField = locKey.kt + 'Id';
|
|
104
|
+
itemData[foreignKeyField] = locKey.lk;
|
|
105
|
+
}
|
|
106
|
+
// Validate hierarchical chains exist
|
|
107
|
+
for (const locKey of hierarchicalLocations){
|
|
108
|
+
await validateHierarchicalChain(models, locKey, kta);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Handle locations options
|
|
113
|
+
// This is the most frequent way relationship ids will be set
|
|
114
|
+
if (options === null || options === void 0 ? void 0 : options.locations) {
|
|
115
|
+
const directLocations = [];
|
|
116
|
+
const hierarchicalLocations = [];
|
|
117
|
+
// Categorize location keys as direct or hierarchical
|
|
118
|
+
for (const locKey of options.locations){
|
|
119
|
+
const relationshipInfo = relationshipUtils.buildRelationshipPath(model, locKey.kt, kta, true);
|
|
120
|
+
if (!relationshipInfo.found) {
|
|
121
|
+
const errorMessage = `Location key '${locKey.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
|
|
122
|
+
logger.error(errorMessage, {
|
|
123
|
+
locations: options.locations,
|
|
124
|
+
kta
|
|
125
|
+
});
|
|
126
|
+
throw new Error(errorMessage);
|
|
127
|
+
}
|
|
128
|
+
if (relationshipInfo.isDirect) {
|
|
129
|
+
directLocations.push(locKey);
|
|
130
|
+
} else {
|
|
131
|
+
hierarchicalLocations.push(locKey);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Set direct foreign keys
|
|
135
|
+
for (const locKey of directLocations){
|
|
136
|
+
const foreignKeyField = locKey.kt + 'Id';
|
|
137
|
+
itemData[foreignKeyField] = locKey.lk;
|
|
138
|
+
}
|
|
139
|
+
// Validate hierarchical chains exist
|
|
140
|
+
for (const locKey of hierarchicalLocations){
|
|
141
|
+
await validateHierarchicalChain(models, locKey, kta);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Create the record
|
|
145
|
+
const createdRecord = await model.create(itemData);
|
|
146
|
+
// Add key and events
|
|
147
|
+
const processedRecord = await RowProcessor.processRow(createdRecord, kta, references, aggregations, registry);
|
|
148
|
+
return core.validateKeys(processedRecord, kta);
|
|
18
149
|
};
|
|
19
150
|
return create;
|
|
20
151
|
};
|
|
21
152
|
|
|
22
153
|
exports.getCreateOperation = getCreateOperation;
|
|
23
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
154
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlLmNqcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7In0=
|
package/dist/cjs/ops/get.cjs
CHANGED
|
@@ -6,8 +6,45 @@ const core = require('@fjell/core');
|
|
|
6
6
|
const logger$1 = require('../logger.cjs');
|
|
7
7
|
const RowProcessor = require('../RowProcessor.cjs');
|
|
8
8
|
const Library = require('@fjell/lib');
|
|
9
|
+
const relationshipUtils = require('../util/relationshipUtils.cjs');
|
|
9
10
|
|
|
10
11
|
const logger = logger$1.default.get('sequelize', 'ops', 'get');
|
|
12
|
+
// Helper function to process composite key and build query options
|
|
13
|
+
const processCompositeKey = (comKey, model, kta)=>{
|
|
14
|
+
const where = {
|
|
15
|
+
id: comKey.pk
|
|
16
|
+
};
|
|
17
|
+
const includes = [];
|
|
18
|
+
for (const locator of comKey.loc){
|
|
19
|
+
const relationshipInfo = relationshipUtils.buildRelationshipPath(model, locator.kt, kta);
|
|
20
|
+
if (!relationshipInfo.found) {
|
|
21
|
+
const errorMessage = `Composite key locator '${locator.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
|
|
22
|
+
logger.error(errorMessage, {
|
|
23
|
+
key: comKey,
|
|
24
|
+
kta
|
|
25
|
+
});
|
|
26
|
+
throw new Error(errorMessage);
|
|
27
|
+
}
|
|
28
|
+
if (relationshipInfo.path) {
|
|
29
|
+
// This requires a relationship traversal
|
|
30
|
+
where[relationshipInfo.path] = locator.lk;
|
|
31
|
+
if (relationshipInfo.includes) {
|
|
32
|
+
includes.push(...relationshipInfo.includes);
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
// This is a direct field
|
|
36
|
+
const fieldName = `${locator.kt}Id`;
|
|
37
|
+
where[fieldName] = locator.lk;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const result = {
|
|
41
|
+
where
|
|
42
|
+
};
|
|
43
|
+
if (includes.length > 0) {
|
|
44
|
+
result.include = includes;
|
|
45
|
+
}
|
|
46
|
+
return result;
|
|
47
|
+
};
|
|
11
48
|
const getGetOperation = (models, definition, registry)=>{
|
|
12
49
|
const { coordinate, options: { references, aggregations } } = definition;
|
|
13
50
|
const { kta } = coordinate;
|
|
@@ -24,17 +61,16 @@ const getGetOperation = (models, definition, registry)=>{
|
|
|
24
61
|
const model = models[0];
|
|
25
62
|
let item;
|
|
26
63
|
if (core.isPriKey(itemKey)) {
|
|
64
|
+
// This is the easy case because we can just find the item by its primary key
|
|
27
65
|
item = await model.findByPk(itemKey.pk);
|
|
28
66
|
} else if (core.isComKey(itemKey)) {
|
|
29
|
-
|
|
67
|
+
// This is a composite key, so we need to build a where clause based on the composite key's locators
|
|
30
68
|
const comKey = itemKey;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
id: comKey.pk,
|
|
35
|
-
[(comKey === null || comKey === void 0 ? void 0 : (_comKey_loc_ = comKey.loc[0]) === null || _comKey_loc_ === void 0 ? void 0 : _comKey_loc_.kt) + 'Id']: comKey === null || comKey === void 0 ? void 0 : (_comKey_loc_1 = comKey.loc[0]) === null || _comKey_loc_1 === void 0 ? void 0 : _comKey_loc_1.lk
|
|
36
|
-
}
|
|
69
|
+
const queryOptions = processCompositeKey(comKey, model, kta);
|
|
70
|
+
logger.default('Composite key query', {
|
|
71
|
+
queryOptions
|
|
37
72
|
});
|
|
73
|
+
item = await model.findOne(queryOptions);
|
|
38
74
|
}
|
|
39
75
|
if (!item) {
|
|
40
76
|
throw new Library.NotFoundError('get', coordinate, key);
|
|
@@ -46,4 +82,4 @@ const getGetOperation = (models, definition, registry)=>{
|
|
|
46
82
|
};
|
|
47
83
|
|
|
48
84
|
exports.getGetOperation = getGetOperation;
|
|
49
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
85
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0LmNqcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7In0=
|