Skip to content

Commit a2d4db8

Browse files
authored
Feature #8 - Reading fields or setting parameters with struct (#16)
1 parent 1d4d531 commit a2d4db8

4 files changed

Lines changed: 617 additions & 2 deletions

File tree

README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,12 @@ Statement statement{attachment, transaction, "select id, name from users where i
4343

4444
// Set parameters
4545
statement.setInt32(0, 42);
46-
/* Or
46+
/*
47+
// Or:
4748
statement.set(0, 42);
49+
50+
// Or:
51+
statement.set(SomeStructOrTuple{42});
4852
*/
4953

5054
// Execute and get results
@@ -56,9 +60,13 @@ if (statement.execute(transaction))
5660
const std::optional<std::int32_t> id = statement.getInt32(0);
5761
const std::optional<std::string> name = statement.getString(1);
5862

59-
/* Or
63+
/*
64+
// Or:
6065
const auto id = statement.get<std::int32_t>(0);
6166
const auto name = statement.get<std::string>(1);
67+
68+
// Or:
69+
const auto [id, name] = statement.get<SomeStructOrTuple>();
6270
*/
6371
} while (statement.fetchNext());
6472
}

src/fb-cpp/Statement.h

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "Descriptor.h"
3737
#include "SmartPtrs.h"
3838
#include "Exception.h"
39+
#include "StructBinding.h"
3940
#include <charconv>
4041
#include <cerrno>
4142
#include <cstdlib>
@@ -2042,6 +2043,51 @@ namespace fbcpp
20422043
template <typename T>
20432044
T get(unsigned index);
20442045

2046+
///
2047+
/// @brief Retrieves all output columns into a user-defined aggregate struct.
2048+
/// @tparam T An aggregate type whose fields match the output column count and types.
2049+
/// @return The populated struct with values from the current row.
2050+
/// @throws FbCppException if field count mismatches output column count.
2051+
/// @throws FbCppException if a NULL value is encountered for a non-optional field.
2052+
///
2053+
template <Aggregate T>
2054+
T get()
2055+
{
2056+
using namespace impl::reflection;
2057+
2058+
constexpr std::size_t N = fieldCountV<T>;
2059+
2060+
if (N != outDescriptors.size())
2061+
{
2062+
throw FbCppException("Struct field count (" + std::to_string(N) +
2063+
") does not match output column count (" + std::to_string(outDescriptors.size()) + ")");
2064+
}
2065+
2066+
return getStruct<T>(std::make_index_sequence<N>{});
2067+
}
2068+
2069+
///
2070+
/// @brief Sets all input parameters from fields of a user-defined aggregate struct.
2071+
/// @tparam T An aggregate type whose fields match the input parameter count.
2072+
/// @param value The struct containing parameter values.
2073+
/// @throws FbCppException if field count mismatches input parameter count.
2074+
///
2075+
template <Aggregate T>
2076+
void set(const T& value)
2077+
{
2078+
using namespace impl::reflection;
2079+
2080+
constexpr std::size_t N = fieldCountV<T>;
2081+
2082+
if (N != inDescriptors.size())
2083+
{
2084+
throw FbCppException("Struct field count (" + std::to_string(N) +
2085+
") does not match input parameter count (" + std::to_string(inDescriptors.size()) + ")");
2086+
}
2087+
2088+
setStruct(value, std::make_index_sequence<N>{});
2089+
}
2090+
20452091
private:
20462092
///
20472093
/// @brief Validates and returns the descriptor for the given input parameter index.
@@ -2065,6 +2111,53 @@ namespace fbcpp
20652111
return outDescriptors[index];
20662112
}
20672113

2114+
///
2115+
/// @brief Helper to retrieve all output columns into a struct.
2116+
///
2117+
template <typename T, std::size_t... Is>
2118+
T getStruct(std::index_sequence<Is...>)
2119+
{
2120+
using namespace impl::reflection;
2121+
2122+
return T{getStructField<FieldType<T, Is>>(static_cast<unsigned>(Is))...};
2123+
}
2124+
2125+
///
2126+
/// @brief Helper to get a single field value, throwing if NULL for non-optional fields.
2127+
///
2128+
template <typename F>
2129+
auto getStructField(unsigned index)
2130+
{
2131+
using namespace impl::reflection;
2132+
2133+
if constexpr (isOptionalV<F>)
2134+
return get<F>(index);
2135+
else
2136+
{
2137+
auto opt = get<std::optional<F>>(index);
2138+
2139+
if (!opt.has_value())
2140+
{
2141+
throw FbCppException(
2142+
"Null value encountered for non-optional field at index " + std::to_string(index));
2143+
}
2144+
2145+
return std::move(opt.value());
2146+
}
2147+
}
2148+
2149+
///
2150+
/// @brief Helper to set all input parameters from a struct.
2151+
///
2152+
template <typename T, std::size_t... Is>
2153+
void setStruct(const T& value, std::index_sequence<Is...>)
2154+
{
2155+
using namespace impl::reflection;
2156+
2157+
const auto tuple = toTupleRef(value);
2158+
(set(static_cast<unsigned>(Is), std::get<Is>(tuple)), ...);
2159+
}
2160+
20682161
///
20692162
/// @brief Converts and writes numeric parameter values following descriptor rules.
20702163
///

0 commit comments

Comments
 (0)