@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
package/dist/es/ops/create.js
CHANGED
|
@@ -1,19 +1,150 @@
|
|
|
1
|
+
import { isPriKey, isComKey, validateKeys } from '@fjell/core';
|
|
1
2
|
import LibLogger from '../logger.js';
|
|
3
|
+
import { processRow } from '../RowProcessor.js';
|
|
4
|
+
import { extractEvents, removeEvents } from '../EventCoordinator.js';
|
|
5
|
+
import { buildRelationshipPath, buildRelationshipChain } from '../util/relationshipUtils.js';
|
|
2
6
|
|
|
3
7
|
const logger = LibLogger.get('sequelize', 'ops', 'create');
|
|
4
|
-
|
|
5
|
-
models,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
// Helper function to validate hierarchical chain exists
|
|
9
|
+
async function validateHierarchicalChain(models, locKey, kta) {
|
|
10
|
+
// Find the direct parent model that contains this locator
|
|
11
|
+
const locatorIndex = kta.indexOf(locKey.kt);
|
|
12
|
+
if (locatorIndex === -1) {
|
|
13
|
+
throw new Error(`Locator type '${locKey.kt}' not found in kta array`);
|
|
14
|
+
}
|
|
15
|
+
// Get the model for this locator
|
|
16
|
+
const locatorModel = models[locatorIndex] || models[0]; // Fallback to primary model
|
|
17
|
+
// Build a query to validate the chain exists
|
|
18
|
+
const chainResult = buildRelationshipChain(locatorModel, kta, locatorIndex, kta.length - 1);
|
|
19
|
+
if (!chainResult.success) {
|
|
20
|
+
// If we can't build a chain, just validate the record exists
|
|
21
|
+
const record = await locatorModel.findByPk(locKey.lk);
|
|
22
|
+
if (!record) {
|
|
23
|
+
throw new Error(`Referenced ${locKey.kt} with id ${locKey.lk} does not exist`);
|
|
24
|
+
}
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
// Validate that the chain exists
|
|
28
|
+
const queryOptions = {
|
|
29
|
+
where: {
|
|
30
|
+
id: locKey.lk
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
if (chainResult.includes && chainResult.includes.length > 0) {
|
|
34
|
+
queryOptions.include = chainResult.includes;
|
|
35
|
+
}
|
|
36
|
+
const record = await locatorModel.findOne(queryOptions);
|
|
37
|
+
if (!record) {
|
|
38
|
+
throw new Error(`Referenced ${locKey.kt} with id ${locKey.lk} does not exist or chain is invalid`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const getCreateOperation = (models, definition, registry)=>{
|
|
8
42
|
const create = async (item, options)=>{
|
|
9
43
|
logger.default('Create', {
|
|
10
44
|
item,
|
|
11
45
|
options
|
|
12
46
|
});
|
|
13
|
-
|
|
47
|
+
const { coordinate, options: { references, aggregations } } = definition;
|
|
48
|
+
const { kta } = coordinate;
|
|
49
|
+
// Get the primary model (first model in array)
|
|
50
|
+
const model = models[0];
|
|
51
|
+
const modelAttributes = model.getAttributes();
|
|
52
|
+
// Validate that all item attributes exist on the model
|
|
53
|
+
let itemData = {
|
|
54
|
+
...item
|
|
55
|
+
};
|
|
56
|
+
// TODO: We need the opposite of processRow, something to step down from fjell to database.
|
|
57
|
+
itemData = extractEvents(itemData);
|
|
58
|
+
itemData = removeEvents(itemData);
|
|
59
|
+
for (const key of Object.keys(itemData)){
|
|
60
|
+
if (!modelAttributes[key]) {
|
|
61
|
+
throw new Error(`Attribute '${key}' does not exist on model ${model.name}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Handle key options
|
|
65
|
+
// If a key is supplied, assume its contents are to be assigned to the appropriate ids.
|
|
66
|
+
// For most cases this will be null as key generation is often through autoIncrement.
|
|
67
|
+
// If this is a CItem then the locations will be present.
|
|
68
|
+
if (options === null || options === void 0 ? void 0 : options.key) {
|
|
69
|
+
const key = options.key;
|
|
70
|
+
if (isPriKey(key)) {
|
|
71
|
+
// Set the primary key
|
|
72
|
+
itemData.id = key.pk;
|
|
73
|
+
} else if (isComKey(key)) {
|
|
74
|
+
// Set primary key
|
|
75
|
+
itemData.id = key.pk;
|
|
76
|
+
// Process location keys - only set direct foreign keys, validate hierarchical chains
|
|
77
|
+
const comKey = key;
|
|
78
|
+
const directLocations = [];
|
|
79
|
+
const hierarchicalLocations = [];
|
|
80
|
+
// Categorize location keys as direct or hierarchical
|
|
81
|
+
for (const locKey of comKey.loc){
|
|
82
|
+
const relationshipInfo = buildRelationshipPath(model, locKey.kt, kta, true);
|
|
83
|
+
if (!relationshipInfo.found) {
|
|
84
|
+
const errorMessage = `Composite key locator '${locKey.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
|
|
85
|
+
logger.error(errorMessage, {
|
|
86
|
+
key: comKey,
|
|
87
|
+
kta
|
|
88
|
+
});
|
|
89
|
+
throw new Error(errorMessage);
|
|
90
|
+
}
|
|
91
|
+
if (relationshipInfo.isDirect) {
|
|
92
|
+
directLocations.push(locKey);
|
|
93
|
+
} else {
|
|
94
|
+
hierarchicalLocations.push(locKey);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Set direct foreign keys
|
|
98
|
+
for (const locKey of directLocations){
|
|
99
|
+
const foreignKeyField = locKey.kt + 'Id';
|
|
100
|
+
itemData[foreignKeyField] = locKey.lk;
|
|
101
|
+
}
|
|
102
|
+
// Validate hierarchical chains exist
|
|
103
|
+
for (const locKey of hierarchicalLocations){
|
|
104
|
+
await validateHierarchicalChain(models, locKey, kta);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Handle locations options
|
|
109
|
+
// This is the most frequent way relationship ids will be set
|
|
110
|
+
if (options === null || options === void 0 ? void 0 : options.locations) {
|
|
111
|
+
const directLocations = [];
|
|
112
|
+
const hierarchicalLocations = [];
|
|
113
|
+
// Categorize location keys as direct or hierarchical
|
|
114
|
+
for (const locKey of options.locations){
|
|
115
|
+
const relationshipInfo = buildRelationshipPath(model, locKey.kt, kta, true);
|
|
116
|
+
if (!relationshipInfo.found) {
|
|
117
|
+
const errorMessage = `Location key '${locKey.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
|
|
118
|
+
logger.error(errorMessage, {
|
|
119
|
+
locations: options.locations,
|
|
120
|
+
kta
|
|
121
|
+
});
|
|
122
|
+
throw new Error(errorMessage);
|
|
123
|
+
}
|
|
124
|
+
if (relationshipInfo.isDirect) {
|
|
125
|
+
directLocations.push(locKey);
|
|
126
|
+
} else {
|
|
127
|
+
hierarchicalLocations.push(locKey);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Set direct foreign keys
|
|
131
|
+
for (const locKey of directLocations){
|
|
132
|
+
const foreignKeyField = locKey.kt + 'Id';
|
|
133
|
+
itemData[foreignKeyField] = locKey.lk;
|
|
134
|
+
}
|
|
135
|
+
// Validate hierarchical chains exist
|
|
136
|
+
for (const locKey of hierarchicalLocations){
|
|
137
|
+
await validateHierarchicalChain(models, locKey, kta);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Create the record
|
|
141
|
+
const createdRecord = await model.create(itemData);
|
|
142
|
+
// Add key and events
|
|
143
|
+
const processedRecord = await processRow(createdRecord, kta, references, aggregations, registry);
|
|
144
|
+
return validateKeys(processedRecord, kta);
|
|
14
145
|
};
|
|
15
146
|
return create;
|
|
16
147
|
};
|
|
17
148
|
|
|
18
149
|
export { getCreateOperation };
|
|
19
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
150
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlLmpzIiwic291cmNlcyI6W10sInNvdXJjZXNDb250ZW50IjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OyJ9
|
package/dist/es/ops/get.js
CHANGED
|
@@ -2,8 +2,45 @@ import { isValidItemKey, isPriKey, isComKey, validateKeys } from '@fjell/core';
|
|
|
2
2
|
import LibLogger from '../logger.js';
|
|
3
3
|
import { processRow } from '../RowProcessor.js';
|
|
4
4
|
import { NotFoundError } from '@fjell/lib';
|
|
5
|
+
import { buildRelationshipPath } from '../util/relationshipUtils.js';
|
|
5
6
|
|
|
6
7
|
const logger = LibLogger.get('sequelize', 'ops', 'get');
|
|
8
|
+
// Helper function to process composite key and build query options
|
|
9
|
+
const processCompositeKey = (comKey, model, kta)=>{
|
|
10
|
+
const where = {
|
|
11
|
+
id: comKey.pk
|
|
12
|
+
};
|
|
13
|
+
const includes = [];
|
|
14
|
+
for (const locator of comKey.loc){
|
|
15
|
+
const relationshipInfo = buildRelationshipPath(model, locator.kt, kta);
|
|
16
|
+
if (!relationshipInfo.found) {
|
|
17
|
+
const errorMessage = `Composite key locator '${locator.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
|
|
18
|
+
logger.error(errorMessage, {
|
|
19
|
+
key: comKey,
|
|
20
|
+
kta
|
|
21
|
+
});
|
|
22
|
+
throw new Error(errorMessage);
|
|
23
|
+
}
|
|
24
|
+
if (relationshipInfo.path) {
|
|
25
|
+
// This requires a relationship traversal
|
|
26
|
+
where[relationshipInfo.path] = locator.lk;
|
|
27
|
+
if (relationshipInfo.includes) {
|
|
28
|
+
includes.push(...relationshipInfo.includes);
|
|
29
|
+
}
|
|
30
|
+
} else {
|
|
31
|
+
// This is a direct field
|
|
32
|
+
const fieldName = `${locator.kt}Id`;
|
|
33
|
+
where[fieldName] = locator.lk;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const result = {
|
|
37
|
+
where
|
|
38
|
+
};
|
|
39
|
+
if (includes.length > 0) {
|
|
40
|
+
result.include = includes;
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
7
44
|
const getGetOperation = (models, definition, registry)=>{
|
|
8
45
|
const { coordinate, options: { references, aggregations } } = definition;
|
|
9
46
|
const { kta } = coordinate;
|
|
@@ -20,17 +57,16 @@ const getGetOperation = (models, definition, registry)=>{
|
|
|
20
57
|
const model = models[0];
|
|
21
58
|
let item;
|
|
22
59
|
if (isPriKey(itemKey)) {
|
|
60
|
+
// This is the easy case because we can just find the item by its primary key
|
|
23
61
|
item = await model.findByPk(itemKey.pk);
|
|
24
62
|
} else if (isComKey(itemKey)) {
|
|
25
|
-
|
|
63
|
+
// This is a composite key, so we need to build a where clause based on the composite key's locators
|
|
26
64
|
const comKey = itemKey;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
id: comKey.pk,
|
|
31
|
-
[(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
|
|
32
|
-
}
|
|
65
|
+
const queryOptions = processCompositeKey(comKey, model, kta);
|
|
66
|
+
logger.default('Composite key query', {
|
|
67
|
+
queryOptions
|
|
33
68
|
});
|
|
69
|
+
item = await model.findOne(queryOptions);
|
|
34
70
|
}
|
|
35
71
|
if (!item) {
|
|
36
72
|
throw new NotFoundError('get', coordinate, key);
|
|
@@ -42,4 +78,4 @@ const getGetOperation = (models, definition, registry)=>{
|
|
|
42
78
|
};
|
|
43
79
|
|
|
44
80
|
export { getGetOperation };
|
|
45
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
81
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0LmpzIiwic291cmNlcyI6W10sInNvdXJjZXNDb250ZW50IjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OyJ9
|
package/dist/es/ops/remove.js
CHANGED
|
@@ -2,8 +2,45 @@ import { isValidItemKey, abbrevIK, isPriKey, isComKey } from '@fjell/core';
|
|
|
2
2
|
import { populateEvents } from '../EventCoordinator.js';
|
|
3
3
|
import { addKey } from '../KeyMaster.js';
|
|
4
4
|
import LibLogger from '../logger.js';
|
|
5
|
+
import { buildRelationshipPath } from '../util/relationshipUtils.js';
|
|
5
6
|
|
|
6
7
|
const logger = LibLogger.get('sequelize', 'ops', 'remove');
|
|
8
|
+
// Helper function to process composite key and build query options
|
|
9
|
+
const processCompositeKey = (comKey, model, kta)=>{
|
|
10
|
+
const where = {
|
|
11
|
+
id: comKey.pk
|
|
12
|
+
};
|
|
13
|
+
const includes = [];
|
|
14
|
+
for (const locator of comKey.loc){
|
|
15
|
+
const relationshipInfo = buildRelationshipPath(model, locator.kt, kta);
|
|
16
|
+
if (!relationshipInfo.found) {
|
|
17
|
+
const errorMessage = `Composite key locator '${locator.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
|
|
18
|
+
logger.error(errorMessage, {
|
|
19
|
+
key: comKey,
|
|
20
|
+
kta
|
|
21
|
+
});
|
|
22
|
+
throw new Error(errorMessage);
|
|
23
|
+
}
|
|
24
|
+
if (relationshipInfo.path) {
|
|
25
|
+
// This requires a relationship traversal
|
|
26
|
+
where[relationshipInfo.path] = locator.lk;
|
|
27
|
+
if (relationshipInfo.includes) {
|
|
28
|
+
includes.push(...relationshipInfo.includes);
|
|
29
|
+
}
|
|
30
|
+
} else {
|
|
31
|
+
// This is a direct field
|
|
32
|
+
const fieldName = `${locator.kt}Id`;
|
|
33
|
+
where[fieldName] = locator.lk;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const result = {
|
|
37
|
+
where
|
|
38
|
+
};
|
|
39
|
+
if (includes.length > 0) {
|
|
40
|
+
result.include = includes;
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
7
44
|
const getRemoveOperation = (models, definition, // eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
8
45
|
registry)=>{
|
|
9
46
|
const { coordinate, options } = definition;
|
|
@@ -24,14 +61,16 @@ registry)=>{
|
|
|
24
61
|
if (isPriKey(key)) {
|
|
25
62
|
item = await model.findByPk(key.pk);
|
|
26
63
|
} else if (isComKey(key)) {
|
|
27
|
-
|
|
64
|
+
// This is a composite key, so we need to build a where clause based on the composite key's locators
|
|
28
65
|
const comKey = key;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
[(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
|
|
33
|
-
}
|
|
66
|
+
const queryOptions = processCompositeKey(comKey, model, kta);
|
|
67
|
+
logger.default('Composite key query', {
|
|
68
|
+
queryOptions
|
|
34
69
|
});
|
|
70
|
+
item = await model.findOne(queryOptions);
|
|
71
|
+
}
|
|
72
|
+
if (!item) {
|
|
73
|
+
throw new Error(`Item not found for removal with key: ${abbrevIK(key)}`);
|
|
35
74
|
}
|
|
36
75
|
const isDeletedAttribute = model.getAttributes().isDeleted;
|
|
37
76
|
const deletedAtAttribute = model.getAttributes().deletedAt;
|
|
@@ -47,14 +86,14 @@ registry)=>{
|
|
|
47
86
|
returnItem = item === null || item === void 0 ? void 0 : item.get({
|
|
48
87
|
plain: true
|
|
49
88
|
});
|
|
50
|
-
returnItem = addKey(returnItem, kta);
|
|
89
|
+
returnItem = addKey(item, returnItem, kta);
|
|
51
90
|
returnItem = populateEvents(returnItem);
|
|
52
91
|
} else if (options.deleteOnRemove) {
|
|
53
92
|
await (item === null || item === void 0 ? void 0 : item.destroy());
|
|
54
93
|
returnItem = item === null || item === void 0 ? void 0 : item.get({
|
|
55
94
|
plain: true
|
|
56
95
|
});
|
|
57
|
-
returnItem = addKey(returnItem, kta);
|
|
96
|
+
returnItem = addKey(item, returnItem, kta);
|
|
58
97
|
returnItem = populateEvents(returnItem);
|
|
59
98
|
} else {
|
|
60
99
|
throw new Error('No deletedAt or isDeleted attribute found in model, and deleteOnRemove is not set');
|
|
@@ -65,4 +104,4 @@ registry)=>{
|
|
|
65
104
|
};
|
|
66
105
|
|
|
67
106
|
export { getRemoveOperation };
|
|
68
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
107
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVtb3ZlLmpzIiwic291cmNlcyI6W10sInNvdXJjZXNDb250ZW50IjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7In0=
|
package/dist/es/ops/update.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { abbrevIK, isPriKey, isComKey, validateKeys } from '@fjell/core';
|
|
2
|
-
import { removeEvents } from '../EventCoordinator.js';
|
|
2
|
+
import { extractEvents, removeEvents } from '../EventCoordinator.js';
|
|
3
3
|
import { removeKey } from '../KeyMaster.js';
|
|
4
4
|
import LibLogger from '../logger.js';
|
|
5
5
|
import { processRow } from '../RowProcessor.js';
|
|
@@ -35,7 +35,9 @@ const getUpdateOperation = (models, definition, registry)=>{
|
|
|
35
35
|
if (response) {
|
|
36
36
|
// Remove the key and events
|
|
37
37
|
let updateProps = removeKey(item);
|
|
38
|
-
|
|
38
|
+
// TODO: We need the opposite of processRow, something to step down from fjell to database.
|
|
39
|
+
updateProps = extractEvents(updateProps);
|
|
40
|
+
updateProps = removeEvents(updateProps);
|
|
39
41
|
logger.default('Response: %s', stringifyJSON(response));
|
|
40
42
|
logger.default('Update Properties: %s', stringifyJSON(updateProps));
|
|
41
43
|
// Update the object
|
|
@@ -52,4 +54,4 @@ const getUpdateOperation = (models, definition, registry)=>{
|
|
|
52
54
|
};
|
|
53
55
|
|
|
54
56
|
export { getUpdateOperation };
|
|
55
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
57
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBkYXRlLmpzIiwic291cmNlcyI6W10sInNvdXJjZXNDb250ZW50IjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OyJ9
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/* eslint-disable indent */ /**
|
|
2
|
+
* Helper function to build relationship chain includes
|
|
3
|
+
*/ const buildRelationshipChain = (targetModel, kta, currentIndex, targetIndex)=>{
|
|
4
|
+
// Build the association path and validate relationships exist
|
|
5
|
+
const associationParts = [];
|
|
6
|
+
const modelChain = [
|
|
7
|
+
targetModel
|
|
8
|
+
];
|
|
9
|
+
let currentModel = targetModel;
|
|
10
|
+
// Validate that all associations exist and build model chain
|
|
11
|
+
for(let i = currentIndex + 1; i <= targetIndex; i++){
|
|
12
|
+
const intermediateType = kta[i];
|
|
13
|
+
const associationName = intermediateType;
|
|
14
|
+
if (!currentModel.associations || !currentModel.associations[associationName]) {
|
|
15
|
+
return {
|
|
16
|
+
success: false
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
associationParts.push(associationName);
|
|
20
|
+
currentModel = currentModel.associations[associationName].target;
|
|
21
|
+
modelChain.push(currentModel);
|
|
22
|
+
}
|
|
23
|
+
// Build the full association path for the target field
|
|
24
|
+
const targetType = kta[targetIndex];
|
|
25
|
+
const associationPath = `$${associationParts.join('.')}.${targetType}Id$`;
|
|
26
|
+
// Build nested includes structure iteratively (clearer than recursion)
|
|
27
|
+
let deepestInclude = null;
|
|
28
|
+
// Build from the deepest level back to the root
|
|
29
|
+
for(let i = targetIndex; i > currentIndex; i--){
|
|
30
|
+
const currentType = kta[i];
|
|
31
|
+
const modelIndex = i - currentIndex;
|
|
32
|
+
const includeObj = {
|
|
33
|
+
model: modelChain[modelIndex],
|
|
34
|
+
as: currentType,
|
|
35
|
+
required: true
|
|
36
|
+
};
|
|
37
|
+
if (deepestInclude) {
|
|
38
|
+
includeObj.include = [
|
|
39
|
+
deepestInclude
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
deepestInclude = includeObj;
|
|
43
|
+
}
|
|
44
|
+
const includes = deepestInclude ? [
|
|
45
|
+
deepestInclude
|
|
46
|
+
] : [];
|
|
47
|
+
return {
|
|
48
|
+
success: true,
|
|
49
|
+
path: associationPath,
|
|
50
|
+
includes
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Helper function to build relationship path for a locator
|
|
55
|
+
* @param includeIsDirect Whether to include the isDirect flag in the result
|
|
56
|
+
*/ const buildRelationshipPath = (targetModel, locatorType, kta, includeIsDirect = false)=>{
|
|
57
|
+
// First check if the field exists directly
|
|
58
|
+
const directFieldName = `${locatorType}Id`;
|
|
59
|
+
const attributes = targetModel.getAttributes();
|
|
60
|
+
if (attributes && attributes[directFieldName]) {
|
|
61
|
+
const result = {
|
|
62
|
+
found: true
|
|
63
|
+
};
|
|
64
|
+
if (includeIsDirect) {
|
|
65
|
+
result.isDirect = true;
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
// If not direct, look for relationship path
|
|
70
|
+
const targetIndex = kta.indexOf(locatorType);
|
|
71
|
+
if (targetIndex === -1) {
|
|
72
|
+
const result = {
|
|
73
|
+
found: false
|
|
74
|
+
};
|
|
75
|
+
if (includeIsDirect) {
|
|
76
|
+
result.isDirect = false;
|
|
77
|
+
}
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
const currentIndex = 0; // We're always looking from the base model
|
|
81
|
+
if (targetIndex <= currentIndex) {
|
|
82
|
+
const result = {
|
|
83
|
+
found: false
|
|
84
|
+
};
|
|
85
|
+
if (includeIsDirect) {
|
|
86
|
+
result.isDirect = false;
|
|
87
|
+
}
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
const chainResult = buildRelationshipChain(targetModel, kta, currentIndex, targetIndex);
|
|
91
|
+
if (chainResult.success) {
|
|
92
|
+
const result = {
|
|
93
|
+
found: true,
|
|
94
|
+
path: chainResult.path,
|
|
95
|
+
includes: chainResult.includes
|
|
96
|
+
};
|
|
97
|
+
if (includeIsDirect) {
|
|
98
|
+
result.isDirect = false;
|
|
99
|
+
}
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
const result = {
|
|
103
|
+
found: false
|
|
104
|
+
};
|
|
105
|
+
if (includeIsDirect) {
|
|
106
|
+
result.isDirect = false;
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export { buildRelationshipChain, buildRelationshipPath };
|
|
112
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVsYXRpb25zaGlwVXRpbHMuanMiLCJzb3VyY2VzIjpbXSwic291cmNlc0NvbnRlbnQiOltdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OyJ9
|