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>
|
template<typename ResultType, typename... QueryTypes>
|
||||||
auto valueWithTransaction(const QueryTypes &...queryValues)
|
auto valueWithTransaction(const QueryTypes &...queryValues)
|
||||||
{
|
{
|
||||||
DeferredTransaction transaction{Base::database()};
|
return withDeferredTransaction(Base::database(), [&] {
|
||||||
|
return Base::template value<ResultType>(queryValues...);
|
||||||
auto resultValue = Base::template value<ResultType>(queryValues...);
|
});
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
|
|
||||||
return resultValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ResultType, typename... QueryTypes>
|
template<typename ResultType, typename... QueryTypes>
|
||||||
auto optionalValueWithTransaction(const QueryTypes &...queryValues)
|
auto optionalValueWithTransaction(const QueryTypes &...queryValues)
|
||||||
{
|
{
|
||||||
DeferredTransaction transaction{Base::database()};
|
return withDeferredTransaction(Base::database(), [&] {
|
||||||
|
return Base::template optionalValue<ResultType>(queryValues...);
|
||||||
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)
|
||||||
{
|
{
|
||||||
DeferredTransaction transaction{Base::database()};
|
return withDeferredTransaction(Base::database(), [&] {
|
||||||
|
return Base::template values<ResultType>(reserveSize, queryValues...);
|
||||||
auto resultValues = Base::template values<ResultType>(reserveSize, queryValues...);
|
});
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
|
|
||||||
return resultValues;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Callable, typename... QueryTypes>
|
template<typename Callable, typename... QueryTypes>
|
||||||
void readCallbackWithTransaction(Callable &&callable, const QueryTypes &...queryValues)
|
void readCallbackWithTransaction(Callable &&callable, const QueryTypes &...queryValues)
|
||||||
{
|
{
|
||||||
DeferredTransaction transaction{Base::database()};
|
withDeferredTransaction(Base::database(), [&] {
|
||||||
|
Base::readCallback(std::forward<Callable>(callable), queryValues...);
|
||||||
Base::readCallback(std::forward<Callable>(callable), queryValues...);
|
});
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Container, typename... QueryTypes>
|
template<typename Container, typename... QueryTypes>
|
||||||
void readToWithTransaction(Container &container, const QueryTypes &...queryValues)
|
void readToWithTransaction(Container &container, const QueryTypes &...queryValues)
|
||||||
{
|
{
|
||||||
DeferredTransaction transaction{Base::database()};
|
withDeferredTransaction(Base::database(), [&] { Base::readTo(container, queryValues...); });
|
||||||
|
|
||||||
Base::readTo(container, queryValues...);
|
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -34,66 +34,48 @@ public:
|
|||||||
template<typename ResultType, typename... QueryTypes>
|
template<typename ResultType, typename... QueryTypes>
|
||||||
auto valueWithTransaction(const QueryTypes &...queryValues)
|
auto valueWithTransaction(const QueryTypes &...queryValues)
|
||||||
{
|
{
|
||||||
ImmediateTransaction transaction{Base::database()};
|
return withImmediateTransaction(Base::database(), [&] {
|
||||||
|
return Base::template value<ResultType>(queryValues...);
|
||||||
auto resultValue = Base::template value<ResultType>(queryValues...);
|
});
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
|
|
||||||
return resultValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ResultType, typename... QueryTypes>
|
template<typename ResultType, typename... QueryTypes>
|
||||||
auto optionalValueWithTransaction(const QueryTypes &...queryValues)
|
auto optionalValueWithTransaction(const QueryTypes &...queryValues)
|
||||||
{
|
{
|
||||||
ImmediateTransaction transaction{Base::database()};
|
return withImmediateTransaction(Base::database(), [&] {
|
||||||
|
return Base::template optionalValue<ResultType>(queryValues...);
|
||||||
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)
|
||||||
{
|
{
|
||||||
ImmediateTransaction transaction{Base::database()};
|
return withImmediateTransaction(Base::database(), [&] {
|
||||||
|
return Base::template values<ResultType>(reserveSize, queryValues...);
|
||||||
auto resultValues = Base::template values<ResultType>(reserveSize, queryValues...);
|
});
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
|
|
||||||
return resultValues;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Callable, typename... QueryTypes>
|
template<typename Callable, typename... QueryTypes>
|
||||||
void readCallbackWithTransaction(Callable &&callable, const QueryTypes &...queryValues)
|
void readCallbackWithTransaction(Callable &&callable, const QueryTypes &...queryValues)
|
||||||
{
|
{
|
||||||
ImmediateTransaction transaction{Base::database()};
|
withImmediateTransaction(Base::database(), [&] {
|
||||||
|
Base::readCallback(std::forward<Callable>(callable), queryValues...);
|
||||||
Base::readCallback(std::forward<Callable>(callable), queryValues...);
|
});
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Container, typename... QueryTypes>
|
template<typename Container, typename... QueryTypes>
|
||||||
void readToWithTransaction(Container &container, const QueryTypes &...queryValues)
|
void readToWithTransaction(Container &container, const QueryTypes &...queryValues)
|
||||||
{
|
{
|
||||||
ImmediateTransaction transaction{Base::database()};
|
withImmediateTransaction(Base::database(), [&] {
|
||||||
|
Base::readTo(container, queryValues...);
|
||||||
Base::readTo(container, queryValues...);
|
});
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void executeWithTransaction()
|
void executeWithTransaction()
|
||||||
{
|
{
|
||||||
ImmediateTransaction transaction{Base::database()};
|
withImmediateTransaction(Base::database(), [&] {
|
||||||
|
Base::execute();
|
||||||
Base::execute();
|
});
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ protected:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TransactionInterface &m_interface;
|
TransactionInterface &m_interface;
|
||||||
std::unique_lock<TransactionInterface> m_locker{m_interface};
|
std::unique_lock<TransactionInterface> m_locker{m_interface};
|
||||||
@@ -183,6 +182,38 @@ public:
|
|||||||
using Base::Base;
|
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>
|
template<typename TransactionInterface>
|
||||||
DeferredTransaction(TransactionInterface &) -> DeferredTransaction<TransactionInterface>;
|
DeferredTransaction(TransactionInterface &) -> DeferredTransaction<TransactionInterface>;
|
||||||
|
|
||||||
@@ -226,6 +257,20 @@ public:
|
|||||||
using Base::Base;
|
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>
|
template<typename TransactionInterface>
|
||||||
ImmediateTransaction(TransactionInterface &) -> ImmediateTransaction<TransactionInterface>;
|
ImmediateTransaction(TransactionInterface &) -> ImmediateTransaction<TransactionInterface>;
|
||||||
|
|
||||||
|
|||||||
@@ -35,12 +35,8 @@ public:
|
|||||||
ImageEntry fetchImage(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp) const override
|
ImageEntry fetchImage(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp) const override
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
Sqlite::DeferredTransaction transaction{database};
|
auto optionalBlob = selectImageStatement.template optionalValueWithTransaction<
|
||||||
|
Sqlite::ByteArrayBlob>(name, minimumTimeStamp.value);
|
||||||
auto optionalBlob = selectImageStatement.template optionalValue<Sqlite::ByteArrayBlob>(
|
|
||||||
name, minimumTimeStamp.value);
|
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
|
|
||||||
if (optionalBlob)
|
if (optionalBlob)
|
||||||
return {readImage(optionalBlob->byteArray)};
|
return {readImage(optionalBlob->byteArray)};
|
||||||
@@ -55,12 +51,8 @@ public:
|
|||||||
Sqlite::TimeStamp minimumTimeStamp) const override
|
Sqlite::TimeStamp minimumTimeStamp) const override
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
Sqlite::DeferredTransaction transaction{database};
|
auto optionalBlob = selectMidSizeImageStatement.template optionalValueWithTransaction<
|
||||||
|
Sqlite::ByteArrayBlob>(name, minimumTimeStamp.value);
|
||||||
auto optionalBlob = selectMidSizeImageStatement.template optionalValue<Sqlite::ByteArrayBlob>(
|
|
||||||
name, minimumTimeStamp.value);
|
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
|
|
||||||
if (optionalBlob)
|
if (optionalBlob)
|
||||||
return {readImage(optionalBlob->byteArray)};
|
return {readImage(optionalBlob->byteArray)};
|
||||||
@@ -75,12 +67,8 @@ public:
|
|||||||
Sqlite::TimeStamp minimumTimeStamp) const override
|
Sqlite::TimeStamp minimumTimeStamp) const override
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
Sqlite::DeferredTransaction transaction{database};
|
auto optionalBlob = selectSmallImageStatement.template optionalValueWithTransaction<
|
||||||
|
Sqlite::ByteArrayBlob>(name, minimumTimeStamp.value);
|
||||||
auto optionalBlob = selectSmallImageStatement.template optionalValue<Sqlite::ByteArrayBlob>(
|
|
||||||
name, minimumTimeStamp.value);
|
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
|
|
||||||
if (optionalBlob)
|
if (optionalBlob)
|
||||||
return ImageEntry{readImage(optionalBlob->byteArray)};
|
return ImageEntry{readImage(optionalBlob->byteArray)};
|
||||||
@@ -95,12 +83,8 @@ public:
|
|||||||
IconEntry fetchIcon(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp) const override
|
IconEntry fetchIcon(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp) const override
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
Sqlite::DeferredTransaction transaction{database};
|
auto optionalBlob = selectIconStatement.template optionalValueWithTransaction<
|
||||||
|
Sqlite::ByteArrayBlob>(name, minimumTimeStamp.value);
|
||||||
auto optionalBlob = selectIconStatement.template optionalValue<Sqlite::ByteArrayBlob>(
|
|
||||||
name, minimumTimeStamp.value);
|
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
|
|
||||||
if (optionalBlob)
|
if (optionalBlob)
|
||||||
return {readIcon(optionalBlob->byteArray)};
|
return {readIcon(optionalBlob->byteArray)};
|
||||||
@@ -119,19 +103,16 @@ public:
|
|||||||
const QImage &smallImage) override
|
const QImage &smallImage) override
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
Sqlite::ImmediateTransaction transaction{database};
|
|
||||||
|
|
||||||
auto imageBuffer = createBuffer(image);
|
auto imageBuffer = createBuffer(image);
|
||||||
auto midSizeImageBuffer = createBuffer(midSizeImage);
|
auto midSizeImageBuffer = createBuffer(midSizeImage);
|
||||||
auto smallImageBuffer = createBuffer(smallImage);
|
auto smallImageBuffer = createBuffer(smallImage);
|
||||||
upsertImageStatement.write(name,
|
Sqlite::withImmediateTransaction(database, [&] {
|
||||||
newTimeStamp.value,
|
upsertImageStatement.write(name,
|
||||||
createBlobView(imageBuffer.get()),
|
newTimeStamp.value,
|
||||||
createBlobView(midSizeImageBuffer.get()),
|
createBlobView(imageBuffer.get()),
|
||||||
createBlobView(smallImageBuffer.get()));
|
createBlobView(midSizeImageBuffer.get()),
|
||||||
|
createBlobView(smallImageBuffer.get()));
|
||||||
transaction.commit();
|
});
|
||||||
|
|
||||||
} catch (const Sqlite::StatementIsBusy &) {
|
} catch (const Sqlite::StatementIsBusy &) {
|
||||||
return storeImage(name, newTimeStamp, image, midSizeImage, smallImage);
|
return storeImage(name, newTimeStamp, image, midSizeImage, smallImage);
|
||||||
}
|
}
|
||||||
@@ -140,12 +121,10 @@ public:
|
|||||||
void storeIcon(Utils::SmallStringView name, Sqlite::TimeStamp newTimeStamp, const QIcon &icon) override
|
void storeIcon(Utils::SmallStringView name, Sqlite::TimeStamp newTimeStamp, const QIcon &icon) override
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
Sqlite::ImmediateTransaction transaction{database};
|
|
||||||
|
|
||||||
auto iconBuffer = createBuffer(icon);
|
auto iconBuffer = createBuffer(icon);
|
||||||
upsertIconStatement.write(name, newTimeStamp.value, createBlobView(iconBuffer.get()));
|
Sqlite::withImmediateTransaction(database, [&] {
|
||||||
|
upsertIconStatement.write(name, newTimeStamp.value, createBlobView(iconBuffer.get()));
|
||||||
transaction.commit();
|
});
|
||||||
|
|
||||||
} catch (const Sqlite::StatementIsBusy &) {
|
} catch (const Sqlite::StatementIsBusy &) {
|
||||||
return storeIcon(name, newTimeStamp, icon);
|
return storeIcon(name, newTimeStamp, icon);
|
||||||
|
|||||||
@@ -45,63 +45,61 @@ public:
|
|||||||
|
|
||||||
void synchronize(Storage::Synchronization::SynchronizationPackage package) override
|
void synchronize(Storage::Synchronization::SynchronizationPackage package) override
|
||||||
{
|
{
|
||||||
Sqlite::ImmediateTransaction transaction{database};
|
Sqlite::withImmediateTransaction(database, [&] {
|
||||||
|
AliasPropertyDeclarations insertedAliasPropertyDeclarations;
|
||||||
|
AliasPropertyDeclarations updatedAliasPropertyDeclarations;
|
||||||
|
|
||||||
AliasPropertyDeclarations insertedAliasPropertyDeclarations;
|
AliasPropertyDeclarations relinkableAliasPropertyDeclarations;
|
||||||
AliasPropertyDeclarations updatedAliasPropertyDeclarations;
|
PropertyDeclarations relinkablePropertyDeclarations;
|
||||||
|
Prototypes relinkablePrototypes;
|
||||||
|
Prototypes relinkableExtensions;
|
||||||
|
TypeIds deletedTypeIds;
|
||||||
|
|
||||||
AliasPropertyDeclarations relinkableAliasPropertyDeclarations;
|
TypeIds updatedTypeIds;
|
||||||
PropertyDeclarations relinkablePropertyDeclarations;
|
updatedTypeIds.reserve(package.types.size());
|
||||||
Prototypes relinkablePrototypes;
|
|
||||||
Prototypes relinkableExtensions;
|
|
||||||
TypeIds deletedTypeIds;
|
|
||||||
|
|
||||||
TypeIds updatedTypeIds;
|
TypeIds typeIdsToBeDeleted;
|
||||||
updatedTypeIds.reserve(package.types.size());
|
|
||||||
|
|
||||||
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);
|
deleteNotUpdatedTypes(updatedTypeIds,
|
||||||
synchronizeImports(package.imports,
|
package.updatedSourceIds,
|
||||||
package.updatedSourceIds,
|
typeIdsToBeDeleted,
|
||||||
package.moduleDependencies,
|
relinkableAliasPropertyDeclarations,
|
||||||
package.updatedModuleDependencySourceIds,
|
relinkablePropertyDeclarations,
|
||||||
package.moduleExportedImports,
|
relinkablePrototypes,
|
||||||
package.updatedModuleIds);
|
relinkableExtensions,
|
||||||
synchronizeTypes(package.types,
|
deletedTypeIds);
|
||||||
updatedTypeIds,
|
|
||||||
insertedAliasPropertyDeclarations,
|
|
||||||
updatedAliasPropertyDeclarations,
|
|
||||||
relinkableAliasPropertyDeclarations,
|
|
||||||
relinkablePropertyDeclarations,
|
|
||||||
relinkablePrototypes,
|
|
||||||
relinkableExtensions,
|
|
||||||
package.updatedSourceIds);
|
|
||||||
|
|
||||||
deleteNotUpdatedTypes(updatedTypeIds,
|
relink(relinkableAliasPropertyDeclarations,
|
||||||
package.updatedSourceIds,
|
relinkablePropertyDeclarations,
|
||||||
typeIdsToBeDeleted,
|
relinkablePrototypes,
|
||||||
relinkableAliasPropertyDeclarations,
|
relinkableExtensions,
|
||||||
relinkablePropertyDeclarations,
|
deletedTypeIds);
|
||||||
relinkablePrototypes,
|
|
||||||
relinkableExtensions,
|
|
||||||
deletedTypeIds);
|
|
||||||
|
|
||||||
relink(relinkableAliasPropertyDeclarations,
|
linkAliases(insertedAliasPropertyDeclarations, updatedAliasPropertyDeclarations);
|
||||||
relinkablePropertyDeclarations,
|
|
||||||
relinkablePrototypes,
|
|
||||||
relinkableExtensions,
|
|
||||||
deletedTypeIds);
|
|
||||||
|
|
||||||
linkAliases(insertedAliasPropertyDeclarations, updatedAliasPropertyDeclarations);
|
synchronizeProjectDatas(package.projectDatas, package.updatedProjectSourceIds);
|
||||||
|
|
||||||
synchronizeProjectDatas(package.projectDatas, package.updatedProjectSourceIds);
|
commonTypeCache_.resetTypeIds();
|
||||||
|
});
|
||||||
commonTypeCache_.resetTypeIds();
|
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ModuleId moduleId(Utils::SmallStringView moduleName) const override
|
ModuleId moduleId(Utils::SmallStringView moduleName) const override
|
||||||
@@ -304,38 +302,35 @@ public:
|
|||||||
|
|
||||||
Storage::Synchronization::Type fetchTypeByTypeId(TypeId typeId)
|
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.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.propertyDeclarations = fetchPropertyDeclarations(type.typeId);
|
type.propertyDeclarations = fetchPropertyDeclarations(type.typeId);
|
||||||
type.functionDeclarations = fetchFunctionDeclarations(type.typeId);
|
type.functionDeclarations = fetchFunctionDeclarations(type.typeId);
|
||||||
type.signalDeclarations = fetchSignalDeclarations(type.typeId);
|
type.signalDeclarations = fetchSignalDeclarations(type.typeId);
|
||||||
type.enumerationDeclarations = fetchEnumerationDeclarations(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)
|
bool fetchIsProtype(TypeId type, TypeId prototype)
|
||||||
@@ -358,13 +353,9 @@ public:
|
|||||||
SourceContextId fetchSourceContextId(Utils::SmallStringView sourceContextPath)
|
SourceContextId fetchSourceContextId(Utils::SmallStringView sourceContextPath)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
Sqlite::DeferredTransaction transaction{database};
|
return Sqlite::withDeferredTransaction(database, [&] {
|
||||||
|
return fetchSourceContextIdUnguarded(sourceContextPath);
|
||||||
auto sourceContextId = fetchSourceContextIdUnguarded(sourceContextPath);
|
});
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
|
|
||||||
return sourceContextId;
|
|
||||||
} catch (const Sqlite::ConstraintPreventsModification &) {
|
} catch (const Sqlite::ConstraintPreventsModification &) {
|
||||||
return fetchSourceContextId(sourceContextPath);
|
return fetchSourceContextId(sourceContextPath);
|
||||||
}
|
}
|
||||||
@@ -372,18 +363,16 @@ public:
|
|||||||
|
|
||||||
Utils::PathString fetchSourceContextPath(SourceContextId sourceContextId) const
|
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
|
if (!optionalSourceContextPath)
|
||||||
.template optionalValue<Utils::PathString>(
|
throw SourceContextIdDoesNotExists();
|
||||||
sourceContextId);
|
|
||||||
|
|
||||||
if (!optionalSourceContextPath)
|
return std::move(*optionalSourceContextPath);
|
||||||
throw SourceContextIdDoesNotExists();
|
});
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
|
|
||||||
return std::move(*optionalSourceContextPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fetchAllSourceContexts() const
|
auto fetchAllSourceContexts() const
|
||||||
@@ -394,13 +383,9 @@ public:
|
|||||||
|
|
||||||
SourceId fetchSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName)
|
SourceId fetchSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName)
|
||||||
{
|
{
|
||||||
Sqlite::DeferredTransaction transaction{database};
|
return Sqlite::withDeferredTransaction(database, [&] {
|
||||||
|
return fetchSourceIdUnguarded(sourceContextId, sourceName);
|
||||||
auto sourceId = fetchSourceIdUnguarded(sourceContextId, sourceName);
|
});
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
|
|
||||||
return sourceId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fetchSourceNameAndSourceContextId(SourceId sourceId) const
|
auto fetchSourceNameAndSourceContextId(SourceId sourceId) const
|
||||||
@@ -416,12 +401,10 @@ public:
|
|||||||
|
|
||||||
void clearSources()
|
void clearSources()
|
||||||
{
|
{
|
||||||
Sqlite::ImmediateTransaction transaction{database};
|
Sqlite::withImmediateTransaction(database, [&] {
|
||||||
|
deleteAllSourceContextsStatement.execute();
|
||||||
deleteAllSourceContextsStatement.execute();
|
deleteAllSourcesStatement.execute();
|
||||||
deleteAllSourcesStatement.execute();
|
});
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceContextId fetchSourceContextId(SourceId sourceId) const
|
SourceContextId fetchSourceContextId(SourceId sourceId) const
|
||||||
@@ -523,24 +506,15 @@ private:
|
|||||||
|
|
||||||
ModuleId fetchModuleId(Utils::SmallStringView moduleName)
|
ModuleId fetchModuleId(Utils::SmallStringView moduleName)
|
||||||
{
|
{
|
||||||
Sqlite::DeferredTransaction transaction{database};
|
return Sqlite::withDeferredTransaction(database,
|
||||||
|
[&] { return fetchModuleIdUnguarded(moduleName); });
|
||||||
ModuleId moduleId = fetchModuleIdUnguarded(moduleName);
|
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
|
|
||||||
return moduleId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fetchModuleName(ModuleId id)
|
auto fetchModuleName(ModuleId id)
|
||||||
{
|
{
|
||||||
Sqlite::DeferredTransaction transaction{database};
|
return Sqlite::withDeferredTransaction(database, [&] {
|
||||||
|
return fetchModuleNameUnguarded(id);
|
||||||
auto moduleName = fetchModuleNameUnguarded(id);
|
});
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
|
|
||||||
return moduleName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fetchAllModules() const
|
auto fetchAllModules() const
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
SqliteReadStatementMockBase::SqliteReadStatementMockBase(Utils::SmallStringView sqlStatement,
|
SqliteReadStatementMockBase::SqliteReadStatementMockBase(Utils::SmallStringView sqlStatement,
|
||||||
SqliteDatabaseMock &databaseMock)
|
SqliteDatabaseMock &databaseMock)
|
||||||
: sqlStatement(sqlStatement)
|
: sqlStatement(sqlStatement)
|
||||||
|
, databaseMock(databaseMock)
|
||||||
{
|
{
|
||||||
databaseMock.prepare(sqlStatement);
|
databaseMock.prepare(sqlStatement);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <projectstorageids.h>
|
#include <projectstorageids.h>
|
||||||
#include <sqliteblob.h>
|
#include <sqliteblob.h>
|
||||||
#include <sqlitetimestamp.h>
|
#include <sqlitetimestamp.h>
|
||||||
|
#include <sqlitetransaction.h>
|
||||||
#include <utils/smallstring.h>
|
#include <utils/smallstring.h>
|
||||||
|
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
@@ -198,7 +199,9 @@ public:
|
|||||||
template<typename ResultType, typename... QueryTypes>
|
template<typename ResultType, typename... QueryTypes>
|
||||||
auto optionalValueWithTransaction(const QueryTypes &...queryValues)
|
auto optionalValueWithTransaction(const QueryTypes &...queryValues)
|
||||||
{
|
{
|
||||||
return optionalValue<ResultType>(queryValues...);
|
return Sqlite::withDeferredTransaction(databaseMock, [&] {
|
||||||
|
return optionalValue<ResultType>(queryValues...);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ResultType, typename... QueryType>
|
template<typename ResultType, typename... QueryType>
|
||||||
@@ -261,6 +264,7 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Utils::SmallString sqlStatement;
|
Utils::SmallString sqlStatement;
|
||||||
|
SqliteDatabaseMock &databaseMock;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<int ResultCount, int BindParameterCount = 0>
|
template<int ResultCount, int BindParameterCount = 0>
|
||||||
|
|||||||
@@ -21,8 +21,13 @@ using Sqlite::ImmediateTransaction;
|
|||||||
|
|
||||||
class SqliteTransaction : public testing::Test
|
class SqliteTransaction : public testing::Test
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
|
SqliteTransaction() { ON_CALL(callableWithReturnMock, Call()).WillByDefault(Return(212)); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
NiceMock<MockSqliteTransactionBackend> mockTransactionBackend;
|
NiceMock<MockSqliteTransactionBackend> mockTransactionBackend;
|
||||||
|
NiceMock<MockFunction<void()>> callableMock;
|
||||||
|
NiceMock<MockFunction<int()>> callableWithReturnMock;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(SqliteTransaction, DeferredTransactionCommit)
|
TEST_F(SqliteTransaction, DeferredTransactionCommit)
|
||||||
@@ -38,19 +43,6 @@ TEST_F(SqliteTransaction, DeferredTransactionCommit)
|
|||||||
transaction.commit();
|
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)
|
TEST_F(SqliteTransaction, DeferredTransactionRollBack)
|
||||||
{
|
{
|
||||||
InSequence s;
|
InSequence s;
|
||||||
@@ -337,4 +329,110 @@ TEST_F(SqliteTransaction, ImmediateSessionTransactionBeginThrowsAndNotRollback)
|
|||||||
ASSERT_ANY_THROW(ImmediateSessionTransaction{mockTransactionBackend});
|
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
|
} // namespace
|
||||||
|
|||||||
Reference in New Issue
Block a user