@fjell/lib-sequelize 4.4.5 → 4.4.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/cjs/Coordinate.cjs +9 -22
  2. package/dist/cjs/Definition.cjs +5 -26
  3. package/dist/cjs/Instance.cjs +26 -10
  4. package/dist/cjs/InstanceFactory.cjs +25 -0
  5. package/dist/cjs/Operations.cjs +7 -2
  6. package/dist/cjs/Options.cjs +14 -7
  7. package/dist/cjs/QueryBuilder.cjs +31 -25
  8. package/dist/cjs/contained/Instance.cjs +15 -8
  9. package/dist/cjs/index.cjs +7 -4
  10. package/dist/cjs/ops/all.cjs +44 -20
  11. package/dist/cjs/ops/create.cjs +138 -40
  12. package/dist/cjs/ops/find.cjs +9 -7
  13. package/dist/cjs/ops/get.cjs +9 -5
  14. package/dist/cjs/ops/one.cjs +7 -6
  15. package/dist/cjs/ops/remove.cjs +10 -7
  16. package/dist/cjs/ops/update.cjs +10 -7
  17. package/dist/cjs/primary/Instance.cjs +16 -9
  18. package/dist/cjs/util/general.cjs +1 -5
  19. package/dist/es/Coordinate.js +9 -3
  20. package/dist/es/Definition.js +5 -7
  21. package/dist/es/Instance.js +26 -11
  22. package/dist/es/InstanceFactory.js +21 -0
  23. package/dist/es/Operations.js +7 -2
  24. package/dist/es/Options.js +14 -7
  25. package/dist/es/QueryBuilder.js +31 -25
  26. package/dist/es/contained/Instance.js +15 -8
  27. package/dist/es/index.js +4 -3
  28. package/dist/es/ops/all.js +44 -20
  29. package/dist/es/ops/create.js +139 -41
  30. package/dist/es/ops/find.js +9 -7
  31. package/dist/es/ops/get.js +9 -5
  32. package/dist/es/ops/one.js +7 -6
  33. package/dist/es/ops/remove.js +11 -8
  34. package/dist/es/ops/update.js +11 -8
  35. package/dist/es/primary/Instance.js +16 -9
  36. package/dist/es/util/general.js +2 -5
  37. package/dist/index.cjs +412 -216
  38. package/dist/index.cjs.map +1 -1
  39. package/dist/types/AggregationBuilder.d.ts +1 -1
  40. package/dist/types/Coordinate.d.ts +3 -2
  41. package/dist/types/Definition.d.ts +3 -3
  42. package/dist/types/Instance.d.ts +22 -2
  43. package/dist/types/InstanceFactory.d.ts +14 -0
  44. package/dist/types/Operations.d.ts +3 -2
  45. package/dist/types/Options.d.ts +1 -1
  46. package/dist/types/Registry.d.ts +6 -0
  47. package/dist/types/contained/Instance.d.ts +3 -3
  48. package/dist/types/index.d.ts +4 -1
  49. package/dist/types/primary/Instance.d.ts +2 -2
  50. package/package.json +23 -23
package/dist/index.cjs CHANGED
@@ -3,10 +3,11 @@
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
4
 
5
5
  const Library = require('@fjell/lib');
6
- const deepmerge = require('deepmerge');
7
6
  const Logging = require('@fjell/logging');
7
+ const registry = require('@fjell/registry');
8
8
  const core = require('@fjell/core');
9
9
  const sequelize = require('sequelize');
10
+ require('deepmerge');
10
11
 
11
12
  function _interopNamespaceDefault(e) {
12
13
  const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } });
@@ -27,20 +28,58 @@ function _interopNamespaceDefault(e) {
27
28
 
28
29
  const Library__namespace = /*#__PURE__*/_interopNamespaceDefault(Library);
29
30
 
31
+ const DEFAULT_SEQUELIZE_OPTIONS = {
32
+ deleteOnRemove: false,
33
+ references: [],
34
+ aggregations: []
35
+ };
36
+ const createOptions = (sequelizeOptions)=>{
37
+ // Create the base lib options
38
+ const baseOptions = Library__namespace.createOptions(sequelizeOptions);
39
+ var _sequelizeOptions_deleteOnRemove, _sequelizeOptions_references, _sequelizeOptions_aggregations;
40
+ // Add Sequelize-specific defaults
41
+ const result = {
42
+ ...baseOptions,
43
+ deleteOnRemove: (_sequelizeOptions_deleteOnRemove = sequelizeOptions === null || sequelizeOptions === void 0 ? void 0 : sequelizeOptions.deleteOnRemove) !== null && _sequelizeOptions_deleteOnRemove !== void 0 ? _sequelizeOptions_deleteOnRemove : DEFAULT_SEQUELIZE_OPTIONS.deleteOnRemove,
44
+ references: (_sequelizeOptions_references = sequelizeOptions === null || sequelizeOptions === void 0 ? void 0 : sequelizeOptions.references) !== null && _sequelizeOptions_references !== void 0 ? _sequelizeOptions_references : DEFAULT_SEQUELIZE_OPTIONS.references,
45
+ aggregations: (_sequelizeOptions_aggregations = sequelizeOptions === null || sequelizeOptions === void 0 ? void 0 : sequelizeOptions.aggregations) !== null && _sequelizeOptions_aggregations !== void 0 ? _sequelizeOptions_aggregations : DEFAULT_SEQUELIZE_OPTIONS.aggregations
46
+ };
47
+ return result;
48
+ };
49
+
50
+ const logger$1.default = Logging.getLogger('@fjell/lib-sequelize');
51
+
52
+ const logger$i = logger$1.default.get('Coordinate');
30
53
  const SCOPE_SEQUELIZE = 'sequelize';
31
54
  const createCoordinate = (kta, scopes)=>{
32
- const coordinate = Library__namespace.createCoordinate(kta, [
55
+ logger$i.debug('createCoordinate', {
56
+ kta,
57
+ scopes
58
+ });
59
+ const coordinate = registry.createCoordinate(kta, [
33
60
  SCOPE_SEQUELIZE,
34
61
  ...scopes || []
35
62
  ]);
36
63
  return coordinate;
37
64
  };
38
65
 
39
- /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable no-undefined */ const clean = (obj)=>{
40
- return Object.fromEntries(Object.entries(obj).filter(([_, v])=>v !== undefined));
66
+ const logger$h = logger$1.default.get('lib-sequelize', 'Definition');
67
+ const createDefinition = (kta, scopes, libOptions)=>{
68
+ logger$h.debug('createDefinition', {
69
+ kta,
70
+ scopes,
71
+ libOptions
72
+ });
73
+ const coordinate = createCoordinate(kta, scopes);
74
+ const options = createOptions(libOptions);
75
+ return {
76
+ coordinate,
77
+ options
78
+ };
41
79
  };
80
+
42
81
  //Recursive implementation of jSON.stringify;
43
- const general.stringifyJSON = function(obj, visited = new Set()) {
82
+ const stringifyJSON = function(obj, visited = new Set()) {
44
83
  const arrOfKeyVals = [];
45
84
  const arrVals = [];
46
85
  let objKeys = [];
@@ -55,7 +94,7 @@ const general.stringifyJSON = function(obj, visited = new Set()) {
55
94
  // Add array to visited before processing its elements
56
95
  visited.add(obj);
57
96
  obj.forEach(function(el) {
58
- arrVals.push(general.stringifyJSON(el, visited));
97
+ arrVals.push(stringifyJSON(el, visited));
59
98
  });
60
99
  return '[' + arrVals + ']';
61
100
  }
@@ -73,7 +112,7 @@ const general.stringifyJSON = function(obj, visited = new Set()) {
73
112
  else if (typeof keyValOut === 'string') arrOfKeyVals.push(keyOut + '"' + keyValOut + '"');
74
113
  else if (typeof keyValOut === 'boolean' || typeof keyValOut === 'number' || keyValOut === null) arrOfKeyVals.push(keyOut + keyValOut);
75
114
  else if (keyValOut instanceof Object) {
76
- arrOfKeyVals.push(keyOut + general.stringifyJSON(keyValOut, visited));
115
+ arrOfKeyVals.push(keyOut + stringifyJSON(keyValOut, visited));
77
116
  }
78
117
  });
79
118
  return '{' + arrOfKeyVals + '}';
@@ -81,39 +120,9 @@ const general.stringifyJSON = function(obj, visited = new Set()) {
81
120
  return '';
82
121
  };
83
122
 
84
- const DEFAULT_OPTIONS = {
85
- deleteOnRemove: false,
86
- references: [],
87
- aggregations: []
88
- };
89
- const createOptions = (libOptions)=>{
90
- const options = Library__namespace.createOptions(libOptions);
91
- return deepmerge(DEFAULT_OPTIONS, clean(options));
92
- };
93
-
94
- const logger$1.default = Logging.getLogger('@fjell/lib-sequelize');
95
-
96
- const logger$f = logger$1.default.get('lib-sequelize', 'Definition');
97
- function createDefinition(kta, scopes, libOptions) {
98
- logger$f.debug('createDefinition', {
99
- kta,
100
- scopes,
101
- libOptions
102
- });
103
- const coordinate = createCoordinate(kta, scopes);
104
- const options = createOptions(libOptions);
105
- const definition = Library__namespace.createDefinition(coordinate, options);
106
- return {
107
- ...definition,
108
- options
109
- };
110
- }
111
-
112
- const logger$e = logger$1.default.get('sequelize', 'QueryBuilder');
123
+ const logger$g = logger$1.default.get('sequelize', 'QueryBuilder');
113
124
  const addDeleteQuery = (options, model)=>{
114
- logger$e.default('Adding Delete Query', {
115
- options
116
- });
125
+ logger$g.default(`QueryBuilder adding delete query with options: ${stringifyJSON(options)}`);
117
126
  if (model.getAttributes().deletedAt) {
118
127
  options.where['deletedAt'] = {
119
128
  [sequelize.Op.eq]: null
@@ -126,10 +135,7 @@ const addDeleteQuery = (options, model)=>{
126
135
  return options;
127
136
  };
128
137
  const addEventQueries = (options, events, model)=>{
129
- logger$e.default('Adding Event Queries', {
130
- options,
131
- events
132
- });
138
+ logger$g.default(`QueryBuilder adding event queries with options: ${stringifyJSON(options)}, events: ${stringifyJSON(events)}`);
133
139
  Object.keys(events).forEach((key)=>{
134
140
  if (!model.getAttributes()[`${key}At`]) {
135
141
  throw new Error(`Event ${key} is not supported on this model, column ${key}At not found`);
@@ -163,20 +169,22 @@ const addEventQueries = (options, events, model)=>{
163
169
  };
164
170
  // Add the references to the query
165
171
  const addReferenceQueries = (options, references, model)=>{
166
- logger$e.default('Adding Reference Queries', {
167
- options,
168
- references
169
- });
172
+ logger$g.default(`QueryBuilder adding reference queries with options: ${stringifyJSON(options)}, references: ${stringifyJSON(references)}`);
170
173
  Object.keys(references).forEach((key)=>{
171
- logger$e.default('Adding Reference Query', {
172
- key,
173
- references
174
- });
174
+ logger$g.default(`QueryBuilder adding reference query for key: ${key}, references: ${stringifyJSON(references)}`);
175
175
  if (!model.getAttributes()[`${key}Id`]) {
176
176
  throw new Error(`Reference ${key} is not supported on this model, column ${key}Id not found`);
177
177
  }
178
178
  if (core.isPriKey(references[key])) {
179
179
  const priKey = references[key];
180
+ if (priKey.pk == null || priKey.pk === '' || typeof priKey.pk === 'object' && Object.keys(priKey.pk).length === 0) {
181
+ logger$g.error(`Reference key '${key}' has invalid pk value: ${stringifyJSON(priKey.pk)}`, {
182
+ priKey,
183
+ references
184
+ });
185
+ throw new Error(`Reference key '${key}' has invalid pk value: ${stringifyJSON(priKey.pk)}`);
186
+ }
187
+ logger$g.trace(`[QueryBuilder] Setting reference where clause: ${key}Id = ${stringifyJSON(priKey.pk)} (type: ${typeof priKey.pk})`);
180
188
  options.where[`${key}Id`] = {
181
189
  [sequelize.Op.eq]: priKey.pk
182
190
  };
@@ -253,6 +261,13 @@ const addAssociationCondition = (conditions, condition, model)=>{
253
261
  // Use Sequelize's $association.attribute$ syntax for querying associated models
254
262
  const sequelizeAssociationColumn = `$${associationName}.${attributeName}$`;
255
263
  const conditionOp = getSequelizeOperator(condition.operator);
264
+ if (condition.value == null && condition.operator !== '==' && condition.operator !== 'in') {
265
+ logger$g.error(`Association condition for '${associationName}.${attributeName}' has undefined/null value`, {
266
+ condition
267
+ });
268
+ throw new Error(`Association condition for '${associationName}.${attributeName}' has undefined/null value`);
269
+ }
270
+ logger$g.trace(`[QueryBuilder] Setting association condition: ${sequelizeAssociationColumn} = ${stringifyJSON(condition.value)} (type: ${typeof condition.value})`);
256
271
  conditions[sequelizeAssociationColumn] = {
257
272
  [conditionOp]: condition.value
258
273
  };
@@ -264,6 +279,13 @@ const addAttributeCondition = (conditions, condition, model)=>{
264
279
  throw new Error(`Condition column ${conditionColumn} not found on model ${model.name}`);
265
280
  }
266
281
  const conditionOp = getSequelizeOperator(condition.operator);
282
+ if (condition.value == null && condition.operator !== '==' && condition.operator !== 'in') {
283
+ logger$g.error(`Attribute condition for '${conditionColumn}' has undefined/null value`, {
284
+ condition
285
+ });
286
+ throw new Error(`Attribute condition for '${conditionColumn}' has undefined/null value`);
287
+ }
288
+ logger$g.trace(`[QueryBuilder] Setting attribute condition: ${conditionColumn} = ${stringifyJSON(condition.value)} (type: ${typeof condition.value})`);
267
289
  conditions[conditionColumn] = {
268
290
  [conditionOp]: condition.value
269
291
  };
@@ -334,16 +356,12 @@ const addAssociationIncludes = (options, model)=>{
334
356
  return options;
335
357
  };
336
358
  const buildQuery = (itemQuery, model)=>{
337
- logger$e.default('build', {
338
- itemQuery
339
- });
359
+ logger$g.default(`QueryBuilder build called with itemQuery: ${stringifyJSON(itemQuery)}`);
340
360
  let options = {
341
361
  where: {}
342
362
  };
343
363
  if (itemQuery.compoundCondition) {
344
- logger$e.default('Adding Conditions', {
345
- compoundCondition: itemQuery.compoundCondition
346
- });
364
+ logger$g.default(`QueryBuilder adding conditions: ${stringifyJSON(itemQuery.compoundCondition)}`);
347
365
  options = addCompoundCondition(options, itemQuery.compoundCondition, model);
348
366
  }
349
367
  // If the model has a deletedAt column, we need to add a delete query
@@ -359,9 +377,7 @@ const buildQuery = (itemQuery, model)=>{
359
377
  // TODO: Once we start to support Aggs on the server-side, we'll need to parse agg queries
360
378
  // Apply a limit to the result set
361
379
  if (itemQuery.limit) {
362
- logger$e.default('Limiting to', {
363
- limit: itemQuery.limit
364
- });
380
+ logger$g.default(`QueryBuilder applying limit: ${itemQuery.limit}`);
365
381
  options.limit = itemQuery.limit;
366
382
  }
367
383
  // Apply an offset to the result set
@@ -497,10 +513,10 @@ const buildQuery = (itemQuery, model)=>{
497
513
  return result;
498
514
  };
499
515
 
500
- const logger$d = logger$1.default.get('sequelize', 'KeyMaster');
516
+ const logger$f = logger$1.default.get('sequelize', 'KeyMaster');
501
517
  // Helper function to extract location key value from item
502
518
  const extractLocationKeyValue = (model, item, locatorType, kta)=>{
503
- logger$d.default('Extracting location key value', {
519
+ logger$f.default('Extracting location key value', {
504
520
  locatorType,
505
521
  kta
506
522
  });
@@ -555,7 +571,7 @@ const extractLocationKeyValue = (model, item, locatorType, kta)=>{
555
571
  }
556
572
  };
557
573
  const removeKey = (item)=>{
558
- logger$d.default('Removing Key', {
574
+ logger$f.default('Removing Key', {
559
575
  item
560
576
  });
561
577
  delete item.key;
@@ -589,7 +605,7 @@ const removeKey = (item)=>{
589
605
  // return item;
590
606
  // }
591
607
  const addKey = (model, item, keyTypes)=>{
592
- logger$d.default('Adding Key', {
608
+ logger$f.default('Adding Key', {
593
609
  item
594
610
  });
595
611
  const key = {};
@@ -615,7 +631,7 @@ const addKey = (model, item, keyTypes)=>{
615
631
  });
616
632
  } catch (error) {
617
633
  const errorMessage = error instanceof Error ? error.message : String(error);
618
- logger$d.error(`Failed to extract location key for '${locatorType}'`, {
634
+ logger$f.error(`Failed to extract location key for '${locatorType}'`, {
619
635
  error: errorMessage,
620
636
  item,
621
637
  keyTypes
@@ -638,7 +654,7 @@ const addKey = (model, item, keyTypes)=>{
638
654
  return item;
639
655
  };
640
656
 
641
- const logger$c = logger$1.default.get('sequelize', 'ReferenceBuilder');
657
+ const logger$e = logger$1.default.get('sequelize', 'ReferenceBuilder');
642
658
  const buildReference = async (item, referenceDefinition, registry, context)=>{
643
659
  // Check if there is more than one key type
644
660
  if (referenceDefinition.kta.length > 1) {
@@ -668,13 +684,13 @@ const buildReference = async (item, referenceDefinition, registry, context)=>{
668
684
  if (context) {
669
685
  // Check if we already have this item cached
670
686
  if (context.isCached(priKey)) {
671
- logger$c.default('Using cached reference', {
687
+ logger$e.default('Using cached reference', {
672
688
  priKey,
673
689
  property: referenceDefinition.property
674
690
  });
675
691
  referencedItem = context.getCached(priKey);
676
692
  } else if (context.isInProgress(priKey)) {
677
- logger$c.default('Circular dependency detected, creating reference placeholder', {
693
+ logger$e.default('Circular dependency detected, creating reference placeholder', {
678
694
  priKey,
679
695
  property: referenceDefinition.property
680
696
  });
@@ -719,7 +735,7 @@ function _define_property(obj, key, value) {
719
735
  }
720
736
  return obj;
721
737
  }
722
- const logger$b = logger$1.default.get('sequelize', 'OperationContext');
738
+ const logger$d = logger$1.default.get('sequelize', 'OperationContext');
723
739
  /**
724
740
  * Serialize an ItemKey to a string for use in sets and maps
725
741
  */ const OperationContext.serializeKey = (key)=>{
@@ -743,7 +759,7 @@ const logger$b = logger$1.default.get('sequelize', 'OperationContext');
743
759
  cache,
744
760
  markInProgress (key) {
745
761
  const serialized = OperationContext.serializeKey(key);
746
- logger$b.default('Marking key as in progress', {
762
+ logger$d.default('Marking key as in progress', {
747
763
  key,
748
764
  serialized
749
765
  });
@@ -751,7 +767,7 @@ const logger$b = logger$1.default.get('sequelize', 'OperationContext');
751
767
  },
752
768
  markComplete (key) {
753
769
  const serialized = OperationContext.serializeKey(key);
754
- logger$b.default('Marking key as complete', {
770
+ logger$d.default('Marking key as complete', {
755
771
  key,
756
772
  serialized
757
773
  });
@@ -760,7 +776,7 @@ const logger$b = logger$1.default.get('sequelize', 'OperationContext');
760
776
  isInProgress (key) {
761
777
  const serialized = OperationContext.serializeKey(key);
762
778
  const result = inProgress.has(serialized);
763
- logger$b.default('Checking if key is in progress', {
779
+ logger$d.default('Checking if key is in progress', {
764
780
  key,
765
781
  serialized,
766
782
  result
@@ -770,7 +786,7 @@ const logger$b = logger$1.default.get('sequelize', 'OperationContext');
770
786
  getCached (key) {
771
787
  const serialized = OperationContext.serializeKey(key);
772
788
  const result = cache.get(serialized);
773
- logger$b.default('Getting cached item', {
789
+ logger$d.default('Getting cached item', {
774
790
  key,
775
791
  serialized,
776
792
  found: !!result
@@ -779,7 +795,7 @@ const logger$b = logger$1.default.get('sequelize', 'OperationContext');
779
795
  },
780
796
  setCached (key, item) {
781
797
  const serialized = OperationContext.serializeKey(key);
782
- logger$b.default('Caching item', {
798
+ logger$d.default('Caching item', {
783
799
  key,
784
800
  serialized
785
801
  });
@@ -788,7 +804,7 @@ const logger$b = logger$1.default.get('sequelize', 'OperationContext');
788
804
  isCached (key) {
789
805
  const serialized = OperationContext.serializeKey(key);
790
806
  const result = cache.has(serialized);
791
- logger$b.default('Checking if key is cached', {
807
+ logger$d.default('Checking if key is cached', {
792
808
  key,
793
809
  serialized,
794
810
  result
@@ -806,7 +822,7 @@ const logger$b = logger$1.default.get('sequelize', 'OperationContext');
806
822
  const contextId = Math.random().toString(36).substring(7);
807
823
  this.contexts.set(contextId, context);
808
824
  this.currentContextId = contextId;
809
- logger$b.default('Set current context', {
825
+ logger$d.default('Set current context', {
810
826
  contextId
811
827
  });
812
828
  return contextId;
@@ -816,7 +832,7 @@ const logger$b = logger$1.default.get('sequelize', 'OperationContext');
816
832
  */ getCurrentContext() {
817
833
  if (this.currentContextId) {
818
834
  const context = this.contexts.get(this.currentContextId);
819
- logger$b.default('Got current context', {
835
+ logger$d.default('Got current context', {
820
836
  contextId: this.currentContextId,
821
837
  found: !!context
822
838
  });
@@ -828,7 +844,7 @@ const logger$b = logger$1.default.get('sequelize', 'OperationContext');
828
844
  * Clear the current context
829
845
  */ clearCurrentContext() {
830
846
  if (this.currentContextId) {
831
- logger$b.default('Clearing current context', {
847
+ logger$d.default('Clearing current context', {
832
848
  contextId: this.currentContextId
833
849
  });
834
850
  this.contexts.delete(this.currentContextId);
@@ -857,7 +873,7 @@ const logger$b = logger$1.default.get('sequelize', 'OperationContext');
857
873
  // Global context manager instance
858
874
  const OperationContext.contextManager = new ContextManager();
859
875
 
860
- const logger$a = logger$1.default.get('sequelize', 'AggregationBuilder');
876
+ const logger$c = logger$1.default.get('sequelize', 'AggregationBuilder');
861
877
  const buildAggregation = async (item, aggregationDefinition, registry, context)=>{
862
878
  const location = core.ikToLKA(item.key);
863
879
  // Get the library instance from the registry using the key type array
@@ -872,7 +888,7 @@ const buildAggregation = async (item, aggregationDefinition, registry, context)=
872
888
  // Check if this aggregation is already cached
873
889
  if (context.cache.has(aggregationCacheKey)) {
874
890
  const cachedResult = context.cache.get(aggregationCacheKey);
875
- logger$a.default('Using cached aggregation result', {
891
+ logger$c.default('Using cached aggregation result', {
876
892
  aggregationCacheKey,
877
893
  property: aggregationDefinition.property
878
894
  });
@@ -912,7 +928,7 @@ const buildAggregation = async (item, aggregationDefinition, registry, context)=
912
928
  });
913
929
  };
914
930
 
915
- const logger$9 = logger$1.default.get("sequelize", "EventCoordinator");
931
+ const logger$b = logger$1.default.get("sequelize", "EventCoordinator");
916
932
  //#endregion
917
933
  const populateEvents = (item)=>{
918
934
  const events = {
@@ -930,7 +946,7 @@ const populateEvents = (item)=>{
930
946
  return item;
931
947
  };
932
948
  const extractEvents = (item)=>{
933
- logger$9.default('Extracting Events to database fields', {
949
+ logger$b.default('Extracting Events to database fields', {
934
950
  item
935
951
  });
936
952
  if (item.events) {
@@ -948,16 +964,16 @@ const extractEvents = (item)=>{
948
964
  return item;
949
965
  };
950
966
  const removeEvents = (item)=>{
951
- logger$9.default('Removing Events', {
967
+ logger$b.default('Removing Events', {
952
968
  item
953
969
  });
954
970
  delete item.events;
955
971
  return item;
956
972
  };
957
973
 
958
- const logger$8 = logger$1.default.get('sequelize', 'RowProcessor');
974
+ const logger$a = logger$1.default.get('sequelize', 'RowProcessor');
959
975
  const processRow = async (row, keyTypes, referenceDefinitions, aggregationDefinitions, registry, context)=>{
960
- logger$8.default('Processing Row', {
976
+ logger$a.default('Processing Row', {
961
977
  row
962
978
  });
963
979
  // Use provided context or create new one
@@ -967,22 +983,22 @@ const processRow = async (row, keyTypes, referenceDefinitions, aggregationDefini
967
983
  let item = row.get({
968
984
  plain: true
969
985
  });
970
- logger$8.default('Adding Key to Item with Key Types: %s', general.stringifyJSON(keyTypes));
986
+ logger$a.default('Adding Key to Item with Key Types: %s', stringifyJSON(keyTypes));
971
987
  item = addKey(row, item, keyTypes);
972
988
  item = populateEvents(item);
973
- logger$8.default('Key Added to Item: %s', general.stringifyJSON(item.key));
989
+ logger$a.default('Key Added to Item: %s', stringifyJSON(item.key));
974
990
  // Mark this item as in progress to detect circular references
975
991
  operationContext.markInProgress(item.key);
976
992
  try {
977
993
  if (referenceDefinitions && referenceDefinitions.length > 0) {
978
994
  for (const referenceDefinition of referenceDefinitions){
979
- logger$8.default('Processing Reference for %s to %s', item.key.kt, general.stringifyJSON(referenceDefinition.kta));
995
+ logger$a.default('Processing Reference for %s to %s', item.key.kt, stringifyJSON(referenceDefinition.kta));
980
996
  item = await buildReference(item, referenceDefinition, registry, operationContext);
981
997
  }
982
998
  }
983
999
  if (aggregationDefinitions && aggregationDefinitions.length > 0) {
984
1000
  for (const aggregationDefinition of aggregationDefinitions){
985
- logger$8.default('Processing Aggregation for %s from %s', item.key.kt, general.stringifyJSON(aggregationDefinition.kta));
1001
+ logger$a.default('Processing Aggregation for %s from %s', item.key.kt, stringifyJSON(aggregationDefinition.kta));
986
1002
  item = await buildAggregation(item, aggregationDefinition, registry, operationContext);
987
1003
  }
988
1004
  }
@@ -992,12 +1008,12 @@ const processRow = async (row, keyTypes, referenceDefinitions, aggregationDefini
992
1008
  // Mark this item as complete
993
1009
  operationContext.markComplete(item.key);
994
1010
  }
995
- logger$8.default('Processed Row: %j', general.stringifyJSON(item));
1011
+ logger$a.default('Processed Row: %j', stringifyJSON(item));
996
1012
  return item;
997
1013
  });
998
1014
  };
999
1015
 
1000
- const logger$7 = logger$1.default.get('sequelize', 'ops', 'all');
1016
+ const logger$9 = logger$1.default.get('sequelize', 'ops', 'all');
1001
1017
  // Helper function to merge includes avoiding duplicates
1002
1018
  const mergeIncludes$1 = (existingIncludes, newIncludes)=>{
1003
1019
  const mergedIncludes = [
@@ -1022,10 +1038,8 @@ const all.getAllOperation = (models, definition, registry)=>{
1022
1038
  const { coordinate, options: { references, aggregations } } = definition;
1023
1039
  //#region Query
1024
1040
  const all = async (itemQuery, locations)=>{
1025
- logger$7.default('All', {
1026
- itemQuery,
1027
- locations
1028
- });
1041
+ var _options_include;
1042
+ logger$9.debug(`ALL operation called on ${models[0].name} with ${(locations === null || locations === void 0 ? void 0 : locations.length) || 0} location filters: ${(locations === null || locations === void 0 ? void 0 : locations.map((loc)=>`${loc.kt}=${loc.lk}`).join(', ')) || 'none'}`);
1029
1043
  const loc = locations || [];
1030
1044
  // @ts-ignore
1031
1045
  const model = models[0];
@@ -1042,7 +1056,7 @@ const all.getAllOperation = (models, definition, registry)=>{
1042
1056
  const relationshipInfo = relationshipUtils.buildRelationshipPath(model, locKey.kt, kta, true);
1043
1057
  if (!relationshipInfo.found) {
1044
1058
  const errorMessage = `Location key '${locKey.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
1045
- logger$7.error(errorMessage, {
1059
+ logger$9.error(errorMessage, {
1046
1060
  locations: loc,
1047
1061
  kta
1048
1062
  });
@@ -1056,24 +1070,44 @@ const all.getAllOperation = (models, definition, registry)=>{
1056
1070
  }
1057
1071
  // Handle direct location keys (simple foreign key constraints)
1058
1072
  for (const locKey of directLocations){
1073
+ if (locKey.lk === undefined || locKey.lk == null || locKey.lk === '' || typeof locKey.lk === 'object' && Object.keys(locKey.lk).length === 0) {
1074
+ logger$9.error(`Location key '${locKey.kt}' has invalid lk value: ${stringifyJSON(locKey.lk)}`, {
1075
+ locKey,
1076
+ locations: loc
1077
+ });
1078
+ throw new Error(`Location key '${locKey.kt}' has invalid lk value: ${stringifyJSON(locKey.lk)}`);
1079
+ }
1059
1080
  const foreignKeyField = locKey.kt + 'Id';
1060
- options.where = {
1061
- ...options.where,
1062
- [foreignKeyField]: {
1063
- [sequelize.Op.eq]: locKey.lk
1064
- }
1081
+ // Check if this field already has a condition from the itemQuery
1082
+ if (options.where[foreignKeyField]) {
1083
+ logger$9.debug(`[ALL] Field ${foreignKeyField} already constrained by itemQuery, skipping location constraint to avoid conflicts`);
1084
+ continue; // Skip this location constraint to avoid conflicts
1085
+ }
1086
+ logger$9.trace(`[ALL] Setting direct location where clause: ${foreignKeyField} = ${stringifyJSON(locKey.lk)} (type: ${typeof locKey.lk})`);
1087
+ options.where[foreignKeyField] = {
1088
+ [sequelize.Op.eq]: locKey.lk
1065
1089
  };
1066
1090
  }
1067
1091
  // Handle hierarchical location keys (requires relationship traversal)
1068
1092
  for (const locKey of hierarchicalLocations){
1093
+ if (locKey.lk === undefined || locKey.lk == null || locKey.lk === '' || typeof locKey.lk === 'object' && Object.keys(locKey.lk).length === 0) {
1094
+ logger$9.error(`Hierarchical location key '${locKey.kt}' has invalid lk value: ${stringifyJSON(locKey.lk)}`, {
1095
+ locKey,
1096
+ locations: loc
1097
+ });
1098
+ throw new Error(`Hierarchical location key '${locKey.kt}' has invalid lk value: ${stringifyJSON(locKey.lk)}`);
1099
+ }
1069
1100
  const relationshipInfo = relationshipUtils.buildRelationshipPath(model, locKey.kt, kta);
1070
1101
  if (relationshipInfo.found && relationshipInfo.path) {
1102
+ // Check if this field already has a condition from the itemQuery
1103
+ if (options.where[relationshipInfo.path]) {
1104
+ logger$9.debug(`[ALL] Field ${relationshipInfo.path} already constrained by itemQuery, skipping hierarchical location constraint to avoid conflicts`);
1105
+ continue; // Skip this location constraint to avoid conflicts
1106
+ }
1071
1107
  // Add the relationship constraint using the path
1072
- options.where = {
1073
- ...options.where,
1074
- [relationshipInfo.path]: {
1075
- [sequelize.Op.eq]: locKey.lk
1076
- }
1108
+ logger$9.trace(`[ALL] Setting hierarchical location where clause: ${relationshipInfo.path} = ${stringifyJSON(locKey.lk)} (type: ${typeof locKey.lk})`);
1109
+ options.where[relationshipInfo.path] = {
1110
+ [sequelize.Op.eq]: locKey.lk
1077
1111
  };
1078
1112
  // Add necessary includes for the relationship traversal
1079
1113
  if (relationshipInfo.includes) {
@@ -1087,63 +1121,134 @@ const all.getAllOperation = (models, definition, registry)=>{
1087
1121
  options.include = mergeIncludes$1(existingIncludes, additionalIncludes);
1088
1122
  }
1089
1123
  }
1090
- logger$7.default('Configured this Item Query', {
1091
- itemQuery,
1092
- options
1093
- });
1124
+ logger$9.default(`All query configured for ${model.name} with where fields: ${options.where ? Object.keys(options.where).join(', ') : 'none'}, includes: ${((_options_include = options.include) === null || _options_include === void 0 ? void 0 : _options_include.length) || 0}`);
1125
+ try {
1126
+ logger$9.trace(`[ALL] Executing ${model.name}.findAll() with options: ${JSON.stringify(options, null, 2)}`);
1127
+ } catch {
1128
+ // Fallback for cases where JSON.stringify fails on Sequelize operators
1129
+ logger$9.trace(`[ALL] Executing ${model.name}.findAll() with options containing non-serializable operators (${Object.keys(options.where || {}).length} where conditions)`);
1130
+ }
1094
1131
  const matchingItems = await model.findAll(options);
1095
1132
  // this.logger.default('Matching Items', { matchingItems });
1096
1133
  // Get the current context from context manager
1097
1134
  const context = OperationContext.contextManager.getCurrentContext();
1098
1135
  // TODO: Move this Up!
1099
- return await Promise.all(matchingItems.map(async (row)=>{
1136
+ const results = await Promise.all(matchingItems.map(async (row)=>{
1100
1137
  const processedRow = await processRow(row, coordinate.kta, references, aggregations, registry, context);
1101
1138
  return core.validateKeys(processedRow, coordinate.kta);
1102
1139
  }));
1140
+ logger$9.debug(`[ALL] Returning ${results.length} ${model.name} records`);
1141
+ return results;
1103
1142
  };
1104
1143
  return all;
1105
1144
  };
1106
1145
 
1107
- const logger$6 = logger$1.default.get('sequelize', 'ops', 'create');
1146
+ const logger$8 = logger$1.default.get('sequelize', 'ops', 'create');
1147
+ // Helper function to translate PostgreSQL errors to meaningful messages
1148
+ function translateDatabaseError(error, itemData, modelName) {
1149
+ var _error_original, _error_original1, _error_original2;
1150
+ const originalMessage = error.message || '';
1151
+ const errorCode = (_error_original = error.original) === null || _error_original === void 0 ? void 0 : _error_original.code;
1152
+ const constraint = (_error_original1 = error.original) === null || _error_original1 === void 0 ? void 0 : _error_original1.constraint;
1153
+ const detail = (_error_original2 = error.original) === null || _error_original2 === void 0 ? void 0 : _error_original2.detail;
1154
+ logger$8.error('Database error during create operation', {
1155
+ errorCode,
1156
+ constraint,
1157
+ detail,
1158
+ originalMessage,
1159
+ modelName,
1160
+ itemData: JSON.stringify(itemData, null, 2)
1161
+ });
1162
+ // Handle specific PostgreSQL error codes
1163
+ switch(errorCode){
1164
+ case '23505':
1165
+ if (constraint) {
1166
+ return new Error(`Duplicate value violates unique constraint '${constraint}'. ${detail || ''}`);
1167
+ }
1168
+ return new Error(`Duplicate value detected. This record already exists. ${detail || ''}`);
1169
+ case '23503':
1170
+ if (constraint) {
1171
+ return new Error(`Foreign key constraint '${constraint}' violated. Referenced record does not exist. ${detail || ''}`);
1172
+ }
1173
+ return new Error(`Referenced record does not exist. Check that all related records are valid. ${detail || ''}`);
1174
+ case '23502':
1175
+ var _error_original3;
1176
+ const column = (_error_original3 = error.original) === null || _error_original3 === void 0 ? void 0 : _error_original3.column;
1177
+ if (column) {
1178
+ return new Error(`Required field '${column}' cannot be null`);
1179
+ }
1180
+ return new Error(`Required field is missing or null`);
1181
+ case '23514':
1182
+ if (constraint) {
1183
+ return new Error(`Check constraint '${constraint}' violated. ${detail || ''}`);
1184
+ }
1185
+ return new Error(`Data validation failed. Check constraint violated. ${detail || ''}`);
1186
+ case '22001':
1187
+ return new Error(`Data too long for field. Check string lengths. ${detail || ''}`);
1188
+ case '22003':
1189
+ return new Error(`Numeric value out of range. Check number values. ${detail || ''}`);
1190
+ case '42703':
1191
+ var _error_original4;
1192
+ const undefinedColumn = (_error_original4 = error.original) === null || _error_original4 === void 0 ? void 0 : _error_original4.column;
1193
+ if (undefinedColumn) {
1194
+ return new Error(`Column '${undefinedColumn}' does not exist in table '${modelName}'`);
1195
+ }
1196
+ return new Error(`Referenced column does not exist`);
1197
+ case '42P01':
1198
+ return new Error(`Table '${modelName}' does not exist`);
1199
+ default:
1200
+ // For unknown errors, provide the original message with context
1201
+ return new Error(`Database error in ${modelName}.create(): ${originalMessage}. Item data: ${JSON.stringify(itemData, null, 2)}`);
1202
+ }
1203
+ }
1108
1204
  // Helper function to validate hierarchical chain exists
1109
1205
  async function validateHierarchicalChain(models, locKey, kta) {
1110
- // Find the direct parent model that contains this locator
1111
- const locatorIndex = kta.indexOf(locKey.kt);
1112
- if (locatorIndex === -1) {
1113
- throw new Error(`Locator type '${locKey.kt}' not found in kta array`);
1114
- }
1115
- // Get the model for this locator
1116
- const locatorModel = models[locatorIndex] || models[0]; // Fallback to primary model
1117
- // Build a query to validate the chain exists
1118
- const chainResult = buildRelationshipChain(locatorModel, kta, locatorIndex, kta.length - 1);
1119
- if (!chainResult.success) {
1120
- // If we can't build a chain, just validate the record exists
1121
- const record = await locatorModel.findByPk(locKey.lk);
1206
+ try {
1207
+ // Find the direct parent model that contains this locator
1208
+ const locatorIndex = kta.indexOf(locKey.kt);
1209
+ if (locatorIndex === -1) {
1210
+ throw new Error(`Locator type '${locKey.kt}' not found in kta array`);
1211
+ }
1212
+ // Get the model for this locator
1213
+ const locatorModel = models[locatorIndex] || models[0]; // Fallback to primary model
1214
+ // Build a query to validate the chain exists
1215
+ const chainResult = buildRelationshipChain(locatorModel, kta, locatorIndex, kta.length - 1);
1216
+ if (!chainResult.success) {
1217
+ // If we can't build a chain, just validate the record exists
1218
+ const record = await locatorModel.findByPk(locKey.lk);
1219
+ if (!record) {
1220
+ throw new Error(`Referenced ${locKey.kt} with id ${locKey.lk} does not exist`);
1221
+ }
1222
+ return;
1223
+ }
1224
+ // Validate that the chain exists
1225
+ const queryOptions = {
1226
+ where: {
1227
+ id: locKey.lk
1228
+ }
1229
+ };
1230
+ if (chainResult.includes && chainResult.includes.length > 0) {
1231
+ queryOptions.include = chainResult.includes;
1232
+ }
1233
+ const record = await locatorModel.findOne(queryOptions);
1122
1234
  if (!record) {
1123
- throw new Error(`Referenced ${locKey.kt} with id ${locKey.lk} does not exist`);
1235
+ throw new Error(`Referenced ${locKey.kt} with id ${locKey.lk} does not exist or chain is invalid`);
1124
1236
  }
1125
- return;
1126
- }
1127
- // Validate that the chain exists
1128
- const queryOptions = {
1129
- where: {
1130
- id: locKey.lk
1237
+ } catch (error) {
1238
+ // Add context to validation errors
1239
+ if (error.original) {
1240
+ throw translateDatabaseError(error, {
1241
+ locKey,
1242
+ kta
1243
+ }, locKey.kt);
1131
1244
  }
1132
- };
1133
- if (chainResult.includes && chainResult.includes.length > 0) {
1134
- queryOptions.include = chainResult.includes;
1135
- }
1136
- const record = await locatorModel.findOne(queryOptions);
1137
- if (!record) {
1138
- throw new Error(`Referenced ${locKey.kt} with id ${locKey.lk} does not exist or chain is invalid`);
1245
+ throw error;
1139
1246
  }
1140
1247
  }
1141
1248
  const getCreateOperation = (models, definition, registry)=>{
1142
1249
  const create = async (item, options)=>{
1143
- logger$6.default('Create', {
1144
- item,
1145
- options
1146
- });
1250
+ logger$8.debug(`CREATE operation called on ${models[0].name} with ${(options === null || options === void 0 ? void 0 : options.key) ? `key: pk=${options.key.pk}, loc=[${core.isComKey(options.key) ? options.key.loc.map((l)=>`${l.kt}=${l.lk}`).join(', ') : ''}]` : (options === null || options === void 0 ? void 0 : options.locations) ? `locations: ${options.locations.map((loc)=>`${loc.kt}=${loc.lk}`).join(', ')}` : 'no constraints'}`);
1251
+ logger$8.default(`Create configured for ${models[0].name} with ${Object.keys(item).length} item fields`);
1147
1252
  const { coordinate, options: { references, aggregations } } = definition;
1148
1253
  const { kta } = coordinate;
1149
1254
  // Get the primary model (first model in array)
@@ -1156,11 +1261,17 @@ const getCreateOperation = (models, definition, registry)=>{
1156
1261
  // TODO: We need the opposite of processRow, something to step down from fjell to database.
1157
1262
  itemData = extractEvents(itemData);
1158
1263
  itemData = removeEvents(itemData);
1264
+ // Validate that all item attributes exist on the model
1265
+ const invalidAttributes = [];
1159
1266
  for (const key of Object.keys(itemData)){
1160
1267
  if (!modelAttributes[key]) {
1161
- throw new Error(`Attribute '${key}' does not exist on model ${model.name}`);
1268
+ invalidAttributes.push(key);
1162
1269
  }
1163
1270
  }
1271
+ if (invalidAttributes.length > 0) {
1272
+ const availableAttributes = Object.keys(modelAttributes).join(', ');
1273
+ throw new Error(`Invalid attributes for model '${model.name}': [${invalidAttributes.join(', ')}]. ` + `Available attributes: [${availableAttributes}]. ` + `Item data: ${JSON.stringify(itemData, null, 2)}`);
1274
+ }
1164
1275
  // Handle key options
1165
1276
  // If a key is supplied, assume its contents are to be assigned to the appropriate ids.
1166
1277
  // For most cases this will be null as key generation is often through autoIncrement.
@@ -1181,10 +1292,12 @@ const getCreateOperation = (models, definition, registry)=>{
1181
1292
  for (const locKey of comKey.loc){
1182
1293
  const relationshipInfo = relationshipUtils.buildRelationshipPath(model, locKey.kt, kta, true);
1183
1294
  if (!relationshipInfo.found) {
1184
- const errorMessage = `Composite key locator '${locKey.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
1185
- logger$6.error(errorMessage, {
1295
+ const associations = model.associations ? Object.keys(model.associations) : [];
1296
+ const errorMessage = `Composite key locator '${locKey.kt}' cannot be resolved on model '${model.name}' or through its relationships. ` + `Available associations: [${associations.join(', ')}]. ` + `KTA: [${kta.join(', ')}]. ` + `Composite key: ${JSON.stringify(comKey, null, 2)}`;
1297
+ logger$8.error(errorMessage, {
1186
1298
  key: comKey,
1187
- kta
1299
+ kta,
1300
+ associations
1188
1301
  });
1189
1302
  throw new Error(errorMessage);
1190
1303
  }
@@ -1196,6 +1309,13 @@ const getCreateOperation = (models, definition, registry)=>{
1196
1309
  }
1197
1310
  // Set direct foreign keys
1198
1311
  for (const locKey of directLocations){
1312
+ if (locKey.lk == null || locKey.lk === '') {
1313
+ logger$8.error(`Composite key location '${locKey.kt}' has undefined/null lk value`, {
1314
+ locKey,
1315
+ key: comKey
1316
+ });
1317
+ throw new Error(`Composite key location '${locKey.kt}' has undefined/null lk value`);
1318
+ }
1199
1319
  const foreignKeyField = locKey.kt + 'Id';
1200
1320
  itemData[foreignKeyField] = locKey.lk;
1201
1321
  }
@@ -1214,10 +1334,12 @@ const getCreateOperation = (models, definition, registry)=>{
1214
1334
  for (const locKey of options.locations){
1215
1335
  const relationshipInfo = relationshipUtils.buildRelationshipPath(model, locKey.kt, kta, true);
1216
1336
  if (!relationshipInfo.found) {
1217
- const errorMessage = `Location key '${locKey.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
1218
- logger$6.error(errorMessage, {
1337
+ const associations = model.associations ? Object.keys(model.associations) : [];
1338
+ const errorMessage = `Location key '${locKey.kt}' cannot be resolved on model '${model.name}' or through its relationships. ` + `Available associations: [${associations.join(', ')}]. ` + `KTA: [${kta.join(', ')}]. ` + `Locations: ${JSON.stringify(options.locations, null, 2)}`;
1339
+ logger$8.error(errorMessage, {
1219
1340
  locations: options.locations,
1220
- kta
1341
+ kta,
1342
+ associations
1221
1343
  });
1222
1344
  throw new Error(errorMessage);
1223
1345
  }
@@ -1229,6 +1351,13 @@ const getCreateOperation = (models, definition, registry)=>{
1229
1351
  }
1230
1352
  // Set direct foreign keys
1231
1353
  for (const locKey of directLocations){
1354
+ if (locKey.lk == null || locKey.lk === '') {
1355
+ logger$8.error(`Location option '${locKey.kt}' has undefined/null lk value`, {
1356
+ locKey,
1357
+ locations: options.locations
1358
+ });
1359
+ throw new Error(`Location option '${locKey.kt}' has undefined/null lk value`);
1360
+ }
1232
1361
  const foreignKeyField = locKey.kt + 'Id';
1233
1362
  itemData[foreignKeyField] = locKey.lk;
1234
1363
  }
@@ -1238,50 +1367,58 @@ const getCreateOperation = (models, definition, registry)=>{
1238
1367
  }
1239
1368
  }
1240
1369
  // Create the record
1241
- const createdRecord = await model.create(itemData);
1242
- // Add key and events
1243
- const processedRecord = await processRow(createdRecord, kta, references, aggregations, registry);
1244
- return core.validateKeys(processedRecord, kta);
1370
+ try {
1371
+ logger$8.trace(`[CREATE] Executing ${model.name}.create() with data: ${stringifyJSON(itemData)}`);
1372
+ const createdRecord = await model.create(itemData);
1373
+ // Add key and events
1374
+ const processedRecord = await processRow(createdRecord, kta, references, aggregations, registry);
1375
+ const result = core.validateKeys(processedRecord, kta);
1376
+ logger$8.debug(`[CREATE] Created ${model.name} with key: ${result.key ? JSON.stringify(result.key) : `id=${createdRecord.id}`}`);
1377
+ return result;
1378
+ } catch (error) {
1379
+ throw translateDatabaseError(error, itemData, model.name);
1380
+ }
1245
1381
  };
1246
1382
  return create;
1247
1383
  };
1248
1384
 
1249
- const logger$5 = logger$1.default.get('sequelize', 'ops', 'find');
1385
+ const logger$7 = logger$1.default.get('sequelize', 'ops', 'find');
1250
1386
  const getFindOperation = (models, definition, registry)=>{
1251
1387
  const { options: { finders, references, aggregations } } = definition;
1252
1388
  const find = async (finder, finderParams, locations)=>{
1253
- logger$5.default('Find', {
1254
- finder,
1255
- finderParams,
1256
- locations
1257
- });
1389
+ logger$7.debug(`FIND operation called on ${models[0].name} with finder '${finder}' and ${(locations === null || locations === void 0 ? void 0 : locations.length) || 0} location filters: ${(locations === null || locations === void 0 ? void 0 : locations.map((loc)=>`${loc.kt}=${loc.lk}`).join(', ')) || 'none'}`);
1390
+ logger$7.default(`Find configured for ${models[0].name} using finder '${finder}' with ${Object.keys(finderParams).length} params`);
1258
1391
  // Note that we execute the createFinders function here because we want to make sure we're always getting the
1259
1392
  // most up to date methods.
1260
1393
  if (finders && finders[finder]) {
1261
1394
  const finderMethod = finders[finder];
1262
1395
  if (finderMethod) {
1396
+ logger$7.trace(`[FIND] Executing finder '${finder}' on ${models[0].name} with params: ${stringifyJSON(finderParams)}, locations: ${stringifyJSON(locations)}`);
1263
1397
  const results = await finderMethod(finderParams, locations);
1264
1398
  if (results && results.length > 0) {
1265
- return await Promise.all(results.map(async (row)=>{
1399
+ const processedResults = await Promise.all(results.map(async (row)=>{
1266
1400
  const processedRow = await processRow(row, definition.coordinate.kta, references, aggregations, registry);
1267
1401
  return core.validateKeys(processedRow, definition.coordinate.kta);
1268
1402
  }));
1403
+ logger$7.debug(`[FIND] Found ${processedResults.length} ${models[0].name} records using finder '${finder}'`);
1404
+ return processedResults;
1269
1405
  } else {
1406
+ logger$7.debug(`[FIND] Found 0 ${models[0].name} records using finder '${finder}'`);
1270
1407
  return [];
1271
1408
  }
1272
1409
  } else {
1273
- logger$5.error(`Finder %s not found`, finder);
1410
+ logger$7.error(`Finder %s not found`, finder);
1274
1411
  throw new Error(`Finder ${finder} not found`);
1275
1412
  }
1276
1413
  } else {
1277
- logger$5.error(`No finders have been defined for this lib`);
1414
+ logger$7.error(`No finders have been defined for this lib`);
1278
1415
  throw new Error(`No finders found`);
1279
1416
  }
1280
1417
  };
1281
1418
  return find;
1282
1419
  };
1283
1420
 
1284
- const logger$4 = logger$1.default.get('sequelize', 'ops', 'get');
1421
+ const logger$6 = logger$1.default.get('sequelize', 'ops', 'get');
1285
1422
  // Helper function to process composite key and build query options
1286
1423
  const processCompositeKey$1 = (comKey, model, kta)=>{
1287
1424
  const where = {
@@ -1292,7 +1429,7 @@ const processCompositeKey$1 = (comKey, model, kta)=>{
1292
1429
  const relationshipInfo = relationshipUtils.buildRelationshipPath(model, locator.kt, kta);
1293
1430
  if (!relationshipInfo.found) {
1294
1431
  const errorMessage = `Composite key locator '${locator.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
1295
- logger$4.error(errorMessage, {
1432
+ logger$6.error(errorMessage, {
1296
1433
  key: comKey,
1297
1434
  kta
1298
1435
  });
@@ -1322,27 +1459,28 @@ const getGetOperation = (models, definition, registry)=>{
1322
1459
  const { coordinate, options: { references, aggregations } } = definition;
1323
1460
  const { kta } = coordinate;
1324
1461
  const get = async (key)=>{
1325
- logger$4.default('Get', {
1326
- key
1327
- });
1328
1462
  if (!core.isValidItemKey(key)) {
1329
- logger$4.error('Key for Get is not a valid ItemKey: %j', key);
1463
+ logger$6.error('Key for Get is not a valid ItemKey: %j', key);
1330
1464
  throw new Error('Key for Get is not a valid ItemKey');
1331
1465
  }
1466
+ logger$6.debug(`GET operation called on ${models[0].name} with ${core.isPriKey(key) ? `primary key: pk=${key.pk}` : `composite key: pk=${key.pk}, loc=[${key.loc.map((l)=>`${l.kt}=${l.lk}`).join(', ')}]`}`);
1467
+ logger$6.default(`Get configured for ${models[0].name} with ${core.isPriKey(key) ? 'primary' : 'composite'} key`);
1332
1468
  const itemKey = key;
1333
1469
  // @ts-ignore
1334
1470
  const model = models[0];
1335
1471
  let item;
1336
1472
  if (core.isPriKey(itemKey)) {
1337
1473
  // This is the easy case because we can just find the item by its primary key
1474
+ logger$6.trace(`[GET] Executing ${model.name}.findByPk() with pk: ${itemKey.pk}`);
1338
1475
  item = await model.findByPk(itemKey.pk);
1339
1476
  } else if (core.isComKey(itemKey)) {
1340
1477
  // This is a composite key, so we need to build a where clause based on the composite key's locators
1341
1478
  const comKey = itemKey;
1342
1479
  const queryOptions = processCompositeKey$1(comKey, model, kta);
1343
- logger$4.default('Composite key query', {
1480
+ logger$6.default('Composite key query', {
1344
1481
  queryOptions
1345
1482
  });
1483
+ logger$6.trace(`[GET] Executing ${model.name}.findOne() with options: ${stringifyJSON(queryOptions)}`);
1346
1484
  item = await model.findOne(queryOptions);
1347
1485
  }
1348
1486
  if (!item) {
@@ -1350,30 +1488,33 @@ const getGetOperation = (models, definition, registry)=>{
1350
1488
  } else {
1351
1489
  // Get the current context from context manager
1352
1490
  const context = OperationContext.contextManager.getCurrentContext();
1353
- return core.validateKeys(await processRow(item, kta, references, aggregations, registry, context), kta);
1491
+ const result = core.validateKeys(await processRow(item, kta, references, aggregations, registry, context), kta);
1492
+ logger$6.debug(`[GET] Retrieved ${model.name} with key: ${result.key ? JSON.stringify(result.key) : `id=${item.id}`}`);
1493
+ return result;
1354
1494
  }
1355
1495
  };
1356
1496
  return get;
1357
1497
  };
1358
1498
 
1359
- const logger$3 = logger$1.default.get('sequelize', 'ops', 'one');
1499
+ const logger$5 = logger$1.default.get('sequelize', 'ops', 'one');
1360
1500
  const getOneOperation = (models, definition, registry)=>{
1361
1501
  const one = async (itemQuery, locations = [])=>{
1362
- logger$3.default('One', {
1363
- itemQuery,
1364
- locations
1365
- });
1502
+ logger$5.debug(`ONE operation called on ${models[0].name} with ${locations.length} location filters: ${locations.map((loc)=>`${loc.kt}=${loc.lk}`).join(', ') || 'none'}`);
1503
+ logger$5.default(`One configured for ${models[0].name} delegating to all operation`);
1366
1504
  const items = await all.getAllOperation(models, definition, registry)(itemQuery, locations);
1367
1505
  if (items.length > 0) {
1368
- return items[0];
1506
+ const result = items[0];
1507
+ logger$5.debug(`[ONE] Found ${models[0].name} record with key: ${result.key ? JSON.stringify(result.key) : 'unknown'}`);
1508
+ return result;
1369
1509
  } else {
1510
+ logger$5.debug(`[ONE] No ${models[0].name} record found`);
1370
1511
  return null;
1371
1512
  }
1372
1513
  };
1373
1514
  return one;
1374
1515
  };
1375
1516
 
1376
- const logger$2 = logger$1.default.get('sequelize', 'ops', 'remove');
1517
+ const logger$4 = logger$1.default.get('sequelize', 'ops', 'remove');
1377
1518
  // Helper function to process composite key and build query options
1378
1519
  const processCompositeKey = (comKey, model, kta)=>{
1379
1520
  const where = {
@@ -1384,7 +1525,7 @@ const processCompositeKey = (comKey, model, kta)=>{
1384
1525
  const relationshipInfo = relationshipUtils.buildRelationshipPath(model, locator.kt, kta);
1385
1526
  if (!relationshipInfo.found) {
1386
1527
  const errorMessage = `Composite key locator '${locator.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
1387
- logger$2.error(errorMessage, {
1528
+ logger$4.error(errorMessage, {
1388
1529
  key: comKey,
1389
1530
  kta
1390
1531
  });
@@ -1415,27 +1556,26 @@ registry)=>{
1415
1556
  const { coordinate, options } = definition;
1416
1557
  const { kta } = coordinate;
1417
1558
  const remove = async (key)=>{
1418
- logger$2.default('Remove', {
1419
- key
1420
- });
1421
1559
  if (!core.isValidItemKey(key)) {
1422
- logger$2.error('Key for Remove is not a valid ItemKey: %j', key);
1560
+ logger$4.error('Key for Remove is not a valid ItemKey: %j', key);
1423
1561
  throw new Error('Key for Remove is not a valid ItemKey');
1424
1562
  }
1563
+ logger$4.debug(`REMOVE operation called on ${models[0].name} with ${core.isPriKey(key) ? `primary key: pk=${key.pk}` : `composite key: pk=${key.pk}, loc=[${key.loc.map((l)=>`${l.kt}=${l.lk}`).join(', ')}]`}`);
1564
+ logger$4.default(`Remove configured for ${models[0].name} with ${core.isPriKey(key) ? 'primary' : 'composite'} key`);
1425
1565
  // @ts-ignore
1426
1566
  const model = models[0];
1427
1567
  let item;
1428
1568
  let returnItem;
1429
- logger$2.debug('remove: %s', core.abbrevIK(key));
1569
+ logger$4.debug('remove: %s', core.abbrevIK(key));
1430
1570
  if (core.isPriKey(key)) {
1571
+ logger$4.debug(`[REMOVE] Executing ${model.name}.findByPk() with pk: ${key.pk}`);
1431
1572
  item = await model.findByPk(key.pk);
1432
1573
  } else if (core.isComKey(key)) {
1433
1574
  // This is a composite key, so we need to build a where clause based on the composite key's locators
1434
1575
  const comKey = key;
1435
1576
  const queryOptions = processCompositeKey(comKey, model, kta);
1436
- logger$2.default('Composite key query', {
1437
- queryOptions
1438
- });
1577
+ logger$4.default(`Remove composite key query for ${model.name} with where fields: ${queryOptions.where ? Object.keys(queryOptions.where).join(', ') : 'none'}`);
1578
+ logger$4.debug(`[REMOVE] Executing ${model.name}.findOne() with options: ${stringifyJSON(queryOptions)}`);
1439
1579
  item = await model.findOne(queryOptions);
1440
1580
  }
1441
1581
  if (!item) {
@@ -1451,6 +1591,7 @@ registry)=>{
1451
1591
  item.deletedAt = new Date();
1452
1592
  }
1453
1593
  // Save the object
1594
+ logger$4.debug(`[REMOVE] Executing ${model.name}.save() for soft delete`);
1454
1595
  await (item === null || item === void 0 ? void 0 : item.save());
1455
1596
  returnItem = item === null || item === void 0 ? void 0 : item.get({
1456
1597
  plain: true
@@ -1458,6 +1599,7 @@ registry)=>{
1458
1599
  returnItem = addKey(item, returnItem, kta);
1459
1600
  returnItem = populateEvents(returnItem);
1460
1601
  } else if (options.deleteOnRemove) {
1602
+ logger$4.debug(`[REMOVE] Executing ${model.name}.destroy() for hard delete`);
1461
1603
  await (item === null || item === void 0 ? void 0 : item.destroy());
1462
1604
  returnItem = item === null || item === void 0 ? void 0 : item.get({
1463
1605
  plain: true
@@ -1467,12 +1609,13 @@ registry)=>{
1467
1609
  } else {
1468
1610
  throw new Error('No deletedAt or isDeleted attribute found in model, and deleteOnRemove is not set');
1469
1611
  }
1612
+ logger$4.debug(`[REMOVE] Removed ${model.name} with key: ${returnItem.key ? JSON.stringify(returnItem.key) : `id=${item.id}`}`);
1470
1613
  return returnItem;
1471
1614
  };
1472
1615
  return remove;
1473
1616
  };
1474
1617
 
1475
- const logger$1 = logger$1.default.get('sequelize', 'ops', 'update');
1618
+ const logger$3 = logger$1.default.get('sequelize', 'ops', 'update');
1476
1619
  // Helper function to merge includes avoiding duplicates
1477
1620
  const mergeIncludes = (existingIncludes, newIncludes)=>{
1478
1621
  const mergedIncludes = [
@@ -1496,9 +1639,10 @@ const mergeIncludes = (existingIncludes, newIncludes)=>{
1496
1639
  const getUpdateOperation = (models, definition, registry)=>{
1497
1640
  const { options: { references, aggregations } } = definition;
1498
1641
  const update = async (key, item)=>{
1642
+ logger$3.debug(`UPDATE operation called on ${models[0].name} with ${core.isPriKey(key) ? `primary key: pk=${key.pk}` : `composite key: pk=${key.pk}, loc=[${key.loc.map((l)=>`${l.kt}=${l.lk}`).join(', ')}]`}`);
1499
1643
  const { coordinate } = definition;
1500
1644
  const { kta } = coordinate;
1501
- logger$1.debug('update: %s, %j', core.abbrevIK(key), item);
1645
+ logger$3.debug('update: %s, %j', core.abbrevIK(key), item);
1502
1646
  // Find the object we're updating
1503
1647
  // @ts-ignore
1504
1648
  const model = models[0];
@@ -1506,6 +1650,7 @@ const getUpdateOperation = (models, definition, registry)=>{
1506
1650
  if (core.isPriKey(key)) {
1507
1651
  // Find the model by using the PK
1508
1652
  const priKey = key;
1653
+ logger$3.trace(`[UPDATE] Executing ${model.name}.findByPk() with pk: ${priKey.pk}`);
1509
1654
  response = await model.findByPk(priKey.pk);
1510
1655
  } else if (core.isComKey(key)) {
1511
1656
  const comKey = key;
@@ -1519,7 +1664,7 @@ const getUpdateOperation = (models, definition, registry)=>{
1519
1664
  const relationshipInfo = relationshipUtils.buildRelationshipPath(model, locator.kt, kta, true);
1520
1665
  if (!relationshipInfo.found) {
1521
1666
  const errorMessage = `Composite key locator '${locator.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
1522
- logger$1.error(errorMessage, {
1667
+ logger$3.error(errorMessage, {
1523
1668
  key: comKey,
1524
1669
  kta
1525
1670
  });
@@ -1547,9 +1692,8 @@ const getUpdateOperation = (models, definition, registry)=>{
1547
1692
  if (additionalIncludes.length > 0) {
1548
1693
  queryOptions.include = mergeIncludes([], additionalIncludes);
1549
1694
  }
1550
- logger$1.default('Composite key query for update', {
1551
- queryOptions
1552
- });
1695
+ logger$3.default(`Update composite key query for ${model.name} with where fields: ${queryOptions.where ? Object.keys(queryOptions.where).join(', ') : 'none'}`);
1696
+ logger$3.trace(`[UPDATE] Executing ${model.name}.findOne() with options: ${stringifyJSON(queryOptions)}`);
1553
1697
  response = await model.findOne(queryOptions);
1554
1698
  }
1555
1699
  if (response) {
@@ -1558,13 +1702,15 @@ const getUpdateOperation = (models, definition, registry)=>{
1558
1702
  // TODO: We need the opposite of processRow, something to step down from fjell to database.
1559
1703
  updateProps = extractEvents(updateProps);
1560
1704
  updateProps = removeEvents(updateProps);
1561
- logger$1.default('Response: %s', general.stringifyJSON(response));
1562
- logger$1.default('Update Properties: %s', general.stringifyJSON(updateProps));
1705
+ logger$3.default(`Update found ${model.name} record to modify`);
1706
+ logger$3.default(`Update properties configured: ${Object.keys(updateProps).join(', ')}`);
1563
1707
  // Update the object
1708
+ logger$3.trace(`[UPDATE] Executing ${model.name}.update() with properties: ${stringifyJSON(updateProps)}`);
1564
1709
  response = await response.update(updateProps);
1565
1710
  // Populate the key and events
1566
1711
  const processedItem = await processRow(response, kta, references, aggregations, registry);
1567
1712
  const returnItem = core.validateKeys(processedItem, kta);
1713
+ logger$3.debug(`[UPDATE] Updated ${model.name} with key: ${returnItem.key ? JSON.stringify(returnItem.key) : `id=${response.id}`}`);
1568
1714
  return returnItem;
1569
1715
  } else {
1570
1716
  throw new Library.NotFoundError('update', coordinate, key);
@@ -1573,8 +1719,13 @@ const getUpdateOperation = (models, definition, registry)=>{
1573
1719
  return update;
1574
1720
  };
1575
1721
 
1576
- const createOperations = (models, definition, registry)=>{
1722
+ const createOperations = (models, coordinate, registry, options)=>{
1577
1723
  const operations = {};
1724
+ // Create a definition-like object for backward compatibility with existing operation functions
1725
+ const definition = {
1726
+ coordinate,
1727
+ options
1728
+ };
1578
1729
  operations.all = all.getAllOperation(models, definition, registry);
1579
1730
  operations.one = getOneOperation(models, definition, registry);
1580
1731
  operations.create = getCreateOperation(models, definition, registry);
@@ -1588,25 +1739,62 @@ const createOperations = (models, definition, registry)=>{
1588
1739
  return operations;
1589
1740
  };
1590
1741
 
1591
- function createInstance$2(keyTypes, models, libOptions = {}, scopes = [], registry) {
1592
- const definition = createDefinition(keyTypes, scopes, libOptions);
1593
- const operations = createOperations(models, definition, registry);
1594
- return {
1595
- definition,
1596
- operations: Library__namespace.wrapOperations(operations, definition, registry),
1742
+ const logger$2 = logger$1.default.get("Instance");
1743
+ /**
1744
+ * Creates a new Sequelize instance that extends the fjell-lib instance
1745
+ * with Sequelize-specific functionality
1746
+ */ const createInstance$2 = (registry, coordinate, models, options)=>{
1747
+ logger$2.debug("createInstance", {
1748
+ coordinate,
1597
1749
  models,
1598
- registry
1750
+ registry,
1751
+ options
1752
+ });
1753
+ // Create Sequelize-specific operations
1754
+ const operations = createOperations(models, coordinate, registry, options);
1755
+ // Create the base fjell-lib instance
1756
+ const libInstance = Library__namespace.createInstance(registry, coordinate, operations, options);
1757
+ return {
1758
+ ...libInstance,
1759
+ models
1599
1760
  };
1600
- }
1761
+ };
1762
+ /**
1763
+ * Type guard to check if an object is a Sequelize Instance
1764
+ */ const isInstance = (instance)=>{
1765
+ return instance != null && instance.coordinate != null && instance.operations != null && instance.options != null && instance.registry != null && instance.models != null && Array.isArray(instance.models);
1766
+ };
1767
+
1768
+ const logger$1 = logger$1.default.get("InstanceFactory");
1769
+ /**
1770
+ * Factory function for creating Sequelize instances
1771
+ * This extends the fjell-lib pattern by adding Sequelize-specific models
1772
+ */ const createInstanceFactory = (models, options)=>{
1773
+ return (coordinate, context)=>{
1774
+ logger$1.debug("Creating Sequelize instance", {
1775
+ coordinate,
1776
+ registry: context.registry,
1777
+ models: models.map((m)=>m.name),
1778
+ options
1779
+ });
1780
+ return createInstance$2(context.registry, coordinate, models, options);
1781
+ };
1782
+ };
1601
1783
 
1602
1784
  function createInstance$1(keyTypes, models, libOptions = {}, scopes = [], registry) {
1603
- const definition = createDefinition(keyTypes, scopes, libOptions);
1604
- const operations = createOperations(models, definition, registry);
1785
+ // Create coordinate and options separately following new pattern
1786
+ const coordinate = createCoordinate(keyTypes, scopes);
1787
+ const options = createOptions(libOptions);
1788
+ // Create operations with the new signature
1789
+ const operations = createOperations(models, coordinate, registry, options);
1790
+ // Wrap operations for contained pattern
1791
+ const wrappedOperations = Library.Contained.wrapOperations(operations, options, coordinate, registry);
1605
1792
  return {
1606
- definition,
1607
- operations: Library.Contained.wrapOperations(operations, definition, registry),
1608
- models,
1609
- registry
1793
+ coordinate,
1794
+ registry,
1795
+ operations: wrappedOperations,
1796
+ options,
1797
+ models
1610
1798
  };
1611
1799
  }
1612
1800
 
@@ -1623,15 +1811,21 @@ function createInstance(keyType, models, libOptions = {}, scopes = [], registry)
1623
1811
  libOptions,
1624
1812
  scopes
1625
1813
  });
1626
- const definition = createDefinition([
1814
+ // Create coordinate and options separately following new pattern
1815
+ const coordinate = createCoordinate([
1627
1816
  keyType
1628
- ], scopes, libOptions);
1629
- const operations = createOperations(models, definition, registry);
1817
+ ], scopes);
1818
+ const options = createOptions(libOptions);
1819
+ // Create operations with the new signature
1820
+ const operations = createOperations(models, coordinate, registry, options);
1821
+ // Wrap operations for primary pattern
1822
+ const wrappedOperations = Library.Primary.wrapOperations(operations, options, coordinate, registry);
1630
1823
  return {
1631
- definition,
1632
- operations: Library.Primary.wrapOperations(operations, definition, registry),
1633
- models,
1634
- registry
1824
+ coordinate,
1825
+ registry,
1826
+ operations: wrappedOperations,
1827
+ options,
1828
+ models
1635
1829
  };
1636
1830
  }
1637
1831
 
@@ -1646,6 +1840,8 @@ exports.SCOPE_SEQUELIZE = SCOPE_SEQUELIZE;
1646
1840
  exports.createCoordinate = createCoordinate;
1647
1841
  exports.createDefinition = createDefinition;
1648
1842
  exports.createInstance = createInstance$2;
1843
+ exports.createInstanceFactory = createInstanceFactory;
1649
1844
  exports.createOperations = createOperations;
1650
1845
  exports.createOptions = createOptions;
1846
+ exports.isInstance = isInstance;
1651
1847
  //# sourceMappingURL=index.cjs.map