@mimersql/node-mimer 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mimer Information Technology AB
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,670 @@
1
+ # node-mimer
2
+
3
+ Node.js driver for Mimer SQL using the Mimer SQL C API.
4
+
5
+ ## Features
6
+
7
+ - Direct bindings to the Mimer SQL C API via [Koffi](https://koffi.dev/) FFI - no ODBC required
8
+ - Pure JavaScript - no C++ compiler needed at install time
9
+ - Promise-based API
10
+ - Parameterized queries with `?` placeholders (SQL injection safe)
11
+ - Prepared statements for repeated execution
12
+ - Result metadata with column names, types, and nullability
13
+ - Support for all major Mimer SQL data types (including BLOB, NCLOB, UUID)
14
+ - Transaction support (commit/rollback)
15
+ - Structured error objects with Mimer error codes
16
+ - Cursor support for streaming large result sets (`for await`)
17
+ - Connection pooling with automatic acquire/release
18
+
19
+ ## Prerequisites
20
+
21
+ - Node.js 18.0 or later
22
+ - Mimer SQL 11.0 or later installed (the `libmimerapi` shared library must be available)
23
+
24
+ No C++ compiler is required. The package uses Koffi FFI to call the Mimer SQL C API
25
+ directly from JavaScript.
26
+
27
+ ## Installation
28
+
29
+ ```bash
30
+ npm install @mimersql/node-mimer
31
+ ```
32
+
33
+ That's it. No native compilation, no prebuilt binaries to download.
34
+
35
+ ### Verifying Mimer SQL is found
36
+
37
+ ```bash
38
+ npm run check-mimer
39
+ ```
40
+
41
+ ### Platform-specific library locations
42
+
43
+ **Linux:** `libmimerapi.so` (found via the standard library search path)
44
+
45
+ **macOS:** `/usr/local/lib/libmimerapi.dylib`
46
+
47
+ **Windows:** Automatically detected via `MIMER_HOME` environment variable,
48
+ Windows Registry, or Program Files scan (highest version wins).
49
+
50
+ ## Usage
51
+
52
+ ### Basic Example
53
+
54
+ ```javascript
55
+ const { connect } = require('@mimersql/node-mimer');
56
+
57
+ async function example() {
58
+ // Connect to database
59
+ const client = await connect({
60
+ dsn: 'mydb',
61
+ user: 'SYSADM',
62
+ password: 'password'
63
+ });
64
+
65
+ // Execute a query
66
+ const result = await client.query('SELECT * FROM my_table');
67
+ console.log(result.rows);
68
+
69
+ // Close connection
70
+ await client.close();
71
+ }
72
+
73
+ example();
74
+ ```
75
+
76
+ ### Using Transactions
77
+
78
+ ```javascript
79
+ const { MimerClient } = require('@mimersql/node-mimer');
80
+
81
+ async function transactionExample() {
82
+ const client = new MimerClient();
83
+
84
+ try {
85
+ await client.connect({
86
+ dsn: 'mydb',
87
+ user: 'SYSADM',
88
+ password: 'password'
89
+ });
90
+
91
+ // Start transaction
92
+ await client.beginTransaction();
93
+
94
+ // Execute multiple statements
95
+ await client.query("INSERT INTO accounts VALUES (1, 1000)");
96
+ await client.query("INSERT INTO accounts VALUES (2, 500)");
97
+
98
+ // Commit transaction
99
+ await client.commit();
100
+
101
+ } catch (error) {
102
+ // Rollback on error
103
+ await client.rollback();
104
+ throw error;
105
+ } finally {
106
+ await client.close();
107
+ }
108
+ }
109
+ ```
110
+
111
+ ### Parameterized Queries
112
+
113
+ Use `?` placeholders to pass parameters safely. This prevents SQL injection and
114
+ lets the database optimize execution.
115
+
116
+ ```javascript
117
+ // INSERT with parameters
118
+ await client.query('INSERT INTO users VALUES (?, ?)', [1, 'Anna']);
119
+
120
+ // SELECT with a WHERE parameter
121
+ const result = await client.query(
122
+ 'SELECT * FROM users WHERE id = ?', [1]
123
+ );
124
+
125
+ // Multiple types are supported
126
+ await client.query(
127
+ 'INSERT INTO readings VALUES (?, ?, ?, ?)',
128
+ [42, 'sensor-1', 3.14, true]
129
+ );
130
+
131
+ // NULL values
132
+ await client.query(
133
+ 'INSERT INTO users VALUES (?, ?)', [2, null]
134
+ );
135
+ ```
136
+
137
+ Parameter types are mapped automatically:
138
+
139
+ | JavaScript type | Mimer SQL binding |
140
+ |-----------------|-------------------|
141
+ | `number` (integer) | `INTEGER` or `BIGINT` |
142
+ | `number` (decimal) | `DOUBLE PRECISION` |
143
+ | `string` | `VARCHAR` / `NVARCHAR` |
144
+ | `boolean` | `BOOLEAN` |
145
+ | `null` / `undefined` | `NULL` |
146
+ | `Buffer` | `BINARY` / `BLOB` |
147
+
148
+ ### Prepared Statements
149
+
150
+ For statements executed multiple times with different parameters, prepared
151
+ statements avoid re-parsing the SQL on each call.
152
+
153
+ ```javascript
154
+ // Prepare once
155
+ const stmt = await client.prepare('INSERT INTO users VALUES (?, ?)');
156
+
157
+ // Execute many times with different parameters
158
+ await stmt.execute([1, 'Anna']);
159
+ await stmt.execute([2, 'Fredrik']);
160
+ await stmt.execute([3, 'Charlie']);
161
+
162
+ // Always close when done to release database resources
163
+ await stmt.close();
164
+ ```
165
+
166
+ Prepared SELECT statements work the same way:
167
+
168
+ ```javascript
169
+ const stmt = await client.prepare(
170
+ 'SELECT * FROM users WHERE id = ?'
171
+ );
172
+
173
+ const r1 = await stmt.execute([1]);
174
+ console.log(r1.rows); // [{ id: 1, name: 'Anna' }]
175
+
176
+ const r2 = await stmt.execute([2]);
177
+ console.log(r2.rows); // [{ id: 2, name: 'Fredrik' }]
178
+
179
+ await stmt.close();
180
+ ```
181
+
182
+ ### Cursors (Streaming Large Result Sets)
183
+
184
+ For large result sets, `queryCursor()` returns a cursor that fetches rows one
185
+ at a time instead of loading everything into memory. The cursor implements the
186
+ async iterator protocol, so you can use `for await...of`.
187
+
188
+ ```javascript
189
+ const cursor = await client.queryCursor('SELECT * FROM big_table');
190
+
191
+ for await (const row of cursor) {
192
+ console.log(row);
193
+ if (someDoneCondition) break; // early exit closes the cursor automatically
194
+ }
195
+ ```
196
+
197
+ You can also iterate manually with `next()` and `close()`:
198
+
199
+ ```javascript
200
+ const cursor = await client.queryCursor(
201
+ 'SELECT * FROM orders WHERE status = ?', ['pending']
202
+ );
203
+
204
+ // Column metadata is available immediately
205
+ console.log(cursor.fields);
206
+ // [{ name: 'id', dataTypeCode: 50, dataTypeName: 'INTEGER', nullable: true }, ...]
207
+
208
+ let row;
209
+ while ((row = await cursor.next()) !== null) {
210
+ process(row);
211
+ }
212
+ // cursor closes automatically when exhausted, or call cursor.close() to stop early
213
+ ```
214
+
215
+ `queryCursor()` only accepts SELECT statements. DDL and DML statements are
216
+ rejected with an error.
217
+
218
+ ### Connection Pool
219
+
220
+ For applications that need concurrent database access, the connection pool
221
+ manages a set of reusable connections — lending them out on demand and returning
222
+ them when done.
223
+
224
+ ```javascript
225
+ const { createPool } = require('@mimersql/node-mimer');
226
+
227
+ const pool = createPool({
228
+ dsn: 'mydb',
229
+ user: 'SYSADM',
230
+ password: 'password',
231
+ max: 10, // maximum connections (default 10)
232
+ idleTimeout: 30000, // ms before idle connection is closed (default 30s)
233
+ acquireTimeout: 5000, // ms to wait for a connection (default 5s)
234
+ });
235
+
236
+ // Convenience — auto-acquires and releases a connection
237
+ const result = await pool.query('SELECT * FROM t WHERE id = ?', [1]);
238
+
239
+ // Cursor — connection held until cursor closes
240
+ const cursor = await pool.queryCursor('SELECT * FROM big_table');
241
+ for await (const row of cursor) { ... }
242
+ // connection auto-released when cursor closes or exhausts
243
+
244
+ // Explicit checkout — for transactions or multiple operations
245
+ const client = await pool.connect();
246
+ try {
247
+ await client.beginTransaction();
248
+ await client.query('INSERT INTO t VALUES (?, ?)', [1, 'a']);
249
+ await client.commit();
250
+ } finally {
251
+ client.release(); // return to pool (NOT client.close())
252
+ }
253
+
254
+ // Shutdown — closes all connections
255
+ await pool.end();
256
+ ```
257
+
258
+ ### Result Metadata
259
+
260
+ SELECT queries return a `fields` array with column metadata alongside `rows`.
261
+ This is available even when the query returns zero rows, letting you discover
262
+ column names and types without needing actual data.
263
+
264
+ ```javascript
265
+ const result = await client.query('SELECT id, name FROM users');
266
+
267
+ console.log(result.fields);
268
+ // [
269
+ // { name: 'id', dataTypeCode: 50, dataTypeName: 'INTEGER', nullable: true },
270
+ // { name: 'name', dataTypeCode: 63, dataTypeName: 'NVARCHAR', nullable: false }
271
+ // ]
272
+
273
+ console.log(result.rows);
274
+ // [{ id: 1, name: 'Anna' }, ...]
275
+ ```
276
+
277
+ Each field object contains:
278
+
279
+ | Property | Type | Description |
280
+ |----------|------|-------------|
281
+ | `name` | string | Column name |
282
+ | `dataTypeCode` | number | Numeric Mimer type code |
283
+ | `dataTypeName` | string | Human-readable SQL type (`INTEGER`, `DOUBLE PRECISION`, `BOOLEAN`, etc.) |
284
+ | `nullable` | boolean | Whether the column allows NULL values |
285
+
286
+ Zero-row results still include full metadata:
287
+
288
+ ```javascript
289
+ const result = await client.query('SELECT * FROM users WHERE 1 = 0');
290
+ console.log(result.rowCount); // 0
291
+ console.log(result.fields.length); // 2 — column info is still available
292
+ console.log(result.fields[0].name); // 'id'
293
+ ```
294
+
295
+ DML statements (INSERT, UPDATE, DELETE) do not return `fields` — only
296
+ `rowCount`.
297
+
298
+ Prepared statements also return `fields` on each `execute()`:
299
+
300
+ ```javascript
301
+ const stmt = await client.prepare('SELECT * FROM users WHERE id = ?');
302
+ const result = await stmt.execute([1]);
303
+ console.log(result.fields[0].dataTypeName); // 'INTEGER'
304
+ await stmt.close();
305
+ ```
306
+
307
+ ### Error Handling
308
+
309
+ All errors from the Mimer SQL C API are thrown as JavaScript `Error` objects
310
+ with structured properties:
311
+
312
+ ```javascript
313
+ try {
314
+ await client.query('INSERT INTO nonexistent VALUES (1)');
315
+ } catch (err) {
316
+ console.log(err.message); // Human-readable description
317
+ console.log(err.mimerCode); // Numeric Mimer error code (e.g. -12200)
318
+ console.log(err.operation); // C API function that failed (e.g. "MimerExecute")
319
+ }
320
+ ```
321
+
322
+ This lets you handle specific error conditions programmatically:
323
+
324
+ ```javascript
325
+ try {
326
+ await client.query('CREATE TABLE t1 (id INTEGER)');
327
+ } catch (err) {
328
+ if (err.mimerCode === -12517) {
329
+ // Table already exists — ignore
330
+ } else {
331
+ throw err;
332
+ }
333
+ }
334
+ ```
335
+
336
+ Parameter binding errors also include structured properties:
337
+
338
+ ```javascript
339
+ try {
340
+ // Wrong number of parameters
341
+ await client.query('INSERT INTO users VALUES (?, ?)', [1]);
342
+ } catch (err) {
343
+ console.log(err.mimerCode); // 0 (validation error, not from Mimer API)
344
+ console.log(err.operation); // "BindParameters"
345
+ }
346
+ ```
347
+
348
+ ### Data Type Mapping
349
+
350
+ | Mimer SQL Type | JavaScript Type |
351
+ |----------------|-----------------|
352
+ | INTEGER, SMALLINT | Number |
353
+ | BIGINT | Number |
354
+ | FLOAT, REAL, DOUBLE | Number |
355
+ | VARCHAR, NVARCHAR | String |
356
+ | CHARACTER, NCHAR | String |
357
+ | DATE, TIME, TIMESTAMP | String |
358
+ | DECIMAL, NUMERIC | String |
359
+ | UUID | String |
360
+ | BINARY, VARBINARY | Buffer |
361
+ | BLOB | Buffer |
362
+ | CLOB, NCLOB | String |
363
+ | BOOLEAN | Boolean |
364
+ | NULL | null |
365
+
366
+ ## Backend Selection
367
+
368
+ By default, `node-mimer` uses the Koffi FFI backend (pure JavaScript).
369
+
370
+ If the optional [`node-mimer-native`](https://github.com/user/node-mimer-native)
371
+ package is installed, it will be used instead. This can be useful as a fallback
372
+ if Koffi is ever unavailable for a given platform.
373
+
374
+ You can force a specific backend with the `NODE_MIMER_BACKEND` environment variable:
375
+
376
+ ```bash
377
+ # Force Koffi FFI (default)
378
+ NODE_MIMER_BACKEND=koffi npm test
379
+
380
+ # Force native C++ addon (requires node-mimer-native)
381
+ NODE_MIMER_BACKEND=native npm test
382
+ ```
383
+
384
+ ## API Reference
385
+
386
+ ### MimerClient
387
+
388
+ #### `async connect(options)`
389
+
390
+ Connect to a Mimer SQL database.
391
+
392
+ **Parameters:**
393
+ - `options.dsn` (string): Database name
394
+ - `options.user` (string): Username
395
+ - `options.password` (string): Password
396
+
397
+ #### `async query(sql, params)`
398
+
399
+ Execute a SQL statement with optional parameter binding.
400
+
401
+ **Parameters:**
402
+ - `sql` (string): SQL statement, may contain `?` placeholders
403
+ - `params` (array, optional): Values to bind to `?` placeholders
404
+
405
+ **Returns:** Result object:
406
+ - For SELECT: `{ rows, rowCount, fields }` — `fields` is an array of column metadata
407
+ - For DML (INSERT/UPDATE/DELETE): `{ rowCount }`
408
+ - For DDL (CREATE/DROP/ALTER): `{ rowCount: 0 }`
409
+
410
+ #### `async prepare(sql)`
411
+
412
+ Prepare a SQL statement for repeated execution.
413
+
414
+ **Parameters:**
415
+ - `sql` (string): SQL statement with `?` placeholders
416
+
417
+ **Returns:** `PreparedStatement` instance
418
+
419
+ ### PreparedStatement
420
+
421
+ #### `async execute(params)`
422
+
423
+ Execute the prepared statement with parameter values.
424
+
425
+ **Parameters:**
426
+ - `params` (array, optional): Values to bind to `?` placeholders
427
+
428
+ **Returns:** Result object:
429
+ - For SELECT statements: `{ rows, rowCount, fields }`
430
+ - For DML statements: `{ rowCount }`
431
+
432
+ #### `async close()`
433
+
434
+ Close the prepared statement and release its database resources. The statement
435
+ cannot be used after calling `close()`.
436
+
437
+ #### `async queryCursor(sql, params)`
438
+
439
+ Execute a SELECT query and return a cursor for row-at-a-time streaming.
440
+
441
+ **Parameters:**
442
+ - `sql` (string): SELECT statement, may contain `?` placeholders
443
+ - `params` (array, optional): Values to bind to `?` placeholders
444
+
445
+ **Returns:** `ResultSet` instance
446
+
447
+ **Throws:** Error if `sql` is a DDL or DML statement.
448
+
449
+ ### ResultSet
450
+
451
+ Returned by `queryCursor()`. Fetches rows one at a time from an open
452
+ database cursor. Implements `Symbol.asyncIterator` for `for await...of`.
453
+
454
+ #### `fields`
455
+
456
+ Column metadata array (same format as `query()` results). Available
457
+ immediately after creation.
458
+
459
+ #### `async next()`
460
+
461
+ Fetch the next row as a plain object, or `null` when all rows have been read.
462
+ The cursor closes automatically when exhausted.
463
+
464
+ #### `async close()`
465
+
466
+ Close the cursor and release database resources. Safe to call multiple times.
467
+ Called automatically when `for await...of` ends or `break`s.
468
+
469
+ #### `async beginTransaction()`
470
+
471
+ Begin a new transaction.
472
+
473
+ #### `async commit()`
474
+
475
+ Commit the current transaction.
476
+
477
+ #### `async rollback()`
478
+
479
+ Rollback the current transaction.
480
+
481
+ #### `async close()`
482
+
483
+ Close the database connection.
484
+
485
+ #### `isConnected()`
486
+
487
+ Check if connected to database.
488
+
489
+ **Returns:** boolean
490
+
491
+ ### Pool
492
+
493
+ #### `createPool(options)`
494
+
495
+ Create a new connection pool.
496
+
497
+ **Parameters:**
498
+ - `options.dsn` (string): Database name
499
+ - `options.user` (string): Username
500
+ - `options.password` (string): Password
501
+ - `options.max` (number, optional): Maximum connections (default 10)
502
+ - `options.idleTimeout` (number, optional): Ms before idle connection is closed (default 30000)
503
+ - `options.acquireTimeout` (number, optional): Ms to wait for a connection (default 5000)
504
+
505
+ **Returns:** `Pool` instance
506
+
507
+ #### `async pool.query(sql, params)`
508
+
509
+ Acquire a connection, execute the query, and release the connection.
510
+
511
+ **Returns:** Result object (same as `MimerClient.query()`)
512
+
513
+ #### `async pool.queryCursor(sql, params)`
514
+
515
+ Acquire a connection and open a cursor. The connection is automatically
516
+ released when the cursor closes or is exhausted.
517
+
518
+ **Returns:** `ResultSet` instance
519
+
520
+ #### `async pool.connect()`
521
+
522
+ Check out a connection for multiple operations (e.g. transactions).
523
+
524
+ **Returns:** `PoolClient` instance
525
+
526
+ #### `async pool.end()`
527
+
528
+ Close all idle connections and reject pending waiters. Operations after
529
+ `end()` will reject with an error.
530
+
531
+ ### PoolClient
532
+
533
+ Returned by `pool.connect()`. Delegates `query()`, `queryCursor()`,
534
+ `prepare()`, `beginTransaction()`, `commit()`, and `rollback()` to the
535
+ underlying `MimerClient`.
536
+
537
+ #### `release()`
538
+
539
+ Return the connection to the pool. Always call this instead of `close()`.
540
+ Safe to call multiple times.
541
+
542
+ ### Helper Functions
543
+
544
+ #### `async connect(options)`
545
+
546
+ Create and connect a new MimerClient instance.
547
+
548
+ **Returns:** Connected MimerClient instance
549
+
550
+ ## Testing
551
+
552
+ Tests use the Node.js built-in test runner (`node:test`) and are split into
553
+ focused files by category:
554
+
555
+ ```
556
+ test/
557
+ helper.js # Shared utilities (createClient, dropTable)
558
+ connection.test.js # Connect, isConnected, close
559
+ basic-queries.test.js # DDL, DML, SELECT
560
+ transactions.test.js # beginTransaction, commit, rollback
561
+ result-metadata.test.js # fields array, properties, edge cases
562
+ unicode.test.js # NVARCHAR round-trip, Unicode WHERE
563
+ parameterized-queries.test.js # ? params, types, NULL, mismatch error
564
+ prepared-statements.test.js # prepare/execute/close lifecycle
565
+ cursor.test.js # queryCursor, for-await-of, early break
566
+ error-handling.test.js # Structured errors (mimerCode, operation)
567
+ pool.test.js # Connection pool, PoolClient, auto-release
568
+ ```
569
+
570
+ ```bash
571
+ # Run all tests (requires a running Mimer SQL instance)
572
+ npm test
573
+
574
+ # Run a single test file
575
+ node --test test/unicode.test.js
576
+
577
+ # Test with a specific backend
578
+ NODE_MIMER_BACKEND=koffi npm test
579
+ NODE_MIMER_BACKEND=native npm test # requires node-mimer-native
580
+ ```
581
+
582
+ ## Architecture
583
+
584
+ The library has two layers:
585
+
586
+ ```
587
+ Application (JavaScript)
588
+ |
589
+ | require('@mimersql/node-mimer')
590
+ v
591
+ JavaScript Wrapper (Promise-based)
592
+ index.js, lib/client.js, lib/prepared.js,
593
+ lib/resultset.js, lib/pool.js
594
+ |
595
+ | lib/native.js (backend selection)
596
+ v
597
+ Koffi FFI Backend (lib/koffi-binding.js)
598
+ — or —
599
+ node-mimer-native (C++ addon, optional)
600
+ |
601
+ | FFI / Node-API calls
602
+ v
603
+ Mimer SQL C API (libmimerapi.so)
604
+ |
605
+ v
606
+ Mimer SQL Database
607
+ ```
608
+
609
+ The Koffi FFI backend (`lib/koffi-binding.js`) calls the Mimer SQL C API
610
+ functions directly using [Koffi](https://koffi.dev/), an FFI library that ships
611
+ its own prebuilt binaries. This means `node-mimer` is a pure JavaScript package
612
+ with no native compilation step.
613
+
614
+ The optional `node-mimer-native` package provides the same interface using a
615
+ C++ Node-API addon. It can be installed alongside `node-mimer` as a drop-in
616
+ replacement if needed.
617
+
618
+ ### Mimer SQL C API Functions Used
619
+
620
+ - `MimerBeginSession8()` - Establish database connection
621
+ - `MimerEndSession()` - Close connection
622
+ - `MimerBeginStatement8()` - Prepare SQL statements
623
+ - `MimerExecuteStatement8()` - Execute DDL statements directly
624
+ - `MimerOpenCursor()` / `MimerFetch()` - Fetch result rows
625
+ - `MimerGetString8()`, `MimerGetInt32()`, etc. - Get column values
626
+ - `MimerSetString8()`, `MimerSetInt32()`, etc. - Bind parameter values
627
+ - `MimerSetLob()` / `MimerSetBlobData()` / `MimerSetNclobData8()` - Write LOBs
628
+ - `MimerGetLob()` / `MimerGetBlobData()` / `MimerGetNclobData8()` - Read LOBs
629
+ - `MimerBeginTransaction()` / `MimerEndTransaction()` - Transaction control
630
+ - `MimerGetError8()` - Error handling
631
+
632
+ ## File Structure
633
+
634
+ ```
635
+ node-mimer/
636
+ ├── lib/ # JavaScript modules
637
+ │ ├── native.js # Backend selection (Koffi or native)
638
+ │ ├── koffi-binding.js # Koffi FFI backend
639
+ │ ├── find-mimer-library.js # Platform-specific library detection
640
+ │ ├── client.js # MimerClient, connect()
641
+ │ ├── prepared.js # PreparedStatement
642
+ │ ├── resultset.js # ResultSet (cursor wrapper)
643
+ │ └── pool.js # Pool, PoolClient
644
+
645
+ ├── scripts/
646
+ │ └── check-mimer.js # Verify Mimer installation
647
+
648
+ ├── index.js # Re-exports from lib/
649
+ ├── index.d.ts # TypeScript type definitions
650
+ ├── package.json
651
+ ├── README.md
652
+
653
+ └── test/
654
+ ├── helper.js # Shared test utilities
655
+ └── *.test.js # Test suites (node:test)
656
+ ```
657
+
658
+ ## License
659
+
660
+ MIT
661
+
662
+ ## Contributing
663
+
664
+ Contributions are welcome! Please submit pull requests or open issues on GitHub.
665
+
666
+ ## References
667
+
668
+ - [Mimer SQL Documentation](https://developer.mimer.com/documentation)
669
+ - [Mimer SQL C API Reference](https://developer.mimer.com/mimerapi)
670
+ - [Koffi FFI Library](https://koffi.dev/)