mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-13 23:52:06 +00:00
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.
This commit is contained in:
@@ -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<Service, EffectSQLiteDatabase<typeof StorageSchema>>()(
|
||||
"@opencode/DatabaseEffect",
|
||||
) {}
|
||||
|
||||
export class Service extends Context.Service<Service, EffectSQLiteDatabase<typeof schema>>()("@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"
|
||||
|
||||
@@ -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<TSchema extends Record<string, unknown>>(path: string, schema: TSchema) {
|
||||
return drizzle({ client: new Database(path, { create: true }), schema })
|
||||
}
|
||||
|
||||
@@ -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<TSchema extends Record<string, unknown>>(path: string, schema: TSchema) {
|
||||
return drizzle({ client: new DatabaseSync(path), schema })
|
||||
}
|
||||
|
||||
@@ -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<typeof open>
|
||||
|
||||
export type Client = SQLiteBunDatabase
|
||||
export type Transaction = Parameters<Parameters<Client["transaction"]>[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
|
||||
|
||||
Reference in New Issue
Block a user