|
|
@@ -1,6 +1,6 @@
|
|
|
import { describe, test, expect, beforeEach, afterEach } from "bun:test"
|
|
|
import { Database } from "bun:sqlite"
|
|
|
-import { drizzle } from "drizzle-orm/bun-sqlite"
|
|
|
+import { drizzle, SQLiteBunDatabase } from "drizzle-orm/bun-sqlite"
|
|
|
import { migrate } from "drizzle-orm/bun-sqlite/migrator"
|
|
|
import path from "path"
|
|
|
import fs from "fs/promises"
|
|
|
@@ -89,18 +89,21 @@ function createTestDb() {
|
|
|
name: entry.name,
|
|
|
}))
|
|
|
.sort((a, b) => a.timestamp - b.timestamp)
|
|
|
- migrate(drizzle({ client: sqlite }), migrations)
|
|
|
|
|
|
- return sqlite
|
|
|
+ const db = drizzle({ client: sqlite })
|
|
|
+ migrate(db, migrations)
|
|
|
+
|
|
|
+ return [sqlite, db] as const
|
|
|
}
|
|
|
|
|
|
describe("JSON to SQLite migration", () => {
|
|
|
let storageDir: string
|
|
|
let sqlite: Database
|
|
|
+ let db: SQLiteBunDatabase
|
|
|
|
|
|
beforeEach(async () => {
|
|
|
storageDir = await setupStorageDir()
|
|
|
- sqlite = createTestDb()
|
|
|
+ ;[sqlite, db] = createTestDb()
|
|
|
})
|
|
|
|
|
|
afterEach(async () => {
|
|
|
@@ -118,11 +121,10 @@ describe("JSON to SQLite migration", () => {
|
|
|
sandboxes: ["/test/sandbox"],
|
|
|
})
|
|
|
|
|
|
- const stats = await JsonMigration.run(sqlite)
|
|
|
+ const stats = await JsonMigration.run(db)
|
|
|
|
|
|
expect(stats?.projects).toBe(1)
|
|
|
|
|
|
- const db = drizzle({ client: sqlite })
|
|
|
const projects = db.select().from(ProjectTable).all()
|
|
|
expect(projects.length).toBe(1)
|
|
|
expect(projects[0].id).toBe(ProjectID.make("proj_test123abc"))
|
|
|
@@ -143,11 +145,10 @@ describe("JSON to SQLite migration", () => {
|
|
|
}),
|
|
|
)
|
|
|
|
|
|
- const stats = await JsonMigration.run(sqlite)
|
|
|
+ const stats = await JsonMigration.run(db)
|
|
|
|
|
|
expect(stats?.projects).toBe(1)
|
|
|
|
|
|
- const db = drizzle({ client: sqlite })
|
|
|
const projects = db.select().from(ProjectTable).all()
|
|
|
expect(projects.length).toBe(1)
|
|
|
expect(projects[0].id).toBe(ProjectID.make("proj_filename")) // Uses filename, not JSON id
|
|
|
@@ -164,11 +165,10 @@ describe("JSON to SQLite migration", () => {
|
|
|
commands: { start: "npm run dev" },
|
|
|
})
|
|
|
|
|
|
- const stats = await JsonMigration.run(sqlite)
|
|
|
+ const stats = await JsonMigration.run(db)
|
|
|
|
|
|
expect(stats?.projects).toBe(1)
|
|
|
|
|
|
- const db = drizzle({ client: sqlite })
|
|
|
const projects = db.select().from(ProjectTable).all()
|
|
|
expect(projects.length).toBe(1)
|
|
|
expect(projects[0].id).toBe(ProjectID.make("proj_with_commands"))
|
|
|
@@ -185,11 +185,10 @@ describe("JSON to SQLite migration", () => {
|
|
|
sandboxes: [],
|
|
|
})
|
|
|
|
|
|
- const stats = await JsonMigration.run(sqlite)
|
|
|
+ const stats = await JsonMigration.run(db)
|
|
|
|
|
|
expect(stats?.projects).toBe(1)
|
|
|
|
|
|
- const db = drizzle({ client: sqlite })
|
|
|
const projects = db.select().from(ProjectTable).all()
|
|
|
expect(projects.length).toBe(1)
|
|
|
expect(projects[0].id).toBe(ProjectID.make("proj_no_commands"))
|
|
|
@@ -216,9 +215,8 @@ describe("JSON to SQLite migration", () => {
|
|
|
share: { url: "https://example.com/share" },
|
|
|
})
|
|
|
|
|
|
- await JsonMigration.run(sqlite)
|
|
|
+ await JsonMigration.run(db)
|
|
|
|
|
|
- const db = drizzle({ client: sqlite })
|
|
|
const sessions = db.select().from(SessionTable).all()
|
|
|
expect(sessions.length).toBe(1)
|
|
|
expect(sessions[0].id).toBe(SessionID.make("ses_test456def"))
|
|
|
@@ -247,12 +245,11 @@ describe("JSON to SQLite migration", () => {
|
|
|
JSON.stringify({ ...fixtures.part }),
|
|
|
)
|
|
|
|
|
|
- const stats = await JsonMigration.run(sqlite)
|
|
|
+ const stats = await JsonMigration.run(db)
|
|
|
|
|
|
expect(stats?.messages).toBe(1)
|
|
|
expect(stats?.parts).toBe(1)
|
|
|
|
|
|
- const db = drizzle({ client: sqlite })
|
|
|
const messages = db.select().from(MessageTable).all()
|
|
|
expect(messages.length).toBe(1)
|
|
|
expect(messages[0].id).toBe(MessageID.make("msg_test789ghi"))
|
|
|
@@ -287,12 +284,11 @@ describe("JSON to SQLite migration", () => {
|
|
|
}),
|
|
|
)
|
|
|
|
|
|
- const stats = await JsonMigration.run(sqlite)
|
|
|
+ const stats = await JsonMigration.run(db)
|
|
|
|
|
|
expect(stats?.messages).toBe(1)
|
|
|
expect(stats?.parts).toBe(1)
|
|
|
|
|
|
- const db = drizzle({ client: sqlite })
|
|
|
const messages = db.select().from(MessageTable).all()
|
|
|
expect(messages.length).toBe(1)
|
|
|
expect(messages[0].id).toBe(MessageID.make("msg_test789ghi"))
|
|
|
@@ -329,11 +325,10 @@ describe("JSON to SQLite migration", () => {
|
|
|
}),
|
|
|
)
|
|
|
|
|
|
- const stats = await JsonMigration.run(sqlite)
|
|
|
+ const stats = await JsonMigration.run(db)
|
|
|
|
|
|
expect(stats?.messages).toBe(1)
|
|
|
|
|
|
- const db = drizzle({ client: sqlite })
|
|
|
const messages = db.select().from(MessageTable).all()
|
|
|
expect(messages.length).toBe(1)
|
|
|
expect(messages[0].id).toBe(MessageID.make("msg_from_filename")) // Uses filename, not JSON id
|
|
|
@@ -367,11 +362,10 @@ describe("JSON to SQLite migration", () => {
|
|
|
}),
|
|
|
)
|
|
|
|
|
|
- const stats = await JsonMigration.run(sqlite)
|
|
|
+ const stats = await JsonMigration.run(db)
|
|
|
|
|
|
expect(stats?.parts).toBe(1)
|
|
|
|
|
|
- const db = drizzle({ client: sqlite })
|
|
|
const parts = db.select().from(PartTable).all()
|
|
|
expect(parts.length).toBe(1)
|
|
|
expect(parts[0].id).toBe(PartID.make("prt_from_filename")) // Uses filename, not JSON id
|
|
|
@@ -392,7 +386,7 @@ describe("JSON to SQLite migration", () => {
|
|
|
}),
|
|
|
)
|
|
|
|
|
|
- const stats = await JsonMigration.run(sqlite)
|
|
|
+ const stats = await JsonMigration.run(db)
|
|
|
|
|
|
expect(stats?.sessions).toBe(0)
|
|
|
})
|
|
|
@@ -420,11 +414,10 @@ describe("JSON to SQLite migration", () => {
|
|
|
time: { created: 1700000000000, updated: 1700000001000 },
|
|
|
})
|
|
|
|
|
|
- const stats = await JsonMigration.run(sqlite)
|
|
|
+ const stats = await JsonMigration.run(db)
|
|
|
|
|
|
expect(stats?.sessions).toBe(1)
|
|
|
|
|
|
- const db = drizzle({ client: sqlite })
|
|
|
const sessions = db.select().from(SessionTable).all()
|
|
|
expect(sessions.length).toBe(1)
|
|
|
expect(sessions[0].id).toBe(SessionID.make("ses_migrated"))
|
|
|
@@ -452,11 +445,10 @@ describe("JSON to SQLite migration", () => {
|
|
|
}),
|
|
|
)
|
|
|
|
|
|
- const stats = await JsonMigration.run(sqlite)
|
|
|
+ const stats = await JsonMigration.run(db)
|
|
|
|
|
|
expect(stats?.sessions).toBe(1)
|
|
|
|
|
|
- const db = drizzle({ client: sqlite })
|
|
|
const sessions = db.select().from(SessionTable).all()
|
|
|
expect(sessions.length).toBe(1)
|
|
|
expect(sessions[0].id).toBe(SessionID.make("ses_from_filename")) // Uses filename, not JSON id
|
|
|
@@ -471,10 +463,9 @@ describe("JSON to SQLite migration", () => {
|
|
|
sandboxes: [],
|
|
|
})
|
|
|
|
|
|
- await JsonMigration.run(sqlite)
|
|
|
- await JsonMigration.run(sqlite)
|
|
|
+ await JsonMigration.run(db)
|
|
|
+ await JsonMigration.run(db)
|
|
|
|
|
|
- const db = drizzle({ client: sqlite })
|
|
|
const projects = db.select().from(ProjectTable).all()
|
|
|
expect(projects.length).toBe(1) // Still only 1 due to onConflictDoNothing
|
|
|
})
|
|
|
@@ -507,11 +498,10 @@ describe("JSON to SQLite migration", () => {
|
|
|
]),
|
|
|
)
|
|
|
|
|
|
- const stats = await JsonMigration.run(sqlite)
|
|
|
+ const stats = await JsonMigration.run(db)
|
|
|
|
|
|
expect(stats?.todos).toBe(2)
|
|
|
|
|
|
- const db = drizzle({ client: sqlite })
|
|
|
const todos = db.select().from(TodoTable).orderBy(TodoTable.position).all()
|
|
|
expect(todos.length).toBe(2)
|
|
|
expect(todos[0].content).toBe("First todo")
|
|
|
@@ -540,9 +530,8 @@ describe("JSON to SQLite migration", () => {
|
|
|
]),
|
|
|
)
|
|
|
|
|
|
- await JsonMigration.run(sqlite)
|
|
|
+ await JsonMigration.run(db)
|
|
|
|
|
|
- const db = drizzle({ client: sqlite })
|
|
|
const todos = db.select().from(TodoTable).orderBy(TodoTable.position).all()
|
|
|
|
|
|
expect(todos.length).toBe(3)
|
|
|
@@ -570,11 +559,10 @@ describe("JSON to SQLite migration", () => {
|
|
|
]
|
|
|
await Bun.write(path.join(storageDir, "permission", "proj_test123abc.json"), JSON.stringify(permissionData))
|
|
|
|
|
|
- const stats = await JsonMigration.run(sqlite)
|
|
|
+ const stats = await JsonMigration.run(db)
|
|
|
|
|
|
expect(stats?.permissions).toBe(1)
|
|
|
|
|
|
- const db = drizzle({ client: sqlite })
|
|
|
const permissions = db.select().from(PermissionTable).all()
|
|
|
expect(permissions.length).toBe(1)
|
|
|
expect(permissions[0].project_id).toBe("proj_test123abc")
|
|
|
@@ -600,11 +588,10 @@ describe("JSON to SQLite migration", () => {
|
|
|
}),
|
|
|
)
|
|
|
|
|
|
- const stats = await JsonMigration.run(sqlite)
|
|
|
+ const stats = await JsonMigration.run(db)
|
|
|
|
|
|
expect(stats?.shares).toBe(1)
|
|
|
|
|
|
- const db = drizzle({ client: sqlite })
|
|
|
const shares = db.select().from(SessionShareTable).all()
|
|
|
expect(shares.length).toBe(1)
|
|
|
expect(shares[0].session_id).toBe("ses_test456def")
|
|
|
@@ -616,7 +603,7 @@ describe("JSON to SQLite migration", () => {
|
|
|
test("returns empty stats when storage directory does not exist", async () => {
|
|
|
await fs.rm(storageDir, { recursive: true, force: true })
|
|
|
|
|
|
- const stats = await JsonMigration.run(sqlite)
|
|
|
+ const stats = await JsonMigration.run(db)
|
|
|
|
|
|
expect(stats.projects).toBe(0)
|
|
|
expect(stats.sessions).toBe(0)
|
|
|
@@ -637,12 +624,11 @@ describe("JSON to SQLite migration", () => {
|
|
|
})
|
|
|
await Bun.write(path.join(storageDir, "project", "broken.json"), "{ invalid json")
|
|
|
|
|
|
- const stats = await JsonMigration.run(sqlite)
|
|
|
+ const stats = await JsonMigration.run(db)
|
|
|
|
|
|
expect(stats.projects).toBe(1)
|
|
|
expect(stats.errors.some((x) => x.includes("failed to read") && x.includes("broken.json"))).toBe(true)
|
|
|
|
|
|
- const db = drizzle({ client: sqlite })
|
|
|
const projects = db.select().from(ProjectTable).all()
|
|
|
expect(projects.length).toBe(1)
|
|
|
expect(projects[0].id).toBe(ProjectID.make("proj_test123abc"))
|
|
|
@@ -666,10 +652,9 @@ describe("JSON to SQLite migration", () => {
|
|
|
]),
|
|
|
)
|
|
|
|
|
|
- const stats = await JsonMigration.run(sqlite)
|
|
|
+ const stats = await JsonMigration.run(db)
|
|
|
expect(stats.todos).toBe(2)
|
|
|
|
|
|
- const db = drizzle({ client: sqlite })
|
|
|
const todos = db.select().from(TodoTable).orderBy(TodoTable.position).all()
|
|
|
expect(todos.length).toBe(2)
|
|
|
expect(todos[0].content).toBe("keep-0")
|
|
|
@@ -714,13 +699,12 @@ describe("JSON to SQLite migration", () => {
|
|
|
JSON.stringify({ id: "share_missing", secret: "secret", url: "https://missing.example.com" }),
|
|
|
)
|
|
|
|
|
|
- const stats = await JsonMigration.run(sqlite)
|
|
|
+ const stats = await JsonMigration.run(db)
|
|
|
|
|
|
expect(stats.todos).toBe(1)
|
|
|
expect(stats.permissions).toBe(1)
|
|
|
expect(stats.shares).toBe(1)
|
|
|
|
|
|
- const db = drizzle({ client: sqlite })
|
|
|
expect(db.select().from(TodoTable).all().length).toBe(1)
|
|
|
expect(db.select().from(PermissionTable).all().length).toBe(1)
|
|
|
expect(db.select().from(SessionShareTable).all().length).toBe(1)
|
|
|
@@ -823,7 +807,7 @@ describe("JSON to SQLite migration", () => {
|
|
|
)
|
|
|
await Bun.write(path.join(storageDir, "session_share", "ses_broken.json"), "{ nope")
|
|
|
|
|
|
- const stats = await JsonMigration.run(sqlite)
|
|
|
+ const stats = await JsonMigration.run(db)
|
|
|
|
|
|
// Projects: proj_test123abc (valid), proj_missing_id (now derives id from filename)
|
|
|
// Sessions: ses_test456def (valid), ses_missing_project (now uses dir path),
|
|
|
@@ -837,7 +821,6 @@ describe("JSON to SQLite migration", () => {
|
|
|
expect(stats.shares).toBe(1)
|
|
|
expect(stats.errors.length).toBeGreaterThanOrEqual(6)
|
|
|
|
|
|
- const db = drizzle({ client: sqlite })
|
|
|
expect(db.select().from(ProjectTable).all().length).toBe(2)
|
|
|
expect(db.select().from(SessionTable).all().length).toBe(3)
|
|
|
expect(db.select().from(MessageTable).all().length).toBe(1)
|