Added the ViewReader

This commit is contained in:
Dr. Patrick Urbanke
2025-04-07 06:22:29 +02:00
parent 1718c19f62
commit 31643ff19a
2 changed files with 91 additions and 2 deletions
+7 -2
View File
@@ -8,6 +8,7 @@
#include <vector>
#include "../Result.hpp"
#include "../parsing/ViewReader.hpp"
namespace sqlgen::internal {
@@ -15,8 +16,12 @@ template <class T>
Result<T> from_str_vec(
const std::vector<std::optional<std::string>>& _str_vec) {
T t;
const auto view = rfl::to_view(t);
auto view = rfl::to_view(t);
auto view_reader = parsing::ViewReader<remove_cvref_t<decltype(view)>>(&view);
const auto [err, num_fields_assigned] = view_reader.read(_str_vec);
if (err) {
return error(err->what());
}
return t;
}
+84
View File
@@ -0,0 +1,84 @@
#ifndef SQLGEN_PARSING_VIEWREADER_HPP_
#define SQLGEN_PARSING_VIEWREADER_HPP_
#include <array>
#include <optional>
#include <rfl.hpp>
#include <sstream>
#include <string_view>
#include <type_traits>
#include <utility>
#include <vector>
#include "../Result.hpp"
#include "Parser.hpp"
namespace sqlgen::parsing {
template <class ViewType>
class ViewReader {
private:
static constexpr size_t size_ = ViewType::size();
public:
ViewReader(ViewType* _view) : view_(_view) {}
~ViewReader() = default;
std::pair<std::optional<Error>, size_t> read(
const std::vector<std::optional<std::string>>& _row) noexcept {
if (_row.size() != size_) {
std::stringstream stream;
stream << "Expected exactly " << std::to_string(size_)
<< " fields, but got " << _row.size() << ".";
return std::make_pair(error(stream.str()), 0);
}
for (size_t i = 0; i < size_; ++i) {
const auto err = assign_to_field_i(
_row, i, &view_, std::make_integer_sequence<size_t, size_>());
if (err) {
return std::make_pair(err, i);
}
}
return std::make_pair(std::nullopt, size_);
}
private:
template <size_t i>
static void assign_if_field_is_field_i(
const std::vector<std::optional<std::string>>& _row, const size_t _i,
ViewType* _view, std::optional<Error>* _err) noexcept {
using FieldType = rfl::tuple_element_t<i, typename ViewType::Fields>;
using OriginalType = typename FieldType::Type;
using T =
std::remove_cvref_t<std::remove_pointer_t<typename FieldType::Type>>;
constexpr auto name = FieldType::name();
if (_i == i) {
auto res = Parser<T>::read(_row[i]);
if (!res) {
std::stringstream stream;
stream << "Failed to parse field '" << std::string(name)
<< "': " << res.error().what();
*_err = Error(stream.str());
return;
}
rfl::get<i>(*_view) = std::move(*res);
}
}
template <size_t... is>
static std::optional<Error> assign_to_field_i(
const std::vector<std::optional<std::string>>& _row, const size_t _i,
ViewType* _view, std::integer_sequence<size_t, is...>) noexcept {
std::optional<Error> err;
(assign_if_field_is_field_i<is>(_row, _i, _view, &err), ...);
return err;
}
private:
ViewType* view_;
};
} // namespace sqlgen::parsing
#endif