repo_description: Local, open-source AI app builder for power users ✨ v0 / Lovable / Replit / Bolt alternative 🌟 Star if you like it!
repo_topics: ai-app-builder anthropic artificial-intelligence bolt deepseek gemini generative-ai github llm llms lovable nextjs ollama openai qwen react typescript v0 vercel
code: // db.ts
  import {
    type BetterSQLite3Database,
    drizzle,
  } from "drizzle-orm/better-sqlite3";
  import Database from "better-sqlite3";
  import * as schema from "./schema";
  import { migrate } from "drizzle-orm/better-sqlite3/migrator";
  import path from "node:path";
  import fs from "node:fs";
  import { getUserDataPath } from "../paths/paths";
  import log from "electron-log";
  
  const logger = log.scope("db");
  
  // Database connection factory
  let _db: ReturnType<typeof drizzle> | null = null;
  
  /**
   * Get the database path based on the current environment
   */
  export function getDatabasePath(): string {
    return path.join(getUserDataPath(), "sqlite.db");
  }
  
  /**
   * Initialize the database connection
   */
  export function initializeDatabase(): BetterSQLite3Database<typeof schema> & {
    $client: Database.Database;
  } {
    if (_db) return _db as any;
  
    const dbPath = getDatabasePath();
    logger.log("Initializing database at:", dbPath);
  
    // Check if the database file exists and remove it if it has issues
    try {
      if (fs.existsSync(dbPath)) {
        const stats = fs.statSync(dbPath);
        if (stats.size < 100) {
          logger.log("Database file exists but may be corrupted. Removing it...");
          fs.unlinkSync(dbPath);
        }
      }
    } catch (error) {
      logger.error("Error checking database file:", error);
    }
  
    fs.mkdirSync(getUserDataPath(), { recursive: true });
  
    const sqlite = new Database(dbPath, { timeout: 10000 });
    sqlite.pragma("foreign_keys = ON");
  
    try {
      sqlite.pragma("journal_mode = WAL");
    } catch (error) {
      logger.warn(
        "Could not enable WAL mode, falling back to default journal mode:",
        error,
      );
    }
  
    _db = drizzle(sqlite, { schema });
  
    try {
      const migrationsFolder = path.join(__dirname, "..", "..", "drizzle");
      if (!fs.existsSync(migrationsFolder)) {
        logger.error("Migrations folder not found:", migrationsFolder);
      } else {
        logger.log("Running migrations from:", migrationsFolder);
        migrate(_db, { migrationsFolder });
      }
    } catch (error) {
      logger.error("Migration error:", error);
    }
  
    return _db as any;
  }
  
  /**
   * Get the database instance (throws if not initialized)
   */
  export function getDb(): BetterSQLite3Database<typeof schema> & {
    $client: Database.Database;
  } {
    if (!_db) {
      throw new Error(
        "Database not initialized. Call initializeDatabase() first.",
      );
    }
    return _db as any;
  }
  
  export const db = new Proxy({} as any, {
    get(target, prop) {
      const database = getDb();
      return database[prop as keyof typeof database];
    },
  }) as BetterSQLite3Database<typeof schema> & {
    $client: Database.Database;
  };
  