From 322bb012575abbecb4ca7cb3cc9f92c148dd989c Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Tue, 28 Apr 2026 14:42:59 -0400 Subject: [PATCH] refactor(opencode): unify drizzle client through effect adapter The Effect adapter is now the only Drizzle wrapper over the bun:sqlite handle. Database.Client owns the lifecycle, DatabaseEffect.Service just exposes that handle. Removes acquire/release ref counting that was ceremony around the same module-level singleton. --- packages/opencode/src/storage/db-effect.ts | 21 ++++-------- packages/opencode/src/storage/db.bun.ts | 8 ++--- packages/opencode/src/storage/db.node.ts | 6 ++-- packages/opencode/src/storage/db.ts | 39 +++------------------- 4 files changed, 16 insertions(+), 58 deletions(-) diff --git a/packages/opencode/src/storage/db-effect.ts b/packages/opencode/src/storage/db-effect.ts index bd24bc2d41..2cdf21ff2d 100644 --- a/packages/opencode/src/storage/db-effect.ts +++ b/packages/opencode/src/storage/db-effect.ts @@ -1,21 +1,12 @@ import { Database } from "@/storage/db" -import * as StorageSchema from "@/storage/schema" import { Context, Effect, Layer } from "effect" -import { drizzle, type EffectSQLiteDatabase } from "@opencode-ai/effect-drizzle-sqlite" +import type { EffectSQLiteDatabase } from "@opencode-ai/effect-drizzle-sqlite" +import * as StorageSchema from "@/storage/schema" -const schema = { ...StorageSchema } +export class Service extends Context.Service>()( + "@opencode/DatabaseEffect", +) {} -export class Service extends Context.Service>()("@opencode/DatabaseEffect") {} - -export const layer = Layer.effect( - Service, - Effect.acquireRelease( - Effect.sync(() => { - const lease = Database.acquire() - return { lease, db: drizzle({ client: lease.client.$client, schema }) } - }), - (value) => Effect.sync(() => value.lease.release()), - ).pipe(Effect.map((value) => value.db)), -) +export const layer = Layer.effect(Service, Effect.sync(Database.Client)) export * as DatabaseEffect from "./db-effect" diff --git a/packages/opencode/src/storage/db.bun.ts b/packages/opencode/src/storage/db.bun.ts index fa6190925a..dfea27aa85 100644 --- a/packages/opencode/src/storage/db.bun.ts +++ b/packages/opencode/src/storage/db.bun.ts @@ -1,8 +1,6 @@ import { Database } from "bun:sqlite" -import { drizzle } from "drizzle-orm/bun-sqlite" +import { drizzle } from "@opencode-ai/effect-drizzle-sqlite" -export function init(path: string) { - const sqlite = new Database(path, { create: true }) - const db = drizzle({ client: sqlite }) - return db +export function init>(path: string, schema: TSchema) { + return drizzle({ client: new Database(path, { create: true }), schema }) } diff --git a/packages/opencode/src/storage/db.node.ts b/packages/opencode/src/storage/db.node.ts index 0dba8dcef3..8c6c67a130 100644 --- a/packages/opencode/src/storage/db.node.ts +++ b/packages/opencode/src/storage/db.node.ts @@ -1,8 +1,6 @@ import { DatabaseSync } from "node:sqlite" import { drizzle } from "drizzle-orm/node-sqlite" -export function init(path: string) { - const sqlite = new DatabaseSync(path) - const db = drizzle({ client: sqlite }) - return db +export function init>(path: string, schema: TSchema) { + return drizzle({ client: new DatabaseSync(path), schema }) } diff --git a/packages/opencode/src/storage/db.ts b/packages/opencode/src/storage/db.ts index dc686203ca..daace68c2d 100644 --- a/packages/opencode/src/storage/db.ts +++ b/packages/opencode/src/storage/db.ts @@ -1,6 +1,4 @@ -import { type SQLiteBunDatabase } from "drizzle-orm/bun-sqlite" import { migrate } from "drizzle-orm/bun-sqlite/migrator" -import { type SQLiteTransaction } from "drizzle-orm/sqlite-core" export * from "drizzle-orm" import { LocalContext } from "@/util/local-context" import { lazy } from "../util/lazy" @@ -14,6 +12,7 @@ import { Flag } from "@opencode-ai/core/flag/flag" import { InstallationChannel } from "@opencode-ai/core/installation/version" import { InstanceState } from "@/effect/instance-state" import { iife } from "@/util/iife" +import * as StorageSchema from "@/storage/schema" import { init } from "#db" declare const OPENCODE_MIGRATIONS: { sql: string; timestamp: number; name: string }[] | undefined @@ -42,9 +41,9 @@ export const Path = iife(() => { return getChannelPath() }) -export type Transaction = SQLiteTransaction<"sync", void> +export type Client = ReturnType -export type Client = SQLiteBunDatabase +export type Transaction = Parameters[0]>[0] type Journal = { sql: string; timestamp: number; name: string }[] @@ -91,7 +90,7 @@ function migrations(dir: string): Journal { export function open() { log.info("opening database", { path: Path }) - const db = init(Path) + const db = init(Path, StorageSchema) db.run("PRAGMA journal_mode = WAL") db.run("PRAGMA synchronous = NORMAL") @@ -123,38 +122,10 @@ export function open() { export const Client = lazy(open) -let layerRefs = 0 -let layerOwner: Client | undefined - -export function acquire() { - const owner = Client.peek() === undefined - const client = Client() - if (owner) layerOwner = client - layerRefs++ - - let released = false - return { - client, - release() { - if (released) return - released = true - layerRefs-- - if (layerRefs === 0 && layerOwner === client) { - layerOwner = undefined - close(client) - } - }, - } -} - export function close(client = Client.peek()) { if (!client) return client.$client.close() - if (Client.peek() === client) { - layerRefs = 0 - layerOwner = undefined - Client.reset() - } + if (Client.peek() === client) Client.reset() } export type TxOrDb = Transaction | Client