Skip to content

Commit d90c87f

Browse files
committed
sqlite: add setReturnArrays method to StatementSync
1 parent 046781e commit d90c87f

File tree

3 files changed

+257
-59
lines changed

3 files changed

+257
-59
lines changed

src/node_sqlite.cc

+131-59
Original file line numberDiff line numberDiff line change
@@ -1582,27 +1582,38 @@ void StatementSync::All(const FunctionCallbackInfo<Value>& args) {
15821582
int num_cols = sqlite3_column_count(stmt->statement_);
15831583
LocalVector<Value> rows(isolate);
15841584
LocalVector<Name> row_keys(isolate);
1585+
15851586
while ((r = sqlite3_step(stmt->statement_)) == SQLITE_ROW) {
1586-
if (row_keys.size() == 0) {
1587-
row_keys.reserve(num_cols);
1587+
if (stmt->return_arrays_) {
1588+
Local<Array> row = Array::New(isolate, num_cols);
15881589
for (int i = 0; i < num_cols; ++i) {
1589-
Local<Name> key;
1590-
if (!stmt->ColumnNameToName(i).ToLocal(&key)) return;
1591-
row_keys.emplace_back(key);
1590+
Local<Value> val;
1591+
if (!stmt->ColumnToValue(i).ToLocal(&val)) return;
1592+
if (row->Set(env->context(), i, val).IsNothing()) return;
1593+
}
1594+
rows.emplace_back(row);
1595+
} else {
1596+
if (row_keys.size() == 0) {
1597+
row_keys.reserve(num_cols);
1598+
for (int i = 0; i < num_cols; ++i) {
1599+
Local<Name> key;
1600+
if (!stmt->ColumnNameToName(i).ToLocal(&key)) return;
1601+
row_keys.emplace_back(key);
1602+
}
15921603
}
1593-
}
15941604

1595-
LocalVector<Value> row_values(isolate);
1596-
row_values.reserve(num_cols);
1597-
for (int i = 0; i < num_cols; ++i) {
1598-
Local<Value> val;
1599-
if (!stmt->ColumnToValue(i).ToLocal(&val)) return;
1600-
row_values.emplace_back(val);
1601-
}
1605+
LocalVector<Value> row_values(isolate);
1606+
row_values.reserve(num_cols);
1607+
for (int i = 0; i < num_cols; ++i) {
1608+
Local<Value> val;
1609+
if (!stmt->ColumnToValue(i).ToLocal(&val)) return;
1610+
row_values.emplace_back(val);
1611+
}
16021612

1603-
Local<Object> row = Object::New(
1604-
isolate, Null(isolate), row_keys.data(), row_values.data(), num_cols);
1605-
rows.emplace_back(row);
1613+
Local<Object> row = Object::New(
1614+
isolate, Null(isolate), row_keys.data(), row_values.data(), num_cols);
1615+
rows.emplace_back(row);
1616+
}
16061617
}
16071618

16081619
CHECK_ERROR_OR_THROW(isolate, stmt->db_.get(), r, SQLITE_DONE, void());
@@ -1645,7 +1656,7 @@ void StatementSync::IterateReturnCallback(
16451656
}
16461657

16471658
void StatementSync::IterateNextCallback(
1648-
const FunctionCallbackInfo<Value>& args) {
1659+
const v8::FunctionCallbackInfo<v8::Value>& args) {
16491660
Environment* env = Environment::GetCurrent(args);
16501661
auto isolate = env->isolate();
16511662
auto context = isolate->GetCurrentContext();
@@ -1688,6 +1699,15 @@ void StatementSync::IterateNextCallback(
16881699
THROW_AND_RETURN_ON_BAD_STATE(
16891700
env, stmt->IsFinalized(), "statement has been finalized");
16901701

1702+
// Get the return_arrays flag from the iterator object
1703+
Local<Value> return_arrays_val;
1704+
bool return_arrays = false;
1705+
if (self->Get(context, FIXED_ONE_BYTE_STRING(isolate, "return_arrays"))
1706+
.ToLocal(&return_arrays_val) &&
1707+
return_arrays_val->IsBoolean()) {
1708+
return_arrays = return_arrays_val.As<Boolean>()->Value();
1709+
}
1710+
16911711
int r = sqlite3_step(stmt->statement_);
16921712
if (r != SQLITE_ROW) {
16931713
CHECK_ERROR_OR_THROW(
@@ -1702,39 +1722,47 @@ void StatementSync::IterateNextCallback(
17021722
return;
17031723
}
17041724

1705-
LocalVector<Name> keys(isolate, {env->done_string(), env->value_string()});
1706-
LocalVector<Value> values(isolate,
1707-
{Boolean::New(isolate, true), Null(isolate)});
1708-
1709-
DCHECK_EQ(keys.size(), values.size());
1725+
Local<Name> keys[] = {env->done_string(), env->value_string()};
1726+
Local<Value> values[] = {Boolean::New(isolate, true), Null(isolate)};
1727+
static_assert(arraysize(keys) == arraysize(values));
17101728
Local<Object> result = Object::New(
1711-
isolate, Null(isolate), keys.data(), values.data(), keys.size());
1729+
isolate, Null(isolate), &keys[0], &values[0], arraysize(keys));
17121730
args.GetReturnValue().Set(result);
17131731
return;
17141732
}
17151733

1716-
LocalVector<Name> row_keys(isolate);
1717-
row_keys.reserve(num_cols);
1718-
LocalVector<Value> row_values(isolate);
1719-
row_values.reserve(num_cols);
1720-
for (int i = 0; i < num_cols; ++i) {
1721-
Local<Name> key;
1722-
if (!stmt->ColumnNameToName(i).ToLocal(&key)) return;
1723-
Local<Value> val;
1724-
if (!stmt->ColumnToValue(i).ToLocal(&val)) return;
1725-
row_keys.emplace_back(key);
1726-
row_values.emplace_back(val);
1727-
}
1728-
1729-
Local<Object> row = Object::New(
1730-
isolate, Null(isolate), row_keys.data(), row_values.data(), num_cols);
1734+
Local<Value> row;
1735+
if (return_arrays) {
1736+
Local<Array> array_row = Array::New(isolate, num_cols);
1737+
for (int i = 0; i < num_cols; ++i) {
1738+
Local<Value> val;
1739+
if (!stmt->ColumnToValue(i).ToLocal(&val)) return;
1740+
if (array_row->Set(env->context(), i, val).IsNothing()) return;
1741+
}
1742+
row = array_row;
1743+
} else {
1744+
LocalVector<Name> row_keys(isolate);
1745+
row_keys.reserve(num_cols);
1746+
LocalVector<Value> row_values(isolate);
1747+
row_values.reserve(num_cols);
1748+
for (int i = 0; i < num_cols; ++i) {
1749+
Local<Name> key;
1750+
if (!stmt->ColumnNameToName(i).ToLocal(&key)) return;
1751+
Local<Value> val;
1752+
if (!stmt->ColumnToValue(i).ToLocal(&val)) return;
1753+
row_keys.emplace_back(key);
1754+
row_values.emplace_back(val);
1755+
}
17311756

1732-
LocalVector<Name> keys(isolate, {env->done_string(), env->value_string()});
1733-
LocalVector<Value> values(isolate, {Boolean::New(isolate, false), row});
1757+
row = Object::New(
1758+
isolate, Null(isolate), row_keys.data(), row_values.data(), num_cols);
1759+
}
17341760

1735-
DCHECK_EQ(keys.size(), values.size());
1761+
Local<Name> keys[] = {env->done_string(), env->value_string()};
1762+
Local<Value> values[] = {Boolean::New(isolate, false), row};
1763+
static_assert(arraysize(keys) == arraysize(values));
17361764
Local<Object> result = Object::New(
1737-
isolate, Null(isolate), keys.data(), values.data(), keys.size());
1765+
isolate, Null(isolate), &keys[0], &values[0], arraysize(keys));
17381766
args.GetReturnValue().Set(result);
17391767
}
17401768

@@ -1804,15 +1832,30 @@ void StatementSync::Iterate(const FunctionCallbackInfo<Value>& args) {
18041832

18051833
auto is_finished_pd =
18061834
v8::PropertyDescriptor(v8::Boolean::New(isolate, false), true);
1807-
stmt_pd.set_enumerable(false);
1808-
stmt_pd.set_configurable(false);
1835+
is_finished_pd.set_enumerable(false);
1836+
is_finished_pd.set_configurable(false);
18091837
if (iterable_iterator
18101838
->DefineProperty(context, env->isfinished_string(), is_finished_pd)
18111839
.IsNothing()) {
18121840
// An error will have been scheduled.
18131841
return;
18141842
}
18151843

1844+
// Add the return_arrays flag to the iterator
1845+
auto return_arrays_pd =
1846+
v8::PropertyDescriptor(v8::Boolean::New(
1847+
isolate, stmt->return_arrays_), false);
1848+
return_arrays_pd.set_enumerable(false);
1849+
return_arrays_pd.set_configurable(false);
1850+
if (iterable_iterator
1851+
->DefineProperty(
1852+
context, FIXED_ONE_BYTE_STRING(
1853+
isolate, "return_arrays"), return_arrays_pd)
1854+
.IsNothing()) {
1855+
// An error will have been scheduled.
1856+
return;
1857+
}
1858+
18161859
args.GetReturnValue().Set(iterable_iterator);
18171860
}
18181861

@@ -1843,24 +1886,35 @@ void StatementSync::Get(const FunctionCallbackInfo<Value>& args) {
18431886
return;
18441887
}
18451888

1846-
LocalVector<Name> keys(isolate);
1847-
keys.reserve(num_cols);
1848-
LocalVector<Value> values(isolate);
1849-
values.reserve(num_cols);
1889+
if (stmt->return_arrays_) {
1890+
Local<Array> result = Array::New(isolate, num_cols);
1891+
for (int i = 0; i < num_cols; ++i) {
1892+
Local<Value> val;
1893+
if (!stmt->ColumnToValue(i).ToLocal(&val)) return;
1894+
if (result->Set(env->context(), i, val).IsNothing()) return;
1895+
}
1896+
args.GetReturnValue().Set(result);
1897+
} else {
1898+
LocalVector<Name> keys(isolate);
1899+
keys.reserve(num_cols);
1900+
LocalVector<Value> values(isolate);
1901+
values.reserve(num_cols);
18501902

1851-
for (int i = 0; i < num_cols; ++i) {
1852-
Local<Name> key;
1853-
if (!stmt->ColumnNameToName(i).ToLocal(&key)) return;
1854-
Local<Value> val;
1855-
if (!stmt->ColumnToValue(i).ToLocal(&val)) return;
1856-
keys.emplace_back(key);
1857-
values.emplace_back(val);
1858-
}
1903+
for (int i = 0; i < num_cols; ++i) {
1904+
Local<Name> key;
1905+
if (!stmt->ColumnNameToName(i).ToLocal(&key)) return;
1906+
Local<Value> val;
1907+
if (!stmt->ColumnToValue(i).ToLocal(&val)) return;
1908+
keys.emplace_back(key);
1909+
values.emplace_back(val);
1910+
}
18591911

1860-
Local<Object> result =
1861-
Object::New(isolate, Null(isolate), keys.data(), values.data(), num_cols);
1912+
Local<Object> result =
1913+
Object::New(
1914+
isolate, Null(isolate), keys.data(), values.data(), num_cols);
18621915

1863-
args.GetReturnValue().Set(result);
1916+
args.GetReturnValue().Set(result);
1917+
}
18641918
}
18651919

18661920
void StatementSync::Run(const FunctionCallbackInfo<Value>& args) {
@@ -2043,6 +2097,22 @@ void StatementSync::SetReadBigInts(const FunctionCallbackInfo<Value>& args) {
20432097
stmt->use_big_ints_ = args[0]->IsTrue();
20442098
}
20452099

2100+
void StatementSync::SetReturnArrays(const FunctionCallbackInfo<Value>& args) {
2101+
StatementSync* stmt;
2102+
ASSIGN_OR_RETURN_UNWRAP(&stmt, args.This());
2103+
Environment* env = Environment::GetCurrent(args);
2104+
THROW_AND_RETURN_ON_BAD_STATE(
2105+
env, stmt->IsFinalized(), "statement has been finalized");
2106+
2107+
if (!args[0]->IsBoolean()) {
2108+
THROW_ERR_INVALID_ARG_TYPE(
2109+
env->isolate(), "The \"returnArrays\" argument must be a boolean.");
2110+
return;
2111+
}
2112+
2113+
stmt->return_arrays_ = args[0]->IsTrue();
2114+
}
2115+
20462116
void IllegalConstructor(const FunctionCallbackInfo<Value>& args) {
20472117
THROW_ERR_ILLEGAL_CONSTRUCTOR(Environment::GetCurrent(args));
20482118
}
@@ -2094,6 +2164,8 @@ Local<FunctionTemplate> StatementSync::GetConstructorTemplate(
20942164
StatementSync::SetAllowBareNamedParameters);
20952165
SetProtoMethod(
20962166
isolate, tmpl, "setReadBigInts", StatementSync::SetReadBigInts);
2167+
SetProtoMethod(
2168+
isolate, tmpl, "setReturnArrays", StatementSync::SetReturnArrays);
20972169
env->set_sqlite_statement_sync_constructor_template(tmpl);
20982170
}
20992171
return tmpl;

src/node_sqlite.h

+2
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ class StatementSync : public BaseObject {
123123
static void SetAllowBareNamedParameters(
124124
const v8::FunctionCallbackInfo<v8::Value>& args);
125125
static void SetReadBigInts(const v8::FunctionCallbackInfo<v8::Value>& args);
126+
static void SetReturnArrays(const v8::FunctionCallbackInfo<v8::Value>& args);
126127
void Finalize();
127128
bool IsFinalized();
128129

@@ -133,6 +134,7 @@ class StatementSync : public BaseObject {
133134
~StatementSync() override;
134135
BaseObjectPtr<DatabaseSync> db_;
135136
sqlite3_stmt* statement_;
137+
bool return_arrays_ = false;
136138
bool use_big_ints_;
137139
bool allow_bare_named_params_;
138140
std::optional<std::map<std::string, std::string>> bare_named_params_;

0 commit comments

Comments
 (0)