import type { Client } from "../abstract/Client";
import type { Cluster } from "../abstract/Cluster";
import type { Shard } from "../abstract/Shard";
import type { Table } from "../types";
import type { Inverse } from "./Inverse";
import type { ShardAffinity } from "./ShardAffinity";
import type { VC } from "./VC";
/**
 * Knows how to locate Shard(s) based on various inputs. In some contexts, we
 * expect exactly one Shard returned, and in other contexts, multiple Shards are
 * okay.
 */
export declare class ShardLocator<TClient extends Client, TTable extends Table, TField extends string> {
    private cluster;
    private entName;
    private shardAffinity;
    private uniqueKey;
    private inverses;
    private globalShard;
    private idAndShardAffinity;
    constructor({ cluster, entName, shardAffinity, uniqueKey, inverses }: {
        cluster: Cluster<TClient>;
        entName: string;
        shardAffinity: ShardAffinity<TField>;
        uniqueKey: readonly string[] | undefined;
        inverses: ReadonlyArray<Inverse<TClient, TTable>>;
    });
    /**
     * Called in a context when we must know exactly 1 Shard to work with (e.g.
     * INSERT, UPSERT etc.). If op === "insert" (fallback to random Shard), then
     * returns a random Shard in case when it can't infer the Shard number from
     * the input (used in e.g. INSERT operations); otherwise throws ShardError
     * (happens in e.g. UPSERT).
     *
     * The "randomness" of the "random Shard" is deterministic by the Ent's unique
     * key (if it's defined), so Ents with the same unique key will map to the
     * same "random" Shard (considering the total number of discovered Shards is
     * unchanged). Notice that this logic applies at INSERT time: since we often
     * times add Shards to the Cluster, we can't rely on it consistently at SELECT
     * time (but relying at INSERT time is more or less fine: it protects against
     * most of "unique key violation" problems, although still doesn't prevent all
     * of them for a fraction of the second when the number of Shards has just
     * been changed).
     */
    singleShardForInsert(input: Record<string, unknown>, op: "insert" | "upsert"): Promise<Shard<TClient>>;
    /**
     * Called in a context when multiple Shards may be involved, e.g. when
     * selecting Ents referred by some Inverses. May also return the empty list of
     * Shards when, although there are fields with Inverses in input (i.e. the
     * filtering is correct), there are no Inverse rows existing in the database.
     */
    multiShardsFromInput(vc: VC, input: Record<string, unknown>, op: string): Promise<Array<Shard<TClient>>>;
    /**
     * A wrapper for Cluster#shard() which injects Ent name to the exception (in
     * case of e.g. "Cannot locate Shard" exception). This is just a convenience
     * for debugging.
     *
     * If this method returns null, that means the caller should give up trying to
     * load the Ent with this ID, because it won't find it anyways (e.g. when we
     * try to load a sharded Ent using an ID from the global Shard). This is
     * identical to the case of an Ent not existing in the database.
     */
    singleShardFromID(field: string, id: string | null | undefined, op: string): Promise<Shard<TClient> | null>;
    /**
     * All shards for this particular Ent depending on its affinity.
     */
    allShards(): Promise<ReadonlyArray<Shard<TClient>>>;
    private singleShardFromAffinity;
    /**
     * A helper to build uniform ShardError error messages.
     */
    private buildShardErrorMessage;
}
//# sourceMappingURL=ShardLocator.d.ts.map