From d8b6eda93ff228100b6d85feda2962f5c9b4f986 Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 15 Mar 2025 01:51:42 +0000 Subject: [PATCH] Simplify SQL client implementations to reduce repetitive code. --- src/modules/Elsa.Sql.MySql/MySqlClient.cs | 74 ++------------- .../Elsa.Sql.PostgreSql/PostgreSqlClient.cs | 74 ++------------- .../Elsa.Sql.SqlServer/SqlServerClient.cs | 74 ++------------- src/modules/Elsa.Sql.Sqlite/SqliteClient.cs | 74 ++------------- src/modules/Elsa.Sql/Client/BaseSqlClient.cs | 94 ++++++++++++++++++- 5 files changed, 123 insertions(+), 267 deletions(-) diff --git a/src/modules/Elsa.Sql.MySql/MySqlClient.cs b/src/modules/Elsa.Sql.MySql/MySqlClient.cs index f8a17c61e..60669f7d1 100644 --- a/src/modules/Elsa.Sql.MySql/MySqlClient.cs +++ b/src/modules/Elsa.Sql.MySql/MySqlClient.cs @@ -1,74 +1,16 @@ using MySql.Data.MySqlClient; using Elsa.Sql.Client; -using System.Data; -using Elsa.Sql.Models; +using System.Data.Common; namespace Elsa.Sql.MySql; -public class MySqlClient : BaseSqlClient, ISqlClient +/// +/// MySql client implementation. +/// +/// +public class MySqlClient(string connectionString) : BaseSqlClient(connectionString) { - private string? _connectionString; + protected override DbConnection CreateConnection() => new MySqlConnection(_connectionString); - /// - /// MySql client implementation. - /// - /// - public MySqlClient(string? connectionString) => _connectionString = connectionString; - - /// - /// - /// - public async Task ExecuteCommandAsync(EvaluatedQuery evaluatedQuery) - { - using var connection = new MySqlConnection(_connectionString); - connection.Open(); - var command = new MySqlCommand(evaluatedQuery.Query, connection); - AddParameters(command, evaluatedQuery.Parameters); - - var result = await command.ExecuteNonQueryAsync(); - return result; - } - - /// - /// - /// - public async Task ExecuteScalarAsync(EvaluatedQuery evaluatedQuery) - { - using var connection = new MySqlConnection(_connectionString); - connection.Open(); - var command = new MySqlCommand(evaluatedQuery.Query, connection); - AddParameters(command, evaluatedQuery.Parameters); - - var result = await command.ExecuteScalarAsync(); - return result; - } - - /// - /// - /// - public async Task ExecuteQueryAsync(EvaluatedQuery evaluatedQuery) - { - using var connection = new MySqlConnection(_connectionString); - connection.Open(); - var command = new MySqlCommand(evaluatedQuery.Query, connection); - AddParameters(command, evaluatedQuery.Parameters); - - using var reader = await command.ExecuteReaderAsync(); - return await Task.FromResult(ReadAsDataSet(reader)); - } - - /// - /// Inject parameters into the query to prevent SQL injection. - /// - /// Command to add the parameters to - /// Parameters to add - /// - private MySqlCommand AddParameters(MySqlCommand command, Dictionary parameters) - { - foreach (var param in parameters) - { - command.Parameters.AddWithValue(param.Key, param.Value ?? DBNull.Value); - } - return command; - } + protected override DbCommand CreateCommand(string query, DbConnection connection) => new MySqlCommand(query, (MySqlConnection)connection); } \ No newline at end of file diff --git a/src/modules/Elsa.Sql.PostgreSql/PostgreSqlClient.cs b/src/modules/Elsa.Sql.PostgreSql/PostgreSqlClient.cs index 48d54101a..5eb5982ba 100644 --- a/src/modules/Elsa.Sql.PostgreSql/PostgreSqlClient.cs +++ b/src/modules/Elsa.Sql.PostgreSql/PostgreSqlClient.cs @@ -1,74 +1,16 @@ using Npgsql; using Elsa.Sql.Client; -using System.Data; -using Elsa.Sql.Models; +using System.Data.Common; namespace Elsa.Sql.PostgreSql; -public class PostgreSqlClient : BaseSqlClient, ISqlClient +/// +/// PostgreSQL client implementation. +/// +/// +public class PostgreSqlClient(string connectionString) : BaseSqlClient(connectionString) { - private string? _connectionString; + protected override DbConnection CreateConnection() => new NpgsqlConnection(_connectionString); - /// - /// PostgreSQL client implementation. - /// - /// - public PostgreSqlClient(string? connectionString) => _connectionString = connectionString; - - /// - /// - /// - public async Task ExecuteCommandAsync(EvaluatedQuery evaluatedQuery) - { - using var connection = new NpgsqlConnection(_connectionString); - connection.Open(); - var command = new NpgsqlCommand(evaluatedQuery.Query, connection); - AddParameters(command, evaluatedQuery.Parameters); - - var result = await command.ExecuteNonQueryAsync(); - return result; - } - - /// - /// - /// - public async Task ExecuteScalarAsync(EvaluatedQuery evaluatedQuery) - { - using var connection = new NpgsqlConnection(_connectionString); - connection.Open(); - var command = new NpgsqlCommand(evaluatedQuery.Query, connection); - AddParameters(command, evaluatedQuery.Parameters); - - var result = await command.ExecuteScalarAsync(); - return result; - } - - /// - /// - /// - public async Task ExecuteQueryAsync(EvaluatedQuery evaluatedQuery) - { - using var connection = new NpgsqlConnection(_connectionString); - connection.Open(); - var command = new NpgsqlCommand(evaluatedQuery.Query, connection); - AddParameters(command, evaluatedQuery.Parameters); - - using var reader = await command.ExecuteReaderAsync(); - return await Task.FromResult(ReadAsDataSet(reader)); - } - - /// - /// Inject parameters into the query to prevent SQL injection. - /// - /// Command to add the parameters to - /// Parameters to add - /// - private NpgsqlCommand AddParameters(NpgsqlCommand command, Dictionary parameters) - { - foreach (var param in parameters) - { - command.Parameters.AddWithValue(param.Key, param.Value ?? DBNull.Value); - } - return command; - } + protected override DbCommand CreateCommand(string query, DbConnection connection) => new NpgsqlCommand(query, (NpgsqlConnection)connection); } \ No newline at end of file diff --git a/src/modules/Elsa.Sql.SqlServer/SqlServerClient.cs b/src/modules/Elsa.Sql.SqlServer/SqlServerClient.cs index 338d9f849..e8780c359 100644 --- a/src/modules/Elsa.Sql.SqlServer/SqlServerClient.cs +++ b/src/modules/Elsa.Sql.SqlServer/SqlServerClient.cs @@ -1,74 +1,16 @@ -using System.Data; +using System.Data.Common; using Elsa.Sql.Client; -using Elsa.Sql.Models; using Microsoft.Data.SqlClient; namespace Elsa.Sql.SqlServer; -public class SqlServerClient : BaseSqlClient, ISqlClient +/// +/// Microsoft SQL server client implementation. +/// +/// +public class SqlServerClient(string connectionString) : BaseSqlClient(connectionString) { - private string? _connectionString; + protected override DbConnection CreateConnection() => new SqlConnection(_connectionString); - /// - /// Microsoft SQL server client implementation. - /// - /// - public SqlServerClient(string? connectionString) => _connectionString = connectionString; - - /// - /// - /// - public async Task ExecuteCommandAsync(EvaluatedQuery evaluatedQuery) - { - using var connection = new SqlConnection(_connectionString); - connection.Open(); - var command = new SqlCommand(evaluatedQuery.Query, connection); - AddParameters(command, evaluatedQuery.Parameters); - - var result = await command.ExecuteNonQueryAsync(); - return result; - } - - /// - /// - /// - public async Task ExecuteScalarAsync(EvaluatedQuery evaluatedQuery) - { - using var connection = new SqlConnection(_connectionString); - connection.Open(); - var command = new SqlCommand(evaluatedQuery.Query, connection); - AddParameters(command, evaluatedQuery.Parameters); - - var result = await command.ExecuteScalarAsync(); - return result; - } - - /// - /// - /// - public async Task ExecuteQueryAsync(EvaluatedQuery evaluatedQuery) - { - using var connection = new SqlConnection(_connectionString); - connection.Open(); - var command = new SqlCommand(evaluatedQuery.Query, connection); - AddParameters(command, evaluatedQuery.Parameters); - - using var reader = await command.ExecuteReaderAsync(); - return await Task.FromResult(ReadAsDataSet(reader)); - } - - /// - /// Inject parameters into the query to prevent SQL injection. - /// - /// Command to add the parameters to - /// Parameters to add - /// - private SqlCommand AddParameters(SqlCommand command, Dictionary parameters) - { - foreach (var param in parameters) - { - command.Parameters.AddWithValue(param.Key, param.Value ?? DBNull.Value); - } - return command; - } + protected override DbCommand CreateCommand(string query, DbConnection connection) => new SqlCommand(query, (SqlConnection)connection); } \ No newline at end of file diff --git a/src/modules/Elsa.Sql.Sqlite/SqliteClient.cs b/src/modules/Elsa.Sql.Sqlite/SqliteClient.cs index 61caf6ef5..ec43f5245 100644 --- a/src/modules/Elsa.Sql.Sqlite/SqliteClient.cs +++ b/src/modules/Elsa.Sql.Sqlite/SqliteClient.cs @@ -1,74 +1,16 @@ -using System.Data; +using System.Data.Common; using Elsa.Sql.Client; -using Elsa.Sql.Models; using Microsoft.Data.Sqlite; namespace Elsa.Sql.Sqlite; -public class SqliteClient : BaseSqlClient, ISqlClient +/// +/// Sqlite client implementation. +/// +/// +public class SqliteClient(string connectionString) : BaseSqlClient(connectionString) { - private string? _connectionString; + protected override DbConnection CreateConnection() => new SqliteConnection(_connectionString); - /// - /// Sqlite client implementation. - /// - /// - public SqliteClient(string? connectionString) => _connectionString = connectionString; - - /// - /// - /// - public async Task ExecuteCommandAsync(EvaluatedQuery evaluatedQuery) - { - using var connection = new SqliteConnection(_connectionString); - connection.Open(); - var command = new SqliteCommand(evaluatedQuery.Query, connection); - AddParameters(command, evaluatedQuery.Parameters); - - var result = await command.ExecuteNonQueryAsync(); - return result; - } - - /// - /// - /// - public async Task ExecuteScalarAsync(EvaluatedQuery evaluatedQuery) - { - using var connection = new SqliteConnection(_connectionString); - connection.Open(); - var command = new SqliteCommand(evaluatedQuery.Query, connection); - AddParameters(command, evaluatedQuery.Parameters); - - var result = await command.ExecuteScalarAsync(); - return result; - } - - /// - /// - /// - public async Task ExecuteQueryAsync(EvaluatedQuery evaluatedQuery) - { - using var connection = new SqliteConnection(_connectionString); - connection.Open(); - var command = new SqliteCommand(evaluatedQuery.Query, connection); - AddParameters(command, evaluatedQuery.Parameters); - - using var reader = await command.ExecuteReaderAsync(); - return await Task.FromResult(ReadAsDataSet(reader)); - } - - /// - /// Inject parameters into the query to prevent SQL injection. - /// - /// Command to add the parameters to - /// Parameters to add - /// - private SqliteCommand AddParameters(SqliteCommand command, Dictionary parameters) - { - foreach (var param in parameters) - { - command.Parameters.AddWithValue(param.Key, param.Value ?? DBNull.Value); - } - return command; - } + protected override DbCommand CreateCommand(string query, DbConnection connection) => new SqliteCommand(query, (SqliteConnection)connection); } \ No newline at end of file diff --git a/src/modules/Elsa.Sql/Client/BaseSqlClient.cs b/src/modules/Elsa.Sql/Client/BaseSqlClient.cs index 6ed7dbfd9..872d4cfcc 100644 --- a/src/modules/Elsa.Sql/Client/BaseSqlClient.cs +++ b/src/modules/Elsa.Sql/Client/BaseSqlClient.cs @@ -1,15 +1,103 @@ using System.Data; +using System.Data.Common; +using Elsa.Sql.Models; namespace Elsa.Sql.Client; -public abstract class BaseSqlClient +public abstract class BaseSqlClient : ISqlClient { + /// + /// The connection string used to connect with the database. + /// + protected readonly string _connectionString; + + /// + /// Create a connection using the client specific connection. + /// + /// + protected abstract DbConnection CreateConnection(); + + /// + /// Create a command using the client specific connection. + /// + /// + /// + /// + protected abstract DbCommand CreateCommand(string query, DbConnection connection); + + /// + /// + /// + /// + protected BaseSqlClient(string connectionString) => _connectionString = connectionString; + + /// + /// + /// + public async Task ExecuteCommandAsync(EvaluatedQuery evaluatedQuery) + { + using var connection = CreateConnection(); + connection.Open(); + var command = CreateCommand(evaluatedQuery.Query, connection); + AddParameters(command, evaluatedQuery.Parameters); + + var result = await command.ExecuteNonQueryAsync(); + return result; + } + + /// + /// + /// + public async Task ExecuteScalarAsync(EvaluatedQuery evaluatedQuery) + { + using var connection = CreateConnection(); + connection.Open(); + var command = CreateCommand(evaluatedQuery.Query, connection); + AddParameters(command, evaluatedQuery.Parameters); + + var result = await command.ExecuteScalarAsync(); + return result; + } + + /// + /// + /// + public async Task ExecuteQueryAsync(EvaluatedQuery evaluatedQuery) + { + using var connection = CreateConnection(); + connection.Open(); + var command = CreateCommand(evaluatedQuery.Query, connection); + AddParameters(command, evaluatedQuery.Parameters); + + using var reader = await command.ExecuteReaderAsync(); + return await Task.FromResult(ReadAsDataSet(reader)); + } + + /// + /// Inject parameters into the query to prevent SQL injection. + /// + /// Command to add the parameters to + /// Parameters to add + /// + private DbCommand AddParameters(DbCommand command, Dictionary parameters) + { + // Add parameters dynamically + foreach (var param in parameters) + { + var dbParam = command.CreateParameter(); + dbParam.ParameterName = param.Key; + dbParam.Value = param.Value ?? DBNull.Value; + command.Parameters.Add(dbParam); + } + return command; + } + /// /// Returns data as a . /// /// Reader to return data from. /// of data. - protected static DataSet ReadAsDataSet(IDataReader reader) + private DataSet ReadAsDataSet(IDataReader reader) { var dataSet = new DataSet("dataset"); dataSet.Tables.Add(ReadAsDataTable(reader)); @@ -21,7 +109,7 @@ public abstract class BaseSqlClient /// /// Reader to return data from. /// of data. - protected static DataTable ReadAsDataTable(IDataReader reader) + private DataTable ReadAsDataTable(IDataReader reader) { var data = new DataTable(); var schemaTable =reader.GetSchemaTable();