@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.
@@ -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 buildAggregation = async (item, aggregationDefinition, registry)=>{
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
- // Based on cardinality, use either one or all operation
15
- if (aggregationDefinition.cardinality === 'one') {
16
- // For one-to-one relationship, use the one operation
17
- return libraryInstance.operations.one({}, location).then((result)=>{
18
- item[aggregationDefinition.property] = result;
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
- } else {
22
- // For one-to-many relationship, use the all operation
23
- return libraryInstance.operations.all({}, location).then((results)=>{
24
- item[aggregationDefinition.property] = results;
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWdncmVnYXRpb25CdWlsZGVyLmNqcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7In0=
65
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWdncmVnYXRpb25CdWlsZGVyLmNqcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OyJ9
@@ -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
- // 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;
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
- // 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
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 item[foreignKeyField] !== 'undefined' && item[foreignKeyField] !== null) {
38
- return item[foreignKeyField];
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiS2V5TWFzdGVyLmNqcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzsifQ==
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 buildReference = async (item, referenceDefinition, registry)=>{
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: item[referenceDefinition.column]
31
+ pk: columnValue
23
32
  };
24
- // Get the referenced item using the Library.Operations get method
25
- const referencedItem = await library.operations.get(priKey);
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmVmZXJlbmNlQnVpbGRlci5janMiLCJzb3VyY2VzIjpbXSwic291cmNlc0NvbnRlbnQiOltdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OyJ9
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
- let item = row.get({
18
- plain: true
19
- });
20
- logger.default('Adding Key to Item with Key Types: %s', general.stringifyJSON(keyTypes));
21
- item = KeyMaster.addKey(row, item, keyTypes);
22
- item = EventCoordinator.populateEvents(item);
23
- logger.default('Key Added to Item: %s', general.stringifyJSON(item.key));
24
- if (referenceDefinitions && referenceDefinitions.length > 0) {
25
- for (const referenceDefinition of referenceDefinitions){
26
- logger.default('Processing Reference for %s to %s', item.key.kt, general.stringifyJSON(referenceDefinition.kta));
27
- item = await ReferenceBuilder.buildReference(item, referenceDefinition, registry);
28
- }
29
- }
30
- if (aggregationDefinitions && aggregationDefinitions.length > 0) {
31
- for (const aggregationDefinition of aggregationDefinitions){
32
- logger.default('Processing Aggregation for %s from %s', item.key.kt, general.stringifyJSON(aggregationDefinition.kta));
33
- item = await AggregationBuilder.buildAggregation(item, aggregationDefinition, registry);
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
- logger.default('Processed Row: %j', general.stringifyJSON(item));
37
- return item;
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUm93UHJvY2Vzc29yLmNqcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OyJ9
56
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUm93UHJvY2Vzc29yLmNqcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OyJ9
@@ -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
- // We have the model here?
45
+ // Build base query from itemQuery
29
46
  const options = QueryBuilder.buildQuery(itemQuery, model);
30
- // If this has a location array, we need to add a where clause
31
- if (loc.length === 1) {
32
- const locKeyType = loc[0].kt;
33
- if (model.associations[locKeyType]) {
34
- const association = model.associations[locKeyType];
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
- [association.foreignKey]: {
38
- [sequelize.Op.eq]: loc[0].lk
75
+ [foreignKeyField]: {
76
+ [sequelize.Op.eq]: locKey.lk
39
77
  }
40
78
  };
41
- } else {
42
- logger.error('Location key type not found in sequelize model association for: %s', locKeyType);
43
- throw new Error('Location key type not found in model');
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWxsLmNqcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OyJ9
121
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWxsLmNqcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7In0=
@@ -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
- return core.validateKeys(await RowProcessor.processRow(item, kta, references, aggregations, registry), kta);
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0LmNqcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7In0=
88
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0LmNqcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7In0=