107 lines
2.9 KiB
JavaScript
107 lines
2.9 KiB
JavaScript
const { Pool } = require('pg');
|
|
require('dotenv').config();
|
|
|
|
// Coolify uses DATABASE_URL
|
|
// If not set, we can fallback to a local postgres or just let it fail
|
|
const pool = new Pool({
|
|
connectionString: process.env.DATABASE_URL,
|
|
});
|
|
|
|
pool.on('error', (err, client) => {
|
|
console.error('Unexpected error on idle client', err);
|
|
process.exit(-1);
|
|
});
|
|
|
|
const initDB = async () => {
|
|
try {
|
|
const client = await pool.connect();
|
|
console.log('Connected to the PostgreSQL database.');
|
|
|
|
await client.query(`
|
|
CREATE TABLE IF NOT EXISTS profiles (
|
|
id TEXT PRIMARY KEY,
|
|
email TEXT UNIQUE,
|
|
password_hash TEXT,
|
|
role TEXT DEFAULT 'user',
|
|
api_credits INTEGER DEFAULT 10,
|
|
storage_limit_mb INTEGER DEFAULT 500,
|
|
is_active BOOLEAN DEFAULT false,
|
|
api_keys TEXT
|
|
)
|
|
`);
|
|
|
|
// In Postgres, ALTER TABLE ADD COLUMN IF NOT EXISTS requires PG >= 9.6
|
|
// So we can catch the error if column exists just like sqlite logic
|
|
try {
|
|
await client.query(`ALTER TABLE profiles ADD COLUMN is_active BOOLEAN DEFAULT false`);
|
|
} catch (err) {
|
|
// Ignore if it already exists
|
|
}
|
|
|
|
try {
|
|
await client.query(`ALTER TABLE profiles ADD COLUMN api_keys TEXT`);
|
|
} catch (err) {
|
|
// Ignore if it already exists
|
|
}
|
|
|
|
try {
|
|
await client.query(`ALTER TABLE profiles ADD COLUMN activation_token TEXT`);
|
|
} catch (err) {
|
|
// Ignore if it already exists
|
|
}
|
|
|
|
try {
|
|
await client.query(`ALTER TABLE profiles ADD COLUMN reset_token TEXT`);
|
|
} catch (err) {
|
|
// Ignore if it already exists
|
|
}
|
|
|
|
await client.query(`
|
|
CREATE TABLE IF NOT EXISTS projects (
|
|
id TEXT PRIMARY KEY,
|
|
user_id TEXT REFERENCES profiles(id),
|
|
name TEXT,
|
|
scene_data TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
`);
|
|
|
|
client.release();
|
|
} catch (err) {
|
|
console.error('Error initializing database:', err);
|
|
}
|
|
};
|
|
|
|
initDB();
|
|
|
|
// Wrapper functions to simulate the old sqlite API but backed by pg
|
|
|
|
const run = async (sql, params = []) => {
|
|
// convert ? to $1, $2, etc.
|
|
let paramIndex = 1;
|
|
const pgSql = sql.replace(/\?/g, () => `$${paramIndex++}`);
|
|
|
|
const res = await pool.query(pgSql, params);
|
|
// `run` in sqlite returns { id: this.lastID, changes: this.changes }
|
|
// Postgres doesn't return lastID unless RETURNING is used, but for uuids it doesn't matter.
|
|
return { changes: res.rowCount };
|
|
};
|
|
|
|
const get = async (sql, params = []) => {
|
|
let paramIndex = 1;
|
|
const pgSql = sql.replace(/\?/g, () => `$${paramIndex++}`);
|
|
|
|
const res = await pool.query(pgSql, params);
|
|
return res.rows[0];
|
|
};
|
|
|
|
const all = async (sql, params = []) => {
|
|
let paramIndex = 1;
|
|
const pgSql = sql.replace(/\?/g, () => `$${paramIndex++}`);
|
|
|
|
const res = await pool.query(pgSql, params);
|
|
return res.rows;
|
|
};
|
|
|
|
module.exports = { db: pool, run, get, all };
|