diff --git a/backend/src/services/DatabasePoolManager.ts b/backend/src/services/DatabasePoolManager.ts index 6fc19ee..26b6571 100644 --- a/backend/src/services/DatabasePoolManager.ts +++ b/backend/src/services/DatabasePoolManager.ts @@ -80,6 +80,38 @@ class DatabasePoolManager { return this.pools.get(databaseId); } + async getDatabaseConfig(databaseId: string): Promise { + try { + const result = await mainPool.query( + 'SELECT * FROM databases WHERE id = $1', + [databaseId] + ); + if (result.rows.length === 0) { + return null; + } + const row = result.rows[0]; + return { + id: row.id, + name: row.name, + type: row.type, + host: row.host, + port: row.port, + database_name: row.database_name, + username: row.username, + password: row.password, + ssl: row.ssl, + is_active: row.is_active, + aql_base_url: row.aql_base_url, + aql_auth_type: row.aql_auth_type, + aql_auth_value: row.aql_auth_value, + aql_headers: row.aql_headers, + }; + } catch (error) { + console.error('Error fetching database config:', error); + return null; + } + } + async getAllDatabaseConfigs(): Promise { try { const result = await mainPool.query( diff --git a/backend/src/services/ScriptExecutor.ts b/backend/src/services/ScriptExecutor.ts index c4a1920..03c04ee 100644 --- a/backend/src/services/ScriptExecutor.ts +++ b/backend/src/services/ScriptExecutor.ts @@ -1,6 +1,8 @@ import { spawn } from 'child_process'; import { sqlExecutor } from './SqlExecutor'; +import { aqlExecutor } from './AqlExecutor'; import { ScriptQuery, EndpointParameter } from '../types'; +import { databasePoolManager } from './DatabasePoolManager'; interface ScriptContext { databaseId: string; @@ -23,32 +25,60 @@ export class ScriptExecutor { } const allParams = { ...context.requestParams, ...additionalParams }; - - let processedQuery = query.sql; - const paramValues: any[] = []; - const paramMatches = query.sql.match(/\$\w+/g) || []; - const uniqueParams = [...new Set(paramMatches.map(p => p.substring(1)))]; - - uniqueParams.forEach((paramName, index) => { - const regex = new RegExp(`\\$${paramName}\\b`, 'g'); - processedQuery = processedQuery.replace(regex, `$${index + 1}`); - const value = allParams[paramName]; - paramValues.push(value !== undefined ? value : null); - }); - const dbId = (query as any).database_id || context.databaseId; if (!dbId) { throw new Error(`Database ID not found for query '${queryName}'. Query database_id: ${(query as any).database_id}, Context databaseId: ${context.databaseId}. Please specify database_id in the Script Queries configuration for query '${queryName}'.`); } - const result = await sqlExecutor.executeQuery(dbId, processedQuery, paramValues); + // Получаем конфигурацию базы данных для определения типа + const dbConfig = await databasePoolManager.getDatabaseConfig(dbId); + if (!dbConfig) { + throw new Error(`Database configuration not found for ID: ${dbId}`); + } - return { - data: result.rows, - rowCount: result.rowCount, - executionTime: result.executionTime, - }; + // Проверяем тип базы данных и выполняем соответствующий запрос + if (dbConfig.type === 'aql') { + // AQL запрос + const result = await aqlExecutor.executeAqlQuery(dbId, { + method: query.aql_method || 'GET', + endpoint: query.aql_endpoint || '', + body: query.aql_body || '', + queryParams: query.aql_query_params || {}, + parameters: allParams, + }); + + return { + data: result.rows, + rowCount: result.rowCount, + executionTime: result.executionTime, + }; + } else { + // SQL запрос + if (!query.sql) { + throw new Error(`SQL query is required for database '${dbConfig.name}' (type: ${dbConfig.type})`); + } + + let processedQuery = query.sql; + const paramValues: any[] = []; + const paramMatches = query.sql.match(/\$\w+/g) || []; + const uniqueParams = [...new Set(paramMatches.map(p => p.substring(1)))]; + + uniqueParams.forEach((paramName, index) => { + const regex = new RegExp(`\\$${paramName}\\b`, 'g'); + processedQuery = processedQuery.replace(regex, `$${index + 1}`); + const value = allParams[paramName]; + paramValues.push(value !== undefined ? value : null); + }); + + const result = await sqlExecutor.executeQuery(dbId, processedQuery, paramValues); + + return { + data: result.rows, + rowCount: result.rowCount, + executionTime: result.executionTime, + }; + } }; // Создаем асинхронную функцию из кода пользователя @@ -149,21 +179,6 @@ print(json.dumps(result)) } const allParams = { ...context.requestParams, ...request.additional_params }; - - // Преобразуем параметры - let processedQuery = query.sql; - const paramValues: any[] = []; - const paramMatches = query.sql.match(/\$\w+/g) || []; - const uniqueParams = [...new Set(paramMatches.map(p => p.substring(1)))]; - - uniqueParams.forEach((paramName, index) => { - const regex = new RegExp(`\\$${paramName}\\b`, 'g'); - processedQuery = processedQuery.replace(regex, `$${index + 1}`); - const value = allParams[paramName]; - paramValues.push(value !== undefined ? value : null); - }); - - // Используем database_id из запроса, если указан, иначе из контекста const dbId = (query as any).database_id || context.databaseId; if (!dbId) { @@ -173,17 +188,65 @@ print(json.dumps(result)) continue; } - const result = await sqlExecutor.executeQuery( - dbId, - processedQuery, - paramValues - ); + // Получаем конфигурацию базы данных для определения типа + const dbConfig = await databasePoolManager.getDatabaseConfig(dbId); + if (!dbConfig) { + python.stdin.write(JSON.stringify({ + error: `Database configuration not found for ID: ${dbId}` + }) + '\n'); + continue; + } - python.stdin.write(JSON.stringify({ - data: result.rows, - rowCount: result.rowCount, - executionTime: result.executionTime, - }) + '\n'); + // Проверяем тип базы данных и выполняем соответствующий запрос + if (dbConfig.type === 'aql') { + // AQL запрос + const result = await aqlExecutor.executeAqlQuery(dbId, { + method: query.aql_method || 'GET', + endpoint: query.aql_endpoint || '', + body: query.aql_body || '', + queryParams: query.aql_query_params || {}, + parameters: allParams, + }); + + python.stdin.write(JSON.stringify({ + data: result.rows, + rowCount: result.rowCount, + executionTime: result.executionTime, + }) + '\n'); + } else { + // SQL запрос + if (!query.sql) { + python.stdin.write(JSON.stringify({ + error: `SQL query is required for database '${dbConfig.name}' (type: ${dbConfig.type})` + }) + '\n'); + continue; + } + + // Преобразуем параметры + let processedQuery = query.sql; + const paramValues: any[] = []; + const paramMatches = query.sql.match(/\$\w+/g) || []; + const uniqueParams = [...new Set(paramMatches.map(p => p.substring(1)))]; + + uniqueParams.forEach((paramName, index) => { + const regex = new RegExp(`\\$${paramName}\\b`, 'g'); + processedQuery = processedQuery.replace(regex, `$${index + 1}`); + const value = allParams[paramName]; + paramValues.push(value !== undefined ? value : null); + }); + + const result = await sqlExecutor.executeQuery( + dbId, + processedQuery, + paramValues + ); + + python.stdin.write(JSON.stringify({ + data: result.rows, + rowCount: result.rowCount, + executionTime: result.executionTime, + }) + '\n'); + } } catch (error: any) { python.stdin.write(JSON.stringify({ error: error.message }) + '\n'); } diff --git a/backend/src/types/index.ts b/backend/src/types/index.ts index 795dbff..746e472 100644 --- a/backend/src/types/index.ts +++ b/backend/src/types/index.ts @@ -86,8 +86,13 @@ export interface EndpointParameter { export interface ScriptQuery { name: string; - sql: string; + sql?: string; database_id?: string; + // AQL fields for script queries + aql_method?: 'GET' | 'POST' | 'PUT' | 'DELETE'; + aql_endpoint?: string; + aql_body?: string; + aql_query_params?: Record; } export interface QueryResult { diff --git a/frontend/src/components/CodeEditor.tsx b/frontend/src/components/CodeEditor.tsx index 0c7e812..2558d4f 100644 --- a/frontend/src/components/CodeEditor.tsx +++ b/frontend/src/components/CodeEditor.tsx @@ -3,7 +3,7 @@ import Editor from '@monaco-editor/react'; interface CodeEditorProps { value: string; onChange: (value: string) => void; - language: 'javascript' | 'python'; + language: 'javascript' | 'python' | 'json'; height?: string; } diff --git a/frontend/src/components/EndpointModal.tsx b/frontend/src/components/EndpointModal.tsx index 3695272..d16d2e1 100644 --- a/frontend/src/components/EndpointModal.tsx +++ b/frontend/src/components/EndpointModal.tsx @@ -377,38 +377,43 @@ export default function EndpointModal({
- +
Используйте $параметр в JSON для подстановки
-