From ccbc79c518932262e8d41c1f92259859862de43a Mon Sep 17 00:00:00 2001 From: Tsiry Sandratraina Date: Sun, 11 Jan 2026 13:12:37 +0300 Subject: [PATCH] Initialize and migrate database on CLI startup Add initializeDatabase() to run Drizzle migrations at startup. Use better-sqlite3 Database and run migrate() against detected migrations folder (prod ./drizzle or dev ../../drizzle). Update drizzle.config to output to ./drizzle and make build copy it into dist. Add db:generate, db:migrate and db:studio npm scripts. --- apps/cli/drizzle.config.ts | 1 + apps/cli/package.json | 5 +++- apps/cli/src/drizzle.ts | 47 ++++++++++++++++++++++++++++++++++++-- apps/cli/src/index.ts | 3 +++ 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/apps/cli/drizzle.config.ts b/apps/cli/drizzle.config.ts index f476ba09..cb314ca7 100644 --- a/apps/cli/drizzle.config.ts +++ b/apps/cli/drizzle.config.ts @@ -11,6 +11,7 @@ console.log(`Database URL: ${chalk.greenBright(url)}`); export default defineConfig({ dialect: "sqlite", schema: "./src/schema", + out: "./drizzle", dbCredentials: { url, }, diff --git a/apps/cli/package.json b/apps/cli/package.json index 1130d351..bd855227 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -11,7 +11,10 @@ "lexgen": "lex gen-server ./src/lexicon ./lexicons/**/* ./lexicons/*", "test": "echo \"Error: no test specified\" && exit 1", "dev": "tsx ./src/index.ts", - "build": "pkgroll && chmod +x ./dist/index.js" + "build": "pkgroll && chmod +x ./dist/index.js && cp -r drizzle ./dist", + "db:generate": "drizzle-kit generate", + "db:migrate": "drizzle-kit migrate", + "db:studio": "drizzle-kit studio" }, "keywords": [ "audioscrobbler", diff --git a/apps/cli/src/drizzle.ts b/apps/cli/src/drizzle.ts index c6dc17da..a831a1cf 100644 --- a/apps/cli/src/drizzle.ts +++ b/apps/cli/src/drizzle.ts @@ -1,10 +1,53 @@ import { drizzle } from "drizzle-orm/better-sqlite3"; +import { migrate } from "drizzle-orm/better-sqlite3/migrator"; +import Database from "better-sqlite3"; import envpaths from "env-paths"; import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); fs.mkdirSync(envpaths("rocksky", { suffix: "" }).data, { recursive: true }); const url = `${envpaths("rocksky", { suffix: "" }).data}/rocksky.sqlite`; -const db = drizzle(url); +const sqlite = new Database(url); +const db = drizzle(sqlite); + +let initialized = false; + +/** + * Initialize the database and run migrations + * This should be called before any database operations + */ +export async function initializeDatabase() { + if (initialized) { + return; + } + + try { + // In production (built), migrations are in ../drizzle + // In development (src), migrations are in ../../drizzle + let migrationsFolder = path.join(__dirname, "../drizzle"); + + if (!fs.existsSync(migrationsFolder)) { + // Try development path + migrationsFolder = path.join(__dirname, "../../drizzle"); + } + + if (fs.existsSync(migrationsFolder)) { + migrate(db, { migrationsFolder }); + initialized = true; + } else { + // No migrations folder found - this might be the first run + // or migrations haven't been generated yet + initialized = true; + } + } catch (error) { + console.error("Failed to run migrations:", error); + throw error; + } +} -export default { db }; +export default { db, initializeDatabase }; diff --git a/apps/cli/src/index.ts b/apps/cli/src/index.ts index 32cce439..3efea8ae 100644 --- a/apps/cli/src/index.ts +++ b/apps/cli/src/index.ts @@ -16,6 +16,9 @@ import { Command } from "commander"; import { version } from "../package.json" assert { type: "json" }; import { login } from "./cmd/login"; import { sync } from "cmd/sync"; +import { initializeDatabase } from "./drizzle"; + +await initializeDatabase(); const program = new Command(); -- 2.51.2