Hello from MCP server

List Files | Just Commands | Repo | Logs

← back |
// composables/useSQLite.ts
import { defineCustomElements as jeepSqlite } from "jeep-sqlite/loader";
import {
  CapacitorSQLite,
  SQLiteConnection,
  SQLiteDBConnection,
} from "@capacitor-community/sqlite";
import { Capacitor } from "@capacitor/core";

import { clearAllIndexedDB } from "./deleteDb";
import { runMigrations } from "./migrations";

declare global {
  interface Window {
    trash: () => void;
    showSchema: () => void;
    secretmode: () => void;
  }
}

window.trash = function () {
  clearAllIndexedDB();
  window.localStorage.clear();
};

window.showSchema = async function () {
  try {
    const sql = await getSQLite();
    const result = await sql.dbConn.query(
      "SELECT name, sql FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name"
    );

    if (result.values && result.values.length > 0) {
      console.log('=== Database Schema ===\n');
      for (const table of result.values) {
        console.log(`--- ${table.name} ---`);
        console.log(table.sql);
        console.log('');
      }
    } else {
      console.log('No tables found');
    }
  } catch (e) {
    console.error('Failed to get schema:', e);
  }
};

window.secretmode = async function () {
  // Dynamically import the session store to avoid circular dependencies
  const { useSessionStore } = await import('@/stores/session');
  const sessionStore = useSessionStore();
  sessionStore.secretMode = true;
  await sessionStore.save();
  console.log('🔓 Secret mode enabled');
};

const DELETE_OLD_DATA = false;
const dbName = "pricebookPlatform";
const dbFileName = "pricebookPlatformSQLite.db";
let isInitialized = false;
let isConnectionReady = false;
let connectionPromise: Promise<any> | null = null;
const sqlConn = new SQLiteConnection(CapacitorSQLite);
let dbConn: SQLiteDBConnection;

// Reset the connection state so next getSQLite() call recreates the database
export const resetSQLiteConnection = async () => {
  console.log('[SQLite] Resetting connection...');

  // Close existing connection if open
  if (dbConn) {
    try {
      await dbConn.close();
    } catch (e) {
      console.log('[SQLite] Connection already closed');
    }
  }

  // Delete the database
  try {
    const isConn = (await sqlConn.isConnection(dbName, false)).result;
    if (isConn) {
      await sqlConn.closeConnection(dbName, false);
    }
    await CapacitorSQLite.deleteDatabase({ database: dbName });
    console.log('[SQLite] Database deleted');
  } catch (e) {
    console.log('[SQLite] Database delete failed (may not exist):', e);
  }

  // Clear web IndexedDB if on web platform
  if (Capacitor.getPlatform() === "web") {
    await clearAllIndexedDB();
    console.log('[SQLite] IndexedDB cleared');
  }

  // Reset singleton state
  isConnectionReady = false;
  connectionPromise = null;

  console.log('[SQLite] Connection reset complete');
};

export const getSQLite = async () => {
  const saveDb = async () => {
    const platform = Capacitor.getPlatform();

    if (platform === "web") {
      try {
        await sqlConn.saveToStore(dbName);
        // console.log("[SQLite] Database saved to IndexedDB");
      } catch (error) {
        console.error("[SQLite] Failed to save to store:", error);
      }
    } else {
      // No-op for native platforms
    }
  };

  const initializeSQLite = async () => {
    if (isInitialized) return sqlConn;
    if (Capacitor.getPlatform() === "web") {
      // Register custom element
      if (!customElements.get("jeep-sqlite")) {
        jeepSqlite(window);
        await customElements.whenDefined("jeep-sqlite");
      }

      // Ensure element is in DOM
      if (!document.querySelector("jeep-sqlite")) {
        const jeepSqliteEl = document.createElement("jeep-sqlite");
        document.body.appendChild(jeepSqliteEl);

        // Wait for element to be ready
        await new Promise((resolve) => setTimeout(resolve, 200));
      }

      // Initialize web store
      try {
        await sqlConn.initWebStore();
      } catch (error) {
        console.error("Failed to initialize web store:", error);
        throw error;
      }
    }

    isInitialized = true;

    if (DELETE_OLD_DATA) {
      clearAllIndexedDB();
    }

    return sqlConn;
  };

  const getConnection = async () => {
    let connection: SQLiteConnection | null = null;

    try {
      connection = await initializeSQLite();
      const retCC = (await connection.checkConnectionsConsistency()).result;
      let isConn = (await connection.isConnection(dbName, false)).result;

      if (retCC && isConn) {
        dbConn = await connection.retrieveConnection(dbName, false);
      } else {
        dbConn = await connection.createConnection(
          dbName,
          false,
          "no-encryption",
          1,
          false,
        );
      }

      await dbConn.open();
      // console.log("Migrations...");
      await runMigrations(dbConn);
      await saveDb();
      return dbConn;
    } catch (error) {
      console.error("SQLite initialization failed:", error);

      // Cleanup on error
      if (dbConn) {
        try {
          await dbConn.close();
        } catch (closeError) {
          console.error("Error closing database:", closeError);
        }
      }

      throw error;
    }
  };

  // Use singleton pattern to avoid running migrations multiple times
  if (isConnectionReady) {
    return {
      sqlConn,
      dbConn,
      dbName,
      saveDb,
    };
  }

  // If already initializing, wait for that to complete
  if (connectionPromise) {
    await connectionPromise;
    return {
      sqlConn,
      dbConn,
      dbName,
      saveDb,
    };
  }

  // Start initialization
  connectionPromise = getConnection();
  await connectionPromise;
  isConnectionReady = true;
  connectionPromise = null;

  return {
    sqlConn,
    dbConn,
    dbName,
    saveDb,
  };
};