79 lines
2.4 KiB
JavaScript
79 lines
2.4 KiB
JavaScript
/**
|
|
* Builds the composite index SiteEvent_sessionId_timestamp_idx on the
|
|
* SiteEvent table using CREATE INDEX CONCURRENTLY.
|
|
*
|
|
* Must connect via the non-pooler (direct) Neon URL because:
|
|
* - CREATE INDEX CONCURRENTLY cannot run inside a transaction
|
|
* - The pooler enforces statement_timeout that overrides SET
|
|
*
|
|
* Usage:
|
|
* DIRECT_URL="postgres://..." node scripts/build-sessionid-index.mjs
|
|
*
|
|
* Never hardcode credentials here. Supply DIRECT_URL from the shell only.
|
|
*/
|
|
|
|
import pkg from "pg";
|
|
const { Client } = pkg;
|
|
|
|
const INDEX_NAME = "SiteEvent_sessionId_timestamp_idx";
|
|
|
|
const directUrl = process.env.DIRECT_URL;
|
|
if (!directUrl) {
|
|
console.error("[build-index] DIRECT_URL is not set. Aborting.");
|
|
process.exit(1);
|
|
}
|
|
|
|
const client = new Client({ connectionString: directUrl });
|
|
|
|
async function run() {
|
|
console.log("[build-index] Connecting via DIRECT_URL...");
|
|
await client.connect();
|
|
console.log("[build-index] Connected.");
|
|
|
|
console.log("[build-index] SET statement_timeout = 0");
|
|
await client.query("SET statement_timeout = 0;");
|
|
|
|
console.log("[build-index] SET lock_timeout = 0");
|
|
await client.query("SET lock_timeout = 0;");
|
|
|
|
console.log(`[build-index] DROP INDEX IF EXISTS "${INDEX_NAME}"`);
|
|
await client.query(`DROP INDEX IF EXISTS "${INDEX_NAME}";`);
|
|
console.log("[build-index] Drop complete (or index did not exist).");
|
|
|
|
console.log(`[build-index] CREATE INDEX CONCURRENTLY "${INDEX_NAME}" -- this may take several minutes on large tables`);
|
|
await client.query(
|
|
`CREATE INDEX CONCURRENTLY "${INDEX_NAME}" ON "public"."SiteEvent" ("sessionId", "timestamp");`,
|
|
);
|
|
console.log("[build-index] Index build complete.");
|
|
|
|
const res = await client.query(
|
|
`SELECT indisvalid
|
|
FROM pg_index
|
|
JOIN pg_class ON pg_class.oid = pg_index.indexrelid
|
|
WHERE pg_class.relname = $1;`,
|
|
[INDEX_NAME],
|
|
);
|
|
|
|
if (res.rows.length === 0) {
|
|
console.error("[build-index] Index not found after creation -- something went wrong.");
|
|
process.exit(1);
|
|
}
|
|
|
|
const { indisvalid } = res.rows[0];
|
|
if (indisvalid) {
|
|
console.log("[build-index] indisvalid = true -- index is VALID and ready.");
|
|
} else {
|
|
console.error("[build-index] indisvalid = false -- index is INVALID. Manual cleanup required.");
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
run()
|
|
.catch((err) => {
|
|
console.error("[build-index] Fatal error:", err.message);
|
|
process.exit(1);
|
|
})
|
|
.finally(() => {
|
|
client.end().catch(() => {});
|
|
});
|