130 lines
5.0 KiB
C++
130 lines
5.0 KiB
C++
#ifndef MATADOR_PK_FIELD_LOCATOR_HPP
|
|
#define MATADOR_PK_FIELD_LOCATOR_HPP
|
|
|
|
#include "matador/utils/primary_key_attribute.hpp"
|
|
#include "matador/utils/field_attributes.hpp"
|
|
#include "matador/utils/foreign_attributes.hpp"
|
|
|
|
#include <variant>
|
|
#include <array>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
|
|
namespace matador::object::detail {
|
|
using uuid16 = std::array<std::uint8_t, 16>;
|
|
using pk_value = std::variant<std::int64_t, std::string, uuid16>;
|
|
|
|
enum class pk_kind { integer, string, uuid };
|
|
|
|
struct pk_field_descriptor {
|
|
std::size_t offset{};
|
|
pk_kind kind{pk_kind::integer};
|
|
|
|
bool (*is_known_at)(const void* obj, std::size_t offset) = nullptr;
|
|
pk_value (*get_at)(const void* obj, std::size_t offset) = nullptr;
|
|
void (*set_at)(void* obj, std::size_t offset, const pk_value& v) = nullptr;
|
|
};
|
|
|
|
template < typename Type >
|
|
struct pk_field_locator {
|
|
Type *base{nullptr};
|
|
pk_field_descriptor desc{};
|
|
bool found{false};
|
|
|
|
explicit pk_field_locator (Type &obj)
|
|
: base(&obj) {}
|
|
|
|
template <typename PrimaryKeyType>
|
|
void on_primary_key(const char *, PrimaryKeyType &pk, const utils::primary_key_attribute & = utils::default_pk_attributes) {
|
|
// Offset bestimmen
|
|
const auto* obj_bytes = reinterpret_cast<std::uint8_t*>(base);
|
|
const auto* pk_bytes = reinterpret_cast<std::uint8_t*>(&pk);
|
|
desc.offset = static_cast<std::size_t>(pk_bytes - obj_bytes);
|
|
if constexpr (std::is_integral_v<PrimaryKeyType> || std::is_enum_v<PrimaryKeyType>) {
|
|
desc.kind = pk_kind::integer;
|
|
|
|
desc.is_known_at = [](void *obj, const std::size_t off) -> bool {
|
|
auto *p = reinterpret_cast<PrimaryKeyType *>(static_cast<std::uint8_t *>(obj) + off);
|
|
return *p != PrimaryKeyType{};
|
|
};
|
|
|
|
desc.get_at = [](void *obj, const std::size_t off) -> pk_value {
|
|
auto *p = reinterpret_cast<PrimaryKeyType *>(static_cast<std::uint8_t *>(obj) + off);
|
|
return static_cast<std::int64_t>(*p);
|
|
};
|
|
|
|
desc.set_at = [](void *obj, const std::size_t off, const pk_value &v) {
|
|
auto *p = reinterpret_cast<PrimaryKeyType *>(static_cast<std::uint8_t *>(obj) + off);
|
|
if (auto *i = std::get_if<std::int64_t>(&v)) {
|
|
*p = static_cast<PrimaryKeyType>(*i);
|
|
} else {
|
|
throw std::logic_error("PK type mismatch: expected integer");
|
|
}
|
|
};
|
|
} else if constexpr (std::is_same_v<PrimaryKeyType, std::string>) {
|
|
desc.kind = pk_kind::string;
|
|
|
|
desc.is_known_at = [](void *obj, const std::size_t off) -> bool {
|
|
const auto *p = reinterpret_cast<std::string *>(static_cast<std::uint8_t *>(obj) + off);
|
|
return !p->empty();
|
|
};
|
|
|
|
desc.get_at = [](void *obj, const std::size_t off) -> pk_value {
|
|
auto *p = reinterpret_cast<std::string *>(static_cast<std::uint8_t *>(obj) + off);
|
|
return *p;
|
|
};
|
|
|
|
desc.set_at = [](void *obj, const std::size_t off, const pk_value &v) {
|
|
auto *p = reinterpret_cast<std::string *>(static_cast<std::uint8_t *>(obj) + off);
|
|
if (auto *s = std::get_if<std::string>(&v)) {
|
|
*p = *s;
|
|
} else {
|
|
throw std::logic_error("PK type mismatch: expected string");
|
|
}
|
|
};
|
|
} else if constexpr (std::is_same_v<PrimaryKeyType, uuid16>) {
|
|
desc.kind = pk_kind::uuid;
|
|
|
|
desc.is_known_at = [](void *obj, const std::size_t off) -> bool {
|
|
auto *p = reinterpret_cast<uuid16 *>(static_cast<std::uint8_t *>(obj) + off);
|
|
// “unknown” = all zeros
|
|
for (auto b: *p) { if (b != 0) return true; }
|
|
return false;
|
|
};
|
|
|
|
desc.get_at = [](void *obj, const std::size_t off) -> pk_value {
|
|
auto *p = reinterpret_cast<uuid16 *>(static_cast<std::uint8_t *>(obj) + off);
|
|
return *p;
|
|
};
|
|
|
|
desc.set_at = [](void *obj, const std::size_t off, const pk_value &v) {
|
|
auto *p = reinterpret_cast<uuid16 *>(static_cast<std::uint8_t *>(obj) + off);
|
|
if (auto *u = std::get_if<uuid16>(&v)) {
|
|
*p = *u;
|
|
} else {
|
|
throw std::logic_error("PK type mismatch: expected uuid16");
|
|
}
|
|
};
|
|
} else {
|
|
throw std::logic_error("Unsupported primary key field type");
|
|
}
|
|
|
|
found = true;
|
|
}
|
|
static void on_revision(const char *, std::uint64_t &) {}
|
|
template <typename V>
|
|
static void on_attribute(const char *, V &, const utils::field_attributes & = matador::utils::null_attributes) {}
|
|
template <typename Pointer>
|
|
static void on_belongs_to(const char *, Pointer &, const utils::foreign_attributes &) {}
|
|
template <typename Pointer>
|
|
static void on_has_one(const char *, Pointer &, const utils::foreign_attributes &) {}
|
|
template <typename Container>
|
|
static void on_has_many(const char *, Container &, const char *, const utils::foreign_attributes &) {}
|
|
template <typename Container>
|
|
static void on_has_many_to_many(const char *, Container &, const char *, const char *,const utils::foreign_attributes &) {}
|
|
template <typename Container>
|
|
static void on_has_many_to_many(const char *, Container &, const utils::foreign_attributes &) {}
|
|
};
|
|
}
|
|
#endif //MATADOR_PK_FIELD_LOCATOR_HPP
|