ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Hoarder(Karakeep)数据库迁移实战:从 Drizzle Schema 到迁移文件生成与应用的完整指南

Hoarder(Karakeep)数据库迁移实战:从 Drizzle Schema 到迁移文件生成与应用的完整指南 HoarderKarakeep数据库迁移实战从 Drizzle Schema 到迁移文件生成与应用的完整指南【免费下载链接】hoarderA self-hostable bookmark-everything app (links, notes and images) with AI-based automatic tagging and full text search项目地址: https://gitcode.com/GitHub_Trending/ho/hoarder本文面向自托管 Hoarder现已更名为 Karakeep的开发者与运维人员系统讲解该项目的数据库迁移工作流从 schema 定义、迁移生成、迁移应用到 Drizzle Studio 可视化调试并深入仓库源码剖析 SQLite 连接、WAL 模式、降级模式等底层机制帮助你安全、可复现地推进任何 schema 变更。引言为什么需要数据库迁移HoarderKarakeep是一款自托管的书签管理应用其核心数据——书签、标签、列表、高亮、用户与 API Key 等——全部持久化在 SQLite 数据库中。当你在本地开发新功能例如给书签表新增一个字段、建立新的关联表时数据库结构schema就会与旧版本不一致。数据库迁移Database Migration正是解决这一问题的标准手段它把 schema 变更固化成可版本化、可回放、可追溯的 SQL 脚本让所有开发者以及生产环境都能以相同顺序、相同结果演进数据库。本指南以 docs/versioned_docs/version-v0.32.0/08-development/03-database.md 为核心骨架结合仓库内packages/db的实际源码与配置完整呈现 Hoarder 的数据库迁移工作流。一、Schema 唯一权威来源packages/db/schema.tsHoarder 采用Drizzle ORM作为数据库抽象层其核心原则是“以 TypeScript 代码定义 schema而不是手写 SQL 建表”。所有数据库表结构的唯一权威来源位于packages/db/schema.ts这是一份超过 1300 行的 TypeScript 定义文件包含用户、书签、标签、列表、高亮、API Key、Webhook、Feed、AI 推理结果等项目的全部数据模型。以用户表为例packages/db/schema.tsexport const users sqliteTable(user, { id: text(id) .notNull() .primaryKey() .$defaultFn(() createId()), name: text(name).notNull(), email: text(email).notNull().unique(), emailVerified: integer(emailVerified, { mode: timestamp_ms }), image: text(image), password: text(password), salt: text(salt).notNull().default(), role: text(role, { enum: [admin, user] }).default(user), // Admin Only Settings bookmarkQuota: integer(bookmarkQuota), storageQuota: integer(storageQuota), ... });几个值得留意的设计细节主键使用paralleldrive/cuid2生成createId()作为$defaultFn主键不是自增整数而是全局唯一的 CUID便于分布式与导入导出场景。时间戳统一封装schema 顶部定义了createdAtField()、modifiedAtField()等工厂函数packages/db/schema.ts统一使用integer(..., { mode: timestamp })存储时间并自动填充创建/更新时间避免各表手写重复逻辑。使用sqliteTableAPI表定义完全类型安全IDE 中修改字段后TypeScript 会立即给出引用处的类型检查反馈。规则第一条任何 schema 变更增删表、增删列、改类型、加索引都必须修改schema.ts随后生成迁移绝不允许绕过迁移直接手改生产数据库。二、三步迁移工作流生成 → 审查 → 应用原文档给出了完整的核心命令全部在仓库根目录下执行。项目通过根 package.json 中的 pnpm 脚本把命令转发到karakeep/db工作区db:generate: pnpm --filter karakeep/db run generate, db:migrate: pnpm --filter karakeep/db run migrate, db:studio: pnpm --filter karakeep/db studio第 1 步生成迁移generatepnpm run db:generate --name description_of_schema_change其中description_of_schema_change是对本次变更的简短英文描述如add-tag-color。该命令实际执行的是packages/db下的pnpm --filter karakeep/db run generate → drizzle-kit generatedrizzle-kit会对比schema.ts与数据库中已有的迁移历史journal自动生成增量 SQL 迁移文件写入packages/db/drizzle/目录由 packages/db/drizzle.config.ts 中的out: ./drizzle指定。生成的产物包含两类文件文件说明drizzle/00XX_名称.sql本次迁移的实际 SQL 语句如CREATE TABLE、ALTER TABLE、CREATE INDEXdrizzle/meta/目录下的 JSON迁移快照snapshot与 journal记录迁移历史与 schema 校验信息以仓库现状为例packages/db/drizzle/中已积累了从0000_luxuriant_johnny_blaze.sql到0025_aspiring_skaar.sql共 26 个迁移文件每个文件名由序号 随机后缀构成顺序即应用顺序。第 2 步审查生成的 SQL生成后务必打开对应的.sql文件人工审查重点确认是否误删/误改了不需要动的表ALTER TABLE是否与 SQLite 的能力兼容例如 SQLite 对ALTER TABLE ... DROP COLUMN支持有限drizzle-kit 有时会生成“重建表”式迁移索引、外键约束是否符合预期。第 3 步应用迁移migratepnpm run db:migrate该命令实际执行packages/db下的tsx migrate.ts即运行 packages/db/migrate.tsimport { migrate } from drizzle-orm/better-sqlite3/migrator; import serverConfig from karakeep/shared/config; import { db } from ./drizzle; if (serverConfig.degradedMode) { console.log(Skipping database migrations in degraded mode); } else { migrate(db, { migrationsFolder: ./drizzle }); }两个要点迁移基于 journal 增量执行drizzle 的 migrator 读取./drizzle下的迁移历史只应用尚未执行过的迁移重复运行是安全的。降级模式degradedMode下自动跳过迁移当环境变量DEGRADED_MODEtrue时packages/shared/config.ts迁移被显式跳过并以只读方式打开数据库详见第五节避免在降级只读场景下意外写库。生产环境如何应用迁移对于自托管部署迁移通常由 Docker 镜像的启动流程自动执行开发阶段则手动执行上述命令。无论哪种方式迁移脚本本身migrate.ts的逻辑与开发环境完全一致保证了开发与生产环境数据库结构的一致性。三、底层连接细节drizzle.ts 与 sqlite.ts迁移命令中 import 的db来自 packages/db/drizzle.ts它负责打开 SQLite 连接并挂载 schemaconst sqlite openSqliteDatabase(dbConfig.dbCredentials.url, { readOnly: serverConfig.degradedMode, walMode: serverConfig.database.walMode, }); instrumentDatabase(sqlite); export const db drizzle(sqlite, { schema }); export type DB typeof db;数据库文件路径由 packages/db/drizzle.config.ts 决定const databaseURL serverConfig.dataDir ? ${serverConfig.dataDir}/db.db : ./db.db;即配置了DATA_DIR时数据库位于${DATA_DIR}/db.db否则位于./db.db。真正的 SQLite 打开与 PRAGMA 设置在 packages/db/sqlite.tsif (!options.readOnly) { if (options.walMode) { sqlite.pragma(journal_mode WAL); sqlite.pragma(synchronous NORMAL); } else { sqlite.pragma(journal_mode DELETE); } } sqlite.pragma(cache_size -65536); sqlite.pragma(foreign_keys ON); sqlite.pragma(temp_store MEMORY); if (options.readOnly) { sqlite.pragma(query_only ON); }这些 PRAGMA 的选择并非随意PRAGMA值作用journal_modeWAL/DELETE默认DELETE回滚日志模式开启DB_WAL_MODEtrue后切换为 WAL 模式读写并发能力更强synchronousNORMAL仅 WAL 模式下设置在持久性与性能之间取得平衡cache_size-65536约 64 MB 页面缓存提升热数据访问性能foreign_keysON强制外键约束保证数据完整性temp_storeMEMORY临时表/排序放入内存query_onlyON仅降级只读模式下设置彻底禁止写入WAL 模式对应的环境变量是DB_WAL_MODE默认false见 packages/shared/config.ts。在并发读写压力较大的自托管场景可以按需开启。四、Drizzle Studio可视化浏览与调试pnpm run db:studio该命令启动Drizzle Studio——一个本地可视化数据库管理界面默认运行在本地端口通过浏览器访问。它直接连接drizzle.config.ts中配置的数据库即${DATA_DIR}/db.db或./db.db让你浏览所有表结构与数据行执行 SQL 查询快速检查某次迁移后的实际数据形态。在开发调试中它非常适合与迁移流程配合生成并应用迁移后立刻在 Studio 中确认新增字段、新表是否按预期出现。五、迁移相关的三个关键环境变量从源码看与数据库迁移直接相关的环境变量有三个均在 packages/shared/config.ts 中定义环境变量默认值说明DATA_DIR数据目录非空时数据库路径为${DATA_DIR}/db.db否则为./db.dbconfig.tsDB_WAL_MODEfalse是否以 WAL 模式打开数据库config.tsDEGRADED_MODEfalse降级模式跳过迁移、以只读方式打开数据库config.ts降级模式是迁移流程中需要特别留意的一点当DEGRADED_MODEtrue时migrate.ts直接打印提示并跳过迁移同时drizzle.ts以readOnly: true打开数据库。这意味着降级模式下数据库结构不会自动演进如果你同时修改了schema.ts并依赖新字段需要先退出降级模式完成迁移。六、为测试而生内存数据库与迁移重放packages/db/drizzle.ts还暴露了一个对测试极其有用的函数export function getInMemoryDB(runMigrations: boolean) { const mem new Database(:memory:); const db drizzle(mem, { schema, logger: false }); if (runMigrations) { migrate(db, { migrationsFolder: path.resolve(__dirname, ./drizzle) }); } return db; }它创建一个纯内存 SQLite 数据库并可选地在上面重放./drizzle目录中的全部迁移。这正是仓库内单元测试例如packages/api与packages/trpc中的各类路由测试验证数据层行为的方式每次测试都能从零构建出与生产完全一致的 schema互不污染。这也从侧面印证了迁移文件的“可重放性”——迁移必须保证能从空库开始依次应用到最新结构因此生成迁移后建议跑一遍相关测试作为回归验证。七、完整开发闭环示例将以上内容串起来一次典型的 schema 变更开发流程如下# 1. 修改 packages/db/schema.ts例如新增一个字段或表 # 2. 生成迁移描述本次变更 pnpm run db:generate --name add-some-new-field # 3. 审查 packages/db/drizzle/ 下新生成的 .sql 与 meta 快照 # 4. 应用到本地开发数据库 pnpm run db:migrate # 5. 用 Drizzle Studio 验证结果 pnpm run db:studio # 6. 运行相关测试测试会通过 getInMemoryDB 重放全部迁移 pnpm test结语HoarderKarakeep的数据库迁移体系可以概括为一条清晰的链路schema.tsTypeScript 单一事实源→drizzle-kit generate增量 SQL→migrate.ts按 journal 增量应用→ Drizzle Studio可视化验证。理解这条链路后无论是新增书签字段、调整标签模型还是排查迁移失败你都能快速定位到对应的源码与配置packages/db/schema.ts、packages/db/drizzle.config.ts、packages/db/migrate.ts、packages/db/drizzle.ts、packages/db/sqlite.ts并安全地在开发与生产环境中推进 schema 演进。【免费下载链接】hoarderA self-hostable bookmark-everything app (links, notes and images) with AI-based automatic tagging and full text search项目地址: https://gitcode.com/GitHub_Trending/ho/hoarder创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表