Table of Contents

Aggregates

Return a single scalar value — COUNT, SUM, AVG, MIN, MAX — from your store. A count or aggregate runs over the whole table (minus soft-deleted rows when soft-delete is declared) and takes only a CancellationToken[InquiryWhere] is not honored on a count or aggregate. For a conditional yes/no test use [InquiryExists] with [InquiryWhere] (see Existence checks below).

You write

using Inquiry.Stores;

public partial class ProductStore : InquiryStore<Product>
{
    [InquiryCount]
    public partial Task<long> CountAsync(CancellationToken ct = default);

    [InquiryAggregate(AggregateFunction.Sum, "UnitsInStock")]
    public partial Task<int?> TotalStockAsync(CancellationToken ct = default);

    [InquiryAggregate(AggregateFunction.Avg, "UnitPrice")]
    public partial Task<decimal?> AverageUnitPriceAsync(CancellationToken ct = default);
}

The generator emits

private const string _sqlCount = "SELECT COUNT(*) FROM \"Products\"";
private const string _sqlAgg_TotalStockAsync       = "SELECT SUM(\"UnitsInStock\") FROM \"Products\"";
private const string _sqlAgg_AverageUnitPriceAsync = "SELECT AVG(\"UnitPrice\") FROM \"Products\"";

Each aggregate routes through ExecuteScalarAsync<T> — the return type drives how the result is converted.

Existence checks

[InquiryExists] returns Task<bool> — the EXISTS / EF .AnyAsync() analog. It short-circuits at the first match, so it's cheaper than a COUNT(*) > 0. Apply zero or more [InquiryWhere] criteria (exactly as on a predicate select); with none, it tests whether the table has any row at all.

[InquiryExists]
public partial Task<bool> AnyAsync(CancellationToken ct = default);

[InquiryExists]
[InquiryWhere("Name")]
public partial Task<bool> ExistsByNameAsync(string name, CancellationToken ct = default);
private const string _sqlExists_AnyAsync =
    "SELECT CASE WHEN EXISTS(SELECT 1 FROM \"Products\") THEN 1 ELSE 0 END";
private const string _sqlExists_ExistsByNameAsync =
    "SELECT CASE WHEN EXISTS(SELECT 1 FROM \"Products\" WHERE \"Name\" = @Name) THEN 1 ELSE 0 END";

The CASE WHEN EXISTS(…) THEN 1 ELSE 0 END form is portable across SQLite / SQL Server / PostgreSQL / MySQL (Oracle appends FROM DUAL); the resulting 1/0 is coerced to bool. Like the aggregates, the inner test composes the active-row filter — a soft-deleted or globally-filtered row doesn't count as existing.

See also