import { DrizzleAdapter } from '@nextlyhq/adapter-drizzle'; import { PostgresAdapterConfig, SqlParam, TransactionContext, TransactionOptions, DatabaseCapabilities, PoolStats, InsertOptions, DatabaseError } from '@nextlyhq/adapter-drizzle/types'; export { AdapterLogger, PoolConfig as AdapterPoolConfig, BaseAdapterConfig, DatabaseCapabilities, DatabaseError, DatabaseErrorKind, DeleteOptions, InsertOptions, JoinSpec, OrderBySpec, PoolStats, PostgresAdapterConfig, SelectOptions, SqlParam, SslConfig, TransactionContext, TransactionOptions, UpdateOptions, UpsertOptions, WhereClause, WhereCondition, WhereOperator } from '@nextlyhq/adapter-drizzle/types'; import { AnyRelations } from 'drizzle-orm'; import { NodePgDatabase } from 'drizzle-orm/node-postgres'; /** * @nextlyhq/adapter-postgres * * PostgreSQL database adapter for Nextly. * Extends the base DrizzleAdapter from @nextlyhq/adapter-drizzle to provide * PostgreSQL-specific functionality. * * @remarks * This adapter uses the `pg` (node-postgres) driver for database connections * and integrates with Drizzle ORM for type-safe queries. * * Features: * - Connection pooling via pg.Pool * - Full transaction support with savepoints * - RETURNING clause support for all CRUD operations * - PostgreSQL-specific error classification * - JSONB support * - Full-text search capabilities * - Automatic retry for serialization failures and deadlocks * * @example * Simple usage with connection string: * ```typescript * import { createPostgresAdapter } from '@nextlyhq/adapter-postgres'; * * const adapter = createPostgresAdapter({ * url: process.env.DATABASE_URL!, * }); * * await adapter.connect(); * ``` * * @example * Full configuration: * ```typescript * import { createPostgresAdapter } from '@nextlyhq/adapter-postgres'; * * const adapter = createPostgresAdapter({ * url: process.env.DATABASE_URL!, * pool: { * min: 2, * max: 20, * idleTimeoutMs: 30000, * }, * ssl: { * rejectUnauthorized: true, * }, * applicationName: 'my-nextly-app', * }); * ``` * * @example * Using the adapter class directly: * ```typescript * import { PostgresAdapter } from '@nextlyhq/adapter-postgres'; * import type { PostgresAdapterConfig } from '@nextlyhq/adapter-postgres'; * * const config: PostgresAdapterConfig = { * url: process.env.DATABASE_URL!, * }; * * const adapter = new PostgresAdapter(config); * await adapter.connect(); * ``` * * @packageDocumentation */ /** * Package version. */ declare const VERSION = "0.1.0"; /** * PostgreSQL database adapter for Nextly. * * @remarks * This class extends the base DrizzleAdapter to provide PostgreSQL-specific * functionality including: * * - Connection pooling with pg.Pool * - Transaction support with savepoints * - PostgreSQL-specific error codes * - JSONB and array type support * - Full-text search * - Automatic retry for serialization failures and deadlocks * * For most use cases, use the `createPostgresAdapter` factory function * instead of instantiating this class directly. * * @example * ```typescript * import { PostgresAdapter } from '@nextlyhq/adapter-postgres'; * * const adapter = new PostgresAdapter({ * url: 'postgres://user:pass@localhost:5432/mydb', * }); * * await adapter.connect(); * * // Use the adapter * const users = await adapter.select('users', { * where: { and: [{ column: 'status', op: '=', value: 'active' }] }, * }); * * await adapter.disconnect(); * ``` * * @public */ declare class PostgresAdapter extends DrizzleAdapter { private drizzleByRelations; private drizzleBare; /** * The database dialect - always 'postgresql' for this adapter. */ readonly dialect: "postgresql"; /** * Adapter configuration. */ protected readonly config: PostgresAdapterConfig; /** * Connection pool instance. */ private pool; /** * Connection state flag. */ private connected; /** * Auto-detected provider (Neon, Supabase, or standard). * Set during connect() from DATABASE_URL pattern or DB_PROVIDER env var. */ private detectedProvider; /** * Provider-specific connection defaults. Applied as fallbacks when * user config doesn't specify a value. */ private providerDefaults; /** * Creates a new PostgreSQL adapter instance. * * @param config - Adapter configuration */ constructor(config: PostgresAdapterConfig); /** * Establishes a connection to the PostgreSQL database. * * @remarks * This method initializes the connection pool and verifies connectivity * by executing a simple query. It is idempotent - calling it multiple * times will not create multiple pools. * * @throws {DatabaseError} If connection fails */ connect(): Promise; /** * Closes the database connection and releases all pool resources. * * @remarks * This method is idempotent - calling it multiple times is safe. * It waits for all checked-out clients to be returned before shutting down. */ disconnect(): Promise; /** * Checks if the adapter is currently connected. * * @returns True if connected and pool is available */ isConnected(): boolean; /** * Executes a raw SQL query. * * @param sql - SQL statement with $1, $2, ... placeholders * @param params - Query parameters * @returns Array of result rows * * @throws {DatabaseError} If query execution fails */ executeQuery(sql: string, params?: SqlParam[]): Promise; /** * Executes a callback within a database transaction. * * @remarks * PostgreSQL supports full ACID transactions with savepoints. * If the callback throws, the transaction is rolled back. * * Supports automatic retry for serialization failures (40001) and * deadlocks (40P01) when `retryCount` is specified in options. * * An error carrying the Nextly application brand is neither retried nor * classified: it is the application refusing the write, so it arrives at the * caller as it was thrown. Retrying it would repeat work whose verdict has * already been given. Every other error, including an unbranded one raised by * the callback, is retried when it is a serialization failure or deadlock and * classified on the way out. * * @param callback - Function to execute within the transaction * @param options - Transaction options (isolation level, timeout, retry) * @returns The result of the callback * * @throws {DatabaseError} If the transaction itself fails after all retries, * or if the callback threw an error that does not carry the application brand * @throws The callback's own error, unchanged, when it carries that brand */ transaction(callback: (ctx: TransactionContext) => Promise, options?: TransactionOptions): Promise; /** * Returns the database capabilities for PostgreSQL. * * @remarks * PostgreSQL has the most comprehensive feature set of all supported * databases, including JSONB, arrays, full-text search, and more. */ getCapabilities(): DatabaseCapabilities; /** * Returns connection pool statistics. * * @returns Pool stats or null if not connected */ getPoolStats(): PoolStats | null; /** * Override insertMany for bulk insert optimization. * * @remarks * Uses a single multi-row INSERT statement for better performance * when inserting multiple records. */ insertMany(table: string, data: Record[], options?: InsertOptions): Promise; /** * Ensures pool is connected and returns it. * * @throws {DatabaseError} If not connected */ private ensurePool; /** * Return the typed Drizzle instance for PostgreSQL. * Guarded for server-only usage and requires an active connection. * * @param schema - Optional schema for relational queries (db.query.*) * @returns Drizzle ORM instance wrapping the pg pool connection * @throws {Error} If called in browser or not connected */ getDrizzle>(relations?: AnyRelations): T; /** * Builds pg Pool configuration from adapter config. */ private buildPoolConfig; /** * Begins a transaction with the specified options. */ private beginTransaction; /** * Creates a TransactionContext for the given client. */ /** * The RETURNING entries that spell each date column's wall clock out as * text, one per alias `dateWallClockAliases` chose. `to_char` renders the * stored value without a zone, which is the only form node-postgres cannot * shift on the way back. */ private wallClockSpelling; /** A table-level `primaryKey({ columns })`, read through the PostgreSQL table config. */ protected compositePrimaryKey(tableObj: Record): object[]; private createTransactionContext; /** * Classifies a PostgreSQL error into a DatabaseError. * * @param error - Original error from pg * @param sql - SQL statement that caused the error (optional) * @returns DatabaseError with proper classification */ protected classifyError(error: unknown, sql?: string): DatabaseError; } /** * Creates a PostgreSQL database adapter instance. * * @remarks * This is the recommended way to create a PostgreSQL adapter. * The adapter is not connected after creation - call `connect()` to * establish the database connection. * * @param config - Adapter configuration * @returns A new PostgresAdapter instance * * @example * Simple usage: * ```typescript * import { createPostgresAdapter } from '@nextlyhq/adapter-postgres'; * * const adapter = createPostgresAdapter({ * url: process.env.DATABASE_URL!, * }); * * await adapter.connect(); * ``` * * @example * With full configuration: * ```typescript * const adapter = createPostgresAdapter({ * url: process.env.DATABASE_URL!, * pool: { * min: 5, * max: 20, * idleTimeoutMs: 30000, * connectionTimeoutMs: 10000, * }, * ssl: { * rejectUnauthorized: true, * ca: process.env.CA_CERT, * }, * applicationName: 'my-app', * statementTimeout: 30000, * }); * ``` * * @public */ declare function createPostgresAdapter(config: PostgresAdapterConfig): PostgresAdapter; /** * Type guard to check if a value is a PostgresAdapter instance. * * @param value - Value to check * @returns True if value is a PostgresAdapter * * @example * ```typescript * import { isPostgresAdapter } from '@nextlyhq/adapter-postgres'; * * if (isPostgresAdapter(adapter)) { * // TypeScript knows adapter is PostgresAdapter * console.log(adapter.dialect); // 'postgresql' * } * ``` * * @public */ declare function isPostgresAdapter(value: unknown): value is PostgresAdapter; export { PostgresAdapter, VERSION, createPostgresAdapter, isPostgresAdapter };