task-fic-display
This commit is contained in:
97
scripts/db/reset-database.ts
Normal file
97
scripts/db/reset-database.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import postgres from 'postgres';
|
||||
|
||||
function loadEnvFile(filePath: string) {
|
||||
if (!fs.existsSync(filePath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
for (const rawLine of content.split(/\r?\n/)) {
|
||||
const line = rawLine.trim();
|
||||
|
||||
if (!line || line.startsWith('#')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const separatorIndex = line.indexOf('=');
|
||||
if (separatorIndex === -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const key = line.slice(0, separatorIndex).trim();
|
||||
let value = line.slice(separatorIndex + 1).trim();
|
||||
|
||||
if (
|
||||
(value.startsWith('"') && value.endsWith('"')) ||
|
||||
(value.startsWith("'") && value.endsWith("'"))
|
||||
) {
|
||||
value = value.slice(1, -1);
|
||||
}
|
||||
|
||||
if (!(key in process.env)) {
|
||||
process.env[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function loadLocalEnv() {
|
||||
loadEnvFile(path.resolve(process.cwd(), '.env.local'));
|
||||
loadEnvFile(path.resolve(process.cwd(), '.env'));
|
||||
}
|
||||
|
||||
function assertSafeToReset(databaseUrl: string) {
|
||||
if (process.env.ALLOW_DB_RESET !== 'true') {
|
||||
throw new Error('ALLOW_DB_RESET=true is required.');
|
||||
}
|
||||
|
||||
if ((process.env.NODE_ENV ?? '').toLowerCase() === 'production') {
|
||||
throw new Error('Database reset is blocked in NODE_ENV=production.');
|
||||
}
|
||||
|
||||
const parsed = new URL(databaseUrl);
|
||||
const host = parsed.hostname.toLowerCase();
|
||||
const databaseName = parsed.pathname.replace(/^\//, '').toLowerCase();
|
||||
|
||||
const blockedHostFragments = ['prod', 'production', 'rds.amazonaws.com'];
|
||||
const blockedDatabaseFragments = ['prod', 'production'];
|
||||
|
||||
if (blockedHostFragments.some((fragment) => host.includes(fragment))) {
|
||||
throw new Error(`Database reset blocked for host ${host}.`);
|
||||
}
|
||||
|
||||
if (blockedDatabaseFragments.some((fragment) => databaseName.includes(fragment))) {
|
||||
throw new Error(`Database reset blocked for database ${databaseName}.`);
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
loadLocalEnv();
|
||||
|
||||
const databaseUrl = process.env.DATABASE_URL?.trim();
|
||||
if (!databaseUrl) {
|
||||
throw new Error('DATABASE_URL is required.');
|
||||
}
|
||||
|
||||
assertSafeToReset(databaseUrl);
|
||||
|
||||
const parsed = new URL(databaseUrl);
|
||||
console.log(
|
||||
`[db:reset] target=${parsed.hostname}/${parsed.pathname.replace(/^\//, '')}`
|
||||
);
|
||||
|
||||
const sql = postgres(databaseUrl, { prepare: false });
|
||||
|
||||
try {
|
||||
await sql.unsafe('DROP SCHEMA IF EXISTS public CASCADE;');
|
||||
await sql.unsafe('CREATE SCHEMA public;');
|
||||
await sql.unsafe('DROP SCHEMA IF EXISTS drizzle CASCADE;');
|
||||
console.log('[db:reset] Database schemas recreated successfully.');
|
||||
} finally {
|
||||
await sql.end();
|
||||
}
|
||||
}
|
||||
|
||||
void main();
|
||||
Reference in New Issue
Block a user