1import * as Effect from "effect/Effect";
2import type { RuntimeContext } from "../../RuntimeContext.ts";
3import { applyAlchemyFormat } from "../../SQL/Migrations/AlchemyFormat.ts";
4import {
5 MigrationError,
6 type MigrationHistoryConflictError,
7 type SqlExecutor,
8} from "../../SQL/Migrations/Format.ts";
9import { inlineSqlParams } from "../../SQL/Migrations/Utils.ts";
10import { DurableObjectState } from "./DurableObjectState.ts";
11import type { SqlMigrationSnapshot } from "./SqlMigrationsRuntime.ts";
12
13/** @internal */
14export const applySqlMigrations: (
15 migrations: SqlMigrationSnapshot,
16) => Effect.Effect<
17 void,
18 MigrationError | MigrationHistoryConflictError,
19 DurableObjectState | RuntimeContext
20> = Effect.fn("Cloudflare.SqlMigrations.apply")(function* (migrations) {
21 const { raw } = yield* DurableObjectState;
22 const storage = raw.storage;
23 const executor: SqlExecutor = {
24 dialect: "sqlite",
25 query: (sql, params = []) =>
26 Effect.try({
27 try: () =>
28 storage.sql.exec(inlineSqlParams(sql, params, "sqlite")).toArray(),
29 catch: (cause) =>
30 new MigrationError({
31 message: "Failed to query migration history",
32 cause,
33 }),
34 }),
35 batch: (statements) =>
36 Effect.try({
37 try: () =>
38 storage.transactionSync(() => {
39 for (const statement of statements) storage.sql.exec(statement);
40 }),
41 catch: (cause) =>
42 new MigrationError({
43 message: "Failed to apply SQL migration",
44 cause,
45 }),
46 }),
47 };
48 yield* applyAlchemyFormat({
49 executor,
50 table: migrations.table,
51 records: migrations.records,
52 });
53});