modified: backend/src/services/AqlExecutor.ts
new file: backend/src/services/AqlExecutor.ts.backup
This commit is contained in:
@@ -140,12 +140,21 @@ export class AqlExecutor {
|
|||||||
console.log('Body:', processedBody || '(no body)');
|
console.log('Body:', processedBody || '(no body)');
|
||||||
console.log('===================\n');
|
console.log('===================\n');
|
||||||
|
|
||||||
// Выполняем HTTP запрос
|
// Формируем опции для fetch
|
||||||
const response = await fetch(fullUrl, {
|
// ВАЖНО: body не должен передаваться для GET запросов
|
||||||
|
// и если он undefined, иначе fetch может изменить метод на GET
|
||||||
|
const fetchOptions: RequestInit = {
|
||||||
method: config.method,
|
method: config.method,
|
||||||
headers,
|
headers,
|
||||||
body: processedBody,
|
};
|
||||||
});
|
|
||||||
|
// Добавляем body только если он есть и метод поддерживает body
|
||||||
|
if (processedBody && config.method !== 'GET') {
|
||||||
|
fetchOptions.body = processedBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Выполняем HTTP запрос
|
||||||
|
const response = await fetch(fullUrl, fetchOptions);
|
||||||
|
|
||||||
const executionTime = Date.now() - startTime;
|
const executionTime = Date.now() - startTime;
|
||||||
|
|
||||||
|
|||||||
260
backend/src/services/AqlExecutor.ts.backup
Normal file
260
backend/src/services/AqlExecutor.ts.backup
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
import { QueryResult, DatabaseConfig } from '../types';
|
||||||
|
import { mainPool } from '../config/database';
|
||||||
|
|
||||||
|
interface AqlRequestConfig {
|
||||||
|
method: 'GET' | 'POST' | 'PUT' | 'DELETE';
|
||||||
|
endpoint: string;
|
||||||
|
body?: string;
|
||||||
|
queryParams?: Record<string, string>;
|
||||||
|
parameters?: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AqlExecutor {
|
||||||
|
/**
|
||||||
|
* Получает конфигурацию AQL базы данных
|
||||||
|
*/
|
||||||
|
private async getDatabaseConfig(databaseId: string): Promise<DatabaseConfig | null> {
|
||||||
|
const result = await mainPool.query(
|
||||||
|
'SELECT * FROM databases WHERE id = $1 AND type = $2',
|
||||||
|
[databaseId, 'aql']
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.rows.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.rows[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Заменяет параметры вида $paramName в строке на значения из объекта parameters
|
||||||
|
*/
|
||||||
|
private replaceParameters(template: string, parameters: Record<string, any>): string {
|
||||||
|
let result = template;
|
||||||
|
|
||||||
|
// Находим все параметры вида $paramName
|
||||||
|
const paramMatches = template.match(/\$\w+/g) || [];
|
||||||
|
const uniqueParams = [...new Set(paramMatches.map(p => p.substring(1)))];
|
||||||
|
|
||||||
|
uniqueParams.forEach((paramName) => {
|
||||||
|
const regex = new RegExp(`\\$${paramName}\\b`, 'g');
|
||||||
|
const value = parameters[paramName];
|
||||||
|
|
||||||
|
if (value !== undefined && value !== null) {
|
||||||
|
// Для строк в JSON нужны кавычки, для чисел - нет
|
||||||
|
const replacement = typeof value === 'string'
|
||||||
|
? value
|
||||||
|
: JSON.stringify(value);
|
||||||
|
result = result.replace(regex, replacement);
|
||||||
|
} else {
|
||||||
|
result = result.replace(regex, '');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Строит query string из объекта параметров
|
||||||
|
*/
|
||||||
|
private buildQueryString(params: Record<string, string>, requestParams: Record<string, any>): string {
|
||||||
|
const processedParams: Record<string, string> = {};
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(params)) {
|
||||||
|
processedParams[key] = this.replaceParameters(value, requestParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryString = new URLSearchParams(processedParams).toString();
|
||||||
|
return queryString ? `?${queryString}` : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Выполняет AQL запрос
|
||||||
|
*/
|
||||||
|
async executeAqlQuery(
|
||||||
|
databaseId: string,
|
||||||
|
config: AqlRequestConfig
|
||||||
|
): Promise<QueryResult> {
|
||||||
|
const startTime = Date.now();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Получаем конфигурацию БД
|
||||||
|
const dbConfig = await this.getDatabaseConfig(databaseId);
|
||||||
|
|
||||||
|
if (!dbConfig) {
|
||||||
|
throw new Error(`AQL database with id ${databaseId} not found or not configured`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dbConfig.aql_base_url) {
|
||||||
|
throw new Error(`AQL base URL not configured for database ${databaseId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const parameters = config.parameters || {};
|
||||||
|
|
||||||
|
// Обрабатываем endpoint с параметрами
|
||||||
|
const processedEndpoint = this.replaceParameters(config.endpoint, parameters);
|
||||||
|
|
||||||
|
// Обрабатываем query параметры
|
||||||
|
const queryString = config.queryParams
|
||||||
|
? this.buildQueryString(config.queryParams, parameters)
|
||||||
|
: '';
|
||||||
|
|
||||||
|
// Формируем полный URL
|
||||||
|
const fullUrl = `${dbConfig.aql_base_url}${processedEndpoint}${queryString}`;
|
||||||
|
|
||||||
|
// Обрабатываем body с параметрами
|
||||||
|
let processedBody: string | undefined;
|
||||||
|
if (config.body) {
|
||||||
|
processedBody = this.replaceParameters(config.body, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Формируем заголовки
|
||||||
|
const headers: Record<string, string> = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Добавляем аутентификацию
|
||||||
|
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_headers) {
|
||||||
|
const customHeaders = typeof dbConfig.aql_headers === 'string'
|
||||||
|
? JSON.parse(dbConfig.aql_headers)
|
||||||
|
: dbConfig.aql_headers;
|
||||||
|
|
||||||
|
Object.assign(headers, customHeaders);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Логируем запрос
|
||||||
|
console.log('\n=== AQL Request ===');
|
||||||
|
console.log('URL:', fullUrl);
|
||||||
|
console.log('Method:', config.method);
|
||||||
|
console.log('Headers:', JSON.stringify(headers, null, 2));
|
||||||
|
console.log('Body:', processedBody || '(no body)');
|
||||||
|
console.log('===================\n');
|
||||||
|
|
||||||
|
// Выполняем HTTP запрос
|
||||||
|
const response = await fetch(fullUrl, {
|
||||||
|
method: config.method,
|
||||||
|
headers,
|
||||||
|
body: processedBody,
|
||||||
|
});
|
||||||
|
|
||||||
|
const executionTime = Date.now() - startTime;
|
||||||
|
|
||||||
|
// Проверяем статус ответа
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorText = await response.text();
|
||||||
|
console.log('\n=== AQL Error Response ===');
|
||||||
|
console.log('Status:', response.status);
|
||||||
|
console.log('Response:', errorText);
|
||||||
|
console.log('==========================\n');
|
||||||
|
throw new Error(`AQL API error (${response.status}): ${errorText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обрабатываем пустой ответ (204 No Content)
|
||||||
|
if (response.status === 204) {
|
||||||
|
console.log('\n=== AQL Response ===');
|
||||||
|
console.log('Status: 204 (No Content)');
|
||||||
|
console.log('====================\n');
|
||||||
|
return {
|
||||||
|
rows: [],
|
||||||
|
rowCount: 0,
|
||||||
|
executionTime,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Парсим JSON ответ
|
||||||
|
const responseText = await response.text();
|
||||||
|
console.log('\n=== AQL Response ===');
|
||||||
|
console.log('Status:', response.status);
|
||||||
|
console.log('Raw Response:', responseText);
|
||||||
|
console.log('====================\n');
|
||||||
|
|
||||||
|
// Если ответ пустой, возвращаем пустой результат
|
||||||
|
if (!responseText || responseText.trim() === '') {
|
||||||
|
return {
|
||||||
|
rows: [],
|
||||||
|
rowCount: 0,
|
||||||
|
executionTime,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let data;
|
||||||
|
try {
|
||||||
|
data = JSON.parse(responseText);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to parse JSON response:', e);
|
||||||
|
throw new Error(`Invalid JSON response: ${responseText.substring(0, 200)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Возвращаем данные как есть
|
||||||
|
return {
|
||||||
|
rows: data,
|
||||||
|
rowCount: Array.isArray(data) ? data.length : (data ? 1 : 0),
|
||||||
|
executionTime,
|
||||||
|
};
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('AQL Execution Error:', error);
|
||||||
|
throw new Error(`AQL Error: ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тестирует AQL запрос
|
||||||
|
*/
|
||||||
|
async testAqlQuery(
|
||||||
|
databaseId: string,
|
||||||
|
config: AqlRequestConfig
|
||||||
|
): Promise<{ success: boolean; error?: string }> {
|
||||||
|
try {
|
||||||
|
await this.executeAqlQuery(databaseId, config);
|
||||||
|
return { success: true };
|
||||||
|
} catch (error: any) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тестирует подключение к AQL базе
|
||||||
|
*/
|
||||||
|
async testConnection(databaseId: string): Promise<{ success: boolean; error?: string }> {
|
||||||
|
try {
|
||||||
|
const dbConfig = await this.getDatabaseConfig(databaseId);
|
||||||
|
|
||||||
|
if (!dbConfig) {
|
||||||
|
return { success: false, error: 'Database not found' };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dbConfig.aql_base_url) {
|
||||||
|
return { success: false, error: 'AQL base URL not configured' };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Пробуем выполнить простой запрос для проверки соединения
|
||||||
|
const response = await fetch(dbConfig.aql_base_url, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok || response.status === 404) {
|
||||||
|
// 404 тоже OK - это значит что сервер доступен
|
||||||
|
return { success: true };
|
||||||
|
} else {
|
||||||
|
return { success: false, error: `HTTP ${response.status}` };
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const aqlExecutor = new AqlExecutor();
|
||||||
Reference in New Issue
Block a user