Node.js bindings for Mimer SQL using a C++ native addon (Node-API) to call the Mimer SQL C API. Prebuilt binaries are shipped for supported platforms.
┌────────────────────────────┐
│ Application (JavaScript) │
└────────────┬───────────────┘
│
│ require('@mimersql/node-mimer')
▼
┌────────────────────────────┐
│ node-mimer (JavaScript) │
│ index.js │
│ - MimerClient │
│ - Promise-based API │
└────────────┬───────────────┘
│ lib/native.js
▼
┌────────────────────────────┐
│ C++ Native Addon │
│ src/connection.cc │
│ src/statement.cc │
│ src/resultset.cc │
│ src/helpers.cc │
└────────────┬───────────────┘
│ C API calls
▼
┌────────────────────────────┐
│ Mimer SQL C API │
│ libmimerapi.so │
└────────────┬───────────────┘
│
▼
┌────────────────────────────┐
│ Mimer SQL Database │
└────────────────────────────┘
Prebuilt .node binaries are shipped in the npm package for supported platforms.
At install time, prebuild-install loads the matching binary. If no prebuilt is
available, the addon is compiled from source using node-gyp.
Native C library included with the Mimer SQL installation.
Key functions:
MimerBeginSession8()- Connect to databaseMimerEndSession()- Close connectionMimerBeginStatement8()/MimerExecuteStatement8()- Execute SQLMimerOpenCursor()/MimerFetch()- Fetch resultsMimerColumnCount(),MimerColumnName8(),MimerColumnType()- Column metadataMimerGetString8(),MimerGetInt32(), etc. - Read column valuesMimerSetString8(),MimerSetInt32(), etc. - Bind parametersMimerBeginTransaction()/MimerEndTransaction()- Transaction controlMimerGetError8()- Error handlingMimerGetLob()/MimerGetBlobData()/MimerGetNclobData8()- LOB readingMimerSetLob()/MimerSetBlobData()/MimerSetNclobData8()- LOB writing
C++ addon that calls the Mimer SQL C API directly. Uses Node-API (N-API v8) for ABI stability across Node.js versions.
Source files:
src/mimer_addon.cc- Module entry pointsrc/connection.cc/h- Connection classsrc/statement.cc/h- Prepared statement classsrc/resultset.cc/h- Cursor/streaming result set classsrc/helpers.cc/h- Parameter binding, row fetching, error handling
Build configuration:
binding.gyp- Node-gyp build config (platform-specific linking)scripts/find-mimer-windows.js- Auto-detect Mimer SQL installation on Windows
Exported classes:
class Connection {
connect(dsn, user, password); // Connect
execute(sql, params); // Execute query with optional params
prepare(sql); // Create prepared statement
executeQuery(sql, params); // Open cursor for streaming results
beginTransaction(); // Start explicit transaction
commit() / rollback(); // End transaction
close(); // Close connection
isConnected(); // Check connection state
}
class Statement {
execute(params); // Execute with params, reusable
close(); // Release statement handle
}
class ResultSet {
fetchNext(); // Fetch one row, or null at end
getFields(); // Column metadata array
close(); // Close cursor and release handle
isClosed(); // Check if cursor is closed
}Promise-based JavaScript API that wraps the binding layer.
Files: index.js (re-exports), lib/client.js, lib/prepared.js, lib/resultset.js, lib/pool.js
Classes: MimerClient, PreparedStatement, ResultSet, Pool, PoolClient
const client = new MimerClient();
await client.connect({ dsn, user, password });
// Simple query
const result = await client.query('SELECT ...');
// Parameterized query
await client.query('INSERT INTO t VALUES (?, ?)', [1, 'hello']);
// Prepared statement (reusable)
const stmt = await client.prepare('SELECT * FROM t WHERE id = ?');
const r1 = await stmt.execute([1]);
const r2 = await stmt.execute([2]);
await stmt.close();
// Cursor for streaming large result sets
const cursor = await client.queryCursor('SELECT * FROM big_table');
for await (const row of cursor) {
process(row);
}
await client.commit();
await client.close();Connection Pool:
const { createPool } = require('@mimersql/node-mimer');
const pool = createPool({ dsn, user, password, max: 10 });
// Auto-acquire/release
const result = await pool.query('SELECT * FROM t');
// Explicit checkout for transactions
const client = await pool.connect();
await client.beginTransaction();
await client.query('INSERT INTO t VALUES (?)', [1]);
await client.commit();
client.release();
await pool.end();lib/native.js uses node-gyp-build
to load the native addon:
- Prebuilt binary from
prebuilds/<platform>-<arch>/(shipped in the npm package) - Dev build from
build/Release/(compiled locally vianode-gyp rebuild)
The install script (prebuild-install || node-gyp rebuild) ensures a binary is
available after npm install.
npm install @mimersql/node-mimerPrebuilt binaries are included for supported platforms. On other platforms, the
addon is compiled from source (requires a C++ compiler and Mimer SQL development
headers). The Mimer SQL client runtime (libmimerapi.so / libmimerapi.dylib /
mimapi64.dll) must be installed on the system.
node-mimer/
├── src/ # C++ native addon
│ ├── mimer_addon.cc # Module entry point
│ ├── connection.cc/h # Connection class
│ ├── statement.cc/h # Prepared statement class
│ ├── resultset.cc/h # Cursor/streaming result set class
│ └── helpers.cc/h # Parameter binding, row fetching, errors
│
├── lib/ # JavaScript source
│ ├── native.js # Loads native addon via node-gyp-build
│ ├── client.js # MimerClient, connect()
│ ├── prepared.js # PreparedStatement
│ ├── resultset.js # ResultSet (cursor wrapper)
│ └── pool.js # Pool, PoolClient
│
├── prebuilds/ # Prebuilt binaries (per platform)
│ └── linux-x64/ # Example: Linux x64 binary
│
├── scripts/
│ ├── check-mimer.js # Verify Mimer installation
│ └── find-mimer-windows.js # Auto-detect Mimer on Windows
│
├── binding.gyp # Native addon build configuration
├── index.js # Re-exports from lib/
├── index.d.ts # TypeScript type definitions
├── package.json # npm configuration
├── README.md # User documentation
│
└── test/
├── helper.js # Shared test utilities
├── *.test.js # Test suites (node:test)
└── test.js # Legacy usage example
- Node-API (N-API v8) — ABI-stable across Node.js versions, no recompilation needed
- Prebuilt binaries — shipped in the npm package for supported platforms (~200KB compressed)
- Fallback compilation —
node-gyp rebuildif no prebuilt is available - Direct C API access — calls
libmimerapifunctions directly from C++
- Modern JavaScript idiom
- Simpler error handling
- Works well with async/await
- DDL statements (CREATE, DROP, ALTER) are executed directly via
MimerExecuteStatement8since they cannot be prepared - DML and queries use
MimerBeginStatement8for preparation, thenMimerOpenCursor/MimerFetchfor SELECT orMimerExecutefor INSERT/UPDATE/DELETE - Column type detection uses ported Mimer helper macros (
mimerIsInt32,mimerIsString, etc.)
- By default, each DML statement auto-commits
- Explicit transactions are started with
MimerBeginTransactionand ended withMimerEndTransaction - DDL statements always auto-commit regardless of transaction state
| Mimer SQL | C++ Type | JavaScript |
|---|---|---|
| INTEGER | int32_t | Number |
| BIGINT | int64_t | Number |
| FLOAT/DOUBLE | double | Number |
| REAL | float | Number |
| VARCHAR/NVARCHAR | char* | String |
| BINARY/VARBINARY | uint8_t* | Buffer |
| BOOLEAN | int32_t | Boolean |
| DATE/TIME/TIMESTAMP | char* | String |
| BLOB | chunked read | Buffer |
| NCLOB | chunked read | String |
| UUID | char* | String |
SELECT queries include a fields array with column metadata, built from
MimerColumnName8 and MimerColumnType before row fetching begins. This
means metadata is available even when a query returns zero rows.
const result = await client.query('SELECT id, name FROM users WHERE 1 = 0');
// result.rowCount === 0
// result.fields === [
// { name: 'id', dataTypeCode: 50, dataTypeName: 'INTEGER', nullable: true },
// { name: 'name', dataTypeCode: 63, dataTypeName: 'NVARCHAR', nullable: false }
// ]Nullability detection uses two Mimer conventions:
- Non-native types: a negative
dataTypeCodemeans nullable - Native types: explicit
_NULLABLEvariant codes (e.g.MIMER_NATIVE_INTEGER_NULLABLE= 50 vsMIMER_NATIVE_INTEGER= 49)
The dataTypeName is resolved by mimerTypeName() in the native addon, mapping
~40 Mimer type constants to standard SQL type names.
DML results (INSERT/UPDATE/DELETE) only contain rowCount — no fields.
Errors propagate through all layers as structured JavaScript Error objects:
Mimer SQL C API Error
↓ (MimerGetError8)
CheckError() in helpers.cc
↓ (Napi::Error with mimerCode + operation properties)
JavaScript Exception
↓ (Promise rejection)
Application Error Handler
Every error thrown by a Mimer C API call includes:
| Property | Type | Description |
|---|---|---|
message |
string | Human-readable error description |
mimerCode |
number | Numeric Mimer error code (e.g. -12200) |
operation |
string | The C API function that failed (e.g. "MimerOpenCursor") |
try {
await client.query('SELECT * FROM nonexistent');
} catch (err) {
console.log(err.message); // "MimerOpenCursor failed: ... (code: -12200)"
console.log(err.mimerCode); // -12200
console.log(err.operation); // "MimerOpenCursor"
}queryCursor() opens a server-side cursor and returns a ResultSet that
fetches rows one at a time, keeping memory usage constant regardless of result
set size.
client.queryCursor(sql, params)
→ Connection.executeQuery()
→ MimerBeginStatement8 (prepare)
→ bindParameters (if params)
→ MimerOpenCursor (open cursor)
→ create ResultSet (owns the stmt handle)
cursor.next()
→ ResultSet.fetchNext()
→ MimerFetch (advance cursor one row)
→ fetchSingleRow (read column values)
→ return JS object (or null at end)
cursor.close()
→ ResultSet.close()
→ MimerCloseCursor
→ MimerEndStatement
// Async iteration (recommended)
const cursor = await client.queryCursor('SELECT * FROM t WHERE x > ?', [100]);
for await (const row of cursor) {
process(row);
if (done) break; // triggers cursor.close() automatically
}
// Manual iteration
const cursor = await client.queryCursor('SELECT * FROM t');
console.log(cursor.fields); // column metadata
let row;
while ((row = await cursor.next()) !== null) {
process(row);
}
// auto-closed when exhausted, or call cursor.close() to stop earlyOnly SELECT statements are accepted — DDL and DML are rejected with an error.
Tests use the Node.js built-in test runner (node:test) with describe/it
blocks and assert/strict. Each test file covers one area and uses isolated
table names to avoid collisions when files run in sequence.
test/
helper.js # createClient(), dropTable()
connection.test.js # Connect, isConnected, close
basic-queries.test.js # DDL, DML, SELECT
transactions.test.js # beginTransaction, commit, rollback
result-metadata.test.js # fields array, properties, edge cases
unicode.test.js # NVARCHAR round-trip, Unicode WHERE
parameterized-queries.test.js # ? params, types, NULL, mismatch error
prepared-statements.test.js # prepare/execute/close lifecycle
cursor.test.js # queryCursor, for-await-of, early break
error-handling.test.js # Structured errors (mimerCode, operation)
pool.test.js # Connection pool, PoolClient, auto-release
test.js # Legacy usage example (not run by npm test)
# Run all tests (requires a running Mimer SQL instance)
npm test
# Run a single test file
node --test test/unicode.test.jsProblem: "Cannot find libmimerapi.so" or similar library loading error
- Make sure Mimer SQL client runtime is installed
- Linux:
ls /usr/lib/libmimerapi.so* - macOS:
ls /usr/local/lib/libmimerapi.dylib - Windows: Verify Mimer SQL installation and that
mimapi64.dllis accessible
Problem: "Cannot connect to database"
- Verify Mimer SQL is running
- Check DSN, user, password
- Test with
bsqlfirst
MIT License
- Mimer SQL Docs: https://developer.mimer.com/documentation
- Mimer SQL C API Reference: https://developer.mimer.com/mimerapi
- Node-API: https://nodejs.org/api/n-api.html