--- paths: - "*QueryableProvider*.cs" - "*AlterQueryable*.cs" - "*DynamicQuery*.cs" - "*Interceptor*.cs" --- # Dynamic Queries — The Default Query Pattern **99% of queries should be dynamic queries.** They provide pagination, filtering, sorting, grouping, and aggregation for free. ## The Standard Pattern: IQueryableProviderOverride ```csharp // File: Features/Orders/OrderQueryableProvider.cs public class OrderQueryableProvider : IQueryableProviderOverride { private readonly AppDbContext _db; public OrderQueryableProvider(AppDbContext db) => _db = db; public Task> GetQueryableAsync(object query, CancellationToken ct = default) => Task.FromResult(_db.Orders.AsQueryable()); } ``` Registration — one line: ```csharp builder.Services.AddDynamicQueryWithProvider(); ``` This automatically creates endpoints with full filtering, sorting, and pagination support. ## Required Dependencies These must be registered before `AddSvrntyCqrs`: ```csharp builder.Services.AddTransient(); builder.Services.AddTransient(); ``` ## Alter Queryable Services (Security Filters, Tenant Isolation) Use `IAlterQueryableService` to modify the queryable before execution — for security filters, tenant isolation, default ordering, etc. ```csharp public class OrderTenantFilter : IAlterQueryableService { private readonly ITenantContext _tenant; public OrderTenantFilter(ITenantContext tenant) => _tenant = tenant; public Task> AlterQueryableAsync( IQueryable query, IDynamicQuery dynamicQuery, CancellationToken ct = default) { return Task.FromResult(query.Where(o => o.TenantId == _tenant.Id)); } } ``` Registration: ```csharp builder.Services.AddAlterQueryable(); ``` ## Interceptors Up to 5 interceptors per query type. These modify the PoweredSoft DynamicQuery criteria at query build time. ```csharp builder.Services.AddDynamicQueryInterceptor(); ``` ## Source to Destination Mapping When the entity type differs from the DTO: ```csharp // Provider returns the source entity queryable public class OrderQueryableProvider : IQueryableProviderOverride { ... } // Registration maps source -> destination builder.Services.AddDynamicQueryWithProvider(); ``` ## Key Interfaces ```csharp IQueryableProvider Task> GetQueryableAsync(object query, CancellationToken ct) IQueryableProviderOverride : IQueryableProvider // Marker interface — same method, signals override registration IAlterQueryableService Task> AlterQueryableAsync(IQueryable query, IDynamicQuery dynamicQuery, CancellationToken ct) ```