import { R as Row, I as IsolationLevel } from '../types-YTdPe6Qz.js'; import { a as RpcTransportConfig, b as RpcPromise } from '../rpc-DFDGfOCs.js'; export { B as BatchResult, M as MapFn, g as RpcExecutionContext, h as RpcQueryResult, R as RpcTransport, f as batchExecute, e as createRowsPromise, d as createRpcPromise, c as createRpcTransport, m as magicMap } from '../rpc-DFDGfOCs.js'; import '@dotdo/postgres-shared/errors'; /** * Capnweb-enabled PostgreSQL client for postgres.do * * This client provides: * - Magic map support for N+1 query elimination * - Promise pipelining for batched operations * - RPC transport with automatic batching * * @example * ```typescript * import { createClient } from 'postgres.do/rpc' * * const db = createClient('postgres.do/my-database') * * // Magic map - N+1 solved in single round trip * const usersWithOrders = await db.query('SELECT * FROM users') * .map(users => Promise.all( * users.map(u => db.query('SELECT * FROM orders WHERE user_id = $1', [u.id])) * )) * * // Promise pipelining - chain without await * const user = db.query('SELECT * FROM users WHERE id = $1', [id]) * const posts = user.map(u => db.query('SELECT * FROM posts WHERE author = $1', [u.id])) * const comments = posts.map(p => db.query('SELECT * FROM comments WHERE post_id = ANY($1)', [p.map(x => x.id)])) * const result = await comments // Single round trip! * * // Transactions with pipelining * await db.transaction(tx => { * const balance = tx.query('SELECT balance FROM accounts WHERE id = $1', [fromId]) * const updated = balance.map(b => { * if (b.balance < amount) throw new Error('Insufficient funds') * return tx.query('UPDATE accounts SET balance = balance - $1 WHERE id = $2', [amount, fromId]) * }) * return updated.map(() => * tx.query('UPDATE accounts SET balance = balance + $1 WHERE id = $2', [amount, toId]) * ) * }) * ``` */ /** * Client configuration options */ interface RpcClientConfig { /** Database URL (postgres.do/database-name or wss://...) */ url?: string; /** API key for authentication */ apiKey?: string; /** Custom WebSocket implementation */ WebSocket?: typeof WebSocket; /** Connection timeout in milliseconds */ connectTimeout?: number; /** Request timeout in milliseconds */ requestTimeout?: number; /** Enable automatic batching (default: true) */ autoBatch?: boolean; /** Custom transport configuration */ transport?: Partial; } /** * Transaction options */ interface TransactionOptions { /** Isolation level for the transaction */ isolationLevel?: IsolationLevel; /** Read-only transaction hint */ readOnly?: boolean; } /** * Transaction client interface */ interface TransactionClient { /** Execute a query within the transaction */ query(sql: string, params?: unknown[]): RpcPromise; /** Execute a query and return only the first row */ queryOne(sql: string, params?: unknown[]): RpcPromise; /** Execute a query and return a scalar value */ queryScalar(sql: string, params?: unknown[]): RpcPromise; /** Execute a statement that doesn't return rows */ execute(sql: string, params?: unknown[]): RpcPromise<{ rowCount: number; }>; } /** * Capnweb-enabled PostgreSQL client */ declare class RpcClient { private transport; constructor(config?: RpcClientConfig); /** * Resolve the database URL */ private resolveUrl; /** * Execute a SQL query * * Returns an RpcPromise that supports .map() for magic map functionality. * * @example * ```typescript * // Simple query * const users = await db.query('SELECT * FROM users') * * // With magic map (N+1 elimination) * const usersWithOrders = await db.query('SELECT id FROM users') * .map(users => Promise.all(users.map(u => * db.query('SELECT * FROM orders WHERE user_id = $1', [u.id]) * ))) * ``` */ query(sql: string, params?: unknown[]): RpcPromise; /** * Execute a query and return only the first row * * @example * ```typescript * const user = await db.queryOne('SELECT * FROM users WHERE id = $1', [id]) * if (user) { * console.log(user.name) * } * ``` */ queryOne(sql: string, params?: unknown[]): RpcPromise; /** * Execute a query and return a scalar value (first column of first row) * * @example * ```typescript * const count = await db.queryScalar('SELECT COUNT(*) FROM users') * ``` */ queryScalar(sql: string, params?: unknown[]): RpcPromise; /** * Execute a SQL statement that doesn't return rows * * @example * ```typescript * const { rowCount } = await db.execute('DELETE FROM users WHERE id = $1', [id]) * console.log(`Deleted ${rowCount} rows`) * ``` */ execute(sql: string, params?: unknown[]): RpcPromise<{ rowCount: number; }>; /** * Execute a batch of queries in a single round trip * * @example * ```typescript * const [users, orders, products] = await db.batch([ * { sql: 'SELECT * FROM users' }, * { sql: 'SELECT * FROM orders' }, * { sql: 'SELECT * FROM products' }, * ]) * ``` */ batch(queries: Array<{ sql: string; params?: unknown[]; }>): Promise; /** * Execute queries within a transaction * * The transaction callback receives a transaction client that supports * the same query methods with promise pipelining. * * @example * ```typescript * await db.transaction(async tx => { * await tx.execute('INSERT INTO users (name) VALUES ($1)', ['Alice']) * await tx.execute('INSERT INTO audit_log (action) VALUES ($1)', ['user_created']) * }) * ``` * * @example Promise pipelining in transactions * ```typescript * await db.transaction(tx => { * const balance = tx.query('SELECT balance FROM accounts WHERE id = $1', [fromId]) * return balance.map(async rows => { * if (rows[0].balance < amount) throw new Error('Insufficient funds') * await tx.execute('UPDATE accounts SET balance = balance - $1 WHERE id = $2', [amount, fromId]) * await tx.execute('UPDATE accounts SET balance = balance + $1 WHERE id = $2', [amount, toId]) * }) * }) * ``` */ transaction(fn: (tx: TransactionClient) => Promise | RpcPromise, options?: TransactionOptions): Promise; /** * Execute queries within a batched transaction * * All queries are collected and executed in a single round trip, * wrapped in BEGIN/COMMIT. * * @example * ```typescript * const results = await db.batchTransaction([ * { sql: 'INSERT INTO users (name) VALUES ($1)', params: ['Alice'] }, * { sql: 'INSERT INTO audit_log (action) VALUES ($1)', params: ['user_created'] }, * ]) * ``` */ batchTransaction(queries: Array<{ sql: string; params?: unknown[]; }>, options?: TransactionOptions): Promise; /** * Health check - verify database is responsive */ ping(): RpcPromise<{ ok: true; durationMs: number; }>; /** * Get database version */ version(): RpcPromise; /** * List all tables in the public schema */ listTables(): RpcPromise; /** * Get table schema information */ describeTable(tableName: string): RpcPromise>; /** * Close the connection */ close(): Promise; /** * Check if connected */ isConnected(): boolean; } /** * Create a capnweb-enabled PostgreSQL client * * @example * ```typescript * import { createClient } from 'postgres.do/rpc' * * const db = createClient('postgres.do/my-database') * * // Query with magic map * const usersWithOrders = await db.query('SELECT * FROM users') * .map(users => Promise.all( * users.map(u => db.query('SELECT * FROM orders WHERE user_id = $1', [u.id])) * )) * ``` */ declare function createClient(urlOrConfig?: string | RpcClientConfig): RpcClient; /** * Shared RPC Types for postgres.do * * These types define the capnweb RPC contract between: * - Client: postgres.do (this package) * - Server: @dotdo/postgres Worker * * IMPORTANT: This file is the single source of truth for RPC types. * Both client and server MUST use these types to ensure type safety. * * @see packages/postgres/src/worker/rpc.ts - Server-side RPC implementation * @see packages/postgres.do/src/transport/rpc.ts - Client-side RPC transport */ /** * Generic row type for query results * Used as a constraint for typed query results */ type RpcRow = Record; /** * Field metadata from query results * Maps to PostgreSQL's column metadata */ interface RpcField { /** Column name */ name: string; /** PostgreSQL OID for the column type */ dataTypeID: number; /** Table OID (0 if not from a table) */ tableID?: number; /** Column position in table */ columnID?: number; /** Data type size in bytes (-1 for variable) */ dataTypeSize?: number; /** Type modifier */ dataTypeModifier?: number; /** Format code (0 = text, 1 = binary) */ format?: string; } /** * RPC query result * * Returned from all query operations (query, queryOne, execute, etc.) */ interface RpcQueryResult { /** Query result rows */ rows: T[]; /** Field metadata */ fields: RpcField[]; /** Number of affected rows (for INSERT/UPDATE/DELETE) or returned rows */ rowCount: number; /** Query execution time in milliseconds */ durationMs: number; } /** * RPC batch query item * * Single query within a batch operation */ interface RpcBatchQuery { /** SQL query string */ sql: string; /** Query parameters (positional: $1, $2, etc.) */ params?: unknown[]; } /** * RPC batch result * * Returned from batch and batchTransaction operations */ interface RpcBatchResult { /** Results for each query in order */ results: RpcQueryResult[]; /** Total execution time in milliseconds */ durationMs: number; } /** * Transaction isolation levels * * Follows PostgreSQL's isolation level semantics */ type RpcIsolationLevel = 'READ UNCOMMITTED' | 'READ COMMITTED' | 'REPEATABLE READ' | 'SERIALIZABLE'; /** * Transaction options * * Passed to transaction() and batchTransaction() operations */ interface RpcTransactionOptions { /** Isolation level for the transaction */ isolationLevel?: RpcIsolationLevel; /** Read-only transaction hint (enables optimizations) */ readOnly?: boolean; /** Deferrable (only valid with SERIALIZABLE + READ ONLY) */ deferrable?: boolean; } /** * Transaction state */ type RpcTransactionState = 'active' | 'committed' | 'rolled_back'; /** * RPC error response structure * * Follows PostgreSQL error format with additional fields */ interface RpcError { /** Error message */ message: string; /** PostgreSQL error code (e.g., '23505' for unique violation) */ code?: string; /** Error severity (ERROR, WARNING, etc.) */ severity?: string; /** Detailed error message */ detail?: string; /** Hint for fixing the error */ hint?: string; /** Position in query where error occurred */ position?: number; /** Schema name if relevant */ schema?: string; /** Table name if relevant */ table?: string; /** Column name if relevant */ column?: string; /** Constraint name if relevant */ constraint?: string; } /** * RPC message types for the WebSocket protocol * * These define the request/response types used over the wire */ declare enum RpcMessageType { /** Single query request */ Query = "query", /** Batch query request */ Batch = "batch", /** Batch transaction request */ BatchTransaction = "batch_tx", /** Start transaction request */ Transaction = "transaction", /** Query within transaction */ TransactionQuery = "tx_query", /** Commit transaction */ TransactionCommit = "tx_commit", /** Rollback transaction */ TransactionRollback = "tx_rollback", /** Ping for keepalive */ Ping = "ping", /** Authentication request */ Auth = "auth", /** Query result response */ QueryResult = "query_result", /** Batch result response */ BatchResult = "batch_result", /** Transaction result response */ TransactionResult = "tx_result", /** Error response */ Error = "error", /** Pong response */ Pong = "pong", /** Auth result response */ AuthResult = "auth_result" } /** * Base RPC message */ interface RpcMessageBase { /** Message type */ type: RpcMessageType; /** Request ID for correlation */ id: number; } /** * Query request message */ interface RpcQueryRequest extends RpcMessageBase { type: RpcMessageType.Query; /** SQL query string */ sql: string; /** Query parameters */ params?: unknown[]; } /** * Batch query request message */ interface RpcBatchRequest extends RpcMessageBase { type: RpcMessageType.Batch; /** Queries to execute */ queries: RpcBatchQuery[]; } /** * Batch transaction request message */ interface RpcBatchTransactionRequest extends RpcMessageBase { type: RpcMessageType.BatchTransaction; /** Queries to execute */ queries: RpcBatchQuery[]; /** Transaction options */ options?: RpcTransactionOptions; } /** * Authentication request message */ interface RpcAuthRequest extends RpcMessageBase { type: RpcMessageType.Auth; /** API key for authentication */ apiKey?: string; } /** * Ping request message */ interface RpcPingRequest extends RpcMessageBase { type: RpcMessageType.Ping; } /** * Query result response message */ interface RpcQueryResultMessage extends RpcMessageBase { type: RpcMessageType.QueryResult; /** Result rows */ rows: T[]; /** Field metadata */ fields: RpcField[]; /** Number of affected/returned rows */ rowCount: number; /** Query execution time */ durationMs: number; /** Command type (SELECT, INSERT, etc.) */ command?: string; } /** * Batch result response message */ interface RpcBatchResultMessage extends RpcMessageBase { type: RpcMessageType.BatchResult; /** Results for each query */ results: RpcQueryResult[]; /** Total execution time */ durationMs: number; } /** * Error response message */ interface RpcErrorMessage extends RpcMessageBase { type: RpcMessageType.Error; /** Error details */ error: RpcError; } /** * Auth result response message */ interface RpcAuthResultMessage extends RpcMessageBase { type: RpcMessageType.AuthResult; /** Whether authentication succeeded */ success: boolean; /** Error message if failed */ error?: string; } /** * Pong response message */ interface RpcPongMessage extends RpcMessageBase { type: RpcMessageType.Pong; } /** * All possible RPC request message types */ type RpcRequestMessage = RpcQueryRequest | RpcBatchRequest | RpcBatchTransactionRequest | RpcAuthRequest | RpcPingRequest; /** * All possible RPC response message types */ type RpcResponseMessage = RpcQueryResultMessage | RpcBatchResultMessage | RpcErrorMessage | RpcAuthResultMessage | RpcPongMessage; /** * All RPC message types */ type RpcMessage = RpcRequestMessage | RpcResponseMessage; /** * PostgresRpcApi interface * * This interface defines the RPC API that the server exposes. * Clients use this interface (via capnweb RPC stubs) to call server methods. * * @example Server-side implementation in @dotdo/postgres: * ```typescript * import type { IPostgresRpcApi } from 'postgres.do/rpc' * * export class PostgresRpcApi extends RpcTarget implements IPostgresRpcApi { * async query(sql: string, params?: unknown[]): Promise> { * // ...implementation * } * } * ``` * * @example Client-side usage: * ```typescript * import { createClient } from 'postgres.do/rpc' * * const db = createClient('postgres.do/my-database') * const result = await db.query('SELECT * FROM users') * ``` */ interface IPostgresRpcApi { /** * Execute a SQL query */ query(sql: string, params?: unknown[]): Promise>; /** * Execute a query and return only the first row */ queryOne(sql: string, params?: unknown[]): Promise; /** * Execute a query and return the scalar value (first column of first row) */ queryScalar(sql: string, params?: unknown[]): Promise; /** * Execute a SQL statement that doesn't return rows */ execute(sql: string, params?: unknown[]): Promise<{ rowCount: number; durationMs: number; }>; /** * Execute a batch of queries */ batch(queries: RpcBatchQuery[]): Promise; /** * Execute a batch of queries within a transaction */ batchTransaction(queries: RpcBatchQuery[], options?: RpcTransactionOptions): Promise; /** * Health check */ ping(): Promise<{ ok: true; durationMs: number; }>; /** * Get database version */ version(): Promise; /** * List all tables in the public schema */ listTables(): Promise; /** * Get table schema information */ describeTable(tableName: string): Promise>; /** * Get database name */ getDatabase(): string; } /** * Transaction RPC API interface */ interface ITransactionRpcApi { /** * Execute a query within this transaction */ query(sql: string, params?: unknown[]): Promise>; /** * Commit the transaction */ commit(): Promise<{ success: true; durationMs: number; }>; /** * Rollback the transaction */ rollback(): Promise<{ success: true; durationMs: number; }>; /** * Get transaction state */ getState(): RpcTransactionState; /** * Get number of queries executed in this transaction */ getQueryCount(): number; } export { type IPostgresRpcApi, type ITransactionRpcApi, type RpcAuthRequest, type RpcAuthResultMessage, type RpcBatchQuery, type RpcBatchRequest, type RpcBatchResult, type RpcBatchResultMessage, type RpcBatchTransactionRequest, RpcClient, type RpcClientConfig, type RpcError, type RpcErrorMessage, type RpcField, type RpcIsolationLevel, type RpcMessage, RpcMessageType, type RpcPingRequest, type RpcPongMessage, RpcPromise, type RpcQueryRequest, type RpcQueryResultMessage, type RpcRequestMessage, type RpcResponseMessage, type RpcRow, type RpcTransactionOptions, type RpcTransactionState, RpcTransportConfig, type RpcQueryResult as SharedRpcQueryResult, type TransactionClient, type TransactionOptions, createClient, createClient as default };