feat: Enhance database initialization script to create target database if it doesn't exist and improve error handling
This commit is contained in:
@@ -1,29 +1,101 @@
|
|||||||
/**
|
/**
|
||||||
* Database initialization script
|
* Database initialization script
|
||||||
* Creates all required tables in PostgreSQL
|
* Creates database and all required tables in PostgreSQL
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import postgres from "postgres";
|
import postgres from "postgres";
|
||||||
import { readFileSync } from "fs";
|
import { readFileSync } from "fs";
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse DATABASE_URL and extract components
|
||||||
|
*/
|
||||||
|
function parseDatabaseUrl(url: string): {
|
||||||
|
protocol: string;
|
||||||
|
user: string;
|
||||||
|
password: string;
|
||||||
|
host: string;
|
||||||
|
port: string;
|
||||||
|
database: string;
|
||||||
|
} {
|
||||||
|
const match = url.match(
|
||||||
|
/^postgresql:\/\/([^:]+):([^@]+)@([^:]+):(\d+)\/(.+)$/
|
||||||
|
);
|
||||||
|
if (!match) {
|
||||||
|
throw new Error(
|
||||||
|
"Invalid DATABASE_URL format. Expected: postgresql://user:password@host:port/database"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
protocol: "postgresql",
|
||||||
|
user: match[1],
|
||||||
|
password: match[2],
|
||||||
|
host: match[3],
|
||||||
|
port: match[4],
|
||||||
|
database: match[5],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async function initDatabase() {
|
async function initDatabase() {
|
||||||
const dbUrl = process.env.DATABASE_URL;
|
const dbUrl = process.env.DATABASE_URL;
|
||||||
|
|
||||||
if (!dbUrl) {
|
if (!dbUrl) {
|
||||||
console.error("Error: DATABASE_URL environment variable is required");
|
console.error("Error: DATABASE_URL environment variable is required");
|
||||||
console.error("Please set it in your .env file or export it:");
|
console.error("Please set it in your .env file or export it:");
|
||||||
console.error(" export DATABASE_URL=postgresql://user:password@host:port/database");
|
console.error(
|
||||||
|
" export DATABASE_URL=postgresql://user:password@host:port/database"
|
||||||
|
);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Connecting to PostgreSQL...");
|
const dbConfig = parseDatabaseUrl(dbUrl);
|
||||||
|
const targetDatabase = dbConfig.database;
|
||||||
|
|
||||||
|
console.log(`Target database: ${targetDatabase}`);
|
||||||
|
console.log(
|
||||||
|
`Connecting to PostgreSQL server (${dbConfig.host}:${dbConfig.port})...`
|
||||||
|
);
|
||||||
|
|
||||||
|
// Connect to postgres database (default database) to create target database
|
||||||
|
const adminUrl = `postgresql://${dbConfig.user}:${dbConfig.password}@${dbConfig.host}:${dbConfig.port}/postgres`;
|
||||||
|
const adminSql = postgres(adminUrl);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check if database exists
|
||||||
|
const dbExists = await adminSql`
|
||||||
|
SELECT 1 FROM pg_database WHERE datname = ${targetDatabase}
|
||||||
|
`;
|
||||||
|
|
||||||
|
if (dbExists.length === 0) {
|
||||||
|
console.log(`Database "${targetDatabase}" does not exist. Creating...`);
|
||||||
|
// Create database (escape database name to prevent SQL injection)
|
||||||
|
// PostgreSQL identifiers are case-insensitive unless quoted, so we quote it
|
||||||
|
const escapedDbName = `"${targetDatabase.replace(/"/g, '""')}"`;
|
||||||
|
await (adminSql as any).unsafe(`CREATE DATABASE ${escapedDbName}`);
|
||||||
|
console.log(`✓ Database "${targetDatabase}" created successfully`);
|
||||||
|
} else {
|
||||||
|
console.log(`✓ Database "${targetDatabase}" already exists`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = (error as Error).message;
|
||||||
|
if (errorMessage.includes("already exists")) {
|
||||||
|
console.log(`✓ Database "${targetDatabase}" already exists`);
|
||||||
|
} else {
|
||||||
|
console.error(`✗ Failed to create database: ${errorMessage}`);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
await adminSql.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now connect to target database and create tables
|
||||||
|
console.log(`\nConnecting to database "${targetDatabase}"...`);
|
||||||
const sql = postgres(dbUrl);
|
const sql = postgres(dbUrl);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Test connection
|
// Test connection
|
||||||
await sql`SELECT 1`;
|
await sql`SELECT 1`;
|
||||||
console.log("✓ Connected to PostgreSQL");
|
console.log("✓ Connected to database");
|
||||||
|
|
||||||
// Read schema file
|
// Read schema file
|
||||||
const schemaPath = join(process.cwd(), "src", "storage", "schema.sql");
|
const schemaPath = join(process.cwd(), "src", "storage", "schema.sql");
|
||||||
@@ -47,8 +119,13 @@ async function initDatabase() {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Check if it's a "already exists" error (which is OK)
|
// Check if it's a "already exists" error (which is OK)
|
||||||
const errorMessage = (error as Error).message;
|
const errorMessage = (error as Error).message;
|
||||||
if (errorMessage.includes("already exists") || errorMessage.includes("duplicate")) {
|
if (
|
||||||
console.log(`⚠ Skipped (already exists): ${statement.substring(0, 50)}...`);
|
errorMessage.includes("already exists") ||
|
||||||
|
errorMessage.includes("duplicate")
|
||||||
|
) {
|
||||||
|
console.log(
|
||||||
|
`⚠ Skipped (already exists): ${statement.substring(0, 50)}...`
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
console.error(`✗ Error executing statement: ${errorMessage}`);
|
console.error(`✗ Error executing statement: ${errorMessage}`);
|
||||||
console.error(` Statement: ${statement.substring(0, 100)}...`);
|
console.error(` Statement: ${statement.substring(0, 100)}...`);
|
||||||
|
|||||||
Reference in New Issue
Block a user