refactor(core): replace Database.path with config-backed configuredPath
This commit is contained in:
parent
ca318328ea
commit
651c23ba1d
4 changed files with 26 additions and 33 deletions
|
|
@ -4,7 +4,7 @@ import { EffectDrizzleSqlite } from "@opencode-ai/effect-drizzle-sqlite"
|
|||
import { layer as sqliteLayer } from "#sqlite"
|
||||
import { Config, Context, Effect, Layer } from "effect"
|
||||
import { Global } from "../global"
|
||||
import { truthy, truthyConfig } from "../flag/flag"
|
||||
import { truthyConfig } from "../flag/flag"
|
||||
import { isAbsolute, join } from "path"
|
||||
import { DatabaseMigration } from "./migration"
|
||||
import { InstallationChannel } from "../installation/version"
|
||||
|
|
@ -40,8 +40,7 @@ export function layerFromPath(filename: string) {
|
|||
return layer.pipe(Layer.provide(sqliteLayer({ filename })))
|
||||
}
|
||||
|
||||
/** One placement rule shared by the config-backed layer and the V1 `path()` helper. */
|
||||
export function resolvePath(input: { readonly file: string | undefined; readonly disableChannelDb: boolean }) {
|
||||
function resolvePath(input: { readonly file: string | undefined; readonly disableChannelDb: boolean }) {
|
||||
if (input.file) {
|
||||
if (input.file === ":memory:" || isAbsolute(input.file)) return input.file
|
||||
return join(Global.Path.data, input.file)
|
||||
|
|
@ -51,24 +50,18 @@ export function resolvePath(input: { readonly file: string | undefined; readonly
|
|||
return join(Global.Path.data, `opencode-${InstallationChannel.replace(/[^a-zA-Z0-9._-]/g, "-")}.db`)
|
||||
}
|
||||
|
||||
/** V1 compatibility helper; reads the process environment at call time. */
|
||||
export function path() {
|
||||
return resolvePath({
|
||||
file: process.env.OPENCODE_DB,
|
||||
disableChannelDb: truthy("OPENCODE_DISABLE_CHANNEL_DB"),
|
||||
})
|
||||
}
|
||||
/**
|
||||
* The database placement every consumer shares, resolved through Effect
|
||||
* Config so tests and tooling can override it with a ConfigProvider. Used by
|
||||
* the layer below and by external tooling such as `opencode db`.
|
||||
*/
|
||||
export const configuredPath = Effect.gen(function* () {
|
||||
const file = yield* Config.string("OPENCODE_DB").pipe(Config.withDefault(undefined))
|
||||
const disableChannelDb = yield* truthyConfig("OPENCODE_DISABLE_CHANNEL_DB")
|
||||
return resolvePath({ file, disableChannelDb })
|
||||
}).pipe(Effect.orDie)
|
||||
|
||||
// Placement is resolved through Effect Config when the layer is built, not at
|
||||
// module import, so tests and tooling can override it with a ConfigProvider.
|
||||
// truthyConfig shares the `truthy` grammar so this layer and the V1 `path()`
|
||||
// helper always agree on the same environment.
|
||||
const configuredLayer = Layer.unwrap(
|
||||
Effect.gen(function* () {
|
||||
const file = yield* Config.string("OPENCODE_DB").pipe(Config.withDefault(undefined))
|
||||
const disableChannelDb = yield* truthyConfig("OPENCODE_DISABLE_CHANNEL_DB")
|
||||
return layerFromPath(resolvePath({ file, disableChannelDb }))
|
||||
}),
|
||||
).pipe(Layer.orDie)
|
||||
// Placement is resolved when the layer is built, not at module import.
|
||||
const configuredLayer = Layer.unwrap(Effect.map(configuredPath, layerFromPath))
|
||||
|
||||
export const node = makeGlobalNode({ service: Service, layer: configuredLayer, deps: [] })
|
||||
|
|
|
|||
|
|
@ -6,16 +6,15 @@ import { Global } from "@opencode-ai/core/global"
|
|||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||
import { tmpdir } from "./fixture/tmpdir"
|
||||
|
||||
const resolve = (env: Record<string, string>) =>
|
||||
Effect.runPromise(Effect.provide(Database.configuredPath, ConfigProvider.layer(ConfigProvider.fromUnknown(env))))
|
||||
|
||||
describe("Database placement", () => {
|
||||
test("resolves explicit files, relative names, and the channel default", () => {
|
||||
expect(Database.resolvePath({ file: ":memory:", disableChannelDb: false })).toBe(":memory:")
|
||||
expect(Database.resolvePath({ file: "/tmp/explicit.db", disableChannelDb: false })).toBe("/tmp/explicit.db")
|
||||
expect(Database.resolvePath({ file: "relative.db", disableChannelDb: false })).toBe(
|
||||
path.join(Global.Path.data, "relative.db"),
|
||||
)
|
||||
expect(Database.resolvePath({ file: undefined, disableChannelDb: true })).toBe(
|
||||
path.join(Global.Path.data, "opencode.db"),
|
||||
)
|
||||
test("resolves explicit files, relative names, and the channel default", async () => {
|
||||
expect(await resolve({ OPENCODE_DB: ":memory:" })).toBe(":memory:")
|
||||
expect(await resolve({ OPENCODE_DB: "/tmp/explicit.db" })).toBe("/tmp/explicit.db")
|
||||
expect(await resolve({ OPENCODE_DB: "relative.db" })).toBe(path.join(Global.Path.data, "relative.db"))
|
||||
expect(await resolve({ OPENCODE_DISABLE_CHANNEL_DB: "true" })).toBe(path.join(Global.Path.data, "opencode.db"))
|
||||
})
|
||||
|
||||
test("reads placement from the active ConfigProvider when the layer is built", async () => {
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ const QueryCommand = effectCmd({
|
|||
}
|
||||
return
|
||||
}
|
||||
const child = spawn("sqlite3", [Database.path()], {
|
||||
const child = spawn("sqlite3", [yield* Database.configuredPath], {
|
||||
stdio: "inherit",
|
||||
})
|
||||
yield* Effect.promise(() => new Promise((resolve) => child.on("close", resolve)))
|
||||
|
|
@ -47,7 +47,7 @@ const PathCommand = effectCmd({
|
|||
describe: "print the database path",
|
||||
instance: false,
|
||||
handler: Effect.fn("Cli.db.path")(function* () {
|
||||
console.log(Database.path())
|
||||
console.log(yield* Database.configuredPath)
|
||||
}),
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import { rm } from "fs/promises"
|
||||
import { Database } from "@opencode-ai/core/database/database"
|
||||
import { Effect } from "effect"
|
||||
import { disposeAllInstances } from "./fixture"
|
||||
|
||||
export async function resetDatabase() {
|
||||
await disposeAllInstances().catch(() => undefined)
|
||||
const dbPath = Database.path()
|
||||
const dbPath = await Effect.runPromise(Database.configuredPath)
|
||||
await rm(dbPath, { force: true }).catch(() => undefined)
|
||||
await rm(`${dbPath}-wal`, { force: true }).catch(() => undefined)
|
||||
await rm(`${dbPath}-shm`, { force: true }).catch(() => undefined)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue