/** * Knex-style chainable query builder for the vector storage battery. * * @module @nhtio/adk/batteries/vector/builder */ import type { VectorRecord, VectorMatch, VectorConsistency } from "./types"; import type { SearchPlan, UpsertPlan, DeletePlan } from "./plan"; import type { VectorFilter, FilterOperator } from "./filters"; /** * The execution backend a {@link VectorQueryBuilder} drains its assembled plans into. Implemented * by the vector store; the builder produces {@link SearchPlan}/{@link UpsertPlan}/{@link DeletePlan} * objects and hands them here rather than touching the adapter directly. */ export interface PlanSink { /** Executes an assembled search plan and resolves the matching records. */ executeSearch(plan: SearchPlan): Promise; /** Executes an assembled upsert plan. */ executeUpsert(plan: UpsertPlan): Promise; /** Executes an assembled delete plan. */ executeDelete(plan: DeletePlan): Promise; } /** * An argument accepted by {@link VectorQueryBuilder.select} — a field name (or `'*'`), a * `[field, config]` tuple, or a `{ field: config }` map selecting and configuring projected fields. */ export type SelectArg = string | [ string, Record ] | Record | true>; /** * A callback that receives a fresh filter-only builder, used to express a parenthesized group of * conditions — `A AND (B OR C)`, `NOT (…)`, and arbitrary nesting. The callback mutates the builder * in place (knex-style); its accumulated conditions become a single nested `VectorFilter`. * * @see {@link FilterBuilder.where} */ export type FilterCallback = (qb: FilterBuilder) => void; /** * The where-clause surface of the query builder, factored out so a grouping callback can be handed * a builder that only exposes filter methods (not `near*`/`select`/`limit` or the terminals). * * Chained `.where()` ANDs; the first `.orWhere()` snapshots the accumulated AND-list into the first * branch of an OR (knex semantics). Any of the where-methods also accepts a {@link FilterCallback} * to open a nested group, letting AND and OR mix to any depth. */ declare class FilterBuilder { #private; protected andConditions: VectorFilter[]; protected orBranches: VectorFilter[][]; /** Build a nested group by running `cb` against a fresh {@link FilterBuilder}. */ protected runGroup(cb: FilterCallback): VectorFilter | undefined; /** Add a parenthesized condition group via a {@link FilterCallback}; ANDed with prior conditions. */ where(cb: FilterCallback): this; /** Add a condition `field op value` (or `field = value` when `c` is omitted); ANDed with prior conditions. */ where(a: string, b?: unknown, c?: unknown): this; /** Add equality conditions for each key of `obj`; ANDed with prior conditions. */ where(obj: Record): this; /** Alias of {@link FilterBuilder.where} (callback group form) for readability in a chain. */ andWhere(cb: FilterCallback): this; /** Alias of {@link FilterBuilder.where} (`field op value` form) for readability in a chain. */ andWhere(a: string, b?: unknown, c?: unknown): this; /** Alias of {@link FilterBuilder.where} (object form) for readability in a chain. */ andWhere(obj: Record): this; /** Open a new OR branch holding a parenthesized condition group via a {@link FilterCallback}. */ orWhere(cb: FilterCallback): this; /** Open a new OR branch holding the equality condition `field = value`. */ orWhere(field: string, value: unknown): this; /** Open a new OR branch holding the condition `field op value`. */ orWhere(field: string, op: FilterOperator, value: unknown): this; /** AND a negated parenthesized condition group via a {@link FilterCallback}. */ whereNot(cb: FilterCallback): this; /** AND the negated equality condition `field != value`. */ whereNot(field: string, value: unknown): this; /** Open a new OR branch holding a negated parenthesized condition group via a {@link FilterCallback}. */ orWhereNot(cb: FilterCallback): this; /** Open a new OR branch holding the negated equality condition `field != value`. */ orWhereNot(field: string, value: unknown): this; /** AND the condition that `field`'s value is one of `values`. */ whereIn(field: string, values: unknown[]): this; /** AND the condition that `field`'s value is none of `values`. */ whereNotIn(field: string, values: unknown[]): this; /** AND the condition that `field` is absent (does not exist). */ whereNull(field: string): this; /** AND the condition that `field` is present (exists). */ whereExists(field: string): this; /** AND a raw, adapter-dialect filter expressed as SQL text plus positional `bindings`. */ whereRaw(sql: string, bindings?: unknown[]): this; /** AND a raw, adapter-dialect filter expressed as a `{ $dialect, $raw, $bindings }` object. */ whereRaw(rawObj: { $dialect: string; $raw: unknown; $bindings?: unknown[]; }): this; protected buildFilter(): VectorFilter | undefined; protected extractIdsFromFilter(): string[]; } declare class VectorQueryBuilder extends FilterBuilder implements PromiseLike { #private; constructor(sink: PlanSink, collection: string, defaultTopK: number); /** * Search by nearest neighbours to a client-supplied query `vector`. Mutually exclusive with the * other `near*` clauses. * * @throws {@link @nhtio/adk/batteries!E_VECTOR_STORE_QUERY_CONFLICT} when a `near*` clause is already set. */ nearVector(vector: number[]): this; /** * Search by nearest neighbours to `text`, embedded server-side by the backend. Mutually exclusive * with the other `near*` clauses. * * @throws {@link @nhtio/adk/batteries!E_VECTOR_STORE_QUERY_CONFLICT} when a `near*` clause is already set. */ nearText(text: string): this; /** * Search by nearest neighbours to the stored vector of the record with the given `id`. Mutually * exclusive with the other `near*` clauses. * * @throws {@link @nhtio/adk/batteries!E_VECTOR_STORE_QUERY_CONFLICT} when a `near*` clause is already set. */ nearId(id: string): this; /** * Declare which fields each match projects (id / vector / document / metadata). Required before a * search terminal runs. Accepts {@link SelectArg}s: `'*'`, field names, `[field, config]` tuples, * or `{ field: config }` maps. */ select(...args: SelectArg[]): this; /** Cap the number of matches returned (the search `topK`). */ limit(n: number): this; /** Skip the first `n` matches before returning results. */ offset(n: number): this; /** * Per-operation read-after-write override for the terminal `.upsert()` / `.delete()`. * Universal across adapters: strongly-consistent backends ignore it (no-op), so a chain * written for an eventually-consistent backend keeps working verbatim when the adapter is * swapped. Precedence: this > the store's `consistency` option > the adapter's declared * `capabilities.consistency.default`. See {@link VectorConsistency}. */ consistency(mode: VectorConsistency): this; then(onfulfilled?: ((value: VectorMatch[]) => TR1 | PromiseLike) | null, onrejected?: ((reason: unknown) => TR2 | PromiseLike) | null): PromiseLike; /** Terminal: insert or replace `records` in the collection. */ upsert(records: VectorRecord[]): Promise; /** Terminal: delete records matching the accumulated filter (or the `id IN [...]` fast path). */ delete(): Promise; } export { VectorQueryBuilder, FilterBuilder };