Skip to content

Commit 2e46281

Browse files
committed
wip: getting things in place :)
1 parent 18fe76b commit 2e46281

File tree

2 files changed

+90
-32
lines changed

2 files changed

+90
-32
lines changed

src/node_sqlite.cc

Lines changed: 85 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -586,8 +586,84 @@ bool DatabaseSync::ShouldIgnoreSQLiteError() {
586586
return ignore_next_sqlite_error_;
587587
}
588588

589-
bool IsURL(Local<Value> value) {
590-
return false;
589+
bool IsURL(Environment* env, Local<Value> path) {
590+
Local<Object> url;
591+
if (!path->ToObject(env->context()).ToLocal(&url)) {
592+
return false;
593+
}
594+
595+
Local<Value> href;
596+
if (!url->Get(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), "href"))
597+
.ToLocal(&href)) {
598+
return false;
599+
}
600+
601+
if (!href->IsString()) {
602+
return false;
603+
}
604+
605+
return true;
606+
}
607+
608+
Local<String> BufferToString(Environment* env, Local<Uint8Array> buffer) {
609+
size_t byteOffset = buffer->ByteOffset();
610+
size_t byteLength = buffer->ByteLength();
611+
if (byteLength == 0) {
612+
THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
613+
"The \"path\" argument must not be empty.");
614+
return Local<String>();
615+
}
616+
617+
auto data =
618+
static_cast<const uint8_t*>(buffer->Buffer()->Data()) + byteOffset;
619+
if (std::find(data, data + byteLength, 0) != data + byteLength) {
620+
THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
621+
"The \"path\" argument must not contain null "
622+
"bytes.");
623+
return Local<String>();
624+
}
625+
626+
auto path = std::string(reinterpret_cast<const char*>(data), byteLength);
627+
return String::NewFromUtf8(
628+
env->isolate(), path.c_str(), NewStringType::kNormal)
629+
.ToLocalChecked();
630+
}
631+
632+
Local<String> ToPathIfURL(Environment* env, Local<Value> path) {
633+
if (!IsURL(env, path)) {
634+
if (path->IsString()) {
635+
return path.As<String>();
636+
}
637+
638+
return BufferToString(env, path.As<Uint8Array>());
639+
}
640+
641+
Local<Object> url = path.As<Object>();
642+
Local<Value> href;
643+
Local<Value> protocol;
644+
if (!url->Get(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), "href"))
645+
.ToLocal(&href)) {
646+
return Local<String>();
647+
}
648+
649+
if (!url->Get(env->context(),
650+
FIXED_ONE_BYTE_STRING(env->isolate(), "protocol"))
651+
.ToLocal(&protocol)) {
652+
return Local<String>();
653+
}
654+
655+
if (!href->IsString() || !protocol->IsString()) {
656+
return Local<String>();
657+
}
658+
659+
std::string protocol_v =
660+
Utf8Value(env->isolate(), protocol.As<String>()).ToString();
661+
if (protocol_v != "file:") {
662+
THROW_ERR_INVALID_URL_SCHEME(env->isolate());
663+
return Local<String>();
664+
}
665+
666+
return href.As<String>();
591667
}
592668

593669
void DatabaseSync::New(const FunctionCallbackInfo<Value>& args) {
@@ -598,41 +674,21 @@ void DatabaseSync::New(const FunctionCallbackInfo<Value>& args) {
598674
return;
599675
}
600676

601-
Local<Value> path = args[0]; // if object, it's a URL, so path will be the
602-
// "href" property then i can check the scheme
603-
// and if it's not file, throw an error
604-
if (!path->IsString() && !path->IsUint8Array() && !IsURL(path)) {
677+
Local<Value> path = args[0];
678+
if (!path->IsString() && !path->IsUint8Array() && !IsURL(env, path)) {
605679
THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
606680
"The \"path\" argument must be a string, "
607681
"Uint8Array, or URL without null bytes.");
608682
return;
609683
}
610684

611-
std::string location;
612-
if (path->IsUint8Array()) {
613-
Local<Uint8Array> buffer = path.As<Uint8Array>();
614-
size_t byteOffset = buffer->ByteOffset();
615-
size_t byteLength = buffer->ByteLength();
616-
if (byteLength == 0) {
617-
THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
618-
"The \"path\" argument must not be empty.");
619-
return;
620-
}
621-
622-
auto data =
623-
static_cast<const uint8_t*>(buffer->Buffer()->Data()) + byteOffset;
624-
if (std::find(data, data + byteLength, 0) != data + byteLength) {
625-
THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
626-
"The \"path\" argument must not contain null "
627-
"bytes.");
628-
return;
629-
}
630-
631-
location = std::string(reinterpret_cast<const char*>(data), byteLength);
632-
} else {
633-
location = Utf8Value(env->isolate(), args[0].As<String>()).ToString();
685+
Local<String> path_str = ToPathIfURL(env, path);
686+
if (path_str.IsEmpty()) {
687+
return;
634688
}
635689

690+
std::string location = Utf8Value(env->isolate(), p).ToString();
691+
636692
// TODO: uncomment this we still need to handle URLs
637693
/* auto parsed_url = ada::parse<ada::url_aggregator>(location, nullptr); */
638694
/* if (parsed_url && parsed_url->type != ada::scheme::FILE) { */

test/parallel/test-sqlite-backup.mjs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ function makeSourceDb(dbPath = ':memory:') {
3232
return database;
3333
}
3434

35+
test.only('location as an URL object', (t) => {
36+
new DatabaseSync(new URL('https://google.com'))
37+
});
38+
3539
describe('backup()', () => {
3640
test('throws if the source database is not provided', (t) => {
3741
t.assert.throws(() => {
@@ -43,9 +47,7 @@ describe('backup()', () => {
4347
});
4448

4549
test('throws if path is not a string', (t) => {
46-
// const database = makeSourceDb();
47-
// TODO: have a separate test handling buffer
48-
const database = makeSourceDb(Buffer.from(':memory:'));
50+
const database = makeSourceDb();
4951

5052
t.assert.throws(() => {
5153
backup(database);

0 commit comments

Comments
 (0)