/* eslint-disable */ /** * Migration: add an index on `order_items.item_status`. * * Why this exists * ─────────────── * The /orders page's tab badges ("New (12)", "Processing (4)") and * its server-side tab filter both run queries of the form * `item_status = "pending" || item_status = "approval_needed" || ...` * on the `order_items` collection. With ~18k items and no index on * `item_status`, every load is a full table scan — the single biggest * cost on the orders page after the deep expand on the orders * collection itself. * * Adding the index makes these queries O(log n) B-tree lookups. The * page-load budget drops from seconds to sub-second on the cold path * (realtime refetches benefit even more because the tab-counts cache * is bypassed for them). * * Schema * ────── * order_items.item_status select (existing field, no schema change) * * The index is non-unique (the same status appears on many rows). * * Idempotent — safe to re-run. The migration checks for the index * before adding it; subsequent runs print "already present, skipping." * * Run with: * npx tsx scripts/migrations/2026-08-04-add-order-items-item-status-index.ts */ import PocketBase from "pocketbase"; import { readFileSync } from "node:fs"; import { resolve } from "node:path"; function loadEnvFile(name: string) { try { const raw = readFileSync(resolve(process.cwd(), name), "utf8"); for (const line of raw.split("\n")) { const trimmed = line.trim(); if (!trimmed || trimmed.startsWith("#")) continue; const m = trimmed.match(/^([A-Z0-9_]+)\s*=\s*(.+)$/i); if (m && !process.env[m[1]]) { process.env[m[1]] = m[2].replace(/^["']|["']$/g, "").trim(); } } } catch { // missing file — fine } } loadEnvFile(".env"); loadEnvFile(".env.local"); async function main() { const url = process.env.NEXT_PUBLIC_POCKETBASE_URL; const email = process.env.PB_ADMIN_EMAIL; const password = process.env.PB_ADMIN_PASSWORD; if (!url || !email || !password) { throw new Error( "Missing NEXT_PUBLIC_POCKETBASE_URL / PB_ADMIN_EMAIL / PB_ADMIN_PASSWORD in env", ); } const pb = new PocketBase(url); await pb.admins.authWithPassword(email, password); const collection = await pb.collections.getOne("order_items"); const INDEX_NAME = "idx_oi_item_status"; const INDEX_SQL = `CREATE INDEX \`${INDEX_NAME}\` ON \`order_items\` (\`item_status\`)`; const existing = (collection.indexes || []) as string[]; if (existing.includes(INDEX_SQL)) { console.log("order_items.item_status index already present, skipping."); return; } await pb.collections.update(collection.id, { indexes: [...existing, INDEX_SQL], }); console.log("Added order_items.item_status index (idx_oi_item_status)."); console.log("Run /orders in the browser — the initial load should be visibly faster."); } main().catch((err) => { console.error(err); process.exit(1); });