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:

// SQL fragment from 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

Connection to Other Layers

  • L6 (Query Engine): Query engine produces SQL, driver executes it
  • L7 (Adapters): Adapters determine SQL dialect, drivers execute it
  • L9 (Client): Client uses driver through query engine

Was this page helpful?