@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/Coordinate.d.ts +2 -3
- package/dist/Coordinate.d.ts.map +1 -1
- package/dist/Definition.d.ts +1 -1
- package/dist/Definition.d.ts.map +1 -1
- package/dist/Operations.d.ts +1 -2
- package/dist/Operations.d.ts.map +1 -1
- package/dist/SequelizeLibrary.d.ts +1 -2
- package/dist/SequelizeLibrary.d.ts.map +1 -1
- package/dist/SequelizeLibraryFactory.d.ts.map +1 -1
- package/dist/errors/sequelizeErrorHandler.d.ts +17 -0
- package/dist/errors/sequelizeErrorHandler.d.ts.map +1 -0
- package/dist/index.js +663 -537
- package/dist/index.js.map +4 -4
- package/dist/ops/all.d.ts +3 -2
- package/dist/ops/all.d.ts.map +1 -1
- package/dist/ops/create.d.ts +2 -8
- package/dist/ops/create.d.ts.map +1 -1
- package/dist/ops/find.d.ts +2 -2
- package/dist/ops/find.d.ts.map +1 -1
- package/dist/ops/get.d.ts +2 -2
- package/dist/ops/get.d.ts.map +1 -1
- package/dist/ops/one.d.ts +2 -2
- package/dist/ops/one.d.ts.map +1 -1
- package/dist/ops/remove.d.ts +2 -3
- package/dist/ops/remove.d.ts.map +1 -1
- package/dist/ops/update.d.ts +2 -2
- package/dist/ops/update.d.ts.map +1 -1
- package/dist/ops/upsert.d.ts +2 -2
- package/dist/ops/upsert.d.ts.map +1 -1
- package/package.json +5 -5
- package/dist/validation/LocationKeyValidator.d.ts +0 -13
- package/dist/validation/LocationKeyValidator.d.ts.map +0 -1
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/
|
|
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 {
|
|
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
|
|
463
|
+
var logger4 = logger_default.get("sequelize", "KeyMaster");
|
|
506
464
|
var extractLocationKeyValue = (model, item, locatorType, kta) => {
|
|
507
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
711
|
+
var logger6 = logger_default.get("sequelize", "RowProcessor");
|
|
754
712
|
var processRow = async (row, keyTypes, referenceDefinitions, aggregationDefinitions, registry, context) => {
|
|
755
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
const
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
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
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
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
|
-
|
|
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
|
|
894
|
-
|
|
895
|
-
|
|
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
|
|
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
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
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
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
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
|
|
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 = `
|
|
1035
|
-
|
|
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
|
-
|
|
1047
|
-
throw new Error(`
|
|
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
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
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
|
-
|
|
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 {
|
|
1102
|
-
|
|
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
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
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
|
-
|
|
1126
|
-
|
|
1226
|
+
logger9.error(`No finders have been defined for this lib`);
|
|
1227
|
+
throw new Error(`No finders found`);
|
|
1127
1228
|
}
|
|
1128
|
-
}
|
|
1129
|
-
|
|
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/
|
|
1148
|
-
var
|
|
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
|
-
|
|
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
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1325
|
+
import { createOneWrapper } from "@fjell/core";
|
|
1326
|
+
var logger11 = logger_default.get("sequelize", "ops", "one");
|
|
1219
1327
|
var getOneOperation = (models, definition, registry) => {
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
const
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
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 {
|
|
1240
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
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
|
-
|
|
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,
|
|
1327
|
-
import {
|
|
1328
|
-
import { NotFoundError as NotFoundError3 } from "@fjell/
|
|
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
|
|
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
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
const
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
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
|
-
|
|
1434
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1596
|
+
var logger15 = logger_default.get("SequelizeLibrary");
|
|
1471
1597
|
var createSequelizeLibrary = (registry, coordinate, models, options) => {
|
|
1472
|
-
|
|
1598
|
+
logger15.debug("createSequelizeLibrary", { coordinate, models, registry, options });
|
|
1473
1599
|
const operations = createOperations(models, coordinate, registry, options);
|
|
1474
|
-
const wrappedOperations =
|
|
1475
|
-
const libLibrary =
|
|
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
|
|
1612
|
+
var logger16 = logger_default.get("InstanceFactory");
|
|
1487
1613
|
var createSequelizeLibraryFactory = (models, options) => {
|
|
1488
1614
|
return (coordinate, context) => {
|
|
1489
|
-
|
|
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
|
|
1660
|
+
var logger17 = logger_default.get("lib-sequelize", "primary", "library");
|
|
1535
1661
|
function createSequelizeLibrary3(keyType, models, libOptions = {}, scopes = [], registry) {
|
|
1536
|
-
|
|
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);
|