@molecule/api-database-mysql
Provider bond · database · API (Node) · v1.2.4 · Apache-2.0
MySQL database provider for molecule.dev
npm install @molecule/api-database-mysqlnpm · Source on GitHub · Implements @molecule/api-database
How it works
@molecule/api-database-mysql is a provider bond on the API (Node) side: it implements the database core interface (@molecule/api-database) with a concrete vendor or library behind it.
Your code calls the core; you wire this provider once at startup. Swapping vendors later is one line in that wiring, not a rewrite.
import { setPool, setStore } from '@molecule/api-database'
import { pool, store } from '@molecule/api-database-mysql'
setPool(pool) // reads MYSQL_URL (or MYSQL_HOST/…) lazily on first use
setStore(store)Works with: @molecule/api-bond, @molecule/api-database, @molecule/api-secrets
Secrets: MYSQL_URL
Reference
MySQL database provider for molecule.dev.
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
Quick Start
import { setPool, setStore } from '@molecule/api-database'
import { pool, store } from '@molecule/api-database-mysql'
setPool(pool) // reads MYSQL_URL (or MYSQL_HOST/…) lazily on first use
setStore(store)
Type
provider
Installation
npm install @molecule/api-database-mysql @molecule/api-bond @molecule/api-database @molecule/api-secrets mysql2
API
Interfaces
Pool
interface Pool extends Connection {
getConnection(): Promise<PoolConnection>
releaseConnection(connection: PoolConnection): void
on(event: 'connection', listener: (connection: PoolConnection) => any): this
on(event: 'acquire', listener: (connection: PoolConnection) => any): this
on(event: 'release', listener: (connection: PoolConnection) => any): this
on(event: 'enqueue', listener: () => any): this
end(): Promise<void>
pool: CorePool
}
PoolOptions
interface PoolOptions extends ConnectionOptions {
/**
* Determines the pool's action when no connections are available and the limit has been reached. If true, the pool will queue
* the connection request and call it when one becomes available. If false, the pool will immediately call back with an error.
* (Default: true)
*/
waitForConnections?: boolean
/**
* The maximum number of connections to create at once. (Default: 10)
*/
connectionLimit?: number
/**
* The maximum number of idle connections. (Default: same as `connectionLimit`)
*/
maxIdle?: number
/**
* The idle connections timeout, in milliseconds. (Default: 60000)
*/
idleTimeout?: number
/**
* The maximum number of connection requests the pool will queue before returning an error from getConnection. If set to 0, there
* is no limit to the number of queued connection requests. (Default: 0)
*/
queueLimit?: number
/**
* Whether to reset the connection state (user variables, temporary tables, transactions, etc.) when
* releasing the connection back to the pool. This ensures each connection starts clean for the next user.
* Requires MySQL 5.7.3+. (Default: false)
*/
resetOnRelease?: boolean
}
ResultSetHeader
declare interface ResultSetHeader {
constructor: {
name: 'ResultSetHeader'
}
affectedRows: number
fieldCount: number
info: string
insertId: number
serverStatus: number
warningStatus: number
/**
* @deprecated
* `changedRows` is deprecated and might be removed in the future major release. Please use `affectedRows` property instead.
*/
changedRows: number
}
RowDataPacket
declare interface RowDataPacket {
constructor: {
name: 'RowDataPacket'
}
[column: string]: any
[column: number]: any
}
QueryResult
Query result with rows and metadata.
interface QueryResult<T = Record<string, unknown>> {
/**
* Array of rows returned by the query.
*/
rows: T[]
/**
* Number of rows affected (for INSERT, UPDATE, DELETE).
*/
rowCount: number | null
/**
* Column metadata (optional, provider-dependent).
*/
fields?: Array<{
name: string
dataTypeID?: number
}>
}
DatabaseConnection
Database connection interface.
interface DatabaseConnection {
/**
* Executes a parameterized query.
*
* @param text - SQL query text with placeholders ($1, $2, etc.)
* @param values - Parameter values
*/
query<T = Record<string, unknown>>(text: string, values?: unknown[]): Promise<QueryResult<T>>
/**
* Releases the connection back to the pool.
*/
release(): void
}
DatabaseTransaction
Database transaction with commit and rollback (extends DatabaseConnection).
interface DatabaseTransaction extends DatabaseConnection {
/**
* Commits the transaction.
*/
commit(): Promise<void>
/**
* Rolls back the transaction.
*/
rollback(): Promise<void>
}
DatabasePool
Database pool interface.
All database providers must implement this interface.
interface DatabasePool {
/**
* Executes a parameterized query using a pool connection.
*
* @param text - SQL query text with placeholders ($1, $2, etc.)
* @param values - Parameter values
*/
query<T = Record<string, unknown>>(text: string, values?: unknown[]): Promise<QueryResult<T>>
/**
* Acquires a connection from the pool.
*/
connect(): Promise<DatabaseConnection>
/**
* Begins a transaction.
*/
transaction?(): Promise<DatabaseTransaction>
/**
* Closes all connections in the pool.
*/
end(): Promise<void>
/**
* Returns pool statistics (optional).
*/
stats?(): {
total: number
idle: number
waiting: number
}
}
DatabaseConfig
Database connection options (host, port, credentials, pool size, timeouts, SSL).
interface DatabaseConfig {
/**
* Database host.
*/
host?: string
/**
* Database port.
*/
port?: number
/**
* Database name.
*/
database?: string
/**
* Database user.
*/
user?: string
/**
* Database password.
*/
password?: string
/**
* Connection string (alternative to individual fields).
*/
connectionString?: string
/**
* Maximum number of connections in the pool.
*/
max?: number
/**
* Minimum number of connections in the pool.
*/
min?: number
/**
* Connection timeout in milliseconds.
*/
connectionTimeoutMillis?: number
/**
* Idle timeout in milliseconds.
*/
idleTimeoutMillis?: number
/**
* Enable SSL.
*/
ssl?:
| boolean
| {
rejectUnauthorized?: boolean
ca?: string
key?: string
cert?: string
}
}
Classes
PoolConnection
declare class PoolConnection extends Connection {
release(): void
connection: Connection;
[Symbol.asyncDispose](): Promise<void>
}
Functions
createMigrator(migrationsDir)
Returns a runMigrations() bound to a migrations directory.
function createMigrator(migrationsDir: string): () => Promise<void>
migrationsDir— Absolute path to the directory of ordered*.sqlmigration files. Resolve viajoin(new URL('.', import.meta.url).pathname, '../../migrations')from the app'sscripts/migrate.ts.
Returns: A no-arg runMigrations() that creates the database (if missing) and applies every migration file in lexical order using a multi-statement connection.
createPool(config)
Creates a MySQL database pool that implements the DatabasePool interface.
Reads MYSQL_URL, MYSQL_HOST, MYSQL_PORT, MYSQL_DATABASE, MYSQL_USER,
and MYSQL_PASSWORD from env if not provided in config.
function createPool(config?: DatabaseConfig): DatabasePool
config— Database connection configuration.
Returns: A DatabasePool backed by a MySQL connection pool.
createStore(pool)
Creates a DataStore backed by a MySQL DatabasePool.
function createStore(pool: DatabasePool): DataStore
pool— The MySQL DatabasePool to use for queries.
Returns: A DataStore that translates CRUD operations to MySQL-compatible SQL.
Constants
MIGRATION_LEDGER
The table that records which migration files have run.
const MIGRATION_LEDGER: '_molecule_migrations'
pool
The default MySQL pool instance, created with env-based configuration on first use.
const pool: DatabasePool
databaseMysqlSecretDefinitions
Secret definitions required by the MySQL database bond.
const databaseMysqlSecretDefinitions: SecretDefinition[]
store
The MySQL-backed DataStore singleton over the default pool. Wired at startup
via setStore(store) from @molecule/api-database, mirroring the
postgresql/sqlite bonds so the injector's setter/provider pairing
(setStore → store) finds it.
const store: DataStore
Core Interface
Implements @molecule/api-database interface.
Bond Wiring
Setup function to register this provider with the core interface:
import { setPool, setStore } from '@molecule/api-database'
import { pool, store } from '@molecule/api-database-mysql'
export function setupDatabaseMysql(): void {
setPool(pool)
setStore(store)
}
Injection Notes
Requirements
Peer dependencies:
@molecule/api-bond^1.0.1@molecule/api-database^1.1.0@molecule/api-secrets^1.0.1
Environment Variables
MYSQL_URL(required) — MySQL connection URL- Setup: MySQL connection string for your database instance. Alternatively, set the discrete MYSQL_HOST / MYSQL_PORT / MYSQL_DATABASE / MYSQL_USER / MYSQL_PASSWORD vars instead — either form fully configures the connection on its own.
- Example:
mysql://user:pass@localhost:3306/myapp
Runtime Dependencies
-
@molecule/api-bond -
@molecule/api-database -
@molecule/api-secrets -
mysql2 -
Connection config is required, one way or another. Set
MYSQL_URL, OR the discreteMYSQL_HOST/MYSQL_PORT/MYSQL_DATABASE/MYSQL_USER/MYSQL_PASSWORDvars, OR pass an explicit config object tocreatePool(). With NONE of those,createPool()now throws an actionable "MYSQL_URL is not set" error at first use instead of silently connecting asroot@localhostwith no password and failing later with a rawECONNREFUSED/ER_ACCESS_DENIED. -
pool.statsisundefined— mysql2 exposes no public stats API. Call it aspool.stats?.()(theDatabasePoolinterface already marks it optional); a fabricated{ total: 0, idle: 0, waiting: 0 }would read as "pool down" to a health page even on a perfectly healthy connection. Only the postgresql bond returns real counts. -
likeis case-insensitive and does NOT escape the value — the caller's own%/_are honored as wildcards, identical to the postgresql/sqlite bonds. For human-typed search input, useilikeinstead (escapes + auto-wraps%…%) — seeWhereCondition['operator']in@molecule/api-database. -
Each migration file runs ONCE: the
_molecule_migrationstable records it, so an edit to an applied file never runs — change an applied schema in a NEW file. -
A migration file with a genuine error (not an idempotent "already exists") now FAILS the boot with every broken file named, instead of warn-logging and booting with a partial schema.