@fjell/lib-sequelize 4.4.4 → 4.4.5
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/AggregationBuilder.cjs +48 -14
- package/dist/cjs/KeyMaster.cjs +33 -11
- package/dist/cjs/OperationContext.cjs +161 -0
- package/dist/cjs/ReferenceBuilder.cjs +47 -5
- package/dist/cjs/RowProcessor.cjs +37 -22
- package/dist/cjs/ops/all.cjs +77 -18
- package/dist/cjs/ops/get.cjs +5 -2
- package/dist/cjs/ops/update.cjs +63 -7
- package/dist/cjs/util/relationshipUtils.cjs +2 -2
- package/dist/es/AggregationBuilder.js +48 -14
- package/dist/es/KeyMaster.js +33 -11
- package/dist/es/OperationContext.js +155 -0
- package/dist/es/ReferenceBuilder.js +47 -5
- package/dist/es/RowProcessor.js +37 -22
- package/dist/es/ops/all.js +77 -18
- package/dist/es/ops/get.js +5 -2
- package/dist/es/ops/update.js +63 -7
- package/dist/es/util/relationshipUtils.js +2 -2
- package/dist/index.cjs +461 -89
- package/dist/index.cjs.map +1 -1
- package/dist/types/AggregationBuilder.d.ts +2 -1
- package/dist/types/EventCoordinator.d.ts +6 -6
- package/dist/types/KeyMaster.d.ts +2 -2
- package/dist/types/OperationContext.d.ts +72 -0
- package/dist/types/ReferenceBuilder.d.ts +2 -1
- package/dist/types/RowProcessor.d.ts +2 -1
- package/dist/types/ops/all.d.ts +1 -1
- package/dist/types/ops/create.d.ts +2 -2
- package/dist/types/ops/update.d.ts +2 -2
- package/package.json +12 -12
|
@@ -3,29 +3,63 @@
|
|
|
3
3
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
4
|
|
|
5
5
|
const core = require('@fjell/core');
|
|
6
|
+
const OperationContext = require('./OperationContext.cjs');
|
|
7
|
+
const logger$1 = require('./logger.cjs');
|
|
6
8
|
|
|
7
|
-
const
|
|
9
|
+
const logger = logger$1.default.get('sequelize', 'AggregationBuilder');
|
|
10
|
+
const buildAggregation = async (item, aggregationDefinition, registry, context)=>{
|
|
8
11
|
const location = core.ikToLKA(item.key);
|
|
9
12
|
// Get the library instance from the registry using the key type array
|
|
10
13
|
const libraryInstance = registry.get(aggregationDefinition.kta);
|
|
11
14
|
if (!libraryInstance) {
|
|
12
15
|
throw new Error(`Library instance not found for key type array: ${aggregationDefinition.kta.join(', ')}`);
|
|
13
16
|
}
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
// Create a cache key for this aggregation query
|
|
18
|
+
// This helps avoid running the same aggregation multiple times
|
|
19
|
+
const aggregationCacheKey = `${aggregationDefinition.kta.join('.')}_${aggregationDefinition.cardinality}_${OperationContext.serializeKey(item.key)}`;
|
|
20
|
+
if (context) {
|
|
21
|
+
// Check if this aggregation is already cached
|
|
22
|
+
if (context.cache.has(aggregationCacheKey)) {
|
|
23
|
+
const cachedResult = context.cache.get(aggregationCacheKey);
|
|
24
|
+
logger.default('Using cached aggregation result', {
|
|
25
|
+
aggregationCacheKey,
|
|
26
|
+
property: aggregationDefinition.property
|
|
27
|
+
});
|
|
28
|
+
item[aggregationDefinition.property] = cachedResult;
|
|
19
29
|
return item;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return item;
|
|
26
|
-
});
|
|
30
|
+
}
|
|
31
|
+
// Note: We don't check for circular dependencies here because:
|
|
32
|
+
// 1. Aggregations are location-based queries, not key-based references
|
|
33
|
+
// 2. They should be allowed to run during normal item processing
|
|
34
|
+
// 3. The main circular dependency concern is with references, not aggregations
|
|
27
35
|
}
|
|
36
|
+
// Execute aggregation within the current context to ensure context sharing
|
|
37
|
+
return OperationContext.contextManager.withContext(context || OperationContext.contextManager.getCurrentContext() || {
|
|
38
|
+
inProgress: new Set(),
|
|
39
|
+
cache: new Map()
|
|
40
|
+
}, async ()=>{
|
|
41
|
+
// Based on cardinality, use either one or all operation
|
|
42
|
+
if (aggregationDefinition.cardinality === 'one') {
|
|
43
|
+
// For one-to-one relationship, use the one operation
|
|
44
|
+
return libraryInstance.operations.one({}, location).then((result)=>{
|
|
45
|
+
if (context) {
|
|
46
|
+
context.cache.set(aggregationCacheKey, result);
|
|
47
|
+
}
|
|
48
|
+
item[aggregationDefinition.property] = result;
|
|
49
|
+
return item;
|
|
50
|
+
});
|
|
51
|
+
} else {
|
|
52
|
+
// For one-to-many relationship, use the all operation
|
|
53
|
+
return libraryInstance.operations.all({}, location).then((results)=>{
|
|
54
|
+
if (context) {
|
|
55
|
+
context.cache.set(aggregationCacheKey, results);
|
|
56
|
+
}
|
|
57
|
+
item[aggregationDefinition.property] = results;
|
|
58
|
+
return item;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
});
|
|
28
62
|
};
|
|
29
63
|
|
|
30
64
|
exports.buildAggregation = buildAggregation;
|
|
31
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
65
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWdncmVnYXRpb25CdWlsZGVyLmNqcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OyJ9
|
package/dist/cjs/KeyMaster.cjs
CHANGED
|
@@ -25,19 +25,41 @@ const extractLocationKeyValue = (model, item, locatorType, kta)=>{
|
|
|
25
25
|
}
|
|
26
26
|
return value;
|
|
27
27
|
} else {
|
|
28
|
-
// Need to traverse relationship
|
|
29
|
-
//
|
|
30
|
-
const
|
|
31
|
-
if (
|
|
32
|
-
|
|
28
|
+
// Need to traverse relationship hierarchy
|
|
29
|
+
// Find the path through the key type array
|
|
30
|
+
const locatorIndex = kta.indexOf(locatorType);
|
|
31
|
+
if (locatorIndex === -1) {
|
|
32
|
+
throw new Error(`Locator type '${locatorType}' not found in key type array`);
|
|
33
33
|
}
|
|
34
|
-
//
|
|
35
|
-
|
|
34
|
+
// Start from the current item (index 0 in kta)
|
|
35
|
+
let currentObject = item;
|
|
36
|
+
// Traverse through each intermediate relationship to reach the target
|
|
37
|
+
for(let i = 1; i < locatorIndex; i++){
|
|
38
|
+
const intermediateType = kta[i];
|
|
39
|
+
// Check if the intermediate relationship object is loaded
|
|
40
|
+
if (currentObject[intermediateType] && typeof currentObject[intermediateType] === 'object') {
|
|
41
|
+
currentObject = currentObject[intermediateType];
|
|
42
|
+
} else {
|
|
43
|
+
// Try the foreign key approach if the relationship object isn't loaded
|
|
44
|
+
const foreignKeyField = `${intermediateType}Id`;
|
|
45
|
+
if (typeof currentObject[foreignKeyField] !== 'undefined' && currentObject[foreignKeyField] !== null) {
|
|
46
|
+
// We have the foreign key but not the loaded object, we can't traverse further
|
|
47
|
+
throw new Error(`Intermediate relationship '${intermediateType}' is not loaded. Cannot traverse to '${locatorType}'. Either include the relationship in your query or ensure it's loaded.`);
|
|
48
|
+
}
|
|
49
|
+
throw new Error(`Intermediate relationship '${intermediateType}' is missing in the relationship chain. Expected path: ${kta.slice(0, locatorIndex + 1).join(' → ')}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Now extract the target locator value from the current object
|
|
53
|
+
// First try to get it from the loaded relationship object
|
|
54
|
+
if (currentObject[locatorType] && typeof currentObject[locatorType] === 'object' && typeof currentObject[locatorType].id !== 'undefined') {
|
|
55
|
+
return currentObject[locatorType].id;
|
|
56
|
+
}
|
|
57
|
+
// If the relationship object isn't loaded, try the foreign key field
|
|
36
58
|
const foreignKeyField = `${locatorType}Id`;
|
|
37
|
-
if (typeof
|
|
38
|
-
return
|
|
59
|
+
if (typeof currentObject[foreignKeyField] !== 'undefined' && currentObject[foreignKeyField] !== null) {
|
|
60
|
+
return currentObject[foreignKeyField];
|
|
39
61
|
}
|
|
40
|
-
throw new Error(`Unable to extract location key for '${locatorType}'. Neither the relationship object nor direct foreign key is available
|
|
62
|
+
throw new Error(`Unable to extract location key for '${locatorType}'. Neither the relationship object nor direct foreign key is available. Traversal path: ${kta.slice(0, locatorIndex + 1).join(' → ')}`);
|
|
41
63
|
}
|
|
42
64
|
};
|
|
43
65
|
const removeKey = (item)=>{
|
|
@@ -126,4 +148,4 @@ const addKey = (model, item, keyTypes)=>{
|
|
|
126
148
|
|
|
127
149
|
exports.addKey = addKey;
|
|
128
150
|
exports.removeKey = removeKey;
|
|
129
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
151
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiS2V5TWFzdGVyLmNqcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7In0=
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
|
+
|
|
5
|
+
const logger$1 = require('./logger.cjs');
|
|
6
|
+
|
|
7
|
+
function _define_property(obj, key, value) {
|
|
8
|
+
if (key in obj) {
|
|
9
|
+
Object.defineProperty(obj, key, {
|
|
10
|
+
value: value,
|
|
11
|
+
enumerable: true,
|
|
12
|
+
configurable: true,
|
|
13
|
+
writable: true
|
|
14
|
+
});
|
|
15
|
+
} else {
|
|
16
|
+
obj[key] = value;
|
|
17
|
+
}
|
|
18
|
+
return obj;
|
|
19
|
+
}
|
|
20
|
+
const logger = logger$1.default.get('sequelize', 'OperationContext');
|
|
21
|
+
/**
|
|
22
|
+
* Serialize an ItemKey to a string for use in sets and maps
|
|
23
|
+
*/ const serializeKey = (key)=>{
|
|
24
|
+
if ('pk' in key && 'kt' in key && !('loc' in key)) {
|
|
25
|
+
// PriKey
|
|
26
|
+
return `${key.kt}:${key.pk}`;
|
|
27
|
+
} else if ('pk' in key && 'kt' in key && 'loc' in key) {
|
|
28
|
+
// ComKey
|
|
29
|
+
const locStr = key.loc.map((l)=>`${l.kt}:${l.lk}`).join(',');
|
|
30
|
+
return `${key.kt}:${key.pk}|${locStr}`;
|
|
31
|
+
}
|
|
32
|
+
throw new Error(`Unsupported key type: ${JSON.stringify(key)}`);
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Create a new OperationContext
|
|
36
|
+
*/ const createOperationContext = ()=>{
|
|
37
|
+
const inProgress = new Set();
|
|
38
|
+
const cache = new Map();
|
|
39
|
+
return {
|
|
40
|
+
inProgress,
|
|
41
|
+
cache,
|
|
42
|
+
markInProgress (key) {
|
|
43
|
+
const serialized = serializeKey(key);
|
|
44
|
+
logger.default('Marking key as in progress', {
|
|
45
|
+
key,
|
|
46
|
+
serialized
|
|
47
|
+
});
|
|
48
|
+
inProgress.add(serialized);
|
|
49
|
+
},
|
|
50
|
+
markComplete (key) {
|
|
51
|
+
const serialized = serializeKey(key);
|
|
52
|
+
logger.default('Marking key as complete', {
|
|
53
|
+
key,
|
|
54
|
+
serialized
|
|
55
|
+
});
|
|
56
|
+
inProgress.delete(serialized);
|
|
57
|
+
},
|
|
58
|
+
isInProgress (key) {
|
|
59
|
+
const serialized = serializeKey(key);
|
|
60
|
+
const result = inProgress.has(serialized);
|
|
61
|
+
logger.default('Checking if key is in progress', {
|
|
62
|
+
key,
|
|
63
|
+
serialized,
|
|
64
|
+
result
|
|
65
|
+
});
|
|
66
|
+
return result;
|
|
67
|
+
},
|
|
68
|
+
getCached (key) {
|
|
69
|
+
const serialized = serializeKey(key);
|
|
70
|
+
const result = cache.get(serialized);
|
|
71
|
+
logger.default('Getting cached item', {
|
|
72
|
+
key,
|
|
73
|
+
serialized,
|
|
74
|
+
found: !!result
|
|
75
|
+
});
|
|
76
|
+
return result;
|
|
77
|
+
},
|
|
78
|
+
setCached (key, item) {
|
|
79
|
+
const serialized = serializeKey(key);
|
|
80
|
+
logger.default('Caching item', {
|
|
81
|
+
key,
|
|
82
|
+
serialized
|
|
83
|
+
});
|
|
84
|
+
cache.set(serialized, item);
|
|
85
|
+
},
|
|
86
|
+
isCached (key) {
|
|
87
|
+
const serialized = serializeKey(key);
|
|
88
|
+
const result = cache.has(serialized);
|
|
89
|
+
logger.default('Checking if key is cached', {
|
|
90
|
+
key,
|
|
91
|
+
serialized,
|
|
92
|
+
result
|
|
93
|
+
});
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Context Manager for sharing context across operations without changing public interfaces
|
|
100
|
+
*/ class ContextManager {
|
|
101
|
+
/**
|
|
102
|
+
* Set the current context for the current operation chain
|
|
103
|
+
*/ setCurrentContext(context) {
|
|
104
|
+
const contextId = Math.random().toString(36).substring(7);
|
|
105
|
+
this.contexts.set(contextId, context);
|
|
106
|
+
this.currentContextId = contextId;
|
|
107
|
+
logger.default('Set current context', {
|
|
108
|
+
contextId
|
|
109
|
+
});
|
|
110
|
+
return contextId;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get the current context if one is set
|
|
114
|
+
*/ getCurrentContext() {
|
|
115
|
+
if (this.currentContextId) {
|
|
116
|
+
const context = this.contexts.get(this.currentContextId);
|
|
117
|
+
logger.default('Got current context', {
|
|
118
|
+
contextId: this.currentContextId,
|
|
119
|
+
found: !!context
|
|
120
|
+
});
|
|
121
|
+
return context;
|
|
122
|
+
}
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Clear the current context
|
|
127
|
+
*/ clearCurrentContext() {
|
|
128
|
+
if (this.currentContextId) {
|
|
129
|
+
logger.default('Clearing current context', {
|
|
130
|
+
contextId: this.currentContextId
|
|
131
|
+
});
|
|
132
|
+
this.contexts.delete(this.currentContextId);
|
|
133
|
+
this.currentContextId = null;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Execute a function with a specific context set as current
|
|
138
|
+
*/ async withContext(context, fn) {
|
|
139
|
+
const previousContextId = this.currentContextId;
|
|
140
|
+
this.setCurrentContext(context);
|
|
141
|
+
try {
|
|
142
|
+
return await fn();
|
|
143
|
+
} finally{
|
|
144
|
+
this.clearCurrentContext();
|
|
145
|
+
if (previousContextId) {
|
|
146
|
+
this.currentContextId = previousContextId;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
constructor(){
|
|
151
|
+
_define_property(this, "contexts", new Map());
|
|
152
|
+
_define_property(this, "currentContextId", null);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Global context manager instance
|
|
156
|
+
const contextManager = new ContextManager();
|
|
157
|
+
|
|
158
|
+
exports.contextManager = contextManager;
|
|
159
|
+
exports.createOperationContext = createOperationContext;
|
|
160
|
+
exports.serializeKey = serializeKey;
|
|
161
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiT3BlcmF0aW9uQ29udGV4dC5janMiLCJzb3VyY2VzIjpbXSwic291cmNlc0NvbnRlbnQiOltdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzsifQ==
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const logger$1 = require('./logger.cjs');
|
|
6
|
+
|
|
7
|
+
const logger = logger$1.default.get('sequelize', 'ReferenceBuilder');
|
|
8
|
+
const buildReference = async (item, referenceDefinition, registry, context)=>{
|
|
6
9
|
// Check if there is more than one key type
|
|
7
10
|
if (referenceDefinition.kta.length > 1) {
|
|
8
11
|
throw new Error("The ReferenceBuilder doesn't work with more than one key type yet");
|
|
@@ -16,13 +19,52 @@ const buildReference = async (item, referenceDefinition, registry)=>{
|
|
|
16
19
|
if (!library) {
|
|
17
20
|
throw new Error("This model definition has a reference definition, but the dependency is not present");
|
|
18
21
|
}
|
|
22
|
+
// Check if the column value is null - if so, skip the reference
|
|
23
|
+
const columnValue = item[referenceDefinition.column];
|
|
24
|
+
if (columnValue == null) {
|
|
25
|
+
item[referenceDefinition.property] = null;
|
|
26
|
+
return item;
|
|
27
|
+
}
|
|
19
28
|
// Create a PriKey using the column value from item
|
|
20
29
|
const priKey = {
|
|
21
30
|
kt: referenceDefinition.kta[0],
|
|
22
|
-
pk:
|
|
31
|
+
pk: columnValue
|
|
23
32
|
};
|
|
24
|
-
|
|
25
|
-
|
|
33
|
+
let referencedItem;
|
|
34
|
+
if (context) {
|
|
35
|
+
// Check if we already have this item cached
|
|
36
|
+
if (context.isCached(priKey)) {
|
|
37
|
+
logger.default('Using cached reference', {
|
|
38
|
+
priKey,
|
|
39
|
+
property: referenceDefinition.property
|
|
40
|
+
});
|
|
41
|
+
referencedItem = context.getCached(priKey);
|
|
42
|
+
} else if (context.isInProgress(priKey)) {
|
|
43
|
+
logger.default('Circular dependency detected, creating reference placeholder', {
|
|
44
|
+
priKey,
|
|
45
|
+
property: referenceDefinition.property
|
|
46
|
+
});
|
|
47
|
+
// Create a minimal reference object with just the key to break the cycle
|
|
48
|
+
referencedItem = {
|
|
49
|
+
key: priKey
|
|
50
|
+
};
|
|
51
|
+
} else {
|
|
52
|
+
// Mark this key as in progress before loading
|
|
53
|
+
context.markInProgress(priKey);
|
|
54
|
+
try {
|
|
55
|
+
// Get the referenced item using the Library.Operations get method (context now managed internally)
|
|
56
|
+
referencedItem = await library.operations.get(priKey);
|
|
57
|
+
// Cache the result
|
|
58
|
+
context.setCached(priKey, referencedItem);
|
|
59
|
+
} finally{
|
|
60
|
+
// Always mark as complete, even if there was an error
|
|
61
|
+
context.markComplete(priKey);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
// Fallback to original behavior if no context provided
|
|
66
|
+
referencedItem = await library.operations.get(priKey);
|
|
67
|
+
}
|
|
26
68
|
// TODO: In a Fjell-compliant implementation, this value should be stored in the ref property
|
|
27
69
|
// For now, we'll just populate the property directly
|
|
28
70
|
// Store the result in the property on item
|
|
@@ -31,4 +73,4 @@ const buildReference = async (item, referenceDefinition, registry)=>{
|
|
|
31
73
|
};
|
|
32
74
|
|
|
33
75
|
exports.buildReference = buildReference;
|
|
34
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
76
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmVmZXJlbmNlQnVpbGRlci5janMiLCJzb3VyY2VzIjpbXSwic291cmNlc0NvbnRlbnQiOltdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OyJ9
|
|
@@ -8,34 +8,49 @@ const ReferenceBuilder = require('./ReferenceBuilder.cjs');
|
|
|
8
8
|
const AggregationBuilder = require('./AggregationBuilder.cjs');
|
|
9
9
|
const general = require('./util/general.cjs');
|
|
10
10
|
const EventCoordinator = require('./EventCoordinator.cjs');
|
|
11
|
+
const OperationContext = require('./OperationContext.cjs');
|
|
11
12
|
|
|
12
13
|
const logger = logger$1.default.get('sequelize', 'RowProcessor');
|
|
13
|
-
const processRow = async (row, keyTypes, referenceDefinitions, aggregationDefinitions, registry)=>{
|
|
14
|
+
const processRow = async (row, keyTypes, referenceDefinitions, aggregationDefinitions, registry, context)=>{
|
|
14
15
|
logger.default('Processing Row', {
|
|
15
16
|
row
|
|
16
17
|
});
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
18
|
+
// Use provided context or create new one
|
|
19
|
+
const operationContext = context || OperationContext.createOperationContext();
|
|
20
|
+
// Process the row within the context to ensure all operations share the same context
|
|
21
|
+
return OperationContext.contextManager.withContext(operationContext, async ()=>{
|
|
22
|
+
let item = row.get({
|
|
23
|
+
plain: true
|
|
24
|
+
});
|
|
25
|
+
logger.default('Adding Key to Item with Key Types: %s', general.stringifyJSON(keyTypes));
|
|
26
|
+
item = KeyMaster.addKey(row, item, keyTypes);
|
|
27
|
+
item = EventCoordinator.populateEvents(item);
|
|
28
|
+
logger.default('Key Added to Item: %s', general.stringifyJSON(item.key));
|
|
29
|
+
// Mark this item as in progress to detect circular references
|
|
30
|
+
operationContext.markInProgress(item.key);
|
|
31
|
+
try {
|
|
32
|
+
if (referenceDefinitions && referenceDefinitions.length > 0) {
|
|
33
|
+
for (const referenceDefinition of referenceDefinitions){
|
|
34
|
+
logger.default('Processing Reference for %s to %s', item.key.kt, general.stringifyJSON(referenceDefinition.kta));
|
|
35
|
+
item = await ReferenceBuilder.buildReference(item, referenceDefinition, registry, operationContext);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (aggregationDefinitions && aggregationDefinitions.length > 0) {
|
|
39
|
+
for (const aggregationDefinition of aggregationDefinitions){
|
|
40
|
+
logger.default('Processing Aggregation for %s from %s', item.key.kt, general.stringifyJSON(aggregationDefinition.kta));
|
|
41
|
+
item = await AggregationBuilder.buildAggregation(item, aggregationDefinition, registry, operationContext);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Cache the fully processed item
|
|
45
|
+
operationContext.setCached(item.key, item);
|
|
46
|
+
} finally{
|
|
47
|
+
// Mark this item as complete
|
|
48
|
+
operationContext.markComplete(item.key);
|
|
34
49
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
50
|
+
logger.default('Processed Row: %j', general.stringifyJSON(item));
|
|
51
|
+
return item;
|
|
52
|
+
});
|
|
38
53
|
};
|
|
39
54
|
|
|
40
55
|
exports.processRow = processRow;
|
|
41
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
56
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUm93UHJvY2Vzc29yLmNqcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OyJ9
|
package/dist/cjs/ops/all.cjs
CHANGED
|
@@ -7,8 +7,30 @@ const QueryBuilder = require('../QueryBuilder.cjs');
|
|
|
7
7
|
const logger$1 = require('../logger.cjs');
|
|
8
8
|
const RowProcessor = require('../RowProcessor.cjs');
|
|
9
9
|
const sequelize = require('sequelize');
|
|
10
|
+
const relationshipUtils = require('../util/relationshipUtils.cjs');
|
|
11
|
+
const OperationContext = require('../OperationContext.cjs');
|
|
10
12
|
|
|
11
13
|
const logger = logger$1.default.get('sequelize', 'ops', 'all');
|
|
14
|
+
// Helper function to merge includes avoiding duplicates
|
|
15
|
+
const mergeIncludes = (existingIncludes, newIncludes)=>{
|
|
16
|
+
const mergedIncludes = [
|
|
17
|
+
...existingIncludes
|
|
18
|
+
];
|
|
19
|
+
for (const newInclude of newIncludes){
|
|
20
|
+
const existingIndex = mergedIncludes.findIndex((existing)=>existing.as === newInclude.as && existing.model === newInclude.model);
|
|
21
|
+
if (existingIndex === -1) {
|
|
22
|
+
mergedIncludes.push(newInclude);
|
|
23
|
+
} else if (newInclude.include && mergedIncludes[existingIndex].include) {
|
|
24
|
+
mergedIncludes[existingIndex].include = [
|
|
25
|
+
...mergedIncludes[existingIndex].include,
|
|
26
|
+
...newInclude.include
|
|
27
|
+
];
|
|
28
|
+
} else if (newInclude.include) {
|
|
29
|
+
mergedIncludes[existingIndex].include = newInclude.include;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return mergedIncludes;
|
|
33
|
+
};
|
|
12
34
|
const getAllOperation = (models, definition, registry)=>{
|
|
13
35
|
const { coordinate, options: { references, aggregations } } = definition;
|
|
14
36
|
//#region Query
|
|
@@ -18,29 +40,64 @@ const getAllOperation = (models, definition, registry)=>{
|
|
|
18
40
|
locations
|
|
19
41
|
});
|
|
20
42
|
const loc = locations || [];
|
|
21
|
-
// SQ Libs don't support locations
|
|
22
|
-
if (loc.length > 1) {
|
|
23
|
-
throw new Error('Not implemented for more than one location key');
|
|
24
|
-
}
|
|
25
|
-
// We have the model here?
|
|
26
43
|
// @ts-ignore
|
|
27
44
|
const model = models[0];
|
|
28
|
-
//
|
|
45
|
+
// Build base query from itemQuery
|
|
29
46
|
const options = QueryBuilder.buildQuery(itemQuery, model);
|
|
30
|
-
//
|
|
31
|
-
if (loc.length
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
47
|
+
// Handle location keys if present
|
|
48
|
+
if (loc.length > 0) {
|
|
49
|
+
const { kta } = coordinate;
|
|
50
|
+
const directLocations = [];
|
|
51
|
+
const hierarchicalLocations = [];
|
|
52
|
+
const additionalIncludes = [];
|
|
53
|
+
// Categorize location keys as direct or hierarchical
|
|
54
|
+
for (const locKey of loc){
|
|
55
|
+
const relationshipInfo = relationshipUtils.buildRelationshipPath(model, locKey.kt, kta, true);
|
|
56
|
+
if (!relationshipInfo.found) {
|
|
57
|
+
const errorMessage = `Location key '${locKey.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
|
|
58
|
+
logger.error(errorMessage, {
|
|
59
|
+
locations: loc,
|
|
60
|
+
kta
|
|
61
|
+
});
|
|
62
|
+
throw new Error(errorMessage);
|
|
63
|
+
}
|
|
64
|
+
if (relationshipInfo.isDirect) {
|
|
65
|
+
directLocations.push(locKey);
|
|
66
|
+
} else {
|
|
67
|
+
hierarchicalLocations.push(locKey);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Handle direct location keys (simple foreign key constraints)
|
|
71
|
+
for (const locKey of directLocations){
|
|
72
|
+
const foreignKeyField = locKey.kt + 'Id';
|
|
35
73
|
options.where = {
|
|
36
74
|
...options.where,
|
|
37
|
-
[
|
|
38
|
-
[sequelize.Op.eq]:
|
|
75
|
+
[foreignKeyField]: {
|
|
76
|
+
[sequelize.Op.eq]: locKey.lk
|
|
39
77
|
}
|
|
40
78
|
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
79
|
+
}
|
|
80
|
+
// Handle hierarchical location keys (requires relationship traversal)
|
|
81
|
+
for (const locKey of hierarchicalLocations){
|
|
82
|
+
const relationshipInfo = relationshipUtils.buildRelationshipPath(model, locKey.kt, kta);
|
|
83
|
+
if (relationshipInfo.found && relationshipInfo.path) {
|
|
84
|
+
// Add the relationship constraint using the path
|
|
85
|
+
options.where = {
|
|
86
|
+
...options.where,
|
|
87
|
+
[relationshipInfo.path]: {
|
|
88
|
+
[sequelize.Op.eq]: locKey.lk
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
// Add necessary includes for the relationship traversal
|
|
92
|
+
if (relationshipInfo.includes) {
|
|
93
|
+
additionalIncludes.push(...relationshipInfo.includes);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Merge additional includes with existing includes
|
|
98
|
+
if (additionalIncludes.length > 0) {
|
|
99
|
+
const existingIncludes = options.include || [];
|
|
100
|
+
options.include = mergeIncludes(existingIncludes, additionalIncludes);
|
|
44
101
|
}
|
|
45
102
|
}
|
|
46
103
|
logger.default('Configured this Item Query', {
|
|
@@ -49,9 +106,11 @@ const getAllOperation = (models, definition, registry)=>{
|
|
|
49
106
|
});
|
|
50
107
|
const matchingItems = await model.findAll(options);
|
|
51
108
|
// this.logger.default('Matching Items', { matchingItems });
|
|
109
|
+
// Get the current context from context manager
|
|
110
|
+
const context = OperationContext.contextManager.getCurrentContext();
|
|
52
111
|
// TODO: Move this Up!
|
|
53
112
|
return await Promise.all(matchingItems.map(async (row)=>{
|
|
54
|
-
const processedRow = await RowProcessor.processRow(row, coordinate.kta, references, aggregations, registry);
|
|
113
|
+
const processedRow = await RowProcessor.processRow(row, coordinate.kta, references, aggregations, registry, context);
|
|
55
114
|
return core.validateKeys(processedRow, coordinate.kta);
|
|
56
115
|
}));
|
|
57
116
|
};
|
|
@@ -59,4 +118,4 @@ const getAllOperation = (models, definition, registry)=>{
|
|
|
59
118
|
};
|
|
60
119
|
|
|
61
120
|
exports.getAllOperation = getAllOperation;
|
|
62
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
121
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWxsLmNqcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7In0=
|
package/dist/cjs/ops/get.cjs
CHANGED
|
@@ -7,6 +7,7 @@ const logger$1 = require('../logger.cjs');
|
|
|
7
7
|
const RowProcessor = require('../RowProcessor.cjs');
|
|
8
8
|
const Library = require('@fjell/lib');
|
|
9
9
|
const relationshipUtils = require('../util/relationshipUtils.cjs');
|
|
10
|
+
const OperationContext = require('../OperationContext.cjs');
|
|
10
11
|
|
|
11
12
|
const logger = logger$1.default.get('sequelize', 'ops', 'get');
|
|
12
13
|
// Helper function to process composite key and build query options
|
|
@@ -75,11 +76,13 @@ const getGetOperation = (models, definition, registry)=>{
|
|
|
75
76
|
if (!item) {
|
|
76
77
|
throw new Library.NotFoundError('get', coordinate, key);
|
|
77
78
|
} else {
|
|
78
|
-
|
|
79
|
+
// Get the current context from context manager
|
|
80
|
+
const context = OperationContext.contextManager.getCurrentContext();
|
|
81
|
+
return core.validateKeys(await RowProcessor.processRow(item, kta, references, aggregations, registry, context), kta);
|
|
79
82
|
}
|
|
80
83
|
};
|
|
81
84
|
return get;
|
|
82
85
|
};
|
|
83
86
|
|
|
84
87
|
exports.getGetOperation = getGetOperation;
|
|
85
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
88
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0LmNqcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7In0=
|