Skip to content

Commit 43350cd

Browse files
geeksilva97aduh95
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 8ce5c7c commit 43350cd

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
@@ -237,6 +237,19 @@ Enables or disables the `loadExtension` SQL function, and the `loadExtension()`
237237
method. When `allowExtension` is `false` when constructing, you cannot enable
238238
loading extensions for security reasons.
239239

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

242255
<!-- YAML
@@ -814,6 +827,7 @@ resolution handler passed to [`database.applyChangeset()`][]. See also
814827
[`sqlite3_column_table_name()`]: https://www.sqlite.org/c3ref/column_database_name.html
815828
[`sqlite3_create_function_v2()`]: https://www.sqlite.org/c3ref/create_function.html
816829
[`sqlite3_create_window_function()`]: https://www.sqlite.org/c3ref/create_function.html
830+
[`sqlite3_db_filename()`]: https://sqlite.org/c3ref/db_filename.html
817831
[`sqlite3_exec()`]: https://www.sqlite.org/c3ref/exec.html
818832
[`sqlite3_expanded_sql()`]: https://www.sqlite.org/c3ref/expanded_sql.html
819833
[`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
@@ -1182,6 +1182,36 @@ void DatabaseSync::CustomFunction(const FunctionCallbackInfo<Value>& args) {
11821182
CHECK_ERROR_OR_THROW(env->isolate(), db, r, SQLITE_OK, void());
11831183
}
11841184

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