core: migrate from custom JSON storage to standard Drizzle migrations to improve database reliability and performance

This replaces the previous manual JSON file system with standard Drizzle migrations, enabling:
- Proper database schema migrations with timestamp-based versioning
- Batched migration for faster migration of large datasets
- Better data integrity with proper table schemas instead of JSON blobs
- Easier database upgrades and rollback capabilities

Migration changes:
- Todo table now uses individual columns with composite PK instead of JSON blob
- Share table removes unused download share data
- Session diff table moved from database table to file storage
- All migrations now use proper Drizzle format with per-folder layout

Users will see a one-time migration on next run that migrates existing JSON data to the new SQLite database.
This commit is contained in:
Dax Raad
2026-01-27 12:36:05 -05:00
parent 5e1639de2b
commit a48a5a3462
26 changed files with 1499 additions and 1407 deletions
+15 -15
View File
@@ -1,8 +1,7 @@
import { sqliteTable, text, integer, index } from "drizzle-orm/sqlite-core"
import { sqliteTable, text, integer, index, primaryKey } from "drizzle-orm/sqlite-core"
import { ProjectTable } from "../project/project.sql"
import type { MessageV2 } from "./message-v2"
import type { Snapshot } from "@/snapshot"
import type { Todo } from "./todo"
import type { PermissionNext } from "@/permission/next"
export const SessionTable = sqliteTable(
@@ -61,19 +60,20 @@ export const PartTable = sqliteTable(
(table) => [index("part_message_idx").on(table.message_id), index("part_session_idx").on(table.session_id)],
)
export const SessionDiffTable = sqliteTable("session_diff", {
session_id: text()
.primaryKey()
.references(() => SessionTable.id, { onDelete: "cascade" }),
data: text({ mode: "json" }).notNull().$type<Snapshot.FileDiff[]>(),
})
export const TodoTable = sqliteTable("todo", {
session_id: text()
.primaryKey()
.references(() => SessionTable.id, { onDelete: "cascade" }),
data: text({ mode: "json" }).notNull().$type<Todo.Info[]>(),
})
export const TodoTable = sqliteTable(
"todo",
{
session_id: text()
.notNull()
.references(() => SessionTable.id, { onDelete: "cascade" }),
id: text().notNull(),
content: text().notNull(),
status: text().notNull(),
priority: text().notNull(),
position: integer().notNull(),
},
(table) => [primaryKey({ columns: [table.session_id, table.id] }), index("todo_session_idx").on(table.session_id)],
)
export const PermissionTable = sqliteTable("permission", {
project_id: text()