import { Response } from 'express'; import { AuthRequest } from '../middleware/auth'; import { mainPool } from '../config/database'; import { databasePoolManager } from '../services/DatabasePoolManager'; import { generateSchemaForDatabase } from './schemaController'; import { Environment } from '../types'; export const getDatabases = async (req: AuthRequest, res: Response) => { try { const result = await mainPool.query( `SELECT id, name, type, host, port, database_name, username, ssl, is_active, aql_base_url, aql_auth_type, aql_auth_value, aql_headers, has_test_env, test_host, test_port, test_database_name, test_username, test_ssl, test_aql_base_url, test_aql_headers, created_at, updated_at FROM databases ORDER BY name` ); res.json(result.rows); } catch (error) { console.error('Get databases error:', error); res.status(500).json({ error: 'Ошибка получения списка баз данных' }); } }; export const getDatabase = async (req: AuthRequest, res: Response) => { try { const { id } = req.params; const result = await mainPool.query( `SELECT id, name, type, host, port, database_name, username, ssl, is_active, aql_base_url, aql_auth_type, aql_auth_value, aql_headers, has_test_env, test_host, test_port, test_database_name, test_username, test_ssl, test_aql_base_url, test_aql_headers, created_at, updated_at FROM databases WHERE id = $1`, [id] ); if (result.rows.length === 0) { return res.status(404).json({ error: 'База данных не найдена' }); } res.json(result.rows[0]); } catch (error) { console.error('Get database error:', error); res.status(500).json({ error: 'Ошибка получения базы данных' }); } }; export const createDatabase = async (req: AuthRequest, res: Response) => { try { const { name, type, host, port, database_name, username, password, ssl, aql_base_url, aql_auth_type, aql_auth_value, aql_headers, has_test_env, test_host, test_port, test_database_name, test_username, test_password, test_ssl, test_aql_base_url, test_aql_auth_value, test_aql_headers } = req.body; const dbType = type || 'postgresql'; if (dbType !== 'aql') { if (!name || !host || !port || !database_name || !username || !password) { return res.status(400).json({ error: 'Не заполнены обязательные поля' }); } } else { if (!name || !aql_base_url) { return res.status(400).json({ error: 'Не заполнены обязательные поля для AQL базы' }); } } const result = await mainPool.query( `INSERT INTO databases ( name, type, host, port, database_name, username, password, ssl, is_active, aql_base_url, aql_auth_type, aql_auth_value, aql_headers, has_test_env, test_host, test_port, test_database_name, test_username, test_password, test_ssl, test_aql_base_url, test_aql_auth_value, test_aql_headers ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, true, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22) RETURNING *`, [ name, dbType, host || '', port || 0, database_name || '', username || '', password || '', ssl || false, aql_base_url || null, aql_auth_type || null, aql_auth_value || null, aql_headers ? JSON.stringify(aql_headers) : null, has_test_env || false, test_host || null, test_port || null, test_database_name || null, test_username || null, test_password || null, test_ssl || null, test_aql_base_url || null, test_aql_auth_value || null, test_aql_headers ? JSON.stringify(test_aql_headers) : null, ] ); const newDb = result.rows[0]; if (dbType !== 'aql') { await databasePoolManager.reloadPool(newDb.id); if (dbType === 'postgresql') { generateSchemaForDatabase(newDb.id).catch(err => { console.error('Background schema generation failed:', err.message); }); } } delete newDb.password; delete newDb.aql_auth_value; delete newDb.test_password; delete newDb.test_aql_auth_value; res.status(201).json(newDb); } catch (error: any) { console.error('Create database error:', error); if (error.code === '23505') { return res.status(400).json({ error: 'База данных с таким именем уже существует' }); } res.status(500).json({ error: 'Ошибка создания базы данных' }); } }; export const updateDatabase = async (req: AuthRequest, res: Response) => { try { const { id } = req.params; const { name, type, host, port, database_name, username, password, ssl, is_active, aql_base_url, aql_auth_type, aql_auth_value, aql_headers, has_test_env, test_host, test_port, test_database_name, test_username, test_password, test_ssl, test_aql_base_url, test_aql_auth_value, test_aql_headers } = req.body; // Build SET clauses and params dynamically to handle optional password fields const setClauses: string[] = []; const params: any[] = []; let idx = 1; const addField = (clause: string, value: any) => { setClauses.push(`${clause} = $${idx}`); params.push(value); idx++; }; const addCoalesce = (field: string, value: any) => { setClauses.push(`${field} = COALESCE($${idx}, ${field})`); params.push(value); idx++; }; addCoalesce('name', name); addCoalesce('type', type); addCoalesce('host', host); addCoalesce('port', port); addCoalesce('database_name', database_name); addCoalesce('username', username); if (password) { addField('password', password); } addCoalesce('ssl', ssl); addCoalesce('is_active', is_active); addCoalesce('aql_base_url', aql_base_url); addCoalesce('aql_auth_type', aql_auth_type); if (aql_auth_value) { addField('aql_auth_value', aql_auth_value); } addCoalesce('aql_headers', aql_headers ? JSON.stringify(aql_headers) : null); addCoalesce('has_test_env', has_test_env); // Test fields: use direct SET (nullable — user may want to clear them) addField('test_host', test_host || null); addField('test_port', test_port || null); addField('test_database_name', test_database_name || null); addField('test_username', test_username || null); if (test_password) { addField('test_password', test_password); } addField('test_ssl', test_ssl !== undefined ? test_ssl : null); addField('test_aql_base_url', test_aql_base_url || null); if (test_aql_auth_value) { addField('test_aql_auth_value', test_aql_auth_value); } addField('test_aql_headers', test_aql_headers ? JSON.stringify(test_aql_headers) : null); setClauses.push('updated_at = CURRENT_TIMESTAMP'); params.push(id); const whereIdx = idx; const query = ` UPDATE databases SET ${setClauses.join(', ')} WHERE id = $${whereIdx} RETURNING id, name, type, host, port, database_name, username, ssl, is_active, aql_base_url, aql_auth_type, aql_headers, has_test_env, test_host, test_port, test_database_name, test_username, test_ssl, test_aql_base_url, test_aql_headers, created_at, updated_at`; const result = await mainPool.query(query, params); if (result.rows.length === 0) { return res.status(404).json({ error: 'База данных не найдена' }); } if (result.rows[0].type !== 'aql') { await databasePoolManager.reloadPool(id); } res.json(result.rows[0]); } catch (error: any) { console.error('Update database error:', error); if (error.code === '23505') { return res.status(400).json({ error: 'База данных с таким именем уже существует' }); } res.status(500).json({ error: 'Ошибка обновления базы данных' }); } }; export const deleteDatabase = async (req: AuthRequest, res: Response) => { try { const { id } = req.params; const endpointCheck = await mainPool.query( 'SELECT COUNT(*) FROM endpoints WHERE database_id = $1', [id] ); if (parseInt(endpointCheck.rows[0].count) > 0) { return res.status(400).json({ error: 'Невозможно удалить базу данных, используемую в эндпоинтах' }); } const result = await mainPool.query( 'DELETE FROM databases WHERE id = $1 RETURNING id', [id] ); if (result.rows.length === 0) { return res.status(404).json({ error: 'База данных не найдена' }); } databasePoolManager.removePool(id); res.json({ message: 'База данных удалена успешно' }); } catch (error) { console.error('Delete database error:', error); res.status(500).json({ error: 'Ошибка удаления базы данных' }); } }; export const testDatabaseConnection = async (req: AuthRequest, res: Response) => { try { const { id } = req.params; const env = (req.query.env as string)?.toLowerCase() === 'test' ? 'test' : 'prod' as Environment; const dbResult = await mainPool.query('SELECT type FROM databases WHERE id = $1', [id]); if (dbResult.rows.length === 0) { return res.status(404).json({ success: false, error: 'База данных не найдена' }); } const dbType = dbResult.rows[0].type; if (dbType === 'aql') { const { aqlExecutor } = require('../services/AqlExecutor'); const result = await aqlExecutor.testConnection(id, env); res.json({ success: result.success, message: result.success ? 'Подключение успешно' : result.error || 'Ошибка подключения', }); } else { const isConnected = await databasePoolManager.testConnection(id, env); res.json({ success: isConnected, message: isConnected ? 'Подключение успешно' : 'Ошибка подключения', }); } } catch (error) { console.error('Test connection error:', error); res.status(500).json({ error: 'Ошибка тестирования подключения' }); } };