Skip to content

Commit e318e85

Browse files
committed
feat: support new Ladybug C API features
1 parent 42ef11c commit e318e85

16 files changed

Lines changed: 573 additions & 9 deletions

‎src_cpp/include/node_connection.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ class NodeConnection : public Napi::ObjectWrap<NodeConnection> {
3434
Napi::Value QueryAsync(const Napi::CallbackInfo& info);
3535
Napi::Value ExecuteSync(const Napi::CallbackInfo& info);
3636
Napi::Value QuerySync(const Napi::CallbackInfo& info);
37+
Napi::Value CreateArrowTableSync(const Napi::CallbackInfo& info);
38+
Napi::Value CreateArrowRelTableSync(const Napi::CallbackInfo& info);
39+
Napi::Value DropArrowTableSync(const Napi::CallbackInfo& info);
3740
void Close(const Napi::CallbackInfo& info);
3841

3942
private:

‎src_cpp/include/node_database.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class NodeDatabase : public Napi::ObjectWrap<NodeDatabase> {
3434
int64_t checkpointThreshold;
3535
bool throwOnWalReplayFailure;
3636
bool enableChecksums;
37+
bool enableDefaultHashIndex;
3738
std::shared_ptr<Database> database;
3839
};
3940

‎src_cpp/include/node_prepared_statement.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class NodePreparedStatement : public Napi::ObjectWrap<NodePreparedStatement> {
2020
Napi::Value InitSync(const Napi::CallbackInfo& info);
2121
void InitCppPreparedStatement();
2222
Napi::Value IsSuccess(const Napi::CallbackInfo& info);
23+
Napi::Value IsReadOnly(const Napi::CallbackInfo& info);
2324
Napi::Value GetErrorMessage(const Napi::CallbackInfo& info);
2425

2526
private:

‎src_cpp/node_connection.cpp‎

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,73 @@
66
#include "include/node_query_result.h"
77
#include "include/node_util.h"
88
#include "main/lbug.h"
9+
#include "storage/table/arrow_table_support.h"
10+
11+
namespace {
12+
13+
template<typename T>
14+
T* GetPointerArgument(const Napi::Value& value, const char* name) {
15+
if (value.IsBigInt()) {
16+
bool lossless = false;
17+
auto address = value.As<Napi::BigInt>().Uint64Value(&lossless);
18+
if (!lossless || address == 0) {
19+
throw std::runtime_error(std::string(name) + " must be a non-zero pointer BigInt.");
20+
}
21+
return reinterpret_cast<T*>(static_cast<uintptr_t>(address));
22+
}
23+
if (value.IsExternal()) {
24+
return value.As<Napi::External<T>>().Data();
25+
}
26+
throw std::runtime_error(std::string(name) + " must be a pointer BigInt or N-API External.");
27+
}
28+
29+
ArrowSchemaWrapper TakeArrowSchema(ArrowSchema* schema) {
30+
ArrowSchemaWrapper wrapper;
31+
static_cast<ArrowSchema&>(wrapper) = *schema;
32+
schema->release = nullptr;
33+
return wrapper;
34+
}
35+
36+
ArrowArrayWrapper TakeArrowArray(ArrowArray* array) {
37+
ArrowArrayWrapper wrapper;
38+
static_cast<ArrowArray&>(wrapper) = *array;
39+
array->release = nullptr;
40+
return wrapper;
41+
}
42+
43+
std::vector<ArrowArrayWrapper> TakeArrowArrays(const Napi::Value& value, uint64_t numArrays) {
44+
std::vector<ArrowArrayWrapper> wrappers;
45+
if (value.IsArray()) {
46+
auto arrayPointers = value.As<Napi::Array>();
47+
wrappers.reserve(arrayPointers.Length());
48+
for (auto i = 0u; i < arrayPointers.Length(); ++i) {
49+
wrappers.push_back(TakeArrowArray(
50+
GetPointerArgument<ArrowArray>(arrayPointers.Get(i), "ArrowArray")));
51+
}
52+
return wrappers;
53+
}
54+
auto* arrays = GetPointerArgument<ArrowArray>(value, "arrays");
55+
wrappers.reserve(numArrays);
56+
for (auto i = 0u; i < numArrays; ++i) {
57+
wrappers.push_back(TakeArrowArray(&arrays[i]));
58+
}
59+
return wrappers;
60+
}
61+
62+
void AdoptArrowQueryResult(Napi::Env env, NodeQueryResult* nodeQueryResult,
63+
std::unique_ptr<QueryResult> result, std::shared_ptr<Connection> connection,
64+
std::shared_ptr<Database> database) {
65+
if (result == nullptr) {
66+
throw std::runtime_error("Arrow table registration did not return a query result.");
67+
}
68+
if (!result->isSuccess()) {
69+
Napi::Error::New(env, result->getErrorMessage()).ThrowAsJavaScriptException();
70+
return;
71+
}
72+
nodeQueryResult->AdoptQueryResult(std::move(result), std::move(connection), std::move(database));
73+
}
74+
75+
} // namespace
976

1077
Napi::Object NodeConnection::Init(Napi::Env env, Napi::Object exports) {
1178
Napi::HandleScope scope(env);
@@ -17,6 +84,9 @@ Napi::Object NodeConnection::Init(Napi::Env env, Napi::Object exports) {
1784
InstanceMethod("queryAsync", &NodeConnection::QueryAsync),
1885
InstanceMethod("executeSync", &NodeConnection::ExecuteSync),
1986
InstanceMethod("querySync", &NodeConnection::QuerySync),
87+
InstanceMethod("createArrowTableSync", &NodeConnection::CreateArrowTableSync),
88+
InstanceMethod("createArrowRelTableSync", &NodeConnection::CreateArrowRelTableSync),
89+
InstanceMethod("dropArrowTableSync", &NodeConnection::DropArrowTableSync),
2090
InstanceMethod("setMaxNumThreadForExec", &NodeConnection::SetMaxNumThreadForExec),
2191
InstanceMethod("setQueryTimeout", &NodeConnection::SetQueryTimeout),
2292
InstanceMethod("close", &NodeConnection::Close)});
@@ -155,3 +225,55 @@ Napi::Value NodeConnection::QueryAsync(const Napi::CallbackInfo& info) {
155225
asyncWorker->Queue();
156226
return info.Env().Undefined();
157227
}
228+
229+
Napi::Value NodeConnection::CreateArrowTableSync(const Napi::CallbackInfo& info) {
230+
Napi::Env env = info.Env();
231+
Napi::HandleScope scope(env);
232+
auto tableName = info[0].As<Napi::String>().Utf8Value();
233+
auto* schema = GetPointerArgument<ArrowSchema>(info[1], "schema");
234+
auto numArrays = info[3].As<Napi::Number>().Int64Value();
235+
auto nodeQueryResult = Napi::ObjectWrap<NodeQueryResult>::Unwrap(info[4].As<Napi::Object>());
236+
try {
237+
auto result = lbug::ArrowTableSupport::createViewFromArrowTable(*connection, tableName,
238+
TakeArrowSchema(schema), TakeArrowArrays(info[2], numArrays));
239+
AdoptArrowQueryResult(
240+
env, nodeQueryResult, std::move(result.queryResult), connection, database);
241+
} catch (const std::exception& exc) {
242+
Napi::Error::New(env, std::string(exc.what())).ThrowAsJavaScriptException();
243+
}
244+
return env.Undefined();
245+
}
246+
247+
Napi::Value NodeConnection::CreateArrowRelTableSync(const Napi::CallbackInfo& info) {
248+
Napi::Env env = info.Env();
249+
Napi::HandleScope scope(env);
250+
auto tableName = info[0].As<Napi::String>().Utf8Value();
251+
auto srcTableName = info[1].As<Napi::String>().Utf8Value();
252+
auto dstTableName = info[2].As<Napi::String>().Utf8Value();
253+
auto* schema = GetPointerArgument<ArrowSchema>(info[3], "schema");
254+
auto numArrays = info[5].As<Napi::Number>().Int64Value();
255+
auto nodeQueryResult = Napi::ObjectWrap<NodeQueryResult>::Unwrap(info[6].As<Napi::Object>());
256+
try {
257+
auto result = lbug::ArrowTableSupport::createRelTableFromArrowTable(*connection, tableName,
258+
srcTableName, dstTableName, TakeArrowSchema(schema), TakeArrowArrays(info[4], numArrays));
259+
AdoptArrowQueryResult(
260+
env, nodeQueryResult, std::move(result.queryResult), connection, database);
261+
} catch (const std::exception& exc) {
262+
Napi::Error::New(env, std::string(exc.what())).ThrowAsJavaScriptException();
263+
}
264+
return env.Undefined();
265+
}
266+
267+
Napi::Value NodeConnection::DropArrowTableSync(const Napi::CallbackInfo& info) {
268+
Napi::Env env = info.Env();
269+
Napi::HandleScope scope(env);
270+
auto tableName = info[0].As<Napi::String>().Utf8Value();
271+
auto nodeQueryResult = Napi::ObjectWrap<NodeQueryResult>::Unwrap(info[1].As<Napi::Object>());
272+
try {
273+
auto result = lbug::ArrowTableSupport::unregisterArrowTable(*connection, tableName);
274+
AdoptArrowQueryResult(env, nodeQueryResult, std::move(result), connection, database);
275+
} catch (const std::exception& exc) {
276+
Napi::Error::New(env, std::string(exc.what())).ThrowAsJavaScriptException();
277+
}
278+
return env.Undefined();
279+
}

‎src_cpp/node_database.cpp‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ NodeDatabase::NodeDatabase(const Napi::CallbackInfo& info) : Napi::ObjectWrap<No
2828
checkpointThreshold = info[6].As<Napi::Number>().Int64Value();
2929
throwOnWalReplayFailure = info[7].As<Napi::Boolean>().Value();
3030
enableChecksums = info[8].As<Napi::Boolean>().Value();
31+
enableDefaultHashIndex = info[9].As<Napi::Boolean>().Value();
3132
}
3233

3334
Napi::Value NodeDatabase::InitSync(const Napi::CallbackInfo& info) {
@@ -67,6 +68,7 @@ void NodeDatabase::InitCppDatabase() {
6768
systemConfig.autoCheckpoint = autoCheckpoint;
6869
systemConfig.throwOnWalReplayFailure = throwOnWalReplayFailure;
6970
systemConfig.enableChecksums = enableChecksums;
71+
systemConfig.enableDefaultHashIndex = enableDefaultHashIndex;
7072
if (checkpointThreshold >= 0) {
7173
systemConfig.checkpointThreshold = checkpointThreshold;
7274
}

‎src_cpp/node_prepared_statement.cpp‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Napi::Object NodePreparedStatement::Init(Napi::Env env, Napi::Object exports) {
88
InstanceMethod("initAsync", &NodePreparedStatement::InitAsync),
99
InstanceMethod("initSync", &NodePreparedStatement::InitSync),
1010
InstanceMethod("isSuccess", &NodePreparedStatement::IsSuccess),
11+
InstanceMethod("isReadOnly", &NodePreparedStatement::IsReadOnly),
1112
InstanceMethod("getErrorMessage", &NodePreparedStatement::GetErrorMessage),
1213
});
1314

@@ -53,6 +54,15 @@ Napi::Value NodePreparedStatement::IsSuccess(const Napi::CallbackInfo& info) {
5354
return Napi::Boolean::New(env, preparedStatement->isSuccess());
5455
}
5556

57+
Napi::Value NodePreparedStatement::IsReadOnly(const Napi::CallbackInfo& info) {
58+
if (preparedStatement == nullptr) {
59+
return Napi::Boolean::New(info.Env(), false);
60+
}
61+
Napi::Env env = info.Env();
62+
Napi::HandleScope scope(env);
63+
return Napi::Boolean::New(env, preparedStatement->isReadOnly());
64+
}
65+
5666
Napi::Value NodePreparedStatement::GetErrorMessage(const Napi::CallbackInfo& info) {
5767
if (preparedStatement == nullptr) {
5868
return Napi::String::New(info.Env(), "Prepared statement is not initialized.");

0 commit comments

Comments
 (0)