diff options
-rw-r--r-- | src/libs/sqlite/sqlitebasestatement.h | 27 | ||||
-rw-r--r-- | src/libs/sqlite/sqlitereadstatement.h | 1 | ||||
-rw-r--r-- | src/libs/sqlite/sqlitereadwritestatement.h | 1 | ||||
-rw-r--r-- | tests/unit/unittest/mocksqlitestatement.h | 3 | ||||
-rw-r--r-- | tests/unit/unittest/sqlitestatement-test.cpp | 59 |
5 files changed, 90 insertions, 1 deletions
diff --git a/src/libs/sqlite/sqlitebasestatement.h b/src/libs/sqlite/sqlitebasestatement.h index 3b68d8a3fc..01ae916131 100644 --- a/src/libs/sqlite/sqlitebasestatement.h +++ b/src/libs/sqlite/sqlitebasestatement.h @@ -336,6 +336,21 @@ public: resetter.reset(); } + template<int ResultTypeCount = 1, typename Container, typename... QueryTypes> + void readTo(Container &container, const QueryTypes &...queryValues) + { + BaseStatement::checkColumnCount(ResultTypeCount); + + Resetter resetter{*this}; + + bindValues(queryValues...); + + while (BaseStatement::next()) + pushBackToContainer<ResultTypeCount>(container); + + resetter.reset(); + } + protected: ~StatementImplementation() = default; @@ -430,6 +445,18 @@ private: return callCallable(callable, std::make_integer_sequence<int, ResultTypeCount>{}); } + template<typename Container, int... ColumnIndices> + void pushBackToContainer(Container &container, std::integer_sequence<int, ColumnIndices...>) + { + container.push_back(Container::value_type(ValueGetter(*this, ColumnIndices)...)); + } + + template<int ResultTypeCount, typename Container> + void pushBackToContainer(Container &container) + { + pushBackToContainer(container, std::make_integer_sequence<int, ResultTypeCount>{}); + } + template<typename ValueType> void bindValuesByIndex(int index, const ValueType &value) { diff --git a/src/libs/sqlite/sqlitereadstatement.h b/src/libs/sqlite/sqlitereadstatement.h index 9314b54e0f..236aab67f1 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 f7e23e100c..6adc9ebb35 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 767840ee8f..141eb9520b 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<typename Type> Type fetchValue(int column) const; diff --git a/tests/unit/unittest/sqlitestatement-test.cpp b/tests/unit/unittest/sqlitestatement-test.cpp index 6749742b77..9f14f5b852 100644 --- a/tests/unit/unittest/sqlitestatement-test.cpp +++ b/tests/unit/unittest/sqlitestatement-test.cpp @@ -37,6 +37,7 @@ #include <QDir> +#include <deque> #include <vector> namespace { @@ -1032,4 +1033,62 @@ TEST_F(SqliteStatement, ReadCallbackCallsResetIfExceptionIsThrown) Sqlite::StatementHasError); } +TEST_F(SqliteStatement, ReadToContainer) +{ + std::deque<FooValue> 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<FooValue> 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<FooValue> values; + SqliteTestStatement statement("SELECT name, number FROM test", database); + + ASSERT_THROW(statement.readTo<1>(values, 2), Sqlite::ColumnCountDoesNotMatch); +} + +TEST_F(SqliteStatement, ReadToCallsResetAfterPushingAllValuesBack) +{ + std::deque<FooValue> values; + MockSqliteStatement mockStatement; + + EXPECT_CALL(mockStatement, reset()); + + mockStatement.readTo(values); +} + +TEST_F(SqliteStatement, ReadToThrowsForError) +{ + std::deque<FooValue> values; + MockSqliteStatement mockStatement; + ON_CALL(mockStatement, next()).WillByDefault(Throw(Sqlite::StatementHasError(""))); + + ASSERT_THROW(mockStatement.readTo(values), Sqlite::StatementHasError); +} + +TEST_F(SqliteStatement, ReadToCallsResetIfExceptionIsThrown) +{ + std::deque<FooValue> values; + MockSqliteStatement mockStatement; + ON_CALL(mockStatement, next()).WillByDefault(Throw(Sqlite::StatementHasError(""))); + + EXPECT_CALL(mockStatement, reset()); + + EXPECT_THROW(mockStatement.readTo(values), Sqlite::StatementHasError); +} + } // namespace |