Data models that represents the payload to be submitted to the service for creating/deleting documents. 
//
// Created by Rakesh on 22/12/2024.
//
#pragma once
#include "create.hpp"
#include "update.hpp"
#include "delete.hpp"
namespace spt::mongoservice::api::model::request
{
  struct TransactionBuilder
  {
    TransactionBuilder( std::string_view database, std::string_view collection ) : database{ database }, collection{ collection } {}
    ~TransactionBuilder() = default;
    TransactionBuilder( const TransactionBuilder& ) = delete;
    TransactionBuilder& operator=( const TransactionBuilder& ) = delete;
    TransactionBuilder( TransactionBuilder&& ) = delete;
    TransactionBuilder& operator=( TransactionBuilder&& ) = delete;
    template <util::Visitable Document, util::Visitable Metadata>
    requires std::is_same_v<decltype(Document::id), bsoncxx::oid>
    void addCreate( const Create<Document, Metadata>& request )
    {
      items << util::marshall( request );
    }
    template <util::Visitable Document, util::Visitable Metadata>
    requires std::is_same_v<decltype(Document::id), bsoncxx::oid>
    void addUpdate( const MergeForId<Document, Metadata>& request )
    {
      items << util::marshall( request );
    }
    template <util::Visitable Document, util::Visitable Metadata, util::Visitable Filter, template<typename, typename, typename> typename Model>
    requires std::is_same_v<Model<Document, Metadata, Filter>, Replace<Document, Metadata, Filter>> ||
      std::is_same_v<Model<Document, Metadata, Filter>, Update<Document, Metadata, Filter>>
    void addUpdate( const Model<Document, Metadata, Filter>& request )
    {
      items << util::marshall( request );
    }
    template <util::Visitable Document, util::Visitable Metadata>
    requires std::constructible_from<Metadata, bsoncxx::document::view>
    void addRemove( const Delete<Document, Metadata>& request )
    {
      items << util::marshall( request );
    }
    [[nodiscard]] bsoncxx::document::value build();
  private:
    std::string database;
    std::string collection;
    bsoncxx::builder::stream::array items;
  };
}
Data models that represents the payloads the service responds with when creating/deleting document(s). 
//
// Created by Rakesh on 19/12/2024.
//
#pragma once
#if defined __has_include
  #if __has_include("../../../common/visit_struct/visit_struct_intrusive.hpp")
    #include "../../../common/visit_struct/visit_struct_intrusive.hpp"
    #include "../../../common/util/serialise.hpp"
  #else
    #include <mongo-service/common/visit_struct/visit_struct_intrusive.hpp>
    #include <mongo-service/common/util/serialise.hpp>
  #endif
#endif
#include <cstdint>
#include <string>
#include <vector>
#include <bsoncxx/oid.hpp>
namespace spt::mongoservice::api::model::response
{
  struct Transaction
  {
    struct History
    {
      History() = default;
      ~History() = default;
      History(History&&) = default;
      History& operator=(History&&) = default;
      bool operator==(const History& rhs) const = default;
      History(const History&) = delete;
      History& operator=(const History&) = delete;
      BEGIN_VISITABLES(History);
      VISITABLE(std::vector<bsoncxx::oid>, created);
      VISITABLE(std::vector<bsoncxx::oid>, updated);
      VISITABLE(std::vector<bsoncxx::oid>, deleted);
      VISITABLE(std::string, database);
      VISITABLE(std::string, collection);
      END_VISITABLES;
    };
    explicit Transaction( bsoncxx::document::view document ) { util::unmarshall( *this, document ); }
    Transaction() = default;
    ~Transaction() = default;
    Transaction(Transaction&&) = default;
    Transaction& operator=(Transaction&&) = default;
    Transaction(const Transaction&) = delete;
    Transaction& operator=(const Transaction&) = delete;
    BEGIN_VISITABLES(Transaction);
    VISITABLE(History, history);
    VISITABLE(int32_t, created);
    VISITABLE(int32_t, updated);
    VISITABLE(int32_t, deleted);
    END_VISITABLES;
  };
}
Sample code illustrating the transaction action. 
#include <mongo-service/api/repository/repository.hpp>
namespace example
{
  struct Document
  {
    explicit Document( bsoncxx::document::view bson ) { spt::util::unmarshall( *this, bson ); }
    Document() = default;
    ~Document() = default;
    Document(Document&&) = default;
    Document& operator=(Document&&) = default;
    bool operator==(const Document&) const = default;
    Document(const Document&) = delete;
    Document& operator=(const Document&) = delete;
    BEGIN_VISITABLES(Document);
    VISITABLE(bsoncxx::oid, id);
    VISITABLE(std::string, str);
    VISITABLE_DIRECT_INIT(spt::util::DateTimeMs, created, {std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::system_clock::now().time_since_epoch() )});
    VISITABLE_DIRECT_INIT(int64_t, integer, {5});
    VISITABLE_DIRECT_INIT(double, floating, {10.345});
    VISITABLE_DIRECT_INIT(bool, boolean, {true});
    END_VISITABLES;
  };
  struct Metadata
  {
    explicit Metadata( bsoncxx::document::view bson ) { spt::util::unmarshall( *this, bson ); }
    Metadata() = default;
    ~Metadata() = default;
    Metadata(Metadata&&) = default;
    Metadata& operator=(Metadata&&) = default;
    bool operator==(const Metadata&) const = default;
    Metadata(const Metadata&) = delete;
    Metadata& operator=(const Metadata&) = delete;
    BEGIN_VISITABLES(Metadata);
    VISITABLE(std::string, project);
    VISITABLE(std::string, product);
    END_VISITABLES;
  };
}
int main()
{
  using namespace spt::mongoservice::api;
  using bsoncxx::builder::stream::open_array;
  using bsoncxx::builder::stream::close_array;
  using bsoncxx::builder::stream::open_document;
  using bsoncxx::builder::stream::close_document;
  auto builder = model::request::TransactionBuilder{ "unit", "test" };
  auto insert = model::request::Create<pmodel::Document, pmodel::Metadata>{};
  insert.database = "test";
  insert.collection = "test";
  insert.application = "unitTest";
  insert.document.str = "value";
  insert.metadata = pmodel::Metadata{};
  insert.metadata->project = "serialisation";
  insert.metadata->product = "mongo-service";
  insert.options = options::Insert{};
  insert.options->writeConcern = options::WriteConcern{};
  insert.options->writeConcern->tag = "test";
  insert.options->writeConcern->majority = std::chrono::milliseconds{ 100 };
  insert.options->writeConcern->timeout = std::chrono::milliseconds{ 250 };
  insert.options->writeConcern->nodes = 2;
  insert.options->writeConcern->acknowledgeLevel = options::WriteConcern::Level::Majority;
  insert.options->writeConcern->journal = true;
  insert.options->bypassValidation = true;
  insert.options->ordered = true;
  builder.addCreate( insert );
  auto update = model::request::Update<bsoncxx::document::value, pmodel::Metadata, model::request::IdFilter>{};
  update.document.filter = model::request::IdFilter{};
  update.document.filter->id = bsoncxx::oid{};
  update.document.update = document{} <<
    "$unset" << open_document << "obsoleteProperty" << 1 << close_document <<
    "$set" <<
      open_document <<
        "modified" << bsoncxx::types::b_date{ std::chrono::system_clock::now() } <<
        "user._id" << bsoncxx::oid{} <<
      close_document <<
    finalize;
  update.database = "unit";
  update.collection = "test";
  update.application = "unitTest";
  update.options = options::Update{};
  update.options->collation = options::Collation{};
  update.options->collation->locale = "en";
  update.options->collation->strength = 1;
  update.options->writeConcern = options::WriteConcern{};
  update.options->writeConcern->tag = "test";
  update.options->writeConcern->majority = std::chrono::milliseconds{ 100 };
  update.options->writeConcern->timeout = std::chrono::milliseconds{ 250 };
  update.options->writeConcern->nodes = 2;
  update.options->writeConcern->acknowledgeLevel = options::WriteConcern::Level::Majority;
  update.options->writeConcern->journal = true;
  update.options->bypassValidation = false;
  update.options->upsert = false;
  builder.addUpdate( update );
  auto remove = model::request::Delete<bsoncxx::document::value, pmodel::Metadata>{ document{} << finalize  };
  remove.database = "unit";
  remove.collection = "test";
  remove.application = "unitTest";
  remove.options = options::Delete{};
  remove.options->collation = options::Collation{};
  remove.options->collation->locale = "en";
  remove.options->collation->strength = 1;
  remove.options->hint = document{} << "name" << 1 << finalize;
  remove.options->writeConcern = options::WriteConcern{};
  remove.options->writeConcern->tag = "test";
  remove.options->writeConcern->majority = std::chrono::milliseconds{ 100 };
  remove.options->writeConcern->timeout = std::chrono::milliseconds{ 250 };
  remove.options->writeConcern->nodes = 2;
  remove.options->writeConcern->acknowledgeLevel = options::WriteConcern::Level::Majority;
  remove.options->writeConcern->journal = true;
  remove.options->let = document{} <<
    "vars" <<
      open_document <<
        "total" <<
          open_document <<
            "$add" << open_array << "$price" << "$tax" << close_array <<
          close_document <<
        "discounted" <<
          open_document <<
            "$cond" <<
              open_document <<
                "if" << "$applyDiscount" << "then" << 0.9 << "else" << 1 <<
              close_document <<
          close_document <<
      close_document <<
    "in" <<
      open_document <<
        "$multiply" << open_array << "$$total" << "$$discounted" << close_array <<
      close_document <<
    finalize;
  builder.addRemove( remove );
  const auto bson = builder.build();
  auto result = repository::transaction( bson );
  if ( !result.has_value() )
  {
    LOG_WARN << "Error executing transaction. " << magic_enum::enum_name( result.error().cause ) << ". " << result.error().message;
  }
}