Skip to content
VibORM
Esc
navigateopen⌘Jpreview
On this page

L8 - Drivers

Handle database connections and execute queries

Location: src/drivers/

Why This Layer Exists

Different database clients have different APIs:

// node-postgres
const result = await client.query(sql, params);

// PGlite (embedded)
const result = await db.exec(sql, params);

// mysql2
const [rows] = await connection.execute(sql, params);

// better-sqlite3
const rows = db.prepare(sql).all(...params);

Drivers abstract these differences behind a common interface.

Driver Interface

Drivers extend the abstract Driver base class (see src/drivers/driver.ts). It is generic over the underlying client and transaction handle, carries the SQL adapter for its dialect, and manages lazy connection, transaction queuing, and error mapping. Subclasses implement five methods:

abstract class Driver<TClient, TTransaction> {
  readonly dialect: Dialect;                    // "postgres" | "mysql" | "sqlite"
  readonly driverName: string;
  abstract readonly adapter: DatabaseAdapter;   // SQL adapter for this dialect
  readonly supportsTransactions: boolean;       // false for batch-only clients (D1 binding, Neon HTTP)
  readonly supportsBatch: boolean;              // true for atomic-batch APIs (D1, Neon HTTP)

  // Subclasses implement:
  protected abstract initClient(): Promise<TClient>;
  protected abstract closeClient(client: TClient | TTransaction): Promise<void>;
  protected abstract execute<T>(client, sql, params, context?): Promise<QueryResult<T>>;
  protected abstract executeRaw<T>(client, sql, params, context?): Promise<QueryResult<T>>;
  protected abstract transaction<T>(client, fn: (tx: TTransaction) => Promise<T>, context?): Promise<T>;
}

Available Drivers

Driver Entry Point Client Use Case
PgDriver viborm/pg node-postgres PostgreSQL servers
PostgresDriver viborm/postgres postgres.js PostgreSQL servers
PGliteDriver viborm/pglite PGlite Embedded PostgreSQL
NeonHTTPDriver viborm/neon-http Neon HTTP Serverless PostgreSQL
BunSQLDriver viborm/bun-sql Bun SQL PostgreSQL from Bun
MySQL2Driver viborm/mysql2 mysql2 MySQL servers
PlanetScaleDriver viborm/planetscale PlanetScale Serverless MySQL
SQLite3Driver viborm/sqlite3 better-sqlite3 SQLite files
LibSQLDriver viborm/libsql libSQL Turso / libSQL
BunSQLiteDriver viborm/bun-sqlite bun SQLite from Bun
D1Driver viborm/d1 D1 binding Cloudflare Workers

What Drivers Handle

Connection Management

Drivers connect lazily and accept either an existing client or connection options. For example, PostgresDriver (postgres.js):

const driver = new PostgresDriver({
  databaseUrl: "postgres://...",  // or options: { host, port, database, ... }
  // client: existingPostgresJsInstance,
  // pgvector: true,
  // postgis: true,
});

Parameterization

Drivers ensure queries use parameterized values:

// Adapter-built SQL fragment composed by the query engine
sql`SELECT * FROM users WHERE id = ${userId}`

// Driver separates template and values
query: "SELECT * FROM users WHERE id = $1"
params: [userId]

Result Transformation

Some databases return results in different formats. Drivers normalize this:

// MySQL returns [rows, fields]
// PostgreSQL returns { rows, rowCount }
// Drivers return just the rows

Error Handling

Database-specific errors are normalized into typed VibORM errors (see src/drivers/error-mapping.ts):

// PostgreSQL: error code "23505"
// MySQL: errno 1062 / "ER_DUP_ENTRY"
// SQLite: "SQLITE_CONSTRAINT_UNIQUE"
// Driver: throws UniqueConstraintError

Provider recognition stops at this boundary. The driver maps provider codes, constraint names, and assertion markers. The query engine can then combine a typed unique failure with the structural racePin on a write; it does not parse provider SQL or error text itself.

Fragment Execution

Drivers do not interpret PlanningFragment, OperationFragment, relation programs, or guards. OperationExecutor lowers those concepts into the surface the driver owns:

  • one statement for a structural direct candidate;
  • ordered statements inside a transaction;
  • one atomic BatchQuery[] envelope for a batch-capable driver.

Adapter batchRefs lower produced-value references for atomic batches. Drivers execute the resulting batch and return normalized results in the same order.

Connection to Other Layers

  • L6 (Query Engine): Query engine lowers portable fragments to driver statements or batches
  • L7 (Adapters): Adapters determine SQL dialect, drivers execute it
  • L9 (Client): Client uses driver through query engine

Was this page helpful?