aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarco Bubke <marco.bubke@qt.io>2021-02-10 15:52:58 +0100
committerMarco Bubke <marco.bubke@qt.io>2021-02-15 10:39:45 +0000
commite3d12e659aa0779cb3cca3b8988abaedb3249748 (patch)
tree6b136d714538e327479e7301f03fca3ae42627ba
parent18fe4233f8a5dedb3740d59af73ae6f312c591a9 (diff)
Sqlite: Add readTo method
There are cases when you want to read to an already existing container. This will prepare for the RETURNING extension in the next Sqlite version where you can write and read. That will simplify quite some code. Change-Id: I740ffbedecf72bb5518392f3707a0a6b2221db56 Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
-rw-r--r--src/libs/sqlite/sqlitebasestatement.h27
-rw-r--r--src/libs/sqlite/sqlitereadstatement.h1
-rw-r--r--src/libs/sqlite/sqlitereadwritestatement.h1
-rw-r--r--tests/unit/unittest/mocksqlitestatement.h3
-rw-r--r--tests/unit/unittest/sqlitestatement-test.cpp59
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