@barakxyz/better-sqlite3 12.7.0 → 12.8.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/lib/database.js
CHANGED
|
@@ -76,6 +76,7 @@ Database.prototype.prepare = wrappers.prepare;
|
|
|
76
76
|
Database.prototype.transaction = require('./methods/transaction');
|
|
77
77
|
Database.prototype.pragma = require('./methods/pragma');
|
|
78
78
|
Database.prototype.backup = require('./methods/backup');
|
|
79
|
+
Database.prototype.backupFrom = require('./methods/backupFrom');
|
|
79
80
|
Database.prototype.serialize = require('./methods/serialize');
|
|
80
81
|
Database.prototype.deserialize = require('./methods/deserialize');
|
|
81
82
|
Database.prototype.function = require('./methods/function');
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const { cppdb } = require('../util');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Synchronous backup from another database to this database.
|
|
6
|
+
* Matches wa-sqlite's sqlite3.backup(dest, destName, source, sourceName) pattern.
|
|
7
|
+
*
|
|
8
|
+
* @param {Database} sourceDb - The source Database instance to backup from
|
|
9
|
+
* @param {string} [destName='main'] - The attached database name for destination
|
|
10
|
+
* @param {string} [srcName='main'] - The attached database name for source
|
|
11
|
+
* @returns {this} The database instance for chaining
|
|
12
|
+
*/
|
|
13
|
+
module.exports = function backupFrom(sourceDb, destName, srcName) {
|
|
14
|
+
// Validate sourceDb is a Database instance (must have cppdb symbol)
|
|
15
|
+
if (sourceDb == null || typeof sourceDb !== 'object' || !sourceDb[cppdb]) {
|
|
16
|
+
throw new TypeError('Expected first argument to be a Database instance');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Validate optional string arguments
|
|
20
|
+
if (destName !== undefined && typeof destName !== 'string') {
|
|
21
|
+
throw new TypeError('Expected second argument to be a string');
|
|
22
|
+
}
|
|
23
|
+
if (srcName !== undefined && typeof srcName !== 'string') {
|
|
24
|
+
throw new TypeError('Expected third argument to be a string');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Pass the native cppdb object from source, not the JS wrapper
|
|
28
|
+
// The C++ side unwraps it to get the Database pointer
|
|
29
|
+
this[cppdb].backupFrom(sourceDb[cppdb], destName, srcName);
|
|
30
|
+
return this;
|
|
31
|
+
};
|
|
@@ -4,14 +4,13 @@ const { cppdb } = require('../util');
|
|
|
4
4
|
/**
|
|
5
5
|
* Deserialize a buffer into the database.
|
|
6
6
|
*
|
|
7
|
-
* Uses the safe pattern:
|
|
7
|
+
* Uses the safe pattern (matches wa-sqlite's import pattern):
|
|
8
8
|
* 1. Create temp in-memory database
|
|
9
9
|
* 2. Deserialize buffer into temp
|
|
10
10
|
* 3. Backup from temp to current database
|
|
11
11
|
* 4. Close temp database
|
|
12
12
|
*
|
|
13
|
-
* This preserves file-based persistence and
|
|
14
|
-
* REF: packages/@livestore/sqlite-wasm/src/make-sqlite-db.ts import implementation
|
|
13
|
+
* This preserves file-based persistence and works with both in-memory and file databases.
|
|
15
14
|
*
|
|
16
15
|
* @param {Buffer} buffer - The serialized database buffer
|
|
17
16
|
* @param {Object} [options] - Options object
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barakxyz/better-sqlite3",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.8.0",
|
|
4
4
|
"description": "The fastest and simplest library for SQLite in Node.js. Fork with session extension enabled.",
|
|
5
5
|
"homepage": "https://github.com/BarakXYZ/better-sqlite3",
|
|
6
6
|
"author": "Joshua Wise <joshuathomaswise@gmail.com>",
|
package/src/objects/database.cpp
CHANGED
|
@@ -131,6 +131,7 @@ INIT(Database::Init) {
|
|
|
131
131
|
SetPrototypeMethod(isolate, data, t, "prepare", JS_prepare);
|
|
132
132
|
SetPrototypeMethod(isolate, data, t, "exec", JS_exec);
|
|
133
133
|
SetPrototypeMethod(isolate, data, t, "backup", JS_backup);
|
|
134
|
+
SetPrototypeMethod(isolate, data, t, "backupFrom", JS_backupFrom);
|
|
134
135
|
SetPrototypeMethod(isolate, data, t, "serialize", JS_serialize);
|
|
135
136
|
SetPrototypeMethod(isolate, data, t, "deserialize", JS_deserialize);
|
|
136
137
|
SetPrototypeMethod(isolate, data, t, "function", JS_function);
|
|
@@ -296,6 +297,85 @@ NODE_METHOD(Database::JS_serialize) {
|
|
|
296
297
|
);
|
|
297
298
|
}
|
|
298
299
|
|
|
300
|
+
NODE_METHOD(Database::JS_backupFrom) {
|
|
301
|
+
// Synchronous backup from another database to this database.
|
|
302
|
+
// Matches wa-sqlite's sqlite3.backup(dest, destName, source, sourceName) pattern.
|
|
303
|
+
// Uses SQLite backup API: sqlite3_backup_init, sqlite3_backup_step, sqlite3_backup_finish.
|
|
304
|
+
|
|
305
|
+
Database* destDb = Unwrap<Database>(info.This());
|
|
306
|
+
REQUIRE_DATABASE_OPEN(destDb);
|
|
307
|
+
REQUIRE_DATABASE_NOT_BUSY(destDb);
|
|
308
|
+
REQUIRE_DATABASE_NO_ITERATORS(destDb);
|
|
309
|
+
|
|
310
|
+
UseAddon;
|
|
311
|
+
UseIsolate;
|
|
312
|
+
|
|
313
|
+
// First argument: source Database object
|
|
314
|
+
// Validate using wa-sqlite's verifyDatabase pattern: check if pointer is in tracked set
|
|
315
|
+
if (info.Length() < 1 || !info[0]->IsObject()) {
|
|
316
|
+
ThrowTypeError("Expected first argument to be a Database instance");
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
v8::Local<v8::Object> srcObj = info[0].As<v8::Object>();
|
|
320
|
+
if (srcObj->InternalFieldCount() < 1) {
|
|
321
|
+
ThrowTypeError("Expected first argument to be a Database instance");
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
Database* srcDb = Unwrap<Database>(srcObj);
|
|
325
|
+
if (addon->dbs.find(srcDb) == addon->dbs.end()) {
|
|
326
|
+
ThrowTypeError("Expected first argument to be a Database instance");
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
if (!srcDb->open) {
|
|
330
|
+
ThrowTypeError("The source database is closed");
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Optional second argument: attached database name for destination (default "main")
|
|
335
|
+
v8::Local<v8::String> destName;
|
|
336
|
+
if (info.Length() > 1 && !info[1]->IsUndefined()) {
|
|
337
|
+
if (!info[1]->IsString()) {
|
|
338
|
+
ThrowTypeError("Expected second argument to be a string");
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
destName = info[1].As<v8::String>();
|
|
342
|
+
} else {
|
|
343
|
+
destName = StringFromUtf8(isolate, "main", -1);
|
|
344
|
+
}
|
|
345
|
+
v8::String::Utf8Value dest_name(isolate, destName);
|
|
346
|
+
|
|
347
|
+
// Optional third argument: attached database name for source (default "main")
|
|
348
|
+
v8::Local<v8::String> srcName;
|
|
349
|
+
if (info.Length() > 2 && !info[2]->IsUndefined()) {
|
|
350
|
+
if (!info[2]->IsString()) {
|
|
351
|
+
ThrowTypeError("Expected third argument to be a string");
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
srcName = info[2].As<v8::String>();
|
|
355
|
+
} else {
|
|
356
|
+
srcName = StringFromUtf8(isolate, "main", -1);
|
|
357
|
+
}
|
|
358
|
+
v8::String::Utf8Value src_name(isolate, srcName);
|
|
359
|
+
|
|
360
|
+
// Initialize backup: sqlite3_backup_init(dest, destName, source, sourceName)
|
|
361
|
+
sqlite3_backup* backup_handle = sqlite3_backup_init(destDb->db_handle, *dest_name, srcDb->db_handle, *src_name);
|
|
362
|
+
if (backup_handle == NULL) {
|
|
363
|
+
destDb->ThrowDatabaseError();
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Copy all pages in one step (-1 = all pages)
|
|
368
|
+
int status = sqlite3_backup_step(backup_handle, -1);
|
|
369
|
+
sqlite3_backup_finish(backup_handle);
|
|
370
|
+
|
|
371
|
+
if (status != SQLITE_DONE) {
|
|
372
|
+
ThrowSqliteError(addon, sqlite3_errstr(status), status);
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
info.GetReturnValue().Set(info.This());
|
|
377
|
+
}
|
|
378
|
+
|
|
299
379
|
NODE_METHOD(Database::JS_deserialize) {
|
|
300
380
|
// Deserialize a buffer into the current database using the safe pattern:
|
|
301
381
|
// 1. Create temp in-memory database
|
|
@@ -304,8 +384,6 @@ NODE_METHOD(Database::JS_deserialize) {
|
|
|
304
384
|
// 4. Close temp database
|
|
305
385
|
//
|
|
306
386
|
// This preserves file-based persistence and matches wa-sqlite's import pattern.
|
|
307
|
-
// REF: packages/@livestore/sqlite-wasm/src/make-sqlite-db.ts import implementation
|
|
308
|
-
// REF: packages/@livestore/wa-sqlite/src/sqlite-api.js backup function
|
|
309
387
|
|
|
310
388
|
Database* db = Unwrap<Database>(info.This());
|
|
311
389
|
REQUIRE_DATABASE_OPEN(db);
|
|
@@ -365,9 +443,8 @@ NODE_METHOD(Database::JS_deserialize) {
|
|
|
365
443
|
return;
|
|
366
444
|
}
|
|
367
445
|
|
|
368
|
-
// Step 3: Backup from temp to current database
|
|
446
|
+
// Step 3: Backup from temp to current database (matches wa-sqlite backup pattern)
|
|
369
447
|
// sqlite3_backup_init(dest, destName, source, sourceName)
|
|
370
|
-
// REF: wa-sqlite sqlite-api.js - backup(dest, destName, source, sourceName)
|
|
371
448
|
sqlite3_backup* backup_handle = sqlite3_backup_init(db->db_handle, *attached_name, temp_handle, "main");
|
|
372
449
|
if (backup_handle == NULL) {
|
|
373
450
|
sqlite3_close(temp_handle);
|
package/src/objects/database.hpp
CHANGED