forked from qt-creator/qt-creator
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>
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
@@ -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;
|
||||
|
@@ -38,6 +38,7 @@ public:
|
||||
|
||||
using StatementImplementation::execute;
|
||||
using StatementImplementation::readCallback;
|
||||
using StatementImplementation::readTo;
|
||||
using StatementImplementation::toValue;
|
||||
using StatementImplementation::value;
|
||||
using StatementImplementation::values;
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user