74 lines
2.7 KiB
TypeScript
74 lines
2.7 KiB
TypeScript
import { config as loadDotenv } from "dotenv";
|
||
import { existsSync } from "node:fs";
|
||
import path from "node:path";
|
||
|
||
// Ladda .env från paketet ELLER monorepo-roten (pnpm --filter sätter cwd till paketet).
|
||
for (const candidate of [".env", "../.env", "../../.env"]) {
|
||
const p = path.resolve(process.cwd(), candidate);
|
||
if (existsSync(p)) {
|
||
loadDotenv({ path: p });
|
||
break;
|
||
}
|
||
}
|
||
import { fileURLToPath } from "node:url";
|
||
import { migrate } from "drizzle-orm/node-postgres/migrator";
|
||
import { createDatabase } from "./client.js";
|
||
|
||
/**
|
||
* Kör alla väntande SQL-migrationer från infrastructure/migrations.
|
||
* Används i dev, CI och deploy (spec §63: migration + rollback + kontroll).
|
||
*
|
||
* `--test` eller `MIGRATE_TARGET=test` migrerar TEST_DATABASE_URL.
|
||
* Utan flagga används ENDAST DATABASE_URL – deploy kan aldrig röra testdatabasen.
|
||
*/
|
||
const isTestTarget = process.argv.includes("--test") || process.env.MIGRATE_TARGET === "test";
|
||
const connectionString = isTestTarget ? process.env.TEST_DATABASE_URL : process.env.DATABASE_URL;
|
||
|
||
if (!connectionString) {
|
||
if (isTestTarget) {
|
||
throw new Error("Sätt TEST_DATABASE_URL för test-migrationer.");
|
||
}
|
||
throw new Error("Sätt DATABASE_URL innan migration körs.");
|
||
}
|
||
|
||
const migrationsFolder = path.resolve(
|
||
path.dirname(fileURLToPath(import.meta.url)),
|
||
"../../../infrastructure/migrations",
|
||
);
|
||
|
||
async function main() {
|
||
const { db, pool } = createDatabase(connectionString);
|
||
console.log(`[migrate] Kör migrationer från ${migrationsFolder}`);
|
||
await migrate(db, { migrationsFolder });
|
||
|
||
// i18n M7: accentokänslig + fuzzy sök. Extensions kräver rättigheter –
|
||
// i produktion skapas de av create-database.sql (master); här är de idempotenta
|
||
// och hoppas över med varning om rättighet saknas.
|
||
try {
|
||
await pool.query("CREATE EXTENSION IF NOT EXISTS unaccent");
|
||
await pool.query("CREATE EXTENSION IF NOT EXISTS pg_trgm");
|
||
await pool.query(
|
||
"CREATE INDEX IF NOT EXISTS canonical_ingredients_name_trgm_idx ON canonical_ingredients USING gin (name_sv gin_trgm_ops)",
|
||
);
|
||
await pool.query(
|
||
"CREATE INDEX IF NOT EXISTS ingredient_translations_name_trgm_idx ON ingredient_translations USING gin (name gin_trgm_ops)",
|
||
);
|
||
await pool.query(
|
||
"CREATE INDEX IF NOT EXISTS recipes_title_trgm_idx ON recipes USING gin (title_sv gin_trgm_ops)",
|
||
);
|
||
console.log("[migrate] Sök-extensions + trigramindex på plats (i18n M7).");
|
||
} catch (err) {
|
||
console.warn(
|
||
"[migrate] VARNING: kunde inte skapa sök-extensions/index (kör create-database.sql som master först):",
|
||
(err as Error).message,
|
||
);
|
||
}
|
||
console.log("[migrate] Klart.");
|
||
await pool.end();
|
||
}
|
||
|
||
main().catch((err) => {
|
||
console.error("[migrate] MISSLYCKADES:", err);
|
||
process.exit(1);
|
||
});
|