Skip to content

Commit

Permalink
src: precompute field names
Browse files Browse the repository at this point in the history
Field names do not change from row to row, so let's create JS strings
only during the process of calling back into JS with the first row, not
with each row. We save the JS strings we created while calling back
with the first row, and re-use them when creating objects for
subsequent rows.

Re: nodejs/abi-stable-node#458
  • Loading branch information
gabrielschulhof committed Mar 24, 2024
1 parent 1609684 commit 0115fa1
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 6 deletions.
30 changes: 25 additions & 5 deletions src/statement.cc
Expand Up @@ -587,8 +587,16 @@ void Statement::Work_AfterAll(napi_env e, napi_status status, void* data) {
Napi::Array result(Napi::Array::New(env, baton->rows.size()));
auto it = static_cast<Rows::const_iterator>(baton->rows.begin());
decltype(it) end = baton->rows.end();
std::vector<napi_value> js_names;
for (int i = 0; it < end; ++it, i++) {
(result).Set(i, RowToJS(env, it->get()));
Row* row = it->get();
if (js_names.empty()) {
for (auto& field : *row) {
const napi_value js_field_name = Napi::String::New(e, field->name);
js_names.push_back(js_field_name);
}
}
(result).Set(i, RowToJS(env, row, js_names));
}

Napi::Value argv[] = { env.Null(), result };
Expand Down Expand Up @@ -711,8 +719,16 @@ void Statement::AsyncEach(uv_async_t* handle) {
Napi::Value argv[2];
argv[0] = env.Null();

for(auto& row : rows) {
argv[1] = RowToJS(env,row.get());
std::vector<napi_value> js_names;
for(auto& rowRef : rows) {
Row* row = rowRef.get();
if (js_names.empty()) {
for (auto& field : *row) {
const napi_value js_field_name = Napi::String::New(env, field->name);
js_names.push_back(js_field_name);
}
}
argv[1] = RowToJS(env, row, js_names);
async->retrieved++;
TRY_CATCH_CALL(async->stmt->Value(), cb, 2, argv);
}
Expand Down Expand Up @@ -787,11 +803,12 @@ void Statement::Work_AfterReset(napi_env e, napi_status status, void* data) {
STATEMENT_END();
}

Napi::Value Statement::RowToJS(Napi::Env env, Row* row) {
Napi::Value Statement::RowToJS(Napi::Env env, Row* row, const std::vector<napi_value>& js_names) {
Napi::EscapableHandleScope scope(env);

auto result = Napi::Object::New(env);

size_t js_name_idx = 0;
for (auto& field : *row) {

Napi::Value value;
Expand All @@ -816,7 +833,10 @@ Napi::Value Statement::RowToJS(Napi::Env env, Row* row) {
} break;
}

result.Set(field->name, value);
napi_value field_name = js_names.empty()
? Napi::String::New(env, field->name)
: js_names[js_name_idx++];
result.Set(field_name, value);
}

return scope.Escape(result);
Expand Down
2 changes: 1 addition & 1 deletion src/statement.h
Expand Up @@ -220,7 +220,7 @@ class Statement : public Napi::ObjectWrap<Statement> {
bool Bind(const Parameters &parameters);

static void GetRow(Row* row, sqlite3_stmt* stmt);
static Napi::Value RowToJS(Napi::Env env, Row* row);
static Napi::Value RowToJS(Napi::Env env, Row* row, const std::vector<napi_value>& js_names = std::vector<napi_value>());
void Schedule(Work_Callback callback, Baton* baton);
void Process();
void CleanQueue();
Expand Down

0 comments on commit 0115fa1

Please sign in to comment.