import type { DocumentByName, GenericDataModel, GenericMutationCtx, GenericQueryCtx, TableNamesInDataModel } from "convex/server";
import type { Key } from "../component/btree.js";
import { type Bound, type Bounds } from "./positions.js";
import type { GenericId, Value as ConvexValue } from "convex/values";
import type { ComponentApi } from "../component/_generated/component.js";
export type RunQueryCtx = {
    runQuery: GenericQueryCtx<GenericDataModel>["runQuery"];
};
export type RunMutationCtx = {
    runMutation: GenericMutationCtx<GenericDataModel>["runMutation"];
};
export type Item<K extends Key, ID extends string> = {
    key: K;
    id: ID;
    sumValue: number;
};
export type { Key, Bound, Bounds };
/**
 * Write data to be aggregated, and read aggregated data.
 *
 * The data structure is effectively a key-value store sorted by key, where the
 * value is an ID and an optional sumValue.
 * 1. The key can be any Convex value (number, string, array, etc.).
 * 2. The ID is a string which should be unique.
 * 3. The sumValue is a number which is aggregated by summing. If not provided,
 *    it's assumed to be zero.
 *
 * Once values have been added to the data structure, you can query for the
 * count and sum of items between a range of keys.
 */
export declare class Aggregate<K extends Key, ID extends string, Namespace extends ConvexValue | undefined = undefined> {
    protected component: ComponentApi;
    constructor(component: ComponentApi);
    /**
     * Counts items between the given bounds.
     */
    count(ctx: RunQueryCtx, ...opts: NamespacedOpts<{
        bounds?: Bounds<K, ID>;
    }, Namespace>): Promise<number>;
    /**
     * Batch version of count() - counts items for multiple bounds in a single call.
     */
    countBatch(ctx: RunQueryCtx, queries: NamespacedOptsBatch<{
        bounds?: Bounds<K, ID>;
    }, Namespace>): Promise<number[]>;
    /**
     * Adds up the sumValue of items between the given bounds.
     */
    sum(ctx: RunQueryCtx, ...opts: NamespacedOpts<{
        bounds?: Bounds<K, ID>;
    }, Namespace>): Promise<number>;
    /**
     * Batch version of sum() - sums items for multiple bounds in a single call.
     */
    sumBatch(ctx: RunQueryCtx, queries: NamespacedOptsBatch<{
        bounds?: Bounds<K, ID>;
    }, Namespace>): Promise<number[]>;
    /**
     * Returns the item at the given offset/index/rank in the order of key,
     * within the bounds. Zero-indexed, so at(0) is the smallest key within the
     * bounds.
     *
     * If offset is negative, it counts from the end of the list, so at(-1) is the
     * item with the largest key within the bounds.
     */
    at(ctx: RunQueryCtx, offset: number, ...opts: NamespacedOpts<{
        bounds?: Bounds<K, ID>;
    }, Namespace>): Promise<Item<K, ID>>;
    /**
     * Batch version of at() - returns items at multiple offsets in a single call.
     */
    atBatch(ctx: RunQueryCtx, queries: NamespacedOptsBatch<{
        offset: number;
        bounds?: Bounds<K, ID>;
    }, Namespace>): Promise<Item<K, ID>[]>;
    /**
     * Returns the rank/offset/index of the given key, within the bounds.
     * Specifically, it returns the index of the first item with
     *
     * - key >= the given key if `order` is "asc" (default)
     * - key <= the given key if `order` is "desc"
     */
    indexOf(ctx: RunQueryCtx, key: K, ...opts: NamespacedOpts<{
        id?: ID;
        bounds?: Bounds<K, ID>;
        order?: "asc" | "desc";
    }, Namespace>): Promise<number>;
    /**
     * @deprecated Use `indexOf` instead.
     */
    offsetOf(ctx: RunQueryCtx, key: K, namespace: Namespace, id?: ID, bounds?: Bounds<K, ID>): Promise<number>;
    /**
     * @deprecated Use `indexOf` instead.
     */
    offsetUntil(ctx: RunQueryCtx, key: K, namespace: Namespace, id?: ID, bounds?: Bounds<K, ID>): Promise<number>;
    /**
     * Gets the minimum item within the given bounds.
     */
    min(ctx: RunQueryCtx, ...opts: NamespacedOpts<{
        bounds?: Bounds<K, ID>;
    }, Namespace>): Promise<Item<K, ID> | null>;
    /**
     * Gets the maximum item within the given bounds.
     */
    max(ctx: RunQueryCtx, ...opts: NamespacedOpts<{
        bounds?: Bounds<K, ID>;
    }, Namespace>): Promise<Item<K, ID> | null>;
    /**
     * Gets a uniformly random item within the given bounds.
     */
    random(ctx: RunQueryCtx, ...opts: NamespacedOpts<{
        bounds?: Bounds<K, ID>;
    }, Namespace>): Promise<Item<K, ID> | null>;
    /**
     * Get a page of items between the given bounds, with a cursor to paginate.
     * Use `iter` to iterate over all items within the bounds.
     */
    paginate(ctx: RunQueryCtx, ...opts: NamespacedOpts<{
        bounds?: Bounds<K, ID>;
        cursor?: string;
        order?: "asc" | "desc";
        pageSize?: number;
    }, Namespace>): Promise<{
        page: Item<K, ID>[];
        cursor: string;
        isDone: boolean;
    }>;
    /**
     * Example usage:
     * ```ts
     * for await (const item of aggregate.iter(ctx, bounds)) {
     *   console.log(item);
     * }
     * ```
     */
    iter(ctx: RunQueryCtx, ...opts: NamespacedOpts<{
        bounds?: Bounds<K, ID>;
        order?: "asc" | "desc";
        pageSize?: number;
    }, Namespace>): AsyncGenerator<Item<K, ID>, void, undefined>;
    /** Write operations. See {@link DirectAggregate} for docstrings. */
    _insert(ctx: RunMutationCtx, namespace: Namespace, key: K, id: ID, summand?: number): Promise<void>;
    _delete(ctx: RunMutationCtx, namespace: Namespace, key: K, id: ID): Promise<void>;
    _replace(ctx: RunMutationCtx, currentNamespace: Namespace, currentKey: K, newNamespace: Namespace, newKey: K, id: ID, summand?: number): Promise<void>;
    _insertIfDoesNotExist(ctx: RunMutationCtx, namespace: Namespace, key: K, id: ID, summand?: number): Promise<void>;
    _deleteIfExists(ctx: RunMutationCtx, namespace: Namespace, key: K, id: ID): Promise<void>;
    _replaceOrInsert(ctx: RunMutationCtx, currentNamespace: Namespace, currentKey: K, newNamespace: Namespace, newKey: K, id: ID, summand?: number): Promise<void>;
    /**
     * (re-)initialize the data structure, removing all items if it exists.
     *
     * Change the maxNodeSize if provided, otherwise keep it the same.
     *   maxNodeSize is how you tune the data structure's width and depth.
     *   Larger values can reduce write contention but increase read latency.
     *   Default is 16.
     * Set rootLazy = false to eagerly compute aggregates on the root node, which
     *   improves aggregation latency at the expense of making all writes contend
     *   with each other, so it's only recommended for read-heavy workloads.
     *   Default is true.
     */
    clear(ctx: RunMutationCtx, ...opts: NamespacedOpts<{
        maxNodeSize?: number;
        rootLazy?: boolean;
    }, Namespace>): Promise<void>;
    /**
     * If rootLazy is false (the default is true but it can be set to false by
     * `clear`), the aggregates data structure writes to a single root node on
     * every insert/delete/replace, which can cause contention.
     *
     * If your data structure has frequent writes, you can reduce contention by
     * calling makeRootLazy, which removes the frequent writes to the root node.
     * With a lazy root node, updates will only contend with other updates to the
     * same shard of the tree. The number of shards is determined by maxNodeSize,
     * so larger maxNodeSize can also help.
     */
    makeRootLazy(ctx: RunMutationCtx, namespace: Namespace): Promise<void>;
    paginateNamespaces(ctx: RunQueryCtx, cursor?: string, pageSize?: number): Promise<{
        page: Namespace[];
        cursor: string;
        isDone: boolean;
    }>;
    iterNamespaces(ctx: RunQueryCtx, pageSize?: number): AsyncGenerator<Namespace, void, undefined>;
    clearAll(ctx: RunMutationCtx & RunQueryCtx, opts?: {
        maxNodeSize?: number;
        rootLazy?: boolean;
    }): Promise<void>;
    makeAllRootsLazy(ctx: RunMutationCtx & RunQueryCtx): Promise<void>;
}
export type DirectAggregateType<K extends Key, ID extends string, Namespace extends ConvexValue | undefined = undefined> = {
    Key: K;
    Id: ID;
    Namespace?: Namespace;
};
type AnyDirectAggregateType = DirectAggregateType<Key, string, ConvexValue | undefined>;
type DirectAggregateNamespace<T extends AnyDirectAggregateType> = "Namespace" extends keyof T ? T["Namespace"] : undefined;
/**
 * A DirectAggregate is an Aggregate where you can insert, delete, and replace
 * items directly, and keys and IDs can be customized.
 *
 * Contrast with TableAggregate, which follows a table with Triggers and
 * computes keys and sumValues from the table's documents.
 */
export declare class DirectAggregate<T extends AnyDirectAggregateType> extends Aggregate<T["Key"], T["Id"], DirectAggregateNamespace<T>> {
    /**
     * Insert a new key into the data structure.
     * The id should be unique.
     * If not provided, the sumValue is assumed to be zero.
     * If the tree does not exist yet, it will be initialized with the default
     * maxNodeSize and lazyRoot=true.
     * If the [key, id] pair already exists, this will throw.
     */
    insert(ctx: RunMutationCtx, args: NamespacedArgs<{
        key: T["Key"];
        id: T["Id"];
        sumValue?: number;
    }, DirectAggregateNamespace<T>>): Promise<void>;
    /**
     * Delete the key with the given ID from the data structure.
     * Throws if the given key and ID do not exist.
     */
    delete(ctx: RunMutationCtx, args: NamespacedArgs<{
        key: T["Key"];
        id: T["Id"];
    }, DirectAggregateNamespace<T>>): Promise<void>;
    /**
     * Update an existing item in the data structure.
     * This is effectively a delete followed by an insert, but it's performed
     * atomically so it's impossible to view the data structure with the key missing.
     */
    replace(ctx: RunMutationCtx, currentItem: NamespacedArgs<{
        key: T["Key"];
        id: T["Id"];
    }, DirectAggregateNamespace<T>>, newItem: NamespacedArgs<{
        key: T["Key"];
        sumValue?: number;
    }, DirectAggregateNamespace<T>>): Promise<void>;
    /**
     * Equivalents to `insert`, `delete`, and `replace` where the item may or may not exist.
     * This can be useful for live backfills:
     * 1. Update live writes to use these methods to write into the new Aggregate.
     * 2. Run a background backfill, paginating over existing data, calling `insertIfDoesNotExist` on each item.
     * 3. Once the backfill is complete, use `insert`, `delete`, and `replace` for live writes.
     * 4. Begin using the Aggregate read methods.
     */
    insertIfDoesNotExist(ctx: RunMutationCtx, args: NamespacedArgs<{
        key: T["Key"];
        id: T["Id"];
        sumValue?: number;
    }, DirectAggregateNamespace<T>>): Promise<void>;
    deleteIfExists(ctx: RunMutationCtx, args: NamespacedArgs<{
        key: T["Key"];
        id: T["Id"];
    }, DirectAggregateNamespace<T>>): Promise<void>;
    replaceOrInsert(ctx: RunMutationCtx, currentItem: NamespacedArgs<{
        key: T["Key"];
        id: T["Id"];
    }, DirectAggregateNamespace<T>>, newItem: NamespacedArgs<{
        key: T["Key"];
        sumValue?: number;
    }, DirectAggregateNamespace<T>>): Promise<void>;
}
export type TableAggregateType<K extends Key, DataModel extends GenericDataModel, TableName extends TableNamesInDataModel<DataModel>, Namespace extends ConvexValue | undefined = undefined> = {
    Key: K;
    DataModel: DataModel;
    TableName: TableName;
    Namespace?: Namespace;
};
type AnyTableAggregateType = TableAggregateType<Key, GenericDataModel, TableNamesInDataModel<GenericDataModel>, ConvexValue | undefined>;
type TableAggregateNamespace<T extends AnyTableAggregateType> = "Namespace" extends keyof T ? T["Namespace"] : undefined;
type TableAggregateDocument<T extends AnyTableAggregateType> = DocumentByName<T["DataModel"], T["TableName"]>;
type TableAggregateId<T extends AnyTableAggregateType> = GenericId<T["TableName"]>;
type TableAggregateTrigger<Ctx, T extends AnyTableAggregateType> = Trigger<Ctx, T["DataModel"], T["TableName"]>;
export declare class TableAggregate<T extends AnyTableAggregateType> extends Aggregate<T["Key"], GenericId<T["TableName"]>, TableAggregateNamespace<T>> {
    private options;
    constructor(component: ComponentApi, options: {
        sortKey: (d: TableAggregateDocument<T>) => T["Key"];
        sumValue?: (d: TableAggregateDocument<T>) => number;
    } & (undefined extends TableAggregateNamespace<T> ? {
        namespace?: (d: TableAggregateDocument<T>) => TableAggregateNamespace<T>;
    } : {
        namespace: (d: TableAggregateDocument<T>) => TableAggregateNamespace<T>;
    }));
    insert(ctx: RunMutationCtx, doc: TableAggregateDocument<T>): Promise<void>;
    delete(ctx: RunMutationCtx, doc: TableAggregateDocument<T>): Promise<void>;
    replace(ctx: RunMutationCtx, oldDoc: TableAggregateDocument<T>, newDoc: TableAggregateDocument<T>): Promise<void>;
    insertIfDoesNotExist(ctx: RunMutationCtx, doc: TableAggregateDocument<T>): Promise<void>;
    deleteIfExists(ctx: RunMutationCtx, doc: TableAggregateDocument<T>): Promise<void>;
    replaceOrInsert(ctx: RunMutationCtx, oldDoc: TableAggregateDocument<T>, newDoc: TableAggregateDocument<T>): Promise<void>;
    /**
     * Returns the rank/offset/index of the given document, within the bounds.
     * This differs from `indexOf` in that it take the document rather than key.
     * Specifically, it returns the index of the first item with
     *
     * - key >= the given doc's key if `order` is "asc" (default)
     * - key <= the given doc's key if `order` is "desc"
     */
    indexOfDoc(ctx: RunQueryCtx, doc: TableAggregateDocument<T>, opts?: {
        id?: TableAggregateId<T>;
        bounds?: Bounds<T["Key"], TableAggregateId<T>>;
        order?: "asc" | "desc";
    }): Promise<number>;
    trigger<Ctx extends RunMutationCtx>(): TableAggregateTrigger<Ctx, T>;
    idempotentTrigger<Ctx extends RunMutationCtx>(): TableAggregateTrigger<Ctx, T>;
}
export type Trigger<Ctx, DataModel extends GenericDataModel, TableName extends TableNamesInDataModel<DataModel>> = (ctx: Ctx, change: Change<DataModel, TableName>) => Promise<void>;
export type Change<DataModel extends GenericDataModel, TableName extends TableNamesInDataModel<DataModel>> = {
    id: GenericId<TableName>;
} & ({
    operation: "insert";
    oldDoc: null;
    newDoc: DocumentByName<DataModel, TableName>;
} | {
    operation: "update";
    oldDoc: DocumentByName<DataModel, TableName>;
    newDoc: DocumentByName<DataModel, TableName>;
} | {
    operation: "delete";
    oldDoc: DocumentByName<DataModel, TableName>;
    newDoc: null;
});
export declare function btreeItemToAggregateItem<K extends Key, ID extends string>({ k, s, }: {
    k: unknown;
    s: number;
}): Item<K, ID>;
export type NamespacedArgs<Args, Namespace> = (Args & {
    namespace: Namespace;
}) | (Namespace extends undefined ? Args : never);
export type NamespacedOpts<Opts, Namespace> = [{
    namespace: Namespace;
} & Opts] | (undefined extends Namespace ? [Opts?] : never);
export type NamespacedOptsBatch<Opts, Namespace> = Array<undefined extends Namespace ? Opts : {
    namespace: Namespace;
} & Opts>;
//# sourceMappingURL=index.d.ts.map