metal-orm 1.0.56 → 1.0.58
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/README.md +41 -33
- package/dist/index.cjs +1461 -195
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +541 -114
- package/dist/index.d.ts +541 -114
- package/dist/index.js +1424 -195
- package/dist/index.js.map +1 -1
- package/package.json +69 -69
- package/src/codegen/naming-strategy.ts +3 -1
- package/src/codegen/typescript.ts +20 -10
- package/src/core/ast/aggregate-functions.ts +14 -0
- package/src/core/ast/builders.ts +38 -20
- package/src/core/ast/expression-builders.ts +70 -2
- package/src/core/ast/expression-nodes.ts +305 -274
- package/src/core/ast/expression-visitor.ts +11 -1
- package/src/core/ast/expression.ts +4 -0
- package/src/core/ast/query.ts +3 -0
- package/src/core/ddl/introspect/catalogs/mysql.ts +5 -0
- package/src/core/ddl/introspect/catalogs/sqlite.ts +3 -0
- package/src/core/ddl/introspect/functions/mssql.ts +13 -0
- package/src/core/ddl/introspect/mssql.ts +4 -0
- package/src/core/ddl/introspect/mysql.ts +4 -0
- package/src/core/ddl/introspect/sqlite.ts +4 -0
- package/src/core/dialect/abstract.ts +552 -531
- package/src/core/dialect/base/function-table-formatter.ts +9 -30
- package/src/core/dialect/base/sql-dialect.ts +24 -0
- package/src/core/dialect/mssql/functions.ts +40 -2
- package/src/core/dialect/mysql/functions.ts +16 -2
- package/src/core/dialect/postgres/functions.ts +66 -2
- package/src/core/dialect/postgres/index.ts +17 -4
- package/src/core/dialect/postgres/table-functions.ts +27 -0
- package/src/core/dialect/sqlite/functions.ts +34 -0
- package/src/core/dialect/sqlite/index.ts +17 -1
- package/src/core/driver/database-driver.ts +9 -1
- package/src/core/driver/mssql-driver.ts +3 -0
- package/src/core/driver/mysql-driver.ts +3 -0
- package/src/core/driver/postgres-driver.ts +3 -0
- package/src/core/driver/sqlite-driver.ts +3 -0
- package/src/core/execution/executors/mssql-executor.ts +5 -0
- package/src/core/execution/executors/mysql-executor.ts +5 -0
- package/src/core/execution/executors/postgres-executor.ts +5 -0
- package/src/core/execution/executors/sqlite-executor.ts +5 -0
- package/src/core/functions/array.ts +26 -0
- package/src/core/functions/control-flow.ts +69 -0
- package/src/core/functions/datetime.ts +50 -0
- package/src/core/functions/definitions/aggregate.ts +16 -0
- package/src/core/functions/definitions/control-flow.ts +24 -0
- package/src/core/functions/definitions/datetime.ts +36 -0
- package/src/core/functions/definitions/helpers.ts +29 -0
- package/src/core/functions/definitions/json.ts +49 -0
- package/src/core/functions/definitions/numeric.ts +55 -0
- package/src/core/functions/definitions/string.ts +43 -0
- package/src/core/functions/function-registry.ts +48 -0
- package/src/core/functions/group-concat-helpers.ts +57 -0
- package/src/core/functions/json.ts +38 -0
- package/src/core/functions/numeric.ts +14 -0
- package/src/core/functions/standard-strategy.ts +86 -115
- package/src/core/functions/standard-table-strategy.ts +13 -0
- package/src/core/functions/table-types.ts +15 -0
- package/src/core/functions/text.ts +57 -0
- package/src/core/sql/sql.ts +59 -38
- package/src/decorators/bootstrap.ts +41 -4
- package/src/index.ts +18 -11
- package/src/orm/entity-meta.ts +6 -3
- package/src/orm/entity.ts +81 -14
- package/src/orm/execute.ts +87 -20
- package/src/orm/hydration-context.ts +10 -0
- package/src/orm/identity-map.ts +19 -0
- package/src/orm/interceptor-pipeline.ts +4 -0
- package/src/orm/lazy-batch.ts +237 -54
- package/src/orm/relations/belongs-to.ts +19 -2
- package/src/orm/relations/has-many.ts +23 -9
- package/src/orm/relations/has-one.ts +19 -2
- package/src/orm/relations/many-to-many.ts +59 -4
- package/src/orm/save-graph-types.ts +2 -2
- package/src/orm/save-graph.ts +18 -18
- package/src/query-builder/relation-conditions.ts +80 -59
- package/src/query-builder/relation-service.ts +399 -95
- package/src/query-builder/relation-types.ts +2 -2
- package/src/query-builder/select.ts +124 -106
- package/src/schema/table-guards.ts +6 -0
- package/src/schema/types.ts +109 -85
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
-
var __esm = (
|
|
4
|
-
return
|
|
3
|
+
var __esm = (fn8, res) => function __init() {
|
|
4
|
+
return fn8 && (res = (0, fn8[__getOwnPropNames(fn8)[0]])(fn8 = 0)), res;
|
|
5
5
|
};
|
|
6
6
|
var __export = (target, all) => {
|
|
7
7
|
for (var name in all)
|
|
@@ -363,7 +363,9 @@ var operandTypes = /* @__PURE__ */ new Set([
|
|
|
363
363
|
"CaseExpression",
|
|
364
364
|
"Cast",
|
|
365
365
|
"WindowFunction",
|
|
366
|
-
"ArithmeticExpression"
|
|
366
|
+
"ArithmeticExpression",
|
|
367
|
+
"BitwiseExpression",
|
|
368
|
+
"Collate"
|
|
367
369
|
]);
|
|
368
370
|
var hasTypeProperty = (value) => typeof value === "object" && value !== null && "type" in value;
|
|
369
371
|
var isOperandNode = (node) => {
|
|
@@ -373,6 +375,7 @@ var isOperandNode = (node) => {
|
|
|
373
375
|
var isFunctionNode = (node) => isOperandNode(node) && node.type === "Function";
|
|
374
376
|
var isCaseExpressionNode = (node) => isOperandNode(node) && node.type === "CaseExpression";
|
|
375
377
|
var isCastExpressionNode = (node) => isOperandNode(node) && node.type === "Cast";
|
|
378
|
+
var isCollateExpressionNode = (node) => isOperandNode(node) && node.type === "Collate";
|
|
376
379
|
var isWindowFunctionNode = (node) => isOperandNode(node) && node.type === "WindowFunction";
|
|
377
380
|
var isExpressionSelectionNode = (node) => isFunctionNode(node) || isCaseExpressionNode(node) || isCastExpressionNode(node) || isWindowFunctionNode(node);
|
|
378
381
|
|
|
@@ -497,6 +500,17 @@ var add = (left2, right2) => createArithmeticExpression("+", left2, right2);
|
|
|
497
500
|
var sub = (left2, right2) => createArithmeticExpression("-", left2, right2);
|
|
498
501
|
var mul = (left2, right2) => createArithmeticExpression("*", left2, right2);
|
|
499
502
|
var div = (left2, right2) => createArithmeticExpression("/", left2, right2);
|
|
503
|
+
var createBitwiseExpression = (operator, left2, right2) => ({
|
|
504
|
+
type: "BitwiseExpression",
|
|
505
|
+
left: toOperand(left2),
|
|
506
|
+
operator,
|
|
507
|
+
right: toOperand(right2)
|
|
508
|
+
});
|
|
509
|
+
var bitAnd = (left2, right2) => createBitwiseExpression("&", left2, right2);
|
|
510
|
+
var bitOr = (left2, right2) => createBitwiseExpression("|", left2, right2);
|
|
511
|
+
var bitXor = (left2, right2) => createBitwiseExpression("^", left2, right2);
|
|
512
|
+
var shiftLeft = (left2, right2) => createBitwiseExpression("<<", left2, right2);
|
|
513
|
+
var shiftRight = (left2, right2) => createBitwiseExpression(">>", left2, right2);
|
|
500
514
|
var jsonPath = (col2, path) => ({
|
|
501
515
|
type: "JsonPath",
|
|
502
516
|
column: columnOperand(col2),
|
|
@@ -525,6 +539,11 @@ var notExists = (subquery) => ({
|
|
|
525
539
|
operator: "NOT EXISTS",
|
|
526
540
|
subquery
|
|
527
541
|
});
|
|
542
|
+
var collate = (expression, collation) => ({
|
|
543
|
+
type: "Collate",
|
|
544
|
+
expression: toOperand(expression),
|
|
545
|
+
collation
|
|
546
|
+
});
|
|
528
547
|
|
|
529
548
|
// src/core/ast/window-functions.ts
|
|
530
549
|
var buildWindowFunction = (name, args = [], partitionBy, orderBy) => {
|
|
@@ -670,6 +689,8 @@ var groupConcat = (col2, options) => ({
|
|
|
670
689
|
orderBy: options?.orderBy?.map(toOrderByNode),
|
|
671
690
|
separator: options?.separator !== void 0 ? valueToOperand(options.separator) : void 0
|
|
672
691
|
});
|
|
692
|
+
var stddev = buildAggregate("STDDEV");
|
|
693
|
+
var variance = buildAggregate("VARIANCE");
|
|
673
694
|
|
|
674
695
|
// src/core/ast/expression-visitor.ts
|
|
675
696
|
var DispatcherRegistry = class _DispatcherRegistry {
|
|
@@ -743,6 +764,9 @@ var visitExpression = (node, visitor) => {
|
|
|
743
764
|
case "ArithmeticExpression":
|
|
744
765
|
if (visitor.visitArithmeticExpression) return visitor.visitArithmeticExpression(node);
|
|
745
766
|
break;
|
|
767
|
+
case "BitwiseExpression":
|
|
768
|
+
if (visitor.visitBitwiseExpression) return visitor.visitBitwiseExpression(node);
|
|
769
|
+
break;
|
|
746
770
|
default:
|
|
747
771
|
break;
|
|
748
772
|
}
|
|
@@ -780,6 +804,9 @@ var visitOperand = (node, visitor) => {
|
|
|
780
804
|
case "Cast":
|
|
781
805
|
if (visitor.visitCast) return visitor.visitCast(node);
|
|
782
806
|
break;
|
|
807
|
+
case "Collate":
|
|
808
|
+
if (visitor.visitCollate) return visitor.visitCollate(node);
|
|
809
|
+
break;
|
|
783
810
|
default:
|
|
784
811
|
break;
|
|
785
812
|
}
|
|
@@ -850,62 +877,337 @@ var derivedTable = (query, alias, columnAliases) => ({
|
|
|
850
877
|
columnAliases
|
|
851
878
|
});
|
|
852
879
|
|
|
880
|
+
// src/core/functions/function-registry.ts
|
|
881
|
+
var FunctionRegistry = class {
|
|
882
|
+
constructor() {
|
|
883
|
+
this.renderers = /* @__PURE__ */ new Map();
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* Registers or overrides a renderer for the given function name.
|
|
887
|
+
*/
|
|
888
|
+
add(name, renderer) {
|
|
889
|
+
this.renderers.set(name, renderer);
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
* Registers a batch of definitions.
|
|
893
|
+
*/
|
|
894
|
+
register(definitions) {
|
|
895
|
+
for (const definition of definitions) {
|
|
896
|
+
this.add(definition.name, definition.renderer);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
/**
|
|
900
|
+
* Merges another registry into this one, allowing overrides from the other source.
|
|
901
|
+
*/
|
|
902
|
+
merge(other) {
|
|
903
|
+
for (const [name, renderer] of other.renderers.entries()) {
|
|
904
|
+
this.renderers.set(name, renderer);
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
/**
|
|
908
|
+
* Retrieves a renderer by function name.
|
|
909
|
+
*/
|
|
910
|
+
get(name) {
|
|
911
|
+
return this.renderers.get(name);
|
|
912
|
+
}
|
|
913
|
+
};
|
|
914
|
+
|
|
915
|
+
// src/core/functions/definitions/helpers.ts
|
|
916
|
+
function unaryRenderer(name) {
|
|
917
|
+
return ({ compiledArgs }) => `${name}(${compiledArgs[0]})`;
|
|
918
|
+
}
|
|
919
|
+
function binaryRenderer(name) {
|
|
920
|
+
return ({ compiledArgs }) => `${name}(${compiledArgs[0]}, ${compiledArgs[1]})`;
|
|
921
|
+
}
|
|
922
|
+
function variadicRenderer(name) {
|
|
923
|
+
return ({ compiledArgs }) => `${name}(${compiledArgs.join(", ")})`;
|
|
924
|
+
}
|
|
925
|
+
function noArgsRenderer(name) {
|
|
926
|
+
return () => `${name}()`;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
// src/core/functions/definitions/aggregate.ts
|
|
930
|
+
var aggregateFunctionDefinitions = [
|
|
931
|
+
{
|
|
932
|
+
name: "COUNT",
|
|
933
|
+
renderer: ({ compiledArgs }) => compiledArgs.length ? `COUNT(${compiledArgs.join(", ")})` : "COUNT(*)"
|
|
934
|
+
},
|
|
935
|
+
{ name: "SUM", renderer: unaryRenderer("SUM") },
|
|
936
|
+
{ name: "AVG", renderer: unaryRenderer("AVG") },
|
|
937
|
+
{ name: "MIN", renderer: unaryRenderer("MIN") },
|
|
938
|
+
{ name: "MAX", renderer: unaryRenderer("MAX") },
|
|
939
|
+
{ name: "STDDEV", renderer: unaryRenderer("STDDEV") },
|
|
940
|
+
{ name: "VARIANCE", renderer: unaryRenderer("VARIANCE") }
|
|
941
|
+
];
|
|
942
|
+
|
|
943
|
+
// src/core/functions/definitions/string.ts
|
|
944
|
+
var stringFunctionDefinitions = [
|
|
945
|
+
{ name: "UPPER", renderer: unaryRenderer("UPPER") },
|
|
946
|
+
{ name: "LOWER", renderer: unaryRenderer("LOWER") },
|
|
947
|
+
{ name: "LENGTH", renderer: unaryRenderer("LENGTH") },
|
|
948
|
+
{ name: "CHAR_LENGTH", renderer: unaryRenderer("CHAR_LENGTH") },
|
|
949
|
+
{ name: "CHARACTER_LENGTH", renderer: unaryRenderer("CHARACTER_LENGTH") },
|
|
950
|
+
{ name: "TRIM", renderer: unaryRenderer("TRIM") },
|
|
951
|
+
{ name: "LTRIM", renderer: unaryRenderer("LTRIM") },
|
|
952
|
+
{ name: "RTRIM", renderer: unaryRenderer("RTRIM") },
|
|
953
|
+
{ name: "SUBSTRING", renderer: variadicRenderer("SUBSTRING") },
|
|
954
|
+
{ name: "SUBSTR", renderer: variadicRenderer("SUBSTR") },
|
|
955
|
+
{ name: "CONCAT", renderer: variadicRenderer("CONCAT") },
|
|
956
|
+
{ name: "CONCAT_WS", renderer: variadicRenderer("CONCAT_WS") },
|
|
957
|
+
{ name: "ASCII", renderer: unaryRenderer("ASCII") },
|
|
958
|
+
{ name: "CHAR", renderer: variadicRenderer("CHAR") },
|
|
959
|
+
{
|
|
960
|
+
name: "POSITION",
|
|
961
|
+
renderer: ({ compiledArgs }) => `POSITION(${compiledArgs[0]} IN ${compiledArgs[1]})`
|
|
962
|
+
},
|
|
963
|
+
{ name: "REPLACE", renderer: ({ compiledArgs }) => `REPLACE(${compiledArgs[0]}, ${compiledArgs[1]}, ${compiledArgs[2]})` },
|
|
964
|
+
{ name: "REPEAT", renderer: binaryRenderer("REPEAT") },
|
|
965
|
+
{ name: "LPAD", renderer: ({ compiledArgs }) => `LPAD(${compiledArgs[0]}, ${compiledArgs[1]}, ${compiledArgs[2]})` },
|
|
966
|
+
{ name: "RPAD", renderer: ({ compiledArgs }) => `RPAD(${compiledArgs[0]}, ${compiledArgs[1]}, ${compiledArgs[2]})` },
|
|
967
|
+
{ name: "LEFT", renderer: binaryRenderer("LEFT") },
|
|
968
|
+
{ name: "RIGHT", renderer: binaryRenderer("RIGHT") },
|
|
969
|
+
{ name: "INSTR", renderer: binaryRenderer("INSTR") },
|
|
970
|
+
{
|
|
971
|
+
name: "LOCATE",
|
|
972
|
+
renderer: ({ compiledArgs }) => compiledArgs.length === 3 ? `LOCATE(${compiledArgs[0]}, ${compiledArgs[1]}, ${compiledArgs[2]})` : `LOCATE(${compiledArgs[0]}, ${compiledArgs[1]})`
|
|
973
|
+
},
|
|
974
|
+
{ name: "SPACE", renderer: unaryRenderer("SPACE") },
|
|
975
|
+
{ name: "REVERSE", renderer: unaryRenderer("REVERSE") },
|
|
976
|
+
{ name: "INITCAP", renderer: unaryRenderer("INITCAP") },
|
|
977
|
+
{ name: "MD5", renderer: unaryRenderer("MD5") },
|
|
978
|
+
{ name: "SHA1", renderer: unaryRenderer("SHA1") },
|
|
979
|
+
{ name: "SHA2", renderer: ({ compiledArgs }) => `SHA2(${compiledArgs[0]}, ${compiledArgs[1]})` }
|
|
980
|
+
];
|
|
981
|
+
|
|
982
|
+
// src/core/functions/definitions/datetime.ts
|
|
983
|
+
var dateTimeFunctionDefinitions = [
|
|
984
|
+
{ name: "NOW", renderer: noArgsRenderer("NOW") },
|
|
985
|
+
{ name: "CURRENT_DATE", renderer: () => "CURRENT_DATE" },
|
|
986
|
+
{ name: "CURRENT_TIME", renderer: () => "CURRENT_TIME" },
|
|
987
|
+
{
|
|
988
|
+
name: "EXTRACT",
|
|
989
|
+
renderer: ({ compiledArgs }) => `EXTRACT(${compiledArgs[0]} FROM ${compiledArgs[1]})`
|
|
990
|
+
},
|
|
991
|
+
{ name: "YEAR", renderer: ({ compiledArgs }) => `EXTRACT(YEAR FROM ${compiledArgs[0]})` },
|
|
992
|
+
{ name: "MONTH", renderer: ({ compiledArgs }) => `EXTRACT(MONTH FROM ${compiledArgs[0]})` },
|
|
993
|
+
{ name: "DAY", renderer: ({ compiledArgs }) => `EXTRACT(DAY FROM ${compiledArgs[0]})` },
|
|
994
|
+
{ name: "HOUR", renderer: ({ compiledArgs }) => `EXTRACT(HOUR FROM ${compiledArgs[0]})` },
|
|
995
|
+
{ name: "MINUTE", renderer: ({ compiledArgs }) => `EXTRACT(MINUTE FROM ${compiledArgs[0]})` },
|
|
996
|
+
{ name: "SECOND", renderer: ({ compiledArgs }) => `EXTRACT(SECOND FROM ${compiledArgs[0]})` },
|
|
997
|
+
{ name: "QUARTER", renderer: ({ compiledArgs }) => `EXTRACT(QUARTER FROM ${compiledArgs[0]})` },
|
|
998
|
+
{ name: "DATE_ADD", renderer: ({ compiledArgs }) => `(${compiledArgs[0]} + INTERVAL ${compiledArgs[1]} ${compiledArgs[2]})` },
|
|
999
|
+
{ name: "DATE_SUB", renderer: ({ compiledArgs }) => `(${compiledArgs[0]} - INTERVAL ${compiledArgs[1]} ${compiledArgs[2]})` },
|
|
1000
|
+
{ name: "DATE_DIFF", renderer: ({ compiledArgs }) => `DATEDIFF(${compiledArgs[0]}, ${compiledArgs[1]})` },
|
|
1001
|
+
{ name: "DATE_FORMAT", renderer: ({ compiledArgs }) => `DATE_FORMAT(${compiledArgs[0]}, ${compiledArgs[1]})` },
|
|
1002
|
+
{ name: "UNIX_TIMESTAMP", renderer: noArgsRenderer("UNIX_TIMESTAMP") },
|
|
1003
|
+
{ name: "FROM_UNIXTIME", renderer: ({ compiledArgs }) => `FROM_UNIXTIME(${compiledArgs[0]})` },
|
|
1004
|
+
{ name: "END_OF_MONTH", renderer: ({ compiledArgs }) => `LAST_DAY(${compiledArgs[0]})` },
|
|
1005
|
+
{ name: "DAY_OF_WEEK", renderer: ({ compiledArgs }) => `DAYOFWEEK(${compiledArgs[0]})` },
|
|
1006
|
+
{ name: "WEEK_OF_YEAR", renderer: ({ compiledArgs }) => `WEEKOFYEAR(${compiledArgs[0]})` },
|
|
1007
|
+
{ name: "DATE_TRUNC", renderer: ({ compiledArgs }) => `DATE_TRUNC(${compiledArgs[0]}, ${compiledArgs[1]})` },
|
|
1008
|
+
{
|
|
1009
|
+
name: "AGE",
|
|
1010
|
+
renderer: ({ compiledArgs }) => compiledArgs.length === 1 ? `AGE(${compiledArgs[0]})` : `AGE(${compiledArgs[0]}, ${compiledArgs[1]})`
|
|
1011
|
+
},
|
|
1012
|
+
{ name: "LOCALTIME", renderer: () => "LOCALTIME" },
|
|
1013
|
+
{ name: "LOCALTIMESTAMP", renderer: () => "LOCALTIMESTAMP" }
|
|
1014
|
+
];
|
|
1015
|
+
|
|
1016
|
+
// src/core/functions/definitions/numeric.ts
|
|
1017
|
+
var numericFunctionDefinitions = [
|
|
1018
|
+
{ name: "ABS", renderer: unaryRenderer("ABS") },
|
|
1019
|
+
{ name: "BIT_LENGTH", renderer: unaryRenderer("BIT_LENGTH") },
|
|
1020
|
+
{ name: "OCTET_LENGTH", renderer: unaryRenderer("OCTET_LENGTH") },
|
|
1021
|
+
{ name: "CHR", renderer: unaryRenderer("CHR") },
|
|
1022
|
+
{ name: "LOG2", renderer: unaryRenderer("LOG2") },
|
|
1023
|
+
{ name: "CBRT", renderer: unaryRenderer("CBRT") },
|
|
1024
|
+
{ name: "ACOS", renderer: unaryRenderer("ACOS") },
|
|
1025
|
+
{ name: "ASIN", renderer: unaryRenderer("ASIN") },
|
|
1026
|
+
{ name: "ATAN", renderer: unaryRenderer("ATAN") },
|
|
1027
|
+
{ name: "ATAN2", renderer: binaryRenderer("ATAN2") },
|
|
1028
|
+
{ name: "CEIL", renderer: unaryRenderer("CEIL") },
|
|
1029
|
+
{ name: "CEILING", renderer: unaryRenderer("CEILING") },
|
|
1030
|
+
{ name: "COS", renderer: unaryRenderer("COS") },
|
|
1031
|
+
{ name: "COT", renderer: unaryRenderer("COT") },
|
|
1032
|
+
{ name: "DEGREES", renderer: unaryRenderer("DEGREES") },
|
|
1033
|
+
{ name: "EXP", renderer: unaryRenderer("EXP") },
|
|
1034
|
+
{ name: "FLOOR", renderer: unaryRenderer("FLOOR") },
|
|
1035
|
+
{ name: "LN", renderer: unaryRenderer("LN") },
|
|
1036
|
+
{
|
|
1037
|
+
name: "LOG",
|
|
1038
|
+
renderer: ({ compiledArgs }) => compiledArgs.length === 2 ? `LOG(${compiledArgs[0]}, ${compiledArgs[1]})` : `LOG(${compiledArgs[0]})`
|
|
1039
|
+
},
|
|
1040
|
+
{ name: "LOG10", renderer: unaryRenderer("LOG10") },
|
|
1041
|
+
{ name: "LOG_BASE", renderer: binaryRenderer("LOG") },
|
|
1042
|
+
{ name: "MOD", renderer: binaryRenderer("MOD") },
|
|
1043
|
+
{ name: "PI", renderer: noArgsRenderer("PI") },
|
|
1044
|
+
{ name: "POWER", renderer: binaryRenderer("POWER") },
|
|
1045
|
+
{ name: "POW", renderer: binaryRenderer("POW") },
|
|
1046
|
+
{ name: "RADIANS", renderer: unaryRenderer("RADIANS") },
|
|
1047
|
+
{ name: "RANDOM", renderer: noArgsRenderer("RANDOM") },
|
|
1048
|
+
{ name: "RAND", renderer: noArgsRenderer("RAND") },
|
|
1049
|
+
{
|
|
1050
|
+
name: "ROUND",
|
|
1051
|
+
renderer: ({ compiledArgs }) => compiledArgs.length === 2 ? `ROUND(${compiledArgs[0]}, ${compiledArgs[1]})` : `ROUND(${compiledArgs[0]})`
|
|
1052
|
+
},
|
|
1053
|
+
{ name: "SIGN", renderer: unaryRenderer("SIGN") },
|
|
1054
|
+
{ name: "SIN", renderer: unaryRenderer("SIN") },
|
|
1055
|
+
{ name: "SQRT", renderer: unaryRenderer("SQRT") },
|
|
1056
|
+
{ name: "TAN", renderer: unaryRenderer("TAN") },
|
|
1057
|
+
{
|
|
1058
|
+
name: "TRUNC",
|
|
1059
|
+
renderer: ({ compiledArgs }) => compiledArgs.length === 2 ? `TRUNC(${compiledArgs[0]}, ${compiledArgs[1]})` : `TRUNC(${compiledArgs[0]})`
|
|
1060
|
+
},
|
|
1061
|
+
{
|
|
1062
|
+
name: "TRUNCATE",
|
|
1063
|
+
renderer: ({ compiledArgs }) => `TRUNCATE(${compiledArgs[0]}, ${compiledArgs[1]})`
|
|
1064
|
+
}
|
|
1065
|
+
];
|
|
1066
|
+
|
|
1067
|
+
// src/core/functions/definitions/control-flow.ts
|
|
1068
|
+
var controlFlowFunctionDefinitions = [
|
|
1069
|
+
{
|
|
1070
|
+
name: "COALESCE",
|
|
1071
|
+
renderer: ({ compiledArgs }) => `COALESCE(${compiledArgs.join(", ")})`
|
|
1072
|
+
},
|
|
1073
|
+
{
|
|
1074
|
+
name: "NULLIF",
|
|
1075
|
+
renderer: ({ compiledArgs }) => `NULLIF(${compiledArgs[0]}, ${compiledArgs[1]})`
|
|
1076
|
+
},
|
|
1077
|
+
{
|
|
1078
|
+
name: "GREATEST",
|
|
1079
|
+
renderer: ({ compiledArgs }) => `GREATEST(${compiledArgs.join(", ")})`
|
|
1080
|
+
},
|
|
1081
|
+
{
|
|
1082
|
+
name: "LEAST",
|
|
1083
|
+
renderer: ({ compiledArgs }) => `LEAST(${compiledArgs.join(", ")})`
|
|
1084
|
+
},
|
|
1085
|
+
{
|
|
1086
|
+
name: "IFNULL",
|
|
1087
|
+
renderer: ({ compiledArgs }) => `IFNULL(${compiledArgs[0]}, ${compiledArgs[1]})`
|
|
1088
|
+
}
|
|
1089
|
+
];
|
|
1090
|
+
|
|
1091
|
+
// src/core/functions/definitions/json.ts
|
|
1092
|
+
var jsonFunctionDefinitions = [
|
|
1093
|
+
{
|
|
1094
|
+
name: "JSON_LENGTH",
|
|
1095
|
+
renderer: ({ compiledArgs }) => {
|
|
1096
|
+
if (compiledArgs.length === 0 || compiledArgs.length > 2) {
|
|
1097
|
+
throw new Error("JSON_LENGTH expects 1 or 2 arguments");
|
|
1098
|
+
}
|
|
1099
|
+
return `JSON_LENGTH(${compiledArgs.join(", ")})`;
|
|
1100
|
+
}
|
|
1101
|
+
},
|
|
1102
|
+
{
|
|
1103
|
+
name: "JSON_SET",
|
|
1104
|
+
renderer: ({ compiledArgs }) => {
|
|
1105
|
+
if (compiledArgs.length < 3 || (compiledArgs.length - 1) % 2 !== 0) {
|
|
1106
|
+
throw new Error("JSON_SET expects a JSON document followed by one or more path/value pairs");
|
|
1107
|
+
}
|
|
1108
|
+
return `JSON_SET(${compiledArgs.join(", ")})`;
|
|
1109
|
+
}
|
|
1110
|
+
},
|
|
1111
|
+
{
|
|
1112
|
+
name: "JSON_ARRAYAGG",
|
|
1113
|
+
renderer: ({ compiledArgs }) => {
|
|
1114
|
+
if (compiledArgs.length !== 1) {
|
|
1115
|
+
throw new Error("JSON_ARRAYAGG expects exactly one argument");
|
|
1116
|
+
}
|
|
1117
|
+
return `JSON_ARRAYAGG(${compiledArgs[0]})`;
|
|
1118
|
+
}
|
|
1119
|
+
},
|
|
1120
|
+
{
|
|
1121
|
+
name: "JSON_CONTAINS",
|
|
1122
|
+
renderer: ({ compiledArgs }) => {
|
|
1123
|
+
if (compiledArgs.length < 2 || compiledArgs.length > 3) {
|
|
1124
|
+
throw new Error("JSON_CONTAINS expects two or three arguments");
|
|
1125
|
+
}
|
|
1126
|
+
return `JSON_CONTAINS(${compiledArgs.join(", ")})`;
|
|
1127
|
+
}
|
|
1128
|
+
},
|
|
1129
|
+
{
|
|
1130
|
+
name: "ARRAY_APPEND",
|
|
1131
|
+
renderer: ({ compiledArgs }) => {
|
|
1132
|
+
if (compiledArgs.length !== 2) {
|
|
1133
|
+
throw new Error("ARRAY_APPEND expects exactly two arguments");
|
|
1134
|
+
}
|
|
1135
|
+
return `ARRAY_APPEND(${compiledArgs[0]}, ${compiledArgs[1]})`;
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
];
|
|
1139
|
+
|
|
1140
|
+
// src/core/functions/group-concat-helpers.ts
|
|
1141
|
+
var DEFAULT_GROUP_CONCAT_SEPARATOR = {
|
|
1142
|
+
type: "Literal",
|
|
1143
|
+
value: ","
|
|
1144
|
+
};
|
|
1145
|
+
function buildGroupConcatOrderBy(ctx) {
|
|
1146
|
+
const orderBy = ctx.node.orderBy;
|
|
1147
|
+
if (!orderBy || orderBy.length === 0) {
|
|
1148
|
+
return "";
|
|
1149
|
+
}
|
|
1150
|
+
const parts = orderBy.map((order) => {
|
|
1151
|
+
const term = isOperandNode(order.term) ? ctx.compileOperand(order.term) : (() => {
|
|
1152
|
+
throw new Error("ORDER BY expressions inside functions must be operands");
|
|
1153
|
+
})();
|
|
1154
|
+
const collation = order.collation ? ` COLLATE ${order.collation}` : "";
|
|
1155
|
+
const nulls = order.nulls ? ` NULLS ${order.nulls}` : "";
|
|
1156
|
+
return `${term} ${order.direction}${collation}${nulls}`;
|
|
1157
|
+
});
|
|
1158
|
+
return `ORDER BY ${parts.join(", ")}`;
|
|
1159
|
+
}
|
|
1160
|
+
function formatGroupConcatSeparator(ctx) {
|
|
1161
|
+
if (!ctx.node.separator) {
|
|
1162
|
+
return "";
|
|
1163
|
+
}
|
|
1164
|
+
return ` SEPARATOR ${ctx.compileOperand(ctx.node.separator)}`;
|
|
1165
|
+
}
|
|
1166
|
+
function getGroupConcatSeparatorOperand(ctx) {
|
|
1167
|
+
return ctx.node.separator ?? DEFAULT_GROUP_CONCAT_SEPARATOR;
|
|
1168
|
+
}
|
|
1169
|
+
function renderStandardGroupConcat(ctx) {
|
|
1170
|
+
const arg = ctx.compiledArgs[0];
|
|
1171
|
+
const orderClause = buildGroupConcatOrderBy(ctx);
|
|
1172
|
+
const orderSegment = orderClause ? ` ${orderClause}` : "";
|
|
1173
|
+
const separatorClause = formatGroupConcatSeparator(ctx);
|
|
1174
|
+
return `GROUP_CONCAT(${arg}${orderSegment}${separatorClause})`;
|
|
1175
|
+
}
|
|
1176
|
+
|
|
853
1177
|
// src/core/functions/standard-strategy.ts
|
|
854
|
-
var StandardFunctionStrategy = class
|
|
1178
|
+
var StandardFunctionStrategy = class {
|
|
855
1179
|
/**
|
|
856
1180
|
* Creates a new StandardFunctionStrategy and registers standard functions.
|
|
857
1181
|
*/
|
|
858
|
-
constructor() {
|
|
859
|
-
this.
|
|
1182
|
+
constructor(registry2) {
|
|
1183
|
+
this.registry = registry2 ?? new FunctionRegistry();
|
|
860
1184
|
this.registerStandard();
|
|
861
1185
|
}
|
|
862
1186
|
registerStandard() {
|
|
863
|
-
this.
|
|
864
|
-
this.
|
|
865
|
-
this.
|
|
866
|
-
this.
|
|
867
|
-
this.
|
|
868
|
-
this.
|
|
869
|
-
this.add("UPPER", ({ compiledArgs }) => `UPPER(${compiledArgs[0]})`);
|
|
870
|
-
this.add("LOWER", ({ compiledArgs }) => `LOWER(${compiledArgs[0]})`);
|
|
871
|
-
this.add("LENGTH", ({ compiledArgs }) => `LENGTH(${compiledArgs[0]})`);
|
|
872
|
-
this.add("TRIM", ({ compiledArgs }) => `TRIM(${compiledArgs[0]})`);
|
|
873
|
-
this.add("LTRIM", ({ compiledArgs }) => `LTRIM(${compiledArgs[0]})`);
|
|
874
|
-
this.add("RTRIM", ({ compiledArgs }) => `RTRIM(${compiledArgs[0]})`);
|
|
875
|
-
this.add("SUBSTRING", ({ compiledArgs }) => `SUBSTRING(${compiledArgs.join(", ")})`);
|
|
876
|
-
this.add("CONCAT", ({ compiledArgs }) => `CONCAT(${compiledArgs.join(", ")})`);
|
|
877
|
-
this.add("NOW", () => `NOW()`);
|
|
878
|
-
this.add("CURRENT_DATE", () => `CURRENT_DATE`);
|
|
879
|
-
this.add("CURRENT_TIME", () => `CURRENT_TIME`);
|
|
880
|
-
this.add("EXTRACT", ({ compiledArgs }) => `EXTRACT(${compiledArgs[0]} FROM ${compiledArgs[1]})`);
|
|
881
|
-
this.add("YEAR", ({ compiledArgs }) => `EXTRACT(YEAR FROM ${compiledArgs[0]})`);
|
|
882
|
-
this.add("MONTH", ({ compiledArgs }) => `EXTRACT(MONTH FROM ${compiledArgs[0]})`);
|
|
883
|
-
this.add("DAY", ({ compiledArgs }) => `EXTRACT(DAY FROM ${compiledArgs[0]})`);
|
|
884
|
-
this.add("DATE_ADD", ({ compiledArgs }) => `(${compiledArgs[0]} + INTERVAL ${compiledArgs[1]} ${compiledArgs[2]})`);
|
|
885
|
-
this.add("DATE_SUB", ({ compiledArgs }) => `(${compiledArgs[0]} - INTERVAL ${compiledArgs[1]} ${compiledArgs[2]})`);
|
|
886
|
-
this.add("DATE_DIFF", ({ compiledArgs }) => `DATEDIFF(${compiledArgs[0]}, ${compiledArgs[1]})`);
|
|
887
|
-
this.add("DATE_FORMAT", ({ compiledArgs }) => `DATE_FORMAT(${compiledArgs[0]}, ${compiledArgs[1]})`);
|
|
888
|
-
this.add("UNIX_TIMESTAMP", () => `UNIX_TIMESTAMP()`);
|
|
889
|
-
this.add("FROM_UNIXTIME", ({ compiledArgs }) => `FROM_UNIXTIME(${compiledArgs[0]})`);
|
|
890
|
-
this.add("END_OF_MONTH", ({ compiledArgs }) => `LAST_DAY(${compiledArgs[0]})`);
|
|
891
|
-
this.add("DAY_OF_WEEK", ({ compiledArgs }) => `DAYOFWEEK(${compiledArgs[0]})`);
|
|
892
|
-
this.add("WEEK_OF_YEAR", ({ compiledArgs }) => `WEEKOFYEAR(${compiledArgs[0]})`);
|
|
893
|
-
this.add("DATE_TRUNC", ({ compiledArgs }) => `DATE_TRUNC(${compiledArgs[0]}, ${compiledArgs[1]})`);
|
|
1187
|
+
this.registerDefinitions(aggregateFunctionDefinitions);
|
|
1188
|
+
this.registerDefinitions(stringFunctionDefinitions);
|
|
1189
|
+
this.registerDefinitions(dateTimeFunctionDefinitions);
|
|
1190
|
+
this.registerDefinitions(numericFunctionDefinitions);
|
|
1191
|
+
this.registerDefinitions(controlFlowFunctionDefinitions);
|
|
1192
|
+
this.registerDefinitions(jsonFunctionDefinitions);
|
|
894
1193
|
this.add("GROUP_CONCAT", (ctx) => this.renderGroupConcat(ctx));
|
|
895
1194
|
}
|
|
1195
|
+
registerDefinitions(definitions) {
|
|
1196
|
+
this.registry.register(definitions);
|
|
1197
|
+
}
|
|
896
1198
|
/**
|
|
897
1199
|
* Registers a renderer for a function name.
|
|
898
1200
|
* @param name - The function name.
|
|
899
1201
|
* @param renderer - The renderer function.
|
|
900
1202
|
*/
|
|
901
1203
|
add(name, renderer) {
|
|
902
|
-
this.
|
|
1204
|
+
this.registry.add(name, renderer);
|
|
903
1205
|
}
|
|
904
1206
|
/**
|
|
905
1207
|
* @inheritDoc
|
|
906
1208
|
*/
|
|
907
1209
|
getRenderer(name) {
|
|
908
|
-
return this.
|
|
1210
|
+
return this.registry.get(name);
|
|
909
1211
|
}
|
|
910
1212
|
/**
|
|
911
1213
|
* Renders the GROUP_CONCAT function with optional ORDER BY and SEPARATOR.
|
|
@@ -913,11 +1215,7 @@ var StandardFunctionStrategy = class _StandardFunctionStrategy {
|
|
|
913
1215
|
* @returns The rendered SQL string.
|
|
914
1216
|
*/
|
|
915
1217
|
renderGroupConcat(ctx) {
|
|
916
|
-
|
|
917
|
-
const orderClause = this.buildOrderByExpression(ctx);
|
|
918
|
-
const orderSegment = orderClause ? ` ${orderClause}` : "";
|
|
919
|
-
const separatorClause = this.formatGroupConcatSeparator(ctx);
|
|
920
|
-
return `GROUP_CONCAT(${arg}${orderSegment}${separatorClause})`;
|
|
1218
|
+
return renderStandardGroupConcat(ctx);
|
|
921
1219
|
}
|
|
922
1220
|
/**
|
|
923
1221
|
* Builds the ORDER BY clause for functions like GROUP_CONCAT.
|
|
@@ -925,19 +1223,7 @@ var StandardFunctionStrategy = class _StandardFunctionStrategy {
|
|
|
925
1223
|
* @returns The ORDER BY SQL clause or empty string.
|
|
926
1224
|
*/
|
|
927
1225
|
buildOrderByExpression(ctx) {
|
|
928
|
-
|
|
929
|
-
if (!orderBy || orderBy.length === 0) {
|
|
930
|
-
return "";
|
|
931
|
-
}
|
|
932
|
-
const parts = orderBy.map((order) => {
|
|
933
|
-
const term = isOperandNode(order.term) ? ctx.compileOperand(order.term) : (() => {
|
|
934
|
-
throw new Error("ORDER BY expressions inside functions must be operands");
|
|
935
|
-
})();
|
|
936
|
-
const collation = order.collation ? ` COLLATE ${order.collation}` : "";
|
|
937
|
-
const nulls = order.nulls ? ` NULLS ${order.nulls}` : "";
|
|
938
|
-
return `${term} ${order.direction}${collation}${nulls}`;
|
|
939
|
-
});
|
|
940
|
-
return `ORDER BY ${parts.join(", ")}`;
|
|
1226
|
+
return buildGroupConcatOrderBy(ctx);
|
|
941
1227
|
}
|
|
942
1228
|
/**
|
|
943
1229
|
* Formats the SEPARATOR clause for GROUP_CONCAT.
|
|
@@ -945,10 +1231,7 @@ var StandardFunctionStrategy = class _StandardFunctionStrategy {
|
|
|
945
1231
|
* @returns The SEPARATOR SQL clause or empty string.
|
|
946
1232
|
*/
|
|
947
1233
|
formatGroupConcatSeparator(ctx) {
|
|
948
|
-
|
|
949
|
-
return "";
|
|
950
|
-
}
|
|
951
|
-
return ` SEPARATOR ${ctx.compileOperand(ctx.node.separator)}`;
|
|
1234
|
+
return formatGroupConcatSeparator(ctx);
|
|
952
1235
|
}
|
|
953
1236
|
/**
|
|
954
1237
|
* Gets the separator operand for GROUP_CONCAT, defaulting to comma.
|
|
@@ -956,14 +1239,24 @@ var StandardFunctionStrategy = class _StandardFunctionStrategy {
|
|
|
956
1239
|
* @returns The separator operand.
|
|
957
1240
|
*/
|
|
958
1241
|
getGroupConcatSeparatorOperand(ctx) {
|
|
959
|
-
return ctx
|
|
1242
|
+
return getGroupConcatSeparatorOperand(ctx);
|
|
960
1243
|
}
|
|
961
1244
|
static {
|
|
962
1245
|
/** Default separator for GROUP_CONCAT, a comma. */
|
|
963
|
-
this.DEFAULT_GROUP_CONCAT_SEPARATOR =
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
1246
|
+
this.DEFAULT_GROUP_CONCAT_SEPARATOR = DEFAULT_GROUP_CONCAT_SEPARATOR;
|
|
1247
|
+
}
|
|
1248
|
+
};
|
|
1249
|
+
|
|
1250
|
+
// src/core/functions/standard-table-strategy.ts
|
|
1251
|
+
var StandardTableFunctionStrategy = class {
|
|
1252
|
+
constructor() {
|
|
1253
|
+
this.renderers = /* @__PURE__ */ new Map();
|
|
1254
|
+
}
|
|
1255
|
+
add(key, renderer) {
|
|
1256
|
+
this.renderers.set(key, renderer);
|
|
1257
|
+
}
|
|
1258
|
+
getRenderer(key) {
|
|
1259
|
+
return this.renderers.get(key);
|
|
967
1260
|
}
|
|
968
1261
|
};
|
|
969
1262
|
|
|
@@ -1137,10 +1430,11 @@ var Dialect = class _Dialect {
|
|
|
1137
1430
|
const combinedCtes = [...normalized.ctes ?? [], ...hoistedCtes];
|
|
1138
1431
|
return combinedCtes.length ? { ...normalized, ctes: combinedCtes } : normalized;
|
|
1139
1432
|
}
|
|
1140
|
-
constructor(functionStrategy) {
|
|
1433
|
+
constructor(functionStrategy, tableFunctionStrategy) {
|
|
1141
1434
|
this.expressionCompilers = /* @__PURE__ */ new Map();
|
|
1142
1435
|
this.operandCompilers = /* @__PURE__ */ new Map();
|
|
1143
1436
|
this.functionStrategy = functionStrategy || new StandardFunctionStrategy();
|
|
1437
|
+
this.tableFunctionStrategy = tableFunctionStrategy || new StandardTableFunctionStrategy();
|
|
1144
1438
|
this.registerDefaultOperandCompilers();
|
|
1145
1439
|
this.registerDefaultExpressionCompilers();
|
|
1146
1440
|
}
|
|
@@ -1149,7 +1443,7 @@ var Dialect = class _Dialect {
|
|
|
1149
1443
|
* @param functionStrategy - Optional function strategy
|
|
1150
1444
|
* @returns New Dialect instance
|
|
1151
1445
|
*/
|
|
1152
|
-
static create(functionStrategy) {
|
|
1446
|
+
static create(functionStrategy, tableFunctionStrategy) {
|
|
1153
1447
|
class TestDialect extends _Dialect {
|
|
1154
1448
|
constructor() {
|
|
1155
1449
|
super(...arguments);
|
|
@@ -1171,7 +1465,7 @@ var Dialect = class _Dialect {
|
|
|
1171
1465
|
throw new Error("Not implemented");
|
|
1172
1466
|
}
|
|
1173
1467
|
}
|
|
1174
|
-
return new TestDialect(functionStrategy);
|
|
1468
|
+
return new TestDialect(functionStrategy, tableFunctionStrategy);
|
|
1175
1469
|
}
|
|
1176
1470
|
/**
|
|
1177
1471
|
* Registers an expression compiler for a specific node type
|
|
@@ -1272,6 +1566,11 @@ var Dialect = class _Dialect {
|
|
|
1272
1566
|
const right2 = this.compileOperand(arith.right, ctx);
|
|
1273
1567
|
return `${left2} ${arith.operator} ${right2}`;
|
|
1274
1568
|
});
|
|
1569
|
+
this.registerExpressionCompiler("BitwiseExpression", (bitwise, ctx) => {
|
|
1570
|
+
const left2 = this.compileOperand(bitwise.left, ctx);
|
|
1571
|
+
const right2 = this.compileOperand(bitwise.right, ctx);
|
|
1572
|
+
return `${left2} ${bitwise.operator} ${right2}`;
|
|
1573
|
+
});
|
|
1275
1574
|
}
|
|
1276
1575
|
registerDefaultOperandCompilers() {
|
|
1277
1576
|
this.registerOperandCompiler("Literal", (literal, ctx) => ctx.addParameter(literal.value));
|
|
@@ -1341,6 +1640,15 @@ var Dialect = class _Dialect {
|
|
|
1341
1640
|
const right2 = this.compileOperand(node.right, ctx);
|
|
1342
1641
|
return `(${left2} ${node.operator} ${right2})`;
|
|
1343
1642
|
});
|
|
1643
|
+
this.registerOperandCompiler("BitwiseExpression", (node, ctx) => {
|
|
1644
|
+
const left2 = this.compileOperand(node.left, ctx);
|
|
1645
|
+
const right2 = this.compileOperand(node.right, ctx);
|
|
1646
|
+
return `(${left2} ${node.operator} ${right2})`;
|
|
1647
|
+
});
|
|
1648
|
+
this.registerOperandCompiler("Collate", (node, ctx) => {
|
|
1649
|
+
const expr = this.compileOperand(node.expression, ctx);
|
|
1650
|
+
return `${expr} COLLATE ${node.collation}`;
|
|
1651
|
+
});
|
|
1344
1652
|
}
|
|
1345
1653
|
// Default fallback, should be overridden by dialects if supported
|
|
1346
1654
|
compileJsonPath(_node) {
|
|
@@ -1373,13 +1681,13 @@ var FunctionTableFormatter = class {
|
|
|
1373
1681
|
* @param dialect - The dialect instance for compiling operands.
|
|
1374
1682
|
* @returns SQL function table expression (e.g., "LATERAL schema.func(args) WITH ORDINALITY AS alias(col1, col2)").
|
|
1375
1683
|
*/
|
|
1376
|
-
static format(
|
|
1377
|
-
const schemaPart = this.formatSchema(
|
|
1378
|
-
const args = this.formatArgs(
|
|
1379
|
-
const base = this.formatBase(
|
|
1380
|
-
const lateral = this.formatLateral(
|
|
1381
|
-
const alias = this.formatAlias(
|
|
1382
|
-
const colAliases = this.formatColumnAliases(
|
|
1684
|
+
static format(fn8, ctx, dialect) {
|
|
1685
|
+
const schemaPart = this.formatSchema(fn8, dialect);
|
|
1686
|
+
const args = this.formatArgs(fn8, ctx, dialect);
|
|
1687
|
+
const base = this.formatBase(fn8, schemaPart, args);
|
|
1688
|
+
const lateral = this.formatLateral(fn8);
|
|
1689
|
+
const alias = this.formatAlias(fn8, dialect);
|
|
1690
|
+
const colAliases = this.formatColumnAliases(fn8, dialect);
|
|
1383
1691
|
return `${lateral}${base}${alias}${colAliases}`;
|
|
1384
1692
|
}
|
|
1385
1693
|
/**
|
|
@@ -1389,9 +1697,9 @@ var FunctionTableFormatter = class {
|
|
|
1389
1697
|
* @returns Schema prefix (e.g., "schema.") or empty string.
|
|
1390
1698
|
* @internal
|
|
1391
1699
|
*/
|
|
1392
|
-
static formatSchema(
|
|
1393
|
-
if (!
|
|
1394
|
-
const quoted = dialect ? dialect.quoteIdentifier(
|
|
1700
|
+
static formatSchema(fn8, dialect) {
|
|
1701
|
+
if (!fn8.schema) return "";
|
|
1702
|
+
const quoted = dialect ? dialect.quoteIdentifier(fn8.schema) : fn8.schema;
|
|
1395
1703
|
return `${quoted}.`;
|
|
1396
1704
|
}
|
|
1397
1705
|
/**
|
|
@@ -1402,8 +1710,8 @@ var FunctionTableFormatter = class {
|
|
|
1402
1710
|
* @returns Comma-separated function arguments.
|
|
1403
1711
|
* @internal
|
|
1404
1712
|
*/
|
|
1405
|
-
static formatArgs(
|
|
1406
|
-
return (
|
|
1713
|
+
static formatArgs(fn8, ctx, dialect) {
|
|
1714
|
+
return (fn8.args || []).map((a) => {
|
|
1407
1715
|
if (ctx && dialect) {
|
|
1408
1716
|
return dialect.compileOperand(a, ctx);
|
|
1409
1717
|
}
|
|
@@ -1419,10 +1727,9 @@ var FunctionTableFormatter = class {
|
|
|
1419
1727
|
* @returns Base function call expression (e.g., "schema.func(args) WITH ORDINALITY").
|
|
1420
1728
|
* @internal
|
|
1421
1729
|
*/
|
|
1422
|
-
static formatBase(
|
|
1423
|
-
const ordinality =
|
|
1424
|
-
|
|
1425
|
-
return `${schemaPart}${quoted}(${args})${ordinality}`;
|
|
1730
|
+
static formatBase(fn8, schemaPart, args) {
|
|
1731
|
+
const ordinality = fn8.withOrdinality ? " WITH ORDINALITY" : "";
|
|
1732
|
+
return `${schemaPart}${fn8.name}(${args})${ordinality}`;
|
|
1426
1733
|
}
|
|
1427
1734
|
/**
|
|
1428
1735
|
* Formats the LATERAL keyword if present.
|
|
@@ -1430,8 +1737,8 @@ var FunctionTableFormatter = class {
|
|
|
1430
1737
|
* @returns "LATERAL " or empty string.
|
|
1431
1738
|
* @internal
|
|
1432
1739
|
*/
|
|
1433
|
-
static formatLateral(
|
|
1434
|
-
return
|
|
1740
|
+
static formatLateral(fn8) {
|
|
1741
|
+
return fn8.lateral ? "LATERAL " : "";
|
|
1435
1742
|
}
|
|
1436
1743
|
/**
|
|
1437
1744
|
* Formats the table alias for the function table.
|
|
@@ -1440,9 +1747,9 @@ var FunctionTableFormatter = class {
|
|
|
1440
1747
|
* @returns " AS alias" or empty string.
|
|
1441
1748
|
* @internal
|
|
1442
1749
|
*/
|
|
1443
|
-
static formatAlias(
|
|
1444
|
-
if (!
|
|
1445
|
-
const quoted = dialect ? dialect.quoteIdentifier(
|
|
1750
|
+
static formatAlias(fn8, dialect) {
|
|
1751
|
+
if (!fn8.alias) return "";
|
|
1752
|
+
const quoted = dialect ? dialect.quoteIdentifier(fn8.alias) : fn8.alias;
|
|
1446
1753
|
return ` AS ${quoted}`;
|
|
1447
1754
|
}
|
|
1448
1755
|
/**
|
|
@@ -1452,9 +1759,9 @@ var FunctionTableFormatter = class {
|
|
|
1452
1759
|
* @returns "(col1, col2, ...)" or empty string.
|
|
1453
1760
|
* @internal
|
|
1454
1761
|
*/
|
|
1455
|
-
static formatColumnAliases(
|
|
1456
|
-
if (!
|
|
1457
|
-
const aliases =
|
|
1762
|
+
static formatColumnAliases(fn8, dialect) {
|
|
1763
|
+
if (!fn8.columnAliases || !fn8.columnAliases.length) return "";
|
|
1764
|
+
const aliases = fn8.columnAliases.map((col2) => dialect ? dialect.quoteIdentifier(col2) : col2).join(", ");
|
|
1458
1765
|
return `(${aliases})`;
|
|
1459
1766
|
}
|
|
1460
1767
|
};
|
|
@@ -1722,8 +2029,24 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1722
2029
|
}
|
|
1723
2030
|
return this.compileTableSource(tableSource);
|
|
1724
2031
|
}
|
|
1725
|
-
compileFunctionTable(
|
|
1726
|
-
|
|
2032
|
+
compileFunctionTable(fn8, ctx) {
|
|
2033
|
+
const key = fn8.key ?? fn8.name;
|
|
2034
|
+
if (ctx) {
|
|
2035
|
+
const renderer = this.tableFunctionStrategy.getRenderer(key);
|
|
2036
|
+
if (renderer) {
|
|
2037
|
+
const compiledArgs = (fn8.args ?? []).map((arg) => this.compileOperand(arg, ctx));
|
|
2038
|
+
return renderer({
|
|
2039
|
+
node: fn8,
|
|
2040
|
+
compiledArgs,
|
|
2041
|
+
compileOperand: (operand) => this.compileOperand(operand, ctx),
|
|
2042
|
+
quoteIdentifier: this.quoteIdentifier.bind(this)
|
|
2043
|
+
});
|
|
2044
|
+
}
|
|
2045
|
+
if (fn8.key) {
|
|
2046
|
+
throw new Error(`Table function "${key}" is not supported by dialect "${this.dialect}".`);
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
return FunctionTableFormatter.format(fn8, ctx, this);
|
|
1727
2050
|
}
|
|
1728
2051
|
compileDerivedTable(table, ctx) {
|
|
1729
2052
|
if (!table.alias) {
|
|
@@ -1882,6 +2205,76 @@ var PostgresFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
1882
2205
|
const separator = ctx.compileOperand(separatorOperand);
|
|
1883
2206
|
return `STRING_AGG(${arg}, ${separator}${orderSegment})`;
|
|
1884
2207
|
});
|
|
2208
|
+
this.add("CHR", ({ compiledArgs }) => `CHR(${compiledArgs[0]})`);
|
|
2209
|
+
this.add("HOUR", ({ compiledArgs }) => `EXTRACT(HOUR FROM ${compiledArgs[0]})`);
|
|
2210
|
+
this.add("MINUTE", ({ compiledArgs }) => `EXTRACT(MINUTE FROM ${compiledArgs[0]})`);
|
|
2211
|
+
this.add("SECOND", ({ compiledArgs }) => `EXTRACT(SECOND FROM ${compiledArgs[0]})`);
|
|
2212
|
+
this.add("QUARTER", ({ compiledArgs }) => `EXTRACT(QUARTER FROM ${compiledArgs[0]})`);
|
|
2213
|
+
this.add("JSON_LENGTH", ({ compiledArgs }) => {
|
|
2214
|
+
if (compiledArgs.length !== 1) throw new Error("JSON_LENGTH expects 1 argument on PostgreSQL");
|
|
2215
|
+
return `jsonb_array_length(${compiledArgs[0]})`;
|
|
2216
|
+
});
|
|
2217
|
+
this.add("JSON_ARRAYAGG", ({ compiledArgs }) => {
|
|
2218
|
+
if (compiledArgs.length !== 1) throw new Error("JSON_ARRAYAGG expects 1 argument on PostgreSQL");
|
|
2219
|
+
return `jsonb_agg(${compiledArgs[0]})`;
|
|
2220
|
+
});
|
|
2221
|
+
this.add("JSON_CONTAINS", ({ compiledArgs }) => {
|
|
2222
|
+
if (compiledArgs.length !== 2) throw new Error("JSON_CONTAINS expects 2 arguments on PostgreSQL");
|
|
2223
|
+
return `(${compiledArgs[0]}::jsonb @> ${compiledArgs[1]}::jsonb)`;
|
|
2224
|
+
});
|
|
2225
|
+
this.add("ARRAY_APPEND", ({ compiledArgs }) => {
|
|
2226
|
+
if (compiledArgs.length !== 2) throw new Error("ARRAY_APPEND expects 2 arguments on PostgreSQL");
|
|
2227
|
+
return `array_append(${compiledArgs[0]}, ${compiledArgs[1]})`;
|
|
2228
|
+
});
|
|
2229
|
+
this.add("JSON_SET", ({ node, compiledArgs }) => {
|
|
2230
|
+
if (compiledArgs.length !== 3) throw new Error("JSON_SET expects exactly 3 arguments on PostgreSQL");
|
|
2231
|
+
const pathNode = node.args[1];
|
|
2232
|
+
if (pathNode.type !== "Literal") {
|
|
2233
|
+
throw new Error("PostgreSQL JSON_SET currently supports literal paths only");
|
|
2234
|
+
}
|
|
2235
|
+
const pathArray = this.formatJsonbPathArray(pathNode);
|
|
2236
|
+
return `jsonb_set(${compiledArgs[0]}, ${pathArray}, ${compiledArgs[2]}::jsonb, true)`;
|
|
2237
|
+
});
|
|
2238
|
+
}
|
|
2239
|
+
formatJsonbPathArray(pathNode) {
|
|
2240
|
+
const rawPath = String(pathNode.value ?? "");
|
|
2241
|
+
if (!rawPath.startsWith("$")) {
|
|
2242
|
+
throw new Error('PostgreSQL JSON_SET paths must start with "$"');
|
|
2243
|
+
}
|
|
2244
|
+
const trimmed = rawPath === "$" ? "" : rawPath.startsWith("$.") ? rawPath.slice(2) : rawPath.slice(1);
|
|
2245
|
+
if (!trimmed) {
|
|
2246
|
+
throw new Error("PostgreSQL JSON_SET requires a non-root path");
|
|
2247
|
+
}
|
|
2248
|
+
if (trimmed.includes("[") || trimmed.includes("]")) {
|
|
2249
|
+
throw new Error("PostgreSQL JSON_SET currently only supports simple dot-separated paths");
|
|
2250
|
+
}
|
|
2251
|
+
const segments = trimmed.split(".").map((segment) => segment.replace(/^['"]?/, "").replace(/['"]?$/, "").trim()).filter(Boolean);
|
|
2252
|
+
if (!segments.length) {
|
|
2253
|
+
throw new Error("PostgreSQL JSON_SET requires at least one path segment");
|
|
2254
|
+
}
|
|
2255
|
+
const escapedSegments = segments.map((segment) => `'${segment.replace(/'/g, "''")}'`);
|
|
2256
|
+
return `ARRAY[${escapedSegments.join(", ")}]`;
|
|
2257
|
+
}
|
|
2258
|
+
};
|
|
2259
|
+
|
|
2260
|
+
// src/core/dialect/postgres/table-functions.ts
|
|
2261
|
+
var PostgresTableFunctionStrategy = class extends StandardTableFunctionStrategy {
|
|
2262
|
+
constructor() {
|
|
2263
|
+
super();
|
|
2264
|
+
this.registerOverrides();
|
|
2265
|
+
}
|
|
2266
|
+
registerOverrides() {
|
|
2267
|
+
this.add("ARRAY_UNNEST", ({ node, compiledArgs, quoteIdentifier }) => {
|
|
2268
|
+
const lateral = node.lateral ?? true;
|
|
2269
|
+
const withOrd = node.withOrdinality ?? false;
|
|
2270
|
+
const base = `unnest(${compiledArgs.join(", ")})${withOrd ? " WITH ORDINALITY" : ""}`;
|
|
2271
|
+
if (node.columnAliases?.length && !node.alias) {
|
|
2272
|
+
throw new Error("tvf(ARRAY_UNNEST) with columnAliases requires an alias.");
|
|
2273
|
+
}
|
|
2274
|
+
const alias = node.alias ? ` AS ${quoteIdentifier(node.alias)}` : "";
|
|
2275
|
+
const cols = node.columnAliases?.length ? `(${node.columnAliases.map(quoteIdentifier).join(", ")})` : "";
|
|
2276
|
+
return `${lateral ? "LATERAL " : ""}${base}${alias}${cols}`;
|
|
2277
|
+
});
|
|
1885
2278
|
}
|
|
1886
2279
|
};
|
|
1887
2280
|
|
|
@@ -1891,8 +2284,20 @@ var PostgresDialect = class extends SqlDialectBase {
|
|
|
1891
2284
|
* Creates a new PostgresDialect instance
|
|
1892
2285
|
*/
|
|
1893
2286
|
constructor() {
|
|
1894
|
-
super(new PostgresFunctionStrategy());
|
|
2287
|
+
super(new PostgresFunctionStrategy(), new PostgresTableFunctionStrategy());
|
|
1895
2288
|
this.dialect = "postgres";
|
|
2289
|
+
this.registerExpressionCompiler("BitwiseExpression", (node, ctx) => {
|
|
2290
|
+
const left2 = this.compileOperand(node.left, ctx);
|
|
2291
|
+
const right2 = this.compileOperand(node.right, ctx);
|
|
2292
|
+
const op = node.operator === "^" ? "#" : node.operator;
|
|
2293
|
+
return `${left2} ${op} ${right2}`;
|
|
2294
|
+
});
|
|
2295
|
+
this.registerOperandCompiler("BitwiseExpression", (node, ctx) => {
|
|
2296
|
+
const left2 = this.compileOperand(node.left, ctx);
|
|
2297
|
+
const right2 = this.compileOperand(node.right, ctx);
|
|
2298
|
+
const op = node.operator === "^" ? "#" : node.operator;
|
|
2299
|
+
return `(${left2} ${op} ${right2})`;
|
|
2300
|
+
});
|
|
1896
2301
|
}
|
|
1897
2302
|
/**
|
|
1898
2303
|
* Quotes an identifier using PostgreSQL double-quote syntax
|
|
@@ -2001,6 +2406,14 @@ var MysqlFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
2001
2406
|
}
|
|
2002
2407
|
return `DATE(${date})`;
|
|
2003
2408
|
});
|
|
2409
|
+
this.add("HOUR", ({ compiledArgs }) => `HOUR(${compiledArgs[0]})`);
|
|
2410
|
+
this.add("MINUTE", ({ compiledArgs }) => `MINUTE(${compiledArgs[0]})`);
|
|
2411
|
+
this.add("SECOND", ({ compiledArgs }) => `SECOND(${compiledArgs[0]})`);
|
|
2412
|
+
this.add("QUARTER", ({ compiledArgs }) => `QUARTER(${compiledArgs[0]})`);
|
|
2413
|
+
this.add("ARRAY_APPEND", ({ compiledArgs }) => {
|
|
2414
|
+
if (compiledArgs.length !== 2) throw new Error("ARRAY_APPEND expects 2 arguments (array, value)");
|
|
2415
|
+
return `JSON_ARRAY_APPEND(${compiledArgs[0]}, '$', ${compiledArgs[1]})`;
|
|
2416
|
+
});
|
|
2004
2417
|
}
|
|
2005
2418
|
};
|
|
2006
2419
|
|
|
@@ -2133,6 +2546,30 @@ var SqliteFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
2133
2546
|
const separator = ctx.compileOperand(separatorOperand);
|
|
2134
2547
|
return `GROUP_CONCAT(${arg}, ${separator})`;
|
|
2135
2548
|
});
|
|
2549
|
+
this.add("HOUR", ({ compiledArgs }) => `CAST(strftime('%H', ${compiledArgs[0]}) AS INTEGER)`);
|
|
2550
|
+
this.add("MINUTE", ({ compiledArgs }) => `CAST(strftime('%M', ${compiledArgs[0]}) AS INTEGER)`);
|
|
2551
|
+
this.add("SECOND", ({ compiledArgs }) => `CAST(strftime('%S', ${compiledArgs[0]}) AS INTEGER)`);
|
|
2552
|
+
this.add("QUARTER", ({ compiledArgs }) => `((CAST(strftime('%m', ${compiledArgs[0]}) AS INTEGER) + 2) / 3)`);
|
|
2553
|
+
this.add("JSON_LENGTH", ({ compiledArgs }) => {
|
|
2554
|
+
if (compiledArgs.length === 0 || compiledArgs.length > 2) {
|
|
2555
|
+
throw new Error("JSON_LENGTH expects 1 or 2 arguments on SQLite");
|
|
2556
|
+
}
|
|
2557
|
+
return `json_array_length(${compiledArgs.join(", ")})`;
|
|
2558
|
+
});
|
|
2559
|
+
this.add("JSON_ARRAYAGG", ({ compiledArgs }) => {
|
|
2560
|
+
if (compiledArgs.length !== 1) {
|
|
2561
|
+
throw new Error("JSON_ARRAYAGG expects 1 argument on SQLite");
|
|
2562
|
+
}
|
|
2563
|
+
return `json_group_array(${compiledArgs[0]})`;
|
|
2564
|
+
});
|
|
2565
|
+
this.add("JSON_CONTAINS", () => {
|
|
2566
|
+
throw new Error("JSON_CONTAINS is not supported on SQLite");
|
|
2567
|
+
});
|
|
2568
|
+
this.add("ARRAY_APPEND", ({ compiledArgs }) => {
|
|
2569
|
+
if (compiledArgs.length !== 2) throw new Error("ARRAY_APPEND expects 2 arguments (array, value)");
|
|
2570
|
+
return `json_array_append(${compiledArgs[0]}, '$', ${compiledArgs[1]})`;
|
|
2571
|
+
});
|
|
2572
|
+
this.add("CHR", ({ compiledArgs }) => `CHAR(${compiledArgs[0]})`);
|
|
2136
2573
|
}
|
|
2137
2574
|
};
|
|
2138
2575
|
|
|
@@ -2144,6 +2581,22 @@ var SqliteDialect = class extends SqlDialectBase {
|
|
|
2144
2581
|
constructor() {
|
|
2145
2582
|
super(new SqliteFunctionStrategy());
|
|
2146
2583
|
this.dialect = "sqlite";
|
|
2584
|
+
this.registerExpressionCompiler("BitwiseExpression", (node, ctx) => {
|
|
2585
|
+
const left2 = this.compileOperand(node.left, ctx);
|
|
2586
|
+
const right2 = this.compileOperand(node.right, ctx);
|
|
2587
|
+
if (node.operator === "^") {
|
|
2588
|
+
return `(${left2} | ${right2}) & ~(${left2} & ${right2})`;
|
|
2589
|
+
}
|
|
2590
|
+
return `${left2} ${node.operator} ${right2}`;
|
|
2591
|
+
});
|
|
2592
|
+
this.registerOperandCompiler("BitwiseExpression", (node, ctx) => {
|
|
2593
|
+
const left2 = this.compileOperand(node.left, ctx);
|
|
2594
|
+
const right2 = this.compileOperand(node.right, ctx);
|
|
2595
|
+
if (node.operator === "^") {
|
|
2596
|
+
return `((${left2} | ${right2}) & ~(${left2} & ${right2}))`;
|
|
2597
|
+
}
|
|
2598
|
+
return `(${left2} ${node.operator} ${right2})`;
|
|
2599
|
+
});
|
|
2147
2600
|
}
|
|
2148
2601
|
/**
|
|
2149
2602
|
* Quotes an identifier using SQLite double-quote syntax
|
|
@@ -2268,6 +2721,33 @@ var MssqlFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
2268
2721
|
const withinGroup = orderClause ? ` WITHIN GROUP (${orderClause})` : "";
|
|
2269
2722
|
return `STRING_AGG(${arg}, ${separator})${withinGroup}`;
|
|
2270
2723
|
});
|
|
2724
|
+
this.add("LENGTH", ({ compiledArgs }) => `LEN(${compiledArgs[0]})`);
|
|
2725
|
+
this.add("CHAR_LENGTH", ({ compiledArgs }) => `LEN(${compiledArgs[0]})`);
|
|
2726
|
+
this.add("CHARACTER_LENGTH", ({ compiledArgs }) => `LEN(${compiledArgs[0]})`);
|
|
2727
|
+
this.add("POSITION", ({ compiledArgs }) => `CHARINDEX(${compiledArgs[0]}, ${compiledArgs[1]})`);
|
|
2728
|
+
this.add("LOCATE", ({ compiledArgs }) => compiledArgs.length === 3 ? `CHARINDEX(${compiledArgs[0]}, ${compiledArgs[1]}, ${compiledArgs[2]})` : `CHARINDEX(${compiledArgs[0]}, ${compiledArgs[1]})`);
|
|
2729
|
+
this.add("INSTR", ({ compiledArgs }) => `CHARINDEX(${compiledArgs[1]}, ${compiledArgs[0]})`);
|
|
2730
|
+
this.add("CHR", ({ compiledArgs }) => `CHAR(${compiledArgs[0]})`);
|
|
2731
|
+
this.add("HOUR", ({ compiledArgs }) => `DATEPART(hour, ${compiledArgs[0]})`);
|
|
2732
|
+
this.add("MINUTE", ({ compiledArgs }) => `DATEPART(minute, ${compiledArgs[0]})`);
|
|
2733
|
+
this.add("SECOND", ({ compiledArgs }) => `DATEPART(second, ${compiledArgs[0]})`);
|
|
2734
|
+
this.add("QUARTER", ({ compiledArgs }) => `DATEPART(quarter, ${compiledArgs[0]})`);
|
|
2735
|
+
this.add("JSON_SET", ({ compiledArgs }) => {
|
|
2736
|
+
if (compiledArgs.length !== 3) throw new Error("JSON_SET expects 3 arguments on SQL Server");
|
|
2737
|
+
return `JSON_MODIFY(${compiledArgs[0]}, ${compiledArgs[1]}, ${compiledArgs[2]})`;
|
|
2738
|
+
});
|
|
2739
|
+
this.add("JSON_LENGTH", () => {
|
|
2740
|
+
throw new Error("JSON_LENGTH is not supported on SQL Server");
|
|
2741
|
+
});
|
|
2742
|
+
this.add("JSON_ARRAYAGG", () => {
|
|
2743
|
+
throw new Error("JSON_ARRAYAGG is not supported on SQL Server");
|
|
2744
|
+
});
|
|
2745
|
+
this.add("JSON_CONTAINS", () => {
|
|
2746
|
+
throw new Error("JSON_CONTAINS is not supported on SQL Server");
|
|
2747
|
+
});
|
|
2748
|
+
this.add("ARRAY_APPEND", () => {
|
|
2749
|
+
throw new Error("ARRAY_APPEND is not supported on SQL Server");
|
|
2750
|
+
});
|
|
2271
2751
|
}
|
|
2272
2752
|
};
|
|
2273
2753
|
|
|
@@ -3372,20 +3852,21 @@ var RelationProjectionHelper = class {
|
|
|
3372
3852
|
var assertNever = (value) => {
|
|
3373
3853
|
throw new Error(`Unhandled relation type: ${JSON.stringify(value)}`);
|
|
3374
3854
|
};
|
|
3375
|
-
var baseRelationCondition = (root, relation, rootAlias) => {
|
|
3855
|
+
var baseRelationCondition = (root, relation, rootAlias, targetTableName) => {
|
|
3376
3856
|
const rootTable = rootAlias || root.name;
|
|
3857
|
+
const targetTable = targetTableName ?? relation.target.name;
|
|
3377
3858
|
const defaultLocalKey = relation.type === RelationKinds.HasMany || relation.type === RelationKinds.HasOne ? findPrimaryKey(root) : findPrimaryKey(relation.target);
|
|
3378
3859
|
const localKey = relation.localKey || defaultLocalKey;
|
|
3379
3860
|
switch (relation.type) {
|
|
3380
3861
|
case RelationKinds.HasMany:
|
|
3381
3862
|
case RelationKinds.HasOne:
|
|
3382
3863
|
return eq(
|
|
3383
|
-
{ type: "Column", table:
|
|
3864
|
+
{ type: "Column", table: targetTable, name: relation.foreignKey },
|
|
3384
3865
|
{ type: "Column", table: rootTable, name: localKey }
|
|
3385
3866
|
);
|
|
3386
3867
|
case RelationKinds.BelongsTo:
|
|
3387
3868
|
return eq(
|
|
3388
|
-
{ type: "Column", table:
|
|
3869
|
+
{ type: "Column", table: targetTable, name: localKey },
|
|
3389
3870
|
{ type: "Column", table: rootTable, name: relation.foreignKey }
|
|
3390
3871
|
);
|
|
3391
3872
|
case RelationKinds.BelongsToMany:
|
|
@@ -3394,7 +3875,7 @@ var baseRelationCondition = (root, relation, rootAlias) => {
|
|
|
3394
3875
|
return assertNever(relation);
|
|
3395
3876
|
}
|
|
3396
3877
|
};
|
|
3397
|
-
var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra, rootAlias) => {
|
|
3878
|
+
var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra, rootAlias, targetTable, targetTableName) => {
|
|
3398
3879
|
const rootKey = relation.localKey || findPrimaryKey(root);
|
|
3399
3880
|
const targetKey = relation.targetKey || findPrimaryKey(relation.target);
|
|
3400
3881
|
const rootTable = rootAlias || root.name;
|
|
@@ -3407,8 +3888,14 @@ var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra, ro
|
|
|
3407
3888
|
{ type: "Table", name: relation.pivotTable.name, schema: relation.pivotTable.schema },
|
|
3408
3889
|
pivotCondition
|
|
3409
3890
|
);
|
|
3891
|
+
const targetSource = targetTable ?? {
|
|
3892
|
+
type: "Table",
|
|
3893
|
+
name: relation.target.name,
|
|
3894
|
+
schema: relation.target.schema
|
|
3895
|
+
};
|
|
3896
|
+
const effectiveTargetName = targetTableName ?? relation.target.name;
|
|
3410
3897
|
let targetCondition = eq(
|
|
3411
|
-
{ type: "Column", table:
|
|
3898
|
+
{ type: "Column", table: effectiveTargetName, name: targetKey },
|
|
3412
3899
|
{ type: "Column", table: relation.pivotTable.name, name: relation.pivotForeignKeyToTarget }
|
|
3413
3900
|
);
|
|
3414
3901
|
if (extra) {
|
|
@@ -3416,24 +3903,25 @@ var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra, ro
|
|
|
3416
3903
|
}
|
|
3417
3904
|
const targetJoin = createJoinNode(
|
|
3418
3905
|
joinKind,
|
|
3419
|
-
|
|
3906
|
+
targetSource,
|
|
3420
3907
|
targetCondition,
|
|
3421
3908
|
relationName
|
|
3422
3909
|
);
|
|
3423
3910
|
return [pivotJoin, targetJoin];
|
|
3424
3911
|
};
|
|
3425
|
-
var buildRelationJoinCondition = (root, relation, extra, rootAlias) => {
|
|
3426
|
-
const base = baseRelationCondition(root, relation, rootAlias);
|
|
3912
|
+
var buildRelationJoinCondition = (root, relation, extra, rootAlias, targetTableName) => {
|
|
3913
|
+
const base = baseRelationCondition(root, relation, rootAlias, targetTableName);
|
|
3427
3914
|
return extra ? and(base, extra) : base;
|
|
3428
3915
|
};
|
|
3429
|
-
var buildRelationCorrelation = (root, relation, rootAlias) => {
|
|
3430
|
-
return baseRelationCondition(root, relation, rootAlias);
|
|
3916
|
+
var buildRelationCorrelation = (root, relation, rootAlias, targetTableName) => {
|
|
3917
|
+
return baseRelationCondition(root, relation, rootAlias, targetTableName);
|
|
3431
3918
|
};
|
|
3432
3919
|
|
|
3433
3920
|
// src/core/ast/join-metadata.ts
|
|
3434
3921
|
var getJoinRelationName = (join) => join.meta?.relationName;
|
|
3435
3922
|
|
|
3436
3923
|
// src/query-builder/relation-service.ts
|
|
3924
|
+
var hasRelationForeignKey = (relation) => relation.type !== RelationKinds.BelongsToMany;
|
|
3437
3925
|
var RelationService = class {
|
|
3438
3926
|
/**
|
|
3439
3927
|
* Creates a new RelationService instance
|
|
@@ -3458,8 +3946,8 @@ var RelationService = class {
|
|
|
3458
3946
|
* @param extraCondition - Additional join condition
|
|
3459
3947
|
* @returns Relation result with updated state and hydration
|
|
3460
3948
|
*/
|
|
3461
|
-
joinRelation(relationName, joinKind, extraCondition) {
|
|
3462
|
-
const nextState = this.withJoin(this.state, relationName, joinKind, extraCondition);
|
|
3949
|
+
joinRelation(relationName, joinKind, extraCondition, tableSource) {
|
|
3950
|
+
const nextState = this.withJoin(this.state, relationName, joinKind, extraCondition, tableSource);
|
|
3463
3951
|
return { state: nextState, hydration: this.hydration };
|
|
3464
3952
|
}
|
|
3465
3953
|
/**
|
|
@@ -3488,14 +3976,58 @@ var RelationService = class {
|
|
|
3488
3976
|
const relation = this.getRelation(relationName);
|
|
3489
3977
|
const aliasPrefix = options?.aliasPrefix ?? relationName;
|
|
3490
3978
|
const alreadyJoined = state.ast.joins.some((j) => getJoinRelationName(j) === relationName);
|
|
3979
|
+
const { selfFilters, crossFilters } = this.splitFilterExpressions(
|
|
3980
|
+
options?.filter,
|
|
3981
|
+
/* @__PURE__ */ new Set([relation.target.name])
|
|
3982
|
+
);
|
|
3983
|
+
const canUseCte = !alreadyJoined && selfFilters.length > 0;
|
|
3984
|
+
const joinFilters = [...crossFilters];
|
|
3985
|
+
if (!canUseCte) {
|
|
3986
|
+
joinFilters.push(...selfFilters);
|
|
3987
|
+
}
|
|
3988
|
+
const joinCondition = this.combineWithAnd(joinFilters);
|
|
3989
|
+
let tableSourceOverride;
|
|
3990
|
+
if (canUseCte) {
|
|
3991
|
+
const cteInfo = this.createFilteredRelationCte(state, relationName, relation, selfFilters);
|
|
3992
|
+
state = cteInfo.state;
|
|
3993
|
+
tableSourceOverride = cteInfo.table;
|
|
3994
|
+
}
|
|
3491
3995
|
if (!alreadyJoined) {
|
|
3492
|
-
|
|
3493
|
-
|
|
3996
|
+
state = this.withJoin(
|
|
3997
|
+
state,
|
|
3998
|
+
relationName,
|
|
3999
|
+
options?.joinKind ?? JOIN_KINDS.LEFT,
|
|
4000
|
+
joinCondition,
|
|
4001
|
+
tableSourceOverride
|
|
4002
|
+
);
|
|
3494
4003
|
}
|
|
3495
4004
|
const projectionResult = this.projectionHelper.ensureBaseProjection(state, hydration);
|
|
3496
4005
|
state = projectionResult.state;
|
|
3497
4006
|
hydration = projectionResult.hydration;
|
|
3498
|
-
|
|
4007
|
+
if (hasRelationForeignKey(relation)) {
|
|
4008
|
+
const fkColumn = this.table.columns[relation.foreignKey];
|
|
4009
|
+
if (fkColumn) {
|
|
4010
|
+
const hasForeignKeySelected = state.ast.columns.some((col2) => {
|
|
4011
|
+
if (col2.type !== "Column") return false;
|
|
4012
|
+
const node = col2;
|
|
4013
|
+
const alias = node.alias ?? node.name;
|
|
4014
|
+
return alias === relation.foreignKey;
|
|
4015
|
+
});
|
|
4016
|
+
if (!hasForeignKeySelected) {
|
|
4017
|
+
const fkSelectionResult = this.selectColumns(state, hydration, {
|
|
4018
|
+
[relation.foreignKey]: fkColumn
|
|
4019
|
+
});
|
|
4020
|
+
state = fkSelectionResult.state;
|
|
4021
|
+
hydration = fkSelectionResult.hydration;
|
|
4022
|
+
}
|
|
4023
|
+
}
|
|
4024
|
+
}
|
|
4025
|
+
const requestedColumns = options?.columns?.length ? [...options.columns] : Object.keys(relation.target.columns);
|
|
4026
|
+
const targetPrimaryKey = findPrimaryKey(relation.target);
|
|
4027
|
+
if (!requestedColumns.includes(targetPrimaryKey)) {
|
|
4028
|
+
requestedColumns.push(targetPrimaryKey);
|
|
4029
|
+
}
|
|
4030
|
+
const targetColumns = requestedColumns;
|
|
3499
4031
|
const buildTypedSelection = (columns, prefix, keys, missingMsg) => {
|
|
3500
4032
|
return keys.reduce((acc, key) => {
|
|
3501
4033
|
const def = columns[key];
|
|
@@ -3579,27 +4111,42 @@ var RelationService = class {
|
|
|
3579
4111
|
* @param extraCondition - Additional join condition
|
|
3580
4112
|
* @returns Updated query state with join
|
|
3581
4113
|
*/
|
|
3582
|
-
withJoin(state, relationName, joinKind, extraCondition) {
|
|
4114
|
+
withJoin(state, relationName, joinKind, extraCondition, tableSource) {
|
|
3583
4115
|
const relation = this.getRelation(relationName);
|
|
3584
4116
|
const rootAlias = state.ast.from.type === "Table" ? state.ast.from.alias : void 0;
|
|
3585
4117
|
if (relation.type === RelationKinds.BelongsToMany) {
|
|
4118
|
+
const targetTableSource = tableSource ?? {
|
|
4119
|
+
type: "Table",
|
|
4120
|
+
name: relation.target.name,
|
|
4121
|
+
schema: relation.target.schema
|
|
4122
|
+
};
|
|
4123
|
+
const targetName2 = this.resolveTargetTableName(targetTableSource, relation);
|
|
3586
4124
|
const joins = buildBelongsToManyJoins(
|
|
3587
4125
|
this.table,
|
|
3588
4126
|
relationName,
|
|
3589
4127
|
relation,
|
|
3590
4128
|
joinKind,
|
|
3591
4129
|
extraCondition,
|
|
3592
|
-
rootAlias
|
|
4130
|
+
rootAlias,
|
|
4131
|
+
targetTableSource,
|
|
4132
|
+
targetName2
|
|
3593
4133
|
);
|
|
3594
4134
|
return joins.reduce((current, join) => this.astService(current).withJoin(join), state);
|
|
3595
4135
|
}
|
|
3596
|
-
const
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
4136
|
+
const targetTable = tableSource ?? {
|
|
4137
|
+
type: "Table",
|
|
4138
|
+
name: relation.target.name,
|
|
4139
|
+
schema: relation.target.schema
|
|
4140
|
+
};
|
|
4141
|
+
const targetName = this.resolveTargetTableName(targetTable, relation);
|
|
4142
|
+
const condition = buildRelationJoinCondition(
|
|
4143
|
+
this.table,
|
|
4144
|
+
relation,
|
|
4145
|
+
extraCondition,
|
|
4146
|
+
rootAlias,
|
|
4147
|
+
targetName
|
|
3602
4148
|
);
|
|
4149
|
+
const joinNode = createJoinNode(joinKind, targetTable, condition, relationName);
|
|
3603
4150
|
return this.astService(state).withJoin(joinNode);
|
|
3604
4151
|
}
|
|
3605
4152
|
/**
|
|
@@ -3616,6 +4163,198 @@ var RelationService = class {
|
|
|
3616
4163
|
hydration: hydration.onColumnsSelected(nextState, addedColumns)
|
|
3617
4164
|
};
|
|
3618
4165
|
}
|
|
4166
|
+
combineWithAnd(expressions) {
|
|
4167
|
+
if (expressions.length === 0) return void 0;
|
|
4168
|
+
if (expressions.length === 1) return expressions[0];
|
|
4169
|
+
return {
|
|
4170
|
+
type: "LogicalExpression",
|
|
4171
|
+
operator: "AND",
|
|
4172
|
+
operands: expressions
|
|
4173
|
+
};
|
|
4174
|
+
}
|
|
4175
|
+
splitFilterExpressions(filter, allowedTables) {
|
|
4176
|
+
const terms = this.flattenAnd(filter);
|
|
4177
|
+
const selfFilters = [];
|
|
4178
|
+
const crossFilters = [];
|
|
4179
|
+
for (const term of terms) {
|
|
4180
|
+
if (this.isExpressionSelfContained(term, allowedTables)) {
|
|
4181
|
+
selfFilters.push(term);
|
|
4182
|
+
} else {
|
|
4183
|
+
crossFilters.push(term);
|
|
4184
|
+
}
|
|
4185
|
+
}
|
|
4186
|
+
return { selfFilters, crossFilters };
|
|
4187
|
+
}
|
|
4188
|
+
flattenAnd(node) {
|
|
4189
|
+
if (!node) return [];
|
|
4190
|
+
if (node.type === "LogicalExpression" && node.operator === "AND") {
|
|
4191
|
+
return node.operands.flatMap((operand) => this.flattenAnd(operand));
|
|
4192
|
+
}
|
|
4193
|
+
return [node];
|
|
4194
|
+
}
|
|
4195
|
+
isExpressionSelfContained(expr, allowedTables) {
|
|
4196
|
+
const collector = this.collectReferencedTables(expr);
|
|
4197
|
+
if (collector.hasSubquery) return false;
|
|
4198
|
+
if (collector.tables.size === 0) return true;
|
|
4199
|
+
for (const table of collector.tables) {
|
|
4200
|
+
if (!allowedTables.has(table)) {
|
|
4201
|
+
return false;
|
|
4202
|
+
}
|
|
4203
|
+
}
|
|
4204
|
+
return true;
|
|
4205
|
+
}
|
|
4206
|
+
collectReferencedTables(expr) {
|
|
4207
|
+
const collector = {
|
|
4208
|
+
tables: /* @__PURE__ */ new Set(),
|
|
4209
|
+
hasSubquery: false
|
|
4210
|
+
};
|
|
4211
|
+
this.collectFromExpression(expr, collector);
|
|
4212
|
+
return collector;
|
|
4213
|
+
}
|
|
4214
|
+
collectFromExpression(expr, collector) {
|
|
4215
|
+
switch (expr.type) {
|
|
4216
|
+
case "BinaryExpression":
|
|
4217
|
+
this.collectFromOperand(expr.left, collector);
|
|
4218
|
+
this.collectFromOperand(expr.right, collector);
|
|
4219
|
+
break;
|
|
4220
|
+
case "LogicalExpression":
|
|
4221
|
+
expr.operands.forEach((operand) => this.collectFromExpression(operand, collector));
|
|
4222
|
+
break;
|
|
4223
|
+
case "NullExpression":
|
|
4224
|
+
this.collectFromOperand(expr.left, collector);
|
|
4225
|
+
break;
|
|
4226
|
+
case "InExpression":
|
|
4227
|
+
this.collectFromOperand(expr.left, collector);
|
|
4228
|
+
if (Array.isArray(expr.right)) {
|
|
4229
|
+
expr.right.forEach((value) => this.collectFromOperand(value, collector));
|
|
4230
|
+
} else {
|
|
4231
|
+
collector.hasSubquery = true;
|
|
4232
|
+
}
|
|
4233
|
+
break;
|
|
4234
|
+
case "ExistsExpression":
|
|
4235
|
+
collector.hasSubquery = true;
|
|
4236
|
+
break;
|
|
4237
|
+
case "BetweenExpression":
|
|
4238
|
+
this.collectFromOperand(expr.left, collector);
|
|
4239
|
+
this.collectFromOperand(expr.lower, collector);
|
|
4240
|
+
this.collectFromOperand(expr.upper, collector);
|
|
4241
|
+
break;
|
|
4242
|
+
case "ArithmeticExpression":
|
|
4243
|
+
case "BitwiseExpression":
|
|
4244
|
+
this.collectFromOperand(expr.left, collector);
|
|
4245
|
+
this.collectFromOperand(expr.right, collector);
|
|
4246
|
+
break;
|
|
4247
|
+
default:
|
|
4248
|
+
break;
|
|
4249
|
+
}
|
|
4250
|
+
}
|
|
4251
|
+
collectFromOperand(node, collector) {
|
|
4252
|
+
switch (node.type) {
|
|
4253
|
+
case "Column":
|
|
4254
|
+
collector.tables.add(node.table);
|
|
4255
|
+
break;
|
|
4256
|
+
case "Function":
|
|
4257
|
+
node.args.forEach((arg) => this.collectFromOperand(arg, collector));
|
|
4258
|
+
if (node.separator) {
|
|
4259
|
+
this.collectFromOperand(node.separator, collector);
|
|
4260
|
+
}
|
|
4261
|
+
if (node.orderBy) {
|
|
4262
|
+
node.orderBy.forEach((order) => this.collectFromOrderingTerm(order.term, collector));
|
|
4263
|
+
}
|
|
4264
|
+
break;
|
|
4265
|
+
case "JsonPath":
|
|
4266
|
+
this.collectFromOperand(node.column, collector);
|
|
4267
|
+
break;
|
|
4268
|
+
case "ScalarSubquery":
|
|
4269
|
+
collector.hasSubquery = true;
|
|
4270
|
+
break;
|
|
4271
|
+
case "CaseExpression":
|
|
4272
|
+
node.conditions.forEach(({ when, then }) => {
|
|
4273
|
+
this.collectFromExpression(when, collector);
|
|
4274
|
+
this.collectFromOperand(then, collector);
|
|
4275
|
+
});
|
|
4276
|
+
if (node.else) {
|
|
4277
|
+
this.collectFromOperand(node.else, collector);
|
|
4278
|
+
}
|
|
4279
|
+
break;
|
|
4280
|
+
case "Cast":
|
|
4281
|
+
this.collectFromOperand(node.expression, collector);
|
|
4282
|
+
break;
|
|
4283
|
+
case "WindowFunction":
|
|
4284
|
+
node.args.forEach((arg) => this.collectFromOperand(arg, collector));
|
|
4285
|
+
node.partitionBy?.forEach((part) => this.collectFromOperand(part, collector));
|
|
4286
|
+
node.orderBy?.forEach((order) => this.collectFromOrderingTerm(order.term, collector));
|
|
4287
|
+
break;
|
|
4288
|
+
case "Collate":
|
|
4289
|
+
this.collectFromOperand(node.expression, collector);
|
|
4290
|
+
break;
|
|
4291
|
+
case "ArithmeticExpression":
|
|
4292
|
+
case "BitwiseExpression":
|
|
4293
|
+
this.collectFromOperand(node.left, collector);
|
|
4294
|
+
this.collectFromOperand(node.right, collector);
|
|
4295
|
+
break;
|
|
4296
|
+
case "Literal":
|
|
4297
|
+
case "AliasRef":
|
|
4298
|
+
break;
|
|
4299
|
+
default:
|
|
4300
|
+
break;
|
|
4301
|
+
}
|
|
4302
|
+
}
|
|
4303
|
+
collectFromOrderingTerm(term, collector) {
|
|
4304
|
+
if (isOperandNode(term)) {
|
|
4305
|
+
this.collectFromOperand(term, collector);
|
|
4306
|
+
return;
|
|
4307
|
+
}
|
|
4308
|
+
this.collectFromExpression(term, collector);
|
|
4309
|
+
}
|
|
4310
|
+
createFilteredRelationCte(state, relationName, relation, filters) {
|
|
4311
|
+
const cteName = this.generateUniqueCteName(state, relationName);
|
|
4312
|
+
const predicate = this.combineWithAnd(filters);
|
|
4313
|
+
if (!predicate) {
|
|
4314
|
+
throw new Error("Unable to build filter CTE without predicates.");
|
|
4315
|
+
}
|
|
4316
|
+
const columns = Object.keys(relation.target.columns).map((name) => ({
|
|
4317
|
+
type: "Column",
|
|
4318
|
+
table: relation.target.name,
|
|
4319
|
+
name
|
|
4320
|
+
}));
|
|
4321
|
+
const cteQuery = {
|
|
4322
|
+
type: "SelectQuery",
|
|
4323
|
+
from: { type: "Table", name: relation.target.name, schema: relation.target.schema },
|
|
4324
|
+
columns,
|
|
4325
|
+
joins: [],
|
|
4326
|
+
where: predicate
|
|
4327
|
+
};
|
|
4328
|
+
const nextState = this.astService(state).withCte(cteName, cteQuery);
|
|
4329
|
+
const tableNode3 = {
|
|
4330
|
+
type: "Table",
|
|
4331
|
+
name: cteName,
|
|
4332
|
+
alias: relation.target.name
|
|
4333
|
+
};
|
|
4334
|
+
return { state: nextState, table: tableNode3 };
|
|
4335
|
+
}
|
|
4336
|
+
generateUniqueCteName(state, relationName) {
|
|
4337
|
+
const existing = new Set((state.ast.ctes ?? []).map((cte) => cte.name));
|
|
4338
|
+
let candidate = `${relationName}__filtered`;
|
|
4339
|
+
let suffix = 1;
|
|
4340
|
+
while (existing.has(candidate)) {
|
|
4341
|
+
candidate = `${relationName}__filtered_${suffix}`;
|
|
4342
|
+
suffix += 1;
|
|
4343
|
+
}
|
|
4344
|
+
return candidate;
|
|
4345
|
+
}
|
|
4346
|
+
resolveTargetTableName(target, relation) {
|
|
4347
|
+
if (target.type === "Table") {
|
|
4348
|
+
return target.alias ?? target.name;
|
|
4349
|
+
}
|
|
4350
|
+
if (target.type === "DerivedTable") {
|
|
4351
|
+
return target.alias;
|
|
4352
|
+
}
|
|
4353
|
+
if (target.type === "FunctionTable") {
|
|
4354
|
+
return target.alias ?? relation.target.name;
|
|
4355
|
+
}
|
|
4356
|
+
return relation.target.name;
|
|
4357
|
+
}
|
|
3619
4358
|
/**
|
|
3620
4359
|
* Gets a relation definition by name
|
|
3621
4360
|
* @param relationName - Name of the relation
|
|
@@ -3966,6 +4705,18 @@ var DefaultHasManyCollection = class {
|
|
|
3966
4705
|
getItems() {
|
|
3967
4706
|
return this.items;
|
|
3968
4707
|
}
|
|
4708
|
+
/**
|
|
4709
|
+
* Array-compatible length for testing frameworks.
|
|
4710
|
+
*/
|
|
4711
|
+
get length() {
|
|
4712
|
+
return this.items.length;
|
|
4713
|
+
}
|
|
4714
|
+
/**
|
|
4715
|
+
* Enables iteration over the collection like an array.
|
|
4716
|
+
*/
|
|
4717
|
+
[Symbol.iterator]() {
|
|
4718
|
+
return this.items[Symbol.iterator]();
|
|
4719
|
+
}
|
|
3969
4720
|
/**
|
|
3970
4721
|
* Adds a new child entity to the collection.
|
|
3971
4722
|
* @param data - Partial data for the new entity
|
|
@@ -4065,6 +4816,17 @@ var hideInternal2 = (obj, keys) => {
|
|
|
4065
4816
|
}
|
|
4066
4817
|
};
|
|
4067
4818
|
var DefaultHasOneReference = class {
|
|
4819
|
+
/**
|
|
4820
|
+
* @param ctx The entity context for tracking changes.
|
|
4821
|
+
* @param meta Metadata for the parent entity.
|
|
4822
|
+
* @param root The parent entity instance.
|
|
4823
|
+
* @param relationName The name of the relation.
|
|
4824
|
+
* @param relation Relation definition.
|
|
4825
|
+
* @param rootTable Table definition of the parent entity.
|
|
4826
|
+
* @param loader Function to load the child entity.
|
|
4827
|
+
* @param createEntity Function to create entity instances from rows.
|
|
4828
|
+
* @param localKey The local key on the parent entity used for the relation.
|
|
4829
|
+
*/
|
|
4068
4830
|
constructor(ctx, meta, root, relationName, relation, rootTable, loader, createEntity, localKey) {
|
|
4069
4831
|
this.ctx = ctx;
|
|
4070
4832
|
this.meta = meta;
|
|
@@ -4182,6 +4944,17 @@ var hideInternal3 = (obj, keys) => {
|
|
|
4182
4944
|
}
|
|
4183
4945
|
};
|
|
4184
4946
|
var DefaultBelongsToReference = class {
|
|
4947
|
+
/**
|
|
4948
|
+
* @param ctx The entity context for tracking changes.
|
|
4949
|
+
* @param meta Metadata for the child entity.
|
|
4950
|
+
* @param root The child entity instance (carrying the foreign key).
|
|
4951
|
+
* @param relationName The name of the relation.
|
|
4952
|
+
* @param relation Relation definition.
|
|
4953
|
+
* @param rootTable Table definition of the child entity.
|
|
4954
|
+
* @param loader Function to load the parent entity.
|
|
4955
|
+
* @param createEntity Function to create entity instances from rows.
|
|
4956
|
+
* @param targetKey The primary key of the target (parent) table.
|
|
4957
|
+
*/
|
|
4185
4958
|
constructor(ctx, meta, root, relationName, relation, rootTable, loader, createEntity, targetKey) {
|
|
4186
4959
|
this.ctx = ctx;
|
|
4187
4960
|
this.meta = meta;
|
|
@@ -4273,6 +5046,17 @@ var hideInternal4 = (obj, keys) => {
|
|
|
4273
5046
|
}
|
|
4274
5047
|
};
|
|
4275
5048
|
var DefaultManyToManyCollection = class {
|
|
5049
|
+
/**
|
|
5050
|
+
* @param ctx The entity context for tracking changes.
|
|
5051
|
+
* @param meta Metadata for the root entity.
|
|
5052
|
+
* @param root The root entity instance.
|
|
5053
|
+
* @param relationName The name of the relation.
|
|
5054
|
+
* @param relation Relation definition.
|
|
5055
|
+
* @param rootTable Table definition of the root entity.
|
|
5056
|
+
* @param loader Function to load the collection items.
|
|
5057
|
+
* @param createEntity Function to create entity instances from rows.
|
|
5058
|
+
* @param localKey The local key used for joining.
|
|
5059
|
+
*/
|
|
4276
5060
|
constructor(ctx, meta, root, relationName, relation, rootTable, loader, createEntity, localKey) {
|
|
4277
5061
|
this.ctx = ctx;
|
|
4278
5062
|
this.meta = meta;
|
|
@@ -4288,6 +5072,10 @@ var DefaultManyToManyCollection = class {
|
|
|
4288
5072
|
hideInternal4(this, ["ctx", "meta", "root", "relationName", "relation", "rootTable", "loader", "createEntity", "localKey"]);
|
|
4289
5073
|
this.hydrateFromCache();
|
|
4290
5074
|
}
|
|
5075
|
+
/**
|
|
5076
|
+
* Loads the collection items if not already loaded.
|
|
5077
|
+
* @returns A promise that resolves to the array of target entities.
|
|
5078
|
+
*/
|
|
4291
5079
|
async load() {
|
|
4292
5080
|
if (this.loaded) return this.items;
|
|
4293
5081
|
const map = await this.loader();
|
|
@@ -4303,9 +5091,30 @@ var DefaultManyToManyCollection = class {
|
|
|
4303
5091
|
this.loaded = true;
|
|
4304
5092
|
return this.items;
|
|
4305
5093
|
}
|
|
5094
|
+
/**
|
|
5095
|
+
* Returns the currently loaded items.
|
|
5096
|
+
* @returns Array of target entities.
|
|
5097
|
+
*/
|
|
4306
5098
|
getItems() {
|
|
4307
5099
|
return this.items;
|
|
4308
5100
|
}
|
|
5101
|
+
/**
|
|
5102
|
+
* Array-compatible length for testing frameworks.
|
|
5103
|
+
*/
|
|
5104
|
+
get length() {
|
|
5105
|
+
return this.items.length;
|
|
5106
|
+
}
|
|
5107
|
+
/**
|
|
5108
|
+
* Enables iteration over the collection like an array.
|
|
5109
|
+
*/
|
|
5110
|
+
[Symbol.iterator]() {
|
|
5111
|
+
return this.items[Symbol.iterator]();
|
|
5112
|
+
}
|
|
5113
|
+
/**
|
|
5114
|
+
* Attaches an entity to the collection.
|
|
5115
|
+
* Registers an 'attach' change in the entity context.
|
|
5116
|
+
* @param target Entity instance or its primary key value.
|
|
5117
|
+
*/
|
|
4309
5118
|
attach(target) {
|
|
4310
5119
|
const entity = this.ensureEntity(target);
|
|
4311
5120
|
const id = this.extractId(entity);
|
|
@@ -4325,6 +5134,11 @@ var DefaultManyToManyCollection = class {
|
|
|
4325
5134
|
{ kind: "attach", entity }
|
|
4326
5135
|
);
|
|
4327
5136
|
}
|
|
5137
|
+
/**
|
|
5138
|
+
* Detaches an entity from the collection.
|
|
5139
|
+
* Registers a 'detach' change in the entity context.
|
|
5140
|
+
* @param target Entity instance or its primary key value.
|
|
5141
|
+
*/
|
|
4328
5142
|
detach(target) {
|
|
4329
5143
|
const id = typeof target === "number" || typeof target === "string" ? target : this.extractId(target);
|
|
4330
5144
|
if (id == null) return;
|
|
@@ -4340,6 +5154,11 @@ var DefaultManyToManyCollection = class {
|
|
|
4340
5154
|
{ kind: "detach", entity: existing }
|
|
4341
5155
|
);
|
|
4342
5156
|
}
|
|
5157
|
+
/**
|
|
5158
|
+
* Syncs the collection with a list of IDs.
|
|
5159
|
+
* Attaches missing IDs and detaches IDs not in the list.
|
|
5160
|
+
* @param ids Array of primary key values to sync with.
|
|
5161
|
+
*/
|
|
4343
5162
|
async syncByIds(ids) {
|
|
4344
5163
|
await this.load();
|
|
4345
5164
|
const normalized = new Set(ids.map((id) => toKey5(id)));
|
|
@@ -4398,10 +5217,27 @@ var DefaultManyToManyCollection = class {
|
|
|
4398
5217
|
};
|
|
4399
5218
|
|
|
4400
5219
|
// src/orm/lazy-batch.ts
|
|
4401
|
-
var
|
|
4402
|
-
|
|
4403
|
-
return acc
|
|
4404
|
-
|
|
5220
|
+
var hasColumns = (columns) => Boolean(columns && columns.length > 0);
|
|
5221
|
+
var buildColumnSelection = (table, columns, missingMsg) => {
|
|
5222
|
+
return columns.reduce((acc, column) => {
|
|
5223
|
+
const def = table.columns[column];
|
|
5224
|
+
if (!def) {
|
|
5225
|
+
throw new Error(missingMsg(column));
|
|
5226
|
+
}
|
|
5227
|
+
acc[column] = def;
|
|
5228
|
+
return acc;
|
|
5229
|
+
}, {});
|
|
5230
|
+
};
|
|
5231
|
+
var filterRow = (row, columns) => {
|
|
5232
|
+
const filtered = {};
|
|
5233
|
+
for (const column of columns) {
|
|
5234
|
+
if (column in row) {
|
|
5235
|
+
filtered[column] = row[column];
|
|
5236
|
+
}
|
|
5237
|
+
}
|
|
5238
|
+
return filtered;
|
|
5239
|
+
};
|
|
5240
|
+
var filterRows = (rows, columns) => rows.map((row) => filterRow(row, columns));
|
|
4405
5241
|
var rowsFromResults = (results) => {
|
|
4406
5242
|
const rows = [];
|
|
4407
5243
|
for (const result of results) {
|
|
@@ -4433,9 +5269,12 @@ var collectKeysFromRoots = (roots, key) => {
|
|
|
4433
5269
|
return collected;
|
|
4434
5270
|
};
|
|
4435
5271
|
var buildInListValues = (keys) => Array.from(keys);
|
|
4436
|
-
var fetchRowsForKeys = async (ctx, table, column, keys) => {
|
|
4437
|
-
|
|
4438
|
-
qb.where(inList(column, buildInListValues(keys)));
|
|
5272
|
+
var fetchRowsForKeys = async (ctx, table, column, keys, selection, filter) => {
|
|
5273
|
+
let qb = new SelectQueryBuilder(table).select(selection);
|
|
5274
|
+
qb = qb.where(inList(column, buildInListValues(keys)));
|
|
5275
|
+
if (filter) {
|
|
5276
|
+
qb = qb.where(filter);
|
|
5277
|
+
}
|
|
4439
5278
|
return executeQuery(ctx, qb);
|
|
4440
5279
|
};
|
|
4441
5280
|
var groupRowsByMany = (rows, keyColumn) => {
|
|
@@ -4462,7 +5301,7 @@ var groupRowsByUnique = (rows, keyColumn) => {
|
|
|
4462
5301
|
}
|
|
4463
5302
|
return lookup;
|
|
4464
5303
|
};
|
|
4465
|
-
var loadHasManyRelation = async (ctx, rootTable,
|
|
5304
|
+
var loadHasManyRelation = async (ctx, rootTable, relationName, relation, options) => {
|
|
4466
5305
|
const localKey = relation.localKey || findPrimaryKey(rootTable);
|
|
4467
5306
|
const roots = ctx.getEntitiesForTable(rootTable);
|
|
4468
5307
|
const keys = collectKeysFromRoots(roots, localKey);
|
|
@@ -4471,10 +5310,30 @@ var loadHasManyRelation = async (ctx, rootTable, _relationName, relation) => {
|
|
|
4471
5310
|
}
|
|
4472
5311
|
const fkColumn = relation.target.columns[relation.foreignKey];
|
|
4473
5312
|
if (!fkColumn) return /* @__PURE__ */ new Map();
|
|
4474
|
-
const
|
|
4475
|
-
|
|
5313
|
+
const requestedColumns = hasColumns(options?.columns) ? [...options.columns] : void 0;
|
|
5314
|
+
const targetPrimaryKey = findPrimaryKey(relation.target);
|
|
5315
|
+
const selectedColumns = requestedColumns ? [...requestedColumns] : Object.keys(relation.target.columns);
|
|
5316
|
+
if (!selectedColumns.includes(targetPrimaryKey)) {
|
|
5317
|
+
selectedColumns.push(targetPrimaryKey);
|
|
5318
|
+
}
|
|
5319
|
+
const queryColumns = new Set(selectedColumns);
|
|
5320
|
+
queryColumns.add(relation.foreignKey);
|
|
5321
|
+
const selection = buildColumnSelection(
|
|
5322
|
+
relation.target,
|
|
5323
|
+
Array.from(queryColumns),
|
|
5324
|
+
(column) => `Column '${column}' not found on relation '${relationName}'`
|
|
5325
|
+
);
|
|
5326
|
+
const rows = await fetchRowsForKeys(ctx, relation.target, fkColumn, keys, selection, options?.filter);
|
|
5327
|
+
const grouped = groupRowsByMany(rows, relation.foreignKey);
|
|
5328
|
+
if (!requestedColumns) return grouped;
|
|
5329
|
+
const visibleColumns = new Set(selectedColumns);
|
|
5330
|
+
const filtered = /* @__PURE__ */ new Map();
|
|
5331
|
+
for (const [key, bucket] of grouped.entries()) {
|
|
5332
|
+
filtered.set(key, filterRows(bucket, visibleColumns));
|
|
5333
|
+
}
|
|
5334
|
+
return filtered;
|
|
4476
5335
|
};
|
|
4477
|
-
var loadHasOneRelation = async (ctx, rootTable,
|
|
5336
|
+
var loadHasOneRelation = async (ctx, rootTable, relationName, relation, options) => {
|
|
4478
5337
|
const localKey = relation.localKey || findPrimaryKey(rootTable);
|
|
4479
5338
|
const roots = ctx.getEntitiesForTable(rootTable);
|
|
4480
5339
|
const keys = collectKeysFromRoots(roots, localKey);
|
|
@@ -4483,22 +5342,98 @@ var loadHasOneRelation = async (ctx, rootTable, _relationName, relation) => {
|
|
|
4483
5342
|
}
|
|
4484
5343
|
const fkColumn = relation.target.columns[relation.foreignKey];
|
|
4485
5344
|
if (!fkColumn) return /* @__PURE__ */ new Map();
|
|
4486
|
-
const
|
|
4487
|
-
|
|
5345
|
+
const requestedColumns = hasColumns(options?.columns) ? [...options.columns] : void 0;
|
|
5346
|
+
const targetPrimaryKey = findPrimaryKey(relation.target);
|
|
5347
|
+
const selectedColumns = requestedColumns ? [...requestedColumns] : Object.keys(relation.target.columns);
|
|
5348
|
+
if (!selectedColumns.includes(targetPrimaryKey)) {
|
|
5349
|
+
selectedColumns.push(targetPrimaryKey);
|
|
5350
|
+
}
|
|
5351
|
+
const queryColumns = new Set(selectedColumns);
|
|
5352
|
+
queryColumns.add(relation.foreignKey);
|
|
5353
|
+
const selection = buildColumnSelection(
|
|
5354
|
+
relation.target,
|
|
5355
|
+
Array.from(queryColumns),
|
|
5356
|
+
(column) => `Column '${column}' not found on relation '${relationName}'`
|
|
5357
|
+
);
|
|
5358
|
+
const rows = await fetchRowsForKeys(ctx, relation.target, fkColumn, keys, selection, options?.filter);
|
|
5359
|
+
const grouped = groupRowsByUnique(rows, relation.foreignKey);
|
|
5360
|
+
if (!requestedColumns) return grouped;
|
|
5361
|
+
const visibleColumns = new Set(selectedColumns);
|
|
5362
|
+
const filtered = /* @__PURE__ */ new Map();
|
|
5363
|
+
for (const [key, row] of grouped.entries()) {
|
|
5364
|
+
filtered.set(key, filterRow(row, visibleColumns));
|
|
5365
|
+
}
|
|
5366
|
+
return filtered;
|
|
4488
5367
|
};
|
|
4489
|
-
var loadBelongsToRelation = async (ctx, rootTable,
|
|
5368
|
+
var loadBelongsToRelation = async (ctx, rootTable, relationName, relation, options) => {
|
|
4490
5369
|
const roots = ctx.getEntitiesForTable(rootTable);
|
|
4491
|
-
const
|
|
5370
|
+
const getForeignKeys = () => collectKeysFromRoots(roots, relation.foreignKey);
|
|
5371
|
+
let foreignKeys = getForeignKeys();
|
|
5372
|
+
if (!foreignKeys.size) {
|
|
5373
|
+
const pkName = findPrimaryKey(rootTable);
|
|
5374
|
+
const pkColumn2 = rootTable.columns[pkName];
|
|
5375
|
+
const fkColumn = rootTable.columns[relation.foreignKey];
|
|
5376
|
+
if (pkColumn2 && fkColumn) {
|
|
5377
|
+
const missingKeys = /* @__PURE__ */ new Set();
|
|
5378
|
+
const entityByPk = /* @__PURE__ */ new Map();
|
|
5379
|
+
for (const tracked of roots) {
|
|
5380
|
+
const entity = tracked.entity;
|
|
5381
|
+
const pkValue = entity[pkName];
|
|
5382
|
+
if (pkValue === void 0 || pkValue === null) continue;
|
|
5383
|
+
const fkValue = entity[relation.foreignKey];
|
|
5384
|
+
if (fkValue === void 0 || fkValue === null) {
|
|
5385
|
+
missingKeys.add(pkValue);
|
|
5386
|
+
entityByPk.set(pkValue, entity);
|
|
5387
|
+
}
|
|
5388
|
+
}
|
|
5389
|
+
if (missingKeys.size) {
|
|
5390
|
+
const selection2 = buildColumnSelection(
|
|
5391
|
+
rootTable,
|
|
5392
|
+
[pkName, relation.foreignKey],
|
|
5393
|
+
(column) => `Column '${column}' not found on table '${rootTable.name}'`
|
|
5394
|
+
);
|
|
5395
|
+
const keyRows = await fetchRowsForKeys(ctx, rootTable, pkColumn2, missingKeys, selection2);
|
|
5396
|
+
for (const row of keyRows) {
|
|
5397
|
+
const pkValue = row[pkName];
|
|
5398
|
+
if (pkValue === void 0 || pkValue === null) continue;
|
|
5399
|
+
const entity = entityByPk.get(pkValue);
|
|
5400
|
+
if (!entity) continue;
|
|
5401
|
+
const fkValue = row[relation.foreignKey];
|
|
5402
|
+
if (fkValue !== void 0 && fkValue !== null) {
|
|
5403
|
+
entity[relation.foreignKey] = fkValue;
|
|
5404
|
+
}
|
|
5405
|
+
}
|
|
5406
|
+
foreignKeys = getForeignKeys();
|
|
5407
|
+
}
|
|
5408
|
+
}
|
|
5409
|
+
}
|
|
4492
5410
|
if (!foreignKeys.size) {
|
|
4493
5411
|
return /* @__PURE__ */ new Map();
|
|
4494
5412
|
}
|
|
4495
5413
|
const targetKey = relation.localKey || findPrimaryKey(relation.target);
|
|
4496
5414
|
const pkColumn = relation.target.columns[targetKey];
|
|
4497
5415
|
if (!pkColumn) return /* @__PURE__ */ new Map();
|
|
4498
|
-
const
|
|
4499
|
-
|
|
5416
|
+
const requestedColumns = hasColumns(options?.columns) ? [...options.columns] : void 0;
|
|
5417
|
+
const selectedColumns = requestedColumns ? [...requestedColumns] : Object.keys(relation.target.columns);
|
|
5418
|
+
if (!selectedColumns.includes(targetKey)) {
|
|
5419
|
+
selectedColumns.push(targetKey);
|
|
5420
|
+
}
|
|
5421
|
+
const selection = buildColumnSelection(
|
|
5422
|
+
relation.target,
|
|
5423
|
+
selectedColumns,
|
|
5424
|
+
(column) => `Column '${column}' not found on relation '${relationName}'`
|
|
5425
|
+
);
|
|
5426
|
+
const rows = await fetchRowsForKeys(ctx, relation.target, pkColumn, foreignKeys, selection, options?.filter);
|
|
5427
|
+
const grouped = groupRowsByUnique(rows, targetKey);
|
|
5428
|
+
if (!requestedColumns) return grouped;
|
|
5429
|
+
const visibleColumns = new Set(selectedColumns);
|
|
5430
|
+
const filtered = /* @__PURE__ */ new Map();
|
|
5431
|
+
for (const [key, row] of grouped.entries()) {
|
|
5432
|
+
filtered.set(key, filterRow(row, visibleColumns));
|
|
5433
|
+
}
|
|
5434
|
+
return filtered;
|
|
4500
5435
|
};
|
|
4501
|
-
var loadBelongsToManyRelation = async (ctx, rootTable,
|
|
5436
|
+
var loadBelongsToManyRelation = async (ctx, rootTable, relationName, relation, options) => {
|
|
4502
5437
|
const rootKey = relation.localKey || findPrimaryKey(rootTable);
|
|
4503
5438
|
const roots = ctx.getEntitiesForTable(rootTable);
|
|
4504
5439
|
const rootIds = collectKeysFromRoots(roots, rootKey);
|
|
@@ -4507,9 +5442,29 @@ var loadBelongsToManyRelation = async (ctx, rootTable, _relationName, relation)
|
|
|
4507
5442
|
}
|
|
4508
5443
|
const pivotColumn = relation.pivotTable.columns[relation.pivotForeignKeyToRoot];
|
|
4509
5444
|
if (!pivotColumn) return /* @__PURE__ */ new Map();
|
|
4510
|
-
const
|
|
5445
|
+
const pivotColumnsRequested = hasColumns(options?.pivot?.columns) ? [...options.pivot.columns] : void 0;
|
|
5446
|
+
const useIncludeDefaults = options !== void 0;
|
|
5447
|
+
let pivotSelectedColumns;
|
|
5448
|
+
if (pivotColumnsRequested) {
|
|
5449
|
+
pivotSelectedColumns = [...pivotColumnsRequested];
|
|
5450
|
+
} else if (useIncludeDefaults) {
|
|
5451
|
+
const pivotPk = relation.pivotPrimaryKey || findPrimaryKey(relation.pivotTable);
|
|
5452
|
+
pivotSelectedColumns = relation.defaultPivotColumns ?? buildDefaultPivotColumns(relation, pivotPk);
|
|
5453
|
+
} else {
|
|
5454
|
+
pivotSelectedColumns = Object.keys(relation.pivotTable.columns);
|
|
5455
|
+
}
|
|
5456
|
+
const pivotQueryColumns = new Set(pivotSelectedColumns);
|
|
5457
|
+
pivotQueryColumns.add(relation.pivotForeignKeyToRoot);
|
|
5458
|
+
pivotQueryColumns.add(relation.pivotForeignKeyToTarget);
|
|
5459
|
+
const pivotSelection = buildColumnSelection(
|
|
5460
|
+
relation.pivotTable,
|
|
5461
|
+
Array.from(pivotQueryColumns),
|
|
5462
|
+
(column) => `Column '${column}' not found on pivot table '${relation.pivotTable.name}'`
|
|
5463
|
+
);
|
|
5464
|
+
const pivotRows = await fetchRowsForKeys(ctx, relation.pivotTable, pivotColumn, rootIds, pivotSelection);
|
|
4511
5465
|
const rootLookup = /* @__PURE__ */ new Map();
|
|
4512
5466
|
const targetIds = /* @__PURE__ */ new Set();
|
|
5467
|
+
const pivotVisibleColumns = new Set(pivotSelectedColumns);
|
|
4513
5468
|
for (const pivot of pivotRows) {
|
|
4514
5469
|
const rootValue = pivot[relation.pivotForeignKeyToRoot];
|
|
4515
5470
|
const targetValue = pivot[relation.pivotForeignKeyToTarget];
|
|
@@ -4519,7 +5474,7 @@ var loadBelongsToManyRelation = async (ctx, rootTable, _relationName, relation)
|
|
|
4519
5474
|
const bucket = rootLookup.get(toKey6(rootValue)) ?? [];
|
|
4520
5475
|
bucket.push({
|
|
4521
5476
|
targetId: targetValue,
|
|
4522
|
-
pivot:
|
|
5477
|
+
pivot: pivotVisibleColumns.size ? filterRow(pivot, pivotVisibleColumns) : {}
|
|
4523
5478
|
});
|
|
4524
5479
|
rootLookup.set(toKey6(rootValue), bucket);
|
|
4525
5480
|
targetIds.add(targetValue);
|
|
@@ -4530,8 +5485,19 @@ var loadBelongsToManyRelation = async (ctx, rootTable, _relationName, relation)
|
|
|
4530
5485
|
const targetKey = relation.targetKey || findPrimaryKey(relation.target);
|
|
4531
5486
|
const targetPkColumn = relation.target.columns[targetKey];
|
|
4532
5487
|
if (!targetPkColumn) return /* @__PURE__ */ new Map();
|
|
4533
|
-
const
|
|
5488
|
+
const targetRequestedColumns = hasColumns(options?.columns) ? [...options.columns] : void 0;
|
|
5489
|
+
const targetSelectedColumns = targetRequestedColumns ? [...targetRequestedColumns] : Object.keys(relation.target.columns);
|
|
5490
|
+
if (!targetSelectedColumns.includes(targetKey)) {
|
|
5491
|
+
targetSelectedColumns.push(targetKey);
|
|
5492
|
+
}
|
|
5493
|
+
const targetSelection = buildColumnSelection(
|
|
5494
|
+
relation.target,
|
|
5495
|
+
targetSelectedColumns,
|
|
5496
|
+
(column) => `Column '${column}' not found on relation '${relationName}'`
|
|
5497
|
+
);
|
|
5498
|
+
const targetRows = await fetchRowsForKeys(ctx, relation.target, targetPkColumn, targetIds, targetSelection, options?.filter);
|
|
4534
5499
|
const targetMap = groupRowsByUnique(targetRows, targetKey);
|
|
5500
|
+
const targetVisibleColumns = new Set(targetSelectedColumns);
|
|
4535
5501
|
const result = /* @__PURE__ */ new Map();
|
|
4536
5502
|
for (const [rootId, entries] of rootLookup.entries()) {
|
|
4537
5503
|
const bucket = [];
|
|
@@ -4539,7 +5505,7 @@ var loadBelongsToManyRelation = async (ctx, rootTable, _relationName, relation)
|
|
|
4539
5505
|
const targetRow = targetMap.get(toKey6(entry.targetId));
|
|
4540
5506
|
if (!targetRow) continue;
|
|
4541
5507
|
bucket.push({
|
|
4542
|
-
...targetRow,
|
|
5508
|
+
...targetRequestedColumns ? filterRow(targetRow, targetVisibleColumns) : targetRow,
|
|
4543
5509
|
_pivot: entry.pivot
|
|
4544
5510
|
});
|
|
4545
5511
|
}
|
|
@@ -4569,12 +5535,13 @@ var relationLoaderCache = (meta, relationName, factory) => {
|
|
|
4569
5535
|
}
|
|
4570
5536
|
return promise;
|
|
4571
5537
|
};
|
|
4572
|
-
var createEntityProxy = (ctx, table, row, lazyRelations = []) => {
|
|
5538
|
+
var createEntityProxy = (ctx, table, row, lazyRelations = [], lazyRelationOptions = /* @__PURE__ */ new Map()) => {
|
|
4573
5539
|
const target = { ...row };
|
|
4574
5540
|
const meta = {
|
|
4575
5541
|
ctx,
|
|
4576
5542
|
table,
|
|
4577
5543
|
lazyRelations: [...lazyRelations],
|
|
5544
|
+
lazyRelationOptions: new Map(lazyRelationOptions),
|
|
4578
5545
|
relationCache: /* @__PURE__ */ new Map(),
|
|
4579
5546
|
relationHydration: /* @__PURE__ */ new Map(),
|
|
4580
5547
|
relationWrappers: /* @__PURE__ */ new Map()
|
|
@@ -4615,14 +5582,14 @@ var createEntityProxy = (ctx, table, row, lazyRelations = []) => {
|
|
|
4615
5582
|
populateHydrationCache(proxy, row, meta);
|
|
4616
5583
|
return proxy;
|
|
4617
5584
|
};
|
|
4618
|
-
var createEntityFromRow = (ctx, table, row, lazyRelations = []) => {
|
|
5585
|
+
var createEntityFromRow = (ctx, table, row, lazyRelations = [], lazyRelationOptions = /* @__PURE__ */ new Map()) => {
|
|
4619
5586
|
const pkName = findPrimaryKey(table);
|
|
4620
5587
|
const pkValue = row[pkName];
|
|
4621
5588
|
if (pkValue !== void 0 && pkValue !== null) {
|
|
4622
5589
|
const tracked = ctx.getEntity(table, pkValue);
|
|
4623
5590
|
if (tracked) return tracked;
|
|
4624
5591
|
}
|
|
4625
|
-
const entity = createEntityProxy(ctx, table, row, lazyRelations);
|
|
5592
|
+
const entity = createEntityProxy(ctx, table, row, lazyRelations, lazyRelationOptions);
|
|
4626
5593
|
if (pkValue !== void 0 && pkValue !== null) {
|
|
4627
5594
|
ctx.trackManaged(table, pkValue, entity);
|
|
4628
5595
|
} else {
|
|
@@ -4672,6 +5639,58 @@ var populateHydrationCache = (entity, row, meta) => {
|
|
|
4672
5639
|
}
|
|
4673
5640
|
}
|
|
4674
5641
|
};
|
|
5642
|
+
var proxifyRelationWrapper = (wrapper) => {
|
|
5643
|
+
return new Proxy(wrapper, {
|
|
5644
|
+
get(target, prop, receiver) {
|
|
5645
|
+
if (typeof prop === "symbol") {
|
|
5646
|
+
return Reflect.get(target, prop, receiver);
|
|
5647
|
+
}
|
|
5648
|
+
if (prop in target) {
|
|
5649
|
+
return Reflect.get(target, prop, receiver);
|
|
5650
|
+
}
|
|
5651
|
+
const getItems = target.getItems;
|
|
5652
|
+
if (typeof getItems === "function") {
|
|
5653
|
+
const items = getItems.call(target);
|
|
5654
|
+
if (items && prop in items) {
|
|
5655
|
+
const propName = prop;
|
|
5656
|
+
const value = items[propName];
|
|
5657
|
+
return typeof value === "function" ? value.bind(items) : value;
|
|
5658
|
+
}
|
|
5659
|
+
}
|
|
5660
|
+
const getRef = target.get;
|
|
5661
|
+
if (typeof getRef === "function") {
|
|
5662
|
+
const current = getRef.call(target);
|
|
5663
|
+
if (current && prop in current) {
|
|
5664
|
+
const propName = prop;
|
|
5665
|
+
const value = current[propName];
|
|
5666
|
+
return typeof value === "function" ? value.bind(current) : value;
|
|
5667
|
+
}
|
|
5668
|
+
}
|
|
5669
|
+
return void 0;
|
|
5670
|
+
},
|
|
5671
|
+
set(target, prop, value, receiver) {
|
|
5672
|
+
if (typeof prop === "symbol") {
|
|
5673
|
+
return Reflect.set(target, prop, value, receiver);
|
|
5674
|
+
}
|
|
5675
|
+
if (prop in target) {
|
|
5676
|
+
return Reflect.set(target, prop, value, receiver);
|
|
5677
|
+
}
|
|
5678
|
+
const getRef = target.get;
|
|
5679
|
+
if (typeof getRef === "function") {
|
|
5680
|
+
const current = getRef.call(target);
|
|
5681
|
+
if (current && typeof current === "object") {
|
|
5682
|
+
return Reflect.set(current, prop, value);
|
|
5683
|
+
}
|
|
5684
|
+
}
|
|
5685
|
+
const getItems = target.getItems;
|
|
5686
|
+
if (typeof getItems === "function") {
|
|
5687
|
+
const items = getItems.call(target);
|
|
5688
|
+
return Reflect.set(items, prop, value);
|
|
5689
|
+
}
|
|
5690
|
+
return Reflect.set(target, prop, value, receiver);
|
|
5691
|
+
}
|
|
5692
|
+
});
|
|
5693
|
+
};
|
|
4675
5694
|
var getRelationWrapper = (meta, relationName, owner) => {
|
|
4676
5695
|
if (meta.relationWrappers.has(relationName)) {
|
|
4677
5696
|
return meta.relationWrappers.get(relationName);
|
|
@@ -4679,12 +5698,13 @@ var getRelationWrapper = (meta, relationName, owner) => {
|
|
|
4679
5698
|
const relation = meta.table.relations[relationName];
|
|
4680
5699
|
if (!relation) return void 0;
|
|
4681
5700
|
const wrapper = instantiateWrapper(meta, relationName, relation, owner);
|
|
4682
|
-
if (wrapper)
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
return
|
|
5701
|
+
if (!wrapper) return void 0;
|
|
5702
|
+
const proxied = proxifyRelationWrapper(wrapper);
|
|
5703
|
+
meta.relationWrappers.set(relationName, proxied);
|
|
5704
|
+
return proxied;
|
|
4686
5705
|
};
|
|
4687
5706
|
var instantiateWrapper = (meta, relationName, relation, owner) => {
|
|
5707
|
+
const lazyOptions = meta.lazyRelationOptions.get(relationName);
|
|
4688
5708
|
switch (relation.type) {
|
|
4689
5709
|
case RelationKinds.HasOne: {
|
|
4690
5710
|
const hasOne2 = relation;
|
|
@@ -4692,7 +5712,7 @@ var instantiateWrapper = (meta, relationName, relation, owner) => {
|
|
|
4692
5712
|
const loader = () => relationLoaderCache(
|
|
4693
5713
|
meta,
|
|
4694
5714
|
relationName,
|
|
4695
|
-
() => loadHasOneRelation(meta.ctx, meta.table, relationName, hasOne2)
|
|
5715
|
+
() => loadHasOneRelation(meta.ctx, meta.table, relationName, hasOne2, lazyOptions)
|
|
4696
5716
|
);
|
|
4697
5717
|
return new DefaultHasOneReference(
|
|
4698
5718
|
meta.ctx,
|
|
@@ -4712,7 +5732,7 @@ var instantiateWrapper = (meta, relationName, relation, owner) => {
|
|
|
4712
5732
|
const loader = () => relationLoaderCache(
|
|
4713
5733
|
meta,
|
|
4714
5734
|
relationName,
|
|
4715
|
-
() => loadHasManyRelation(meta.ctx, meta.table, relationName, hasMany2)
|
|
5735
|
+
() => loadHasManyRelation(meta.ctx, meta.table, relationName, hasMany2, lazyOptions)
|
|
4716
5736
|
);
|
|
4717
5737
|
return new DefaultHasManyCollection(
|
|
4718
5738
|
meta.ctx,
|
|
@@ -4732,7 +5752,7 @@ var instantiateWrapper = (meta, relationName, relation, owner) => {
|
|
|
4732
5752
|
const loader = () => relationLoaderCache(
|
|
4733
5753
|
meta,
|
|
4734
5754
|
relationName,
|
|
4735
|
-
() => loadBelongsToRelation(meta.ctx, meta.table, relationName, belongsTo2)
|
|
5755
|
+
() => loadBelongsToRelation(meta.ctx, meta.table, relationName, belongsTo2, lazyOptions)
|
|
4736
5756
|
);
|
|
4737
5757
|
return new DefaultBelongsToReference(
|
|
4738
5758
|
meta.ctx,
|
|
@@ -4752,7 +5772,7 @@ var instantiateWrapper = (meta, relationName, relation, owner) => {
|
|
|
4752
5772
|
const loader = () => relationLoaderCache(
|
|
4753
5773
|
meta,
|
|
4754
5774
|
relationName,
|
|
4755
|
-
() => loadBelongsToManyRelation(meta.ctx, meta.table, relationName, many)
|
|
5775
|
+
() => loadBelongsToManyRelation(meta.ctx, meta.table, relationName, many, lazyOptions)
|
|
4756
5776
|
);
|
|
4757
5777
|
return new DefaultManyToManyCollection(
|
|
4758
5778
|
meta.ctx,
|
|
@@ -4791,11 +5811,17 @@ var executeWithContexts = async (execCtx, entityCtx, qb) => {
|
|
|
4791
5811
|
const compiled = execCtx.dialect.compileSelect(ast);
|
|
4792
5812
|
const executed = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
4793
5813
|
const rows = flattenResults(executed);
|
|
5814
|
+
const lazyRelations = qb.getLazyRelations();
|
|
5815
|
+
const lazyRelationOptions = qb.getLazyRelationOptions();
|
|
4794
5816
|
if (ast.setOps && ast.setOps.length > 0) {
|
|
4795
|
-
|
|
5817
|
+
const proxies = rows.map((row) => createEntityProxy(entityCtx, qb.getTable(), row, lazyRelations, lazyRelationOptions));
|
|
5818
|
+
await loadLazyRelationsForTable(entityCtx, qb.getTable(), lazyRelations, lazyRelationOptions);
|
|
5819
|
+
return proxies;
|
|
4796
5820
|
}
|
|
4797
5821
|
const hydrated = hydrateRows(rows, qb.getHydrationPlan());
|
|
4798
|
-
|
|
5822
|
+
const entities = hydrated.map((row) => createEntityFromRow(entityCtx, qb.getTable(), row, lazyRelations, lazyRelationOptions));
|
|
5823
|
+
await loadLazyRelationsForTable(entityCtx, qb.getTable(), lazyRelations, lazyRelationOptions);
|
|
5824
|
+
return entities;
|
|
4799
5825
|
};
|
|
4800
5826
|
async function executeHydrated(session, qb) {
|
|
4801
5827
|
return executeWithContexts(session.getExecutionContext(), session, qb);
|
|
@@ -4807,6 +5833,52 @@ async function executeHydratedWithContexts(execCtx, hydCtx, qb) {
|
|
|
4807
5833
|
}
|
|
4808
5834
|
return executeWithContexts(execCtx, entityCtx, qb);
|
|
4809
5835
|
}
|
|
5836
|
+
var loadLazyRelationsForTable = async (ctx, table, lazyRelations, lazyRelationOptions) => {
|
|
5837
|
+
if (!lazyRelations.length) return;
|
|
5838
|
+
const tracked = ctx.getEntitiesForTable(table);
|
|
5839
|
+
if (!tracked.length) return;
|
|
5840
|
+
const meta = getEntityMeta(tracked[0].entity);
|
|
5841
|
+
if (!meta) return;
|
|
5842
|
+
for (const relationName of lazyRelations) {
|
|
5843
|
+
const relation = table.relations[relationName];
|
|
5844
|
+
if (!relation) continue;
|
|
5845
|
+
const key = relationName;
|
|
5846
|
+
const options = lazyRelationOptions.get(key);
|
|
5847
|
+
if (!options) {
|
|
5848
|
+
continue;
|
|
5849
|
+
}
|
|
5850
|
+
switch (relation.type) {
|
|
5851
|
+
case RelationKinds.HasOne:
|
|
5852
|
+
await relationLoaderCache(
|
|
5853
|
+
meta,
|
|
5854
|
+
key,
|
|
5855
|
+
() => loadHasOneRelation(ctx, table, key, relation, options)
|
|
5856
|
+
);
|
|
5857
|
+
break;
|
|
5858
|
+
case RelationKinds.HasMany:
|
|
5859
|
+
await relationLoaderCache(
|
|
5860
|
+
meta,
|
|
5861
|
+
key,
|
|
5862
|
+
() => loadHasManyRelation(ctx, table, key, relation, options)
|
|
5863
|
+
);
|
|
5864
|
+
break;
|
|
5865
|
+
case RelationKinds.BelongsTo:
|
|
5866
|
+
await relationLoaderCache(
|
|
5867
|
+
meta,
|
|
5868
|
+
key,
|
|
5869
|
+
() => loadBelongsToRelation(ctx, table, key, relation, options)
|
|
5870
|
+
);
|
|
5871
|
+
break;
|
|
5872
|
+
case RelationKinds.BelongsToMany:
|
|
5873
|
+
await relationLoaderCache(
|
|
5874
|
+
meta,
|
|
5875
|
+
key,
|
|
5876
|
+
() => loadBelongsToManyRelation(ctx, table, key, relation, options)
|
|
5877
|
+
);
|
|
5878
|
+
break;
|
|
5879
|
+
}
|
|
5880
|
+
}
|
|
5881
|
+
};
|
|
4810
5882
|
|
|
4811
5883
|
// src/query-builder/query-resolution.ts
|
|
4812
5884
|
function resolveSelectQuery(query) {
|
|
@@ -4823,7 +5895,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4823
5895
|
* @param hydration - Optional hydration manager
|
|
4824
5896
|
* @param dependencies - Optional query builder dependencies
|
|
4825
5897
|
*/
|
|
4826
|
-
constructor(table, state, hydration, dependencies, lazyRelations) {
|
|
5898
|
+
constructor(table, state, hydration, dependencies, lazyRelations, lazyRelationOptions) {
|
|
4827
5899
|
const deps = resolveSelectQueryBuilderDependencies(dependencies);
|
|
4828
5900
|
this.env = { table, deps };
|
|
4829
5901
|
const initialState = state ?? deps.createState(table);
|
|
@@ -4833,6 +5905,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4833
5905
|
hydration: initialHydration
|
|
4834
5906
|
};
|
|
4835
5907
|
this.lazyRelations = new Set(lazyRelations ?? []);
|
|
5908
|
+
this.lazyRelationOptions = new Map(lazyRelationOptions ?? []);
|
|
4836
5909
|
this.columnSelector = deps.createColumnSelector(this.env);
|
|
4837
5910
|
this.relationManager = deps.createRelationManager(this.env);
|
|
4838
5911
|
}
|
|
@@ -4842,8 +5915,15 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4842
5915
|
* @param lazyRelations - Updated lazy relations set
|
|
4843
5916
|
* @returns New SelectQueryBuilder instance
|
|
4844
5917
|
*/
|
|
4845
|
-
clone(context = this.context, lazyRelations = new Set(this.lazyRelations)) {
|
|
4846
|
-
return new _SelectQueryBuilder(
|
|
5918
|
+
clone(context = this.context, lazyRelations = new Set(this.lazyRelations), lazyRelationOptions = new Map(this.lazyRelationOptions)) {
|
|
5919
|
+
return new _SelectQueryBuilder(
|
|
5920
|
+
this.env.table,
|
|
5921
|
+
context.state,
|
|
5922
|
+
context.hydration,
|
|
5923
|
+
this.env.deps,
|
|
5924
|
+
lazyRelations,
|
|
5925
|
+
lazyRelationOptions
|
|
5926
|
+
);
|
|
4847
5927
|
}
|
|
4848
5928
|
/**
|
|
4849
5929
|
* Applies an alias to the root FROM table.
|
|
@@ -5090,36 +6170,40 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5090
6170
|
/**
|
|
5091
6171
|
* Includes a relation lazily in the query results
|
|
5092
6172
|
* @param relationName - Name of the relation to include lazily
|
|
6173
|
+
* @param options - Optional include options for lazy loading
|
|
5093
6174
|
* @returns New query builder instance with lazy relation inclusion
|
|
5094
6175
|
*/
|
|
5095
|
-
includeLazy(relationName) {
|
|
5096
|
-
|
|
5097
|
-
nextLazy.add(relationName);
|
|
5098
|
-
return this.clone(this.context, nextLazy);
|
|
5099
|
-
}
|
|
5100
|
-
/**
|
|
5101
|
-
* Selects columns for a related table in a single hop.
|
|
5102
|
-
*/
|
|
5103
|
-
selectRelationColumns(relationName, ...cols) {
|
|
6176
|
+
includeLazy(relationName, options) {
|
|
6177
|
+
let nextContext = this.context;
|
|
5104
6178
|
const relation = this.env.table.relations[relationName];
|
|
5105
|
-
if (
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
)
|
|
6179
|
+
if (relation?.type === RelationKinds.BelongsTo) {
|
|
6180
|
+
const foreignKey = relation.foreignKey;
|
|
6181
|
+
const fkColumn = this.env.table.columns[foreignKey];
|
|
6182
|
+
if (fkColumn) {
|
|
6183
|
+
const hasAlias2 = nextContext.state.ast.columns.some((col2) => {
|
|
6184
|
+
const node = col2;
|
|
6185
|
+
return (node.alias ?? node.name) === foreignKey;
|
|
6186
|
+
});
|
|
6187
|
+
if (!hasAlias2) {
|
|
6188
|
+
nextContext = this.columnSelector.select(nextContext, { [foreignKey]: fkColumn });
|
|
6189
|
+
}
|
|
5114
6190
|
}
|
|
5115
6191
|
}
|
|
5116
|
-
|
|
6192
|
+
const nextLazy = new Set(this.lazyRelations);
|
|
6193
|
+
nextLazy.add(relationName);
|
|
6194
|
+
const nextOptions = new Map(this.lazyRelationOptions);
|
|
6195
|
+
if (options) {
|
|
6196
|
+
nextOptions.set(relationName, options);
|
|
6197
|
+
} else {
|
|
6198
|
+
nextOptions.delete(relationName);
|
|
6199
|
+
}
|
|
6200
|
+
return this.clone(nextContext, nextLazy, nextOptions);
|
|
5117
6201
|
}
|
|
5118
6202
|
/**
|
|
5119
|
-
* Convenience alias for
|
|
6203
|
+
* Convenience alias for including only specific columns from a relation.
|
|
5120
6204
|
*/
|
|
5121
6205
|
includePick(relationName, cols) {
|
|
5122
|
-
return this.
|
|
6206
|
+
return this.include(relationName, { columns: cols });
|
|
5123
6207
|
}
|
|
5124
6208
|
/**
|
|
5125
6209
|
* Selects columns for the root table and relations from an array of entries
|
|
@@ -5132,7 +6216,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5132
6216
|
if (entry.type === "root") {
|
|
5133
6217
|
currBuilder = currBuilder.select(...entry.columns);
|
|
5134
6218
|
} else {
|
|
5135
|
-
currBuilder = currBuilder.
|
|
6219
|
+
currBuilder = currBuilder.include(entry.relationName, { columns: entry.columns });
|
|
5136
6220
|
}
|
|
5137
6221
|
}
|
|
5138
6222
|
return currBuilder;
|
|
@@ -5144,6 +6228,13 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5144
6228
|
getLazyRelations() {
|
|
5145
6229
|
return Array.from(this.lazyRelations);
|
|
5146
6230
|
}
|
|
6231
|
+
/**
|
|
6232
|
+
* Gets lazy relation include options
|
|
6233
|
+
* @returns Map of relation names to include options
|
|
6234
|
+
*/
|
|
6235
|
+
getLazyRelationOptions() {
|
|
6236
|
+
return new Map(this.lazyRelationOptions);
|
|
6237
|
+
}
|
|
5147
6238
|
/**
|
|
5148
6239
|
* Gets the table definition for this query builder
|
|
5149
6240
|
* @returns Table definition
|
|
@@ -7568,6 +8659,14 @@ var repeat = (value, count2) => fn("REPEAT", [value, count2]);
|
|
|
7568
8659
|
var lpad = (value, len, pad) => fn("LPAD", [value, len, pad]);
|
|
7569
8660
|
var rpad = (value, len, pad) => fn("RPAD", [value, len, pad]);
|
|
7570
8661
|
var space = (count2) => fn("SPACE", [count2]);
|
|
8662
|
+
var reverse = (value) => fn("REVERSE", [value]);
|
|
8663
|
+
var initcap = (value) => fn("INITCAP", [value]);
|
|
8664
|
+
var md5 = (value) => fn("MD5", [value]);
|
|
8665
|
+
var sha1 = (value) => fn("SHA1", [value]);
|
|
8666
|
+
var sha2 = (value, bits) => fn("SHA2", [value, bits]);
|
|
8667
|
+
var bitLength = (value) => fn("BIT_LENGTH", [value]);
|
|
8668
|
+
var octetLength = (value) => fn("OCTET_LENGTH", [value]);
|
|
8669
|
+
var chr = (code) => fn("CHR", [code]);
|
|
7571
8670
|
|
|
7572
8671
|
// src/core/ddl/introspect/functions/mssql.ts
|
|
7573
8672
|
var isColumnReference = (value) => typeof value === "object" && value !== null && !("type" in value) && "name" in value && typeof value.name === "string";
|
|
@@ -8126,6 +9225,8 @@ var sqrt = (value) => fn3("SQRT", [value]);
|
|
|
8126
9225
|
var tan = (value) => fn3("TAN", [value]);
|
|
8127
9226
|
var trunc = (value, decimals) => decimals === void 0 ? fn3("TRUNC", [value]) : fn3("TRUNC", [value, decimals]);
|
|
8128
9227
|
var truncate = (value, decimals) => fn3("TRUNCATE", [value, decimals]);
|
|
9228
|
+
var log2 = (value) => fn3("LOG2", [value]);
|
|
9229
|
+
var cbrt = (value) => fn3("CBRT", [value]);
|
|
8129
9230
|
|
|
8130
9231
|
// src/core/functions/datetime.ts
|
|
8131
9232
|
var isColumnDef3 = (val) => !!val && typeof val === "object" && "type" in val && "name" in val;
|
|
@@ -8137,12 +9238,15 @@ var toOperand4 = (input) => {
|
|
|
8137
9238
|
var fn4 = (key, args) => ({
|
|
8138
9239
|
type: "Function",
|
|
8139
9240
|
name: key,
|
|
9241
|
+
fn: key,
|
|
8140
9242
|
args: args.map(toOperand4)
|
|
8141
9243
|
});
|
|
8142
9244
|
var now = () => fn4("NOW", []);
|
|
8143
9245
|
var currentDate = () => fn4("CURRENT_DATE", []);
|
|
8144
9246
|
var currentTime = () => fn4("CURRENT_TIME", []);
|
|
8145
9247
|
var utcNow = () => fn4("UTC_NOW", []);
|
|
9248
|
+
var localTime = () => fn4("LOCALTIME", []);
|
|
9249
|
+
var localTimestamp = () => fn4("LOCALTIMESTAMP", []);
|
|
8146
9250
|
var extract = (part, date) => fn4("EXTRACT", [part, date]);
|
|
8147
9251
|
var year = (date) => fn4("YEAR", [date]);
|
|
8148
9252
|
var month = (date) => fn4("MONTH", [date]);
|
|
@@ -8157,6 +9261,72 @@ var endOfMonth = (date) => fn4("END_OF_MONTH", [date]);
|
|
|
8157
9261
|
var dayOfWeek = (date) => fn4("DAY_OF_WEEK", [date]);
|
|
8158
9262
|
var weekOfYear = (date) => fn4("WEEK_OF_YEAR", [date]);
|
|
8159
9263
|
var dateTrunc = (part, date) => fn4("DATE_TRUNC", [part, date]);
|
|
9264
|
+
var age = (timestamp, baseTimestamp) => baseTimestamp === void 0 ? fn4("AGE", [timestamp]) : fn4("AGE", [timestamp, baseTimestamp]);
|
|
9265
|
+
var hour = (date) => fn4("HOUR", [date]);
|
|
9266
|
+
var minute = (date) => fn4("MINUTE", [date]);
|
|
9267
|
+
var second = (date) => fn4("SECOND", [date]);
|
|
9268
|
+
var quarter = (date) => fn4("QUARTER", [date]);
|
|
9269
|
+
|
|
9270
|
+
// src/core/functions/control-flow.ts
|
|
9271
|
+
var isColumnDef4 = (val) => !!val && typeof val === "object" && "type" in val && "name" in val;
|
|
9272
|
+
var toOperand5 = (input) => {
|
|
9273
|
+
if (isOperandNode(input)) return input;
|
|
9274
|
+
if (isColumnDef4(input)) return columnOperand(input);
|
|
9275
|
+
return valueToOperand(input);
|
|
9276
|
+
};
|
|
9277
|
+
var fn5 = (key, args) => ({
|
|
9278
|
+
type: "Function",
|
|
9279
|
+
name: key,
|
|
9280
|
+
fn: key,
|
|
9281
|
+
args: args.map(toOperand5)
|
|
9282
|
+
});
|
|
9283
|
+
var coalesce = (...args) => {
|
|
9284
|
+
if (args.length < 2) throw new Error("coalesce() expects at least 2 arguments");
|
|
9285
|
+
return fn5("COALESCE", args);
|
|
9286
|
+
};
|
|
9287
|
+
var nullif = (val1, val2) => fn5("NULLIF", [val1, val2]);
|
|
9288
|
+
var greatest = (...args) => {
|
|
9289
|
+
if (args.length < 2) throw new Error("greatest() expects at least 2 arguments");
|
|
9290
|
+
return fn5("GREATEST", args);
|
|
9291
|
+
};
|
|
9292
|
+
var least = (...args) => {
|
|
9293
|
+
if (args.length < 2) throw new Error("least() expects at least 2 arguments");
|
|
9294
|
+
return fn5("LEAST", args);
|
|
9295
|
+
};
|
|
9296
|
+
var ifNull = (val, defaultValue) => coalesce(val, defaultValue);
|
|
9297
|
+
|
|
9298
|
+
// src/core/functions/json.ts
|
|
9299
|
+
var isColumnDef5 = (val) => !!val && typeof val === "object" && "type" in val && "name" in val;
|
|
9300
|
+
var toOperand6 = (input) => {
|
|
9301
|
+
if (isOperandNode(input)) return input;
|
|
9302
|
+
if (isColumnDef5(input)) return columnOperand(input);
|
|
9303
|
+
return valueToOperand(input);
|
|
9304
|
+
};
|
|
9305
|
+
var fn6 = (key, args) => ({
|
|
9306
|
+
type: "Function",
|
|
9307
|
+
name: key,
|
|
9308
|
+
fn: key,
|
|
9309
|
+
args: args.map(toOperand6)
|
|
9310
|
+
});
|
|
9311
|
+
var jsonLength = (target, path) => path === void 0 ? fn6("JSON_LENGTH", [target]) : fn6("JSON_LENGTH", [target, path]);
|
|
9312
|
+
var jsonSet = (target, path, value) => fn6("JSON_SET", [target, path, value]);
|
|
9313
|
+
var jsonArrayAgg = (value) => fn6("JSON_ARRAYAGG", [value]);
|
|
9314
|
+
var jsonContains = (target, candidate, path) => path === void 0 ? fn6("JSON_CONTAINS", [target, candidate]) : fn6("JSON_CONTAINS", [target, candidate, path]);
|
|
9315
|
+
|
|
9316
|
+
// src/core/functions/array.ts
|
|
9317
|
+
var isColumnDef6 = (val) => !!val && typeof val === "object" && "type" in val && "name" in val;
|
|
9318
|
+
var toOperand7 = (input) => {
|
|
9319
|
+
if (isOperandNode(input)) return input;
|
|
9320
|
+
if (isColumnDef6(input)) return columnOperand(input);
|
|
9321
|
+
return valueToOperand(input);
|
|
9322
|
+
};
|
|
9323
|
+
var fn7 = (key, args) => ({
|
|
9324
|
+
type: "Function",
|
|
9325
|
+
name: key,
|
|
9326
|
+
fn: key,
|
|
9327
|
+
args: args.map(toOperand7)
|
|
9328
|
+
});
|
|
9329
|
+
var arrayAppend = (array, value) => fn7("ARRAY_APPEND", [array, value]);
|
|
8160
9330
|
|
|
8161
9331
|
// src/orm/als.ts
|
|
8162
9332
|
var AsyncLocalStorage = class {
|
|
@@ -8236,7 +9406,7 @@ var DefaultNamingStrategy = class {
|
|
|
8236
9406
|
* @returns Capitalized table name (handles schema-qualified names)
|
|
8237
9407
|
*/
|
|
8238
9408
|
tableToSymbol(table) {
|
|
8239
|
-
const tableName = typeof table === "string" ? table : table.type === "DerivedTable" ? table.alias : table.name;
|
|
9409
|
+
const tableName = typeof table === "string" ? table : table.type === "DerivedTable" ? table.alias : table.type === "FunctionTable" ? table.alias ?? table.name : table.name;
|
|
8240
9410
|
if (tableName.includes(".")) {
|
|
8241
9411
|
return tableName.split(".").map((part) => this.capitalize(part)).join("");
|
|
8242
9412
|
}
|
|
@@ -8392,6 +9562,7 @@ var TypeScriptGenerator = class {
|
|
|
8392
9562
|
case "CaseExpression":
|
|
8393
9563
|
case "WindowFunction":
|
|
8394
9564
|
case "Cast":
|
|
9565
|
+
case "Collate":
|
|
8395
9566
|
return this.printOperand(term);
|
|
8396
9567
|
default:
|
|
8397
9568
|
return this.printExpression(term);
|
|
@@ -8454,6 +9625,9 @@ var TypeScriptGenerator = class {
|
|
|
8454
9625
|
visitCast(node) {
|
|
8455
9626
|
return this.printCastOperand(node);
|
|
8456
9627
|
}
|
|
9628
|
+
visitCollate(node) {
|
|
9629
|
+
return this.printCollateOperand(node);
|
|
9630
|
+
}
|
|
8457
9631
|
visitAliasRef(node) {
|
|
8458
9632
|
return `aliasRef('${node.name}')`;
|
|
8459
9633
|
}
|
|
@@ -8465,12 +9639,12 @@ var TypeScriptGenerator = class {
|
|
|
8465
9639
|
printBinaryExpression(binary) {
|
|
8466
9640
|
const left2 = this.printOperand(binary.left);
|
|
8467
9641
|
const right2 = this.printOperand(binary.right);
|
|
8468
|
-
const
|
|
9642
|
+
const fn8 = this.mapOp(binary.operator);
|
|
8469
9643
|
const args = [left2, right2];
|
|
8470
9644
|
if (binary.escape) {
|
|
8471
9645
|
args.push(this.printOperand(binary.escape));
|
|
8472
9646
|
}
|
|
8473
|
-
return `${
|
|
9647
|
+
return `${fn8}(${args.join(", ")})`;
|
|
8474
9648
|
}
|
|
8475
9649
|
/**
|
|
8476
9650
|
* Prints a logical expression to TypeScript code
|
|
@@ -8499,13 +9673,13 @@ var TypeScriptGenerator = class {
|
|
|
8499
9673
|
*/
|
|
8500
9674
|
printInExpression(inExpr) {
|
|
8501
9675
|
const left2 = this.printOperand(inExpr.left);
|
|
8502
|
-
const
|
|
9676
|
+
const fn8 = this.mapOp(inExpr.operator);
|
|
8503
9677
|
if (Array.isArray(inExpr.right)) {
|
|
8504
9678
|
const values = inExpr.right.map((v) => this.printOperand(v)).join(", ");
|
|
8505
|
-
return `${
|
|
9679
|
+
return `${fn8}(${left2}, [${values}])`;
|
|
8506
9680
|
}
|
|
8507
9681
|
const subquery = this.inlineChain(this.buildSelectLines(inExpr.right.query));
|
|
8508
|
-
return `${
|
|
9682
|
+
return `${fn8}(${left2}, (${subquery}))`;
|
|
8509
9683
|
}
|
|
8510
9684
|
/**
|
|
8511
9685
|
* Prints a null expression to TypeScript code
|
|
@@ -8514,8 +9688,8 @@ var TypeScriptGenerator = class {
|
|
|
8514
9688
|
*/
|
|
8515
9689
|
printNullExpression(nullExpr) {
|
|
8516
9690
|
const left2 = this.printOperand(nullExpr.left);
|
|
8517
|
-
const
|
|
8518
|
-
return `${
|
|
9691
|
+
const fn8 = this.mapOp(nullExpr.operator);
|
|
9692
|
+
return `${fn8}(${left2})`;
|
|
8519
9693
|
}
|
|
8520
9694
|
/**
|
|
8521
9695
|
* Prints a BETWEEN expression to TypeScript code
|
|
@@ -8559,9 +9733,9 @@ var TypeScriptGenerator = class {
|
|
|
8559
9733
|
* @param fn - Function node
|
|
8560
9734
|
* @returns TypeScript code representation
|
|
8561
9735
|
*/
|
|
8562
|
-
printFunctionOperand(
|
|
8563
|
-
const args =
|
|
8564
|
-
return `${
|
|
9736
|
+
printFunctionOperand(fn8) {
|
|
9737
|
+
const args = fn8.args.map((a) => this.printOperand(a)).join(", ");
|
|
9738
|
+
return `${fn8.name.toLowerCase()}(${args})`;
|
|
8565
9739
|
}
|
|
8566
9740
|
/**
|
|
8567
9741
|
* Prints a JSON path operand to TypeScript code
|
|
@@ -8625,6 +9799,9 @@ var TypeScriptGenerator = class {
|
|
|
8625
9799
|
const typeLiteral = node.castType.replace(/'/g, "\\'");
|
|
8626
9800
|
return `cast(${this.printOperand(node.expression)}, '${typeLiteral}')`;
|
|
8627
9801
|
}
|
|
9802
|
+
printCollateOperand(node) {
|
|
9803
|
+
return `collate(${this.printOperand(node.expression)}, '${node.collation}')`;
|
|
9804
|
+
}
|
|
8628
9805
|
/**
|
|
8629
9806
|
* Converts method chain lines to inline format
|
|
8630
9807
|
* @param lines - Method chain lines
|
|
@@ -8655,10 +9832,20 @@ var IdentityMap = class {
|
|
|
8655
9832
|
get bucketsMap() {
|
|
8656
9833
|
return this.buckets;
|
|
8657
9834
|
}
|
|
9835
|
+
/**
|
|
9836
|
+
* Retrieves an entity from the identity map if it exists.
|
|
9837
|
+
* @param table The table definition of the entity.
|
|
9838
|
+
* @param pk The primary key value.
|
|
9839
|
+
* @returns The entity instance if found, undefined otherwise.
|
|
9840
|
+
*/
|
|
8658
9841
|
getEntity(table, pk) {
|
|
8659
9842
|
const bucket = this.buckets.get(table.name);
|
|
8660
9843
|
return bucket?.get(this.toIdentityKey(pk))?.entity;
|
|
8661
9844
|
}
|
|
9845
|
+
/**
|
|
9846
|
+
* Registers a tracked entity in the identity map.
|
|
9847
|
+
* @param tracked The tracked entity metadata and instance.
|
|
9848
|
+
*/
|
|
8662
9849
|
register(tracked) {
|
|
8663
9850
|
if (tracked.pk == null) return;
|
|
8664
9851
|
const bucket = this.buckets.get(tracked.table.name) ?? /* @__PURE__ */ new Map();
|
|
@@ -8670,6 +9857,11 @@ var IdentityMap = class {
|
|
|
8670
9857
|
const bucket = this.buckets.get(tracked.table.name);
|
|
8671
9858
|
bucket?.delete(this.toIdentityKey(tracked.pk));
|
|
8672
9859
|
}
|
|
9860
|
+
/**
|
|
9861
|
+
* Returns all tracked entities for a specific table.
|
|
9862
|
+
* @param table The table definition.
|
|
9863
|
+
* @returns Array of tracked entities.
|
|
9864
|
+
*/
|
|
8673
9865
|
getEntitiesForTable(table) {
|
|
8674
9866
|
const bucket = this.buckets.get(table.name);
|
|
8675
9867
|
return bucket ? Array.from(bucket.values()) : [];
|
|
@@ -9794,15 +10986,15 @@ var OrmSession = class {
|
|
|
9794
10986
|
* @returns The result of the function
|
|
9795
10987
|
* @throws If the transaction fails
|
|
9796
10988
|
*/
|
|
9797
|
-
async transaction(
|
|
10989
|
+
async transaction(fn8) {
|
|
9798
10990
|
if (!this.executor.capabilities.transactions) {
|
|
9799
|
-
const result = await
|
|
10991
|
+
const result = await fn8(this);
|
|
9800
10992
|
await this.commit();
|
|
9801
10993
|
return result;
|
|
9802
10994
|
}
|
|
9803
10995
|
await this.executor.beginTransaction();
|
|
9804
10996
|
try {
|
|
9805
|
-
const result = await
|
|
10997
|
+
const result = await fn8(this);
|
|
9806
10998
|
await this.flushWithHooks();
|
|
9807
10999
|
await this.executor.commitTransaction();
|
|
9808
11000
|
await this.domainEvents.dispatch(this.unitOfWork.getTracked(), this);
|
|
@@ -9905,11 +11097,11 @@ var Orm = class {
|
|
|
9905
11097
|
* @returns The result of the function
|
|
9906
11098
|
* @throws If the transaction fails
|
|
9907
11099
|
*/
|
|
9908
|
-
async transaction(
|
|
11100
|
+
async transaction(fn8) {
|
|
9909
11101
|
const executor = this.executorFactory.createTransactionalExecutor();
|
|
9910
11102
|
const session = new OrmSession({ orm: this, executor });
|
|
9911
11103
|
try {
|
|
9912
|
-
return await session.transaction(() =>
|
|
11104
|
+
return await session.transaction(() => fn8(session));
|
|
9913
11105
|
} finally {
|
|
9914
11106
|
await session.dispose();
|
|
9915
11107
|
}
|
|
@@ -10734,8 +11926,10 @@ export {
|
|
|
10734
11926
|
acos,
|
|
10735
11927
|
add,
|
|
10736
11928
|
addDomainEvent,
|
|
11929
|
+
age,
|
|
10737
11930
|
aliasRef,
|
|
10738
11931
|
and,
|
|
11932
|
+
arrayAppend,
|
|
10739
11933
|
ascii,
|
|
10740
11934
|
asin,
|
|
10741
11935
|
atan,
|
|
@@ -10744,16 +11938,24 @@ export {
|
|
|
10744
11938
|
belongsTo,
|
|
10745
11939
|
belongsToMany,
|
|
10746
11940
|
between,
|
|
11941
|
+
bitAnd,
|
|
11942
|
+
bitLength,
|
|
11943
|
+
bitOr,
|
|
11944
|
+
bitXor,
|
|
10747
11945
|
bootstrapEntities,
|
|
10748
11946
|
caseWhen,
|
|
10749
11947
|
cast,
|
|
11948
|
+
cbrt,
|
|
10750
11949
|
ceil,
|
|
10751
11950
|
ceiling,
|
|
10752
11951
|
char,
|
|
10753
11952
|
charLength,
|
|
11953
|
+
chr,
|
|
10754
11954
|
clearExpressionDispatchers,
|
|
10755
11955
|
clearOperandDispatchers,
|
|
11956
|
+
coalesce,
|
|
10756
11957
|
col,
|
|
11958
|
+
collate,
|
|
10757
11959
|
columnOperand,
|
|
10758
11960
|
concat,
|
|
10759
11961
|
concatWs,
|
|
@@ -10805,18 +12007,23 @@ export {
|
|
|
10805
12007
|
getDecoratorMetadata,
|
|
10806
12008
|
getSchemaIntrospector,
|
|
10807
12009
|
getTableDefFromEntity,
|
|
12010
|
+
greatest,
|
|
10808
12011
|
groupConcat,
|
|
10809
12012
|
gt,
|
|
10810
12013
|
gte,
|
|
10811
12014
|
hasMany,
|
|
10812
12015
|
hasOne,
|
|
12016
|
+
hour,
|
|
10813
12017
|
hydrateRows,
|
|
12018
|
+
ifNull,
|
|
10814
12019
|
inList,
|
|
10815
12020
|
inSubquery,
|
|
12021
|
+
initcap,
|
|
10816
12022
|
instr,
|
|
10817
12023
|
introspectSchema,
|
|
10818
12024
|
isCaseExpressionNode,
|
|
10819
12025
|
isCastExpressionNode,
|
|
12026
|
+
isCollateExpressionNode,
|
|
10820
12027
|
isExpressionSelectionNode,
|
|
10821
12028
|
isFunctionNode,
|
|
10822
12029
|
isNotNull,
|
|
@@ -10824,11 +12031,16 @@ export {
|
|
|
10824
12031
|
isOperandNode,
|
|
10825
12032
|
isValueOperandInput,
|
|
10826
12033
|
isWindowFunctionNode,
|
|
12034
|
+
jsonArrayAgg,
|
|
12035
|
+
jsonContains,
|
|
12036
|
+
jsonLength,
|
|
10827
12037
|
jsonPath,
|
|
12038
|
+
jsonSet,
|
|
10828
12039
|
jsonify,
|
|
10829
12040
|
lag,
|
|
10830
12041
|
lastValue,
|
|
10831
12042
|
lead,
|
|
12043
|
+
least,
|
|
10832
12044
|
left,
|
|
10833
12045
|
length,
|
|
10834
12046
|
like,
|
|
@@ -10837,9 +12049,12 @@ export {
|
|
|
10837
12049
|
loadBelongsToRelation,
|
|
10838
12050
|
loadHasManyRelation,
|
|
10839
12051
|
loadHasOneRelation,
|
|
12052
|
+
localTime,
|
|
12053
|
+
localTimestamp,
|
|
10840
12054
|
locate,
|
|
10841
12055
|
log,
|
|
10842
12056
|
log10,
|
|
12057
|
+
log2,
|
|
10843
12058
|
logBase,
|
|
10844
12059
|
lower,
|
|
10845
12060
|
lpad,
|
|
@@ -10847,7 +12062,9 @@ export {
|
|
|
10847
12062
|
lte,
|
|
10848
12063
|
ltrim,
|
|
10849
12064
|
max,
|
|
12065
|
+
md5,
|
|
10850
12066
|
min,
|
|
12067
|
+
minute,
|
|
10851
12068
|
mod,
|
|
10852
12069
|
month,
|
|
10853
12070
|
mul,
|
|
@@ -10860,12 +12077,15 @@ export {
|
|
|
10860
12077
|
notLike,
|
|
10861
12078
|
now,
|
|
10862
12079
|
ntile,
|
|
12080
|
+
nullif,
|
|
12081
|
+
octetLength,
|
|
10863
12082
|
or,
|
|
10864
12083
|
outerRef,
|
|
10865
12084
|
pi,
|
|
10866
12085
|
position,
|
|
10867
12086
|
pow,
|
|
10868
12087
|
power,
|
|
12088
|
+
quarter,
|
|
10869
12089
|
radians,
|
|
10870
12090
|
rand,
|
|
10871
12091
|
random,
|
|
@@ -10873,22 +12093,30 @@ export {
|
|
|
10873
12093
|
registerExpressionDispatcher,
|
|
10874
12094
|
registerOperandDispatcher,
|
|
10875
12095
|
registerSchemaIntrospector,
|
|
12096
|
+
relationLoaderCache,
|
|
10876
12097
|
renderColumnDefinition,
|
|
10877
12098
|
renderTypeWithArgs,
|
|
10878
12099
|
repeat,
|
|
10879
12100
|
replace,
|
|
12101
|
+
reverse,
|
|
10880
12102
|
right,
|
|
10881
12103
|
round,
|
|
10882
12104
|
rowNumber,
|
|
10883
12105
|
rowsToQueryResult,
|
|
10884
12106
|
rpad,
|
|
10885
12107
|
rtrim,
|
|
12108
|
+
second,
|
|
10886
12109
|
sel,
|
|
10887
12110
|
selectFromEntity,
|
|
12111
|
+
sha1,
|
|
12112
|
+
sha2,
|
|
12113
|
+
shiftLeft,
|
|
12114
|
+
shiftRight,
|
|
10888
12115
|
sign,
|
|
10889
12116
|
sin,
|
|
10890
12117
|
space,
|
|
10891
12118
|
sqrt,
|
|
12119
|
+
stddev,
|
|
10892
12120
|
sub,
|
|
10893
12121
|
substr,
|
|
10894
12122
|
sum,
|
|
@@ -10904,6 +12132,7 @@ export {
|
|
|
10904
12132
|
upper,
|
|
10905
12133
|
utcNow,
|
|
10906
12134
|
valueToOperand,
|
|
12135
|
+
variance,
|
|
10907
12136
|
visitExpression,
|
|
10908
12137
|
visitOperand,
|
|
10909
12138
|
weekOfYear,
|