From 95dd89e59c3a9623b62651a2dbb56e6d1fe36d21 Mon Sep 17 00:00:00 2001 From: Christiaan Landman Date: Wed, 6 Nov 2024 15:00:27 +0200 Subject: [PATCH 1/3] Result object keys are no longer ordered alphabetically, but rather maintain insertion order. The behaviour now matches other libraries. --- .changeset/selfish-worms-buy.md | 5 +++ cpp/JSIHelper.cpp | 67 +++++++++++++++++---------------- 2 files changed, 39 insertions(+), 33 deletions(-) create mode 100644 .changeset/selfish-worms-buy.md diff --git a/.changeset/selfish-worms-buy.md b/.changeset/selfish-worms-buy.md new file mode 100644 index 0000000..c0379ad --- /dev/null +++ b/.changeset/selfish-worms-buy.md @@ -0,0 +1,5 @@ +--- +"@journeyapps/react-native-quick-sqlite": patch +--- + +Result object keys are no longer ordered alphabetically, but rather maintain insertion order. The behaviour now matches other libraries. diff --git a/cpp/JSIHelper.cpp b/cpp/JSIHelper.cpp index ac86be4..423bc2c 100644 --- a/cpp/JSIHelper.cpp +++ b/cpp/JSIHelper.cpp @@ -143,45 +143,46 @@ jsi::Value createSequelQueryExecutionResult(jsi::Runtime &rt, SQLiteOPResult sta // Converting row results into objects size_t rowCount = results->size(); jsi::Object rows = jsi::Object(rt); - if (rowCount > 0) + if (rowCount > 0 && metadata != NULL) { auto array = jsi::Array(rt, rowCount); for (int i = 0; i < rowCount; i++) { - jsi::Object rowObject = jsi::Object(rt); - auto row = results->at(i); - for (auto const &entry : row) - { - std::string columnName = entry.first; - QuickValue value = entry.second; - if (value.dataType == TEXT) - { - // using value.textValue (std::string) directly allows jsi::String to use length property of std::string (allowing strings with NULLs in them like SQLite does) - rowObject.setProperty(rt, columnName.c_str(), jsi::String::createFromUtf8(rt, value.textValue)); - } - else if (value.dataType == INTEGER) - { - rowObject.setProperty(rt, columnName.c_str(), jsi::Value(value.doubleOrIntValue)); - } - else if (value.dataType == DOUBLE) + jsi::Object rowObject = jsi::Object(rt); + auto row = results -> at(i); + // Iterate over metadata to maintain column order + for (const auto &column: * metadata) { - rowObject.setProperty(rt, columnName.c_str(), jsi::Value(value.doubleOrIntValue)); + std::string columnName = column.colunmName; + auto it = row.find(columnName); + if (it != row.end()) + { + QuickValue value = it -> second; + if (value.dataType == TEXT) + { + // using value.textValue (std::string) directly allows jsi::String to use length property of std::string (allowing strings with NULLs in them like SQLite does) + rowObject.setProperty(rt, columnName.c_str(), jsi::String::createFromUtf8(rt, value.textValue)); + } else if (value.dataType == INTEGER || value.dataType == DOUBLE) + { + rowObject.setProperty(rt, columnName.c_str(), jsi::Value(value.doubleOrIntValue)); + } else if (value.dataType == ARRAY_BUFFER) + { + jsi::Function array_buffer_ctor = rt.global().getPropertyAsFunction(rt, "ArrayBuffer"); + jsi::Object o = array_buffer_ctor.callAsConstructor(rt, (int) value.arrayBufferSize).getObject(rt); + jsi::ArrayBuffer buf = o.getArrayBuffer(rt); + // It's a shame we have to copy here: see https://github.com/facebook/hermes/pull/419 and https://github.com/facebook/hermes/issues/564. + memcpy(buf.data(rt), value.arrayBufferValue.get(), value.arrayBufferSize); + rowObject.setProperty(rt, columnName.c_str(), o); + } else + { + rowObject.setProperty(rt, columnName.c_str(), jsi::Value(nullptr)); + } + } else + { + rowObject.setProperty(rt, columnName.c_str(), jsi::Value(nullptr)); + } } - else if (value.dataType == ARRAY_BUFFER) - { - jsi::Function array_buffer_ctor = rt.global().getPropertyAsFunction(rt, "ArrayBuffer"); - jsi::Object o = array_buffer_ctor.callAsConstructor(rt, (int)value.arrayBufferSize).getObject(rt); - jsi::ArrayBuffer buf = o.getArrayBuffer(rt); - // It's a shame we have to copy here: see https://github.com/facebook/hermes/pull/419 and https://github.com/facebook/hermes/issues/564. - memcpy(buf.data(rt), value.arrayBufferValue.get(), value.arrayBufferSize); - rowObject.setProperty(rt, columnName.c_str(), o); - } - else - { - rowObject.setProperty(rt, columnName.c_str(), jsi::Value(nullptr)); - } - } - array.setValueAtIndex(rt, i, move(rowObject)); + array.setValueAtIndex(rt, i, move(rowObject)); } rows.setProperty(rt, "_array", move(array)); res.setProperty(rt, "rows", move(rows)); From 854ead5d7b42f1312c4a157110a8f38f99c4059b Mon Sep 17 00:00:00 2001 From: Christiaan Landman Date: Wed, 6 Nov 2024 17:54:46 +0200 Subject: [PATCH 2/3] Formatting. --- cpp/JSIHelper.cpp | 69 ++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/cpp/JSIHelper.cpp b/cpp/JSIHelper.cpp index 423bc2c..48c0d0a 100644 --- a/cpp/JSIHelper.cpp +++ b/cpp/JSIHelper.cpp @@ -148,41 +148,44 @@ jsi::Value createSequelQueryExecutionResult(jsi::Runtime &rt, SQLiteOPResult sta auto array = jsi::Array(rt, rowCount); for (int i = 0; i < rowCount; i++) { - jsi::Object rowObject = jsi::Object(rt); - auto row = results -> at(i); - // Iterate over metadata to maintain column order - for (const auto &column: * metadata) + jsi::Object rowObject = jsi::Object(rt); + auto row = results -> at(i); + // Iterate over metadata to maintain column order + for (const auto &column : *metadata) + { + std::string columnName = column.colunmName; + auto it = row.find(columnName); + if (it != row.end()) + { + QuickValue value = it -> second; + if (value.dataType == TEXT) + { + // using value.textValue (std::string) directly allows jsi::String to use length property of std::string (allowing strings with NULLs in them like SQLite does) + rowObject.setProperty(rt, columnName.c_str(), jsi::String::createFromUtf8(rt, value.textValue)); + } else if (value.dataType == INTEGER) + { + rowObject.setProperty(rt, columnName.c_str(), jsi::Value(value.doubleOrIntValue)); + } else if (value.dataType == DOUBLE) + { + rowObject.setProperty(rt, columnName.c_str(), jsi::Value(value.doubleOrIntValue)); + } else if (value.dataType == ARRAY_BUFFER) + { + jsi::Function array_buffer_ctor = rt.global().getPropertyAsFunction(rt, "ArrayBuffer"); + jsi::Object o = array_buffer_ctor.callAsConstructor(rt, (int) value.arrayBufferSize).getObject(rt); + jsi::ArrayBuffer buf = o.getArrayBuffer(rt); + // It's a shame we have to copy here: see https://github.com/facebook/hermes/pull/419 and https://github.com/facebook/hermes/issues/564. + memcpy(buf.data(rt), value.arrayBufferValue.get(), value.arrayBufferSize); + rowObject.setProperty(rt, columnName.c_str(), o); + } else + { + rowObject.setProperty(rt, columnName.c_str(), jsi::Value(nullptr)); + } + } else { - std::string columnName = column.colunmName; - auto it = row.find(columnName); - if (it != row.end()) - { - QuickValue value = it -> second; - if (value.dataType == TEXT) - { - // using value.textValue (std::string) directly allows jsi::String to use length property of std::string (allowing strings with NULLs in them like SQLite does) - rowObject.setProperty(rt, columnName.c_str(), jsi::String::createFromUtf8(rt, value.textValue)); - } else if (value.dataType == INTEGER || value.dataType == DOUBLE) - { - rowObject.setProperty(rt, columnName.c_str(), jsi::Value(value.doubleOrIntValue)); - } else if (value.dataType == ARRAY_BUFFER) - { - jsi::Function array_buffer_ctor = rt.global().getPropertyAsFunction(rt, "ArrayBuffer"); - jsi::Object o = array_buffer_ctor.callAsConstructor(rt, (int) value.arrayBufferSize).getObject(rt); - jsi::ArrayBuffer buf = o.getArrayBuffer(rt); - // It's a shame we have to copy here: see https://github.com/facebook/hermes/pull/419 and https://github.com/facebook/hermes/issues/564. - memcpy(buf.data(rt), value.arrayBufferValue.get(), value.arrayBufferSize); - rowObject.setProperty(rt, columnName.c_str(), o); - } else - { - rowObject.setProperty(rt, columnName.c_str(), jsi::Value(nullptr)); - } - } else - { - rowObject.setProperty(rt, columnName.c_str(), jsi::Value(nullptr)); - } + rowObject.setProperty(rt, columnName.c_str(), jsi::Value(nullptr)); } - array.setValueAtIndex(rt, i, move(rowObject)); + } + array.setValueAtIndex(rt, i, move(rowObject)); } rows.setProperty(rt, "_array", move(array)); res.setProperty(rt, "rows", move(rows)); From 2f87bf9c72fdcd73612ad1146f96708693ebd159 Mon Sep 17 00:00:00 2001 From: Christiaan Landman Date: Thu, 7 Nov 2024 10:41:43 +0200 Subject: [PATCH 3/3] Fixed columnName typo. --- cpp/JSIHelper.cpp | 4 ++-- cpp/JSIHelper.h | 2 +- cpp/sqliteExecute.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/JSIHelper.cpp b/cpp/JSIHelper.cpp index 48c0d0a..6fcb149 100644 --- a/cpp/JSIHelper.cpp +++ b/cpp/JSIHelper.cpp @@ -153,7 +153,7 @@ jsi::Value createSequelQueryExecutionResult(jsi::Runtime &rt, SQLiteOPResult sta // Iterate over metadata to maintain column order for (const auto &column : *metadata) { - std::string columnName = column.colunmName; + std::string columnName = column.columnName; auto it = row.find(columnName); if (it != row.end()) { @@ -198,7 +198,7 @@ jsi::Value createSequelQueryExecutionResult(jsi::Runtime &rt, SQLiteOPResult sta for (int i = 0; i < column_count; i++) { auto column = metadata->at(i); jsi::Object column_object = jsi::Object(rt); - column_object.setProperty(rt, "columnName", jsi::String::createFromUtf8(rt, column.colunmName.c_str())); + column_object.setProperty(rt, "columnName", jsi::String::createFromUtf8(rt, column.columnName.c_str())); column_object.setProperty(rt, "columnDeclaredType", jsi::String::createFromUtf8(rt, column.columnDeclaredType.c_str())); column_object.setProperty(rt, "columnIndex", jsi::Value(column.columnIndex)); column_array.setValueAtIndex(rt, i, move(column_object)); diff --git a/cpp/JSIHelper.h b/cpp/JSIHelper.h index 9372937..cf84c4d 100644 --- a/cpp/JSIHelper.h +++ b/cpp/JSIHelper.h @@ -91,7 +91,7 @@ struct SequelBatchOperationResult */ struct QuickColumnMetadata { - string colunmName; + string columnName; int columnIndex; string columnDeclaredType; }; diff --git a/cpp/sqliteExecute.cpp b/cpp/sqliteExecute.cpp index 843a41c..3865d57 100644 --- a/cpp/sqliteExecute.cpp +++ b/cpp/sqliteExecute.cpp @@ -139,7 +139,7 @@ sqliteExecuteWithDB(sqlite3 *db, std::string const &query, const char *tp = sqlite3_column_decltype(statement, i); column_declared_type = tp != NULL ? tp : "UNKNOWN"; QuickColumnMetadata meta = { - .colunmName = column_name, + .columnName = column_name, .columnIndex = i, .columnDeclaredType = column_declared_type, };