< Summary

Information
Class: ArturRios.Mediator.Query.QueryMediator
Assembly: ArturRios.Mediator
File(s): /home/ci/agent/workspace/dotnet-mediator-docs_main/app/src/Query/QueryMediator.cs
Line coverage
100%
Covered lines: 25
Uncovered lines: 0
Coverable lines: 25
Total lines: 147
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage
100%
Covered methods: 5
Fully covered methods: 5
Total methods: 5
Method coverage: 100%
Full method coverage: 100%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
ExecutePaginatedQuery(...)100%11100%
ExecutePaginatedQueryAsync()100%11100%
ExecuteQuery(...)100%11100%
ExecuteQueryAsync()100%11100%

File(s)

/home/ci/agent/workspace/dotnet-mediator-docs_main/app/src/Query/QueryMediator.cs

#LineLine coverage
 1using ArturRios.Mediator.Query.Interfaces;
 2using ArturRios.Output;
 3using Microsoft.Extensions.DependencyInjection;
 4
 5namespace ArturRios.Mediator.Query;
 6
 7/// <summary>
 8/// Dispatches queries to their registered handlers. For each call a new dependency
 9/// injection scope is created, the matching handler is resolved from it, and the
 10/// handler is invoked. Supports both single-result and paginated queries.
 11/// </summary>
 12/// <remarks>
 13/// Register this mediator and the query handlers in your dependency injection container.
 14/// Because a fresh scope is created per execution, scoped dependencies of a handler
 15/// (such as a database context) are isolated to a single query execution.
 16/// </remarks>
 17/// <param name="scopeFactory">
 18/// The factory used to create a dependency injection scope for resolving handlers.
 19/// </param>
 3620public class QueryMediator(IServiceScopeFactory scopeFactory)
 21{
 22    /// <summary>
 23    /// Resolves the synchronous paginated handler for the given query and executes it.
 24    /// </summary>
 25    /// <typeparam name="TQuery">The query type to execute.</typeparam>
 26    /// <typeparam name="TOutput">The type of the items in the paginated result.</typeparam>
 27    /// <param name="query">The query instance to execute, including the requested page metadata.</param>
 28    /// <returns>The <see cref="PaginatedOutput{T}"/> returned by the resolved handler.</returns>
 29    /// <exception cref="ArgumentNullException"><paramref name="query"/> is <see langword="null"/>.</exception>
 30    /// <exception cref="InvalidOperationException">
 31    /// Thrown when no <see cref="IPaginatedQueryHandler{TQuery, TOutput}"/> is registered for the
 32    /// requested query and output types.
 33    /// </exception>
 34    public PaginatedOutput<TOutput> ExecutePaginatedQuery<TQuery, TOutput>(TQuery query)
 35        where TQuery : BaseQuery
 36        where TOutput : QueryOutput
 37    {
 438        ArgumentNullException.ThrowIfNull(query);
 39
 340        using var scoped = scopeFactory.CreateScope();
 41
 342        var handler = scoped.ServiceProvider.GetRequiredService<IPaginatedQueryHandler<TQuery, TOutput>>();
 43
 244        return handler.Handle(query);
 245    }
 46
 47    /// <summary>
 48    /// Resolves the asynchronous paginated handler for the given query and executes it.
 49    /// </summary>
 50    /// <typeparam name="TQuery">The query type to execute.</typeparam>
 51    /// <typeparam name="TOutput">The type of the items in the paginated result.</typeparam>
 52    /// <param name="query">The query instance to execute, including the requested page metadata.</param>
 53    /// <param name="cancellationToken">Cancels the execution, and the dispatch itself.</param>
 54    /// <returns>
 55    /// A task that resolves to the <see cref="PaginatedOutput{T}"/> returned by the resolved handler.
 56    /// </returns>
 57    /// <exception cref="ArgumentNullException"><paramref name="query"/> is <see langword="null"/>.</exception>
 58    /// <exception cref="InvalidOperationException">
 59    /// Thrown when no <see cref="IPaginatedQueryHandlerAsync{TQuery, TOutput}"/> is registered for the
 60    /// requested query and output types.
 61    /// </exception>
 62    /// <exception cref="OperationCanceledException">
 63    /// <paramref name="cancellationToken"/> was already canceled. The check happens before the scope is
 64    /// created, so a canceled dispatch costs nothing.
 65    /// </exception>
 66    public async Task<PaginatedOutput<TOutput>> ExecutePaginatedQueryAsync<TQuery, TOutput>(
 67        TQuery query,
 68        CancellationToken cancellationToken = default)
 69        where TQuery : BaseQuery
 70        where TOutput : QueryOutput
 71    {
 972        ArgumentNullException.ThrowIfNull(query);
 873        cancellationToken.ThrowIfCancellationRequested();
 74
 75        // Disposed asynchronously: a scoped dependency that only implements IAsyncDisposable makes a
 76        // synchronous Dispose throw, after the handler has already run.
 777        var scoped = scopeFactory.CreateAsyncScope();
 778        await using var scopeDisposal = scoped.ConfigureAwait(false);
 79
 780        var handler = scoped.ServiceProvider.GetRequiredService<IPaginatedQueryHandlerAsync<TQuery, TOutput>>();
 81
 782        return await handler.HandleAsync(query, cancellationToken).ConfigureAwait(false);
 783    }
 84
 85    /// <summary>
 86    /// Resolves the synchronous single-result handler for the given query and executes it.
 87    /// </summary>
 88    /// <typeparam name="TQuery">The query type to execute.</typeparam>
 89    /// <typeparam name="TOutput">The type of the data payload produced by the handler.</typeparam>
 90    /// <param name="query">The query instance to execute.</param>
 91    /// <returns>The <see cref="DataOutput{T}"/> returned by the resolved handler.</returns>
 92    /// <exception cref="ArgumentNullException"><paramref name="query"/> is <see langword="null"/>.</exception>
 93    /// <exception cref="InvalidOperationException">
 94    /// Thrown when no <see cref="IQueryHandler{TQuery, TOutput}"/> is registered for the
 95    /// requested query and output types.
 96    /// </exception>
 97    public DataOutput<TOutput?> ExecuteQuery<TQuery, TOutput>(TQuery query)
 98        where TQuery : BaseQuery
 99        where TOutput : QueryOutput
 100    {
 4101        ArgumentNullException.ThrowIfNull(query);
 102
 3103        using var scoped = scopeFactory.CreateScope();
 104
 3105        var handler = scoped.ServiceProvider.GetRequiredService<IQueryHandler<TQuery, TOutput>>();
 106
 2107        return handler.Handle(query);
 2108    }
 109
 110    /// <summary>
 111    /// Resolves the asynchronous single-result handler for the given query and executes it.
 112    /// </summary>
 113    /// <typeparam name="TQuery">The query type to execute.</typeparam>
 114    /// <typeparam name="TOutput">The type of the data payload produced by the handler.</typeparam>
 115    /// <param name="query">The query instance to execute.</param>
 116    /// <param name="cancellationToken">Cancels the execution, and the dispatch itself.</param>
 117    /// <returns>
 118    /// A task that resolves to the <see cref="DataOutput{T}"/> returned by the resolved handler.
 119    /// </returns>
 120    /// <exception cref="ArgumentNullException"><paramref name="query"/> is <see langword="null"/>.</exception>
 121    /// <exception cref="InvalidOperationException">
 122    /// Thrown when no <see cref="IQueryHandlerAsync{TQuery, TOutput}"/> is registered for the
 123    /// requested query and output types.
 124    /// </exception>
 125    /// <exception cref="OperationCanceledException">
 126    /// <paramref name="cancellationToken"/> was already canceled. The check happens before the scope is
 127    /// created, so a canceled dispatch costs nothing.
 128    /// </exception>
 129    public async Task<DataOutput<TOutput?>> ExecuteQueryAsync<TQuery, TOutput>(
 130        TQuery query,
 131        CancellationToken cancellationToken = default)
 132        where TQuery : BaseQuery
 133        where TOutput : QueryOutput
 134    {
 9135        ArgumentNullException.ThrowIfNull(query);
 8136        cancellationToken.ThrowIfCancellationRequested();
 137
 138        // Disposed asynchronously: a scoped dependency that only implements IAsyncDisposable makes a
 139        // synchronous Dispose throw, after the handler has already run.
 7140        var scoped = scopeFactory.CreateAsyncScope();
 7141        await using var scopeDisposal = scoped.ConfigureAwait(false);
 142
 7143        var handler = scoped.ServiceProvider.GetRequiredService<IQueryHandlerAsync<TQuery, TOutput>>();
 144
 7145        return await handler.HandleAsync(query, cancellationToken).ConfigureAwait(false);
 7146    }
 147}