import pg from "pg";
import type { ClientConnectionIssue, ClientOptions, ClientPingInput, ClientRole } from "../abstract/Client";
import { Client } from "../abstract/Client";
import type { SwallowedErrorLoggerProps } from "../abstract/Loggers";
import type { QueryAnnotation } from "../abstract/QueryAnnotation";
import { TimelineManager } from "../abstract/TimelineManager";
import type { MaybeCallable, PickPartial } from "../internal/misc";
import type { Hints, Literal } from "../types";
/**
 * Options for PgClient constructor.
 */
export interface PgClientOptions<TPool extends pg.Pool = pg.Pool> extends ClientOptions {
    /** Node-Postgres config. We can't make it MaybeCallable unfortunately,
     * because it's used to initialize Node-Postgres Pool. */
    config: pg.PoolConfig & {
        min?: number | undefined;
    };
    /** Should create an instance of Pool class compatible with node-postgres
     * Pool. By default, node-postgres Pool is used. */
    createPool?: (config: pg.PoolConfig) => TPool;
    /** Close the connection after the query if it was opened long time ago. */
    maxConnLifetimeMs?: MaybeCallable<number>;
    /** Jitter for maxConnLifetimeMs. */
    maxConnLifetimeJitter?: MaybeCallable<number>;
    /** Add not more than this number of connections in each prewarm interval. New
     * connections are expensive to establish (especially when SSL is enabled). */
    prewarmIntervalStep?: MaybeCallable<number>;
    /** How often to send bursts of prewarm queries to all Clients to keep the
     * minimal number of open connections. The default value is half of the
     * default node-postgres'es idleTimeoutMillis=10s. Together with 1..1.5x
     * jitter (default prewarmIntervalJitter=0.5), it is still slightly below
     * idleTimeoutMillis, and thus, doesn't let Ent Framework close the
     * connections prematurely. */
    prewarmIntervalMs?: MaybeCallable<number>;
    /** Jitter for prewarmIntervalMs. */
    prewarmIntervalJitter?: MaybeCallable<number>;
    /** What prewarm query to send. */
    prewarmQuery?: MaybeCallable<string>;
    /** If true, also sends prewarm queries and keeps the min number of
     * connections in all sub-pools. See pool() method for details. */
    prewarmSubPools?: boolean;
    /** PG "SET key=value" hints to run before each query. Often times we use it
     * to pass statement_timeout option since e.g. PGBouncer doesn't support
     * per-connection statement timeout in transaction pooling mode: it throws
     * "unsupported startup parameter" error. I.e. we may want to emit "SET
     * statement_timeout TO ..." before each query in multi-query mode. */
    hints?: MaybeCallable<Hints> | null;
    /** After how many milliseconds we give up waiting for the replica to catch up
     * with the master. When role="replica", then this option is the only way to
     * "unlatch" the reads from the master node after a write. */
    maxReplicationLagMs?: MaybeCallable<number>;
    /** Sometimes, the role of this Client is known statically, e.g. when pointing
     * to AWS Aurora writer and reader endpoints. If "master" or "replica" are
     * provided, then no attempt is made to use functions like
     * pg_current_wal_insert_lsn() etc. (they are barely supported in e.g. AWS
     * Aurora). Instead, for "replica" role, it is treated as "always lagging up
     * until maxReplicationLagMs after the last write". If role="unknown", then
     * auto-detection and automatic lag tracking is performed using
     * pg_current_wal_insert_lsn() and other built-in PostgreSQL functions. */
    role?: ClientRole;
    /** Up to how often we call TimelineManager#triggerRefresh(). */
    replicaTimelinePosRefreshMs?: MaybeCallable<number>;
}
/**
 * An opened low-level PostgreSQL connection.
 */
export interface PgClientConn<TPool extends pg.Pool = pg.Pool> extends pg.PoolClient {
    /** Pool instance that created this connection. */
    pool: TPool;
    /** An additional property to the vanilla client: auto-incrementing ID of the
     * connection for logging purposes. */
    id: number;
    /** An additional property to the vanilla client: number of queries sent
     * within this connection. */
    queriesSent: number;
    /** An additional property to the vanilla client: when do we want to
     * hard-close that connection. */
    closeAt: number | null;
}
/**
 * A named low-level Pool config used to create sub-pools. Sub-pool derives
 * configuration from the default PgClientOptions#config, but allow overrides.
 * See PgClient#pool() method for details.
 */
export interface PgClientSubPoolConfig extends Partial<pg.PoolConfig> {
    name: string;
}
/**
 * An abstract PostgreSQL Client. Includes connection pooling logic.
 *
 * Since the class is cloneable internally (using the prototype substitution
 * technique, see withShard()), the contract of this class is that ALL its
 * derived classes may only have readonly immediate properties. Use Ref helper
 * if you need some mutable properties.
 */
export declare class PgClient<TPool extends pg.Pool = pg.Pool> extends Client {
    /** Default values for the constructor options. */
    static readonly DEFAULT_OPTIONS: Required<PickPartial<PgClientOptions<pg.Pool>>>;
    /** PG named connection pools to use. The default pool has `null` key.*/
    private readonly pools;
    /** Prewarming periodic timer (if scheduled). */
    private readonly prewarmTimeout;
    /** Whether the pool has been ended and is not usable anymore. */
    private readonly ended;
    /** This value is set after each request to reflect the actual role of the
     * client. The idea is that master/replica role may change online, without
     * reconnecting the Client, so we need to refresh it after each request and be
     * ready for a fallback. The expectation is that the initial value is
     * populated during the very first shardNos() call. */
    private readonly reportedRoleAfterLastQuery;
    /** This value is non-null if there was an unsuccessful connection attempt
     * (i.e. the PG is down), and there were no successful queries since then. */
    private readonly reportedConnectionIssue;
    /** PgClient configuration options. */
    readonly options: Required<PgClientOptions<TPool>>;
    /** Name of the shard associated to this Client. */
    readonly shardName: string;
    /** An active TimelineManager for this particular Client. */
    readonly timelineManager: TimelineManager;
    /**
     * Calls swallowedErrorLogger() doing some preliminary amendment.
     */
    protected logSwallowedError(props: SwallowedErrorLoggerProps): void;
    /**
     * Initializes an instance of PgClient.
     */
    constructor(options: PgClientOptions<TPool>);
    /**
     * Represents the full destination address this Client is working with.
     * Depending on the implementation, it may include hostname, port number,
     * database name, shard name etc. It is required that the address is stable
     * enough to be able to cache some destination database related metadata (e.g.
     * shardNos) based on that address.
     */
    address(): string;
    /**
     * Gracefully closes all the connections of this Client to let the caller
     * destroy it. The pending queries are awaited to finish before returning. The
     * Client becomes unusable right after calling this method (even before the
     * connections are drained): you should not send queries to it.
     */
    end(): Promise<void>;
    /**
     * Returns true if the Client is ended and can't be used anymore.
     */
    isEnded(): boolean;
    /**
     * Returns all Shard numbers discoverable via the connection to the Client's
     * database.
     */
    shardNos(): Promise<readonly number[]>;
    /**
     * Sends a read or write test query to the server. Tells the server to sit and
     * wait for at least the provided number of milliseconds.
     */
    ping({ execTimeMs, isWrite, annotation }: ClientPingInput): Promise<void>;
    /**
     * Creates a new Client which is namespaced to the provided Shard number. The
     * new Client will share the same connection pool with the parent's Client.
     */
    withShard(no: number): this;
    /**
     * Returns the Client's role reported after the last successful query. Master
     * and replica roles may switch online unpredictably, without reconnecting, so
     * we only know the role after a query.
     */
    role(): ClientRole;
    /**
     * Returns a non-nullable value if the Client couldn't connect to the server
     * (or it could, but the load balancer reported the remote server as not
     * working), so it should ideally be removed from the list of active replicas
     * until e.g. the next discovery query to it (or any query) succeeds.
     */
    connectionIssue(): ClientConnectionIssue | null;
    /**
     * A convenience method to put connections prewarming logic to. The idea is to
     * keep the needed number of open connections and also, in each connection,
     * minimize the time which the very 1st query will take (e.g. pre-cache
     * full-text dictionaries).
     */
    prewarm(): void;
    /**
     * Returns a default pool (when subPoolConfig is not passed), or a "sub-pool"
     * (a named low-level Pool implementation compatible to node-postgres). The
     * method is specific to the current class and is not a part of
     * database-agnostic Client API.
     * - Sub-pools are lazily created and memoized by the provided name. They may
     *   differ by config options (like statement_timeout or max connections).
     * - Sub-pools inherit the properties from default PgClientOptions.config.
     * - It is implied (but not enforced) that all sub-pools use the same physical
     *   database, because otherwise it makes not a lot of sense.
     */
    pool(subPoolConfig?: PgClientSubPoolConfig): TPool;
    /**
     * Called when the Client needs a connection in the default pool (when
     * subPoolConfig is not passed), or in a sub-pool (see pool() method) to run a
     * query against. Implies than the caller MUST call release() method on the
     * returned object. The difference from pool().connect() is that when calling
     * release() on a result of acquireConn(), it additionally closes the
     * connection automatically if was OPENED (not queried!) more than
     * maxConnLifetimeMs ago (node-postgres Pool doesn't have this feature) The
     * method is specific to the current class and is not a part of
     * database-agnostic Client API.
     */
    acquireConn(subPoolConfig?: PgClientSubPoolConfig): Promise<PgClientConn<TPool>>;
    /**
     * Sends a query (internally, a multi-query) through the default Pool (if
     * subPoolConfig is not passed), or through a named sub-pool (see pool()
     * method). After the query finishes, we should expect that role() returns the
     * actual master/replica role. The method is specific to the current class and
     * is not a part of database-agnostic Client API.
     */
    query<TRow>({ query: queryLiteral, hints, isWrite, annotations, op, table, batchFactor, subPoolConfig }: {
        query: Literal;
        hints?: Hints;
        isWrite: boolean;
        annotations: QueryAnnotation[];
        op: string;
        table: string;
        batchFactor?: number;
        subPoolConfig?: PgClientSubPoolConfig;
    }): Promise<TRow[]>;
    /**
     * Prepares a PG Client multi-query from the query literal and hints.
     */
    private buildMultiQuery;
    private sendMultiQuery;
}
/**
 * For backward compatibility, exposing the old name as well.
 * @deprecated Use PgClient instead.
 * @ignore
 */
export declare const PgClientPool: typeof PgClient;
/**
 * For backward compatibility, exposing the old name as well.
 * @deprecated Use PgClient instead.
 * @ignore
 */
export type PgClientPool = PgClient;
/**
 * For backward compatibility, exposing the old name as well.
 * @deprecated Use PgClientOptions instead.
 * @ignore
 */
export type PgClientPoolOptions = PgClientOptions;
//# sourceMappingURL=PgClient.d.ts.map