diff --git a/include/caosdb/transaction.h b/include/caosdb/transaction.h index 569f0335c6371a324f7209eeab09e1883e0a3bcd..0699e14b28ae6e4b44ff495695c843ffa2e8d01f 100644 --- a/include/caosdb/transaction.h +++ b/include/caosdb/transaction.h @@ -196,6 +196,14 @@ public: [[nodiscard]] virtual auto size() const noexcept -> int = 0; [[nodiscard]] virtual auto at(const int index) const -> const Entity & = 0; [[nodiscard]] virtual auto mutable_at(int index) const -> Entity * = 0; + /** + * Return the Entity at the given index. + * + * This method releases the entity from the underlying collection and thus + * leaves the ResultSet in a corrupted state. + * + * This method can be called only once for each index. + */ [[nodiscard]] virtual auto release_at(int index) -> Entity * = 0; auto begin() const -> iterator; auto end() const -> iterator; @@ -217,6 +225,11 @@ private: class AbstractMultiResultSet : public ResultSet { public: + /** + * Copy Constructor. + * + * Copies the underlying collection of entities. + */ inline AbstractMultiResultSet(const AbstractMultiResultSet &original) { for (const Entity &entity : original) { this->items.push_back(std::make_unique<Entity>(entity)); @@ -232,9 +245,20 @@ public: [[nodiscard]] inline auto mutable_at(int index) const -> Entity * override { return this->items.at(index).get(); } + /** + * Return the Entity at the given index. + * + * This method releases the entity from the underlying collection and thus + * leaves the ResultSet in a corrupted state. + * + * This method can be called only once for each index. + */ [[nodiscard]] inline auto release_at(int index) -> Entity * override { return this->items.at(index).release(); } + /** + * Remove all entities from this result set. + */ inline auto clear() noexcept -> void { this->items.clear(); } protected: @@ -375,14 +399,38 @@ public: */ [[nodiscard]] inline auto GetStatus() const noexcept -> TransactionStatus { return this->status; } + /** + * Return the ResultSet of this transaction. + * + * Note: If this method is called before the transaction has terminated + * (GetStatus().GetCode() < 0) this method has undefined behavior. + * + * Instead, do Execute() or WaitForIt() and only call this method afterwards. + */ [[nodiscard]] inline auto GetResultSet() const noexcept -> const ResultSet & { if (!this->result_set) { - // TODO(tf) Discuss. This condition implies a programming error. Should we handle it? + CAOSDB_LOG_ERROR(logger_name) + << "GetResultSet was called before the transaction has terminated. This is a programming " + "error of the code which uses the transaction."; + // TODO(tf) This is a really bad SegFault factory. When the transaction + // terminates and the result_set is being overriden, the unique_ptr + // created here will be deleted and any client of the return ResultSet + // will have a SegFault. this->result_set = std::make_unique<MultiResultSet>(std::vector<std::unique_ptr<Entity>>()); } return *(this->result_set.get()); } + /** + * Return the ResultSet of this transaction. + * + * This method releases the ResultSet from the transaction leaving it in a + * currupted state. + * + * This method can be called only once and only after the transaction has terminated. + * + * Otherwise, this method has undefined behavior. + */ [[nodiscard]] inline auto ReleaseResultSet() noexcept -> const ResultSet * { this->status = TransactionStatus::SPOILED(); return this->result_set.release();