@adonis-agora/filter
Version:
Server-side query filtering/sorting/pagination for AdonisJS — Spatie-style input, a Lucid adapter, and field allow-listing. Part of the Agora ecosystem.
87 lines • 4.94 kB
TypeScript
import { type ApplyFromRequestOptions, type FilterRequestContext } from './apply_from_request.js';
import { type FilterClass } from './filter_class.js';
import type { FilterSpec } from './filter_spec.js';
import type { ResolvedPagination } from './runner.js';
/**
* The static slice of a Lucid query-builder class we register onto: Adonis'
* `Macroable.macro(name, fn)` adds `fn` to the builder prototype so every query
* instance gains the method. Declared structurally so this module never
* hard-imports `@adonisjs/lucid` at runtime (the provider passes the real
* `ModelQueryBuilder` in) — matching how the rest of the package stays
* framework-free.
*/
export interface MacroableQueryBuilder {
macro(name: string, fn: (this: unknown, ...args: never[]) => unknown): void;
}
/**
* Register the chainable filter macros onto a Lucid query-builder class (the
* method-call form of {@link applyFilterFromRequest}). Call this from a provider's
* `boot()` with `ModelQueryBuilder` (from `@adonisjs/lucid/orm`); the
* `@adonis-agora/filter` provider does exactly that.
*
* Two macros are added:
*
* - `query.applyFilterFromRequest(spec, ctx, options?)` — applies the spec's
* server scope + allow-listed filter/sort/search and returns the query so it
* chains (`User.query().applyFilterFromRequest(spec, ctx).orderBy(...)`). The
* resolved pagination is dropped; use `filterPaginate` (or the free function)
* when you need it.
* - `query.filterPaginate(spec, ctx, options?)` — applies the same and then
* `paginate(page, size)` with the resolved pagination, returning Lucid's
* paginator (`await User.query().filterPaginate(spec, ctx)`).
*
* Idempotent enough to call once at boot; calling twice re-defines the macros to
* the same implementations.
*/
export declare function registerFilterMacros(ModelQueryBuilder: MacroableQueryBuilder): void;
declare module '@adonisjs/lucid/types/model' {
interface ModelQueryBuilderContract<Model extends LucidModel, Result = InstanceType<Model>> {
/**
* Apply a {@link FilterSpec} from the request context (server scope +
* allow-listed filter/sort/search) and return the query for chaining — the
* method form of the free `applyFilterFromRequest`. Pagination is resolved
* but not returned here; use {@link filterPaginate} when you need it.
*
* `ctx` is optional: when omitted, the active `HttpContext` is read from
* AsyncLocalStorage (`HttpContext.getOrFail()`). Pass it explicitly outside a
* request scope (e.g. a job/command), where there is no ambient context.
*/
applyFilterFromRequest(spec: FilterSpec, ctx?: FilterRequestContext, options?: ApplyFromRequestOptions): this;
/**
* The same for a filter **class**: resolved through the IoC container (so `@inject()` works),
* `setup()` first, then every request key the class owns a method for.
*
* Resolution is async, so this returns a promise — of the resolved `{ page, size }`, not of
* the builder (a Lucid builder is thenable, so awaiting a promise of one would run the query).
* The builder is the one you called it on, still yours to compose on:
*
* ```ts
* const query = User.query().whereNull('deletedAt')
* const { page, size } = await query.applyFilterFromRequest(UserFilter)
* return query.preload('team').paginate(page, size)
* ```
*/
applyFilterFromRequest(filter: FilterClass, ctx?: FilterRequestContext, options?: ApplyFromRequestOptions): Promise<ResolvedPagination>;
/**
* Apply a {@link FilterSpec} from the request context and paginate with the
* resolved `{ page, size }`, returning Lucid's paginator — filter + paginate
* in one terminal call. `ctx` is optional (see {@link applyFilterFromRequest}).
*/
filterPaginate(spec: FilterSpec, ctx?: FilterRequestContext, options?: ApplyFromRequestOptions): ReturnType<this['paginate']>;
/** The filter-class form of {@link filterPaginate} — async, for the same reason. */
filterPaginate(filter: FilterClass, ctx?: FilterRequestContext, options?: ApplyFromRequestOptions): Promise<Awaited<ReturnType<this['paginate']>>>;
/**
* Page a query that has **already** been filtered (by the model's `filter()` or by the
* `applyFilterFromRequest` macro) with the `{ page, size }` that call resolved — so a
* controller can keep composing on the builder and still page it the way the request asked.
*
* ```ts
* const query = await User.filter(ctx)
* query.whereNotNull('confirmedAt')
* return query.filterPaginate()
* ```
*/
filterPaginate(): ReturnType<this['paginate']>;
}
}
//# sourceMappingURL=lucid_macros.d.ts.map