126 lines
No EOL
3.4 KiB
TypeScript
126 lines
No EOL
3.4 KiB
TypeScript
import { createClient } from 'redis';
|
|
import pkg from 'pg';
|
|
const { Pool } = pkg;
|
|
|
|
export interface DatabaseConfig {
|
|
redis: {
|
|
url: string;
|
|
maxRetriesPerRequest: number;
|
|
};
|
|
postgres: {
|
|
host: string;
|
|
port: number;
|
|
database: string;
|
|
user: string;
|
|
password: string;
|
|
max: number;
|
|
};
|
|
}
|
|
|
|
export const databaseConfig: DatabaseConfig = {
|
|
redis: {
|
|
url: process.env.REDIS_URL || 'redis://localhost:6379',
|
|
maxRetriesPerRequest: 3,
|
|
},
|
|
postgres: {
|
|
host: process.env.POSTGRES_HOST || 'localhost',
|
|
port: parseInt(process.env.POSTGRES_PORT || '5432'),
|
|
database: process.env.POSTGRES_DB || 'gaplace',
|
|
user: process.env.POSTGRES_USER || 'gaplace',
|
|
password: process.env.POSTGRES_PASSWORD || 'password',
|
|
max: 20,
|
|
},
|
|
};
|
|
|
|
// Redis client
|
|
export const redisClient = createClient({
|
|
url: databaseConfig.redis.url,
|
|
});
|
|
|
|
redisClient.on('error', (err) => {
|
|
console.error('Redis Client Error:', err);
|
|
});
|
|
|
|
redisClient.on('connect', () => {
|
|
console.log('✅ Connected to Redis');
|
|
});
|
|
|
|
// PostgreSQL client
|
|
export const pgPool = new Pool(databaseConfig.postgres);
|
|
|
|
pgPool.on('error', (err) => {
|
|
console.error('PostgreSQL Pool Error:', err);
|
|
});
|
|
|
|
export async function initializeDatabase(): Promise<void> {
|
|
try {
|
|
// Connect to Redis
|
|
await redisClient.connect();
|
|
|
|
// Test PostgreSQL connection
|
|
const client = await pgPool.connect();
|
|
console.log('✅ Connected to PostgreSQL');
|
|
client.release();
|
|
|
|
// Create tables if they don't exist
|
|
await createTables();
|
|
} catch (error) {
|
|
console.error('❌ Database initialization failed:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async function createTables(): Promise<void> {
|
|
const client = await pgPool.connect();
|
|
|
|
try {
|
|
await client.query(`
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
username VARCHAR(50) UNIQUE NOT NULL,
|
|
email VARCHAR(255) UNIQUE,
|
|
password_hash VARCHAR(255),
|
|
avatar_url TEXT,
|
|
is_guest BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMP DEFAULT NOW(),
|
|
last_seen TIMESTAMP DEFAULT NOW()
|
|
);
|
|
`);
|
|
|
|
await client.query(`
|
|
CREATE TABLE IF NOT EXISTS canvases (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
name VARCHAR(100) NOT NULL,
|
|
width INTEGER NOT NULL DEFAULT 1000,
|
|
height INTEGER NOT NULL DEFAULT 1000,
|
|
chunk_size INTEGER NOT NULL DEFAULT 64,
|
|
is_public BOOLEAN DEFAULT TRUE,
|
|
created_by UUID REFERENCES users(id),
|
|
created_at TIMESTAMP DEFAULT NOW(),
|
|
updated_at TIMESTAMP DEFAULT NOW()
|
|
);
|
|
`);
|
|
|
|
await client.query(`
|
|
CREATE TABLE IF NOT EXISTS user_sessions (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID REFERENCES users(id),
|
|
canvas_id UUID REFERENCES canvases(id),
|
|
session_token VARCHAR(255) UNIQUE NOT NULL,
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
last_activity TIMESTAMP DEFAULT NOW(),
|
|
created_at TIMESTAMP DEFAULT NOW()
|
|
);
|
|
`);
|
|
|
|
await client.query(`
|
|
CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
|
|
CREATE INDEX IF NOT EXISTS idx_canvases_public ON canvases(is_public);
|
|
CREATE INDEX IF NOT EXISTS idx_sessions_active ON user_sessions(is_active, last_activity);
|
|
`);
|
|
|
|
console.log('✅ Database tables created/verified');
|
|
} finally {
|
|
client.release();
|
|
}
|
|
} |