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