Clio  develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
Tuple.hpp
1#pragma once
2
3#include "data/cassandra/impl/ManagedObject.hpp"
4#include "util/UnsupportedType.hpp"
5
6#include <cassandra.h>
7#include <xrpl/basics/base_uint.h>
8
9#include <cstddef>
10#include <cstdint>
11#include <functional>
12#include <stdexcept>
13#include <string>
14#include <string_view>
15#include <tuple>
16#include <type_traits>
17
18namespace data::cassandra::impl {
19
20class Tuple : public ManagedObject<CassTuple> {
21 static constexpr auto kDELETER = [](CassTuple* ptr) { cass_tuple_free(ptr); };
22
23public:
24 /* implicit */ Tuple(CassTuple* ptr);
25
26 template <typename... Types>
27 explicit Tuple(std::tuple<Types...>&& value)
28 : ManagedObject{cass_tuple_new(std::tuple_size<std::tuple<Types...>>{}), kDELETER}
29 {
30 std::apply(std::bind_front(&Tuple::bind<Types...>, this), std::move(value));
31 }
32
33 template <typename... Args>
34 void
35 bind(Args&&... args) const
36 {
37 std::size_t idx = 0;
38 (this->bindAt<Args>(idx++, std::forward<Args>(args)), ...);
39 }
40
41 template <typename Type>
42 void
43 bindAt(std::size_t const idx, Type&& value) const
44 {
45 using std::to_string;
46 auto throwErrorIfNeeded = [idx](CassError rc, std::string_view label) {
47 if (rc != CASS_OK) {
48 auto const tag = '[' + std::string{label} + ']';
49 throw std::logic_error(
50 tag + " at idx " + to_string(idx) + ": " + cass_error_desc(rc)
51 );
52 }
53 };
54
55 using DecayedType = std::decay_t<Type>;
56
57 if constexpr (std::is_same_v<DecayedType, bool>) {
58 auto const rc = cass_tuple_set_bool(*this, idx, value ? cass_true : cass_false);
59 throwErrorIfNeeded(rc, "Bind bool");
60 }
61 // clio only uses bigint (int64_t) so we convert any incoming type
62 else if constexpr (std::is_convertible_v<DecayedType, int64_t>) {
63 auto const rc = cass_tuple_set_int64(*this, idx, std::forward<Type>(value));
64 throwErrorIfNeeded(rc, "Bind int64");
65 } else if constexpr (std::is_same_v<DecayedType, ripple::uint256>) {
66 auto const rc = cass_tuple_set_bytes(
67 *this,
68 idx,
69 static_cast<cass_byte_t const*>(static_cast<unsigned char const*>(value.data())),
70 value.size()
71 );
72 throwErrorIfNeeded(rc, "Bind ripple::uint256");
73 } else {
74 // type not supported for binding
75 static_assert(util::Unsupported<DecayedType>);
76 }
77 }
78};
79
80class TupleIterator : public ManagedObject<CassIterator> {
81public:
82 /* implicit */ TupleIterator(CassIterator* ptr);
83
84 [[nodiscard]] static TupleIterator
85 fromTuple(CassValue const* value);
86
87 template <typename... Types>
88 [[nodiscard]] std::tuple<Types...>
89 extract() const
90 {
91 return {extractNext<Types>()...};
92 }
93
94private:
95 template <typename Type>
96 Type
97 extractNext() const
98 {
99 using std::to_string;
100 Type output;
101
102 if (not cass_iterator_next(*this))
103 throw std::logic_error("Could not extract next value from tuple iterator");
104
105 auto throwErrorIfNeeded = [](CassError rc, std::string_view label) {
106 if (rc != CASS_OK) {
107 auto const tag = '[' + std::string{label} + ']';
108 throw std::logic_error(tag + ": " + cass_error_desc(rc));
109 }
110 };
111
112 using DecayedType = std::decay_t<Type>;
113
114 // clio only uses bigint (int64_t) so we convert any incoming type
115 if constexpr (std::is_convertible_v<DecayedType, int64_t>) {
116 int64_t out = 0;
117 auto const rc = cass_value_get_int64(cass_iterator_get_value(*this), &out);
118 throwErrorIfNeeded(rc, "Extract int64 from tuple");
119 output = static_cast<DecayedType>(out);
120 } else {
121 // type not supported for extraction
122 static_assert(util::Unsupported<DecayedType>);
123 }
124
125 return output;
126 }
127};
128
129} // namespace data::cassandra::impl
static constexpr bool Unsupported
used for compile time checking of unsupported types
Definition UnsupportedType.hpp:7