Skip to content

Commit 10eb2b0

Browse files
geeksilva97RafaelGSS
authored andcommitted
sqlite: add location method
PR-URL: #57860 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
1 parent 7e3503f commit 10eb2b0

4 files changed

Lines changed: 99 additions & 0 deletions

File tree

‎doc/api/sqlite.md‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,19 @@ Enables or disables the `loadExtension` SQL function, and the `loadExtension()`
241241
method. When `allowExtension` is `false` when constructing, you cannot enable
242242
loading extensions for security reasons.
243243

244+
### `database.location([dbName])`
245+
246+
<!-- YAML
247+
added: REPLACEME
248+
-->
249+
250+
*`dbName` {string} Name of the database. This can be `'main'` (the default primary database) or any other
251+
database that has been added with [`ATTACH DATABASE`][]**Default:**`'main'`.
252+
* Returns: {string | null} The location of the database file. When using an in-memory database,
253+
this method returns null.
254+
255+
This method is a wrapper around [`sqlite3_db_filename()`][]
256+
244257
### `database.exec(sql)`
245258

246259
<!-- YAML
@@ -846,6 +859,7 @@ resolution handler passed to [`database.applyChangeset()`][]. See also
846859
[`sqlite3_column_table_name()`]: https://www.sqlite.org/c3ref/column_database_name.html
847860
[`sqlite3_create_function_v2()`]: https://www.sqlite.org/c3ref/create_function.html
848861
[`sqlite3_create_window_function()`]: https://www.sqlite.org/c3ref/create_function.html
862+
[`sqlite3_db_filename()`]: https://sqlite.org/c3ref/db_filename.html
849863
[`sqlite3_exec()`]: https://www.sqlite.org/c3ref/exec.html
850864
[`sqlite3_expanded_sql()`]: https://www.sqlite.org/c3ref/expanded_sql.html
851865
[`sqlite3_get_autocommit()`]: https://sqlite.org/c3ref/get_autocommit.html

‎src/node_sqlite.cc‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,36 @@ void DatabaseSync::CustomFunction(const FunctionCallbackInfo<Value>& args) {
11841184
CHECK_ERROR_OR_THROW(env->isolate(), db, r, SQLITE_OK, void());
11851185
}
11861186

1187+
voidDatabaseSync::Location(const FunctionCallbackInfo<Value>& args) {
1188+
DatabaseSync* db;
1189+
ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
1190+
Environment* env = Environment::GetCurrent(args);
1191+
THROW_AND_RETURN_ON_BAD_STATE(env, !db->IsOpen(), "database is not open");
1192+
1193+
std::string db_name = "main";
1194+
if (!args[0]->IsUndefined()) {
1195+
if (!args[0]->IsString()) {
1196+
THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
1197+
"The \"dbName\" argument must be a string.");
1198+
return;
1199+
}
1200+
1201+
db_name = Utf8Value(env->isolate(), args[0].As<String>()).ToString();
1202+
}
1203+
1204+
constchar* db_filename =
1205+
sqlite3_db_filename(db->connection_, db_name.c_str());
1206+
if (!db_filename || db_filename[0] == '\0') {
1207+
args.GetReturnValue().Set(Null(env->isolate()));
1208+
return;
1209+
}
1210+
1211+
Local<String> ret;
1212+
if (String::NewFromUtf8(env->isolate(), db_filename).ToLocal(&ret)) {
1213+
args.GetReturnValue().Set(ret);
1214+
}
1215+
}
1216+
11871217
voidDatabaseSync::AggregateFunction(const FunctionCallbackInfo<Value>& args) {
11881218
DatabaseSync* db;
11891219
ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
@@ -2616,6 +2646,8 @@ static void Initialize(Local<Object> target,
26162646
SetProtoMethod(isolate, db_tmpl, "prepare", DatabaseSync::Prepare);
26172647
SetProtoMethod(isolate, db_tmpl, "exec", DatabaseSync::Exec);
26182648
SetProtoMethod(isolate, db_tmpl, "function", DatabaseSync::CustomFunction);
2649+
SetProtoMethodNoSideEffect(
2650+
isolate, db_tmpl, "location", DatabaseSync::Location);
26192651
SetProtoMethod(
26202652
isolate, db_tmpl, "aggregate", DatabaseSync::AggregateFunction);
26212653
SetProtoMethod(

‎src/node_sqlite.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ class DatabaseSync : public BaseObject {
6666
staticvoidClose(const v8::FunctionCallbackInfo<v8::Value>& args);
6767
staticvoidPrepare(const v8::FunctionCallbackInfo<v8::Value>& args);
6868
staticvoidExec(const v8::FunctionCallbackInfo<v8::Value>& args);
69+
staticvoidLocation(const v8::FunctionCallbackInfo<v8::Value>& args);
6970
staticvoidCustomFunction(const v8::FunctionCallbackInfo<v8::Value>& args);
7071
staticvoidAggregateFunction(
7172
const v8::FunctionCallbackInfo<v8::Value>& args);

‎test/parallel/test-sqlite-database-sync.js‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,3 +361,55 @@ suite('DatabaseSync.prototype.isTransaction', () => {
361361
});
362362
});
363363
});
364+
365+
suite('DatabaseSync.prototype.location()',()=>{
366+
test('throws if database is not open',(t)=>{
367+
constdb=newDatabaseSync(nextDb(),{open: false});
368+
369+
t.assert.throws(()=>{
370+
db.location();
371+
},{
372+
code: 'ERR_INVALID_STATE',
373+
message: /databaseisnotopen/,
374+
});
375+
});
376+
377+
test('throws if provided dbName is not string',(t)=>{
378+
constdb=newDatabaseSync(nextDb());
379+
t.after(()=>{db.close();});
380+
381+
t.assert.throws(()=>{
382+
db.location(null);
383+
},{
384+
code: 'ERR_INVALID_ARG_TYPE',
385+
message: /The"dbName"argumentmustbeastring/,
386+
});
387+
});
388+
389+
test('returns null when connected to in-memory database',(t)=>{
390+
constdb=newDatabaseSync(':memory:');
391+
t.assert.strictEqual(db.location(),null);
392+
});
393+
394+
test('returns db path when connected to a persistent database',(t)=>{
395+
constdbPath=nextDb();
396+
constdb=newDatabaseSync(dbPath);
397+
t.after(()=>{db.close();});
398+
t.assert.strictEqual(db.location(),dbPath);
399+
});
400+
401+
test('returns that specific db path when attached',(t)=>{
402+
constdbPath=nextDb();
403+
constotherPath=nextDb();
404+
constdb=newDatabaseSync(dbPath);
405+
t.after(()=>{db.close();});
406+
constother=newDatabaseSync(dbPath);
407+
t.after(()=>{other.close();});
408+
409+
// Adding this escape because the test with unusual chars have a single quote which breaks the query
410+
constescapedPath=otherPath.replace("'","''");
411+
db.exec(`ATTACH DATABASE '${escapedPath}' AS other`);
412+
413+
t.assert.strictEqual(db.location('other'),otherPath);
414+
});
415+
});

0 commit comments

Comments
 (0)