diff --git a/src/libs/sqlite/sqlitebasestatement.h b/src/libs/sqlite/sqlitebasestatement.h index 3b68d8a3fc6..01ae9161318 100644 --- a/src/libs/sqlite/sqlitebasestatement.h +++ b/src/libs/sqlite/sqlitebasestatement.h @@ -336,6 +336,21 @@ public: resetter.reset(); } + template + void readTo(Container &container, const QueryTypes &...queryValues) + { + BaseStatement::checkColumnCount(ResultTypeCount); + + Resetter resetter{*this}; + + bindValues(queryValues...); + + while (BaseStatement::next()) + pushBackToContainer(container); + + resetter.reset(); + } + protected: ~StatementImplementation() = default; @@ -430,6 +445,18 @@ private: return callCallable(callable, std::make_integer_sequence{}); } + template + void pushBackToContainer(Container &container, std::integer_sequence) + { + container.push_back(Container::value_type(ValueGetter(*this, ColumnIndices)...)); + } + + template + void pushBackToContainer(Container &container) + { + pushBackToContainer(container, std::make_integer_sequence{}); + } + template void bindValuesByIndex(int index, const ValueType &value) { diff --git a/src/libs/sqlite/sqlitereadstatement.h b/src/libs/sqlite/sqlitereadstatement.h index 9314b54e0fe..236aab67f17 100644 --- a/src/libs/sqlite/sqlitereadstatement.h +++ b/src/libs/sqlite/sqlitereadstatement.h @@ -35,6 +35,7 @@ public: explicit ReadStatement(Utils::SmallStringView sqlStatement, Database &database); using StatementImplementation::readCallback; + using StatementImplementation::readTo; using StatementImplementation::toValue; using StatementImplementation::value; using StatementImplementation::values; diff --git a/src/libs/sqlite/sqlitereadwritestatement.h b/src/libs/sqlite/sqlitereadwritestatement.h index f7e23e100c2..6adc9ebb35f 100644 --- a/src/libs/sqlite/sqlitereadwritestatement.h +++ b/src/libs/sqlite/sqlitereadwritestatement.h @@ -38,6 +38,7 @@ public: using StatementImplementation::execute; using StatementImplementation::readCallback; + using StatementImplementation::readTo; using StatementImplementation::toValue; using StatementImplementation::value; using StatementImplementation::values; diff --git a/tests/unit/unittest/mocksqlitestatement.h b/tests/unit/unittest/mocksqlitestatement.h index 767840ee8f4..141eb9520ba 100644 --- a/tests/unit/unittest/mocksqlitestatement.h +++ b/tests/unit/unittest/mocksqlitestatement.h @@ -41,9 +41,10 @@ public: MOCK_CONST_METHOD1(fetchLongValue, long (int)); MOCK_CONST_METHOD1(fetchLongLongValue, long long (int)); MOCK_CONST_METHOD1(fetchDoubleValue, double (int)); - MOCK_CONST_METHOD1(fetchSmallStringValue, Utils::SmallString (int)); + MOCK_CONST_METHOD1(fetchSmallStringValue, Utils::SmallString(int)); MOCK_CONST_METHOD1(fetchSmallStringViewValue, Utils::SmallStringView(int)); MOCK_CONST_METHOD1(fetchPathStringValue, Utils::PathString (int)); + MOCK_CONST_METHOD1(fetchValueView, Sqlite::ValueView(int)); template Type fetchValue(int column) const; diff --git a/tests/unit/unittest/sqlitestatement-test.cpp b/tests/unit/unittest/sqlitestatement-test.cpp index 6749742b77b..9f14f5b852b 100644 --- a/tests/unit/unittest/sqlitestatement-test.cpp +++ b/tests/unit/unittest/sqlitestatement-test.cpp @@ -37,6 +37,7 @@ #include +#include #include namespace { @@ -1032,4 +1033,62 @@ TEST_F(SqliteStatement, ReadCallbackCallsResetIfExceptionIsThrown) Sqlite::StatementHasError); } +TEST_F(SqliteStatement, ReadToContainer) +{ + std::deque values; + ReadStatement statement("SELECT number FROM test", database); + + statement.readTo<1>(values); + + ASSERT_THAT(values, UnorderedElementsAre(Eq("blah"), Eq(23.3), Eq(40))); +} + +TEST_F(SqliteStatement, ReadToContainerCallCallbackWithArguments) +{ + std::deque values; + ReadStatement statement("SELECT number FROM test WHERE value=?", database); + + statement.readTo(values, 2); + + ASSERT_THAT(values, ElementsAre(Eq(23.3))); +} + +TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForToManyArgumentsForReadTo) +{ + std::deque values; + SqliteTestStatement statement("SELECT name, number FROM test", database); + + ASSERT_THROW(statement.readTo<1>(values, 2), Sqlite::ColumnCountDoesNotMatch); +} + +TEST_F(SqliteStatement, ReadToCallsResetAfterPushingAllValuesBack) +{ + std::deque values; + MockSqliteStatement mockStatement; + + EXPECT_CALL(mockStatement, reset()); + + mockStatement.readTo(values); +} + +TEST_F(SqliteStatement, ReadToThrowsForError) +{ + std::deque values; + MockSqliteStatement mockStatement; + ON_CALL(mockStatement, next()).WillByDefault(Throw(Sqlite::StatementHasError(""))); + + ASSERT_THROW(mockStatement.readTo(values), Sqlite::StatementHasError); +} + +TEST_F(SqliteStatement, ReadToCallsResetIfExceptionIsThrown) +{ + std::deque values; + MockSqliteStatement mockStatement; + ON_CALL(mockStatement, next()).WillByDefault(Throw(Sqlite::StatementHasError(""))); + + EXPECT_CALL(mockStatement, reset()); + + EXPECT_THROW(mockStatement.readTo(values), Sqlite::StatementHasError); +} + } // namespace