Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,12 @@ Statement statement{attachment, transaction, "select id, name from users where i

// Set parameters
statement.setInt32(0, 42);
/* Or
/*
// Or:
statement.set(0, 42);

// Or:
statement.set(SomeStructOrTuple{42});
*/

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

/* Or
/*
// Or:
const auto id = statement.get<std::int32_t>(0);
const auto name = statement.get<std::string>(1);

// Or:
const auto [id, name] = statement.get<SomeStructOrTuple>();
*/
} while (statement.fetchNext());
}
Expand Down
93 changes: 93 additions & 0 deletions src/fb-cpp/Statement.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "Descriptor.h"
#include "SmartPtrs.h"
#include "Exception.h"
#include "StructBinding.h"
#include <charconv>
#include <cerrno>
#include <cstdlib>
Expand Down Expand Up @@ -2042,6 +2043,51 @@ namespace fbcpp
template <typename T>
T get(unsigned index);

///
/// @brief Retrieves all output columns into a user-defined aggregate struct.
/// @tparam T An aggregate type whose fields match the output column count and types.
/// @return The populated struct with values from the current row.
/// @throws FbCppException if field count mismatches output column count.
/// @throws FbCppException if a NULL value is encountered for a non-optional field.
///
template <Aggregate T>
T get()
{
using namespace impl::reflection;

constexpr std::size_t N = fieldCountV<T>;

if (N != outDescriptors.size())
{
throw FbCppException("Struct field count (" + std::to_string(N) +
") does not match output column count (" + std::to_string(outDescriptors.size()) + ")");
}

return getStruct<T>(std::make_index_sequence<N>{});
}

///
/// @brief Sets all input parameters from fields of a user-defined aggregate struct.
/// @tparam T An aggregate type whose fields match the input parameter count.
/// @param value The struct containing parameter values.
/// @throws FbCppException if field count mismatches input parameter count.
///
template <Aggregate T>
void set(const T& value)
{
using namespace impl::reflection;

constexpr std::size_t N = fieldCountV<T>;

if (N != inDescriptors.size())
{
throw FbCppException("Struct field count (" + std::to_string(N) +
") does not match input parameter count (" + std::to_string(inDescriptors.size()) + ")");
}

setStruct(value, std::make_index_sequence<N>{});
}

private:
///
/// @brief Validates and returns the descriptor for the given input parameter index.
Expand All @@ -2065,6 +2111,53 @@ namespace fbcpp
return outDescriptors[index];
}

///
/// @brief Helper to retrieve all output columns into a struct.
///
template <typename T, std::size_t... Is>
T getStruct(std::index_sequence<Is...>)
{
using namespace impl::reflection;

return T{getStructField<FieldType<T, Is>>(static_cast<unsigned>(Is))...};
}

///
/// @brief Helper to get a single field value, throwing if NULL for non-optional fields.
///
template <typename F>
auto getStructField(unsigned index)
{
using namespace impl::reflection;

if constexpr (isOptionalV<F>)
return get<F>(index);
else
{
auto opt = get<std::optional<F>>(index);

if (!opt.has_value())
{
throw FbCppException(
"Null value encountered for non-optional field at index " + std::to_string(index));
}

return std::move(opt.value());
}
}

///
/// @brief Helper to set all input parameters from a struct.
///
template <typename T, std::size_t... Is>
void setStruct(const T& value, std::index_sequence<Is...>)
{
using namespace impl::reflection;

const auto tuple = toTupleRef(value);
(set(static_cast<unsigned>(Is), std::get<Is>(tuple)), ...);
}

///
/// @brief Converts and writes numeric parameter values following descriptor rules.
///
Expand Down
Loading