diff --git a/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/ISqlObjectManagerAppService.cs b/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/ISqlObjectManagerAppService.cs
index e17904e..adef427 100644
--- a/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/ISqlObjectManagerAppService.cs
+++ b/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/ISqlObjectManagerAppService.cs
@@ -1,4 +1,3 @@
-using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
@@ -6,47 +5,26 @@ using Volo.Abp.Application.Services;
namespace Sozsoft.SqlQueryManager.Application.Contracts;
///
-/// Unified service for SQL Object Explorer and CRUD operations
+/// SQL Query Manager - executes T-SQL and provides database metadata.
+/// Does not persist SQL objects to its own tables.
///
public interface ISqlObjectManagerAppService : IApplicationService
{
///
- /// Get all SQL objects for Object Explorer (Queries, SPs, Views, Functions, Tables, Templates)
+ /// Returns tables (and optionally templates) available on the given data source.
///
- /// Data source code to filter objects
- /// Combined response with all object types
Task GetAllObjectsAsync(string dataSourceCode);
- // Query Operations
- Task CreateQueryAsync(CreateSqlQueryDto input);
- Task UpdateQueryAsync(Guid id, UpdateSqlQueryDto input);
- Task DeleteQueryAsync(Guid id);
+ ///
+ /// Executes raw T-SQL against the specified data source.
+ ///
Task ExecuteQueryAsync(ExecuteSqlQueryDto input);
- Task ExecuteSavedQueryAsync(Guid id);
-
- // Stored Procedure Operations
- Task UpdateStoredProcedureAsync(Guid id, UpdateSqlStoredProcedureDto input);
- Task DeleteStoredProcedureAsync(Guid id);
- Task DeployStoredProcedureAsync(DeployStoredProcedureDto input);
-
- // View Operations
- Task UpdateViewAsync(Guid id, UpdateSqlViewDto input);
- Task DeleteViewAsync(Guid id);
- Task DeployViewAsync(DeployViewDto input);
-
- // Function Operations
- Task UpdateFunctionAsync(Guid id, UpdateSqlFunctionDto input);
- Task DeleteFunctionAsync(Guid id);
- Task DeployFunctionAsync(DeployFunctionDto input);
// Database Metadata Operations
Task> GetTableColumnsAsync(string dataSourceCode, string schemaName, string tableName);
-
+
///
/// Gets the SQL definition/body of a native SQL Server object (Stored Procedure, View, or Function)
///
Task GetNativeObjectDefinitionAsync(string dataSourceCode, string schemaName, string objectName);
-
- // Smart Save - Analyzes SQL and saves to appropriate table with auto-deploy
- Task SmartSaveAsync(SmartSaveInputDto input);
}
diff --git a/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/SmartSaveDto.cs b/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/SmartSaveDto.cs
deleted file mode 100644
index 7b3b3b9..0000000
--- a/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/SmartSaveDto.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System;
-
-namespace Sozsoft.SqlQueryManager.Application.Contracts;
-
-///
-/// Input for smart save operation
-///
-public class SmartSaveInputDto
-{
- public string SqlText { get; set; }
- public string DataSourceCode { get; set; }
- public string Name { get; set; }
- public string Description { get; set; }
-}
-
-///
-/// Result of smart save operation
-///
-public class SmartSaveResultDto
-{
- public string ObjectType { get; set; }
- public Guid ObjectId { get; set; }
- public bool Deployed { get; set; }
- public string Message { get; set; }
-}
diff --git a/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/SqlExecutionDto.cs b/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/SqlExecutionDto.cs
new file mode 100644
index 0000000..e180eaf
--- /dev/null
+++ b/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/SqlExecutionDto.cs
@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+
+namespace Sozsoft.SqlQueryManager.Application.Contracts;
+
+public class ExecuteSqlQueryDto
+{
+ public string QueryText { get; set; }
+ public string DataSourceCode { get; set; }
+ public Dictionary Parameters { get; set; }
+}
+
+public class SqlQueryExecutionResultDto
+{
+ public bool Success { get; set; }
+ public string Message { get; set; }
+ public IEnumerable Data { get; set; }
+ public int RowsAffected { get; set; }
+ public long ExecutionTimeMs { get; set; }
+ public Dictionary Metadata { get; set; }
+}
diff --git a/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/SqlFunctionDto.cs b/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/SqlFunctionDto.cs
deleted file mode 100644
index 8c0aa01..0000000
--- a/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/SqlFunctionDto.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Sozsoft.SqlQueryManager.Domain.Shared;
-using Volo.Abp.Application.Dtos;
-
-namespace Sozsoft.SqlQueryManager.Application.Contracts;
-
-public class SqlFunctionDto : FullAuditedEntityDto
-{
- public string FunctionName { get; set; }
- public string SchemaName { get; set; }
- public string DisplayName { get; set; }
- public string Description { get; set; }
- public SqlFunctionType FunctionType { get; set; }
- public string FunctionBody { get; set; }
- public string ReturnType { get; set; }
- public string DataSourceCode { get; set; }
- public SqlQueryStatus Status { get; set; }
- public string Category { get; set; }
- public bool IsDeployed { get; set; }
- public DateTime? LastDeployedAt { get; set; }
- public string Parameters { get; set; }
- public bool IsCustom { get; set; } // true = stored in database, false = native SQL Server object
-}
-
-public class CreateSqlFunctionDto
-{
- public string FunctionName { get; set; }
- public string SchemaName { get; set; }
- public string DisplayName { get; set; }
- public string Description { get; set; }
- public SqlFunctionType FunctionType { get; set; }
- public string FunctionBody { get; set; }
- public string ReturnType { get; set; }
- public string DataSourceCode { get; set; }
- public string Category { get; set; }
- public string Parameters { get; set; }
-}
-
-public class UpdateSqlFunctionDto
-{
- public string DisplayName { get; set; }
- public string Description { get; set; }
- public string FunctionBody { get; set; }
- public string ReturnType { get; set; }
- public string Category { get; set; }
- public string Parameters { get; set; }
-}
-
-public class DeployFunctionDto
-{
- public Guid Id { get; set; }
- public bool DropIfExists { get; set; }
-}
diff --git a/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/SqlObjectExplorerDto.cs b/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/SqlObjectExplorerDto.cs
index 453dd6d..513c0ae 100644
--- a/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/SqlObjectExplorerDto.cs
+++ b/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/SqlObjectExplorerDto.cs
@@ -3,37 +3,23 @@ using System.Collections.Generic;
namespace Sozsoft.SqlQueryManager.Application.Contracts;
///
-/// Combined DTO for Object Explorer containing all SQL objects
+/// A native SQL Server object (view, stored procedure, or function) discovered from system catalogs.
+///
+public class SqlNativeObjectDto
+{
+ public string SchemaName { get; set; } = "dbo";
+ public string ObjectName { get; set; } = "";
+ public string FullName => $"[{SchemaName}].[{ObjectName}]";
+}
+
+///
+/// Object Explorer DTO - reflects the live SQL Server catalog structure.
///
public class SqlObjectExplorerDto
{
- ///
- /// SQL Queries
- ///
- public List Queries { get; set; } = new();
-
- ///
- /// Stored Procedures
- ///
- public List StoredProcedures { get; set; } = new();
-
- ///
- /// Views
- ///
- public List Views { get; set; } = new();
-
- ///
- /// Functions
- ///
- public List Functions { get; set; } = new();
-
- ///
- /// Database Tables
- ///
public List Tables { get; set; } = new();
-
- ///
- /// Query Templates
- ///
+ public List Views { get; set; } = new();
+ public List StoredProcedures { get; set; } = new();
+ public List Functions { get; set; } = new();
public List Templates { get; set; } = new();
}
diff --git a/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/SqlQueryDto.cs b/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/SqlQueryDto.cs
deleted file mode 100644
index 0280be3..0000000
--- a/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/SqlQueryDto.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Sozsoft.SqlQueryManager.Domain.Shared;
-using Volo.Abp.Application.Dtos;
-
-namespace Sozsoft.SqlQueryManager.Application.Contracts;
-
-public class SqlQueryDto : FullAuditedEntityDto
-{
- public string Code { get; set; }
- public string Name { get; set; }
- public string Description { get; set; }
- public string QueryText { get; set; }
- public string DataSourceCode { get; set; }
- public SqlQueryStatus Status { get; set; }
- public string Category { get; set; }
- public string Tags { get; set; }
- public DateTime? LastExecutedAt { get; set; }
- public int ExecutionCount { get; set; }
- public bool IsModifyingData { get; set; }
- public string Parameters { get; set; }
-}
-
-public class CreateSqlQueryDto
-{
- public string Code { get; set; }
- public string Name { get; set; }
- public string Description { get; set; }
- public string QueryText { get; set; }
- public string DataSourceCode { get; set; }
- public string Category { get; set; }
- public string Tags { get; set; }
- public bool IsModifyingData { get; set; }
- public string Parameters { get; set; }
-}
-
-public class UpdateSqlQueryDto
-{
- public string Code { get; set; }
- public string Name { get; set; }
- public string Description { get; set; }
- public string QueryText { get; set; }
- public string DataSourceCode { get; set; }
- public string Category { get; set; }
- public string Tags { get; set; }
- public bool IsModifyingData { get; set; }
- public string Parameters { get; set; }
-}
-
-public class ExecuteSqlQueryDto
-{
- public string QueryText { get; set; }
- public string DataSourceCode { get; set; }
- public Dictionary Parameters { get; set; }
-}
-
-public class SqlQueryExecutionResultDto
-{
- public bool Success { get; set; }
- public string Message { get; set; }
- public IEnumerable Data { get; set; }
- public int RowsAffected { get; set; }
- public long ExecutionTimeMs { get; set; }
- public Dictionary Metadata { get; set; }
-}
diff --git a/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/SqlStoredProcedureDto.cs b/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/SqlStoredProcedureDto.cs
deleted file mode 100644
index 539cfd2..0000000
--- a/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/SqlStoredProcedureDto.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Sozsoft.SqlQueryManager.Domain.Shared;
-using Volo.Abp.Application.Dtos;
-
-namespace Sozsoft.SqlQueryManager.Application.Contracts;
-
-public class SqlStoredProcedureDto : FullAuditedEntityDto
-{
- public string ProcedureName { get; set; }
- public string SchemaName { get; set; }
- public string DisplayName { get; set; }
- public string Description { get; set; }
- public string ProcedureBody { get; set; }
- public string DataSourceCode { get; set; }
- public SqlQueryStatus Status { get; set; }
- public string Category { get; set; }
- public bool IsDeployed { get; set; }
- public DateTime? LastDeployedAt { get; set; }
- public string Parameters { get; set; }
- public bool IsCustom { get; set; } // true = stored in database, false = native SQL Server object
-}
-
-public class CreateSqlStoredProcedureDto
-{
- public string ProcedureName { get; set; }
- public string SchemaName { get; set; }
- public string DisplayName { get; set; }
- public string Description { get; set; }
- public string ProcedureBody { get; set; }
- public string DataSourceCode { get; set; }
- public string Category { get; set; }
- public string Parameters { get; set; }
-}
-
-public class UpdateSqlStoredProcedureDto
-{
- public string DisplayName { get; set; }
- public string Description { get; set; }
- public string ProcedureBody { get; set; }
- public string Category { get; set; }
- public string Parameters { get; set; }
-}
-
-public class DeployStoredProcedureDto
-{
- public Guid Id { get; set; }
- public bool DropIfExists { get; set; }
-}
diff --git a/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/SqlViewDto.cs b/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/SqlViewDto.cs
deleted file mode 100644
index 9cb91c3..0000000
--- a/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application.Contracts/SqlViewDto.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Sozsoft.SqlQueryManager.Domain.Shared;
-using Volo.Abp.Application.Dtos;
-
-namespace Sozsoft.SqlQueryManager.Application.Contracts;
-
-public class SqlViewDto : FullAuditedEntityDto
-{
- public string ViewName { get; set; }
- public string SchemaName { get; set; }
- public string DisplayName { get; set; }
- public string Description { get; set; }
- public string ViewDefinition { get; set; }
- public string DataSourceCode { get; set; }
- public SqlQueryStatus Status { get; set; }
- public string Category { get; set; }
- public bool IsDeployed { get; set; }
- public DateTime? LastDeployedAt { get; set; }
- public bool WithSchemaBinding { get; set; }
- public bool IsCustom { get; set; } // true = stored in database, false = native SQL Server object
-}
-
-public class CreateSqlViewDto
-{
- public string ViewName { get; set; }
- public string SchemaName { get; set; }
- public string DisplayName { get; set; }
- public string Description { get; set; }
- public string ViewDefinition { get; set; }
- public string DataSourceCode { get; set; }
- public string Category { get; set; }
- public bool WithSchemaBinding { get; set; }
-}
-
-public class UpdateSqlViewDto
-{
- public string DisplayName { get; set; }
- public string Description { get; set; }
- public string ViewDefinition { get; set; }
- public string Category { get; set; }
- public bool WithSchemaBinding { get; set; }
-}
-
-public class DeployViewDto
-{
- public Guid Id { get; set; }
- public bool DropIfExists { get; set; }
-}
diff --git a/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application/SqlObjectManagerAppService.cs b/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application/SqlObjectManagerAppService.cs
index feec6ec..8d40c06 100644
--- a/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application/SqlObjectManagerAppService.cs
+++ b/api/modules/Sozsoft.SqlQueryManager/Sozsoft.SqlQueryManager.Application/SqlObjectManagerAppService.cs
@@ -1,52 +1,34 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
-using System.Security.Cryptography;
-using System.Text;
using System.Threading.Tasks;
using Sozsoft.SqlQueryManager.Application.Contracts;
-using Sozsoft.SqlQueryManager.Domain.Entities;
using Sozsoft.SqlQueryManager.Domain.Services;
-using Sozsoft.SqlQueryManager.Domain.Shared;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Volo.Abp.Application.Services;
-using Volo.Abp.Domain.Repositories;
using Volo.Abp.MultiTenancy;
namespace Sozsoft.SqlQueryManager.Application;
///
-/// Unified service for SQL Object Explorer
-/// Combines all SQL objects into a single endpoint
+/// Executes T-SQL against configured data sources and exposes database metadata.
+/// Does not persist SQL objects (queries, procedures, views, functions) to its own tables.
///
[Authorize("App.SqlQueryManager")]
public class SqlObjectManagerAppService : ApplicationService, ISqlObjectManagerAppService
{
- private readonly IRepository _queryRepository;
- private readonly IRepository _procedureRepository;
- private readonly IRepository _viewRepository;
- private readonly IRepository _functionRepository;
private readonly ISqlExecutorService _sqlExecutorService;
private readonly ISqlTemplateProvider _templateProvider;
private readonly ICurrentTenant _currentTenant;
private readonly IHttpContextAccessor _httpContextAccessor;
public SqlObjectManagerAppService(
- IRepository queryRepository,
- IRepository procedureRepository,
- IRepository viewRepository,
- IRepository functionRepository,
ISqlExecutorService sqlExecutorService,
ISqlTemplateProvider templateProvider,
ICurrentTenant currentTenant,
- IHttpContextAccessor httpContextAccessor
- )
+ IHttpContextAccessor httpContextAccessor)
{
- _queryRepository = queryRepository;
- _procedureRepository = procedureRepository;
- _viewRepository = viewRepository;
- _functionRepository = functionRepository;
_sqlExecutorService = sqlExecutorService;
_templateProvider = templateProvider;
_currentTenant = currentTenant;
@@ -80,41 +62,11 @@ public class SqlObjectManagerAppService : ApplicationService, ISqlObjectManagerA
ValidateTenantAccess();
var result = new SqlObjectExplorerDto();
- // Get all queries for this data source
- var queries = await _queryRepository.GetListAsync();
- result.Queries = queries
- .Where(q => q.DataSourceCode == dataSourceCode)
- .Select(q => new SqlQueryDto
- {
- Id = q.Id,
- Code = q.Code,
- Name = q.Name,
- Description = q.Description,
- QueryText = q.QueryText,
- DataSourceCode = q.DataSourceCode,
- Status = q.Status,
- Category = q.Category,
- Tags = q.Tags,
- IsModifyingData = q.IsModifyingData,
- Parameters = q.Parameters,
- ExecutionCount = q.ExecutionCount,
- LastExecutedAt = q.LastExecutedAt
- })
- .ToList();
-
- // Get all stored procedures for this data source (custom + native merged)
- result.StoredProcedures = await GetMergedStoredProceduresAsync(dataSourceCode);
-
- // Get all views for this data source (custom + native merged)
- result.Views = await GetMergedViewsAsync(dataSourceCode);
-
- // Get all functions for this data source (custom + native merged)
- result.Functions = await GetMergedFunctionsAsync(dataSourceCode);
-
- // Get all database tables
result.Tables = await GetTablesAsync(dataSourceCode);
+ result.Views = await GetNativeObjectsAsync(dataSourceCode, "V");
+ result.StoredProcedures = await GetNativeObjectsAsync(dataSourceCode, "P");
+ result.Functions = await GetNativeObjectsAsync(dataSourceCode, "FN", "IF", "TF");
- // Get all templates
result.Templates = _templateProvider.GetAvailableQueryTemplates()
.Select(t => new SqlTemplateDto
{
@@ -128,6 +80,43 @@ public class SqlObjectManagerAppService : ApplicationService, ISqlObjectManagerA
return result;
}
+ private async Task> GetNativeObjectsAsync(string dataSourceCode, params string[] objectTypes)
+ {
+ var typeList = string.Join(",", objectTypes.Select(t => $"'{t}'"));
+ var query = $@"
+ SELECT
+ SCHEMA_NAME(o.schema_id) AS SchemaName,
+ o.name AS ObjectName
+ FROM
+ sys.objects o
+ WHERE
+ o.type IN ({typeList})
+ AND o.is_ms_shipped = 0
+ ORDER BY
+ SCHEMA_NAME(o.schema_id), o.name";
+
+ var result = await _sqlExecutorService.ExecuteQueryAsync(query, dataSourceCode);
+
+ var objects = new List();
+ if (result.Success && result.Data != null)
+ {
+ foreach (var row in result.Data)
+ {
+ var dict = row as IDictionary;
+ if (dict != null)
+ {
+ objects.Add(new SqlNativeObjectDto
+ {
+ SchemaName = dict["SchemaName"]?.ToString() ?? "dbo",
+ ObjectName = dict["ObjectName"]?.ToString() ?? ""
+ });
+ }
+ }
+ }
+
+ return objects;
+ }
+
private async Task> GetTablesAsync(string dataSourceCode)
{
var query = @"
@@ -148,7 +137,7 @@ public class SqlObjectManagerAppService : ApplicationService, ISqlObjectManagerA
{
foreach (var row in result.Data)
{
- var dict = row as System.Collections.Generic.IDictionary;
+ var dict = row as IDictionary;
if (dict != null)
{
tables.Add(new DatabaseTableDto
@@ -163,581 +152,16 @@ public class SqlObjectManagerAppService : ApplicationService, ISqlObjectManagerA
return tables;
}
- private async Task> GetMergedStoredProceduresAsync(string dataSourceCode)
- {
- // Get custom stored procedures from database
- var customProcedures = await _procedureRepository.GetListAsync();
- var customList = customProcedures
- .Where(p => p.DataSourceCode == dataSourceCode)
- .Select(p => new SqlStoredProcedureDto
- {
- Id = p.Id,
- ProcedureName = p.ProcedureName,
- SchemaName = p.SchemaName,
- DisplayName = $"{p.SchemaName}.{p.ProcedureName}",
- Description = p.Description,
- ProcedureBody = p.ProcedureBody,
- DataSourceCode = p.DataSourceCode,
- Category = p.Category,
- Parameters = p.Parameters,
- IsDeployed = p.IsDeployed,
- LastDeployedAt = p.LastDeployedAt,
- IsCustom = true
- })
- .ToList();
-
- // Get native stored procedures from SQL Server
- var nativeQuery = @"
- SELECT
- SCHEMA_NAME(p.schema_id) AS SchemaName,
- p.name AS ProcedureName,
- p.create_date AS CreatedDate,
- p.modify_date AS ModifiedDate
- FROM
- sys.procedures p
- WHERE
- p.is_ms_shipped = 0
- ORDER BY
- SCHEMA_NAME(p.schema_id), p.name";
-
- var result = await _sqlExecutorService.ExecuteQueryAsync(nativeQuery, dataSourceCode);
- var nativeList = new List();
-
- if (result.Success && result.Data != null)
- {
- foreach (var row in result.Data)
- {
- var dict = row as System.Collections.Generic.IDictionary;
- if (dict != null)
- {
- var schemaName = dict["SchemaName"]?.ToString() ?? "dbo";
- var procName = dict["ProcedureName"]?.ToString() ?? "";
-
- // Skip if already exists in custom list
- if (!customList.Any(c => c.SchemaName == schemaName && c.ProcedureName == procName))
- {
- // Generate deterministic GUID from schema and name to ensure uniqueness
- var uniqueId = GenerateDeterministicGuid($"SP_{dataSourceCode}_{schemaName}_{procName}");
-
- nativeList.Add(new SqlStoredProcedureDto
- {
- Id = uniqueId,
- SchemaName = schemaName,
- ProcedureName = procName,
- DisplayName = $"{schemaName}.{procName}",
- DataSourceCode = dataSourceCode,
- IsCustom = false,
- IsDeployed = true // Native objects are already deployed
- });
- }
- }
- }
- }
-
- // Merge and return
- return customList.Concat(nativeList).ToList();
- }
-
- private async Task> GetMergedViewsAsync(string dataSourceCode)
- {
- // Get custom views from database
- var customViews = await _viewRepository.GetListAsync();
- var customList = customViews
- .Where(v => v.DataSourceCode == dataSourceCode)
- .Select(v => new SqlViewDto
- {
- Id = v.Id,
- ViewName = v.ViewName,
- SchemaName = v.SchemaName,
- DisplayName = $"{v.SchemaName}.{v.ViewName}",
- Description = v.Description,
- ViewDefinition = v.ViewDefinition,
- DataSourceCode = v.DataSourceCode,
- Category = v.Category,
- WithSchemaBinding = v.WithSchemaBinding,
- IsDeployed = v.IsDeployed,
- LastDeployedAt = v.LastDeployedAt,
- IsCustom = true
- })
- .ToList();
-
- // Get native views from SQL Server
- var nativeQuery = @"
- SELECT
- SCHEMA_NAME(v.schema_id) AS SchemaName,
- v.name AS ViewName,
- v.create_date AS CreatedDate,
- v.modify_date AS ModifiedDate
- FROM
- sys.views v
- WHERE
- v.is_ms_shipped = 0
- ORDER BY
- SCHEMA_NAME(v.schema_id), v.name";
-
- var result = await _sqlExecutorService.ExecuteQueryAsync(nativeQuery, dataSourceCode);
- var nativeList = new List();
-
- if (result.Success && result.Data != null)
- {
- foreach (var row in result.Data)
- {
- var dict = row as System.Collections.Generic.IDictionary;
- if (dict != null)
- {
- var schemaName = dict["SchemaName"]?.ToString() ?? "dbo";
- var viewName = dict["ViewName"]?.ToString() ?? "";
-
- // Skip if already exists in custom list
- if (!customList.Any(c => c.SchemaName == schemaName && c.ViewName == viewName))
- {
- // Generate deterministic GUID from schema and name to ensure uniqueness
- var uniqueId = GenerateDeterministicGuid($"VIEW_{dataSourceCode}_{schemaName}_{viewName}");
-
- nativeList.Add(new SqlViewDto
- {
- Id = uniqueId,
- SchemaName = schemaName,
- ViewName = viewName,
- DisplayName = $"{schemaName}.{viewName}",
- DataSourceCode = dataSourceCode,
- IsCustom = false,
- IsDeployed = true
- });
- }
- }
- }
- }
-
- return customList.Concat(nativeList).ToList();
- }
-
- private async Task> GetMergedFunctionsAsync(string dataSourceCode)
- {
- // Get custom functions from database
- var customFunctions = await _functionRepository.GetListAsync();
- var customList = customFunctions
- .Where(f => f.DataSourceCode == dataSourceCode)
- .Select(f => new SqlFunctionDto
- {
- Id = f.Id,
- FunctionName = f.FunctionName,
- SchemaName = f.SchemaName,
- DisplayName = $"[{f.SchemaName}].[{f.FunctionName}]",
- Description = f.Description,
- FunctionType = f.FunctionType,
- FunctionBody = f.FunctionBody,
- ReturnType = f.ReturnType,
- DataSourceCode = f.DataSourceCode,
- Category = f.Category,
- Parameters = f.Parameters,
- IsDeployed = f.IsDeployed,
- LastDeployedAt = f.LastDeployedAt,
- IsCustom = true
- })
- .ToList();
-
- // Get native functions from SQL Server
- var nativeQuery = @"
- SELECT
- SCHEMA_NAME(o.schema_id) AS SchemaName,
- o.name AS FunctionName,
- o.create_date AS CreatedDate,
- o.modify_date AS ModifiedDate,
- CASE o.type
- WHEN 'FN' THEN 'Scalar'
- WHEN 'IF' THEN 'InlineTableValued'
- WHEN 'TF' THEN 'TableValued'
- ELSE 'Unknown'
- END AS FunctionType
- FROM
- sys.objects o
- WHERE
- o.type IN ('FN', 'IF', 'TF')
- AND o.is_ms_shipped = 0
- ORDER BY
- SCHEMA_NAME(o.schema_id), o.name";
-
- var result = await _sqlExecutorService.ExecuteQueryAsync(nativeQuery, dataSourceCode);
- var nativeList = new List();
-
- if (result.Success && result.Data != null)
- {
- foreach (var row in result.Data)
- {
- var dict = row as System.Collections.Generic.IDictionary;
- if (dict != null)
- {
- var schemaName = dict["SchemaName"]?.ToString() ?? "dbo";
- var funcName = dict["FunctionName"]?.ToString() ?? "";
-
- // Skip if already exists in custom list
- if (!customList.Any(c => c.SchemaName == schemaName && c.FunctionName == funcName))
- {
- var funcTypeStr = dict["FunctionType"]?.ToString() ?? "Scalar";
- var funcType = funcTypeStr == "Scalar" ? SqlFunctionType.ScalarFunction :
- funcTypeStr == "InlineTableValued" ? SqlFunctionType.InlineTableValuedFunction :
- SqlFunctionType.TableValuedFunction;
-
- // Generate deterministic GUID from schema and name to ensure uniqueness
- var uniqueId = GenerateDeterministicGuid($"FUNC_{dataSourceCode}_{schemaName}_{funcName}");
-
- nativeList.Add(new SqlFunctionDto
- {
- Id = uniqueId,
- SchemaName = schemaName,
- FunctionName = funcName,
- DisplayName = $"{schemaName}.{funcName}",
- DataSourceCode = dataSourceCode,
- FunctionType = funcType,
- IsCustom = false,
- IsDeployed = true
- });
- }
- }
- }
- }
-
- return customList.Concat(nativeList).ToList();
- }
-
- #region Query Operations
-
- public async Task CreateQueryAsync(CreateSqlQueryDto input)
- {
- ValidateTenantAccess();
-
- var query = ObjectMapper.Map(input);
- query.Status = SqlQueryStatus.Draft;
-
- var created = await _queryRepository.InsertAsync(query, autoSave: true);
- return ObjectMapper.Map(created);
- }
-
- public async Task UpdateQueryAsync(Guid id, UpdateSqlQueryDto input)
- {
- ValidateTenantAccess();
- var query = await _queryRepository.GetAsync(id);
-
- query.Name = input.Name;
- query.Description = input.Description;
- query.QueryText = input.QueryText;
- query.Category = input.Category;
- query.Tags = input.Tags;
-
- var updated = await _queryRepository.UpdateAsync(query, autoSave: true);
- return ObjectMapper.Map(updated);
- }
-
- public async Task DeleteQueryAsync(Guid id)
- {
- ValidateTenantAccess();
- await _queryRepository.DeleteAsync(id);
- }
-
public async Task ExecuteQueryAsync(ExecuteSqlQueryDto input)
{
ValidateTenantAccess();
- var sqlText = input.QueryText.Trim();
- var sqlUpper = sqlText.ToUpperInvariant();
-
- // Check if this is a DDL command (CREATE/ALTER/DROP for VIEW/PROCEDURE/FUNCTION)
- bool isDDLCommand =
- sqlUpper.Contains("CREATE VIEW") || sqlUpper.Contains("ALTER VIEW") ||
- sqlUpper.Contains("CREATE PROCEDURE") || sqlUpper.Contains("CREATE PROC") ||
- sqlUpper.Contains("ALTER PROCEDURE") || sqlUpper.Contains("ALTER PROC") ||
- sqlUpper.Contains("CREATE FUNCTION") || sqlUpper.Contains("ALTER FUNCTION") ||
- sqlUpper.Contains("DROP VIEW") || sqlUpper.Contains("DROP PROCEDURE") ||
- sqlUpper.Contains("DROP PROC") || sqlUpper.Contains("DROP FUNCTION");
-
- if (isDDLCommand)
- {
- // For DDL commands, only validate syntax without executing
- try
- {
- // Try to parse/validate the SQL using SET PARSEONLY
- var validationSql = $"SET PARSEONLY ON;\n{sqlText}\nSET PARSEONLY OFF;";
- await _sqlExecutorService.ExecuteNonQueryAsync(validationSql, input.DataSourceCode);
-
- return new SqlQueryExecutionResultDto
- {
- Success = true,
- Message = "SQL syntax is valid. Use Save button to save and Deploy button to create in SQL Server.",
- Data = new List