@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.
61 lines • 3.04 kB
TypeScript
import type { RelationSpec } from './filter_spec.js';
import type { ComputedFields } from './types.js';
/**
* The structural slice of a booted Lucid relation the aggregate-subquery
* compiler reads. A real `@adonisjs/lucid` `HasMany` / `ManyToMany` relation
* satisfies it — declared locally so this module never hard-imports Lucid. The
* key-column fields are optional because they differ by relation kind
* (one-to-many exposes `foreignKeyColumnName`; many-to-many exposes the pivot
* fields), and only the relevant ones are read per kind.
*/
export interface LucidRelationLike {
/** Relation kind — `'hasMany'` / `'manyToMany'` are the to-many kinds we correlate. */
type: string;
/** Compute the relation's key columns from the naming strategy (idempotent). */
boot(): void;
/** The related (child) model — its `table` is the child table name. */
relatedModel(): {
table?: string;
};
foreignKeyColumnName?: string;
localKeyColumnName?: string;
relatedKeyColumnName?: string;
pivotTable?: string;
pivotForeignKey?: string;
pivotRelatedForeignKey?: string;
}
/**
* The structural slice of a Lucid model the aggregate discovery reads: its table
* name and a relation accessor. `$getRelation` is typed with `any` for the same
* reason `QueryBuilderLike.whereHas` is — Lucid types it with a generic
* literal-union `Name`, and `string` is not assignable to that union, so a
* narrower signature would make every real model fail to satisfy this interface.
*/
export interface LucidModelLike {
table?: string;
$getRelation(name: any): LucidRelationLike | undefined;
}
/**
* Discover to-many aggregate {@link ComputedSource}s from a Lucid model's
* relation metadata, for the relations the spec whitelisted. For each declared
* to-many relation (hasMany / manyToMany) this synthesises:
*
* - `<rel>.$count` — always;
* - `<rel>.$sum|$avg|$min|$max.<col>` — one per column the relation's
* {@link RelationSpec.aggregates} declares (Lucid does not reflect SQL column
* types, so the dev asserts numeric-ness by listing the column there).
*
* To-one relations (belongsTo / hasOne) are excluded. The whole thing degrades
* gracefully: a relation that is not on the model, is to-one, or cannot be
* booted (e.g. no DB adapter yet) is simply skipped, and a model without the
* introspection capability yields an empty map — so aggregates activate only
* when the metadata is actually available.
*
* The result is merged into the spec's `computed` map, so aggregate fields ARE
* computed fields with auto-generated correlated-subquery sources — they reuse
* the exact same runner routing, allow-list bypass (their discovery IS their
* allow-list, gated by the relation whitelist), injection-safe value binding,
* and codegen surfacing.
*/
export declare function discoverAggregateSources(model: LucidModelLike | undefined, relations: Readonly<Record<string, RelationSpec>>): ComputedFields;
//# sourceMappingURL=aggregate.d.ts.map