Skip to content

Commit b42a338

Browse files
committed
sqlite: add location method
1 parent 09ecd2e commit b42a338

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
@@ -837,6 +850,7 @@ resolution handler passed to [`database.applyChangeset()`][]. See also
837850
[`sqlite3_column_table_name()`]: https://www.sqlite.org/c3ref/column_database_name.html
838851
[`sqlite3_create_function_v2()`]: https://www.sqlite.org/c3ref/create_function.html
839852
[`sqlite3_create_window_function()`]: https://www.sqlite.org/c3ref/create_function.html
853+
[`sqlite3_db_filename()`]: https://sqlite.org/c3ref/db_filename.html
840854
[`sqlite3_exec()`]: https://www.sqlite.org/c3ref/exec.html
841855
[`sqlite3_expanded_sql()`]: https://www.sqlite.org/c3ref/expanded_sql.html
842856
[`sqlite3_last_insert_rowid()`]: https://www.sqlite.org/c3ref/last_insert_rowid.html

src/node_sqlite.cc

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,6 +1175,31 @@ void DatabaseSync::CustomFunction(const FunctionCallbackInfo<Value>& args) {
11751175
CHECK_ERROR_OR_THROW(env->isolate(), db, r, SQLITE_OK, void());
11761176
}
11771177

1178+
void DatabaseSync::Location(const FunctionCallbackInfo<Value>& args) {
1179+
DatabaseSync* db;
1180+
ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
1181+
Environment* env = Environment::GetCurrent(args);
1182+
THROW_AND_RETURN_ON_BAD_STATE(env, !db->IsOpen(), "database is not open");
1183+
1184+
std::string db_name = "main";
1185+
if (!args[0]->IsUndefined()) {
1186+
if (!args[0]->IsString()) {
1187+
THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
1188+
"The \"dbName\" argument must be a string.");
1189+
return;
1190+
}
1191+
1192+
db_name = Utf8Value(env->isolate(), args[0].As<String>()).ToString();
1193+
}
1194+
1195+
const char* db_filename =
1196+
sqlite3_db_filename(db->connection_, db_name.c_str());
1197+
1198+
args.GetReturnValue().Set(
1199+
String::NewFromUtf8(env->isolate(), db_filename, NewStringType::kNormal)
1200+
.ToLocalChecked());
1201+
}
1202+
11781203
void DatabaseSync::AggregateFunction(const FunctionCallbackInfo<Value>& args) {
11791204
DatabaseSync* db;
11801205
ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
@@ -2607,6 +2632,7 @@ static void Initialize(Local<Object> target,
26072632
SetProtoMethod(isolate, db_tmpl, "prepare", DatabaseSync::Prepare);
26082633
SetProtoMethod(isolate, db_tmpl, "exec", DatabaseSync::Exec);
26092634
SetProtoMethod(isolate, db_tmpl, "function", DatabaseSync::CustomFunction);
2635+
SetProtoMethod(isolate, db_tmpl, "location", DatabaseSync::Location);
26102636
SetProtoMethod(
26112637
isolate, db_tmpl, "aggregate", DatabaseSync::AggregateFunction);
26122638
SetProtoMethod(

src/node_sqlite.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class DatabaseSync : public BaseObject {
6464
static void Close(const v8::FunctionCallbackInfo<v8::Value>& args);
6565
static void Prepare(const v8::FunctionCallbackInfo<v8::Value>& args);
6666
static void Exec(const v8::FunctionCallbackInfo<v8::Value>& args);
67+
static void Location(const v8::FunctionCallbackInfo<v8::Value>& args);
6768
static void CustomFunction(const v8::FunctionCallbackInfo<v8::Value>& args);
6869
static void AggregateFunction(
6970
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
@@ -324,3 +324,52 @@ suite('DatabaseSync.prototype.exec()', () => {
324324
});
325325
});
326326
});
327+
328+
suite('DatabaseSync.prototype.location()', () => {
329+
test('throws if database is not open', (t) => {
330+
const db = new DatabaseSync(nextDb(), { open: false });
331+
332+
t.assert.throws(() => {
333+
db.location();
334+
}, {
335+
code: 'ERR_INVALID_STATE',
336+
message: /database is not open/,
337+
});
338+
});
339+
340+
test('throws if provided dbName is not string', (t) => {
341+
const db = new DatabaseSync(nextDb());
342+
343+
t.assert.throws(() => {
344+
db.location(null);
345+
}, {
346+
code: 'ERR_INVALID_ARG_TYPE',
347+
message: /The "dbName" argument must be a string/,
348+
});
349+
});
350+
351+
test('returns empty string when connected to in-memory database', (t) => {
352+
const db = new DatabaseSync(':memory:');
353+
t.assert.equal(db.location(), '');
354+
});
355+
356+
test('returns db path when connected to a persistent database', (t) => {
357+
const dbPath = nextDb();
358+
const db = new DatabaseSync(dbPath);
359+
t.after(() => { db.close(); });
360+
t.assert.equal(db.location(), dbPath);
361+
});
362+
363+
test('returns that specific db path when attached', (t) => {
364+
const dbPath = nextDb();
365+
const otherPath = nextDb();
366+
const db = new DatabaseSync(dbPath);
367+
t.after(() => { db.close(); });
368+
const other = new DatabaseSync(dbPath);
369+
t.after(() => { other.close(); });
370+
371+
db.exec(`ATTACH DATABASE '${otherPath}' AS other`);
372+
373+
t.assert.equal(db.location('other'), otherPath);
374+
});
375+
});

0 commit comments

Comments
 (0)