Skip to content

Commit d1b44a1

Browse files
committed
sqlite: add location method
1 parent 422529a commit d1b44a1

File tree

4 files changed

+90
-0
lines changed

4 files changed

+90
-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 have been added with [`ATTACH DATABASE`][] **Default:** `'main'`.
252+
* Returns: {string} The location of the database file. When using an `in-memory` database,
253+
this method returns an empty string.
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: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,31 @@ 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+
1207+
args.GetReturnValue().Set(
1208+
String::NewFromUtf8(env->isolate(), db_filename, NewStringType::kNormal)
1209+
.ToLocalChecked());
1210+
}
1211+
11871212
void DatabaseSync::AggregateFunction(const FunctionCallbackInfo<Value>& args) {
11881213
DatabaseSync* db;
11891214
ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
@@ -2616,6 +2641,7 @@ static void Initialize(Local<Object> target,
26162641
SetProtoMethod(isolate, db_tmpl, "prepare", DatabaseSync::Prepare);
26172642
SetProtoMethod(isolate, db_tmpl, "exec", DatabaseSync::Exec);
26182643
SetProtoMethod(isolate, db_tmpl, "function", DatabaseSync::CustomFunction);
2644+
SetProtoMethod(isolate, db_tmpl, "location", DatabaseSync::Location);
26192645
SetProtoMethod(
26202646
isolate, db_tmpl, "aggregate", DatabaseSync::AggregateFunction);
26212647
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: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,3 +361,52 @@ 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+
380+
t.assert.throws(() => {
381+
db.location(null);
382+
}, {
383+
code: 'ERR_INVALID_ARG_TYPE',
384+
message: /The "dbName" argument must be a string/,
385+
});
386+
});
387+
388+
test('returns empty string when connected to in-memory database', (t) => {
389+
const db = new DatabaseSync(':memory:');
390+
t.assert.equal(db.location(), '');
391+
});
392+
393+
test('returns db path when connected to a persistent database', (t) => {
394+
const dbPath = nextDb();
395+
const db = new DatabaseSync(dbPath);
396+
t.after(() => { db.close(); });
397+
t.assert.equal(db.location(), dbPath);
398+
});
399+
400+
test('returns that specific db path when attached', (t) => {
401+
const dbPath = nextDb();
402+
const otherPath = nextDb();
403+
const db = new DatabaseSync(dbPath);
404+
t.after(() => { db.close(); });
405+
const other = new DatabaseSync(dbPath);
406+
t.after(() => { other.close(); });
407+
408+
db.exec(`ATTACH DATABASE '${otherPath}' AS other`);
409+
410+
t.assert.equal(db.location('other'), otherPath);
411+
});
412+
});

0 commit comments

Comments
 (0)