added assignment from value, conversion to database_type and appropriate tests

This commit is contained in:
Sascha Kühl 2026-04-05 12:48:13 +02:00
parent 9e4660c4ee
commit 1806e2670c
7 changed files with 170 additions and 5 deletions

View File

@ -42,6 +42,7 @@ public:
[[nodiscard]] utils::constraints type() const;
[[nodiscard]] size_t size() const;
[[nodiscard]] int index() const;
[[nodiscard]] utils::value value() const;
template<class Type>
std::optional<Type> as() const {

View File

@ -9,6 +9,7 @@ namespace matador::utils {
enum class utils_error {
InvalidVersionString,
IdentifierTypeMismatch
};
class utils_category_impl final : public std::error_category

View File

@ -16,6 +16,7 @@
#include <variant>
namespace matador::utils {
class value;
class identifier_serializer {
public:
virtual ~identifier_serializer() = default;
@ -94,7 +95,6 @@ public:
>;
identifier();
template<typename Type, std::enable_if_t<is_identifier_supported_v<Type>, int> = 0>
explicit identifier(Type &&id)
: value_(std::forward<Type>(id)) {
@ -117,9 +117,7 @@ public:
}
identifier& operator=(const std::string &value);
identifier& operator=(const char *value);
template<typename Type, std::enable_if_t<is_identifier_supported_v<Type> && std::is_same_v<std::decay_t<Type>, bool>, int> = 0>
identifier& operator=(Type &&value) {
value_ = std::forward<Type>(value);
@ -128,6 +126,11 @@ public:
~identifier() = default;
result<void, error> assign(const value &val);
static result<identifier, error> from_value(const value &val);
[[nodiscard]] database_type to_database_type() const;
bool operator==(const identifier &x) const;
bool operator!=(const identifier &x) const;
bool operator<(const identifier &x) const;

View File

@ -10,6 +10,8 @@ std::string utils_category_impl::message(const int ev) const {
switch (static_cast<utils_error>(ev)) {
case (utils_error::InvalidVersionString):
return "Invalid version string";
case utils_error::IdentifierTypeMismatch:
return "Identifier type mismatch";
default:
return "Unknown error";
}

View File

@ -1,7 +1,9 @@
#include "matador/utils/identifier.hpp"
#include "matador/utils/value.hpp"
#include "matador/utils/errors.hpp"
#include <ostream>
#include <stdexcept>
#include <utility>
namespace matador::utils {
@ -121,6 +123,73 @@ identifier & identifier::operator=(const char *value) {
return *this;
}
result<identifier, error> identifier::from_value(const value &val) {
identifier id;
if (const auto result = id.assign(val); result.is_error()) {
return failure(result.err());
}
return ok(id);
}
database_type identifier::to_database_type() const {
return std::visit([](const auto &v) -> database_type {
using T = std::decay_t<decltype(v)>;
if constexpr (std::is_same_v<T, std::monostate>) {
return nullptr;
} else if constexpr (std::is_same_v<T, std::string>) {
return v;
} else {
return static_cast<T>(v);
}
}, value_);
}
result<void, error> identifier::assign(const value &val) {
switch (val.type()) {
case basic_type::Null:
value_ = std::monostate{};
return ok<void>{};
case basic_type::Int8:
if (auto v = val.as<int8_t>()) { value_ = *v; return ok<void>{}; }
break;
case basic_type::Int16:
if (auto v = val.as<int16_t>()) { value_ = *v; return ok<void>{}; }
break;
case basic_type::Int32:
if (auto v = val.as<int32_t>()) { value_ = *v; return ok<void>{}; }
break;
case basic_type::Int64:
if (auto v = val.as<int64_t>()) { value_ = *v; return ok<void>{}; }
break;
case basic_type::UInt8:
if (auto v = val.as<uint8_t>()) { value_ = *v; return ok<void>{}; }
break;
case basic_type::UInt16:
if (auto v = val.as<uint16_t>()) { value_ = *v; return ok<void>{}; }
break;
case basic_type::UInt32:
if (auto v = val.as<uint32_t>()) { value_ = *v; return ok<void>{}; }
break;
case basic_type::UInt64:
if (auto v = val.as<uint64_t>()) { value_ = *v; return ok<void>{}; }
break;
case basic_type::Text:
case basic_type::Varchar:
if (auto v = val.as<std::string>()) { value_ = *v; return ok<void>{}; }
break;
default:
break;
}
return failure(error{utils_error::IdentifierTypeMismatch});
}
bool identifier::operator==(const identifier &x) const {
return value_ == x.value_;
}

View File

@ -62,6 +62,10 @@ int field::index() const {
return index_;
}
utils::value field::value() const {
return value_;
}
std::ostream &operator<<(std::ostream &out, const field &col) {
out << col.str();
return out;

View File

@ -2,6 +2,7 @@
#include "matador/utils/identifier.hpp"
#include "matador/utils/default_type_traits.hpp"
#include "matador/utils/value.hpp"
using namespace matador::utils;
@ -279,3 +280,87 @@ TEST_CASE("identifier as() and convert() behave consistently for same integer ty
REQUIRE(conv_u64.is_ok());
REQUIRE(*conv_u64 == 77);
}
TEST_CASE("identifier assign from value", "[utils][identifier][assign]") {
identifier id;
value v1{int32_t{17}};
const auto r1 = id.assign(v1);
REQUIRE(r1.is_ok());
REQUIRE(id.is_integer());
REQUIRE(id.str() == "17");
value v2{std::string{"abc"}};
const auto r2 = id.assign(v2);
REQUIRE(r2.is_ok());
REQUIRE(id.is_varchar());
REQUIRE(id.str() == "abc");
value v3{basic_type::Double, 0};
const auto r3 = id.assign(v3);
REQUIRE(r3.is_error());
}
TEST_CASE("identifier assign from value with exact type mapping", "[utils][identifier][assign]") {
identifier id;
SECTION("integer types") {
value v{int16_t{12}};
const auto r = id.assign(v);
REQUIRE(r.is_ok());
REQUIRE(id.is_integer());
REQUIRE(id.str() == "12");
}
SECTION("string types") {
value v{std::string{"abc"}};
const auto r = id.assign(v);
REQUIRE(r.is_ok());
REQUIRE(id.is_varchar());
REQUIRE(id.str() == "abc");
}
SECTION("null") {
value v{basic_type::Null, 0};
const auto r = id.assign(v);
REQUIRE(r.is_ok());
REQUIRE(id.is_null());
}
}
TEST_CASE("identifier::to_database_type converts internal value to database_type", "[identifier]") {
SECTION("null identifier becomes nullptr") {
identifier id{nullptr};
const auto db_value = id.to_database_type();
REQUIRE(std::holds_alternative<std::nullptr_t>(db_value));
}
SECTION("signed integral identifier becomes same signed database type") {
identifier id{int32_t{42}};
const auto db_value = id.to_database_type();
REQUIRE(std::holds_alternative<int32_t>(db_value));
REQUIRE(std::get<int32_t>(db_value) == 42);
}
SECTION("unsigned integral identifier becomes same unsigned database type") {
identifier id{uint64_t{123456789ULL}};
const auto db_value = id.to_database_type();
REQUIRE(std::holds_alternative<uint64_t>(db_value));
REQUIRE(std::get<uint64_t>(db_value) == 123456789ULL);
}
SECTION("string identifier becomes std::string database type") {
identifier id{std::string{"customer_1"}};
const auto db_value = id.to_database_type();
REQUIRE(std::holds_alternative<std::string>(db_value));
REQUIRE(std::get<std::string>(db_value) == "customer_1");
}
}