From d815d2a2fc2969d33dd25b0212ca3156d4c5d049 Mon Sep 17 00:00:00 2001 From: Riku Virtanen Date: Thu, 30 Nov 2023 15:18:02 +0200 Subject: [PATCH 1/4] Changed data type of QueryParameter.Value --- Frends.MicrosoftSQL.ExecuteQuery/CHANGELOG.md | 4 + .../AutoUnitTests.cs | 2 +- .../ExecuteReaderUnitTests.cs | 409 ++++++++++-------- .../TestData/Test_image.png | Bin 0 -> 1944 bytes .../Definitions/Input.cs | 3 +- .../Definitions/Result.cs | 6 +- .../ExecuteQuery.cs | 18 +- .../Frends.MicrosoftSQL.ExecuteQuery.csproj | 2 +- 8 files changed, 241 insertions(+), 203 deletions(-) create mode 100644 Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/TestData/Test_image.png diff --git a/Frends.MicrosoftSQL.ExecuteQuery/CHANGELOG.md b/Frends.MicrosoftSQL.ExecuteQuery/CHANGELOG.md index 016a615..3665498 100644 --- a/Frends.MicrosoftSQL.ExecuteQuery/CHANGELOG.md +++ b/Frends.MicrosoftSQL.ExecuteQuery/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## [1.2.0] - 2023-11-30 +### Changed +- [Breaking] QueryParameter.Value type to object so that binary data can be used. + ## [1.1.0] - 2023-01-27 ### Changed - Naming: Result.QueryResult to Result.Data. diff --git a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/AutoUnitTests.cs b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/AutoUnitTests.cs index 4823807..1a26eb5 100644 --- a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/AutoUnitTests.cs +++ b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/AutoUnitTests.cs @@ -9,7 +9,7 @@ namespace Frends.MicrosoftSQL.ExecuteQuery.Tests; public class AutoUnitTests { /* - docker-compose up + docker-compose up -d How to use via terminal: docker exec -it sql1 "bash" diff --git a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/ExecuteReaderUnitTests.cs b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/ExecuteReaderUnitTests.cs index e2eaded..bcf5b24 100644 --- a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/ExecuteReaderUnitTests.cs +++ b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/ExecuteReaderUnitTests.cs @@ -1,183 +1,228 @@ -using Frends.MicrosoftSQL.ExecuteQuery.Definitions; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Newtonsoft.Json.Linq; -using System.Data.SqlClient; - -namespace Frends.MicrosoftSQL.ExecuteQuery.Tests; - -[TestClass] -public class ExecuteReaderUnitTests -{ - /* - docker-compose up - - How to use via terminal: - docker exec -it sql1 "bash" - /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "Salakala123!" - SELECT * FROM TestTable - GO - */ - - private static readonly string _connString = "Server=127.0.0.1,1433;Database=Master;User Id=SA;Password=Salakala123!"; - private static readonly string _tableName = "TestTable"; - - [TestInitialize] - public void Init() - { - using var connection = new SqlConnection(_connString); - connection.Open(); - var createTable = connection.CreateCommand(); - createTable.CommandText = $@"IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{_tableName}') BEGIN CREATE TABLE {_tableName} ( Id int, LastName varchar(255), FirstName varchar(255) ); END"; - createTable.ExecuteNonQuery(); - connection.Close(); - connection.Dispose(); - } - - [TestCleanup] - public void CleanUp() - { - using var connection = new SqlConnection(_connString); - connection.Open(); - var createTable = connection.CreateCommand(); - createTable.CommandText = $@"IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{_tableName}') BEGIN DROP TABLE IF EXISTS {_tableName}; END"; - createTable.ExecuteNonQuery(); - connection.Close(); - connection.Dispose(); - } - - [TestMethod] - public async Task TestExecuteQuery_ExecuteReader() - { - var transactionLevels = new List() { - SqlTransactionIsolationLevel.Unspecified, - SqlTransactionIsolationLevel.Serializable, - SqlTransactionIsolationLevel.None, - SqlTransactionIsolationLevel.ReadUncommitted, - SqlTransactionIsolationLevel.ReadCommitted - }; - - var inputInsert = new Input() - { - ConnectionString = _connString, - Query = $@"INSERT INTO {_tableName} VALUES (1, 'Suku', 'Etu'), (2, 'Last', 'Forst'), (3, 'Hiiri', 'Mikki')", - ExecuteType = ExecuteTypes.ExecuteReader, - Parameters = null - }; - - var inputSelect = new Input() - { - ConnectionString = _connString, - Query = $"select * from {_tableName}", - ExecuteType = ExecuteTypes.ExecuteReader, - Parameters = null - }; - - var inputSelectSingle = new Input() - { - ConnectionString = _connString, - Query = $"select * from {_tableName} where Id = 1", - ExecuteType = ExecuteTypes.ExecuteReader, - Parameters = null - }; - - var inputUpdate = new Input() - { - ConnectionString = _connString, - Query = $@"update {_tableName} set LastName = 'Edit' where Id = 2", - ExecuteType = ExecuteTypes.ExecuteReader, - Parameters = null - }; - - var inputDelete = new Input() - { - ConnectionString = _connString, - Query = $"delete from {_tableName} where Id = 2", - ExecuteType = ExecuteTypes.ExecuteReader, - Parameters = null - }; - - foreach (var level in transactionLevels) - { - Init(); - - var options = new Options() - { - SqlTransactionIsolationLevel = level, - CommandTimeoutSeconds = 2, - ThrowErrorOnFailure = true - }; - - // Insert rows - var insert = await MicrosoftSQL.ExecuteQuery(inputInsert, options, default); - Assert.IsTrue(insert.Success); - Assert.AreEqual(3, insert.RecordsAffected); - Assert.IsNull(insert.ErrorMessage); - Assert.AreEqual(3, GetRowCount()); // Make sure rows inserted before moving on. - - // Select all - var select = await MicrosoftSQL.ExecuteQuery(inputSelect, options, default); - Assert.IsTrue(select.Success); - Assert.AreEqual(-1, select.RecordsAffected); - Assert.IsNull(select.ErrorMessage); - Assert.AreEqual(typeof(JArray), select.Data.GetType()); - Assert.AreEqual("Suku", (string)select.Data[0]["LastName"]); - Assert.AreEqual("Etu", (string)select.Data[0]["FirstName"]); - Assert.AreEqual("Last", (string)select.Data[1]["LastName"]); - Assert.AreEqual("Forst", (string)select.Data[1]["FirstName"]); - Assert.AreEqual("Hiiri", (string)select.Data[2]["LastName"]); - Assert.AreEqual("Mikki", (string)select.Data[2]["FirstName"]); - Assert.AreEqual(3, GetRowCount()); // double check - - // Select single - var selectSingle = await MicrosoftSQL.ExecuteQuery(inputSelectSingle, options, default); - Assert.IsTrue(selectSingle.Success); - Assert.AreEqual(-1, selectSingle.RecordsAffected); - Assert.IsNull(selectSingle.ErrorMessage); - Assert.AreEqual(typeof(JArray), selectSingle.Data.GetType()); - Assert.AreEqual("Suku", (string)selectSingle.Data[0]["LastName"]); - Assert.AreEqual("Etu", (string)selectSingle.Data[0]["FirstName"]); - Assert.AreEqual(3, GetRowCount()); // double check - - // Update - var update = await MicrosoftSQL.ExecuteQuery(inputUpdate, options, default); - Assert.IsTrue(update.Success); - Assert.AreEqual(1, update.RecordsAffected); - Assert.IsNull(update.ErrorMessage); - Assert.AreEqual(3, GetRowCount()); // double check - var checkUpdateResult = await MicrosoftSQL.ExecuteQuery(inputSelect, options, default); - Assert.AreEqual("Suku", (string)checkUpdateResult.Data[0]["LastName"]); - Assert.AreEqual("Etu", (string)checkUpdateResult.Data[0]["FirstName"]); - Assert.AreEqual("Edit", (string)checkUpdateResult.Data[1]["LastName"]); - Assert.AreEqual("Forst", (string)checkUpdateResult.Data[1]["FirstName"]); - Assert.AreEqual("Hiiri", (string)checkUpdateResult.Data[2]["LastName"]); - Assert.AreEqual("Mikki", (string)checkUpdateResult.Data[2]["FirstName"]); - Assert.AreEqual(3, GetRowCount()); // double check - - // Delete - var delete = await MicrosoftSQL.ExecuteQuery(inputDelete, options, default); - Assert.IsTrue(delete.Success); - Assert.AreEqual(1, delete.RecordsAffected); - Assert.IsNull(delete.ErrorMessage); - Assert.AreEqual(2, GetRowCount()); // double check - var checkDeleteResult = await MicrosoftSQL.ExecuteQuery(inputSelect, options, default); - Assert.AreEqual("Suku", (string)checkDeleteResult.Data[0]["LastName"]); - Assert.AreEqual("Etu", (string)checkDeleteResult.Data[0]["FirstName"]); - Assert.AreEqual("Hiiri", (string)checkDeleteResult.Data[1]["LastName"]); - Assert.AreEqual("Mikki", (string)checkDeleteResult.Data[1]["FirstName"]); - - CleanUp(); - } - } - - private static int GetRowCount() - { - using var connection = new SqlConnection(_connString); - connection.Open(); - var getRows = connection.CreateCommand(); - getRows.CommandText = $"SELECT COUNT(*) FROM {_tableName}"; - var count = (int)getRows.ExecuteScalar(); - connection.Close(); - connection.Dispose(); - return count; - } +using Frends.MicrosoftSQL.ExecuteQuery.Definitions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Newtonsoft.Json.Linq; +using System.Data.SqlClient; + +namespace Frends.MicrosoftSQL.ExecuteQuery.Tests; + +[TestClass] +public class ExecuteReaderUnitTests +{ + /* + docker-compose up + + How to use via terminal: + docker exec -it sql1 "bash" + /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "Salakala123!" + SELECT * FROM TestTable + GO + */ + + private static readonly string _connString = "Server=127.0.0.1,1433;Database=Master;User Id=SA;Password=Salakala123!"; + private static readonly string _tableName = "TestTable"; + + [TestInitialize] + public void Init() + { + var command = $@"IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{_tableName}') BEGIN CREATE TABLE {_tableName} ( Id int, LastName varchar(255), FirstName varchar(255) ); END"; + ExecuteQuery(command); + } + + [TestCleanup] + public void CleanUp() + { + var command = $@"IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{_tableName}') BEGIN DROP TABLE IF EXISTS {_tableName}; END"; + ExecuteQuery(command); + } + + [TestMethod] + public async Task TestExecuteQuery_ExecuteReader() + { + var transactionLevels = new List() { + SqlTransactionIsolationLevel.Unspecified, + SqlTransactionIsolationLevel.Serializable, + SqlTransactionIsolationLevel.None, + SqlTransactionIsolationLevel.ReadUncommitted, + SqlTransactionIsolationLevel.ReadCommitted + }; + + var inputInsert = new Input() + { + ConnectionString = _connString, + Query = $@"INSERT INTO {_tableName} VALUES (1, 'Suku', 'Etu'), (2, 'Last', 'Forst'), (3, 'Hiiri', 'Mikki')", + ExecuteType = ExecuteTypes.ExecuteReader, + Parameters = null + }; + + var inputSelect = new Input() + { + ConnectionString = _connString, + Query = $"select * from {_tableName}", + ExecuteType = ExecuteTypes.ExecuteReader, + Parameters = null + }; + + var inputSelectSingle = new Input() + { + ConnectionString = _connString, + Query = $"select * from {_tableName} where Id = 1", + ExecuteType = ExecuteTypes.ExecuteReader, + Parameters = null + }; + + var inputUpdate = new Input() + { + ConnectionString = _connString, + Query = $@"update {_tableName} set LastName = 'Edit' where Id = 2", + ExecuteType = ExecuteTypes.ExecuteReader, + Parameters = null + }; + + var inputDelete = new Input() + { + ConnectionString = _connString, + Query = $"delete from {_tableName} where Id = 2", + ExecuteType = ExecuteTypes.ExecuteReader, + Parameters = null + }; + + foreach (var level in transactionLevels) + { + Init(); + + var options = new Options() + { + SqlTransactionIsolationLevel = level, + CommandTimeoutSeconds = 2, + ThrowErrorOnFailure = true + }; + + // Insert rows + var insert = await MicrosoftSQL.ExecuteQuery(inputInsert, options, default); + Assert.IsTrue(insert.Success); + Assert.AreEqual(3, insert.RecordsAffected); + Assert.IsNull(insert.ErrorMessage); + Assert.AreEqual(3, GetRowCount()); // Make sure rows inserted before moving on. + + // Select all + var select = await MicrosoftSQL.ExecuteQuery(inputSelect, options, default); + Assert.IsTrue(select.Success); + Assert.AreEqual(-1, select.RecordsAffected); + Assert.IsNull(select.ErrorMessage); + Assert.AreEqual(typeof(JArray), select.Data.GetType()); + Assert.AreEqual("Suku", (string)select.Data[0]["LastName"]); + Assert.AreEqual("Etu", (string)select.Data[0]["FirstName"]); + Assert.AreEqual("Last", (string)select.Data[1]["LastName"]); + Assert.AreEqual("Forst", (string)select.Data[1]["FirstName"]); + Assert.AreEqual("Hiiri", (string)select.Data[2]["LastName"]); + Assert.AreEqual("Mikki", (string)select.Data[2]["FirstName"]); + Assert.AreEqual(3, GetRowCount()); // double check + + // Select single + var selectSingle = await MicrosoftSQL.ExecuteQuery(inputSelectSingle, options, default); + Assert.IsTrue(selectSingle.Success); + Assert.AreEqual(-1, selectSingle.RecordsAffected); + Assert.IsNull(selectSingle.ErrorMessage); + Assert.AreEqual(typeof(JArray), selectSingle.Data.GetType()); + Assert.AreEqual("Suku", (string)selectSingle.Data[0]["LastName"]); + Assert.AreEqual("Etu", (string)selectSingle.Data[0]["FirstName"]); + Assert.AreEqual(3, GetRowCount()); // double check + + // Update + var update = await MicrosoftSQL.ExecuteQuery(inputUpdate, options, default); + Assert.IsTrue(update.Success); + Assert.AreEqual(1, update.RecordsAffected); + Assert.IsNull(update.ErrorMessage); + Assert.AreEqual(3, GetRowCount()); // double check + var checkUpdateResult = await MicrosoftSQL.ExecuteQuery(inputSelect, options, default); + Assert.AreEqual("Suku", (string)checkUpdateResult.Data[0]["LastName"]); + Assert.AreEqual("Etu", (string)checkUpdateResult.Data[0]["FirstName"]); + Assert.AreEqual("Edit", (string)checkUpdateResult.Data[1]["LastName"]); + Assert.AreEqual("Forst", (string)checkUpdateResult.Data[1]["FirstName"]); + Assert.AreEqual("Hiiri", (string)checkUpdateResult.Data[2]["LastName"]); + Assert.AreEqual("Mikki", (string)checkUpdateResult.Data[2]["FirstName"]); + Assert.AreEqual(3, GetRowCount()); // double check + + // Delete + var delete = await MicrosoftSQL.ExecuteQuery(inputDelete, options, default); + Assert.IsTrue(delete.Success); + Assert.AreEqual(1, delete.RecordsAffected); + Assert.IsNull(delete.ErrorMessage); + Assert.AreEqual(2, GetRowCount()); // double check + var checkDeleteResult = await MicrosoftSQL.ExecuteQuery(inputSelect, options, default); + Assert.AreEqual("Suku", (string)checkDeleteResult.Data[0]["LastName"]); + Assert.AreEqual("Etu", (string)checkDeleteResult.Data[0]["FirstName"]); + Assert.AreEqual("Hiiri", (string)checkDeleteResult.Data[1]["LastName"]); + Assert.AreEqual("Mikki", (string)checkDeleteResult.Data[1]["FirstName"]); + + CleanUp(); + } + } + + [TestMethod] + public async Task ExecuteQueryTestWithBinaryData() + { + var table = "binarytest"; + var command = $"IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{table}') BEGIN CREATE TABLE {table} ( Id int, Data varbinary(MAX)); END"; + ExecuteQuery(command); + + var binary = File.ReadAllBytes(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "../../../TestData/", "Test_image.png")); + + var input = new Input + { + ConnectionString = _connString, + Query = $"INSERT INTO {table} VALUES (1, @bin)", + ExecuteType = ExecuteTypes.NonQuery, + Parameters = new QueryParameter[] { new QueryParameter { Name = "bin", Value = binary, SqlDataType = SqlDataTypes.VarBinary } } + }; + + var options = new Options + { + CommandTimeoutSeconds = 30, + SqlTransactionIsolationLevel = SqlTransactionIsolationLevel.ReadCommitted, + ThrowErrorOnFailure = true + }; + + var result = await MicrosoftSQL.ExecuteQuery(input, options, default); + Assert.IsTrue(result.Success); + + input = new Input + { + ConnectionString = _connString, + Query = $@"SELECT Id, Data From {table}", + ExecuteType = ExecuteTypes.ExecuteReader, + Parameters = null + }; + + result = await MicrosoftSQL.ExecuteQuery(input, options, default); + + command = $"IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '{table}') BEGIN DROP TABLE IF EXISTS {table}; END"; + ExecuteQuery(command); + + Assert.IsTrue(result.Success); + Assert.AreEqual(Convert.ToBase64String(binary), Convert.ToBase64String((byte[])result.Data[0]["Data"])); + } + + private static int GetRowCount() + { + using var connection = new SqlConnection(_connString); + connection.Open(); + var getRows = connection.CreateCommand(); + getRows.CommandText = $"SELECT COUNT(*) FROM {_tableName}"; + var count = (int)getRows.ExecuteScalar(); + connection.Close(); + connection.Dispose(); + return count; + } + + private static void ExecuteQuery(string command) + { + using var connection = new SqlConnection(_connString); + connection.Open(); + var createTable = connection.CreateCommand(); + createTable.CommandText = command; + createTable.ExecuteNonQuery(); + connection.Close(); + connection.Dispose(); + } } \ No newline at end of file diff --git a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/TestData/Test_image.png b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/TestData/Test_image.png new file mode 100644 index 0000000000000000000000000000000000000000..7055e4111428ff4423d32995865c2453dd115587 GIT binary patch literal 1944 zcma)-c{~#e0LO=s^c+#hQM6)_`^cShb~H5ieP44`LwM{7=^#tXrj$y{ea_LN94Yq^ zWA@yZVdhF=&2v2OpZE9sTF(C2@})fH770010Qfmxb4 z#Cff~a1TFiCD~PE;*bw6(U8RFTO^JQ`Hg-FDSodAx>&5HR8e43EcalJhxi0~?G&$A z6#abX>yQk;k9_LC3d}WjNp`BN3_EQlVJEm>N>cS;R1;?R<=Se#@lxGNkNP2_Z+!aM z%a_j%ugvZR$4(Zue%&`L}%}+|WZ(4fqf8tWowyx1$kpX5=SjWJi^m$$$ zb#nQvEmMqxjQUq)56?gTxRdMv>@A47efGn|cDTiY7Nb=j68rM*!r+9iAI zSoSm?NbW86Cka_u!%t`2 z8G@L5V$fdIZ}Mj$JlpLq_%R;KB9*e4Sf_f<_fPjeP^AqU^5#b@ir~VEKgGXiNa!L!odi5s)*yBuC^pN$sVf%d)f^~|ist<35tav!6{cSoH6p0aFs6cNhg9SAuEVq@4zwNrsKA?a~B=eOKq#4Aw)UbF?0CqO_!Uzf}j^O9@-?F zL}Ci*kR*0x9LGy{U3a6_bj$g?!L@7}x!vtSsrrvuI30A&Zd$F|<=(tp9kb_zww zsY{NzLLT5#(^ax(Iua^zgPoI{a)lgrrSm{@dmRycq39|4v2@Ah{@Rqzx#qtXE7WY= za<#66ZNA1HZmWq=lm}YtQv?YKkH><{8=d;nr{Z!8o3C9ApE1?UlHEwvW+*)+1Jra3 zuh)FXlpY)X8xK>FO$jrCZlyOo> z^3b)A+c<3_N!!9tv)KJ+x0dh@Qha=(VNHX24sTjqGTu?k&2&m*1n}=NzSZeaugXg* z$M~wr{)IP3pltSMCxCGUQ?U zGy4U1srJmhogQ9uRqpl_vQToRE0pj1G!EVc74t8pxXL+tHapgx998vz&%0!$kxo(#{yOJP= z4`Af{-bTg+%m(V{vICPS<-U+o-W3~U8YTmo68*)&>(%S?9)ID3dVEiZir&{_AVuRK z^q>$>^_nFo*lOU9*qaA?@j3>(IQ_`T7MFosjn6U&k@WCl*yMFMH-=^=OJK-!{y0|u zLg66;b5hEc9acL=Gy<=s@*Epoh8A!B=B|cN;Dm!0`$QyqNE>uzk /// Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword; [PasswordPropertyText] + [DisplayFormat(DataFormatString = "Text")] [DefaultValue("Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;")] public string ConnectionString { get; set; } @@ -64,7 +65,7 @@ public class QueryParameter /// The value of the parameter. /// /// FirstName - public string Value { get; set; } + public object Value { get; set; } /// /// SQL Server-specific data type. diff --git a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/Definitions/Result.cs b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/Definitions/Result.cs index 418caa4..88ccd22 100644 --- a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/Definitions/Result.cs +++ b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/Definitions/Result.cs @@ -1,4 +1,6 @@ -namespace Frends.MicrosoftSQL.ExecuteQuery.Definitions; +using System.Collections.Generic; + +namespace Frends.MicrosoftSQL.ExecuteQuery.Definitions; /// /// Task's result. @@ -26,7 +28,7 @@ public class Result public string ErrorMessage { get; private set; } /// - /// Query result as JToken. + /// Query result as Dictionary. /// /// /// Input.ExecuteType = ExecuteReader: [{"ID": "1","FIRST_NAME": "Saija","LAST_NAME": "Saijalainen","START_DATE": ""}], diff --git a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/ExecuteQuery.cs b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/ExecuteQuery.cs index 7871306..ddd3c60 100644 --- a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/ExecuteQuery.cs +++ b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/ExecuteQuery.cs @@ -1,11 +1,11 @@ using Frends.MicrosoftSQL.ExecuteQuery.Definitions; using Newtonsoft.Json.Linq; using System; +using System.Linq; using System.ComponentModel; using System.Data; using System.Data.SqlClient; -using System.Reflection; -using System.Runtime.Loader; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using IsolationLevel = System.Data.IsolationLevel; @@ -17,15 +17,6 @@ namespace Frends.MicrosoftSQL.ExecuteQuery; /// public class MicrosoftSQL { - /// Mem cleanup. - static MicrosoftSQL() - { - var currentAssembly = Assembly.GetExecutingAssembly(); - var currentContext = AssemblyLoadContext.GetLoadContext(currentAssembly); - if (currentContext != null) - currentContext.Unloading += OnPluginUnloadingRequested; - } - /// /// Execute MSSQL query. /// [Documentation](https://tasks.frends.com/tasks/frends-tasks/Frends.MicrosoftSQL.ExecuteQuery) @@ -182,9 +173,4 @@ private static IsolationLevel GetIsolationLevel(Options options) _ => IsolationLevel.ReadCommitted, }; } - - private static void OnPluginUnloadingRequested(AssemblyLoadContext obj) - { - obj.Unloading -= OnPluginUnloadingRequested; - } } \ No newline at end of file diff --git a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.csproj b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.csproj index 01c73eb..2a2c5c5 100644 --- a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.csproj +++ b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.csproj @@ -2,7 +2,7 @@ net6.0 - 1.1.0 + 1.2.0 Frends Frends Frends From cfcea276df680aca1f8e03aa49bfd50b6be5675d Mon Sep 17 00:00:00 2001 From: Riku Virtanen Date: Fri, 1 Dec 2023 07:53:50 +0200 Subject: [PATCH 2/4] Linting fixes and added Tests for code coverage --- .../AutoUnitTests.cs | 2 +- .../ExceptionUnitTests.cs | 45 ++++++++++++++++++- .../ExecuteReaderUnitTests.cs | 2 +- .../ManualTesting.cs | 2 +- .../NonQueryUnitTests.cs | 2 +- .../ScalarUnitTests.cs | 2 +- .../Definitions/Enums.cs | 10 ++--- 7 files changed, 54 insertions(+), 11 deletions(-) diff --git a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/AutoUnitTests.cs b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/AutoUnitTests.cs index 1a26eb5..9e07445 100644 --- a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/AutoUnitTests.cs +++ b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/AutoUnitTests.cs @@ -20,7 +20,7 @@ docker exec -it sql1 "bash" private static readonly string _connString = "Server=127.0.0.1,1433;Database=Master;User Id=SA;Password=Salakala123!"; private static readonly string _tableName = "TestTable"; - + [TestInitialize] public void Init() { diff --git a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/ExceptionUnitTests.cs b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/ExceptionUnitTests.cs index 040de24..664abaf 100644 --- a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/ExceptionUnitTests.cs +++ b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/ExceptionUnitTests.cs @@ -19,7 +19,7 @@ docker exec -it sql1 "bash" private static readonly string _connString = "Server=127.0.0.1,1433;Database=Master;User Id=SA;Password=Salakala123!"; private static readonly string _tableName = "TestTable"; - + [TestInitialize] public void Init() { @@ -83,4 +83,47 @@ public async Task TestExecuteQuery_Invalid_Creds_ReturnErrorMessage() Assert.IsTrue(result.ErrorMessage.Contains("Login failed for user 'SA'.")); Assert.AreEqual(0, result.RecordsAffected); } + + [TestMethod] + public void TestExecuteQuery_ExceptionIsThrownWhenQueryFails() + { + var input = new Input() + { + Query = $"INSERT INTO {_tableName} VALUES (1, Unit, Tests, 456)", + ExecuteType = ExecuteTypes.NonQuery, + ConnectionString = _connString, + }; + + var options = new Options() + { + SqlTransactionIsolationLevel = SqlTransactionIsolationLevel.ReadCommitted, + CommandTimeoutSeconds = 2, + ThrowErrorOnFailure = true + }; + + var ex = Assert.ThrowsExceptionAsync(async () => await MicrosoftSQL.ExecuteQuery(input, options, default)); + Assert.IsTrue(ex.Result.Message.Contains("System.Data.SqlClient.SqlException (0x80131904): Invalid column name 'Unit'.")); + } + + [TestMethod] + public async Task TestExecuteQuery_ErrorMessageWhenQueryFails() + { + var input = new Input() + { + Query = $"INSERT INTO {_tableName} VALUES (1, Unit, Tests, 456)", + ExecuteType = ExecuteTypes.NonQuery, + ConnectionString = _connString, + }; + + var options = new Options() + { + SqlTransactionIsolationLevel = SqlTransactionIsolationLevel.ReadCommitted, + CommandTimeoutSeconds = 2, + ThrowErrorOnFailure = false + }; + + var result = await MicrosoftSQL.ExecuteQuery(input, options, default); + Assert.IsFalse(result.Success); + Assert.IsTrue(result.ErrorMessage.Contains("System.Data.SqlClient.SqlException (0x80131904): Invalid column name 'Unit'.")); + } } \ No newline at end of file diff --git a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/ExecuteReaderUnitTests.cs b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/ExecuteReaderUnitTests.cs index bcf5b24..db6b381 100644 --- a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/ExecuteReaderUnitTests.cs +++ b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/ExecuteReaderUnitTests.cs @@ -20,7 +20,7 @@ docker exec -it sql1 "bash" private static readonly string _connString = "Server=127.0.0.1,1433;Database=Master;User Id=SA;Password=Salakala123!"; private static readonly string _tableName = "TestTable"; - + [TestInitialize] public void Init() { diff --git a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/ManualTesting.cs b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/ManualTesting.cs index 950a8a5..0ca3eaa 100644 --- a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/ManualTesting.cs +++ b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/ManualTesting.cs @@ -21,7 +21,7 @@ docker exec -it sql1 "bash" private static readonly string _connString = "Server=127.0.0.1,1433;Database=Master;User Id=SA;Password=Salakala123!"; private static readonly string _tableName = "TestTable"; - + [TestInitialize] public void Init() { diff --git a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/NonQueryUnitTests.cs b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/NonQueryUnitTests.cs index 7be4b94..c06bc78 100644 --- a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/NonQueryUnitTests.cs +++ b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/NonQueryUnitTests.cs @@ -20,7 +20,7 @@ docker exec -it sql1 "bash" private static readonly string _connString = "Server=127.0.0.1,1433;Database=Master;User Id=SA;Password=Salakala123!"; private static readonly string _tableName = "TestTable"; - + [TestInitialize] public void Init() { diff --git a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/ScalarUnitTests.cs b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/ScalarUnitTests.cs index ed9df56..9f3ef74 100644 --- a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/ScalarUnitTests.cs +++ b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/ScalarUnitTests.cs @@ -19,7 +19,7 @@ docker exec -it sql1 "bash" private static readonly string _connString = "Server=127.0.0.1,1433;Database=Master;User Id=SA;Password=Salakala123!"; private static readonly string _tableName = "TestTable"; - + [TestInitialize] public void Init() { diff --git a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/Definitions/Enums.cs b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/Definitions/Enums.cs index e82aa67..9566f01 100644 --- a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/Definitions/Enums.cs +++ b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/Definitions/Enums.cs @@ -3,7 +3,7 @@ /// /// SQL transaction isolation levels. /// -public enum SqlTransactionIsolationLevel +public enum SqlTransactionIsolationLevel { /// /// A different isolation level than the one specified is being used, but the level cannot be determined. @@ -28,8 +28,8 @@ public enum SqlTransactionIsolationLevel /// /// A dirty read is possible, meaning that no shared locks are issued and no exclusive locks are honored. /// - ReadUncommitted = 256, - + ReadUncommitted = 256, + /// /// Locks are placed on all data that is used in a query, preventing other users from updating the data. /// Prevents non-repeatable reads but phantom rows are still possible. @@ -40,12 +40,12 @@ public enum SqlTransactionIsolationLevel /// A range lock is placed on the System.Data.DataSet, preventing other users from updating or inserting rows into the dataset until the transaction is complete. /// Serializable = 1048576, - + /// /// Reduces blocking by storing a version of data that one application can read while another is modifying the same data. /// Indicates that from one transaction you cannot see changes made in other transactions, even if you requery. /// - Snapshot = 16777216 + Snapshot = 16777216, } /// From d5bec603e206b4d0c1388a1565b518c87b617272 Mon Sep 17 00:00:00 2001 From: Riku Virtanen Date: Mon, 4 Dec 2023 10:19:05 +0200 Subject: [PATCH 3/4] PR review changes --- .../NonQueryUnitTests.cs | 1 - .../Frends.MicrosoftSQL.ExecuteQuery/Definitions/Result.cs | 4 +--- .../Frends.MicrosoftSQL.ExecuteQuery/ExecuteQuery.cs | 2 -- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/NonQueryUnitTests.cs b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/NonQueryUnitTests.cs index c06bc78..17ed38f 100644 --- a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/NonQueryUnitTests.cs +++ b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery.Tests/NonQueryUnitTests.cs @@ -1,6 +1,5 @@ using Frends.MicrosoftSQL.ExecuteQuery.Definitions; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Newtonsoft.Json.Linq; using System.Data.SqlClient; namespace Frends.MicrosoftSQL.ExecuteQuery.Tests; diff --git a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/Definitions/Result.cs b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/Definitions/Result.cs index 88ccd22..cf38450 100644 --- a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/Definitions/Result.cs +++ b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/Definitions/Result.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace Frends.MicrosoftSQL.ExecuteQuery.Definitions; +namespace Frends.MicrosoftSQL.ExecuteQuery.Definitions; /// /// Task's result. diff --git a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/ExecuteQuery.cs b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/ExecuteQuery.cs index ddd3c60..0e3803f 100644 --- a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/ExecuteQuery.cs +++ b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/ExecuteQuery.cs @@ -1,11 +1,9 @@ using Frends.MicrosoftSQL.ExecuteQuery.Definitions; using Newtonsoft.Json.Linq; using System; -using System.Linq; using System.ComponentModel; using System.Data; using System.Data.SqlClient; -using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using IsolationLevel = System.Data.IsolationLevel; From d0cb9f8f67a44e729c854be76474046a4c76eefe Mon Sep 17 00:00:00 2001 From: Riku Virtanen Date: Mon, 4 Dec 2023 13:59:30 +0200 Subject: [PATCH 4/4] PR --- .../Frends.MicrosoftSQL.ExecuteQuery/Definitions/Result.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/Definitions/Result.cs b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/Definitions/Result.cs index cf38450..418caa4 100644 --- a/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/Definitions/Result.cs +++ b/Frends.MicrosoftSQL.ExecuteQuery/Frends.MicrosoftSQL.ExecuteQuery/Definitions/Result.cs @@ -26,7 +26,7 @@ public class Result public string ErrorMessage { get; private set; } /// - /// Query result as Dictionary. + /// Query result as JToken. /// /// /// Input.ExecuteType = ExecuteReader: [{"ID": "1","FIRST_NAME": "Saija","LAST_NAME": "Saijalainen","START_DATE": ""}],