import { Response } from 'express'; import { AuthRequest } from '../middleware/auth'; import { mainPool } from '../config/database'; import { databasePoolManager } from '../services/DatabasePoolManager'; import { generateSchemaForDatabase } from './schemaController'; // Только админы могут управлять базами данных 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, 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, 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 } = req.body; const dbType = type || 'postgresql'; // Валидация для обычных БД if (dbType !== 'aql') { if (!name || !host || !port || !database_name || !username || !password) { return res.status(400).json({ error: 'Не заполнены обязательные поля' }); } } else { // Валидация для AQL 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 ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, true, $9, $10, $11, $12) 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 ] ); const newDb = result.rows[0]; // Добавить пул подключений (только для не-AQL баз) if (dbType !== 'aql') { await databasePoolManager.reloadPool(newDb.id); // Generate schema in background for PostgreSQL databases if (dbType === 'postgresql') { generateSchemaForDatabase(newDb.id).catch(err => { console.error('Background schema generation failed:', err.message); }); } } // Не возвращаем пароль delete newDb.password; delete newDb.aql_auth_value; // Также не возвращаем 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 } = req.body; // Если пароль/auth не передан, не обновляем его let query; let params; if (password || aql_auth_value) { query = ` UPDATE databases SET name = COALESCE($1, name), type = COALESCE($2, type), host = COALESCE($3, host), port = COALESCE($4, port), database_name = COALESCE($5, database_name), username = COALESCE($6, username), password = COALESCE($7, password), ssl = COALESCE($8, ssl), is_active = COALESCE($9, is_active), aql_base_url = COALESCE($10, aql_base_url), aql_auth_type = COALESCE($11, aql_auth_type), aql_auth_value = COALESCE($12, aql_auth_value), aql_headers = COALESCE($13, aql_headers), updated_at = CURRENT_TIMESTAMP WHERE id = $14 RETURNING id, name, type, host, port, database_name, username, ssl, is_active, aql_base_url, aql_auth_type, aql_headers, created_at, updated_at `; params = [ name, type, host, port, database_name, username, password || aql_auth_value, ssl, is_active, aql_base_url, aql_auth_type, aql_auth_value, aql_headers ? JSON.stringify(aql_headers) : null, id ]; } else { query = ` UPDATE databases SET name = COALESCE($1, name), type = COALESCE($2, type), host = COALESCE($3, host), port = COALESCE($4, port), database_name = COALESCE($5, database_name), username = COALESCE($6, username), ssl = COALESCE($7, ssl), is_active = COALESCE($8, is_active), aql_base_url = COALESCE($9, aql_base_url), aql_auth_type = COALESCE($10, aql_auth_type), aql_headers = COALESCE($11, aql_headers), updated_at = CURRENT_TIMESTAMP WHERE id = $12 RETURNING id, name, type, host, port, database_name, username, ssl, is_active, aql_base_url, aql_auth_type, aql_headers, created_at, updated_at `; params = [ name, type, host, port, database_name, username, ssl, is_active, aql_base_url, aql_auth_type, aql_headers ? JSON.stringify(aql_headers) : null, id ]; } const result = await mainPool.query(query, params); if (result.rows.length === 0) { return res.status(404).json({ error: 'База данных не найдена' }); } // Перезагрузить пул (только для не-AQL баз) 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 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') { // Для AQL используем aqlExecutor const { aqlExecutor } = require('../services/AqlExecutor'); const result = await aqlExecutor.testConnection(id); res.json({ success: result.success, message: result.success ? 'Подключение успешно' : result.error || 'Ошибка подключения', }); } else { // Для обычных БД используем databasePoolManager const isConnected = await databasePoolManager.testConnection(id); res.json({ success: isConnected, message: isConnected ? 'Подключение успешно' : 'Ошибка подключения', }); } } catch (error) { console.error('Test connection error:', error); res.status(500).json({ error: 'Ошибка тестирования подключения' }); } };