101 lines
2.8 KiB
JavaScript
101 lines
2.8 KiB
JavaScript
const { Pool } = require('pg');
|
|
|
|
const config = {
|
|
user: process.env.DB_USER,
|
|
password: process.env.DB_PASSWORD,
|
|
host: process.env.DB_HOST,
|
|
port: process.env.DB_PORT,
|
|
database: process.env.USERS_DB || process.env.DB_NAME,
|
|
max: 10,
|
|
idleTimeoutMillis: 30000,
|
|
connectionTimeoutMillis: 5000
|
|
};
|
|
|
|
const pool = new Pool(config);
|
|
|
|
pool.on('error', (err) => {
|
|
console.error('[DB] Pool error:', err.message);
|
|
});
|
|
|
|
async function query(text, params) {
|
|
const start = Date.now();
|
|
try {
|
|
const result = await pool.query(text, params);
|
|
const duration = Date.now() - start;
|
|
if (duration > 100) {
|
|
console.warn(`[DB] Slow query (${duration}ms):`, text.substring(0, 80));
|
|
}
|
|
return result;
|
|
} catch (err) {
|
|
console.error('[DB] Query failed:', err.message, '| code:', err.code);
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
async function getClient() {
|
|
return await pool.connect();
|
|
}
|
|
|
|
async function initDb() {
|
|
await pool.query('SELECT NOW()');
|
|
|
|
try {
|
|
await pool.query(`CREATE EXTENSION IF NOT EXISTS pgcrypto;`);
|
|
} catch (err) {
|
|
console.warn('[DB] Could not create pgcrypto extension:', err.message);
|
|
}
|
|
|
|
await pool.query(`
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
username VARCHAR(50) UNIQUE NOT NULL,
|
|
password_hash VARCHAR(255) NOT NULL,
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMP DEFAULT NOW(),
|
|
telegram_id VARCHAR(50) UNIQUE
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
|
|
CREATE INDEX IF NOT EXISTS idx_users_telegram_id ON users(telegram_id);
|
|
`);
|
|
|
|
await pool.query(`
|
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
session_code VARCHAR(64) NOT NULL,
|
|
encoded_username TEXT NOT NULL DEFAULT '',
|
|
ip_address INET,
|
|
user_agent TEXT,
|
|
browser VARCHAR(100),
|
|
os VARCHAR(100),
|
|
device_type VARCHAR(50),
|
|
location_country VARCHAR(100),
|
|
location_city VARCHAR(100),
|
|
created_at TIMESTAMP DEFAULT NOW(),
|
|
last_active TIMESTAMP DEFAULT NOW(),
|
|
is_revoked BOOLEAN DEFAULT FALSE
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_sessions_code ON sessions(session_code);
|
|
CREATE INDEX IF NOT EXISTS idx_sessions_user_id ON sessions(user_id);
|
|
`);
|
|
}
|
|
|
|
async function checkPostgres() {
|
|
try {
|
|
await pool.query('SELECT NOW()');
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
pool,
|
|
query,
|
|
getClient,
|
|
initDb,
|
|
checkPostgres
|
|
};
|