refactor(core): internalize effect sqlite adapter
This commit is contained in:
@@ -375,7 +375,6 @@
|
||||
"@modelcontextprotocol/sdk": "1.29.0",
|
||||
"@opencode-ai/ai": "workspace:*",
|
||||
"@opencode-ai/codemode": "workspace:*",
|
||||
"@opencode-ai/effect-drizzle-sqlite": "workspace:*",
|
||||
"@opencode-ai/plugin": "workspace:*",
|
||||
"@opencode-ai/schema": "workspace:*",
|
||||
"@opencode-ai/util": "workspace:*",
|
||||
@@ -477,20 +476,6 @@
|
||||
"@parcel/watcher-win32-x64": "2.5.1",
|
||||
},
|
||||
},
|
||||
"packages/effect-drizzle-sqlite": {
|
||||
"name": "@opencode-ai/effect-drizzle-sqlite",
|
||||
"version": "1.18.15",
|
||||
"dependencies": {
|
||||
"drizzle-orm": "catalog:",
|
||||
"effect": "catalog:",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@effect/sql-sqlite-bun": "catalog:",
|
||||
"@tsconfig/bun": "catalog:",
|
||||
"@types/bun": "catalog:",
|
||||
"@typescript/native-preview": "catalog:",
|
||||
},
|
||||
},
|
||||
"packages/enterprise": {
|
||||
"name": "@opencode-ai/enterprise",
|
||||
"version": "1.18.15",
|
||||
@@ -2088,8 +2073,6 @@
|
||||
|
||||
"@opencode-ai/desktop": ["@opencode-ai/desktop@workspace:packages/desktop"],
|
||||
|
||||
"@opencode-ai/effect-drizzle-sqlite": ["@opencode-ai/effect-drizzle-sqlite@workspace:packages/effect-drizzle-sqlite"],
|
||||
|
||||
"@opencode-ai/enterprise": ["@opencode-ai/enterprise@workspace:packages/enterprise"],
|
||||
|
||||
"@opencode-ai/function": ["@opencode-ai/function@workspace:packages/function"],
|
||||
|
||||
@@ -100,7 +100,6 @@
|
||||
"@ff-labs/fff-bun": "0.10.1",
|
||||
"@ff-labs/fff-node": "0.10.1",
|
||||
"@opencode-ai/codemode": "workspace:*",
|
||||
"@opencode-ai/effect-drizzle-sqlite": "workspace:*",
|
||||
"@opencode-ai/ai": "workspace:*",
|
||||
"@opencode-ai/schema": "workspace:*",
|
||||
"@opencode-ai/plugin": "workspace:*",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as Database from "./database.js"
|
||||
|
||||
import { EffectDrizzleSqlite } from "@opencode-ai/effect-drizzle-sqlite"
|
||||
import { EffectDrizzleSqlite } from "./drizzle.js"
|
||||
import { sqliteLayer, supportsForeignKeyToggle, supportsTuningPragmas } from "#sqlite"
|
||||
import { Context, Effect, Layer, Schema } from "effect"
|
||||
import type { SqlClient } from "effect/unstable/sql"
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./drizzle/index.js"
|
||||
@@ -3,7 +3,7 @@ export * as DatabaseMigration from "./migration.js"
|
||||
import { sql } from "drizzle-orm"
|
||||
import { Effect, Semaphore } from "effect"
|
||||
import { supportsForeignKeyToggle } from "#sqlite"
|
||||
import type { EffectDrizzleSqlite } from "@opencode-ai/effect-drizzle-sqlite"
|
||||
import type { EffectDrizzleSqlite } from "./drizzle.js"
|
||||
import { migrations } from "./migration.gen.js"
|
||||
import schema from "./schema.gen.js"
|
||||
import { Global } from "@opencode-ai/util/global"
|
||||
|
||||
@@ -7,7 +7,7 @@ import { makeGlobalNode } from "@opencode-ai/util/effect/app-node"
|
||||
import { AbsolutePath } from "../schema.js"
|
||||
import { ProjectSchema } from "./schema.js"
|
||||
import { ProjectDirectoryTable } from "./sql.js"
|
||||
import type { EffectDrizzleSqlite } from "@opencode-ai/effect-drizzle-sqlite"
|
||||
import type { EffectDrizzleSqlite } from "../database/drizzle.js"
|
||||
import type { Project } from "../project.js"
|
||||
|
||||
export type Directory = Project.Directory
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { EffectDrizzleSqlite } from "@opencode-ai/effect-drizzle-sqlite"
|
||||
import type { EffectDrizzleSqlite } from "../database/drizzle.js"
|
||||
import { isNotNull, isNull, ne, or } from "drizzle-orm"
|
||||
import { sqliteTable, text, integer, primaryKey } from "drizzle-orm/sqlite-core"
|
||||
import { absoluteArrayColumn, absoluteColumn } from "../database/path.js"
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core"
|
||||
import { Effect } from "effect"
|
||||
import type { SqlClient as SqlClientService } from "effect/unstable/sql/SqlClient"
|
||||
import { isSqlError } from "effect/unstable/sql/SqlError"
|
||||
import { EffectDrizzleSqlite } from "../src/index.js"
|
||||
import { EffectDrizzleSqlite } from "@opencode-ai/core/database/drizzle"
|
||||
|
||||
const users = sqliteTable("users", {
|
||||
id: integer().primaryKey({ autoIncrement: true }),
|
||||
@@ -3,7 +3,7 @@ import { $ } from "bun"
|
||||
import { fileURLToPath } from "url"
|
||||
import path from "path"
|
||||
import { SqliteClient } from "@effect/sql-sqlite-bun"
|
||||
import { EffectDrizzleSqlite } from "@opencode-ai/effect-drizzle-sqlite"
|
||||
import { EffectDrizzleSqlite } from "@opencode-ai/core/database/drizzle"
|
||||
import { Effect, Layer } from "effect"
|
||||
import { sql } from "drizzle-orm"
|
||||
import { DatabaseMigration } from "@opencode-ai/core/database/migration"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { SqliteClient } from "@effect/sql-sqlite-bun"
|
||||
import { EffectDrizzleSqlite } from "@opencode-ai/effect-drizzle-sqlite"
|
||||
import { EffectDrizzleSqlite } from "@opencode-ai/core/database/drizzle"
|
||||
import { Database } from "@opencode-ai/core/database/database"
|
||||
import { DatabaseMigration } from "@opencode-ai/core/database/migration"
|
||||
import { V1Migration } from "@opencode-ai/core/database/v1-migration"
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
# Effect Drizzle SQLite
|
||||
|
||||
This package vendors a Drizzle Effect SQLite adapter for this repo.
|
||||
|
||||
- Keep this package generic: Drizzle + Effect + SQLite only.
|
||||
- Do not add opencode-specific tables, paths, migrations, post-commit hooks, or domain storage APIs here.
|
||||
- Runtime code should depend on generic `effect/unstable/sql/SqlClient`, not a specific SQLite driver.
|
||||
- Concrete SQLite clients such as `@effect/sql-sqlite-bun` belong in tests or examples unless this package intentionally adds a driver-specific helper.
|
||||
- Preserve Drizzle adapter naming and behavior where possible so this can be replaced by upstream `drizzle-orm/effect-sqlite` later.
|
||||
- If touching copied Drizzle internals, compare with current `drizzle-orm@1.0.0-rc.2` declarations and runtime JS.
|
||||
- If touching Effect APIs, verify against `/Users/kit/code/open-source/effect-smol`.
|
||||
|
||||
Useful entry points:
|
||||
|
||||
- `src/effect-sqlite/driver.ts`: creates the Effect-backed Drizzle database with `make` and `makeWithDefaults`.
|
||||
- `src/effect-sqlite/session.ts`: adapts generic Effect `SqlClient` execution and transactions to Drizzle SQLite sessions.
|
||||
- `src/sqlite-core/effect/*`: Effect-yieldable SQLite query builders.
|
||||
- `src/internal/drizzle-utils.ts`: local typed shims for Drizzle runtime internals that RC2 does not expose in declarations.
|
||||
- `examples/basic.ts`: minimal usage example with Bun SQLite.
|
||||
@@ -1,92 +0,0 @@
|
||||
import { SqliteClient } from "@effect/sql-sqlite-bun"
|
||||
import { eq } from "drizzle-orm"
|
||||
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core"
|
||||
import * as Context from "effect/Context"
|
||||
import * as Effect from "effect/Effect"
|
||||
import * as Layer from "effect/Layer"
|
||||
import * as Schema from "effect/Schema"
|
||||
import { EffectDrizzleSqlite } from "../src/index.js"
|
||||
|
||||
const users = sqliteTable("users", {
|
||||
id: integer().primaryKey({ autoIncrement: true }),
|
||||
name: text().notNull(),
|
||||
})
|
||||
|
||||
type User = typeof users.$inferSelect
|
||||
|
||||
const makeDatabase = EffectDrizzleSqlite.makeWithDefaults()
|
||||
type DatabaseShape = Effect.Success<typeof makeDatabase>
|
||||
|
||||
const sqliteLayer = SqliteClient.layer({ filename: ":memory:", disableWAL: true })
|
||||
|
||||
class Database extends Context.Service<Database, DatabaseShape>()("@opencode/example/Database") {
|
||||
static layer = Layer.effect(Database, makeDatabase).pipe(Layer.provide(sqliteLayer))
|
||||
}
|
||||
|
||||
class UserStoreError extends Schema.TaggedErrorClass<UserStoreError>()("UserStoreError", {
|
||||
message: Schema.String,
|
||||
cause: Schema.optional(Schema.Defect()),
|
||||
}) {}
|
||||
|
||||
const mapStoreError = (message: string) => (cause: unknown) => new UserStoreError({ message, cause })
|
||||
|
||||
interface UserStoreShape {
|
||||
migrate(): Effect.Effect<void, UserStoreError>
|
||||
create(name: string): Effect.Effect<void, UserStoreError>
|
||||
rename(from: string, to: string): Effect.Effect<void, UserStoreError>
|
||||
list(): Effect.Effect<User[], UserStoreError>
|
||||
}
|
||||
|
||||
class UserStore extends Context.Service<UserStore, UserStoreShape>()("@opencode/example/UserStore") {
|
||||
static layer = Layer.effect(
|
||||
UserStore,
|
||||
Effect.gen(function* () {
|
||||
const db = yield* Database
|
||||
|
||||
return UserStore.of({
|
||||
migrate: Effect.fn("UserStore.migrate")(function* () {
|
||||
yield* EffectDrizzleSqlite.migrate(db, { migrationsFolder: `${import.meta.dirname}/migrations` }).pipe(
|
||||
Effect.mapError((cause) => new UserStoreError({ message: "Failed to migrate users", cause })),
|
||||
)
|
||||
}),
|
||||
create: Effect.fn("UserStore.create")(function* (name: string) {
|
||||
yield* db
|
||||
.insert(users)
|
||||
.values({ name })
|
||||
.pipe(Effect.asVoid, Effect.mapError(mapStoreError("Failed to create user")))
|
||||
}),
|
||||
rename: Effect.fn("UserStore.rename")(function* (from: string, to: string) {
|
||||
yield* db
|
||||
.transaction(
|
||||
Effect.fnUntraced(function* (tx) {
|
||||
yield* tx.insert(users).values({ name: from })
|
||||
yield* tx.update(users).set({ name: to }).where(eq(users.name, from))
|
||||
}),
|
||||
{ behavior: "immediate" },
|
||||
)
|
||||
.pipe(Effect.asVoid, Effect.mapError(mapStoreError("Failed to rename user")))
|
||||
}),
|
||||
list: Effect.fn("UserStore.list")(function* () {
|
||||
return yield* db
|
||||
.select()
|
||||
.from(users)
|
||||
.pipe(Effect.mapError(mapStoreError("Failed to list users")))
|
||||
}),
|
||||
})
|
||||
}),
|
||||
).pipe(Layer.provide(Database.layer))
|
||||
}
|
||||
|
||||
const program = Effect.gen(function* () {
|
||||
const userStore = yield* UserStore
|
||||
|
||||
yield* userStore.migrate()
|
||||
yield* userStore.create("Ada")
|
||||
yield* userStore.rename("Grace", "Grace Hopper")
|
||||
|
||||
return yield* userStore.list()
|
||||
})
|
||||
|
||||
const rows = await Effect.runPromise(program.pipe(Effect.provide(UserStore.layer)))
|
||||
|
||||
console.log(rows)
|
||||
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "1.18.15",
|
||||
"name": "@opencode-ai/effect-drizzle-sqlite",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test": "bun test --timeout 30000 --only-failures",
|
||||
"typecheck": "tsgo --noEmit"
|
||||
},
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./effect-sqlite": "./src/effect-sqlite/index.ts",
|
||||
"./effect-sqlite/migrator": "./src/effect-sqlite/migrator.ts",
|
||||
"./sqlite-core/effect": "./src/sqlite-core/effect/index.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@effect/sql-sqlite-bun": "catalog:",
|
||||
"@tsconfig/bun": "catalog:",
|
||||
"@types/bun": "catalog:",
|
||||
"@typescript/native-preview": "catalog:"
|
||||
},
|
||||
"dependencies": {
|
||||
"drizzle-orm": "catalog:",
|
||||
"effect": "catalog:"
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "@tsconfig/bun/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"allowImportingTsExtensions": false,
|
||||
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
||||
"noUncheckedIndexedAccess": false,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "@effect/language-service",
|
||||
"transform": "@effect/language-service/transform",
|
||||
"namespaceImportPackages": ["effect", "@effect/*"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user