Skip to content

Commit

Permalink
sqlite,test,doc: move backup implementation to a separate function
Browse files Browse the repository at this point in the history
  • Loading branch information
geeksilva97 committed Jan 24, 2025
1 parent 0df678e commit 0909d3e
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 149 deletions.
41 changes: 21 additions & 20 deletions doc/api/sqlite.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,26 +115,6 @@ added: v22.5.0

Constructs a new `DatabaseSync` instance.

### `database.backup(destination[, options])`

<!-- YAML
added: REPLACEME
-->

* `destination` {string} The path where the backup will be created. If the file already exists, the contents will be
overwritten.
* `options` {Object} Optional configuration for the backup. The
following properties are supported:
* `source` {string} Name of the source database. **Default:** `'main'`.
* `target` {string} Name of the target database. **Default:** `'main'`.
* `rate` {number} Number of pages to be transmitted in each batch of the backup. **Default:** `100`.
* `progress` {Function} Callback function that will be called with the number of pages copied and the total number of
pages.
* Returns: {Promise} A promise that resolves when the backup is completed and rejects if an error occurs.

This method makes a database backup. This method abstracts the [`sqlite3_backup_init()`][], [`sqlite3_backup_step()`][]
and [`sqlite3_backup_finish()`][] functions.

### `database.close()`

<!-- YAML
Expand Down Expand Up @@ -543,6 +523,27 @@ exception.
| `TEXT` | {string} |
| `BLOB` | {Uint8Array} |

## `sqlite.backup(sourceDb, destination[, options])`

<!-- YAML
added: REPLACEME
-->

* `sourceDb` A `DatabaseSync` object to be the source of the backup. The source database must be open.
* `destination` {string} The path where the backup will be created. If the file already exists, the contents will be
overwritten.
* `options` {Object} Optional configuration for the backup. The
following properties are supported:
* `source` {string} Name of the source database. **Default:** `'main'`.
* `target` {string} Name of the target database. **Default:** `'main'`.
* `rate` {number} Number of pages to be transmitted in each batch of the backup. **Default:** `100`.
* `progress` {Function} Callback function that will be called with the number of pages copied and the total number of
pages.
* Returns: {Promise} A promise that resolves when the backup is completed and rejects if an error occurs.

This method makes a database backup. This method abstracts the [`sqlite3_backup_init()`][], [`sqlite3_backup_step()`][]
and [`sqlite3_backup_finish()`][] functions.

## `sqlite.constants`

<!-- YAML
Expand Down
1 change: 1 addition & 0 deletions src/env_properties.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
V(asn1curve_string, "asn1Curve") \
V(async_ids_stack_string, "async_ids_stack") \
V(attributes_string, "attributes") \
V(backup_string, "backup") \
V(base_string, "base") \
V(bits_string, "bits") \
V(block_list_string, "blockList") \
Expand Down
226 changes: 119 additions & 107 deletions src/node_sqlite.cc
Original file line number Diff line number Diff line change
Expand Up @@ -725,112 +725,6 @@ void DatabaseSync::Exec(const FunctionCallbackInfo<Value>& args) {
CHECK_ERROR_OR_THROW(env->isolate(), db->connection_, r, SQLITE_OK, void());
}

void DatabaseSync::Backup(const FunctionCallbackInfo<Value>& args) {
DatabaseSync* db;
ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
Environment* env = Environment::GetCurrent(args);
THROW_AND_RETURN_ON_BAD_STATE(env, !db->IsOpen(), "database is not open");

if (!args[0]->IsString()) {
THROW_ERR_INVALID_ARG_TYPE(
env->isolate(), "The \"destination\" argument must be a string.");
return;
}

int rate = 100;
std::string source_db = "main";
std::string dest_db = "main";

Utf8Value dest_path(env->isolate(), args[0].As<String>());
Local<Function> progressFunc = Local<Function>();

if (args.Length() > 1) {
if (!args[1]->IsObject()) {
THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
"The \"options\" argument must be an object.");
return;
}

Local<Object> options = args[1].As<Object>();
Local<Value> rate_v;
if (!options->Get(env->context(), env->rate_string()).ToLocal(&rate_v)) {
return;
}

if (!rate_v->IsUndefined()) {
if (!rate_v->IsInt32()) {
THROW_ERR_INVALID_ARG_TYPE(
env->isolate(),
"The \"options.rate\" argument must be an integer.");
return;
}
rate = rate_v.As<Int32>()->Value();
}

Local<Value> source_v;
if (!options->Get(env->context(), env->source_string())
.ToLocal(&source_v)) {
return;
}

if (!source_v->IsUndefined()) {
if (!source_v->IsString()) {
THROW_ERR_INVALID_ARG_TYPE(
env->isolate(),
"The \"options.source\" argument must be a string.");
return;
}

source_db = Utf8Value(env->isolate(), source_v.As<String>()).ToString();
}

Local<Value> target_v;
if (!options->Get(env->context(), env->target_string())
.ToLocal(&target_v)) {
return;
}

if (!target_v->IsUndefined()) {
if (!target_v->IsString()) {
THROW_ERR_INVALID_ARG_TYPE(
env->isolate(),
"The \"options.target\" argument must be a string.");
return;
}

dest_db = Utf8Value(env->isolate(), target_v.As<String>()).ToString();
}

Local<Value> progress_v;
if (!options->Get(env->context(), env->progress_string())
.ToLocal(&progress_v)) {
return;
}

if (!progress_v->IsUndefined()) {
if (!progress_v->IsFunction()) {
THROW_ERR_INVALID_ARG_TYPE(
env->isolate(),
"The \"options.progress\" argument must be a function.");
return;
}
progressFunc = progress_v.As<Function>();
}
}

Local<Promise::Resolver> resolver;
if (!Promise::Resolver::New(env->context()).ToLocal(&resolver)) {
return;
}

args.GetReturnValue().Set(resolver->GetPromise());

BackupJob* job = new BackupJob(
env, db, resolver, source_db, *dest_path, dest_db, rate, progressFunc);
db->backups_.insert(job);
job->ScheduleBackup();
}

void DatabaseSync::CustomFunction(const FunctionCallbackInfo<Value>& args) {
DatabaseSync* db;
ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
Expand Down Expand Up @@ -1041,6 +935,117 @@ void DatabaseSync::CreateSession(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(session->object());
}

void Backup(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
if (args.Length() < 1 || !args[0]->IsObject()) {
THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
"The \"sourceDb\" argument must be an object.");
return;
}

DatabaseSync* db;
ASSIGN_OR_RETURN_UNWRAP(&db, args[0].As<Object>());
THROW_AND_RETURN_ON_BAD_STATE(env, !db->IsOpen(), "database is not open");
if (!args[1]->IsString()) {
THROW_ERR_INVALID_ARG_TYPE(
env->isolate(), "The \"destination\" argument must be a string.");
return;
}

int rate = 100;
std::string source_db = "main";
std::string dest_db = "main";

Utf8Value dest_path(env->isolate(), args[1].As<String>());
Local<Function> progressFunc = Local<Function>();

if (args.Length() > 2) {
if (!args[2]->IsObject()) {
THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
"The \"options\" argument must be an object.");
return;
}

Local<Object> options = args[2].As<Object>();
Local<Value> rate_v;
if (!options->Get(env->context(), env->rate_string()).ToLocal(&rate_v)) {
return;
}

if (!rate_v->IsUndefined()) {
if (!rate_v->IsInt32()) {
THROW_ERR_INVALID_ARG_TYPE(
env->isolate(),
"The \"options.rate\" argument must be an integer.");
return;
}
rate = rate_v.As<Int32>()->Value();
}

Local<Value> source_v;
if (!options->Get(env->context(), env->source_string())
.ToLocal(&source_v)) {
return;
}

if (!source_v->IsUndefined()) {
if (!source_v->IsString()) {
THROW_ERR_INVALID_ARG_TYPE(
env->isolate(),
"The \"options.source\" argument must be a string.");
return;
}

source_db = Utf8Value(env->isolate(), source_v.As<String>()).ToString();
}

Local<Value> target_v;
if (!options->Get(env->context(), env->target_string())
.ToLocal(&target_v)) {
return;
}

if (!target_v->IsUndefined()) {
if (!target_v->IsString()) {
THROW_ERR_INVALID_ARG_TYPE(
env->isolate(),
"The \"options.target\" argument must be a string.");
return;
}

dest_db = Utf8Value(env->isolate(), target_v.As<String>()).ToString();
}

Local<Value> progress_v;
if (!options->Get(env->context(), env->progress_string())
.ToLocal(&progress_v)) {
return;
}

if (!progress_v->IsUndefined()) {
if (!progress_v->IsFunction()) {
THROW_ERR_INVALID_ARG_TYPE(
env->isolate(),
"The \"options.progress\" argument must be a function.");
return;
}
progressFunc = progress_v.As<Function>();
}
}

Local<Promise::Resolver> resolver;
if (!Promise::Resolver::New(env->context()).ToLocal(&resolver)) {
return;
}

args.GetReturnValue().Set(resolver->GetPromise());

BackupJob* job = new BackupJob(
env, db, resolver, source_db, *dest_path, dest_db, rate, progressFunc);
db->backups_.insert(job);
job->ScheduleBackup();
}

// the reason for using static functions here is that SQLite needs a
// function pointer
static std::function<int(int)> conflictCallback;
Expand Down Expand Up @@ -2016,7 +2021,6 @@ static void Initialize(Local<Object> target,
SetProtoMethod(isolate, db_tmpl, "close", DatabaseSync::Close);
SetProtoMethod(isolate, db_tmpl, "prepare", DatabaseSync::Prepare);
SetProtoMethod(isolate, db_tmpl, "exec", DatabaseSync::Exec);
SetProtoMethod(isolate, db_tmpl, "backup", DatabaseSync::Backup);
SetProtoMethod(isolate, db_tmpl, "function", DatabaseSync::CustomFunction);
SetProtoMethod(
isolate, db_tmpl, "createSession", DatabaseSync::CreateSession);
Expand All @@ -2035,6 +2039,14 @@ static void Initialize(Local<Object> target,
StatementSync::GetConstructorTemplate(env));

target->Set(context, env->constants_string(), constants).Check();

Local<Function> backup_function;

if (!Function::New(context, Backup).ToLocal(&backup_function)) {
return;
}

target->Set(context, env->backup_string(), backup_function).Check();
}

} // namespace sqlite
Expand Down
1 change: 0 additions & 1 deletion src/node_sqlite.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ class DatabaseSync : public BaseObject {
static void Close(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Prepare(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Exec(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Backup(const v8::FunctionCallbackInfo<v8::Value>& args);
static void CustomFunction(const v8::FunctionCallbackInfo<v8::Value>& args);
static void CreateSession(const v8::FunctionCallbackInfo<v8::Value>& args);
static void ApplyChangeset(const v8::FunctionCallbackInfo<v8::Value>& args);
Expand Down
Loading

0 comments on commit 0909d3e

Please sign in to comment.