Database

Elide ships three built-in database drivers, each exposed as a synthetic ESM module under the elide: scheme:
ModuleImportDriverConnection style
elide:sqliteimport { Database } from "elide:sqlite"SQLite 3 (JDBC, embedded)Synchronous; new Database(path?)
elide:postgresimport { Database } from "elide:postgres"PostgreSQL (JDBC + HikariCP pool)Asynchronous; await Database.connect(config)
elide:mysqlimport { Database } from "elide:mysql"MySQL (JDBC + HikariCP pool)Asynchronous; await Database.connect(config)
There is no Elide.db global and no Elide.db.connect(); each driver is its own module, imported by name. MongoDB and Redis are not supported, and there is no ORM or query builder — these modules execute SQL directly.

Each module is registered lazily via ModuleRegistry.deferred(...) and resolves only when imported; importing a module does not pollute the global scope.

elide:sqlite

SQLite is fully synchronous and embedded — there is no connection pool and no network. You construct a Database directly.

> Source: dev.elide.lang.javascript.sqlite.JsSqliteModule:SqliteDatabaseConstructor, > interface dev.elide.db.sqlite3.SqliteDatabase, > statement interface dev.elide.db.sqlite3.SqliteStatement.

Constructor

javascript
new Database()                  // in-memory database
new Database(":memory:")        // in-memory database (explicit)
new Database("")                // in-memory database (empty string)
new Database("./data.db")       // file-backed database
new Database("./data.db", opts) // file-backed with options
The second argument is an options object (file-backed databases only):
OptionTypeDefaultEffect
createbooleanfalseCreate the file if it does not exist (parent directory must be writable).
readonlybooleanfalseOpen the database read-only.
If a path is given that does not exist and create is not true, the constructor throws FileNotFoundException.

Database methods

MethodSignatureReturns
queryquery(sql, ...args)Statement
prepareprepare(sql, ...args)Statement
execexec(sql, ...args)undefined (runs without returning rows)
transactiontransaction(fn)Transaction (a callable wrapper)
loadExtensionloadExtension(name)loads a SQLite extension
serializeserialize(schema?)Uint8Array snapshot of the database
closeclose(throwOnError?)closes the database
query and prepare both return a Statement. The difference is intent: query is for one-off execution, prepare for reuse. The statement is prepared eagerly when arguments are passed.

Statement methods

MethodSignatureReturns
allall(...args)array of row objects
valuesvalues(...args)array of value arrays (one per row)
getget(...args)single row object, or undefined if none
runrun(...args)executes the statement, returns nothing
Rows are returned as objects keyed by column name.

Example

javascript
import { Database } from "elide:sqlite";

const db = new Database(); // in-memory

db.exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)");
db.exec("INSERT INTO users (name) VALUES (?)", "Ada");
db.exec("INSERT INTO users (name) VALUES (?)", "Linus");

const all = db.query("SELECT * FROM users").all();
// → [ { id: 1, name: "Ada" }, { id: 2, name: "Linus" } ]

const one = db.query("SELECT name FROM users WHERE id = ?", 1).get();
// → { name: "Ada" }

db.close();

Transactions wrap a function; the returned wrapper is invoked to run the function inside BEGIN / COMMIT (rolling back on a thrown error):

javascript
const insertAll = db.transaction((names) => {
  for (const name of names) db.exec("INSERT INTO users (name) VALUES (?)", name);
});
insertAll(["Grace", "Margaret"]);

elide:postgres and elide:mysql

PostgreSQL and MySQL share an identical JavaScript surface — only the import name, default port, and SQL dialect differ. Both connect over a pooled JDBC connection (HikariCP) and expose async methods that return Promises.

> Sources: dev.elide.lang.javascript.postgresql.JsPostgresModule, > dev.elide.lang.javascript.mysql.JsMysqlModule, > dev.elide.db.postgresql.PostgresDatabase, dev.elide.db.mysql.MysqlDatabase, > config dev.elide.db.jdbc.JdbcConnectionConfig.

Database.connect(config | url)

Database is a factory object with a single static method, connect, which returns a Promise resolving to a database instance. It accepts either a configuration object or a connection URL string.
javascript
await Database.connect({
  host: "localhost",      // optional, default "localhost"
  port: 5432,             // optional, default 5432 (postgres) / 3306 (mysql)
  database: "myapp",      // required
  user: "postgres",       // required
  password: "secret",     // required
  pool: { /* PoolConfig */ },
  ssl:  { /* SslConfig  */ },
  properties: { /* extra JDBC props */ },
});

// Or a URL:
await Database.connect("postgresql:<<>>
await Database.connect("mysql://root:secret@localhost:3306/myapp");
database, user, and password are required when passing a config object; omitting any throws a TypeError.

pool (optional)

FieldTypeDefault
minSizenumber2
maxSizenumber10
connectionTimeoutnumber (ms)5000
idleTimeoutnumber (ms)30000
maxLifetimenumber (ms)1800000
leakDetectionThresholdnumber (ms)0 (disabled)

ssl (optional)

FieldTypeDefault
enabledbooleanfalse
rejectUnauthorizedbooleantrue
castring (path)
certstring (path)
keystring (path)

Database instance

MemberSignatureReturns
connectedpropertyboolean — whether the pool is active
poolStatspropertypool statistics object
queryquery(sql, ...args)a lazy query (.all() / .get() / .values())
execexec(sql, ...args)Promise
prepareprepare(sql)Promise
transactiontransaction(fn)Promise — runs fn(tx) in a transaction
batchbatch([[sql, args], ...])Promise
closeclose()Promise
query returns synchronously a lazy result object; the SQL is not executed until you call one of its consuming methods:
MethodReturns
all()Promise — all rows as objects keyed by column
get()`Promisenull> — the first row, or null`
values()Promise — rows as positional value arrays
ExecResult carries affectedRows (number), insertId (number | null), and insertIds (number[]).

Parameter placeholders

PostgreSQL uses positional $1, $2, … placeholders (these must be sequential, no gaps or repeats). MySQL uses ? placeholders. In both cases, bind values are passed as trailing arguments to query / exec.

Example (PostgreSQL)

javascript
import { Database } from "elide:postgres";

const db = await Database.connect({
  database: "myapp",
  user: "postgres",
  password: "secret",
});

// Read
const users = await db.query("SELECT * FROM users WHERE active = $1", true).all();

// Single row
const user = await db.query("SELECT * FROM users WHERE id = $1", 42).get();

// Write
const res = await db.exec("INSERT INTO users (name) VALUES ($1)", "Ada");
res.affectedRows; // → 1
res.insertId;     // → generated key (or null)

// Transaction
await db.transaction(async (tx) => {
  await tx.exec("UPDATE accounts SET balance = balance - $1 WHERE id = $2", 100, 1);
  await tx.exec("UPDATE accounts SET balance = balance + $1 WHERE id = $2", 100, 2);
});

await db.close();

Example (MySQL)

javascript
import { Database } from "elide:mysql";

const db = await Database.connect({
  database: "myapp",
  user: "root",
  password: "secret",
});

const rows = await db.query("SELECT * FROM users WHERE name = ?", "Ada").all();
await db.exec("INSERT INTO users (name) VALUES (?)", "Linus");
await db.close();

Prepared statements

javascript
const stmt = await db.prepare("INSERT INTO logs (msg) VALUES ($1)");
await stmt.exec("started");
await stmt.exec("stopped");
await stmt.close();

A prepared Statement exposes query(...args), exec(...args), executeBatch(argsList), and close().

Transactions

The callback passed to transaction receives a Transaction object. It is committed when the callback resolves and rolled back if it throws (or its returned Promise rejects). The transaction object exposes:
MemberDescription
isolationcurrent isolation level (READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE)
activewhether the transaction is still open
query(sql, ...args) / exec(sql, ...args)run statements in the transaction
commit() / rollback()settle the transaction explicitly
savepoint(name) / rollbackTo(name)nested savepoints
The default isolation level is READ_COMMITTED.

Notes

  • SQLite is synchronous; PostgreSQL and MySQL are asynchronous (Promise-based).
  • Connection pooling (PostgreSQL/MySQL) is provided by HikariCP and configured via the pool option.
  • Plain JavaScript objects cannot be bound as SQL parameters — use primitives, strings, byte arrays, or arrays.

See also

  • SQLite upstream:
  • PostgreSQL upstream:
  • MySQL upstream: