metal-orm 1.1.3 → 1.1.4
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 +715 -703
- package/dist/index.cjs +655 -75
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +170 -8
- package/dist/index.d.ts +170 -8
- package/dist/index.js +649 -75
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/scripts/naming-strategy.mjs +16 -1
- package/src/core/ast/procedure.ts +21 -0
- package/src/core/ast/query.ts +47 -19
- package/src/core/ddl/introspect/utils.ts +56 -56
- package/src/core/dialect/abstract.ts +560 -547
- package/src/core/dialect/base/sql-dialect.ts +43 -29
- package/src/core/dialect/mssql/index.ts +369 -232
- package/src/core/dialect/mysql/index.ts +99 -7
- package/src/core/dialect/postgres/index.ts +121 -60
- package/src/core/dialect/sqlite/index.ts +97 -64
- package/src/core/execution/db-executor.ts +108 -90
- package/src/core/execution/executors/mssql-executor.ts +28 -24
- package/src/core/execution/executors/mysql-executor.ts +62 -27
- package/src/core/execution/executors/sqlite-executor.ts +10 -9
- package/src/index.ts +9 -6
- package/src/orm/execute-procedure.ts +77 -0
- package/src/orm/execute.ts +74 -73
- package/src/orm/interceptor-pipeline.ts +21 -17
- package/src/orm/pooled-executor-factory.ts +41 -20
- package/src/orm/unit-of-work.ts +6 -4
- package/src/query/index.ts +8 -5
- package/src/query-builder/delete.ts +3 -2
- package/src/query-builder/insert-query-state.ts +47 -19
- package/src/query-builder/insert.ts +142 -28
- package/src/query-builder/procedure-call.ts +122 -0
- package/src/query-builder/select/select-operations.ts +5 -2
- package/src/query-builder/select.ts +1146 -1105
- package/src/query-builder/update.ts +3 -2
- package/src/tree/tree-manager.ts +754 -754
package/dist/index.cjs
CHANGED
|
@@ -55,6 +55,7 @@ __export(index_exports, {
|
|
|
55
55
|
CPF: () => CPF,
|
|
56
56
|
Capitalize: () => Capitalize,
|
|
57
57
|
Column: () => Column,
|
|
58
|
+
ConflictBuilder: () => ConflictBuilder,
|
|
58
59
|
ConstructorMaterializationStrategy: () => ConstructorMaterializationStrategy,
|
|
59
60
|
DEFAULT_TREE_CONFIG: () => DEFAULT_TREE_CONFIG,
|
|
60
61
|
DateTimeTypeStrategy: () => DateTimeTypeStrategy,
|
|
@@ -87,6 +88,7 @@ __export(index_exports, {
|
|
|
87
88
|
Pool: () => Pool,
|
|
88
89
|
PostgresDialect: () => PostgresDialect,
|
|
89
90
|
PrimaryKey: () => PrimaryKey,
|
|
91
|
+
ProcedureCallBuilder: () => ProcedureCallBuilder,
|
|
90
92
|
PrototypeMaterializationStrategy: () => PrototypeMaterializationStrategy,
|
|
91
93
|
QueryCacheManager: () => QueryCacheManager,
|
|
92
94
|
RedisCacheAdapter: () => RedisCacheAdapter,
|
|
@@ -136,6 +138,7 @@ __export(index_exports, {
|
|
|
136
138
|
buildScopeConditions: () => buildScopeConditions,
|
|
137
139
|
calculateRowDepths: () => calculateRowDepths,
|
|
138
140
|
calculateTotalPages: () => calculateTotalPages,
|
|
141
|
+
callProcedure: () => callProcedure,
|
|
139
142
|
canonicalizeSchema: () => canonicalizeSchema,
|
|
140
143
|
caseWhen: () => caseWhen,
|
|
141
144
|
cast: () => cast,
|
|
@@ -208,6 +211,7 @@ __export(index_exports, {
|
|
|
208
211
|
executeHydratedPlain: () => executeHydratedPlain,
|
|
209
212
|
executeHydratedPlainWithContexts: () => executeHydratedPlainWithContexts,
|
|
210
213
|
executeHydratedWithContexts: () => executeHydratedWithContexts,
|
|
214
|
+
executeProcedureAst: () => executeProcedureAst,
|
|
211
215
|
executeSchemaSql: () => executeSchemaSql,
|
|
212
216
|
executeSchemaSqlFor: () => executeSchemaSqlFor,
|
|
213
217
|
exists: () => exists,
|
|
@@ -335,6 +339,7 @@ __export(index_exports, {
|
|
|
335
339
|
paginationParamsSchema: () => paginationParamsSchema,
|
|
336
340
|
parameterToRef: () => parameterToRef,
|
|
337
341
|
parseDuration: () => parseDuration,
|
|
342
|
+
payloadResultSets: () => payloadResultSets,
|
|
338
343
|
pi: () => pi,
|
|
339
344
|
pick: () => pick,
|
|
340
345
|
position: () => position,
|
|
@@ -394,6 +399,7 @@ __export(index_exports, {
|
|
|
394
399
|
threadResults: () => threadResults,
|
|
395
400
|
threadedNodeToOpenApiSchema: () => threadedNodeToOpenApiSchema,
|
|
396
401
|
toColumnRef: () => toColumnRef,
|
|
402
|
+
toExecutionPayload: () => toExecutionPayload,
|
|
397
403
|
toPagedResponse: () => toPagedResponse,
|
|
398
404
|
toPagedResponseBuilder: () => toPagedResponseBuilder,
|
|
399
405
|
toPaginationParams: () => toPaginationParams,
|
|
@@ -1835,6 +1841,9 @@ var Dialect = class _Dialect {
|
|
|
1835
1841
|
compileDeleteAst() {
|
|
1836
1842
|
throw new Error("Not implemented");
|
|
1837
1843
|
}
|
|
1844
|
+
compileProcedureCall() {
|
|
1845
|
+
throw new Error("Not implemented");
|
|
1846
|
+
}
|
|
1838
1847
|
}
|
|
1839
1848
|
return new TestDialect(functionStrategy, tableFunctionStrategy);
|
|
1840
1849
|
}
|
|
@@ -2297,8 +2306,14 @@ var SqlDialectBase = class extends Dialect {
|
|
|
2297
2306
|
const table = this.compileTableName(ast.into);
|
|
2298
2307
|
const columnList = this.compileInsertColumnList(ast.columns);
|
|
2299
2308
|
const source = this.compileInsertSource(ast.source, ctx);
|
|
2309
|
+
const upsert = this.compileUpsertClause(ast, ctx);
|
|
2300
2310
|
const returning = this.compileReturning(ast.returning, ctx);
|
|
2301
|
-
return `INSERT INTO ${table} (${columnList}) ${source}${returning}`;
|
|
2311
|
+
return `INSERT INTO ${table} (${columnList}) ${source}${upsert}${returning}`;
|
|
2312
|
+
}
|
|
2313
|
+
compileUpsertClause(ast, _ctx) {
|
|
2314
|
+
void _ctx;
|
|
2315
|
+
if (!ast.onConflict) return "";
|
|
2316
|
+
throw new Error(`UPSERT/ON CONFLICT is not supported by dialect "${this.dialect}".`);
|
|
2302
2317
|
}
|
|
2303
2318
|
compileReturning(returning, ctx) {
|
|
2304
2319
|
return this.returningStrategy.compileReturning(returning, ctx);
|
|
@@ -2317,6 +2332,11 @@ var SqlDialectBase = class extends Dialect {
|
|
|
2317
2332
|
compileInsertColumnList(columns) {
|
|
2318
2333
|
return columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
|
|
2319
2334
|
}
|
|
2335
|
+
ensureConflictColumns(clause, message) {
|
|
2336
|
+
if (!clause.target.columns.length) {
|
|
2337
|
+
throw new Error(message);
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2320
2340
|
compileSelectCore(ast, ctx) {
|
|
2321
2341
|
const columns = this.compileSelectColumns(ast, ctx);
|
|
2322
2342
|
const from = this.compileFrom(ast.from, ctx);
|
|
@@ -2699,9 +2719,52 @@ var PostgresDialect = class extends SqlDialectBase {
|
|
|
2699
2719
|
const columns = this.formatReturningColumns(returning);
|
|
2700
2720
|
return ` RETURNING ${columns}`;
|
|
2701
2721
|
}
|
|
2722
|
+
compileUpsertClause(ast, ctx) {
|
|
2723
|
+
if (!ast.onConflict) return "";
|
|
2724
|
+
const clause = ast.onConflict;
|
|
2725
|
+
const target = clause.target.constraint ? ` ON CONFLICT ON CONSTRAINT ${this.quoteIdentifier(clause.target.constraint)}` : (() => {
|
|
2726
|
+
this.ensureConflictColumns(
|
|
2727
|
+
clause,
|
|
2728
|
+
"PostgreSQL ON CONFLICT requires conflict columns or a constraint name."
|
|
2729
|
+
);
|
|
2730
|
+
const cols = clause.target.columns.map((col2) => this.quoteIdentifier(col2.name)).join(", ");
|
|
2731
|
+
return ` ON CONFLICT (${cols})`;
|
|
2732
|
+
})();
|
|
2733
|
+
if (clause.action.type === "DoNothing") {
|
|
2734
|
+
return `${target} DO NOTHING`;
|
|
2735
|
+
}
|
|
2736
|
+
if (!clause.action.set.length) {
|
|
2737
|
+
throw new Error("PostgreSQL ON CONFLICT DO UPDATE requires at least one assignment.");
|
|
2738
|
+
}
|
|
2739
|
+
const assignments = this.compileUpdateAssignments(clause.action.set, ast.into, ctx);
|
|
2740
|
+
const where = clause.action.where ? ` WHERE ${this.compileExpression(clause.action.where, ctx)}` : "";
|
|
2741
|
+
return `${target} DO UPDATE SET ${assignments}${where}`;
|
|
2742
|
+
}
|
|
2702
2743
|
supportsDmlReturningClause() {
|
|
2703
2744
|
return true;
|
|
2704
2745
|
}
|
|
2746
|
+
compileProcedureCall(ast) {
|
|
2747
|
+
const ctx = this.createCompilerContext();
|
|
2748
|
+
const qualifiedName = ast.ref.schema ? `${this.quoteIdentifier(ast.ref.schema)}.${this.quoteIdentifier(ast.ref.name)}` : this.quoteIdentifier(ast.ref.name);
|
|
2749
|
+
const args = [];
|
|
2750
|
+
for (const param of ast.params) {
|
|
2751
|
+
if (param.direction === "out") continue;
|
|
2752
|
+
if (!param.value) {
|
|
2753
|
+
throw new Error(`Procedure parameter "${param.name}" requires a value for direction "${param.direction}".`);
|
|
2754
|
+
}
|
|
2755
|
+
args.push(this.compileOperand(param.value, ctx));
|
|
2756
|
+
}
|
|
2757
|
+
const outNames = ast.params.filter((param) => param.direction === "out" || param.direction === "inout").map((param) => param.name);
|
|
2758
|
+
const rawSql = `CALL ${qualifiedName}(${args.join(", ")})`;
|
|
2759
|
+
return {
|
|
2760
|
+
sql: `${rawSql};`,
|
|
2761
|
+
params: [...ctx.params],
|
|
2762
|
+
outParams: {
|
|
2763
|
+
source: outNames.length ? "firstResultSet" : "none",
|
|
2764
|
+
names: outNames
|
|
2765
|
+
}
|
|
2766
|
+
};
|
|
2767
|
+
}
|
|
2705
2768
|
/**
|
|
2706
2769
|
* PostgreSQL requires unqualified column names in SET clause
|
|
2707
2770
|
*/
|
|
@@ -2801,6 +2864,7 @@ var MysqlFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
2801
2864
|
};
|
|
2802
2865
|
|
|
2803
2866
|
// src/core/dialect/mysql/index.ts
|
|
2867
|
+
var sanitizeVariableSuffix = (value) => value.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
2804
2868
|
var MySqlDialect = class extends SqlDialectBase {
|
|
2805
2869
|
dialect = "mysql";
|
|
2806
2870
|
/**
|
|
@@ -2826,6 +2890,73 @@ var MySqlDialect = class extends SqlDialectBase {
|
|
|
2826
2890
|
const col2 = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
|
|
2827
2891
|
return `${col2}->'${node.path}'`;
|
|
2828
2892
|
}
|
|
2893
|
+
compileUpsertClause(ast, ctx) {
|
|
2894
|
+
if (!ast.onConflict) return "";
|
|
2895
|
+
const clause = ast.onConflict;
|
|
2896
|
+
if (clause.action.type === "DoNothing") {
|
|
2897
|
+
const noOpColumn = clause.target.columns[0] ?? ast.columns[0];
|
|
2898
|
+
if (!noOpColumn) {
|
|
2899
|
+
throw new Error("MySQL ON DUPLICATE KEY UPDATE requires at least one target column.");
|
|
2900
|
+
}
|
|
2901
|
+
const col2 = this.quoteIdentifier(noOpColumn.name);
|
|
2902
|
+
return ` ON DUPLICATE KEY UPDATE ${col2} = ${col2}`;
|
|
2903
|
+
}
|
|
2904
|
+
if (clause.action.where) {
|
|
2905
|
+
throw new Error("MySQL ON DUPLICATE KEY UPDATE does not support a WHERE clause.");
|
|
2906
|
+
}
|
|
2907
|
+
if (!clause.action.set.length) {
|
|
2908
|
+
throw new Error("MySQL ON DUPLICATE KEY UPDATE requires at least one assignment.");
|
|
2909
|
+
}
|
|
2910
|
+
const assignments = clause.action.set.map((assignment) => {
|
|
2911
|
+
const target = this.quoteIdentifier(assignment.column.name);
|
|
2912
|
+
const value = this.compileOperand(assignment.value, ctx);
|
|
2913
|
+
return `${target} = ${value}`;
|
|
2914
|
+
}).join(", ");
|
|
2915
|
+
return ` ON DUPLICATE KEY UPDATE ${assignments}`;
|
|
2916
|
+
}
|
|
2917
|
+
compileProcedureCall(ast) {
|
|
2918
|
+
const ctx = this.createCompilerContext();
|
|
2919
|
+
const qualifiedName = ast.ref.schema ? `${this.quoteIdentifier(ast.ref.schema)}.${this.quoteIdentifier(ast.ref.name)}` : this.quoteIdentifier(ast.ref.name);
|
|
2920
|
+
const prelude = [];
|
|
2921
|
+
const callArgs = [];
|
|
2922
|
+
const outVars = [];
|
|
2923
|
+
ast.params.forEach((param, index) => {
|
|
2924
|
+
const suffix = sanitizeVariableSuffix(param.name || `p${index + 1}`);
|
|
2925
|
+
const variable = `@__metal_${suffix}_${index + 1}`;
|
|
2926
|
+
if (param.direction === "in") {
|
|
2927
|
+
if (!param.value) {
|
|
2928
|
+
throw new Error(`Procedure parameter "${param.name}" requires a value for direction "in".`);
|
|
2929
|
+
}
|
|
2930
|
+
callArgs.push(this.compileOperand(param.value, ctx));
|
|
2931
|
+
return;
|
|
2932
|
+
}
|
|
2933
|
+
if (param.direction === "inout") {
|
|
2934
|
+
if (!param.value) {
|
|
2935
|
+
throw new Error(`Procedure parameter "${param.name}" requires a value for direction "inout".`);
|
|
2936
|
+
}
|
|
2937
|
+
prelude.push(`SET ${variable} = ${this.compileOperand(param.value, ctx)};`);
|
|
2938
|
+
}
|
|
2939
|
+
callArgs.push(variable);
|
|
2940
|
+
outVars.push({ variable, name: param.name });
|
|
2941
|
+
});
|
|
2942
|
+
const statements = [];
|
|
2943
|
+
if (prelude.length) {
|
|
2944
|
+
statements.push(...prelude);
|
|
2945
|
+
}
|
|
2946
|
+
statements.push(`CALL ${qualifiedName}(${callArgs.join(", ")});`);
|
|
2947
|
+
if (outVars.length) {
|
|
2948
|
+
const selectOut = outVars.map(({ variable, name }) => `${variable} AS ${this.quoteIdentifier(name)}`).join(", ");
|
|
2949
|
+
statements.push(`SELECT ${selectOut};`);
|
|
2950
|
+
}
|
|
2951
|
+
return {
|
|
2952
|
+
sql: statements.join(" "),
|
|
2953
|
+
params: [...ctx.params],
|
|
2954
|
+
outParams: {
|
|
2955
|
+
source: outVars.length ? "lastResultSet" : "none",
|
|
2956
|
+
names: outVars.map((item) => item.name)
|
|
2957
|
+
}
|
|
2958
|
+
};
|
|
2959
|
+
}
|
|
2829
2960
|
};
|
|
2830
2961
|
|
|
2831
2962
|
// src/core/dialect/sqlite/functions.ts
|
|
@@ -3014,9 +3145,32 @@ var SqliteDialect = class extends SqlDialectBase {
|
|
|
3014
3145
|
return `${this.quoteIdentifier(column.name)}${alias}`;
|
|
3015
3146
|
}).join(", ");
|
|
3016
3147
|
}
|
|
3148
|
+
compileUpsertClause(ast, ctx) {
|
|
3149
|
+
if (!ast.onConflict) return "";
|
|
3150
|
+
const clause = ast.onConflict;
|
|
3151
|
+
if (clause.target.constraint) {
|
|
3152
|
+
throw new Error("SQLite ON CONFLICT does not support named constraints.");
|
|
3153
|
+
}
|
|
3154
|
+
this.ensureConflictColumns(clause, "SQLite ON CONFLICT requires conflict columns.");
|
|
3155
|
+
const cols = clause.target.columns.map((col2) => this.quoteIdentifier(col2.name)).join(", ");
|
|
3156
|
+
const target = ` ON CONFLICT (${cols})`;
|
|
3157
|
+
if (clause.action.type === "DoNothing") {
|
|
3158
|
+
return `${target} DO NOTHING`;
|
|
3159
|
+
}
|
|
3160
|
+
if (!clause.action.set.length) {
|
|
3161
|
+
throw new Error("SQLite ON CONFLICT DO UPDATE requires at least one assignment.");
|
|
3162
|
+
}
|
|
3163
|
+
const assignments = this.compileUpdateAssignments(clause.action.set, ast.into, ctx);
|
|
3164
|
+
const where = clause.action.where ? ` WHERE ${this.compileExpression(clause.action.where, ctx)}` : "";
|
|
3165
|
+
return `${target} DO UPDATE SET ${assignments}${where}`;
|
|
3166
|
+
}
|
|
3017
3167
|
supportsDmlReturningClause() {
|
|
3018
3168
|
return true;
|
|
3019
3169
|
}
|
|
3170
|
+
compileProcedureCall(_ast) {
|
|
3171
|
+
void _ast;
|
|
3172
|
+
throw new Error("Stored procedures are not supported by the SQLite dialect.");
|
|
3173
|
+
}
|
|
3020
3174
|
};
|
|
3021
3175
|
|
|
3022
3176
|
// src/core/dialect/mssql/functions.ts
|
|
@@ -3135,6 +3289,8 @@ var MssqlFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
3135
3289
|
};
|
|
3136
3290
|
|
|
3137
3291
|
// src/core/dialect/mssql/index.ts
|
|
3292
|
+
var sanitizeVariableSuffix2 = (value) => value.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
3293
|
+
var toProcedureParamReference = (value) => value.startsWith("@") ? value : `@${value}`;
|
|
3138
3294
|
var SqlServerDialect = class extends SqlDialectBase {
|
|
3139
3295
|
dialect = "mssql";
|
|
3140
3296
|
/**
|
|
@@ -3290,12 +3446,58 @@ var SqlServerDialect = class extends SqlDialectBase {
|
|
|
3290
3446
|
if (!ast.columns.length) {
|
|
3291
3447
|
throw new Error("INSERT queries must specify columns.");
|
|
3292
3448
|
}
|
|
3449
|
+
if (ast.onConflict) {
|
|
3450
|
+
return this.compileMergeInsert(ast, ctx);
|
|
3451
|
+
}
|
|
3293
3452
|
const table = this.compileTableName(ast.into);
|
|
3294
3453
|
const columnList = ast.columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
|
|
3295
3454
|
const output = this.compileReturning(ast.returning, ctx);
|
|
3296
3455
|
const source = this.compileInsertValues(ast, ctx);
|
|
3297
3456
|
return `INSERT INTO ${table} (${columnList})${output} ${source}`;
|
|
3298
3457
|
}
|
|
3458
|
+
compileMergeInsert(ast, ctx) {
|
|
3459
|
+
const clause = ast.onConflict;
|
|
3460
|
+
if (clause.target.constraint) {
|
|
3461
|
+
throw new Error("MSSQL MERGE does not support conflict target by constraint name.");
|
|
3462
|
+
}
|
|
3463
|
+
this.ensureConflictColumns(clause, "MSSQL MERGE requires conflict columns for the ON clause.");
|
|
3464
|
+
const table = this.compileTableName(ast.into);
|
|
3465
|
+
const targetRef = this.quoteIdentifier(ast.into.alias ?? ast.into.name);
|
|
3466
|
+
const sourceAlias = this.quoteIdentifier("src");
|
|
3467
|
+
const sourceColumns = ast.columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
|
|
3468
|
+
const usingSource = this.compileMergeUsingSource(ast, ctx);
|
|
3469
|
+
const onClause = clause.target.columns.map((column) => `${targetRef}.${this.quoteIdentifier(column.name)} = ${sourceAlias}.${this.quoteIdentifier(column.name)}`).join(" AND ");
|
|
3470
|
+
const branches = [];
|
|
3471
|
+
if (clause.action.type === "DoUpdate") {
|
|
3472
|
+
if (!clause.action.set.length) {
|
|
3473
|
+
throw new Error("MSSQL MERGE WHEN MATCHED UPDATE requires at least one assignment.");
|
|
3474
|
+
}
|
|
3475
|
+
const assignments = clause.action.set.map((assignment) => {
|
|
3476
|
+
const target = `${targetRef}.${this.quoteIdentifier(assignment.column.name)}`;
|
|
3477
|
+
const value = this.compileOperand(assignment.value, ctx);
|
|
3478
|
+
return `${target} = ${value}`;
|
|
3479
|
+
}).join(", ");
|
|
3480
|
+
const guard = clause.action.where ? ` AND ${this.compileExpression(clause.action.where, ctx)}` : "";
|
|
3481
|
+
branches.push(`WHEN MATCHED${guard} THEN UPDATE SET ${assignments}`);
|
|
3482
|
+
}
|
|
3483
|
+
const insertColumns = ast.columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
|
|
3484
|
+
const insertValues = ast.columns.map((column) => `${sourceAlias}.${this.quoteIdentifier(column.name)}`).join(", ");
|
|
3485
|
+
branches.push(`WHEN NOT MATCHED THEN INSERT (${insertColumns}) VALUES (${insertValues})`);
|
|
3486
|
+
const output = this.compileReturning(ast.returning, ctx);
|
|
3487
|
+
return `MERGE INTO ${table} USING ${usingSource} AS ${sourceAlias} (${sourceColumns}) ON ${onClause} ${branches.join(" ")}${output}`;
|
|
3488
|
+
}
|
|
3489
|
+
compileMergeUsingSource(ast, ctx) {
|
|
3490
|
+
if (ast.source.type === "InsertValues") {
|
|
3491
|
+
if (!ast.source.rows.length) {
|
|
3492
|
+
throw new Error("INSERT ... VALUES requires at least one row.");
|
|
3493
|
+
}
|
|
3494
|
+
const rows = ast.source.rows.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
|
|
3495
|
+
return `(VALUES ${rows})`;
|
|
3496
|
+
}
|
|
3497
|
+
const normalized = this.normalizeSelectAst(ast.source.query);
|
|
3498
|
+
const selectSql = this.compileSelectAst(normalized, ctx).trim().replace(/;$/, "");
|
|
3499
|
+
return `(${selectSql})`;
|
|
3500
|
+
}
|
|
3299
3501
|
compileInsertValues(ast, ctx) {
|
|
3300
3502
|
const source = ast.source;
|
|
3301
3503
|
if (source.type === "InsertValues") {
|
|
@@ -3318,6 +3520,57 @@ var SqlServerDialect = class extends SqlDialectBase {
|
|
|
3318
3520
|
}).join(", ");
|
|
3319
3521
|
return `WITH ${defs} `;
|
|
3320
3522
|
}
|
|
3523
|
+
compileProcedureCall(ast) {
|
|
3524
|
+
const ctx = this.createCompilerContext();
|
|
3525
|
+
const qualifiedName = ast.ref.schema ? `${this.quoteIdentifier(ast.ref.schema)}.${this.quoteIdentifier(ast.ref.name)}` : this.quoteIdentifier(ast.ref.name);
|
|
3526
|
+
const declarations = [];
|
|
3527
|
+
const assignments = [];
|
|
3528
|
+
const execArgs = [];
|
|
3529
|
+
const outVars = [];
|
|
3530
|
+
ast.params.forEach((param, index) => {
|
|
3531
|
+
const targetParam = toProcedureParamReference(param.name);
|
|
3532
|
+
if (param.direction === "in") {
|
|
3533
|
+
if (!param.value) {
|
|
3534
|
+
throw new Error(`Procedure parameter "${param.name}" requires a value for direction "in".`);
|
|
3535
|
+
}
|
|
3536
|
+
execArgs.push(`${targetParam} = ${this.compileOperand(param.value, ctx)}`);
|
|
3537
|
+
return;
|
|
3538
|
+
}
|
|
3539
|
+
if (!param.dbType) {
|
|
3540
|
+
throw new Error(
|
|
3541
|
+
`MSSQL procedure parameter "${param.name}" requires "dbType" for direction "${param.direction}".`
|
|
3542
|
+
);
|
|
3543
|
+
}
|
|
3544
|
+
const suffix = sanitizeVariableSuffix2(param.name || `p${index + 1}`);
|
|
3545
|
+
const variable = `@__metal_${suffix}_${index + 1}`;
|
|
3546
|
+
declarations.push(`DECLARE ${variable} ${param.dbType};`);
|
|
3547
|
+
if (param.direction === "inout") {
|
|
3548
|
+
if (!param.value) {
|
|
3549
|
+
throw new Error(`Procedure parameter "${param.name}" requires a value for direction "inout".`);
|
|
3550
|
+
}
|
|
3551
|
+
assignments.push(`SET ${variable} = ${this.compileOperand(param.value, ctx)};`);
|
|
3552
|
+
}
|
|
3553
|
+
execArgs.push(`${targetParam} = ${variable} OUTPUT`);
|
|
3554
|
+
outVars.push({ variable, name: param.name });
|
|
3555
|
+
});
|
|
3556
|
+
const statements = [];
|
|
3557
|
+
if (declarations.length) statements.push(...declarations);
|
|
3558
|
+
if (assignments.length) statements.push(...assignments);
|
|
3559
|
+
const argsSql = execArgs.length ? ` ${execArgs.join(", ")}` : "";
|
|
3560
|
+
statements.push(`EXEC ${qualifiedName}${argsSql};`);
|
|
3561
|
+
if (outVars.length) {
|
|
3562
|
+
const selectOut = outVars.map(({ variable, name }) => `${variable} AS ${this.quoteIdentifier(name)}`).join(", ");
|
|
3563
|
+
statements.push(`SELECT ${selectOut};`);
|
|
3564
|
+
}
|
|
3565
|
+
return {
|
|
3566
|
+
sql: statements.join(" "),
|
|
3567
|
+
params: [...ctx.params],
|
|
3568
|
+
outParams: {
|
|
3569
|
+
source: outVars.length ? "lastResultSet" : "none",
|
|
3570
|
+
names: outVars.map((item) => item.name)
|
|
3571
|
+
}
|
|
3572
|
+
};
|
|
3573
|
+
}
|
|
3321
3574
|
};
|
|
3322
3575
|
|
|
3323
3576
|
// src/core/dialect/dialect-factory.ts
|
|
@@ -7023,6 +7276,56 @@ var preloadRelationIncludes = async (entities, includeTree, depth = 0) => {
|
|
|
7023
7276
|
}
|
|
7024
7277
|
};
|
|
7025
7278
|
|
|
7279
|
+
// src/core/execution/db-executor.ts
|
|
7280
|
+
var toExecutionPayload = (resultSets) => {
|
|
7281
|
+
const payload = resultSets;
|
|
7282
|
+
payload.resultSets = resultSets;
|
|
7283
|
+
return payload;
|
|
7284
|
+
};
|
|
7285
|
+
var payloadResultSets = (payload) => payload.resultSets ?? payload;
|
|
7286
|
+
function rowsToQueryResult(rows) {
|
|
7287
|
+
if (rows.length === 0) {
|
|
7288
|
+
return { columns: [], values: [] };
|
|
7289
|
+
}
|
|
7290
|
+
const columns = Object.keys(rows[0]);
|
|
7291
|
+
const values = rows.map((row) => columns.map((c) => row[c]));
|
|
7292
|
+
return { columns, values };
|
|
7293
|
+
}
|
|
7294
|
+
function createExecutorFromQueryRunner(runner) {
|
|
7295
|
+
const supportsTransactions = typeof runner.beginTransaction === "function" && typeof runner.commitTransaction === "function" && typeof runner.rollbackTransaction === "function";
|
|
7296
|
+
return {
|
|
7297
|
+
capabilities: {
|
|
7298
|
+
transactions: supportsTransactions
|
|
7299
|
+
},
|
|
7300
|
+
async executeSql(sql, params) {
|
|
7301
|
+
const rows = await runner.query(sql, params);
|
|
7302
|
+
const result = rowsToQueryResult(rows);
|
|
7303
|
+
return toExecutionPayload([result]);
|
|
7304
|
+
},
|
|
7305
|
+
async beginTransaction() {
|
|
7306
|
+
if (!supportsTransactions) {
|
|
7307
|
+
throw new Error("Transactions are not supported by this executor");
|
|
7308
|
+
}
|
|
7309
|
+
await runner.beginTransaction.call(runner);
|
|
7310
|
+
},
|
|
7311
|
+
async commitTransaction() {
|
|
7312
|
+
if (!supportsTransactions) {
|
|
7313
|
+
throw new Error("Transactions are not supported by this executor");
|
|
7314
|
+
}
|
|
7315
|
+
await runner.commitTransaction.call(runner);
|
|
7316
|
+
},
|
|
7317
|
+
async rollbackTransaction() {
|
|
7318
|
+
if (!supportsTransactions) {
|
|
7319
|
+
throw new Error("Transactions are not supported by this executor");
|
|
7320
|
+
}
|
|
7321
|
+
await runner.rollbackTransaction.call(runner);
|
|
7322
|
+
},
|
|
7323
|
+
async dispose() {
|
|
7324
|
+
await runner.dispose?.call(runner);
|
|
7325
|
+
}
|
|
7326
|
+
};
|
|
7327
|
+
}
|
|
7328
|
+
|
|
7026
7329
|
// src/orm/execute.ts
|
|
7027
7330
|
var flattenResults = (results) => {
|
|
7028
7331
|
const rows = [];
|
|
@@ -7042,7 +7345,7 @@ var executeWithContexts = async (execCtx, entityCtx, qb) => {
|
|
|
7042
7345
|
const ast = qb.getAST();
|
|
7043
7346
|
const compiled = execCtx.dialect.compileSelect(ast);
|
|
7044
7347
|
const executed = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
7045
|
-
const rows = flattenResults(executed);
|
|
7348
|
+
const rows = flattenResults(payloadResultSets(executed));
|
|
7046
7349
|
const lazyRelations = qb.getLazyRelations();
|
|
7047
7350
|
const lazyRelationOptions = qb.getLazyRelationOptions();
|
|
7048
7351
|
const includeTree = qb.getIncludeTree();
|
|
@@ -7062,7 +7365,7 @@ var executePlainWithContexts = async (execCtx, qb) => {
|
|
|
7062
7365
|
const ast = qb.getAST();
|
|
7063
7366
|
const compiled = execCtx.dialect.compileSelect(ast);
|
|
7064
7367
|
const executed = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
7065
|
-
const rows = flattenResults(executed);
|
|
7368
|
+
const rows = flattenResults(payloadResultSets(executed));
|
|
7066
7369
|
if (ast.setOps && ast.setOps.length > 0) {
|
|
7067
7370
|
return rows;
|
|
7068
7371
|
}
|
|
@@ -7330,7 +7633,8 @@ async function executeCount(context, env, session) {
|
|
|
7330
7633
|
};
|
|
7331
7634
|
const execCtx = session.getExecutionContext();
|
|
7332
7635
|
const compiled = execCtx.dialect.compileSelect(countQuery);
|
|
7333
|
-
const
|
|
7636
|
+
const payload = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
7637
|
+
const results = payloadResultSets(payload);
|
|
7334
7638
|
const value = results[0]?.values?.[0]?.[0];
|
|
7335
7639
|
if (typeof value === "number") return value;
|
|
7336
7640
|
if (typeof value === "bigint") return Number(value);
|
|
@@ -7362,7 +7666,8 @@ async function executeCountRows(context, env, session) {
|
|
|
7362
7666
|
};
|
|
7363
7667
|
const execCtx = session.getExecutionContext();
|
|
7364
7668
|
const compiled = execCtx.dialect.compileSelect(countQuery);
|
|
7365
|
-
const
|
|
7669
|
+
const payload = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
7670
|
+
const results = payloadResultSets(payload);
|
|
7366
7671
|
const value = results[0]?.values?.[0]?.[0];
|
|
7367
7672
|
if (typeof value === "number") return value;
|
|
7368
7673
|
if (typeof value === "bigint") return Number(value);
|
|
@@ -8336,6 +8641,45 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
8336
8641
|
* // rows is EntityInstance<UserTable>[] (plain objects)
|
|
8337
8642
|
* rows[0] instanceof User; // false
|
|
8338
8643
|
*/
|
|
8644
|
+
/**
|
|
8645
|
+
* Executes the query with LIMIT 1 and returns the first result.
|
|
8646
|
+
* Throws if no record is found.
|
|
8647
|
+
*
|
|
8648
|
+
* @param ctx - ORM session context
|
|
8649
|
+
* @returns Promise of a single entity instance
|
|
8650
|
+
* @throws Error if no results are found
|
|
8651
|
+
* @example
|
|
8652
|
+
* const user = await selectFromEntity(User)
|
|
8653
|
+
* .where(eq(users.email, 'alice@example.com'))
|
|
8654
|
+
* .firstOrFail(session);
|
|
8655
|
+
*/
|
|
8656
|
+
async firstOrFail(ctx) {
|
|
8657
|
+
const rows = await this.limit(1).execute(ctx);
|
|
8658
|
+
if (rows.length === 0) {
|
|
8659
|
+
throw new Error("No results found");
|
|
8660
|
+
}
|
|
8661
|
+
return rows[0];
|
|
8662
|
+
}
|
|
8663
|
+
/**
|
|
8664
|
+
* Executes the query with LIMIT 1 and returns the first result as a plain object (POJO).
|
|
8665
|
+
* Throws if no record is found.
|
|
8666
|
+
*
|
|
8667
|
+
* @param ctx - ORM session context
|
|
8668
|
+
* @returns Promise of a single plain object
|
|
8669
|
+
* @throws Error if no results are found
|
|
8670
|
+
* @example
|
|
8671
|
+
* const user = await selectFromEntity(User)
|
|
8672
|
+
* .where(eq(users.email, 'alice@example.com'))
|
|
8673
|
+
* .firstOrFailPlain(session);
|
|
8674
|
+
* // user is a plain object, not an instance of User
|
|
8675
|
+
*/
|
|
8676
|
+
async firstOrFailPlain(ctx) {
|
|
8677
|
+
const rows = await this.limit(1).executePlain(ctx);
|
|
8678
|
+
if (rows.length === 0) {
|
|
8679
|
+
throw new Error("No results found");
|
|
8680
|
+
}
|
|
8681
|
+
return rows[0];
|
|
8682
|
+
}
|
|
8339
8683
|
async executePlain(ctx) {
|
|
8340
8684
|
const builder = this.ensureDefaultSelection();
|
|
8341
8685
|
const rows = await executeHydratedPlain(ctx, builder);
|
|
@@ -9035,9 +9379,95 @@ var InsertQueryState = class _InsertQueryState {
|
|
|
9035
9379
|
returning: [...columns]
|
|
9036
9380
|
});
|
|
9037
9381
|
}
|
|
9382
|
+
/**
|
|
9383
|
+
* Adds an UPSERT conflict clause to the INSERT query
|
|
9384
|
+
* @param clause - Conflict clause and action
|
|
9385
|
+
* @returns A new InsertQueryState with conflict handling configured
|
|
9386
|
+
*/
|
|
9387
|
+
withOnConflict(clause) {
|
|
9388
|
+
return this.clone({
|
|
9389
|
+
...this.ast,
|
|
9390
|
+
onConflict: {
|
|
9391
|
+
target: {
|
|
9392
|
+
columns: [...clause.target.columns],
|
|
9393
|
+
constraint: clause.target.constraint
|
|
9394
|
+
},
|
|
9395
|
+
action: clause.action.type === "DoUpdate" ? {
|
|
9396
|
+
type: "DoUpdate",
|
|
9397
|
+
set: clause.action.set.map((assignment) => ({
|
|
9398
|
+
column: { ...assignment.column },
|
|
9399
|
+
value: assignment.value
|
|
9400
|
+
})),
|
|
9401
|
+
where: clause.action.where
|
|
9402
|
+
} : { type: "DoNothing" }
|
|
9403
|
+
}
|
|
9404
|
+
});
|
|
9405
|
+
}
|
|
9038
9406
|
};
|
|
9039
9407
|
|
|
9040
9408
|
// src/query-builder/insert.ts
|
|
9409
|
+
var ConflictBuilder = class {
|
|
9410
|
+
table;
|
|
9411
|
+
columns;
|
|
9412
|
+
constraint;
|
|
9413
|
+
applyClause;
|
|
9414
|
+
constructor(table, columns, constraint, applyClause) {
|
|
9415
|
+
this.table = table;
|
|
9416
|
+
this.columns = columns;
|
|
9417
|
+
this.constraint = constraint;
|
|
9418
|
+
this.applyClause = applyClause;
|
|
9419
|
+
}
|
|
9420
|
+
/**
|
|
9421
|
+
* Adds ON CONFLICT ... DO UPDATE
|
|
9422
|
+
* @param set - Column assignments for update branch
|
|
9423
|
+
* @param where - Optional filter for update branch
|
|
9424
|
+
* @returns InsertQueryBuilder with the upsert clause configured
|
|
9425
|
+
*/
|
|
9426
|
+
doUpdate(set, where) {
|
|
9427
|
+
const assignments = this.buildAssignments(set);
|
|
9428
|
+
return this.applyClause({
|
|
9429
|
+
target: this.buildTarget(),
|
|
9430
|
+
action: {
|
|
9431
|
+
type: "DoUpdate",
|
|
9432
|
+
set: assignments,
|
|
9433
|
+
where
|
|
9434
|
+
}
|
|
9435
|
+
});
|
|
9436
|
+
}
|
|
9437
|
+
/**
|
|
9438
|
+
* Adds ON CONFLICT ... DO NOTHING
|
|
9439
|
+
* @returns InsertQueryBuilder with the upsert clause configured
|
|
9440
|
+
*/
|
|
9441
|
+
doNothing() {
|
|
9442
|
+
return this.applyClause({
|
|
9443
|
+
target: this.buildTarget(),
|
|
9444
|
+
action: { type: "DoNothing" }
|
|
9445
|
+
});
|
|
9446
|
+
}
|
|
9447
|
+
buildTarget() {
|
|
9448
|
+
return {
|
|
9449
|
+
columns: [...this.columns],
|
|
9450
|
+
constraint: this.constraint
|
|
9451
|
+
};
|
|
9452
|
+
}
|
|
9453
|
+
buildAssignments(set) {
|
|
9454
|
+
const entries = Object.entries(set);
|
|
9455
|
+
if (!entries.length) {
|
|
9456
|
+
throw new Error("ON CONFLICT DO UPDATE requires at least one assignment.");
|
|
9457
|
+
}
|
|
9458
|
+
return entries.map(([columnName, rawValue]) => {
|
|
9459
|
+
if (!isValueOperandInput(rawValue)) {
|
|
9460
|
+
throw new Error(
|
|
9461
|
+
`Invalid upsert value for column "${columnName}": only string, number, boolean, Date, Buffer, null, or OperandNodes are allowed`
|
|
9462
|
+
);
|
|
9463
|
+
}
|
|
9464
|
+
return {
|
|
9465
|
+
column: buildColumnNode(this.table, { name: columnName, table: this.table.name }),
|
|
9466
|
+
value: valueToOperand(rawValue)
|
|
9467
|
+
};
|
|
9468
|
+
});
|
|
9469
|
+
}
|
|
9470
|
+
};
|
|
9041
9471
|
var InsertQueryBuilder = class _InsertQueryBuilder {
|
|
9042
9472
|
table;
|
|
9043
9473
|
state;
|
|
@@ -9053,6 +9483,9 @@ var InsertQueryBuilder = class _InsertQueryBuilder {
|
|
|
9053
9483
|
clone(state) {
|
|
9054
9484
|
return new _InsertQueryBuilder(this.table, state);
|
|
9055
9485
|
}
|
|
9486
|
+
withOnConflict(clause) {
|
|
9487
|
+
return this.clone(this.state.withOnConflict(clause));
|
|
9488
|
+
}
|
|
9056
9489
|
/**
|
|
9057
9490
|
* Adds VALUES to the INSERT query
|
|
9058
9491
|
* @param rowOrRows - Single row object or array of row objects to insert
|
|
@@ -9084,6 +9517,21 @@ var InsertQueryBuilder = class _InsertQueryBuilder {
|
|
|
9084
9517
|
const nodes = columns.length ? this.resolveColumnNodes(columns) : [];
|
|
9085
9518
|
return this.clone(this.state.withSelect(ast, nodes));
|
|
9086
9519
|
}
|
|
9520
|
+
/**
|
|
9521
|
+
* Configures UPSERT conflict handling for INSERT.
|
|
9522
|
+
* @param columns - Conflict target columns (ignored by MySQL)
|
|
9523
|
+
* @param constraint - Named unique/primary constraint (PostgreSQL only)
|
|
9524
|
+
* @returns ConflictBuilder for selecting action (DO UPDATE / DO NOTHING)
|
|
9525
|
+
*/
|
|
9526
|
+
onConflict(columns = [], constraint) {
|
|
9527
|
+
const resolvedColumns = columns.length ? this.resolveColumnNodes(columns) : [];
|
|
9528
|
+
return new ConflictBuilder(
|
|
9529
|
+
this.table,
|
|
9530
|
+
resolvedColumns,
|
|
9531
|
+
constraint,
|
|
9532
|
+
(clause) => this.withOnConflict(clause)
|
|
9533
|
+
);
|
|
9534
|
+
}
|
|
9087
9535
|
/**
|
|
9088
9536
|
* Adds a RETURNING clause to the INSERT query
|
|
9089
9537
|
* @param columns - Columns to return after insertion
|
|
@@ -9361,7 +9809,8 @@ var UpdateQueryBuilder = class _UpdateQueryBuilder {
|
|
|
9361
9809
|
async execute(session) {
|
|
9362
9810
|
const execCtx = session.getExecutionContext();
|
|
9363
9811
|
const compiled = this.compile(execCtx.dialect);
|
|
9364
|
-
|
|
9812
|
+
const payload = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
9813
|
+
return payloadResultSets(payload);
|
|
9365
9814
|
}
|
|
9366
9815
|
/**
|
|
9367
9816
|
* Returns the Abstract Syntax Tree (AST) representation of the query
|
|
@@ -9551,7 +10000,8 @@ var DeleteQueryBuilder = class _DeleteQueryBuilder {
|
|
|
9551
10000
|
async execute(session) {
|
|
9552
10001
|
const execCtx = session.getExecutionContext();
|
|
9553
10002
|
const compiled = this.compile(execCtx.dialect);
|
|
9554
|
-
|
|
10003
|
+
const payload = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
10004
|
+
return payloadResultSets(payload);
|
|
9555
10005
|
}
|
|
9556
10006
|
/**
|
|
9557
10007
|
* Returns the Abstract Syntax Tree (AST) representation of the query
|
|
@@ -9563,6 +10013,149 @@ var DeleteQueryBuilder = class _DeleteQueryBuilder {
|
|
|
9563
10013
|
};
|
|
9564
10014
|
var isTableSourceNode2 = (source) => typeof source.type === "string";
|
|
9565
10015
|
|
|
10016
|
+
// src/orm/execute-procedure.ts
|
|
10017
|
+
var resolveColumnIndex = (columns, expectedName) => {
|
|
10018
|
+
const exact = columns.findIndex((column) => column === expectedName);
|
|
10019
|
+
if (exact >= 0) return exact;
|
|
10020
|
+
const lowerExpected = expectedName.toLowerCase();
|
|
10021
|
+
return columns.findIndex((column) => column.toLowerCase() === lowerExpected);
|
|
10022
|
+
};
|
|
10023
|
+
var extractOutValues = (compiled, resultSets) => {
|
|
10024
|
+
if (!compiled.outParams.names.length || compiled.outParams.source === "none") {
|
|
10025
|
+
return {};
|
|
10026
|
+
}
|
|
10027
|
+
const sourceSet = compiled.outParams.source === "firstResultSet" ? resultSets[0] : resultSets[resultSets.length - 1];
|
|
10028
|
+
if (!sourceSet) {
|
|
10029
|
+
throw new Error(
|
|
10030
|
+
`Procedure expected OUT parameters in ${compiled.outParams.source}, but no result set was returned.`
|
|
10031
|
+
);
|
|
10032
|
+
}
|
|
10033
|
+
if (!sourceSet.values.length) {
|
|
10034
|
+
throw new Error(
|
|
10035
|
+
`Procedure expected OUT parameters in ${compiled.outParams.source}, but the result set has no rows.`
|
|
10036
|
+
);
|
|
10037
|
+
}
|
|
10038
|
+
const firstRow = sourceSet.values[0];
|
|
10039
|
+
const out = {};
|
|
10040
|
+
for (const expectedName of compiled.outParams.names) {
|
|
10041
|
+
const columnIndex = resolveColumnIndex(sourceSet.columns, expectedName);
|
|
10042
|
+
if (columnIndex < 0) {
|
|
10043
|
+
const available = sourceSet.columns.length ? sourceSet.columns.join(", ") : "(none)";
|
|
10044
|
+
throw new Error(
|
|
10045
|
+
`Procedure OUT parameter "${expectedName}" was not found in ${compiled.outParams.source}. Available columns: ${available}.`
|
|
10046
|
+
);
|
|
10047
|
+
}
|
|
10048
|
+
out[expectedName] = firstRow[columnIndex];
|
|
10049
|
+
}
|
|
10050
|
+
return out;
|
|
10051
|
+
};
|
|
10052
|
+
var executeProcedureAst = async (session, ast) => {
|
|
10053
|
+
const execCtx = session.getExecutionContext();
|
|
10054
|
+
const compiled = execCtx.dialect.compileProcedureCall(ast);
|
|
10055
|
+
const payload = await execCtx.interceptors.run(
|
|
10056
|
+
{ sql: compiled.sql, params: compiled.params },
|
|
10057
|
+
execCtx.executor
|
|
10058
|
+
);
|
|
10059
|
+
const resultSets = payloadResultSets(payload);
|
|
10060
|
+
return {
|
|
10061
|
+
resultSets,
|
|
10062
|
+
out: extractOutValues(compiled, resultSets)
|
|
10063
|
+
};
|
|
10064
|
+
};
|
|
10065
|
+
|
|
10066
|
+
// src/query-builder/procedure-call.ts
|
|
10067
|
+
var cloneParam = (param) => ({
|
|
10068
|
+
...param,
|
|
10069
|
+
value: param.value ? { ...param.value } : void 0
|
|
10070
|
+
});
|
|
10071
|
+
var ProcedureCallBuilder = class _ProcedureCallBuilder {
|
|
10072
|
+
ast;
|
|
10073
|
+
constructor(name, options, ast) {
|
|
10074
|
+
this.ast = ast ?? {
|
|
10075
|
+
type: "ProcedureCall",
|
|
10076
|
+
ref: {
|
|
10077
|
+
name,
|
|
10078
|
+
schema: options?.schema
|
|
10079
|
+
},
|
|
10080
|
+
params: []
|
|
10081
|
+
};
|
|
10082
|
+
}
|
|
10083
|
+
clone(nextParams) {
|
|
10084
|
+
return new _ProcedureCallBuilder(
|
|
10085
|
+
this.ast.ref.name,
|
|
10086
|
+
{ schema: this.ast.ref.schema },
|
|
10087
|
+
{
|
|
10088
|
+
...this.ast,
|
|
10089
|
+
ref: { ...this.ast.ref },
|
|
10090
|
+
params: nextParams
|
|
10091
|
+
}
|
|
10092
|
+
);
|
|
10093
|
+
}
|
|
10094
|
+
in(name, value) {
|
|
10095
|
+
return this.clone([
|
|
10096
|
+
...this.ast.params.map(cloneParam),
|
|
10097
|
+
{
|
|
10098
|
+
name,
|
|
10099
|
+
direction: "in",
|
|
10100
|
+
value: valueToOperand(value)
|
|
10101
|
+
}
|
|
10102
|
+
]);
|
|
10103
|
+
}
|
|
10104
|
+
out(name, options) {
|
|
10105
|
+
return this.clone([
|
|
10106
|
+
...this.ast.params.map(cloneParam),
|
|
10107
|
+
{
|
|
10108
|
+
name,
|
|
10109
|
+
direction: "out",
|
|
10110
|
+
dbType: options?.dbType
|
|
10111
|
+
}
|
|
10112
|
+
]);
|
|
10113
|
+
}
|
|
10114
|
+
inOut(name, value, options) {
|
|
10115
|
+
return this.clone([
|
|
10116
|
+
...this.ast.params.map(cloneParam),
|
|
10117
|
+
{
|
|
10118
|
+
name,
|
|
10119
|
+
direction: "inout",
|
|
10120
|
+
value: valueToOperand(value),
|
|
10121
|
+
dbType: options?.dbType
|
|
10122
|
+
}
|
|
10123
|
+
]);
|
|
10124
|
+
}
|
|
10125
|
+
compile(dialect) {
|
|
10126
|
+
const resolved = resolveDialectInput(dialect);
|
|
10127
|
+
this.validateMssqlOutDbType(resolved);
|
|
10128
|
+
return resolved.compileProcedureCall(this.getAST());
|
|
10129
|
+
}
|
|
10130
|
+
toSql(dialect) {
|
|
10131
|
+
return this.compile(dialect).sql;
|
|
10132
|
+
}
|
|
10133
|
+
getAST() {
|
|
10134
|
+
return {
|
|
10135
|
+
...this.ast,
|
|
10136
|
+
ref: { ...this.ast.ref },
|
|
10137
|
+
params: this.ast.params.map(cloneParam)
|
|
10138
|
+
};
|
|
10139
|
+
}
|
|
10140
|
+
async execute(session) {
|
|
10141
|
+
this.validateMssqlOutDbType(session.getExecutionContext().dialect);
|
|
10142
|
+
return executeProcedureAst(session, this.getAST());
|
|
10143
|
+
}
|
|
10144
|
+
validateMssqlOutDbType(dialect) {
|
|
10145
|
+
const isMssqlDialect = dialect.constructor.name === "SqlServerDialect";
|
|
10146
|
+
if (!isMssqlDialect) return;
|
|
10147
|
+
for (const param of this.ast.params) {
|
|
10148
|
+
const needsDbType = param.direction === "out" || param.direction === "inout";
|
|
10149
|
+
if (needsDbType && !param.dbType) {
|
|
10150
|
+
throw new Error(
|
|
10151
|
+
`MSSQL requires "dbType" for procedure parameter "${param.name}" with direction "${param.direction}".`
|
|
10152
|
+
);
|
|
10153
|
+
}
|
|
10154
|
+
}
|
|
10155
|
+
}
|
|
10156
|
+
};
|
|
10157
|
+
var callProcedure = (name, options) => new ProcedureCallBuilder(name, options);
|
|
10158
|
+
|
|
9566
10159
|
// src/query/target.ts
|
|
9567
10160
|
var resolveEntityTarget = (ctor) => {
|
|
9568
10161
|
const table = getTableDefFromEntity(ctor);
|
|
@@ -12741,7 +13334,8 @@ var UnitOfWork = class {
|
|
|
12741
13334
|
* @returns Query results
|
|
12742
13335
|
*/
|
|
12743
13336
|
async executeCompiled(compiled) {
|
|
12744
|
-
|
|
13337
|
+
const payload = await this.executor.executeSql(compiled.sql, compiled.params);
|
|
13338
|
+
return payloadResultSets(payload);
|
|
12745
13339
|
}
|
|
12746
13340
|
/**
|
|
12747
13341
|
* Gets columns for RETURNING clause.
|
|
@@ -13885,9 +14479,9 @@ var InterceptorPipeline = class {
|
|
|
13885
14479
|
const dispatch = async () => {
|
|
13886
14480
|
const interceptor = this.interceptors[i++];
|
|
13887
14481
|
if (!interceptor) {
|
|
13888
|
-
return executor.executeSql(ctx.sql, ctx.params);
|
|
14482
|
+
return toExecutionPayload(await executor.executeSql(ctx.sql, ctx.params));
|
|
13889
14483
|
}
|
|
13890
|
-
return interceptor(ctx, dispatch);
|
|
14484
|
+
return toExecutionPayload(await interceptor(ctx, dispatch));
|
|
13891
14485
|
};
|
|
13892
14486
|
return dispatch();
|
|
13893
14487
|
}
|
|
@@ -15141,50 +15735,6 @@ function CEP(options) {
|
|
|
15141
15735
|
};
|
|
15142
15736
|
}
|
|
15143
15737
|
|
|
15144
|
-
// src/core/execution/db-executor.ts
|
|
15145
|
-
function rowsToQueryResult(rows) {
|
|
15146
|
-
if (rows.length === 0) {
|
|
15147
|
-
return { columns: [], values: [] };
|
|
15148
|
-
}
|
|
15149
|
-
const columns = Object.keys(rows[0]);
|
|
15150
|
-
const values = rows.map((row) => columns.map((c) => row[c]));
|
|
15151
|
-
return { columns, values };
|
|
15152
|
-
}
|
|
15153
|
-
function createExecutorFromQueryRunner(runner) {
|
|
15154
|
-
const supportsTransactions = typeof runner.beginTransaction === "function" && typeof runner.commitTransaction === "function" && typeof runner.rollbackTransaction === "function";
|
|
15155
|
-
return {
|
|
15156
|
-
capabilities: {
|
|
15157
|
-
transactions: supportsTransactions
|
|
15158
|
-
},
|
|
15159
|
-
async executeSql(sql, params) {
|
|
15160
|
-
const rows = await runner.query(sql, params);
|
|
15161
|
-
const result = rowsToQueryResult(rows);
|
|
15162
|
-
return [result];
|
|
15163
|
-
},
|
|
15164
|
-
async beginTransaction() {
|
|
15165
|
-
if (!supportsTransactions) {
|
|
15166
|
-
throw new Error("Transactions are not supported by this executor");
|
|
15167
|
-
}
|
|
15168
|
-
await runner.beginTransaction.call(runner);
|
|
15169
|
-
},
|
|
15170
|
-
async commitTransaction() {
|
|
15171
|
-
if (!supportsTransactions) {
|
|
15172
|
-
throw new Error("Transactions are not supported by this executor");
|
|
15173
|
-
}
|
|
15174
|
-
await runner.commitTransaction.call(runner);
|
|
15175
|
-
},
|
|
15176
|
-
async rollbackTransaction() {
|
|
15177
|
-
if (!supportsTransactions) {
|
|
15178
|
-
throw new Error("Transactions are not supported by this executor");
|
|
15179
|
-
}
|
|
15180
|
-
await runner.rollbackTransaction.call(runner);
|
|
15181
|
-
},
|
|
15182
|
-
async dispose() {
|
|
15183
|
-
await runner.dispose?.call(runner);
|
|
15184
|
-
}
|
|
15185
|
-
};
|
|
15186
|
-
}
|
|
15187
|
-
|
|
15188
15738
|
// src/core/execution/pooling/pool.ts
|
|
15189
15739
|
var deferred = () => {
|
|
15190
15740
|
let resolve;
|
|
@@ -15412,6 +15962,36 @@ function createPostgresExecutor(client) {
|
|
|
15412
15962
|
}
|
|
15413
15963
|
|
|
15414
15964
|
// src/core/execution/executors/mysql-executor.ts
|
|
15965
|
+
var isRowObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15966
|
+
var isRowObjectArray = (value) => Array.isArray(value) && value.every(isRowObject);
|
|
15967
|
+
var isMysqlResultHeader = (value) => isRowObject(value) && ("affectedRows" in value || "insertId" in value || "warningStatus" in value || "serverStatus" in value);
|
|
15968
|
+
var headerToQueryResult = (header) => ({
|
|
15969
|
+
columns: [],
|
|
15970
|
+
values: [],
|
|
15971
|
+
meta: {
|
|
15972
|
+
insertId: header.insertId,
|
|
15973
|
+
rowsAffected: header.affectedRows
|
|
15974
|
+
}
|
|
15975
|
+
});
|
|
15976
|
+
var normalizeMysqlResults = (rows) => {
|
|
15977
|
+
if (!Array.isArray(rows)) {
|
|
15978
|
+
return isMysqlResultHeader(rows) ? [headerToQueryResult(rows)] : [rowsToQueryResult([])];
|
|
15979
|
+
}
|
|
15980
|
+
if (isRowObjectArray(rows)) {
|
|
15981
|
+
return [rowsToQueryResult(rows)];
|
|
15982
|
+
}
|
|
15983
|
+
const normalized = [];
|
|
15984
|
+
for (const chunk of rows) {
|
|
15985
|
+
if (isRowObjectArray(chunk)) {
|
|
15986
|
+
normalized.push(rowsToQueryResult(chunk));
|
|
15987
|
+
continue;
|
|
15988
|
+
}
|
|
15989
|
+
if (isMysqlResultHeader(chunk)) {
|
|
15990
|
+
normalized.push(headerToQueryResult(chunk));
|
|
15991
|
+
}
|
|
15992
|
+
}
|
|
15993
|
+
return normalized.length ? normalized : [rowsToQueryResult([])];
|
|
15994
|
+
};
|
|
15415
15995
|
function createMysqlExecutor(client) {
|
|
15416
15996
|
const supportsTransactions = typeof client.beginTransaction === "function" && typeof client.commit === "function" && typeof client.rollback === "function";
|
|
15417
15997
|
return {
|
|
@@ -15420,21 +16000,7 @@ function createMysqlExecutor(client) {
|
|
|
15420
16000
|
},
|
|
15421
16001
|
async executeSql(sql, params) {
|
|
15422
16002
|
const [rows] = await client.query(sql, params);
|
|
15423
|
-
|
|
15424
|
-
const header = rows;
|
|
15425
|
-
return [{
|
|
15426
|
-
columns: [],
|
|
15427
|
-
values: [],
|
|
15428
|
-
meta: {
|
|
15429
|
-
insertId: header.insertId,
|
|
15430
|
-
rowsAffected: header.affectedRows
|
|
15431
|
-
}
|
|
15432
|
-
}];
|
|
15433
|
-
}
|
|
15434
|
-
const result = rowsToQueryResult(
|
|
15435
|
-
rows
|
|
15436
|
-
);
|
|
15437
|
-
return [result];
|
|
16003
|
+
return toExecutionPayload(normalizeMysqlResults(rows));
|
|
15438
16004
|
},
|
|
15439
16005
|
async beginTransaction() {
|
|
15440
16006
|
if (!supportsTransactions) {
|
|
@@ -15469,7 +16035,7 @@ function createSqliteExecutor(client) {
|
|
|
15469
16035
|
async executeSql(sql, params) {
|
|
15470
16036
|
const rows = await client.all(sql, params);
|
|
15471
16037
|
const result = rowsToQueryResult(rows);
|
|
15472
|
-
return [result];
|
|
16038
|
+
return toExecutionPayload([result]);
|
|
15473
16039
|
},
|
|
15474
16040
|
async beginTransaction() {
|
|
15475
16041
|
if (!supportsTransactions) {
|
|
@@ -15502,9 +16068,9 @@ function createMssqlExecutor(client) {
|
|
|
15502
16068
|
transactions: supportsTransactions
|
|
15503
16069
|
},
|
|
15504
16070
|
async executeSql(sql, params) {
|
|
15505
|
-
const { recordset } = await client.query(sql, params);
|
|
15506
|
-
const
|
|
15507
|
-
return [
|
|
16071
|
+
const { recordset, recordsets } = await client.query(sql, params);
|
|
16072
|
+
const sets = Array.isArray(recordsets) ? recordsets : [recordset ?? []];
|
|
16073
|
+
return toExecutionPayload(sets.map((set) => rowsToQueryResult(set ?? [])));
|
|
15508
16074
|
},
|
|
15509
16075
|
async beginTransaction() {
|
|
15510
16076
|
if (!supportsTransactions) {
|
|
@@ -15570,7 +16136,7 @@ function createTediousMssqlClient(connection, { Request, TYPES }, options) {
|
|
|
15570
16136
|
connection.execSql(request);
|
|
15571
16137
|
}
|
|
15572
16138
|
);
|
|
15573
|
-
return { recordset: rows };
|
|
16139
|
+
return { recordset: rows, recordsets: [rows] };
|
|
15574
16140
|
},
|
|
15575
16141
|
beginTransaction: connection.beginTransaction ? () => new Promise((resolve, reject) => {
|
|
15576
16142
|
connection.beginTransaction(
|
|
@@ -15595,6 +16161,8 @@ function createTediousExecutor(connection, module2, options) {
|
|
|
15595
16161
|
}
|
|
15596
16162
|
|
|
15597
16163
|
// src/orm/pooled-executor-factory.ts
|
|
16164
|
+
var isQueryResult = (value) => typeof value === "object" && value !== null && Array.isArray(value.columns) && Array.isArray(value.values);
|
|
16165
|
+
var isRowArray = (value) => Array.isArray(value) && value.every((item) => typeof item === "object" && item !== null && !Array.isArray(item));
|
|
15598
16166
|
function createPooledExecutorFactory(opts) {
|
|
15599
16167
|
const { pool, adapter } = opts;
|
|
15600
16168
|
const makeExecutor = (mode) => {
|
|
@@ -15606,7 +16174,13 @@ function createPooledExecutorFactory(opts) {
|
|
|
15606
16174
|
};
|
|
15607
16175
|
const executeWithConn = async (conn, sql, params) => {
|
|
15608
16176
|
const rows = await adapter.query(conn, sql, params);
|
|
15609
|
-
|
|
16177
|
+
if (Array.isArray(rows) && rows.length > 0 && rows.every(isQueryResult)) {
|
|
16178
|
+
return toExecutionPayload(rows);
|
|
16179
|
+
}
|
|
16180
|
+
if (Array.isArray(rows) && rows.length > 0 && rows.every(isRowArray)) {
|
|
16181
|
+
return toExecutionPayload(rows.map((set) => rowsToQueryResult(set)));
|
|
16182
|
+
}
|
|
16183
|
+
return toExecutionPayload([rowsToQueryResult(rows)]);
|
|
15610
16184
|
};
|
|
15611
16185
|
return {
|
|
15612
16186
|
capabilities: { transactions: true },
|
|
@@ -19182,6 +19756,7 @@ var TagIndex = class {
|
|
|
19182
19756
|
CPF,
|
|
19183
19757
|
Capitalize,
|
|
19184
19758
|
Column,
|
|
19759
|
+
ConflictBuilder,
|
|
19185
19760
|
ConstructorMaterializationStrategy,
|
|
19186
19761
|
DEFAULT_TREE_CONFIG,
|
|
19187
19762
|
DateTimeTypeStrategy,
|
|
@@ -19214,6 +19789,7 @@ var TagIndex = class {
|
|
|
19214
19789
|
Pool,
|
|
19215
19790
|
PostgresDialect,
|
|
19216
19791
|
PrimaryKey,
|
|
19792
|
+
ProcedureCallBuilder,
|
|
19217
19793
|
PrototypeMaterializationStrategy,
|
|
19218
19794
|
QueryCacheManager,
|
|
19219
19795
|
RedisCacheAdapter,
|
|
@@ -19263,6 +19839,7 @@ var TagIndex = class {
|
|
|
19263
19839
|
buildScopeConditions,
|
|
19264
19840
|
calculateRowDepths,
|
|
19265
19841
|
calculateTotalPages,
|
|
19842
|
+
callProcedure,
|
|
19266
19843
|
canonicalizeSchema,
|
|
19267
19844
|
caseWhen,
|
|
19268
19845
|
cast,
|
|
@@ -19335,6 +19912,7 @@ var TagIndex = class {
|
|
|
19335
19912
|
executeHydratedPlain,
|
|
19336
19913
|
executeHydratedPlainWithContexts,
|
|
19337
19914
|
executeHydratedWithContexts,
|
|
19915
|
+
executeProcedureAst,
|
|
19338
19916
|
executeSchemaSql,
|
|
19339
19917
|
executeSchemaSqlFor,
|
|
19340
19918
|
exists,
|
|
@@ -19462,6 +20040,7 @@ var TagIndex = class {
|
|
|
19462
20040
|
paginationParamsSchema,
|
|
19463
20041
|
parameterToRef,
|
|
19464
20042
|
parseDuration,
|
|
20043
|
+
payloadResultSets,
|
|
19465
20044
|
pi,
|
|
19466
20045
|
pick,
|
|
19467
20046
|
position,
|
|
@@ -19521,6 +20100,7 @@ var TagIndex = class {
|
|
|
19521
20100
|
threadResults,
|
|
19522
20101
|
threadedNodeToOpenApiSchema,
|
|
19523
20102
|
toColumnRef,
|
|
20103
|
+
toExecutionPayload,
|
|
19524
20104
|
toPagedResponse,
|
|
19525
20105
|
toPagedResponseBuilder,
|
|
19526
20106
|
toPaginationParams,
|