Simplify SQL client implementations to reduce repetitive code.

This commit is contained in:
Matt 2025-03-15 01:51:42 +00:00
parent a4e6e75e55
commit d8b6eda93f
5 changed files with 123 additions and 267 deletions

View file

@ -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
/// <summary>
/// MySql client implementation.
/// </summary>
/// <param name="connectionString"></param>
public class MySqlClient(string connectionString) : BaseSqlClient(connectionString)
{
private string? _connectionString;
protected override DbConnection CreateConnection() => new MySqlConnection(_connectionString);
/// <summary>
/// MySql client implementation.
/// </summary>
/// <param name="connectionString"></param>
public MySqlClient(string? connectionString) => _connectionString = connectionString;
/// <summary>
/// <inheritdoc/>
/// </summary>
public async Task<int?> 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;
}
/// <summary>
/// <inheritdoc/>
/// </summary>
public async Task<object?> 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;
}
/// <summary>
/// <inheritdoc/>
/// </summary>
public async Task<DataSet?> 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));
}
/// <summary>
/// Inject parameters into the query to prevent SQL injection.
/// </summary>
/// <param name="command">Command to add the parameters to</param>
/// <param name="parameters">Parameters to add</param>
/// <returns></returns>
private MySqlCommand AddParameters(MySqlCommand command, Dictionary<string, object?> 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);
}

View file

@ -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
/// <summary>
/// PostgreSQL client implementation.
/// </summary>
/// <param name="connectionString"></param>
public class PostgreSqlClient(string connectionString) : BaseSqlClient(connectionString)
{
private string? _connectionString;
protected override DbConnection CreateConnection() => new NpgsqlConnection(_connectionString);
/// <summary>
/// PostgreSQL client implementation.
/// </summary>
/// <param name="connectionString"></param>
public PostgreSqlClient(string? connectionString) => _connectionString = connectionString;
/// <summary>
/// <inheritdoc/>
/// </summary>
public async Task<int?> 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;
}
/// <summary>
/// <inheritdoc/>
/// </summary>
public async Task<object?> 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;
}
/// <summary>
/// <inheritdoc/>
/// </summary>
public async Task<DataSet?> 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));
}
/// <summary>
/// Inject parameters into the query to prevent SQL injection.
/// </summary>
/// <param name="command">Command to add the parameters to</param>
/// <param name="parameters">Parameters to add</param>
/// <returns></returns>
private NpgsqlCommand AddParameters(NpgsqlCommand command, Dictionary<string, object?> 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);
}

View file

@ -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
/// <summary>
/// Microsoft SQL server client implementation.
/// </summary>
/// <param name="connectionString"></param>
public class SqlServerClient(string connectionString) : BaseSqlClient(connectionString)
{
private string? _connectionString;
protected override DbConnection CreateConnection() => new SqlConnection(_connectionString);
/// <summary>
/// Microsoft SQL server client implementation.
/// </summary>
/// <param name="connectionString"></param>
public SqlServerClient(string? connectionString) => _connectionString = connectionString;
/// <summary>
/// <inheritdoc/>
/// </summary>
public async Task<int?> 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;
}
/// <summary>
/// <inheritdoc/>
/// </summary>
public async Task<object?> 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;
}
/// <summary>
/// <inheritdoc/>
/// </summary>
public async Task<DataSet?> 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));
}
/// <summary>
/// Inject parameters into the query to prevent SQL injection.
/// </summary>
/// <param name="command">Command to add the parameters to</param>
/// <param name="parameters">Parameters to add</param>
/// <returns></returns>
private SqlCommand AddParameters(SqlCommand command, Dictionary<string, object?> 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);
}

View file

@ -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
/// <summary>
/// Sqlite client implementation.
/// </summary>
/// <param name="connectionString"></param>
public class SqliteClient(string connectionString) : BaseSqlClient(connectionString)
{
private string? _connectionString;
protected override DbConnection CreateConnection() => new SqliteConnection(_connectionString);
/// <summary>
/// Sqlite client implementation.
/// </summary>
/// <param name="connectionString"></param>
public SqliteClient(string? connectionString) => _connectionString = connectionString;
/// <summary>
/// <inheritdoc/>
/// </summary>
public async Task<int?> 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;
}
/// <summary>
/// <inheritdoc/>
/// </summary>
public async Task<object?> 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;
}
/// <summary>
/// <inheritdoc/>
/// </summary>
public async Task<DataSet?> 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));
}
/// <summary>
/// Inject parameters into the query to prevent SQL injection.
/// </summary>
/// <param name="command">Command to add the parameters to</param>
/// <param name="parameters">Parameters to add</param>
/// <returns></returns>
private SqliteCommand AddParameters(SqliteCommand command, Dictionary<string, object?> 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);
}

View file

@ -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
{
/// <summary>
/// The connection string used to connect with the database.
/// </summary>
protected readonly string _connectionString;
/// <summary>
/// Create a connection using the client specific connection.
/// </summary>
/// <returns></returns>
protected abstract DbConnection CreateConnection();
/// <summary>
/// Create a command using the client specific connection.
/// </summary>
/// <param name="query"></param>
/// <param name="connection"></param>
/// <returns></returns>
protected abstract DbCommand CreateCommand(string query, DbConnection connection);
/// <summary>
///
/// </summary>
/// <param name="connectionString"></param>
protected BaseSqlClient(string connectionString) => _connectionString = connectionString;
/// <summary>
/// <inheritdoc/>
/// </summary>
public async Task<int?> 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;
}
/// <summary>
/// <inheritdoc/>
/// </summary>
public async Task<object?> 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;
}
/// <summary>
/// <inheritdoc/>
/// </summary>
public async Task<DataSet?> 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));
}
/// <summary>
/// Inject parameters into the query to prevent SQL injection.
/// </summary>
/// <param name="command">Command to add the parameters to</param>
/// <param name="parameters">Parameters to add</param>
/// <returns></returns>
private DbCommand AddParameters(DbCommand command, Dictionary<string, object?> 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;
}
/// <summary>
/// Returns <see cref="IDataReader"/> data as a <see cref="DataSet"/>.
/// </summary>
/// <param name="reader">Reader to return data from.</param>
/// <returns><see cref="DataSet"/> of data.</returns>
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
/// </summary>
/// <param name="reader">Reader to return data from.</param>
/// <returns><see cref="DataTable"/> of data.</returns>
protected static DataTable ReadAsDataTable(IDataReader reader)
private DataTable ReadAsDataTable(IDataReader reader)
{
var data = new DataTable();
var schemaTable =reader.GetSchemaTable();