/* * Voert db/schema.sql en db/seed.sql uit tegen DATABASE_URL. * Maakt de database aan als die nog niet bestaat. * * npm run db:setup # schema + seed * npm run db:setup -- --no-seed * * Twee van de seed-accounts — de bouwer en het account voor de beoordelaar van de app-store — krijgen * hun échte adres en wachtwoord uit de omgeving (SEED_BRAM_* en SEED_REVIEW_*). Staan die er niet, dan * blijven ze wat ze in de seed zijn: @voorbeeld.nl met het gewone seed-wachtwoord. Zo staat er geen * enkel bruikbaar inloggegeven in deze repository, die openbaar is, terwijl een echte installatie toch * met één opdracht klaarstaat voor een review. */ import { readFile, readdir } from "node:fs/promises"; import { fileURLToPath } from "node:url"; import path from "node:path"; import pg from "pg"; const here = path.dirname(fileURLToPath(import.meta.url)); const url = new URL(process.env.DATABASE_URL ?? "postgres://postgres@localhost:5432/liefdesbrieven"); const dbName = url.pathname.slice(1); const withSeed = !process.argv.includes("--no-seed"); /* 1. Database aanmaken indien nodig (via de standaard 'postgres'-database) */ { const admin = new pg.Client({ connectionString: new URL("/postgres", url).toString() }); await admin.connect(); const { rowCount } = await admin.query("select 1 from pg_database where datname = $1", [dbName]); if (rowCount === 0) { await admin.query(`create database "${dbName.replace(/"/g, '""')}"`); console.log(`database ${dbName} aangemaakt`); } await admin.end(); } /* 2. Schema en seed uitvoeren */ { const client = new pg.Client({ connectionString: url.toString() }); await client.connect(); const files = ["schema.sql", ...(withSeed ? ["seed.sql"] : [])]; for (const f of files) { await client.query(await readFile(path.join(here, f), "utf8")); console.log(`${f} uitgevoerd`); } /* * Een bestáánde database verandert via db/migrations/ (npm run db:migrate); dit script is er * alleen nog voor een verse. schema.sql heeft elke migratie al verwerkt, dus een verse opbouw * registreert ze meteen als uitgevoerd — anders zou db:migrate hierna toevoegen wat er al staat. */ let migraties = []; try { migraties = (await readdir(path.join(here, "migrations"))).filter((f) => f.endsWith(".sql")).sort(); } catch (err) { if (err.code !== "ENOENT") throw err; } for (const f of migraties) await client.query("insert into schema_migrations (filename) values ($1)", [f]); if (migraties.length) console.log(`${migraties.length} migratie(s) als uitgevoerd geregistreerd — schema.sql is al de nieuwste stand`); /* * De echte inloggegevens erover, als de omgeving ze aandraagt. Per veld: wie alleen een wachtwoord * zet houdt het adres uit de seed, en andersom. Zwijgt de omgeving, dan gebeurt er niets — dat is * het gewone geval op een ontwikkelmachine. */ if (withSeed) { const { hashPassword } = await import("../server/auth.js"); const echte = [ { naam: "Bram", email: process.env.SEED_BRAM_EMAIL, wachtwoord: process.env.SEED_BRAM_PASSWORD }, { naam: "Nina", email: process.env.SEED_REVIEW_EMAIL, wachtwoord: process.env.SEED_REVIEW_PASSWORD }, ]; for (const p of echte) { if (!p.email && !p.wachtwoord) continue; const waarden = [p.naam]; const zetten = []; if (p.email) { waarden.push(p.email.trim().toLowerCase()); zetten.push(`email = $${waarden.length}`); } if (p.wachtwoord) { waarden.push(await hashPassword(p.wachtwoord)); zetten.push(`password_hash = $${waarden.length}`); } const { rowCount } = await client.query(`update users set ${zetten.join(", ")} where name = $1`, waarden); /* Het wachtwoord zelf komt hier niet in beeld, en het adres alleen als het gezet is. */ console.log(rowCount ? `${p.naam}: eigen inloggegevens gezet (${zetten.length === 2 ? "adres en wachtwoord" : p.email ? "adres" : "wachtwoord"})` : `${p.naam}: niet gevonden in de seed — inloggegevens niet gezet`); } } await client.end(); }