Skip to content

Commit 10eb2b0

Browse files
geeksilva97RafaelGSS
authored andcommitted
sqlite: add location method
PR-URL: #57860 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Colin Ihrig <[email protected]>
1 parent 7e3503f commit 10eb2b0

File tree

4 files changed

+99
-0
lines changed

4 files changed

+99
-0
lines changed

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+
void DatabaseSync::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+
const char* 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
void DatabaseSync::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
static void Close(const v8::FunctionCallbackInfo<v8::Value>& args);
6767
static void Prepare(const v8::FunctionCallbackInfo<v8::Value>& args);
6868
static void Exec(const v8::FunctionCallbackInfo<v8::Value>& args);
69+
static void Location(const v8::FunctionCallbackInfo<v8::Value>& args);
6970
static void CustomFunction(const v8::FunctionCallbackInfo<v8::Value>& args);
7071
static void AggregateFunction(
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+
const db = new DatabaseSync(nextDb(), { open: false });
368+
369+
t.assert.throws(() => {
370+
db.location();
371+
}, {
372+
code: 'ERR_INVALID_STATE',
373+
message: /database is not open/,
374+
});
375+
});
376+
377+
test('throws if provided dbName is not string', (t) => {
378+
const db = new DatabaseSync(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" argument must be a string/,
386+
});
387+
});
388+
389+
test('returns null when connected to in-memory database', (t) => {
390+
const db = new DatabaseSync(':memory:');
391+
t.assert.strictEqual(db.location(), null);
392+
});
393+
394+
test('returns db path when connected to a persistent database', (t) => {
395+
const dbPath = nextDb();
396+
const db = new DatabaseSync(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+
const dbPath = nextDb();
403+
const otherPath = nextDb();
404+
const db = new DatabaseSync(dbPath);
405+
t.after(() => { db.close(); });
406+
const other = new DatabaseSync(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+
const escapedPath = 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)