Sqlite: Add unoptional value fetcher

There is now value, valueWithTransaction, optionalValue and
optionalValueWithTransaction. Sometimes you want to return
the default constructed value as default. So this is now possible.
This simplifies some code but can be even more optimal.

Change-Id: Ibbb6b5ca47803344ed646bfa257602b6db52e0fe
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Marco Bubke
2021-04-29 19:33:07 +02:00
committed by Thomas Hartmann
parent c78d1c171f
commit ef4f2a4dcf
11 changed files with 175 additions and 38 deletions

View File

@@ -87,7 +87,7 @@ public:
{ {
auto &statement = m_statementFactory.selectDirectoryIdFromDirectoriesByDirectoryPath; auto &statement = m_statementFactory.selectDirectoryIdFromDirectoriesByDirectoryPath;
return statement.template value<int>(directoryPath); return statement.template optionalValue<int>(directoryPath);
} }
int writeDirectoryId(Utils::SmallStringView directoryPath) int writeDirectoryId(Utils::SmallStringView directoryPath)
@@ -106,7 +106,7 @@ public:
auto &statement = m_statementFactory.selectDirectoryPathFromDirectoriesByDirectoryId; auto &statement = m_statementFactory.selectDirectoryPathFromDirectoriesByDirectoryId;
auto optionalDirectoryPath = statement.template value<Utils::PathString>(directoryPathId); auto optionalDirectoryPath = statement.template optionalValue<Utils::PathString>(directoryPathId);
if (!optionalDirectoryPath) if (!optionalDirectoryPath)
throw DirectoryPathIdDoesNotExists(); throw DirectoryPathIdDoesNotExists();
@@ -176,7 +176,7 @@ public:
{ {
auto &statement = m_statementFactory.selectSourceIdFromSourcesByDirectoryIdAndSourceName; auto &statement = m_statementFactory.selectSourceIdFromSourcesByDirectoryIdAndSourceName;
return statement.template value<int>(directoryId, sourceName); return statement.template optionalValue<int>(directoryId, sourceName);
} }
Sources::SourceNameAndDirectoryId fetchSourceNameAndDirectoryId(int sourceId) Sources::SourceNameAndDirectoryId fetchSourceNameAndDirectoryId(int sourceId)
@@ -186,7 +186,7 @@ public:
auto &statement = m_statementFactory.selectSourceNameAndDirectoryIdFromSourcesBySourceId; auto &statement = m_statementFactory.selectSourceNameAndDirectoryIdFromSourcesBySourceId;
auto optionalSourceName = statement.template value<Sources::SourceNameAndDirectoryId>( auto optionalSourceName = statement.template optionalValue<Sources::SourceNameAndDirectoryId>(
sourceId); sourceId);
if (!optionalSourceName) if (!optionalSourceName)
@@ -207,7 +207,7 @@ public:
auto &statement = m_statementFactory.selectDirectoryIdFromSourcesBySourceId; auto &statement = m_statementFactory.selectDirectoryIdFromSourcesBySourceId;
auto optionalDirectoryId = statement.template value<int>(sourceId); auto optionalDirectoryId = statement.template optionalValue<int>(sourceId);
if (!optionalDirectoryId) if (!optionalDirectoryId)
throw SourceNameIdDoesNotExists(); throw SourceNameIdDoesNotExists();

View File

@@ -77,7 +77,7 @@ public:
bool preCompiledHeaderWasGenerated(ProjectPartId projectPartId) const bool preCompiledHeaderWasGenerated(ProjectPartId projectPartId) const
{ {
auto value = fetchProjectPrecompiledHeaderBuildTimeStatement.template value<long long>( auto value = fetchProjectPrecompiledHeaderBuildTimeStatement.template optionalValue<long long>(
projectPartId.projectPathId); projectPartId.projectPathId);
return value && *value > 0; return value && *value > 0;
@@ -92,7 +92,7 @@ public:
Sqlite::DeferredTransaction transaction{database}; Sqlite::DeferredTransaction transaction{database};
for (ProjectPartId projectPartId : projectPartIds) { for (ProjectPartId projectPartId : projectPartIds) {
auto value = fetchProjectPartByIdStatement.template value<ProjectPartContainer>( auto value = fetchProjectPartByIdStatement.template optionalValue<ProjectPartContainer>(
projectPartId.projectPathId); projectPartId.projectPathId);
if (value) { if (value) {
value->headerPathIds = fetchHeaders(projectPartId); value->headerPathIds = fetchHeaders(projectPartId);
@@ -112,7 +112,7 @@ public:
ProjectPartId fetchProjectPartIdUnguarded(Utils::SmallStringView projectPartName) const override ProjectPartId fetchProjectPartIdUnguarded(Utils::SmallStringView projectPartName) const override
{ {
auto optionalProjectPartId = fetchProjectPartIdStatement.template value<ProjectPartId>( auto optionalProjectPartId = fetchProjectPartIdStatement.template optionalValue<ProjectPartId>(
projectPartName); projectPartName);
if (optionalProjectPartId) { if (optionalProjectPartId) {
@@ -147,8 +147,9 @@ public:
try { try {
Sqlite::DeferredTransaction transaction{database}; Sqlite::DeferredTransaction transaction{database};
auto optionalProjectPartName = fetchProjectPartNameStatement.template value<Utils::PathString>( auto optionalProjectPartName = fetchProjectPartNameStatement
projectPartId.projectPathId); .template optionalValue<Utils::PathString>(
projectPartId.projectPathId);
transaction.commit(); transaction.commit();
@@ -246,7 +247,7 @@ public:
auto &statement = getProjectPartArtefactsBySourceId; auto &statement = getProjectPartArtefactsBySourceId;
auto value = statement.template value<ProjectPartArtefact>(sourceId.filePathId); auto value = statement.template optionalValue<ProjectPartArtefact>(sourceId.filePathId);
transaction.commit(); transaction.commit();
@@ -263,7 +264,8 @@ public:
auto &statement = getProjectPartArtefactsByProjectPartId; auto &statement = getProjectPartArtefactsByProjectPartId;
auto value = statement.template value<ProjectPartArtefact>(projectPartId.projectPathId); auto value = statement.template optionalValue<ProjectPartArtefact>(
projectPartId.projectPathId);
transaction.commit(); transaction.commit();

View File

@@ -216,6 +216,22 @@ public:
template<typename ResultType, typename... QueryTypes> template<typename ResultType, typename... QueryTypes>
auto value(const QueryTypes &...queryValues) auto value(const QueryTypes &...queryValues)
{
Resetter resetter{this};
ResultType resultValue;
bindValues(queryValues...);
if (BaseStatement::next())
resultValue = createValue<ResultType>();
resetter.reset();
return resultValue;
}
template<typename ResultType, typename... QueryTypes>
auto optionalValue(const QueryTypes &...queryValues)
{ {
Resetter resetter{this}; Resetter resetter{this};
Utils::optional<ResultType> resultValue; Utils::optional<ResultType> resultValue;

View File

@@ -42,6 +42,7 @@ public:
Base::checkColumnCount(ResultCount); Base::checkColumnCount(ResultCount);
} }
using Base::optionalValue;
using Base::range; using Base::range;
using Base::rangeWithTransaction; using Base::rangeWithTransaction;
using Base::readCallback; using Base::readCallback;
@@ -62,6 +63,18 @@ public:
return resultValue; return resultValue;
} }
template<typename ResultType, typename... QueryTypes>
auto optionalValueWithTransaction(const QueryTypes &...queryValues)
{
DeferredTransaction transaction{Base::database()};
auto resultValue = Base::template optionalValue<ResultType>(queryValues...);
transaction.commit();
return resultValue;
}
template<typename ResultType, typename... QueryTypes> template<typename ResultType, typename... QueryTypes>
auto valuesWithTransaction(std::size_t reserveSize, const QueryTypes &...queryValues) auto valuesWithTransaction(std::size_t reserveSize, const QueryTypes &...queryValues)
{ {

View File

@@ -43,6 +43,7 @@ public:
} }
using Base::execute; using Base::execute;
using Base::optionalValue;
using Base::readCallback; using Base::readCallback;
using Base::readTo; using Base::readTo;
using Base::toValue; using Base::toValue;
@@ -62,6 +63,18 @@ public:
return resultValue; return resultValue;
} }
template<typename ResultType, typename... QueryTypes>
auto optionalValueWithTransaction(const QueryTypes &...queryValues)
{
ImmediateTransaction transaction{Base::database()};
auto resultValue = Base::template optionalValue<ResultType>(queryValues...);
transaction.commit();
return resultValue;
}
template<typename ResultType, typename... QueryTypes> template<typename ResultType, typename... QueryTypes>
auto valuesWithTransaction(std::size_t reserveSize, const QueryTypes &...queryValues) auto valuesWithTransaction(std::size_t reserveSize, const QueryTypes &...queryValues)
{ {

View File

@@ -152,7 +152,7 @@ public:
{ {
auto &statement = m_statementFactory.selectLocationOfSymbol; auto &statement = m_statementFactory.selectLocationOfSymbol;
return statement.template value<SourceLocation>(symbolId, int(kind)); return statement.template optionalValue<SourceLocation>(symbolId, int(kind));
} }
private: private:
StatementFactory &m_statementFactory; StatementFactory &m_statementFactory;

View File

@@ -58,7 +58,7 @@ public:
try { try {
Sqlite::DeferredTransaction transaction{database}; Sqlite::DeferredTransaction transaction{database};
auto optionalBlob = selectImageStatement.template value<Sqlite::ByteArrayBlob>( auto optionalBlob = selectImageStatement.template optionalValue<Sqlite::ByteArrayBlob>(
name, minimumTimeStamp.value); name, minimumTimeStamp.value);
transaction.commit(); transaction.commit();
@@ -78,7 +78,7 @@ public:
try { try {
Sqlite::DeferredTransaction transaction{database}; Sqlite::DeferredTransaction transaction{database};
auto optionalBlob = selectSmallImageStatement.template value<Sqlite::ByteArrayBlob>( auto optionalBlob = selectSmallImageStatement.template optionalValue<Sqlite::ByteArrayBlob>(
name, minimumTimeStamp.value); name, minimumTimeStamp.value);
transaction.commit(); transaction.commit();
@@ -98,7 +98,7 @@ public:
try { try {
Sqlite::DeferredTransaction transaction{database}; Sqlite::DeferredTransaction transaction{database};
auto optionalBlob = selectIconStatement.template value<Sqlite::ByteArrayBlob>( auto optionalBlob = selectIconStatement.template optionalValue<Sqlite::ByteArrayBlob>(
name, minimumTimeStamp.value); name, minimumTimeStamp.value);
transaction.commit(); transaction.commit();

View File

@@ -102,7 +102,7 @@ public:
{ {
auto &statement = getLowestLastModifiedTimeOfDependencies; auto &statement = getLowestLastModifiedTimeOfDependencies;
return statement.template value<long long>(sourceId.filePathId).value_or(0); return statement.template optionalValue<long long>(sourceId.filePathId).value_or(0);
} }
void insertOrUpdateUsedMacros(const UsedMacros &usedMacros) override void insertOrUpdateUsedMacros(const UsedMacros &usedMacros) override
@@ -131,7 +131,8 @@ public:
ProjectPartId fetchProjectPartId(Utils::SmallStringView projectPartName) override ProjectPartId fetchProjectPartId(Utils::SmallStringView projectPartName) override
{ {
auto projectPartId = fetchProjectPartIdStatement.template value<ProjectPartId>(projectPartName); auto projectPartId = fetchProjectPartIdStatement.template optionalValue<ProjectPartId>(
projectPartName);
if (projectPartId) if (projectPartId)
return *projectPartId; return *projectPartId;

View File

@@ -145,7 +145,7 @@ public:
try { try {
Sqlite::DeferredTransaction transaction{database}; Sqlite::DeferredTransaction transaction{database};
auto value = fetchSystemPrecompiledHeaderPathStatement.template value<FilePath>( auto value = fetchSystemPrecompiledHeaderPathStatement.template optionalValue<FilePath>(
projectPartId.projectPathId); projectPartId.projectPathId);
transaction.commit(); transaction.commit();
@@ -165,7 +165,7 @@ public:
try { try {
Sqlite::DeferredTransaction transaction{database}; Sqlite::DeferredTransaction transaction{database};
auto value = fetchPrecompiledHeaderStatement.template value<FilePath>( auto value = fetchPrecompiledHeaderStatement.template optionalValue<FilePath>(
projectPartId.projectPathId); projectPartId.projectPathId);
transaction.commit(); transaction.commit();
@@ -185,7 +185,7 @@ public:
try { try {
Sqlite::DeferredTransaction transaction{database}; Sqlite::DeferredTransaction transaction{database};
auto value = fetchPrecompiledHeadersStatement.template value<PchPaths>( auto value = fetchPrecompiledHeadersStatement.template optionalValue<PchPaths>(
projectPartId.projectPathId); projectPartId.projectPathId);
transaction.commit(); transaction.commit();
@@ -205,7 +205,7 @@ public:
try { try {
Sqlite::DeferredTransaction transaction{database}; Sqlite::DeferredTransaction transaction{database};
auto value = fetchTimeStampsStatement.template value<PrecompiledHeaderTimeStamps>( auto value = fetchTimeStampsStatement.template optionalValue<PrecompiledHeaderTimeStamps>(
projectPartId.projectPathId); projectPartId.projectPathId);
transaction.commit(); transaction.commit();

View File

@@ -161,7 +161,7 @@ public:
(int projectPartId)); (int projectPartId));
template<typename ResultType, typename... QueryTypes> template<typename ResultType, typename... QueryTypes>
auto value(const QueryTypes &...queryValues) auto optionalValue(const QueryTypes &...queryValues)
{ {
if constexpr (std::is_same_v<ResultType, Sqlite::ByteArrayBlob>) if constexpr (std::is_same_v<ResultType, Sqlite::ByteArrayBlob>)
return valueReturnBlob(queryValues...); return valueReturnBlob(queryValues...);
@@ -196,6 +196,19 @@ public:
"SqliteReadStatementMock::value does not handle result type!"); "SqliteReadStatementMock::value does not handle result type!");
} }
template<typename ResultType, typename... QueryTypes>
auto value(const QueryTypes &...queryValues)
{
static_assert(!std::is_same_v<ResultType, ResultType>,
"SqliteReadStatementMock::value does not handle result type!");
}
template<typename ResultType, typename... QueryTypes>
auto optionalValueWithTransaction(const QueryTypes &...queryValues)
{
return optionalValue<ResultType>(queryValues...);
}
template<typename ResultType, typename... QueryType> template<typename ResultType, typename... QueryType>
auto values(std::size_t reserveSize, const QueryType &...queryValues) auto values(std::size_t reserveSize, const QueryType &...queryValues)
{ {

View File

@@ -133,8 +133,11 @@ protected:
struct Output struct Output
{ {
Output(Utils::SmallStringView name, Utils::SmallStringView number, long long value) explicit Output() = default;
: name(name), number(number), value(value) explicit Output(Utils::SmallStringView name, Utils::SmallStringView number, long long value)
: name(name)
, number(number)
, value(value)
{} {}
Utils::SmallString name; Utils::SmallString name;
@@ -559,7 +562,7 @@ TEST_F(SqliteStatement, WriteSqliteBlobValue)
statement.write(Sqlite::Value{bytes}); statement.write(Sqlite::Value{bytes});
ASSERT_THAT(readStatement.template value<Sqlite::Blob>(), ASSERT_THAT(readStatement.template optionalValue<Sqlite::Blob>(),
Optional(Field(&Sqlite::Blob::bytes, Eq(bytes)))); Optional(Field(&Sqlite::Blob::bytes, Eq(bytes))));
} }
@@ -611,7 +614,7 @@ TEST_F(SqliteStatement, WriteSqliteBlobValueView)
statement.write(Sqlite::ValueView::create(bytes)); statement.write(Sqlite::ValueView::create(bytes));
ASSERT_THAT(readStatement.template value<Sqlite::Blob>(), ASSERT_THAT(readStatement.template optionalValue<Sqlite::Blob>(),
Optional(Field(&Sqlite::Blob::bytes, Eq(bytes)))); Optional(Field(&Sqlite::Blob::bytes, Eq(bytes))));
} }
@@ -648,7 +651,7 @@ TEST_F(SqliteStatement, WriteBlobs)
statement.write(bytes); statement.write(bytes);
ASSERT_THAT(readStatement.template value<Sqlite::Blob>(), ASSERT_THAT(readStatement.template optionalValue<Sqlite::Blob>(),
Optional(Field(&Sqlite::Blob::bytes, Eq(bytes)))); Optional(Field(&Sqlite::Blob::bytes, Eq(bytes))));
} }
@@ -1049,29 +1052,29 @@ TEST_F(SqliteStatement, GetBlobValues)
ASSERT_THAT(values, ElementsAre(Field(&Sqlite::Blob::bytes, Eq(bytes)))); ASSERT_THAT(values, ElementsAre(Field(&Sqlite::Blob::bytes, Eq(bytes))));
} }
TEST_F(SqliteStatement, GetEmptyBlobValueForInteger) TEST_F(SqliteStatement, GetEmptyOptionalBlobValueForInteger)
{ {
ReadStatement<1> statement("SELECT value FROM test WHERE name='poo'", database); ReadStatement<1> statement("SELECT value FROM test WHERE name='poo'", database);
auto value = statement.value<Sqlite::Blob>(); auto value = statement.optionalValue<Sqlite::Blob>();
ASSERT_THAT(value, Optional(Field(&Sqlite::Blob::bytes, IsEmpty()))); ASSERT_THAT(value, Optional(Field(&Sqlite::Blob::bytes, IsEmpty())));
} }
TEST_F(SqliteStatement, GetEmptyBlobValueForFloat) TEST_F(SqliteStatement, GetEmptyOptionalBlobValueForFloat)
{ {
ReadStatement<1> statement("SELECT number FROM test WHERE name='foo'", database); ReadStatement<1> statement("SELECT number FROM test WHERE name='foo'", database);
auto value = statement.value<Sqlite::Blob>(); auto value = statement.optionalValue<Sqlite::Blob>();
ASSERT_THAT(value, Optional(Field(&Sqlite::Blob::bytes, IsEmpty()))); ASSERT_THAT(value, Optional(Field(&Sqlite::Blob::bytes, IsEmpty())));
} }
TEST_F(SqliteStatement, GetEmptyBlobValueForText) TEST_F(SqliteStatement, GetEmptyOptionalBlobValueForText)
{ {
ReadStatement<1> statement("SELECT number FROM test WHERE name='bar'", database); ReadStatement<1> statement("SELECT number FROM test WHERE name='bar'", database);
auto value = statement.value<Sqlite::Blob>(); auto value = statement.optionalValue<Sqlite::Blob>();
ASSERT_THAT(value, Optional(Field(&Sqlite::Blob::bytes, IsEmpty()))); ASSERT_THAT(value, Optional(Field(&Sqlite::Blob::bytes, IsEmpty())));
} }
@@ -1081,7 +1084,7 @@ TEST_F(SqliteStatement, GetOptionalSingleValueAndMultipleQueryValue)
ReadStatement<1> statement("SELECT name FROM test WHERE name=? AND number=? AND value=?", ReadStatement<1> statement("SELECT name FROM test WHERE name=? AND number=? AND value=?",
database); database);
auto value = statement.value<Utils::SmallString>("bar", "blah", 1); auto value = statement.optionalValue<Utils::SmallString>("bar", "blah", 1);
ASSERT_THAT(value.value(), Eq("bar")); ASSERT_THAT(value.value(), Eq("bar"));
} }
@@ -1091,7 +1094,7 @@ TEST_F(SqliteStatement, GetOptionalOutputValueAndMultipleQueryValue)
ReadStatement<3> statement( ReadStatement<3> statement(
"SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database); "SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database);
auto value = statement.value<Output>("bar", "blah", 1); auto value = statement.optionalValue<Output>("bar", "blah", 1);
ASSERT_THAT(value.value(), Eq(Output{"bar", "blah", 1})); ASSERT_THAT(value.value(), Eq(Output{"bar", "blah", 1}));
} }
@@ -1102,7 +1105,7 @@ TEST_F(SqliteStatement, GetOptionalTupleValueAndMultipleQueryValue)
ReadStatement<3> statement( ReadStatement<3> statement(
"SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database); "SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database);
auto value = statement.value<Tuple>("bar", "blah", 1); auto value = statement.optionalValue<Tuple>("bar", "blah", 1);
ASSERT_THAT(value.value(), Eq(Tuple{"bar", "blah", 1})); ASSERT_THAT(value.value(), Eq(Tuple{"bar", "blah", 1}));
} }
@@ -1113,7 +1116,7 @@ TEST_F(SqliteStatement, GetOptionalValueCallsReset)
EXPECT_CALL(mockStatement, reset()); EXPECT_CALL(mockStatement, reset());
mockStatement.value<int>("bar"); mockStatement.optionalValue<int>("bar");
} }
TEST_F(SqliteStatement, GetOptionalValueCallsResetIfExceptionIsThrown) TEST_F(SqliteStatement, GetOptionalValueCallsResetIfExceptionIsThrown)
@@ -1123,6 +1126,56 @@ TEST_F(SqliteStatement, GetOptionalValueCallsResetIfExceptionIsThrown)
EXPECT_CALL(mockStatement, reset()); EXPECT_CALL(mockStatement, reset());
EXPECT_THROW(mockStatement.optionalValue<int>("bar"), Sqlite::StatementHasError);
}
TEST_F(SqliteStatement, GetSingleValueAndMultipleQueryValue)
{
ReadStatement<1> statement("SELECT name FROM test WHERE name=? AND number=? AND value=?",
database);
auto value = statement.value<Utils::SmallString>("bar", "blah", 1);
ASSERT_THAT(value, Eq("bar"));
}
TEST_F(SqliteStatement, GetOutputValueAndMultipleQueryValue)
{
ReadStatement<3> statement(
"SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database);
auto value = statement.value<Output>("bar", "blah", 1);
ASSERT_THAT(value, Eq(Output{"bar", "blah", 1}));
}
TEST_F(SqliteStatement, GetTupleValueAndMultipleQueryValue)
{
using Tuple = std::tuple<Utils::SmallString, Utils::SmallString, long long>;
ReadStatement<3> statement(
"SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database);
auto value = statement.value<Tuple>("bar", "blah", 1);
ASSERT_THAT(value, Eq(Tuple{"bar", "blah", 1}));
}
TEST_F(SqliteStatement, GetValueCallsReset)
{
MockSqliteStatement mockStatement{databaseMock};
EXPECT_CALL(mockStatement, reset());
mockStatement.value<int>("bar");
}
TEST_F(SqliteStatement, GetValueCallsResetIfExceptionIsThrown)
{
MockSqliteStatement mockStatement{databaseMock};
ON_CALL(mockStatement, next()).WillByDefault(Throw(Sqlite::StatementHasError("")));
EXPECT_CALL(mockStatement, reset());
EXPECT_THROW(mockStatement.value<int>("bar"), Sqlite::StatementHasError); EXPECT_THROW(mockStatement.value<int>("bar"), Sqlite::StatementHasError);
} }
@@ -1402,6 +1455,19 @@ TEST_F(SqliteStatement, ReadStatementValueWithTransactions)
auto value = statement.valueWithTransaction<Tuple>("bar", "blah"); auto value = statement.valueWithTransaction<Tuple>("bar", "blah");
ASSERT_THAT(value, Eq(Tuple{"bar", "blah", 1}));
database.lock();
}
TEST_F(SqliteStatement, ReadStatementOptionalValueWithTransactions)
{
using Tuple = std::tuple<Utils::SmallString, Utils::SmallString, long long>;
ReadStatement<3> statement("SELECT name, number, value FROM test WHERE name=? AND number=?",
database);
database.unlock();
auto value = statement.optionalValueWithTransaction<Tuple>("bar", "blah");
ASSERT_THAT(*value, Eq(Tuple{"bar", "blah", 1})); ASSERT_THAT(*value, Eq(Tuple{"bar", "blah", 1}));
database.lock(); database.lock();
} }
@@ -1456,6 +1522,19 @@ TEST_F(SqliteStatement, ReadWriteStatementValueWithTransactions)
auto value = statement.valueWithTransaction<Tuple>("bar", "blah"); auto value = statement.valueWithTransaction<Tuple>("bar", "blah");
ASSERT_THAT(value, Eq(Tuple{"bar", "blah", 1}));
database.lock();
}
TEST_F(SqliteStatement, ReadWriteStatementOptionalValueWithTransactions)
{
using Tuple = std::tuple<Utils::SmallString, Utils::SmallString, long long>;
ReadWriteStatement<3> statement(
"SELECT name, number, value FROM test WHERE name=? AND number=?", database);
database.unlock();
auto value = statement.optionalValueWithTransaction<Tuple>("bar", "blah");
ASSERT_THAT(*value, Eq(Tuple{"bar", "blah", 1})); ASSERT_THAT(*value, Eq(Tuple{"bar", "blah", 1}));
database.lock(); database.lock();
} }