Skip to content
Snippets Groups Projects

F multi retrieve

Merged Timm Fitschen requested to merge f-multi-retrieve into dev
All threads resolved!
+ 199
20
@@ -18,21 +18,98 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef CAOSDB_TRANSACTION_H
#define CAOSDB_TRANSACTION_H
/**
* @brief Creation and execution of transactions.
*/
#include "caosdb/entity.h" // for Entity
#include "boost/log/core/record.hpp" // for record
#include "boost/log/sources/record_ostream.hpp" // for basic_record_o...
#include "boost/preprocessor/seq/limits/enum_256.hpp" // for BOOST_PP_SEQ_E...
#include "boost/preprocessor/seq/limits/size_256.hpp" // for BOOST_PP_SEQ_S...
#include "caosdb/entity.h" // for Entity
#include "caosdb/logging.h"
#include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for EntityTransactionSe...
#include "caosdb/entity/v1alpha1/main.pb.h" // for Entity, RetrieveReq...
#include "caosdb/transaction_status.h" // for TransactionStatus
#include "caosdb/status_code.h" // for StatusCode
#include "google/protobuf/util/json_util.h" // for MessageToJsonString, Jso...
#include <memory> // for shared_ptr, unique_ptr
#include <string> // for string
#include <stdexcept>
#include <iterator>
// IWYU pragma: no_include <ext/alloc_traits.h>
#include <memory> // for shared_ptr, unique_ptr
#include <string> // for string
#include <vector> // for vector
/**
* @brief Creation and execution of transactions.
* @author Timm Fitschen
* @date 2021-08-05
*/
namespace caosdb::transaction {
/**
* Do all necessary checks and assure that another retrieval (by id or by
* query) can be added as a sub-request to a transaction.
*/
#define ASSERT_CAN_ADD_RETRIEVAL \
if (!IsStatus(TransactionStatus::INITIAL())) { \
return StatusCode::TRANSACTION_STATUS_ERROR; \
} \
switch (this->transaction_type) { \
case NONE: \
this->transaction_type = TransactionType::READ_ONLY; \
case READ_ONLY: \
case MIXED_READ_AND_WRITE: \
break; \
default: \
CAOSDB_LOG_ERROR_AND_RETURN_STATUS( \
logger_name, StatusCode::TRANSACTION_TYPE_ERROR, \
"You cannot add a retrieval to this transaction because it has the " \
"wrong TransactionType.") \
}
/**
* Do all necessary checks and assure that another deletion can be added as a
* sub-request to a transaction.
*/
#define ASSERT_CAN_ADD_DELETION \
if (!IsStatus(TransactionStatus::INITIAL())) { \
return StatusCode::TRANSACTION_STATUS_ERROR; \
} \
switch (this->transaction_type) { \
case NONE: \
this->transaction_type = TransactionType::DELETE; \
case DELETE: \
case MIXED_WRITE: \
case MIXED_READ_AND_WRITE: \
break; \
default: \
CAOSDB_LOG_ERROR_AND_RETURN_STATUS( \
logger_name, StatusCode::TRANSACTION_TYPE_ERROR, \
"You cannot add a deletion to this transaction because it has the " \
"wrong TransactionType.") \
}
/**
* Do all necessary checks and assure that another insertion can be added as a
* sub-request to a transaction.
*/
#define ASSERT_CAN_ADD_INSERTION \
if (!IsStatus(TransactionStatus::INITIAL())) { \
return StatusCode::TRANSACTION_STATUS_ERROR; \
} \
switch (this->transaction_type) { \
case NONE: \
this->transaction_type = TransactionType::INSERT; \
case INSERT: \
case MIXED_WRITE: \
case MIXED_READ_AND_WRITE: \
break; \
default: \
CAOSDB_LOG_ERROR_AND_RETURN_STATUS( \
logger_name, StatusCode::TRANSACTION_TYPE_ERROR, \
"You cannot add an insertion to this transaction because it has the " \
"wrong TransactionType.") \
}
using caosdb::entity::Entity;
using ProtoEntity = caosdb::entity::v1alpha1::Entity;
using caosdb::entity::v1alpha1::EntityTransactionService;
@@ -40,20 +117,65 @@ using caosdb::entity::v1alpha1::IdResponse;
using caosdb::entity::v1alpha1::MultiTransactionRequest;
using caosdb::entity::v1alpha1::MultiTransactionResponse;
using caosdb::transaction::TransactionStatus;
using WrappedResponseCase =
caosdb::entity::v1alpha1::TransactionResponse::WrappedResponseCase;
class Transaction;
static const std::string logger_name = "caosdb::transaction";
/**
* Abstract base class for the results of a Transaction.
*/
class ResultSet {
public:
virtual ~ResultSet() = default;
[[nodiscard]] virtual auto Size() const noexcept -> int = 0;
[[nodiscard]] virtual auto At(const int index) const -> const Entity & = 0;
};
/**
* Container with results of a transaction.
*
* In contrast to UniqueResult, this one can also hold multiple entities or zero
* entities.
*/
class MultiResultSet : public ResultSet {
public:
~MultiResultSet() = default;
explicit MultiResultSet(MultiTransactionResponse *response);
[[nodiscard]] inline auto Size() const noexcept -> int override {
return this->entities.size();
}
[[nodiscard]] inline auto At(const int index) const
-> const Entity & override {
return *(this->entities.at(index));
}
std::vector<std::unique_ptr<Entity>> entities;
};
/**
* Container with the single result of a transaction.
*
* In contrast to MultiResultSet, this one guarantees to hold exactly one
* entity.
*/
class UniqueResult : public ResultSet {
public:
~UniqueResult(){};
~UniqueResult() = default;
explicit inline UniqueResult(ProtoEntity *protoEntity)
: entity(new Entity(protoEntity)){};
explicit inline UniqueResult(IdResponse *idResponse)
: entity(new Entity(idResponse)){};
[[nodiscard]] auto GetEntity() const -> const Entity &;
[[nodiscard]] inline auto Size() const noexcept -> int override { return 1; }
[[nodiscard]] inline auto At(const int index) const
-> const Entity & override {
if (index != 0) {
throw std::out_of_range("Index out of range. Length is 1.");
}
return *(this->entity);
}
private:
std::unique_ptr<Entity> entity;
@@ -63,15 +185,23 @@ private:
* @brief Create a transaction via `CaosDBConnection.createTransaction()`
*/
class Transaction {
private:
mutable std::unique_ptr<ResultSet> result_set;
mutable TransactionStatus status = TransactionStatus::INITIAL();
std::shared_ptr<EntityTransactionService::Stub> service_stub;
MultiTransactionRequest *request;
mutable MultiTransactionResponse *response;
std::string error_message;
public:
/**
* The transaction type restricts the kind of sub-transaction which may be
* added to a transaction (insertion, update, deletion, retrieval).
*
* @note MIXED_READ_AND_WRITE and MIXED_WRITE transaction are not supported
* yet.
*/
enum TransactionType {
NONE, /// Unspecified or not specified yet.
READ_ONLY, /// Only retrievals (by id, by query)
INSERT, /// Only insertions
UPDATE, /// Only updates
DELETE, /// Only deletions
MIXED_WRITE, /// Only insertions, deletions, updates
MIXED_READ_AND_WRITE /// all kind of transaction.
};
Transaction(std::shared_ptr<EntityTransactionService::Stub> service_stub);
/**
@@ -80,7 +210,21 @@ public:
* The retrieval is being processed when the Execute() or
* ExecuteAsynchronously() methods of this transaction are called.
*/
auto RetrieveById(const std::string &id) -> void;
auto RetrieveById(const std::string &id) noexcept -> StatusCode;
/**
* Add all entity ids to this transaction for retrieval.
*/
template <class InputIterator>
inline auto RetrieveById(InputIterator begin, InputIterator end) noexcept
-> StatusCode;
/**
* Add a query to this transaction.
*
* Currently, only FIND and COUNT queries are supported.
*/
auto Query(const std::string &query) noexcept -> StatusCode;
/**
* Add the entity to this transaction for an insertion.
@@ -90,7 +234,7 @@ public:
*
* Changing the entity afterwards results in undefined behavior.
*/
auto InsertEntity(Entity *entity) -> void;
auto InsertEntity(Entity *entity) noexcept -> StatusCode;
/**
* Add an entity id to this transaction for deletion.
@@ -98,7 +242,7 @@ public:
* The deletion is being processed when the Execute() or
* ExecuteAsynchronously() methods of this transaction are called.
*/
auto DeleteById(const std::string &id) -> void;
auto DeleteById(const std::string &id) noexcept -> StatusCode;
inline auto IsStatus(const TransactionStatus &status) const noexcept -> bool {
return this->status.GetCode() == status.GetCode();
@@ -116,7 +260,7 @@ public:
*
* Use WaitForIt() to join the back-ground execution of this transaction.
*/
auto ExecuteAsynchronously() noexcept -> void;
auto ExecuteAsynchronously() noexcept -> StatusCode;
/**
* Join the background execution and return the status when the execution
@@ -138,13 +282,48 @@ public:
return *result_set;
}
/**
* Return the number of sub-requests in this transaction.
*
* This is meant for debugging because the number of sub-requests is a
* GRPC-API detail.
*/
[[nodiscard]] inline auto GetRequestCount() const -> int {
return this->request->requests_size();
}
inline auto RequestToString() const -> const std::string {
google::protobuf::util::JsonOptions options;
std::string out;
google::protobuf::util::MessageToJsonString(*this->request, &out, options);
return out;
}
private:
TransactionType transaction_type = TransactionType::NONE;
mutable std::unique_ptr<ResultSet> result_set;
mutable TransactionStatus status = TransactionStatus::INITIAL();
std::shared_ptr<EntityTransactionService::Stub> service_stub;
MultiTransactionRequest *request;
mutable MultiTransactionResponse *response;
std::string error_message;
};
template <class InputIterator>
inline auto Transaction::RetrieveById(InputIterator begin,
InputIterator end) noexcept
-> StatusCode {
ASSERT_CAN_ADD_RETRIEVAL
auto next = begin;
while (next != end) {
auto *sub_request = this->request->add_requests();
sub_request->mutable_retrieve_request()->set_id(*next);
next = std::next(next);
}
return StatusCode::INITIAL;
}
} // namespace caosdb::transaction
#endif
Loading