metal-orm 1.1.3 → 1.1.5
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/generate-entities/render.mjs +24 -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.js
CHANGED
|
@@ -1440,6 +1440,9 @@ var Dialect = class _Dialect {
|
|
|
1440
1440
|
compileDeleteAst() {
|
|
1441
1441
|
throw new Error("Not implemented");
|
|
1442
1442
|
}
|
|
1443
|
+
compileProcedureCall() {
|
|
1444
|
+
throw new Error("Not implemented");
|
|
1445
|
+
}
|
|
1443
1446
|
}
|
|
1444
1447
|
return new TestDialect(functionStrategy, tableFunctionStrategy);
|
|
1445
1448
|
}
|
|
@@ -1902,8 +1905,14 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1902
1905
|
const table = this.compileTableName(ast.into);
|
|
1903
1906
|
const columnList = this.compileInsertColumnList(ast.columns);
|
|
1904
1907
|
const source = this.compileInsertSource(ast.source, ctx);
|
|
1908
|
+
const upsert = this.compileUpsertClause(ast, ctx);
|
|
1905
1909
|
const returning = this.compileReturning(ast.returning, ctx);
|
|
1906
|
-
return `INSERT INTO ${table} (${columnList}) ${source}${returning}`;
|
|
1910
|
+
return `INSERT INTO ${table} (${columnList}) ${source}${upsert}${returning}`;
|
|
1911
|
+
}
|
|
1912
|
+
compileUpsertClause(ast, _ctx) {
|
|
1913
|
+
void _ctx;
|
|
1914
|
+
if (!ast.onConflict) return "";
|
|
1915
|
+
throw new Error(`UPSERT/ON CONFLICT is not supported by dialect "${this.dialect}".`);
|
|
1907
1916
|
}
|
|
1908
1917
|
compileReturning(returning, ctx) {
|
|
1909
1918
|
return this.returningStrategy.compileReturning(returning, ctx);
|
|
@@ -1922,6 +1931,11 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1922
1931
|
compileInsertColumnList(columns) {
|
|
1923
1932
|
return columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
|
|
1924
1933
|
}
|
|
1934
|
+
ensureConflictColumns(clause, message) {
|
|
1935
|
+
if (!clause.target.columns.length) {
|
|
1936
|
+
throw new Error(message);
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1925
1939
|
compileSelectCore(ast, ctx) {
|
|
1926
1940
|
const columns = this.compileSelectColumns(ast, ctx);
|
|
1927
1941
|
const from = this.compileFrom(ast.from, ctx);
|
|
@@ -2304,9 +2318,52 @@ var PostgresDialect = class extends SqlDialectBase {
|
|
|
2304
2318
|
const columns = this.formatReturningColumns(returning);
|
|
2305
2319
|
return ` RETURNING ${columns}`;
|
|
2306
2320
|
}
|
|
2321
|
+
compileUpsertClause(ast, ctx) {
|
|
2322
|
+
if (!ast.onConflict) return "";
|
|
2323
|
+
const clause = ast.onConflict;
|
|
2324
|
+
const target = clause.target.constraint ? ` ON CONFLICT ON CONSTRAINT ${this.quoteIdentifier(clause.target.constraint)}` : (() => {
|
|
2325
|
+
this.ensureConflictColumns(
|
|
2326
|
+
clause,
|
|
2327
|
+
"PostgreSQL ON CONFLICT requires conflict columns or a constraint name."
|
|
2328
|
+
);
|
|
2329
|
+
const cols = clause.target.columns.map((col2) => this.quoteIdentifier(col2.name)).join(", ");
|
|
2330
|
+
return ` ON CONFLICT (${cols})`;
|
|
2331
|
+
})();
|
|
2332
|
+
if (clause.action.type === "DoNothing") {
|
|
2333
|
+
return `${target} DO NOTHING`;
|
|
2334
|
+
}
|
|
2335
|
+
if (!clause.action.set.length) {
|
|
2336
|
+
throw new Error("PostgreSQL ON CONFLICT DO UPDATE requires at least one assignment.");
|
|
2337
|
+
}
|
|
2338
|
+
const assignments = this.compileUpdateAssignments(clause.action.set, ast.into, ctx);
|
|
2339
|
+
const where = clause.action.where ? ` WHERE ${this.compileExpression(clause.action.where, ctx)}` : "";
|
|
2340
|
+
return `${target} DO UPDATE SET ${assignments}${where}`;
|
|
2341
|
+
}
|
|
2307
2342
|
supportsDmlReturningClause() {
|
|
2308
2343
|
return true;
|
|
2309
2344
|
}
|
|
2345
|
+
compileProcedureCall(ast) {
|
|
2346
|
+
const ctx = this.createCompilerContext();
|
|
2347
|
+
const qualifiedName = ast.ref.schema ? `${this.quoteIdentifier(ast.ref.schema)}.${this.quoteIdentifier(ast.ref.name)}` : this.quoteIdentifier(ast.ref.name);
|
|
2348
|
+
const args = [];
|
|
2349
|
+
for (const param of ast.params) {
|
|
2350
|
+
if (param.direction === "out") continue;
|
|
2351
|
+
if (!param.value) {
|
|
2352
|
+
throw new Error(`Procedure parameter "${param.name}" requires a value for direction "${param.direction}".`);
|
|
2353
|
+
}
|
|
2354
|
+
args.push(this.compileOperand(param.value, ctx));
|
|
2355
|
+
}
|
|
2356
|
+
const outNames = ast.params.filter((param) => param.direction === "out" || param.direction === "inout").map((param) => param.name);
|
|
2357
|
+
const rawSql = `CALL ${qualifiedName}(${args.join(", ")})`;
|
|
2358
|
+
return {
|
|
2359
|
+
sql: `${rawSql};`,
|
|
2360
|
+
params: [...ctx.params],
|
|
2361
|
+
outParams: {
|
|
2362
|
+
source: outNames.length ? "firstResultSet" : "none",
|
|
2363
|
+
names: outNames
|
|
2364
|
+
}
|
|
2365
|
+
};
|
|
2366
|
+
}
|
|
2310
2367
|
/**
|
|
2311
2368
|
* PostgreSQL requires unqualified column names in SET clause
|
|
2312
2369
|
*/
|
|
@@ -2406,6 +2463,7 @@ var MysqlFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
2406
2463
|
};
|
|
2407
2464
|
|
|
2408
2465
|
// src/core/dialect/mysql/index.ts
|
|
2466
|
+
var sanitizeVariableSuffix = (value) => value.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
2409
2467
|
var MySqlDialect = class extends SqlDialectBase {
|
|
2410
2468
|
dialect = "mysql";
|
|
2411
2469
|
/**
|
|
@@ -2431,6 +2489,73 @@ var MySqlDialect = class extends SqlDialectBase {
|
|
|
2431
2489
|
const col2 = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
|
|
2432
2490
|
return `${col2}->'${node.path}'`;
|
|
2433
2491
|
}
|
|
2492
|
+
compileUpsertClause(ast, ctx) {
|
|
2493
|
+
if (!ast.onConflict) return "";
|
|
2494
|
+
const clause = ast.onConflict;
|
|
2495
|
+
if (clause.action.type === "DoNothing") {
|
|
2496
|
+
const noOpColumn = clause.target.columns[0] ?? ast.columns[0];
|
|
2497
|
+
if (!noOpColumn) {
|
|
2498
|
+
throw new Error("MySQL ON DUPLICATE KEY UPDATE requires at least one target column.");
|
|
2499
|
+
}
|
|
2500
|
+
const col2 = this.quoteIdentifier(noOpColumn.name);
|
|
2501
|
+
return ` ON DUPLICATE KEY UPDATE ${col2} = ${col2}`;
|
|
2502
|
+
}
|
|
2503
|
+
if (clause.action.where) {
|
|
2504
|
+
throw new Error("MySQL ON DUPLICATE KEY UPDATE does not support a WHERE clause.");
|
|
2505
|
+
}
|
|
2506
|
+
if (!clause.action.set.length) {
|
|
2507
|
+
throw new Error("MySQL ON DUPLICATE KEY UPDATE requires at least one assignment.");
|
|
2508
|
+
}
|
|
2509
|
+
const assignments = clause.action.set.map((assignment) => {
|
|
2510
|
+
const target = this.quoteIdentifier(assignment.column.name);
|
|
2511
|
+
const value = this.compileOperand(assignment.value, ctx);
|
|
2512
|
+
return `${target} = ${value}`;
|
|
2513
|
+
}).join(", ");
|
|
2514
|
+
return ` ON DUPLICATE KEY UPDATE ${assignments}`;
|
|
2515
|
+
}
|
|
2516
|
+
compileProcedureCall(ast) {
|
|
2517
|
+
const ctx = this.createCompilerContext();
|
|
2518
|
+
const qualifiedName = ast.ref.schema ? `${this.quoteIdentifier(ast.ref.schema)}.${this.quoteIdentifier(ast.ref.name)}` : this.quoteIdentifier(ast.ref.name);
|
|
2519
|
+
const prelude = [];
|
|
2520
|
+
const callArgs = [];
|
|
2521
|
+
const outVars = [];
|
|
2522
|
+
ast.params.forEach((param, index) => {
|
|
2523
|
+
const suffix = sanitizeVariableSuffix(param.name || `p${index + 1}`);
|
|
2524
|
+
const variable = `@__metal_${suffix}_${index + 1}`;
|
|
2525
|
+
if (param.direction === "in") {
|
|
2526
|
+
if (!param.value) {
|
|
2527
|
+
throw new Error(`Procedure parameter "${param.name}" requires a value for direction "in".`);
|
|
2528
|
+
}
|
|
2529
|
+
callArgs.push(this.compileOperand(param.value, ctx));
|
|
2530
|
+
return;
|
|
2531
|
+
}
|
|
2532
|
+
if (param.direction === "inout") {
|
|
2533
|
+
if (!param.value) {
|
|
2534
|
+
throw new Error(`Procedure parameter "${param.name}" requires a value for direction "inout".`);
|
|
2535
|
+
}
|
|
2536
|
+
prelude.push(`SET ${variable} = ${this.compileOperand(param.value, ctx)};`);
|
|
2537
|
+
}
|
|
2538
|
+
callArgs.push(variable);
|
|
2539
|
+
outVars.push({ variable, name: param.name });
|
|
2540
|
+
});
|
|
2541
|
+
const statements = [];
|
|
2542
|
+
if (prelude.length) {
|
|
2543
|
+
statements.push(...prelude);
|
|
2544
|
+
}
|
|
2545
|
+
statements.push(`CALL ${qualifiedName}(${callArgs.join(", ")});`);
|
|
2546
|
+
if (outVars.length) {
|
|
2547
|
+
const selectOut = outVars.map(({ variable, name }) => `${variable} AS ${this.quoteIdentifier(name)}`).join(", ");
|
|
2548
|
+
statements.push(`SELECT ${selectOut};`);
|
|
2549
|
+
}
|
|
2550
|
+
return {
|
|
2551
|
+
sql: statements.join(" "),
|
|
2552
|
+
params: [...ctx.params],
|
|
2553
|
+
outParams: {
|
|
2554
|
+
source: outVars.length ? "lastResultSet" : "none",
|
|
2555
|
+
names: outVars.map((item) => item.name)
|
|
2556
|
+
}
|
|
2557
|
+
};
|
|
2558
|
+
}
|
|
2434
2559
|
};
|
|
2435
2560
|
|
|
2436
2561
|
// src/core/dialect/sqlite/functions.ts
|
|
@@ -2619,9 +2744,32 @@ var SqliteDialect = class extends SqlDialectBase {
|
|
|
2619
2744
|
return `${this.quoteIdentifier(column.name)}${alias}`;
|
|
2620
2745
|
}).join(", ");
|
|
2621
2746
|
}
|
|
2747
|
+
compileUpsertClause(ast, ctx) {
|
|
2748
|
+
if (!ast.onConflict) return "";
|
|
2749
|
+
const clause = ast.onConflict;
|
|
2750
|
+
if (clause.target.constraint) {
|
|
2751
|
+
throw new Error("SQLite ON CONFLICT does not support named constraints.");
|
|
2752
|
+
}
|
|
2753
|
+
this.ensureConflictColumns(clause, "SQLite ON CONFLICT requires conflict columns.");
|
|
2754
|
+
const cols = clause.target.columns.map((col2) => this.quoteIdentifier(col2.name)).join(", ");
|
|
2755
|
+
const target = ` ON CONFLICT (${cols})`;
|
|
2756
|
+
if (clause.action.type === "DoNothing") {
|
|
2757
|
+
return `${target} DO NOTHING`;
|
|
2758
|
+
}
|
|
2759
|
+
if (!clause.action.set.length) {
|
|
2760
|
+
throw new Error("SQLite ON CONFLICT DO UPDATE requires at least one assignment.");
|
|
2761
|
+
}
|
|
2762
|
+
const assignments = this.compileUpdateAssignments(clause.action.set, ast.into, ctx);
|
|
2763
|
+
const where = clause.action.where ? ` WHERE ${this.compileExpression(clause.action.where, ctx)}` : "";
|
|
2764
|
+
return `${target} DO UPDATE SET ${assignments}${where}`;
|
|
2765
|
+
}
|
|
2622
2766
|
supportsDmlReturningClause() {
|
|
2623
2767
|
return true;
|
|
2624
2768
|
}
|
|
2769
|
+
compileProcedureCall(_ast) {
|
|
2770
|
+
void _ast;
|
|
2771
|
+
throw new Error("Stored procedures are not supported by the SQLite dialect.");
|
|
2772
|
+
}
|
|
2625
2773
|
};
|
|
2626
2774
|
|
|
2627
2775
|
// src/core/dialect/mssql/functions.ts
|
|
@@ -2740,6 +2888,8 @@ var MssqlFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
2740
2888
|
};
|
|
2741
2889
|
|
|
2742
2890
|
// src/core/dialect/mssql/index.ts
|
|
2891
|
+
var sanitizeVariableSuffix2 = (value) => value.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
2892
|
+
var toProcedureParamReference = (value) => value.startsWith("@") ? value : `@${value}`;
|
|
2743
2893
|
var SqlServerDialect = class extends SqlDialectBase {
|
|
2744
2894
|
dialect = "mssql";
|
|
2745
2895
|
/**
|
|
@@ -2895,12 +3045,58 @@ var SqlServerDialect = class extends SqlDialectBase {
|
|
|
2895
3045
|
if (!ast.columns.length) {
|
|
2896
3046
|
throw new Error("INSERT queries must specify columns.");
|
|
2897
3047
|
}
|
|
3048
|
+
if (ast.onConflict) {
|
|
3049
|
+
return this.compileMergeInsert(ast, ctx);
|
|
3050
|
+
}
|
|
2898
3051
|
const table = this.compileTableName(ast.into);
|
|
2899
3052
|
const columnList = ast.columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
|
|
2900
3053
|
const output = this.compileReturning(ast.returning, ctx);
|
|
2901
3054
|
const source = this.compileInsertValues(ast, ctx);
|
|
2902
3055
|
return `INSERT INTO ${table} (${columnList})${output} ${source}`;
|
|
2903
3056
|
}
|
|
3057
|
+
compileMergeInsert(ast, ctx) {
|
|
3058
|
+
const clause = ast.onConflict;
|
|
3059
|
+
if (clause.target.constraint) {
|
|
3060
|
+
throw new Error("MSSQL MERGE does not support conflict target by constraint name.");
|
|
3061
|
+
}
|
|
3062
|
+
this.ensureConflictColumns(clause, "MSSQL MERGE requires conflict columns for the ON clause.");
|
|
3063
|
+
const table = this.compileTableName(ast.into);
|
|
3064
|
+
const targetRef = this.quoteIdentifier(ast.into.alias ?? ast.into.name);
|
|
3065
|
+
const sourceAlias = this.quoteIdentifier("src");
|
|
3066
|
+
const sourceColumns = ast.columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
|
|
3067
|
+
const usingSource = this.compileMergeUsingSource(ast, ctx);
|
|
3068
|
+
const onClause = clause.target.columns.map((column) => `${targetRef}.${this.quoteIdentifier(column.name)} = ${sourceAlias}.${this.quoteIdentifier(column.name)}`).join(" AND ");
|
|
3069
|
+
const branches = [];
|
|
3070
|
+
if (clause.action.type === "DoUpdate") {
|
|
3071
|
+
if (!clause.action.set.length) {
|
|
3072
|
+
throw new Error("MSSQL MERGE WHEN MATCHED UPDATE requires at least one assignment.");
|
|
3073
|
+
}
|
|
3074
|
+
const assignments = clause.action.set.map((assignment) => {
|
|
3075
|
+
const target = `${targetRef}.${this.quoteIdentifier(assignment.column.name)}`;
|
|
3076
|
+
const value = this.compileOperand(assignment.value, ctx);
|
|
3077
|
+
return `${target} = ${value}`;
|
|
3078
|
+
}).join(", ");
|
|
3079
|
+
const guard = clause.action.where ? ` AND ${this.compileExpression(clause.action.where, ctx)}` : "";
|
|
3080
|
+
branches.push(`WHEN MATCHED${guard} THEN UPDATE SET ${assignments}`);
|
|
3081
|
+
}
|
|
3082
|
+
const insertColumns = ast.columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
|
|
3083
|
+
const insertValues = ast.columns.map((column) => `${sourceAlias}.${this.quoteIdentifier(column.name)}`).join(", ");
|
|
3084
|
+
branches.push(`WHEN NOT MATCHED THEN INSERT (${insertColumns}) VALUES (${insertValues})`);
|
|
3085
|
+
const output = this.compileReturning(ast.returning, ctx);
|
|
3086
|
+
return `MERGE INTO ${table} USING ${usingSource} AS ${sourceAlias} (${sourceColumns}) ON ${onClause} ${branches.join(" ")}${output}`;
|
|
3087
|
+
}
|
|
3088
|
+
compileMergeUsingSource(ast, ctx) {
|
|
3089
|
+
if (ast.source.type === "InsertValues") {
|
|
3090
|
+
if (!ast.source.rows.length) {
|
|
3091
|
+
throw new Error("INSERT ... VALUES requires at least one row.");
|
|
3092
|
+
}
|
|
3093
|
+
const rows = ast.source.rows.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
|
|
3094
|
+
return `(VALUES ${rows})`;
|
|
3095
|
+
}
|
|
3096
|
+
const normalized = this.normalizeSelectAst(ast.source.query);
|
|
3097
|
+
const selectSql = this.compileSelectAst(normalized, ctx).trim().replace(/;$/, "");
|
|
3098
|
+
return `(${selectSql})`;
|
|
3099
|
+
}
|
|
2904
3100
|
compileInsertValues(ast, ctx) {
|
|
2905
3101
|
const source = ast.source;
|
|
2906
3102
|
if (source.type === "InsertValues") {
|
|
@@ -2923,6 +3119,57 @@ var SqlServerDialect = class extends SqlDialectBase {
|
|
|
2923
3119
|
}).join(", ");
|
|
2924
3120
|
return `WITH ${defs} `;
|
|
2925
3121
|
}
|
|
3122
|
+
compileProcedureCall(ast) {
|
|
3123
|
+
const ctx = this.createCompilerContext();
|
|
3124
|
+
const qualifiedName = ast.ref.schema ? `${this.quoteIdentifier(ast.ref.schema)}.${this.quoteIdentifier(ast.ref.name)}` : this.quoteIdentifier(ast.ref.name);
|
|
3125
|
+
const declarations = [];
|
|
3126
|
+
const assignments = [];
|
|
3127
|
+
const execArgs = [];
|
|
3128
|
+
const outVars = [];
|
|
3129
|
+
ast.params.forEach((param, index) => {
|
|
3130
|
+
const targetParam = toProcedureParamReference(param.name);
|
|
3131
|
+
if (param.direction === "in") {
|
|
3132
|
+
if (!param.value) {
|
|
3133
|
+
throw new Error(`Procedure parameter "${param.name}" requires a value for direction "in".`);
|
|
3134
|
+
}
|
|
3135
|
+
execArgs.push(`${targetParam} = ${this.compileOperand(param.value, ctx)}`);
|
|
3136
|
+
return;
|
|
3137
|
+
}
|
|
3138
|
+
if (!param.dbType) {
|
|
3139
|
+
throw new Error(
|
|
3140
|
+
`MSSQL procedure parameter "${param.name}" requires "dbType" for direction "${param.direction}".`
|
|
3141
|
+
);
|
|
3142
|
+
}
|
|
3143
|
+
const suffix = sanitizeVariableSuffix2(param.name || `p${index + 1}`);
|
|
3144
|
+
const variable = `@__metal_${suffix}_${index + 1}`;
|
|
3145
|
+
declarations.push(`DECLARE ${variable} ${param.dbType};`);
|
|
3146
|
+
if (param.direction === "inout") {
|
|
3147
|
+
if (!param.value) {
|
|
3148
|
+
throw new Error(`Procedure parameter "${param.name}" requires a value for direction "inout".`);
|
|
3149
|
+
}
|
|
3150
|
+
assignments.push(`SET ${variable} = ${this.compileOperand(param.value, ctx)};`);
|
|
3151
|
+
}
|
|
3152
|
+
execArgs.push(`${targetParam} = ${variable} OUTPUT`);
|
|
3153
|
+
outVars.push({ variable, name: param.name });
|
|
3154
|
+
});
|
|
3155
|
+
const statements = [];
|
|
3156
|
+
if (declarations.length) statements.push(...declarations);
|
|
3157
|
+
if (assignments.length) statements.push(...assignments);
|
|
3158
|
+
const argsSql = execArgs.length ? ` ${execArgs.join(", ")}` : "";
|
|
3159
|
+
statements.push(`EXEC ${qualifiedName}${argsSql};`);
|
|
3160
|
+
if (outVars.length) {
|
|
3161
|
+
const selectOut = outVars.map(({ variable, name }) => `${variable} AS ${this.quoteIdentifier(name)}`).join(", ");
|
|
3162
|
+
statements.push(`SELECT ${selectOut};`);
|
|
3163
|
+
}
|
|
3164
|
+
return {
|
|
3165
|
+
sql: statements.join(" "),
|
|
3166
|
+
params: [...ctx.params],
|
|
3167
|
+
outParams: {
|
|
3168
|
+
source: outVars.length ? "lastResultSet" : "none",
|
|
3169
|
+
names: outVars.map((item) => item.name)
|
|
3170
|
+
}
|
|
3171
|
+
};
|
|
3172
|
+
}
|
|
2926
3173
|
};
|
|
2927
3174
|
|
|
2928
3175
|
// src/core/dialect/dialect-factory.ts
|
|
@@ -6628,6 +6875,56 @@ var preloadRelationIncludes = async (entities, includeTree, depth = 0) => {
|
|
|
6628
6875
|
}
|
|
6629
6876
|
};
|
|
6630
6877
|
|
|
6878
|
+
// src/core/execution/db-executor.ts
|
|
6879
|
+
var toExecutionPayload = (resultSets) => {
|
|
6880
|
+
const payload = resultSets;
|
|
6881
|
+
payload.resultSets = resultSets;
|
|
6882
|
+
return payload;
|
|
6883
|
+
};
|
|
6884
|
+
var payloadResultSets = (payload) => payload.resultSets ?? payload;
|
|
6885
|
+
function rowsToQueryResult(rows) {
|
|
6886
|
+
if (rows.length === 0) {
|
|
6887
|
+
return { columns: [], values: [] };
|
|
6888
|
+
}
|
|
6889
|
+
const columns = Object.keys(rows[0]);
|
|
6890
|
+
const values = rows.map((row) => columns.map((c) => row[c]));
|
|
6891
|
+
return { columns, values };
|
|
6892
|
+
}
|
|
6893
|
+
function createExecutorFromQueryRunner(runner) {
|
|
6894
|
+
const supportsTransactions = typeof runner.beginTransaction === "function" && typeof runner.commitTransaction === "function" && typeof runner.rollbackTransaction === "function";
|
|
6895
|
+
return {
|
|
6896
|
+
capabilities: {
|
|
6897
|
+
transactions: supportsTransactions
|
|
6898
|
+
},
|
|
6899
|
+
async executeSql(sql, params) {
|
|
6900
|
+
const rows = await runner.query(sql, params);
|
|
6901
|
+
const result = rowsToQueryResult(rows);
|
|
6902
|
+
return toExecutionPayload([result]);
|
|
6903
|
+
},
|
|
6904
|
+
async beginTransaction() {
|
|
6905
|
+
if (!supportsTransactions) {
|
|
6906
|
+
throw new Error("Transactions are not supported by this executor");
|
|
6907
|
+
}
|
|
6908
|
+
await runner.beginTransaction.call(runner);
|
|
6909
|
+
},
|
|
6910
|
+
async commitTransaction() {
|
|
6911
|
+
if (!supportsTransactions) {
|
|
6912
|
+
throw new Error("Transactions are not supported by this executor");
|
|
6913
|
+
}
|
|
6914
|
+
await runner.commitTransaction.call(runner);
|
|
6915
|
+
},
|
|
6916
|
+
async rollbackTransaction() {
|
|
6917
|
+
if (!supportsTransactions) {
|
|
6918
|
+
throw new Error("Transactions are not supported by this executor");
|
|
6919
|
+
}
|
|
6920
|
+
await runner.rollbackTransaction.call(runner);
|
|
6921
|
+
},
|
|
6922
|
+
async dispose() {
|
|
6923
|
+
await runner.dispose?.call(runner);
|
|
6924
|
+
}
|
|
6925
|
+
};
|
|
6926
|
+
}
|
|
6927
|
+
|
|
6631
6928
|
// src/orm/execute.ts
|
|
6632
6929
|
var flattenResults = (results) => {
|
|
6633
6930
|
const rows = [];
|
|
@@ -6647,7 +6944,7 @@ var executeWithContexts = async (execCtx, entityCtx, qb) => {
|
|
|
6647
6944
|
const ast = qb.getAST();
|
|
6648
6945
|
const compiled = execCtx.dialect.compileSelect(ast);
|
|
6649
6946
|
const executed = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
6650
|
-
const rows = flattenResults(executed);
|
|
6947
|
+
const rows = flattenResults(payloadResultSets(executed));
|
|
6651
6948
|
const lazyRelations = qb.getLazyRelations();
|
|
6652
6949
|
const lazyRelationOptions = qb.getLazyRelationOptions();
|
|
6653
6950
|
const includeTree = qb.getIncludeTree();
|
|
@@ -6667,7 +6964,7 @@ var executePlainWithContexts = async (execCtx, qb) => {
|
|
|
6667
6964
|
const ast = qb.getAST();
|
|
6668
6965
|
const compiled = execCtx.dialect.compileSelect(ast);
|
|
6669
6966
|
const executed = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
6670
|
-
const rows = flattenResults(executed);
|
|
6967
|
+
const rows = flattenResults(payloadResultSets(executed));
|
|
6671
6968
|
if (ast.setOps && ast.setOps.length > 0) {
|
|
6672
6969
|
return rows;
|
|
6673
6970
|
}
|
|
@@ -6935,7 +7232,8 @@ async function executeCount(context, env, session) {
|
|
|
6935
7232
|
};
|
|
6936
7233
|
const execCtx = session.getExecutionContext();
|
|
6937
7234
|
const compiled = execCtx.dialect.compileSelect(countQuery);
|
|
6938
|
-
const
|
|
7235
|
+
const payload = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
7236
|
+
const results = payloadResultSets(payload);
|
|
6939
7237
|
const value = results[0]?.values?.[0]?.[0];
|
|
6940
7238
|
if (typeof value === "number") return value;
|
|
6941
7239
|
if (typeof value === "bigint") return Number(value);
|
|
@@ -6967,7 +7265,8 @@ async function executeCountRows(context, env, session) {
|
|
|
6967
7265
|
};
|
|
6968
7266
|
const execCtx = session.getExecutionContext();
|
|
6969
7267
|
const compiled = execCtx.dialect.compileSelect(countQuery);
|
|
6970
|
-
const
|
|
7268
|
+
const payload = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
7269
|
+
const results = payloadResultSets(payload);
|
|
6971
7270
|
const value = results[0]?.values?.[0]?.[0];
|
|
6972
7271
|
if (typeof value === "number") return value;
|
|
6973
7272
|
if (typeof value === "bigint") return Number(value);
|
|
@@ -7941,6 +8240,45 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
7941
8240
|
* // rows is EntityInstance<UserTable>[] (plain objects)
|
|
7942
8241
|
* rows[0] instanceof User; // false
|
|
7943
8242
|
*/
|
|
8243
|
+
/**
|
|
8244
|
+
* Executes the query with LIMIT 1 and returns the first result.
|
|
8245
|
+
* Throws if no record is found.
|
|
8246
|
+
*
|
|
8247
|
+
* @param ctx - ORM session context
|
|
8248
|
+
* @returns Promise of a single entity instance
|
|
8249
|
+
* @throws Error if no results are found
|
|
8250
|
+
* @example
|
|
8251
|
+
* const user = await selectFromEntity(User)
|
|
8252
|
+
* .where(eq(users.email, 'alice@example.com'))
|
|
8253
|
+
* .firstOrFail(session);
|
|
8254
|
+
*/
|
|
8255
|
+
async firstOrFail(ctx) {
|
|
8256
|
+
const rows = await this.limit(1).execute(ctx);
|
|
8257
|
+
if (rows.length === 0) {
|
|
8258
|
+
throw new Error("No results found");
|
|
8259
|
+
}
|
|
8260
|
+
return rows[0];
|
|
8261
|
+
}
|
|
8262
|
+
/**
|
|
8263
|
+
* Executes the query with LIMIT 1 and returns the first result as a plain object (POJO).
|
|
8264
|
+
* Throws if no record is found.
|
|
8265
|
+
*
|
|
8266
|
+
* @param ctx - ORM session context
|
|
8267
|
+
* @returns Promise of a single plain object
|
|
8268
|
+
* @throws Error if no results are found
|
|
8269
|
+
* @example
|
|
8270
|
+
* const user = await selectFromEntity(User)
|
|
8271
|
+
* .where(eq(users.email, 'alice@example.com'))
|
|
8272
|
+
* .firstOrFailPlain(session);
|
|
8273
|
+
* // user is a plain object, not an instance of User
|
|
8274
|
+
*/
|
|
8275
|
+
async firstOrFailPlain(ctx) {
|
|
8276
|
+
const rows = await this.limit(1).executePlain(ctx);
|
|
8277
|
+
if (rows.length === 0) {
|
|
8278
|
+
throw new Error("No results found");
|
|
8279
|
+
}
|
|
8280
|
+
return rows[0];
|
|
8281
|
+
}
|
|
7944
8282
|
async executePlain(ctx) {
|
|
7945
8283
|
const builder = this.ensureDefaultSelection();
|
|
7946
8284
|
const rows = await executeHydratedPlain(ctx, builder);
|
|
@@ -8640,9 +8978,95 @@ var InsertQueryState = class _InsertQueryState {
|
|
|
8640
8978
|
returning: [...columns]
|
|
8641
8979
|
});
|
|
8642
8980
|
}
|
|
8981
|
+
/**
|
|
8982
|
+
* Adds an UPSERT conflict clause to the INSERT query
|
|
8983
|
+
* @param clause - Conflict clause and action
|
|
8984
|
+
* @returns A new InsertQueryState with conflict handling configured
|
|
8985
|
+
*/
|
|
8986
|
+
withOnConflict(clause) {
|
|
8987
|
+
return this.clone({
|
|
8988
|
+
...this.ast,
|
|
8989
|
+
onConflict: {
|
|
8990
|
+
target: {
|
|
8991
|
+
columns: [...clause.target.columns],
|
|
8992
|
+
constraint: clause.target.constraint
|
|
8993
|
+
},
|
|
8994
|
+
action: clause.action.type === "DoUpdate" ? {
|
|
8995
|
+
type: "DoUpdate",
|
|
8996
|
+
set: clause.action.set.map((assignment) => ({
|
|
8997
|
+
column: { ...assignment.column },
|
|
8998
|
+
value: assignment.value
|
|
8999
|
+
})),
|
|
9000
|
+
where: clause.action.where
|
|
9001
|
+
} : { type: "DoNothing" }
|
|
9002
|
+
}
|
|
9003
|
+
});
|
|
9004
|
+
}
|
|
8643
9005
|
};
|
|
8644
9006
|
|
|
8645
9007
|
// src/query-builder/insert.ts
|
|
9008
|
+
var ConflictBuilder = class {
|
|
9009
|
+
table;
|
|
9010
|
+
columns;
|
|
9011
|
+
constraint;
|
|
9012
|
+
applyClause;
|
|
9013
|
+
constructor(table, columns, constraint, applyClause) {
|
|
9014
|
+
this.table = table;
|
|
9015
|
+
this.columns = columns;
|
|
9016
|
+
this.constraint = constraint;
|
|
9017
|
+
this.applyClause = applyClause;
|
|
9018
|
+
}
|
|
9019
|
+
/**
|
|
9020
|
+
* Adds ON CONFLICT ... DO UPDATE
|
|
9021
|
+
* @param set - Column assignments for update branch
|
|
9022
|
+
* @param where - Optional filter for update branch
|
|
9023
|
+
* @returns InsertQueryBuilder with the upsert clause configured
|
|
9024
|
+
*/
|
|
9025
|
+
doUpdate(set, where) {
|
|
9026
|
+
const assignments = this.buildAssignments(set);
|
|
9027
|
+
return this.applyClause({
|
|
9028
|
+
target: this.buildTarget(),
|
|
9029
|
+
action: {
|
|
9030
|
+
type: "DoUpdate",
|
|
9031
|
+
set: assignments,
|
|
9032
|
+
where
|
|
9033
|
+
}
|
|
9034
|
+
});
|
|
9035
|
+
}
|
|
9036
|
+
/**
|
|
9037
|
+
* Adds ON CONFLICT ... DO NOTHING
|
|
9038
|
+
* @returns InsertQueryBuilder with the upsert clause configured
|
|
9039
|
+
*/
|
|
9040
|
+
doNothing() {
|
|
9041
|
+
return this.applyClause({
|
|
9042
|
+
target: this.buildTarget(),
|
|
9043
|
+
action: { type: "DoNothing" }
|
|
9044
|
+
});
|
|
9045
|
+
}
|
|
9046
|
+
buildTarget() {
|
|
9047
|
+
return {
|
|
9048
|
+
columns: [...this.columns],
|
|
9049
|
+
constraint: this.constraint
|
|
9050
|
+
};
|
|
9051
|
+
}
|
|
9052
|
+
buildAssignments(set) {
|
|
9053
|
+
const entries = Object.entries(set);
|
|
9054
|
+
if (!entries.length) {
|
|
9055
|
+
throw new Error("ON CONFLICT DO UPDATE requires at least one assignment.");
|
|
9056
|
+
}
|
|
9057
|
+
return entries.map(([columnName, rawValue]) => {
|
|
9058
|
+
if (!isValueOperandInput(rawValue)) {
|
|
9059
|
+
throw new Error(
|
|
9060
|
+
`Invalid upsert value for column "${columnName}": only string, number, boolean, Date, Buffer, null, or OperandNodes are allowed`
|
|
9061
|
+
);
|
|
9062
|
+
}
|
|
9063
|
+
return {
|
|
9064
|
+
column: buildColumnNode(this.table, { name: columnName, table: this.table.name }),
|
|
9065
|
+
value: valueToOperand(rawValue)
|
|
9066
|
+
};
|
|
9067
|
+
});
|
|
9068
|
+
}
|
|
9069
|
+
};
|
|
8646
9070
|
var InsertQueryBuilder = class _InsertQueryBuilder {
|
|
8647
9071
|
table;
|
|
8648
9072
|
state;
|
|
@@ -8658,6 +9082,9 @@ var InsertQueryBuilder = class _InsertQueryBuilder {
|
|
|
8658
9082
|
clone(state) {
|
|
8659
9083
|
return new _InsertQueryBuilder(this.table, state);
|
|
8660
9084
|
}
|
|
9085
|
+
withOnConflict(clause) {
|
|
9086
|
+
return this.clone(this.state.withOnConflict(clause));
|
|
9087
|
+
}
|
|
8661
9088
|
/**
|
|
8662
9089
|
* Adds VALUES to the INSERT query
|
|
8663
9090
|
* @param rowOrRows - Single row object or array of row objects to insert
|
|
@@ -8689,6 +9116,21 @@ var InsertQueryBuilder = class _InsertQueryBuilder {
|
|
|
8689
9116
|
const nodes = columns.length ? this.resolveColumnNodes(columns) : [];
|
|
8690
9117
|
return this.clone(this.state.withSelect(ast, nodes));
|
|
8691
9118
|
}
|
|
9119
|
+
/**
|
|
9120
|
+
* Configures UPSERT conflict handling for INSERT.
|
|
9121
|
+
* @param columns - Conflict target columns (ignored by MySQL)
|
|
9122
|
+
* @param constraint - Named unique/primary constraint (PostgreSQL only)
|
|
9123
|
+
* @returns ConflictBuilder for selecting action (DO UPDATE / DO NOTHING)
|
|
9124
|
+
*/
|
|
9125
|
+
onConflict(columns = [], constraint) {
|
|
9126
|
+
const resolvedColumns = columns.length ? this.resolveColumnNodes(columns) : [];
|
|
9127
|
+
return new ConflictBuilder(
|
|
9128
|
+
this.table,
|
|
9129
|
+
resolvedColumns,
|
|
9130
|
+
constraint,
|
|
9131
|
+
(clause) => this.withOnConflict(clause)
|
|
9132
|
+
);
|
|
9133
|
+
}
|
|
8692
9134
|
/**
|
|
8693
9135
|
* Adds a RETURNING clause to the INSERT query
|
|
8694
9136
|
* @param columns - Columns to return after insertion
|
|
@@ -8966,7 +9408,8 @@ var UpdateQueryBuilder = class _UpdateQueryBuilder {
|
|
|
8966
9408
|
async execute(session) {
|
|
8967
9409
|
const execCtx = session.getExecutionContext();
|
|
8968
9410
|
const compiled = this.compile(execCtx.dialect);
|
|
8969
|
-
|
|
9411
|
+
const payload = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
9412
|
+
return payloadResultSets(payload);
|
|
8970
9413
|
}
|
|
8971
9414
|
/**
|
|
8972
9415
|
* Returns the Abstract Syntax Tree (AST) representation of the query
|
|
@@ -9156,7 +9599,8 @@ var DeleteQueryBuilder = class _DeleteQueryBuilder {
|
|
|
9156
9599
|
async execute(session) {
|
|
9157
9600
|
const execCtx = session.getExecutionContext();
|
|
9158
9601
|
const compiled = this.compile(execCtx.dialect);
|
|
9159
|
-
|
|
9602
|
+
const payload = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
9603
|
+
return payloadResultSets(payload);
|
|
9160
9604
|
}
|
|
9161
9605
|
/**
|
|
9162
9606
|
* Returns the Abstract Syntax Tree (AST) representation of the query
|
|
@@ -9168,6 +9612,149 @@ var DeleteQueryBuilder = class _DeleteQueryBuilder {
|
|
|
9168
9612
|
};
|
|
9169
9613
|
var isTableSourceNode2 = (source) => typeof source.type === "string";
|
|
9170
9614
|
|
|
9615
|
+
// src/orm/execute-procedure.ts
|
|
9616
|
+
var resolveColumnIndex = (columns, expectedName) => {
|
|
9617
|
+
const exact = columns.findIndex((column) => column === expectedName);
|
|
9618
|
+
if (exact >= 0) return exact;
|
|
9619
|
+
const lowerExpected = expectedName.toLowerCase();
|
|
9620
|
+
return columns.findIndex((column) => column.toLowerCase() === lowerExpected);
|
|
9621
|
+
};
|
|
9622
|
+
var extractOutValues = (compiled, resultSets) => {
|
|
9623
|
+
if (!compiled.outParams.names.length || compiled.outParams.source === "none") {
|
|
9624
|
+
return {};
|
|
9625
|
+
}
|
|
9626
|
+
const sourceSet = compiled.outParams.source === "firstResultSet" ? resultSets[0] : resultSets[resultSets.length - 1];
|
|
9627
|
+
if (!sourceSet) {
|
|
9628
|
+
throw new Error(
|
|
9629
|
+
`Procedure expected OUT parameters in ${compiled.outParams.source}, but no result set was returned.`
|
|
9630
|
+
);
|
|
9631
|
+
}
|
|
9632
|
+
if (!sourceSet.values.length) {
|
|
9633
|
+
throw new Error(
|
|
9634
|
+
`Procedure expected OUT parameters in ${compiled.outParams.source}, but the result set has no rows.`
|
|
9635
|
+
);
|
|
9636
|
+
}
|
|
9637
|
+
const firstRow = sourceSet.values[0];
|
|
9638
|
+
const out = {};
|
|
9639
|
+
for (const expectedName of compiled.outParams.names) {
|
|
9640
|
+
const columnIndex = resolveColumnIndex(sourceSet.columns, expectedName);
|
|
9641
|
+
if (columnIndex < 0) {
|
|
9642
|
+
const available = sourceSet.columns.length ? sourceSet.columns.join(", ") : "(none)";
|
|
9643
|
+
throw new Error(
|
|
9644
|
+
`Procedure OUT parameter "${expectedName}" was not found in ${compiled.outParams.source}. Available columns: ${available}.`
|
|
9645
|
+
);
|
|
9646
|
+
}
|
|
9647
|
+
out[expectedName] = firstRow[columnIndex];
|
|
9648
|
+
}
|
|
9649
|
+
return out;
|
|
9650
|
+
};
|
|
9651
|
+
var executeProcedureAst = async (session, ast) => {
|
|
9652
|
+
const execCtx = session.getExecutionContext();
|
|
9653
|
+
const compiled = execCtx.dialect.compileProcedureCall(ast);
|
|
9654
|
+
const payload = await execCtx.interceptors.run(
|
|
9655
|
+
{ sql: compiled.sql, params: compiled.params },
|
|
9656
|
+
execCtx.executor
|
|
9657
|
+
);
|
|
9658
|
+
const resultSets = payloadResultSets(payload);
|
|
9659
|
+
return {
|
|
9660
|
+
resultSets,
|
|
9661
|
+
out: extractOutValues(compiled, resultSets)
|
|
9662
|
+
};
|
|
9663
|
+
};
|
|
9664
|
+
|
|
9665
|
+
// src/query-builder/procedure-call.ts
|
|
9666
|
+
var cloneParam = (param) => ({
|
|
9667
|
+
...param,
|
|
9668
|
+
value: param.value ? { ...param.value } : void 0
|
|
9669
|
+
});
|
|
9670
|
+
var ProcedureCallBuilder = class _ProcedureCallBuilder {
|
|
9671
|
+
ast;
|
|
9672
|
+
constructor(name, options, ast) {
|
|
9673
|
+
this.ast = ast ?? {
|
|
9674
|
+
type: "ProcedureCall",
|
|
9675
|
+
ref: {
|
|
9676
|
+
name,
|
|
9677
|
+
schema: options?.schema
|
|
9678
|
+
},
|
|
9679
|
+
params: []
|
|
9680
|
+
};
|
|
9681
|
+
}
|
|
9682
|
+
clone(nextParams) {
|
|
9683
|
+
return new _ProcedureCallBuilder(
|
|
9684
|
+
this.ast.ref.name,
|
|
9685
|
+
{ schema: this.ast.ref.schema },
|
|
9686
|
+
{
|
|
9687
|
+
...this.ast,
|
|
9688
|
+
ref: { ...this.ast.ref },
|
|
9689
|
+
params: nextParams
|
|
9690
|
+
}
|
|
9691
|
+
);
|
|
9692
|
+
}
|
|
9693
|
+
in(name, value) {
|
|
9694
|
+
return this.clone([
|
|
9695
|
+
...this.ast.params.map(cloneParam),
|
|
9696
|
+
{
|
|
9697
|
+
name,
|
|
9698
|
+
direction: "in",
|
|
9699
|
+
value: valueToOperand(value)
|
|
9700
|
+
}
|
|
9701
|
+
]);
|
|
9702
|
+
}
|
|
9703
|
+
out(name, options) {
|
|
9704
|
+
return this.clone([
|
|
9705
|
+
...this.ast.params.map(cloneParam),
|
|
9706
|
+
{
|
|
9707
|
+
name,
|
|
9708
|
+
direction: "out",
|
|
9709
|
+
dbType: options?.dbType
|
|
9710
|
+
}
|
|
9711
|
+
]);
|
|
9712
|
+
}
|
|
9713
|
+
inOut(name, value, options) {
|
|
9714
|
+
return this.clone([
|
|
9715
|
+
...this.ast.params.map(cloneParam),
|
|
9716
|
+
{
|
|
9717
|
+
name,
|
|
9718
|
+
direction: "inout",
|
|
9719
|
+
value: valueToOperand(value),
|
|
9720
|
+
dbType: options?.dbType
|
|
9721
|
+
}
|
|
9722
|
+
]);
|
|
9723
|
+
}
|
|
9724
|
+
compile(dialect) {
|
|
9725
|
+
const resolved = resolveDialectInput(dialect);
|
|
9726
|
+
this.validateMssqlOutDbType(resolved);
|
|
9727
|
+
return resolved.compileProcedureCall(this.getAST());
|
|
9728
|
+
}
|
|
9729
|
+
toSql(dialect) {
|
|
9730
|
+
return this.compile(dialect).sql;
|
|
9731
|
+
}
|
|
9732
|
+
getAST() {
|
|
9733
|
+
return {
|
|
9734
|
+
...this.ast,
|
|
9735
|
+
ref: { ...this.ast.ref },
|
|
9736
|
+
params: this.ast.params.map(cloneParam)
|
|
9737
|
+
};
|
|
9738
|
+
}
|
|
9739
|
+
async execute(session) {
|
|
9740
|
+
this.validateMssqlOutDbType(session.getExecutionContext().dialect);
|
|
9741
|
+
return executeProcedureAst(session, this.getAST());
|
|
9742
|
+
}
|
|
9743
|
+
validateMssqlOutDbType(dialect) {
|
|
9744
|
+
const isMssqlDialect = dialect.constructor.name === "SqlServerDialect";
|
|
9745
|
+
if (!isMssqlDialect) return;
|
|
9746
|
+
for (const param of this.ast.params) {
|
|
9747
|
+
const needsDbType = param.direction === "out" || param.direction === "inout";
|
|
9748
|
+
if (needsDbType && !param.dbType) {
|
|
9749
|
+
throw new Error(
|
|
9750
|
+
`MSSQL requires "dbType" for procedure parameter "${param.name}" with direction "${param.direction}".`
|
|
9751
|
+
);
|
|
9752
|
+
}
|
|
9753
|
+
}
|
|
9754
|
+
}
|
|
9755
|
+
};
|
|
9756
|
+
var callProcedure = (name, options) => new ProcedureCallBuilder(name, options);
|
|
9757
|
+
|
|
9171
9758
|
// src/query/target.ts
|
|
9172
9759
|
var resolveEntityTarget = (ctor) => {
|
|
9173
9760
|
const table = getTableDefFromEntity(ctor);
|
|
@@ -12346,7 +12933,8 @@ var UnitOfWork = class {
|
|
|
12346
12933
|
* @returns Query results
|
|
12347
12934
|
*/
|
|
12348
12935
|
async executeCompiled(compiled) {
|
|
12349
|
-
|
|
12936
|
+
const payload = await this.executor.executeSql(compiled.sql, compiled.params);
|
|
12937
|
+
return payloadResultSets(payload);
|
|
12350
12938
|
}
|
|
12351
12939
|
/**
|
|
12352
12940
|
* Gets columns for RETURNING clause.
|
|
@@ -13490,9 +14078,9 @@ var InterceptorPipeline = class {
|
|
|
13490
14078
|
const dispatch = async () => {
|
|
13491
14079
|
const interceptor = this.interceptors[i++];
|
|
13492
14080
|
if (!interceptor) {
|
|
13493
|
-
return executor.executeSql(ctx.sql, ctx.params);
|
|
14081
|
+
return toExecutionPayload(await executor.executeSql(ctx.sql, ctx.params));
|
|
13494
14082
|
}
|
|
13495
|
-
return interceptor(ctx, dispatch);
|
|
14083
|
+
return toExecutionPayload(await interceptor(ctx, dispatch));
|
|
13496
14084
|
};
|
|
13497
14085
|
return dispatch();
|
|
13498
14086
|
}
|
|
@@ -14746,50 +15334,6 @@ function CEP(options) {
|
|
|
14746
15334
|
};
|
|
14747
15335
|
}
|
|
14748
15336
|
|
|
14749
|
-
// src/core/execution/db-executor.ts
|
|
14750
|
-
function rowsToQueryResult(rows) {
|
|
14751
|
-
if (rows.length === 0) {
|
|
14752
|
-
return { columns: [], values: [] };
|
|
14753
|
-
}
|
|
14754
|
-
const columns = Object.keys(rows[0]);
|
|
14755
|
-
const values = rows.map((row) => columns.map((c) => row[c]));
|
|
14756
|
-
return { columns, values };
|
|
14757
|
-
}
|
|
14758
|
-
function createExecutorFromQueryRunner(runner) {
|
|
14759
|
-
const supportsTransactions = typeof runner.beginTransaction === "function" && typeof runner.commitTransaction === "function" && typeof runner.rollbackTransaction === "function";
|
|
14760
|
-
return {
|
|
14761
|
-
capabilities: {
|
|
14762
|
-
transactions: supportsTransactions
|
|
14763
|
-
},
|
|
14764
|
-
async executeSql(sql, params) {
|
|
14765
|
-
const rows = await runner.query(sql, params);
|
|
14766
|
-
const result = rowsToQueryResult(rows);
|
|
14767
|
-
return [result];
|
|
14768
|
-
},
|
|
14769
|
-
async beginTransaction() {
|
|
14770
|
-
if (!supportsTransactions) {
|
|
14771
|
-
throw new Error("Transactions are not supported by this executor");
|
|
14772
|
-
}
|
|
14773
|
-
await runner.beginTransaction.call(runner);
|
|
14774
|
-
},
|
|
14775
|
-
async commitTransaction() {
|
|
14776
|
-
if (!supportsTransactions) {
|
|
14777
|
-
throw new Error("Transactions are not supported by this executor");
|
|
14778
|
-
}
|
|
14779
|
-
await runner.commitTransaction.call(runner);
|
|
14780
|
-
},
|
|
14781
|
-
async rollbackTransaction() {
|
|
14782
|
-
if (!supportsTransactions) {
|
|
14783
|
-
throw new Error("Transactions are not supported by this executor");
|
|
14784
|
-
}
|
|
14785
|
-
await runner.rollbackTransaction.call(runner);
|
|
14786
|
-
},
|
|
14787
|
-
async dispose() {
|
|
14788
|
-
await runner.dispose?.call(runner);
|
|
14789
|
-
}
|
|
14790
|
-
};
|
|
14791
|
-
}
|
|
14792
|
-
|
|
14793
15337
|
// src/core/execution/pooling/pool.ts
|
|
14794
15338
|
var deferred = () => {
|
|
14795
15339
|
let resolve;
|
|
@@ -15017,6 +15561,36 @@ function createPostgresExecutor(client) {
|
|
|
15017
15561
|
}
|
|
15018
15562
|
|
|
15019
15563
|
// src/core/execution/executors/mysql-executor.ts
|
|
15564
|
+
var isRowObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15565
|
+
var isRowObjectArray = (value) => Array.isArray(value) && value.every(isRowObject);
|
|
15566
|
+
var isMysqlResultHeader = (value) => isRowObject(value) && ("affectedRows" in value || "insertId" in value || "warningStatus" in value || "serverStatus" in value);
|
|
15567
|
+
var headerToQueryResult = (header) => ({
|
|
15568
|
+
columns: [],
|
|
15569
|
+
values: [],
|
|
15570
|
+
meta: {
|
|
15571
|
+
insertId: header.insertId,
|
|
15572
|
+
rowsAffected: header.affectedRows
|
|
15573
|
+
}
|
|
15574
|
+
});
|
|
15575
|
+
var normalizeMysqlResults = (rows) => {
|
|
15576
|
+
if (!Array.isArray(rows)) {
|
|
15577
|
+
return isMysqlResultHeader(rows) ? [headerToQueryResult(rows)] : [rowsToQueryResult([])];
|
|
15578
|
+
}
|
|
15579
|
+
if (isRowObjectArray(rows)) {
|
|
15580
|
+
return [rowsToQueryResult(rows)];
|
|
15581
|
+
}
|
|
15582
|
+
const normalized = [];
|
|
15583
|
+
for (const chunk of rows) {
|
|
15584
|
+
if (isRowObjectArray(chunk)) {
|
|
15585
|
+
normalized.push(rowsToQueryResult(chunk));
|
|
15586
|
+
continue;
|
|
15587
|
+
}
|
|
15588
|
+
if (isMysqlResultHeader(chunk)) {
|
|
15589
|
+
normalized.push(headerToQueryResult(chunk));
|
|
15590
|
+
}
|
|
15591
|
+
}
|
|
15592
|
+
return normalized.length ? normalized : [rowsToQueryResult([])];
|
|
15593
|
+
};
|
|
15020
15594
|
function createMysqlExecutor(client) {
|
|
15021
15595
|
const supportsTransactions = typeof client.beginTransaction === "function" && typeof client.commit === "function" && typeof client.rollback === "function";
|
|
15022
15596
|
return {
|
|
@@ -15025,21 +15599,7 @@ function createMysqlExecutor(client) {
|
|
|
15025
15599
|
},
|
|
15026
15600
|
async executeSql(sql, params) {
|
|
15027
15601
|
const [rows] = await client.query(sql, params);
|
|
15028
|
-
|
|
15029
|
-
const header = rows;
|
|
15030
|
-
return [{
|
|
15031
|
-
columns: [],
|
|
15032
|
-
values: [],
|
|
15033
|
-
meta: {
|
|
15034
|
-
insertId: header.insertId,
|
|
15035
|
-
rowsAffected: header.affectedRows
|
|
15036
|
-
}
|
|
15037
|
-
}];
|
|
15038
|
-
}
|
|
15039
|
-
const result = rowsToQueryResult(
|
|
15040
|
-
rows
|
|
15041
|
-
);
|
|
15042
|
-
return [result];
|
|
15602
|
+
return toExecutionPayload(normalizeMysqlResults(rows));
|
|
15043
15603
|
},
|
|
15044
15604
|
async beginTransaction() {
|
|
15045
15605
|
if (!supportsTransactions) {
|
|
@@ -15074,7 +15634,7 @@ function createSqliteExecutor(client) {
|
|
|
15074
15634
|
async executeSql(sql, params) {
|
|
15075
15635
|
const rows = await client.all(sql, params);
|
|
15076
15636
|
const result = rowsToQueryResult(rows);
|
|
15077
|
-
return [result];
|
|
15637
|
+
return toExecutionPayload([result]);
|
|
15078
15638
|
},
|
|
15079
15639
|
async beginTransaction() {
|
|
15080
15640
|
if (!supportsTransactions) {
|
|
@@ -15107,9 +15667,9 @@ function createMssqlExecutor(client) {
|
|
|
15107
15667
|
transactions: supportsTransactions
|
|
15108
15668
|
},
|
|
15109
15669
|
async executeSql(sql, params) {
|
|
15110
|
-
const { recordset } = await client.query(sql, params);
|
|
15111
|
-
const
|
|
15112
|
-
return [
|
|
15670
|
+
const { recordset, recordsets } = await client.query(sql, params);
|
|
15671
|
+
const sets = Array.isArray(recordsets) ? recordsets : [recordset ?? []];
|
|
15672
|
+
return toExecutionPayload(sets.map((set) => rowsToQueryResult(set ?? [])));
|
|
15113
15673
|
},
|
|
15114
15674
|
async beginTransaction() {
|
|
15115
15675
|
if (!supportsTransactions) {
|
|
@@ -15175,7 +15735,7 @@ function createTediousMssqlClient(connection, { Request, TYPES }, options) {
|
|
|
15175
15735
|
connection.execSql(request);
|
|
15176
15736
|
}
|
|
15177
15737
|
);
|
|
15178
|
-
return { recordset: rows };
|
|
15738
|
+
return { recordset: rows, recordsets: [rows] };
|
|
15179
15739
|
},
|
|
15180
15740
|
beginTransaction: connection.beginTransaction ? () => new Promise((resolve, reject) => {
|
|
15181
15741
|
connection.beginTransaction(
|
|
@@ -15200,6 +15760,8 @@ function createTediousExecutor(connection, module, options) {
|
|
|
15200
15760
|
}
|
|
15201
15761
|
|
|
15202
15762
|
// src/orm/pooled-executor-factory.ts
|
|
15763
|
+
var isQueryResult = (value) => typeof value === "object" && value !== null && Array.isArray(value.columns) && Array.isArray(value.values);
|
|
15764
|
+
var isRowArray = (value) => Array.isArray(value) && value.every((item) => typeof item === "object" && item !== null && !Array.isArray(item));
|
|
15203
15765
|
function createPooledExecutorFactory(opts) {
|
|
15204
15766
|
const { pool, adapter } = opts;
|
|
15205
15767
|
const makeExecutor = (mode) => {
|
|
@@ -15211,7 +15773,13 @@ function createPooledExecutorFactory(opts) {
|
|
|
15211
15773
|
};
|
|
15212
15774
|
const executeWithConn = async (conn, sql, params) => {
|
|
15213
15775
|
const rows = await adapter.query(conn, sql, params);
|
|
15214
|
-
|
|
15776
|
+
if (Array.isArray(rows) && rows.length > 0 && rows.every(isQueryResult)) {
|
|
15777
|
+
return toExecutionPayload(rows);
|
|
15778
|
+
}
|
|
15779
|
+
if (Array.isArray(rows) && rows.length > 0 && rows.every(isRowArray)) {
|
|
15780
|
+
return toExecutionPayload(rows.map((set) => rowsToQueryResult(set)));
|
|
15781
|
+
}
|
|
15782
|
+
return toExecutionPayload([rowsToQueryResult(rows)]);
|
|
15215
15783
|
};
|
|
15216
15784
|
return {
|
|
15217
15785
|
capabilities: { transactions: true },
|
|
@@ -18786,6 +19354,7 @@ export {
|
|
|
18786
19354
|
CPF,
|
|
18787
19355
|
Capitalize,
|
|
18788
19356
|
Column,
|
|
19357
|
+
ConflictBuilder,
|
|
18789
19358
|
ConstructorMaterializationStrategy,
|
|
18790
19359
|
DEFAULT_TREE_CONFIG,
|
|
18791
19360
|
DateTimeTypeStrategy,
|
|
@@ -18818,6 +19387,7 @@ export {
|
|
|
18818
19387
|
Pool,
|
|
18819
19388
|
PostgresDialect,
|
|
18820
19389
|
PrimaryKey,
|
|
19390
|
+
ProcedureCallBuilder,
|
|
18821
19391
|
PrototypeMaterializationStrategy,
|
|
18822
19392
|
QueryCacheManager,
|
|
18823
19393
|
RedisCacheAdapter,
|
|
@@ -18867,6 +19437,7 @@ export {
|
|
|
18867
19437
|
buildScopeConditions,
|
|
18868
19438
|
calculateRowDepths,
|
|
18869
19439
|
calculateTotalPages,
|
|
19440
|
+
callProcedure,
|
|
18870
19441
|
canonicalizeSchema,
|
|
18871
19442
|
caseWhen,
|
|
18872
19443
|
cast,
|
|
@@ -18939,6 +19510,7 @@ export {
|
|
|
18939
19510
|
executeHydratedPlain,
|
|
18940
19511
|
executeHydratedPlainWithContexts,
|
|
18941
19512
|
executeHydratedWithContexts,
|
|
19513
|
+
executeProcedureAst,
|
|
18942
19514
|
executeSchemaSql,
|
|
18943
19515
|
executeSchemaSqlFor,
|
|
18944
19516
|
exists,
|
|
@@ -19066,6 +19638,7 @@ export {
|
|
|
19066
19638
|
paginationParamsSchema,
|
|
19067
19639
|
parameterToRef,
|
|
19068
19640
|
parseDuration,
|
|
19641
|
+
payloadResultSets,
|
|
19069
19642
|
pi,
|
|
19070
19643
|
pick,
|
|
19071
19644
|
position,
|
|
@@ -19125,6 +19698,7 @@ export {
|
|
|
19125
19698
|
threadResults,
|
|
19126
19699
|
threadedNodeToOpenApiSchema,
|
|
19127
19700
|
toColumnRef,
|
|
19701
|
+
toExecutionPayload,
|
|
19128
19702
|
toPagedResponse,
|
|
19129
19703
|
toPagedResponseBuilder,
|
|
19130
19704
|
toPaginationParams,
|