@stoolap/node 0.3.5 → 0.3.7
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/README.md +19 -0
- package/index.d.ts +6 -0
- package/lib/database.js +8 -0
- package/package.json +6 -6
- package/src/stoolap.c +33 -5
package/README.md
CHANGED
|
@@ -108,6 +108,7 @@ Sync methods run on the main thread. Faster for simple operations but block the
|
|
|
108
108
|
| Method | Returns | Description |
|
|
109
109
|
|--------|---------|-------------|
|
|
110
110
|
| `Database.openSync(path)` | `Database` | Open a database |
|
|
111
|
+
| `clone()` | `Database` | Clone handle (shared engine, own state) |
|
|
111
112
|
| `executeSync(sql, params?)` | `RunResult` | Execute DML statement |
|
|
112
113
|
| `execSync(sql)` | `void` | Execute a DDL statement |
|
|
113
114
|
| `querySync(sql, params?)` | `Object[]` | Query rows as objects |
|
|
@@ -189,6 +190,24 @@ Controls the durability vs. performance trade-off:
|
|
|
189
190
|
| `compression` | | Set both `wal_compression` and `snapshot_compression` |
|
|
190
191
|
| `compression_threshold` | `64` | Minimum bytes before compressing an entry |
|
|
191
192
|
|
|
193
|
+
#### Cloning
|
|
194
|
+
|
|
195
|
+
`clone()` creates a new `Database` handle that shares the same underlying engine (data, indexes, transactions) but has its own executor and error state. Useful for concurrent access patterns such as worker threads.
|
|
196
|
+
|
|
197
|
+
```js
|
|
198
|
+
const db = await Database.open('./mydata');
|
|
199
|
+
const db2 = db.clone();
|
|
200
|
+
|
|
201
|
+
// Both see the same data
|
|
202
|
+
await db.execute('INSERT INTO users VALUES ($1, $2)', [1, 'Alice']);
|
|
203
|
+
const row = db2.queryOneSync('SELECT * FROM users WHERE id = $1', [1]);
|
|
204
|
+
// { id: 1, name: 'Alice' }
|
|
205
|
+
|
|
206
|
+
// Each clone must be closed independently
|
|
207
|
+
await db2.close();
|
|
208
|
+
await db.close();
|
|
209
|
+
```
|
|
210
|
+
|
|
192
211
|
#### Raw Query Format
|
|
193
212
|
|
|
194
213
|
`queryRaw` / `queryRawSync` return `{ columns: string[], rows: any[][] }` instead of an array of objects. Faster when you don't need named keys.
|
package/index.d.ts
CHANGED
|
@@ -17,6 +17,12 @@ export declare class Database {
|
|
|
17
17
|
* Open a database synchronously.
|
|
18
18
|
*/
|
|
19
19
|
static openSync(path: string): Database;
|
|
20
|
+
/**
|
|
21
|
+
* Clone this database handle. The clone shares the same underlying engine
|
|
22
|
+
* (data, indexes, transactions) but has its own executor and error state.
|
|
23
|
+
* Each clone must be closed independently.
|
|
24
|
+
*/
|
|
25
|
+
clone(): Database;
|
|
20
26
|
/**
|
|
21
27
|
* Execute a DDL/DML statement. Returns Promise<{ changes: number }>.
|
|
22
28
|
*
|
package/lib/database.js
CHANGED
|
@@ -128,6 +128,14 @@ class Database {
|
|
|
128
128
|
return this.#stoolap.dbExecBatchBuf(this.#ptr, sql, batchBuf);
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
// -- Clone --
|
|
132
|
+
|
|
133
|
+
clone() {
|
|
134
|
+
this.#checkOpen();
|
|
135
|
+
const clonedPtr = this.#stoolap.dbClone(this.#ptr);
|
|
136
|
+
return new Database(clonedPtr, this.#stoolap);
|
|
137
|
+
}
|
|
138
|
+
|
|
131
139
|
// -- Execute (DML) --
|
|
132
140
|
|
|
133
141
|
async execute(sql, params) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stoolap/node",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "High-performance Node.js driver for Stoolap embedded SQL database",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
"bench": "node benchmark.mjs"
|
|
19
19
|
},
|
|
20
20
|
"optionalDependencies": {
|
|
21
|
-
"@stoolap/lib-darwin-arm64": "0.3.
|
|
22
|
-
"@stoolap/lib-darwin-x64": "0.3.
|
|
23
|
-
"@stoolap/lib-linux-arm64-gnu": "0.3.
|
|
24
|
-
"@stoolap/lib-linux-x64-gnu": "0.3.
|
|
25
|
-
"@stoolap/lib-win32-x64-msvc": "0.3.
|
|
21
|
+
"@stoolap/lib-darwin-arm64": "0.3.7",
|
|
22
|
+
"@stoolap/lib-darwin-x64": "0.3.7",
|
|
23
|
+
"@stoolap/lib-linux-arm64-gnu": "0.3.7",
|
|
24
|
+
"@stoolap/lib-linux-x64-gnu": "0.3.7",
|
|
25
|
+
"@stoolap/lib-win32-x64-msvc": "0.3.7"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"better-sqlite3": "^12.6.2",
|
package/src/stoolap.c
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
#include <stdlib.h>
|
|
13
13
|
#include <string.h>
|
|
14
14
|
#include <stdint.h>
|
|
15
|
+
#include <stdio.h>
|
|
15
16
|
|
|
16
17
|
#ifdef _WIN32
|
|
17
18
|
#include <windows.h>
|
|
@@ -68,6 +69,7 @@ typedef struct {
|
|
|
68
69
|
typedef const char* (*fn_version)(void);
|
|
69
70
|
typedef int32_t (*fn_open)(const char*, StoolapDB**);
|
|
70
71
|
typedef int32_t (*fn_open_mem)(StoolapDB**);
|
|
72
|
+
typedef int32_t (*fn_clone)(StoolapDB*, StoolapDB**);
|
|
71
73
|
typedef int32_t (*fn_close)(StoolapDB*);
|
|
72
74
|
typedef const char* (*fn_errmsg)(const StoolapDB*);
|
|
73
75
|
typedef int32_t (*fn_exec)(StoolapDB*, const char*, int64_t*);
|
|
@@ -112,6 +114,7 @@ static struct {
|
|
|
112
114
|
fn_version version;
|
|
113
115
|
fn_open open;
|
|
114
116
|
fn_open_mem open_mem;
|
|
117
|
+
fn_clone clone;
|
|
115
118
|
fn_close close;
|
|
116
119
|
fn_errmsg errmsg;
|
|
117
120
|
fn_exec exec;
|
|
@@ -156,6 +159,8 @@ static LibHandle lib_handle = NULL;
|
|
|
156
159
|
/* ---- Helpers ---- */
|
|
157
160
|
|
|
158
161
|
#define THROW(env, msg) do { napi_throw_error(env, NULL, msg); return NULL; } while(0)
|
|
162
|
+
#define ERR_SAVE(msg, fallback) \
|
|
163
|
+
char _eb[512]; snprintf(_eb, sizeof(_eb), "%s", (msg) ? (msg) : (fallback))
|
|
159
164
|
#define CHECK(env, status) if ((status) != napi_ok) return NULL
|
|
160
165
|
|
|
161
166
|
static napi_value make_changes(napi_env env, int64_t n) {
|
|
@@ -1510,6 +1515,7 @@ static napi_value fn_load_library(napi_env env, napi_callback_info info) {
|
|
|
1510
1515
|
LOAD(version, "stoolap_version");
|
|
1511
1516
|
LOAD(open, "stoolap_open");
|
|
1512
1517
|
LOAD(open_mem, "stoolap_open_in_memory");
|
|
1518
|
+
LOAD(clone, "stoolap_clone");
|
|
1513
1519
|
LOAD(close, "stoolap_close");
|
|
1514
1520
|
LOAD(errmsg, "stoolap_errmsg");
|
|
1515
1521
|
LOAD(exec, "stoolap_exec");
|
|
@@ -1586,6 +1592,27 @@ static napi_value fn_db_open(napi_env env, napi_callback_info info) {
|
|
|
1586
1592
|
return ext;
|
|
1587
1593
|
}
|
|
1588
1594
|
|
|
1595
|
+
/* dbClone(external): external */
|
|
1596
|
+
static napi_value fn_db_clone(napi_env env, napi_callback_info info) {
|
|
1597
|
+
size_t argc = 1;
|
|
1598
|
+
napi_value argv[1];
|
|
1599
|
+
napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
|
|
1600
|
+
|
|
1601
|
+
StoolapDB* db;
|
|
1602
|
+
napi_get_value_external(env, argv[0], (void**)&db);
|
|
1603
|
+
|
|
1604
|
+
StoolapDB* cloned = NULL;
|
|
1605
|
+
int32_t rc = S.clone(db, &cloned);
|
|
1606
|
+
if (rc != STOOLAP_OK) {
|
|
1607
|
+
const char* msg = S.errmsg(db);
|
|
1608
|
+
THROW(env, msg ? msg : "Failed to clone database");
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
napi_value ext;
|
|
1612
|
+
napi_create_external(env, cloned, NULL, NULL, &ext);
|
|
1613
|
+
return ext;
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1589
1616
|
/* dbClose(external): void */
|
|
1590
1617
|
static napi_value fn_db_close(napi_env env, napi_callback_info info) {
|
|
1591
1618
|
size_t argc = 1;
|
|
@@ -3023,10 +3050,10 @@ static napi_value wrap_tx_exec_batch(napi_env env, napi_callback_info info) {
|
|
|
3023
3050
|
for (int k = 0; k < tbuf_cnt; k++) { free(tbufs[k]); tbufs[k] = NULL; }
|
|
3024
3051
|
|
|
3025
3052
|
if (rc != STOOLAP_OK) {
|
|
3053
|
+
ERR_SAVE(S.tx_errmsg(tx), "Transaction batch exec error");
|
|
3026
3054
|
free(vals); free(tbufs);
|
|
3027
|
-
const char* msg = S.tx_errmsg(tx);
|
|
3028
3055
|
if (stmt) S.stmt_finalize(stmt);
|
|
3029
|
-
THROW(env,
|
|
3056
|
+
THROW(env, _eb);
|
|
3030
3057
|
}
|
|
3031
3058
|
|
|
3032
3059
|
total_affected += affected;
|
|
@@ -3202,7 +3229,7 @@ static napi_value wrap_db_exec_batch_buf(napi_env env, napi_callback_info info)
|
|
|
3202
3229
|
int use_stmt = (S.tx_stmt_exec != NULL);
|
|
3203
3230
|
if (use_stmt) {
|
|
3204
3231
|
rc = S.prepare(db, sql, &stmt);
|
|
3205
|
-
if (rc != STOOLAP_OK) { S.
|
|
3232
|
+
if (rc != STOOLAP_OK) { ERR_SAVE(S.errmsg(db), "Prepare error"); S.tx_rollback(tx); THROW(env, _eb); }
|
|
3206
3233
|
}
|
|
3207
3234
|
int64_t total = 0;
|
|
3208
3235
|
for (uint32_t i = 0; i < row_count; i++) {
|
|
@@ -3217,12 +3244,12 @@ static napi_value wrap_db_exec_batch_buf(napi_env env, napi_callback_info info)
|
|
|
3217
3244
|
} else {
|
|
3218
3245
|
rc = S.tx_exec_p(tx, sql, vals, decoded, &affected);
|
|
3219
3246
|
}
|
|
3220
|
-
if (rc != STOOLAP_OK) {
|
|
3247
|
+
if (rc != STOOLAP_OK) { ERR_SAVE(S.tx_errmsg(tx), "Batch exec error"); if (stmt) S.stmt_finalize(stmt); S.tx_rollback(tx); THROW(env, _eb); }
|
|
3221
3248
|
total += affected;
|
|
3222
3249
|
}
|
|
3223
3250
|
if (stmt) S.stmt_finalize(stmt);
|
|
3224
3251
|
rc = S.tx_commit(tx);
|
|
3225
|
-
if (rc != STOOLAP_OK) {
|
|
3252
|
+
if (rc != STOOLAP_OK) { THROW(env, "Commit error"); }
|
|
3226
3253
|
return make_changes(env, total);
|
|
3227
3254
|
}
|
|
3228
3255
|
|
|
@@ -3278,6 +3305,7 @@ static napi_value Init(napi_env env, napi_value exports) {
|
|
|
3278
3305
|
EXPORT_FN(env, exports, "loadLibrary", fn_load_library);
|
|
3279
3306
|
EXPORT_FN(env, exports, "dbOpen", fn_db_open);
|
|
3280
3307
|
EXPORT_FN(env, exports, "dbOpenAsync", fn_db_open_async);
|
|
3308
|
+
EXPORT_FN(env, exports, "dbClone", fn_db_clone);
|
|
3281
3309
|
EXPORT_FN(env, exports, "dbClose", fn_db_close);
|
|
3282
3310
|
EXPORT_FN(env, exports, "dbCloseAsync", fn_db_close_async);
|
|
3283
3311
|
EXPORT_FN(env, exports, "dbExec", fn_db_exec);
|