forked from qt-creator/qt-creator
Sqlite: Improve transaction by inversion of control
Using a callable makes it possible to omit the commit call. It is now called by the withDeferredTransaction and withImmediateTransaction function. Change-Id: I9b7bfa7e32f269fe8fcba2fe5e1218e73f5846d1 Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Vikas Pachdha <vikas.pachdha@qt.io>
This commit is contained in:
@@ -34,57 +34,39 @@ public:
|
||||
template<typename ResultType, typename... QueryTypes>
|
||||
auto valueWithTransaction(const QueryTypes &...queryValues)
|
||||
{
|
||||
DeferredTransaction transaction{Base::database()};
|
||||
|
||||
auto resultValue = Base::template value<ResultType>(queryValues...);
|
||||
|
||||
transaction.commit();
|
||||
|
||||
return resultValue;
|
||||
return withDeferredTransaction(Base::database(), [&] {
|
||||
return Base::template value<ResultType>(queryValues...);
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
return withDeferredTransaction(Base::database(), [&] {
|
||||
return Base::template optionalValue<ResultType>(queryValues...);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename ResultType, typename... QueryTypes>
|
||||
auto valuesWithTransaction(std::size_t reserveSize, const QueryTypes &...queryValues)
|
||||
{
|
||||
DeferredTransaction transaction{Base::database()};
|
||||
|
||||
auto resultValues = Base::template values<ResultType>(reserveSize, queryValues...);
|
||||
|
||||
transaction.commit();
|
||||
|
||||
return resultValues;
|
||||
return withDeferredTransaction(Base::database(), [&] {
|
||||
return Base::template values<ResultType>(reserveSize, queryValues...);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename Callable, typename... QueryTypes>
|
||||
void readCallbackWithTransaction(Callable &&callable, const QueryTypes &...queryValues)
|
||||
{
|
||||
DeferredTransaction transaction{Base::database()};
|
||||
|
||||
Base::readCallback(std::forward<Callable>(callable), queryValues...);
|
||||
|
||||
transaction.commit();
|
||||
withDeferredTransaction(Base::database(), [&] {
|
||||
Base::readCallback(std::forward<Callable>(callable), queryValues...);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename Container, typename... QueryTypes>
|
||||
void readToWithTransaction(Container &container, const QueryTypes &...queryValues)
|
||||
{
|
||||
DeferredTransaction transaction{Base::database()};
|
||||
|
||||
Base::readTo(container, queryValues...);
|
||||
|
||||
transaction.commit();
|
||||
withDeferredTransaction(Base::database(), [&] { Base::readTo(container, queryValues...); });
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -34,66 +34,48 @@ public:
|
||||
template<typename ResultType, typename... QueryTypes>
|
||||
auto valueWithTransaction(const QueryTypes &...queryValues)
|
||||
{
|
||||
ImmediateTransaction transaction{Base::database()};
|
||||
|
||||
auto resultValue = Base::template value<ResultType>(queryValues...);
|
||||
|
||||
transaction.commit();
|
||||
|
||||
return resultValue;
|
||||
return withImmediateTransaction(Base::database(), [&] {
|
||||
return Base::template value<ResultType>(queryValues...);
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
return withImmediateTransaction(Base::database(), [&] {
|
||||
return Base::template optionalValue<ResultType>(queryValues...);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename ResultType, typename... QueryTypes>
|
||||
auto valuesWithTransaction(std::size_t reserveSize, const QueryTypes &...queryValues)
|
||||
{
|
||||
ImmediateTransaction transaction{Base::database()};
|
||||
|
||||
auto resultValues = Base::template values<ResultType>(reserveSize, queryValues...);
|
||||
|
||||
transaction.commit();
|
||||
|
||||
return resultValues;
|
||||
return withImmediateTransaction(Base::database(), [&] {
|
||||
return Base::template values<ResultType>(reserveSize, queryValues...);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename Callable, typename... QueryTypes>
|
||||
void readCallbackWithTransaction(Callable &&callable, const QueryTypes &...queryValues)
|
||||
{
|
||||
ImmediateTransaction transaction{Base::database()};
|
||||
|
||||
Base::readCallback(std::forward<Callable>(callable), queryValues...);
|
||||
|
||||
transaction.commit();
|
||||
withImmediateTransaction(Base::database(), [&] {
|
||||
Base::readCallback(std::forward<Callable>(callable), queryValues...);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename Container, typename... QueryTypes>
|
||||
void readToWithTransaction(Container &container, const QueryTypes &...queryValues)
|
||||
{
|
||||
ImmediateTransaction transaction{Base::database()};
|
||||
|
||||
Base::readTo(container, queryValues...);
|
||||
|
||||
transaction.commit();
|
||||
withImmediateTransaction(Base::database(), [&] {
|
||||
Base::readTo(container, queryValues...);
|
||||
});
|
||||
}
|
||||
|
||||
void executeWithTransaction()
|
||||
{
|
||||
ImmediateTransaction transaction{Base::database()};
|
||||
|
||||
Base::execute();
|
||||
|
||||
transaction.commit();
|
||||
withImmediateTransaction(Base::database(), [&] {
|
||||
Base::execute();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -60,7 +60,6 @@ protected:
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
TransactionInterface &m_interface;
|
||||
std::unique_lock<TransactionInterface> m_locker{m_interface};
|
||||
@@ -183,6 +182,38 @@ public:
|
||||
using Base::Base;
|
||||
};
|
||||
|
||||
template<typename Transaction, typename TransactionInterface, typename Callable>
|
||||
auto withTransaction(TransactionInterface &transactionInterface, Callable &&callable)
|
||||
-> std::invoke_result_t<Callable>
|
||||
{
|
||||
Transaction transaction{transactionInterface};
|
||||
|
||||
if constexpr (std::is_void_v<std::invoke_result_t<Callable>>) {
|
||||
callable();
|
||||
|
||||
transaction.commit();
|
||||
} else {
|
||||
auto results = callable();
|
||||
|
||||
transaction.commit();
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TransactionInterface, typename Callable>
|
||||
auto withDeferredTransaction(TransactionInterface &transactionInterface, Callable &&callable)
|
||||
{
|
||||
if constexpr (std::is_void_v<std::invoke_result_t<Callable>>) {
|
||||
withTransaction<DeferredTransaction<TransactionInterface>>(transactionInterface,
|
||||
std::forward<Callable>(callable));
|
||||
} else {
|
||||
return withTransaction<DeferredTransaction<TransactionInterface>>(transactionInterface,
|
||||
std::forward<Callable>(
|
||||
callable));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TransactionInterface>
|
||||
DeferredTransaction(TransactionInterface &) -> DeferredTransaction<TransactionInterface>;
|
||||
|
||||
@@ -226,6 +257,20 @@ public:
|
||||
using Base::Base;
|
||||
};
|
||||
|
||||
template<typename TransactionInterface, typename Callable>
|
||||
auto withImmediateTransaction(TransactionInterface &transactionInterface, Callable &&callable)
|
||||
{
|
||||
if constexpr (std::is_void_v<std::invoke_result_t<Callable>>) {
|
||||
withTransaction<ImmediateTransaction<TransactionInterface>>(transactionInterface,
|
||||
std::forward<Callable>(
|
||||
callable));
|
||||
} else {
|
||||
return withTransaction<ImmediateTransaction<TransactionInterface>>(transactionInterface,
|
||||
std::forward<Callable>(
|
||||
callable));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TransactionInterface>
|
||||
ImmediateTransaction(TransactionInterface &) -> ImmediateTransaction<TransactionInterface>;
|
||||
|
||||
|
||||
@@ -35,12 +35,8 @@ public:
|
||||
ImageEntry fetchImage(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp) const override
|
||||
{
|
||||
try {
|
||||
Sqlite::DeferredTransaction transaction{database};
|
||||
|
||||
auto optionalBlob = selectImageStatement.template optionalValue<Sqlite::ByteArrayBlob>(
|
||||
name, minimumTimeStamp.value);
|
||||
|
||||
transaction.commit();
|
||||
auto optionalBlob = selectImageStatement.template optionalValueWithTransaction<
|
||||
Sqlite::ByteArrayBlob>(name, minimumTimeStamp.value);
|
||||
|
||||
if (optionalBlob)
|
||||
return {readImage(optionalBlob->byteArray)};
|
||||
@@ -55,12 +51,8 @@ public:
|
||||
Sqlite::TimeStamp minimumTimeStamp) const override
|
||||
{
|
||||
try {
|
||||
Sqlite::DeferredTransaction transaction{database};
|
||||
|
||||
auto optionalBlob = selectMidSizeImageStatement.template optionalValue<Sqlite::ByteArrayBlob>(
|
||||
name, minimumTimeStamp.value);
|
||||
|
||||
transaction.commit();
|
||||
auto optionalBlob = selectMidSizeImageStatement.template optionalValueWithTransaction<
|
||||
Sqlite::ByteArrayBlob>(name, minimumTimeStamp.value);
|
||||
|
||||
if (optionalBlob)
|
||||
return {readImage(optionalBlob->byteArray)};
|
||||
@@ -75,12 +67,8 @@ public:
|
||||
Sqlite::TimeStamp minimumTimeStamp) const override
|
||||
{
|
||||
try {
|
||||
Sqlite::DeferredTransaction transaction{database};
|
||||
|
||||
auto optionalBlob = selectSmallImageStatement.template optionalValue<Sqlite::ByteArrayBlob>(
|
||||
name, minimumTimeStamp.value);
|
||||
|
||||
transaction.commit();
|
||||
auto optionalBlob = selectSmallImageStatement.template optionalValueWithTransaction<
|
||||
Sqlite::ByteArrayBlob>(name, minimumTimeStamp.value);
|
||||
|
||||
if (optionalBlob)
|
||||
return ImageEntry{readImage(optionalBlob->byteArray)};
|
||||
@@ -95,12 +83,8 @@ public:
|
||||
IconEntry fetchIcon(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp) const override
|
||||
{
|
||||
try {
|
||||
Sqlite::DeferredTransaction transaction{database};
|
||||
|
||||
auto optionalBlob = selectIconStatement.template optionalValue<Sqlite::ByteArrayBlob>(
|
||||
name, minimumTimeStamp.value);
|
||||
|
||||
transaction.commit();
|
||||
auto optionalBlob = selectIconStatement.template optionalValueWithTransaction<
|
||||
Sqlite::ByteArrayBlob>(name, minimumTimeStamp.value);
|
||||
|
||||
if (optionalBlob)
|
||||
return {readIcon(optionalBlob->byteArray)};
|
||||
@@ -119,19 +103,16 @@ public:
|
||||
const QImage &smallImage) override
|
||||
{
|
||||
try {
|
||||
Sqlite::ImmediateTransaction transaction{database};
|
||||
|
||||
auto imageBuffer = createBuffer(image);
|
||||
auto midSizeImageBuffer = createBuffer(midSizeImage);
|
||||
auto smallImageBuffer = createBuffer(smallImage);
|
||||
upsertImageStatement.write(name,
|
||||
newTimeStamp.value,
|
||||
createBlobView(imageBuffer.get()),
|
||||
createBlobView(midSizeImageBuffer.get()),
|
||||
createBlobView(smallImageBuffer.get()));
|
||||
|
||||
transaction.commit();
|
||||
|
||||
Sqlite::withImmediateTransaction(database, [&] {
|
||||
upsertImageStatement.write(name,
|
||||
newTimeStamp.value,
|
||||
createBlobView(imageBuffer.get()),
|
||||
createBlobView(midSizeImageBuffer.get()),
|
||||
createBlobView(smallImageBuffer.get()));
|
||||
});
|
||||
} catch (const Sqlite::StatementIsBusy &) {
|
||||
return storeImage(name, newTimeStamp, image, midSizeImage, smallImage);
|
||||
}
|
||||
@@ -140,12 +121,10 @@ public:
|
||||
void storeIcon(Utils::SmallStringView name, Sqlite::TimeStamp newTimeStamp, const QIcon &icon) override
|
||||
{
|
||||
try {
|
||||
Sqlite::ImmediateTransaction transaction{database};
|
||||
|
||||
auto iconBuffer = createBuffer(icon);
|
||||
upsertIconStatement.write(name, newTimeStamp.value, createBlobView(iconBuffer.get()));
|
||||
|
||||
transaction.commit();
|
||||
Sqlite::withImmediateTransaction(database, [&] {
|
||||
upsertIconStatement.write(name, newTimeStamp.value, createBlobView(iconBuffer.get()));
|
||||
});
|
||||
|
||||
} catch (const Sqlite::StatementIsBusy &) {
|
||||
return storeIcon(name, newTimeStamp, icon);
|
||||
|
||||
@@ -45,63 +45,61 @@ public:
|
||||
|
||||
void synchronize(Storage::Synchronization::SynchronizationPackage package) override
|
||||
{
|
||||
Sqlite::ImmediateTransaction transaction{database};
|
||||
Sqlite::withImmediateTransaction(database, [&] {
|
||||
AliasPropertyDeclarations insertedAliasPropertyDeclarations;
|
||||
AliasPropertyDeclarations updatedAliasPropertyDeclarations;
|
||||
|
||||
AliasPropertyDeclarations insertedAliasPropertyDeclarations;
|
||||
AliasPropertyDeclarations updatedAliasPropertyDeclarations;
|
||||
AliasPropertyDeclarations relinkableAliasPropertyDeclarations;
|
||||
PropertyDeclarations relinkablePropertyDeclarations;
|
||||
Prototypes relinkablePrototypes;
|
||||
Prototypes relinkableExtensions;
|
||||
TypeIds deletedTypeIds;
|
||||
|
||||
AliasPropertyDeclarations relinkableAliasPropertyDeclarations;
|
||||
PropertyDeclarations relinkablePropertyDeclarations;
|
||||
Prototypes relinkablePrototypes;
|
||||
Prototypes relinkableExtensions;
|
||||
TypeIds deletedTypeIds;
|
||||
TypeIds updatedTypeIds;
|
||||
updatedTypeIds.reserve(package.types.size());
|
||||
|
||||
TypeIds updatedTypeIds;
|
||||
updatedTypeIds.reserve(package.types.size());
|
||||
TypeIds typeIdsToBeDeleted;
|
||||
|
||||
TypeIds typeIdsToBeDeleted;
|
||||
std::sort(package.updatedSourceIds.begin(), package.updatedSourceIds.end());
|
||||
|
||||
std::sort(package.updatedSourceIds.begin(), package.updatedSourceIds.end());
|
||||
synchronizeFileStatuses(package.fileStatuses, package.updatedFileStatusSourceIds);
|
||||
synchronizeImports(package.imports,
|
||||
package.updatedSourceIds,
|
||||
package.moduleDependencies,
|
||||
package.updatedModuleDependencySourceIds,
|
||||
package.moduleExportedImports,
|
||||
package.updatedModuleIds);
|
||||
synchronizeTypes(package.types,
|
||||
updatedTypeIds,
|
||||
insertedAliasPropertyDeclarations,
|
||||
updatedAliasPropertyDeclarations,
|
||||
relinkableAliasPropertyDeclarations,
|
||||
relinkablePropertyDeclarations,
|
||||
relinkablePrototypes,
|
||||
relinkableExtensions,
|
||||
package.updatedSourceIds);
|
||||
|
||||
synchronizeFileStatuses(package.fileStatuses, package.updatedFileStatusSourceIds);
|
||||
synchronizeImports(package.imports,
|
||||
package.updatedSourceIds,
|
||||
package.moduleDependencies,
|
||||
package.updatedModuleDependencySourceIds,
|
||||
package.moduleExportedImports,
|
||||
package.updatedModuleIds);
|
||||
synchronizeTypes(package.types,
|
||||
updatedTypeIds,
|
||||
insertedAliasPropertyDeclarations,
|
||||
updatedAliasPropertyDeclarations,
|
||||
relinkableAliasPropertyDeclarations,
|
||||
relinkablePropertyDeclarations,
|
||||
relinkablePrototypes,
|
||||
relinkableExtensions,
|
||||
package.updatedSourceIds);
|
||||
deleteNotUpdatedTypes(updatedTypeIds,
|
||||
package.updatedSourceIds,
|
||||
typeIdsToBeDeleted,
|
||||
relinkableAliasPropertyDeclarations,
|
||||
relinkablePropertyDeclarations,
|
||||
relinkablePrototypes,
|
||||
relinkableExtensions,
|
||||
deletedTypeIds);
|
||||
|
||||
deleteNotUpdatedTypes(updatedTypeIds,
|
||||
package.updatedSourceIds,
|
||||
typeIdsToBeDeleted,
|
||||
relinkableAliasPropertyDeclarations,
|
||||
relinkablePropertyDeclarations,
|
||||
relinkablePrototypes,
|
||||
relinkableExtensions,
|
||||
deletedTypeIds);
|
||||
relink(relinkableAliasPropertyDeclarations,
|
||||
relinkablePropertyDeclarations,
|
||||
relinkablePrototypes,
|
||||
relinkableExtensions,
|
||||
deletedTypeIds);
|
||||
|
||||
relink(relinkableAliasPropertyDeclarations,
|
||||
relinkablePropertyDeclarations,
|
||||
relinkablePrototypes,
|
||||
relinkableExtensions,
|
||||
deletedTypeIds);
|
||||
linkAliases(insertedAliasPropertyDeclarations, updatedAliasPropertyDeclarations);
|
||||
|
||||
linkAliases(insertedAliasPropertyDeclarations, updatedAliasPropertyDeclarations);
|
||||
synchronizeProjectDatas(package.projectDatas, package.updatedProjectSourceIds);
|
||||
|
||||
synchronizeProjectDatas(package.projectDatas, package.updatedProjectSourceIds);
|
||||
|
||||
commonTypeCache_.resetTypeIds();
|
||||
|
||||
transaction.commit();
|
||||
commonTypeCache_.resetTypeIds();
|
||||
});
|
||||
}
|
||||
|
||||
ModuleId moduleId(Utils::SmallStringView moduleName) const override
|
||||
@@ -304,38 +302,35 @@ public:
|
||||
|
||||
Storage::Synchronization::Type fetchTypeByTypeId(TypeId typeId)
|
||||
{
|
||||
Sqlite::DeferredTransaction transaction{database};
|
||||
return Sqlite::withDeferredTransaction(database, [&] {
|
||||
auto type = selectTypeByTypeIdStatement.template value<Storage::Synchronization::Type>(
|
||||
typeId);
|
||||
|
||||
auto type = selectTypeByTypeIdStatement.template value<Storage::Synchronization::Type>(typeId);
|
||||
|
||||
type.exportedTypes = fetchExportedTypes(typeId);
|
||||
type.propertyDeclarations = fetchPropertyDeclarations(type.typeId);
|
||||
type.functionDeclarations = fetchFunctionDeclarations(type.typeId);
|
||||
type.signalDeclarations = fetchSignalDeclarations(type.typeId);
|
||||
type.enumerationDeclarations = fetchEnumerationDeclarations(type.typeId);
|
||||
|
||||
transaction.commit();
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
Storage::Synchronization::Types fetchTypes()
|
||||
{
|
||||
Sqlite::DeferredTransaction transaction{database};
|
||||
|
||||
auto types = selectTypesStatement.template values<Storage::Synchronization::Type>(64);
|
||||
|
||||
for (Storage::Synchronization::Type &type : types) {
|
||||
type.exportedTypes = fetchExportedTypes(type.typeId);
|
||||
type.exportedTypes = fetchExportedTypes(typeId);
|
||||
type.propertyDeclarations = fetchPropertyDeclarations(type.typeId);
|
||||
type.functionDeclarations = fetchFunctionDeclarations(type.typeId);
|
||||
type.signalDeclarations = fetchSignalDeclarations(type.typeId);
|
||||
type.enumerationDeclarations = fetchEnumerationDeclarations(type.typeId);
|
||||
}
|
||||
|
||||
transaction.commit();
|
||||
return type;
|
||||
});
|
||||
}
|
||||
|
||||
return types;
|
||||
Storage::Synchronization::Types fetchTypes()
|
||||
{
|
||||
return Sqlite::withDeferredTransaction(database, [&] {
|
||||
auto types = selectTypesStatement.template values<Storage::Synchronization::Type>(64);
|
||||
|
||||
for (Storage::Synchronization::Type &type : types) {
|
||||
type.exportedTypes = fetchExportedTypes(type.typeId);
|
||||
type.propertyDeclarations = fetchPropertyDeclarations(type.typeId);
|
||||
type.functionDeclarations = fetchFunctionDeclarations(type.typeId);
|
||||
type.signalDeclarations = fetchSignalDeclarations(type.typeId);
|
||||
type.enumerationDeclarations = fetchEnumerationDeclarations(type.typeId);
|
||||
}
|
||||
|
||||
return types;
|
||||
});
|
||||
}
|
||||
|
||||
bool fetchIsProtype(TypeId type, TypeId prototype)
|
||||
@@ -358,13 +353,9 @@ public:
|
||||
SourceContextId fetchSourceContextId(Utils::SmallStringView sourceContextPath)
|
||||
{
|
||||
try {
|
||||
Sqlite::DeferredTransaction transaction{database};
|
||||
|
||||
auto sourceContextId = fetchSourceContextIdUnguarded(sourceContextPath);
|
||||
|
||||
transaction.commit();
|
||||
|
||||
return sourceContextId;
|
||||
return Sqlite::withDeferredTransaction(database, [&] {
|
||||
return fetchSourceContextIdUnguarded(sourceContextPath);
|
||||
});
|
||||
} catch (const Sqlite::ConstraintPreventsModification &) {
|
||||
return fetchSourceContextId(sourceContextPath);
|
||||
}
|
||||
@@ -372,18 +363,16 @@ public:
|
||||
|
||||
Utils::PathString fetchSourceContextPath(SourceContextId sourceContextId) const
|
||||
{
|
||||
Sqlite::DeferredTransaction transaction{database};
|
||||
return Sqlite::withDeferredTransaction(database, [&] {
|
||||
auto optionalSourceContextPath = selectSourceContextPathFromSourceContextsBySourceContextIdStatement
|
||||
.template optionalValue<Utils::PathString>(
|
||||
sourceContextId);
|
||||
|
||||
auto optionalSourceContextPath = selectSourceContextPathFromSourceContextsBySourceContextIdStatement
|
||||
.template optionalValue<Utils::PathString>(
|
||||
sourceContextId);
|
||||
if (!optionalSourceContextPath)
|
||||
throw SourceContextIdDoesNotExists();
|
||||
|
||||
if (!optionalSourceContextPath)
|
||||
throw SourceContextIdDoesNotExists();
|
||||
|
||||
transaction.commit();
|
||||
|
||||
return std::move(*optionalSourceContextPath);
|
||||
return std::move(*optionalSourceContextPath);
|
||||
});
|
||||
}
|
||||
|
||||
auto fetchAllSourceContexts() const
|
||||
@@ -394,13 +383,9 @@ public:
|
||||
|
||||
SourceId fetchSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName)
|
||||
{
|
||||
Sqlite::DeferredTransaction transaction{database};
|
||||
|
||||
auto sourceId = fetchSourceIdUnguarded(sourceContextId, sourceName);
|
||||
|
||||
transaction.commit();
|
||||
|
||||
return sourceId;
|
||||
return Sqlite::withDeferredTransaction(database, [&] {
|
||||
return fetchSourceIdUnguarded(sourceContextId, sourceName);
|
||||
});
|
||||
}
|
||||
|
||||
auto fetchSourceNameAndSourceContextId(SourceId sourceId) const
|
||||
@@ -416,12 +401,10 @@ public:
|
||||
|
||||
void clearSources()
|
||||
{
|
||||
Sqlite::ImmediateTransaction transaction{database};
|
||||
|
||||
deleteAllSourceContextsStatement.execute();
|
||||
deleteAllSourcesStatement.execute();
|
||||
|
||||
transaction.commit();
|
||||
Sqlite::withImmediateTransaction(database, [&] {
|
||||
deleteAllSourceContextsStatement.execute();
|
||||
deleteAllSourcesStatement.execute();
|
||||
});
|
||||
}
|
||||
|
||||
SourceContextId fetchSourceContextId(SourceId sourceId) const
|
||||
@@ -523,24 +506,15 @@ private:
|
||||
|
||||
ModuleId fetchModuleId(Utils::SmallStringView moduleName)
|
||||
{
|
||||
Sqlite::DeferredTransaction transaction{database};
|
||||
|
||||
ModuleId moduleId = fetchModuleIdUnguarded(moduleName);
|
||||
|
||||
transaction.commit();
|
||||
|
||||
return moduleId;
|
||||
return Sqlite::withDeferredTransaction(database,
|
||||
[&] { return fetchModuleIdUnguarded(moduleName); });
|
||||
}
|
||||
|
||||
auto fetchModuleName(ModuleId id)
|
||||
{
|
||||
Sqlite::DeferredTransaction transaction{database};
|
||||
|
||||
auto moduleName = fetchModuleNameUnguarded(id);
|
||||
|
||||
transaction.commit();
|
||||
|
||||
return moduleName;
|
||||
return Sqlite::withDeferredTransaction(database, [&] {
|
||||
return fetchModuleNameUnguarded(id);
|
||||
});
|
||||
}
|
||||
|
||||
auto fetchAllModules() const
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
SqliteReadStatementMockBase::SqliteReadStatementMockBase(Utils::SmallStringView sqlStatement,
|
||||
SqliteDatabaseMock &databaseMock)
|
||||
: sqlStatement(sqlStatement)
|
||||
, databaseMock(databaseMock)
|
||||
{
|
||||
databaseMock.prepare(sqlStatement);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <projectstorageids.h>
|
||||
#include <sqliteblob.h>
|
||||
#include <sqlitetimestamp.h>
|
||||
#include <sqlitetransaction.h>
|
||||
#include <utils/smallstring.h>
|
||||
|
||||
#include <QImage>
|
||||
@@ -198,7 +199,9 @@ public:
|
||||
template<typename ResultType, typename... QueryTypes>
|
||||
auto optionalValueWithTransaction(const QueryTypes &...queryValues)
|
||||
{
|
||||
return optionalValue<ResultType>(queryValues...);
|
||||
return Sqlite::withDeferredTransaction(databaseMock, [&] {
|
||||
return optionalValue<ResultType>(queryValues...);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename ResultType, typename... QueryType>
|
||||
@@ -261,6 +264,7 @@ public:
|
||||
|
||||
public:
|
||||
Utils::SmallString sqlStatement;
|
||||
SqliteDatabaseMock &databaseMock;
|
||||
};
|
||||
|
||||
template<int ResultCount, int BindParameterCount = 0>
|
||||
|
||||
@@ -21,8 +21,13 @@ using Sqlite::ImmediateTransaction;
|
||||
|
||||
class SqliteTransaction : public testing::Test
|
||||
{
|
||||
protected:
|
||||
SqliteTransaction() { ON_CALL(callableWithReturnMock, Call()).WillByDefault(Return(212)); }
|
||||
|
||||
protected:
|
||||
NiceMock<MockSqliteTransactionBackend> mockTransactionBackend;
|
||||
NiceMock<MockFunction<void()>> callableMock;
|
||||
NiceMock<MockFunction<int()>> callableWithReturnMock;
|
||||
};
|
||||
|
||||
TEST_F(SqliteTransaction, DeferredTransactionCommit)
|
||||
@@ -38,19 +43,6 @@ TEST_F(SqliteTransaction, DeferredTransactionCommit)
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
TEST_F(SqliteTransaction, DeferredTransactionCommitCallsInterface)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mockTransactionBackend, lock());
|
||||
EXPECT_CALL(mockTransactionBackend, deferredBegin());
|
||||
EXPECT_CALL(mockTransactionBackend, commit());
|
||||
EXPECT_CALL(mockTransactionBackend, unlock());
|
||||
|
||||
DeferredTransaction transaction{mockTransactionBackend};
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
TEST_F(SqliteTransaction, DeferredTransactionRollBack)
|
||||
{
|
||||
InSequence s;
|
||||
@@ -337,4 +329,110 @@ TEST_F(SqliteTransaction, ImmediateSessionTransactionBeginThrowsAndNotRollback)
|
||||
ASSERT_ANY_THROW(ImmediateSessionTransaction{mockTransactionBackend});
|
||||
}
|
||||
|
||||
TEST_F(SqliteTransaction, WithDeferredTransactionNoReturnCommit)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mockTransactionBackend, lock());
|
||||
EXPECT_CALL(mockTransactionBackend, deferredBegin());
|
||||
EXPECT_CALL(callableMock, Call());
|
||||
EXPECT_CALL(mockTransactionBackend, commit());
|
||||
EXPECT_CALL(mockTransactionBackend, unlock());
|
||||
|
||||
Sqlite::withDeferredTransaction(mockTransactionBackend, callableMock.AsStdFunction());
|
||||
}
|
||||
|
||||
TEST_F(SqliteTransaction, WithDeferredTransactionWithReturnCommit)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mockTransactionBackend, lock());
|
||||
EXPECT_CALL(mockTransactionBackend, deferredBegin());
|
||||
EXPECT_CALL(callableWithReturnMock, Call());
|
||||
EXPECT_CALL(mockTransactionBackend, commit());
|
||||
EXPECT_CALL(mockTransactionBackend, unlock());
|
||||
|
||||
Sqlite::withDeferredTransaction(mockTransactionBackend, callableWithReturnMock.AsStdFunction());
|
||||
}
|
||||
|
||||
TEST_F(SqliteTransaction, WithDeferredTransactionReturnsValue)
|
||||
{
|
||||
auto callable = callableWithReturnMock.AsStdFunction();
|
||||
|
||||
auto value = Sqlite::withDeferredTransaction(mockTransactionBackend,
|
||||
callableWithReturnMock.AsStdFunction());
|
||||
|
||||
ASSERT_THAT(value, Eq(212));
|
||||
}
|
||||
|
||||
TEST_F(SqliteTransaction, WithDeferredTransactionRollsbackForException)
|
||||
{
|
||||
InSequence s;
|
||||
ON_CALL(callableMock, Call()).WillByDefault(Throw(std::exception{}));
|
||||
|
||||
EXPECT_CALL(mockTransactionBackend, lock());
|
||||
EXPECT_CALL(mockTransactionBackend, deferredBegin());
|
||||
EXPECT_CALL(callableMock, Call());
|
||||
EXPECT_CALL(mockTransactionBackend, rollback());
|
||||
EXPECT_CALL(mockTransactionBackend, unlock());
|
||||
|
||||
try {
|
||||
Sqlite::withDeferredTransaction(mockTransactionBackend, callableMock.AsStdFunction());
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SqliteTransaction, WithImmediateTransactionNoReturnCommit)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mockTransactionBackend, lock());
|
||||
EXPECT_CALL(mockTransactionBackend, immediateBegin());
|
||||
EXPECT_CALL(callableMock, Call());
|
||||
EXPECT_CALL(mockTransactionBackend, commit());
|
||||
EXPECT_CALL(mockTransactionBackend, unlock());
|
||||
|
||||
Sqlite::withImmediateTransaction(mockTransactionBackend, callableMock.AsStdFunction());
|
||||
}
|
||||
|
||||
TEST_F(SqliteTransaction, WithImmediateTransactionWithReturnCommit)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mockTransactionBackend, lock());
|
||||
EXPECT_CALL(mockTransactionBackend, immediateBegin());
|
||||
EXPECT_CALL(callableWithReturnMock, Call());
|
||||
EXPECT_CALL(mockTransactionBackend, commit());
|
||||
EXPECT_CALL(mockTransactionBackend, unlock());
|
||||
|
||||
Sqlite::withImmediateTransaction(mockTransactionBackend, callableWithReturnMock.AsStdFunction());
|
||||
}
|
||||
|
||||
TEST_F(SqliteTransaction, WithImmediateTransactionReturnsValue)
|
||||
{
|
||||
auto callable = callableWithReturnMock.AsStdFunction();
|
||||
|
||||
auto value = Sqlite::withImmediateTransaction(mockTransactionBackend,
|
||||
callableWithReturnMock.AsStdFunction());
|
||||
|
||||
ASSERT_THAT(value, Eq(212));
|
||||
}
|
||||
|
||||
TEST_F(SqliteTransaction, WithImmediateTransactionRollsbackForException)
|
||||
{
|
||||
InSequence s;
|
||||
ON_CALL(callableMock, Call()).WillByDefault(Throw(std::exception{}));
|
||||
|
||||
EXPECT_CALL(mockTransactionBackend, lock());
|
||||
EXPECT_CALL(mockTransactionBackend, immediateBegin());
|
||||
EXPECT_CALL(callableMock, Call());
|
||||
EXPECT_CALL(mockTransactionBackend, rollback());
|
||||
EXPECT_CALL(mockTransactionBackend, unlock());
|
||||
|
||||
try {
|
||||
Sqlite::withImmediateTransaction(mockTransactionBackend, callableMock.AsStdFunction());
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user