diff --git a/src/env_properties.h b/src/env_properties.h index 087193faba98..c4e3bc5c72a0 100644 --- a/src/env_properties.h +++ b/src/env_properties.h @@ -451,6 +451,7 @@ V(socketaddress_constructor_template, v8::FunctionTemplate) \ V(space_stats_template, v8::DictionaryTemplate) \ V(sqlite_column_template, v8::DictionaryTemplate) \ + V(sqlite_database_constructor_template, v8::FunctionTemplate) \ V(sqlite_limits_template, v8::ObjectTemplate) \ V(sqlite_run_result_template, v8::DictionaryTemplate) \ V(sqlite_statement_sync_constructor_template, v8::FunctionTemplate) \ diff --git a/src/node_sqlite.cc b/src/node_sqlite.cc index b4fbfa88746a..ef02983c94e3 100644 --- a/src/node_sqlite.cc +++ b/src/node_sqlite.cc @@ -3208,9 +3208,11 @@ void Database::CreateSession(const FunctionCallbackInfo& args) { void Backup(const FunctionCallbackInfo& 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."); + if (!args[0]->IsObject() || + !env->sqlite_database_constructor_template()->HasInstance(args[0])) { + THROW_ERR_INVALID_ARG_TYPE( + env->isolate(), + "The \"sourceDb\" argument must be a DatabaseSync instance."); return; } @@ -5381,51 +5383,60 @@ static void Initialize(Local target, } }); } - Local db_tmpl = NewFunctionTemplate(isolate, Database::New); - db_tmpl->InstanceTemplate()->SetInternalFieldCount( - Database::kInternalFieldCount); Local constants = Object::New(isolate); DefineConstants(constants); - SetProtoMethod(isolate, db_tmpl, "open", Database::Open); - SetProtoMethod(isolate, db_tmpl, "close", Database::Close); - SetProtoDispose(isolate, db_tmpl, Database::Dispose); - SetProtoMethod(isolate, db_tmpl, "prepare", Database::Prepare); - SetProtoMethod(isolate, db_tmpl, "exec", Database::Exec); - SetProtoMethod(isolate, db_tmpl, "function", Database::CustomFunction); - SetProtoMethod(isolate, db_tmpl, "createTagStore", Database::CreateTagStore); - SetProtoMethodNoSideEffect(isolate, db_tmpl, "location", Database::Location); - SetProtoMethod(isolate, db_tmpl, "aggregate", Database::AggregateFunction); - SetProtoMethod(isolate, db_tmpl, "createSession", Database::CreateSession); - SetProtoMethod(isolate, db_tmpl, "applyChangeset", Database::ApplyChangeset); - SetProtoMethod( - isolate, db_tmpl, "enableLoadExtension", Database::EnableLoadExtension); - SetProtoMethod( - isolate, db_tmpl, "enableDefensive", Database::EnableDefensive); - SetProtoMethod(isolate, db_tmpl, "loadExtension", Database::LoadExtension); - SetProtoMethod(isolate, db_tmpl, "serialize", Database::Serialize); - SetProtoMethod(isolate, db_tmpl, "deserialize", Database::Deserialize); - SetProtoMethod(isolate, db_tmpl, "setAuthorizer", Database::SetAuthorizer); - SetProtoMethod(isolate, db_tmpl, "createModule", Database::CreateModule); - SetSideEffectFreeGetter(isolate, - db_tmpl, - FIXED_ONE_BYTE_STRING(isolate, "isOpen"), - Database::IsOpenGetter); - SetSideEffectFreeGetter(isolate, - db_tmpl, - FIXED_ONE_BYTE_STRING(isolate, "isTransaction"), - Database::IsTransactionGetter); - SetSideEffectFreeGetter( - isolate, db_tmpl, env->limits_string(), Database::LimitsGetter); - Local sqlite_type_key = FIXED_ONE_BYTE_STRING(isolate, "sqlite-type"); - Local sqlite_type_symbol = - v8::Symbol::For(isolate, sqlite_type_key); - Local database_sync_string = - FIXED_ONE_BYTE_STRING(isolate, "node:sqlite"); - db_tmpl->InstanceTemplate()->Set(sqlite_type_symbol, database_sync_string); - - SetConstructorFunction(context, target, "Database", db_tmpl); + Local db_tmpl = env->sqlite_database_constructor_template(); + if (db_tmpl.IsEmpty()) { + db_tmpl = NewFunctionTemplate(isolate, Database::New); + db_tmpl->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "Database")); + db_tmpl->InstanceTemplate()->SetInternalFieldCount( + Database::kInternalFieldCount); + SetProtoMethod(isolate, db_tmpl, "open", Database::Open); + SetProtoMethod(isolate, db_tmpl, "close", Database::Close); + SetProtoDispose(isolate, db_tmpl, Database::Dispose); + SetProtoMethod(isolate, db_tmpl, "prepare", Database::Prepare); + SetProtoMethod(isolate, db_tmpl, "exec", Database::Exec); + SetProtoMethod(isolate, db_tmpl, "function", Database::CustomFunction); + SetProtoMethod( + isolate, db_tmpl, "createTagStore", Database::CreateTagStore); + SetProtoMethodNoSideEffect( + isolate, db_tmpl, "location", Database::Location); + SetProtoMethod(isolate, db_tmpl, "aggregate", Database::AggregateFunction); + SetProtoMethod(isolate, db_tmpl, "createSession", Database::CreateSession); + SetProtoMethod( + isolate, db_tmpl, "applyChangeset", Database::ApplyChangeset); + SetProtoMethod( + isolate, db_tmpl, "enableLoadExtension", Database::EnableLoadExtension); + SetProtoMethod( + isolate, db_tmpl, "enableDefensive", Database::EnableDefensive); + SetProtoMethod(isolate, db_tmpl, "loadExtension", Database::LoadExtension); + SetProtoMethod(isolate, db_tmpl, "serialize", Database::Serialize); + SetProtoMethod(isolate, db_tmpl, "deserialize", Database::Deserialize); + SetProtoMethod(isolate, db_tmpl, "setAuthorizer", Database::SetAuthorizer); + SetProtoMethod(isolate, db_tmpl, "createModule", Database::CreateModule); + SetSideEffectFreeGetter(isolate, + db_tmpl, + FIXED_ONE_BYTE_STRING(isolate, "isOpen"), + Database::IsOpenGetter); + SetSideEffectFreeGetter(isolate, + db_tmpl, + FIXED_ONE_BYTE_STRING(isolate, "isTransaction"), + Database::IsTransactionGetter); + SetSideEffectFreeGetter( + isolate, db_tmpl, env->limits_string(), Database::LimitsGetter); + Local sqlite_type_key = + FIXED_ONE_BYTE_STRING(isolate, "sqlite-type"); + Local sqlite_type_symbol = + v8::Symbol::For(isolate, sqlite_type_key); + Local database_sync_string = + FIXED_ONE_BYTE_STRING(isolate, "node:sqlite"); + db_tmpl->InstanceTemplate()->Set(sqlite_type_symbol, database_sync_string); + env->set_sqlite_database_constructor_template(db_tmpl); + } + SetConstructorFunction( + context, target, "Database", db_tmpl, SetConstructorFunctionFlag::NONE); SetConstructorFunction(context, target, "Statement", diff --git a/test/parallel/test-sqlite-backup.mjs b/test/parallel/test-sqlite-backup.mjs index cae097aa92ec..485076c04b93 100644 --- a/test/parallel/test-sqlite-backup.mjs +++ b/test/parallel/test-sqlite-backup.mjs @@ -48,10 +48,26 @@ describe('backup()', () => { backup(); }, { code: 'ERR_INVALID_ARG_TYPE', - message: 'The "sourceDb" argument must be an object.' + message: 'The "sourceDb" argument must be a DatabaseSync instance.' }); }); + test('throws if the source is not a DatabaseSync', (t) => { + const database = makeSourceDb(); + for (const source of [ + {}, + database.prepare('SELECT 1'), + database.createSession(), + ]) { + t.assert.throws(() => { + backup(source, 'out.db'); + }, { + code: 'ERR_INVALID_ARG_TYPE', + message: 'The "sourceDb" argument must be a DatabaseSync instance.' + }); + } + }); + test('throws if path is not a string, URL, or Buffer', (t) => { const database = makeSourceDb();