async_postgres/pg_connection/lifecycle

Connection lifecycle: auth, single/multi-host connect, and close.

Internal module: not part of the public API. Import the pg_connection hub instead.

Procs

proc close(conn: PgConnection): Future[void] {.
    ...raises: [Exception, LibraryError, SslError, ValueError],
    tags: [RootEffect, TimeEffect], forbids: [].}
Idempotent close; asyncdispatch may orphan blocking pump until it unwinds. Waiter → PgStateError.
proc closeImpl(conn: PgConnection; byUser: bool): Future[void] {.
    ...stackTrace: false, raises: [Exception, LibraryError, SslError, ValueError],
    tags: [RootEffect, TimeEffect], forbids: [].}
Close with ownership flag: byUser=false keeps PgConnectionError for pool evictions.
proc connect(config: ConnConfig): Future[PgConnection] {....raises: [Exception,
    ValueError, PgConfigError, PgConnectionError, CatchableError],
    tags: [RootEffect, WriteIOEffect, TimeEffect], forbids: [].}
Connect with multi-host failover, targetSessionAttrs, connectTimeout per address a host resolves to. Per-host failures fold into one PgConnectionError; a PgConfigError escapes the fold. Unlike libpq, a failed authentication or security check moves on to the next host; a host's next address is tried only after a failed dial or a timeout. Its attempts hold each host's latest failure, a mismatch included (serverErrors collects their refusals), its parent the last one; a PgSecurityError when every host was. A single host's timeout raises AsyncTimeoutError (not folded).
proc connect(dsn: string): Future[PgConnection] {....raises: [Exception,
    ValueError, PgConfigError, PgConnectionError, CatchableError],
    tags: [RootEffect, WriteIOEffect, TimeEffect, ReadIOEffect], forbids: [].}
Shorthand for connect(parseDsn(dsn)).
proc connectToHost(config: ConnConfig; entry: HostEntry): Future[PgConnection] {....raises: [
    Exception, ValueError, PgConfigError, CancelledError, PgConnectionError,
    LibraryError, SslError, CatchableError, PgUnavailableError, OSError, IOError],
    tags: [RootEffect, WriteIOEffect, TimeEffect], forbids: [].}

Connect to a single host (dial hostaddr else host; verify via host). With a hostaddr, a "127.0.0.1" host is not verified (see effectiveHost), so sslVerifyFull then needs a real name.

Low-level dial primitive. Unlike connect it does not apply targetSessionAttrs, connectTimeout or connect tracing, and it moves on to the host's next address only when a dial fails.

On Unix sockets TLS is skipped (libpq parity); if sslCert is set a stderr warning is emitted because the client certificate is not sent.

proc filterSaslByRequireAuth(mechs: seq[string]; allowed: set[AuthMethod]): seq[
    string] {....raises: [], tags: [], forbids: [].}
Filter a server-offered SASL mechanism list by the client's requireAuth policy. An empty allowed set performs no filtering (matching libpq semantics when require_auth is unset).
proc orderedHosts(config: ConnConfig): seq[HostEntry] {.
    ...raises: [PgConnectionError], tags: [], forbids: [].}
Hosts per loadBalanceHosts (lbhRandom shuffles via urandom; no global state).
proc selectScramMechanism(sslEnabled: bool; serverCertDer: openArray[byte];
                          saslMechanisms: seq[string]; mode: ChannelBindingMode;
                          allowed: set[AuthMethod] = {};
                          certMissing = ServerCertUnavailable): tuple[
    mechanism: string, cbType: string, cbData: seq[byte],
    cbSupportedButUnused: bool, cbLost: bool] {.
    ...raises: [PgSecurityError, PgConnectionError], tags: [RootEffect],
    forbids: [].}
Pick SCRAM mechanism/binding from the server's offer narrowed to allowed (raises if mode or allowed unsatisfied; cbSupportedButUnused → y,, else n,,). cbLost: cbPrefer passed over an offered -PLUS for lack of a server certificate, which certMissing explains.