Files
task-manager/server/db.ts
T
paul-nothaft 784968521a Prepare application for production deployment with Docker and PostgreSQL
Integrate PostgreSQL database with Drizzle ORM, implement database migrations, and enhance Dockerfile for production build.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: ceced2fc-aa46-458d-ba87-ddd4b7bb1518
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/659922a9-0087-461c-90dd-6d9a58b81d4d/ceced2fc-aa46-458d-ba87-ddd4b7bb1518/ahHWEFX
2025-10-23 13:31:02 +00:00

116 lines
3.1 KiB
TypeScript

import { drizzle } from 'drizzle-orm/node-postgres';
import { Pool } from 'pg';
import { migrate } from 'drizzle-orm/node-postgres/migrator';
import * as schema from '@shared/schema';
import { sql } from 'drizzle-orm';
let db: ReturnType<typeof drizzle> | null = null;
let pool: Pool | null = null;
export function getDatabase() {
if (!db) {
const databaseUrl = process.env.DATABASE_URL;
if (!databaseUrl) {
throw new Error('DATABASE_URL environment variable is not set');
}
pool = new Pool({
connectionString: databaseUrl,
});
db = drizzle(pool, { schema });
}
return db;
}
export async function runMigrations() {
try {
const database = getDatabase();
// Push schema to database (creates/updates tables as needed)
// This is equivalent to running `drizzle-kit push`
console.log('Checking database schema...');
// Enable pgcrypto extension for gen_random_uuid()
await database.execute(sql`CREATE EXTENSION IF NOT EXISTS "pgcrypto"`);
// Create tables if they don't exist
await database.execute(sql`
CREATE TABLE IF NOT EXISTS users (
id VARCHAR PRIMARY KEY DEFAULT gen_random_uuid(),
username TEXT NOT NULL UNIQUE,
password TEXT NOT NULL
)
`);
await database.execute(sql`
CREATE TABLE IF NOT EXISTS labels (
id VARCHAR PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
color TEXT NOT NULL
)
`);
await database.execute(sql`
CREATE TABLE IF NOT EXISTS tasks (
id VARCHAR PRIMARY KEY DEFAULT gen_random_uuid(),
title TEXT NOT NULL,
description TEXT,
status TEXT NOT NULL DEFAULT 'todo',
priority TEXT NOT NULL DEFAULT 'medium',
due_date TIMESTAMP,
time_tracked INTEGER NOT NULL DEFAULT 0,
is_tracking BOOLEAN NOT NULL DEFAULT false,
project_id TEXT,
notes TEXT,
label_id VARCHAR REFERENCES labels(id)
)
`);
console.log('✓ Database schema is up to date');
} catch (error) {
console.error('Failed to run migrations:', error);
throw error;
}
}
export async function initializeDatabase() {
try {
// Run migrations first
await runMigrations();
const database = getDatabase();
// Create default labels if they don't exist
const existingLabels = await database.select().from(schema.labels);
if (existingLabels.length === 0) {
const defaultLabels = [
{ name: "Work", color: "#3B82F6" },
{ name: "Personal", color: "#10B981" },
{ name: "Urgent", color: "#EF4444" },
{ name: "Study", color: "#8B5CF6" },
];
await database.insert(schema.labels).values(defaultLabels);
console.log('✓ Created default labels');
}
console.log('✓ Database initialized successfully');
} catch (error) {
console.error('Failed to initialize database:', error);
throw error;
}
}
export async function closeDatabase() {
if (pool) {
await pool.end();
pool = null;
db = null;
console.log('✓ Database connection closed');
}
}