Add test/prod environments for databases
- Migration 010: test_* columns on databases table, environment column on request_logs - DatabasePoolManager: dual-pool strategy (prod + test), getPool(id, env) with fallback - All executors (SQL, Script, AQL): environment param threaded through execution paths - dynamicApiController: X-Environment header detection, environment in logging - databaseManagementController: CRUD for test credentials, testConnection with ?env=test - Frontend: test env form in DatabaseModal, env toggle in EndpointEditor test panel Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { QueryResult, DatabaseConfig } from '../types';
|
||||
import { QueryResult, DatabaseConfig, Environment } from '../types';
|
||||
import { mainPool } from '../config/database';
|
||||
import { databasePoolManager } from './DatabasePoolManager';
|
||||
|
||||
interface AqlRequestConfig {
|
||||
method: 'GET' | 'POST' | 'PUT' | 'DELETE';
|
||||
@@ -73,19 +74,30 @@ export class AqlExecutor {
|
||||
*/
|
||||
async executeAqlQuery(
|
||||
databaseId: string,
|
||||
config: AqlRequestConfig
|
||||
config: AqlRequestConfig,
|
||||
environment: Environment = 'prod'
|
||||
): Promise<QueryResult> {
|
||||
const startTime = Date.now();
|
||||
|
||||
try {
|
||||
// Получаем конфигурацию БД
|
||||
const dbConfig = await this.getDatabaseConfig(databaseId);
|
||||
const dbConfig = await databasePoolManager.getDatabaseConfig(databaseId);
|
||||
|
||||
if (!dbConfig) {
|
||||
throw new Error(`AQL database with id ${databaseId} not found or not configured`);
|
||||
}
|
||||
|
||||
if (!dbConfig.aql_base_url) {
|
||||
// Use test credentials when environment is test and test env is configured
|
||||
let baseUrl = dbConfig.aql_base_url;
|
||||
let authValue = dbConfig.aql_auth_value;
|
||||
let headers_config = dbConfig.aql_headers;
|
||||
|
||||
if (environment === 'test' && dbConfig.has_test_env) {
|
||||
if (dbConfig.test_aql_base_url) baseUrl = dbConfig.test_aql_base_url;
|
||||
if (dbConfig.test_aql_auth_value) authValue = dbConfig.test_aql_auth_value;
|
||||
if (dbConfig.test_aql_headers) headers_config = dbConfig.test_aql_headers;
|
||||
}
|
||||
|
||||
if (!baseUrl) {
|
||||
throw new Error(`AQL base URL not configured for database ${databaseId}`);
|
||||
}
|
||||
|
||||
@@ -100,7 +112,7 @@ export class AqlExecutor {
|
||||
: '';
|
||||
|
||||
// Формируем полный URL
|
||||
const fullUrl = `${dbConfig.aql_base_url}${processedEndpoint}${queryString}`;
|
||||
const fullUrl = `${baseUrl}${processedEndpoint}${queryString}`;
|
||||
|
||||
// Обрабатываем body с параметрами
|
||||
let processedBody: string | undefined;
|
||||
@@ -115,19 +127,19 @@ export class AqlExecutor {
|
||||
};
|
||||
|
||||
// Добавляем аутентификацию
|
||||
if (dbConfig.aql_auth_type === 'basic' && dbConfig.aql_auth_value) {
|
||||
headers['Authorization'] = `Basic ${dbConfig.aql_auth_value}`;
|
||||
} else if (dbConfig.aql_auth_type === 'bearer' && dbConfig.aql_auth_value) {
|
||||
headers['Authorization'] = `Bearer ${dbConfig.aql_auth_value}`;
|
||||
} else if (dbConfig.aql_auth_type === 'custom' && dbConfig.aql_auth_value) {
|
||||
headers['Authorization'] = dbConfig.aql_auth_value;
|
||||
if (dbConfig.aql_auth_type === 'basic' && authValue) {
|
||||
headers['Authorization'] = `Basic ${authValue}`;
|
||||
} else if (dbConfig.aql_auth_type === 'bearer' && authValue) {
|
||||
headers['Authorization'] = `Bearer ${authValue}`;
|
||||
} else if (dbConfig.aql_auth_type === 'custom' && authValue) {
|
||||
headers['Authorization'] = authValue;
|
||||
}
|
||||
|
||||
// Добавляем кастомные заголовки из конфигурации БД
|
||||
if (dbConfig.aql_headers) {
|
||||
const customHeaders = typeof dbConfig.aql_headers === 'string'
|
||||
? JSON.parse(dbConfig.aql_headers)
|
||||
: dbConfig.aql_headers;
|
||||
if (headers_config) {
|
||||
const customHeaders = typeof headers_config === 'string'
|
||||
? JSON.parse(headers_config)
|
||||
: headers_config;
|
||||
|
||||
Object.assign(headers, customHeaders);
|
||||
}
|
||||
@@ -234,28 +246,29 @@ export class AqlExecutor {
|
||||
/**
|
||||
* Тестирует подключение к AQL базе
|
||||
*/
|
||||
async testConnection(databaseId: string): Promise<{ success: boolean; error?: string }> {
|
||||
async testConnection(databaseId: string, environment: Environment = 'prod'): Promise<{ success: boolean; error?: string }> {
|
||||
try {
|
||||
const dbConfig = await this.getDatabaseConfig(databaseId);
|
||||
const dbConfig = await databasePoolManager.getDatabaseConfig(databaseId);
|
||||
|
||||
if (!dbConfig) {
|
||||
return { success: false, error: 'Database not found' };
|
||||
}
|
||||
|
||||
if (!dbConfig.aql_base_url) {
|
||||
let testUrl = dbConfig.aql_base_url;
|
||||
if (environment === 'test' && dbConfig.has_test_env && dbConfig.test_aql_base_url) {
|
||||
testUrl = dbConfig.test_aql_base_url;
|
||||
}
|
||||
|
||||
if (!testUrl) {
|
||||
return { success: false, error: 'AQL base URL not configured' };
|
||||
}
|
||||
|
||||
// Пробуем выполнить простой запрос для проверки соединения
|
||||
const response = await fetch(dbConfig.aql_base_url, {
|
||||
const response = await fetch(testUrl, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
headers: { 'Accept': 'application/json' },
|
||||
});
|
||||
|
||||
if (response.ok || response.status === 404) {
|
||||
// 404 тоже OK - это значит что сервер доступен
|
||||
return { success: true };
|
||||
} else {
|
||||
return { success: false, error: `HTTP ${response.status}` };
|
||||
|
||||
Reference in New Issue
Block a user