Skip to content

Commit

Permalink
Merge pull request #52 from MikeAmputer/kravtsov/command-execution-li…
Browse files Browse the repository at this point in the history
…stener

Command execution listener
  • Loading branch information
MikeAmputer authored Aug 5, 2024
2 parents f5a5680 + c073ffe commit db5a010
Show file tree
Hide file tree
Showing 13 changed files with 133 additions and 33 deletions.
8 changes: 6 additions & 2 deletions examples/Example.Simple/Context/ExampleContextFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,22 @@ namespace ClickHouse.Facades.Example;
public class ExampleContextFactory : ClickHouseContextFactory<ExampleContext>
{
private readonly string _connectionString;
private readonly IClickHouseCommandExecutionListener _commandExecutionListener;

public ExampleContextFactory(IOptions<ClickHouseConfig> config)
public ExampleContextFactory(IOptions<ClickHouseConfig> config, QueryLogger queryLogger)
{
ArgumentNullException.ThrowIfNull(config);
ArgumentNullException.ThrowIfNull(queryLogger);

_connectionString = config.Value.ConnectionString;
_commandExecutionListener = queryLogger;
}

protected override void SetupContextOptions(ClickHouseContextOptionsBuilder<ExampleContext> optionsBuilder)
{
optionsBuilder
.WithConnectionString(_connectionString)
.WithCommandExecutionStrategy(CommandExecutionStrategy.Cancelable);
.WithCommandExecutionStrategy(CommandExecutionStrategy.Cancelable)
.WithCommandExecutionListener(_commandExecutionListener);
}
}
1 change: 1 addition & 0 deletions examples/Example.Simple/Example.Simple.csproj.DotSettings
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=configs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=context/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=logging/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=migrations/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=migrations_005Csettings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
28 changes: 28 additions & 0 deletions examples/Example.Simple/Logging/QueryLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using ClickHouse.Client.ADO;
using Microsoft.Extensions.Logging;

namespace ClickHouse.Facades.Example;

public class QueryLogger : IClickHouseCommandExecutionListener
{
private readonly ILogger _logger;

public QueryLogger(ILogger<QueryLogger> logger)
{
ArgumentNullException.ThrowIfNull(logger);

_logger = logger;
}

public async Task ProcessExecutedCommand(ClickHouseCommand command, CancellationToken cancellationToken = default)
{
await Task.Yield();

var stats = command.QueryStats;

if (stats != null && stats.ReadRows > 0)
{
_logger.LogDebug($"{command.CommandText}\nReadRows: {stats.ReadRows} | ReadBytes: {stats.ReadBytes}");
}
}
}
9 changes: 9 additions & 0 deletions examples/Example.Simple/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

var host = CreateHostBuilder(args).Build();
var serviceProvider = host.Services;
Expand All @@ -29,13 +30,21 @@ static IHostBuilder CreateHostBuilder(string[] args) =>
var path = Path.Combine(context.HostingEnvironment.ContentRootPath, "appsettings.json");
builder.AddJsonFile(path, false, true);
})
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.AddConsole();
logging.SetMinimumLevel(LogLevel.Debug);
})
.ConfigureServices((_, services) =>
{
services.AddOptions<ClickHouseConfig>()
.BindConfiguration(nameof(ClickHouseConfig));
services.AddOptions<OrdersGeneratingConfig>()
.BindConfiguration(nameof(OrdersGeneratingConfig));

services.AddSingleton<QueryLogger>();

services.AddClickHouseMigrations<ClickHouseMigrationInstructions, ClickHouseMigrationsLocator>();

services.AddClickHouseContext<ExampleContext, ExampleContextFactory>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public static IServiceCollection AddClickHouseTestContext<TContext, TContextFact
.CreateInstance<TContextFactory>(serviceProvider)
.Setup(
serviceProvider.GetRequiredService<ClickHouseFacadeFactory<TContext>>(),
(_, _) => new ClickHouseConnectionBrokerStub<TContext>(serviceProvider)),
_ => new ClickHouseConnectionBrokerStub<TContext>(serviceProvider)),
factoryLifetime);

if (exposedFactoryType != null)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using ClickHouse.Client.ADO;

namespace ClickHouse.Facades;

public interface IClickHouseCommandExecutionListener
{
public Task ProcessExecutedCommand(ClickHouseCommand command, CancellationToken cancellationToken = default);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,29 @@ internal class ClickHouseConnectionBroker : IClickHouseConnectionBroker
private readonly ClickHouseConnection _connection;
private readonly bool _sessionEnabled;
private readonly ICommandExecutionStrategy _commandExecutionStrategy;
private readonly IClickHouseCommandExecutionListener? _commandExecutionListener;

public ClickHouseConnectionBroker(
ClickHouseConnection connection,
ICommandExecutionStrategy commandExecutionStrategy)
public ClickHouseConnectionBroker(ConnectionBrokerParameters brokerParameters)
{
if (_connection != null)
{
throw new InvalidOperationException($"{GetType()} is already connected.");
}

_connection = connection
?? throw new ArgumentNullException(nameof(connection));
if (brokerParameters == null)
{
throw new ArgumentNullException(nameof(brokerParameters));
}

_connection = brokerParameters.Connection
?? throw new ArgumentNullException(nameof(brokerParameters.Connection));

_commandExecutionStrategy = brokerParameters.CommandExecutionStrategy
?? throw new ArgumentNullException(nameof(brokerParameters.CommandExecutionStrategy));

_commandExecutionStrategy = commandExecutionStrategy
?? throw new ArgumentNullException(nameof(commandExecutionStrategy));
_commandExecutionListener = brokerParameters.CommandExecutionListener;

_sessionEnabled = connection.ConnectionString
_sessionEnabled = brokerParameters.Connection.ConnectionString
.GetConnectionStringParameters()
.Contains(new KeyValuePair<string, string?>(UseSessionConnectionStringParameter, true.ToString()));
}
Expand All @@ -58,7 +64,12 @@ public async Task<object> ExecuteScalarAsync(
command.CommandText = query;
SetParameters(command, parameters);

return await _commandExecutionStrategy.ExecuteScalarAsync(_connection, command, cancellationToken);
var result = await _commandExecutionStrategy
.ExecuteScalarAsync(_connection, command, cancellationToken);

await PublishExecutedCommand(command, cancellationToken);

return result;
}

public async Task<int> ExecuteNonQueryAsync(
Expand All @@ -72,7 +83,12 @@ public async Task<int> ExecuteNonQueryAsync(
command.CommandText = statement;
SetParameters(command, parameters);

return await _commandExecutionStrategy.ExecuteNonQueryAsync(_connection, command, cancellationToken);
var result = await _commandExecutionStrategy
.ExecuteNonQueryAsync(_connection, command, cancellationToken);

await PublishExecutedCommand(command, cancellationToken);

return result;
}

public async Task<DbDataReader> ExecuteReaderAsync(
Expand All @@ -86,7 +102,12 @@ public async Task<DbDataReader> ExecuteReaderAsync(
command.CommandText = query;
SetParameters(command, parameters);

return await _commandExecutionStrategy.ExecuteDataReaderAsync(_connection, command, cancellationToken);
var result = await _commandExecutionStrategy
.ExecuteDataReaderAsync(_connection, command, cancellationToken);

await PublishExecutedCommand(command, cancellationToken);

return result;
}

public DataTable ExecuteDataTable(
Expand Down Expand Up @@ -224,4 +245,12 @@ private void ThrowIfNotConnected()
throw new InvalidOperationException($"{GetType()} is not connected.");
}
}

private async Task PublishExecutedCommand(ClickHouseCommand command, CancellationToken cancellationToken)
{
if (_commandExecutionListener != null)
{
await _commandExecutionListener.ProcessExecutedCommand(command, cancellationToken);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using ClickHouse.Client.ADO;

namespace ClickHouse.Facades;

internal class ConnectionBrokerParameters
{
public ClickHouseConnection? Connection { get; set; }

public ICommandExecutionStrategy? CommandExecutionStrategy { get; set; }

public IClickHouseCommandExecutionListener? CommandExecutionListener { get; set; }
}
9 changes: 6 additions & 3 deletions src/ClickHouse.Facades/Context/Context/ClickHouseContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,12 @@ internal async Task Initialize(ClickHouseContextOptions<TContext> options)

_connection.SetFormDataParameters(options.ParametersInBody);

_connectionBroker = options.ConnectionBrokerProvider(
_connection,
ICommandExecutionStrategy.Pick(options.CommandExecutionStrategy));
_connectionBroker = options.ConnectionBrokerProvider(new ConnectionBrokerParameters
{
Connection = _connection,
CommandExecutionStrategy = ICommandExecutionStrategy.Pick(options.CommandExecutionStrategy),
CommandExecutionListener = options.CommandExecutionListener,
});

_facadeFactory = options.FacadeFactory;
_allowDatabaseChanges = options.AllowDatabaseChanges;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using ClickHouse.Client.ADO;

namespace ClickHouse.Facades;
namespace ClickHouse.Facades;

public sealed class ClickHouseContextOptions<TContext>
where TContext : ClickHouseContext<TContext>
Expand All @@ -19,14 +17,16 @@ internal ClickHouseContextOptions()

internal ClickHouseFacadeFactory<TContext> FacadeFactory { get; set; } = null!;

internal Func<ClickHouseConnection, ICommandExecutionStrategy, IClickHouseConnectionBroker> ConnectionBrokerProvider
internal Func<ConnectionBrokerParameters, IClickHouseConnectionBroker> ConnectionBrokerProvider
{
get;
set;
} = null!;

internal CommandExecutionStrategy CommandExecutionStrategy { get; set; } = CommandExecutionStrategy.Default;

internal IClickHouseCommandExecutionListener? CommandExecutionListener { get; set; } = null;

internal TransactionBrokerOptions TransactionBrokerOptions { get; set; } = null!;

internal bool ParametersInBody { get; set; } = false;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using ClickHouse.Client.ADO;
using ClickHouse.Facades.Utility;
using ClickHouse.Facades.Utility;

namespace ClickHouse.Facades;

Expand All @@ -20,9 +19,10 @@ public sealed class ClickHouseContextOptionsBuilder<TContext>
private OptionalValue<ClickHouseFacadeFactory<TContext>> _facadeFactory;

private OptionalValue<
Func<ClickHouseConnection, ICommandExecutionStrategy, IClickHouseConnectionBroker>> _connectionBrokerProvider;
Func<ConnectionBrokerParameters, IClickHouseConnectionBroker>> _connectionBrokerProvider;

private OptionalValue<CommandExecutionStrategy> _commandExecutionStrategy;
private OptionalValue<IClickHouseCommandExecutionListener> _commandExecutionListener;

private OptionalValue<Action<TransactionBrokerOptionsBuilder>> _setupTransactionBrokerOptions;

Expand All @@ -46,6 +46,15 @@ public ClickHouseContextOptionsBuilder<TContext> WithCommandExecutionStrategy(
commandExecutionStrategy);
}

public ClickHouseContextOptionsBuilder<TContext> WithCommandExecutionListener(
IClickHouseCommandExecutionListener commandExecutionListener)
{
return WithPropertyValue(
builder => builder._commandExecutionListener,
(builder, value) => builder._commandExecutionListener = value,
commandExecutionListener);
}

public ClickHouseContextOptionsBuilder<TContext> WithHttpClientFactory(
IHttpClientFactory httpClientFactory,
string httpClientName)
Expand Down Expand Up @@ -127,7 +136,7 @@ internal ClickHouseContextOptionsBuilder<TContext> WithFacadeFactory(
}

internal ClickHouseContextOptionsBuilder<TContext> WithConnectionBrokerProvider(
Func<ClickHouseConnection, ICommandExecutionStrategy, IClickHouseConnectionBroker> connectionBrokerProvider)
Func<ConnectionBrokerParameters, IClickHouseConnectionBroker> connectionBrokerProvider)
{
ExceptionHelpers.ThrowIfNull(connectionBrokerProvider);

Expand Down Expand Up @@ -169,6 +178,7 @@ protected override ClickHouseContextOptions<TContext> BuildCore()
FacadeFactory = _facadeFactory.NotNullOrThrow(),
ConnectionBrokerProvider = _connectionBrokerProvider.NotNullOrThrow(),
CommandExecutionStrategy = _commandExecutionStrategy.OrElseValue(CommandExecutionStrategy.Default),
CommandExecutionListener = _commandExecutionListener.OrElseValue(null),
TransactionBrokerOptions = transactionBrokerOptions,
ParametersInBody = _parametersInBody.OrDefault(),
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
using ClickHouse.Client.ADO;

namespace ClickHouse.Facades;
namespace ClickHouse.Facades;

public abstract class ClickHouseContextFactory<TContext> : IClickHouseContextFactory<TContext>
where TContext : ClickHouseContext<TContext>, new()
{
private ClickHouseFacadeFactory<TContext> _facadeFactory = null!;

private Func<ClickHouseConnection, ICommandExecutionStrategy, IClickHouseConnectionBroker>
private Func<ConnectionBrokerParameters, IClickHouseConnectionBroker>
_connectionBrokerProvider = null!;

internal ClickHouseContextFactory<TContext> Setup(
ClickHouseFacadeFactory<TContext> facadeFactory,
Func<ClickHouseConnection, ICommandExecutionStrategy, IClickHouseConnectionBroker> connectionBrokerProvider)
Func<ConnectionBrokerParameters, IClickHouseConnectionBroker> connectionBrokerProvider)
{
_facadeFactory = facadeFactory ?? throw new ArgumentNullException(nameof(facadeFactory));
_connectionBrokerProvider = connectionBrokerProvider
Expand Down
4 changes: 1 addition & 3 deletions src/ClickHouse.Facades/Setup/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,7 @@ public static IServiceCollection AddClickHouseContext<TContext, TContextFactory>
.CreateInstance<TContextFactory>(serviceProvider)
.Setup(
serviceProvider.GetRequiredService<ClickHouseFacadeFactory<TContext>>(),
(connection, commandExecutionStrategy) => new ClickHouseConnectionBroker(
connection,
commandExecutionStrategy)),
brokerParameters => new ClickHouseConnectionBroker(brokerParameters)),
factoryLifetime);

services.Add(descriptor);
Expand Down

0 comments on commit db5a010

Please sign in to comment.