OpenCode 源码解析
第 14 讲:Database 与存储层——SQLite + Drizzle 持久化架构
基于 dev 分支源码 · 2026-07-21
一、存储层:OpenCode 的持久化引擎
前十三讲覆盖了 OpenCode 从 CLI 到 TUI 的核心能力。这一讲进入Database 与存储层——OpenCode 基于 SQLite + Drizzle ORM 构建的持久化架构。数据库模块横跨 packages/core/src/database/ 和 13 个 SQL Schema 文件,支撑 Session、Event、Account、Permission、Share 等所有核心数据。
📦 本讲核心文件
packages/core/src/database/database.ts(57 行)— 数据库服务
packages/core/src/database/sqlite.ts(8 行)— SQLite 抽象层
packages/core/src/session/sql.ts(176 行)— Session Schema
packages/core/src/account/sql.ts— Account Schema
packages/core/src/permission/sql.ts— Permission Schema
二、Database Service 架构
database.ts(57 行)实现了 OpenCode 的数据库服务,基于 Effect + Drizzle ORM + SQLite 构建。
1. 数据库服务接口
📄 database/database.ts (第 16-37 行)
export interface Interface {
db: DatabaseShape
}
export class Service extends Context.Service<
Service, Interface
>("@opencode/v2/storage/Database") {}
const layer = Layer.effect(
Service,
Effect.gen(function* () {
const db = yield* makeDatabase
// SQLite 优化配置
yield* db.run("PRAGMA journal_mode = WAL")
yield* db.run("PRAGMA synchronous = NORMAL")
yield* db.run("PRAGMA busy_timeout = 5000")
yield* db.run("PRAGMA cache_size = -64000")
yield* db.run("PRAGMA foreign_keys = ON")
yield* db.run("PRAGMA wal_checkpoint(PASSIVE)")
// 自动应用数据库迁移
yield* DatabaseMigration.apply(db)
return { db }
}).pipe(Effect.orDie),
)
设计亮点:数据库服务在初始化时配置了 6 个 SQLite PRAGMA 优化参数,包括 WAL 模式、同步级别、忙超时、缓存大小、外键约束和被动检查点。迁移自动应用,确保 Schema 一致性。
2. SQLite 优化配置
| PRAGMA | 值 | 作用 |
|---|---|---|
| journal_mode | WAL | 预写日志模式,读写不阻塞 |
| synchronous | NORMAL | 平衡安全与性能 |
| busy_timeout | 5000ms | 忙等待超时 5 秒 |
| cache_size | -64000 | 64MB 缓存 |
| foreign_keys | ON | 启用外键约束 |
| wal_checkpoint | PASSIVE | 被动检查点 |
三、Drizzle ORM Schema 设计
OpenCode 使用 Drizzle ORM 定义所有数据库 Schema,遵循 snake_case 命名规范。
1. Session Schema
📄 session/sql.ts (第 1-60 行)
import { sqliteTable, text, integer, real }
from "drizzle-orm/sqlite-core"
export const SessionTable = sqliteTable(
"session", {
id: text().primaryKey(),
directory: text().notNull(),
title: text().notNull(),
model: text().notNull(),
provider: text().notNull(),
time_created: integer().notNull(),
time_updated: integer().notNull(),
time_used: real().notNull(),
// ... 更多字段
}
)
export const SessionInputTable = sqliteTable(
"session_input", {
id: text().primaryKey(),
session_id: text().notNull(),
content: text().notNull(),
time_created: integer().notNull(),
}
)
export const SessionMessageTable = sqliteTable(
"session_message", {
id: text().primaryKey(),
session_id: text().notNull(),
role: text().notNull(),
content: text().notNull(),
time_created: integer().notNull(),
}
)
Schema 设计:Session 表存储会话元数据,SessionInput 表存储用户输入,SessionMessage 表存储消息。所有表使用 snake_case 命名,时间字段使用整数存储。
四、数据库迁移系统
OpenCode 使用自动迁移系统,确保数据库 Schema 与代码版本一致。
1. 迁移流程
📄 database/database.ts (第 33 行)
// 自动应用数据库迁移
yield* DatabaseMigration.apply(db)
迁移流程:数据库服务初始化时自动调用 DatabaseMigration.apply(db),检查并应用所有待执行的迁移。迁移文件存储在 database/migration/ 目录。
五、总结
🔹 SQLite + Drizzle ORM + Effect 三层架构
🔹 6 个 PRAGMA 优化参数:WAL、NORMAL、5000ms、64MB、外键、被动检查点
🔹 Session/Input/Message 三表设计
🔹 自动迁移系统确保 Schema 一致性
🔹 snake_case 命名规范
🔹 13 个 SQL Schema 文件覆盖 Session、Event、Account、Permission、Share 等
← 系列导航 →
← 第 13 讲:TUI 终端界面 | 第 15 讲:Env 与运行时标志 →
关注公众号获取更多 OpenCode 源码解析干货
源码:https://github.com/opencode-ai/opencode
夜雨聆风