GCC Code Coverage Report


Directory: libimgdoc2/
File: libimgdoc2/src/doc/transactionHelper.h
Date: 2025-02-03 12:41:04
Exec Total Coverage
Lines: 13 17 76.5%
Functions: 2 2 100.0%
Branches: 6 12 50.0%

Line Branch Exec Source
1 // SPDX-FileCopyrightText: 2023 Carl Zeiss Microscopy GmbH
2 //
3 // SPDX-License-Identifier: MIT
4
5 #pragma once
6
7 #include <functional>
8 #include <utility>
9 #include <memory>
10
11 /// A utility in order to wrap a piece of code into a database-transaction.
12 ///
13 /// \tparam t_return_value Type of the return value.
14 template <typename t_return_value>
15 class TransactionHelper
16 {
17 private:
18 std::function< t_return_value()> action_;
19 std::shared_ptr<IDbConnection> database_connection_;
20 public:
21 41918 TransactionHelper(
22 std::shared_ptr<IDbConnection> database_connection,
23 std::function<t_return_value()> action) :
24 41918 action_(std::move(action)),
25 41918 database_connection_(std::move(database_connection))
26 41918 {}
27
28 /// Execute the action guarded with Begin-/End-Transaction. Or, in more detail, what this is about
29 /// is:
30 /// First thing to be aware of is that the DbConnection-objection is taking care of maintaing a "transaction state",
31 /// i. e. whether currently we are inside a transaction. Background here is that nested transactions are not supported
32 /// with SQLite (https://www.sqlite.org/lang_transaction.html), so a transaction is a "global state".
33 /// So, what we do here, is
34 /// - we query the DbConnection-object if there is a transaction pending
35 /// - if this is the case, we execute the action right away
36 /// - if not, we initiate a transaction, then call the action, then end the transaction
37 /// In other words - if there is no pending transaction, we wrap the action into a Begin-/End-Transaction.
38 /// If the action is throwing an execption, we end the transaction with a rollback (i.e. again, only if we
39 /// initiated the transaction).
40 /// \returns {t_return_value} The return value of the action.
41 41918 t_return_value Execute()
42 {
43 41918 bool transaction_initiated = false;
44
2/2
✓ Branch 2 taken 41914 times.
✓ Branch 3 taken 4 times.
41918 if (!this->database_connection_->IsTransactionPending())
45 {
46 41914 this->database_connection_->BeginTransaction();
47 41914 transaction_initiated = true;
48 }
49
50 try
51 {
52
1/2
✓ Branch 1 taken 41918 times.
✗ Branch 2 not taken.
41918 t_return_value return_value = this->action_();
53
54
2/2
✓ Branch 0 taken 41914 times.
✓ Branch 1 taken 4 times.
41918 if (transaction_initiated)
55 {
56 // TODO(JBL): I guess we need to think about how to deal with "exception from the next line"
57
1/2
✓ Branch 2 taken 41914 times.
✗ Branch 3 not taken.
41914 this->database_connection_->EndTransaction(true);
58 }
59
60 41918 return return_value;
61 }
62 catch (...)
63 {
64 if (transaction_initiated)
65 {
66 this->database_connection_->EndTransaction(false);
67 }
68
69 throw;
70 }
71 }
72 };
73