@fjell/lib-sequelize 4.4.54 → 4.4.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -26,7 +26,7 @@ var LibLogger = Logging.getLogger("@fjell/lib-sequelize");
26
26
  var logger_default = LibLogger;
27
27
 
28
28
  // src/Coordinate.ts
29
- import { createCoordinate as createBaseCoordinate } from "@fjell/registry";
29
+ import { createCoordinate as createBaseCoordinate } from "@fjell/core";
30
30
  var logger = logger_default.get("Coordinate");
31
31
  var SCOPE_SEQUELIZE = "sequelize";
32
32
  var createCoordinate = (kta, scopes) => {
@@ -48,10 +48,14 @@ var createDefinition = (kta, scopes, libOptions) => {
48
48
  };
49
49
 
50
50
  // src/SequelizeLibrary.ts
51
+ import * as Library3 from "@fjell/lib";
52
+
53
+ // src/Operations.ts
51
54
  import * as Library2 from "@fjell/lib";
52
55
 
53
56
  // src/ops/all.ts
54
- import { validateKeys } from "@fjell/core";
57
+ import { createAllWrapper } from "@fjell/core";
58
+ import { validateKeys } from "@fjell/core/validation";
55
59
 
56
60
  // src/QueryBuilder.ts
57
61
  import {
@@ -376,52 +380,6 @@ var buildQuery = (itemQuery, model) => {
376
380
  return options;
377
381
  };
378
382
 
379
- // src/validation/LocationKeyValidator.ts
380
- var logger4 = logger_default.get("LocationKeyValidator");
381
- var validateLocations = (locations, coordinate, operation) => {
382
- if (!locations || locations.length === 0) {
383
- return;
384
- }
385
- const keyTypeArray = coordinate.kta;
386
- const expectedLocationTypes = keyTypeArray.slice(1);
387
- const actualLocationTypes = locations.map((loc) => loc.kt);
388
- logger4.debug(`Validating locations for ${operation}`, {
389
- expected: expectedLocationTypes,
390
- actual: actualLocationTypes,
391
- coordinate: keyTypeArray
392
- });
393
- if (actualLocationTypes.length > expectedLocationTypes.length) {
394
- logger4.error("Location key array has too many elements", {
395
- expected: expectedLocationTypes.length,
396
- actual: actualLocationTypes.length,
397
- expectedTypes: expectedLocationTypes,
398
- actualTypes: actualLocationTypes,
399
- coordinate,
400
- operation
401
- });
402
- throw new Error(
403
- `Invalid location key array for ${operation}: Expected at most ${expectedLocationTypes.length} location keys (hierarchy: [${expectedLocationTypes.join(", ")}]), but received ${actualLocationTypes.length} (types: [${actualLocationTypes.join(", ")}])`
404
- );
405
- }
406
- for (let i = 0; i < actualLocationTypes.length; i++) {
407
- if (expectedLocationTypes[i] !== actualLocationTypes[i]) {
408
- logger4.error("Location key array order mismatch", {
409
- position: i,
410
- expected: expectedLocationTypes[i],
411
- actual: actualLocationTypes[i],
412
- expectedHierarchy: expectedLocationTypes,
413
- actualOrder: actualLocationTypes,
414
- coordinate,
415
- operation
416
- });
417
- throw new Error(
418
- `Invalid location key array order for ${operation}: At position ${i}, expected key type "${expectedLocationTypes[i]}" but received "${actualLocationTypes[i]}". Location keys must be ordered according to the hierarchy: [${expectedLocationTypes.join(", ")}]. Received order: [${actualLocationTypes.join(", ")}]`
419
- );
420
- }
421
- }
422
- logger4.debug(`Location key array validation passed for ${operation}`, { locations });
423
- };
424
-
425
383
  // src/util/relationshipUtils.ts
426
384
  var buildRelationshipChain = (targetModel, kta, currentIndex, targetIndex) => {
427
385
  const associationParts = [];
@@ -502,9 +460,9 @@ var buildRelationshipPath = (targetModel, locatorType, kta, includeIsDirect = fa
502
460
  };
503
461
 
504
462
  // src/KeyMaster.ts
505
- var logger5 = logger_default.get("sequelize", "KeyMaster");
463
+ var logger4 = logger_default.get("sequelize", "KeyMaster");
506
464
  var extractLocationKeyValue = (model, item, locatorType, kta) => {
507
- logger5.default("Extracting location key value", { locatorType, kta });
465
+ logger4.default("Extracting location key value", { locatorType, kta });
508
466
  const relationshipInfo = buildRelationshipPath(model, locatorType, kta, true);
509
467
  if (!relationshipInfo.found) {
510
468
  throw new Error(`Location key '${locatorType}' cannot be resolved on model '${model.name}' or through its relationships. Key type array: [${kta.join(", ")}]. Available associations: [${Object.keys(model.associations || {}).join(", ")}]`);
@@ -548,12 +506,12 @@ var extractLocationKeyValue = (model, item, locatorType, kta) => {
548
506
  }
549
507
  };
550
508
  var removeKey = (item) => {
551
- logger5.default("Removing Key", { item });
509
+ logger4.default("Removing Key", { item });
552
510
  delete item.key;
553
511
  return item;
554
512
  };
555
513
  var addKey = (model, item, keyTypes) => {
556
- logger5.default("Adding Key", { item });
514
+ logger4.default("Adding Key", { item });
557
515
  const key = {};
558
516
  const modelClass = model.constructor;
559
517
  const primaryKeyAttr = modelClass.primaryKeyAttribute;
@@ -568,7 +526,7 @@ var addKey = (model, item, keyTypes) => {
568
526
  locationKeys.push({ kt: locatorType, lk });
569
527
  } catch (error) {
570
528
  const errorMessage = error instanceof Error ? error.message : String(error);
571
- logger5.error(`Failed to extract location key for '${locatorType}'`, { error: errorMessage, item, keyTypes });
529
+ logger4.error(`Failed to extract location key for '${locatorType}'`, { error: errorMessage, item, keyTypes });
572
530
  throw error;
573
531
  }
574
532
  }
@@ -589,7 +547,7 @@ import {
589
547
 
590
548
  // src/EventCoordinator.ts
591
549
  import deepmerge from "deepmerge";
592
- var logger6 = logger_default.get("sequelize", "EventCoordinator");
550
+ var logger5 = logger_default.get("sequelize", "EventCoordinator");
593
551
  var populateEvents = (item) => {
594
552
  const events = {
595
553
  created: { at: item.createdAt || null },
@@ -600,7 +558,7 @@ var populateEvents = (item) => {
600
558
  return item;
601
559
  };
602
560
  var extractEvents = (item) => {
603
- logger6.default("Extracting Events to database fields", { item });
561
+ logger5.default("Extracting Events to database fields", { item });
604
562
  if (item.events) {
605
563
  if (item.events.created?.at) {
606
564
  item.createdAt = item.events.created.at;
@@ -615,7 +573,7 @@ var extractEvents = (item) => {
615
573
  return item;
616
574
  };
617
575
  var removeEvents = (item) => {
618
- logger6.default("Removing Events", { item });
576
+ logger5.default("Removing Events", { item });
619
577
  delete item.events;
620
578
  return item;
621
579
  };
@@ -750,27 +708,27 @@ var stripSequelizeReferenceItems = (item, referenceDefinitions) => {
750
708
  };
751
709
 
752
710
  // src/RowProcessor.ts
753
- var logger7 = logger_default.get("sequelize", "RowProcessor");
711
+ var logger6 = logger_default.get("sequelize", "RowProcessor");
754
712
  var processRow = async (row, keyTypes, referenceDefinitions, aggregationDefinitions, registry, context) => {
755
- logger7.default("Processing Row", { row });
713
+ logger6.default("Processing Row", { row });
756
714
  const operationContext = context || createOperationContext();
757
715
  return contextManager.withContext(operationContext, async () => {
758
716
  let item = row.get({ plain: true });
759
- logger7.default("Adding Key to Item with Key Types: %s", stringifyJSON(keyTypes));
717
+ logger6.default("Adding Key to Item with Key Types: %s", stringifyJSON(keyTypes));
760
718
  item = addKey(row, item, keyTypes);
761
719
  item = populateEvents(item);
762
- logger7.default("Key Added to Item: %s", stringifyJSON(item.key));
720
+ logger6.default("Key Added to Item: %s", stringifyJSON(item.key));
763
721
  operationContext.markInProgress(item.key);
764
722
  try {
765
723
  if (referenceDefinitions && referenceDefinitions.length > 0) {
766
724
  for (const referenceDefinition of referenceDefinitions) {
767
- logger7.default("Processing Reference for %s to %s", item.key.kt, stringifyJSON(referenceDefinition.kta));
725
+ logger6.default("Processing Reference for %s to %s", item.key.kt, stringifyJSON(referenceDefinition.kta));
768
726
  item = await buildSequelizeReference(item, referenceDefinition, registry, operationContext);
769
727
  }
770
728
  }
771
729
  if (aggregationDefinitions && aggregationDefinitions.length > 0) {
772
730
  for (const aggregationDefinition of aggregationDefinitions) {
773
- logger7.default("Processing Aggregation for %s from %s", item.key.kt, stringifyJSON(aggregationDefinition.kta));
731
+ logger6.default("Processing Aggregation for %s from %s", item.key.kt, stringifyJSON(aggregationDefinition.kta));
774
732
  item = await buildAggregation(item, aggregationDefinition, registry, operationContext);
775
733
  }
776
734
  }
@@ -778,14 +736,205 @@ var processRow = async (row, keyTypes, referenceDefinitions, aggregationDefiniti
778
736
  } finally {
779
737
  operationContext.markComplete(item.key);
780
738
  }
781
- logger7.default("Processed Row: %j", stringifyJSON(item));
739
+ logger6.default("Processed Row: %j", stringifyJSON(item));
782
740
  return item;
783
741
  });
784
742
  };
785
743
 
786
744
  // src/ops/all.ts
787
745
  import { Op as Op2 } from "sequelize";
788
- var logger8 = logger_default.get("sequelize", "ops", "all");
746
+
747
+ // src/errors/sequelizeErrorHandler.ts
748
+ import {
749
+ BusinessLogicError,
750
+ DuplicateError,
751
+ ValidationError
752
+ } from "@fjell/core";
753
+ function transformSequelizeError(error, itemType, key, modelName, itemData) {
754
+ if (error.code === "23505" || error.original?.code === "23505") {
755
+ const constraint = error.original?.constraint;
756
+ const detail = error.original?.detail;
757
+ let message = "";
758
+ if (constraint && detail) {
759
+ message = `Duplicate value violates unique constraint '${constraint}'. ${detail}`;
760
+ } else if (detail) {
761
+ message = `Duplicate value detected. This record already exists. ${detail}`;
762
+ } else {
763
+ message = `${itemType} already exists`;
764
+ }
765
+ const field = error.fields ? Object.keys(error.fields)[0] : "unique constraint";
766
+ return new DuplicateError(message, key, field);
767
+ }
768
+ if (error.name === "SequelizeUniqueConstraintError" || error.code === "ER_DUP_ENTRY") {
769
+ const field = error.fields ? Object.keys(error.fields)[0] : "unique constraint";
770
+ return new DuplicateError(
771
+ `${itemType} already exists`,
772
+ key,
773
+ field
774
+ );
775
+ }
776
+ if (error.name === "SequelizeValidationError") {
777
+ const fields = error.errors?.map((e) => e.path) || [];
778
+ const message = error.errors?.map((e) => e.message).join(", ") || `Validation failed for ${itemType}`;
779
+ return new ValidationError(
780
+ message,
781
+ fields,
782
+ "Fix validation errors and try again"
783
+ );
784
+ }
785
+ if (error.code === "23503" || error.original?.code === "23503") {
786
+ const constraint = error.original?.constraint;
787
+ const detail = error.original?.detail;
788
+ let message = "";
789
+ if (constraint && detail) {
790
+ message = `Foreign key constraint '${constraint}' violated. Referenced record does not exist. ${detail}`;
791
+ } else if (constraint) {
792
+ message = `Foreign key constraint '${constraint}' violated. Referenced record does not exist.`;
793
+ } else if (detail) {
794
+ message = `Referenced record does not exist. Check that all related records are valid. ${detail}`;
795
+ } else {
796
+ message = "Referenced item does not exist";
797
+ }
798
+ return new ValidationError(
799
+ message,
800
+ void 0,
801
+ "Ensure all referenced items exist before creating this relationship"
802
+ );
803
+ }
804
+ if (error.name === "SequelizeForeignKeyConstraintError" || error.code === "ER_NO_REFERENCED_ROW") {
805
+ return new ValidationError(
806
+ "Referenced item does not exist",
807
+ void 0,
808
+ "Ensure all referenced items exist before creating this relationship"
809
+ );
810
+ }
811
+ if (error.code === "23502" || error.original?.code === "23502") {
812
+ const column = error.original?.column;
813
+ const fields = column ? [column] : void 0;
814
+ return new ValidationError(
815
+ column ? `Required field '${column}' cannot be null` : "Required field is missing or null",
816
+ fields,
817
+ "Provide all required fields"
818
+ );
819
+ }
820
+ if (error.code === "23514" || error.original?.code === "23514") {
821
+ const constraint = error.original?.constraint;
822
+ const detail = error.original?.detail;
823
+ let message = "";
824
+ if (constraint && detail) {
825
+ message = `Check constraint '${constraint}' violated. ${detail}`;
826
+ } else if (detail) {
827
+ message = `Data validation failed. Check constraint violated. ${detail}`;
828
+ } else if (constraint) {
829
+ message = `Check constraint '${constraint}' violated`;
830
+ } else {
831
+ message = "Data validation failed";
832
+ }
833
+ return new ValidationError(
834
+ message,
835
+ void 0,
836
+ "Ensure data meets all constraints"
837
+ );
838
+ }
839
+ if (error.name === "SequelizeDatabaseError" && error.message?.includes("Unknown column")) {
840
+ const match = error.message.match(/Unknown column '(.+?)'/);
841
+ const field = match ? match[1] : "unknown field";
842
+ return new ValidationError(
843
+ `Invalid field: ${field}`,
844
+ [field],
845
+ "Check the field names in your request"
846
+ );
847
+ }
848
+ if (error.code === "22001" || error.original?.code === "22001") {
849
+ const detail = error.original?.detail;
850
+ const message = detail ? `Data too long for field. Check string lengths. ${detail}` : "Data too long for field";
851
+ return new ValidationError(
852
+ message,
853
+ void 0,
854
+ "Check string lengths and try again"
855
+ );
856
+ }
857
+ if (error.code === "22003" || error.original?.code === "22003") {
858
+ const detail = error.original?.detail;
859
+ const message = detail ? `Numeric value out of range. Check number values. ${detail}` : "Numeric value out of range";
860
+ return new ValidationError(
861
+ message,
862
+ void 0,
863
+ "Check number values and try again"
864
+ );
865
+ }
866
+ if (error.code === "42703" || error.original?.code === "42703") {
867
+ const column = error.original?.column;
868
+ const fields = column ? [column] : void 0;
869
+ const message = column && modelName ? `Column '${column}' does not exist in table '${modelName}'` : column ? `Column '${column}' does not exist` : "Referenced column does not exist";
870
+ return new ValidationError(
871
+ message,
872
+ fields,
873
+ "Check the field names in your request"
874
+ );
875
+ }
876
+ if (error.code === "42P01" || error.original?.code === "42P01") {
877
+ const message = modelName ? `Table '${modelName}' does not exist` : "Table does not exist";
878
+ return new ValidationError(
879
+ message,
880
+ void 0,
881
+ "Check the table name and database configuration"
882
+ );
883
+ }
884
+ if (error.message?.includes("notNull Violation") || error.message?.includes("cannot be null")) {
885
+ const fieldMatches = error.message.match(/([a-zA-Z]+\.[a-zA-Z]+) cannot be null/g);
886
+ if (fieldMatches) {
887
+ const fields = fieldMatches.map((match) => {
888
+ const parts = match.split(".");
889
+ return parts[1]?.split(" ")[0];
890
+ }).filter(Boolean);
891
+ if (fields.length > 0) {
892
+ return new ValidationError(
893
+ `Required field${fields.length > 1 ? "s" : ""} ${fields.join(", ")} cannot be null`,
894
+ fields,
895
+ "Provide all required fields"
896
+ );
897
+ }
898
+ }
899
+ return new ValidationError(
900
+ "Required fields are missing",
901
+ void 0,
902
+ "Provide all required fields"
903
+ );
904
+ }
905
+ if (error.name === "SequelizeConnectionError" || error.name === "SequelizeConnectionRefusedError") {
906
+ return new BusinessLogicError(
907
+ "Database connection failed",
908
+ "Check database connectivity and try again",
909
+ true
910
+ // retryable
911
+ );
912
+ }
913
+ if (error.name === "SequelizeTimeoutError") {
914
+ return new BusinessLogicError(
915
+ "Database operation timed out",
916
+ "Try again or simplify the operation",
917
+ true
918
+ // retryable
919
+ );
920
+ }
921
+ if (!error.original && modelName && itemData && error.message) {
922
+ const formattedData = JSON.stringify(itemData, null, 2);
923
+ return new Error(
924
+ `Database error in ${modelName}.create(): ${error.message}. Item data: ${formattedData}`
925
+ );
926
+ }
927
+ if (error.original && modelName && itemData) {
928
+ const formattedData = JSON.stringify(itemData, null, 2);
929
+ return new Error(
930
+ `Database error in ${modelName}.create(): ${error.message}. Item data: ${formattedData}`
931
+ );
932
+ }
933
+ return error;
934
+ }
935
+
936
+ // src/ops/all.ts
937
+ var logger7 = logger_default.get("sequelize", "ops", "all");
789
938
  var mergeIncludes = (existingIncludes, newIncludes) => {
790
939
  const mergedIncludes = [...existingIncludes];
791
940
  for (const newInclude of newIncludes) {
@@ -807,162 +956,105 @@ var mergeIncludes = (existingIncludes, newIncludes) => {
807
956
  };
808
957
  var getAllOperation = (models, definition, registry) => {
809
958
  const { coordinate, options: { references, aggregations } } = definition;
810
- const all = async (itemQuery, locations) => {
811
- logger8.debug(`ALL operation called on ${models[0].name} with ${locations?.length || 0} location filters: ${locations?.map((loc2) => `${loc2.kt}=${loc2.lk}`).join(", ") || "none"}`);
812
- validateLocations(locations, coordinate, "all");
813
- const loc = locations || [];
814
- const model = models[0];
815
- const options = buildQuery(itemQuery, model);
816
- if (loc.length > 0) {
817
- const { kta } = coordinate;
818
- const directLocations = [];
819
- const hierarchicalLocations = [];
820
- const additionalIncludes = [];
821
- for (const locKey of loc) {
822
- const relationshipInfo = buildRelationshipPath(model, locKey.kt, kta, true);
823
- if (!relationshipInfo.found) {
824
- const errorMessage = `Location key '${locKey.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
825
- logger8.error(errorMessage, { locations: loc, kta });
826
- throw new Error(errorMessage);
827
- }
828
- if (relationshipInfo.isDirect) {
829
- directLocations.push(locKey);
830
- } else {
831
- hierarchicalLocations.push(locKey);
832
- }
833
- }
834
- for (const locKey of directLocations) {
835
- if (locKey.lk === void 0 || locKey.lk == null || locKey.lk === "" || typeof locKey.lk === "object" && Object.keys(locKey.lk).length === 0) {
836
- logger8.error(`Location key '${locKey.kt}' has invalid lk value: ${stringifyJSON(locKey.lk)}`, { locKey, locations: loc });
837
- throw new Error(`Location key '${locKey.kt}' has invalid lk value: ${stringifyJSON(locKey.lk)}`);
838
- }
839
- const foreignKeyField = locKey.kt + "Id";
840
- if (options.where[foreignKeyField]) {
841
- logger8.debug(`[ALL] Field ${foreignKeyField} already constrained by itemQuery, skipping location constraint to avoid conflicts`);
842
- continue;
843
- }
844
- logger8.trace(`[ALL] Setting direct location where clause: ${foreignKeyField} = ${stringifyJSON(locKey.lk)} (type: ${typeof locKey.lk})`);
845
- options.where[foreignKeyField] = {
846
- [Op2.eq]: locKey.lk
847
- };
848
- }
849
- for (const locKey of hierarchicalLocations) {
850
- if (locKey.lk === void 0 || locKey.lk == null || locKey.lk === "" || typeof locKey.lk === "object" && Object.keys(locKey.lk).length === 0) {
851
- logger8.error(`Hierarchical location key '${locKey.kt}' has invalid lk value: ${stringifyJSON(locKey.lk)}`, { locKey, locations: loc });
852
- throw new Error(`Hierarchical location key '${locKey.kt}' has invalid lk value: ${stringifyJSON(locKey.lk)}`);
853
- }
854
- const relationshipInfo = buildRelationshipPath(model, locKey.kt, kta);
855
- if (relationshipInfo.found && relationshipInfo.path) {
856
- if (options.where[relationshipInfo.path]) {
857
- logger8.debug(`[ALL] Field ${relationshipInfo.path} already constrained by itemQuery, skipping hierarchical location constraint to avoid conflicts`);
858
- continue;
959
+ return createAllWrapper(
960
+ coordinate,
961
+ async (itemQuery, locations) => {
962
+ try {
963
+ const locs = locations ?? [];
964
+ logger7.debug(`ALL operation called on ${models[0].name} with ${locs.length} location filters: ${locs.map((loc2) => `${loc2.kt}=${loc2.lk}`).join(", ") || "none"}`);
965
+ const loc = locs;
966
+ const model = models[0];
967
+ const options = buildQuery(itemQuery ?? {}, model);
968
+ if (loc.length > 0) {
969
+ const { kta } = coordinate;
970
+ const directLocations = [];
971
+ const hierarchicalLocations = [];
972
+ const additionalIncludes = [];
973
+ for (const locKey of loc) {
974
+ const relationshipInfo = buildRelationshipPath(model, locKey.kt, kta, true);
975
+ if (!relationshipInfo.found) {
976
+ const errorMessage = `Location key '${locKey.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
977
+ logger7.error(errorMessage, { locations: loc, kta });
978
+ throw new Error(errorMessage);
979
+ }
980
+ if (relationshipInfo.isDirect) {
981
+ directLocations.push(locKey);
982
+ } else {
983
+ hierarchicalLocations.push(locKey);
984
+ }
985
+ }
986
+ for (const locKey of directLocations) {
987
+ if (locKey.lk === void 0 || locKey.lk == null || locKey.lk === "" || typeof locKey.lk === "object" && Object.keys(locKey.lk).length === 0) {
988
+ logger7.error(`Location key '${locKey.kt}' has invalid lk value: ${stringifyJSON(locKey.lk)}`, { locKey, locations: loc });
989
+ throw new Error(`Location key '${locKey.kt}' has invalid lk value: ${stringifyJSON(locKey.lk)}`);
990
+ }
991
+ const foreignKeyField = locKey.kt + "Id";
992
+ if (options.where[foreignKeyField]) {
993
+ logger7.debug(`[ALL] Field ${foreignKeyField} already constrained by itemQuery, skipping location constraint to avoid conflicts`);
994
+ continue;
995
+ }
996
+ logger7.trace(`[ALL] Setting direct location where clause: ${foreignKeyField} = ${stringifyJSON(locKey.lk)} (type: ${typeof locKey.lk})`);
997
+ options.where[foreignKeyField] = {
998
+ [Op2.eq]: locKey.lk
999
+ };
859
1000
  }
860
- logger8.trace(`[ALL] Setting hierarchical location where clause: ${relationshipInfo.path} = ${stringifyJSON(locKey.lk)} (type: ${typeof locKey.lk})`);
861
- options.where[relationshipInfo.path] = {
862
- [Op2.eq]: locKey.lk
863
- };
864
- if (relationshipInfo.includes) {
865
- additionalIncludes.push(...relationshipInfo.includes);
1001
+ for (const locKey of hierarchicalLocations) {
1002
+ if (locKey.lk === void 0 || locKey.lk == null || locKey.lk === "" || typeof locKey.lk === "object" && Object.keys(locKey.lk).length === 0) {
1003
+ logger7.error(`Hierarchical location key '${locKey.kt}' has invalid lk value: ${stringifyJSON(locKey.lk)}`, { locKey, locations: loc });
1004
+ throw new Error(`Hierarchical location key '${locKey.kt}' has invalid lk value: ${stringifyJSON(locKey.lk)}`);
1005
+ }
1006
+ const relationshipInfo = buildRelationshipPath(model, locKey.kt, kta);
1007
+ if (relationshipInfo.found && relationshipInfo.path) {
1008
+ if (options.where[relationshipInfo.path]) {
1009
+ logger7.debug(`[ALL] Field ${relationshipInfo.path} already constrained by itemQuery, skipping hierarchical location constraint to avoid conflicts`);
1010
+ continue;
1011
+ }
1012
+ logger7.trace(`[ALL] Setting hierarchical location where clause: ${relationshipInfo.path} = ${stringifyJSON(locKey.lk)} (type: ${typeof locKey.lk})`);
1013
+ options.where[relationshipInfo.path] = {
1014
+ [Op2.eq]: locKey.lk
1015
+ };
1016
+ if (relationshipInfo.includes) {
1017
+ additionalIncludes.push(...relationshipInfo.includes);
1018
+ }
1019
+ }
1020
+ }
1021
+ if (additionalIncludes.length > 0) {
1022
+ const existingIncludes = options.include || [];
1023
+ options.include = mergeIncludes(existingIncludes, additionalIncludes);
866
1024
  }
867
1025
  }
1026
+ logger7.default(`All query configured for ${model.name} with where fields: ${options.where ? Object.keys(options.where).join(", ") : "none"}, includes: ${options.include?.length || 0}`);
1027
+ try {
1028
+ logger7.trace(`[ALL] Executing ${model.name}.findAll() with options: ${JSON.stringify(options, null, 2)}`);
1029
+ } catch {
1030
+ logger7.trace(`[ALL] Executing ${model.name}.findAll() with options containing non-serializable operators (${Object.keys(options.where || {}).length} where conditions)`);
1031
+ }
1032
+ const matchingItems = await model.findAll(options);
1033
+ const currentContext = contextManager.getCurrentContext();
1034
+ const results = await Promise.all(matchingItems.map(async (row) => {
1035
+ const processedRow = await processRow(row, coordinate.kta, references || [], aggregations || [], registry, currentContext);
1036
+ return validateKeys(processedRow, coordinate.kta);
1037
+ }));
1038
+ logger7.debug(`[ALL] Returning ${results.length} ${model.name} records`);
1039
+ return results;
1040
+ } catch (error) {
1041
+ throw transformSequelizeError(error, coordinate.kta[0]);
868
1042
  }
869
- if (additionalIncludes.length > 0) {
870
- const existingIncludes = options.include || [];
871
- options.include = mergeIncludes(existingIncludes, additionalIncludes);
872
- }
873
- }
874
- logger8.default(`All query configured for ${model.name} with where fields: ${options.where ? Object.keys(options.where).join(", ") : "none"}, includes: ${options.include?.length || 0}`);
875
- try {
876
- logger8.trace(`[ALL] Executing ${model.name}.findAll() with options: ${JSON.stringify(options, null, 2)}`);
877
- } catch {
878
- logger8.trace(`[ALL] Executing ${model.name}.findAll() with options containing non-serializable operators (${Object.keys(options.where || {}).length} where conditions)`);
879
1043
  }
880
- const matchingItems = await model.findAll(options);
881
- const currentContext = contextManager.getCurrentContext();
882
- const results = await Promise.all(matchingItems.map(async (row) => {
883
- const processedRow = await processRow(row, coordinate.kta, references || [], aggregations || [], registry, currentContext);
884
- return validateKeys(processedRow, coordinate.kta);
885
- }));
886
- logger8.debug(`[ALL] Returning ${results.length} ${model.name} records`);
887
- return results;
888
- };
889
- return all;
1044
+ );
890
1045
  };
891
1046
 
892
1047
  // src/ops/create.ts
893
- import { isComKey as isComKey2, isPriKey as isPriKey2, validateKeys as validateKeys2 } from "@fjell/core";
894
- var logger9 = logger_default.get("sequelize", "ops", "create");
895
- function translateDatabaseError(error, itemData, modelName) {
896
- const originalMessage = error.message || "";
897
- const errorCode = error.original?.code;
898
- const constraint = error.original?.constraint;
899
- const detail = error.original?.detail;
900
- logger9.error("Database error during create operation", {
901
- errorCode,
902
- constraint,
903
- detail,
904
- originalMessage,
905
- modelName,
906
- itemData: JSON.stringify(itemData, null, 2)
907
- });
908
- switch (errorCode) {
909
- case "23505":
910
- if (constraint) {
911
- return new Error(`Duplicate value violates unique constraint '${constraint}'. ${detail || ""}`);
912
- }
913
- return new Error(`Duplicate value detected. This record already exists. ${detail || ""}`);
914
- case "23503":
915
- if (constraint) {
916
- return new Error(`Foreign key constraint '${constraint}' violated. Referenced record does not exist. ${detail || ""}`);
917
- }
918
- return new Error(`Referenced record does not exist. Check that all related records are valid. ${detail || ""}`);
919
- case "23502":
920
- const column = error.original?.column;
921
- if (column) {
922
- return new Error(`Required field '${column}' cannot be null`);
923
- }
924
- return new Error(`Required field is missing or null`);
925
- case "23514":
926
- if (constraint) {
927
- return new Error(`Check constraint '${constraint}' violated. ${detail || ""}`);
928
- }
929
- return new Error(`Data validation failed. Check constraint violated. ${detail || ""}`);
930
- case "22001":
931
- return new Error(`Data too long for field. Check string lengths. ${detail || ""}`);
932
- case "22003":
933
- return new Error(`Numeric value out of range. Check number values. ${detail || ""}`);
934
- case "42703":
935
- const undefinedColumn = error.original?.column;
936
- if (undefinedColumn) {
937
- return new Error(`Column '${undefinedColumn}' does not exist in table '${modelName}'`);
938
- }
939
- return new Error(`Referenced column does not exist`);
940
- case "42P01":
941
- return new Error(`Table '${modelName}' does not exist`);
942
- default:
943
- if (originalMessage.includes("notNull Violation")) {
944
- const fieldMatches = originalMessage.match(/([a-zA-Z]+\.[a-zA-Z]+) cannot be null/g);
945
- if (fieldMatches) {
946
- const fields = fieldMatches.map((match) => {
947
- const parts = match.split(".");
948
- return parts[1]?.split(" ")[0];
949
- }).filter(Boolean);
950
- if (fields.length > 0) {
951
- return new Error(`Required field${fields.length > 1 ? "s" : ""} ${fields.join(", ")} cannot be null`);
952
- }
953
- }
954
- return new Error("Required fields are missing");
955
- }
956
- return new Error(`Database error in ${modelName}.create(): ${originalMessage}. Item data: ${JSON.stringify(itemData, null, 2)}`);
957
- }
958
- }
1048
+ import { createCreateWrapper, isComKey as isComKey2, isPriKey as isPriKey2 } from "@fjell/core";
1049
+ import { validateKeys as validateKeys2 } from "@fjell/core/validation";
1050
+ var logger8 = logger_default.get("sequelize", "ops", "create");
959
1051
  async function validateHierarchicalChain(models, locKey, kta) {
1052
+ const locatorIndex = kta.indexOf(locKey.kt);
1053
+ if (locatorIndex === -1) {
1054
+ throw new Error(`Locator type '${locKey.kt}' not found in kta array`);
1055
+ }
1056
+ const locatorModel = models[locatorIndex] || models[0];
960
1057
  try {
961
- const locatorIndex = kta.indexOf(locKey.kt);
962
- if (locatorIndex === -1) {
963
- throw new Error(`Locator type '${locKey.kt}' not found in kta array`);
964
- }
965
- const locatorModel = models[locatorIndex] || models[0];
966
1058
  const chainResult = buildRelationshipChain(locatorModel, kta, locatorIndex, kta.length - 1);
967
1059
  if (!chainResult.success) {
968
1060
  const record2 = await locatorModel.findByPk(locKey.lk);
@@ -983,56 +1075,82 @@ async function validateHierarchicalChain(models, locKey, kta) {
983
1075
  }
984
1076
  } catch (error) {
985
1077
  if (error.original) {
986
- throw translateDatabaseError(error, { locKey, kta }, locKey.kt);
1078
+ throw transformSequelizeError(error, locKey.kt, { locKey, kta }, locatorModel.name);
987
1079
  }
988
1080
  throw error;
989
1081
  }
990
1082
  }
991
1083
  var getCreateOperation = (models, definition, registry) => {
992
- const create = async (item, options) => {
993
- const constraints = options?.key ? `key: pk=${options.key.pk}, loc=[${isComKey2(options.key) ? options.key.loc.map((l) => `${l.kt}=${l.lk}`).join(", ") : ""}]` : options?.locations ? `locations: ${options.locations.map((loc) => `${loc.kt}=${loc.lk}`).join(", ")}` : "no constraints";
994
- logger9.debug(`CREATE operation called on ${models[0].name} with ${constraints}`);
995
- logger9.default(`Create configured for ${models[0].name} with ${Object.keys(item).length} item fields`);
996
- const { coordinate, options: { references, aggregations } } = definition;
997
- const { kta } = coordinate;
998
- if (options?.locations) {
999
- validateLocations(options.locations, coordinate, "create");
1000
- }
1001
- if (options?.key && isComKey2(options.key)) {
1002
- validateLocations(options.key.loc, coordinate, "create");
1003
- }
1004
- const model = models[0];
1005
- const modelAttributes = model.getAttributes();
1006
- let itemData = { ...item };
1007
- itemData = extractEvents(itemData);
1008
- itemData = removeEvents(itemData);
1009
- const invalidAttributes = [];
1010
- for (const key of Object.keys(itemData)) {
1011
- if (!modelAttributes[key]) {
1012
- invalidAttributes.push(key);
1084
+ const { coordinate, options: { references, aggregations } } = definition;
1085
+ const { kta } = coordinate;
1086
+ return createCreateWrapper(
1087
+ coordinate,
1088
+ async (item, options) => {
1089
+ const constraints = options?.key ? `key: pk=${options.key.pk}, loc=[${isComKey2(options.key) ? options.key.loc.map((l) => `${l.kt}=${l.lk}`).join(", ") : ""}]` : options?.locations ? `locations: ${options.locations.map((loc) => `${loc.kt}=${loc.lk}`).join(", ")}` : "no constraints";
1090
+ logger8.debug(`CREATE operation called on ${models[0].name} with ${constraints}`);
1091
+ logger8.default(`Create configured for ${models[0].name} with ${Object.keys(item).length} item fields`);
1092
+ const model = models[0];
1093
+ const modelAttributes = model.getAttributes();
1094
+ let itemData = { ...item };
1095
+ itemData = extractEvents(itemData);
1096
+ itemData = removeEvents(itemData);
1097
+ const invalidAttributes = [];
1098
+ for (const key of Object.keys(itemData)) {
1099
+ if (!modelAttributes[key]) {
1100
+ invalidAttributes.push(key);
1101
+ }
1013
1102
  }
1014
- }
1015
- if (invalidAttributes.length > 0) {
1016
- const availableAttributes = Object.keys(modelAttributes).join(", ");
1017
- throw new Error(
1018
- `Invalid attributes for model '${model.name}': [${invalidAttributes.join(", ")}]. Available attributes: [${availableAttributes}]. Item data: ${JSON.stringify(itemData, null, 2)}`
1019
- );
1020
- }
1021
- if (options?.key) {
1022
- const key = options.key;
1023
- if (isPriKey2(key)) {
1024
- itemData.id = key.pk;
1025
- } else if (isComKey2(key)) {
1026
- itemData.id = key.pk;
1027
- const comKey = key;
1103
+ if (invalidAttributes.length > 0) {
1104
+ const availableAttributes = Object.keys(modelAttributes).join(", ");
1105
+ throw new Error(
1106
+ `Invalid attributes for model '${model.name}': [${invalidAttributes.join(", ")}]. Available attributes: [${availableAttributes}]. Item data: ${JSON.stringify(itemData, null, 2)}`
1107
+ );
1108
+ }
1109
+ if (options?.key) {
1110
+ const key = options.key;
1111
+ if (isPriKey2(key)) {
1112
+ itemData.id = key.pk;
1113
+ } else if (isComKey2(key)) {
1114
+ itemData.id = key.pk;
1115
+ const comKey = key;
1116
+ const directLocations = [];
1117
+ const hierarchicalLocations = [];
1118
+ for (const locKey of comKey.loc) {
1119
+ const relationshipInfo = buildRelationshipPath(model, locKey.kt, kta, true);
1120
+ if (!relationshipInfo.found) {
1121
+ const associations = model.associations ? Object.keys(model.associations) : [];
1122
+ 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)}`;
1123
+ logger8.error(errorMessage, { key: comKey, kta, associations });
1124
+ throw new Error(errorMessage);
1125
+ }
1126
+ if (relationshipInfo.isDirect) {
1127
+ directLocations.push(locKey);
1128
+ } else {
1129
+ hierarchicalLocations.push(locKey);
1130
+ }
1131
+ }
1132
+ for (const locKey of directLocations) {
1133
+ if (locKey.lk == null || locKey.lk === "") {
1134
+ logger8.error(`Composite key location '${locKey.kt}' has undefined/null lk value`, { locKey, key: comKey });
1135
+ throw new Error(`Composite key location '${locKey.kt}' has undefined/null lk value`);
1136
+ }
1137
+ const foreignKeyField = locKey.kt + "Id";
1138
+ itemData[foreignKeyField] = locKey.lk;
1139
+ }
1140
+ for (const locKey of hierarchicalLocations) {
1141
+ await validateHierarchicalChain(models, locKey, kta);
1142
+ }
1143
+ }
1144
+ }
1145
+ if (options?.locations) {
1028
1146
  const directLocations = [];
1029
1147
  const hierarchicalLocations = [];
1030
- for (const locKey of comKey.loc) {
1148
+ for (const locKey of options.locations) {
1031
1149
  const relationshipInfo = buildRelationshipPath(model, locKey.kt, kta, true);
1032
1150
  if (!relationshipInfo.found) {
1033
1151
  const associations = model.associations ? Object.keys(model.associations) : [];
1034
- 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)}`;
1035
- logger9.error(errorMessage, { key: comKey, kta, associations });
1152
+ 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)}`;
1153
+ logger8.error(errorMessage, { locations: options.locations, kta, associations });
1036
1154
  throw new Error(errorMessage);
1037
1155
  }
1038
1156
  if (relationshipInfo.isDirect) {
@@ -1043,8 +1161,8 @@ var getCreateOperation = (models, definition, registry) => {
1043
1161
  }
1044
1162
  for (const locKey of directLocations) {
1045
1163
  if (locKey.lk == null || locKey.lk === "") {
1046
- logger9.error(`Composite key location '${locKey.kt}' has undefined/null lk value`, { locKey, key: comKey });
1047
- throw new Error(`Composite key location '${locKey.kt}' has undefined/null lk value`);
1164
+ logger8.error(`Location option '${locKey.kt}' has undefined/null lk value`, { locKey, locations: options.locations });
1165
+ throw new Error(`Location option '${locKey.kt}' has undefined/null lk value`);
1048
1166
  }
1049
1167
  const foreignKeyField = locKey.kt + "Id";
1050
1168
  itemData[foreignKeyField] = locKey.lk;
@@ -1053,99 +1171,78 @@ var getCreateOperation = (models, definition, registry) => {
1053
1171
  await validateHierarchicalChain(models, locKey, kta);
1054
1172
  }
1055
1173
  }
1056
- }
1057
- if (options?.locations) {
1058
- const directLocations = [];
1059
- const hierarchicalLocations = [];
1060
- for (const locKey of options.locations) {
1061
- const relationshipInfo = buildRelationshipPath(model, locKey.kt, kta, true);
1062
- if (!relationshipInfo.found) {
1063
- const associations = model.associations ? Object.keys(model.associations) : [];
1064
- 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)}`;
1065
- logger9.error(errorMessage, { locations: options.locations, kta, associations });
1066
- throw new Error(errorMessage);
1067
- }
1068
- if (relationshipInfo.isDirect) {
1069
- directLocations.push(locKey);
1070
- } else {
1071
- hierarchicalLocations.push(locKey);
1072
- }
1073
- }
1074
- for (const locKey of directLocations) {
1075
- if (locKey.lk == null || locKey.lk === "") {
1076
- logger9.error(`Location option '${locKey.kt}' has undefined/null lk value`, { locKey, locations: options.locations });
1077
- throw new Error(`Location option '${locKey.kt}' has undefined/null lk value`);
1078
- }
1079
- const foreignKeyField = locKey.kt + "Id";
1080
- itemData[foreignKeyField] = locKey.lk;
1081
- }
1082
- for (const locKey of hierarchicalLocations) {
1083
- await validateHierarchicalChain(models, locKey, kta);
1174
+ try {
1175
+ logger8.trace(`[CREATE] Executing ${model.name}.create() with data: ${stringifyJSON(itemData)}`);
1176
+ const createdRecord = await model.create(itemData);
1177
+ const processedRecord = await processRow(createdRecord, kta, references || [], aggregations || [], registry);
1178
+ const result = validateKeys2(processedRecord, kta);
1179
+ logger8.debug(`[CREATE] Created ${model.name} with key: ${result.key ? JSON.stringify(result.key) : `id=${createdRecord.id}`}`);
1180
+ return result;
1181
+ } catch (error) {
1182
+ throw transformSequelizeError(error, kta[0], options?.key, model.name, itemData);
1084
1183
  }
1085
1184
  }
1086
- try {
1087
- logger9.trace(`[CREATE] Executing ${model.name}.create() with data: ${stringifyJSON(itemData)}`);
1088
- const createdRecord = await model.create(itemData);
1089
- const processedRecord = await processRow(createdRecord, kta, references || [], aggregations || [], registry);
1090
- const result = validateKeys2(processedRecord, kta);
1091
- logger9.debug(`[CREATE] Created ${model.name} with key: ${result.key ? JSON.stringify(result.key) : `id=${createdRecord.id}`}`);
1092
- return result;
1093
- } catch (error) {
1094
- throw translateDatabaseError(error, itemData, model.name);
1095
- }
1096
- };
1097
- return create;
1185
+ );
1098
1186
  };
1099
1187
 
1100
1188
  // src/ops/find.ts
1101
- import { validateKeys as validateKeys3 } from "@fjell/core";
1102
- var logger10 = logger_default.get("sequelize", "ops", "find");
1189
+ import { createFindWrapper } from "@fjell/core";
1190
+ import { validateKeys as validateKeys3 } from "@fjell/core/validation";
1191
+ var logger9 = logger_default.get("sequelize", "ops", "find");
1103
1192
  var getFindOperation = (models, definition, registry) => {
1104
1193
  const { options: { finders, references, aggregations } } = definition;
1105
- const find = async (finder, finderParams, locations) => {
1106
- const locationFilters = locations?.map((loc) => `${loc.kt}=${loc.lk}`).join(", ") || "none";
1107
- logger10.debug(
1108
- `FIND operation called on ${models[0].name} with finder '${finder}' and ${locations?.length || 0} location filters: ${locationFilters}`
1109
- );
1110
- logger10.default(`Find configured for ${models[0].name} using finder '${finder}' with ${Object.keys(finderParams).length} params`);
1111
- validateLocations(locations, definition.coordinate, "find");
1112
- if (finders && finders[finder]) {
1113
- const finderMethod = finders[finder];
1114
- if (finderMethod) {
1115
- logger10.trace(`[FIND] Executing finder '${finder}' on ${models[0].name} with params: ${stringifyJSON(finderParams)}, locations: ${stringifyJSON(locations)}`);
1116
- const results = await finderMethod(finderParams, locations);
1117
- if (results && results.length > 0) {
1118
- const processedResults = await Promise.all(results.map(async (row) => {
1119
- const processedRow = await processRow(row, definition.coordinate.kta, references || [], aggregations || [], registry);
1120
- return validateKeys3(processedRow, definition.coordinate.kta);
1121
- }));
1122
- logger10.debug(`[FIND] Found ${processedResults.length} ${models[0].name} records using finder '${finder}'`);
1123
- return processedResults;
1194
+ return createFindWrapper(
1195
+ definition.coordinate,
1196
+ async (finder, finderParams, locations) => {
1197
+ try {
1198
+ const locs = locations ?? [];
1199
+ const params = finderParams ?? {};
1200
+ const locationFilters = locs.map((loc) => `${loc.kt}=${loc.lk}`).join(", ") || "none";
1201
+ logger9.debug(
1202
+ `FIND operation called on ${models[0].name} with finder '${finder}' and ${locs.length} location filters: ${locationFilters}`
1203
+ );
1204
+ logger9.default(`Find configured for ${models[0].name} using finder '${finder}' with ${Object.keys(params).length} params`);
1205
+ if (finders && finders[finder]) {
1206
+ const finderMethod = finders[finder];
1207
+ if (finderMethod) {
1208
+ logger9.trace(`[FIND] Executing finder '${finder}' on ${models[0].name} with params: ${stringifyJSON(params)}, locations: ${stringifyJSON(locs)}`);
1209
+ const results = await finderMethod(params, locs);
1210
+ if (results && results.length > 0) {
1211
+ const processedResults = await Promise.all(results.map(async (row) => {
1212
+ const processedRow = await processRow(row, definition.coordinate.kta, references || [], aggregations || [], registry);
1213
+ return validateKeys3(processedRow, definition.coordinate.kta);
1214
+ }));
1215
+ logger9.debug(`[FIND] Found ${processedResults.length} ${models[0].name} records using finder '${finder}'`);
1216
+ return processedResults;
1217
+ } else {
1218
+ logger9.debug(`[FIND] Found 0 ${models[0].name} records using finder '${finder}'`);
1219
+ return [];
1220
+ }
1221
+ } else {
1222
+ logger9.error(`Finder %s not found`, finder);
1223
+ throw new Error(`Finder ${finder} not found`);
1224
+ }
1124
1225
  } else {
1125
- logger10.debug(`[FIND] Found 0 ${models[0].name} records using finder '${finder}'`);
1126
- return [];
1226
+ logger9.error(`No finders have been defined for this lib`);
1227
+ throw new Error(`No finders found`);
1127
1228
  }
1128
- } else {
1129
- logger10.error(`Finder %s not found`, finder);
1130
- throw new Error(`Finder ${finder} not found`);
1229
+ } catch (error) {
1230
+ throw transformSequelizeError(error, definition.coordinate.kta[0]);
1131
1231
  }
1132
- } else {
1133
- logger10.error(`No finders have been defined for this lib`);
1134
- throw new Error(`No finders found`);
1135
1232
  }
1136
- };
1137
- return find;
1233
+ );
1138
1234
  };
1139
1235
 
1140
1236
  // src/ops/get.ts
1141
1237
  import {
1238
+ createGetWrapper,
1142
1239
  isComKey as isComKey3,
1143
1240
  isPriKey as isPriKey3,
1144
1241
  isValidItemKey,
1145
1242
  validateKeys as validateKeys4
1146
1243
  } from "@fjell/core";
1147
- import { NotFoundError } from "@fjell/lib";
1148
- var logger11 = logger_default.get("sequelize", "ops", "get");
1244
+ import { NotFoundError } from "@fjell/core";
1245
+ var logger10 = logger_default.get("sequelize", "ops", "get");
1149
1246
  var processCompositeKey = (comKey, model, kta) => {
1150
1247
  const where = { id: comKey.pk };
1151
1248
  const includes = [];
@@ -1153,7 +1250,7 @@ var processCompositeKey = (comKey, model, kta) => {
1153
1250
  const relationshipInfo = buildRelationshipPath(model, locator.kt, kta);
1154
1251
  if (!relationshipInfo.found) {
1155
1252
  const errorMessage = `Composite key locator '${locator.kt}' cannot be resolved on model '${model.name}' or through its relationships. Key type array: [${kta.join(", ")}], Composite key: ${stringifyJSON(comKey)}, Available associations: [${Object.keys(model.associations || {}).join(", ")}]`;
1156
- logger11.error(errorMessage, { key: comKey, kta });
1253
+ logger10.error(errorMessage, { key: comKey, kta });
1157
1254
  throw new Error(errorMessage);
1158
1255
  }
1159
1256
  if (relationshipInfo.path) {
@@ -1175,70 +1272,82 @@ var processCompositeKey = (comKey, model, kta) => {
1175
1272
  var getGetOperation = (models, definition, registry) => {
1176
1273
  const { coordinate, options: { references, aggregations } } = definition;
1177
1274
  const { kta } = coordinate;
1178
- const get = async (key) => {
1179
- if (!isValidItemKey(key)) {
1180
- logger11.error("Key for Get is not a valid ItemKey: %j", key);
1181
- throw new Error("Key for Get is not a valid ItemKey");
1182
- }
1183
- const keyDescription = isPriKey3(key) ? `primary key: pk=${key.pk}` : `composite key: pk=${key.pk}, loc=[${key.loc.map((l) => `${l.kt}=${l.lk}`).join(", ")}]`;
1184
- logger11.debug(`GET operation called on ${models[0].name} with ${keyDescription}`);
1185
- logger11.default(`Get configured for ${models[0].name} with ${isPriKey3(key) ? "primary" : "composite"} key`);
1186
- const itemKey = key;
1187
- const model = models[0];
1188
- let item;
1189
- if (isPriKey3(itemKey)) {
1190
- logger11.trace(`[GET] Executing ${model.name}.findByPk() with pk: ${itemKey.pk}`);
1191
- item = await model.findByPk(itemKey.pk);
1192
- } else if (isComKey3(itemKey)) {
1193
- const comKey = itemKey;
1194
- if (comKey.loc.length === 0) {
1195
- logger11.debug(`[GET] Empty loc array detected - finding by primary key across all locations: ${comKey.pk}`);
1196
- logger11.trace(`[GET] Executing ${model.name}.findByPk() with pk: ${comKey.pk}`);
1197
- item = await model.findByPk(comKey.pk);
1198
- } else {
1199
- const queryOptions = processCompositeKey(comKey, model, kta);
1200
- logger11.default("Composite key query", { queryOptions });
1201
- logger11.trace(`[GET] Executing ${model.name}.findOne() with options: ${stringifyJSON(queryOptions)}`);
1202
- item = await model.findOne(queryOptions);
1275
+ return createGetWrapper(
1276
+ coordinate,
1277
+ async (key) => {
1278
+ try {
1279
+ if (!isValidItemKey(key)) {
1280
+ logger10.error("Key for Get is not a valid ItemKey: %j", key);
1281
+ throw new Error("Key for Get is not a valid ItemKey");
1282
+ }
1283
+ const keyDescription = isPriKey3(key) ? `primary key: pk=${key.pk}` : `composite key: pk=${key.pk}, loc=[${key.loc.map((l) => `${l.kt}=${l.lk}`).join(", ")}]`;
1284
+ logger10.debug(`GET operation called on ${models[0].name} with ${keyDescription}`);
1285
+ logger10.default(`Get configured for ${models[0].name} with ${isPriKey3(key) ? "primary" : "composite"} key`);
1286
+ const itemKey = key;
1287
+ const model = models[0];
1288
+ let item;
1289
+ if (isPriKey3(itemKey)) {
1290
+ logger10.trace(`[GET] Executing ${model.name}.findByPk() with pk: ${itemKey.pk}`);
1291
+ item = await model.findByPk(itemKey.pk);
1292
+ } else if (isComKey3(itemKey)) {
1293
+ const comKey = itemKey;
1294
+ if (comKey.loc.length === 0) {
1295
+ logger10.debug(`[GET] Empty loc array detected - finding by primary key across all locations: ${comKey.pk}`);
1296
+ logger10.trace(`[GET] Executing ${model.name}.findByPk() with pk: ${comKey.pk}`);
1297
+ item = await model.findByPk(comKey.pk);
1298
+ } else {
1299
+ const queryOptions = processCompositeKey(comKey, model, kta);
1300
+ logger10.default("Composite key query", { queryOptions });
1301
+ logger10.trace(`[GET] Executing ${model.name}.findOne() with options: ${stringifyJSON(queryOptions)}`);
1302
+ item = await model.findOne(queryOptions);
1303
+ }
1304
+ }
1305
+ if (!item) {
1306
+ throw new NotFoundError(
1307
+ `${kta[0]} not found`,
1308
+ kta[0],
1309
+ key
1310
+ );
1311
+ }
1312
+ const currentContext = contextManager.getCurrentContext();
1313
+ const result = validateKeys4(await processRow(item, kta, references || [], aggregations || [], registry, currentContext), kta);
1314
+ logger10.debug(`[GET] Retrieved ${model.name} with key: ${result.key ? JSON.stringify(result.key) : `id=${item.id}`}`);
1315
+ return result;
1316
+ } catch (error) {
1317
+ if (error instanceof NotFoundError) throw error;
1318
+ throw transformSequelizeError(error, kta[0], key);
1203
1319
  }
1204
1320
  }
1205
- if (!item) {
1206
- throw new NotFoundError("get", coordinate, key);
1207
- } else {
1208
- const currentContext = contextManager.getCurrentContext();
1209
- const result = validateKeys4(await processRow(item, kta, references || [], aggregations || [], registry, currentContext), kta);
1210
- logger11.debug(`[GET] Retrieved ${model.name} with key: ${result.key ? JSON.stringify(result.key) : `id=${item.id}`}`);
1211
- return result;
1212
- }
1213
- };
1214
- return get;
1321
+ );
1215
1322
  };
1216
1323
 
1217
1324
  // src/ops/one.ts
1218
- var logger12 = logger_default.get("sequelize", "ops", "one");
1325
+ import { createOneWrapper } from "@fjell/core";
1326
+ var logger11 = logger_default.get("sequelize", "ops", "one");
1219
1327
  var getOneOperation = (models, definition, registry) => {
1220
- const one = async (itemQuery, locations = []) => {
1221
- logger12.debug(`ONE operation called on ${models[0].name} with ${locations.length} location filters: ${locations.map((loc) => `${loc.kt}=${loc.lk}`).join(", ") || "none"}`);
1222
- logger12.default(`One configured for ${models[0].name} delegating to all operation`);
1223
- validateLocations(locations, definition.coordinate, "one");
1224
- const items = await getAllOperation(models, definition, registry)(itemQuery, locations);
1225
- if (items.length > 0) {
1226
- const result = items[0];
1227
- logger12.debug(`[ONE] Found ${models[0].name} record with key: ${result.key ? JSON.stringify(result.key) : "unknown"}`);
1228
- return result;
1229
- } else {
1230
- logger12.debug(`[ONE] No ${models[0].name} record found`);
1231
- return null;
1328
+ return createOneWrapper(
1329
+ definition.coordinate,
1330
+ async (itemQuery, locations) => {
1331
+ const locs = locations ?? [];
1332
+ logger11.debug(`ONE operation called on ${models[0].name} with ${locs.length} location filters: ${locs.map((loc) => `${loc.kt}=${loc.lk}`).join(", ") || "none"}`);
1333
+ logger11.default(`One configured for ${models[0].name} delegating to all operation`);
1334
+ const items = await getAllOperation(models, definition, registry)(itemQuery ?? {}, locs);
1335
+ if (items.length > 0) {
1336
+ const result = items[0];
1337
+ logger11.debug(`[ONE] Found ${models[0].name} record with key: ${result.key ? JSON.stringify(result.key) : "unknown"}`);
1338
+ return result;
1339
+ } else {
1340
+ logger11.debug(`[ONE] No ${models[0].name} record found`);
1341
+ return null;
1342
+ }
1232
1343
  }
1233
- };
1234
- return one;
1344
+ );
1235
1345
  };
1236
1346
 
1237
1347
  // src/ops/remove.ts
1238
- import { isValidItemKey as isValidItemKey2 } from "@fjell/core";
1239
- import { abbrevIK, isComKey as isComKey4, isPriKey as isPriKey4 } from "@fjell/core";
1240
- import { NotFoundError as NotFoundError2 } from "@fjell/lib";
1241
- var logger13 = logger_default.get("sequelize", "ops", "remove");
1348
+ import { abbrevIK, isComKey as isComKey4, isPriKey as isPriKey4, isValidItemKey as isValidItemKey2, createRemoveWrapper } from "@fjell/core";
1349
+ import { NotFoundError as NotFoundError2 } from "@fjell/core";
1350
+ var logger12 = logger_default.get("sequelize", "ops", "remove");
1242
1351
  var processCompositeKey2 = (comKey, model, kta) => {
1243
1352
  const where = { id: comKey.pk };
1244
1353
  const includes = [];
@@ -1246,7 +1355,7 @@ var processCompositeKey2 = (comKey, model, kta) => {
1246
1355
  const relationshipInfo = buildRelationshipPath(model, locator.kt, kta);
1247
1356
  if (!relationshipInfo.found) {
1248
1357
  const errorMessage = `Composite key locator '${locator.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
1249
- logger13.error(errorMessage, { key: comKey, kta });
1358
+ logger12.error(errorMessage, { key: comKey, kta });
1250
1359
  throw new Error(errorMessage);
1251
1360
  }
1252
1361
  if (relationshipInfo.path) {
@@ -1268,66 +1377,77 @@ var processCompositeKey2 = (comKey, model, kta) => {
1268
1377
  var getRemoveOperation = (models, definition, _registry) => {
1269
1378
  const { coordinate, options } = definition;
1270
1379
  const { kta } = coordinate;
1271
- const remove = async (key) => {
1272
- if (!isValidItemKey2(key)) {
1273
- logger13.error("Key for Remove is not a valid ItemKey: %j", key);
1274
- throw new Error("Key for Remove is not a valid ItemKey");
1275
- }
1276
- const keyDescription = isPriKey4(key) ? `primary key: pk=${key.pk}` : `composite key: pk=${key.pk}, loc=[${key.loc.map((l) => `${l.kt}=${l.lk}`).join(", ")}]`;
1277
- logger13.debug(`REMOVE operation called on ${models[0].name} with ${keyDescription}`);
1278
- logger13.default(`Remove configured for ${models[0].name} with ${isPriKey4(key) ? "primary" : "composite"} key`);
1279
- const model = models[0];
1280
- let item;
1281
- let returnItem;
1282
- logger13.debug("remove: %s", abbrevIK(key));
1283
- if (isPriKey4(key)) {
1284
- logger13.debug(`[REMOVE] Executing ${model.name}.findByPk() with pk: ${key.pk}`);
1285
- item = await model.findByPk(key.pk);
1286
- } else if (isComKey4(key)) {
1287
- const comKey = key;
1288
- const queryOptions = processCompositeKey2(comKey, model, kta);
1289
- logger13.default(`Remove composite key query for ${model.name} with where fields: ${queryOptions.where ? Object.keys(queryOptions.where).join(", ") : "none"}`);
1290
- logger13.debug(`[REMOVE] Executing ${model.name}.findOne() with options: ${stringifyJSON(queryOptions)}`);
1291
- item = await model.findOne(queryOptions);
1292
- }
1293
- if (!item) {
1294
- throw new NotFoundError2("remove", coordinate, key);
1295
- }
1296
- const isDeletedAttribute = model.getAttributes().isDeleted;
1297
- const deletedAtAttribute = model.getAttributes().deletedAt;
1298
- if (isDeletedAttribute || deletedAtAttribute) {
1299
- if (model.getAttributes().isDeleted) {
1300
- item.isDeleted = true;
1301
- }
1302
- if (model.getAttributes().deletedAt) {
1303
- item.deletedAt = /* @__PURE__ */ new Date();
1380
+ return createRemoveWrapper(
1381
+ coordinate,
1382
+ async (key) => {
1383
+ try {
1384
+ if (!isValidItemKey2(key)) {
1385
+ logger12.error("Key for Remove is not a valid ItemKey: %j", key);
1386
+ throw new Error("Key for Remove is not a valid ItemKey");
1387
+ }
1388
+ const keyDescription = isPriKey4(key) ? `primary key: pk=${key.pk}` : `composite key: pk=${key.pk}, loc=[${key.loc.map((l) => `${l.kt}=${l.lk}`).join(", ")}]`;
1389
+ logger12.debug(`REMOVE operation called on ${models[0].name} with ${keyDescription}`);
1390
+ logger12.default(`Remove configured for ${models[0].name} with ${isPriKey4(key) ? "primary" : "composite"} key`);
1391
+ const model = models[0];
1392
+ let item;
1393
+ let returnItem;
1394
+ logger12.debug("remove: %s", abbrevIK(key));
1395
+ if (isPriKey4(key)) {
1396
+ logger12.debug(`[REMOVE] Executing ${model.name}.findByPk() with pk: ${key.pk}`);
1397
+ item = await model.findByPk(key.pk);
1398
+ } else if (isComKey4(key)) {
1399
+ const comKey = key;
1400
+ const queryOptions = processCompositeKey2(comKey, model, kta);
1401
+ logger12.default(`Remove composite key query for ${model.name} with where fields: ${queryOptions.where ? Object.keys(queryOptions.where).join(", ") : "none"}`);
1402
+ logger12.debug(`[REMOVE] Executing ${model.name}.findOne() with options: ${stringifyJSON(queryOptions)}`);
1403
+ item = await model.findOne(queryOptions);
1404
+ }
1405
+ if (!item) {
1406
+ throw new NotFoundError2(
1407
+ `Cannot remove: ${kta[0]} not found`,
1408
+ kta[0],
1409
+ key
1410
+ );
1411
+ }
1412
+ const isDeletedAttribute = model.getAttributes().isDeleted;
1413
+ const deletedAtAttribute = model.getAttributes().deletedAt;
1414
+ if (isDeletedAttribute || deletedAtAttribute) {
1415
+ if (model.getAttributes().isDeleted) {
1416
+ item.isDeleted = true;
1417
+ }
1418
+ if (model.getAttributes().deletedAt) {
1419
+ item.deletedAt = /* @__PURE__ */ new Date();
1420
+ }
1421
+ logger12.debug(`[REMOVE] Executing ${model.name}.save() for soft delete`);
1422
+ await item?.save();
1423
+ returnItem = item?.get({ plain: true });
1424
+ returnItem = addKey(item, returnItem, kta);
1425
+ returnItem = populateEvents(returnItem);
1426
+ } else if (options.deleteOnRemove) {
1427
+ logger12.debug(`[REMOVE] Executing ${model.name}.destroy() for hard delete`);
1428
+ await item?.destroy();
1429
+ returnItem = item?.get({ plain: true });
1430
+ returnItem = addKey(item, returnItem, kta);
1431
+ returnItem = populateEvents(returnItem);
1432
+ } else {
1433
+ throw new Error("No deletedAt or isDeleted attribute found in model, and deleteOnRemove is not set");
1434
+ }
1435
+ logger12.debug(`[REMOVE] Removed ${model.name} with key: ${returnItem.key ? JSON.stringify(returnItem.key) : `id=${item.id}`}`);
1436
+ return returnItem;
1437
+ } catch (error) {
1438
+ if (error instanceof NotFoundError2) throw error;
1439
+ throw transformSequelizeError(error, kta[0], key);
1304
1440
  }
1305
- logger13.debug(`[REMOVE] Executing ${model.name}.save() for soft delete`);
1306
- await item?.save();
1307
- returnItem = item?.get({ plain: true });
1308
- returnItem = addKey(item, returnItem, kta);
1309
- returnItem = populateEvents(returnItem);
1310
- } else if (options.deleteOnRemove) {
1311
- logger13.debug(`[REMOVE] Executing ${model.name}.destroy() for hard delete`);
1312
- await item?.destroy();
1313
- returnItem = item?.get({ plain: true });
1314
- returnItem = addKey(item, returnItem, kta);
1315
- returnItem = populateEvents(returnItem);
1316
- } else {
1317
- throw new Error("No deletedAt or isDeleted attribute found in model, and deleteOnRemove is not set");
1318
1441
  }
1319
- logger13.debug(`[REMOVE] Removed ${model.name} with key: ${returnItem.key ? JSON.stringify(returnItem.key) : `id=${item.id}`}`);
1320
- return returnItem;
1321
- };
1322
- return remove;
1442
+ );
1323
1443
  };
1324
1444
 
1325
1445
  // src/ops/update.ts
1326
- import { abbrevIK as abbrevIK2, isComKey as isComKey5, validateKeys as validateKeys5 } from "@fjell/core";
1327
- import { isPriKey as isPriKey5 } from "@fjell/core";
1328
- import { NotFoundError as NotFoundError3 } from "@fjell/lib";
1446
+ import { abbrevIK as abbrevIK2, createUpdateWrapper, isComKey as isComKey5, isPriKey as isPriKey5 } from "@fjell/core";
1447
+ import { validateKeys as validateKeys5 } from "@fjell/core/validation";
1448
+ import { NotFoundError as NotFoundError3 } from "@fjell/core";
1329
1449
  import { Op as Op3 } from "sequelize";
1330
- var logger14 = logger_default.get("sequelize", "ops", "update");
1450
+ var logger13 = logger_default.get("sequelize", "ops", "update");
1331
1451
  var mergeIncludes2 = (existingIncludes, newIncludes) => {
1332
1452
  const mergedIncludes = [...existingIncludes];
1333
1453
  for (const newInclude of newIncludes) {
@@ -1349,130 +1469,136 @@ var mergeIncludes2 = (existingIncludes, newIncludes) => {
1349
1469
  };
1350
1470
  var getUpdateOperation = (models, definition, registry) => {
1351
1471
  const { options: { references, aggregations } } = definition;
1352
- const update = async (key, item) => {
1353
- const keyDescription = isPriKey5(key) ? `primary key: pk=${key.pk}` : `composite key: pk=${key.pk}, loc=[${key.loc.map((l) => `${l.kt}=${l.lk}`).join(", ")}]`;
1354
- logger14.debug(`UPDATE operation called on ${models[0].name} with ${keyDescription}`);
1355
- const { coordinate } = definition;
1356
- const { kta } = coordinate;
1357
- logger14.debug("update: %s, %j", abbrevIK2(key), item);
1358
- const model = models[0];
1359
- let response;
1360
- if (isPriKey5(key)) {
1361
- const priKey = key;
1362
- logger14.trace(`[UPDATE] Executing ${model.name}.findByPk() with pk: ${priKey.pk}`);
1363
- response = await model.findByPk(priKey.pk);
1364
- } else if (isComKey5(key)) {
1365
- const comKey = key;
1366
- const where = { id: comKey.pk };
1367
- const additionalIncludes = [];
1368
- for (const locator of comKey.loc) {
1369
- const relationshipInfo = buildRelationshipPath(model, locator.kt, kta, true);
1370
- if (!relationshipInfo.found) {
1371
- const errorMessage = `Composite key locator '${locator.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
1372
- logger14.error(errorMessage, { key: comKey, kta });
1373
- throw new Error(errorMessage);
1374
- }
1375
- if (relationshipInfo.isDirect) {
1376
- const fieldName = `${locator.kt}Id`;
1377
- where[fieldName] = locator.lk;
1378
- } else if (relationshipInfo.path) {
1379
- where[relationshipInfo.path] = {
1380
- [Op3.eq]: locator.lk
1381
- };
1382
- if (relationshipInfo.includes) {
1383
- additionalIncludes.push(...relationshipInfo.includes);
1472
+ return createUpdateWrapper(
1473
+ definition.coordinate,
1474
+ async (key, item) => {
1475
+ try {
1476
+ const keyDescription = isPriKey5(key) ? `primary key: pk=${key.pk}` : `composite key: pk=${key.pk}, loc=[${key.loc.map((l) => `${l.kt}=${l.lk}`).join(", ")}]`;
1477
+ logger13.debug(`UPDATE operation called on ${models[0].name} with ${keyDescription}`);
1478
+ const { coordinate } = definition;
1479
+ const { kta } = coordinate;
1480
+ logger13.debug("update: %s, %j", abbrevIK2(key), item);
1481
+ const model = models[0];
1482
+ let response;
1483
+ if (isPriKey5(key)) {
1484
+ const priKey = key;
1485
+ logger13.trace(`[UPDATE] Executing ${model.name}.findByPk() with pk: ${priKey.pk}`);
1486
+ response = await model.findByPk(priKey.pk);
1487
+ } else if (isComKey5(key)) {
1488
+ const comKey = key;
1489
+ const where = { id: comKey.pk };
1490
+ const additionalIncludes = [];
1491
+ for (const locator of comKey.loc) {
1492
+ const relationshipInfo = buildRelationshipPath(model, locator.kt, kta, true);
1493
+ if (!relationshipInfo.found) {
1494
+ const errorMessage = `Composite key locator '${locator.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
1495
+ logger13.error(errorMessage, { key: comKey, kta });
1496
+ throw new Error(errorMessage);
1497
+ }
1498
+ if (relationshipInfo.isDirect) {
1499
+ const fieldName = `${locator.kt}Id`;
1500
+ where[fieldName] = locator.lk;
1501
+ } else if (relationshipInfo.path) {
1502
+ where[relationshipInfo.path] = {
1503
+ [Op3.eq]: locator.lk
1504
+ };
1505
+ if (relationshipInfo.includes) {
1506
+ additionalIncludes.push(...relationshipInfo.includes);
1507
+ }
1508
+ }
1509
+ }
1510
+ const queryOptions = { where };
1511
+ if (additionalIncludes.length > 0) {
1512
+ queryOptions.include = mergeIncludes2([], additionalIncludes);
1384
1513
  }
1514
+ logger13.default(`Update composite key query for ${model.name} with where fields: ${queryOptions.where ? Object.keys(queryOptions.where).join(", ") : "none"}`);
1515
+ logger13.trace(`[UPDATE] Executing ${model.name}.findOne() with options: ${stringifyJSON(queryOptions)}`);
1516
+ response = await model.findOne(queryOptions);
1385
1517
  }
1518
+ if (!response) {
1519
+ throw new NotFoundError3(
1520
+ `Cannot update: ${kta[0]} not found`,
1521
+ kta[0],
1522
+ key
1523
+ );
1524
+ }
1525
+ let updateProps = removeKey(item);
1526
+ updateProps = extractEvents(updateProps);
1527
+ updateProps = removeEvents(updateProps);
1528
+ logger13.default(`Update found ${model.name} record to modify`);
1529
+ logger13.default(`Update properties configured: ${Object.keys(updateProps).join(", ")}`);
1530
+ logger13.trace(`[UPDATE] Executing ${model.name}.update() with properties: ${stringifyJSON(updateProps)}`);
1531
+ response = await response.update(updateProps);
1532
+ const processedItem = await processRow(response, kta, references || [], aggregations || [], registry);
1533
+ const returnItem = validateKeys5(processedItem, kta);
1534
+ logger13.debug(`[UPDATE] Updated ${model.name} with key: ${returnItem.key ? JSON.stringify(returnItem.key) : `id=${response.id}`}`);
1535
+ return returnItem;
1536
+ } catch (error) {
1537
+ if (error instanceof NotFoundError3) throw error;
1538
+ throw transformSequelizeError(error, definition.coordinate.kta[0], key);
1386
1539
  }
1387
- const queryOptions = { where };
1388
- if (additionalIncludes.length > 0) {
1389
- queryOptions.include = mergeIncludes2([], additionalIncludes);
1390
- }
1391
- logger14.default(`Update composite key query for ${model.name} with where fields: ${queryOptions.where ? Object.keys(queryOptions.where).join(", ") : "none"}`);
1392
- logger14.trace(`[UPDATE] Executing ${model.name}.findOne() with options: ${stringifyJSON(queryOptions)}`);
1393
- response = await model.findOne(queryOptions);
1394
1540
  }
1395
- if (response) {
1396
- let updateProps = removeKey(item);
1397
- updateProps = extractEvents(updateProps);
1398
- updateProps = removeEvents(updateProps);
1399
- logger14.default(`Update found ${model.name} record to modify`);
1400
- logger14.default(`Update properties configured: ${Object.keys(updateProps).join(", ")}`);
1401
- logger14.trace(`[UPDATE] Executing ${model.name}.update() with properties: ${stringifyJSON(updateProps)}`);
1402
- response = await response.update(updateProps);
1403
- const processedItem = await processRow(response, kta, references || [], aggregations || [], registry);
1404
- const returnItem = validateKeys5(processedItem, kta);
1405
- logger14.debug(`[UPDATE] Updated ${model.name} with key: ${returnItem.key ? JSON.stringify(returnItem.key) : `id=${response.id}`}`);
1406
- return returnItem;
1407
- } else {
1408
- throw new NotFoundError3("update", coordinate, key);
1409
- }
1410
- };
1411
- return update;
1541
+ );
1412
1542
  };
1413
1543
 
1414
1544
  // src/ops/upsert.ts
1415
- import { isValidItemKey as isValidItemKey3 } from "@fjell/core";
1416
- var logger15 = logger_default.get("sequelize", "ops", "upsert");
1545
+ import { createUpsertWrapper, isValidItemKey as isValidItemKey3 } from "@fjell/core";
1546
+ var logger14 = logger_default.get("sequelize", "ops", "upsert");
1417
1547
  var getUpsertOperation = (models, definition, registry) => {
1418
1548
  const get = getGetOperation(models, definition, registry);
1419
1549
  const update = getUpdateOperation(models, definition, registry);
1420
1550
  const create = getCreateOperation(models, definition, registry);
1421
- const upsert = async (key, item) => {
1422
- if (!isValidItemKey3(key)) {
1423
- logger15.error("Key for Upsert is not a valid ItemKey: %j", key);
1424
- throw new Error(`Key for Upsert is not a valid ItemKey: ${stringifyJSON(key)}`);
1425
- }
1426
- logger15.debug(`[UPSERT] Attempting upsert with key: ${stringifyJSON(key)}`);
1427
- try {
1428
- const existingItem = await get(key);
1429
- if (existingItem) {
1430
- logger15.debug(`[UPSERT] Item exists, updating with key: ${stringifyJSON(key)}`);
1431
- return await update(key, item);
1551
+ return createUpsertWrapper(
1552
+ definition.coordinate,
1553
+ async (key, item) => {
1554
+ if (!isValidItemKey3(key)) {
1555
+ logger14.error("Key for Upsert is not a valid ItemKey: %j", key);
1556
+ throw new Error(`Key for Upsert is not a valid ItemKey: ${stringifyJSON(key)}`);
1432
1557
  }
1433
- } catch {
1434
- logger15.debug(`[UPSERT] Item not found, creating new item with key: ${stringifyJSON(key)}`);
1558
+ logger14.debug(`[UPSERT] Attempting upsert with key: ${stringifyJSON(key)}`);
1559
+ try {
1560
+ const existingItem = await get(key);
1561
+ if (existingItem) {
1562
+ logger14.debug(`[UPSERT] Item exists, updating with key: ${stringifyJSON(key)}`);
1563
+ return await update(key, item);
1564
+ }
1565
+ } catch {
1566
+ logger14.debug(`[UPSERT] Item not found, creating new item with key: ${stringifyJSON(key)}`);
1567
+ }
1568
+ return await create(item, { key });
1435
1569
  }
1436
- return await create(item, { key });
1437
- };
1438
- return upsert;
1570
+ );
1439
1571
  };
1440
1572
 
1441
1573
  // src/Operations.ts
1442
1574
  var createOperations = (models, coordinate, registry, options) => {
1443
- const operations = {};
1444
1575
  const definition = { coordinate, options };
1445
- operations.all = getAllOperation(models, definition, registry);
1446
- operations.one = getOneOperation(models, definition, registry);
1447
- operations.create = getCreateOperation(models, definition, registry);
1448
- operations.update = getUpdateOperation(models, definition, registry);
1449
- operations.get = getGetOperation(models, definition, registry);
1450
- operations.remove = getRemoveOperation(models, definition, registry);
1451
- operations.find = getFindOperation(models, definition, registry);
1452
- operations.upsert = getUpsertOperation(models, definition, registry);
1453
- operations.allFacet = async () => {
1454
- };
1455
- operations.allAction = async () => {
1456
- };
1457
- operations.action = async () => {
1576
+ const implOps = {
1577
+ all: getAllOperation(models, definition, registry),
1578
+ one: getOneOperation(models, definition, registry),
1579
+ create: getCreateOperation(models, definition, registry),
1580
+ update: getUpdateOperation(models, definition, registry),
1581
+ get: getGetOperation(models, definition, registry),
1582
+ remove: getRemoveOperation(models, definition, registry),
1583
+ find: getFindOperation(models, definition, registry),
1584
+ // findOne depends on find, so set it after
1585
+ findOne: null,
1586
+ upsert: getUpsertOperation(models, definition, registry)
1458
1587
  };
1459
- operations.facet = async () => {
1588
+ implOps.findOne = async (finder, params, locations) => {
1589
+ const results = await implOps.find(finder, params || {}, locations);
1590
+ return results.length > 0 ? results[0] : null;
1460
1591
  };
1461
- operations.finders = { ...options.finders || {} };
1462
- operations.actions = { ...options.actions || {} };
1463
- operations.facets = { ...options.facets || {} };
1464
- operations.allActions = { ...options.allActions || {} };
1465
- operations.allFacets = { ...options.allFacets || {} };
1466
- return operations;
1592
+ return Library2.wrapImplementationOperations(implOps, options);
1467
1593
  };
1468
1594
 
1469
1595
  // src/SequelizeLibrary.ts
1470
- var logger16 = logger_default.get("SequelizeLibrary");
1596
+ var logger15 = logger_default.get("SequelizeLibrary");
1471
1597
  var createSequelizeLibrary = (registry, coordinate, models, options) => {
1472
- logger16.debug("createSequelizeLibrary", { coordinate, models, registry, options });
1598
+ logger15.debug("createSequelizeLibrary", { coordinate, models, registry, options });
1473
1599
  const operations = createOperations(models, coordinate, registry, options);
1474
- const wrappedOperations = Library2.wrapOperations(operations, options, coordinate, registry);
1475
- const libLibrary = Library2.createLibrary(registry, coordinate, wrappedOperations, options);
1600
+ const wrappedOperations = Library3.wrapOperations(operations, options, coordinate, registry);
1601
+ const libLibrary = Library3.createLibrary(registry, coordinate, wrappedOperations, options);
1476
1602
  return {
1477
1603
  ...libLibrary,
1478
1604
  models
@@ -1483,10 +1609,10 @@ var isSequelizeLibrary = (library) => {
1483
1609
  };
1484
1610
 
1485
1611
  // src/SequelizeLibraryFactory.ts
1486
- var logger17 = logger_default.get("InstanceFactory");
1612
+ var logger16 = logger_default.get("InstanceFactory");
1487
1613
  var createSequelizeLibraryFactory = (models, options) => {
1488
1614
  return (coordinate, context) => {
1489
- logger17.debug("Creating Sequelize instance", {
1615
+ logger16.debug("Creating Sequelize instance", {
1490
1616
  coordinate,
1491
1617
  registry: context.registry,
1492
1618
  models: models.map((m) => m.name),
@@ -1531,9 +1657,9 @@ __export(primary_exports, {
1531
1657
 
1532
1658
  // src/primary/SequelizeLibrary.ts
1533
1659
  import { Primary } from "@fjell/lib";
1534
- var logger18 = logger_default.get("lib-sequelize", "primary", "library");
1660
+ var logger17 = logger_default.get("lib-sequelize", "primary", "library");
1535
1661
  function createSequelizeLibrary3(keyType, models, libOptions = {}, scopes = [], registry) {
1536
- logger18.debug("createSequelizeLibrary", { keyType, models, libOptions, scopes });
1662
+ logger17.debug("createSequelizeLibrary", { keyType, models, libOptions, scopes });
1537
1663
  const coordinate = createCoordinate([keyType], scopes);
1538
1664
  const options = createOptions2(libOptions);
1539
1665
  const operations = createOperations(models, coordinate, registry, options);