From 3d419a6e7cdc426f7234333125f7a8ff57339a94 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sedat=20=C3=96ZT=C3=9CRK?=
<76204082+iamsedatozturk@users.noreply.github.com>
Date: Fri, 5 Dec 2025 11:56:53 +0300
Subject: [PATCH] Sql Query Manager
---
api/Erp.Platform.sln | 40 +-
...lQueryManager.Application.Contracts.csproj | 16 +
.../FodyWeavers.xml | 3 +
.../FodyWeavers.xsd | 30 ++
.../ISqlFunctionAppService.cs | 29 ++
.../ISqlQueryAppService.cs | 39 ++
.../ISqlStoredProcedureAppService.cs | 29 ++
.../ISqlTemplateAppService.cs | 34 ++
.../ISqlViewAppService.cs | 29 ++
.../SqlFunctionDto.cs | 53 +++
.../SqlQueryDto.cs | 65 +++
...lQueryManagerApplicationContractsModule.cs | 14 +
.../SqlStoredProcedureDto.cs | 48 +++
.../SqlTemplateDto.cs | 18 +
.../SqlViewDto.cs | 48 +++
.../Erp.SqlQueryManager.Application.csproj | 18 +
.../FodyWeavers.xml | 3 +
.../FodyWeavers.xsd | 30 ++
.../SqlFunctionAppService.cs | 139 ++++++
.../SqlQueryAppService.cs | 124 ++++++
.../SqlQueryManagerApplicationModule.cs | 25 ++
.../SqlQueryManagerAutoMapperProfile.cs | 87 ++++
.../SqlStoredProcedureAppService.cs | 134 ++++++
.../SqlTemplateAppService.cs | 59 +++
.../SqlViewAppService.cs | 133 ++++++
.../Erp.SqlQueryManager.Domain.Shared.csproj | 24 ++
.../ErpSqlQueryManagerResource.cs | 8 +
.../FodyWeavers.xml | 3 +
.../FodyWeavers.xsd | 30 ++
.../SqlObjectType.cs | 23 +
.../SqlQueryManagerDomainSharedModule.cs | 34 ++
.../SqlQueryManagerErrorCodes.cs | 11 +
.../SqlQueryManagerPermissions.cs | 57 +++
.../Entities/SqlFunction.cs | 120 ++++++
.../Entities/SqlQuery.cs | 116 +++++
.../Entities/SqlStoredProcedure.cs | 106 +++++
.../Entities/SqlView.cs | 107 +++++
.../Erp.SqlQueryManager.Domain.csproj | 16 +
.../FodyWeavers.xml | 3 +
.../FodyWeavers.xsd | 30 ++
.../Services/ISqlExecutorService.cs | 96 +++++
.../Services/ISqlTemplateProvider.cs | 42 ++
.../Services/SqlExecutorService.cs | 301 +++++++++++++
.../Services/SqlTemplateProvider.cs | 395 +++++++++++++++++
.../SqlQueryManagerDbProperties.cs | 19 +
.../SqlQueryManagerDomainModule.cs | 17 +
...SqlQueryManager.EntityFrameworkCore.csproj | 15 +
.../FodyWeavers.xml | 3 +
.../FodyWeavers.xsd | 30 ++
.../SqlQueryManagerDbContext.cs | 27 ++
...ManagerDbContextModelCreatingExtensions.cs | 104 +++++
...qlQueryManagerEntityFrameworkCoreModule.cs | 20 +
api/modules/Erp.SqlQueryManager/common.props | 24 ++
.../EntityFrameworkCore/PlatformDbContext.cs | 2 +
.../PlatformEntityFrameworkCoreModule.cs | 4 +-
.../Erp.Platform.EntityFrameworkCore.csproj | 1 +
....cs => 20251205085044_Initial.Designer.cs} | 405 +++++++++++++++++-
...8_Initial.cs => 20251205085044_Initial.cs} | 220 ++++++++++
.../PlatformDbContextModelSnapshot.cs | 403 +++++++++++++++++
.../Erp.Platform.HttpApi.Host.csproj | 2 +-
.../PlatformHttpApiHostModule.cs | 6 +-
61 files changed, 4064 insertions(+), 7 deletions(-)
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/Erp.SqlQueryManager.Application.Contracts.csproj
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/FodyWeavers.xml
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/FodyWeavers.xsd
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/ISqlFunctionAppService.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/ISqlQueryAppService.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/ISqlStoredProcedureAppService.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/ISqlTemplateAppService.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/ISqlViewAppService.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlFunctionDto.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlQueryDto.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlQueryManagerApplicationContractsModule.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlStoredProcedureDto.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlTemplateDto.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlViewDto.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/Erp.SqlQueryManager.Application.csproj
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/FodyWeavers.xml
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/FodyWeavers.xsd
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlFunctionAppService.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlQueryAppService.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlQueryManagerApplicationModule.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlQueryManagerAutoMapperProfile.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlStoredProcedureAppService.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlTemplateAppService.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlViewAppService.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/Erp.SqlQueryManager.Domain.Shared.csproj
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/ErpSqlQueryManagerResource.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/FodyWeavers.xml
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/FodyWeavers.xsd
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/SqlObjectType.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/SqlQueryManagerDomainSharedModule.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/SqlQueryManagerErrorCodes.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/SqlQueryManagerPermissions.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Entities/SqlFunction.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Entities/SqlQuery.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Entities/SqlStoredProcedure.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Entities/SqlView.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Erp.SqlQueryManager.Domain.csproj
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/FodyWeavers.xml
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/FodyWeavers.xsd
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Services/ISqlExecutorService.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Services/ISqlTemplateProvider.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Services/SqlExecutorService.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Services/SqlTemplateProvider.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/SqlQueryManagerDbProperties.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/SqlQueryManagerDomainModule.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/Erp.SqlQueryManager.EntityFrameworkCore.csproj
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/FodyWeavers.xml
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/FodyWeavers.xsd
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/SqlQueryManagerDbContext.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/SqlQueryManagerDbContextModelCreatingExtensions.cs
create mode 100644 api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/SqlQueryManagerEntityFrameworkCoreModule.cs
create mode 100644 api/modules/Erp.SqlQueryManager/common.props
rename api/src/Erp.Platform.EntityFrameworkCore/Migrations/{20251204192908_Initial.Designer.cs => 20251205085044_Initial.Designer.cs} (98%)
rename api/src/Erp.Platform.EntityFrameworkCore/Migrations/{20251204192908_Initial.cs => 20251205085044_Initial.cs} (97%)
diff --git a/api/Erp.Platform.sln b/api/Erp.Platform.sln
index b88e9b38..e8dba0e3 100644
--- a/api/Erp.Platform.sln
+++ b/api/Erp.Platform.sln
@@ -80,6 +80,18 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
README.md = README.md
EndProjectSection
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Erp.SqlQueryManager", "Erp.SqlQueryManager", "{2889482E-64CA-4A25-91D8-5B963D83681B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Erp.SqlQueryManager.Domain.Shared", "modules\Erp.SqlQueryManager\Erp.SqlQueryManager.Domain.Shared\Erp.SqlQueryManager.Domain.Shared.csproj", "{10D71F44-C9FD-41F2-8F1A-D93FAE3CE696}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Erp.SqlQueryManager.Domain", "modules\Erp.SqlQueryManager\Erp.SqlQueryManager.Domain\Erp.SqlQueryManager.Domain.csproj", "{8730045F-91F5-4438-8772-C6E31E89AACC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Erp.SqlQueryManager.Application.Contracts", "modules\Erp.SqlQueryManager\Erp.SqlQueryManager.Application.Contracts\Erp.SqlQueryManager.Application.Contracts.csproj", "{B45A3E8B-286B-4A74-9602-FC192ACEE8C4}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Erp.SqlQueryManager.Application", "modules\Erp.SqlQueryManager\Erp.SqlQueryManager.Application\Erp.SqlQueryManager.Application.csproj", "{ED9C639A-A706-4ECB-9638-A15B3681BDEC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Erp.SqlQueryManager.EntityFrameworkCore", "modules\Erp.SqlQueryManager\Erp.SqlQueryManager.EntityFrameworkCore\Erp.SqlQueryManager.EntityFrameworkCore.csproj", "{1DA666D8-DBFE-40F7-8EBF-95CC892E4EB6}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -198,6 +210,26 @@ Global
{D9E0D333-60F3-493F-A5B2-5758ACA42A17}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D9E0D333-60F3-493F-A5B2-5758ACA42A17}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D9E0D333-60F3-493F-A5B2-5758ACA42A17}.Release|Any CPU.Build.0 = Release|Any CPU
+ {10D71F44-C9FD-41F2-8F1A-D93FAE3CE696}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {10D71F44-C9FD-41F2-8F1A-D93FAE3CE696}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {10D71F44-C9FD-41F2-8F1A-D93FAE3CE696}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {10D71F44-C9FD-41F2-8F1A-D93FAE3CE696}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8730045F-91F5-4438-8772-C6E31E89AACC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8730045F-91F5-4438-8772-C6E31E89AACC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8730045F-91F5-4438-8772-C6E31E89AACC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8730045F-91F5-4438-8772-C6E31E89AACC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B45A3E8B-286B-4A74-9602-FC192ACEE8C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B45A3E8B-286B-4A74-9602-FC192ACEE8C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B45A3E8B-286B-4A74-9602-FC192ACEE8C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B45A3E8B-286B-4A74-9602-FC192ACEE8C4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {ED9C639A-A706-4ECB-9638-A15B3681BDEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {ED9C639A-A706-4ECB-9638-A15B3681BDEC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ED9C639A-A706-4ECB-9638-A15B3681BDEC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {ED9C639A-A706-4ECB-9638-A15B3681BDEC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1DA666D8-DBFE-40F7-8EBF-95CC892E4EB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1DA666D8-DBFE-40F7-8EBF-95CC892E4EB6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1DA666D8-DBFE-40F7-8EBF-95CC892E4EB6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1DA666D8-DBFE-40F7-8EBF-95CC892E4EB6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -236,10 +268,14 @@ Global
{631092C7-B59D-4EA7-92D0-5E181AB4F9F6} = {41A473FE-2537-4223-8CF3-A4A2A4A4F41E}
{23659070-58F7-403B-8973-B2E20B5E9BE1} = {41A473FE-2537-4223-8CF3-A4A2A4A4F41E}
{D9E0D333-60F3-493F-A5B2-5758ACA42A17} = {41A473FE-2537-4223-8CF3-A4A2A4A4F41E}
+ {2889482E-64CA-4A25-91D8-5B963D83681B} = {03E1C8DA-035E-4882-AF81-F392139FCF38}
+ {10D71F44-C9FD-41F2-8F1A-D93FAE3CE696} = {2889482E-64CA-4A25-91D8-5B963D83681B}
+ {8730045F-91F5-4438-8772-C6E31E89AACC} = {2889482E-64CA-4A25-91D8-5B963D83681B}
+ {B45A3E8B-286B-4A74-9602-FC192ACEE8C4} = {2889482E-64CA-4A25-91D8-5B963D83681B}
+ {ED9C639A-A706-4ECB-9638-A15B3681BDEC} = {2889482E-64CA-4A25-91D8-5B963D83681B}
+ {1DA666D8-DBFE-40F7-8EBF-95CC892E4EB6} = {2889482E-64CA-4A25-91D8-5B963D83681B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {28315BFD-90E7-4E14-A2EA-F3D23AF4126F}
EndGlobalSection
EndGlobal
-
-
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/Erp.SqlQueryManager.Application.Contracts.csproj b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/Erp.SqlQueryManager.Application.Contracts.csproj
new file mode 100644
index 00000000..eb7458db
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/Erp.SqlQueryManager.Application.Contracts.csproj
@@ -0,0 +1,16 @@
+
+
+
+
+
+ net9.0
+ Erp.SqlQueryManager
+
+
+
+
+
+
+
+
+
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/FodyWeavers.xml b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/FodyWeavers.xml
new file mode 100644
index 00000000..00e1d9a1
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/FodyWeavers.xsd b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/FodyWeavers.xsd
new file mode 100644
index 00000000..3f3946e2
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/ISqlFunctionAppService.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/ISqlFunctionAppService.cs
new file mode 100644
index 00000000..99179ef5
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/ISqlFunctionAppService.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Threading.Tasks;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Application.Services;
+
+namespace Erp.SqlQueryManager.Application.Contracts;
+
+public interface ISqlFunctionAppService : ICrudAppService<
+ SqlFunctionDto,
+ Guid,
+ PagedAndSortedResultRequestDto,
+ CreateSqlFunctionDto,
+ UpdateSqlFunctionDto>
+{
+ ///
+ /// Deploy function to database
+ ///
+ Task DeployAsync(DeployFunctionDto input);
+
+ ///
+ /// Check if function exists in database
+ ///
+ Task CheckExistsAsync(Guid id);
+
+ ///
+ /// Drop function from database
+ ///
+ Task DropAsync(Guid id);
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/ISqlQueryAppService.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/ISqlQueryAppService.cs
new file mode 100644
index 00000000..f7a0e794
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/ISqlQueryAppService.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Threading.Tasks;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Application.Services;
+
+namespace Erp.SqlQueryManager.Application.Contracts;
+
+public interface ISqlQueryAppService : ICrudAppService<
+ SqlQueryDto,
+ Guid,
+ PagedAndSortedResultRequestDto,
+ CreateSqlQueryDto,
+ UpdateSqlQueryDto>
+{
+ ///
+ /// Execute a SQL query
+ ///
+ Task ExecuteQueryAsync(ExecuteSqlQueryDto input);
+
+ ///
+ /// Execute a saved query by ID
+ ///
+ Task ExecuteSavedQueryAsync(Guid id);
+
+ ///
+ /// Validate SQL query syntax
+ ///
+ Task<(bool IsValid, string ErrorMessage)> ValidateQueryAsync(string sql);
+
+ ///
+ /// Activate query
+ ///
+ Task ActivateAsync(Guid id);
+
+ ///
+ /// Archive query
+ ///
+ Task ArchiveAsync(Guid id);
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/ISqlStoredProcedureAppService.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/ISqlStoredProcedureAppService.cs
new file mode 100644
index 00000000..48edcb87
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/ISqlStoredProcedureAppService.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Threading.Tasks;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Application.Services;
+
+namespace Erp.SqlQueryManager.Application.Contracts;
+
+public interface ISqlStoredProcedureAppService : ICrudAppService<
+ SqlStoredProcedureDto,
+ Guid,
+ PagedAndSortedResultRequestDto,
+ CreateSqlStoredProcedureDto,
+ UpdateSqlStoredProcedureDto>
+{
+ ///
+ /// Deploy stored procedure to database
+ ///
+ Task DeployAsync(DeployStoredProcedureDto input);
+
+ ///
+ /// Check if procedure exists in database
+ ///
+ Task CheckExistsAsync(Guid id);
+
+ ///
+ /// Drop procedure from database
+ ///
+ Task DropAsync(Guid id);
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/ISqlTemplateAppService.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/ISqlTemplateAppService.cs
new file mode 100644
index 00000000..9f192b33
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/ISqlTemplateAppService.cs
@@ -0,0 +1,34 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Erp.SqlQueryManager.Domain.Shared;
+using Volo.Abp.Application.Services;
+
+namespace Erp.SqlQueryManager.Application.Contracts;
+
+public interface ISqlTemplateAppService : IApplicationService
+{
+ ///
+ /// Get all available query templates
+ ///
+ Task> GetQueryTemplatesAsync();
+
+ ///
+ /// Get stored procedure template
+ ///
+ Task GetStoredProcedureTemplateAsync(string procedureName, string schemaName = "dbo");
+
+ ///
+ /// Get view template
+ ///
+ Task GetViewTemplateAsync(string viewName, string schemaName = "dbo", bool withSchemaBinding = false);
+
+ ///
+ /// Get function template
+ ///
+ Task GetFunctionTemplateAsync(string functionName, SqlFunctionType functionType, string schemaName = "dbo");
+
+ ///
+ /// Get specific query template
+ ///
+ Task GetQueryTemplateAsync(string templateType);
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/ISqlViewAppService.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/ISqlViewAppService.cs
new file mode 100644
index 00000000..4fb02584
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/ISqlViewAppService.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Threading.Tasks;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Application.Services;
+
+namespace Erp.SqlQueryManager.Application.Contracts;
+
+public interface ISqlViewAppService : ICrudAppService<
+ SqlViewDto,
+ Guid,
+ PagedAndSortedResultRequestDto,
+ CreateSqlViewDto,
+ UpdateSqlViewDto>
+{
+ ///
+ /// Deploy view to database
+ ///
+ Task DeployAsync(DeployViewDto input);
+
+ ///
+ /// Check if view exists in database
+ ///
+ Task CheckExistsAsync(Guid id);
+
+ ///
+ /// Drop view from database
+ ///
+ Task DropAsync(Guid id);
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlFunctionDto.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlFunctionDto.cs
new file mode 100644
index 00000000..785a704a
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlFunctionDto.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+using Erp.SqlQueryManager.Domain.Shared;
+using Volo.Abp.Application.Dtos;
+
+namespace Erp.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 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/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlQueryDto.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlQueryDto.cs
new file mode 100644
index 00000000..08870104
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlQueryDto.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+using Erp.SqlQueryManager.Domain.Shared;
+using Volo.Abp.Application.Dtos;
+
+namespace Erp.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/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlQueryManagerApplicationContractsModule.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlQueryManagerApplicationContractsModule.cs
new file mode 100644
index 00000000..f4bb644f
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlQueryManagerApplicationContractsModule.cs
@@ -0,0 +1,14 @@
+using Volo.Abp.Application;
+using Volo.Abp.Authorization;
+using Volo.Abp.Modularity;
+
+namespace Erp.SqlQueryManager;
+
+[DependsOn(
+ typeof(SqlQueryManagerDomainSharedModule),
+ typeof(AbpDddApplicationContractsModule),
+ typeof(AbpAuthorizationModule)
+)]
+public class SqlQueryManagerApplicationContractsModule : AbpModule
+{
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlStoredProcedureDto.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlStoredProcedureDto.cs
new file mode 100644
index 00000000..ca4bf544
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlStoredProcedureDto.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+using Erp.SqlQueryManager.Domain.Shared;
+using Volo.Abp.Application.Dtos;
+
+namespace Erp.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 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/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlTemplateDto.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlTemplateDto.cs
new file mode 100644
index 00000000..5fdf5ae0
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlTemplateDto.cs
@@ -0,0 +1,18 @@
+using System.Collections.Generic;
+
+namespace Erp.SqlQueryManager.Application.Contracts;
+
+public class SqlTemplateDto
+{
+ public string Type { get; set; }
+ public string Name { get; set; }
+ public string Description { get; set; }
+ public string Template { get; set; }
+}
+
+public class GetTemplateInput
+{
+ public string TemplateType { get; set; }
+ public string ObjectName { get; set; }
+ public string SchemaName { get; set; }
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlViewDto.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlViewDto.cs
new file mode 100644
index 00000000..e8bcb9c4
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application.Contracts/SqlViewDto.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+using Erp.SqlQueryManager.Domain.Shared;
+using Volo.Abp.Application.Dtos;
+
+namespace Erp.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 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/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/Erp.SqlQueryManager.Application.csproj b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/Erp.SqlQueryManager.Application.csproj
new file mode 100644
index 00000000..5f4683e5
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/Erp.SqlQueryManager.Application.csproj
@@ -0,0 +1,18 @@
+
+
+
+
+
+ net9.0
+ Erp.SqlQueryManager
+
+
+
+
+
+
+
+
+
+
+
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/FodyWeavers.xml b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/FodyWeavers.xml
new file mode 100644
index 00000000..00e1d9a1
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/FodyWeavers.xsd b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/FodyWeavers.xsd
new file mode 100644
index 00000000..3f3946e2
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlFunctionAppService.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlFunctionAppService.cs
new file mode 100644
index 00000000..2ce9b3bc
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlFunctionAppService.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Threading.Tasks;
+using Erp.SqlQueryManager.Application.Contracts;
+using Erp.SqlQueryManager.Domain.Entities;
+using Erp.SqlQueryManager.Domain.Services;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Application.Services;
+using Volo.Abp.Domain.Repositories;
+
+namespace Erp.SqlQueryManager.Application;
+
+public class SqlFunctionAppService : CrudAppService<
+ SqlFunction,
+ SqlFunctionDto,
+ Guid,
+ PagedAndSortedResultRequestDto,
+ CreateSqlFunctionDto,
+ UpdateSqlFunctionDto>, ISqlFunctionAppService
+{
+ private readonly ISqlExecutorService _sqlExecutorService;
+
+ public SqlFunctionAppService(
+ IRepository repository,
+ ISqlExecutorService sqlExecutorService) : base(repository)
+ {
+ _sqlExecutorService = sqlExecutorService;
+ }
+
+ public override async Task CreateAsync(CreateSqlFunctionDto input)
+ {
+ var entity = new SqlFunction(
+ GuidGenerator.Create(),
+ input.FunctionName,
+ input.SchemaName ?? "dbo",
+ input.DisplayName,
+ input.FunctionType,
+ input.FunctionBody,
+ input.ReturnType,
+ input.DataSourceCode,
+ CurrentTenant.Id)
+ {
+ Description = input.Description,
+ Category = input.Category,
+ Parameters = input.Parameters
+ };
+
+ await Repository.InsertAsync(entity);
+ return ObjectMapper.Map(entity);
+ }
+
+ public override async Task UpdateAsync(Guid id, UpdateSqlFunctionDto input)
+ {
+ var entity = await Repository.GetAsync(id);
+
+ entity.DisplayName = input.DisplayName;
+ entity.Description = input.Description;
+ entity.UpdateBody(input.FunctionBody);
+ entity.ReturnType = input.ReturnType;
+ entity.Category = input.Category;
+ entity.Parameters = input.Parameters;
+
+ await Repository.UpdateAsync(entity);
+ return ObjectMapper.Map(entity);
+ }
+
+ public async Task DeployAsync(DeployFunctionDto input)
+ {
+ var function = await Repository.GetAsync(input.Id);
+
+ // Drop if exists and requested
+ if (input.DropIfExists)
+ {
+ var objectType = function.FunctionType.ToString().ToUpperInvariant().Replace("FUNCTION", "_FUNCTION");
+ await _sqlExecutorService.DropObjectAsync(
+ function.FunctionName,
+ $"SQL_{objectType}",
+ function.DataSourceCode,
+ function.SchemaName);
+ }
+
+ // Deploy the function
+ var result = await _sqlExecutorService.DeployFunctionAsync(
+ function.FunctionBody,
+ function.DataSourceCode);
+
+ if (result.Success)
+ {
+ function.MarkAsDeployed();
+ await Repository.UpdateAsync(function);
+ }
+
+ return MapExecutionResult(result);
+ }
+
+ public async Task CheckExistsAsync(Guid id)
+ {
+ var function = await Repository.GetAsync(id);
+ var objectType = function.FunctionType.ToString().ToUpperInvariant().Replace("FUNCTION", "_FUNCTION");
+
+ return await _sqlExecutorService.CheckObjectExistsAsync(
+ function.FunctionName,
+ $"SQL_{objectType}",
+ function.DataSourceCode,
+ function.SchemaName);
+ }
+
+ public async Task DropAsync(Guid id)
+ {
+ var function = await Repository.GetAsync(id);
+ var objectType = function.FunctionType.ToString().ToUpperInvariant().Replace("FUNCTION", "_FUNCTION");
+
+ var result = await _sqlExecutorService.DropObjectAsync(
+ function.FunctionName,
+ $"SQL_{objectType}",
+ function.DataSourceCode,
+ function.SchemaName);
+
+ if (result.Success)
+ {
+ function.IsDeployed = false;
+ await Repository.UpdateAsync(function);
+ }
+
+ return MapExecutionResult(result);
+ }
+
+ private SqlQueryExecutionResultDto MapExecutionResult(SqlExecutionResult result)
+ {
+ return new SqlQueryExecutionResultDto
+ {
+ Success = result.Success,
+ Message = result.Message,
+ Data = result.Data,
+ RowsAffected = result.RowsAffected,
+ ExecutionTimeMs = result.ExecutionTimeMs,
+ Metadata = result.Metadata
+ };
+ }
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlQueryAppService.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlQueryAppService.cs
new file mode 100644
index 00000000..c0d55036
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlQueryAppService.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using Erp.SqlQueryManager.Application.Contracts;
+using Erp.SqlQueryManager.Domain.Entities;
+using Erp.SqlQueryManager.Domain.Services;
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Application.Services;
+using Volo.Abp.Domain.Repositories;
+
+namespace Erp.SqlQueryManager.Application;
+
+public class SqlQueryAppService : CrudAppService<
+ SqlQuery,
+ SqlQueryDto,
+ Guid,
+ PagedAndSortedResultRequestDto,
+ CreateSqlQueryDto,
+ UpdateSqlQueryDto>, ISqlQueryAppService
+{
+ private readonly ISqlExecutorService _sqlExecutorService;
+
+ public SqlQueryAppService(
+ IRepository repository,
+ ISqlExecutorService sqlExecutorService) : base(repository)
+ {
+ _sqlExecutorService = sqlExecutorService;
+ }
+
+ public override async Task CreateAsync(CreateSqlQueryDto input)
+ {
+ var entity = new SqlQuery(
+ GuidGenerator.Create(),
+ input.Code,
+ input.Name,
+ input.QueryText,
+ input.DataSourceCode,
+ CurrentTenant.Id)
+ {
+ Description = input.Description,
+ Category = input.Category,
+ Tags = input.Tags,
+ IsModifyingData = input.IsModifyingData,
+ Parameters = input.Parameters
+ };
+
+ await Repository.InsertAsync(entity);
+ return ObjectMapper.Map(entity);
+ }
+
+ public override async Task UpdateAsync(Guid id, UpdateSqlQueryDto input)
+ {
+ var entity = await Repository.GetAsync(id);
+
+ entity.Name = input.Name;
+ entity.Description = input.Description;
+ entity.UpdateQueryText(input.QueryText);
+ entity.DataSourceCode = input.DataSourceCode;
+ entity.Category = input.Category;
+ entity.Tags = input.Tags;
+ entity.IsModifyingData = input.IsModifyingData;
+ entity.Parameters = input.Parameters;
+
+ await Repository.UpdateAsync(entity);
+ return ObjectMapper.Map(entity);
+ }
+
+ public async Task ExecuteQueryAsync(ExecuteSqlQueryDto input)
+ {
+ var result = input.QueryText.TrimStart().StartsWith("SELECT", StringComparison.OrdinalIgnoreCase)
+ ? await _sqlExecutorService.ExecuteQueryAsync(input.QueryText, input.DataSourceCode, input.Parameters)
+ : await _sqlExecutorService.ExecuteNonQueryAsync(input.QueryText, input.DataSourceCode, input.Parameters);
+
+ return MapExecutionResult(result);
+ }
+
+ public async Task ExecuteSavedQueryAsync(Guid id)
+ {
+ var query = await Repository.GetAsync(id);
+
+ var result = query.IsModifyingData
+ ? await _sqlExecutorService.ExecuteNonQueryAsync(query.QueryText, query.DataSourceCode)
+ : await _sqlExecutorService.ExecuteQueryAsync(query.QueryText, query.DataSourceCode);
+
+ // Update execution statistics
+ query.MarkAsExecuted();
+ await Repository.UpdateAsync(query);
+
+ return MapExecutionResult(result);
+ }
+
+ public async Task<(bool IsValid, string ErrorMessage)> ValidateQueryAsync(string sql)
+ {
+ return await _sqlExecutorService.ValidateSqlAsync(sql);
+ }
+
+ public async Task ActivateAsync(Guid id)
+ {
+ var entity = await Repository.GetAsync(id);
+ entity.Activate();
+ await Repository.UpdateAsync(entity);
+ }
+
+ public async Task ArchiveAsync(Guid id)
+ {
+ var entity = await Repository.GetAsync(id);
+ entity.Archive();
+ await Repository.UpdateAsync(entity);
+ }
+
+ private SqlQueryExecutionResultDto MapExecutionResult(SqlExecutionResult result)
+ {
+ return new SqlQueryExecutionResultDto
+ {
+ Success = result.Success,
+ Message = result.Message,
+ Data = result.Data,
+ RowsAffected = result.RowsAffected,
+ ExecutionTimeMs = result.ExecutionTimeMs,
+ Metadata = result.Metadata
+ };
+ }
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlQueryManagerApplicationModule.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlQueryManagerApplicationModule.cs
new file mode 100644
index 00000000..146b8f00
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlQueryManagerApplicationModule.cs
@@ -0,0 +1,25 @@
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.Application;
+using Volo.Abp.AutoMapper;
+using Volo.Abp.Modularity;
+
+namespace Erp.SqlQueryManager;
+
+[DependsOn(
+ typeof(SqlQueryManagerDomainModule),
+ typeof(SqlQueryManagerApplicationContractsModule),
+ typeof(AbpDddApplicationModule),
+ typeof(AbpAutoMapperModule)
+)]
+public class SqlQueryManagerApplicationModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ context.Services.AddAutoMapperObjectMapper();
+
+ Configure(options =>
+ {
+ options.AddMaps(validate: true);
+ });
+ }
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlQueryManagerAutoMapperProfile.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlQueryManagerAutoMapperProfile.cs
new file mode 100644
index 00000000..48c7eadf
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlQueryManagerAutoMapperProfile.cs
@@ -0,0 +1,87 @@
+using AutoMapper;
+using Erp.SqlQueryManager.Application.Contracts;
+using Erp.SqlQueryManager.Domain.Entities;
+using Volo.Abp.AutoMapper;
+
+namespace Erp.SqlQueryManager.Application;
+
+public class SqlQueryManagerAutoMapperProfile : Profile
+{
+ public SqlQueryManagerAutoMapperProfile()
+ {
+ CreateMap();
+ CreateMap()
+ .IgnoreFullAuditedObjectProperties()
+ .Ignore(x => x.Id)
+ .Ignore(x => x.TenantId)
+ .Ignore(x => x.Status)
+ .Ignore(x => x.LastExecutedAt)
+ .Ignore(x => x.ExecutionCount);
+
+ CreateMap()
+ .IgnoreFullAuditedObjectProperties()
+ .Ignore(x => x.Id)
+ .Ignore(x => x.TenantId)
+ .Ignore(x => x.Status)
+ .Ignore(x => x.LastExecutedAt)
+ .Ignore(x => x.ExecutionCount);
+
+ CreateMap();
+ CreateMap()
+ .IgnoreFullAuditedObjectProperties()
+ .Ignore(x => x.Id)
+ .Ignore(x => x.TenantId)
+ .Ignore(x => x.Status)
+ .Ignore(x => x.IsDeployed)
+ .Ignore(x => x.LastDeployedAt);
+ CreateMap()
+ .IgnoreFullAuditedObjectProperties()
+ .Ignore(x => x.Id)
+ .Ignore(x => x.TenantId)
+ .Ignore(x => x.ProcedureName)
+ .Ignore(x => x.SchemaName)
+ .Ignore(x => x.DataSourceCode)
+ .Ignore(x => x.Status)
+ .Ignore(x => x.IsDeployed)
+ .Ignore(x => x.LastDeployedAt);
+
+ CreateMap();
+ CreateMap()
+ .IgnoreFullAuditedObjectProperties()
+ .Ignore(x => x.Id)
+ .Ignore(x => x.TenantId)
+ .Ignore(x => x.Status)
+ .Ignore(x => x.IsDeployed)
+ .Ignore(x => x.LastDeployedAt);
+ CreateMap()
+ .IgnoreFullAuditedObjectProperties()
+ .Ignore(x => x.Id)
+ .Ignore(x => x.TenantId)
+ .Ignore(x => x.ViewName)
+ .Ignore(x => x.SchemaName)
+ .Ignore(x => x.DataSourceCode)
+ .Ignore(x => x.Status)
+ .Ignore(x => x.IsDeployed)
+ .Ignore(x => x.LastDeployedAt);
+
+ CreateMap();
+ CreateMap()
+ .IgnoreFullAuditedObjectProperties()
+ .Ignore(x => x.Id)
+ .Ignore(x => x.TenantId)
+ .Ignore(x => x.Status)
+ .Ignore(x => x.IsDeployed)
+ .Ignore(x => x.LastDeployedAt);
+ CreateMap()
+ .IgnoreFullAuditedObjectProperties()
+ .Ignore(x => x.Id)
+ .Ignore(x => x.TenantId)
+ .Ignore(x => x.FunctionName)
+ .Ignore(x => x.SchemaName)
+ .Ignore(x => x.FunctionType)
+ .Ignore(x => x.DataSourceCode)
+ .Ignore(x => x.Status)
+ .Ignore(x => x.IsDeployed)
+ .Ignore(x => x.LastDeployedAt);
+ }
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlStoredProcedureAppService.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlStoredProcedureAppService.cs
new file mode 100644
index 00000000..2208577c
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlStoredProcedureAppService.cs
@@ -0,0 +1,134 @@
+using System;
+using System.Threading.Tasks;
+using Erp.SqlQueryManager.Application.Contracts;
+using Erp.SqlQueryManager.Domain.Entities;
+using Erp.SqlQueryManager.Domain.Services;
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Application.Services;
+using Volo.Abp.Domain.Repositories;
+
+namespace Erp.SqlQueryManager.Application;
+
+public class SqlStoredProcedureAppService : CrudAppService<
+ SqlStoredProcedure,
+ SqlStoredProcedureDto,
+ Guid,
+ PagedAndSortedResultRequestDto,
+ CreateSqlStoredProcedureDto,
+ UpdateSqlStoredProcedureDto>, ISqlStoredProcedureAppService
+{
+ private readonly ISqlExecutorService _sqlExecutorService;
+
+ public SqlStoredProcedureAppService(
+ IRepository repository,
+ ISqlExecutorService sqlExecutorService) : base(repository)
+ {
+ _sqlExecutorService = sqlExecutorService;
+ }
+
+ public override async Task CreateAsync(CreateSqlStoredProcedureDto input)
+ {
+ var entity = new SqlStoredProcedure(
+ GuidGenerator.Create(),
+ input.ProcedureName,
+ input.SchemaName ?? "dbo",
+ input.DisplayName,
+ input.ProcedureBody,
+ input.DataSourceCode,
+ CurrentTenant.Id)
+ {
+ Description = input.Description,
+ Category = input.Category,
+ Parameters = input.Parameters
+ };
+
+ await Repository.InsertAsync(entity);
+ return ObjectMapper.Map(entity);
+ }
+
+ public override async Task UpdateAsync(Guid id, UpdateSqlStoredProcedureDto input)
+ {
+ var entity = await Repository.GetAsync(id);
+
+ entity.DisplayName = input.DisplayName;
+ entity.Description = input.Description;
+ entity.UpdateBody(input.ProcedureBody);
+ entity.Category = input.Category;
+ entity.Parameters = input.Parameters;
+
+ await Repository.UpdateAsync(entity);
+ return ObjectMapper.Map(entity);
+ }
+
+ public async Task DeployAsync(DeployStoredProcedureDto input)
+ {
+ var procedure = await Repository.GetAsync(input.Id);
+
+ // Drop if exists and requested
+ if (input.DropIfExists)
+ {
+ await _sqlExecutorService.DropObjectAsync(
+ procedure.ProcedureName,
+ "SQL_STORED_PROCEDURE",
+ procedure.DataSourceCode,
+ procedure.SchemaName);
+ }
+
+ // Deploy the procedure
+ var result = await _sqlExecutorService.DeployStoredProcedureAsync(
+ procedure.ProcedureBody,
+ procedure.DataSourceCode);
+
+ if (result.Success)
+ {
+ procedure.MarkAsDeployed();
+ await Repository.UpdateAsync(procedure);
+ }
+
+ return MapExecutionResult(result);
+ }
+
+ public async Task CheckExistsAsync(Guid id)
+ {
+ var procedure = await Repository.GetAsync(id);
+
+ return await _sqlExecutorService.CheckObjectExistsAsync(
+ procedure.ProcedureName,
+ "SQL_STORED_PROCEDURE",
+ procedure.DataSourceCode,
+ procedure.SchemaName);
+ }
+
+ public async Task DropAsync(Guid id)
+ {
+ var procedure = await Repository.GetAsync(id);
+
+ var result = await _sqlExecutorService.DropObjectAsync(
+ procedure.ProcedureName,
+ "SQL_STORED_PROCEDURE",
+ procedure.DataSourceCode,
+ procedure.SchemaName);
+
+ if (result.Success)
+ {
+ procedure.IsDeployed = false;
+ await Repository.UpdateAsync(procedure);
+ }
+
+ return MapExecutionResult(result);
+ }
+
+ private SqlQueryExecutionResultDto MapExecutionResult(SqlExecutionResult result)
+ {
+ return new SqlQueryExecutionResultDto
+ {
+ Success = result.Success,
+ Message = result.Message,
+ Data = result.Data,
+ RowsAffected = result.RowsAffected,
+ ExecutionTimeMs = result.ExecutionTimeMs,
+ Metadata = result.Metadata
+ };
+ }
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlTemplateAppService.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlTemplateAppService.cs
new file mode 100644
index 00000000..3387159f
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlTemplateAppService.cs
@@ -0,0 +1,59 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Erp.SqlQueryManager.Application.Contracts;
+using Erp.SqlQueryManager.Domain.Services;
+using Erp.SqlQueryManager.Domain.Shared;
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp.Application.Services;
+
+namespace Erp.SqlQueryManager.Application;
+
+public class SqlTemplateAppService : ApplicationService, ISqlTemplateAppService
+{
+ private readonly ISqlTemplateProvider _templateProvider;
+
+ public SqlTemplateAppService(ISqlTemplateProvider templateProvider)
+ {
+ _templateProvider = templateProvider;
+ }
+
+ public Task> GetQueryTemplatesAsync()
+ {
+ var templates = _templateProvider.GetAvailableQueryTemplates()
+ .Select(t => new SqlTemplateDto
+ {
+ Type = t.Type,
+ Name = t.Name,
+ Description = t.Description,
+ Template = _templateProvider.GetQueryTemplate(t.Type)
+ })
+ .ToList();
+
+ return Task.FromResult(templates);
+ }
+
+ public Task GetStoredProcedureTemplateAsync(string procedureName, string schemaName = "dbo")
+ {
+ var template = _templateProvider.GetStoredProcedureTemplate(procedureName, schemaName);
+ return Task.FromResult(template);
+ }
+
+ public Task GetViewTemplateAsync(string viewName, string schemaName = "dbo", bool withSchemaBinding = false)
+ {
+ var template = _templateProvider.GetViewTemplate(viewName, schemaName, withSchemaBinding);
+ return Task.FromResult(template);
+ }
+
+ public Task GetFunctionTemplateAsync(string functionName, SqlFunctionType functionType, string schemaName = "dbo")
+ {
+ var template = _templateProvider.GetFunctionTemplate(functionName, functionType, schemaName);
+ return Task.FromResult(template);
+ }
+
+ public Task GetQueryTemplateAsync(string templateType)
+ {
+ var template = _templateProvider.GetQueryTemplate(templateType);
+ return Task.FromResult(template);
+ }
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlViewAppService.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlViewAppService.cs
new file mode 100644
index 00000000..447aecca
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Application/SqlViewAppService.cs
@@ -0,0 +1,133 @@
+using System;
+using System.Threading.Tasks;
+using Erp.SqlQueryManager.Application.Contracts;
+using Erp.SqlQueryManager.Domain.Entities;
+using Erp.SqlQueryManager.Domain.Services;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Application.Services;
+using Volo.Abp.Domain.Repositories;
+
+namespace Erp.SqlQueryManager.Application;
+
+public class SqlViewAppService : CrudAppService<
+ SqlView,
+ SqlViewDto,
+ Guid,
+ PagedAndSortedResultRequestDto,
+ CreateSqlViewDto,
+ UpdateSqlViewDto>, ISqlViewAppService
+{
+ private readonly ISqlExecutorService _sqlExecutorService;
+
+ public SqlViewAppService(
+ IRepository repository,
+ ISqlExecutorService sqlExecutorService) : base(repository)
+ {
+ _sqlExecutorService = sqlExecutorService;
+ }
+
+ public override async Task CreateAsync(CreateSqlViewDto input)
+ {
+ var entity = new SqlView(
+ GuidGenerator.Create(),
+ input.ViewName,
+ input.SchemaName ?? "dbo",
+ input.DisplayName,
+ input.ViewDefinition,
+ input.DataSourceCode,
+ CurrentTenant.Id)
+ {
+ Description = input.Description,
+ Category = input.Category,
+ WithSchemaBinding = input.WithSchemaBinding
+ };
+
+ await Repository.InsertAsync(entity);
+ return ObjectMapper.Map(entity);
+ }
+
+ public override async Task UpdateAsync(Guid id, UpdateSqlViewDto input)
+ {
+ var entity = await Repository.GetAsync(id);
+
+ entity.DisplayName = input.DisplayName;
+ entity.Description = input.Description;
+ entity.UpdateDefinition(input.ViewDefinition);
+ entity.Category = input.Category;
+ entity.WithSchemaBinding = input.WithSchemaBinding;
+
+ await Repository.UpdateAsync(entity);
+ return ObjectMapper.Map(entity);
+ }
+
+ public async Task DeployAsync(DeployViewDto input)
+ {
+ var view = await Repository.GetAsync(input.Id);
+
+ // Drop if exists and requested
+ if (input.DropIfExists)
+ {
+ await _sqlExecutorService.DropObjectAsync(
+ view.ViewName,
+ "VIEW",
+ view.DataSourceCode,
+ view.SchemaName);
+ }
+
+ // Deploy the view
+ var result = await _sqlExecutorService.DeployViewAsync(
+ view.ViewDefinition,
+ view.DataSourceCode);
+
+ if (result.Success)
+ {
+ view.MarkAsDeployed();
+ await Repository.UpdateAsync(view);
+ }
+
+ return MapExecutionResult(result);
+ }
+
+ public async Task CheckExistsAsync(Guid id)
+ {
+ var view = await Repository.GetAsync(id);
+
+ return await _sqlExecutorService.CheckObjectExistsAsync(
+ view.ViewName,
+ "VIEW",
+ view.DataSourceCode,
+ view.SchemaName);
+ }
+
+ public async Task DropAsync(Guid id)
+ {
+ var view = await Repository.GetAsync(id);
+
+ var result = await _sqlExecutorService.DropObjectAsync(
+ view.ViewName,
+ "VIEW",
+ view.DataSourceCode,
+ view.SchemaName);
+
+ if (result.Success)
+ {
+ view.IsDeployed = false;
+ await Repository.UpdateAsync(view);
+ }
+
+ return MapExecutionResult(result);
+ }
+
+ private SqlQueryExecutionResultDto MapExecutionResult(SqlExecutionResult result)
+ {
+ return new SqlQueryExecutionResultDto
+ {
+ Success = result.Success,
+ Message = result.Message,
+ Data = result.Data,
+ RowsAffected = result.RowsAffected,
+ ExecutionTimeMs = result.ExecutionTimeMs,
+ Metadata = result.Metadata
+ };
+ }
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/Erp.SqlQueryManager.Domain.Shared.csproj b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/Erp.SqlQueryManager.Domain.Shared.csproj
new file mode 100644
index 00000000..adc9c7dc
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/Erp.SqlQueryManager.Domain.Shared.csproj
@@ -0,0 +1,24 @@
+
+
+
+
+
+ net9.0
+ true
+ Erp.SqlQueryManager
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/ErpSqlQueryManagerResource.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/ErpSqlQueryManagerResource.cs
new file mode 100644
index 00000000..30b86d00
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/ErpSqlQueryManagerResource.cs
@@ -0,0 +1,8 @@
+using Volo.Abp.Localization;
+
+namespace Erp.SqlQueryManager.Domain.Shared;
+
+[LocalizationResourceName("SqlQueryManager")]
+public class ErpSqlQueryManagerResource
+{
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/FodyWeavers.xml b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/FodyWeavers.xml
new file mode 100644
index 00000000..00e1d9a1
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/FodyWeavers.xsd b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/FodyWeavers.xsd
new file mode 100644
index 00000000..3f3946e2
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/SqlObjectType.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/SqlObjectType.cs
new file mode 100644
index 00000000..939b244e
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/SqlObjectType.cs
@@ -0,0 +1,23 @@
+namespace Erp.SqlQueryManager.Domain.Shared;
+
+public enum SqlObjectType
+{
+ Query = 1,
+ StoredProcedure = 2,
+ View = 3,
+ Function = 4
+}
+
+public enum SqlFunctionType
+{
+ ScalarFunction = 1,
+ TableValuedFunction = 2,
+ InlineTableValuedFunction = 3
+}
+
+public enum SqlQueryStatus
+{
+ Draft = 1,
+ Active = 2,
+ Archived = 3
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/SqlQueryManagerDomainSharedModule.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/SqlQueryManagerDomainSharedModule.cs
new file mode 100644
index 00000000..d5294314
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/SqlQueryManagerDomainSharedModule.cs
@@ -0,0 +1,34 @@
+using Erp.SqlQueryManager.Domain.Shared;
+using Volo.Abp.Domain;
+using Volo.Abp.Localization;
+using Volo.Abp.Localization.ExceptionHandling;
+using Volo.Abp.Modularity;
+using Volo.Abp.Validation;
+using Volo.Abp.VirtualFileSystem;
+
+namespace Erp.SqlQueryManager;
+
+[DependsOn(
+ typeof(AbpValidationModule),
+ typeof(AbpDddDomainSharedModule)
+)]
+public class SqlQueryManagerDomainSharedModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ Configure(options =>
+ {
+ options.FileSets.AddEmbedded();
+ });
+
+ Configure(options =>
+ {
+ options.Resources.Add("en");
+ });
+
+ Configure(options =>
+ {
+ options.MapCodeNamespace("SqlQueryManager", typeof(ErpSqlQueryManagerResource));
+ });
+ }
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/SqlQueryManagerErrorCodes.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/SqlQueryManagerErrorCodes.cs
new file mode 100644
index 00000000..e74a6deb
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/SqlQueryManagerErrorCodes.cs
@@ -0,0 +1,11 @@
+namespace Erp.SqlQueryManager.Domain.Shared;
+
+public static class SqlQueryManagerErrorCodes
+{
+ public const string InvalidSqlQuery = "SqlQueryManager:InvalidSqlQuery";
+ public const string DataSourceNotFound = "SqlQueryManager:DataSourceNotFound";
+ public const string ExecutionFailed = "SqlQueryManager:ExecutionFailed";
+ public const string PermissionDenied = "SqlQueryManager:PermissionDenied";
+ public const string InvalidObjectName = "SqlQueryManager:InvalidObjectName";
+ public const string ObjectAlreadyExists = "SqlQueryManager:ObjectAlreadyExists";
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/SqlQueryManagerPermissions.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/SqlQueryManagerPermissions.cs
new file mode 100644
index 00000000..64cb894d
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain.Shared/SqlQueryManagerPermissions.cs
@@ -0,0 +1,57 @@
+using Volo.Abp.Reflection;
+
+namespace Erp.SqlQueryManager.Domain.Shared;
+
+public static class SqlQueryManagerPermissions
+{
+ public const string GroupName = "SqlQueryManager";
+
+ public static class SqlQuery
+ {
+ public const string Default = GroupName + ".SqlQuery";
+ public const string Create = Default + ".Create";
+ public const string Update = Default + ".Update";
+ public const string Delete = Default + ".Delete";
+ public const string Execute = Default + ".Execute";
+ }
+
+ public static class SqlStoredProcedure
+ {
+ public const string Default = GroupName + ".SqlStoredProcedure";
+ public const string Create = Default + ".Create";
+ public const string Update = Default + ".Update";
+ public const string Delete = Default + ".Delete";
+ public const string Deploy = Default + ".Deploy";
+ public const string Drop = Default + ".Drop";
+ }
+
+ public static class SqlView
+ {
+ public const string Default = GroupName + ".SqlView";
+ public const string Create = Default + ".Create";
+ public const string Update = Default + ".Update";
+ public const string Delete = Default + ".Delete";
+ public const string Deploy = Default + ".Deploy";
+ public const string Drop = Default + ".Drop";
+ }
+
+ public static class SqlFunction
+ {
+ public const string Default = GroupName + ".SqlFunction";
+ public const string Create = Default + ".Create";
+ public const string Update = Default + ".Update";
+ public const string Delete = Default + ".Delete";
+ public const string Deploy = Default + ".Deploy";
+ public const string Drop = Default + ".Drop";
+ }
+
+ public static class Templates
+ {
+ public const string Default = GroupName + ".Templates";
+ }
+
+ public static string[] GetAll()
+ {
+ return ReflectionHelper.GetPublicConstantsRecursively(typeof(SqlQueryManagerPermissions));
+ }
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Entities/SqlFunction.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Entities/SqlFunction.cs
new file mode 100644
index 00000000..24b537cf
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Entities/SqlFunction.cs
@@ -0,0 +1,120 @@
+using System;
+using Erp.SqlQueryManager.Domain.Shared;
+using Volo.Abp.Domain.Entities.Auditing;
+using Volo.Abp.MultiTenancy;
+
+namespace Erp.SqlQueryManager.Domain.Entities;
+
+///
+/// SQL Function entity for creating and managing database functions
+///
+public class SqlFunction : FullAuditedEntity, IMultiTenant
+{
+ public Guid? TenantId { get; set; }
+
+ ///
+ /// Function name in database
+ ///
+ public string FunctionName { get; set; }
+
+ ///
+ /// Schema name (default: dbo)
+ ///
+ public string SchemaName { get; set; }
+
+ ///
+ /// Display name
+ ///
+ public string DisplayName { get; set; }
+
+ ///
+ /// Description
+ ///
+ public string Description { get; set; }
+
+ ///
+ /// Function type
+ ///
+ public SqlFunctionType FunctionType { get; set; }
+
+ ///
+ /// Full function definition (CREATE/ALTER)
+ ///
+ public string FunctionBody { get; set; }
+
+ ///
+ /// Return type definition
+ ///
+ public string ReturnType { get; set; }
+
+ ///
+ /// DataSource code
+ ///
+ public string DataSourceCode { get; set; }
+
+ ///
+ /// Status
+ ///
+ public SqlQueryStatus Status { get; set; }
+
+ ///
+ /// Category
+ ///
+ public string Category { get; set; }
+
+ ///
+ /// Whether function exists in database
+ ///
+ public bool IsDeployed { get; set; }
+
+ ///
+ /// Last deployment time
+ ///
+ public DateTime? LastDeployedAt { get; set; }
+
+ ///
+ /// Parameter definitions (JSON)
+ ///
+ public string Parameters { get; set; }
+
+ protected SqlFunction()
+ {
+ }
+
+ public SqlFunction(
+ Guid id,
+ string functionName,
+ string schemaName,
+ string displayName,
+ SqlFunctionType functionType,
+ string functionBody,
+ string returnType,
+ string dataSourceCode,
+ Guid? tenantId = null) : base(id)
+ {
+ FunctionName = functionName;
+ SchemaName = schemaName ?? "dbo";
+ DisplayName = displayName;
+ FunctionType = functionType;
+ FunctionBody = functionBody;
+ ReturnType = returnType;
+ DataSourceCode = dataSourceCode;
+ TenantId = tenantId;
+ Status = SqlQueryStatus.Draft;
+ IsDeployed = false;
+ }
+
+ public void UpdateBody(string body)
+ {
+ FunctionBody = body;
+ }
+
+ public void MarkAsDeployed()
+ {
+ IsDeployed = true;
+ LastDeployedAt = DateTime.UtcNow;
+ Status = SqlQueryStatus.Active;
+ }
+
+ public string GetFullName() => $"{SchemaName}.{FunctionName}";
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Entities/SqlQuery.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Entities/SqlQuery.cs
new file mode 100644
index 00000000..e982758a
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Entities/SqlQuery.cs
@@ -0,0 +1,116 @@
+using System;
+using Erp.SqlQueryManager.Domain.Shared;
+using Volo.Abp.Domain.Entities.Auditing;
+using Volo.Abp.MultiTenancy;
+
+namespace Erp.SqlQueryManager.Domain.Entities;
+
+///
+/// SQL Query entity for storing and managing SQL queries
+///
+public class SqlQuery : FullAuditedEntity, IMultiTenant
+{
+ public Guid? TenantId { get; set; }
+
+ ///
+ /// Unique code for the query
+ ///
+ public string Code { get; set; }
+
+ ///
+ /// Display name
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Description of the query
+ ///
+ public string Description { get; set; }
+
+ ///
+ /// SQL query content
+ ///
+ public string QueryText { get; set; }
+
+ ///
+ /// DataSource code to use for execution
+ ///
+ public string DataSourceCode { get; set; }
+
+ ///
+ /// Query status
+ ///
+ public SqlQueryStatus Status { get; set; }
+
+ ///
+ /// Category for organization
+ ///
+ public string Category { get; set; }
+
+ ///
+ /// Tags for filtering
+ ///
+ public string Tags { get; set; }
+
+ ///
+ /// Last execution time
+ ///
+ public DateTime? LastExecutedAt { get; set; }
+
+ ///
+ /// Execution count
+ ///
+ public int ExecutionCount { get; set; }
+
+ ///
+ /// Whether query modifies data
+ ///
+ public bool IsModifyingData { get; set; }
+
+ ///
+ /// Expected parameter definitions (JSON format)
+ ///
+ public string Parameters { get; set; }
+
+ protected SqlQuery()
+ {
+ }
+
+ public SqlQuery(
+ Guid id,
+ string code,
+ string name,
+ string queryText,
+ string dataSourceCode,
+ Guid? tenantId = null) : base(id)
+ {
+ Code = code;
+ Name = name;
+ QueryText = queryText;
+ DataSourceCode = dataSourceCode;
+ TenantId = tenantId;
+ Status = SqlQueryStatus.Draft;
+ ExecutionCount = 0;
+ }
+
+ public void UpdateQueryText(string queryText)
+ {
+ QueryText = queryText;
+ }
+
+ public void MarkAsExecuted()
+ {
+ LastExecutedAt = DateTime.UtcNow;
+ ExecutionCount++;
+ }
+
+ public void Activate()
+ {
+ Status = SqlQueryStatus.Active;
+ }
+
+ public void Archive()
+ {
+ Status = SqlQueryStatus.Archived;
+ }
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Entities/SqlStoredProcedure.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Entities/SqlStoredProcedure.cs
new file mode 100644
index 00000000..bd7d0f97
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Entities/SqlStoredProcedure.cs
@@ -0,0 +1,106 @@
+using System;
+using Erp.SqlQueryManager.Domain.Shared;
+using Volo.Abp.Domain.Entities.Auditing;
+using Volo.Abp.MultiTenancy;
+
+namespace Erp.SqlQueryManager.Domain.Entities;
+
+///
+/// SQL Stored Procedure entity for creating and managing stored procedures
+///
+public class SqlStoredProcedure : FullAuditedEntity, IMultiTenant
+{
+ public Guid? TenantId { get; set; }
+
+ ///
+ /// Procedure name in database
+ ///
+ public string ProcedureName { get; set; }
+
+ ///
+ /// Schema name (default: dbo)
+ ///
+ public string SchemaName { get; set; }
+
+ ///
+ /// Display name
+ ///
+ public string DisplayName { get; set; }
+
+ ///
+ /// Description
+ ///
+ public string Description { get; set; }
+
+ ///
+ /// Full procedure definition (CREATE/ALTER)
+ ///
+ public string ProcedureBody { get; set; }
+
+ ///
+ /// DataSource code
+ ///
+ public string DataSourceCode { get; set; }
+
+ ///
+ /// Status
+ ///
+ public SqlQueryStatus Status { get; set; }
+
+ ///
+ /// Category
+ ///
+ public string Category { get; set; }
+
+ ///
+ /// Whether procedure exists in database
+ ///
+ public bool IsDeployed { get; set; }
+
+ ///
+ /// Last deployment time
+ ///
+ public DateTime? LastDeployedAt { get; set; }
+
+ ///
+ /// Parameter definitions (JSON)
+ ///
+ public string Parameters { get; set; }
+
+ protected SqlStoredProcedure()
+ {
+ }
+
+ public SqlStoredProcedure(
+ Guid id,
+ string procedureName,
+ string schemaName,
+ string displayName,
+ string procedureBody,
+ string dataSourceCode,
+ Guid? tenantId = null) : base(id)
+ {
+ ProcedureName = procedureName;
+ SchemaName = schemaName ?? "dbo";
+ DisplayName = displayName;
+ ProcedureBody = procedureBody;
+ DataSourceCode = dataSourceCode;
+ TenantId = tenantId;
+ Status = SqlQueryStatus.Draft;
+ IsDeployed = false;
+ }
+
+ public void UpdateBody(string body)
+ {
+ ProcedureBody = body;
+ }
+
+ public void MarkAsDeployed()
+ {
+ IsDeployed = true;
+ LastDeployedAt = DateTime.UtcNow;
+ Status = SqlQueryStatus.Active;
+ }
+
+ public string GetFullName() => $"{SchemaName}.{ProcedureName}";
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Entities/SqlView.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Entities/SqlView.cs
new file mode 100644
index 00000000..643ba09b
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Entities/SqlView.cs
@@ -0,0 +1,107 @@
+using System;
+using Erp.SqlQueryManager.Domain.Shared;
+using Volo.Abp.Domain.Entities.Auditing;
+using Volo.Abp.MultiTenancy;
+
+namespace Erp.SqlQueryManager.Domain.Entities;
+
+///
+/// SQL View entity for creating and managing database views
+///
+public class SqlView : FullAuditedEntity, IMultiTenant
+{
+ public Guid? TenantId { get; set; }
+
+ ///
+ /// View name in database
+ ///
+ public string ViewName { get; set; }
+
+ ///
+ /// Schema name (default: dbo)
+ ///
+ public string SchemaName { get; set; }
+
+ ///
+ /// Display name
+ ///
+ public string DisplayName { get; set; }
+
+ ///
+ /// Description
+ ///
+ public string Description { get; set; }
+
+ ///
+ /// View definition (SELECT statement)
+ ///
+ public string ViewDefinition { get; set; }
+
+ ///
+ /// DataSource code
+ ///
+ public string DataSourceCode { get; set; }
+
+ ///
+ /// Status
+ ///
+ public SqlQueryStatus Status { get; set; }
+
+ ///
+ /// Category
+ ///
+ public string Category { get; set; }
+
+ ///
+ /// Whether view exists in database
+ ///
+ public bool IsDeployed { get; set; }
+
+ ///
+ /// Last deployment time
+ ///
+ public DateTime? LastDeployedAt { get; set; }
+
+ ///
+ /// Whether to use WITH SCHEMABINDING
+ ///
+ public bool WithSchemaBinding { get; set; }
+
+ protected SqlView()
+ {
+ }
+
+ public SqlView(
+ Guid id,
+ string viewName,
+ string schemaName,
+ string displayName,
+ string viewDefinition,
+ string dataSourceCode,
+ Guid? tenantId = null) : base(id)
+ {
+ ViewName = viewName;
+ SchemaName = schemaName ?? "dbo";
+ DisplayName = displayName;
+ ViewDefinition = viewDefinition;
+ DataSourceCode = dataSourceCode;
+ TenantId = tenantId;
+ Status = SqlQueryStatus.Draft;
+ IsDeployed = false;
+ WithSchemaBinding = false;
+ }
+
+ public void UpdateDefinition(string definition)
+ {
+ ViewDefinition = definition;
+ }
+
+ public void MarkAsDeployed()
+ {
+ IsDeployed = true;
+ LastDeployedAt = DateTime.UtcNow;
+ Status = SqlQueryStatus.Active;
+ }
+
+ public string GetFullName() => $"{SchemaName}.{ViewName}";
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Erp.SqlQueryManager.Domain.csproj b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Erp.SqlQueryManager.Domain.csproj
new file mode 100644
index 00000000..d457b53e
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Erp.SqlQueryManager.Domain.csproj
@@ -0,0 +1,16 @@
+
+
+
+
+
+ net9.0
+ Erp.SqlQueryManager
+
+
+
+
+
+
+
+
+
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/FodyWeavers.xml b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/FodyWeavers.xml
new file mode 100644
index 00000000..00e1d9a1
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/FodyWeavers.xsd b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/FodyWeavers.xsd
new file mode 100644
index 00000000..3f3946e2
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Services/ISqlExecutorService.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Services/ISqlExecutorService.cs
new file mode 100644
index 00000000..5c6fff3b
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Services/ISqlExecutorService.cs
@@ -0,0 +1,96 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Erp.SqlQueryManager.Domain.Services;
+
+///
+/// Result of SQL query execution
+///
+public class SqlExecutionResult
+{
+ 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; }
+
+ public SqlExecutionResult()
+ {
+ Metadata = new Dictionary();
+ }
+}
+
+///
+/// Service for executing SQL commands
+///
+public interface ISqlExecutorService
+{
+ ///
+ /// Execute a SELECT query and return results
+ ///
+ Task ExecuteQueryAsync(
+ string sql,
+ string dataSourceCode,
+ Dictionary parameters = null);
+
+ ///
+ /// Execute a non-query command (INSERT, UPDATE, DELETE)
+ ///
+ Task ExecuteNonQueryAsync(
+ string sql,
+ string dataSourceCode,
+ Dictionary parameters = null);
+
+ ///
+ /// Execute scalar query (returns single value)
+ ///
+ Task ExecuteScalarAsync(
+ string sql,
+ string dataSourceCode,
+ Dictionary parameters = null);
+
+ ///
+ /// Deploy stored procedure to database
+ ///
+ Task DeployStoredProcedureAsync(
+ string procedureBody,
+ string dataSourceCode);
+
+ ///
+ /// Deploy view to database
+ ///
+ Task DeployViewAsync(
+ string viewDefinition,
+ string dataSourceCode);
+
+ ///
+ /// Deploy function to database
+ ///
+ Task DeployFunctionAsync(
+ string functionBody,
+ string dataSourceCode);
+
+ ///
+ /// Check if database object exists
+ ///
+ Task CheckObjectExistsAsync(
+ string objectName,
+ string objectType,
+ string dataSourceCode,
+ string schemaName = "dbo");
+
+ ///
+ /// Drop database object
+ ///
+ Task DropObjectAsync(
+ string objectName,
+ string objectType,
+ string dataSourceCode,
+ string schemaName = "dbo");
+
+ ///
+ /// Validate SQL syntax (basic validation)
+ ///
+ Task<(bool IsValid, string ErrorMessage)> ValidateSqlAsync(string sql);
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Services/ISqlTemplateProvider.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Services/ISqlTemplateProvider.cs
new file mode 100644
index 00000000..0b0c26c8
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Services/ISqlTemplateProvider.cs
@@ -0,0 +1,42 @@
+using System.Collections.Generic;
+using Erp.SqlQueryManager.Domain.Shared;
+
+namespace Erp.SqlQueryManager.Domain.Services;
+
+///
+/// Provides SQL templates for creating database objects
+///
+public interface ISqlTemplateProvider
+{
+ ///
+ /// Get stored procedure template
+ ///
+ string GetStoredProcedureTemplate(string procedureName, string schemaName = "dbo");
+
+ ///
+ /// Get view template
+ ///
+ string GetViewTemplate(string viewName, string schemaName = "dbo", bool withSchemaBinding = false);
+
+ ///
+ /// Get function template
+ ///
+ string GetFunctionTemplate(string functionName, SqlFunctionType functionType, string schemaName = "dbo");
+
+ ///
+ /// Get query template with common patterns
+ ///
+ string GetQueryTemplate(string queryType);
+
+ ///
+ /// Get available query template types
+ ///
+ List GetAvailableQueryTemplates();
+}
+
+public class QueryTemplateInfo
+{
+ public string Type { get; set; }
+ public string Name { get; set; }
+ public string Description { get; set; }
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Services/SqlExecutorService.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Services/SqlExecutorService.cs
new file mode 100644
index 00000000..f94baffd
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Services/SqlExecutorService.cs
@@ -0,0 +1,301 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using Erp.Platform.DynamicData;
+using Erp.Platform.Queries;
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp;
+using Volo.Abp.Domain.Services;
+
+namespace Erp.SqlQueryManager.Domain.Services;
+
+public class SqlExecutorService : DomainService, ISqlExecutorService
+{
+ private readonly IDataSourceManager _dataSourceManager;
+ private readonly IServiceProvider _serviceProvider;
+
+ public SqlExecutorService(
+ IDataSourceManager dataSourceManager,
+ IServiceProvider serviceProvider)
+ {
+ _dataSourceManager = dataSourceManager;
+ _serviceProvider = serviceProvider;
+ }
+
+ private async Task GetRepositoryAsync(string dataSourceCode)
+ {
+ // Get DataSource to determine database type
+ var dataSource = await _dataSourceManager.GetDataSourceAsync(
+ CurrentTenant.IsAvailable,
+ dataSourceCode);
+
+ if (dataSource == null)
+ {
+ throw new BusinessException("SqlQueryManager:DataSourceNotFound")
+ .WithData("DataSourceCode", dataSourceCode);
+ }
+
+ // Get appropriate repository based on database type
+ // For now, using MS SQL Server repository
+ var repository = _serviceProvider.GetKeyedService("Ms");
+
+ if (repository == null)
+ {
+ throw new BusinessException("SqlQueryManager:RepositoryNotFound")
+ .WithData("DatabaseType", "Ms");
+ }
+
+ return repository;
+ }
+
+ public async Task ExecuteQueryAsync(
+ string sql,
+ string dataSourceCode,
+ Dictionary parameters = null)
+ {
+ var stopwatch = Stopwatch.StartNew();
+ var result = new SqlExecutionResult();
+
+ try
+ {
+ var connectionString = await _dataSourceManager.GetConnectionStringAsync(
+ CurrentTenant.IsAvailable,
+ dataSourceCode);
+
+ if (string.IsNullOrWhiteSpace(connectionString))
+ {
+ throw new BusinessException("SqlQueryManager:InvalidConnectionString")
+ .WithData("DataSourceCode", dataSourceCode);
+ }
+
+ var repository = await GetRepositoryAsync(dataSourceCode);
+ var data = await repository.QueryAsync(sql, connectionString, parameters);
+
+ stopwatch.Stop();
+
+ result.Success = true;
+ result.Data = data;
+ result.RowsAffected = data?.Count() ?? 0;
+ result.ExecutionTimeMs = stopwatch.ElapsedMilliseconds;
+ result.Message = $"Query executed successfully. Rows returned: {result.RowsAffected}";
+ }
+ catch (Exception ex)
+ {
+ stopwatch.Stop();
+ result.Success = false;
+ result.Message = $"Query execution failed: {ex.Message}";
+ result.ExecutionTimeMs = stopwatch.ElapsedMilliseconds;
+ result.Metadata["ErrorDetail"] = ex.ToString();
+ }
+
+ return result;
+ }
+
+ public async Task ExecuteNonQueryAsync(
+ string sql,
+ string dataSourceCode,
+ Dictionary parameters = null)
+ {
+ var stopwatch = Stopwatch.StartNew();
+ var result = new SqlExecutionResult();
+
+ try
+ {
+ var connectionString = await _dataSourceManager.GetConnectionStringAsync(
+ CurrentTenant.IsAvailable,
+ dataSourceCode);
+
+ if (string.IsNullOrWhiteSpace(connectionString))
+ {
+ throw new BusinessException("SqlQueryManager:InvalidConnectionString")
+ .WithData("DataSourceCode", dataSourceCode);
+ }
+
+ var repository = await GetRepositoryAsync(dataSourceCode);
+ var rowsAffected = await repository.ExecuteAsync(sql, connectionString, parameters);
+
+ stopwatch.Stop();
+
+ result.Success = true;
+ result.RowsAffected = rowsAffected;
+ result.ExecutionTimeMs = stopwatch.ElapsedMilliseconds;
+ result.Message = $"Command executed successfully. Rows affected: {rowsAffected}";
+ }
+ catch (Exception ex)
+ {
+ stopwatch.Stop();
+ result.Success = false;
+ result.Message = $"Command execution failed: {ex.Message}";
+ result.ExecutionTimeMs = stopwatch.ElapsedMilliseconds;
+ result.Metadata["ErrorDetail"] = ex.ToString();
+ }
+
+ return result;
+ }
+
+ public async Task ExecuteScalarAsync(
+ string sql,
+ string dataSourceCode,
+ Dictionary parameters = null)
+ {
+ var stopwatch = Stopwatch.StartNew();
+ var result = new SqlExecutionResult();
+
+ try
+ {
+ var connectionString = await _dataSourceManager.GetConnectionStringAsync(
+ CurrentTenant.IsAvailable,
+ dataSourceCode);
+
+ if (string.IsNullOrWhiteSpace(connectionString))
+ {
+ throw new BusinessException("SqlQueryManager:InvalidConnectionString")
+ .WithData("DataSourceCode", dataSourceCode);
+ }
+
+ var repository = await GetRepositoryAsync(dataSourceCode);
+ var scalarValue = await repository.ExecuteScalarAsync(sql, connectionString, parameters);
+
+ stopwatch.Stop();
+
+ result.Success = true;
+ result.Data = new[] { new { Value = scalarValue } };
+ result.ExecutionTimeMs = stopwatch.ElapsedMilliseconds;
+ result.Message = "Scalar query executed successfully";
+ result.Metadata["ScalarValue"] = scalarValue;
+ }
+ catch (Exception ex)
+ {
+ stopwatch.Stop();
+ result.Success = false;
+ result.Message = $"Scalar query execution failed: {ex.Message}";
+ result.ExecutionTimeMs = stopwatch.ElapsedMilliseconds;
+ result.Metadata["ErrorDetail"] = ex.ToString();
+ }
+
+ return result;
+ }
+
+ public async Task DeployStoredProcedureAsync(
+ string procedureBody,
+ string dataSourceCode)
+ {
+ return await ExecuteNonQueryAsync(procedureBody, dataSourceCode);
+ }
+
+ public async Task DeployViewAsync(
+ string viewDefinition,
+ string dataSourceCode)
+ {
+ return await ExecuteNonQueryAsync(viewDefinition, dataSourceCode);
+ }
+
+ public async Task DeployFunctionAsync(
+ string functionBody,
+ string dataSourceCode)
+ {
+ return await ExecuteNonQueryAsync(functionBody, dataSourceCode);
+ }
+
+ public async Task CheckObjectExistsAsync(
+ string objectName,
+ string objectType,
+ string dataSourceCode,
+ string schemaName = "dbo")
+ {
+ try
+ {
+ var sql = $@"
+ SELECT COUNT(*)
+ FROM sys.objects o
+ INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
+ WHERE s.name = @SchemaName
+ AND o.name = @ObjectName
+ AND o.type_desc = @ObjectType";
+
+ var parameters = new Dictionary
+ {
+ { "SchemaName", schemaName },
+ { "ObjectName", objectName },
+ { "ObjectType", objectType.ToUpperInvariant() }
+ };
+
+ var result = await ExecuteScalarAsync(sql, dataSourceCode, parameters);
+
+ return result.Success && result.Metadata.ContainsKey("ScalarValue")
+ && Convert.ToInt32(result.Metadata["ScalarValue"]) > 0;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ public async Task DropObjectAsync(
+ string objectName,
+ string objectType,
+ string dataSourceCode,
+ string schemaName = "dbo")
+ {
+ var dropCommand = objectType.ToUpperInvariant() switch
+ {
+ "SQL_STORED_PROCEDURE" => $"DROP PROCEDURE IF EXISTS [{schemaName}].[{objectName}]",
+ "VIEW" => $"DROP VIEW IF EXISTS [{schemaName}].[{objectName}]",
+ "SQL_SCALAR_FUNCTION" => $"DROP FUNCTION IF EXISTS [{schemaName}].[{objectName}]",
+ "SQL_TABLE_VALUED_FUNCTION" => $"DROP FUNCTION IF EXISTS [{schemaName}].[{objectName}]",
+ "SQL_INLINE_TABLE_VALUED_FUNCTION" => $"DROP FUNCTION IF EXISTS [{schemaName}].[{objectName}]",
+ _ => throw new BusinessException("SqlQueryManager:UnsupportedObjectType")
+ .WithData("ObjectType", objectType)
+ };
+
+ return await ExecuteNonQueryAsync(dropCommand, dataSourceCode);
+ }
+
+ public Task<(bool IsValid, string ErrorMessage)> ValidateSqlAsync(string sql)
+ {
+ try
+ {
+ if (string.IsNullOrWhiteSpace(sql))
+ {
+ return Task.FromResult((false, "SQL query is empty"));
+ }
+
+ // Basic validation - check for dangerous keywords
+ var dangerousPatterns = new[]
+ {
+ @"\bDROP\s+DATABASE\b",
+ @"\bDROP\s+SCHEMA\b",
+ @"\bTRUNCATE\s+TABLE\b",
+ @"\bALTER\s+DATABASE\b",
+ @"\bSHUTDOWN\b",
+ @"\bxp_cmdshell\b"
+ };
+
+ foreach (var pattern in dangerousPatterns)
+ {
+ if (Regex.IsMatch(sql, pattern, RegexOptions.IgnoreCase))
+ {
+ return Task.FromResult((false, $"SQL contains potentially dangerous command: {pattern}"));
+ }
+ }
+
+ // Check for balanced parentheses
+ var openCount = sql.Count(c => c == '(');
+ var closeCount = sql.Count(c => c == ')');
+
+ if (openCount != closeCount)
+ {
+ return Task.FromResult((false, "Unbalanced parentheses in SQL"));
+ }
+
+ return Task.FromResult((true, string.Empty));
+ }
+ catch (Exception ex)
+ {
+ return Task.FromResult((false, $"Validation error: {ex.Message}"));
+ }
+ }
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Services/SqlTemplateProvider.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Services/SqlTemplateProvider.cs
new file mode 100644
index 00000000..75ca9384
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/Services/SqlTemplateProvider.cs
@@ -0,0 +1,395 @@
+using System.Collections.Generic;
+using System.Text;
+using Erp.SqlQueryManager.Domain.Shared;
+using Volo.Abp.DependencyInjection;
+
+namespace Erp.SqlQueryManager.Domain.Services;
+
+public class SqlTemplateProvider : ISqlTemplateProvider, ITransientDependency
+{
+ public string GetStoredProcedureTemplate(string procedureName, string schemaName = "dbo")
+ {
+ return $@"-- =============================================
+-- Author:
+-- Create date:
+-- Description:
+-- =============================================
+CREATE OR ALTER PROCEDURE [{schemaName}].[{procedureName}]
+ -- Add parameters here
+ @Parameter1 INT = NULL,
+ @Parameter2 NVARCHAR(100) = NULL
+AS
+BEGIN
+ -- SET NOCOUNT ON added to prevent extra result sets from
+ -- interfering with SELECT statements.
+ SET NOCOUNT ON;
+
+ -- Insert statements for procedure here
+ SELECT
+ @Parameter1 AS Parameter1,
+ @Parameter2 AS Parameter2
+
+ -- Example error handling
+ BEGIN TRY
+ -- Your logic here
+
+ END TRY
+ BEGIN CATCH
+ -- Error handling
+ DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE();
+ DECLARE @ErrorSeverity INT = ERROR_SEVERITY();
+ DECLARE @ErrorState INT = ERROR_STATE();
+
+ RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState);
+ END CATCH
+END
+GO";
+ }
+
+ public string GetViewTemplate(string viewName, string schemaName = "dbo", bool withSchemaBinding = false)
+ {
+ var schemaBindingClause = withSchemaBinding ? " WITH SCHEMABINDING" : "";
+
+ return $@"-- =============================================
+-- Author:
+-- Create date:
+-- Description:
+-- =============================================
+CREATE OR ALTER VIEW [{schemaName}].[{viewName}]{schemaBindingClause}
+AS
+ -- Define your SELECT statement here
+ SELECT
+ Column1,
+ Column2,
+ Column3
+ FROM
+ TableName
+ WHERE
+ -- Add your conditions
+ 1 = 1
+GO";
+ }
+
+ public string GetFunctionTemplate(string functionName, SqlFunctionType functionType, string schemaName = "dbo")
+ {
+ return functionType switch
+ {
+ SqlFunctionType.ScalarFunction => GetScalarFunctionTemplate(functionName, schemaName),
+ SqlFunctionType.TableValuedFunction => GetTableValuedFunctionTemplate(functionName, schemaName),
+ SqlFunctionType.InlineTableValuedFunction => GetInlineTableValuedFunctionTemplate(functionName, schemaName),
+ _ => GetScalarFunctionTemplate(functionName, schemaName)
+ };
+ }
+
+ private string GetScalarFunctionTemplate(string functionName, string schemaName)
+ {
+ return $@"-- =============================================
+-- Author:
+-- Create date:
+-- Description: Scalar function that returns a single value
+-- =============================================
+CREATE OR ALTER FUNCTION [{schemaName}].[{functionName}]
+(
+ -- Add parameters here
+ @Parameter1 INT,
+ @Parameter2 NVARCHAR(100)
+)
+RETURNS INT
+AS
+BEGIN
+ -- Declare the return variable here
+ DECLARE @Result INT;
+
+ -- Add your logic here
+ SELECT @Result = COUNT(*)
+ FROM YourTable
+ WHERE Column1 = @Parameter1;
+
+ -- Return the result
+ RETURN @Result;
+END
+GO";
+ }
+
+ private string GetTableValuedFunctionTemplate(string functionName, string schemaName)
+ {
+ return $@"-- =============================================
+-- Author:
+-- Create date:
+-- Description: Multi-statement table-valued function
+-- =============================================
+CREATE OR ALTER FUNCTION [{schemaName}].[{functionName}]
+(
+ -- Add parameters here
+ @Parameter1 INT,
+ @Parameter2 NVARCHAR(100)
+)
+RETURNS @ResultTable TABLE
+(
+ -- Define the structure of the result table
+ Id INT,
+ Name NVARCHAR(100),
+ Value DECIMAL(18,2)
+)
+AS
+BEGIN
+ -- Fill the table variable with data
+ INSERT INTO @ResultTable (Id, Name, Value)
+ SELECT
+ Id,
+ Name,
+ Value
+ FROM
+ YourTable
+ WHERE
+ Column1 = @Parameter1;
+
+ -- Return
+ RETURN;
+END
+GO";
+ }
+
+ private string GetInlineTableValuedFunctionTemplate(string functionName, string schemaName)
+ {
+ return $@"-- =============================================
+-- Author:
+-- Create date:
+-- Description: Inline table-valued function
+-- =============================================
+CREATE OR ALTER FUNCTION [{schemaName}].[{functionName}]
+(
+ -- Add parameters here
+ @Parameter1 INT,
+ @Parameter2 NVARCHAR(100)
+)
+RETURNS TABLE
+AS
+RETURN
+(
+ -- Add your SELECT statement here
+ SELECT
+ Id,
+ Name,
+ Value,
+ CreatedDate
+ FROM
+ YourTable
+ WHERE
+ Column1 = @Parameter1
+ AND Column2 LIKE '%' + @Parameter2 + '%'
+)
+GO";
+ }
+
+ public string GetQueryTemplate(string queryType)
+ {
+ return queryType?.ToUpperInvariant() switch
+ {
+ "SELECT" => GetSelectTemplate(),
+ "INSERT" => GetInsertTemplate(),
+ "UPDATE" => GetUpdateTemplate(),
+ "DELETE" => GetDeleteTemplate(),
+ "JOIN" => GetJoinTemplate(),
+ "CTE" => GetCteTemplate(),
+ "PIVOT" => GetPivotTemplate(),
+ "TRANSACTION" => GetTransactionTemplate(),
+ _ => GetSelectTemplate()
+ };
+ }
+
+ private string GetSelectTemplate()
+ {
+ return @"-- Basic SELECT query
+SELECT
+ Column1,
+ Column2,
+ Column3
+FROM
+ TableName
+WHERE
+ -- Add your conditions
+ Column1 = 'value'
+ AND IsActive = 1
+ORDER BY
+ Column1 ASC;";
+ }
+
+ private string GetInsertTemplate()
+ {
+ return @"-- INSERT statement
+INSERT INTO TableName
+(
+ Column1,
+ Column2,
+ Column3,
+ CreatedDate
+)
+VALUES
+(
+ 'Value1',
+ 'Value2',
+ 123,
+ GETDATE()
+);
+
+-- Or with SELECT
+INSERT INTO TableName (Column1, Column2)
+SELECT
+ Column1,
+ Column2
+FROM
+ SourceTable
+WHERE
+ Condition = 1;";
+ }
+
+ private string GetUpdateTemplate()
+ {
+ return @"-- UPDATE statement
+UPDATE TableName
+SET
+ Column1 = 'NewValue',
+ Column2 = 'NewValue2',
+ UpdatedDate = GETDATE()
+WHERE
+ Id = 123
+ AND IsActive = 1;";
+ }
+
+ private string GetDeleteTemplate()
+ {
+ return @"-- DELETE statement
+DELETE FROM TableName
+WHERE
+ Id = 123
+ AND IsActive = 0;
+
+-- Soft delete pattern
+UPDATE TableName
+SET
+ IsDeleted = 1,
+ DeletedDate = GETDATE(),
+ DeletedBy = 'UserName'
+WHERE
+ Id = 123;";
+ }
+
+ private string GetJoinTemplate()
+ {
+ return @"-- JOIN query example
+SELECT
+ t1.Column1,
+ t1.Column2,
+ t2.Column3,
+ t3.Column4
+FROM
+ Table1 t1
+ INNER JOIN Table2 t2 ON t1.Id = t2.Table1Id
+ LEFT JOIN Table3 t3 ON t2.Id = t3.Table2Id
+WHERE
+ t1.IsActive = 1
+ AND t2.Status = 'Active'
+ORDER BY
+ t1.Column1;";
+ }
+
+ private string GetCteTemplate()
+ {
+ return @"-- Common Table Expression (CTE) example
+WITH CTE_Name AS
+(
+ SELECT
+ Column1,
+ Column2,
+ COUNT(*) as RecordCount
+ FROM
+ TableName
+ WHERE
+ IsActive = 1
+ GROUP BY
+ Column1, Column2
+)
+SELECT
+ *
+FROM
+ CTE_Name
+WHERE
+ RecordCount > 5
+ORDER BY
+ RecordCount DESC;";
+ }
+
+ private string GetPivotTemplate()
+ {
+ return @"-- PIVOT example
+SELECT
+ *
+FROM
+(
+ SELECT
+ Category,
+ Year,
+ Amount
+ FROM
+ Sales
+) AS SourceTable
+PIVOT
+(
+ SUM(Amount)
+ FOR Year IN ([2021], [2022], [2023], [2024])
+) AS PivotTable
+ORDER BY
+ Category;";
+ }
+
+ private string GetTransactionTemplate()
+ {
+ return @"-- Transaction example
+BEGIN TRANSACTION;
+
+BEGIN TRY
+ -- Your SQL statements here
+ UPDATE Table1
+ SET Column1 = 'Value'
+ WHERE Id = 1;
+
+ INSERT INTO Table2 (Column1, Column2)
+ VALUES ('Value1', 'Value2');
+
+ DELETE FROM Table3
+ WHERE Id = 123;
+
+ -- Commit if all successful
+ COMMIT TRANSACTION;
+END TRY
+BEGIN CATCH
+ -- Rollback on error
+ ROLLBACK TRANSACTION;
+
+ -- Return error information
+ SELECT
+ ERROR_NUMBER() AS ErrorNumber,
+ ERROR_SEVERITY() AS ErrorSeverity,
+ ERROR_STATE() AS ErrorState,
+ ERROR_PROCEDURE() AS ErrorProcedure,
+ ERROR_LINE() AS ErrorLine,
+ ERROR_MESSAGE() AS ErrorMessage;
+END CATCH;";
+ }
+
+ public List GetAvailableQueryTemplates()
+ {
+ return new List
+ {
+ new() { Type = "SELECT", Name = "Basic Select", Description = "Simple SELECT query with WHERE and ORDER BY" },
+ new() { Type = "INSERT", Name = "Insert Data", Description = "INSERT statement with VALUES or SELECT" },
+ new() { Type = "UPDATE", Name = "Update Data", Description = "UPDATE statement with conditions" },
+ new() { Type = "DELETE", Name = "Delete Data", Description = "DELETE statement with soft delete example" },
+ new() { Type = "JOIN", Name = "Join Tables", Description = "Query with INNER and LEFT JOINs" },
+ new() { Type = "CTE", Name = "Common Table Expression", Description = "CTE (WITH clause) example" },
+ new() { Type = "PIVOT", Name = "Pivot Table", Description = "PIVOT query for data transformation" },
+ new() { Type = "TRANSACTION", Name = "Transaction", Description = "Transaction with error handling" }
+ };
+ }
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/SqlQueryManagerDbProperties.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/SqlQueryManagerDbProperties.cs
new file mode 100644
index 00000000..b50bf12a
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/SqlQueryManagerDbProperties.cs
@@ -0,0 +1,19 @@
+namespace Erp.SqlQueryManager;
+
+public static class Prefix
+{
+ public static string MenuPrefix { get; set; } = "Sqm";
+ public static string HostPrefix { get; set; } = "T";
+ public static string? DbSchema { get; set; } = null;
+
+ public const string ConnectionStringName = "SqlQueryManager";
+}
+
+public static class TablePrefix
+{
+ public static string ByName(string tableName)
+ {
+ return $"{Prefix.MenuPrefix}_{Prefix.HostPrefix}_{tableName}";
+ }
+}
+
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/SqlQueryManagerDomainModule.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/SqlQueryManagerDomainModule.cs
new file mode 100644
index 00000000..e00c5838
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.Domain/SqlQueryManagerDomainModule.cs
@@ -0,0 +1,17 @@
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.Domain;
+using Volo.Abp.Modularity;
+
+namespace Erp.SqlQueryManager;
+
+[DependsOn(
+ typeof(AbpDddDomainModule),
+ typeof(SqlQueryManagerDomainSharedModule)
+)]
+public class SqlQueryManagerDomainModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ // Domain services configuration can be added here
+ }
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/Erp.SqlQueryManager.EntityFrameworkCore.csproj b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/Erp.SqlQueryManager.EntityFrameworkCore.csproj
new file mode 100644
index 00000000..e129f51e
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/Erp.SqlQueryManager.EntityFrameworkCore.csproj
@@ -0,0 +1,15 @@
+
+
+
+
+
+ net9.0
+ Erp.SqlQueryManager
+
+
+
+
+
+
+
+
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/FodyWeavers.xml b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/FodyWeavers.xml
new file mode 100644
index 00000000..00e1d9a1
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/FodyWeavers.xsd b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/FodyWeavers.xsd
new file mode 100644
index 00000000..3f3946e2
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/SqlQueryManagerDbContext.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/SqlQueryManagerDbContext.cs
new file mode 100644
index 00000000..07e903ec
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/SqlQueryManagerDbContext.cs
@@ -0,0 +1,27 @@
+using Erp.SqlQueryManager.Domain.Entities;
+using Microsoft.EntityFrameworkCore;
+using Volo.Abp.Data;
+using Volo.Abp.EntityFrameworkCore;
+
+namespace Erp.SqlQueryManager.EntityFrameworkCore;
+
+[ConnectionStringName("Default")]
+public class SqlQueryManagerDbContext : AbpDbContext
+{
+ public DbSet SqlQueries { get; set; }
+ public DbSet SqlStoredProcedures { get; set; }
+ public DbSet SqlViews { get; set; }
+ public DbSet SqlFunctions { get; set; }
+
+ public SqlQueryManagerDbContext(DbContextOptions options)
+ : base(options)
+ {
+ }
+
+ protected override void OnModelCreating(ModelBuilder builder)
+ {
+ base.OnModelCreating(builder);
+
+ builder.ConfigureSqlQueryManager();
+ }
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/SqlQueryManagerDbContextModelCreatingExtensions.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/SqlQueryManagerDbContextModelCreatingExtensions.cs
new file mode 100644
index 00000000..938f1be2
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/SqlQueryManagerDbContextModelCreatingExtensions.cs
@@ -0,0 +1,104 @@
+using Erp.SqlQueryManager.Domain.Entities;
+using Microsoft.EntityFrameworkCore;
+using Volo.Abp;
+using Volo.Abp.EntityFrameworkCore.Modeling;
+
+namespace Erp.SqlQueryManager.EntityFrameworkCore;
+
+public static class SqlQueryManagerDbContextModelCreatingExtensions
+{
+ public static void ConfigureSqlQueryManager(this ModelBuilder builder)
+ {
+ Check.NotNull(builder, nameof(builder));
+
+ // SqlQuery
+ builder.Entity(b =>
+ {
+ b.ToTable(TablePrefix.ByName(nameof(SqlQuery)), Prefix.DbSchema);
+ b.ConfigureByConvention();
+
+ b.Property(x => x.Code).IsRequired().HasMaxLength(128);
+ b.Property(x => x.Name).IsRequired().HasMaxLength(256);
+ b.Property(x => x.Description).HasMaxLength(1000);
+ b.Property(x => x.QueryText).IsRequired();
+ b.Property(x => x.DataSourceCode).IsRequired().HasMaxLength(128);
+ b.Property(x => x.Status).IsRequired();
+ b.Property(x => x.Category).HasMaxLength(128);
+ b.Property(x => x.Tags).HasMaxLength(500);
+ b.Property(x => x.Parameters).HasMaxLength(4000);
+
+ b.HasIndex(x => x.Code);
+ b.HasIndex(x => x.DataSourceCode);
+ b.HasIndex(x => x.Status);
+ b.HasIndex(x => x.Category);
+ });
+
+ // SqlStoredProcedure
+ builder.Entity(b =>
+ {
+ b.ToTable(TablePrefix.ByName(nameof(SqlStoredProcedure)), Prefix.DbSchema);
+ b.ConfigureByConvention();
+
+ b.Property(x => x.ProcedureName).IsRequired().HasMaxLength(128);
+ b.Property(x => x.SchemaName).IsRequired().HasMaxLength(128);
+ b.Property(x => x.DisplayName).IsRequired().HasMaxLength(256);
+ b.Property(x => x.Description).HasMaxLength(1000);
+ b.Property(x => x.ProcedureBody).IsRequired();
+ b.Property(x => x.DataSourceCode).IsRequired().HasMaxLength(128);
+ b.Property(x => x.Status).IsRequired();
+ b.Property(x => x.Category).HasMaxLength(128);
+ b.Property(x => x.Parameters).HasMaxLength(4000);
+
+ b.HasIndex(x => new { x.SchemaName, x.ProcedureName });
+ b.HasIndex(x => x.DataSourceCode);
+ b.HasIndex(x => x.Status);
+ b.HasIndex(x => x.IsDeployed);
+ });
+
+ // SqlView
+ builder.Entity(b =>
+ {
+ b.ToTable(TablePrefix.ByName(nameof(SqlView)), Prefix.DbSchema);
+ b.ConfigureByConvention();
+
+ b.Property(x => x.ViewName).IsRequired().HasMaxLength(128);
+ b.Property(x => x.SchemaName).IsRequired().HasMaxLength(128);
+ b.Property(x => x.DisplayName).IsRequired().HasMaxLength(256);
+ b.Property(x => x.Description).HasMaxLength(1000);
+ b.Property(x => x.ViewDefinition).IsRequired();
+ b.Property(x => x.DataSourceCode).IsRequired().HasMaxLength(128);
+ b.Property(x => x.Status).IsRequired();
+ b.Property(x => x.Category).HasMaxLength(128);
+
+ b.HasIndex(x => new { x.SchemaName, x.ViewName });
+ b.HasIndex(x => x.DataSourceCode);
+ b.HasIndex(x => x.Status);
+ b.HasIndex(x => x.IsDeployed);
+ });
+
+ // SqlFunction
+ builder.Entity(b =>
+ {
+ b.ToTable(TablePrefix.ByName(nameof(SqlFunction)), Prefix.DbSchema);
+ b.ConfigureByConvention();
+
+ b.Property(x => x.FunctionName).IsRequired().HasMaxLength(128);
+ b.Property(x => x.SchemaName).IsRequired().HasMaxLength(128);
+ b.Property(x => x.DisplayName).IsRequired().HasMaxLength(256);
+ b.Property(x => x.Description).HasMaxLength(1000);
+ b.Property(x => x.FunctionType).IsRequired();
+ b.Property(x => x.FunctionBody).IsRequired();
+ b.Property(x => x.ReturnType).IsRequired().HasMaxLength(256);
+ b.Property(x => x.DataSourceCode).IsRequired().HasMaxLength(128);
+ b.Property(x => x.Status).IsRequired();
+ b.Property(x => x.Category).HasMaxLength(128);
+ b.Property(x => x.Parameters).HasMaxLength(4000);
+
+ b.HasIndex(x => new { x.SchemaName, x.FunctionName });
+ b.HasIndex(x => x.DataSourceCode);
+ b.HasIndex(x => x.Status);
+ b.HasIndex(x => x.FunctionType);
+ b.HasIndex(x => x.IsDeployed);
+ });
+ }
+}
diff --git a/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/SqlQueryManagerEntityFrameworkCoreModule.cs b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/SqlQueryManagerEntityFrameworkCoreModule.cs
new file mode 100644
index 00000000..cc9c66ee
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/Erp.SqlQueryManager.EntityFrameworkCore/SqlQueryManagerEntityFrameworkCoreModule.cs
@@ -0,0 +1,20 @@
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.EntityFrameworkCore;
+using Volo.Abp.Modularity;
+
+namespace Erp.SqlQueryManager.EntityFrameworkCore;
+
+[DependsOn(
+ typeof(SqlQueryManagerDomainModule),
+ typeof(AbpEntityFrameworkCoreModule)
+)]
+public class SqlQueryManagerEntityFrameworkCoreModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ context.Services.AddAbpDbContext(options =>
+ {
+ options.AddDefaultRepositories(includeAllEntities: true);
+ });
+ }
+}
diff --git a/api/modules/Erp.SqlQueryManager/common.props b/api/modules/Erp.SqlQueryManager/common.props
new file mode 100644
index 00000000..87cf88dc
--- /dev/null
+++ b/api/modules/Erp.SqlQueryManager/common.props
@@ -0,0 +1,24 @@
+
+
+ latest
+ 0.1.0
+ $(NoWarn);CS1591
+ module
+
+
+
+
+
+ All
+ runtime; build; native; contentfiles; analyzers
+
+
+
+
+
+
+ $(NoWarn);0436
+
+
+
+
\ No newline at end of file
diff --git a/api/src/Erp.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs b/api/src/Erp.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs
index 46fb4c9f..980bed66 100644
--- a/api/src/Erp.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs
+++ b/api/src/Erp.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs
@@ -26,6 +26,7 @@ using System.Text.Json;
using static Erp.Platform.PlatformConsts;
using static Erp.Settings.SettingsConsts;
using Erp.Platform.Enums;
+using Erp.SqlQueryManager.EntityFrameworkCore;
namespace Erp.Platform.EntityFrameworkCore;
@@ -333,6 +334,7 @@ public class PlatformDbContext :
builder.ConfigureSettings();
builder.ConfigureMailQueue();
builder.ConfigureNotification();
+ builder.ConfigureSqlQueryManager();
//Saas
builder.Entity(b =>
diff --git a/api/src/Erp.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformEntityFrameworkCoreModule.cs b/api/src/Erp.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformEntityFrameworkCoreModule.cs
index 95c31d6d..725e2d7c 100644
--- a/api/src/Erp.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformEntityFrameworkCoreModule.cs
+++ b/api/src/Erp.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformEntityFrameworkCoreModule.cs
@@ -2,6 +2,7 @@
using Erp.Languages.EntityFrameworkCore;
using Erp.Notifications.EntityFrameworkCore;
using Erp.Settings.EntityFrameworkCore;
+using Erp.SqlQueryManager.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.BackgroundJobs.EntityFrameworkCore;
@@ -34,7 +35,8 @@ namespace Erp.Platform.EntityFrameworkCore;
typeof(AbpFeatureManagementEntityFrameworkCoreModule),
typeof(LanguagesEntityFrameworkCoreModule),
typeof(SettingsEntityFrameworkCoreModule),
- typeof(NotificationEntityFrameworkCoreModule)
+ typeof(NotificationEntityFrameworkCoreModule),
+ typeof(SqlQueryManagerEntityFrameworkCoreModule)
)]
public class PlatformEntityFrameworkCoreModule : AbpModule
{
diff --git a/api/src/Erp.Platform.EntityFrameworkCore/Erp.Platform.EntityFrameworkCore.csproj b/api/src/Erp.Platform.EntityFrameworkCore/Erp.Platform.EntityFrameworkCore.csproj
index a0e2e39a..36f011bf 100644
--- a/api/src/Erp.Platform.EntityFrameworkCore/Erp.Platform.EntityFrameworkCore.csproj
+++ b/api/src/Erp.Platform.EntityFrameworkCore/Erp.Platform.EntityFrameworkCore.csproj
@@ -28,6 +28,7 @@
+
diff --git a/api/src/Erp.Platform.EntityFrameworkCore/Migrations/20251204192908_Initial.Designer.cs b/api/src/Erp.Platform.EntityFrameworkCore/Migrations/20251205085044_Initial.Designer.cs
similarity index 98%
rename from api/src/Erp.Platform.EntityFrameworkCore/Migrations/20251204192908_Initial.Designer.cs
rename to api/src/Erp.Platform.EntityFrameworkCore/Migrations/20251205085044_Initial.Designer.cs
index c5db0512..3fae3871 100644
--- a/api/src/Erp.Platform.EntityFrameworkCore/Migrations/20251204192908_Initial.Designer.cs
+++ b/api/src/Erp.Platform.EntityFrameworkCore/Migrations/20251205085044_Initial.Designer.cs
@@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
namespace Erp.Platform.Migrations
{
[DbContext(typeof(PlatformDbContext))]
- [Migration("20251204192908_Initial")]
+ [Migration("20251205085044_Initial")]
partial class Initial
{
///
@@ -16250,6 +16250,409 @@ namespace Erp.Platform.Migrations
b.ToTable("Plat_H_SettingDefinition", (string)null);
});
+ modelBuilder.Entity("Erp.SqlQueryManager.Domain.Entities.SqlFunction", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uniqueidentifier");
+
+ b.Property("Category")
+ .HasMaxLength(128)
+ .HasColumnType("nvarchar(128)");
+
+ b.Property("CreationTime")
+ .HasColumnType("datetime2")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("CreatorId");
+
+ b.Property("DataSourceCode")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("nvarchar(128)");
+
+ b.Property("DeleterId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("DeleterId");
+
+ b.Property("DeletionTime")
+ .HasColumnType("datetime2")
+ .HasColumnName("DeletionTime");
+
+ b.Property("Description")
+ .HasMaxLength(1000)
+ .HasColumnType("nvarchar(1000)");
+
+ b.Property("DisplayName")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("nvarchar(256)");
+
+ b.Property("FunctionBody")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("FunctionName")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("nvarchar(128)");
+
+ b.Property("FunctionType")
+ .HasColumnType("int");
+
+ b.Property("IsDeleted")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bit")
+ .HasDefaultValue(false)
+ .HasColumnName("IsDeleted");
+
+ b.Property("IsDeployed")
+ .HasColumnType("bit");
+
+ b.Property("LastDeployedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("datetime2")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("LastModifierId");
+
+ b.Property("Parameters")
+ .HasMaxLength(4000)
+ .HasColumnType("nvarchar(4000)");
+
+ b.Property("ReturnType")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("nvarchar(256)");
+
+ b.Property("SchemaName")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("nvarchar(128)");
+
+ b.Property("Status")
+ .HasColumnType("int");
+
+ b.Property("TenantId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("TenantId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("DataSourceCode");
+
+ b.HasIndex("FunctionType");
+
+ b.HasIndex("IsDeployed");
+
+ b.HasIndex("Status");
+
+ b.HasIndex("SchemaName", "FunctionName");
+
+ b.ToTable("Sqm_T_SqlFunction", (string)null);
+ });
+
+ modelBuilder.Entity("Erp.SqlQueryManager.Domain.Entities.SqlQuery", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uniqueidentifier");
+
+ b.Property("Category")
+ .HasMaxLength(128)
+ .HasColumnType("nvarchar(128)");
+
+ b.Property("Code")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("nvarchar(128)");
+
+ b.Property("CreationTime")
+ .HasColumnType("datetime2")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("CreatorId");
+
+ b.Property("DataSourceCode")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("nvarchar(128)");
+
+ b.Property("DeleterId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("DeleterId");
+
+ b.Property("DeletionTime")
+ .HasColumnType("datetime2")
+ .HasColumnName("DeletionTime");
+
+ b.Property("Description")
+ .HasMaxLength(1000)
+ .HasColumnType("nvarchar(1000)");
+
+ b.Property("ExecutionCount")
+ .HasColumnType("int");
+
+ b.Property("IsDeleted")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bit")
+ .HasDefaultValue(false)
+ .HasColumnName("IsDeleted");
+
+ b.Property("IsModifyingData")
+ .HasColumnType("bit");
+
+ b.Property("LastExecutedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("datetime2")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("LastModifierId");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("nvarchar(256)");
+
+ b.Property("Parameters")
+ .HasMaxLength(4000)
+ .HasColumnType("nvarchar(4000)");
+
+ b.Property("QueryText")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Status")
+ .HasColumnType("int");
+
+ b.Property("Tags")
+ .HasMaxLength(500)
+ .HasColumnType("nvarchar(500)");
+
+ b.Property("TenantId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("TenantId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Category");
+
+ b.HasIndex("Code");
+
+ b.HasIndex("DataSourceCode");
+
+ b.HasIndex("Status");
+
+ b.ToTable("Sqm_T_SqlQuery", (string)null);
+ });
+
+ modelBuilder.Entity("Erp.SqlQueryManager.Domain.Entities.SqlStoredProcedure", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uniqueidentifier");
+
+ b.Property("Category")
+ .HasMaxLength(128)
+ .HasColumnType("nvarchar(128)");
+
+ b.Property("CreationTime")
+ .HasColumnType("datetime2")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("CreatorId");
+
+ b.Property("DataSourceCode")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("nvarchar(128)");
+
+ b.Property("DeleterId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("DeleterId");
+
+ b.Property("DeletionTime")
+ .HasColumnType("datetime2")
+ .HasColumnName("DeletionTime");
+
+ b.Property("Description")
+ .HasMaxLength(1000)
+ .HasColumnType("nvarchar(1000)");
+
+ b.Property("DisplayName")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("nvarchar(256)");
+
+ b.Property("IsDeleted")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bit")
+ .HasDefaultValue(false)
+ .HasColumnName("IsDeleted");
+
+ b.Property("IsDeployed")
+ .HasColumnType("bit");
+
+ b.Property("LastDeployedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("datetime2")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("LastModifierId");
+
+ b.Property("Parameters")
+ .HasMaxLength(4000)
+ .HasColumnType("nvarchar(4000)");
+
+ b.Property("ProcedureBody")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("ProcedureName")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("nvarchar(128)");
+
+ b.Property("SchemaName")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("nvarchar(128)");
+
+ b.Property("Status")
+ .HasColumnType("int");
+
+ b.Property("TenantId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("TenantId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("DataSourceCode");
+
+ b.HasIndex("IsDeployed");
+
+ b.HasIndex("Status");
+
+ b.HasIndex("SchemaName", "ProcedureName");
+
+ b.ToTable("Sqm_T_SqlStoredProcedure", (string)null);
+ });
+
+ modelBuilder.Entity("Erp.SqlQueryManager.Domain.Entities.SqlView", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uniqueidentifier");
+
+ b.Property("Category")
+ .HasMaxLength(128)
+ .HasColumnType("nvarchar(128)");
+
+ b.Property("CreationTime")
+ .HasColumnType("datetime2")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("CreatorId");
+
+ b.Property("DataSourceCode")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("nvarchar(128)");
+
+ b.Property("DeleterId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("DeleterId");
+
+ b.Property("DeletionTime")
+ .HasColumnType("datetime2")
+ .HasColumnName("DeletionTime");
+
+ b.Property("Description")
+ .HasMaxLength(1000)
+ .HasColumnType("nvarchar(1000)");
+
+ b.Property("DisplayName")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("nvarchar(256)");
+
+ b.Property("IsDeleted")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bit")
+ .HasDefaultValue(false)
+ .HasColumnName("IsDeleted");
+
+ b.Property("IsDeployed")
+ .HasColumnType("bit");
+
+ b.Property("LastDeployedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("datetime2")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("LastModifierId");
+
+ b.Property("SchemaName")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("nvarchar(128)");
+
+ b.Property("Status")
+ .HasColumnType("int");
+
+ b.Property("TenantId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("TenantId");
+
+ b.Property("ViewDefinition")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("ViewName")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("nvarchar(128)");
+
+ b.Property("WithSchemaBinding")
+ .HasColumnType("bit");
+
+ b.HasKey("Id");
+
+ b.HasIndex("DataSourceCode");
+
+ b.HasIndex("IsDeployed");
+
+ b.HasIndex("Status");
+
+ b.HasIndex("SchemaName", "ViewName");
+
+ b.ToTable("Sqm_T_SqlView", (string)null);
+ });
+
modelBuilder.Entity("MaterialUom", b =>
{
b.Property("AlternativeUomsId")
diff --git a/api/src/Erp.Platform.EntityFrameworkCore/Migrations/20251204192908_Initial.cs b/api/src/Erp.Platform.EntityFrameworkCore/Migrations/20251205085044_Initial.cs
similarity index 97%
rename from api/src/Erp.Platform.EntityFrameworkCore/Migrations/20251204192908_Initial.cs
rename to api/src/Erp.Platform.EntityFrameworkCore/Migrations/20251205085044_Initial.cs
index 91b7cbd0..8a3673a2 100644
--- a/api/src/Erp.Platform.EntityFrameworkCore/Migrations/20251204192908_Initial.cs
+++ b/api/src/Erp.Platform.EntityFrameworkCore/Migrations/20251205085044_Initial.cs
@@ -2864,6 +2864,129 @@ namespace Erp.Platform.Migrations
table.PrimaryKey("PK_Scp_T_SupplyType", x => x.Id);
});
+ migrationBuilder.CreateTable(
+ name: "Sqm_T_SqlFunction",
+ columns: table => new
+ {
+ Id = table.Column(type: "uniqueidentifier", nullable: false),
+ TenantId = table.Column(type: "uniqueidentifier", nullable: true),
+ FunctionName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false),
+ SchemaName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false),
+ DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false),
+ Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true),
+ FunctionType = table.Column(type: "int", nullable: false),
+ FunctionBody = table.Column(type: "nvarchar(max)", nullable: false),
+ ReturnType = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false),
+ DataSourceCode = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false),
+ Status = table.Column(type: "int", nullable: false),
+ Category = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true),
+ IsDeployed = table.Column(type: "bit", nullable: false),
+ LastDeployedAt = table.Column(type: "datetime2", nullable: true),
+ Parameters = table.Column(type: "nvarchar(4000)", maxLength: 4000, nullable: true),
+ CreationTime = table.Column(type: "datetime2", nullable: false),
+ CreatorId = table.Column(type: "uniqueidentifier", nullable: true),
+ LastModificationTime = table.Column(type: "datetime2", nullable: true),
+ LastModifierId = table.Column(type: "uniqueidentifier", nullable: true),
+ IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false),
+ DeleterId = table.Column(type: "uniqueidentifier", nullable: true),
+ DeletionTime = table.Column(type: "datetime2", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Sqm_T_SqlFunction", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Sqm_T_SqlQuery",
+ columns: table => new
+ {
+ Id = table.Column(type: "uniqueidentifier", nullable: false),
+ TenantId = table.Column(type: "uniqueidentifier", nullable: true),
+ Code = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false),
+ Name = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false),
+ Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true),
+ QueryText = table.Column(type: "nvarchar(max)", nullable: false),
+ DataSourceCode = table.Column