UNPKG

supastash

Version:

Offline-first sync engine for Supabase in React Native using SQLite

75 lines (74 loc) 2.94 kB
import { getSupastashDb } from "../db/dbInitializer"; import { logError } from "./logs"; import { getAllTables } from "./sync/getAllTables"; /** * Create a single-column index on "id" where it actually helps. * - Skips virtual tables (e.g. FTS), views, system tables. * - Skips when "id" doesn't exist. * - Skips when "id" is already PK (including TEXT PK which has an implicit unique index). * - Skips when there's already an index on "id". */ export async function createIdIndexes() { const db = await getSupastashDb(); const tables = await getAllTables(); if (!tables || !tables.length) return; const q = (s) => `"${s.replace(/"/g, '""')}"`; for (const table of tables) { if (!table) continue; try { // 1) Check sqlite_schema for table kind + DDL const schemaRow = await db.getFirstAsync( `SELECT type, sql FROM sqlite_schema WHERE name = ?1`, [table] ); if (!schemaRow) continue; // not a real table in this db if (schemaRow.type !== "table") continue; // views, triggers, etc. const ddl = schemaRow.sql || ""; // Virtual tables get skipped if (/\bCREATE\s+VIRTUAL\s+TABLE\b/i.test(ddl)) { continue; } // 2) Inspect columns; ensure "id" exists and get PK info const columns = await db.getAllAsync(`PRAGMA table_info(${q(table)})`); if (!columns?.length) continue; const idCol = columns.find((c) => c.name === "id"); if (!idCol) continue; // no "id" column → nothing to do // If "id" is part of the PK, indexing is unnecessary/redundant: // - INTEGER PRIMARY KEY uses rowid (fast already). // - TEXT/other PRIMARY KEYs get an implicit unique index. const pkCols = columns.filter((c) => c.pk > 0); const idIsPk = idCol.pk > 0; if (idIsPk) { // If it's the only PK column or part of composite PK, skip — already indexed enough. continue; } // 3) Check if an index on "id" already exists const indexes = await db.getAllAsync(`PRAGMA index_list(${q(table)})`); let hasIdOnlyIndex = false; if (indexes?.length) { for (const ix of indexes) { // Ignore partial indexes for simplicity const cols = await db.getAllAsync(`PRAGMA index_info(${q(ix.name)})`); if (!cols?.length) continue; if (cols.length === 1 && cols[0].name === "id") { hasIdOnlyIndex = true; break; } } } if (hasIdOnlyIndex) continue; // 4) Create the index safely const idxName = `idx_${table}_id`; try { await db.runAsync( `CREATE INDEX IF NOT EXISTS ${q(idxName)} ON ${q(table)}("id");` ); } catch (e) { await db.runAsync("ROLLBACK"); logError(`[index-skip] ${table}: ${e.message}`); } } catch (err) { logError(`[index-check-failed] ${table}: ${err.message}`); } } }