From 7708787446f2aae8e073b16bcaa8b01f10aeb8ac Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Thu, 20 Feb 2025 23:29:23 +1100 Subject: [PATCH 01/34] Changelog update --- CHANGELOG.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 315d9d8..3e138f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,13 +3,13 @@ All notable changes to this project documented here. ## [Released] +## [1.1.0](https://www.nuget.org/packages/QueryDB/1.1.0) - 2025-02-20 +### Added +- Execute scalar queries (returning a single value). + ## [1.0.0](https://www.nuget.org/packages/QueryDB/1.0.0) - 2025-02-18 ### Added - QueryDB framework for simplified querying and executing transactions across multiple database systems. - Retrieve data from database. - Execute database commands. - - Execute transactions while maintaining atomicity. - -## [1.1.0](https://www.nuget.org/packages/QueryDB/1.1.0) - 2025-02-20 -### Added -- Execute scalar queries (returning a single value). \ No newline at end of file + - Execute transactions while maintaining atomicity. \ No newline at end of file From 7db20f895d019900996121ae77604fb06f02a168 Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Thu, 20 Feb 2025 23:31:11 +1100 Subject: [PATCH 02/34] Readme update --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index f5b43a5..0e8ebfc 100644 --- a/README.md +++ b/README.md @@ -45,8 +45,14 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof ``` var result = dbContext.FetchData(); var result = dbContext.FetchData(); + ``` + ``` var result = dbContext.ExecuteScalar(); var result = dbContext.ExecuteScalar(); + ``` + ``` var result = dbContext.ExecuteCommand(); + ``` + ``` var result = dbContext.ExecuteTransaction(); ``` From a746ea5fd9e6f6e3dba76894d5f975303829dc1d Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Thu, 20 Feb 2025 23:37:56 +1100 Subject: [PATCH 03/34] Readme update --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0e8ebfc..180a647 100644 --- a/README.md +++ b/README.md @@ -34,13 +34,14 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof - Execute transactions while maintaining atomicity. ## Getting Started -- Setup DBContext with the database of your choice + +- Setup `DBContext` with the database of your choice ``` var dbContext = new DBContext(DB., ); ``` -- Execute DBContext commands +- Execute `DBContext` commands ``` var result = dbContext.FetchData(); From 1e95f3df7ee31c4c37bd948b698a399fd3aa6561 Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Thu, 20 Feb 2025 23:39:36 +1100 Subject: [PATCH 04/34] Readme update --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 180a647..395f431 100644 --- a/README.md +++ b/README.md @@ -35,13 +35,13 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof ## Getting Started -- Setup `DBContext` with the database of your choice +- _**Setup `DBContext` with the database of your choice**_ ``` var dbContext = new DBContext(DB., ); ``` -- Execute `DBContext` commands +- _**Execute `DBContext` commands**_ ``` var result = dbContext.FetchData(); From 07fd73145b043a296457e32349dc12d3d7b85fb4 Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Sun, 23 Feb 2025 14:00:25 +1100 Subject: [PATCH 05/34] Addition - Fetch Data Async --- QueryDB.Core.Tests/MSSQLTests.cs | 286 +++++++++++++++++++++++++- QueryDB.Core.Tests/MySQLTests.cs | 266 +++++++++++++++++++++++- QueryDB.Core.Tests/OracleTests.cs | 268 +++++++++++++++++++++++- QueryDB.Core.Tests/PostgreSQLTests.cs | 260 ++++++++++++++++++++++- QueryDB/DBContext.cs | 104 +++++++++- QueryDB/IDBContext.cs | 29 ++- QueryDB/MSSQL/Adapter.cs | 124 ++++++++++- QueryDB/MySQL/Adapter.cs | 123 ++++++++++- QueryDB/Oracle/Adapter.cs | 130 +++++++++++- QueryDB/PostgreSQL/Adapter.cs | 123 ++++++++++- QueryDB/Resources/Utils.cs | 57 +++++ 11 files changed, 1702 insertions(+), 68 deletions(-) diff --git a/QueryDB.Core.Tests/MSSQLTests.cs b/QueryDB.Core.Tests/MSSQLTests.cs index 5df4bd7..7db6b5d 100644 --- a/QueryDB.Core.Tests/MSSQLTests.cs +++ b/QueryDB.Core.Tests/MSSQLTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; namespace QueryDB.Core.Tests { @@ -174,7 +175,150 @@ public void Test_MSSQL_FetchData_Dictionary_DataTypes_Check() #endregion - #region Fetch Data Tests - << List FetchData(string selectSql) >> + #region Fetch Data Async Tests - << Task> FetchDataAsync(string selectSql, bool upperCaseKeys = false) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_FetchDataAsync_Dictionary_SelectQuery() + { + var selectSql = Queries.MSSQLQueries.TestDB.SelectSql; + var data = await new DBContext(DB.MSSQL, MSSQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(12, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["Agent_Name"] == "Benjamin"); + Assert.AreEqual("A009", agent.ReferenceData["Agent_Code"]); + Assert.AreEqual("Benjamin", agent.ReferenceData["Agent_Name"]); + Assert.AreEqual("Hampshair", agent.ReferenceData["Working_Area"]); + Assert.AreEqual("0.11", agent.ReferenceData["Commission"]); + Assert.AreEqual("008-22536178", agent.ReferenceData["Phone_No"]); + Assert.AreEqual("", agent.ReferenceData["Country"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_FetchDataAsync_Dictionary_SelectQuery_UpperCaseKeys() + { + var selectSql = Queries.MSSQLQueries.TestDB.SelectSql; + var data = await new DBContext(DB.MSSQL, MSSQLConnectionString).FetchDataAsync(selectSql, upperCaseKeys: true); + Assert.AreEqual(12, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["AGENT_NAME"] == "Benjamin"); + Assert.AreEqual("A009", agent.ReferenceData["AGENT_CODE"]); + Assert.AreEqual("Benjamin", agent.ReferenceData["AGENT_NAME"]); + Assert.AreEqual("Hampshair", agent.ReferenceData["WORKING_AREA"]); + Assert.AreEqual("0.11", agent.ReferenceData["COMMISSION"]); + Assert.AreEqual("008-22536178", agent.ReferenceData["PHONE_NO"]); + Assert.AreEqual("", agent.ReferenceData["COUNTRY"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_FetchDataAsync_Dictionary_SelectQuery_Joins() + { + var selectSql = Queries.MSSQLQueries.TestDB.SelectSql_Join; + var data = await new DBContext(DB.MSSQL, MSSQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["Agent_Code"] == "A004" && X.ReferenceData["Cust_Code"] == "C00006"); + Assert.AreEqual("A004", agent.ReferenceData["Agent_Code"]); + Assert.AreEqual("Ivan", agent.ReferenceData["Agent_Name"]); + Assert.AreEqual("C00006", agent.ReferenceData["Cust_Code"]); + Assert.AreEqual("Shilton", agent.ReferenceData["Cust_Name"]); + Assert.AreEqual("200104", agent.ReferenceData["Ord_Num"]); + Assert.AreEqual("1500.00", agent.ReferenceData["Ord_Amount"]); + Assert.AreEqual("500.00", agent.ReferenceData["Advance_Amount"]); + Assert.AreEqual("SOD", agent.ReferenceData["Ord_Description"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_FetchDataAsync_Dictionary_SelectQuery_Joins_UpperCaseKeys() + { + var selectSql = Queries.MSSQLQueries.TestDB.SelectSql_Join; + var data = await new DBContext(DB.MSSQL, MSSQLConnectionString).FetchDataAsync(selectSql, upperCaseKeys: true); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["AGENT_CODE"] == "A004" && X.ReferenceData["CUST_CODE"] == "C00006"); + Assert.AreEqual("A004", agent.ReferenceData["AGENT_CODE"]); + Assert.AreEqual("Ivan", agent.ReferenceData["AGENT_NAME"]); + Assert.AreEqual("C00006", agent.ReferenceData["CUST_CODE"]); + Assert.AreEqual("Shilton", agent.ReferenceData["CUST_NAME"]); + Assert.AreEqual("200104", agent.ReferenceData["ORD_NUM"]); + Assert.AreEqual("1500.00", agent.ReferenceData["ORD_AMOUNT"]); + Assert.AreEqual("500.00", agent.ReferenceData["ADVANCE_AMOUNT"]); + Assert.AreEqual("SOD", agent.ReferenceData["ORD_DESCRIPTION"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_FetchDataAsync_Dictionary_SelectQuery_Aliases() + { + var selectSql = Queries.MSSQLQueries.TestDB.SelectSql_Alias; + var data = await new DBContext(DB.MSSQL, MSSQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["Agent_Code"] == "A004" && X.ReferenceData["Cust_Code"] == "C00006"); + Assert.AreEqual("A004", agent.ReferenceData["Agent_Code"]); + Assert.AreEqual("Ivan", agent.ReferenceData["Agent"]); + Assert.AreEqual("Torento", agent.ReferenceData["Agent_Location"]); + Assert.AreEqual("C00006", agent.ReferenceData["Cust_Code"]); + Assert.AreEqual("Shilton", agent.ReferenceData["Customer"]); + Assert.AreEqual("Torento", agent.ReferenceData["Customer_Location"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_FetchDataAsync_Dictionary_SelectQuery_Aliases_UpperCaseKeys() + { + var selectSql = Queries.MSSQLQueries.TestDB.SelectSql_Alias; + var data = await new DBContext(DB.MSSQL, MSSQLConnectionString).FetchDataAsync(selectSql, upperCaseKeys: true); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["AGENT_CODE"] == "A004" && X.ReferenceData["CUST_CODE"] == "C00006"); + Assert.AreEqual("A004", agent.ReferenceData["AGENT_CODE"]); + Assert.AreEqual("Ivan", agent.ReferenceData["AGENT"]); + Assert.AreEqual("Torento", agent.ReferenceData["AGENT_LOCATION"]); + Assert.AreEqual("C00006", agent.ReferenceData["CUST_CODE"]); + Assert.AreEqual("Shilton", agent.ReferenceData["CUSTOMER"]); + Assert.AreEqual("Torento", agent.ReferenceData["CUSTOMER_LOCATION"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_FetchDataAsync_Dictionary_DataTypes_Check() + { + var selectSql = Queries.MSSQLQueries.TestDB.SelectSql_DataTypes; + var data = await new DBContext(DB.MSSQL, MSSQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(1, data.Count); + var dataType = data.FirstOrDefault(); + Assert.AreEqual("9223372036854775807", dataType.ReferenceData["BigInt_Column"]); + Assert.AreEqual("EjRWeJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", dataType.ReferenceData["Binary_Column"]); + Assert.AreEqual("True", dataType.ReferenceData["Bit_Column"]); + Assert.AreEqual("CharData", dataType.ReferenceData["Char_Column"]); + Assert.AreEqual("09/21/2024 00:00:00", ConvertToUSFormat(dataType.ReferenceData["Date_Column"])); + Assert.AreEqual("09/21/2024 08:34:51", ConvertToUSFormat(dataType.ReferenceData["DateTime_Column"])); + Assert.AreEqual("09/21/2024 08:34:51", ConvertToUSFormat(dataType.ReferenceData["DateTime2_Column"])); + Assert.AreEqual("09/20/2024 22:34:51", ConvertToUTCInUSFormat(dataType.ReferenceData["DateTimeOffset_Column"])); + Assert.AreEqual("123456.78", dataType.ReferenceData["Decimal_Column"]); + Assert.AreEqual("123456.78", dataType.ReferenceData["Float_Column"]); + Assert.AreEqual("EjRWeJA=", dataType.ReferenceData["Image_Column"]); + Assert.AreEqual("2147483647", dataType.ReferenceData["Int_Column"]); + Assert.AreEqual("123456.7800", dataType.ReferenceData["Money_Column"]); + Assert.AreEqual("NCharData", dataType.ReferenceData["NChar_Column"]); + Assert.AreEqual("NTextData", dataType.ReferenceData["NText_Column"]); + Assert.AreEqual("123456.78", dataType.ReferenceData["Numeric_Column"]); + Assert.AreEqual("NVarCharData", dataType.ReferenceData["NVarChar_Column"]); + Assert.AreEqual("123.45", dataType.ReferenceData["Real_Column"]); + Assert.AreEqual("09/21/2024 08:35:00", ConvertToUSFormat(dataType.ReferenceData["SmallDateTime_Column"])); + Assert.AreEqual("32767", dataType.ReferenceData["SmallInt_Column"]); + Assert.AreEqual("123456.7800", dataType.ReferenceData["SmallMoney_Column"]); + Assert.AreEqual("SampleVariant", dataType.ReferenceData["SqlVariant_Column"]); + Assert.AreEqual("TextData", dataType.ReferenceData["Text_Column"]); + Assert.AreEqual("08:34:51", dataType.ReferenceData["Time_Column"]); + Assert.AreEqual("255", dataType.ReferenceData["TinyInt_Column"]); + Assert.AreEqual("12345678-1234-1234-1234-123456789012", dataType.ReferenceData["UniqueIdentifier_Column"]); + Assert.AreEqual("EjRWeJA=", dataType.ReferenceData["VarBinary_Column"]); + Assert.AreEqual("VarCharData", dataType.ReferenceData["VarChar_Column"]); + Assert.AreEqual("XmlData", dataType.ReferenceData["Xml_Column"]); + } + + #endregion + + #region Fetch Data Tests - << List FetchData(string selectSql, bool strict = false) >> [TestMethod] [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] @@ -310,7 +454,143 @@ public void Test_MSSQL_FetchData_Entity_Strict_Error_Check() #endregion - #region Execute Scalar Tests - << string ExecuteScalar(string sqlStatement); >> + #region Fetch Data Async Tests - << Task> FetchDataAsync(string selectSql, bool strict = false) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_FetchDataAsync_Entity_SelectQuery() + { + var selectSql = Queries.MSSQLQueries.TestDB.SelectSql; + var data = await new DBContext(DB.MSSQL, MSSQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(12, data.Count); + var agent = data.FirstOrDefault(X => X.Agent_Name == "Benjamin"); + Assert.AreEqual("A009", agent.Agent_Code); + Assert.AreEqual("Benjamin", agent.Agent_Name); + Assert.AreEqual("Hampshair", agent.Working_Area); + Assert.AreEqual((decimal)0.11, agent.Commission); + Assert.AreEqual("008-22536178", agent.Phone_No); + Assert.AreEqual("", agent.Country); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_FetchDataAsync_Entity_SelectQuery_Joins() + { + var selectSql = Queries.MSSQLQueries.TestDB.SelectSql_Join; + var data = await new DBContext(DB.MSSQL, MSSQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.Agent_Code == "A004" && X.Cust_Code == "C00006"); + Assert.AreEqual("A004", agent.Agent_Code); + Assert.AreEqual("Ivan", agent.Agent_Name); + Assert.AreEqual("C00006", agent.Cust_Code); + Assert.AreEqual("Shilton", agent.Cust_Name); + Assert.AreEqual(200104, agent.Ord_Num); + Assert.AreEqual((decimal)1500.00, agent.Ord_Amount); + Assert.AreEqual((decimal)500.00, agent.Advance_Amount); + Assert.AreEqual("SOD", agent.Ord_Description); + // Non Existent Query Data + Assert.IsNull(agent.Agent); + Assert.IsNull(agent.Agent_Location); + Assert.IsNull(agent.Customer); + Assert.IsNull(agent.Customer_Location); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_FetchDataAsync_Entity_SelectQuery_Aliases() + { + var selectSql = Queries.MSSQLQueries.TestDB.SelectSql_Alias; + var data = await new DBContext(DB.MSSQL, MSSQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.Agent_Code == "A004" && X.Cust_Code == "C00006"); + Assert.AreEqual("A004", agent.Agent_Code); + Assert.AreEqual("Ivan", agent.Agent); + Assert.AreEqual("Torento", agent.Agent_Location); + Assert.AreEqual("C00006", agent.Cust_Code); + Assert.AreEqual("Shilton", agent.Customer); + Assert.AreEqual("Torento", agent.Customer_Location); + // Non Existent Query Data + Assert.IsNull(agent.Agent_Name); + Assert.IsNull(agent.Cust_Name); + Assert.AreEqual(0, agent.Ord_Num); + Assert.AreEqual(0, agent.Ord_Amount); + Assert.AreEqual(0, agent.Advance_Amount); + Assert.IsNull(agent.Ord_Description); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_FetchDataAsync_Entity_DataTypes_Check() + { + var selectSql = Queries.MSSQLQueries.TestDB.SelectSql_DataTypes; + var data = await new DBContext(DB.MSSQL, MSSQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(1, data.Count); + var dataType = data.FirstOrDefault(); + Assert.AreEqual(9223372036854775807, dataType.BigInt_Column); + Assert.AreEqual("EjRWeJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", ConvertByteArrayToBase64(dataType.Binary_Column)); + Assert.IsTrue(dataType.Bit_Column); + Assert.AreEqual("CharData", dataType.Char_Column); + Assert.AreEqual("09/21/2024 00:00:00", ConvertToUSFormat(dataType.Date_Column.ToString())); + Assert.AreEqual("09/21/2024 08:34:51", ConvertToUSFormat(dataType.DateTime_Column.ToString())); + Assert.AreEqual("09/21/2024 08:34:51", ConvertToUSFormat(dataType.DateTime2_Column.ToString())); + Assert.AreEqual("09/20/2024 22:34:51", ConvertToUTCInUSFormat(dataType.DateTimeOffset_Column.ToString())); + Assert.AreEqual((decimal)123456.78, dataType.Decimal_Column); + Assert.AreEqual((double)123456.78, dataType.Float_Column); + Assert.AreEqual("EjRWeJA=", ConvertByteArrayToBase64(dataType.Image_Column)); + Assert.AreEqual(2147483647, dataType.Int_Column); + Assert.AreEqual((decimal)123456.7800, dataType.Money_Column); + Assert.AreEqual("NCharData", dataType.NChar_Column); + Assert.AreEqual("NTextData", dataType.NText_Column); + Assert.AreEqual((decimal)123456.78, dataType.Numeric_Column); + Assert.AreEqual("NVarCharData", dataType.NVarChar_Column); + Assert.AreEqual((float)123.45, dataType.Real_Column); + Assert.AreEqual("09/21/2024 08:35:00", ConvertToUSFormat(dataType.SmallDateTime_Column.ToString())); + Assert.AreEqual(32767, dataType.SmallInt_Column); + Assert.AreEqual((decimal)123456.7800, dataType.SmallMoney_Column); + Assert.AreEqual("SampleVariant", dataType.SqlVariant_Column.ToString()); + Assert.AreEqual("TextData", dataType.Text_Column); + Assert.AreEqual("08:34:51", dataType.Time_Column.ToString()); + Assert.AreEqual(255, dataType.TinyInt_Column); + Assert.AreEqual("12345678-1234-1234-1234-123456789012", dataType.UniqueIdentifier_Column.ToString()); + Assert.AreEqual("EjRWeJA=", ConvertByteArrayToBase64(dataType.VarBinary_Column)); + Assert.AreEqual("VarCharData", dataType.VarChar_Column); + Assert.AreEqual("XmlData", dataType.Xml_Column); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_FetchDataAsync_Entity_Strict_Check() + { + var selectSql = Queries.MSSQLQueries.TestDB.SelectSql_Strict; + var data = await new DBContext(DB.MSSQL, MSSQLConnectionString).FetchDataAsync(selectSql, strict: true); + Assert.AreEqual(34, data.Count); + var dataType = data.FirstOrDefault(); + Assert.AreEqual("A003", dataType.Agent_Code); + Assert.AreEqual("Alex", dataType.Agent); + Assert.AreEqual("C00013", dataType.Cust_Code); + Assert.AreEqual("Holmes", dataType.Customer); + Assert.AreEqual(200100, dataType.Ord_Num); + Assert.AreEqual((decimal)1000.00, dataType.Ord_Amount); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_FetchDataAsync_Entity_Strict_Error_Check() + { + var selectSql = Queries.MSSQLQueries.TestDB.SelectSql_Strict; + try + { + var data = await new DBContext(DB.MSSQL, MSSQLConnectionString).FetchDataAsync(selectSql, strict: true); + } + catch (IndexOutOfRangeException ex) + { + Assert.AreEqual("Agent_Name", ex.Message); + } + } + + #endregion + + #region Execute Scalar Tests - << string ExecuteScalar(string sqlStatement) >> [TestMethod] [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] @@ -396,7 +676,7 @@ public void Test_MSSQL_ExecuteScalar_As_StringReturn_UnsupportedCommands() #endregion - #region Execute Scalar Tests - << T ExecuteScalar(string sqlStatement); >> + #region Execute Scalar Tests - << T ExecuteScalar(string sqlStatement) >> [TestMethod] [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] diff --git a/QueryDB.Core.Tests/MySQLTests.cs b/QueryDB.Core.Tests/MySQLTests.cs index ef00ffc..eb2f755 100644 --- a/QueryDB.Core.Tests/MySQLTests.cs +++ b/QueryDB.Core.Tests/MySQLTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; namespace QueryDB.Core.Tests { @@ -164,7 +165,140 @@ public void Test_MySQL_FetchData_Dictionary_DataTypes_Check() #endregion - #region Fetch Data Tests - << List FetchData(string selectSql) >> + #region Fetch Data Async Tests - << Task> FetchDataAsync(string selectSql, bool upperCaseKeys = false) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_FetchDataAsync_Dictionary_SelectQuery() + { + var selectSql = Queries.MySQLQueries.TestDB.SelectSql; + var data = await new DBContext(DB.MySQL, MySQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(12, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["Agent_Name"] == "Benjamin"); + Assert.AreEqual("A009", agent.ReferenceData["Agent_Code"]); + Assert.AreEqual("Benjamin", agent.ReferenceData["Agent_Name"]); + Assert.AreEqual("Hampshair", agent.ReferenceData["Working_Area"]); + Assert.AreEqual("0.11", agent.ReferenceData["Commission"]); + Assert.AreEqual("008-22536178", agent.ReferenceData["Phone_No"]); + Assert.AreEqual("", agent.ReferenceData["Country"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_FetchDataAsync_Dictionary_SelectQuery_UpperCaseKeys() + { + var selectSql = Queries.MySQLQueries.TestDB.SelectSql; + var data = await new DBContext(DB.MySQL, MySQLConnectionString).FetchDataAsync(selectSql, upperCaseKeys: true); + Assert.AreEqual(12, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["AGENT_NAME"] == "Benjamin"); + Assert.AreEqual("A009", agent.ReferenceData["AGENT_CODE"]); + Assert.AreEqual("Benjamin", agent.ReferenceData["AGENT_NAME"]); + Assert.AreEqual("Hampshair", agent.ReferenceData["WORKING_AREA"]); + Assert.AreEqual("0.11", agent.ReferenceData["COMMISSION"]); + Assert.AreEqual("008-22536178", agent.ReferenceData["PHONE_NO"]); + Assert.AreEqual("", agent.ReferenceData["COUNTRY"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_FetchDataAsync_Dictionary_SelectQuery_Joins() + { + var selectSql = Queries.MySQLQueries.TestDB.SelectSql_Join; + var data = await new DBContext(DB.MySQL, MySQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["Agent_Code"] == "A004" && X.ReferenceData["Cust_Code"] == "C00006"); + Assert.AreEqual("A004", agent.ReferenceData["Agent_Code"]); + Assert.AreEqual("Ivan", agent.ReferenceData["Agent_Name"]); + Assert.AreEqual("C00006", agent.ReferenceData["Cust_Code"]); + Assert.AreEqual("Shilton", agent.ReferenceData["Cust_Name"]); + Assert.AreEqual("200104", agent.ReferenceData["Ord_Num"]); + Assert.AreEqual("1500.00", agent.ReferenceData["Ord_Amount"]); + Assert.AreEqual("500.00", agent.ReferenceData["Advance_Amount"]); + Assert.AreEqual("SOD", agent.ReferenceData["Ord_Description"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_FetchDataAsync_Dictionary_SelectQuery_Joins_UpperCaseKeys() + { + var selectSql = Queries.MySQLQueries.TestDB.SelectSql_Join; + var data = await new DBContext(DB.MySQL, MySQLConnectionString).FetchDataAsync(selectSql, upperCaseKeys: true); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["AGENT_CODE"] == "A004" && X.ReferenceData["CUST_CODE"] == "C00006"); + Assert.AreEqual("A004", agent.ReferenceData["AGENT_CODE"]); + Assert.AreEqual("Ivan", agent.ReferenceData["AGENT_NAME"]); + Assert.AreEqual("C00006", agent.ReferenceData["CUST_CODE"]); + Assert.AreEqual("Shilton", agent.ReferenceData["CUST_NAME"]); + Assert.AreEqual("200104", agent.ReferenceData["ORD_NUM"]); + Assert.AreEqual("1500.00", agent.ReferenceData["ORD_AMOUNT"]); + Assert.AreEqual("500.00", agent.ReferenceData["ADVANCE_AMOUNT"]); + Assert.AreEqual("SOD", agent.ReferenceData["ORD_DESCRIPTION"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_FetchDataAsync_Dictionary_SelectQuery_Aliases() + { + var selectSql = Queries.MySQLQueries.TestDB.SelectSql_Alias; + var data = await new DBContext(DB.MySQL, MySQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["Agent_Code"] == "A004" && X.ReferenceData["Cust_Code"] == "C00006"); + Assert.AreEqual("A004", agent.ReferenceData["Agent_Code"]); + Assert.AreEqual("Ivan", agent.ReferenceData["Agent"]); + Assert.AreEqual("Torento", agent.ReferenceData["Agent_Location"]); + Assert.AreEqual("C00006", agent.ReferenceData["Cust_Code"]); + Assert.AreEqual("Shilton", agent.ReferenceData["Customer"]); + Assert.AreEqual("Torento", agent.ReferenceData["Customer_Location"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_FetchDataAsync_Dictionary_SelectQuery_Aliases_UpperCaseKeys() + { + var selectSql = Queries.MySQLQueries.TestDB.SelectSql_Alias; + var data = await new DBContext(DB.MySQL, MySQLConnectionString).FetchDataAsync(selectSql, upperCaseKeys: true); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["AGENT_CODE"] == "A004" && X.ReferenceData["CUST_CODE"] == "C00006"); + Assert.AreEqual("A004", agent.ReferenceData["AGENT_CODE"]); + Assert.AreEqual("Ivan", agent.ReferenceData["AGENT"]); + Assert.AreEqual("Torento", agent.ReferenceData["AGENT_LOCATION"]); + Assert.AreEqual("C00006", agent.ReferenceData["CUST_CODE"]); + Assert.AreEqual("Shilton", agent.ReferenceData["CUSTOMER"]); + Assert.AreEqual("Torento", agent.ReferenceData["CUSTOMER_LOCATION"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_FetchDataAsync_Dictionary_DataTypes_Check() + { + var selectSql = Queries.MySQLQueries.TestDB.SelectSql_DataTypes; + var data = await new DBContext(DB.MySQL, MySQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(1, data.Count); + var dataType = data.FirstOrDefault(); + Assert.AreEqual("9223372036854775807", dataType.ReferenceData["BigInt_Column"]); + Assert.AreEqual("1", dataType.ReferenceData["Bit_Column"]); + Assert.AreEqual("A", dataType.ReferenceData["Char_Column"]); + Assert.AreEqual("09/21/2024 00:00:00", ConvertToUSFormat(dataType.ReferenceData["Date_Column"])); + Assert.AreEqual("09/21/2024 13:24:10", ConvertToUSFormat(dataType.ReferenceData["DateTime_Column"])); + Assert.AreEqual("12345.67", dataType.ReferenceData["Decimal_Column"]); + Assert.AreEqual("123.45", dataType.ReferenceData["Float_Column"]); + Assert.AreEqual("2147483647", dataType.ReferenceData["Int_Column"]); + Assert.AreEqual("This is a long text", dataType.ReferenceData["LongText_Column"]); + Assert.AreEqual("8388607", dataType.ReferenceData["MediumInt_Column"]); + Assert.AreEqual("This is a medium text", dataType.ReferenceData["MediumText_Column"]); + Assert.AreEqual("32767", dataType.ReferenceData["SmallInt_Column"]); + Assert.AreEqual("This is a text", dataType.ReferenceData["Text_Column"]); + Assert.AreEqual("13:24:10", dataType.ReferenceData["Time_Column"]); + Assert.AreEqual("09/21/2024 13:24:10", ConvertToUSFormat(dataType.ReferenceData["Timestamp_Column"])); + Assert.AreEqual("127", dataType.ReferenceData["TinyInt_Column"]); + Assert.AreEqual("This is a tiny text", dataType.ReferenceData["TinyText_Column"]); + Assert.AreEqual("3q2+7w==", dataType.ReferenceData["VarBinary_Column"]); + Assert.AreEqual("This is a varchar", dataType.ReferenceData["VarChar_Column"]); + } + + #endregion + + #region Fetch Data Tests - << List FetchData(string selectSql, bool strict = false) >> [TestMethod] [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] @@ -290,7 +424,133 @@ public void Test_MySQL_FetchData_Entity_Strict_Error_Check() #endregion - #region Execute Scalar Tests - << string ExecuteScalar(string sqlStatement); >> + #region Fetch Data Async Tests - << List FetchData(string selectSql, bool strict = false) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_FetchDataAsync_Entity_SelectQuery() + { + var selectSql = Queries.MySQLQueries.TestDB.SelectSql; + var data = await new DBContext(DB.MySQL, MySQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(12, data.Count); + var agent = data.FirstOrDefault(X => X.Agent_Name == "Benjamin"); + Assert.AreEqual("A009", agent.Agent_Code); + Assert.AreEqual("Benjamin", agent.Agent_Name); + Assert.AreEqual("Hampshair", agent.Working_Area); + Assert.AreEqual((decimal)0.11, agent.Commission); + Assert.AreEqual("008-22536178", agent.Phone_No); + Assert.AreEqual("", agent.Country); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_FetchDataAsync_Entity_SelectQuery_Joins() + { + var selectSql = Queries.MySQLQueries.TestDB.SelectSql_Join; + var data = await new DBContext(DB.MySQL, MySQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.Agent_Code == "A004" && X.Cust_Code == "C00006"); + Assert.AreEqual("A004", agent.Agent_Code); + Assert.AreEqual("Ivan", agent.Agent_Name); + Assert.AreEqual("C00006", agent.Cust_Code); + Assert.AreEqual("Shilton", agent.Cust_Name); + Assert.AreEqual(200104, agent.Ord_Num); + Assert.AreEqual((decimal)1500.00, agent.Ord_Amount); + Assert.AreEqual((decimal)500.00, agent.Advance_Amount); + Assert.AreEqual("SOD", agent.Ord_Description); + // Non Existent Query Data + Assert.IsNull(agent.Agent); + Assert.IsNull(agent.Agent_Location); + Assert.IsNull(agent.Customer); + Assert.IsNull(agent.Customer_Location); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_FetchDataAsync_Entity_SelectQuery_Aliases() + { + var selectSql = Queries.MySQLQueries.TestDB.SelectSql_Alias; + var data = await new DBContext(DB.MySQL, MySQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.Agent_Code == "A004" && X.Cust_Code == "C00006"); + Assert.AreEqual("A004", agent.Agent_Code); + Assert.AreEqual("Ivan", agent.Agent); + Assert.AreEqual("Torento", agent.Agent_Location); + Assert.AreEqual("C00006", agent.Cust_Code); + Assert.AreEqual("Shilton", agent.Customer); + Assert.AreEqual("Torento", agent.Customer_Location); + // Non Existent Query Data + Assert.IsNull(agent.Agent_Name); + Assert.IsNull(agent.Cust_Name); + Assert.AreEqual(0, agent.Ord_Num); + Assert.AreEqual(0, agent.Ord_Amount); + Assert.AreEqual(0, agent.Advance_Amount); + Assert.IsNull(agent.Ord_Description); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_FetchDataAsync_Entity_DataTypes_Check() + { + var selectSql = Queries.MySQLQueries.TestDB.SelectSql_DataTypes; + var data = await new DBContext(DB.MySQL, MySQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(1, data.Count); + var dataType = data.FirstOrDefault(); + Assert.AreEqual(9223372036854775807, dataType.BigInt_Column); + Assert.AreEqual((ulong?)1, dataType.Bit_Column); + Assert.AreEqual("A", dataType.Char_Column); + Assert.AreEqual("09/21/2024 00:00:00", ConvertToUSFormat(dataType.Date_Column.ToString())); + Assert.AreEqual("09/21/2024 13:24:10", ConvertToUSFormat(dataType.DateTime_Column.ToString())); + Assert.AreEqual((decimal)12345.67, dataType.Decimal_Column); + Assert.AreEqual((float)123.45, dataType.Float_Column); + Assert.AreEqual(2147483647, dataType.Int_Column); + Assert.AreEqual("This is a long text", dataType.LongText_Column); + Assert.AreEqual(8388607, dataType.MediumInt_Column); + Assert.AreEqual("This is a medium text", dataType.MediumText_Column); + Assert.AreEqual((short)32767, dataType.SmallInt_Column); + Assert.AreEqual("This is a text", dataType.Text_Column); + Assert.AreEqual("13:24:10", dataType.Time_Column.ToString()); + Assert.AreEqual("09/21/2024 13:24:10", ConvertToUSFormat(dataType.Timestamp_Column.ToString())); + Assert.AreEqual((sbyte?)127, dataType.TinyInt_Column); + Assert.AreEqual("This is a tiny text", dataType.TinyText_Column); + Assert.AreEqual("3q2+7w==", ConvertByteArrayToBase64(dataType.VarBinary_Column)); + Assert.AreEqual("This is a varchar", dataType.VarChar_Column); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_FetchDataAsync_Entity_Strict_Check() + { + var selectSql = Queries.MySQLQueries.TestDB.SelectSql_Strict; + var data = await new DBContext(DB.MySQL, MySQLConnectionString).FetchDataAsync(selectSql, strict: true); + Assert.AreEqual(34, data.Count); + var dataType = data.FirstOrDefault(); + Assert.AreEqual("A003", dataType.Agent_Code); + Assert.AreEqual("Alex", dataType.Agent); + Assert.AreEqual("C00013", dataType.Cust_Code); + Assert.AreEqual("Holmes", dataType.Customer); + Assert.AreEqual(200100, dataType.Ord_Num); + Assert.AreEqual((decimal)1000.00, dataType.Ord_Amount); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_FetchDataAsync_Entity_Strict_Error_Check() + { + var selectSql = Queries.MySQLQueries.TestDB.SelectSql_Strict; + try + { + var data = await new DBContext(DB.MySQL, MySQLConnectionString).FetchDataAsync(selectSql, strict: true); + } + catch (IndexOutOfRangeException ex) + { + Assert.AreEqual("Could not find specified column in results: Agent_Name", ex.Message); + } + } + + #endregion + + #region Execute Scalar Tests - << string ExecuteScalar(string sqlStatement) >> [TestMethod] [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] @@ -376,7 +636,7 @@ public void Test_MySQL_ExecuteScalar_As_StringReturn_UnsupportedCommands() #endregion - #region Execute Scalar Tests - << T ExecuteScalar(string sqlStatement); >> + #region Execute Scalar Tests - << T ExecuteScalar(string sqlStatement) >> [TestMethod] [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] diff --git a/QueryDB.Core.Tests/OracleTests.cs b/QueryDB.Core.Tests/OracleTests.cs index af5c9b8..420fc1f 100644 --- a/QueryDB.Core.Tests/OracleTests.cs +++ b/QueryDB.Core.Tests/OracleTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; namespace QueryDB.Core.Tests { @@ -165,7 +166,141 @@ public void Test_Oracle_FetchData_Dictionary_DataTypes_Check() #endregion - #region Fetch Data Tests - << List FetchData(string selectSql) >> + #region Fetch Data Async Tests - << List FetchData(string selectSql, bool upperCaseKeys = false) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_FetchDataAsync_Dictionary_SelectQuery() + { + var selectSql = Queries.OracleQueries.TestDB.SelectSql; + var data = await new DBContext(DB.Oracle, OracleConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(12, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["AGENT_NAME"] == "Benjamin"); + Assert.AreEqual("A009", agent.ReferenceData["AGENT_CODE"]); + Assert.AreEqual("Benjamin", agent.ReferenceData["AGENT_NAME"]); + Assert.AreEqual("Hampshair", agent.ReferenceData["WORKING_AREA"]); + Assert.AreEqual("0.11", agent.ReferenceData["COMMISSION"]); + Assert.AreEqual("008-22536178", agent.ReferenceData["PHONE_NO"]); + Assert.AreEqual("", agent.ReferenceData["COUNTRY"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_FetchDataAsync_Dictionary_SelectQuery_UpperCaseKeys() + { + var selectSql = Queries.OracleQueries.TestDB.SelectSql; + var data = await new DBContext(DB.Oracle, OracleConnectionString).FetchDataAsync(selectSql, upperCaseKeys: true); + Assert.AreEqual(12, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["AGENT_NAME"] == "Benjamin"); + Assert.AreEqual("A009", agent.ReferenceData["AGENT_CODE"]); + Assert.AreEqual("Benjamin", agent.ReferenceData["AGENT_NAME"]); + Assert.AreEqual("Hampshair", agent.ReferenceData["WORKING_AREA"]); + Assert.AreEqual("0.11", agent.ReferenceData["COMMISSION"]); + Assert.AreEqual("008-22536178", agent.ReferenceData["PHONE_NO"]); + Assert.AreEqual("", agent.ReferenceData["COUNTRY"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_FetchDataAsync_Dictionary_SelectQuery_Joins() + { + var selectSql = Queries.OracleQueries.TestDB.SelectSql_Join; + var data = await new DBContext(DB.Oracle, OracleConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["AGENT_CODE"] == "A004" && X.ReferenceData["CUST_CODE"] == "C00006"); + Assert.AreEqual("A004", agent.ReferenceData["AGENT_CODE"]); + Assert.AreEqual("Ivan", agent.ReferenceData["AGENT_NAME"]); + Assert.AreEqual("C00006", agent.ReferenceData["CUST_CODE"]); + Assert.AreEqual("Shilton", agent.ReferenceData["CUST_NAME"]); + Assert.AreEqual("200104", agent.ReferenceData["ORD_NUM"]); + Assert.AreEqual("1500", agent.ReferenceData["ORD_AMOUNT"]); + Assert.AreEqual("500", agent.ReferenceData["ADVANCE_AMOUNT"]); + Assert.AreEqual("SOD", agent.ReferenceData["ORD_DESCRIPTION"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_FetchDataAsync_Dictionary_SelectQuery_Joins_UpperCaseKeys() + { + var selectSql = Queries.OracleQueries.TestDB.SelectSql_Join; + var data = await new DBContext(DB.Oracle, OracleConnectionString).FetchDataAsync(selectSql, upperCaseKeys: true); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["AGENT_CODE"] == "A004" && X.ReferenceData["CUST_CODE"] == "C00006"); + Assert.AreEqual("A004", agent.ReferenceData["AGENT_CODE"]); + Assert.AreEqual("Ivan", agent.ReferenceData["AGENT_NAME"]); + Assert.AreEqual("C00006", agent.ReferenceData["CUST_CODE"]); + Assert.AreEqual("Shilton", agent.ReferenceData["CUST_NAME"]); + Assert.AreEqual("200104", agent.ReferenceData["ORD_NUM"]); + Assert.AreEqual("1500", agent.ReferenceData["ORD_AMOUNT"]); + Assert.AreEqual("500", agent.ReferenceData["ADVANCE_AMOUNT"]); + Assert.AreEqual("SOD", agent.ReferenceData["ORD_DESCRIPTION"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_FetchDataAsync_Dictionary_SelectQuery_Aliases() + { + var selectSql = Queries.OracleQueries.TestDB.SelectSql_Alias; + var data = await new DBContext(DB.Oracle, OracleConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["AGENT_CODE"] == "A004" && X.ReferenceData["CUST_CODE"] == "C00006"); + Assert.AreEqual("A004", agent.ReferenceData["AGENT_CODE"]); + Assert.AreEqual("Ivan", agent.ReferenceData["AGENT"]); + Assert.AreEqual("Torento", agent.ReferenceData["AGENT_LOCATION"]); + Assert.AreEqual("C00006", agent.ReferenceData["CUST_CODE"]); + Assert.AreEqual("Shilton", agent.ReferenceData["CUSTOMER"]); + Assert.AreEqual("Torento", agent.ReferenceData["CUSTOMER_LOCATION"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_FetchDataAsync_Dictionary_SelectQuery_Aliases_UpperCaseKeys() + { + var selectSql = Queries.OracleQueries.TestDB.SelectSql_Alias; + var data = await new DBContext(DB.Oracle, OracleConnectionString).FetchDataAsync(selectSql, upperCaseKeys: true); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["AGENT_CODE"] == "A004" && X.ReferenceData["CUST_CODE"] == "C00006"); + Assert.AreEqual("A004", agent.ReferenceData["AGENT_CODE"]); + Assert.AreEqual("Ivan", agent.ReferenceData["AGENT"]); + Assert.AreEqual("Torento", agent.ReferenceData["AGENT_LOCATION"]); + Assert.AreEqual("C00006", agent.ReferenceData["CUST_CODE"]); + Assert.AreEqual("Shilton", agent.ReferenceData["CUSTOMER"]); + Assert.AreEqual("Torento", agent.ReferenceData["CUSTOMER_LOCATION"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_FetchDataAsync_Dictionary_DataTypes_Check() + { + var selectSql = Queries.OracleQueries.TestDB.SelectSql_DataTypes; + var data = await new DBContext(DB.Oracle, OracleConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(2, data.Count); + var dataType = data.FirstOrDefault(); + Assert.AreEqual(GetBase64Content(Environment.CurrentDirectory + "/SeedData/oracle.sql"), dataType.ReferenceData["BFILE_COLUMN"]); + Assert.AreEqual("3q2+7w==", dataType.ReferenceData["BLOB_COLUMN"]); + Assert.AreEqual("A", dataType.ReferenceData["CHAR_COLUMN"]); + Assert.AreEqual("Sample CLOB data", dataType.ReferenceData["CLOB_COLUMN"]); + Assert.AreEqual("09/21/2024 00:00:00", ConvertToUSFormat(dataType.ReferenceData["DATE_COLUMN"])); + Assert.AreEqual("123.45", dataType.ReferenceData["FLOAT_COLUMN"]); + Assert.AreEqual("123", dataType.ReferenceData["INTEGER_COLUMN"]); + Assert.AreEqual("14", dataType.ReferenceData["INTERVALYEARTOMONTH_COLUMN"]); + Assert.AreEqual("1.02:03:04.5000000", dataType.ReferenceData["INTERNALDAYTOSECOND_COLUMN"]); + Assert.AreEqual("Sample LONG data", dataType.ReferenceData["LONG_COLUMN"]); + Assert.AreEqual("A", dataType.ReferenceData["NCHAR_COLUMN"]); + Assert.AreEqual("Sample NCLOB data", dataType.ReferenceData["NCLOB_COLUMN"]); + Assert.AreEqual("123.45", dataType.ReferenceData["NUMBER_COLUMN"]); + Assert.AreEqual("Sample NVARCHAR2 data", dataType.ReferenceData["NVARCHAR2_COLUMN"]); + Assert.AreEqual("3q2+7w==", dataType.ReferenceData["RAW_COLUMN"]); + Assert.AreEqual("09/21/2024 12:34:56", ConvertToUSFormat(dataType.ReferenceData["TIMESTAMP_COLUMN"])); + Assert.AreEqual("09/21/2024 12:34:56", ConvertToUSFormat(dataType.ReferenceData["TIMESTAMPWITHTIMEZONE_COLUMN"])); + Assert.AreEqual("09/21/2024 12:34:56", ConvertToUSFormat(dataType.ReferenceData["TIMESTAMPWITHLOCALTIMEZONE_COLUMN"])); + Assert.AreEqual("Sample VARCHAR data", dataType.ReferenceData["VARCHAR_COLUMN"]); + Assert.AreEqual("Sample VARCHAR2 data", dataType.ReferenceData["VARCHAR2_COLUMN"]); + } + + #endregion + + #region Fetch Data Tests - << List FetchData(string selectSql, bool strict = false) >> [TestMethod] [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] @@ -292,7 +427,134 @@ public void Test_Oracle_FetchData_Entity_Strict_Error_Check() #endregion - #region Execute Scalar Tests - << string ExecuteScalar(string sqlStatement); >> + #region Fetch Data Async Tests - << List FetchData(string selectSql, bool strict = false) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_FetchDataAsync_Entity_SelectQuery() + { + var selectSql = Queries.OracleQueries.TestDB.SelectSql; + var data = await new DBContext(DB.Oracle, OracleConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(12, data.Count); + var agent = data.FirstOrDefault(X => X.Agent_Name == "Benjamin"); + Assert.AreEqual("A009", agent.Agent_Code); + Assert.AreEqual("Benjamin", agent.Agent_Name); + Assert.AreEqual("Hampshair", agent.Working_Area); + Assert.AreEqual(0.11, agent.Commission); + Assert.AreEqual("008-22536178", agent.Phone_No); + Assert.IsNull(agent.Country); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_FetchDataAsync_Entity_SelectQuery_Joins() + { + var selectSql = Queries.OracleQueries.TestDB.SelectSql_Join; + var data = await new DBContext(DB.Oracle, OracleConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.Agent_Code == "A004" && X.Cust_Code == "C00006"); + Assert.AreEqual("A004", agent.Agent_Code); + Assert.AreEqual("Ivan", agent.Agent_Name); + Assert.AreEqual("C00006", agent.Cust_Code); + Assert.AreEqual("Shilton", agent.Cust_Name); + Assert.AreEqual(200104, agent.Ord_Num); + Assert.AreEqual(1500.00, agent.Ord_Amount); + Assert.AreEqual(500.00, agent.Advance_Amount); + Assert.AreEqual("SOD", agent.Ord_Description); + // Non Existent Query Data + Assert.IsNull(agent.Agent); + Assert.IsNull(agent.Agent_Location); + Assert.IsNull(agent.Customer); + Assert.IsNull(agent.Customer_Location); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_FetchDataAsync_Entity_SelectQuery_Aliases() + { + var selectSql = Queries.OracleQueries.TestDB.SelectSql_Alias; + var data = await new DBContext(DB.Oracle, OracleConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.Agent_Code == "A004" && X.Cust_Code == "C00006"); + Assert.AreEqual("A004", agent.Agent_Code); + Assert.AreEqual("Ivan", agent.Agent); + Assert.AreEqual("Torento", agent.Agent_Location); + Assert.AreEqual("C00006", agent.Cust_Code); + Assert.AreEqual("Shilton", agent.Customer); + Assert.AreEqual("Torento", agent.Customer_Location); + // Non Existent Query Data + Assert.IsNull(agent.Agent_Name); + Assert.IsNull(agent.Cust_Name); + Assert.AreEqual(0, agent.Ord_Num); + Assert.AreEqual(0, agent.Ord_Amount); + Assert.AreEqual(0, agent.Advance_Amount); + Assert.IsNull(agent.Ord_Description); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_FetchDataAsync_Entity_DataTypes_Check() + { + var selectSql = Queries.OracleQueries.TestDB.SelectSql_DataTypes; + var data = await new DBContext(DB.Oracle, OracleConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(2, data.Count); + var dataType = data.FirstOrDefault(); + Assert.AreEqual(GetBase64Content(Environment.CurrentDirectory + "/SeedData/oracle.sql"), ConvertByteArrayToBase64(dataType.BFile_Column)); + Assert.AreEqual("3q2+7w==", ConvertByteArrayToBase64(dataType.Blob_Column)); + Assert.AreEqual("A", dataType.Char_Column); + Assert.AreEqual("Sample CLOB data", dataType.Clob_Column); + Assert.AreEqual("09/21/2024 00:00:00", ConvertToUSFormat(dataType.Date_Column.ToString())); + Assert.AreEqual((decimal)123.45, dataType.Float_Column); + Assert.AreEqual(123, (int)dataType.Integer_Column); + Assert.AreEqual(14, dataType.IntervalYearToMonth_Column); + Assert.AreEqual("1.02:03:04.5000000", dataType.InternalDayToSecond_Column.ToString()); + Assert.AreEqual("Sample LONG data", dataType.Long_Column); + Assert.AreEqual("A", dataType.NChar_Column); + Assert.AreEqual("Sample NCLOB data", dataType.NClob_Column); + Assert.AreEqual((decimal)123.45, dataType.Number_Column); + Assert.AreEqual("Sample NVARCHAR2 data", dataType.NVarchar2_Column); + Assert.AreEqual("3q2+7w==", ConvertByteArrayToBase64(dataType.Raw_Column)); + Assert.AreEqual("09/21/2024 12:34:56", ConvertToUSFormat(dataType.Timestamp_Column.ToString())); + Assert.AreEqual("09/21/2024 12:34:56", ConvertToUSFormat(dataType.TimestampWithTimeZone_Column.ToString())); + Assert.AreEqual("09/21/2024 12:34:56", ConvertToUSFormat(dataType.TimestampWithLocalTimeZone_Column.ToString())); + Assert.AreEqual("Sample VARCHAR data", dataType.Varchar_Column); + Assert.AreEqual("Sample VARCHAR2 data", dataType.Varchar2_Column); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_FetchDataAsync_Entity_Strict_Check() + { + var selectSql = Queries.OracleQueries.TestDB.SelectSql_Strict; + var data = await new DBContext(DB.Oracle, OracleConnectionString).FetchDataAsync(selectSql, strict: true); + Assert.AreEqual(34, data.Count); + var dataType = data.FirstOrDefault(); + Assert.AreEqual("A003", dataType.Agent_Code); + Assert.AreEqual("Alex", dataType.Agent); + Assert.AreEqual("C00013", dataType.Cust_Code); + Assert.AreEqual("Holmes", dataType.Customer); + Assert.AreEqual(200100, dataType.Ord_Num); + Assert.AreEqual(1000.00, dataType.Ord_Amount); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_FetchDataAsync_Entity_Strict_Error_Check() + { + var selectSql = Queries.OracleQueries.TestDB.SelectSql_Strict; + try + { + var data = await new DBContext(DB.Oracle, OracleConnectionString).FetchDataAsync(selectSql, strict: true); + } + catch (IndexOutOfRangeException ex) + { + Assert.AreEqual("Unable to find specified column in result set", ex.Message); + } + } + + #endregion + + #region Execute Scalar Tests - << string ExecuteScalar(string sqlStatement) >> [TestMethod] [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] @@ -378,7 +640,7 @@ public void Test_Oracle_ExecuteScalar_As_StringReturn_UnsupportedCommands() #endregion - #region Execute Scalar Tests - << T ExecuteScalar(string sqlStatement); >> + #region Execute Scalar Tests - << T ExecuteScalar(string sqlStatement) >> [TestMethod] [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] diff --git a/QueryDB.Core.Tests/PostgreSQLTests.cs b/QueryDB.Core.Tests/PostgreSQLTests.cs index 73678d9..88868aa 100644 --- a/QueryDB.Core.Tests/PostgreSQLTests.cs +++ b/QueryDB.Core.Tests/PostgreSQLTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; namespace QueryDB.Core.Tests { @@ -161,7 +162,137 @@ public void Test_PostgreSQL_FetchData_Dictionary_DataTypes_Check() #endregion - #region Fetch Data Tests - << List FetchData(string selectSql) >> + #region Fetch Data Async Tests - << Task> FetchDataAsync(string selectSql, bool upperCaseKeys = false) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_FetchDataAsync_Dictionary_SelectQuery() + { + var selectSql = Queries.PostgreSQLQueries.TestDB.SelectSql; + var data = await new DBContext(DB.PostgreSQL, PostgreSQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(12, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["agent_name"] == "Benjamin"); + Assert.AreEqual("A009", agent.ReferenceData["agent_code"]); + Assert.AreEqual("Benjamin", agent.ReferenceData["agent_name"]); + Assert.AreEqual("Hampshair", agent.ReferenceData["working_area"]); + Assert.AreEqual("0.11", agent.ReferenceData["commission"]); + Assert.AreEqual("008-22536178", agent.ReferenceData["phone_no"]); + Assert.AreEqual("", agent.ReferenceData["country"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_FetchDataAsync_Dictionary_SelectQuery_UpperCaseKeys() + { + var selectSql = Queries.PostgreSQLQueries.TestDB.SelectSql; + var data = await new DBContext(DB.PostgreSQL, PostgreSQLConnectionString).FetchDataAsync(selectSql, upperCaseKeys: true); + Assert.AreEqual(12, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["AGENT_NAME"] == "Benjamin"); + Assert.AreEqual("A009", agent.ReferenceData["AGENT_CODE"]); + Assert.AreEqual("Benjamin", agent.ReferenceData["AGENT_NAME"]); + Assert.AreEqual("Hampshair", agent.ReferenceData["WORKING_AREA"]); + Assert.AreEqual("0.11", agent.ReferenceData["COMMISSION"]); + Assert.AreEqual("008-22536178", agent.ReferenceData["PHONE_NO"]); + Assert.AreEqual("", agent.ReferenceData["COUNTRY"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_FetchDataAsync_Dictionary_SelectQuery_Joins() + { + var selectSql = Queries.PostgreSQLQueries.TestDB.SelectSql_Join; + var data = await new DBContext(DB.PostgreSQL, PostgreSQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["agent_code"] == "A004" && X.ReferenceData["cust_code"] == "C00006"); + Assert.AreEqual("A004", agent.ReferenceData["agent_code"]); + Assert.AreEqual("Ivan", agent.ReferenceData["agent_name"]); + Assert.AreEqual("C00006", agent.ReferenceData["cust_code"]); + Assert.AreEqual("Shilton", agent.ReferenceData["cust_name"]); + Assert.AreEqual("200104", agent.ReferenceData["ord_num"]); + Assert.AreEqual("1500.00", agent.ReferenceData["ord_amount"]); + Assert.AreEqual("500.00", agent.ReferenceData["advance_amount"]); + Assert.AreEqual("SOD", agent.ReferenceData["ord_description"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_FetchDataAsync_Dictionary_SelectQuery_Joins_UpperCaseKeys() + { + var selectSql = Queries.PostgreSQLQueries.TestDB.SelectSql_Join; + var data = await new DBContext(DB.PostgreSQL, PostgreSQLConnectionString).FetchDataAsync(selectSql, upperCaseKeys: true); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["AGENT_CODE"] == "A004" && X.ReferenceData["CUST_CODE"] == "C00006"); + Assert.AreEqual("A004", agent.ReferenceData["AGENT_CODE"]); + Assert.AreEqual("Ivan", agent.ReferenceData["AGENT_NAME"]); + Assert.AreEqual("C00006", agent.ReferenceData["CUST_CODE"]); + Assert.AreEqual("Shilton", agent.ReferenceData["CUST_NAME"]); + Assert.AreEqual("200104", agent.ReferenceData["ORD_NUM"]); + Assert.AreEqual("1500.00", agent.ReferenceData["ORD_AMOUNT"]); + Assert.AreEqual("500.00", agent.ReferenceData["ADVANCE_AMOUNT"]); + Assert.AreEqual("SOD", agent.ReferenceData["ORD_DESCRIPTION"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_FetchDataAsync_Dictionary_SelectQuery_Aliases() + { + var selectSql = Queries.PostgreSQLQueries.TestDB.SelectSql_Alias; + var data = await new DBContext(DB.PostgreSQL, PostgreSQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["agent_code"] == "A004" && X.ReferenceData["cust_code"] == "C00006"); + Assert.AreEqual("A004", agent.ReferenceData["agent_code"]); + Assert.AreEqual("Ivan", agent.ReferenceData["agent"]); + Assert.AreEqual("Torento", agent.ReferenceData["agent_location"]); + Assert.AreEqual("C00006", agent.ReferenceData["cust_code"]); + Assert.AreEqual("Shilton", agent.ReferenceData["customer"]); + Assert.AreEqual("Torento", agent.ReferenceData["customer_location"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_FetchDataAsync_Dictionary_SelectQuery_Aliases_UpperCaseKeys() + { + var selectSql = Queries.PostgreSQLQueries.TestDB.SelectSql_Alias; + var data = await new DBContext(DB.PostgreSQL, PostgreSQLConnectionString).FetchDataAsync(selectSql, upperCaseKeys: true); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.ReferenceData["AGENT_CODE"] == "A004" && X.ReferenceData["CUST_CODE"] == "C00006"); + Assert.AreEqual("A004", agent.ReferenceData["AGENT_CODE"]); + Assert.AreEqual("Ivan", agent.ReferenceData["AGENT"]); + Assert.AreEqual("Torento", agent.ReferenceData["AGENT_LOCATION"]); + Assert.AreEqual("C00006", agent.ReferenceData["CUST_CODE"]); + Assert.AreEqual("Shilton", agent.ReferenceData["CUSTOMER"]); + Assert.AreEqual("Torento", agent.ReferenceData["CUSTOMER_LOCATION"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_FetchDataAsync_Dictionary_DataTypes_Check() + { + var selectSql = Queries.PostgreSQLQueries.TestDB.SelectSql_DataTypes; + var data = await new DBContext(DB.PostgreSQL, PostgreSQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(1, data.Count); + var dataType = data.FirstOrDefault(); + Assert.AreEqual("9223372036854775807", dataType.ReferenceData["bigint_column"]); + Assert.AreEqual("True", dataType.ReferenceData["boolean_column"]); + Assert.AreEqual("3q2+7w==", dataType.ReferenceData["bytea_column"]); + Assert.AreEqual("char10", dataType.ReferenceData["char_column"]); + Assert.AreEqual("varchar50", dataType.ReferenceData["varchar_column"]); + Assert.AreEqual("09/21/2024 00:00:00", ConvertToUSFormat(dataType.ReferenceData["date_column"])); + Assert.AreEqual("123456.789", dataType.ReferenceData["double_column"]); + Assert.AreEqual("2147483647", dataType.ReferenceData["int_column"]); + Assert.AreEqual("12345.67", dataType.ReferenceData["money_column"]); + Assert.AreEqual("123456.789", dataType.ReferenceData["numeric_column"]); + Assert.AreEqual("12345.67", dataType.ReferenceData["real_column"]); + Assert.AreEqual("32767", dataType.ReferenceData["smallint_column"]); + Assert.AreEqual("some text", dataType.ReferenceData["text_column"]); + Assert.AreEqual("12:34:56", dataType.ReferenceData["time_column"]); + Assert.AreEqual("09/21/2024 14:34:56", ConvertToUSFormat(dataType.ReferenceData["timestamp_column"])); + Assert.AreEqual("123e4567-e89b-12d3-a456-426614174000", dataType.ReferenceData["uuid_column"]); + } + + #endregion + + #region Fetch Data Tests - << List FetchData(string selectSql, bool strict = false) >> [TestMethod] [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] @@ -284,7 +415,130 @@ public void Test_PostgreSQL_FetchData_Entity_Strict_Error_Check() #endregion - #region Execute Scalar Tests - << string ExecuteScalar(string sqlStatement); >> + #region Fetch Data Async Tests - << Task> FetchDataAsync(string selectSql, bool strict = false) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_FetchDataAsync_Entity_SelectQuery() + { + var selectSql = Queries.PostgreSQLQueries.TestDB.SelectSql; + var data = await new DBContext(DB.PostgreSQL, PostgreSQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(12, data.Count); + var agent = data.FirstOrDefault(X => X.Agent_Name == "Benjamin"); + Assert.AreEqual("A009", agent.Agent_Code); + Assert.AreEqual("Benjamin", agent.Agent_Name); + Assert.AreEqual("Hampshair", agent.Working_Area); + Assert.AreEqual((decimal)0.11, agent.Commission); + Assert.AreEqual("008-22536178", agent.Phone_No); + Assert.AreEqual("", agent.Country); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_FetchDataAsync_Entity_SelectQuery_Joins() + { + var selectSql = Queries.PostgreSQLQueries.TestDB.SelectSql_Join; + var data = await new DBContext(DB.PostgreSQL, PostgreSQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.Agent_Code == "A004" && X.Cust_Code == "C00006"); + Assert.AreEqual("A004", agent.Agent_Code); + Assert.AreEqual("Ivan", agent.Agent_Name); + Assert.AreEqual("C00006", agent.Cust_Code); + Assert.AreEqual("Shilton", agent.Cust_Name); + Assert.AreEqual(200104, agent.Ord_Num); + Assert.AreEqual((decimal)1500.00, agent.Ord_Amount); + Assert.AreEqual((decimal)500.00, agent.Advance_Amount); + Assert.AreEqual("SOD", agent.Ord_Description); + // Non Existent Query Data + Assert.IsNull(agent.Agent); + Assert.IsNull(agent.Agent_Location); + Assert.IsNull(agent.Customer); + Assert.IsNull(agent.Customer_Location); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_FetchDataAsync_Entity_SelectQuery_Aliases() + { + var selectSql = Queries.PostgreSQLQueries.TestDB.SelectSql_Alias; + var data = await new DBContext(DB.PostgreSQL, PostgreSQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(34, data.Count); + var agent = data.FirstOrDefault(X => X.Agent_Code == "A004" && X.Cust_Code == "C00006"); + Assert.AreEqual("A004", agent.Agent_Code); + Assert.AreEqual("Ivan", agent.Agent); + Assert.AreEqual("Torento", agent.Agent_Location); + Assert.AreEqual("C00006", agent.Cust_Code); + Assert.AreEqual("Shilton", agent.Customer); + Assert.AreEqual("Torento", agent.Customer_Location); + // Non Existent Query Data + Assert.IsNull(agent.Agent_Name); + Assert.IsNull(agent.Cust_Name); + Assert.AreEqual(0, agent.Ord_Num); + Assert.AreEqual(0, agent.Ord_Amount); + Assert.AreEqual(0, agent.Advance_Amount); + Assert.IsNull(agent.Ord_Description); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_FetchDataAsync_Entity_DataTypes_Check() + { + var selectSql = Queries.PostgreSQLQueries.TestDB.SelectSql_DataTypes; + var data = await new DBContext(DB.PostgreSQL, PostgreSQLConnectionString).FetchDataAsync(selectSql); + Assert.AreEqual(1, data.Count); + var dataType = data.FirstOrDefault(); + Assert.AreEqual(9223372036854775807, dataType.BigInt_Column); + Assert.IsTrue(dataType.Boolean_Column); + Assert.AreEqual("3q2+7w==", ConvertByteArrayToBase64(dataType.Bytea_Column)); + Assert.AreEqual("char10", dataType.Char_Column); + Assert.AreEqual("varchar50", dataType.Varchar_Column); + Assert.AreEqual("09/21/2024 00:00:00", ConvertToUSFormat(dataType.Date_Column.ToString())); + Assert.AreEqual(123456.789, dataType.Double_Column); + Assert.AreEqual(2147483647, dataType.Int_Column); + Assert.AreEqual((decimal)12345.67, dataType.Money_Column); + Assert.AreEqual((decimal)123456.789, dataType.Numeric_Column); + Assert.AreEqual((float)12345.67, dataType.Real_Column); + Assert.AreEqual(32767, dataType.SmallInt_Column); + Assert.AreEqual("some text", dataType.Text_Column); + Assert.AreEqual("12:34:56", dataType.Time_Column.ToString()); + Assert.AreEqual("09/21/2024 14:34:56", ConvertToUSFormat(dataType.Timestamp_Column.ToString())); + Assert.AreEqual("123e4567-e89b-12d3-a456-426614174000", dataType.Uuid_Column.ToString()); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_FetchDataAsync_Entity_Strict_Check() + { + var selectSql = Queries.PostgreSQLQueries.TestDB.SelectSql_Strict; + var data = await new DBContext(DB.PostgreSQL, PostgreSQLConnectionString).FetchDataAsync(selectSql, strict: true); + Assert.AreEqual(34, data.Count); + var dataType = data.FirstOrDefault(); + Assert.AreEqual("A003", dataType.Agent_Code); + Assert.AreEqual("Alex", dataType.Agent); + Assert.AreEqual("C00013", dataType.Cust_Code); + Assert.AreEqual("Holmes", dataType.Customer); + Assert.AreEqual(200100, dataType.Ord_Num); + Assert.AreEqual((decimal)1000.00, dataType.Ord_Amount); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_FetchDataAsync_Entity_Strict_Error_Check() + { + var selectSql = Queries.PostgreSQLQueries.TestDB.SelectSql_Strict; + try + { + var data = await new DBContext(DB.PostgreSQL, PostgreSQLConnectionString).FetchDataAsync(selectSql, strict: true); + } + catch (IndexOutOfRangeException ex) + { + Assert.AreEqual("Field not found in row: Agent_Name", ex.Message); + } + } + + #endregion + + #region Execute Scalar Tests - << string ExecuteScalar(string sqlStatement) >> [TestMethod] [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] @@ -370,7 +624,7 @@ public void Test_PostgreSQL_ExecuteScalar_As_StringReturn_UnsupportedCommands() #endregion - #region Execute Scalar Tests - << T ExecuteScalar(string sqlStatement); >> + #region Execute Scalar Tests - << T ExecuteScalar(string sqlStatement) >> [TestMethod] [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] diff --git a/QueryDB/DBContext.cs b/QueryDB/DBContext.cs index fbc45d0..4d79bac 100644 --- a/QueryDB/DBContext.cs +++ b/QueryDB/DBContext.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; +using System.Threading.Tasks; namespace QueryDB { @@ -56,13 +57,13 @@ public DBContext(DB database, string connectionString) } /// - /// Retrieves records for 'Select' queries from the database. + /// Executes and retrieves records for 'Select' queries from the database. /// Converts column names to keys holding values, with multiple database rows returned into a list. /// Note: Use aliases in query for similar column names. /// /// 'Select' query. - /// Boolean parameter to return dictionary keys in uppercase. Default - 'false'. - /// List of data Dictionary with column names as keys holding values into a list for multiple rows of data. + /// Boolean parameter to return dictionary keys in uppercase. Default - false. + /// List of with column names as keys holding values into a list for multiple rows of data. public List FetchData(string selectSql, bool upperCaseKeys = false) { var dataList = new List(); @@ -102,12 +103,58 @@ public List FetchData(string selectSql, bool upperCaseKeys = fal } /// - /// Retrieves records for 'Select' queries from the database. + /// Asynchronously executes and retrieves records for 'Select' queries from the database. + /// Converts column names to keys holding values, with multiple database rows returned into a list. + /// Note: Use aliases in query for similar column names. + /// + /// 'Select' query. + /// Boolean parameter to return dictionary keys in uppercase. Default - false. + /// List of with column names as keys holding values into a list for multiple rows of data. + public async Task> FetchDataAsync(string selectSql, bool upperCaseKeys = false) + { + var dataList = new List(); + if (Database.Equals(DB.MSSQL)) + { + using (var msSqlDBConnection = GetSqlServerConnection()) + { + var _systemAdapter = new MSSQL.Adapter(); + dataList = await _systemAdapter.FetchDataAsync(selectSql, msSqlDBConnection.SqlConnection, upperCaseKeys); + } + } + else if (Database.Equals(DB.MySQL)) + { + using (var mySqlDBConnection = GetMySqlConnection()) + { + var _systemAdapter = new MySQL.Adapter(); + dataList = await _systemAdapter.FetchDataAsync(selectSql, mySqlDBConnection.MySqlConnection, upperCaseKeys); + } + } + else if (Database.Equals(DB.Oracle)) + { + using (var oracleDBConnection = GetOracleConnection()) + { + var _systemAdapter = new Oracle.Adapter(); + dataList = await _systemAdapter.FetchDataAsync(selectSql, oracleDBConnection.OracleConnection, upperCaseKeys); + } + } + else if (Database.Equals(DB.PostgreSQL)) + { + using (var postgreSqlDBConnection = GetPostgreSqlConnection()) + { + var _systemAdapter = new PostgreSQL.Adapter(); + dataList = await _systemAdapter.FetchDataAsync(selectSql, postgreSqlDBConnection.PostgreSQLConnection, upperCaseKeys); + } + } + return dataList; + } + + /// + /// Executes and retrieves records for 'Select' queries from the database. /// /// Object entity to return data mapped into. /// 'Select' query. - /// Enables fetch data only for object properties existing in database query result. Default - 'false'. - /// List of data rows mapped into object entity into a list for multiple rows of data. + /// Enables fetch data only for object type properties existing in database query result. Default - false. + /// List of data rows mapped into object of type . public List FetchData(string selectSql, bool strict = false) where T : new() { var dataList = new List(); @@ -146,6 +193,51 @@ public List FetchData(string selectSql, bool upperCaseKeys = fal return dataList; } + /// + /// Asynchronously executes and retrieves records for 'Select' queries from the database. + /// + /// Object entity to return data mapped into. + /// 'Select' query. + /// Enables fetch data only for object type properties existing in database query result. Default - false. + /// List of data rows mapped into object of type . + public async Task> FetchDataAsync(string selectSql, bool strict = false) where T : new() + { + var dataList = new List(); + if (Database.Equals(DB.MSSQL)) + { + using (var msSqlDBConnection = GetSqlServerConnection()) + { + var _systemAdapter = new MSSQL.Adapter(); + dataList = await _systemAdapter.FetchDataAsync(selectSql, msSqlDBConnection.SqlConnection, strict); + } + } + else if (Database.Equals(DB.MySQL)) + { + using (var mySqlDBConnection = GetMySqlConnection()) + { + var _systemAdapter = new MySQL.Adapter(); + dataList = await _systemAdapter.FetchDataAsync(selectSql, mySqlDBConnection.MySqlConnection, strict); + } + } + else if (Database.Equals(DB.Oracle)) + { + using (var oracleDBConnection = GetOracleConnection()) + { + var _systemAdapter = new Oracle.Adapter(); + dataList = await _systemAdapter.FetchDataAsync(selectSql, oracleDBConnection.OracleConnection, strict); + } + } + else if (Database.Equals(DB.PostgreSQL)) + { + using (var postgreSqlDBConnection = GetPostgreSqlConnection()) + { + var _systemAdapter = new PostgreSQL.Adapter(); + dataList = await _systemAdapter.FetchDataAsync(selectSql, postgreSqlDBConnection.PostgreSQLConnection, strict); + } + } + return dataList; + } + /// /// Executes a SQL query and returns the result as a string. /// diff --git a/QueryDB/IDBContext.cs b/QueryDB/IDBContext.cs index f14d694..92de5f2 100644 --- a/QueryDB/IDBContext.cs +++ b/QueryDB/IDBContext.cs @@ -1,5 +1,6 @@ using QueryDB.Resources; using System.Collections.Generic; +using System.Threading.Tasks; namespace QueryDB { @@ -9,22 +10,38 @@ namespace QueryDB interface IDBContext { /// - /// Retrieves records for 'Select' queries from the database. + /// Executes and retrieves records for 'Select' queries from the database. /// /// 'Select' query. - /// Boolean parameter to return dictionary keys in uppercase. Default - 'false'. - /// List of data Dictionary with column names as keys holding values into a list for multiple rows of data. + /// Boolean parameter to return dictionary keys in uppercase. Default - false. + /// List of with column names as keys holding values into a list for multiple rows of data. List FetchData(string selectSql, bool upperCaseKeys = false); /// - /// Retrieves records for 'Select' queries from the database. + /// Asynchronously executes and retrieves records for 'Select' queries from the database. + /// + /// 'Select' query. + /// Boolean parameter to return dictionary keys in uppercase. Default - false. + /// List of with column names as keys holding values into a list for multiple rows of data. + Task> FetchDataAsync(string selectSql, bool upperCaseKeys = false); + + /// + /// Executes and retrieves records for 'Select' queries from the database. /// /// Object entity to return data mapped into. /// 'Select' query. - /// Enables fetch data only for object properties existing in database query result. Default - 'false'. - /// List of data rows mapped into object entity into a list for multiple rows of data. + /// Enables fetch data only for object type properties existing in database query result. Default - false. + /// List of data rows mapped into object of type . List FetchData(string selectSql, bool strict = false) where T : new(); + /// + /// Asynchronously executes and retrieves records for 'Select' queries from the database. + /// + /// Object entity to return data mapped into. + /// 'Select' query. + /// Enables fetch data only for object type properties existing in database query result. Default - false. + Task> FetchDataAsync(string selectSql, bool strict = false) where T : new(); + /// /// Executes a SQL query and returns the result as a string. /// diff --git a/QueryDB/MSSQL/Adapter.cs b/QueryDB/MSSQL/Adapter.cs index 4fd939d..3e21d9a 100644 --- a/QueryDB/MSSQL/Adapter.cs +++ b/QueryDB/MSSQL/Adapter.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Data; +using System.Threading.Tasks; namespace QueryDB.MSSQL { @@ -11,13 +12,16 @@ namespace QueryDB.MSSQL /// internal class Adapter { + + #region Synchronous + /// - /// Gets the 'SQL Server' data reader. + /// Executes the specified SQL command and returns 'SQL Server' data reader. /// /// The text of the query. - /// 'SQL Server' connection. + /// The object used to connect to the database. /// Sql command type. - /// 'SQL Server' data reader. + /// A object that can be used to read the query results. internal SqlDataReader GetSqlReader(string cmdText, SqlConnection connection, CommandType commandType) { connection.Open(); @@ -32,7 +36,7 @@ internal SqlDataReader GetSqlReader(string cmdText, SqlConnection connection, Co /// connection, and command type. Opens the connection before creating the command. /// /// The SQL command text to execute. - /// The to use. + /// The object used to connect to the database. /// The type of the command (e.g., Text, StoredProcedure). /// A configured instance. internal SqlCommand GetSqlCommand(string cmdText, SqlConnection connection, CommandType commandType) @@ -68,13 +72,14 @@ internal static SqlTransaction GetSqlTransaction(SqlConnection connection) } /// - /// Retrieves records for 'Select' queries from the database. + /// Executes and retrieves records for 'Select' queries from the database. /// Converts column names to keys holding values, with multiple database rows returned into a list. + /// Note: Use aliases in query for similar column names. /// /// 'Select' query. - /// 'Sql' Connection. + /// The object used to connect to the database. /// Boolean parameter to return dictionary keys in uppercase. - /// List of data Dictionary with column names as keys holding values into a list for multiple rows of data. + /// List of with column names as keys holding values into a list for multiple rows of data. /// Note: Byte[] is returned as Base64 string. internal List FetchData(string selectSql, SqlConnection connection, bool upperCaseKeys) { @@ -99,13 +104,13 @@ internal List FetchData(string selectSql, SqlConnection connecti } /// - /// Retrieves records for 'Select' queries from the database. + /// Executes and retrieves records for 'Select' queries from the database. /// /// Object entity to return data mapped into. /// 'Select' query. - /// 'Sql' Connection. - /// Enables fetch data only for object properties existing in database query result. - /// List of data rows mapped into object entity into a list for multiple rows of data. + /// The object used to connect to the database. + /// Enables fetch data only for object type properties existing in database query result. + /// List of data rows mapped into object of type . internal List FetchData(string selectSql, SqlConnection connection, bool strict) where T : new() { var dataList = new List(); @@ -214,5 +219,102 @@ internal static bool ExecuteTransaction(List sqlStatements, SqlConnectio } } } + + #endregion + + #region Asynchronous + + /// + /// Asynchronously executes the specified SQL command and returns 'SQL Server' data reader. + /// + /// The text of the query. + /// The object used to connect to the database. + /// Sql command type. + /// A object that can be used to read the query results. + internal async Task GetSqlReaderAsync(string cmdText, SqlConnection connection, CommandType commandType) + { + await connection.OpenAsync(); + using (var sqlCommand = new SqlCommand(cmdText, connection) { CommandType = commandType }) + { + return await sqlCommand.ExecuteReaderAsync(); + } + } + + /// + /// Asynchronously creates and returns a new with the specified command text, + /// connection, and command type. Opens the connection before creating the command. + /// + /// The SQL command text to execute. + /// The object used to connect to the database. + /// The type of the command (e.g., Text, StoredProcedure). + /// A configured instance. + internal async Task GetSqlCommandAsync(string cmdText, SqlConnection connection, CommandType commandType) + { + await connection.OpenAsync(); + var sqlCommand = new SqlCommand(cmdText, connection) { CommandType = commandType }; + return sqlCommand; + } + + /// + /// Asynchronously executes and retrieves records for 'Select' queries from the database. + /// Converts column names to keys holding values, with multiple database rows returned into a list. + /// Note: Use aliases in query for similar column names. + /// + /// 'Select' query. + /// The object used to connect to the database. + /// Boolean parameter to return dictionary keys in uppercase. + /// List of with column names as keys holding values into a list for multiple rows of data. + /// Note: Byte[] is returned as Base64 string. + internal async Task> FetchDataAsync(string selectSql, SqlConnection connection, bool upperCaseKeys) + { + var dataList = new List(); + using (var reader = await GetSqlReaderAsync(selectSql, connection, CommandType.Text)) + { + while (await reader.ReadAsync()) + { + var addRow = new DataDictionary(); + for (int i = 0; i < reader.FieldCount; i++) + { + string key = upperCaseKeys ? reader.GetName(i).ToUpper() : reader.GetName(i); + if (reader.GetValue(i) is byte[] value) + addRow.ReferenceData.Add(key, Convert.ToBase64String(value)); + else + addRow.ReferenceData.Add(key, reader.GetValue(i).ToString()); + } + dataList.Add(addRow); + } + } + return dataList; + } + + /// + /// Asynchronously executes and retrieves records for 'Select' queries from the database. + /// + /// Object entity to return data mapped into. + /// 'Select' query. + /// The object used to connect to the database. + /// Enables fetch data only for object type properties existing in database query result. + /// List of data rows mapped into object of type . + internal async Task> FetchDataAsync(string selectSql, SqlConnection connection, bool strict) where T : new() + { + var dataList = new List(); + using (var reader = await GetSqlReaderAsync(selectSql, connection, CommandType.Text)) + { + while (await reader.ReadAsync()) + { + var addObjectRow = new T(); + foreach (var prop in typeof(T).GetProperties()) + { + if ((strict || Utils.ColumnExists(reader, prop.Name)) && !reader.IsDBNull(reader.GetOrdinal(prop.Name))) + prop.SetValue(addObjectRow, reader[prop.Name]); + } + dataList.Add(addObjectRow); + } + } + return dataList; + } + + #endregion + } } diff --git a/QueryDB/MySQL/Adapter.cs b/QueryDB/MySQL/Adapter.cs index c3081dc..8cc6d1d 100644 --- a/QueryDB/MySQL/Adapter.cs +++ b/QueryDB/MySQL/Adapter.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Data; +using System.Threading.Tasks; namespace QueryDB.MySQL { @@ -11,13 +12,16 @@ namespace QueryDB.MySQL /// internal class Adapter { + + #region Synchronous + /// - /// Gets the 'MySQL' data reader. + /// Executes the specified SQL command and returns 'MySQL' data reader. /// /// The text of the query. - /// 'MySQL' connection. + /// The object used to connect to the database. /// Sql command type. - /// 'MySQL' data reader. + /// A object that can be used to read the query results. internal MySqlDataReader GetMySqlReader(string cmdText, MySqlConnection connection, CommandType commandType) { connection.Open(); @@ -32,7 +36,7 @@ internal MySqlDataReader GetMySqlReader(string cmdText, MySqlConnection connecti /// connection, and command type. Opens the connection before creating the command. /// /// The SQL command text to execute. - /// The to use. + /// The object used to connect to the database. /// The type of the command (e.g., Text, StoredProcedure). /// A configured instance. internal MySqlCommand GetMySqlCommand(string cmdText, MySqlConnection connection, CommandType commandType) @@ -68,13 +72,14 @@ internal static MySqlTransaction GetMySqlTransaction(MySqlConnection connection) } /// - /// Retrieves records for 'Select' queries from the database. + /// Executes and retrieves records for 'Select' queries from the database. /// Converts column names to keys holding values, with multiple database rows returned into a list. + /// Note: Use aliases in query for similar column names. /// /// 'Select' query. - /// 'MySQL' Connection. + /// The object used to connect to the database. /// Boolean parameter to return dictionary keys in uppercase. - /// List of data Dictionary with column names as keys holding values into a list for multiple rows of data. + /// List of with column names as keys holding values into a list for multiple rows of data. /// Note: Byte[] is returned as Base64 string. internal List FetchData(string selectSql, MySqlConnection connection, bool upperCaseKeys) { @@ -99,13 +104,13 @@ internal List FetchData(string selectSql, MySqlConnection connec } /// - /// Retrieves records for 'Select' queries from the database. + /// Executes and retrieves records for 'Select' queries from the database. /// /// Object entity to return data mapped into. /// 'Select' query. - /// 'MySQL' Connection. - /// Enables fetch data only for object properties existing in database query result. - /// List of data rows mapped into object entity into a list for multiple rows of data. + /// The object used to connect to the database. + /// Enables fetch data only for object type properties existing in database query result. + /// List of data rows mapped into object of type . internal List FetchData(string selectSql, MySqlConnection connection, bool strict) where T : new() { var dataList = new List(); @@ -214,5 +219,101 @@ internal static bool ExecuteTransaction(List sqlStatements, MySqlConnect } } } + + #endregion + + #region Asynchronous + + /// + /// Asynchronously executes the specified SQL command and returns 'MySQL' data reader. + /// + /// The text of the query. + /// The object used to connect to the database. + /// Sql command type. + /// A object that can be used to read the query results. + internal async Task GetMySqlReaderAsync(string cmdText, MySqlConnection connection, CommandType commandType) + { + await connection.OpenAsync(); + using (var sqlCommand = new MySqlCommand(cmdText, connection) { CommandType = commandType }) + { + return (MySqlDataReader) await sqlCommand.ExecuteReaderAsync(); + } + } + + /// + /// Asynchronously creates and returns a new with the specified command text, + /// connection, and command type. Opens the connection before creating the command. + /// + /// The SQL command text to execute. + /// The object used to connect to the database. + /// The type of the command (e.g., Text, StoredProcedure). + /// A configured instance. + internal async Task GetMySqlCommandAsync(string cmdText, MySqlConnection connection, CommandType commandType) + { + await connection.OpenAsync(); + var sqlCommand = new MySqlCommand(cmdText, connection) { CommandType = commandType }; + return sqlCommand; + } + + /// + /// Asynchronously executes and retrieves records for 'Select' queries from the database. + /// Converts column names to keys holding values, with multiple database rows returned into a list. + /// Note: Use aliases in query for similar column names. + /// + /// 'Select' query. + /// The object used to connect to the database. + /// Boolean parameter to return dictionary keys in uppercase. + /// List of with column names as keys holding values into a list for multiple rows of data. + internal async Task> FetchDataAsync(string selectSql, MySqlConnection connection, bool upperCaseKeys) + { + var dataList = new List(); + using (var reader = await GetMySqlReaderAsync(selectSql, connection, CommandType.Text)) + { + while (await reader.ReadAsync()) + { + var addRow = new DataDictionary(); + for (int i = 0; i < reader.FieldCount; i++) + { + string key = upperCaseKeys ? reader.GetName(i).ToUpper() : reader.GetName(i); + if (reader.GetValue(i) is byte[] value) + addRow.ReferenceData.Add(key, Convert.ToBase64String(value)); + else + addRow.ReferenceData.Add(key, reader.GetValue(i).ToString()); + } + dataList.Add(addRow); + } + } + return dataList; + } + + /// + /// Asynchronously executes and retrieves records for 'Select' queries from the database. + /// + /// Object entity to return data mapped into. + /// 'Select' query. + /// The object used to connect to the database. + /// Enables fetch data only for object type properties existing in database query result. + /// List of data rows mapped into object of type . + internal async Task> FetchDataAsync(string selectSql, MySqlConnection connection, bool strict) where T : new() + { + var dataList = new List(); + using (var reader = await GetMySqlReaderAsync(selectSql, connection, CommandType.Text)) + { + while (await reader.ReadAsync()) + { + var addObjectRow = new T(); + foreach (var prop in typeof(T).GetProperties()) + { + if ((strict || Utils.ColumnExists(reader, prop.Name)) && !reader.IsDBNull(reader.GetOrdinal(prop.Name))) + prop.SetValue(addObjectRow, reader[prop.Name]); + } + dataList.Add(addObjectRow); + } + } + return dataList; + } + + #endregion + } } \ No newline at end of file diff --git a/QueryDB/Oracle/Adapter.cs b/QueryDB/Oracle/Adapter.cs index 526d25c..59f5b0d 100644 --- a/QueryDB/Oracle/Adapter.cs +++ b/QueryDB/Oracle/Adapter.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Data; +using System.Threading.Tasks; namespace QueryDB.Oracle { @@ -11,13 +12,16 @@ namespace QueryDB.Oracle /// internal class Adapter { + + #region Synchronous + /// - /// Gets the 'Oracle' data reader. + /// Executes the specified SQL command and returns 'Oracle' data reader. /// /// The text of the query. - /// 'Oracle' connection. + /// The object used to connect to the database. /// Sql command type. - /// 'Oracle' data reader. + /// A object that can be used to read the query results. internal OracleDataReader GetOracleReader(string cmdText, OracleConnection connection, CommandType commandType) { connection.Open(); @@ -32,7 +36,7 @@ internal OracleDataReader GetOracleReader(string cmdText, OracleConnection conne /// connection, and command type. Opens the connection before creating the command. /// /// The SQL command text to execute. - /// The to use. + /// The object used to connect to the database. /// The type of the command (e.g., Text, StoredProcedure). /// A configured instance. internal OracleCommand GetOracleCommand(string cmdText, OracleConnection connection, CommandType commandType) @@ -67,13 +71,14 @@ internal static OracleTransaction GetOracleTransaction(OracleConnection connecti } /// - /// Retrieves records for 'Select' queries from the database. + /// Executes and retrieves records for 'Select' queries from the database. /// Converts column names to keys holding values, with multiple database rows returned into a list. + /// Note: Use aliases in query for similar column names. /// /// 'Select' query. - /// 'Oracle' Connection. + /// The object used to connect to the database. /// Boolean parameter to return dictionary keys in uppercase. - /// List of data Dictionary with column names as keys holding values into a list for multiple rows of data. + /// List of with column names as keys holding values into a list for multiple rows of data. /// Note: Byte[]/BFile is returned as Base64 string. internal List FetchData(string selectSql, OracleConnection connection, bool upperCaseKeys) { @@ -100,13 +105,13 @@ internal List FetchData(string selectSql, OracleConnection conne } /// - /// Retrieves records for 'Select' queries from the database. + /// Executes and retrieves records for 'Select' queries from the database. /// /// Object entity to return data mapped into. /// 'Select' query. - /// 'Oracle' Connection. - /// Enables fetch data only for object properties existing in database query result. - /// List of data rows mapped into object entity into a list for multiple rows of data. + /// The object used to connect to the database. + /// Enables fetch data only for object type properties existing in database query result. + /// List of data rows mapped into object of type . internal List FetchData(string selectSql, OracleConnection connection, bool strict) where T : new() { var dataList = new List(); @@ -221,5 +226,108 @@ internal static bool ExecuteTransaction(List sqlStatements, OracleConnec } } } + + #endregion + + #region Asynchronous + + /// + /// Asynchronously executes the specified SQL command and returns 'Oracle' data reader. + /// + /// The text of the query. + /// The object used to connect to the database. + /// Sql command type. + /// A object that can be used to read the query results. + internal async Task GetOracleReaderAsync(string cmdText, OracleConnection connection, CommandType commandType) + { + await connection.OpenAsync(); + using (var sqlCommand = new OracleCommand(cmdText, connection) { CommandType = commandType }) + { + return (OracleDataReader) await sqlCommand.ExecuteReaderAsync(); + } + } + + /// + /// Asynchronously creates and returns a new with the specified command text, + /// connection, and command type. Opens the connection before creating the command. + /// + /// The SQL command text to execute. + /// The object used to connect to the database. + /// The type of the command (e.g., Text, StoredProcedure). + /// A configured instance. + internal async Task GetOracleCommandAsync(string cmdText, OracleConnection connection, CommandType commandType) + { + await connection.OpenAsync(); + var sqlCommand = new OracleCommand(cmdText, connection) { CommandType = commandType }; + return sqlCommand; + } + + /// + /// Asynchronously executes and retrieves records for 'Select' queries from the database. + /// Converts column names to keys holding values, with multiple database rows returned into a list. + /// Note: Use aliases in query for similar column names. + /// + /// 'Select' query. + /// The object used to connect to the database. + /// Boolean parameter to return dictionary keys in uppercase. + /// List of with column names as keys holding values into a list for multiple rows of data. + /// Note: Byte[]/BFile is returned as Base64 string. + internal async Task> FetchDataAsync(string selectSql, OracleConnection connection, bool upperCaseKeys) + { + var dataList = new List(); + using (var reader = await GetOracleReaderAsync(selectSql, connection, CommandType.Text)) + { + while (await reader.ReadAsync()) + { + var addRow = new DataDictionary(); + for (int i = 0; i < reader.FieldCount; i++) + { + string key = upperCaseKeys ? reader.GetName(i).ToUpper() : reader.GetName(i); + if (Utils.IsBFileColumn(reader, i)) + addRow.ReferenceData.Add(key, await Utils.GetBFileBase64ContentAsync(reader, i)); + else if (reader.GetValue(i) is byte[] value) + addRow.ReferenceData.Add(key, Convert.ToBase64String(value)); + else + addRow.ReferenceData.Add(key, reader.GetValue(i).ToString()); + } + dataList.Add(addRow); + } + } + return dataList; + } + + /// + /// Asynchronously executes and retrieves records for 'Select' queries from the database. + /// + /// Object entity to return data mapped into. + /// 'Select' query. + /// The object used to connect to the database. + /// Enables fetch data only for object type properties existing in database query result. + /// List of data rows mapped into object of type . + internal async Task> FetchDataAsync(string selectSql, OracleConnection connection, bool strict) where T : new() + { + var dataList = new List(); + using (var reader = await GetOracleReaderAsync(selectSql, connection, CommandType.Text)) + { + while (await reader.ReadAsync()) + { + var addObjectRow = new T(); + foreach (var prop in typeof(T).GetProperties()) + { + if ((strict || Utils.ColumnExists(reader, prop.Name)) && !reader.IsDBNull(reader.GetOrdinal(prop.Name))) + { + if (Utils.IsBFileColumn(reader, prop.Name)) + prop.SetValue(addObjectRow, await Utils.GetBFileByteContentAsync(reader, prop.Name)); + else + prop.SetValue(addObjectRow, reader[prop.Name]); + } + } + dataList.Add(addObjectRow); + } + } + return dataList; + } + + #endregion } } \ No newline at end of file diff --git a/QueryDB/PostgreSQL/Adapter.cs b/QueryDB/PostgreSQL/Adapter.cs index 1239630..537e65f 100644 --- a/QueryDB/PostgreSQL/Adapter.cs +++ b/QueryDB/PostgreSQL/Adapter.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Data; +using System.Threading.Tasks; namespace QueryDB.PostgreSQL { @@ -11,13 +12,16 @@ namespace QueryDB.PostgreSQL /// internal class Adapter { + + #region Synchronous + /// - /// Gets the 'PostgreSQL' data reader. + /// Executes the specified SQL command and returns 'PostgreSQL' data reader. /// /// The text of the query. - /// 'PostgreSQL' connection. + /// The object used to connect to the database. /// Sql command type. - /// 'PostgreSQL' data reader. + /// A object that can be used to read the query results. internal NpgsqlDataReader GetPostgreSqlReader(string cmdText, NpgsqlConnection connection, CommandType commandType) { connection.Open(); @@ -32,7 +36,7 @@ internal NpgsqlDataReader GetPostgreSqlReader(string cmdText, NpgsqlConnection c /// connection, and command type. Opens the connection before creating the command. /// /// The SQL command text to execute. - /// The to use. + /// The object used to connect to the database. /// The type of the command (e.g., Text, StoredProcedure). /// A configured instance. internal NpgsqlCommand GetPostgreSqlCommand(string cmdText, NpgsqlConnection connection, CommandType commandType) @@ -68,13 +72,14 @@ internal static NpgsqlTransaction GetPostgreSqlTransaction(NpgsqlConnection conn } /// - /// Retrieves records for 'Select' queries from the database. + /// Executes and retrieves records for 'Select' queries from the database. /// Converts column names to keys holding values, with multiple database rows returned into a list. + /// Note: Use aliases in query for similar column names. /// /// 'Select' query. - /// 'PostgreSQL' Connection. + /// The object used to connect to the database. /// Boolean parameter to return dictionary keys in uppercase. - /// List of data Dictionary with column names as keys holding values into a list for multiple rows of data. + /// List of with column names as keys holding values into a list for multiple rows of data. /// Note: Byte[] is returned as Base64 string. internal List FetchData(string selectSql, NpgsqlConnection connection, bool upperCaseKeys) { @@ -99,13 +104,13 @@ internal List FetchData(string selectSql, NpgsqlConnection conne } /// - /// Retrieves records for 'Select' queries from the database. + /// Executes and retrieves records for 'Select' queries from the database. /// /// Object entity to return data mapped into. /// 'Select' query. - /// 'PostgreSQL' Connection. - /// Enables fetch data only for object properties existing in database query result. - /// List of data rows mapped into object entity into a list for multiple rows of data. + /// The object used to connect to the database. + /// Enables fetch data only for object type properties existing in database query result. + /// List of data rows mapped into object of type . internal List FetchData(string selectSql, NpgsqlConnection connection, bool strict) where T : new() { var dataList = new List(); @@ -214,5 +219,101 @@ internal static bool ExecuteTransaction(List sqlStatements, NpgsqlConnec } } } + + #endregion + + #region Asynchronous + + /// + /// Asynchronously executes the specified SQL command and returns 'PostgreSQL' data reader. + /// + /// The text of the query. + /// The object used to connect to the database. + /// Sql command type. + /// A object that can be used to read the query results. + internal async Task GetPostgreSqlReaderAsync(string cmdText, NpgsqlConnection connection, CommandType commandType) + { + await connection.OpenAsync(); + using (var sqlCommand = new NpgsqlCommand(cmdText, connection) { CommandType = commandType }) + { + return await sqlCommand.ExecuteReaderAsync(); + } + } + + /// + /// Asynchronously creates and returns a new with the specified command text, + /// connection, and command type. Opens the connection before creating the command. + /// + /// The SQL command text to execute. + /// The object used to connect to the database. + /// The type of the command (e.g., Text, StoredProcedure). + /// A configured instance. + internal async Task GetPostgreSqlCommandAsync(string cmdText, NpgsqlConnection connection, CommandType commandType) + { + await connection.OpenAsync(); + var sqlCommand = new NpgsqlCommand(cmdText, connection) { CommandType = commandType }; + return sqlCommand; + } + + /// + /// Asynchronously executes and retrieves records for 'Select' queries from the database. + /// Converts column names to keys holding values, with multiple database rows returned into a list. + /// Note: Use aliases in query for similar column names. + /// + /// 'Select' query. + /// The object used to connect to the database. + /// Boolean parameter to return dictionary keys in uppercase. + /// List of with column names as keys holding values into a list for multiple rows of data. + /// Note: Byte[] is returned as Base64 string. + internal async Task> FetchDataAsync(string selectSql, NpgsqlConnection connection, bool upperCaseKeys) + { + var dataList = new List(); + using (var reader = await GetPostgreSqlReaderAsync(selectSql, connection, CommandType.Text)) + { + while (await reader.ReadAsync()) + { + var addRow = new DataDictionary(); + for (int i = 0; i < reader.FieldCount; i++) + { + string key = upperCaseKeys ? reader.GetName(i).ToUpper() : reader.GetName(i); + if (reader.GetValue(i) is byte[] value) + addRow.ReferenceData.Add(key, Convert.ToBase64String(value)); + else + addRow.ReferenceData.Add(key, reader.GetValue(i).ToString()); + } + dataList.Add(addRow); + } + } + return dataList; + } + + /// + /// Asynchronously executes and retrieves records for 'Select' queries from the database. + /// + /// Object entity to return data mapped into. + /// 'Select' query. + /// The object used to connect to the database. + /// Enables fetch data only for object type properties existing in database query result. + /// List of data rows mapped into object of type . + internal async Task> FetchDataAsync(string selectSql, NpgsqlConnection connection, bool strict) where T : new() + { + var dataList = new List(); + using (var reader = await GetPostgreSqlReaderAsync(selectSql, connection, CommandType.Text)) + { + while (await reader.ReadAsync()) + { + var addObjectRow = new T(); + foreach (var prop in typeof(T).GetProperties()) + { + if ((strict || Utils.ColumnExists(reader, prop.Name)) && !reader.IsDBNull(reader.GetOrdinal(prop.Name))) + prop.SetValue(addObjectRow, reader[prop.Name]); + } + dataList.Add(addObjectRow); + } + } + return dataList; + } + + #endregion } } diff --git a/QueryDB/Resources/Utils.cs b/QueryDB/Resources/Utils.cs index 8a4bdf1..4de5003 100644 --- a/QueryDB/Resources/Utils.cs +++ b/QueryDB/Resources/Utils.cs @@ -1,6 +1,7 @@ using Oracle.ManagedDataAccess.Client; using System; using System.Data; +using System.Threading.Tasks; namespace QueryDB.Resources { @@ -88,6 +89,34 @@ internal static string GetBFileBase64Content(OracleDataReader reader, int column return content; } + /// + /// Asynchronously retrieves the content of a BFILE column from an Oracle data reader as a Base64-encoded string. + /// + /// The Oracle data reader containing the BFILE column. + /// The index of the BFILE column to read. + /// Returns the BFILE content as a Base64-encoded string, or an empty string if the BFILE is null. + internal static async Task GetBFileBase64ContentAsync(OracleDataReader reader, int columnIndex) + { + string content = string.Empty; + var bFile = reader.GetOracleBFile(columnIndex); + if (bFile != null && !reader.IsDBNull(columnIndex)) + { + bFile.OpenFile(); + byte[] buffer = new byte[bFile.Length]; + int bytesReadTotal = 0; + while (bytesReadTotal < buffer.Length) + { + int bytesRead = await bFile.ReadAsync(buffer, bytesReadTotal, buffer.Length - bytesReadTotal); + if (bytesRead == 0) + break; + bytesReadTotal += bytesRead; + } + content = Convert.ToBase64String(buffer); + bFile.Close(); + } + return content; + } + /// /// Retrieves the content of a BFILE column from an Oracle data reader as a byte array, using the column name. /// @@ -115,5 +144,33 @@ internal static byte[] GetBFileByteContent(OracleDataReader reader, string colum } return buffer; } + + /// + /// Asynchronously retrieves the content of a BFILE column from an Oracle data reader as a byte array, using the column name. + /// + /// The Oracle data reader containing the BFILE column. + /// The name of the BFILE column to read. + /// Returns the BFILE content as a byte array, or null if the BFILE is null or the column value is null. + internal static async Task GetBFileByteContentAsync(OracleDataReader reader, string columnName) + { + byte[] buffer = null; + int columnIndex = reader.GetOrdinal(columnName); + var bFile = reader.GetOracleBFile(columnIndex); + if (bFile != null && !reader.IsDBNull(columnIndex)) + { + bFile.OpenFile(); + buffer = new byte[bFile.Length]; + int bytesReadTotal = 0; + while (bytesReadTotal < buffer.Length) + { + int bytesRead = await bFile.ReadAsync(buffer, bytesReadTotal, buffer.Length - bytesReadTotal); + if (bytesRead == 0) + break; + bytesReadTotal += bytesRead; + } + bFile.Close(); + } + return buffer; + } } } From 545721ae95e53135f36f9cf52e579de85ce4936d Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Sun, 23 Feb 2025 14:19:05 +1100 Subject: [PATCH 06/34] Test updates --- QueryDB.Core.Tests/MSSQLTests.cs | 2 ++ QueryDB.Core.Tests/MySQLTests.cs | 2 ++ QueryDB.Core.Tests/OracleTests.cs | 2 ++ QueryDB.Core.Tests/PostgreSQLTests.cs | 2 ++ 4 files changed, 8 insertions(+) diff --git a/QueryDB.Core.Tests/MSSQLTests.cs b/QueryDB.Core.Tests/MSSQLTests.cs index 7db6b5d..1b1d817 100644 --- a/QueryDB.Core.Tests/MSSQLTests.cs +++ b/QueryDB.Core.Tests/MSSQLTests.cs @@ -445,6 +445,7 @@ public void Test_MSSQL_FetchData_Entity_Strict_Error_Check() try { var data = new DBContext(DB.MSSQL, MSSQLConnectionString).FetchData(selectSql, strict: true); + Assert.Fail("No Exception"); } catch (IndexOutOfRangeException ex) { @@ -581,6 +582,7 @@ public async Task Test_MSSQL_FetchDataAsync_Entity_Strict_Error_Check() try { var data = await new DBContext(DB.MSSQL, MSSQLConnectionString).FetchDataAsync(selectSql, strict: true); + Assert.Fail("No Exception"); } catch (IndexOutOfRangeException ex) { diff --git a/QueryDB.Core.Tests/MySQLTests.cs b/QueryDB.Core.Tests/MySQLTests.cs index eb2f755..7b19329 100644 --- a/QueryDB.Core.Tests/MySQLTests.cs +++ b/QueryDB.Core.Tests/MySQLTests.cs @@ -415,6 +415,7 @@ public void Test_MySQL_FetchData_Entity_Strict_Error_Check() try { var data = new DBContext(DB.MySQL, MySQLConnectionString).FetchData(selectSql, strict: true); + Assert.Fail("No Exception"); } catch (IndexOutOfRangeException ex) { @@ -541,6 +542,7 @@ public async Task Test_MySQL_FetchDataAsync_Entity_Strict_Error_Check() try { var data = await new DBContext(DB.MySQL, MySQLConnectionString).FetchDataAsync(selectSql, strict: true); + Assert.Fail("No Exception"); } catch (IndexOutOfRangeException ex) { diff --git a/QueryDB.Core.Tests/OracleTests.cs b/QueryDB.Core.Tests/OracleTests.cs index 420fc1f..255bab3 100644 --- a/QueryDB.Core.Tests/OracleTests.cs +++ b/QueryDB.Core.Tests/OracleTests.cs @@ -418,6 +418,7 @@ public void Test_Oracle_FetchData_Entity_Strict_Error_Check() try { var data = new DBContext(DB.Oracle, OracleConnectionString).FetchData(selectSql, strict: true); + Assert.Fail("No Exception"); } catch (IndexOutOfRangeException ex) { @@ -545,6 +546,7 @@ public async Task Test_Oracle_FetchDataAsync_Entity_Strict_Error_Check() try { var data = await new DBContext(DB.Oracle, OracleConnectionString).FetchDataAsync(selectSql, strict: true); + Assert.Fail("No Exception"); } catch (IndexOutOfRangeException ex) { diff --git a/QueryDB.Core.Tests/PostgreSQLTests.cs b/QueryDB.Core.Tests/PostgreSQLTests.cs index 88868aa..5faddd5 100644 --- a/QueryDB.Core.Tests/PostgreSQLTests.cs +++ b/QueryDB.Core.Tests/PostgreSQLTests.cs @@ -406,6 +406,7 @@ public void Test_PostgreSQL_FetchData_Entity_Strict_Error_Check() try { var data = new DBContext(DB.PostgreSQL, PostgreSQLConnectionString).FetchData(selectSql, strict: true); + Assert.Fail("No Exception"); } catch (IndexOutOfRangeException ex) { @@ -529,6 +530,7 @@ public async Task Test_PostgreSQL_FetchDataAsync_Entity_Strict_Error_Check() try { var data = await new DBContext(DB.PostgreSQL, PostgreSQLConnectionString).FetchDataAsync(selectSql, strict: true); + Assert.Fail("No Exception"); } catch (IndexOutOfRangeException ex) { From 5e52a128947b647120efdf7e6712560b5ffbfcef Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Sun, 23 Feb 2025 14:20:26 +1100 Subject: [PATCH 07/34] CQ - Use IsDBNullAsync for async --- QueryDB/MSSQL/Adapter.cs | 2 +- QueryDB/MySQL/Adapter.cs | 2 +- QueryDB/Oracle/Adapter.cs | 2 +- QueryDB/PostgreSQL/Adapter.cs | 2 +- QueryDB/Resources/Utils.cs | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/QueryDB/MSSQL/Adapter.cs b/QueryDB/MSSQL/Adapter.cs index 3e21d9a..0b13d54 100644 --- a/QueryDB/MSSQL/Adapter.cs +++ b/QueryDB/MSSQL/Adapter.cs @@ -305,7 +305,7 @@ internal async Task> FetchDataAsync(string selectSql, SqlCo var addObjectRow = new T(); foreach (var prop in typeof(T).GetProperties()) { - if ((strict || Utils.ColumnExists(reader, prop.Name)) && !reader.IsDBNull(reader.GetOrdinal(prop.Name))) + if ((strict || Utils.ColumnExists(reader, prop.Name)) && !await reader.IsDBNullAsync(reader.GetOrdinal(prop.Name))) prop.SetValue(addObjectRow, reader[prop.Name]); } dataList.Add(addObjectRow); diff --git a/QueryDB/MySQL/Adapter.cs b/QueryDB/MySQL/Adapter.cs index 8cc6d1d..d2ae9e2 100644 --- a/QueryDB/MySQL/Adapter.cs +++ b/QueryDB/MySQL/Adapter.cs @@ -304,7 +304,7 @@ internal async Task> FetchDataAsync(string selectSql, MySql var addObjectRow = new T(); foreach (var prop in typeof(T).GetProperties()) { - if ((strict || Utils.ColumnExists(reader, prop.Name)) && !reader.IsDBNull(reader.GetOrdinal(prop.Name))) + if ((strict || Utils.ColumnExists(reader, prop.Name)) && !await reader.IsDBNullAsync(reader.GetOrdinal(prop.Name))) prop.SetValue(addObjectRow, reader[prop.Name]); } dataList.Add(addObjectRow); diff --git a/QueryDB/Oracle/Adapter.cs b/QueryDB/Oracle/Adapter.cs index 59f5b0d..07086d9 100644 --- a/QueryDB/Oracle/Adapter.cs +++ b/QueryDB/Oracle/Adapter.cs @@ -314,7 +314,7 @@ internal async Task> FetchDataAsync(string selectSql, Oracl var addObjectRow = new T(); foreach (var prop in typeof(T).GetProperties()) { - if ((strict || Utils.ColumnExists(reader, prop.Name)) && !reader.IsDBNull(reader.GetOrdinal(prop.Name))) + if ((strict || Utils.ColumnExists(reader, prop.Name)) && !await reader.IsDBNullAsync(reader.GetOrdinal(prop.Name))) { if (Utils.IsBFileColumn(reader, prop.Name)) prop.SetValue(addObjectRow, await Utils.GetBFileByteContentAsync(reader, prop.Name)); diff --git a/QueryDB/PostgreSQL/Adapter.cs b/QueryDB/PostgreSQL/Adapter.cs index 537e65f..47cc50c 100644 --- a/QueryDB/PostgreSQL/Adapter.cs +++ b/QueryDB/PostgreSQL/Adapter.cs @@ -305,7 +305,7 @@ internal async Task> FetchDataAsync(string selectSql, Npgsq var addObjectRow = new T(); foreach (var prop in typeof(T).GetProperties()) { - if ((strict || Utils.ColumnExists(reader, prop.Name)) && !reader.IsDBNull(reader.GetOrdinal(prop.Name))) + if ((strict || Utils.ColumnExists(reader, prop.Name)) && !await reader.IsDBNullAsync(reader.GetOrdinal(prop.Name))) prop.SetValue(addObjectRow, reader[prop.Name]); } dataList.Add(addObjectRow); diff --git a/QueryDB/Resources/Utils.cs b/QueryDB/Resources/Utils.cs index 4de5003..ca114c8 100644 --- a/QueryDB/Resources/Utils.cs +++ b/QueryDB/Resources/Utils.cs @@ -99,7 +99,7 @@ internal static async Task GetBFileBase64ContentAsync(OracleDataReader r { string content = string.Empty; var bFile = reader.GetOracleBFile(columnIndex); - if (bFile != null && !reader.IsDBNull(columnIndex)) + if (bFile != null && !await reader.IsDBNullAsync(columnIndex)) { bFile.OpenFile(); byte[] buffer = new byte[bFile.Length]; @@ -156,7 +156,7 @@ internal static async Task GetBFileByteContentAsync(OracleDataReader rea byte[] buffer = null; int columnIndex = reader.GetOrdinal(columnName); var bFile = reader.GetOracleBFile(columnIndex); - if (bFile != null && !reader.IsDBNull(columnIndex)) + if (bFile != null && !await reader.IsDBNullAsync(columnIndex)) { bFile.OpenFile(); buffer = new byte[bFile.Length]; From f744de3ba782df9cf6f0f46b9f57203dccf0e358 Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Sun, 23 Feb 2025 14:28:16 +1100 Subject: [PATCH 08/34] CQ - All method overloads should be adjacent. --- QueryDB/DBContext.cs | 42 +++++++++++++++++++++--------------------- QueryDB/IDBContext.cs | 16 ++++++++-------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/QueryDB/DBContext.cs b/QueryDB/DBContext.cs index 4d79bac..439516e 100644 --- a/QueryDB/DBContext.cs +++ b/QueryDB/DBContext.cs @@ -103,22 +103,21 @@ public List FetchData(string selectSql, bool upperCaseKeys = fal } /// - /// Asynchronously executes and retrieves records for 'Select' queries from the database. - /// Converts column names to keys holding values, with multiple database rows returned into a list. - /// Note: Use aliases in query for similar column names. + /// Executes and retrieves records for 'Select' queries from the database. /// + /// Object entity to return data mapped into. /// 'Select' query. - /// Boolean parameter to return dictionary keys in uppercase. Default - false. - /// List of with column names as keys holding values into a list for multiple rows of data. - public async Task> FetchDataAsync(string selectSql, bool upperCaseKeys = false) + /// Enables fetch data only for object type properties existing in database query result. Default - false. + /// List of data rows mapped into object of type . + public List FetchData(string selectSql, bool strict = false) where T : new() { - var dataList = new List(); + var dataList = new List(); if (Database.Equals(DB.MSSQL)) { using (var msSqlDBConnection = GetSqlServerConnection()) { var _systemAdapter = new MSSQL.Adapter(); - dataList = await _systemAdapter.FetchDataAsync(selectSql, msSqlDBConnection.SqlConnection, upperCaseKeys); + dataList = _systemAdapter.FetchData(selectSql, msSqlDBConnection.SqlConnection, strict); } } else if (Database.Equals(DB.MySQL)) @@ -126,7 +125,7 @@ public async Task> FetchDataAsync(string selectSql, bool up using (var mySqlDBConnection = GetMySqlConnection()) { var _systemAdapter = new MySQL.Adapter(); - dataList = await _systemAdapter.FetchDataAsync(selectSql, mySqlDBConnection.MySqlConnection, upperCaseKeys); + dataList = _systemAdapter.FetchData(selectSql, mySqlDBConnection.MySqlConnection, strict); } } else if (Database.Equals(DB.Oracle)) @@ -134,7 +133,7 @@ public async Task> FetchDataAsync(string selectSql, bool up using (var oracleDBConnection = GetOracleConnection()) { var _systemAdapter = new Oracle.Adapter(); - dataList = await _systemAdapter.FetchDataAsync(selectSql, oracleDBConnection.OracleConnection, upperCaseKeys); + dataList = _systemAdapter.FetchData(selectSql, oracleDBConnection.OracleConnection, strict); } } else if (Database.Equals(DB.PostgreSQL)) @@ -142,28 +141,29 @@ public async Task> FetchDataAsync(string selectSql, bool up using (var postgreSqlDBConnection = GetPostgreSqlConnection()) { var _systemAdapter = new PostgreSQL.Adapter(); - dataList = await _systemAdapter.FetchDataAsync(selectSql, postgreSqlDBConnection.PostgreSQLConnection, upperCaseKeys); + dataList = _systemAdapter.FetchData(selectSql, postgreSqlDBConnection.PostgreSQLConnection, strict); } } return dataList; } /// - /// Executes and retrieves records for 'Select' queries from the database. + /// Asynchronously executes and retrieves records for 'Select' queries from the database. + /// Converts column names to keys holding values, with multiple database rows returned into a list. + /// Note: Use aliases in query for similar column names. /// - /// Object entity to return data mapped into. /// 'Select' query. - /// Enables fetch data only for object type properties existing in database query result. Default - false. - /// List of data rows mapped into object of type . - public List FetchData(string selectSql, bool strict = false) where T : new() + /// Boolean parameter to return dictionary keys in uppercase. Default - false. + /// List of with column names as keys holding values into a list for multiple rows of data. + public async Task> FetchDataAsync(string selectSql, bool upperCaseKeys = false) { - var dataList = new List(); + var dataList = new List(); if (Database.Equals(DB.MSSQL)) { using (var msSqlDBConnection = GetSqlServerConnection()) { var _systemAdapter = new MSSQL.Adapter(); - dataList = _systemAdapter.FetchData(selectSql, msSqlDBConnection.SqlConnection, strict); + dataList = await _systemAdapter.FetchDataAsync(selectSql, msSqlDBConnection.SqlConnection, upperCaseKeys); } } else if (Database.Equals(DB.MySQL)) @@ -171,7 +171,7 @@ public async Task> FetchDataAsync(string selectSql, bool up using (var mySqlDBConnection = GetMySqlConnection()) { var _systemAdapter = new MySQL.Adapter(); - dataList = _systemAdapter.FetchData(selectSql, mySqlDBConnection.MySqlConnection, strict); + dataList = await _systemAdapter.FetchDataAsync(selectSql, mySqlDBConnection.MySqlConnection, upperCaseKeys); } } else if (Database.Equals(DB.Oracle)) @@ -179,7 +179,7 @@ public async Task> FetchDataAsync(string selectSql, bool up using (var oracleDBConnection = GetOracleConnection()) { var _systemAdapter = new Oracle.Adapter(); - dataList = _systemAdapter.FetchData(selectSql, oracleDBConnection.OracleConnection, strict); + dataList = await _systemAdapter.FetchDataAsync(selectSql, oracleDBConnection.OracleConnection, upperCaseKeys); } } else if (Database.Equals(DB.PostgreSQL)) @@ -187,7 +187,7 @@ public async Task> FetchDataAsync(string selectSql, bool up using (var postgreSqlDBConnection = GetPostgreSqlConnection()) { var _systemAdapter = new PostgreSQL.Adapter(); - dataList = _systemAdapter.FetchData(selectSql, postgreSqlDBConnection.PostgreSQLConnection, strict); + dataList = await _systemAdapter.FetchDataAsync(selectSql, postgreSqlDBConnection.PostgreSQLConnection, upperCaseKeys); } } return dataList; diff --git a/QueryDB/IDBContext.cs b/QueryDB/IDBContext.cs index 92de5f2..b6934b7 100644 --- a/QueryDB/IDBContext.cs +++ b/QueryDB/IDBContext.cs @@ -17,14 +17,6 @@ interface IDBContext /// List of with column names as keys holding values into a list for multiple rows of data. List FetchData(string selectSql, bool upperCaseKeys = false); - /// - /// Asynchronously executes and retrieves records for 'Select' queries from the database. - /// - /// 'Select' query. - /// Boolean parameter to return dictionary keys in uppercase. Default - false. - /// List of with column names as keys holding values into a list for multiple rows of data. - Task> FetchDataAsync(string selectSql, bool upperCaseKeys = false); - /// /// Executes and retrieves records for 'Select' queries from the database. /// @@ -34,6 +26,14 @@ interface IDBContext /// List of data rows mapped into object of type . List FetchData(string selectSql, bool strict = false) where T : new(); + /// + /// Asynchronously executes and retrieves records for 'Select' queries from the database. + /// + /// 'Select' query. + /// Boolean parameter to return dictionary keys in uppercase. Default - false. + /// List of with column names as keys holding values into a list for multiple rows of data. + Task> FetchDataAsync(string selectSql, bool upperCaseKeys = false); + /// /// Asynchronously executes and retrieves records for 'Select' queries from the database. /// From 9c2dc74dc80dbe9362780aa24ffcdf736c1f7721 Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Sun, 23 Feb 2025 17:32:26 +1100 Subject: [PATCH 09/34] Addition - Execute Scalar Async --- QueryDB.Core.Tests/MSSQLTests.cs | 251 ++++++++++++++++++++++++++ QueryDB.Core.Tests/MySQLTests.cs | 251 ++++++++++++++++++++++++++ QueryDB.Core.Tests/OracleTests.cs | 251 ++++++++++++++++++++++++++ QueryDB.Core.Tests/PostgreSQLTests.cs | 251 ++++++++++++++++++++++++++ QueryDB/DBContext.cs | 121 ++++++++++++- QueryDB/IDBContext.cs | 43 ++++- QueryDB/MSSQL/Adapter.cs | 39 ++++ QueryDB/MySQL/Adapter.cs | 38 ++++ QueryDB/Oracle/Adapter.cs | 39 ++++ QueryDB/PostgreSQL/Adapter.cs | 39 ++++ 10 files changed, 1311 insertions(+), 12 deletions(-) diff --git a/QueryDB.Core.Tests/MSSQLTests.cs b/QueryDB.Core.Tests/MSSQLTests.cs index 1b1d817..599f5a6 100644 --- a/QueryDB.Core.Tests/MSSQLTests.cs +++ b/QueryDB.Core.Tests/MSSQLTests.cs @@ -678,6 +678,92 @@ public void Test_MSSQL_ExecuteScalar_As_StringReturn_UnsupportedCommands() #endregion + #region Execute Scalar Async Tests - << Task ExecuteScalarAsync(string sqlStatement) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_ExecuteScalarAsync_As_StringReturn_Scalar_Queries() + { + var countOfRecords = Queries.MSSQLQueries.TestDB.ScalarQueries.Count_Of_Records; + var max = Queries.MSSQLQueries.TestDB.ScalarQueries.Max; + var min = Queries.MSSQLQueries.TestDB.ScalarQueries.Min; + var sum = Queries.MSSQLQueries.TestDB.ScalarQueries.Sum; + var avg = Queries.MSSQLQueries.TestDB.ScalarQueries.Avg; + var singleValueSelect = Queries.MSSQLQueries.TestDB.ScalarQueries.Single_Value_Select; + + var dbContext = new DBContext(DB.MSSQL, MSSQLConnectionString); + + var count = await dbContext.ExecuteScalarAsync(countOfRecords); + Assert.AreEqual("12", count); + var maxValue = await dbContext.ExecuteScalarAsync(max); + Assert.AreEqual("10000.00", maxValue); + var minValue = await dbContext.ExecuteScalarAsync(min); + Assert.AreEqual("3000.00", minValue); + var sumValue = await dbContext.ExecuteScalarAsync(sum); + Assert.AreEqual("161000.00", sumValue); + var avgValue = await dbContext.ExecuteScalarAsync(avg); + Assert.AreEqual("6520.000000", avgValue); + var singleValue = await dbContext.ExecuteScalarAsync(singleValueSelect); + Assert.AreEqual("2", singleValue); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_ExecuteScalarAsync_As_StringReturn_DefaultValue() + { + var noValueReturned = Queries.MSSQLQueries.TestDB.ScalarQueries.No_Value_Returned; + var dBNullValue = Queries.MSSQLQueries.TestDB.ScalarQueries.DB_Null_Value; + + var dbContext = new DBContext(DB.MSSQL, MSSQLConnectionString); + + var result = await dbContext .ExecuteScalarAsync(noValueReturned); + Assert.IsInstanceOfType(result); + Assert.AreEqual("", result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(string.Empty, result); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_ExecuteScalarAsync_As_StringReturn_UnsupportedCommands() + { + var sqlStatements = new List + { + Queries.MSSQLQueries.TestDB.DDL.Create_Table, + Queries.MSSQLQueries.TestDB.DDL.Alter_Table, + Queries.MSSQLQueries.TestDB.DDL.Comment_Table, + Queries.MSSQLQueries.TestDB.DDL.Truncate_Table, + Queries.MSSQLQueries.TestDB.DDL.Drop_Table, + + Queries.MSSQLQueries.TestDB.DML.InsertSql, + Queries.MSSQLQueries.TestDB.DML.UpdateSql, + Queries.MSSQLQueries.TestDB.DML.DeleteSql, + + Queries.MSSQLQueries.TestDB.DCL.GrantSql_Command_Table_User, + Queries.MSSQLQueries.TestDB.DCL.RevokeSql_Command_Table_User + }; + + foreach (var sqlStatement in sqlStatements) + { + try + { + var dbContext = new DBContext(DB.MSSQL, MSSQLConnectionString); + await dbContext.ExecuteScalarAsync(sqlStatement); + Assert.Fail("No Exception"); + } + catch (QueryDBException ex) + { + Assert.AreEqual("Only SELECT queries are supported here.", ex.Message); + Assert.AreEqual("UnsupportedCommand", ex.ErrorType); + Assert.AreEqual("'ExecuteScalar' only supports SELECT queries that have a scalar (single value) return.", ex.AdditionalInfo); + } + } + } + + #endregion + #region Execute Scalar Tests - << T ExecuteScalar(string sqlStatement) >> [TestMethod] @@ -843,6 +929,171 @@ public void Test_MSSQL_ExecuteScalar_As_TypedReturn_UnsupportedCommands() #endregion + #region Execute Scalar Async Tests - << Task ExecuteScalarAsync(string sqlStatement) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_ExecuteScalarAsync_As_TypedReturn_Scalar_Queries() + { + var countOfRecords = Queries.MSSQLQueries.TestDB.ScalarQueries.Count_Of_Records; + var max = Queries.MSSQLQueries.TestDB.ScalarQueries.Max; + var min = Queries.MSSQLQueries.TestDB.ScalarQueries.Min; + var sum = Queries.MSSQLQueries.TestDB.ScalarQueries.Sum; + var avg = Queries.MSSQLQueries.TestDB.ScalarQueries.Avg; + var singleValueSelect = Queries.MSSQLQueries.TestDB.ScalarQueries.Single_Value_Select; + + var dbContext = new DBContext(DB.MSSQL, MSSQLConnectionString); + + var count = await dbContext.ExecuteScalarAsync(countOfRecords); + Assert.AreEqual(12, count); + var maxValue = await dbContext.ExecuteScalarAsync(max); + Assert.AreEqual(10000.00, maxValue); + var minValue = await dbContext.ExecuteScalarAsync(min); + Assert.AreEqual(3000.00, minValue); + var sumValue = await dbContext.ExecuteScalarAsync(sum); + Assert.AreEqual(161000.00, sumValue); + var avgValue = await dbContext.ExecuteScalarAsync(avg); + Assert.AreEqual((decimal)6520.000000, avgValue); + var singleValue = await dbContext.ExecuteScalarAsync(singleValueSelect); + Assert.AreEqual("2", singleValue); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_ExecuteScalarAsync_As_TypedReturn_DefaultValue() + { + var dBNullValue = Queries.MSSQLQueries.TestDB.ScalarQueries.DB_Null_Value; + + var dbContext = new DBContext(DB.MSSQL, MSSQLConnectionString); + + dynamic result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(int), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(long), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(short), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(uint), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(ulong), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(ushort), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(decimal), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(double), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(float), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(byte), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(bool), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(DateTime), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(Guid), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(string), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(int?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(long?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(short?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(decimal?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(double?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(float?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(bool?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(DateTime?), result); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_ExecuteScalarAsync_As_TypedReturn_UnsupportedCommands() + { + var sqlStatements = new List + { + Queries.MSSQLQueries.TestDB.DDL.Create_Table, + Queries.MSSQLQueries.TestDB.DDL.Alter_Table, + Queries.MSSQLQueries.TestDB.DDL.Comment_Table, + Queries.MSSQLQueries.TestDB.DDL.Truncate_Table, + Queries.MSSQLQueries.TestDB.DDL.Drop_Table, + + Queries.MSSQLQueries.TestDB.DML.InsertSql, + Queries.MSSQLQueries.TestDB.DML.UpdateSql, + Queries.MSSQLQueries.TestDB.DML.DeleteSql, + + Queries.MSSQLQueries.TestDB.DCL.GrantSql_Command_Table_User, + Queries.MSSQLQueries.TestDB.DCL.RevokeSql_Command_Table_User + }; + + foreach (var sqlStatement in sqlStatements) + { + try + { + var dbContext = new DBContext(DB.MSSQL, MSSQLConnectionString); + await dbContext.ExecuteScalarAsync(sqlStatement); + Assert.Fail("No Exception"); + } + catch (QueryDBException ex) + { + Assert.AreEqual("Only SELECT queries are supported here.", ex.Message); + Assert.AreEqual("UnsupportedCommand", ex.ErrorType); + Assert.AreEqual("'ExecuteScalar' only supports SELECT queries that have a scalar (single value) return.", ex.AdditionalInfo); + } + } + } + + #endregion + #region Execute Command Tests - << int ExecuteCommand(string sqlStatement) >> [TestMethod] diff --git a/QueryDB.Core.Tests/MySQLTests.cs b/QueryDB.Core.Tests/MySQLTests.cs index 7b19329..3b43c7b 100644 --- a/QueryDB.Core.Tests/MySQLTests.cs +++ b/QueryDB.Core.Tests/MySQLTests.cs @@ -638,6 +638,92 @@ public void Test_MySQL_ExecuteScalar_As_StringReturn_UnsupportedCommands() #endregion + #region Execute Scalar Async Tests - << Task ExecuteScalarAsync(string sqlStatement) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_ExecuteScalarAsync_As_StringReturn_Scalar_Queries() + { + var countOfRecords = Queries.MySQLQueries.TestDB.ScalarQueries.Count_Of_Records; + var max = Queries.MySQLQueries.TestDB.ScalarQueries.Max; + var min = Queries.MySQLQueries.TestDB.ScalarQueries.Min; + var sum = Queries.MySQLQueries.TestDB.ScalarQueries.Sum; + var avg = Queries.MySQLQueries.TestDB.ScalarQueries.Avg; + var singleValueSelect = Queries.MySQLQueries.TestDB.ScalarQueries.Single_Value_Select; + + var dbContext = new DBContext(DB.MySQL, MySQLConnectionString); + + var count = await dbContext.ExecuteScalarAsync(countOfRecords); + Assert.AreEqual("12", count); + var maxValue = await dbContext.ExecuteScalarAsync(max); + Assert.AreEqual("10000.00", maxValue); + var minValue = await dbContext.ExecuteScalarAsync(min); + Assert.AreEqual("3000.00", minValue); + var sumValue = await dbContext.ExecuteScalarAsync(sum); + Assert.AreEqual("161000.00", sumValue); + var avgValue = await dbContext.ExecuteScalarAsync(avg); + Assert.AreEqual("6520.000000", avgValue); + var singleValue = await dbContext.ExecuteScalarAsync(singleValueSelect); + Assert.AreEqual("2", singleValue); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_ExecuteScalarAsync_As_StringReturn_DefaultValue() + { + var noValueReturned = Queries.MySQLQueries.TestDB.ScalarQueries.No_Value_Returned; + var dBNullValue = Queries.MySQLQueries.TestDB.ScalarQueries.DB_Null_Value; + + var dbContext = new DBContext(DB.MySQL, MySQLConnectionString); + + var result = await dbContext.ExecuteScalarAsync(noValueReturned); + Assert.IsInstanceOfType(result); + Assert.AreEqual("", result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(string.Empty, result); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_ExecuteScalarAsync_As_StringReturn_UnsupportedCommands() + { + var sqlStatements = new List + { + Queries.MySQLQueries.TestDB.DDL.Create_Table, + Queries.MySQLQueries.TestDB.DDL.Alter_Table, + Queries.MySQLQueries.TestDB.DDL.Comment_Table, + Queries.MySQLQueries.TestDB.DDL.Truncate_Table, + Queries.MySQLQueries.TestDB.DDL.Drop_Table, + + Queries.MySQLQueries.TestDB.DML.InsertSql, + Queries.MySQLQueries.TestDB.DML.UpdateSql, + Queries.MySQLQueries.TestDB.DML.DeleteSql, + + Queries.MySQLQueries.TestDB.DCL.GrantSql_Command_Table_User, + Queries.MySQLQueries.TestDB.DCL.RevokeSql_Command_Table_User + }; + + foreach (var sqlStatement in sqlStatements) + { + try + { + var dbContext = new DBContext(DB.MySQL, MySQLConnectionString); + await dbContext.ExecuteScalarAsync(sqlStatement); + Assert.Fail("No Exception"); + } + catch (QueryDBException ex) + { + Assert.AreEqual("Only SELECT queries are supported here.", ex.Message); + Assert.AreEqual("UnsupportedCommand", ex.ErrorType); + Assert.AreEqual("'ExecuteScalar' only supports SELECT queries that have a scalar (single value) return.", ex.AdditionalInfo); + } + } + } + + #endregion + #region Execute Scalar Tests - << T ExecuteScalar(string sqlStatement) >> [TestMethod] @@ -803,6 +889,171 @@ public void Test_MySQL_ExecuteScalar_As_TypedReturn_UnsupportedCommands() #endregion + #region Execute Scalar Async Tests - << Task ExecuteScalarAsync(string sqlStatement) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_ExecuteScalarAsync_As_TypedReturn_Scalar_Queries() + { + var countOfRecords = Queries.MySQLQueries.TestDB.ScalarQueries.Count_Of_Records; + var max = Queries.MySQLQueries.TestDB.ScalarQueries.Max; + var min = Queries.MySQLQueries.TestDB.ScalarQueries.Min; + var sum = Queries.MySQLQueries.TestDB.ScalarQueries.Sum; + var avg = Queries.MySQLQueries.TestDB.ScalarQueries.Avg; + var singleValueSelect = Queries.MySQLQueries.TestDB.ScalarQueries.Single_Value_Select; + + var dbContext = new DBContext(DB.MySQL, MySQLConnectionString); + + var count = await dbContext.ExecuteScalarAsync(countOfRecords); + Assert.AreEqual(12, count); + var maxValue = await dbContext.ExecuteScalarAsync(max); + Assert.AreEqual(10000.00, maxValue); + var minValue = await dbContext.ExecuteScalarAsync(min); + Assert.AreEqual(3000.00, minValue); + var sumValue = await dbContext.ExecuteScalarAsync(sum); + Assert.AreEqual(161000.00, sumValue); + var avgValue = await dbContext.ExecuteScalarAsync(avg); + Assert.AreEqual((decimal)6520.000000, avgValue); + var singleValue = await dbContext.ExecuteScalarAsync(singleValueSelect); + Assert.AreEqual("2", singleValue); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_ExecuteScalarAsync_As_TypedReturn_DefaultValue() + { + var dBNullValue = Queries.MySQLQueries.TestDB.ScalarQueries.DB_Null_Value; + + var dbContext = new DBContext(DB.MySQL, MySQLConnectionString); + + dynamic result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(int), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(long), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(short), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(uint), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(ulong), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(ushort), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(decimal), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(double), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(float), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(byte), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(bool), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(DateTime), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(Guid), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(string), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(int?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(long?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(short?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(decimal?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(double?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(float?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(bool?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(DateTime?), result); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_ExecuteScalarAsync_As_TypedReturn_UnsupportedCommands() + { + var sqlStatements = new List + { + Queries.MySQLQueries.TestDB.DDL.Create_Table, + Queries.MySQLQueries.TestDB.DDL.Alter_Table, + Queries.MySQLQueries.TestDB.DDL.Comment_Table, + Queries.MySQLQueries.TestDB.DDL.Truncate_Table, + Queries.MySQLQueries.TestDB.DDL.Drop_Table, + + Queries.MySQLQueries.TestDB.DML.InsertSql, + Queries.MySQLQueries.TestDB.DML.UpdateSql, + Queries.MySQLQueries.TestDB.DML.DeleteSql, + + Queries.MySQLQueries.TestDB.DCL.GrantSql_Command_Table_User, + Queries.MySQLQueries.TestDB.DCL.RevokeSql_Command_Table_User + }; + + foreach (var sqlStatement in sqlStatements) + { + try + { + var dbContext = new DBContext(DB.MySQL, MySQLConnectionString); + await dbContext.ExecuteScalarAsync(sqlStatement); + Assert.Fail("No Exception"); + } + catch (QueryDBException ex) + { + Assert.AreEqual("Only SELECT queries are supported here.", ex.Message); + Assert.AreEqual("UnsupportedCommand", ex.ErrorType); + Assert.AreEqual("'ExecuteScalar' only supports SELECT queries that have a scalar (single value) return.", ex.AdditionalInfo); + } + } + } + + #endregion + #region Execute Command Tests - << int ExecuteCommand(string sqlStatement) >> [TestMethod] diff --git a/QueryDB.Core.Tests/OracleTests.cs b/QueryDB.Core.Tests/OracleTests.cs index 255bab3..886d5b3 100644 --- a/QueryDB.Core.Tests/OracleTests.cs +++ b/QueryDB.Core.Tests/OracleTests.cs @@ -642,6 +642,92 @@ public void Test_Oracle_ExecuteScalar_As_StringReturn_UnsupportedCommands() #endregion + #region Execute Scalar Async Tests - << Task ExecuteScalarAsync(string sqlStatement) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_ExecuteScalarAsync_As_StringReturn_Scalar_Queries() + { + var countOfRecords = Queries.OracleQueries.TestDB.ScalarQueries.Count_Of_Records; + var max = Queries.OracleQueries.TestDB.ScalarQueries.Max; + var min = Queries.OracleQueries.TestDB.ScalarQueries.Min; + var sum = Queries.OracleQueries.TestDB.ScalarQueries.Sum; + var avg = Queries.OracleQueries.TestDB.ScalarQueries.Avg; + var singleValueSelect = Queries.OracleQueries.TestDB.ScalarQueries.Single_Value_Select; + + var dbContext = new DBContext(DB.Oracle, OracleConnectionString); + + var count = await dbContext.ExecuteScalarAsync(countOfRecords); + Assert.AreEqual("12", count); + var maxValue = await dbContext.ExecuteScalarAsync(max); + Assert.AreEqual("10000", maxValue); + var minValue = await dbContext.ExecuteScalarAsync(min); + Assert.AreEqual("3000", minValue); + var sumValue = await dbContext.ExecuteScalarAsync(sum); + Assert.AreEqual("161000", sumValue); + var avgValue = await dbContext.ExecuteScalarAsync(avg); + Assert.AreEqual("6520", avgValue); + var singleValue = await dbContext.ExecuteScalarAsync(singleValueSelect); + Assert.AreEqual("2", singleValue); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_ExecuteScalarAsync_As_StringReturn_DefaultValue() + { + var noValueReturned = Queries.OracleQueries.TestDB.ScalarQueries.No_Value_Returned; + var dBNullValue = Queries.OracleQueries.TestDB.ScalarQueries.DB_Null_Value; + + var dbContext = new DBContext(DB.Oracle, OracleConnectionString); + + var result = await dbContext.ExecuteScalarAsync(noValueReturned); + Assert.IsInstanceOfType(result); + Assert.AreEqual("", result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(string.Empty, result); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_ExecuteScalarAsync_As_StringReturn_UnsupportedCommands() + { + var sqlStatements = new List + { + Queries.OracleQueries.TestDB.DDL.Create_Table, + Queries.OracleQueries.TestDB.DDL.Alter_Table, + Queries.OracleQueries.TestDB.DDL.Comment_Table, + Queries.OracleQueries.TestDB.DDL.Truncate_Table, + Queries.OracleQueries.TestDB.DDL.Drop_Table, + + Queries.OracleQueries.TestDB.DML.InsertSql, + Queries.OracleQueries.TestDB.DML.UpdateSql, + Queries.OracleQueries.TestDB.DML.DeleteSql, + + Queries.OracleQueries.TestDB.DCL.GrantSql_Command_Table_User, + Queries.OracleQueries.TestDB.DCL.RevokeSql_Command_Table_User + }; + + foreach (var sqlStatement in sqlStatements) + { + try + { + var dbContext = new DBContext(DB.Oracle, OracleConnectionString); + await dbContext.ExecuteScalarAsync(sqlStatement); + Assert.Fail("No Exception"); + } + catch (QueryDBException ex) + { + Assert.AreEqual("Only SELECT queries are supported here.", ex.Message); + Assert.AreEqual("UnsupportedCommand", ex.ErrorType); + Assert.AreEqual("'ExecuteScalar' only supports SELECT queries that have a scalar (single value) return.", ex.AdditionalInfo); + } + } + } + + #endregion + #region Execute Scalar Tests - << T ExecuteScalar(string sqlStatement) >> [TestMethod] @@ -807,6 +893,171 @@ public void Test_Oracle_ExecuteScalar_As_TypedReturn_UnsupportedCommands() #endregion + #region Execute Scalar Async Tests - << Task ExecuteScalarAsync(string sqlStatement) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_ExecuteScalarAsync_As_TypedReturn_Scalar_Queries() + { + var countOfRecords = Queries.OracleQueries.TestDB.ScalarQueries.Count_Of_Records; + var max = Queries.OracleQueries.TestDB.ScalarQueries.Max; + var min = Queries.OracleQueries.TestDB.ScalarQueries.Min; + var sum = Queries.OracleQueries.TestDB.ScalarQueries.Sum; + var avg = Queries.OracleQueries.TestDB.ScalarQueries.Avg; + var singleValueSelect = Queries.OracleQueries.TestDB.ScalarQueries.Single_Value_Select; + + var dbContext = new DBContext(DB.Oracle, OracleConnectionString); + + var count = await dbContext.ExecuteScalarAsync(countOfRecords); + Assert.AreEqual(12, count); + var maxValue = await dbContext.ExecuteScalarAsync(max); + Assert.AreEqual(10000.00, maxValue); + var minValue = await dbContext.ExecuteScalarAsync(min); + Assert.AreEqual(3000.00, minValue); + var sumValue = await dbContext.ExecuteScalarAsync(sum); + Assert.AreEqual(161000.00, sumValue); + var avgValue = await dbContext.ExecuteScalarAsync(avg); + Assert.AreEqual((decimal)6520.000000, avgValue); + var singleValue = await dbContext.ExecuteScalarAsync(singleValueSelect); + Assert.AreEqual("2", singleValue); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_ExecuteScalarAsync_As_TypedReturn_DefaultValue() + { + var dBNullValue = Queries.OracleQueries.TestDB.ScalarQueries.DB_Null_Value; + + var dbContext = new DBContext(DB.Oracle, OracleConnectionString); + + dynamic result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(int), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(long), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(short), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(uint), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(ulong), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(ushort), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(decimal), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(double), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(float), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(byte), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(bool), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(DateTime), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(Guid), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(string), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(int?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(long?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(short?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(decimal?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(double?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(float?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(bool?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(DateTime?), result); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_ExecuteScalarAsync_As_TypedReturn_UnsupportedCommands() + { + var sqlStatements = new List + { + Queries.OracleQueries.TestDB.DDL.Create_Table, + Queries.OracleQueries.TestDB.DDL.Alter_Table, + Queries.OracleQueries.TestDB.DDL.Comment_Table, + Queries.OracleQueries.TestDB.DDL.Truncate_Table, + Queries.OracleQueries.TestDB.DDL.Drop_Table, + + Queries.OracleQueries.TestDB.DML.InsertSql, + Queries.OracleQueries.TestDB.DML.UpdateSql, + Queries.OracleQueries.TestDB.DML.DeleteSql, + + Queries.OracleQueries.TestDB.DCL.GrantSql_Command_Table_User, + Queries.OracleQueries.TestDB.DCL.RevokeSql_Command_Table_User + }; + + foreach (var sqlStatement in sqlStatements) + { + try + { + var dbContext = new DBContext(DB.Oracle, OracleConnectionString); + await dbContext.ExecuteScalarAsync(sqlStatement); + Assert.Fail("No Exception"); + } + catch (QueryDBException ex) + { + Assert.AreEqual("Only SELECT queries are supported here.", ex.Message); + Assert.AreEqual("UnsupportedCommand", ex.ErrorType); + Assert.AreEqual("'ExecuteScalar' only supports SELECT queries that have a scalar (single value) return.", ex.AdditionalInfo); + } + } + } + + #endregion + #region Execute Command Tests - << int ExecuteCommand(string sqlStatement) >> [TestMethod] diff --git a/QueryDB.Core.Tests/PostgreSQLTests.cs b/QueryDB.Core.Tests/PostgreSQLTests.cs index 5faddd5..5e5b3ce 100644 --- a/QueryDB.Core.Tests/PostgreSQLTests.cs +++ b/QueryDB.Core.Tests/PostgreSQLTests.cs @@ -626,6 +626,92 @@ public void Test_PostgreSQL_ExecuteScalar_As_StringReturn_UnsupportedCommands() #endregion + #region Execute Scalar Async Tests - << Task ExecuteScalarAsync(string sqlStatement) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_ExecuteScalarAsync_As_StringReturn_Scalar_Queries() + { + var countOfRecords = Queries.PostgreSQLQueries.TestDB.ScalarQueries.Count_Of_Records; + var max = Queries.PostgreSQLQueries.TestDB.ScalarQueries.Max; + var min = Queries.PostgreSQLQueries.TestDB.ScalarQueries.Min; + var sum = Queries.PostgreSQLQueries.TestDB.ScalarQueries.Sum; + var avg = Queries.PostgreSQLQueries.TestDB.ScalarQueries.Avg; + var singleValueSelect = Queries.PostgreSQLQueries.TestDB.ScalarQueries.Single_Value_Select; + + var dbContext = new DBContext(DB.PostgreSQL, PostgreSQLConnectionString); + + var count = await dbContext.ExecuteScalarAsync(countOfRecords); + Assert.AreEqual("12", count); + var maxValue = await dbContext.ExecuteScalarAsync(max); + Assert.AreEqual("10000.00", maxValue); + var minValue = await dbContext.ExecuteScalarAsync(min); + Assert.AreEqual("3000.00", minValue); + var sumValue = await dbContext.ExecuteScalarAsync(sum); + Assert.AreEqual("161000.00", sumValue); + var avgValue = await dbContext.ExecuteScalarAsync(avg); + Assert.AreEqual("6520.0000000000000000", avgValue); + var singleValue = await dbContext.ExecuteScalarAsync(singleValueSelect); + Assert.AreEqual("2", singleValue); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_ExecuteScalarAsync_As_StringReturn_DefaultValue() + { + var noValueReturned = Queries.PostgreSQLQueries.TestDB.ScalarQueries.No_Value_Returned; + var dBNullValue = Queries.PostgreSQLQueries.TestDB.ScalarQueries.DB_Null_Value; + + var dbContext = new DBContext(DB.PostgreSQL, PostgreSQLConnectionString); + + var result = await dbContext.ExecuteScalarAsync(noValueReturned); + Assert.IsInstanceOfType(result); + Assert.AreEqual("", result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(string.Empty, result); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_ExecuteScalarAsync_As_StringReturn_UnsupportedCommands() + { + var sqlStatements = new List + { + Queries.PostgreSQLQueries.TestDB.DDL.Create_Table, + Queries.PostgreSQLQueries.TestDB.DDL.Alter_Table, + Queries.PostgreSQLQueries.TestDB.DDL.Comment_Table, + Queries.PostgreSQLQueries.TestDB.DDL.Truncate_Table, + Queries.PostgreSQLQueries.TestDB.DDL.Drop_Table, + + Queries.PostgreSQLQueries.TestDB.DML.InsertSql, + Queries.PostgreSQLQueries.TestDB.DML.UpdateSql, + Queries.PostgreSQLQueries.TestDB.DML.DeleteSql, + + Queries.PostgreSQLQueries.TestDB.DCL.GrantSql_Command_Table_User, + Queries.PostgreSQLQueries.TestDB.DCL.RevokeSql_Command_Table_User + }; + + foreach (var sqlStatement in sqlStatements) + { + try + { + var dbContext = new DBContext(DB.PostgreSQL, PostgreSQLConnectionString); + await dbContext.ExecuteScalarAsync(sqlStatement); + Assert.Fail("No Exception"); + } + catch (QueryDBException ex) + { + Assert.AreEqual("Only SELECT queries are supported here.", ex.Message); + Assert.AreEqual("UnsupportedCommand", ex.ErrorType); + Assert.AreEqual("'ExecuteScalar' only supports SELECT queries that have a scalar (single value) return.", ex.AdditionalInfo); + } + } + } + + #endregion + #region Execute Scalar Tests - << T ExecuteScalar(string sqlStatement) >> [TestMethod] @@ -791,6 +877,171 @@ public void Test_PostgreSQL_ExecuteScalar_As_TypedReturn_UnsupportedCommands() #endregion + #region Execute Scalar Async Tests - << Task ExecuteScalarAsync(string sqlStatement) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_ExecuteScalarAsync_As_TypedReturn_Scalar_Queries() + { + var countOfRecords = Queries.PostgreSQLQueries.TestDB.ScalarQueries.Count_Of_Records; + var max = Queries.PostgreSQLQueries.TestDB.ScalarQueries.Max; + var min = Queries.PostgreSQLQueries.TestDB.ScalarQueries.Min; + var sum = Queries.PostgreSQLQueries.TestDB.ScalarQueries.Sum; + var avg = Queries.PostgreSQLQueries.TestDB.ScalarQueries.Avg; + var singleValueSelect = Queries.PostgreSQLQueries.TestDB.ScalarQueries.Single_Value_Select; + + var dbContext = new DBContext(DB.PostgreSQL, PostgreSQLConnectionString); + + var count = await dbContext.ExecuteScalarAsync(countOfRecords); + Assert.AreEqual(12, count); + var maxValue = await dbContext.ExecuteScalarAsync(max); + Assert.AreEqual(10000.00, maxValue); + var minValue = await dbContext.ExecuteScalarAsync(min); + Assert.AreEqual(3000.00, minValue); + var sumValue = await dbContext.ExecuteScalarAsync(sum); + Assert.AreEqual(161000.00, sumValue); + var avgValue = await dbContext.ExecuteScalarAsync(avg); + Assert.AreEqual((decimal)6520.0000000000000000, avgValue); + var singleValue = await dbContext.ExecuteScalarAsync(singleValueSelect); + Assert.AreEqual("2", singleValue); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_ExecuteScalarAsync_As_TypedReturn_DefaultValue() + { + var dBNullValue = Queries.PostgreSQLQueries.TestDB.ScalarQueries.DB_Null_Value; + + var dbContext = new DBContext(DB.PostgreSQL, PostgreSQLConnectionString); + + dynamic result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(int), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(long), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(short), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(uint), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(ulong), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(ushort), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(decimal), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(double), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(float), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(byte), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(bool), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(DateTime), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsInstanceOfType(result); + Assert.AreEqual(default(Guid), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(string), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(int?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(long?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(short?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(decimal?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(double?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(float?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(bool?), result); + + result = await dbContext.ExecuteScalarAsync(dBNullValue); + Assert.IsNull(result); + Assert.AreEqual(default(DateTime?), result); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_ExecuteScalarAsync_As_TypedReturn_UnsupportedCommands() + { + var sqlStatements = new List + { + Queries.PostgreSQLQueries.TestDB.DDL.Create_Table, + Queries.PostgreSQLQueries.TestDB.DDL.Alter_Table, + Queries.PostgreSQLQueries.TestDB.DDL.Comment_Table, + Queries.PostgreSQLQueries.TestDB.DDL.Truncate_Table, + Queries.PostgreSQLQueries.TestDB.DDL.Drop_Table, + + Queries.PostgreSQLQueries.TestDB.DML.InsertSql, + Queries.PostgreSQLQueries.TestDB.DML.UpdateSql, + Queries.PostgreSQLQueries.TestDB.DML.DeleteSql, + + Queries.PostgreSQLQueries.TestDB.DCL.GrantSql_Command_Table_User, + Queries.PostgreSQLQueries.TestDB.DCL.RevokeSql_Command_Table_User + }; + + foreach (var sqlStatement in sqlStatements) + { + try + { + var dbContext = new DBContext(DB.PostgreSQL, PostgreSQLConnectionString); + await dbContext.ExecuteScalarAsync(sqlStatement); + Assert.Fail("No Exception"); + } + catch (QueryDBException ex) + { + Assert.AreEqual("Only SELECT queries are supported here.", ex.Message); + Assert.AreEqual("UnsupportedCommand", ex.ErrorType); + Assert.AreEqual("'ExecuteScalar' only supports SELECT queries that have a scalar (single value) return.", ex.AdditionalInfo); + } + } + } + + #endregion + #region Execute Command Tests - << int ExecuteCommand(string sqlStatement) >> [TestMethod] diff --git a/QueryDB/DBContext.cs b/QueryDB/DBContext.cs index 439516e..09ef60d 100644 --- a/QueryDB/DBContext.cs +++ b/QueryDB/DBContext.cs @@ -239,10 +239,14 @@ public async Task> FetchDataAsync(string selectSql, bool up } /// - /// Executes a SQL query and returns the result as a string. + /// Executes the provided SQL statement and returns the first column of the first row in the result set. + /// If the result is DBNull, an empty string is returned. /// - /// The SQL query to execute. - /// A string representing the result of the query. If the result is DBNull, an empty string is returned. + /// The SQL statement to execute. It should be a query that returns a single value. + /// + /// A representing the value of the first column of the first row in the result set, + /// or an empty string if the result is DBNull. + /// public string ExecuteScalar(string sqlStatement) { if (!Regex.IsMatch(sqlStatement, Utils.SelectQueryPattern, RegexOptions.IgnoreCase | RegexOptions.Singleline, TimeSpan.FromSeconds(5))) @@ -285,11 +289,15 @@ public string ExecuteScalar(string sqlStatement) } /// - /// Executes a SQL query and returns the result as the specified type. + /// Executes the provided SQL statement and returns the first column of the first row in the result set, + /// converted to the specified type . If the result is DBNull, the default value of is returned. /// /// The type to which the result should be converted. - /// The SQL query to execute. - /// The result of the query, converted to the specified type. If the result is DBNull, the default value for the type is returned. + /// The SQL statement to execute. It should be a query that returns a single value. + /// + /// The value of the first column of the first row in the result set, converted to type , + /// or the default value of if the result is DBNull. + /// public T ExecuteScalar(string sqlStatement) { if (!Regex.IsMatch(sqlStatement, Utils.SelectQueryPattern, RegexOptions.IgnoreCase | RegexOptions.Singleline, TimeSpan.FromSeconds(5))) @@ -331,6 +339,107 @@ public T ExecuteScalar(string sqlStatement) return value; } + /// + /// Asynchronously executes the provided SQL statement and returns the first column of the first row in the result set. + /// If the result is DBNull, an empty string is returned. + /// + /// The SQL statement to execute. It should be a query that returns a single value. + /// + /// A representing the value of the first column of the first row in the result set, + /// or an empty string if the result is DBNull. + /// + public async Task ExecuteScalarAsync(string sqlStatement) + { + if (!Regex.IsMatch(sqlStatement, Utils.SelectQueryPattern, RegexOptions.IgnoreCase | RegexOptions.Singleline, TimeSpan.FromSeconds(5))) + throw new QueryDBException(QueryDBExceptions.ErrorMessage.UnsupportedExecuteScalarCommand, + QueryDBExceptions.ErrorType.UnsupportedCommand, QueryDBExceptions.AdditionalInfo.UnsupportedExecuteScalarCommand); + var value = string.Empty; + if (Database.Equals(DB.MSSQL)) + { + using (var msSqlDBConnection = GetSqlServerConnection()) + { + var _systemAdapter = new MSSQL.Adapter(); + value = await _systemAdapter.ExecuteScalarAsync(sqlStatement, msSqlDBConnection.SqlConnection); + } + } + else if (Database.Equals(DB.MySQL)) + { + using (var mySqlDBConnection = GetMySqlConnection()) + { + var _systemAdapter = new MySQL.Adapter(); + value = await _systemAdapter.ExecuteScalarAsync(sqlStatement, mySqlDBConnection.MySqlConnection); + } + } + else if (Database.Equals(DB.Oracle)) + { + using (var oracleDBConnection = GetOracleConnection()) + { + var _systemAdapter = new Oracle.Adapter(); + value = await _systemAdapter.ExecuteScalarAsync(sqlStatement, oracleDBConnection.OracleConnection); + } + } + else if (Database.Equals(DB.PostgreSQL)) + { + using (var postgreSqlDBConnection = GetPostgreSqlConnection()) + { + var _systemAdapter = new PostgreSQL.Adapter(); + value = await _systemAdapter.ExecuteScalarAsync(sqlStatement, postgreSqlDBConnection.PostgreSQLConnection); + } + } + return value; + } + + /// + /// Asynchronously executes the provided SQL statement and returns the first column of the first row in the result set, + /// converted to the specified type . If the result is DBNull, the default value of is returned. + /// + /// The type to which the result should be converted. + /// The SQL statement to execute. It should be a query that returns a single value. + /// + /// The value of the first column of the first row in the result set, converted to type , + /// or the default value of if the result is DBNull. + /// + public async Task ExecuteScalarAsync(string sqlStatement) + { + if (!Regex.IsMatch(sqlStatement, Utils.SelectQueryPattern, RegexOptions.IgnoreCase | RegexOptions.Singleline, TimeSpan.FromSeconds(5))) + throw new QueryDBException(QueryDBExceptions.ErrorMessage.UnsupportedExecuteScalarCommand, + QueryDBExceptions.ErrorType.UnsupportedCommand, QueryDBExceptions.AdditionalInfo.UnsupportedExecuteScalarCommand); + var value = default(T); + if (Database.Equals(DB.MSSQL)) + { + using (var msSqlDBConnection = GetSqlServerConnection()) + { + var _systemAdapter = new MSSQL.Adapter(); + value = await _systemAdapter.ExecuteScalarAsync(sqlStatement, msSqlDBConnection.SqlConnection); + } + } + else if (Database.Equals(DB.MySQL)) + { + using (var mySqlDBConnection = GetMySqlConnection()) + { + var _systemAdapter = new MySQL.Adapter(); + value = await _systemAdapter.ExecuteScalarAsync(sqlStatement, mySqlDBConnection.MySqlConnection); + } + } + else if (Database.Equals(DB.Oracle)) + { + using (var oracleDBConnection = GetOracleConnection()) + { + var _systemAdapter = new Oracle.Adapter(); + value = await _systemAdapter.ExecuteScalarAsync(sqlStatement, oracleDBConnection.OracleConnection); + } + } + else if (Database.Equals(DB.PostgreSQL)) + { + using (var postgreSqlDBConnection = GetPostgreSqlConnection()) + { + var _systemAdapter = new PostgreSQL.Adapter(); + value = await _systemAdapter.ExecuteScalarAsync(sqlStatement, postgreSqlDBConnection.PostgreSQLConnection); + } + } + return value; + } + /// /// Executes SQL commands. /// diff --git a/QueryDB/IDBContext.cs b/QueryDB/IDBContext.cs index b6934b7..fa854c3 100644 --- a/QueryDB/IDBContext.cs +++ b/QueryDB/IDBContext.cs @@ -43,20 +43,51 @@ interface IDBContext Task> FetchDataAsync(string selectSql, bool strict = false) where T : new(); /// - /// Executes a SQL query and returns the result as a string. + /// Executes the provided SQL statement and returns the first column of the first row in the result set. + /// If the result is DBNull, an empty string is returned. /// - /// The SQL query to execute. - /// A string representing the result of the query. If the result is DBNull, an empty string is returned. + /// The SQL statement to execute. It should be a query that returns a single value. + /// + /// A representing the value of the first column of the first row in the result set, + /// or an empty string if the result is DBNull. + /// string ExecuteScalar(string sqlStatement); /// - /// Executes a SQL query and returns the result as the specified type. + /// Executes the provided SQL statement and returns the first column of the first row in the result set, + /// converted to the specified type . If the result is DBNull, the default value of is returned. /// /// The type to which the result should be converted. - /// The SQL query to execute. - /// The result of the query, converted to the specified type. If the result is DBNull, the default value for the type is returned. + /// The SQL statement to execute. It should be a query that returns a single value. + /// + /// The value of the first column of the first row in the result set, converted to type , + /// or the default value of if the result is DBNull. + /// T ExecuteScalar(string sqlStatement); + /// + /// Asynchronously executes the provided SQL statement and returns the first column of the first row in the result set. + /// If the result is DBNull, an empty string is returned. + /// + /// The SQL statement to execute. It should be a query that returns a single value. + /// + /// A representing the value of the first column of the first row in the result set, + /// or an empty string if the result is DBNull. + /// + Task ExecuteScalarAsync(string sqlStatement); + + /// + /// Asynchronously executes the provided SQL statement and returns the first column of the first row in the result set, + /// converted to the specified type . If the result is DBNull, the default value of is returned. + /// + /// The type to which the result should be converted. + /// The SQL statement to execute. It should be a query that returns a single value. + /// + /// The value of the first column of the first row in the result set, converted to type , + /// or the default value of if the result is DBNull. + /// + Task ExecuteScalarAsync(string sqlStatement); + /// /// Executes SQL commands. /// diff --git a/QueryDB/MSSQL/Adapter.cs b/QueryDB/MSSQL/Adapter.cs index 0b13d54..4d142cf 100644 --- a/QueryDB/MSSQL/Adapter.cs +++ b/QueryDB/MSSQL/Adapter.cs @@ -314,6 +314,45 @@ internal async Task> FetchDataAsync(string selectSql, SqlCo return dataList; } + /// + /// Asynchronously executes the provided SQL statement using the given SQL connection and returns the first column of the first row in the result set. + /// If the result is DBNull, an empty string is returned. + /// + /// The SQL statement to execute. It should be a query that returns a single value. + /// The to use for executing the SQL statement. + /// + /// A representing the value of the first column of the first row in the result set, + /// or an empty string if the result is DBNull. + /// + internal async Task ExecuteScalarAsync(string sqlStatement, SqlConnection connection) + { + using (var sqlCommand = await GetSqlCommandAsync(sqlStatement, connection, CommandType.Text)) + { + var result = await sqlCommand.ExecuteScalarAsync(); + return result == DBNull.Value ? string.Empty : result.ToString(); + } + } + + /// + /// Asynchronously executes the provided SQL statement using the given SQL connection and returns the first column of the first row in the result set, + /// converted to the specified type . If the result is DBNull, the default value of is returned. + /// + /// The type to which the result should be converted. + /// The SQL statement to execute. It should be a query that returns a single value. + /// The to use for executing the SQL statement. + /// + /// The value of the first column of the first row in the result set, converted to type , + /// or the default value of if the result is DBNull. + /// + internal async Task ExecuteScalarAsync(string sqlStatement, SqlConnection connection) + { + using (var sqlCommand = await GetSqlCommandAsync(sqlStatement, connection, CommandType.Text)) + { + var result = await sqlCommand.ExecuteScalarAsync(); + return result == DBNull.Value ? default : (T)Convert.ChangeType(result, typeof(T)); + } + } + #endregion } diff --git a/QueryDB/MySQL/Adapter.cs b/QueryDB/MySQL/Adapter.cs index d2ae9e2..b5bddce 100644 --- a/QueryDB/MySQL/Adapter.cs +++ b/QueryDB/MySQL/Adapter.cs @@ -313,6 +313,44 @@ internal async Task> FetchDataAsync(string selectSql, MySql return dataList; } + /// + /// Asynchronously executes the provided SQL statement using the given MySQL connection and returns the first column of the first row in the result set. + /// If the result is DBNull, an empty string is returned. + /// + /// The SQL statement to execute. It should be a query that returns a single value. + /// The to use for executing the SQL statement. + /// + /// A representing the value of the first column of the first row in the result set, + /// or an empty string if the res + internal async Task ExecuteScalarAsync(string sqlStatement, MySqlConnection connection) + { + using (var sqlCommand = await GetMySqlCommandAsync(sqlStatement, connection, CommandType.Text)) + { + var result = await sqlCommand.ExecuteScalarAsync(); + return result == DBNull.Value ? string.Empty : result.ToString(); + } + } + + /// + /// Asynchronously executes the provided SQL statement using the given MySQL connection and returns the first column of the first row in the result set, + /// converted to the specified type . If the result is DBNull, the default value of is returned. + /// + /// The type to which the result should be converted. + /// The SQL statement to execute. It should be a query that returns a single value. + /// The to use for executing the SQL statement. + /// + /// The value of the first column of the first row in the result set, converted to type , + /// or the default value of if the result is DBNull. + /// + internal async Task ExecuteScalarAsync(string sqlStatement, MySqlConnection connection) + { + using (var sqlCommand = await GetMySqlCommandAsync(sqlStatement, connection, CommandType.Text)) + { + var result = await sqlCommand.ExecuteScalarAsync(); + return result == DBNull.Value ? default : (T)Convert.ChangeType(result, typeof(T)); + } + } + #endregion } diff --git a/QueryDB/Oracle/Adapter.cs b/QueryDB/Oracle/Adapter.cs index 07086d9..60dc94a 100644 --- a/QueryDB/Oracle/Adapter.cs +++ b/QueryDB/Oracle/Adapter.cs @@ -328,6 +328,45 @@ internal async Task> FetchDataAsync(string selectSql, Oracl return dataList; } + /// + /// Asynchronously executes the provided SQL statement using the given Oracle connection and returns the first column of the first row in the result set. + /// If the result is DBNull, an empty string is returned. + /// + /// The SQL statement to execute. It should be a query that returns a single value. + /// The to use for executing the SQL statement. + /// + /// A representing the value of the first column of the first row in the result set, + /// or an empty string if the result is DBNull. + /// + internal async Task ExecuteScalarAsync(string sqlStatement, OracleConnection connection) + { + using (var sqlCommand = await GetOracleCommandAsync(sqlStatement, connection, CommandType.Text)) + { + var result = await sqlCommand.ExecuteScalarAsync(); + return result == DBNull.Value ? string.Empty : result.ToString(); + } + } + + /// + /// Asynchronously executes the provided SQL statement using the given Oracle connection and returns the first column of the first row in the result set, + /// converted to the specified type . If the result is DBNull, the default value of is returned. + /// + /// The type to which the result should be converted. + /// The SQL statement to execute. It should be a query that returns a single value. + /// The to use for executing the SQL statement. + /// + /// The value of the first column of the first row in the result set, converted to type , + /// or the default value of if the result is DBNull. + /// + internal async Task ExecuteScalarAsync(string sqlStatement, OracleConnection connection) + { + using (var sqlCommand = await GetOracleCommandAsync(sqlStatement, connection, CommandType.Text)) + { + var result = await sqlCommand.ExecuteScalarAsync(); + return result == null || result == DBNull.Value ? default : (T)Convert.ChangeType(result, typeof(T)); + } + } + #endregion } } \ No newline at end of file diff --git a/QueryDB/PostgreSQL/Adapter.cs b/QueryDB/PostgreSQL/Adapter.cs index 47cc50c..7c10f94 100644 --- a/QueryDB/PostgreSQL/Adapter.cs +++ b/QueryDB/PostgreSQL/Adapter.cs @@ -314,6 +314,45 @@ internal async Task> FetchDataAsync(string selectSql, Npgsq return dataList; } + /// + /// Asynchronously executes the provided SQL statement using the given PostgreSQL connection and returns the first column of the first row in the result set. + /// If the result is DBNull, an empty string is returned. + /// + /// The SQL statement to execute. It should be a query that returns a single value. + /// The to use for executing the SQL statement. + /// + /// A representing the value of the first column of the first row in the result set, + /// or an empty string if the result is DBNull. + /// + internal async Task ExecuteScalarAsync(string sqlStatement, NpgsqlConnection connection) + { + using (var sqlCommand = await GetPostgreSqlCommandAsync(sqlStatement, connection, CommandType.Text)) + { + var result = await sqlCommand.ExecuteScalarAsync(); + return result == null || result == DBNull.Value ? string.Empty : result.ToString(); + } + } + + /// + /// Asynchronously executes the provided SQL statement using the given PostgreSQL connection and returns the first column of the first row in the result set, + /// converted to the specified type . If the result is DBNull, the default value of is returned. + /// + /// The type to which the result should be converted. + /// The SQL statement to execute. It should be a query that returns a single value. + /// The to use for executing the SQL statement. + /// + /// The value of the first column of the first row in the result set, converted to type , + /// or the default value of if the result is DBNull. + /// + internal async Task ExecuteScalarAsync(string sqlStatement, NpgsqlConnection connection) + { + using (var sqlCommand = await GetPostgreSqlCommandAsync(sqlStatement, connection, CommandType.Text)) + { + var result = await sqlCommand.ExecuteScalarAsync(); + return result == null || result == DBNull.Value ? default : (T)Convert.ChangeType(result, typeof(T)); + } + } + #endregion } } From e59a1bec7f54e7416158e119534ecb3c616a73e6 Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Mon, 24 Feb 2025 00:28:19 +1100 Subject: [PATCH 10/34] Addition - Execute Command Async --- QueryDB.Core.Tests/MSSQLTests.cs | 174 ++++++++++++++++++++++++++ QueryDB.Core.Tests/MySQLTests.cs | 163 ++++++++++++++++++++++++ QueryDB.Core.Tests/OracleTests.cs | 172 +++++++++++++++++++++++++ QueryDB.Core.Tests/PostgreSQLTests.cs | 163 ++++++++++++++++++++++++ QueryDB/DBContext.cs | 51 +++++++- QueryDB/IDBContext.cs | 13 +- QueryDB/MSSQL/Adapter.cs | 22 +++- QueryDB/MySQL/Adapter.cs | 22 +++- QueryDB/Oracle/Adapter.cs | 22 +++- QueryDB/PostgreSQL/Adapter.cs | 22 +++- 10 files changed, 802 insertions(+), 22 deletions(-) diff --git a/QueryDB.Core.Tests/MSSQLTests.cs b/QueryDB.Core.Tests/MSSQLTests.cs index 599f5a6..7f2b5d7 100644 --- a/QueryDB.Core.Tests/MSSQLTests.cs +++ b/QueryDB.Core.Tests/MSSQLTests.cs @@ -1265,6 +1265,180 @@ public void Test_MSSQL_ExecuteCommand_DCL_Queries() #endregion + #region Execute Command Async Tests - << Task ExecuteCommandAsync(string sqlStatement) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_ExecuteCommandAsync_DDL_Queries() + { + var createTableSql = Queries.MSSQLQueries.TestDB.DDL.Create_Table; + var alterTableSql = Queries.MSSQLQueries.TestDB.DDL.Alter_Table; + var commentTableSql = Queries.MSSQLQueries.TestDB.DDL.Comment_Table; + var commentTableColumnSql = Queries.MSSQLQueries.TestDB.DDL.Comment_Table_Column; + var truncateTableSql = Queries.MSSQLQueries.TestDB.DDL.Truncate_Table; + var renameTableSql = Queries.MSSQLQueries.TestDB.DDL.Rename_Table; + var dropTableSql = Queries.MSSQLQueries.TestDB.DDL.Drop_Table; + var dDLExecutionCheckSql = Queries.MSSQLQueries.TestDB.DDL.DDL_Execute_check; + var dDLTableCommentCheckSql = Queries.MSSQLQueries.TestDB.DDL.DDL_Table_Comment_check; + var dDLTableColumnCommentCheckSql = Queries.MSSQLQueries.TestDB.DDL.DDL_Table_Column_Comment_check; + + var dbContext = new DBContext(DB.MSSQL, MSSQLConnectionString); + await dbContext.ExecuteCommandAsync(createTableSql); + await dbContext.ExecuteCommandAsync(alterTableSql); + await dbContext.ExecuteCommandAsync(commentTableSql); + await dbContext.ExecuteCommandAsync(commentTableColumnSql); + await dbContext.ExecuteCommandAsync(truncateTableSql); + + var tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "dbo", "Employee")); + Assert.AreEqual("1", tableCount[0].ReferenceData["Table_Count"]); + var tableComment = await dbContext + .FetchDataAsync(string.Format(dDLTableCommentCheckSql, "dbo", "Employee")); + Assert.AreEqual("This table stores employee records", tableComment[0].ReferenceData["Table_Comment"]); + var tableColumnComment = await dbContext + .FetchDataAsync(string.Format(dDLTableColumnCommentCheckSql, "dbo", "Employee")); + Assert.AreEqual("This column stores employee middle name", tableColumnComment[0].ReferenceData["Table_Column_Comment"]); + + await dbContext.ExecuteCommandAsync(renameTableSql); + + tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "dbo", "Employee")); + Assert.AreEqual("0", tableCount[0].ReferenceData["Table_Count"]); + tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "dbo", "Employees")); + Assert.AreEqual("1", tableCount[0].ReferenceData["Table_Count"]); + + await dbContext.ExecuteCommandAsync(dropTableSql); + + tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "dbo", "Employees")); + Assert.AreEqual("0", tableCount[0].ReferenceData["Table_Count"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_ExecuteCommandAsync_DML_Queries() + { + var insertSql = Queries.MSSQLQueries.TestDB.DML.InsertSql; + var updateSql = Queries.MSSQLQueries.TestDB.DML.UpdateSql; + var deleteSql = Queries.MSSQLQueries.TestDB.DML.DeleteSql; + var verifyDMLExecution = Queries.MSSQLQueries.TestDB.DML.VerifyDMLExecution; + + var dbContext = new DBContext(DB.MSSQL, MSSQLConnectionString); + + // Insert + var rows = await dbContext.ExecuteCommandAsync(insertSql); + Assert.AreEqual(1, rows); + var data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(1, data.Count); + var agent = data.FirstOrDefault(); + Assert.AreEqual("A020", agent.ReferenceData["Agent_Code"]); + Assert.AreEqual("John", agent.ReferenceData["Agent_Name"]); + Assert.AreEqual("Wick", agent.ReferenceData["Working_Area"]); + Assert.AreEqual("0.11", agent.ReferenceData["Commission"]); + Assert.AreEqual("010-44536178", agent.ReferenceData["Phone_No"]); + Assert.AreEqual("", agent.ReferenceData["Country"]); + + // Update + rows = await dbContext.ExecuteCommandAsync(updateSql); + Assert.AreEqual(1, rows); + data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(1, data.Count); + agent = data.FirstOrDefault(); + Assert.AreEqual("A020", agent.ReferenceData["Agent_Code"]); + Assert.AreEqual("John", agent.ReferenceData["Agent_Name"]); + Assert.AreEqual("Wick", agent.ReferenceData["Working_Area"]); + Assert.AreEqual("0.15", agent.ReferenceData["Commission"]); + Assert.AreEqual("010-44536178", agent.ReferenceData["Phone_No"]); + Assert.AreEqual("", agent.ReferenceData["Country"]); + + // Delete + rows = await dbContext.ExecuteCommandAsync(deleteSql); + Assert.AreEqual(1, rows); + data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(0, data.Count); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_ExecuteCommandAsync_DML_Unsupported_SELECT_Queries() + { + var selectSql = Queries.MSSQLQueries.TestDB.DML.SelectSql; + + // Select + try + { + var dbContext = new DBContext(DB.MSSQL, MSSQLConnectionString); + var rows = await dbContext.ExecuteCommandAsync(selectSql); + Assert.Fail("No Exception"); + } + catch (QueryDBException ex) + { + Assert.AreEqual("SELECT queries are not supported here.", ex.Message); + Assert.AreEqual("UnsupportedCommand", ex.ErrorType); + Assert.AreEqual("'ExecuteCommand' doesn't support SELECT queries.", ex.AdditionalInfo); + } + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_ExecuteCommandAsync_DCL_Queries() + { + var login = "test_user"; + var user = "test_user"; + var password = "Test@1234"; + var table = "agents"; + var commands = "SELECT, UPDATE"; + var checkCommand = "SELECT"; + + var createLogin = string.Format(Queries.MSSQLQueries.TestDB.DCL.CreateLoginSql_Login_Password, login, password); + var createUser = string.Format(Queries.MSSQLQueries.TestDB.DCL.CreateUserSql_User_Login, user, login); + var grantSql = string.Format(Queries.MSSQLQueries.TestDB.DCL.GrantSql_Command_Table_User, commands, table, user); + var revokeSql = string.Format(Queries.MSSQLQueries.TestDB.DCL.RevokeSql_Command_Table_User, commands, table, user); + var verifyPermissions = string.Format(Queries.MSSQLQueries.TestDB.DCL.VerifyPermission_User_Table_Command, user, table, checkCommand); + var removeUser = string.Format(Queries.MSSQLQueries.TestDB.DCL.RemoveUserSql_User, user); + var removeLogin = string.Format(Queries.MSSQLQueries.TestDB.DCL.RemoveLoginSql_Login, login); + + var dbContext = new DBContext(DB.MSSQL, MSSQLConnectionString); + + // Create Login + var result = await dbContext.ExecuteCommandAsync(createLogin); + Assert.AreEqual(-1, result); + + // Create User + result = await dbContext.ExecuteCommandAsync(createUser); + Assert.AreEqual(-1, result); + + // Existing Permissions + var data = await dbContext.FetchDataAsync(verifyPermissions); + var dataRow = data.FirstOrDefault(); + Assert.AreEqual("0", dataRow.ReferenceData["HasPermission"]); + + // Grant + result = await dbContext.ExecuteCommandAsync(grantSql); + Assert.AreEqual(-1, result); + data = await dbContext.FetchDataAsync(verifyPermissions); + dataRow = data.FirstOrDefault(); + Assert.AreEqual("1", dataRow.ReferenceData["HasPermission"]); + + // Revoke + result = await dbContext.ExecuteCommandAsync(revokeSql); + Assert.AreEqual(-1, result); + data = await dbContext.FetchDataAsync(verifyPermissions); + dataRow = data.FirstOrDefault(); + Assert.AreEqual("0", dataRow.ReferenceData["HasPermission"]); + + // Remove User + result = await dbContext.ExecuteCommandAsync(removeUser); + Assert.AreEqual(-1, result); + + // Remove Login + result = await dbContext.ExecuteCommandAsync(removeLogin); + Assert.AreEqual(-1, result); + } + + #endregion + #region Execute Transaction Tests - << bool ExecuteTransaction(List sqlStatements) >> [TestMethod] diff --git a/QueryDB.Core.Tests/MySQLTests.cs b/QueryDB.Core.Tests/MySQLTests.cs index 3b43c7b..46e4076 100644 --- a/QueryDB.Core.Tests/MySQLTests.cs +++ b/QueryDB.Core.Tests/MySQLTests.cs @@ -1217,6 +1217,169 @@ public void Test_MySQL_ExecuteCommand_DCL_Queries() #endregion + #region Execute Command Async Tests - << Task ExecuteCommandAsync(string sqlStatement) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_ExecuteCommandAsync_DDL_Queries() + { + var createTableSql = Queries.MySQLQueries.TestDB.DDL.Create_Table; + var alterTableSql = Queries.MySQLQueries.TestDB.DDL.Alter_Table; + var commentTableSql = Queries.MySQLQueries.TestDB.DDL.Comment_Table; + var commentTableColumnSql = Queries.MySQLQueries.TestDB.DDL.Comment_Table_Column; + var truncateTableSql = Queries.MySQLQueries.TestDB.DDL.Truncate_Table; + var renameTableSql = Queries.MySQLQueries.TestDB.DDL.Rename_Table; + var dropTableSql = Queries.MySQLQueries.TestDB.DDL.Drop_Table; + var dDLExecutionCheckSql = Queries.MySQLQueries.TestDB.DDL.DDL_Execute_check; + var dDLTableCommentCheckSql = Queries.MySQLQueries.TestDB.DDL.DDL_Table_Comment_check; + var dDLTableColumnCommentCheckSql = Queries.MySQLQueries.TestDB.DDL.DDL_Table_Column_Comment_check; + + var dbContext = new DBContext(DB.MySQL, MySQLConnectionString); + await dbContext.ExecuteCommandAsync(createTableSql); + await dbContext.ExecuteCommandAsync(alterTableSql); + await dbContext.ExecuteCommandAsync(commentTableSql); + await dbContext.ExecuteCommandAsync(commentTableColumnSql); + await dbContext.ExecuteCommandAsync(truncateTableSql); + + var tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "mysql", "Employee")); + Assert.AreEqual("1", tableCount[0].ReferenceData["Table_Count"]); + var tableComment = await dbContext + .FetchDataAsync(string.Format(dDLTableCommentCheckSql, "mysql", "Employee")); + Assert.AreEqual("This table stores employee records", tableComment[0].ReferenceData["Table_Comment"]); + var tableColumnComment = await dbContext + .FetchDataAsync(string.Format(dDLTableColumnCommentCheckSql, "mysql", "Employee")); + Assert.AreEqual("This column stores employee middle name", tableColumnComment[3].ReferenceData["Table_Column_Comment"]); + + await dbContext.ExecuteCommandAsync(renameTableSql); + + tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "mysql", "Employee")); + Assert.AreEqual("0", tableCount[0].ReferenceData["Table_Count"]); + tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "mysql", "Employees")); + Assert.AreEqual("1", tableCount[0].ReferenceData["Table_Count"]); + + await dbContext.ExecuteCommandAsync(dropTableSql); + + tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "mysql", "Employees")); + Assert.AreEqual("0", tableCount[0].ReferenceData["Table_Count"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_ExecuteCommandAsync_DML_Queries() + { + var insertSql = Queries.MySQLQueries.TestDB.DML.InsertSql; + var updateSql = Queries.MySQLQueries.TestDB.DML.UpdateSql; + var deleteSql = Queries.MySQLQueries.TestDB.DML.DeleteSql; + var verifyDMLExecution = Queries.MySQLQueries.TestDB.DML.VerifyDMLExecution; + + var dbContext = new DBContext(DB.MySQL, MySQLConnectionString); + + // Insert + var rows = await dbContext.ExecuteCommandAsync(insertSql); + Assert.AreEqual(1, rows); + var data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(1, data.Count); + var agent = data.FirstOrDefault(); + Assert.AreEqual("A020", agent.ReferenceData["Agent_Code"]); + Assert.AreEqual("John", agent.ReferenceData["Agent_Name"]); + Assert.AreEqual("Wick", agent.ReferenceData["Working_Area"]); + Assert.AreEqual("0.11", agent.ReferenceData["Commission"]); + Assert.AreEqual("010-44536178", agent.ReferenceData["Phone_No"]); + Assert.AreEqual("", agent.ReferenceData["Country"]); + + // Update + rows = await dbContext.ExecuteCommandAsync(updateSql); + Assert.AreEqual(1, rows); + data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(1, data.Count); + agent = data.FirstOrDefault(); + Assert.AreEqual("A020", agent.ReferenceData["Agent_Code"]); + Assert.AreEqual("John", agent.ReferenceData["Agent_Name"]); + Assert.AreEqual("Wick", agent.ReferenceData["Working_Area"]); + Assert.AreEqual("0.15", agent.ReferenceData["Commission"]); + Assert.AreEqual("010-44536178", agent.ReferenceData["Phone_No"]); + Assert.AreEqual("", agent.ReferenceData["Country"]); + + // Delete + rows = await dbContext.ExecuteCommandAsync(deleteSql); + Assert.AreEqual(1, rows); + data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(0, data.Count); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_ExecuteCommandAsync_DML_Unsupported_SELECT_Queries() + { + var selectSql = Queries.MySQLQueries.TestDB.DML.SelectSql; + + // Select + try + { + var dbContext = new DBContext(DB.MySQL, MySQLConnectionString); + var rows = await dbContext.ExecuteCommandAsync(selectSql); + Assert.Fail("No Exception"); + } + catch (QueryDBException ex) + { + Assert.AreEqual("SELECT queries are not supported here.", ex.Message); + Assert.AreEqual("UnsupportedCommand", ex.ErrorType); + Assert.AreEqual("'ExecuteCommand' doesn't support SELECT queries.", ex.AdditionalInfo); + } + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_ExecuteCommandAsync_DCL_Queries() + { + var user = "test_user"; + var password = "Test@1234"; + var table = "Agents"; + var commands = "SELECT, UPDATE"; + var checkCommand = "SELECT"; + + var createUser = string.Format(Queries.MySQLQueries.TestDB.DCL.CreateUserSql_User_Password, user, password); + var grantSql = string.Format(Queries.MySQLQueries.TestDB.DCL.GrantSql_Command_Table_User, commands, table, user); + var revokeSql = string.Format(Queries.MySQLQueries.TestDB.DCL.RevokeSql_Command_Table_User, commands, table, user); + var verifyPermissions = string.Format(Queries.MySQLQueries.TestDB.DCL.VerifyPermission_User, user); + var removeUser = string.Format(Queries.MySQLQueries.TestDB.DCL.RemoveUserSql_User, user); + + var dbContext = new DBContext(DB.MySQL, MySQLConnectionString); + + // Create User + var result = await dbContext.ExecuteCommandAsync(createUser); + Assert.AreEqual(0, result); + + // Existing Permissions + var data = await dbContext.FetchDataAsync(verifyPermissions); + Assert.AreEqual(1, data.Count); + Assert.IsFalse(data.Any(data => data.ReferenceData.Values.Any(value => value.Contains(checkCommand)))); + + // Grant + result = await dbContext.ExecuteCommandAsync(grantSql); + Assert.AreEqual(0, result); + data = await dbContext.FetchDataAsync(verifyPermissions); + Assert.AreEqual(2, data.Count); + Assert.IsTrue(data.Any(data => data.ReferenceData.Values.Any(value => value.Contains(checkCommand)))); + + // Revoke + result = await dbContext.ExecuteCommandAsync(revokeSql); + Assert.AreEqual(0, result); + data = await dbContext.FetchDataAsync(verifyPermissions); + Assert.AreEqual(1, data.Count); + Assert.IsFalse(data.Any(data => data.ReferenceData.Values.Any(value => value.Contains(checkCommand)))); + + //Remove User + result = await dbContext.ExecuteCommandAsync(removeUser); + Assert.AreEqual(0, result); + } + + #endregion + #region Execute Transaction Tests - << bool ExecuteTransaction(List sqlStatements) >> [TestMethod] diff --git a/QueryDB.Core.Tests/OracleTests.cs b/QueryDB.Core.Tests/OracleTests.cs index 886d5b3..d2cf216 100644 --- a/QueryDB.Core.Tests/OracleTests.cs +++ b/QueryDB.Core.Tests/OracleTests.cs @@ -1230,6 +1230,178 @@ public void Test_Oracle_ExecuteCommand_DCL_Queries() #endregion + #region Execute Command Async Tests - << Task ExecuteCommandAsync(string sqlStatement) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_ExecuteCommandAsync_DDL_Queries() + { + var createTableSql = Queries.OracleQueries.TestDB.DDL.Create_Table; + var alterTableSql = Queries.OracleQueries.TestDB.DDL.Alter_Table; + var commentTableSql = Queries.OracleQueries.TestDB.DDL.Comment_Table; + var commentTableColumnSql = Queries.OracleQueries.TestDB.DDL.Comment_Table_Column; + var truncateTableSql = Queries.OracleQueries.TestDB.DDL.Truncate_Table; + var renameTableSql = Queries.OracleQueries.TestDB.DDL.Rename_Table; + var dropTableSql = Queries.OracleQueries.TestDB.DDL.Drop_Table; + var dDLExecutionCheckSql = Queries.OracleQueries.TestDB.DDL.DDL_Execute_check; + var dDLTableCommentCheckSql = Queries.OracleQueries.TestDB.DDL.DDL_Table_Comment_check; + var dDLTableColumnCommentCheckSql = Queries.OracleQueries.TestDB.DDL.DDL_Table_Column_Comment_check; + + var dbContext = new DBContext(DB.Oracle, OracleConnectionString); + await dbContext.ExecuteCommandAsync(createTableSql); + await dbContext.ExecuteCommandAsync(alterTableSql); + await dbContext.ExecuteCommandAsync(commentTableSql); + await dbContext.ExecuteCommandAsync(commentTableColumnSql); + await dbContext.ExecuteCommandAsync(truncateTableSql); + + var tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "Employee")); + Assert.AreEqual("1", tableCount[0].ReferenceData["TABLE_COUNT"]); + var tableComment = await dbContext + .FetchDataAsync(string.Format(dDLTableCommentCheckSql, "Employee")); + Assert.AreEqual("This table stores employee records", tableComment[0].ReferenceData["TABLE_COMMENT"]); + var tableColumnComment = await dbContext + .FetchDataAsync(string.Format(dDLTableColumnCommentCheckSql, "Employee")); + Assert.AreEqual("This column stores employee middle name", tableColumnComment[3].ReferenceData["TABLE_COLUMN_COMMENT"]); + + await dbContext.ExecuteCommandAsync(renameTableSql); + + tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "Employee")); + Assert.AreEqual("0", tableCount[0].ReferenceData["TABLE_COUNT"]); + tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "Employees")); + Assert.AreEqual("1", tableCount[0].ReferenceData["TABLE_COUNT"]); + + await dbContext.ExecuteCommandAsync(dropTableSql); + + tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "Employees")); + Assert.AreEqual("0", tableCount[0].ReferenceData["TABLE_COUNT"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_ExecuteCommandAsync_DML_Queries() + { + var insertSql = Queries.OracleQueries.TestDB.DML.InsertSql; + var updateSql = Queries.OracleQueries.TestDB.DML.UpdateSql; + var deleteSql = Queries.OracleQueries.TestDB.DML.DeleteSql; + var verifyDMLExecution = Queries.OracleQueries.TestDB.DML.VerifyDMLExecution; + + var dbContext = new DBContext(DB.Oracle, OracleConnectionString); + + // Insert + var rows = await dbContext.ExecuteCommandAsync(insertSql); + Assert.AreEqual(1, rows); + var data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(1, data.Count); + var agent = data.FirstOrDefault(); + Assert.AreEqual("A020", agent.ReferenceData["AGENT_CODE"]); + Assert.AreEqual("John", agent.ReferenceData["AGENT_NAME"]); + Assert.AreEqual("Wick", agent.ReferenceData["WORKING_AREA"]); + Assert.AreEqual("0.11", agent.ReferenceData["COMMISSION"]); + Assert.AreEqual("010-44536178", agent.ReferenceData["PHONE_NO"]); + Assert.AreEqual("", agent.ReferenceData["COUNTRY"]); + + // Update + rows = await dbContext.ExecuteCommandAsync(updateSql); + Assert.AreEqual(1, rows); + data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(1, data.Count); + agent = data.FirstOrDefault(); + Assert.AreEqual("A020", agent.ReferenceData["AGENT_CODE"]); + Assert.AreEqual("John", agent.ReferenceData["AGENT_NAME"]); + Assert.AreEqual("Wick", agent.ReferenceData["WORKING_AREA"]); + Assert.AreEqual("0.15", agent.ReferenceData["COMMISSION"]); + Assert.AreEqual("010-44536178", agent.ReferenceData["PHONE_NO"]); + Assert.AreEqual("", agent.ReferenceData["COUNTRY"]); + + // Delete + rows = await dbContext.ExecuteCommandAsync(deleteSql); + Assert.AreEqual(1, rows); + data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(0, data.Count); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_ExecuteCommandAsync_DML_Unsupported_SELECT_Queries() + { + var selectSql = Queries.OracleQueries.TestDB.DML.SelectSql; + + // Select + try + { + var dbContext = new DBContext(DB.Oracle, OracleConnectionString); + var rows = await dbContext.ExecuteCommandAsync(selectSql); + Assert.Fail("No Exception"); + } + catch (QueryDBException ex) + { + Assert.AreEqual("SELECT queries are not supported here.", ex.Message); + Assert.AreEqual("UnsupportedCommand", ex.ErrorType); + Assert.AreEqual("'ExecuteCommand' doesn't support SELECT queries.", ex.AdditionalInfo); + } + } + + [TestMethod] + [TestCategory(ORACLE_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_ExecuteCommandAsync_DCL_Queries() + { + var user = "C##TEST_USER"; + var password = "Test123456"; + var table = "AGENTS"; + var commands = "SELECT, UPDATE"; + var checkCommand = "SELECT"; + + var createUser = string.Format(Queries.OracleQueries.TestDB.DCL.CreateUserSql_User_Password, user, password); + var grantConnect = string.Format(Queries.OracleQueries.TestDB.DCL.GrantConnectSql_User, user); + var grantSql = string.Format(Queries.OracleQueries.TestDB.DCL.GrantSql_Command_Table_User, commands, table, user); + var revokeSql = string.Format(Queries.OracleQueries.TestDB.DCL.RevokeSql_Command_Table_User, commands, table, user); + var verifyPermissions = string.Format(Queries.OracleQueries.TestDB.DCL.VerifyPermission_User, user); + var removeUser = string.Format(Queries.OracleQueries.TestDB.DCL.RemoveUserSql_User, user); + + var dbContext = new DBContext(DB.Oracle, OracleConnectionString); + + // Create User + var result = await dbContext.ExecuteCommandAsync(createUser); + Assert.AreEqual(0, result); + + // Grant CONNECT to User + result = await dbContext.ExecuteCommandAsync("CREATE ROLE CONNECT"); + result = await dbContext.ExecuteCommandAsync($"GRANT CONNECT, RESOURCE TO {user}"); + //result = await dbContext.ExecuteCommandAsync($"GRANT CREATE SEQUENCE TO {user}"); + //result = await dbContext.ExecuteCommandAsync($"GRANT CREATE SYNONYM TO {user}"); + //result = await dbContext.ExecuteCommandAsync($"GRANT UNLIMITED TABLESPACE TO {user}"); + //Assert.AreEqual(0, result); + + // Existing Permissions + var data = await dbContext.FetchDataAsync(verifyPermissions); + Assert.AreEqual(1, data.Count); + Assert.IsFalse(data.Any(data => data.ReferenceData.Values.Any(value => value.Contains(checkCommand)))); + + // Grant + result = await dbContext.ExecuteCommandAsync(grantSql); + Assert.AreEqual(0, result); + data = await dbContext.FetchDataAsync(verifyPermissions); + Assert.AreEqual(2, data.Count); + Assert.IsTrue(data.Any(data => data.ReferenceData.Values.Any(value => value.Contains(checkCommand)))); + + // Revoke + result = await dbContext.ExecuteCommandAsync(revokeSql); + Assert.AreEqual(0, result); + data = await dbContext.FetchDataAsync(verifyPermissions); + Assert.AreEqual(1, data.Count); + Assert.IsFalse(data.Any(data => data.ReferenceData.Values.Any(value => value.Contains(checkCommand)))); + + // Remove User + result = await dbContext.ExecuteCommandAsync(removeUser); + Assert.AreEqual(0, result); + } + + #endregion + #region Execute Transaction Tests - << bool ExecuteTransaction(List sqlStatements) >> [TestMethod] diff --git a/QueryDB.Core.Tests/PostgreSQLTests.cs b/QueryDB.Core.Tests/PostgreSQLTests.cs index 5e5b3ce..db5f904 100644 --- a/QueryDB.Core.Tests/PostgreSQLTests.cs +++ b/QueryDB.Core.Tests/PostgreSQLTests.cs @@ -1205,6 +1205,169 @@ public void Test_PostgreSQL_ExecuteCommand_DCL_Queries() #endregion + #region Execute Command Async Tests - << Task ExecuteCommandAsync(string sqlStatement) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_ExecuteCommandAsync_DDL_Queries() + { + var createTableSql = Queries.PostgreSQLQueries.TestDB.DDL.Create_Table; + var alterTableSql = Queries.PostgreSQLQueries.TestDB.DDL.Alter_Table; + var commentTableSql = Queries.PostgreSQLQueries.TestDB.DDL.Comment_Table; + var commentTableColumnSql = Queries.PostgreSQLQueries.TestDB.DDL.Comment_Table_Column; + var truncateTableSql = Queries.PostgreSQLQueries.TestDB.DDL.Truncate_Table; + var renameTableSql = Queries.PostgreSQLQueries.TestDB.DDL.Rename_Table; + var dropTableSql = Queries.PostgreSQLQueries.TestDB.DDL.Drop_Table; + var dDLExecutionCheckSql = Queries.PostgreSQLQueries.TestDB.DDL.DDL_Execute_check; + var dDLTableCommentCheckSql = Queries.PostgreSQLQueries.TestDB.DDL.DDL_Table_Comment_check; + var dDLTableColumnCommentCheckSql = Queries.PostgreSQLQueries.TestDB.DDL.DDL_Table_Column_Comment_check; + + var dbContext = new DBContext(DB.PostgreSQL, PostgreSQLConnectionString); + await dbContext.ExecuteCommandAsync(createTableSql); + await dbContext.ExecuteCommandAsync(alterTableSql); + await dbContext.ExecuteCommandAsync(commentTableSql); + await dbContext.ExecuteCommandAsync(commentTableColumnSql); + await dbContext.ExecuteCommandAsync(truncateTableSql); + + var tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "public", "Employee")); + Assert.AreEqual("1", tableCount[0].ReferenceData["table_count"]); + var tableComment = await dbContext + .FetchDataAsync(string.Format(dDLTableCommentCheckSql, "public", "Employee")); + Assert.AreEqual("This table stores employee records", tableComment[0].ReferenceData["table_comment"]); + var tableColumnComment = await dbContext + .FetchDataAsync(string.Format(dDLTableColumnCommentCheckSql, "public", "Employee")); + Assert.AreEqual("This column stores employee middle name", tableColumnComment[3].ReferenceData["table_column_comment"]); + + await dbContext.ExecuteCommandAsync(renameTableSql); + + tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "public", "Employee")); + Assert.AreEqual("0", tableCount[0].ReferenceData["table_count"]); + tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "public", "Employees")); + Assert.AreEqual("1", tableCount[0].ReferenceData["table_count"]); + + await dbContext.ExecuteCommandAsync(dropTableSql); + + tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "public", "Employees")); + Assert.AreEqual("0", tableCount[0].ReferenceData["table_count"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_ExecuteCommandAsync_DML_Queries() + { + var insertSql = Queries.PostgreSQLQueries.TestDB.DML.InsertSql; + var updateSql = Queries.PostgreSQLQueries.TestDB.DML.UpdateSql; + var deleteSql = Queries.PostgreSQLQueries.TestDB.DML.DeleteSql; + var verifyDMLExecution = Queries.PostgreSQLQueries.TestDB.DML.VerifyDMLExecution; + + var dbContext = new DBContext(DB.PostgreSQL, PostgreSQLConnectionString); + + // Insert + var rows = await dbContext.ExecuteCommandAsync(insertSql); + Assert.AreEqual(1, rows); + var data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(1, data.Count); + var agent = data.FirstOrDefault(); + Assert.AreEqual("A020", agent.ReferenceData["agent_code"]); + Assert.AreEqual("John", agent.ReferenceData["agent_name"]); + Assert.AreEqual("Wick", agent.ReferenceData["working_area"]); + Assert.AreEqual("0.11", agent.ReferenceData["commission"]); + Assert.AreEqual("010-44536178", agent.ReferenceData["phone_no"]); + Assert.AreEqual("", agent.ReferenceData["country"]); + + // Update + rows = await dbContext.ExecuteCommandAsync(updateSql); + Assert.AreEqual(1, rows); + data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(1, data.Count); + agent = data.FirstOrDefault(); + Assert.AreEqual("A020", agent.ReferenceData["agent_code"]); + Assert.AreEqual("John", agent.ReferenceData["agent_name"]); + Assert.AreEqual("Wick", agent.ReferenceData["working_area"]); + Assert.AreEqual("0.15", agent.ReferenceData["commission"]); + Assert.AreEqual("010-44536178", agent.ReferenceData["phone_no"]); + Assert.AreEqual("", agent.ReferenceData["country"]); + + // Delete + rows = await dbContext.ExecuteCommandAsync(deleteSql); + Assert.AreEqual(1, rows); + data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(0, data.Count); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_ExecuteCommandAsync_DML_Unsupported_SELECT_Queries() + { + var selectSql = Queries.PostgreSQLQueries.TestDB.DML.SelectSql; + + // Select + try + { + var dbContext = new DBContext(DB.PostgreSQL, PostgreSQLConnectionString); + var rows = await dbContext.ExecuteCommandAsync(selectSql); + Assert.Fail("No Exception"); + } + catch (QueryDBException ex) + { + Assert.AreEqual("SELECT queries are not supported here.", ex.Message); + Assert.AreEqual("UnsupportedCommand", ex.ErrorType); + Assert.AreEqual("'ExecuteCommand' doesn't support SELECT queries.", ex.AdditionalInfo); + } + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_ExecuteCommandAsync_DCL_Queries() + { + var user = "test_user"; + var password = "Test@1234"; + var table = "Agents"; + var commands = "SELECT, UPDATE"; + var checkCommand = "SELECT"; + + var createUser = string.Format(Queries.PostgreSQLQueries.TestDB.DCL.CreateUserSql_User_Password, user, password); + var grantSql = string.Format(Queries.PostgreSQLQueries.TestDB.DCL.GrantSql_Command_Table_User, commands, table, user); + var revokeSql = string.Format(Queries.PostgreSQLQueries.TestDB.DCL.RevokeSql_Command_Table_User, commands, table, user); + var verifyPermissions = string.Format(Queries.PostgreSQLQueries.TestDB.DCL.VerifyPermission_User, user); + var removeUser = string.Format(Queries.PostgreSQLQueries.TestDB.DCL.RemoveUserSql_User, user); + + var dbContext = new DBContext(DB.PostgreSQL, PostgreSQLConnectionString); + + // Create User + var result = await dbContext.ExecuteCommandAsync(createUser); + Assert.AreEqual(-1, result); + + // Existing Permissions + var data = await dbContext.FetchDataAsync(verifyPermissions); + Assert.AreEqual(0, data.Count); + Assert.IsFalse(data.Any(data => data.ReferenceData.Values.Any(value => value.Contains(checkCommand)))); + + // Grant + result = await dbContext.ExecuteCommandAsync(grantSql); + Assert.AreEqual(-1, result); + data = await dbContext.FetchDataAsync(verifyPermissions); + Assert.AreEqual(2, data.Count); + Assert.IsTrue(data.Any(data => data.ReferenceData.Values.Any(value => value.Contains(checkCommand)))); + + // Revoke + result = await dbContext.ExecuteCommandAsync(revokeSql); + Assert.AreEqual(-1, result); + data = await dbContext.FetchDataAsync(verifyPermissions); + Assert.AreEqual(0, data.Count); + Assert.IsFalse(data.Any(data => data.ReferenceData.Values.Any(value => value.Contains(checkCommand)))); + + // Remove User + result = await dbContext.ExecuteCommandAsync(removeUser); + Assert.AreEqual(-1, result); + } + + #endregion + #region Execute Transaction Tests - << bool ExecuteTransaction(List sqlStatements) >> [TestMethod] diff --git a/QueryDB/DBContext.cs b/QueryDB/DBContext.cs index 09ef60d..b026110 100644 --- a/QueryDB/DBContext.cs +++ b/QueryDB/DBContext.cs @@ -441,10 +441,10 @@ public async Task ExecuteScalarAsync(string sqlStatement) } /// - /// Executes SQL commands. + /// Executes a SQL statement that does not return a result set. /// - /// SQL statement as command. - /// The number of rows affected. + /// SQL statement to execute. + /// The number of rows affected by the execution of the SQL statement. public int ExecuteCommand(string sqlStatement) { if (Regex.IsMatch(sqlStatement, Utils.SelectQueryPattern, RegexOptions.IgnoreCase | RegexOptions.Singleline, TimeSpan.FromSeconds(5))) @@ -485,6 +485,51 @@ public int ExecuteCommand(string sqlStatement) return -1; } + /// + /// Asynchronously executes a SQL statement that does not return a result set. + /// + /// SQL statement to execute. + /// The number of rows affected by the execution of the SQL statement. + public async Task ExecuteCommandAsync(string sqlStatement) + { + if (Regex.IsMatch(sqlStatement, Utils.SelectQueryPattern, RegexOptions.IgnoreCase | RegexOptions.Singleline, TimeSpan.FromSeconds(5))) + throw new QueryDBException(QueryDBExceptions.ErrorMessage.UnsupportedSelectExecuteCommand, + QueryDBExceptions.ErrorType.UnsupportedCommand, QueryDBExceptions.AdditionalInfo.UnsupportedSelectExecuteCommand); + if (Database.Equals(DB.MSSQL)) + { + using (var msSqlDBConnection = GetSqlServerConnection()) + { + var _systemAdapter = new MSSQL.Adapter(); + return await _systemAdapter.ExecuteCommandAsync(sqlStatement, msSqlDBConnection.SqlConnection); + } + } + else if (Database.Equals(DB.MySQL)) + { + using (var mySqlDBConnection = GetMySqlConnection()) + { + var _systemAdapter = new MySQL.Adapter(); + return await _systemAdapter.ExecuteCommandAsync(sqlStatement, mySqlDBConnection.MySqlConnection); + } + } + else if (Database.Equals(DB.Oracle)) + { + using (var oracleDBConnection = GetOracleConnection()) + { + var _systemAdapter = new Oracle.Adapter(); + return await _systemAdapter.ExecuteCommandAsync(sqlStatement, oracleDBConnection.OracleConnection); + } + } + else if (Database.Equals(DB.PostgreSQL)) + { + using (var postgreSqlDBConnection = GetPostgreSqlConnection()) + { + var _systemAdapter = new PostgreSQL.Adapter(); + return await _systemAdapter.ExecuteCommandAsync(sqlStatement, postgreSqlDBConnection.PostgreSQLConnection); + } + } + return -1; + } + /// /// Executes multiple SQL statements within a transaction, ensuring that all statements are executed together. /// diff --git a/QueryDB/IDBContext.cs b/QueryDB/IDBContext.cs index fa854c3..7f55da3 100644 --- a/QueryDB/IDBContext.cs +++ b/QueryDB/IDBContext.cs @@ -89,12 +89,19 @@ interface IDBContext Task ExecuteScalarAsync(string sqlStatement); /// - /// Executes SQL commands. + /// Executes a SQL statement that does not return a result set. /// - /// SQL statement as command. - /// The number of rows affected. + /// SQL statement to execute. + /// The number of rows affected by the execution of the SQL statement. int ExecuteCommand(string sqlStatement); + /// + /// Asynchronously executes a SQL statement that does not return a result set. + /// + /// SQL statement to execute. + /// The number of rows affected by the execution of the SQL statement. + Task ExecuteCommandAsync(string sqlStatement); + /// /// Executes multiple SQL statements within a transaction, ensuring that all statements are executed together. /// diff --git a/QueryDB/MSSQL/Adapter.cs b/QueryDB/MSSQL/Adapter.cs index 4d142cf..6230ba1 100644 --- a/QueryDB/MSSQL/Adapter.cs +++ b/QueryDB/MSSQL/Adapter.cs @@ -170,11 +170,11 @@ internal T ExecuteScalar(string sqlStatement, SqlConnection connection) } /// - /// Executes SQL commands. + /// Executes a SQL statement that does not return a result set. /// - /// SQL statement as command. - /// 'Sql' Connection. - /// The number of rows affected. + /// SQL statement to execute. + /// The object used to connect to the database. + /// The number of rows affected by the execution of the SQL statement. internal int ExecuteCommand(string sqlStatement, SqlConnection connection) { using(var sqlCommand = GetSqlCommand(sqlStatement, connection, CommandType.Text)) @@ -353,6 +353,20 @@ internal async Task ExecuteScalarAsync(string sqlStatement, SqlConnection } } + /// + /// Asynchronously executes a SQL statement that does not return a result set. + /// + /// SQL statement to execute. + /// The object used to connect to the database. + /// The number of rows affected by the execution of the SQL statement. + internal async Task ExecuteCommandAsync(string sqlStatement, SqlConnection connection) + { + using (var sqlCommand = await GetSqlCommandAsync(sqlStatement, connection, CommandType.Text)) + { + return await sqlCommand.ExecuteNonQueryAsync(); + } + } + #endregion } diff --git a/QueryDB/MySQL/Adapter.cs b/QueryDB/MySQL/Adapter.cs index b5bddce..0cdf23a 100644 --- a/QueryDB/MySQL/Adapter.cs +++ b/QueryDB/MySQL/Adapter.cs @@ -170,11 +170,11 @@ internal T ExecuteScalar(string sqlStatement, MySqlConnection connection) } /// - /// Executes SQL commands. + /// Executes a SQL statement that does not return a result set. /// - /// SQL statement as command. - /// 'MySQL' Connection. - /// The number of rows affected. + /// SQL statement to execute. + /// The object used to connect to the database. + /// The number of rows affected by the execution of the SQL statement. internal int ExecuteCommand(string sqlStatement, MySqlConnection connection) { using (var sqlCommand = GetMySqlCommand(sqlStatement, connection, CommandType.Text)) @@ -351,6 +351,20 @@ internal async Task ExecuteScalarAsync(string sqlStatement, MySqlConnectio } } + /// + /// Asynchronously executes a SQL statement that does not return a result set. + /// + /// SQL statement to execute. + /// The object used to connect to the database. + /// The number of rows affected by the execution of the SQL statement. + internal async Task ExecuteCommandAsync(string sqlStatement, MySqlConnection connection) + { + using (var sqlCommand = await GetMySqlCommandAsync(sqlStatement, connection, CommandType.Text)) + { + return await sqlCommand.ExecuteNonQueryAsync(); + } + } + #endregion } diff --git a/QueryDB/Oracle/Adapter.cs b/QueryDB/Oracle/Adapter.cs index 60dc94a..6f0738a 100644 --- a/QueryDB/Oracle/Adapter.cs +++ b/QueryDB/Oracle/Adapter.cs @@ -176,11 +176,11 @@ internal T ExecuteScalar(string sqlStatement, OracleConnection connection) } /// - /// Executes SQL commands. + /// Executes a SQL statement that does not return a result set. /// - /// SQL statement as command. - /// 'Oracle' Connection. - /// The number of rows affected. + /// SQL statement to execute. + /// The object used to connect to the database. + /// The number of rows affected by the execution of the SQL statement. internal int ExecuteCommand(string sqlStatement, OracleConnection connection) { using (var sqlCommand = GetOracleCommand(sqlStatement, connection, CommandType.Text)) @@ -367,6 +367,20 @@ internal async Task ExecuteScalarAsync(string sqlStatement, OracleConnecti } } + /// + /// Asynchronously executes a SQL statement that does not return a result set. + /// + /// SQL statement to execute. + /// The object used to connect to the database. + /// The number of rows affected by the execution of the SQL statement. + internal async Task ExecuteCommandAsync(string sqlStatement, OracleConnection connection) + { + using (var sqlCommand = await GetOracleCommandAsync(sqlStatement, connection, CommandType.Text)) + { + return await sqlCommand.ExecuteNonQueryAsync(); + } + } + #endregion } } \ No newline at end of file diff --git a/QueryDB/PostgreSQL/Adapter.cs b/QueryDB/PostgreSQL/Adapter.cs index 7c10f94..96b9939 100644 --- a/QueryDB/PostgreSQL/Adapter.cs +++ b/QueryDB/PostgreSQL/Adapter.cs @@ -170,11 +170,11 @@ internal T ExecuteScalar(string sqlStatement, NpgsqlConnection connection) } /// - /// Executes SQL commands. + /// Executes a SQL statement that does not return a result set. /// - /// SQL statement as command. - /// 'PostgreSQL' Connection. - /// The number of rows affected + /// SQL statement to execute. + /// The object used to connect to the database. + /// The number of rows affected by the execution of the SQL statement. internal int ExecuteCommand(string sqlStatement, NpgsqlConnection connection) { using (var sqlCommand = GetPostgreSqlCommand(sqlStatement, connection, CommandType.Text)) @@ -353,6 +353,20 @@ internal async Task ExecuteScalarAsync(string sqlStatement, NpgsqlConnecti } } + /// + /// Asynchronously executes a SQL statement that does not return a result set. + /// + /// SQL statement to execute. + /// The object used to connect to the database. + /// The number of rows affected by the execution of the SQL statement. + internal async Task ExecuteCommandAsync(string sqlStatement, NpgsqlConnection connection) + { + using (var sqlCommand = await GetPostgreSqlCommandAsync(sqlStatement, connection, CommandType.Text)) + { + return await sqlCommand.ExecuteNonQueryAsync(); + } + } + #endregion } } From 7d16e5176e14d00e09e1907aa6801eb14b29ccf0 Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Mon, 24 Feb 2025 00:48:02 +1100 Subject: [PATCH 11/34] Test - Execute Command Async --- QueryDB.Core.Tests/QueryDBTests.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/QueryDB.Core.Tests/QueryDBTests.cs b/QueryDB.Core.Tests/QueryDBTests.cs index c847e8e..edf9731 100644 --- a/QueryDB.Core.Tests/QueryDBTests.cs +++ b/QueryDB.Core.Tests/QueryDBTests.cs @@ -1,5 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Collections.Generic; +using System.Threading.Tasks; namespace QueryDB.Core.Tests { @@ -21,6 +22,18 @@ public void ExecuteCommand_UnknownDB_ReturnsNegativeOne() Assert.AreEqual(-1, result); } + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(UNKNOW_DB_TESTS)] + public async Task ExecuteCommandAsync_UnknownDB_ReturnsNegativeOne() + { + string sqlStatement = "DELETE FROM users"; + + var dbContext = new DBContext((DB)999, "some_invalid_connection_string"); + var result = await dbContext.ExecuteCommandAsync(sqlStatement); + + Assert.AreEqual(-1, result); + } + [TestMethod] [TestCategory(DB_TESTS), TestCategory(UNKNOW_DB_TESTS)] public void ExecuteTransaction_UnknownDB_ReturnsFalse() From 9ea10bcabcaf1715fda743662dca9d676a3d24aa Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Tue, 25 Feb 2025 19:32:19 +1100 Subject: [PATCH 12/34] Addition - Execute Transaction Async --- QueryDB.Core.Tests/MSSQLTests.cs | 139 +++++++++++++++++++++++++- QueryDB.Core.Tests/MySQLTests.cs | 133 ++++++++++++++++++++++++ QueryDB.Core.Tests/OracleTests.cs | 133 ++++++++++++++++++++++++ QueryDB.Core.Tests/PostgreSQLTests.cs | 133 ++++++++++++++++++++++++ QueryDB/DBContext.cs | 45 +++++++++ QueryDB/IDBContext.cs | 10 ++ QueryDB/MSSQL/Adapter.cs | 53 +++++++++- QueryDB/MySQL/Adapter.cs | 53 +++++++++- QueryDB/Oracle/Adapter.cs | 58 ++++++++++- QueryDB/PostgreSQL/Adapter.cs | 54 +++++++++- 10 files changed, 799 insertions(+), 12 deletions(-) diff --git a/QueryDB.Core.Tests/MSSQLTests.cs b/QueryDB.Core.Tests/MSSQLTests.cs index 7f2b5d7..a3c626a 100644 --- a/QueryDB.Core.Tests/MSSQLTests.cs +++ b/QueryDB.Core.Tests/MSSQLTests.cs @@ -214,7 +214,7 @@ public async Task Test_MSSQL_FetchDataAsync_Dictionary_SelectQuery_UpperCaseKeys public async Task Test_MSSQL_FetchDataAsync_Dictionary_SelectQuery_Joins() { var selectSql = Queries.MSSQLQueries.TestDB.SelectSql_Join; - var data = await new DBContext(DB.MSSQL, MSSQLConnectionString).FetchDataAsync(selectSql); + var data = await new DBContext(DB.MSSQL, MSSQLConnectionString).FetchDataAsync(selectSql); Assert.AreEqual(34, data.Count); var agent = data.FirstOrDefault(X => X.ReferenceData["Agent_Code"] == "A004" && X.ReferenceData["Cust_Code"] == "C00006"); Assert.AreEqual("A004", agent.ReferenceData["Agent_Code"]); @@ -250,7 +250,7 @@ public async Task Test_MSSQL_FetchDataAsync_Dictionary_SelectQuery_Joins_UpperCa public async Task Test_MSSQL_FetchDataAsync_Dictionary_SelectQuery_Aliases() { var selectSql = Queries.MSSQLQueries.TestDB.SelectSql_Alias; - var data = await new DBContext(DB.MSSQL, MSSQLConnectionString).FetchDataAsync(selectSql); + var data = await new DBContext(DB.MSSQL, MSSQLConnectionString).FetchDataAsync(selectSql); Assert.AreEqual(34, data.Count); var agent = data.FirstOrDefault(X => X.ReferenceData["Agent_Code"] == "A004" && X.ReferenceData["Cust_Code"] == "C00006"); Assert.AreEqual("A004", agent.ReferenceData["Agent_Code"]); @@ -716,7 +716,7 @@ public async Task Test_MSSQL_ExecuteScalarAsync_As_StringReturn_DefaultValue() var dbContext = new DBContext(DB.MSSQL, MSSQLConnectionString); - var result = await dbContext .ExecuteScalarAsync(noValueReturned); + var result = await dbContext.ExecuteScalarAsync(noValueReturned); Assert.IsInstanceOfType(result); Assert.AreEqual("", result); @@ -1572,6 +1572,139 @@ public void Test_MSSQL_ExecuteTransaction_DML_Unsupported_SELECT_Queries() #endregion + #region Execute Transaction Async Tests - << Task ExecuteTransactionAsync(List sqlStatements) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_ExecuteTransactionAsync_DDL_Multiple_Queries() + { + var createTableSql = Queries.MSSQLQueries.TestDB.DDL.Create_Table; + var alterTableSql = Queries.MSSQLQueries.TestDB.DDL.Alter_Table; + var truncateTableSql = Queries.MSSQLQueries.TestDB.DDL.Truncate_Table; + var renameTableSql = Queries.MSSQLQueries.TestDB.DDL.Rename_Table; + var dropTableSql = Queries.MSSQLQueries.TestDB.DDL.Drop_Table; + var dDLExecutionCheckSql = Queries.MSSQLQueries.TestDB.DDL.DDL_Execute_check; + + // Create, Alter & Truncate + var statements = new List + { + createTableSql, + alterTableSql, + truncateTableSql + }; + var dbContext = new DBContext(DB.MSSQL, MSSQLConnectionString); + var result = await dbContext.ExecuteTransactionAsync(statements); + Assert.IsTrue(result); + + var tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "dbo", "Employee")); + Assert.AreEqual("1", tableCount[0].ReferenceData["Table_Count"]); + + // Rename & Drop + statements = new List + { + renameTableSql, + dropTableSql + }; + result = await dbContext.ExecuteTransactionAsync(statements); + Assert.IsTrue(result); + + tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "dbo", "Employees")); + Assert.AreEqual("0", tableCount[0].ReferenceData["Table_Count"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_ExecuteTransactionAsync_DML_Multiple_Queries() + { + var insertSql = Queries.MSSQLQueries.TestDB.DML.InsertSql; + var updateSql = Queries.MSSQLQueries.TestDB.DML.UpdateSql; + var deleteSql = Queries.MSSQLQueries.TestDB.DML.DeleteSql; + var verifyDMLExecution = Queries.MSSQLQueries.TestDB.DML.VerifyDMLExecution; + + var statements = new List + { + insertSql, + updateSql + }; + var dbContext = new DBContext(DB.MSSQL, MSSQLConnectionString); + + // Insert & Update + var result = await dbContext.ExecuteTransactionAsync(statements); + Assert.IsTrue(result); + var data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(1, data.Count); + var agent = data.FirstOrDefault(); + Assert.AreEqual("A020", agent.ReferenceData["Agent_Code"]); + Assert.AreEqual("John", agent.ReferenceData["Agent_Name"]); + Assert.AreEqual("Wick", agent.ReferenceData["Working_Area"]); + Assert.AreEqual("0.15", agent.ReferenceData["Commission"]); + Assert.AreEqual("010-44536178", agent.ReferenceData["Phone_No"]); + Assert.AreEqual("", agent.ReferenceData["Country"]); + + // Delete + statements = new List + { + deleteSql + }; + result = await dbContext.ExecuteTransactionAsync(statements); + Assert.IsTrue(result); + data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(0, data.Count); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_ExecuteTransactionAsync_Incomplete_Transaction_Rollback_On_Error() + { + var insertSql = Queries.MSSQLQueries.TestDB.DML.InsertSql; + var updateSql = Queries.MSSQLQueries.TestDB.DML.UpdateSql; + var updateErrorSql = "UPDATE"; + var verifyDMLExecution = Queries.MSSQLQueries.TestDB.DML.VerifyDMLExecution; + + var statements = new List + { + insertSql, + updateSql, + updateErrorSql + }; + var dbContext = new DBContext(DB.MSSQL, MSSQLConnectionString); + + // Insert & Update + var result = await dbContext.ExecuteTransactionAsync(statements); + Assert.IsFalse(result); + var data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(0, data.Count); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MSSQL_TESTS)] + public async Task Test_MSSQL_ExecuteTransactionAsync_DML_Unsupported_SELECT_Queries() + { + var selectSql = Queries.MSSQLQueries.TestDB.DML.SelectSql; + + // Select + try + { + var statements = new List + { + selectSql + }; + var dbContext = new DBContext(DB.MSSQL, MSSQLConnectionString); + var result = await dbContext.ExecuteTransactionAsync(statements); + Assert.Fail("No Exception"); + } + catch (QueryDBException ex) + { + Assert.AreEqual("SELECT queries are not supported here.", ex.Message); + Assert.AreEqual("UnsupportedCommand", ex.ErrorType); + Assert.AreEqual("'ExecuteTransaction' doesn't support SELECT queries.", ex.AdditionalInfo); + } + } + + #endregion + #endregion } diff --git a/QueryDB.Core.Tests/MySQLTests.cs b/QueryDB.Core.Tests/MySQLTests.cs index 46e4076..46ad26e 100644 --- a/QueryDB.Core.Tests/MySQLTests.cs +++ b/QueryDB.Core.Tests/MySQLTests.cs @@ -1513,6 +1513,139 @@ public void Test_MySQL_ExecuteTransaction_DML_Unsupported_SELECT_Queries() #endregion + #region Execute Transaction Async Tests - << Task ExecuteTransactionAsync(List sqlStatements) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_ExecuteTransactionAsync_DDL_Multiple_Queries() + { + var createTableSql = Queries.MySQLQueries.TestDB.DDL.Create_Table; + var alterTableSql = Queries.MySQLQueries.TestDB.DDL.Alter_Table; + var truncateTableSql = Queries.MySQLQueries.TestDB.DDL.Truncate_Table; + var renameTableSql = Queries.MySQLQueries.TestDB.DDL.Rename_Table; + var dropTableSql = Queries.MySQLQueries.TestDB.DDL.Drop_Table; + var dDLExecutionCheckSql = Queries.MySQLQueries.TestDB.DDL.DDL_Execute_check; + + // Create, Alter & Truncate + var statements = new List + { + createTableSql, + alterTableSql, + truncateTableSql + }; + var dbContext = new DBContext(DB.MySQL, MySQLConnectionString); + var result = await dbContext.ExecuteTransactionAsync(statements); + Assert.IsTrue(result); + + var tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "mysql", "Employee")); + Assert.AreEqual("1", tableCount[0].ReferenceData["Table_Count"]); + + // Rename & Drop + statements = new List + { + renameTableSql, + dropTableSql + }; + result = await dbContext.ExecuteTransactionAsync(statements); + Assert.IsTrue(result); + + tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "mysql", "Employees")); + Assert.AreEqual("0", tableCount[0].ReferenceData["Table_Count"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_ExecuteTransactionAsync_DML_Multiple_Queries() + { + var insertSql = Queries.MySQLQueries.TestDB.DML.InsertSql; + var updateSql = Queries.MySQLQueries.TestDB.DML.UpdateSql; + var deleteSql = Queries.MySQLQueries.TestDB.DML.DeleteSql; + var verifyDMLExecution = Queries.MySQLQueries.TestDB.DML.VerifyDMLExecution; + + var statements = new List + { + insertSql, + updateSql + }; + var dbContext = new DBContext(DB.MySQL, MySQLConnectionString); + + // Insert & Update + var result = await dbContext.ExecuteTransactionAsync(statements); + Assert.IsTrue(result); + var data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(1, data.Count); + var agent = data.FirstOrDefault(); + Assert.AreEqual("A020", agent.ReferenceData["Agent_Code"]); + Assert.AreEqual("John", agent.ReferenceData["Agent_Name"]); + Assert.AreEqual("Wick", agent.ReferenceData["Working_Area"]); + Assert.AreEqual("0.15", agent.ReferenceData["Commission"]); + Assert.AreEqual("010-44536178", agent.ReferenceData["Phone_No"]); + Assert.AreEqual("", agent.ReferenceData["Country"]); + + // Delete + statements = new List + { + deleteSql + }; + result = await dbContext.ExecuteTransactionAsync(statements); + Assert.IsTrue(result); + data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(0, data.Count); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_ExecuteTransactionAsync_Incomplete_Transaction_Rollback_On_Error() + { + var insertSql = Queries.MySQLQueries.TestDB.DML.InsertSql; + var updateSql = Queries.MySQLQueries.TestDB.DML.UpdateSql; + var updateErrorSql = "UPDATE"; + var verifyDMLExecution = Queries.MySQLQueries.TestDB.DML.VerifyDMLExecution; + + var statements = new List + { + insertSql, + updateSql, + updateErrorSql + }; + var dbContext = new DBContext(DB.MySQL, MySQLConnectionString); + + // Insert & Update + var result = await dbContext.ExecuteTransactionAsync(statements); + Assert.IsFalse(result); + var data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(0, data.Count); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(MYSQL_TESTS)] + public async Task Test_MySQL_ExecuteTransactionAsync_DML_Unsupported_SELECT_Queries() + { + var selectSql = Queries.MySQLQueries.TestDB.DML.SelectSql; + + // Select + try + { + var statements = new List + { + selectSql + }; + var dbContext = new DBContext(DB.MySQL, MySQLConnectionString); + var result = await dbContext.ExecuteTransactionAsync(statements); + Assert.Fail("No Exception"); + } + catch (QueryDBException ex) + { + Assert.AreEqual("SELECT queries are not supported here.", ex.Message); + Assert.AreEqual("UnsupportedCommand", ex.ErrorType); + Assert.AreEqual("'ExecuteTransaction' doesn't support SELECT queries.", ex.AdditionalInfo); + } + } + + #endregion + #endregion } diff --git a/QueryDB.Core.Tests/OracleTests.cs b/QueryDB.Core.Tests/OracleTests.cs index d2cf216..0492836 100644 --- a/QueryDB.Core.Tests/OracleTests.cs +++ b/QueryDB.Core.Tests/OracleTests.cs @@ -1535,6 +1535,139 @@ public void Test_Oracle_ExecuteTransaction_DML_Unsupported_SELECT_Queries() #endregion + #region Execute Transaction Async Tests - << Task ExecuteTransactionAsync(List sqlStatements) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_ExecuteTransactionAsync_DDL_Multiple_Queries() + { + var createTableSql = Queries.OracleQueries.TestDB.DDL.Create_Table; + var alterTableSql = Queries.OracleQueries.TestDB.DDL.Alter_Table; + var truncateTableSql = Queries.OracleQueries.TestDB.DDL.Truncate_Table; + var renameTableSql = Queries.OracleQueries.TestDB.DDL.Rename_Table; + var dropTableSql = Queries.OracleQueries.TestDB.DDL.Drop_Table; + var dDLExecutionCheckSql = Queries.OracleQueries.TestDB.DDL.DDL_Execute_check; + + // Create, Alter & Truncate + var statements = new List + { + createTableSql, + alterTableSql, + truncateTableSql + }; + var dbContext = new DBContext(DB.Oracle, OracleConnectionString); + var result = await dbContext.ExecuteTransactionAsync(statements); + Assert.IsTrue(result); + + var tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "Employee")); + Assert.AreEqual("1", tableCount[0].ReferenceData["TABLE_COUNT"]); + + // Rename & Drop + statements = new List + { + renameTableSql, + dropTableSql + }; + result = await dbContext.ExecuteTransactionAsync(statements); + Assert.IsTrue(result); + + tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "Employees")); + Assert.AreEqual("0", tableCount[0].ReferenceData["TABLE_COUNT"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_ExecuteTransactionAsync_DML_Multiple_Queries() + { + var insertSql = Queries.OracleQueries.TestDB.DML.InsertSql; + var updateSql = Queries.OracleQueries.TestDB.DML.UpdateSql; + var deleteSql = Queries.OracleQueries.TestDB.DML.DeleteSql; + var verifyDMLExecution = Queries.OracleQueries.TestDB.DML.VerifyDMLExecution; + + var statements = new List + { + insertSql, + updateSql + }; + var dbContext = new DBContext(DB.Oracle, OracleConnectionString); + + // Insert & Update + var result = await dbContext.ExecuteTransactionAsync(statements); + Assert.IsTrue(result); + var data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(1, data.Count); + var agent = data.FirstOrDefault(); + Assert.AreEqual("A020", agent.ReferenceData["AGENT_CODE"]); + Assert.AreEqual("John", agent.ReferenceData["AGENT_NAME"]); + Assert.AreEqual("Wick", agent.ReferenceData["WORKING_AREA"]); + Assert.AreEqual("0.15", agent.ReferenceData["COMMISSION"]); + Assert.AreEqual("010-44536178", agent.ReferenceData["PHONE_NO"]); + Assert.AreEqual("", agent.ReferenceData["COUNTRY"]); + + // Delete + statements = new List + { + deleteSql + }; + result = await dbContext.ExecuteTransactionAsync(statements); + Assert.IsTrue(result); + data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(0, data.Count); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_ExecuteTransactionAsync_Incomplete_Transaction_Rollback_On_Error() + { + var insertSql = Queries.OracleQueries.TestDB.DML.InsertSql; + var updateSql = Queries.OracleQueries.TestDB.DML.UpdateSql; + var updateErrorSql = "UPDATE"; + var verifyDMLExecution = Queries.OracleQueries.TestDB.DML.VerifyDMLExecution; + + var statements = new List + { + insertSql, + updateSql, + updateErrorSql + }; + var dbContext = new DBContext(DB.Oracle, OracleConnectionString); + + // Insert & Update + var result = await dbContext.ExecuteTransactionAsync(statements); + Assert.IsFalse(result); + var data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(0, data.Count); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(ORACLE_TESTS)] + public async Task Test_Oracle_ExecuteTransactionAsync_DML_Unsupported_SELECT_Queries() + { + var selectSql = Queries.OracleQueries.TestDB.DML.SelectSql; + + // Select + try + { + var statements = new List + { + selectSql + }; + var dbContext = new DBContext(DB.Oracle, OracleConnectionString); + var result = await dbContext.ExecuteTransactionAsync(statements); + Assert.Fail("No Exception"); + } + catch (QueryDBException ex) + { + Assert.AreEqual("SELECT queries are not supported here.", ex.Message); + Assert.AreEqual("UnsupportedCommand", ex.ErrorType); + Assert.AreEqual("'ExecuteTransaction' doesn't support SELECT queries.", ex.AdditionalInfo); + } + } + + #endregion + #endregion } diff --git a/QueryDB.Core.Tests/PostgreSQLTests.cs b/QueryDB.Core.Tests/PostgreSQLTests.cs index db5f904..be9cdcb 100644 --- a/QueryDB.Core.Tests/PostgreSQLTests.cs +++ b/QueryDB.Core.Tests/PostgreSQLTests.cs @@ -1501,6 +1501,139 @@ public void Test_PostgreSQL_ExecuteTransaction_DML_Unsupported_SELECT_Queries() #endregion + #region Execute Transaction Async Tests - << Task ExecuteTransactionAsync(List sqlStatements) >> + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_ExecuteTransactionAsync_DDL_Multiple_Queries() + { + var createTableSql = Queries.PostgreSQLQueries.TestDB.DDL.Create_Table; + var alterTableSql = Queries.PostgreSQLQueries.TestDB.DDL.Alter_Table; + var truncateTableSql = Queries.PostgreSQLQueries.TestDB.DDL.Truncate_Table; + var renameTableSql = Queries.PostgreSQLQueries.TestDB.DDL.Rename_Table; + var dropTableSql = Queries.PostgreSQLQueries.TestDB.DDL.Drop_Table; + var dDLExecutionCheckSql = Queries.PostgreSQLQueries.TestDB.DDL.DDL_Execute_check; + + // Create, Alter & Truncate + var statements = new List + { + createTableSql, + alterTableSql, + truncateTableSql + }; + var dbContext = new DBContext(DB.PostgreSQL, PostgreSQLConnectionString); + var result = await dbContext.ExecuteTransactionAsync(statements); + Assert.IsTrue(result); + + var tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "public", "Employee")); + Assert.AreEqual("1", tableCount[0].ReferenceData["table_count"]); + + // Rename & Drop + statements = new List + { + renameTableSql, + dropTableSql + }; + result = await dbContext.ExecuteTransactionAsync(statements); + Assert.IsTrue(result); + + tableCount = await dbContext + .FetchDataAsync(string.Format(dDLExecutionCheckSql, "public", "Employees")); + Assert.AreEqual("0", tableCount[0].ReferenceData["table_count"]); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_ExecuteTransactionAsync_DML_Multiple_Queries() + { + var insertSql = Queries.PostgreSQLQueries.TestDB.DML.InsertSql; + var updateSql = Queries.PostgreSQLQueries.TestDB.DML.UpdateSql; + var deleteSql = Queries.PostgreSQLQueries.TestDB.DML.DeleteSql; + var verifyDMLExecution = Queries.PostgreSQLQueries.TestDB.DML.VerifyDMLExecution; + + var statements = new List + { + insertSql, + updateSql + }; + var dbContext = new DBContext(DB.PostgreSQL, PostgreSQLConnectionString); + + // Insert & Update + var result = await dbContext.ExecuteTransactionAsync(statements); + Assert.IsTrue(result); + var data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(1, data.Count); + var agent = data.FirstOrDefault(); + Assert.AreEqual("A020", agent.ReferenceData["agent_code"]); + Assert.AreEqual("John", agent.ReferenceData["agent_name"]); + Assert.AreEqual("Wick", agent.ReferenceData["working_area"]); + Assert.AreEqual("0.15", agent.ReferenceData["commission"]); + Assert.AreEqual("010-44536178", agent.ReferenceData["phone_no"]); + Assert.AreEqual("", agent.ReferenceData["country"]); + + // Delete + statements = new List + { + deleteSql + }; + result = await dbContext.ExecuteTransactionAsync(statements); + Assert.IsTrue(result); + data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(0, data.Count); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_ExecuteTransactionAsync_Incomplete_Transaction_Rollback_On_Error() + { + var insertSql = Queries.PostgreSQLQueries.TestDB.DML.InsertSql; + var updateSql = Queries.PostgreSQLQueries.TestDB.DML.UpdateSql; + var updateErrorSql = "UPDATE"; + var verifyDMLExecution = Queries.PostgreSQLQueries.TestDB.DML.VerifyDMLExecution; + + var statements = new List + { + insertSql, + updateSql, + updateErrorSql + }; + var dbContext = new DBContext(DB.PostgreSQL, PostgreSQLConnectionString); + + // Insert & Update + var result = await dbContext.ExecuteTransactionAsync(statements); + Assert.IsFalse(result); + var data = await dbContext.FetchDataAsync(verifyDMLExecution); + Assert.AreEqual(0, data.Count); + } + + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(POSTGRESQL_TESTS)] + public async Task Test_PostgreSQL_ExecuteTransactionAsync_DML_Unsupported_SELECT_Queries() + { + var selectSql = Queries.PostgreSQLQueries.TestDB.DML.SelectSql; + + // Select + try + { + var statements = new List + { + selectSql + }; + var dbContext = new DBContext(DB.PostgreSQL, PostgreSQLConnectionString); + var result = await dbContext.ExecuteTransactionAsync(statements); + Assert.Fail("No Exception"); + } + catch (QueryDBException ex) + { + Assert.AreEqual("SELECT queries are not supported here.", ex.Message); + Assert.AreEqual("UnsupportedCommand", ex.ErrorType); + Assert.AreEqual("'ExecuteTransaction' doesn't support SELECT queries.", ex.AdditionalInfo); + } + } + + #endregion + #endregion } diff --git a/QueryDB/DBContext.cs b/QueryDB/DBContext.cs index b026110..c1d32fe 100644 --- a/QueryDB/DBContext.cs +++ b/QueryDB/DBContext.cs @@ -575,6 +575,51 @@ public bool ExecuteTransaction(List sqlStatements) return false; } + /// + /// Asynchronously executes multiple SQL statements within a transaction, ensuring that all statements are executed together. + /// + /// A list of SQL statements to execute. + /// + /// Returns true if all statements are executed successfully and the transaction is committed; + /// false if any statement fails and the transaction is rolled back. + /// + public async Task ExecuteTransactionAsync(List sqlStatements) + { + var selectExists = sqlStatements.Any(sqlStatement => Regex.IsMatch(sqlStatement, Utils.SelectQueryPattern, RegexOptions.IgnoreCase | RegexOptions.Singleline, TimeSpan.FromSeconds(5))); + if (selectExists) + throw new QueryDBException(QueryDBExceptions.ErrorMessage.UnsupportedSelectExecuteTransaction, + QueryDBExceptions.ErrorType.UnsupportedCommand, QueryDBExceptions.AdditionalInfo.UnsupportedSelectExecuteTransaction); + if (Database.Equals(DB.MSSQL)) + { + using (var msSqlDBConnection = GetSqlServerConnection()) + { + return await MSSQL.Adapter.ExecuteTransactionAsync(sqlStatements, msSqlDBConnection.SqlConnection); + } + } + else if (Database.Equals(DB.MySQL)) + { + using (var mySqlDBConnection = GetMySqlConnection()) + { + return await MySQL.Adapter.ExecuteTransactionAsync(sqlStatements, mySqlDBConnection.MySqlConnection); + } + } + else if (Database.Equals(DB.Oracle)) + { + using (var oracleDBConnection = GetOracleConnection()) + { + return await Oracle.Adapter.ExecuteTransactionAsync(sqlStatements, oracleDBConnection.OracleConnection); + } + } + else if (Database.Equals(DB.PostgreSQL)) + { + using (var postgreSqlDBConnection = GetPostgreSqlConnection()) + { + return await PostgreSQL.Adapter.ExecuteTransactionAsync(sqlStatements, postgreSqlDBConnection.PostgreSQLConnection); + } + } + return false; + } + /// /// Gets 'SQL Server' connection. /// diff --git a/QueryDB/IDBContext.cs b/QueryDB/IDBContext.cs index 7f55da3..1d9bf3a 100644 --- a/QueryDB/IDBContext.cs +++ b/QueryDB/IDBContext.cs @@ -111,5 +111,15 @@ interface IDBContext /// false if any statement fails and the transaction is rolled back. /// bool ExecuteTransaction(List sqlStatements); + + /// + /// Asynchronously executes multiple SQL statements within a transaction, ensuring that all statements are executed together. + /// + /// A list of SQL statements to execute. + /// + /// Returns true if all statements are executed successfully and the transaction is committed; + /// false if any statement fails and the transaction is rolled back. + /// + Task ExecuteTransactionAsync(List sqlStatements); } } diff --git a/QueryDB/MSSQL/Adapter.cs b/QueryDB/MSSQL/Adapter.cs index 6230ba1..0fbc715 100644 --- a/QueryDB/MSSQL/Adapter.cs +++ b/QueryDB/MSSQL/Adapter.cs @@ -62,7 +62,7 @@ internal static SqlCommand GetSqlCommand(string cmdText, SqlConnection connectio /// /// Initiates and returns a new SQL transaction for the specified database connection. /// - /// The SQL database connection. + /// The object used to connect to the database. /// A new associated with the provided connection. internal static SqlTransaction GetSqlTransaction(SqlConnection connection) { @@ -187,7 +187,7 @@ internal int ExecuteCommand(string sqlStatement, SqlConnection connection) /// Executes multiple SQL statements within a transaction to ensure atomicity. /// /// A list of SQL statements to execute. - /// The SQL database connection. + /// The object used to connect to the database. /// /// Returns true if the transaction is committed successfully; /// otherwise, false if an error occurs and the transaction is rolled back. @@ -255,6 +255,18 @@ internal async Task GetSqlCommandAsync(string cmdText, SqlConnection return sqlCommand; } + /// + /// Asynchronously initiates and returns a new SQL transaction for the specified database connection. + /// + /// The object used to connect to the database. + /// A new associated with the provided connection. + internal static async Task GetSqlTransactionAsync(SqlConnection connection) + { + await connection.OpenAsync(); + var sqlTransaction = connection.BeginTransaction(); + return sqlTransaction; + } + /// /// Asynchronously executes and retrieves records for 'Select' queries from the database. /// Converts column names to keys holding values, with multiple database rows returned into a list. @@ -367,6 +379,43 @@ internal async Task ExecuteCommandAsync(string sqlStatement, SqlConnection } } + /// + /// Asynchronously executes multiple SQL statements within a transaction to ensure atomicity. + /// + /// A list of SQL statements to execute. + /// The object used to connect to the database. + /// + /// Returns true if the transaction is committed successfully; + /// otherwise, false if an error occurs and the transaction is rolled back. + /// + /// + /// Logs and handles exceptions if any SQL command execution fails. + /// + internal static async Task ExecuteTransactionAsync(List sqlStatements, SqlConnection connection) + { + using (SqlTransaction transaction = await GetSqlTransactionAsync(connection)) + { + try + { + foreach (var sqlStatement in sqlStatements) + { + using (var sqlCommand = GetSqlCommand(sqlStatement, connection, transaction)) + { + await sqlCommand.ExecuteNonQueryAsync(); + } + } + transaction.Commit(); + return true; + } + catch (Exception ex) + { + transaction.Rollback(); + Console.WriteLine($"Transaction rolled back due to error: {ex.Message}"); + return false; + } + } + } + #endregion } diff --git a/QueryDB/MySQL/Adapter.cs b/QueryDB/MySQL/Adapter.cs index 0cdf23a..4b9eb78 100644 --- a/QueryDB/MySQL/Adapter.cs +++ b/QueryDB/MySQL/Adapter.cs @@ -62,7 +62,7 @@ internal static MySqlCommand GetMySqlCommand(string cmdText, MySqlConnection con /// /// Initiates and returns a new MySQL transaction for the given database connection. /// - /// The MySQL database connection. + /// The object used to connect to the database. /// A new associated with the provided connection. internal static MySqlTransaction GetMySqlTransaction(MySqlConnection connection) { @@ -187,7 +187,7 @@ internal int ExecuteCommand(string sqlStatement, MySqlConnection connection) /// Executes multiple SQL statements within a MySQL transaction to ensure atomicity. /// /// A list of SQL statements to execute. - /// The MySQL database connection. + /// The object used to connect to the database. /// /// Returns true if the transaction is committed successfully; /// otherwise, false if an error occurs and the transaction is rolled back. @@ -255,6 +255,18 @@ internal async Task GetMySqlCommandAsync(string cmdText, MySqlConn return sqlCommand; } + /// + /// Asynchronously initiates and returns a new MySQL transaction for the given database connection. + /// + /// The object used to connect to the database. + /// A new associated with the provided connection. + internal static async Task GetMySqlTransactionAsync(MySqlConnection connection) + { + await connection.OpenAsync(); + var mySqlTransaction = await connection.BeginTransactionAsync(); + return mySqlTransaction; + } + /// /// Asynchronously executes and retrieves records for 'Select' queries from the database. /// Converts column names to keys holding values, with multiple database rows returned into a list. @@ -365,6 +377,43 @@ internal async Task ExecuteCommandAsync(string sqlStatement, MySqlConnectio } } + /// + /// Asynchronously executes multiple SQL statements within a MySQL transaction to ensure atomicity. + /// + /// A list of SQL statements to execute. + /// The object used to connect to the database. + /// + /// Returns true if the transaction is committed successfully; + /// otherwise, false if an error occurs and the transaction is rolled back. + /// + /// + /// Logs and handles exceptions if any SQL command execution fails. + /// + internal static async Task ExecuteTransactionAsync(List sqlStatements, MySqlConnection connection) + { + using (MySqlTransaction transaction = await GetMySqlTransactionAsync(connection)) + { + try + { + foreach (var sqlStatement in sqlStatements) + { + using (var sqlCommand = GetMySqlCommand(sqlStatement, connection, transaction)) + { + await sqlCommand.ExecuteNonQueryAsync(); + } + } + transaction.Commit(); + return true; + } + catch (Exception ex) + { + transaction.Rollback(); + Console.WriteLine($"Transaction rolled back due to error: {ex.Message}"); + return false; + } + } + } + #endregion } diff --git a/QueryDB/Oracle/Adapter.cs b/QueryDB/Oracle/Adapter.cs index 6f0738a..163cf1a 100644 --- a/QueryDB/Oracle/Adapter.cs +++ b/QueryDB/Oracle/Adapter.cs @@ -61,7 +61,7 @@ internal static OracleCommand GetOracleCommand(string cmdText, OracleConnection /// /// Initiates and returns a new Oracle transaction for the specified database connection. /// - /// The Oracle database connection. + /// The object used to connect to the database. /// A new associated with the provided connection. internal static OracleTransaction GetOracleTransaction(OracleConnection connection) { @@ -128,7 +128,7 @@ internal List FetchData(string selectSql, OracleConnection conne prop.SetValue(addObjectRow, Utils.GetBFileByteContent(reader, prop.Name)); else prop.SetValue(addObjectRow, reader[prop.Name]); - } + } } dataList.Add(addObjectRow); } @@ -193,7 +193,7 @@ internal int ExecuteCommand(string sqlStatement, OracleConnection connection) /// Executes multiple SQL statements within an Oracle transaction to ensure atomicity. /// /// A list of SQL statements to execute. - /// The Oracle database connection. + /// The object used to connect to the database. /// /// Returns true if the transaction is committed successfully; /// otherwise, false if an error occurs and the transaction is rolled back. @@ -262,6 +262,18 @@ internal async Task GetOracleCommandAsync(string cmdText, OracleC return sqlCommand; } + /// + /// Asynchronously initiates and returns a new Oracle transaction for the specified database connection. + /// + /// The object used to connect to the database. + /// A new associated with the provided connection. + internal static async Task GetOracleTransactionAsync(OracleConnection connection) + { + await connection.OpenAsync(); + var oracleTransaction = connection.BeginTransaction(); + return oracleTransaction; + } + /// /// Asynchronously executes and retrieves records for 'Select' queries from the database. /// Converts column names to keys holding values, with multiple database rows returned into a list. @@ -381,6 +393,46 @@ internal async Task ExecuteCommandAsync(string sqlStatement, OracleConnecti } } + /// + /// Asynchronously executes multiple SQL statements within an Oracle transaction to ensure atomicity. + /// + /// A list of SQL statements to execute. + /// The object used to connect to the database. + /// + /// Returns true if the transaction is committed successfully; + /// otherwise, false if an error occurs and the transaction is rolled back. + /// + /// + /// Logs and handles exceptions if any SQL command execution fails. + /// + internal static async Task ExecuteTransactionAsync(List sqlStatements, OracleConnection connection) + { + using (OracleTransaction transaction = await GetOracleTransactionAsync(connection)) + { + try + { + foreach (var sqlStatement in sqlStatements) + { + using (var sqlCommand = GetOracleCommand(sqlStatement, connection)) + { + sqlCommand.Transaction = transaction; + await sqlCommand.ExecuteNonQueryAsync(); + } + } + transaction.Commit(); + return true; + } + catch (Exception ex) + { + transaction.Rollback(); + Console.WriteLine($"Transaction rolled back due to error: {ex.Message}"); + return false; + } + } + + } + #endregion + } } \ No newline at end of file diff --git a/QueryDB/PostgreSQL/Adapter.cs b/QueryDB/PostgreSQL/Adapter.cs index 96b9939..b6f8d64 100644 --- a/QueryDB/PostgreSQL/Adapter.cs +++ b/QueryDB/PostgreSQL/Adapter.cs @@ -62,7 +62,7 @@ internal static NpgsqlCommand GetPostgreSqlCommand(string cmdText, NpgsqlConnect /// /// Initiates and returns a new PostgreSQL transaction for the specified database connection. /// - /// The PostgreSQL database connection. + /// The object used to connect to the database. /// A new associated with the provided connection. internal static NpgsqlTransaction GetPostgreSqlTransaction(NpgsqlConnection connection) { @@ -187,7 +187,7 @@ internal int ExecuteCommand(string sqlStatement, NpgsqlConnection connection) /// Executes multiple SQL statements within a PostgreSQL transaction to ensure atomicity. /// /// A list of SQL statements to execute. - /// The PostgreSQL database connection. + /// The object used to connect to the database. /// /// Returns true if the transaction is committed successfully; /// otherwise, false if an error occurs and the transaction is rolled back. @@ -255,6 +255,18 @@ internal async Task GetPostgreSqlCommandAsync(string cmdText, Npg return sqlCommand; } + /// + /// Asynchronously initiates and returns a new PostgreSQL transaction for the specified database connection. + /// + /// The object used to connect to the database. + /// A new associated with the provided connection. + internal static async Task GetPostgreSqlTransactionAsync(NpgsqlConnection connection) + { + await connection.OpenAsync(); + var npgsqlTransaction = connection.BeginTransaction(); + return npgsqlTransaction; + + } /// /// Asynchronously executes and retrieves records for 'Select' queries from the database. /// Converts column names to keys holding values, with multiple database rows returned into a list. @@ -367,6 +379,44 @@ internal async Task ExecuteCommandAsync(string sqlStatement, NpgsqlConnecti } } + /// + /// Asynchronously executes multiple SQL statements within a PostgreSQL transaction to ensure atomicity. + /// + /// A list of SQL statements to execute. + /// The object used to connect to the database. + /// + /// Returns true if the transaction is committed successfully; + /// otherwise, false if an error occurs and the transaction is rolled back. + /// + /// + /// Logs and handles exceptions if any SQL command execution fails. + /// + internal static async Task ExecuteTransactionAsync(List sqlStatements, NpgsqlConnection connection) + { + using (NpgsqlTransaction transaction = await GetPostgreSqlTransactionAsync(connection)) + { + try + { + foreach (var sqlStatement in sqlStatements) + { + using (var sqlCommand = GetPostgreSqlCommand(sqlStatement, connection, transaction)) + { + await sqlCommand.ExecuteNonQueryAsync(); + } + } + transaction.Commit(); + return true; + } + catch (Exception ex) + { + transaction.Rollback(); + Console.WriteLine($"Transaction rolled back due to error: {ex.Message}"); + return false; + } + } + } + #endregion + } } From c0b4ca30777153d5201da60a3a8099db849877af Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Tue, 25 Feb 2025 20:07:27 +1100 Subject: [PATCH 13/34] Test - Execute Transaction Async --- QueryDB.Core.Tests/QueryDBTests.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/QueryDB.Core.Tests/QueryDBTests.cs b/QueryDB.Core.Tests/QueryDBTests.cs index edf9731..353104a 100644 --- a/QueryDB.Core.Tests/QueryDBTests.cs +++ b/QueryDB.Core.Tests/QueryDBTests.cs @@ -49,6 +49,21 @@ public void ExecuteTransaction_UnknownDB_ReturnsFalse() Assert.IsFalse(result); } + [TestMethod] + [TestCategory(DB_TESTS), TestCategory(UNKNOW_DB_TESTS)] + public async Task ExecuteTransactionAsync_UnknownDB_ReturnsFalse() + { + var sqlStatements = new List + { + "DELETE FROM users" + }; + + var dbContext = new DBContext((DB)999, "some_invalid_connection_string"); + var result = await dbContext.ExecuteTransactionAsync(sqlStatements); + + Assert.IsFalse(result); + } + #endregion } From 1251a840c5465830c94db88427c1b66ee582c43e Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Wed, 26 Feb 2025 21:09:38 +1100 Subject: [PATCH 14/34] CQ - use async instead --- QueryDB/PostgreSQL/Adapter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/QueryDB/PostgreSQL/Adapter.cs b/QueryDB/PostgreSQL/Adapter.cs index b6f8d64..c3e65e6 100644 --- a/QueryDB/PostgreSQL/Adapter.cs +++ b/QueryDB/PostgreSQL/Adapter.cs @@ -404,12 +404,12 @@ internal static async Task ExecuteTransactionAsync(List sqlStateme await sqlCommand.ExecuteNonQueryAsync(); } } - transaction.Commit(); + await transaction.CommitAsync(); return true; } catch (Exception ex) { - transaction.Rollback(); + await transaction.RollbackAsync(); Console.WriteLine($"Transaction rolled back due to error: {ex.Message}"); return false; } From b8a285be94340155e51127b88402c41a58955434 Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Wed, 26 Feb 2025 22:41:41 +1100 Subject: [PATCH 15/34] Refactor --- QueryDB/Oracle/Adapter.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/QueryDB/Oracle/Adapter.cs b/QueryDB/Oracle/Adapter.cs index 163cf1a..c5f6b4c 100644 --- a/QueryDB/Oracle/Adapter.cs +++ b/QueryDB/Oracle/Adapter.cs @@ -429,7 +429,6 @@ internal static async Task ExecuteTransactionAsync(List sqlStateme return false; } } - } #endregion From d0e164e587455679195cf8e3b86e8d199cc0025f Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Thu, 27 Feb 2025 00:02:52 +1100 Subject: [PATCH 16/34] Execute Trnasaction - Returns transaction outcome and exception details in case of failure instead of logging into console --- QueryDB.Core.Tests/MSSQLTests.cs | 22 +++++++++------- QueryDB.Core.Tests/MySQLTests.cs | 22 +++++++++------- QueryDB.Core.Tests/OracleTests.cs | 22 +++++++++------- QueryDB.Core.Tests/PostgreSQLTests.cs | 22 +++++++++------- QueryDB.Core.Tests/QueryDBTests.cs | 8 +++--- QueryDB/DBContext.cs | 38 ++++++++++++++++----------- QueryDB/IDBContext.cs | 16 ++++++----- QueryDB/MSSQL/Adapter.cs | 28 +++++++++----------- QueryDB/MySQL/Adapter.cs | 28 +++++++++----------- QueryDB/Oracle/Adapter.cs | 28 +++++++++----------- QueryDB/PostgreSQL/Adapter.cs | 28 +++++++++----------- QueryDB/Resources/Result.cs | 20 ++++++++++++++ 12 files changed, 152 insertions(+), 130 deletions(-) create mode 100644 QueryDB/Resources/Result.cs diff --git a/QueryDB.Core.Tests/MSSQLTests.cs b/QueryDB.Core.Tests/MSSQLTests.cs index a3c626a..7a569fd 100644 --- a/QueryDB.Core.Tests/MSSQLTests.cs +++ b/QueryDB.Core.Tests/MSSQLTests.cs @@ -1461,7 +1461,7 @@ public void Test_MSSQL_ExecuteTransaction_DDL_Multiple_Queries() }; var dbContext = new DBContext(DB.MSSQL, MSSQLConnectionString); var result = dbContext.ExecuteTransaction(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); var tableCount = dbContext .FetchData(string.Format(dDLExecutionCheckSql, "dbo", "Employee")); @@ -1474,7 +1474,7 @@ public void Test_MSSQL_ExecuteTransaction_DDL_Multiple_Queries() dropTableSql }; result = dbContext.ExecuteTransaction(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); tableCount = dbContext .FetchData(string.Format(dDLExecutionCheckSql, "dbo", "Employees")); @@ -1499,7 +1499,7 @@ public void Test_MSSQL_ExecuteTransaction_DML_Multiple_Queries() // Insert & Update var result = dbContext.ExecuteTransaction(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); var data = dbContext.FetchData(verifyDMLExecution); Assert.AreEqual(1, data.Count); var agent = data.FirstOrDefault(); @@ -1516,7 +1516,7 @@ public void Test_MSSQL_ExecuteTransaction_DML_Multiple_Queries() deleteSql }; result = dbContext.ExecuteTransaction(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); data = dbContext.FetchData(verifyDMLExecution); Assert.AreEqual(0, data.Count); } @@ -1540,7 +1540,8 @@ public void Test_MSSQL_ExecuteTransaction_Incomplete_Transaction_Rollback_On_Err // Insert & Update var result = dbContext.ExecuteTransaction(statements); - Assert.IsFalse(result); + Assert.IsFalse(result.Success); + Assert.AreEqual("Incorrect syntax near 'UPDATE'.", result.Exception.Message); var data = dbContext.FetchData(verifyDMLExecution); Assert.AreEqual(0, data.Count); } @@ -1594,7 +1595,7 @@ public async Task Test_MSSQL_ExecuteTransactionAsync_DDL_Multiple_Queries() }; var dbContext = new DBContext(DB.MSSQL, MSSQLConnectionString); var result = await dbContext.ExecuteTransactionAsync(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); var tableCount = await dbContext .FetchDataAsync(string.Format(dDLExecutionCheckSql, "dbo", "Employee")); @@ -1607,7 +1608,7 @@ public async Task Test_MSSQL_ExecuteTransactionAsync_DDL_Multiple_Queries() dropTableSql }; result = await dbContext.ExecuteTransactionAsync(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); tableCount = await dbContext .FetchDataAsync(string.Format(dDLExecutionCheckSql, "dbo", "Employees")); @@ -1632,7 +1633,7 @@ public async Task Test_MSSQL_ExecuteTransactionAsync_DML_Multiple_Queries() // Insert & Update var result = await dbContext.ExecuteTransactionAsync(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); var data = await dbContext.FetchDataAsync(verifyDMLExecution); Assert.AreEqual(1, data.Count); var agent = data.FirstOrDefault(); @@ -1649,7 +1650,7 @@ public async Task Test_MSSQL_ExecuteTransactionAsync_DML_Multiple_Queries() deleteSql }; result = await dbContext.ExecuteTransactionAsync(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); data = await dbContext.FetchDataAsync(verifyDMLExecution); Assert.AreEqual(0, data.Count); } @@ -1673,7 +1674,8 @@ public async Task Test_MSSQL_ExecuteTransactionAsync_Incomplete_Transaction_Roll // Insert & Update var result = await dbContext.ExecuteTransactionAsync(statements); - Assert.IsFalse(result); + Assert.IsFalse(result.Success); + Assert.AreEqual("Incorrect syntax near 'UPDATE'.", result.Exception.Message); var data = await dbContext.FetchDataAsync(verifyDMLExecution); Assert.AreEqual(0, data.Count); } diff --git a/QueryDB.Core.Tests/MySQLTests.cs b/QueryDB.Core.Tests/MySQLTests.cs index 46ad26e..6dd4469 100644 --- a/QueryDB.Core.Tests/MySQLTests.cs +++ b/QueryDB.Core.Tests/MySQLTests.cs @@ -1402,7 +1402,7 @@ public void Test_MySQL_ExecuteTransaction_DDL_Multiple_Queries() }; var dbContext = new DBContext(DB.MySQL, MySQLConnectionString); var result = dbContext.ExecuteTransaction(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); var tableCount = dbContext .FetchData(string.Format(dDLExecutionCheckSql, "mysql", "Employee")); @@ -1415,7 +1415,7 @@ public void Test_MySQL_ExecuteTransaction_DDL_Multiple_Queries() dropTableSql }; result = dbContext.ExecuteTransaction(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); tableCount = dbContext .FetchData(string.Format(dDLExecutionCheckSql, "mysql", "Employees")); @@ -1440,7 +1440,7 @@ public void Test_MySQL_ExecuteTransaction_DML_Multiple_Queries() // Insert & Update var result = dbContext.ExecuteTransaction(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); var data = dbContext.FetchData(verifyDMLExecution); Assert.AreEqual(1, data.Count); var agent = data.FirstOrDefault(); @@ -1457,7 +1457,7 @@ public void Test_MySQL_ExecuteTransaction_DML_Multiple_Queries() deleteSql }; result = dbContext.ExecuteTransaction(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); data = dbContext.FetchData(verifyDMLExecution); Assert.AreEqual(0, data.Count); } @@ -1481,7 +1481,8 @@ public void Test_MySQL_ExecuteTransaction_Incomplete_Transaction_Rollback_On_Err // Insert & Update var result = dbContext.ExecuteTransaction(statements); - Assert.IsFalse(result); + Assert.IsFalse(result.Success); + Assert.AreEqual("You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1", result.Exception.Message); var data = dbContext.FetchData(verifyDMLExecution); Assert.AreEqual(0, data.Count); } @@ -1535,7 +1536,7 @@ public async Task Test_MySQL_ExecuteTransactionAsync_DDL_Multiple_Queries() }; var dbContext = new DBContext(DB.MySQL, MySQLConnectionString); var result = await dbContext.ExecuteTransactionAsync(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); var tableCount = await dbContext .FetchDataAsync(string.Format(dDLExecutionCheckSql, "mysql", "Employee")); @@ -1548,7 +1549,7 @@ public async Task Test_MySQL_ExecuteTransactionAsync_DDL_Multiple_Queries() dropTableSql }; result = await dbContext.ExecuteTransactionAsync(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); tableCount = await dbContext .FetchDataAsync(string.Format(dDLExecutionCheckSql, "mysql", "Employees")); @@ -1573,7 +1574,7 @@ public async Task Test_MySQL_ExecuteTransactionAsync_DML_Multiple_Queries() // Insert & Update var result = await dbContext.ExecuteTransactionAsync(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); var data = await dbContext.FetchDataAsync(verifyDMLExecution); Assert.AreEqual(1, data.Count); var agent = data.FirstOrDefault(); @@ -1590,7 +1591,7 @@ public async Task Test_MySQL_ExecuteTransactionAsync_DML_Multiple_Queries() deleteSql }; result = await dbContext.ExecuteTransactionAsync(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); data = await dbContext.FetchDataAsync(verifyDMLExecution); Assert.AreEqual(0, data.Count); } @@ -1614,7 +1615,8 @@ public async Task Test_MySQL_ExecuteTransactionAsync_Incomplete_Transaction_Roll // Insert & Update var result = await dbContext.ExecuteTransactionAsync(statements); - Assert.IsFalse(result); + Assert.IsFalse(result.Success); + Assert.AreEqual("You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1", result.Exception.Message); var data = await dbContext.FetchDataAsync(verifyDMLExecution); Assert.AreEqual(0, data.Count); } diff --git a/QueryDB.Core.Tests/OracleTests.cs b/QueryDB.Core.Tests/OracleTests.cs index 0492836..d9c0e84 100644 --- a/QueryDB.Core.Tests/OracleTests.cs +++ b/QueryDB.Core.Tests/OracleTests.cs @@ -1424,7 +1424,7 @@ public void Test_Oracle_ExecuteTransaction_DDL_Multiple_Queries() }; var dbContext = new DBContext(DB.Oracle, OracleConnectionString); var result = dbContext.ExecuteTransaction(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); var tableCount = dbContext .FetchData(string.Format(dDLExecutionCheckSql, "Employee")); @@ -1437,7 +1437,7 @@ public void Test_Oracle_ExecuteTransaction_DDL_Multiple_Queries() dropTableSql }; result = dbContext.ExecuteTransaction(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); tableCount = dbContext .FetchData(string.Format(dDLExecutionCheckSql, "Employees")); @@ -1462,7 +1462,7 @@ public void Test_Oracle_ExecuteTransaction_DML_Multiple_Queries() // Insert & Update var result = dbContext.ExecuteTransaction(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); var data = dbContext.FetchData(verifyDMLExecution); Assert.AreEqual(1, data.Count); var agent = data.FirstOrDefault(); @@ -1479,7 +1479,7 @@ public void Test_Oracle_ExecuteTransaction_DML_Multiple_Queries() deleteSql }; result = dbContext.ExecuteTransaction(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); data = dbContext.FetchData(verifyDMLExecution); Assert.AreEqual(0, data.Count); } @@ -1503,7 +1503,8 @@ public void Test_Oracle_ExecuteTransaction_Incomplete_Transaction_Rollback_On_Er // Insert & Update var result = dbContext.ExecuteTransaction(statements); - Assert.IsFalse(result); + Assert.IsFalse(result.Success); + Assert.AreEqual("ORA-00903: invalid table name", result.Exception.Message); var data = dbContext.FetchData(verifyDMLExecution); Assert.AreEqual(0, data.Count); } @@ -1557,7 +1558,7 @@ public async Task Test_Oracle_ExecuteTransactionAsync_DDL_Multiple_Queries() }; var dbContext = new DBContext(DB.Oracle, OracleConnectionString); var result = await dbContext.ExecuteTransactionAsync(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); var tableCount = await dbContext .FetchDataAsync(string.Format(dDLExecutionCheckSql, "Employee")); @@ -1570,7 +1571,7 @@ public async Task Test_Oracle_ExecuteTransactionAsync_DDL_Multiple_Queries() dropTableSql }; result = await dbContext.ExecuteTransactionAsync(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); tableCount = await dbContext .FetchDataAsync(string.Format(dDLExecutionCheckSql, "Employees")); @@ -1595,7 +1596,7 @@ public async Task Test_Oracle_ExecuteTransactionAsync_DML_Multiple_Queries() // Insert & Update var result = await dbContext.ExecuteTransactionAsync(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); var data = await dbContext.FetchDataAsync(verifyDMLExecution); Assert.AreEqual(1, data.Count); var agent = data.FirstOrDefault(); @@ -1612,7 +1613,7 @@ public async Task Test_Oracle_ExecuteTransactionAsync_DML_Multiple_Queries() deleteSql }; result = await dbContext.ExecuteTransactionAsync(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); data = await dbContext.FetchDataAsync(verifyDMLExecution); Assert.AreEqual(0, data.Count); } @@ -1636,7 +1637,8 @@ public async Task Test_Oracle_ExecuteTransactionAsync_Incomplete_Transaction_Rol // Insert & Update var result = await dbContext.ExecuteTransactionAsync(statements); - Assert.IsFalse(result); + Assert.IsFalse(result.Success); + Assert.AreEqual("ORA-00903: invalid table name", result.Exception.Message); var data = await dbContext.FetchDataAsync(verifyDMLExecution); Assert.AreEqual(0, data.Count); } diff --git a/QueryDB.Core.Tests/PostgreSQLTests.cs b/QueryDB.Core.Tests/PostgreSQLTests.cs index be9cdcb..7ee40f8 100644 --- a/QueryDB.Core.Tests/PostgreSQLTests.cs +++ b/QueryDB.Core.Tests/PostgreSQLTests.cs @@ -1390,7 +1390,7 @@ public void Test_PostgreSQL_ExecuteTransaction_DDL_Multiple_Queries() }; var dbContext = new DBContext(DB.PostgreSQL, PostgreSQLConnectionString); var result = dbContext.ExecuteTransaction(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); var tableCount = dbContext .FetchData(string.Format(dDLExecutionCheckSql, "public", "Employee")); @@ -1403,7 +1403,7 @@ public void Test_PostgreSQL_ExecuteTransaction_DDL_Multiple_Queries() dropTableSql }; result = dbContext.ExecuteTransaction(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); tableCount = dbContext .FetchData(string.Format(dDLExecutionCheckSql, "public", "Employees")); @@ -1428,7 +1428,7 @@ public void Test_PostgreSQL_ExecuteTransaction_DML_Multiple_Queries() // Insert & Update var result = dbContext.ExecuteTransaction(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); var data = dbContext.FetchData(verifyDMLExecution); Assert.AreEqual(1, data.Count); var agent = data.FirstOrDefault(); @@ -1445,7 +1445,7 @@ public void Test_PostgreSQL_ExecuteTransaction_DML_Multiple_Queries() deleteSql }; result = dbContext.ExecuteTransaction(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); data = dbContext.FetchData(verifyDMLExecution); Assert.AreEqual(0, data.Count); } @@ -1469,7 +1469,8 @@ public void Test_PostgreSQL_ExecuteTransaction_Incomplete_Transaction_Rollback_O // Insert & Update var result = dbContext.ExecuteTransaction(statements); - Assert.IsFalse(result); + Assert.IsFalse(result.Success); + Assert.AreEqual("42601: syntax error at end of input\r\n\r\nPOSITION: 7", result.Exception.Message); var data = dbContext.FetchData(verifyDMLExecution); Assert.AreEqual(0, data.Count); } @@ -1523,7 +1524,7 @@ public async Task Test_PostgreSQL_ExecuteTransactionAsync_DDL_Multiple_Queries() }; var dbContext = new DBContext(DB.PostgreSQL, PostgreSQLConnectionString); var result = await dbContext.ExecuteTransactionAsync(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); var tableCount = await dbContext .FetchDataAsync(string.Format(dDLExecutionCheckSql, "public", "Employee")); @@ -1536,7 +1537,7 @@ public async Task Test_PostgreSQL_ExecuteTransactionAsync_DDL_Multiple_Queries() dropTableSql }; result = await dbContext.ExecuteTransactionAsync(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); tableCount = await dbContext .FetchDataAsync(string.Format(dDLExecutionCheckSql, "public", "Employees")); @@ -1561,7 +1562,7 @@ public async Task Test_PostgreSQL_ExecuteTransactionAsync_DML_Multiple_Queries() // Insert & Update var result = await dbContext.ExecuteTransactionAsync(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); var data = await dbContext.FetchDataAsync(verifyDMLExecution); Assert.AreEqual(1, data.Count); var agent = data.FirstOrDefault(); @@ -1578,7 +1579,7 @@ public async Task Test_PostgreSQL_ExecuteTransactionAsync_DML_Multiple_Queries() deleteSql }; result = await dbContext.ExecuteTransactionAsync(statements); - Assert.IsTrue(result); + Assert.IsTrue(result.Success); data = await dbContext.FetchDataAsync(verifyDMLExecution); Assert.AreEqual(0, data.Count); } @@ -1602,7 +1603,8 @@ public async Task Test_PostgreSQL_ExecuteTransactionAsync_Incomplete_Transaction // Insert & Update var result = await dbContext.ExecuteTransactionAsync(statements); - Assert.IsFalse(result); + Assert.IsFalse(result.Success); + Assert.AreEqual("42601: syntax error at end of input\r\n\r\nPOSITION: 7", result.Exception.Message); var data = await dbContext.FetchDataAsync(verifyDMLExecution); Assert.AreEqual(0, data.Count); } diff --git a/QueryDB.Core.Tests/QueryDBTests.cs b/QueryDB.Core.Tests/QueryDBTests.cs index 353104a..9b810d2 100644 --- a/QueryDB.Core.Tests/QueryDBTests.cs +++ b/QueryDB.Core.Tests/QueryDBTests.cs @@ -35,7 +35,7 @@ public async Task ExecuteCommandAsync_UnknownDB_ReturnsNegativeOne() } [TestMethod] - [TestCategory(DB_TESTS), TestCategory(UNKNOW_DB_TESTS)] + [TestCategory(UNKNOW_DB_TESTS)] public void ExecuteTransaction_UnknownDB_ReturnsFalse() { var sqlStatements = new List @@ -46,11 +46,11 @@ public void ExecuteTransaction_UnknownDB_ReturnsFalse() var dbContext = new DBContext((DB)999, "some_invalid_connection_string"); var result = dbContext.ExecuteTransaction(sqlStatements); - Assert.IsFalse(result); + Assert.IsFalse(result.Success); } [TestMethod] - [TestCategory(DB_TESTS), TestCategory(UNKNOW_DB_TESTS)] + [TestCategory(UNKNOW_DB_TESTS)] public async Task ExecuteTransactionAsync_UnknownDB_ReturnsFalse() { var sqlStatements = new List @@ -61,7 +61,7 @@ public async Task ExecuteTransactionAsync_UnknownDB_ReturnsFalse() var dbContext = new DBContext((DB)999, "some_invalid_connection_string"); var result = await dbContext.ExecuteTransactionAsync(sqlStatements); - Assert.IsFalse(result); + Assert.IsFalse(result.Success); } #endregion diff --git a/QueryDB/DBContext.cs b/QueryDB/DBContext.cs index c1d32fe..cc879fd 100644 --- a/QueryDB/DBContext.cs +++ b/QueryDB/DBContext.cs @@ -535,11 +535,14 @@ public async Task ExecuteCommandAsync(string sqlStatement) /// /// A list of SQL statements to execute. /// - /// Returns true if all statements are executed successfully and the transaction is committed; - /// false if any statement fails and the transaction is rolled back. + /// A object indicating the outcome of the transaction. + /// The property is true if the transaction is committed successfully; + /// otherwise, false if an error occurs and the transaction is rolled back. + /// If an error occurs, the property contains the exception details. /// - public bool ExecuteTransaction(List sqlStatements) + public Result ExecuteTransaction(List sqlStatements) { + var result = new Result(); var selectExists = sqlStatements.Any(sqlStatement => Regex.IsMatch(sqlStatement, Utils.SelectQueryPattern, RegexOptions.IgnoreCase | RegexOptions.Singleline, TimeSpan.FromSeconds(5))); if (selectExists) throw new QueryDBException(QueryDBExceptions.ErrorMessage.UnsupportedSelectExecuteTransaction, @@ -548,31 +551,31 @@ public bool ExecuteTransaction(List sqlStatements) { using (var msSqlDBConnection = GetSqlServerConnection()) { - return MSSQL.Adapter.ExecuteTransaction(sqlStatements, msSqlDBConnection.SqlConnection); + result = MSSQL.Adapter.ExecuteTransaction(sqlStatements, msSqlDBConnection.SqlConnection); } } else if (Database.Equals(DB.MySQL)) { using (var mySqlDBConnection = GetMySqlConnection()) { - return MySQL.Adapter.ExecuteTransaction(sqlStatements, mySqlDBConnection.MySqlConnection); + result = MySQL.Adapter.ExecuteTransaction(sqlStatements, mySqlDBConnection.MySqlConnection); } } else if (Database.Equals(DB.Oracle)) { using (var oracleDBConnection = GetOracleConnection()) { - return Oracle.Adapter.ExecuteTransaction(sqlStatements, oracleDBConnection.OracleConnection); + result = Oracle.Adapter.ExecuteTransaction(sqlStatements, oracleDBConnection.OracleConnection); } } else if (Database.Equals(DB.PostgreSQL)) { using (var postgreSqlDBConnection = GetPostgreSqlConnection()) { - return PostgreSQL.Adapter.ExecuteTransaction(sqlStatements, postgreSqlDBConnection.PostgreSQLConnection); + result = PostgreSQL.Adapter.ExecuteTransaction(sqlStatements, postgreSqlDBConnection.PostgreSQLConnection); } } - return false; + return result; } /// @@ -580,11 +583,14 @@ public bool ExecuteTransaction(List sqlStatements) /// /// A list of SQL statements to execute. /// - /// Returns true if all statements are executed successfully and the transaction is committed; - /// false if any statement fails and the transaction is rolled back. + /// A object indicating the outcome of the transaction. + /// The property is true if the transaction is committed successfully; + /// otherwise, false if an error occurs and the transaction is rolled back. + /// If an error occurs, the property contains the exception details. /// - public async Task ExecuteTransactionAsync(List sqlStatements) + public async Task ExecuteTransactionAsync(List sqlStatements) { + var result = new Result(); var selectExists = sqlStatements.Any(sqlStatement => Regex.IsMatch(sqlStatement, Utils.SelectQueryPattern, RegexOptions.IgnoreCase | RegexOptions.Singleline, TimeSpan.FromSeconds(5))); if (selectExists) throw new QueryDBException(QueryDBExceptions.ErrorMessage.UnsupportedSelectExecuteTransaction, @@ -593,31 +599,31 @@ public async Task ExecuteTransactionAsync(List sqlStatements) { using (var msSqlDBConnection = GetSqlServerConnection()) { - return await MSSQL.Adapter.ExecuteTransactionAsync(sqlStatements, msSqlDBConnection.SqlConnection); + result = await MSSQL.Adapter.ExecuteTransactionAsync(sqlStatements, msSqlDBConnection.SqlConnection); } } else if (Database.Equals(DB.MySQL)) { using (var mySqlDBConnection = GetMySqlConnection()) { - return await MySQL.Adapter.ExecuteTransactionAsync(sqlStatements, mySqlDBConnection.MySqlConnection); + result = await MySQL.Adapter.ExecuteTransactionAsync(sqlStatements, mySqlDBConnection.MySqlConnection); } } else if (Database.Equals(DB.Oracle)) { using (var oracleDBConnection = GetOracleConnection()) { - return await Oracle.Adapter.ExecuteTransactionAsync(sqlStatements, oracleDBConnection.OracleConnection); + result = await Oracle.Adapter.ExecuteTransactionAsync(sqlStatements, oracleDBConnection.OracleConnection); } } else if (Database.Equals(DB.PostgreSQL)) { using (var postgreSqlDBConnection = GetPostgreSqlConnection()) { - return await PostgreSQL.Adapter.ExecuteTransactionAsync(sqlStatements, postgreSqlDBConnection.PostgreSQLConnection); + result = await PostgreSQL.Adapter.ExecuteTransactionAsync(sqlStatements, postgreSqlDBConnection.PostgreSQLConnection); } } - return false; + return result; } /// diff --git a/QueryDB/IDBContext.cs b/QueryDB/IDBContext.cs index 1d9bf3a..786a856 100644 --- a/QueryDB/IDBContext.cs +++ b/QueryDB/IDBContext.cs @@ -107,19 +107,23 @@ interface IDBContext /// /// A list of SQL statements to execute. /// - /// Returns true if all statements are executed successfully and the transaction is committed; - /// false if any statement fails and the transaction is rolled back. + /// A object indicating the outcome of the transaction. + /// The property is true if the transaction is committed successfully; + /// otherwise, false if an error occurs and the transaction is rolled back. + /// If an error occurs, the property contains the exception details. /// - bool ExecuteTransaction(List sqlStatements); + Result ExecuteTransaction(List sqlStatements); /// /// Asynchronously executes multiple SQL statements within a transaction, ensuring that all statements are executed together. /// /// A list of SQL statements to execute. /// - /// Returns true if all statements are executed successfully and the transaction is committed; - /// false if any statement fails and the transaction is rolled back. + /// A object indicating the outcome of the transaction. + /// The property is true if the transaction is committed successfully; + /// otherwise, false if an error occurs and the transaction is rolled back. + /// If an error occurs, the property contains the exception details. /// - Task ExecuteTransactionAsync(List sqlStatements); + Task ExecuteTransactionAsync(List sqlStatements); } } diff --git a/QueryDB/MSSQL/Adapter.cs b/QueryDB/MSSQL/Adapter.cs index 0fbc715..8d1b025 100644 --- a/QueryDB/MSSQL/Adapter.cs +++ b/QueryDB/MSSQL/Adapter.cs @@ -189,13 +189,12 @@ internal int ExecuteCommand(string sqlStatement, SqlConnection connection) /// A list of SQL statements to execute. /// The object used to connect to the database. /// - /// Returns true if the transaction is committed successfully; + /// A object indicating the outcome of the transaction. + /// The property is true if the transaction is committed successfully; /// otherwise, false if an error occurs and the transaction is rolled back. + /// If an error occurs, the property contains the exception details. /// - /// - /// Logs and handles exceptions if any SQL command execution fails. - /// - internal static bool ExecuteTransaction(List sqlStatements, SqlConnection connection) + internal static Result ExecuteTransaction(List sqlStatements, SqlConnection connection) { using (SqlTransaction transaction = GetSqlTransaction(connection)) { @@ -209,13 +208,12 @@ internal static bool ExecuteTransaction(List sqlStatements, SqlConnectio } } transaction.Commit(); - return true; + return new Result { Success = true }; } catch (Exception ex) { transaction.Rollback(); - Console.WriteLine($"Transaction rolled back due to error: {ex.Message}"); - return false; + return new Result { Success = false, Exception = ex }; } } } @@ -385,13 +383,12 @@ internal async Task ExecuteCommandAsync(string sqlStatement, SqlConnection /// A list of SQL statements to execute. /// The object used to connect to the database. /// - /// Returns true if the transaction is committed successfully; + /// A object indicating the outcome of the transaction. + /// The property is true if the transaction is committed successfully; /// otherwise, false if an error occurs and the transaction is rolled back. + /// If an error occurs, the property contains the exception details. /// - /// - /// Logs and handles exceptions if any SQL command execution fails. - /// - internal static async Task ExecuteTransactionAsync(List sqlStatements, SqlConnection connection) + internal static async Task ExecuteTransactionAsync(List sqlStatements, SqlConnection connection) { using (SqlTransaction transaction = await GetSqlTransactionAsync(connection)) { @@ -405,13 +402,12 @@ internal static async Task ExecuteTransactionAsync(List sqlStateme } } transaction.Commit(); - return true; + return new Result { Success = true}; } catch (Exception ex) { transaction.Rollback(); - Console.WriteLine($"Transaction rolled back due to error: {ex.Message}"); - return false; + return new Result { Success = false, Exception = ex }; } } } diff --git a/QueryDB/MySQL/Adapter.cs b/QueryDB/MySQL/Adapter.cs index 4b9eb78..d26e39c 100644 --- a/QueryDB/MySQL/Adapter.cs +++ b/QueryDB/MySQL/Adapter.cs @@ -189,13 +189,12 @@ internal int ExecuteCommand(string sqlStatement, MySqlConnection connection) /// A list of SQL statements to execute. /// The object used to connect to the database. /// - /// Returns true if the transaction is committed successfully; + /// A object indicating the outcome of the transaction. + /// The property is true if the transaction is committed successfully; /// otherwise, false if an error occurs and the transaction is rolled back. + /// If an error occurs, the property contains the exception details. /// - /// - /// Logs and handles exceptions if any SQL command execution fails. - /// - internal static bool ExecuteTransaction(List sqlStatements, MySqlConnection connection) + internal static Result ExecuteTransaction(List sqlStatements, MySqlConnection connection) { using (MySqlTransaction transaction = GetMySqlTransaction(connection)) { @@ -209,13 +208,12 @@ internal static bool ExecuteTransaction(List sqlStatements, MySqlConnect } } transaction.Commit(); - return true; + return new Result { Success = true }; } catch (Exception ex) { transaction.Rollback(); - Console.WriteLine($"Transaction rolled back due to error: {ex.Message}"); - return false; + return new Result { Success = false, Exception = ex }; } } } @@ -383,13 +381,12 @@ internal async Task ExecuteCommandAsync(string sqlStatement, MySqlConnectio /// A list of SQL statements to execute. /// The object used to connect to the database. /// - /// Returns true if the transaction is committed successfully; + /// A object indicating the outcome of the transaction. + /// The property is true if the transaction is committed successfully; /// otherwise, false if an error occurs and the transaction is rolled back. + /// If an error occurs, the property contains the exception details. /// - /// - /// Logs and handles exceptions if any SQL command execution fails. - /// - internal static async Task ExecuteTransactionAsync(List sqlStatements, MySqlConnection connection) + internal static async Task ExecuteTransactionAsync(List sqlStatements, MySqlConnection connection) { using (MySqlTransaction transaction = await GetMySqlTransactionAsync(connection)) { @@ -403,13 +400,12 @@ internal static async Task ExecuteTransactionAsync(List sqlStateme } } transaction.Commit(); - return true; + return new Result { Success = true }; } catch (Exception ex) { transaction.Rollback(); - Console.WriteLine($"Transaction rolled back due to error: {ex.Message}"); - return false; + return new Result { Success = false, Exception = ex }; } } } diff --git a/QueryDB/Oracle/Adapter.cs b/QueryDB/Oracle/Adapter.cs index c5f6b4c..82e9764 100644 --- a/QueryDB/Oracle/Adapter.cs +++ b/QueryDB/Oracle/Adapter.cs @@ -195,13 +195,12 @@ internal int ExecuteCommand(string sqlStatement, OracleConnection connection) /// A list of SQL statements to execute. /// The object used to connect to the database. /// - /// Returns true if the transaction is committed successfully; + /// A object indicating the outcome of the transaction. + /// The property is true if the transaction is committed successfully; /// otherwise, false if an error occurs and the transaction is rolled back. + /// If an error occurs, the property contains the exception details. /// - /// - /// Logs and handles exceptions if any SQL command execution fails. - /// - internal static bool ExecuteTransaction(List sqlStatements, OracleConnection connection) + internal static Result ExecuteTransaction(List sqlStatements, OracleConnection connection) { using (OracleTransaction transaction = GetOracleTransaction(connection)) { @@ -216,13 +215,12 @@ internal static bool ExecuteTransaction(List sqlStatements, OracleConnec } } transaction.Commit(); - return true; + return new Result { Success = true }; } catch (Exception ex) { transaction.Rollback(); - Console.WriteLine($"Transaction rolled back due to error: {ex.Message}"); - return false; + return new Result { Success = false, Exception = ex }; } } } @@ -399,13 +397,12 @@ internal async Task ExecuteCommandAsync(string sqlStatement, OracleConnecti /// A list of SQL statements to execute. /// The object used to connect to the database. /// - /// Returns true if the transaction is committed successfully; + /// A object indicating the outcome of the transaction. + /// The property is true if the transaction is committed successfully; /// otherwise, false if an error occurs and the transaction is rolled back. + /// If an error occurs, the property contains the exception details. /// - /// - /// Logs and handles exceptions if any SQL command execution fails. - /// - internal static async Task ExecuteTransactionAsync(List sqlStatements, OracleConnection connection) + internal static async Task ExecuteTransactionAsync(List sqlStatements, OracleConnection connection) { using (OracleTransaction transaction = await GetOracleTransactionAsync(connection)) { @@ -420,13 +417,12 @@ internal static async Task ExecuteTransactionAsync(List sqlStateme } } transaction.Commit(); - return true; + return new Result { Success = true }; } catch (Exception ex) { transaction.Rollback(); - Console.WriteLine($"Transaction rolled back due to error: {ex.Message}"); - return false; + return new Result { Success = false, Exception = ex }; } } } diff --git a/QueryDB/PostgreSQL/Adapter.cs b/QueryDB/PostgreSQL/Adapter.cs index c3e65e6..7c13feb 100644 --- a/QueryDB/PostgreSQL/Adapter.cs +++ b/QueryDB/PostgreSQL/Adapter.cs @@ -189,13 +189,12 @@ internal int ExecuteCommand(string sqlStatement, NpgsqlConnection connection) /// A list of SQL statements to execute. /// The object used to connect to the database. /// - /// Returns true if the transaction is committed successfully; + /// A object indicating the outcome of the transaction. + /// The property is true if the transaction is committed successfully; /// otherwise, false if an error occurs and the transaction is rolled back. + /// If an error occurs, the property contains the exception details. /// - /// - /// Logs and handles exceptions if any SQL command execution fails. - /// - internal static bool ExecuteTransaction(List sqlStatements, NpgsqlConnection connection) + internal static Result ExecuteTransaction(List sqlStatements, NpgsqlConnection connection) { using (NpgsqlTransaction transaction = GetPostgreSqlTransaction(connection)) { @@ -209,13 +208,12 @@ internal static bool ExecuteTransaction(List sqlStatements, NpgsqlConnec } } transaction.Commit(); - return true; + return new Result { Success = true }; } catch (Exception ex) { transaction.Rollback(); - Console.WriteLine($"Transaction rolled back due to error: {ex.Message}"); - return false; + return new Result { Success = false, Exception = ex }; } } } @@ -385,13 +383,12 @@ internal async Task ExecuteCommandAsync(string sqlStatement, NpgsqlConnecti /// A list of SQL statements to execute. /// The object used to connect to the database. /// - /// Returns true if the transaction is committed successfully; + /// A object indicating the outcome of the transaction. + /// The property is true if the transaction is committed successfully; /// otherwise, false if an error occurs and the transaction is rolled back. + /// If an error occurs, the property contains the exception details. /// - /// - /// Logs and handles exceptions if any SQL command execution fails. - /// - internal static async Task ExecuteTransactionAsync(List sqlStatements, NpgsqlConnection connection) + internal static async Task ExecuteTransactionAsync(List sqlStatements, NpgsqlConnection connection) { using (NpgsqlTransaction transaction = await GetPostgreSqlTransactionAsync(connection)) { @@ -405,13 +402,12 @@ internal static async Task ExecuteTransactionAsync(List sqlStateme } } await transaction.CommitAsync(); - return true; + return new Result { Success = true }; } catch (Exception ex) { await transaction.RollbackAsync(); - Console.WriteLine($"Transaction rolled back due to error: {ex.Message}"); - return false; + return new Result { Success = false, Exception = ex }; } } } diff --git a/QueryDB/Resources/Result.cs b/QueryDB/Resources/Result.cs new file mode 100644 index 0000000..dc66d2d --- /dev/null +++ b/QueryDB/Resources/Result.cs @@ -0,0 +1,20 @@ +using System; + +namespace QueryDB.Resources +{ + /// + /// Represents the outcome of an operation, indicating success or failure. + /// + public class Result + { + /// + /// Gets or sets a value indicating whether the operation was successful. + /// + public bool Success { get; internal set; } + + /// + /// Gets or sets the exception that occurred during the operation, if any. + /// + public Exception Exception { get; internal set; } + } +} From f156a62ca1741798e3fc60b6ae576d72daa2f144 Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Thu, 27 Feb 2025 00:10:15 +1100 Subject: [PATCH 17/34] Test failure update --- QueryDB.Core.Tests/PostgreSQLTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/QueryDB.Core.Tests/PostgreSQLTests.cs b/QueryDB.Core.Tests/PostgreSQLTests.cs index 7ee40f8..cb04a28 100644 --- a/QueryDB.Core.Tests/PostgreSQLTests.cs +++ b/QueryDB.Core.Tests/PostgreSQLTests.cs @@ -1470,7 +1470,7 @@ public void Test_PostgreSQL_ExecuteTransaction_Incomplete_Transaction_Rollback_O // Insert & Update var result = dbContext.ExecuteTransaction(statements); Assert.IsFalse(result.Success); - Assert.AreEqual("42601: syntax error at end of input\r\n\r\nPOSITION: 7", result.Exception.Message); + Assert.IsTrue(result.Exception.Message.Contains("42601: syntax error at end of input")); var data = dbContext.FetchData(verifyDMLExecution); Assert.AreEqual(0, data.Count); } @@ -1604,7 +1604,7 @@ public async Task Test_PostgreSQL_ExecuteTransactionAsync_Incomplete_Transaction // Insert & Update var result = await dbContext.ExecuteTransactionAsync(statements); Assert.IsFalse(result.Success); - Assert.AreEqual("42601: syntax error at end of input\r\n\r\nPOSITION: 7", result.Exception.Message); + Assert.IsTrue(result.Exception.Message.Contains("42601: syntax error at end of input")); var data = await dbContext.FetchDataAsync(verifyDMLExecution); Assert.AreEqual(0, data.Count); } From adc928ec6cf9a1b4d6ed14df7d5005773a4272c3 Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Thu, 27 Feb 2025 00:31:55 +1100 Subject: [PATCH 18/34] Remove non applicable tests --- QueryDB.Core.Tests/QueryDBTests.cs | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/QueryDB.Core.Tests/QueryDBTests.cs b/QueryDB.Core.Tests/QueryDBTests.cs index 9b810d2..95f2d8a 100644 --- a/QueryDB.Core.Tests/QueryDBTests.cs +++ b/QueryDB.Core.Tests/QueryDBTests.cs @@ -34,36 +34,6 @@ public async Task ExecuteCommandAsync_UnknownDB_ReturnsNegativeOne() Assert.AreEqual(-1, result); } - [TestMethod] - [TestCategory(UNKNOW_DB_TESTS)] - public void ExecuteTransaction_UnknownDB_ReturnsFalse() - { - var sqlStatements = new List - { - "DELETE FROM users" - }; - - var dbContext = new DBContext((DB)999, "some_invalid_connection_string"); - var result = dbContext.ExecuteTransaction(sqlStatements); - - Assert.IsFalse(result.Success); - } - - [TestMethod] - [TestCategory(UNKNOW_DB_TESTS)] - public async Task ExecuteTransactionAsync_UnknownDB_ReturnsFalse() - { - var sqlStatements = new List - { - "DELETE FROM users" - }; - - var dbContext = new DBContext((DB)999, "some_invalid_connection_string"); - var result = await dbContext.ExecuteTransactionAsync(sqlStatements); - - Assert.IsFalse(result.Success); - } - #endregion } From 1dfdd17cfb83d6c642573707b475fbd7d19ca0bd Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Thu, 27 Feb 2025 22:35:44 +1100 Subject: [PATCH 19/34] Readme update --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 395f431..7594b78 100644 --- a/README.md +++ b/README.md @@ -32,17 +32,19 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof - Execute scalar queries (returning a single value). - Execute non-query database commands (e.g. `INSERT`, `UPDATE`, `DELETE`). - Execute transactions while maintaining atomicity. +- Support for Synchronous and Asynchronous operations. ## Getting Started -- _**Setup `DBContext` with the database of your choice**_ +- _**Setup `DBContext` with the database of your choice :**_ ``` var dbContext = new DBContext(DB., ); ``` -- _**Execute `DBContext` commands**_ +- _**Execute `DBContext` commands :**_ + > __Synchronous__ ``` var result = dbContext.FetchData(); var result = dbContext.FetchData(); @@ -57,3 +59,9 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof ``` var result = dbContext.ExecuteTransaction(); ``` + + > __Asynchronous__ + ``` + var result = dbContext.FetchDataAsync(); + var result = dbContext.FetchDataAsync(); + ``` From 90d6eff64897f563e676a7a62e3594ad2b2e4934 Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Thu, 27 Feb 2025 22:39:49 +1100 Subject: [PATCH 20/34] Readme update --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 7594b78..a1ee256 100644 --- a/README.md +++ b/README.md @@ -47,10 +47,14 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof > __Synchronous__ ``` var result = dbContext.FetchData(); + ``` + ``` var result = dbContext.FetchData(); ``` ``` var result = dbContext.ExecuteScalar(); + ``` + ``` var result = dbContext.ExecuteScalar(); ``` ``` @@ -63,5 +67,7 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof > __Asynchronous__ ``` var result = dbContext.FetchDataAsync(); + ``` + ``` var result = dbContext.FetchDataAsync(); ``` From 537208a280c3bbd1783afaa425af8df6730ff7b1 Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Thu, 27 Feb 2025 22:43:39 +1100 Subject: [PATCH 21/34] Readme update --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a1ee256..fce5223 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof - _**Execute `DBContext` commands :**_ - > __Synchronous__ + > __SYNCHRONOUS__ ``` var result = dbContext.FetchData(); ``` @@ -64,7 +64,7 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof var result = dbContext.ExecuteTransaction(); ``` - > __Asynchronous__ + > __ASYNCHRONOUS__ ``` var result = dbContext.FetchDataAsync(); ``` From fc6a11a9532f5923ff3cee8ec7a4796ae824fe95 Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Thu, 27 Feb 2025 22:51:43 +1100 Subject: [PATCH 22/34] Readme update --- README.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/README.md b/README.md index fce5223..bf7acf2 100644 --- a/README.md +++ b/README.md @@ -71,3 +71,41 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof ``` var result = dbContext.FetchDataAsync(); ``` + +
+ + SYNCHRONOUS + + ``` + var result = dbContext.FetchData(); + ``` + ``` + var result = dbContext.FetchData(); + ``` + ``` + var result = dbContext.ExecuteScalar(); + ``` + ``` + var result = dbContext.ExecuteScalar(); + ``` + ``` + var result = dbContext.ExecuteCommand(); + ``` + ``` + var result = dbContext.ExecuteTransaction(); + ``` + +
+ +
+ + ASYNCHRONOUS + + ``` + var result = dbContext.FetchDataAsync(); + ``` + ``` + var result = dbContext.FetchDataAsync(); + ``` + +
\ No newline at end of file From 4e7213f1e25750508c4fd194e2d21f6a4a9686e2 Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Thu, 27 Feb 2025 22:56:45 +1100 Subject: [PATCH 23/34] Readme update --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bf7acf2..eadc2f3 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof
- SYNCHRONOUS + Run DBContext Commands Synchronously ``` var result = dbContext.FetchData(); @@ -99,8 +99,8 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof
- ASYNCHRONOUS - + Run DBContext Commands Asynchronously + ``` var result = dbContext.FetchDataAsync(); ``` From 13766f574782a0eecc32794081de2297db235fea Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Thu, 27 Feb 2025 22:57:54 +1100 Subject: [PATCH 24/34] Readme update --- README.md | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index eadc2f3..6a58a82 100644 --- a/README.md +++ b/README.md @@ -44,37 +44,9 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof - _**Execute `DBContext` commands :**_ - > __SYNCHRONOUS__ - ``` - var result = dbContext.FetchData(); - ``` - ``` - var result = dbContext.FetchData(); - ``` - ``` - var result = dbContext.ExecuteScalar(); - ``` - ``` - var result = dbContext.ExecuteScalar(); - ``` - ``` - var result = dbContext.ExecuteCommand(); - ``` - ``` - var result = dbContext.ExecuteTransaction(); - ``` - - > __ASYNCHRONOUS__ - ``` - var result = dbContext.FetchDataAsync(); - ``` - ``` - var result = dbContext.FetchDataAsync(); - ``` -
- Run DBContext Commands Synchronously + Execute DBContext Commands Synchronously ``` var result = dbContext.FetchData(); @@ -99,7 +71,7 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof
- Run DBContext Commands Asynchronously + Execute DBContext Commands Asynchronously ``` var result = dbContext.FetchDataAsync(); From 8c8adbfd705f4adee99b6bfa300ab957f1199a64 Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Fri, 28 Feb 2025 22:29:34 +1100 Subject: [PATCH 25/34] Readme update --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6a58a82..7610b2f 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof
- Execute DBContext Commands Synchronously + Execute DBContext Commands Synchronously
``` var result = dbContext.FetchData(); @@ -71,7 +71,7 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof
- Execute DBContext Commands Asynchronously + Execute DBContext Commands Asynchronously ``` var result = dbContext.FetchDataAsync(); From 9c4209faebe09b62258b38aef48ef6cfadf992a2 Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Fri, 28 Feb 2025 22:30:39 +1100 Subject: [PATCH 26/34] Readme update --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7610b2f..48c74c0 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof ``` var result = dbContext.FetchData(); ``` - ``` + ``` var result = dbContext.FetchData(); ``` ``` @@ -71,7 +71,7 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof
- Execute DBContext Commands Asynchronously + Execute DBContext Commands Asynchronously
``` var result = dbContext.FetchDataAsync(); From 92486bd9f103aa58f4c9f6c151a06e76a76179c2 Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Fri, 28 Feb 2025 22:32:24 +1100 Subject: [PATCH 27/34] Readme update --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 48c74c0..606aa57 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof
- Execute DBContext Commands Synchronously
+ Execute DBContext Commands Synchronously
``` var result = dbContext.FetchData(); @@ -71,7 +71,7 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof
- Execute DBContext Commands Asynchronously
+ Execute DBContext Commands Asynchronously
``` var result = dbContext.FetchDataAsync(); From bf189966e1f3ee23c6e1954e32bcaf3f34d1ec03 Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Fri, 28 Feb 2025 22:34:39 +1100 Subject: [PATCH 28/34] Readme update --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 606aa57..d91d31f 100644 --- a/README.md +++ b/README.md @@ -79,5 +79,17 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof ``` var result = dbContext.FetchDataAsync(); ``` + ``` + var result = dbContext.ExecuteScalarAsync(); + ``` + ``` + var result = dbContext.ExecuteScalarAsync(); + ``` + ``` + var result = dbContext.ExecuteCommandAsync(); + ``` + ``` + var result = dbContext.ExecuteTransactionAsync(); + ```
\ No newline at end of file From 90c56cff69b40fb3cfdecb1fc39917785b816c00 Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Fri, 28 Feb 2025 22:57:09 +1100 Subject: [PATCH 29/34] Readme update --- README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d91d31f..e2a3019 100644 --- a/README.md +++ b/README.md @@ -92,4 +92,16 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof var result = dbContext.ExecuteTransactionAsync(); ``` -
\ No newline at end of file +
+ +## Examples + +``` +var sql = "SELECT A.Agent_Code, A.Agent_Name, C.Cust_Code, C.Cust_Name, O.Ord_Num, O.Ord_Amount, O.Advance_Amount, O.Ord_Date, O.Ord_Description FROM Agents A INNER JOIN + Customer C ON C.Agent_Code = A.Agent_Code INNER JOIN + Orders O ON O.Cust_Code = C.Cust_Code AND O.Agent_Code = A.Agent_Code"; + +var data = new DBContext(DB., ) + .FetchData(selectSql); +var agent = data.FirstOrDefault(X => X.Agent_Name == "Benjamin"); +``` \ No newline at end of file From 114b14f2827b2d3e091d1b0476f989300ecf60be Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Fri, 28 Feb 2025 23:02:06 +1100 Subject: [PATCH 30/34] Readme update --- README.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index e2a3019..1f51391 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof - _**Setup `DBContext` with the database of your choice :**_ - ``` + ``` csharp var dbContext = new DBContext(DB., ); ``` @@ -48,22 +48,22 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof Execute DBContext Commands Synchronously
- ``` + ``` csharp var result = dbContext.FetchData(); ``` - ``` + ``` csharp var result = dbContext.FetchData(); ``` - ``` + ``` csharp var result = dbContext.ExecuteScalar(); ``` - ``` + ``` csharp var result = dbContext.ExecuteScalar(); ``` - ``` + ``` csharp var result = dbContext.ExecuteCommand(); ``` - ``` + ``` csharp var result = dbContext.ExecuteTransaction(); ``` @@ -73,22 +73,22 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof Execute DBContext Commands Asynchronously
- ``` + ``` csharp var result = dbContext.FetchDataAsync(); ``` - ``` + ``` csharp var result = dbContext.FetchDataAsync(); ``` - ``` + ``` csharp var result = dbContext.ExecuteScalarAsync(); ``` - ``` + ``` csharp var result = dbContext.ExecuteScalarAsync(); ``` - ``` + ``` csharp var result = dbContext.ExecuteCommandAsync(); ``` - ``` + ``` csharp var result = dbContext.ExecuteTransactionAsync(); ``` @@ -96,12 +96,12 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof ## Examples -``` -var sql = "SELECT A.Agent_Code, A.Agent_Name, C.Cust_Code, C.Cust_Name, O.Ord_Num, O.Ord_Amount, O.Advance_Amount, O.Ord_Date, O.Ord_Description FROM Agents A INNER JOIN +``` csharp +var sql = @"SELECT A.Agent_Code, A.Agent_Name, C.Cust_Code, C.Cust_Name, O.Ord_Num, O.Ord_Amount, O.Advance_Amount, O.Ord_Date, O.Ord_Description FROM Agents A INNER JOIN Customer C ON C.Agent_Code = A.Agent_Code INNER JOIN Orders O ON O.Cust_Code = C.Cust_Code AND O.Agent_Code = A.Agent_Code"; var data = new DBContext(DB., ) - .FetchData(selectSql); + .FetchData(selectSql); var agent = data.FirstOrDefault(X => X.Agent_Name == "Benjamin"); ``` \ No newline at end of file From 64b3f2147886c1c7716b8277b7dc6c9dcce88ad1 Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Fri, 28 Feb 2025 23:27:19 +1100 Subject: [PATCH 31/34] Readme update --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index 1f51391..51ef940 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,22 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof ## Examples ``` csharp +public class Orders +{ + public string Agent_Code { get; set; } + public string Agent { get; set; } + public string Agent_Name { get; set; } + public string Agent_Location { get; set; } + public string Cust_Code { get; set; } + public string Customer { get; set; } + public string Cust_Name { get; set; } + public string Customer_Location { get; set; } + public decimal Ord_Num { get; set; } + public decimal Ord_Amount { get; set; } + public decimal Advance_Amount { get; set; } + public string Ord_Description { get; set; } +} + var sql = @"SELECT A.Agent_Code, A.Agent_Name, C.Cust_Code, C.Cust_Name, O.Ord_Num, O.Ord_Amount, O.Advance_Amount, O.Ord_Date, O.Ord_Description FROM Agents A INNER JOIN Customer C ON C.Agent_Code = A.Agent_Code INNER JOIN Orders O ON O.Cust_Code = C.Cust_Code AND O.Agent_Code = A.Agent_Code"; From 87f2611a789ef6488765ab65852ed3746387d3b1 Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Fri, 28 Feb 2025 23:38:18 +1100 Subject: [PATCH 32/34] Readme update --- README.md | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 51ef940..39be17a 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,7 @@ Built on **.NET Standard 2.0** - ( [_Supported Versions_](https://learn.microsof ## Examples +> Data Retrieval ``` csharp public class Orders { @@ -117,7 +118,20 @@ var sql = @"SELECT A.Agent_Code, A.Agent_Name, C.Cust_Code, C.Cust_Name, O.Ord_N Customer C ON C.Agent_Code = A.Agent_Code INNER JOIN Orders O ON O.Cust_Code = C.Cust_Code AND O.Agent_Code = A.Agent_Code"; -var data = new DBContext(DB., ) - .FetchData(selectSql); -var agent = data.FirstOrDefault(X => X.Agent_Name == "Benjamin"); -``` \ No newline at end of file +var data = new DBContext(DB., ).FetchData(selectSql); +var agent = data.FirstOrDefault(X => X.Agent_Name == "Foo"); +``` + +> Transaction + +``` csharp +// Create, Insert & Update +var statements = new List +{ + "CREATE TABLE Employee (EmployeeID INT PRIMARY KEY, FirstName NVARCHAR(50), LastName NVARCHAR(50))", + "INSERT INTO Employee VALUES ('E01', 'John', 'Wick')", + "UPDATE Employee SET FirstName = 'Jack' LastName = 'Reacher' WHERE EmployeeID = 'E01'" +}; +var dbContext = new DBContext(DB.MSSQL, MSSQLConnectionString); +var result = dbContext.ExecuteTransaction(statements); +--- From eff1800154bb3143906da43f18e9594538ef2e22 Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Fri, 28 Feb 2025 23:40:55 +1100 Subject: [PATCH 33/34] Readme update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 39be17a..81892d3 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,7 @@ var sql = @"SELECT A.Agent_Code, A.Agent_Name, C.Cust_Code, C.Cust_Name, O.Ord_N var data = new DBContext(DB., ).FetchData(selectSql); var agent = data.FirstOrDefault(X => X.Agent_Name == "Foo"); ``` - +--- > Transaction ``` csharp From a9805ab30ea452874362c255428931747228282e Mon Sep 17 00:00:00 2001 From: abhinavminhas Date: Sun, 2 Mar 2025 10:20:35 +1100 Subject: [PATCH 34/34] Nuget package creation - v1.2.0 --- .github/workflows/publish-nuget-Package.yml | 2 +- CHANGELOG.md | 10 ++++++++++ QueryDB/QueryDB.csproj | 8 +++++--- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish-nuget-Package.yml b/.github/workflows/publish-nuget-Package.yml index 46f5a75..fbf7cab 100644 --- a/.github/workflows/publish-nuget-Package.yml +++ b/.github/workflows/publish-nuget-Package.yml @@ -1,7 +1,7 @@ name: Publish Nuget Package env: - NUGET_PACKAGE_NAME_VERSION: "QueryDB.1.1.0.nupkg" + NUGET_PACKAGE_NAME_VERSION: "QueryDB.1.2.0.nupkg" on: workflow_dispatch: diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e138f4..17bdde9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project documented here. ## [Released] +## [1.2.0](https://www.nuget.org/packages/QueryDB/1.2.0) - 2025-03-04 +### Added +- Asynchronous operations + - `FetchDataAsync()` + - `ExecuteScalarAsync()` + - `ExecuteCommandAsync()` + - `ExecuteTransactionAsync()` +### Changed +- Execute transaction to return transaction outcome and exception details in case of failure instead of logging into console. + ## [1.1.0](https://www.nuget.org/packages/QueryDB/1.1.0) - 2025-02-20 ### Added - Execute scalar queries (returning a single value). diff --git a/QueryDB/QueryDB.csproj b/QueryDB/QueryDB.csproj index 90e834f..e1f90ba 100644 --- a/QueryDB/QueryDB.csproj +++ b/QueryDB/QueryDB.csproj @@ -15,14 +15,16 @@ Features: - Retrieve data from the database. - Execute scalar queries (returning a single value). - Execute non-query database commands. -- Execute transactions while maintaining atomicity. +- Execute transactions while maintaining atomicity. +- Support for Synchronous and Asynchronous operations. https://github.com/abhinavminhas/QueryDB.NET https://github.com/abhinavminhas/QueryDB.NET git LICENSE sql, query, rdbms, database, mssql, sqlserver, mysql, oracle, postgresql - 1. Execute scalar queries (returning a single value). - 1.1.0 + 1. Asynchronous operations. +2. Execute transaction to return transaction outcome and exception details in case of failures. + 1.2.0