added assignment from value, conversion to database_type and appropriate tests
This commit is contained in:
parent
9e4660c4ee
commit
1806e2670c
|
|
@ -42,6 +42,7 @@ public:
|
||||||
[[nodiscard]] utils::constraints type() const;
|
[[nodiscard]] utils::constraints type() const;
|
||||||
[[nodiscard]] size_t size() const;
|
[[nodiscard]] size_t size() const;
|
||||||
[[nodiscard]] int index() const;
|
[[nodiscard]] int index() const;
|
||||||
|
[[nodiscard]] utils::value value() const;
|
||||||
|
|
||||||
template<class Type>
|
template<class Type>
|
||||||
std::optional<Type> as() const {
|
std::optional<Type> as() const {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ namespace matador::utils {
|
||||||
|
|
||||||
enum class utils_error {
|
enum class utils_error {
|
||||||
InvalidVersionString,
|
InvalidVersionString,
|
||||||
|
IdentifierTypeMismatch
|
||||||
};
|
};
|
||||||
|
|
||||||
class utils_category_impl final : public std::error_category
|
class utils_category_impl final : public std::error_category
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
namespace matador::utils {
|
namespace matador::utils {
|
||||||
|
class value;
|
||||||
class identifier_serializer {
|
class identifier_serializer {
|
||||||
public:
|
public:
|
||||||
virtual ~identifier_serializer() = default;
|
virtual ~identifier_serializer() = default;
|
||||||
|
|
@ -94,7 +95,6 @@ public:
|
||||||
>;
|
>;
|
||||||
|
|
||||||
identifier();
|
identifier();
|
||||||
|
|
||||||
template<typename Type, std::enable_if_t<is_identifier_supported_v<Type>, int> = 0>
|
template<typename Type, std::enable_if_t<is_identifier_supported_v<Type>, int> = 0>
|
||||||
explicit identifier(Type &&id)
|
explicit identifier(Type &&id)
|
||||||
: value_(std::forward<Type>(id)) {
|
: value_(std::forward<Type>(id)) {
|
||||||
|
|
@ -117,17 +117,20 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
identifier& operator=(const std::string &value);
|
identifier& operator=(const std::string &value);
|
||||||
|
|
||||||
identifier& operator=(const char *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>
|
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) {
|
identifier& operator=(Type &&value) {
|
||||||
value_ = std::forward<Type>(value);
|
value_ = std::forward<Type>(value);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
~identifier() = default;
|
~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;
|
bool operator!=(const identifier &x) const;
|
||||||
bool operator<(const identifier &x) const;
|
bool operator<(const identifier &x) const;
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ std::string utils_category_impl::message(const int ev) const {
|
||||||
switch (static_cast<utils_error>(ev)) {
|
switch (static_cast<utils_error>(ev)) {
|
||||||
case (utils_error::InvalidVersionString):
|
case (utils_error::InvalidVersionString):
|
||||||
return "Invalid version string";
|
return "Invalid version string";
|
||||||
|
case utils_error::IdentifierTypeMismatch:
|
||||||
|
return "Identifier type mismatch";
|
||||||
default:
|
default:
|
||||||
return "Unknown error";
|
return "Unknown error";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
#include "matador/utils/identifier.hpp"
|
#include "matador/utils/identifier.hpp"
|
||||||
|
|
||||||
|
#include "matador/utils/value.hpp"
|
||||||
|
#include "matador/utils/errors.hpp"
|
||||||
|
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <stdexcept>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace matador::utils {
|
namespace matador::utils {
|
||||||
|
|
@ -121,6 +123,73 @@ identifier & identifier::operator=(const char *value) {
|
||||||
return *this;
|
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 {
|
bool identifier::operator==(const identifier &x) const {
|
||||||
return value_ == x.value_;
|
return value_ == x.value_;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,10 @@ int field::index() const {
|
||||||
return index_;
|
return index_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
utils::value field::value() const {
|
||||||
|
return value_;
|
||||||
|
}
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &out, const field &col) {
|
std::ostream &operator<<(std::ostream &out, const field &col) {
|
||||||
out << col.str();
|
out << col.str();
|
||||||
return out;
|
return out;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "matador/utils/identifier.hpp"
|
#include "matador/utils/identifier.hpp"
|
||||||
#include "matador/utils/default_type_traits.hpp"
|
#include "matador/utils/default_type_traits.hpp"
|
||||||
|
#include "matador/utils/value.hpp"
|
||||||
|
|
||||||
using namespace matador::utils;
|
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.is_ok());
|
||||||
REQUIRE(*conv_u64 == 77);
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue