@fragno-dev/db 0.0.1 → 0.1.0
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/.turbo/turbo-build.log +137 -13
- package/.turbo/turbo-test.log +36 -0
- package/CHANGELOG.md +7 -0
- package/dist/adapters/adapters.d.ts +18 -0
- package/dist/adapters/adapters.d.ts.map +1 -0
- package/dist/adapters/drizzle/drizzle-adapter.d.ts +21 -0
- package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -0
- package/dist/adapters/drizzle/drizzle-adapter.js +62 -0
- package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -0
- package/dist/adapters/drizzle/drizzle-query.d.ts +17 -0
- package/dist/adapters/drizzle/drizzle-query.d.ts.map +1 -0
- package/dist/adapters/drizzle/drizzle-query.js +139 -0
- package/dist/adapters/drizzle/drizzle-query.js.map +1 -0
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts +9 -0
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts.map +1 -0
- package/dist/adapters/drizzle/drizzle-uow-compiler.js +300 -0
- package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +1 -0
- package/dist/adapters/drizzle/drizzle-uow-decoder.js +82 -0
- package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +1 -0
- package/dist/adapters/drizzle/drizzle-uow-executor.js +125 -0
- package/dist/adapters/drizzle/drizzle-uow-executor.js.map +1 -0
- package/dist/adapters/drizzle/generate.js +273 -0
- package/dist/adapters/drizzle/generate.js.map +1 -0
- package/dist/adapters/drizzle/join-column-utils.js +28 -0
- package/dist/adapters/drizzle/join-column-utils.js.map +1 -0
- package/dist/adapters/drizzle/shared.js +11 -0
- package/dist/adapters/drizzle/shared.js.map +1 -0
- package/dist/adapters/kysely/kysely-adapter.d.ts +23 -0
- package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -0
- package/dist/adapters/kysely/kysely-adapter.js +119 -0
- package/dist/adapters/kysely/kysely-adapter.js.map +1 -0
- package/dist/adapters/kysely/kysely-query-builder.js +306 -0
- package/dist/adapters/kysely/kysely-query-builder.js.map +1 -0
- package/dist/adapters/kysely/kysely-query-compiler.js +67 -0
- package/dist/adapters/kysely/kysely-query-compiler.js.map +1 -0
- package/dist/adapters/kysely/kysely-query.js +158 -0
- package/dist/adapters/kysely/kysely-query.js.map +1 -0
- package/dist/adapters/kysely/kysely-uow-compiler.js +139 -0
- package/dist/adapters/kysely/kysely-uow-compiler.js.map +1 -0
- package/dist/adapters/kysely/kysely-uow-executor.js +89 -0
- package/dist/adapters/kysely/kysely-uow-executor.js.map +1 -0
- package/dist/adapters/kysely/migration/execute.js +176 -0
- package/dist/adapters/kysely/migration/execute.js.map +1 -0
- package/dist/fragment.d.ts +54 -0
- package/dist/fragment.d.ts.map +1 -0
- package/dist/fragment.js +92 -0
- package/dist/fragment.js.map +1 -0
- package/dist/id.d.ts +2 -0
- package/dist/migration-engine/auto-from-schema.js +116 -0
- package/dist/migration-engine/auto-from-schema.js.map +1 -0
- package/dist/migration-engine/create.d.ts +41 -0
- package/dist/migration-engine/create.d.ts.map +1 -0
- package/dist/migration-engine/create.js +58 -0
- package/dist/migration-engine/create.js.map +1 -0
- package/dist/migration-engine/shared.d.ts +90 -0
- package/dist/migration-engine/shared.d.ts.map +1 -0
- package/dist/migration-engine/shared.js +8 -0
- package/dist/migration-engine/shared.js.map +1 -0
- package/dist/mod.d.ts +55 -2
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +111 -2
- package/dist/mod.js.map +1 -1
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/column-builder.js +108 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/column-builder.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/column.js +55 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/column.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/entity.js +18 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/entity.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/columns/common.js +183 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/columns/common.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/columns/enum.js +58 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/columns/enum.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/foreign-keys.js +68 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/foreign-keys.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/unique-constraint.js +56 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/unique-constraint.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/utils/array.js +65 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/utils/array.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/expressions/conditions.js +81 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/expressions/conditions.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/expressions/select.js +13 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/expressions/select.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/functions/aggregate.js +10 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/functions/aggregate.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/sql.js +372 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/sql.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/subquery.js +23 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/subquery.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/table.js +62 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/table.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/table.utils.js +6 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/table.utils.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/tracing-utils.js +8 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/tracing-utils.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/tracing.js +8 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/tracing.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/view-common.js +6 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/view-common.js.map +1 -0
- package/dist/query/condition-builder.d.ts +41 -0
- package/dist/query/condition-builder.d.ts.map +1 -0
- package/dist/query/condition-builder.js +93 -0
- package/dist/query/condition-builder.js.map +1 -0
- package/dist/query/cursor.d.ts +88 -0
- package/dist/query/cursor.d.ts.map +1 -0
- package/dist/query/cursor.js +103 -0
- package/dist/query/cursor.js.map +1 -0
- package/dist/query/orm/orm.d.ts +18 -0
- package/dist/query/orm/orm.d.ts.map +1 -0
- package/dist/query/orm/orm.js +48 -0
- package/dist/query/orm/orm.js.map +1 -0
- package/dist/query/query.d.ts +79 -0
- package/dist/query/query.d.ts.map +1 -0
- package/dist/query/query.js +1 -0
- package/dist/query/result-transform.js +155 -0
- package/dist/query/result-transform.js.map +1 -0
- package/dist/query/unit-of-work.d.ts +435 -0
- package/dist/query/unit-of-work.d.ts.map +1 -0
- package/dist/query/unit-of-work.js +549 -0
- package/dist/query/unit-of-work.js.map +1 -0
- package/dist/schema/create.d.ts +273 -116
- package/dist/schema/create.d.ts.map +1 -1
- package/dist/schema/create.js +410 -222
- package/dist/schema/create.js.map +1 -1
- package/dist/schema/serialize.js +101 -0
- package/dist/schema/serialize.js.map +1 -0
- package/dist/schema-generator/schema-generator.d.ts +15 -0
- package/dist/schema-generator/schema-generator.d.ts.map +1 -0
- package/dist/shared/providers.d.ts +6 -0
- package/dist/shared/providers.d.ts.map +1 -0
- package/dist/util/import-generator.js +26 -0
- package/dist/util/import-generator.js.map +1 -0
- package/dist/util/parse.js +15 -0
- package/dist/util/parse.js.map +1 -0
- package/dist/util/types.d.ts +8 -0
- package/dist/util/types.d.ts.map +1 -0
- package/package.json +63 -2
- package/src/adapters/adapters.ts +22 -0
- package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +433 -0
- package/src/adapters/drizzle/drizzle-adapter.test.ts +122 -0
- package/src/adapters/drizzle/drizzle-adapter.ts +118 -0
- package/src/adapters/drizzle/drizzle-query.ts +234 -0
- package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +1084 -0
- package/src/adapters/drizzle/drizzle-uow-compiler.ts +546 -0
- package/src/adapters/drizzle/drizzle-uow-decoder.ts +165 -0
- package/src/adapters/drizzle/drizzle-uow-executor.ts +213 -0
- package/src/adapters/drizzle/generate.test.ts +643 -0
- package/src/adapters/drizzle/generate.ts +481 -0
- package/src/adapters/drizzle/join-column-utils.test.ts +79 -0
- package/src/adapters/drizzle/join-column-utils.ts +39 -0
- package/src/adapters/drizzle/migrate-drizzle.test.ts +226 -0
- package/src/adapters/drizzle/shared.ts +22 -0
- package/src/adapters/drizzle/test-utils.ts +56 -0
- package/src/adapters/kysely/kysely-adapter-pglite.test.ts +789 -0
- package/src/adapters/kysely/kysely-adapter.ts +196 -0
- package/src/adapters/kysely/kysely-query-builder.test.ts +1344 -0
- package/src/adapters/kysely/kysely-query-builder.ts +611 -0
- package/src/adapters/kysely/kysely-query-compiler.ts +124 -0
- package/src/adapters/kysely/kysely-query.ts +254 -0
- package/src/adapters/kysely/kysely-uow-compiler.test.ts +916 -0
- package/src/adapters/kysely/kysely-uow-compiler.ts +271 -0
- package/src/adapters/kysely/kysely-uow-executor.ts +149 -0
- package/src/adapters/kysely/kysely-uow-joins.test.ts +811 -0
- package/src/adapters/kysely/migration/execute-mysql.test.ts +1173 -0
- package/src/adapters/kysely/migration/execute-postgres.test.ts +2657 -0
- package/src/adapters/kysely/migration/execute.ts +382 -0
- package/src/adapters/kysely/migration/kysely-migrator.test.ts +197 -0
- package/src/fragment.test.ts +287 -0
- package/src/fragment.ts +198 -0
- package/src/migration-engine/auto-from-schema.test.ts +118 -58
- package/src/migration-engine/auto-from-schema.ts +103 -32
- package/src/migration-engine/create.test.ts +34 -46
- package/src/migration-engine/create.ts +41 -26
- package/src/migration-engine/shared.ts +26 -6
- package/src/mod.ts +197 -1
- package/src/query/condition-builder.test.ts +379 -0
- package/src/query/condition-builder.ts +294 -0
- package/src/query/cursor.test.ts +296 -0
- package/src/query/cursor.ts +147 -0
- package/src/query/orm/orm.ts +92 -0
- package/src/query/query-type.test.ts +429 -0
- package/src/query/query.ts +200 -0
- package/src/query/result-transform.test.ts +795 -0
- package/src/query/result-transform.ts +247 -0
- package/src/query/unit-of-work-types.test.ts +192 -0
- package/src/query/unit-of-work.test.ts +947 -0
- package/src/query/unit-of-work.ts +1199 -0
- package/src/schema/create.test.ts +653 -110
- package/src/schema/create.ts +708 -337
- package/src/schema/serialize.test.ts +559 -0
- package/src/schema/serialize.ts +359 -0
- package/src/schema-generator/schema-generator.ts +12 -0
- package/src/shared/config.ts +0 -8
- package/src/util/import-generator.ts +28 -0
- package/src/util/parse.ts +16 -0
- package/src/util/types.ts +4 -0
- package/tsconfig.json +1 -1
- package/tsdown.config.ts +11 -1
- package/vitest.config.ts +3 -0
- /package/dist/{cuid.js → id.js} +0 -0
- /package/src/{cuid.ts → id.ts} +0 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { SQL, StringChunk, sql, type SQLChunk } from "drizzle-orm";
|
|
2
|
+
import type { CompiledMutation, MutationResult } from "../../query/unit-of-work";
|
|
3
|
+
import type { DBType } from "./shared";
|
|
4
|
+
import type { DrizzleCompiledQuery } from "./drizzle-uow-compiler";
|
|
5
|
+
import type { DrizzleResult } from "./drizzle-query";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Convert a DrizzleCompiledQuery (SQL string + params) to a Drizzle SQL object
|
|
9
|
+
*
|
|
10
|
+
* This reconstructs the SQL object with proper parameter chunks by parsing
|
|
11
|
+
* the SQL string and replacing placeholders ($1, $2, etc.) with Param objects.
|
|
12
|
+
* Uses Drizzle's exported classes (StringChunk, Param, SQL) to build the queryChunks.
|
|
13
|
+
*/
|
|
14
|
+
function toSQL(query: DrizzleCompiledQuery): SQL {
|
|
15
|
+
const { sql: sqlString, params } = query;
|
|
16
|
+
|
|
17
|
+
// Match parameter placeholders like $1, $2, etc.
|
|
18
|
+
const placeholderRegex = /\$(\d+)/g;
|
|
19
|
+
const queryChunks: SQLChunk[] = [];
|
|
20
|
+
let lastIndex = 0;
|
|
21
|
+
let match: RegExpExecArray | null;
|
|
22
|
+
|
|
23
|
+
while ((match = placeholderRegex.exec(sqlString)) !== null) {
|
|
24
|
+
// Add the string chunk before the placeholder
|
|
25
|
+
const textBefore = sqlString.substring(lastIndex, match.index);
|
|
26
|
+
if (textBefore) {
|
|
27
|
+
queryChunks.push(new StringChunk(textBefore));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Add the parameter value as a Param
|
|
31
|
+
const paramIndex = parseInt(match[1]!, 10) - 1; // $1 is index 0
|
|
32
|
+
queryChunks.push(sql.param(params[paramIndex]));
|
|
33
|
+
|
|
34
|
+
lastIndex = match.index + match[0].length;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Add any remaining string after the last placeholder
|
|
38
|
+
const textAfter = sqlString.substring(lastIndex);
|
|
39
|
+
if (textAfter) {
|
|
40
|
+
queryChunks.push(new StringChunk(textAfter));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Construct SQL object directly with queryChunks (same pattern as sql`` tagged template)
|
|
44
|
+
// Safe: We're reusing Drizzle's SQL constructor the same way the sql`` function does
|
|
45
|
+
return new SQL(queryChunks);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get the number of affected rows from a Drizzle query result
|
|
50
|
+
*/
|
|
51
|
+
function getAffectedRows(result: unknown): number {
|
|
52
|
+
// Drizzle returns different formats depending on the database
|
|
53
|
+
// For MySQL: array with affectedRows property
|
|
54
|
+
// For PostgreSQL/SQLite: array with rowCount or similar
|
|
55
|
+
if (Array.isArray(result)) {
|
|
56
|
+
// This is likely a select/returning result
|
|
57
|
+
return result.length;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Check for MySQL-style result
|
|
61
|
+
if (
|
|
62
|
+
result &&
|
|
63
|
+
typeof result === "object" &&
|
|
64
|
+
"affectedRows" in result &&
|
|
65
|
+
typeof result["affectedRows"] === "number"
|
|
66
|
+
) {
|
|
67
|
+
return result["affectedRows"];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Check for PostgreSQL-style result with rowCount
|
|
71
|
+
if (
|
|
72
|
+
result &&
|
|
73
|
+
typeof result === "object" &&
|
|
74
|
+
"rowCount" in result &&
|
|
75
|
+
(typeof result["rowCount"] === "number" || typeof result["rowCount"] === "bigint")
|
|
76
|
+
) {
|
|
77
|
+
const rowCount = result["rowCount"];
|
|
78
|
+
if (rowCount > Number.MAX_SAFE_INTEGER) {
|
|
79
|
+
throw new Error(`rowCount BigInt value ${rowCount.toString()} exceeds JS safe integer range`);
|
|
80
|
+
}
|
|
81
|
+
return Number(rowCount);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// For update/delete operations, Drizzle might return an object with affected rows info
|
|
85
|
+
// Try to extract it from common patterns
|
|
86
|
+
if (result && typeof result === "object") {
|
|
87
|
+
// Check for changes/changes count
|
|
88
|
+
if ("changes" in result && typeof result["changes"] === "number") {
|
|
89
|
+
return result["changes"];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
throw new Error(`Unable to determine affected rows from result: ${JSON.stringify(result)}`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Execute the retrieval phase of a Unit of Work using Drizzle
|
|
98
|
+
*
|
|
99
|
+
* All retrieval queries are executed inside a single transaction to ensure
|
|
100
|
+
* snapshot isolation - all reads see a consistent view of the database.
|
|
101
|
+
*
|
|
102
|
+
* @param db - The Drizzle database instance
|
|
103
|
+
* @param retrievalBatch - Array of Drizzle SQL queries
|
|
104
|
+
* @returns Array of query results matching the retrieval operations order
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```ts
|
|
108
|
+
* const retrievalResults = await executeDrizzleRetrievalPhase(db, compiled.retrievalBatch);
|
|
109
|
+
* const [users, posts] = retrievalResults;
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export async function executeDrizzleRetrievalPhase(
|
|
113
|
+
db: DBType,
|
|
114
|
+
retrievalBatch: DrizzleCompiledQuery[],
|
|
115
|
+
): Promise<DrizzleResult[]> {
|
|
116
|
+
// If no retrieval operations, return empty array immediately
|
|
117
|
+
if (retrievalBatch.length === 0) {
|
|
118
|
+
return [];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const retrievalResults: DrizzleResult[] = [];
|
|
122
|
+
|
|
123
|
+
// Execute all retrieval queries inside a transaction for snapshot isolation
|
|
124
|
+
await db.transaction(async (tx) => {
|
|
125
|
+
for (const query of retrievalBatch) {
|
|
126
|
+
const result = (await tx.execute(toSQL(query))) as DrizzleResult;
|
|
127
|
+
retrievalResults.push(result);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
return retrievalResults;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Execute the mutation phase of a Unit of Work using Drizzle
|
|
136
|
+
*
|
|
137
|
+
* All mutation queries are executed in a transaction with optimistic locking.
|
|
138
|
+
* If any version check fails, the entire transaction is rolled back and
|
|
139
|
+
* success=false is returned.
|
|
140
|
+
*
|
|
141
|
+
* @param db - The Drizzle database instance
|
|
142
|
+
* @param mutationBatch - Array of compiled mutation SQL queries with expected affected rows
|
|
143
|
+
* @returns Object with success flag and internal IDs from create operations
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* const { success } = await executeDrizzleMutationPhase(db, compiled.mutationBatch);
|
|
148
|
+
* if (!success) {
|
|
149
|
+
* console.log("Version conflict detected, retrying...");
|
|
150
|
+
* }
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
export async function executeDrizzleMutationPhase(
|
|
154
|
+
db: DBType,
|
|
155
|
+
mutationBatch: CompiledMutation<DrizzleCompiledQuery>[],
|
|
156
|
+
): Promise<MutationResult> {
|
|
157
|
+
// If there are no mutations, return success immediately
|
|
158
|
+
if (mutationBatch.length === 0) {
|
|
159
|
+
return { success: true, createdInternalIds: [] };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const createdInternalIds: (bigint | null)[] = [];
|
|
163
|
+
|
|
164
|
+
// Execute mutation batch in a transaction
|
|
165
|
+
try {
|
|
166
|
+
await db.transaction(async (tx) => {
|
|
167
|
+
for (const compiledMutation of mutationBatch) {
|
|
168
|
+
const result = await tx.execute(toSQL(compiledMutation.query));
|
|
169
|
+
|
|
170
|
+
// For creates (expectedAffectedRows === null), try to extract internal ID
|
|
171
|
+
if (compiledMutation.expectedAffectedRows === null) {
|
|
172
|
+
// Check if result is an array with rows (RETURNING clause supported)
|
|
173
|
+
if (Array.isArray(result) && result.length > 0) {
|
|
174
|
+
const row = result[0] as Record<string, unknown>;
|
|
175
|
+
// Look for _internalId column in the returned row
|
|
176
|
+
if ("_internalId" in row || "_internal_id" in row) {
|
|
177
|
+
const internalId = (row["_internalId"] ?? row["_internal_id"]) as bigint;
|
|
178
|
+
createdInternalIds.push(internalId);
|
|
179
|
+
} else {
|
|
180
|
+
// RETURNING supported but _internalId not found
|
|
181
|
+
createdInternalIds.push(null);
|
|
182
|
+
}
|
|
183
|
+
} else {
|
|
184
|
+
// No RETURNING support (e.g., MySQL)
|
|
185
|
+
createdInternalIds.push(null);
|
|
186
|
+
}
|
|
187
|
+
} else {
|
|
188
|
+
// Check affected rows for updates/deletes
|
|
189
|
+
const affectedRows = getAffectedRows(result);
|
|
190
|
+
|
|
191
|
+
if (affectedRows !== compiledMutation.expectedAffectedRows) {
|
|
192
|
+
// Version conflict detected - the UPDATE/DELETE didn't affect the expected number of rows
|
|
193
|
+
// This means either the row doesn't exist or the version has changed
|
|
194
|
+
throw new Error(
|
|
195
|
+
`Version conflict: expected ${compiledMutation.expectedAffectedRows} rows affected, but got ${affectedRows}`,
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
return { success: true, createdInternalIds };
|
|
203
|
+
} catch (error) {
|
|
204
|
+
// Transaction failed - could be version conflict or other constraint violation
|
|
205
|
+
// Return success=false to indicate the UOW should be retried
|
|
206
|
+
if (error instanceof Error && error.message.includes("Version conflict")) {
|
|
207
|
+
return { success: false };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Other database errors should be thrown
|
|
211
|
+
throw error;
|
|
212
|
+
}
|
|
213
|
+
}
|