98 lines
2.7 KiB
TypeScript
98 lines
2.7 KiB
TypeScript
import Database from 'better-sqlite3';
|
|
import { drizzle } from 'drizzle-orm/better-sqlite3';
|
|
import { app } from 'electron';
|
|
import path from 'node:path';
|
|
import * as schema from './schema';
|
|
|
|
// SQL to create all tables if they don't exist (non-destructive push strategy)
|
|
const MIGRATION_SQL = `
|
|
CREATE TABLE IF NOT EXISTS clients (
|
|
id TEXT PRIMARY KEY,
|
|
parent_id TEXT,
|
|
name TEXT NOT NULL,
|
|
industry TEXT,
|
|
created_at INTEGER NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS projects (
|
|
id TEXT PRIMARY KEY,
|
|
client_id TEXT,
|
|
name TEXT NOT NULL,
|
|
status TEXT NOT NULL DEFAULT 'active',
|
|
ai_summary TEXT,
|
|
created_at INTEGER NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS tasks (
|
|
id TEXT PRIMARY KEY,
|
|
project_id TEXT,
|
|
title TEXT NOT NULL,
|
|
description TEXT,
|
|
status TEXT NOT NULL DEFAULT 'todo',
|
|
priority TEXT NOT NULL DEFAULT 'medium',
|
|
assignee TEXT,
|
|
due_date INTEGER,
|
|
is_ai_suggested INTEGER NOT NULL DEFAULT 0,
|
|
is_approved INTEGER NOT NULL DEFAULT 1,
|
|
created_at INTEGER NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS checkpoints (
|
|
id TEXT PRIMARY KEY,
|
|
project_id TEXT NOT NULL,
|
|
title TEXT NOT NULL,
|
|
date INTEGER NOT NULL,
|
|
is_ai_suggested INTEGER NOT NULL DEFAULT 0,
|
|
is_approved INTEGER NOT NULL DEFAULT 0,
|
|
created_at INTEGER NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS notes (
|
|
id TEXT PRIMARY KEY,
|
|
project_id TEXT,
|
|
title TEXT NOT NULL,
|
|
content TEXT NOT NULL DEFAULT '',
|
|
created_at INTEGER NOT NULL,
|
|
updated_at INTEGER NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS task_comments (
|
|
id TEXT PRIMARY KEY,
|
|
task_id TEXT NOT NULL,
|
|
author TEXT NOT NULL,
|
|
content TEXT NOT NULL,
|
|
created_at INTEGER NOT NULL
|
|
);
|
|
`;
|
|
|
|
type DbInstance = ReturnType<typeof drizzle<typeof schema>>;
|
|
|
|
let dbInstance: DbInstance | null = null;
|
|
|
|
export function initDb(): DbInstance {
|
|
const userDataPath = app.getPath('userData');
|
|
const dbPath = path.join(userDataPath, 'adiuva.db');
|
|
|
|
const sqlite = new Database(dbPath);
|
|
|
|
// Enable WAL mode for better concurrent read performance
|
|
sqlite.pragma('journal_mode = WAL');
|
|
|
|
// Run non-destructive migrations on every start
|
|
sqlite.exec(MIGRATION_SQL);
|
|
|
|
// Additive column migrations (SQLite has no ADD COLUMN IF NOT EXISTS)
|
|
try { sqlite.exec('ALTER TABLE tasks ADD COLUMN is_ai_suggested INTEGER NOT NULL DEFAULT 0'); } catch { /* already exists */ }
|
|
try { sqlite.exec('ALTER TABLE tasks ADD COLUMN is_approved INTEGER NOT NULL DEFAULT 1'); } catch { /* already exists */ }
|
|
|
|
dbInstance = drizzle(sqlite, { schema });
|
|
return dbInstance;
|
|
}
|
|
|
|
export function getDb(): DbInstance {
|
|
if (!dbInstance) {
|
|
throw new Error('Database not initialized. Call initDb() first.');
|
|
}
|
|
return dbInstance;
|
|
}
|