modified: backend/src/services/DatabasePoolManager.ts

modified:   backend/src/services/ScriptExecutor.ts
	modified:   backend/src/types/index.ts
	modified:   frontend/src/components/CodeEditor.tsx
	modified:   frontend/src/components/EndpointModal.tsx
	deleted:    frontend/src/pages/Databases.tsx
	modified:   frontend/src/pages/Settings.tsx
	modified:   frontend/src/types/index.ts
This commit is contained in:
GEgorov
2025-10-07 20:16:53 +03:00
parent 65e4f5b423
commit c85fa20634
8 changed files with 311 additions and 562 deletions

View File

@@ -80,6 +80,38 @@ class DatabasePoolManager {
return this.pools.get(databaseId);
}
async getDatabaseConfig(databaseId: string): Promise<DatabaseConfig | null> {
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<DatabaseConfig[]> {
try {
const result = await mainPool.query(

View File

@@ -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');
}

View File

@@ -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<string, string>;
}
export interface QueryResult {