query/include/matador/object/pk_field_locator.hpp

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