Compare commits

..

No commits in common. "57246d874299a431963a3cdfb781412e51c98e1b" and "f751541bddff3fc2c4a5f14b50fa69ab2061aeb2" have entirely different histories.

49 changed files with 610 additions and 1111 deletions

View File

@ -281,7 +281,7 @@ utils::result<std::vector<object::attribute>, utils::error> postgres_connection:
null_opt = object::null_option_type::NotNull; null_opt = object::null_option_type::NotNull;
} }
// f.default_value(res->column(4)); // f.default_value(res->column(4));
prototype.emplace_back(name, type, utils::NullAttributes, null_opt); prototype.emplace_back(name, type, utils::null_attributes, null_opt);
} }
return utils::ok(prototype); return utils::ok(prototype);

View File

@ -29,7 +29,7 @@ public:
attribute() = default; attribute() = default;
attribute(std::string name, attribute(std::string name,
utils::basic_type type, utils::basic_type type,
const utils::field_attributes& opts = utils::NullAttributes, const utils::field_attributes& opts = utils::null_attributes,
null_option_type null_opt = null_option_type::NotNull) null_option_type null_opt = null_option_type::NotNull)
: name_(std::move(name)), type_(type), options_(opts), null_option_type_(null_opt) {} : name_(std::move(name)), type_(type), options_(opts), null_option_type_(null_opt) {}

View File

@ -28,7 +28,7 @@ public:
attribute() = default; attribute() = default;
attribute(std::string name, attribute(std::string name,
utils::basic_type type, utils::basic_type type,
const utils::field_attributes &attr = utils::NullAttributes, const utils::field_attributes &attr = utils::null_attributes,
null_option_type null_opt = null_option_type::NotNull); null_option_type null_opt = null_option_type::NotNull);
[[nodiscard]] const std::string& name() const; [[nodiscard]] const std::string& name() const;
@ -39,9 +39,9 @@ public:
[[nodiscard]] bool is_nullable() const; [[nodiscard]] bool is_nullable() const;
[[nodiscard]] utils::basic_type type() const; [[nodiscard]] utils::basic_type type() const;
[[nodiscard]] std::shared_ptr<object> owner() const; [[nodiscard]] std::shared_ptr<object> owner() const;
void change_type(utils::basic_type type, const utils::field_attributes &attr = utils::NullAttributes); void change_type(utils::basic_type type, const utils::field_attributes &attr = utils::null_attributes);
template < typename Type > template < typename Type >
void change_type(const utils::field_attributes &attr = utils::NullAttributes) { void change_type(const utils::field_attributes &attr = utils::null_attributes) {
type_ = utils::data_type_traits<Type>::type(attr.size()); type_ = utils::data_type_traits<Type>::type(attr.size());
} }

View File

@ -39,12 +39,12 @@ public:
} }
template<class PrimaryKeyType> template<class PrimaryKeyType>
static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, const utils::primary_key_attribute & /*attr*/) {} static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, const utils::primary_key_attribute & /*attr*/ = utils::default_pk_attributes) {}
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {} static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
template<typename AttributeType> template<typename AttributeType>
static void on_attribute(const char * /*id*/, AttributeType &/*val*/, const utils::field_attributes &/*attr*/) {} static void on_attribute(const char * /*id*/, AttributeType &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template<typename AttributeType> template<typename AttributeType>
static void on_attribute(const char * /*id*/, std::optional<AttributeType> &/*val*/, const utils::field_attributes &/*attr*/) {} static void on_attribute(const char * /*id*/, std::optional<AttributeType> &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template<class ForeignPointerType> template<class ForeignPointerType>
void on_belongs_to(const char *id, ForeignPointerType &/*obj*/, const utils::foreign_attributes &/*attr*/); void on_belongs_to(const char *id, ForeignPointerType &/*obj*/, const utils::foreign_attributes &/*attr*/);
template<class ForeignPointerType> template<class ForeignPointerType>

View File

@ -25,10 +25,10 @@ public:
return join_columns_; return join_columns_;
} }
template < class V > template < class V >
static void on_primary_key(const char * /*id*/, V &, const utils::primary_key_attribute& /*attr*/) {} static void on_primary_key(const char * /*id*/, V &, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {}
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {} static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
template<typename Type> template<typename Type>
static void on_attribute(const char * /*id*/, Type &, const utils::field_attributes &/*attr*/) {} static void on_attribute(const char * /*id*/, Type &, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template<class Pointer> template<class Pointer>
static void on_belongs_to(const char * /*id*/, Pointer &/*obj*/, const utils::foreign_attributes &/*attr*/) {} static void on_belongs_to(const char * /*id*/, Pointer &/*obj*/, const utils::foreign_attributes &/*attr*/) {}
template<class Pointer> template<class Pointer>

View File

@ -25,13 +25,13 @@ public:
} }
template<typename ValueType> template<typename ValueType>
void on_primary_key(const char *, ValueType &/*pk*/, const utils::primary_key_attribute& attr) { void on_primary_key(const char *, ValueType &/*pk*/, const utils::primary_key_attribute& attr = utils::default_pk_attributes) {
type_ = utils::data_type_traits<ValueType>::type(attr.size()); type_ = utils::data_type_traits<ValueType>::type(attr.size());
} }
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {} static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
template < class Type > template < class Type >
static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/) {} static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
static void on_attribute(const char * /*id*/, char * /*x*/, const utils::field_attributes &/*attr*/) {} static void on_attribute(const char * /*id*/, char * /*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template<class Pointer> template<class Pointer>
static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
template<class Pointer> template<class Pointer>
@ -75,14 +75,14 @@ public:
} }
template < class Type > template < class Type >
void on_primary_key(const char *, Type &x, const utils::primary_key_attribute& attr); void on_primary_key(const char *, Type &x, const utils::primary_key_attribute& attr = utils::default_pk_attributes);
void on_revision(const char *id, uint64_t &rev); void on_revision(const char *id, uint64_t &rev);
template<typename Type> template<typename Type>
void on_attribute(const char *id, Type &x, const utils::field_attributes &attr); void on_attribute(const char *id, Type &x, const utils::field_attributes &attr = utils::null_attributes);
template<typename Type> template<typename Type>
void on_attribute(const char *id, std::optional<Type> &x, const utils::field_attributes &attr); void on_attribute(const char *id, std::optional<Type> &x, const utils::field_attributes &attr = utils::null_attributes);
template<class Pointer> template<class Pointer>
void on_belongs_to(const char *id, Pointer &x, const utils::foreign_attributes &/*attr*/) { void on_belongs_to(const char *id, Pointer &x, const utils::foreign_attributes &/*attr*/) {

View File

@ -35,7 +35,7 @@ struct pk_field_locator {
: base(&obj) {} : base(&obj) {}
template <typename PrimaryKeyType> template <typename PrimaryKeyType>
void on_primary_key(const char *, PrimaryKeyType &pk, const utils::primary_key_attribute & /*attr*/) { void on_primary_key(const char *, PrimaryKeyType &pk, const utils::primary_key_attribute & = utils::default_pk_attributes) {
// Offset bestimmen // Offset bestimmen
const auto* obj_bytes = reinterpret_cast<std::uint8_t*>(base); const auto* obj_bytes = reinterpret_cast<std::uint8_t*>(base);
const auto* pk_bytes = reinterpret_cast<std::uint8_t*>(&pk); const auto* pk_bytes = reinterpret_cast<std::uint8_t*>(&pk);
@ -113,7 +113,7 @@ struct pk_field_locator {
} }
static void on_revision(const char *, std::uint64_t &) {} static void on_revision(const char *, std::uint64_t &) {}
template <typename V> template <typename V>
static void on_attribute(const char *, V &, const utils::field_attributes &/*attr*/) {} static void on_attribute(const char *, V &, const utils::field_attributes & = matador::utils::null_attributes) {}
template <typename Pointer> template <typename Pointer>
static void on_belongs_to(const char *, Pointer &, const utils::foreign_attributes &) {} static void on_belongs_to(const char *, Pointer &, const utils::foreign_attributes &) {}
template <typename Pointer> template <typename Pointer>

View File

@ -44,7 +44,7 @@ public:
} }
template < class Type > template < class Type >
void on_primary_key(const char *id, Type &pk, const utils::primary_key_attribute& attr) { void on_primary_key(const char *id, Type &pk, const utils::primary_key_attribute& attr = utils::default_pk_attributes) {
primary_key_info_.pk_column_name = id; primary_key_info_.pk_column_name = id;
primary_key_info_.type = utils::data_type_traits<Type>::type(attr.size()); primary_key_info_.type = utils::data_type_traits<Type>::type(attr.size());
primary_key_info_.pk = pk; primary_key_info_.pk = pk;
@ -52,7 +52,7 @@ public:
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {} static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
template<typename Type> template<typename Type>
static void on_attribute(const char * /*id*/, Type &/*val*/, const utils::field_attributes &/*attr*/) {} static void on_attribute(const char * /*id*/, Type &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template<class Pointer> template<class Pointer>
static void on_belongs_to(const char * /*id*/, Pointer &/*val*/, const utils::foreign_attributes &/*attr*/) {} static void on_belongs_to(const char * /*id*/, Pointer &/*val*/, const utils::foreign_attributes &/*attr*/) {}
template<class Pointer> template<class Pointer>

View File

@ -29,12 +29,12 @@ public:
} }
template<class PrimaryKeyType> template<class PrimaryKeyType>
static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, const utils::primary_key_attribute& /*attr*/) {} static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {}
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {} static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
template<typename AttributeType> template<typename AttributeType>
static void on_attribute(const char * /*id*/, AttributeType &/*val*/, const utils::field_attributes &/*attr*/) {} static void on_attribute(const char * /*id*/, AttributeType &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template<typename AttributeType> template<typename AttributeType>
static void on_attribute(const char * /*id*/, std::optional<AttributeType> &/*val*/, const utils::field_attributes &/*attr*/) {} static void on_attribute(const char * /*id*/, std::optional<AttributeType> &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template<class ForeignPointerType> template<class ForeignPointerType>
void on_belongs_to(const char *id, ForeignPointerType &/*obj*/, const utils::foreign_attributes &/*attr*/) { void on_belongs_to(const char *id, ForeignPointerType &/*obj*/, const utils::foreign_attributes &/*attr*/) {
@ -103,12 +103,12 @@ public:
} }
template<class PrimaryKeyType> template<class PrimaryKeyType>
static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, const utils::primary_key_attribute& /*attr*/) {} static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {}
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {} static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
template<typename AttributeType> template<typename AttributeType>
static void on_attribute(const char * /*id*/, AttributeType &/*val*/, const utils::field_attributes &/*attr*/) {} static void on_attribute(const char * /*id*/, AttributeType &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template<typename AttributeType> template<typename AttributeType>
static void on_attribute(const char * /*id*/, std::optional<AttributeType> &/*val*/, const utils::field_attributes &/*attr*/) {} static void on_attribute(const char * /*id*/, std::optional<AttributeType> &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template<class ForeignPointerType> template<class ForeignPointerType>
void on_belongs_to(const char *id, ForeignPointerType &obj, const utils::foreign_attributes &attr); void on_belongs_to(const char *id, ForeignPointerType &obj, const utils::foreign_attributes &attr);

View File

@ -179,7 +179,7 @@ public:
} }
template<class Type> template<class Type>
void on_primary_key(const char * /*id*/, Type &x, const utils::primary_key_attribute & /*attr*/) { void on_primary_key(const char * /*id*/, Type &x, const utils::primary_key_attribute & /*attr*/ = utils::default_pk_attributes) {
stmt_.bind(binding_position_, x); stmt_.bind(binding_position_, x);
} }
@ -187,17 +187,17 @@ public:
} }
template<class Type> template<class Type>
static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/) {} static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template<class Pointer> template<class Pointer>
static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {}
template<class Pointer> template<class Pointer>
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many(const char * /*id*/, static void on_has_many(const char * /*id*/,
ContainerType &/*c*/, ContainerType &/*c*/,
const char * /*join_column*/, const char * /*join_column*/,
const utils::foreign_attributes &/*attr*/) {} const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many_to_many(const char * /*id*/, static void on_has_many_to_many(const char * /*id*/,

View File

@ -41,12 +41,12 @@ public:
return generator_type_; return generator_type_;
} }
template<class V> template<class V>
void on_primary_key(const char * /*id*/, V &/*pk*/, const utils::primary_key_attribute &attr) { void on_primary_key(const char * /*id*/, V &/*pk*/, const utils::primary_key_attribute &attr = utils::default_pk_attributes) {
generator_type_ = attr.generator(); generator_type_ = attr.generator();
} }
static void on_revision(const char * /*id*/, uint64_t & /*rev*/) {} static void on_revision(const char * /*id*/, uint64_t & /*rev*/) {}
template<typename T> template<typename T>
static void on_attribute(const char * /*id*/, T &, const utils::field_attributes &/*attr*/) {} static void on_attribute(const char * /*id*/, T &, const utils::field_attributes & = utils::null_attributes) {}
template<class P> template<class P>
static void on_belongs_to(const char * /*id*/, P &, const utils::foreign_attributes & ) {} static void on_belongs_to(const char * /*id*/, P &, const utils::foreign_attributes & ) {}
template<class P> template<class P>

View File

@ -60,15 +60,15 @@ struct dependency_collector {
std::vector<fk_ref> refs; std::vector<fk_ref> refs;
template<class V> template<class V>
static void on_primary_key(const char*, V&, const utils::primary_key_attribute& /*attr*/) {} static void on_primary_key(const char*, V&, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {}
static void on_revision(const char*, std::uint64_t&) {} static void on_revision(const char*, std::uint64_t&) {}
template<class V> template<class V>
static void on_attribute(const char*, V&, const utils::field_attributes &/*attr*/) {} static void on_attribute(const char*, V&, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template<class Pointer> template<class Pointer>
void on_belongs_to(const char* id, Pointer& p, utils::foreign_attributes &/*attr*/) { void on_belongs_to(const char* id, Pointer& p, utils::foreign_attributes &attr) {
// Erwartung: Pointer verhält sich wie matador::object::object_ptr<T> // Erwartung: Pointer verhält sich wie matador::object::object_ptr<T>
// also: p.get() liefert raw ptr, und Pointer::value_type / element_type ist T. // also: p.get() liefert raw ptr, und Pointer::value_type / element_type ist T.
auto* raw = p.get(); auto* raw = p.get();

View File

@ -25,13 +25,13 @@ public:
} }
template<typename ValueType> template<typename ValueType>
void on_primary_key(const char *, ValueType &pk, const utils::primary_key_attribute& /*attr*/) { void on_primary_key(const char *, ValueType &pk, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {
value_ = pk; value_ = pk;
} }
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {} static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
template < class Type > template < class Type >
static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/) {} static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
static void on_attribute(const char * /*id*/, char * /*x*/, const utils::field_attributes &/*attr*/) {} static void on_attribute(const char * /*id*/, char * /*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template<class Pointer> template<class Pointer>
static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
template<class Pointer> template<class Pointer>

View File

@ -64,13 +64,13 @@ public:
} }
template < class V > template < class V >
void on_primary_key(const char *id, V &, const utils::primary_key_attribute& /*attr*/) { void on_primary_key(const char *id, V &, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {
push(id); push(id);
} }
void on_revision(const char *id, uint64_t &/*rev*/); void on_revision(const char *id, uint64_t &/*rev*/);
template<typename Type> template<typename Type>
void on_attribute(const char *id, Type &, const utils::field_attributes &/*attr*/) { void on_attribute(const char *id, Type &, const utils::field_attributes &/*attr*/ = utils::null_attributes) {
push(id); push(id);
} }
@ -105,7 +105,7 @@ public:
} }
template<class CollectionType> template<class CollectionType>
void on_has_many(const char * /*id*/, CollectionType &, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/, std::enable_if_t<!object::is_object_ptr<typename CollectionType::value_type>::value> * = nullptr) { void on_has_many(const char * /*id*/, CollectionType &, const char *join_column, const utils::foreign_attributes &attr, std::enable_if_t<!object::is_object_ptr<typename CollectionType::value_type>::value> * = nullptr) {
} }
template<class ContainerType> template<class ContainerType>
@ -170,13 +170,13 @@ public:
} }
template < class V > template < class V >
void on_primary_key(const char * /*id*/, V &/*x*/, const utils::primary_key_attribute& /*attr*/) { void on_primary_key(const char * /*id*/, V &/*x*/, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {
result_.emplace_back(utils::_); result_.emplace_back(utils::_);
} }
void on_revision(const char *id, uint64_t &/*rev*/); void on_revision(const char *id, uint64_t &/*rev*/);
template<typename Type> template<typename Type>
void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/) { void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {
result_.emplace_back(utils::_); result_.emplace_back(utils::_);
} }
@ -228,13 +228,13 @@ public:
} }
template < class V > template < class V >
void on_primary_key(const char *id, V &x, const utils::primary_key_attribute& /*attr*/) { void on_primary_key(const char *id, V &x, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {
push_back(id, x); push_back(id, x);
} }
void on_revision(const char *id, uint64_t &/*rev*/); void on_revision(const char *id, uint64_t &/*rev*/);
template<typename Type> template<typename Type>
void on_attribute(const char *id, Type &x, const utils::field_attributes &/*attr*/) { void on_attribute(const char *id, Type &x, const utils::field_attributes &/*attr*/ = utils::null_attributes) {
push_back(id, x); push_back(id, x);
} }

View File

@ -6,9 +6,81 @@
#include "matador/query/query.hpp" #include "matador/query/query.hpp"
#include "matador/query/query_builder_exception.hpp" #include "matador/query/query_builder_exception.hpp"
#include "matador/utils/primary_key_accessor.hpp"
namespace matador::query { namespace matador::query {
struct pk_setter {
const std::string &name;
std::uint64_t value;
template<class V>
void on_primary_key(const char *id, V &pk, const utils::primary_key_attribute & = utils::default_pk_attributes) {
if (id != nullptr && name == id) {
pk = static_cast<V>(value);
}
}
static void on_revision(const char * /*id*/, uint64_t & /*rev*/) {}
template<typename T>
static void on_attribute(const char * /*id*/, T &, const utils::field_attributes & = utils::null_attributes) {}
template<class P>
static void on_belongs_to(const char * /*id*/, P &, const utils::foreign_attributes & ) {}
template<class P>
static void on_has_one(const char * /*id*/, P &, const utils::foreign_attributes & ) {}
template<class C>
static void on_has_many(const char * /*id*/, C &, const char * /*join_column*/, const utils::foreign_attributes & ) {}
template<class C>
static void on_has_many_to_many(const char * /*id*/, C &, const char * /*join_column*/, const char * /*inverse_join_column*/, const utils::foreign_attributes & ) {}
template<class C>
static void on_has_many_to_many(const char * /*id*/, C &, const utils::foreign_attributes & ) {}
};
struct pk_unset_checker {
const std::string &name;
bool unset{true};
template<class V>
void on_primary_key(const char *id, V &pk, const utils::primary_key_attribute & = utils::default_pk_attributes) {
if (id != nullptr && name == id) {
// Your convention: 0 means unset for integer PKs
unset = (static_cast<std::uint64_t>(pk) == 0ULL);
}
}
static void on_revision(const char * /*id*/, uint64_t & /*rev*/) {}
template<typename T>
static void on_attribute(const char * /*id*/, T &, const utils::field_attributes & = utils::null_attributes) {}
template<class P>
static void on_belongs_to(const char * /*id*/, P &, const utils::foreign_attributes & ) {}
template<class P>
static void on_has_one(const char * /*id*/, P &, const utils::foreign_attributes & ) {}
template<class C>
static void on_has_many(const char * /*id*/, C &, const char * /*join_column*/, const utils::foreign_attributes & ) {}
template<class C>
static void on_has_many_to_many(const char * /*id*/, C &, const char * /*join_column*/, const char * /*inverse_join_column*/, const utils::foreign_attributes & ) {}
template<class C>
static void on_has_many_to_many(const char * /*id*/, C &, const utils::foreign_attributes & ) {}
};
struct pk_value_extractor {
std::uint64_t value{0};
template<class V>
void on_primary_key(const char * /*id*/, V &pk, const utils::primary_key_attribute & = utils::default_pk_attributes) {
value = static_cast<std::uint64_t>(pk);
}
static void on_revision(const char * /*id*/, uint64_t & /*rev*/) {}
template<typename T>
static void on_attribute(const char * /*id*/, T &, const utils::field_attributes & = utils::null_attributes) {}
template<class P>
static void on_belongs_to(const char * /*id*/, P &, const utils::foreign_attributes & ) {}
template<class P>
static void on_has_one(const char * /*id*/, P &, const utils::foreign_attributes & ) {}
template<class C>
static void on_has_many(const char * /*id*/, C &, const char * /*join_column*/, const utils::foreign_attributes & ) {}
template<class C>
static void on_has_many_to_many(const char * /*id*/, C &, const char * /*join_column*/, const char * /*inverse_join_column*/, const utils::foreign_attributes & ) {}
template<class C>
static void on_has_many_to_many(const char * /*id*/, C &, const utils::foreign_attributes & ) {}
};
class insert_query_builder { class insert_query_builder {
public: public:
using step_query_t = std::variant<executable_query, fetchable_query>; using step_query_t = std::variant<executable_query, fetchable_query>;
@ -18,7 +90,10 @@ public:
// Session uses these to handle manual/sequence/table pre-insert PKs // Session uses these to handle manual/sequence/table pre-insert PKs
utils::generator_type pk_generator{utils::generator_type::Manual}; utils::generator_type pk_generator{utils::generator_type::Manual};
utils::primary_key_accessor pk_accessor; std::string pk_name;
std::function<bool()> pk_is_unset{};
std::function<void(std::uint64_t)> set_pk{};
// Identity post-insert // Identity post-insert
std::function<void(const sql::record &)> apply_returning{}; std::function<void(const sql::record &)> apply_returning{};
@ -48,11 +123,11 @@ public:
} }
template < class V > template < class V >
static void on_primary_key(const char * /*id*/, V &, const utils::primary_key_attribute& /*attr*/) {} static void on_primary_key(const char * /*id*/, V &, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {}
static void on_revision(const char *id, uint64_t &/*rev*/); static void on_revision(const char *id, uint64_t &/*rev*/);
template<typename Type> template<typename Type>
static void on_attribute(const char * /*id*/, Type &, const utils::field_attributes &/*attr*/) {} static void on_attribute(const char * /*id*/, Type &, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template<class Pointer> template<class Pointer>
void on_belongs_to(const char * /*id*/, Pointer &obj, const utils::foreign_attributes &attr) { void on_belongs_to(const char * /*id*/, Pointer &obj, const utils::foreign_attributes &attr) {
@ -63,19 +138,8 @@ public:
void on_has_one(const char * /*id*/, Pointer &obj, const utils::foreign_attributes &attr) { void on_has_one(const char * /*id*/, Pointer &obj, const utils::foreign_attributes &attr) {
on_foreign_object(obj, attr); on_foreign_object(obj, attr);
} }
template<class CollectionType> template<class Collection>
void on_has_many(const char * /*id*/, CollectionType &con, const char *, const utils::foreign_attributes &attr, std::enable_if_t<object::is_object_ptr<typename CollectionType::value_type>::value> * = nullptr) { static void on_has_many(const char * /*id*/, Collection &/*con*/, const char * /*join_column*/, const utils::foreign_attributes & ) {}
if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Insert)) {
return;
}
for (auto &obj : con) {
obj.is_persistent() ? build_for(obj) : on_foreign_object(obj, attr);
}
}
template<class CollectionType>
void on_has_many(const char * /*id*/, CollectionType &/*con*/, const char *, const utils::foreign_attributes &/*attr*/, std::enable_if_t<!object::is_object_ptr<typename CollectionType::value_type>::value> * = nullptr) {}
template<class Collection> template<class Collection>
void on_has_many_to_many(const char *id, Collection &container, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes & ) { void on_has_many_to_many(const char *id, Collection &container, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes & ) {
if (id == nullptr || join_column == nullptr || inverse_join_column == nullptr) { if (id == nullptr || join_column == nullptr || inverse_join_column == nullptr) {
@ -105,18 +169,19 @@ public:
} }
// Extract FK value from the foreign object // Extract FK value from the foreign object
insert_step rel_step{}; pk_value_extractor fk{};
const auto pk = rel_step.pk_accessor.get(obj); access::process(fk, *obj);
if (pk.is_valid()) { if (fk.value == 0ULL) {
continue; continue;
} }
// Build INSERT into relation table with the 2 FK columns // Build INSERT into relation table with the 2 FK columns
// rel_step.query = executable_query{ insert_step rel_step{};
// insert() rel_step.query = executable_query{
// .into(relation_table, {table_column{&relation_table, join_column}, table_column{&relation_table, inverse_join_column}}) insert()
// .values({utils::database_type{current_entity_pk_}, utils::database_type{fk.value}}) .into(relation_table, {table_column{&relation_table, join_column}, table_column{&relation_table, inverse_join_column}})
// }; .values({utils::database_type{current_entity_pk_}, utils::database_type{fk.value}})
};
relation_steps_.push_back(std::move(rel_step)); relation_steps_.push_back(std::move(rel_step));
} }
} }
@ -162,18 +227,29 @@ private:
const auto &info = it->second.node().info(); const auto &info = it->second.node().info();
insert_step step{}; insert_step step{};
if (info.has_primary_key()) { if (info.has_primary_key()) {
step.pk_name = info.primary_key_attribute()->name();
step.pk_generator = it->second.pk_generator().type(); step.pk_generator = it->second.pk_generator().type();
step.pk_is_unset = [ptr, name = step.pk_name]() {
pk_unset_checker chk{name};
access::process(chk, *ptr);
return chk.unset;
};
step.set_pk = [ptr, name = step.pk_name](std::uint64_t v) {
pk_setter setter{name, v};
access::process(setter, *ptr);
};
} }
if (info.has_primary_key() && step.pk_generator == utils::generator_type::Identity) { if (info.has_primary_key() && step.pk_generator == utils::generator_type::Identity) {
const auto pk_name = info.primary_key_attribute()->name(); const table_column pk_col(&it->second.table(), step.pk_name);
const table_column pk_col(&it->second.table(), pk_name);
step.query = fetchable_query{insert().into(it->second.table()).values(*ptr).returning(pk_col)}; step.query = fetchable_query{insert().into(it->second.table()).values(*ptr).returning(pk_col)};
step.apply_returning = [ptr, &step, pk_name = pk_name](const sql::record &rec) { step.apply_returning = [ptr, pk_name = step.pk_name](const sql::record &rec) {
const auto& f = rec.at(pk_name); if (auto v = rec.at<std::uint64_t>(pk_name); v.has_value()) {
utils::identifier id; pk_setter setter{pk_name, *v};
id.assign(f.value()); access::process(setter, *ptr);
step.pk_accessor.set(*ptr, id); }
}; };
} else { } else {
step.query = executable_query{insert().into(it->second.table()).values(*ptr)}; step.query = executable_query{insert().into(it->second.table()).values(*ptr)};
@ -202,7 +278,6 @@ private:
std::vector<insert_step> relation_steps_; std::vector<insert_step> relation_steps_;
std::unordered_set<std::pair<std::type_index, const void *>, visit_key_hash> visited_; std::unordered_set<std::pair<std::type_index, const void *>, visit_key_hash> visited_;
std::uint64_t current_entity_pk_{0}; std::uint64_t current_entity_pk_{0};
}; };
} }

View File

@ -27,13 +27,13 @@ public:
} }
template < class V > template < class V >
void on_primary_key(const char *id, V &x, const utils::primary_key_attribute& /*attr*/) { void on_primary_key(const char *id, V &x, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {
result_.emplace_back(id, x); result_.emplace_back(id, x);
} }
void on_revision(const char *id, uint64_t &/*rev*/) const; void on_revision(const char *id, uint64_t &/*rev*/) const;
template<typename Type> template<typename Type>
void on_attribute(const char *id, Type &x, const utils::field_attributes &/*attr*/) { void on_attribute(const char *id, Type &x, const utils::field_attributes &/*attr*/ = utils::null_attributes) {
result_.emplace_back(id, x); result_.emplace_back(id, x);
} }

View File

@ -61,10 +61,10 @@ public:
{} {}
template<typename ValueType> template<typename ValueType>
static void on_primary_key(const char * /*id*/, ValueType &/*value*/, const utils::primary_key_attribute& /*attr*/) {} static void on_primary_key(const char * /*id*/, ValueType &/*value*/, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {}
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {} static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
template<class Type> template<class Type>
static void on_attribute(const char * /*id*/, Type &/*value*/, const utils::field_attributes &/*attr*/) {} static void on_attribute(const char * /*id*/, Type &/*value*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template<class Pointer> template<class Pointer>
static void on_belongs_to(const char * /*id*/, Pointer & /*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_belongs_to(const char * /*id*/, Pointer & /*x*/, const utils::foreign_attributes &/*attr*/) {}
template<class Pointer> template<class Pointer>

View File

@ -90,7 +90,7 @@ public:
} }
template < class V > template < class V >
void on_primary_key(const char *id, V &, const utils::primary_key_attribute& /*attr*/) { void on_primary_key(const char *id, V &, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {
push(id); push(id);
if (!is_root_entity()) { if (!is_root_entity()) {
return; return;
@ -101,7 +101,7 @@ public:
void on_revision(const char *id, uint64_t &/*rev*/); void on_revision(const char *id, uint64_t &/*rev*/);
template<typename Type> template<typename Type>
void on_attribute(const char *id, Type &, const utils::field_attributes &/*attr*/) void on_attribute(const char *id, Type &, const utils::field_attributes &/*attr*/ = utils::null_attributes)
{ {
push(id); push(id);
} }

View File

@ -26,16 +26,16 @@ public:
} }
template<typename ValueType> template<typename ValueType>
void on_primary_key(const char *, ValueType &x, const utils::primary_key_attribute& attr) { void on_primary_key(const char *, ValueType &x, const utils::primary_key_attribute& attr = utils::default_pk_attributes) {
utils::data_type_traits<ValueType>::bind_value(*this, 0, x, attr.size()); utils::data_type_traits<ValueType>::bind_value(*this, 0, x, attr.size());
} }
void on_revision(const char *id, uint64_t &rev); void on_revision(const char *id, uint64_t &rev);
template < class Type > template < class Type >
void on_attribute(const char *, Type &x, const utils::field_attributes &/*attr*/) { void on_attribute(const char *, Type &x, const utils::field_attributes &/*attr*/ = utils::null_attributes) {
utils::data_type_traits<Type>::bind_value(*this, 0, x); utils::data_type_traits<Type>::bind_value(*this, 0, x);
} }
void on_attribute(const char *id, char *x, const utils::field_attributes &/*attr*/); void on_attribute(const char *id, char *x, const utils::field_attributes &/*attr*/ = utils::null_attributes);
void on_attribute(const char *id, std::string &x, const utils::field_attributes &/*attr*/); void on_attribute(const char *id, std::string &x, const utils::field_attributes &/*attr*/ = utils::null_attributes);
template<class Type, template < class ... > class Pointer> template<class Type, template < class ... > class Pointer>
void on_belongs_to(const char * /*id*/, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/) { void on_belongs_to(const char * /*id*/, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/) {

View File

@ -42,7 +42,6 @@ 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 {

View File

@ -45,7 +45,7 @@ public:
} }
template < class V > template < class V >
void on_primary_key(const char *id, V &, const utils::primary_key_attribute& /*attr*/) { void on_primary_key(const char *id, V &, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {
if (has_many_to_many_) { if (has_many_to_many_) {
return; return;
} }
@ -54,7 +54,7 @@ public:
void on_revision(const char *id, uint64_t &/*rev*/); void on_revision(const char *id, uint64_t &/*rev*/);
template<typename Type> template<typename Type>
void on_attribute(const char *id, Type &, const utils::field_attributes &/*attr*/) { void on_attribute(const char *id, Type &, const utils::field_attributes &/*attr*/ = utils::null_attributes) {
if (has_many_to_many_) { if (has_many_to_many_) {
return; return;
} }

View File

@ -23,14 +23,14 @@ public:
} }
template<typename ValueType> template<typename ValueType>
void on_primary_key(const char *id, ValueType &value, const utils::primary_key_attribute& attr) { void on_primary_key(const char *id, ValueType &value, const utils::primary_key_attribute& attr = utils::default_pk_attributes) {
utils::data_type_traits<ValueType>::read_value(reader_, id, column_index_, value, attr.size()); utils::data_type_traits<ValueType>::read_value(reader_, id, column_index_, value, attr.size());
identifier_ = value; identifier_ = value;
} }
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {} static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
template < class Type > template < class Type >
static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/) {} static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template < class Pointer > template < class Pointer >
static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
template < class Pointer > template < class Pointer >

View File

@ -28,21 +28,21 @@ public:
} }
template<typename ValueType> template<typename ValueType>
void on_primary_key(const char *id, ValueType &value, const utils::primary_key_attribute& attr); void on_primary_key(const char *id, ValueType &value, const utils::primary_key_attribute& attr = utils::default_pk_attributes);
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {} static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
template < class Type > template < class Type >
static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/) {} static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template < class Pointer > template < class Pointer >
static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {}
template < class Pointer > template < class Pointer >
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many(const char * /*id*/, static void on_has_many(const char * /*id*/,
ContainerType &/*c*/, ContainerType &/*c*/,
const char * /*join_column*/, const char * /*join_column*/,
const utils::foreign_attributes &/*attr*/) {} const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many_to_many(const char * /*id*/, static void on_has_many_to_many(const char * /*id*/,
ContainerType &/*c*/, ContainerType &/*c*/,
@ -74,32 +74,32 @@ public:
void reset(); void reset();
template < class Type > template < class Type >
void on_primary_key(const char *id, Type &val, const utils::primary_key_attribute& attr) { void on_primary_key(const char *id, Type &val, const utils::primary_key_attribute& attr = utils::default_pk_attributes) {
utils::data_type_traits<Type>::read_value(*binder_, id, index_++, val, attr.size()); utils::data_type_traits<Type>::read_value(*binder_, id, index_++, val, attr.size());
} }
void on_revision(const char *id, uint64_t &/*rev*/); void on_revision(const char *id, uint64_t &/*rev*/);
template<typename Type> template<typename Type>
void on_attribute(const char *id, Type &val, const utils::field_attributes &/*attr*/) { void on_attribute(const char *id, Type &val, const utils::field_attributes &/*attr*/ = utils::null_attributes) {
utils::data_type_traits<Type>::read_value(*binder_, id, index_++, val); utils::data_type_traits<Type>::read_value(*binder_, id, index_++, val);
} }
void on_attribute(const char *id, char *value, const utils::field_attributes &attr); void on_attribute(const char *id, char *value, const utils::field_attributes &attr = utils::null_attributes);
void on_attribute(const char *id, std::string &value, const utils::field_attributes &attr); void on_attribute(const char *id, std::string &value, const utils::field_attributes &attr = utils::null_attributes);
void on_attribute(const char *id, utils::value &val, const utils::field_attributes &attr); void on_attribute(const char *id, utils::value &val, const utils::field_attributes &attr = utils::null_attributes);
template<class Type, template < class ... > class Pointer> template<class Type, template < class ... > class Pointer>
void on_belongs_to(const char *id, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/) { void on_belongs_to(const char *id, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {
fk_result_binder_.bind(*x, id, index_++, *binder_); fk_result_binder_.bind(*x, id, index_++, *binder_);
} }
template<class Type, template < class ... > class Pointer> template<class Type, template < class ... > class Pointer>
void on_has_one(const char *id, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/) { void on_has_one(const char *id, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {
fk_result_binder_.bind(*x, id, index_++, *binder_); fk_result_binder_.bind(*x, id, index_++, *binder_);
} }
template<class ContainerType> template<class ContainerType>
static void on_has_many(const char * /*id*/, static void on_has_many(const char * /*id*/,
ContainerType &/*c*/, ContainerType &/*c*/,
const char * /*join_column*/, const char * /*join_column*/,
const utils::foreign_attributes &/*attr*/) {} const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many_to_many(const char * /*id*/, static void on_has_many_to_many(const char * /*id*/,
ContainerType &/*c*/, ContainerType &/*c*/,

View File

@ -15,13 +15,13 @@ public:
} }
template<typename ValueType> template<typename ValueType>
void on_primary_key(const char *id, ValueType &value, const utils::primary_key_attribute& attr); void on_primary_key(const char *id, ValueType &value, const utils::primary_key_attribute& attr = utils::default_pk_attributes);
void on_revision(const char * /*id*/, uint64_t &/*rev*/) { void on_revision(const char * /*id*/, uint64_t &/*rev*/) {
++column_index_; ++column_index_;
} }
template<class Type> template<class Type>
void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/) { void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {
++column_index_; ++column_index_;
} }

View File

@ -41,7 +41,7 @@ public:
size_t column_index = 0); size_t column_index = 0);
template<typename ValueType> template<typename ValueType>
void on_primary_key(const char *id, ValueType &value, const utils::primary_key_attribute& attr) { void on_primary_key(const char *id, ValueType &value, const utils::primary_key_attribute& attr = utils::default_pk_attributes) {
utils::data_type_traits<ValueType>::read_value(*reader_, id, column_index_++, value, attr.size()); utils::data_type_traits<ValueType>::read_value(*reader_, id, column_index_++, value, attr.size());
if (type_stack_.size() == 1) { if (type_stack_.size() == 1) {
last_pk_ = current_pk_; last_pk_ = current_pk_;
@ -52,13 +52,13 @@ public:
void on_revision(const char *id, uint64_t &rev); void on_revision(const char *id, uint64_t &rev);
template<class Type> template<class Type>
void on_attribute(const char *id, Type &x, const utils::field_attributes &/*attr*/) { void on_attribute(const char *id, Type &x, const utils::field_attributes &/*attr*/ = utils::null_attributes) {
utils::data_type_traits<Type>::read_value(*reader_, id, column_index_++, x); utils::data_type_traits<Type>::read_value(*reader_, id, column_index_++, x);
} }
void on_attribute(const char *id, char *value, const utils::field_attributes &attr); void on_attribute(const char *id, char *value, const utils::field_attributes &attr = utils::null_attributes);
void on_attribute(const char *id, std::string &value, const utils::field_attributes &attr); void on_attribute(const char *id, std::string &value, const utils::field_attributes &attr = utils::null_attributes);
void on_attribute(const char *id, utils::value &val, const utils::field_attributes &attr); void on_attribute(const char *id, utils::value &val, const utils::field_attributes &attr = utils::null_attributes);
template<class Pointer> template<class Pointer>
void on_belongs_to(const char * /*id*/, Pointer &x, const utils::foreign_attributes &attr) { void on_belongs_to(const char * /*id*/, Pointer &x, const utils::foreign_attributes &attr) {

View File

@ -28,7 +28,7 @@ public:
} }
template<typename ValueType> template<typename ValueType>
void on_primary_key(const char *id, ValueType &/*value*/, const utils::primary_key_attribute& attr) { void on_primary_key(const char *id, ValueType &/*value*/, const utils::primary_key_attribute& attr = utils::default_pk_attributes) {
if (!type_stack_.empty()) { if (!type_stack_.empty()) {
return; return;
} }
@ -39,8 +39,8 @@ public:
void on_revision(const char * /*id*/, uint64_t &/*rev*/) { ++column_index_; } void on_revision(const char * /*id*/, uint64_t &/*rev*/) { ++column_index_; }
template < class Type > template < class Type >
void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/) { ++column_index_; } void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) { ++column_index_; }
void on_attribute(const char *id, const utils::value &x, const utils::field_attributes &attr); void on_attribute(const char *id, const utils::value &x, const utils::field_attributes &attr = utils::null_attributes);
template < class Pointer > template < class Pointer >
void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &attr) { on_foreign_key<typename Pointer::value_type>(attr.fetch() ); } void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &attr) { on_foreign_key<typename Pointer::value_type>(attr.fetch() ); }

View File

@ -18,29 +18,29 @@ public:
[[nodiscard]] size_t current_index() const; [[nodiscard]] size_t current_index() const;
template < class Type > template < class Type >
void on_primary_key(const char * /*id*/, Type &val, const utils::primary_key_attribute& attr) { void on_primary_key(const char * /*id*/, Type &val, const utils::primary_key_attribute& attr = utils::default_pk_attributes) {
utils::data_type_traits<Type>::bind_value(*binder_, index_++, val, attr.size()); utils::data_type_traits<Type>::bind_value(*binder_, index_++, val, attr.size());
} }
void on_revision(const char *id, uint64_t &/*rev*/); void on_revision(const char *id, uint64_t &/*rev*/);
template<typename Type> template<typename Type>
void on_attribute(const char * /*id*/, Type &val, const utils::field_attributes &/*attr*/) { void on_attribute(const char * /*id*/, Type &val, const utils::field_attributes &/*attr*/ = utils::null_attributes) {
utils::data_type_traits<Type>::bind_value(*binder_, index_++, val); utils::data_type_traits<Type>::bind_value(*binder_, index_++, val);
} }
template<class Type, template < class ... > class Pointer> template<class Type, template < class ... > class Pointer>
void on_belongs_to(const char * /*id*/, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/) { void on_belongs_to(const char * /*id*/, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {
pk_binder_.bind(*x, index_++, *binder_); pk_binder_.bind(*x, index_++, *binder_);
} }
template<class Type, template < class ... > class Pointer> template<class Type, template < class ... > class Pointer>
void on_has_one(const char * /*id*/, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/) { void on_has_one(const char * /*id*/, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {
pk_binder_.bind(*x, index_++, *binder_); pk_binder_.bind(*x, index_++, *binder_);
} }
template<class ContainerType> template<class ContainerType>
static void on_has_many(const char * /*id*/, static void on_has_many(const char * /*id*/,
ContainerType &/*c*/, ContainerType &/*c*/,
const char * /*join_column*/, const char * /*join_column*/,
const utils::foreign_attributes &/*attr*/) {} const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many_to_many(const char * /*id*/, static void on_has_many_to_many(const char * /*id*/,
ContainerType &/*c*/, ContainerType &/*c*/,

View File

@ -20,21 +20,21 @@ public:
} }
template<typename ValueType> template<typename ValueType>
void on_primary_key(const char *id, ValueType &value, const utils::primary_key_attribute& attr); void on_primary_key(const char *id, ValueType &value, const utils::primary_key_attribute& attr = utils::default_pk_attributes);
static void on_revision(const char * /*id*/, unsigned long long &/*rev*/) {} static void on_revision(const char * /*id*/, unsigned long long &/*rev*/) {}
template < class Type > template < class Type >
static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/) {} static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template < class Pointer > template < class Pointer >
static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {}
template < class Pointer > template < class Pointer >
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many(const char * /*id*/, static void on_has_many(const char * /*id*/,
ContainerType &/*c*/, ContainerType &/*c*/,
const char * /*join_column*/, const char * /*join_column*/,
const utils::foreign_attributes &/*attr*/) {} const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many_to_many(const char * /*id*/, static void on_has_many_to_many(const char * /*id*/,
ContainerType &/*c*/, ContainerType &/*c*/,

View File

@ -1,10 +1,7 @@
#ifndef OOS_ACCESS_HPP #ifndef OOS_ACCESS_HPP
#define OOS_ACCESS_HPP #define OOS_ACCESS_HPP
#include "matador/utils/primary_key_attribute.hpp" #include <cstdint>
#include "matador/utils/field_attributes.hpp"
#include "matador/utils/foreign_attributes.hpp"
#include <optional> #include <optional>
namespace matador { namespace matador {
@ -32,66 +29,108 @@ template<class Base, class Derived, class Operator>
void process_base(Operator &op, const Derived &object) { void process_base(Operator &op, const Derived &object) {
static_assert(!std::is_same_v<Base, Derived>, "class Base must not be of same type as class Derived"); static_assert(!std::is_same_v<Base, Derived>, "class Base must not be of same type as class Derived");
static_assert(std::is_base_of_v<Base, Derived>, "class Base must be base of class Derived"); static_assert(std::is_base_of_v<Base, Derived>, "class Base must be base of class Derived");
op.on_base(static_cast<const Base&>(object)); process(op, static_cast<const Base&>(object));
} }
template<class Base, class Derived, class Operator> template<class Base, class Derived, class Operator>
void process_base(Operator &op, Derived &object) { void process_base(Operator &op, Derived &object) {
static_assert(!std::is_same_v<Base, Derived>, "class Base must not be of same type as class Derived"); static_assert(!std::is_same_v<Base, Derived>, "class Base must not be of same type as class Derived");
static_assert(std::is_base_of_v<Base, Derived>, "class Base must be base of class Derived"); static_assert(std::is_base_of_v<Base, Derived>, "class Base must be base of class Derived");
op.on_base(static_cast<Base&>(object)); process(op, static_cast<Base&>(object));
} }
template< class Operator, class Type > template< class Operator, class Type >
void primary_key(Operator &op, const char *id, Type &value, const utils::primary_key_attribute &attr = utils::DefaultPkAttributes) { void primary_key(Operator &op, const char *id, Type &value, const utils::primary_key_attribute &attr) {
op.on_primary_key(id, value, attr); op.on_primary_key(id, value, attr);
} }
template< class Operator, class Type >
void primary_key(Operator &op, const char *id, Type &value) {
op.on_primary_key(id, value);
}
template<class Operator> template<class Operator>
void revision(Operator &op, const char *id, uint64_t &value) { void revision(Operator &op, const char *id, uint64_t &value) {
op.on_revision(id, value); op.on_revision(id, value);
} }
template<class Operator, class Type> template<class Operator, class Type>
void attribute(Operator &op, const char *id, Type &value, const utils::field_attributes &attr = utils::NullAttributes) { void attribute(Operator &op, const char *id, Type &value, const utils::field_attributes &attr) {
op.on_attribute(id, value, attr); op.on_attribute(id, value, attr);
} }
template<class Operator, class Type> template<class Operator, class Type>
void attribute(Operator &op, const char *id, std::optional<Type> &value, const utils::field_attributes &attr = utils::NullAttributes) { void attribute(Operator &op, const char *id, std::optional<Type> &value, const utils::field_attributes &attr) {
op.on_attribute(id, value, attr); op.on_attribute(id, value, attr);
} }
template<class Operator, class Type> template<class Operator, class Type>
void has_one(Operator &op, const char *id, Type &value, const utils::foreign_attributes &attr = utils::CascadeNoneFetchLazy) { void attribute(Operator &op, const char *id, Type &value) {
op.on_attribute(id, value);
}
template<class Operator, class Type>
void has_one(Operator &op, const char *id, Type &value, const utils::foreign_attributes &attr) {
op.on_has_one(id, value, attr); op.on_has_one(id, value, attr);
} }
template<class Operator, class Type> template<class Operator, class Type>
void belongs_to(Operator &op, const char *id, Type &value, const utils::foreign_attributes &attr = utils::CascadeNoneFetchLazy) { void has_one(Operator &op, const char *id, Type &value) {
op.on_has_one(id, value);
}
template<class Operator, class Type>
void belongs_to(Operator &op, const char *id, Type &value, const utils::foreign_attributes &attr) {
op.on_belongs_to(id, value, attr); op.on_belongs_to(id, value, attr);
} }
template<class Operator, class Type>
void belongs_to(Operator &op, const char *id, Type &value) {
op.on_belongs_to(id, value);
}
template<class Operator, class Type, template<class ...> class ContainerType> template<class Operator, class Type, template<class ...> class ContainerType>
void has_many(Operator &op, const char *id, ContainerType<Type> &c, const char *join_column, const utils::foreign_attributes &attr = utils::CascadeNoneFetchLazy) { void has_many(Operator &op, const char *id, ContainerType<Type> &c, const char *join_column, const utils::foreign_attributes &attr) {
op.on_has_many(id, c, join_column, attr); op.on_has_many(id, c, join_column, attr);
} }
template<class Operator, class Type, template<class ...> class ContainerType> template<class Operator, class Type, template<class ...> class ContainerType>
void has_many(Operator &op, const char *id, ContainerType<Type> &c, const utils::foreign_attributes &attr = utils::CascadeNoneFetchLazy) { void has_many(Operator &op, const char *id, ContainerType<Type> &c, const char *join_column) {
op.on_has_many(id, c, join_column);
}
template<class Operator, class Type, template<class ...> class ContainerType>
void has_many(Operator &op, const char *id, ContainerType<Type> &c, const utils::foreign_attributes &attr) {
op.on_has_many(id, c, attr); op.on_has_many(id, c, attr);
} }
template<class Operator, class Type, template<class ...> class ContainerType>
void has_many(Operator &op, const char *id, ContainerType<Type> &c) {
op.on_has_many(id, c);
}
template<class Operator, class ContainerType> template<class Operator, class ContainerType>
void has_many_to_many(Operator &op, const char *id, ContainerType &c, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &attr = utils::CascadeNoneFetchLazy) { void has_many_to_many(Operator &op, const char *id, ContainerType &c, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &attr) {
op.on_has_many_to_many(id, c, join_column, inverse_join_column, attr); op.on_has_many_to_many(id, c, join_column, inverse_join_column, attr);
} }
template<class Operator, class ContainerType> template<class Operator, class ContainerType>
void has_many_to_many(Operator &op, const char *id, ContainerType &c, const utils::foreign_attributes &attr = utils::CascadeNoneFetchLazy) { void has_many_to_many(Operator &op, const char *id, ContainerType &c, const char *join_column, const char *inverse_join_column) {
op.on_has_many_to_many(id, c, join_column, inverse_join_column);
}
template<class Operator, class ContainerType>
void has_many_to_many(Operator &op, const char *id, ContainerType &c, const utils::foreign_attributes &attr) {
op.on_has_many_to_many(id, c, attr); op.on_has_many_to_many(id, c, attr);
} }
template<class Operator, class ContainerType>
void has_many_to_many(Operator &op, const char *id, ContainerType &c) {
op.on_has_many_to_many(id, c);
} }
}
} }
#endif //OOS_ACCESS_HPP #endif //OOS_ACCESS_HPP

View File

@ -9,7 +9,6 @@ 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

View File

@ -74,7 +74,7 @@ private:
constraints options_ = constraints::None; constraints options_ = constraints::None;
}; };
const field_attributes NullAttributes {}; const field_attributes null_attributes {};
} }
#endif //MATADOR_FIELD_ATTRIBUTES_HPP #endif //MATADOR_FIELD_ATTRIBUTES_HPP

View File

@ -1,22 +1,16 @@
#ifndef MATADOR_IDENTIFIER_HPP #ifndef MATADOR_IDENTIFIER_HPP
#define MATADOR_IDENTIFIER_HPP #define MATADOR_IDENTIFIER_HPP
#include "matador/utils/basic_types.hpp"
#include "matador/utils/default_type_traits.hpp" #include "matador/utils/default_type_traits.hpp"
#include "matador/utils/error.hpp"
#include "matador/utils/field_attributes.hpp" #include "matador/utils/field_attributes.hpp"
#include "matador/utils/result.hpp" #include "matador/utils/basic_types.hpp"
#include "matador/utils/types.hpp" #include "matador/utils/types.hpp"
#include <memory> #include <memory>
#include <ostream>
#include <string> #include <string>
#include <type_traits>
#include <typeindex> #include <typeindex>
#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;
@ -37,13 +31,7 @@ template<typename Type, class Enabled = void>
struct identifier_type_traits; struct identifier_type_traits;
template<typename Type> template<typename Type>
struct identifier_type_traits<Type, std::enable_if_t<std::is_integral_v<Type> && std::is_signed_v<Type> > > { struct identifier_type_traits<Type, std::enable_if_t<std::is_integral_v<Type> > > {
static bool is_valid(Type value) { return value != 0; }
static std::string to_string(const Type value) { return std::to_string(value); }
};
template<typename Type>
struct identifier_type_traits<Type, std::enable_if_t<std::is_integral_v<Type> && !std::is_signed_v<Type> > > {
static bool is_valid(Type value) { return value > 0; } static bool is_valid(Type value) { return value > 0; }
static std::string to_string(const Type value) { return std::to_string(value); } static std::string to_string(const Type value) { return std::to_string(value); }
}; };
@ -60,77 +48,127 @@ struct identifier_type_traits<null_type_t, void> {
static std::string to_string() { return "null"; } static std::string to_string() { return "null"; }
}; };
template<>
struct identifier_type_traits<const char *, void> {
static bool is_valid(const char *value);
static std::string to_string(const char *value);
};
namespace detail { namespace detail {
template<typename Type> template<typename Type>
size_t hash(const Type &value) { size_t hash(const Type &value) {
return std::hash<Type>()(value); return std::hash<Type>()(value);
} }
size_t hash(const std::string &value); size_t hash(const char *value);
} }
template <class T>
struct is_identifier_supported : std::false_type {};
template <> struct is_identifier_supported<int8_t> : std::true_type {};
template <> struct is_identifier_supported<int16_t> : std::true_type {};
template <> struct is_identifier_supported<int32_t> : std::true_type {};
template <> struct is_identifier_supported<int64_t> : std::true_type {};
template <> struct is_identifier_supported<uint8_t> : std::true_type {};
template <> struct is_identifier_supported<uint16_t> : std::true_type {};
template <> struct is_identifier_supported<uint32_t> : std::true_type {};
template <> struct is_identifier_supported<uint64_t> : std::true_type {};
template <> struct is_identifier_supported<std::string> : std::true_type {};
template <class T>
inline constexpr bool is_identifier_supported_v = is_identifier_supported<std::decay_t<T>>::value;
class identifier { class identifier {
public: private:
using value_type = std::variant< struct base {
std::monostate, base(const std::type_index &ti, basic_type type);
int8_t, int16_t, int32_t, int64_t, base(const base &x) = delete;
uint8_t, uint16_t, uint32_t, uint64_t, base &operator=(const base &x) = delete;
std::string base(base &&x) = delete;
>; base &operator=(base &&x) = delete;
virtual ~base() = default;
identifier(); [[nodiscard]] virtual base *copy() const = 0;
template<typename Type, std::enable_if_t<is_identifier_supported_v<Type>, int> = 0> [[nodiscard]] virtual bool equal_to(const base &x) const = 0;
explicit identifier(Type &&id) [[nodiscard]] virtual bool less(const base &x) const = 0;
: value_(std::forward<Type>(id)) { [[nodiscard]] virtual bool is_valid() const = 0;
virtual void serialize(identifier_serializer &s) = 0;
[[nodiscard]] virtual std::string str() const = 0;
[[nodiscard]] virtual size_t hash() const = 0;
std::type_index type_index_;
basic_type type_{basic_type::Null};
};
template<class IdType>
struct pk final : base {
using self = pk;
explicit pk(const IdType &id)
: base(std::type_index(typeid(IdType)), data_type_traits<IdType>::type(1))
, id_(id)
, size_(sizeof(IdType)) {
} }
identifier(const identifier &x) = default; [[nodiscard]] base *copy() const override {
return new self(id_);
}
[[nodiscard]] bool equal_to(const base &x) const override {
return static_cast<const pk &>(x).id_ == id_;
}
[[nodiscard]] bool less(const base &x) const override {
return id_ < static_cast<const pk &>(x).id_;
}
[[nodiscard]] bool is_valid() const override {
return identifier_type_traits<IdType>::is_valid(id_);
}
[[nodiscard]] std::string str() const override {
return identifier_type_traits<IdType>::to_string(id_);
}
void serialize(identifier_serializer &s) override {
s.serialize(id_, size_);
}
[[nodiscard]] size_t hash() const override {
return detail::hash(id_);
}
IdType id_;
size_t size_{};
};
struct null_pk final : base {
null_pk();
[[nodiscard]] base *copy() const override;
[[nodiscard]] bool equal_to(const base &x) const override;
[[nodiscard]] bool less(const base &x) const override;
[[nodiscard]] bool is_valid() const override;
void serialize(identifier_serializer &s) override;
[[nodiscard]] std::string str() const override;
[[nodiscard]] size_t hash() const override;
null_type_t null_;
};
public:
identifier();
template<typename Type>
explicit identifier(const Type &id)
: id_(std::make_shared<pk<Type> >(id)) {
}
explicit identifier(const char *id)
: id_(std::make_shared<pk<std::string> >(id)) {
}
identifier(const identifier &x);
identifier &operator=(const identifier &x); identifier &operator=(const identifier &x);
identifier(identifier &&x) noexcept = default; identifier(identifier &&x) noexcept;
identifier &operator=(identifier &&x) noexcept = default; identifier &operator=(identifier &&x) noexcept;
explicit identifier(std::nullptr_t); template<typename Type>
explicit identifier(const char *value); identifier &operator=(const Type &value) {
id_ = std::make_shared<pk<Type> >(value);
identifier& operator=(std::nullptr_t);
template<typename Type, std::enable_if_t<std::is_integral_v<std::decay_t<Type>> && !std::is_same_v<std::decay_t<Type>, bool>, int> = 0>
identifier& operator=(Type value) {
assign_integral(value);
return *this; return *this;
} }
identifier& operator=(const std::string &value); identifier &operator=(const char *value) {
identifier& operator=(const char *value); id_ = std::make_shared<pk<std::string> >(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);
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;
@ -142,8 +180,17 @@ public:
[[nodiscard]] const std::type_index &type_index() const; [[nodiscard]] const std::type_index &type_index() const;
[[nodiscard]] basic_type type() const; [[nodiscard]] basic_type type() const;
[[nodiscard]] identifier share() const;
[[nodiscard]] size_t use_count() const;
[[nodiscard]] bool is_integer() const; [[nodiscard]] bool is_integer() const;
[[nodiscard]] bool is_floating_point() const;
[[nodiscard]] bool is_bool() const;
[[nodiscard]] bool is_varchar() const; [[nodiscard]] bool is_varchar() const;
[[nodiscard]] bool is_date() const;
[[nodiscard]] bool is_time() const;
[[nodiscard]] bool is_timestamp() const;
[[nodiscard]] bool is_blob() const;
[[nodiscard]] bool is_null() const; [[nodiscard]] bool is_null() const;
[[nodiscard]] bool is_valid() const; [[nodiscard]] bool is_valid() const;
@ -153,97 +200,15 @@ public:
[[nodiscard]] size_t hash() const; [[nodiscard]] size_t hash() const;
template <typename Type, std::enable_if_t<is_identifier_supported_v<Type>, int> = 0>
result<Type, error> as() const;
template <typename Type, std::enable_if_t<std::is_integral_v<Type> && !std::is_same_v<Type, bool>, int> = 0>
result<Type, error> convert() const;
friend std::ostream &operator<<(std::ostream &out, const identifier &id); friend std::ostream &operator<<(std::ostream &out, const identifier &id);
private: private:
template<typename Type> explicit identifier(const std::shared_ptr<base> &id);
void assign_integral(Type value) {
if constexpr (std::is_signed_v<Type>) {
if (sizeof(Type) <= sizeof(int8_t)) {
value_ = static_cast<int8_t>(value);
} else if (sizeof(Type) <= sizeof(int16_t)) {
value_ = static_cast<int16_t>(value);
} else if (sizeof(Type) <= sizeof(int32_t)) {
value_ = static_cast<int32_t>(value);
} else {
value_ = static_cast<int64_t>(value);
}
} else {
if (sizeof(Type) <= sizeof(uint8_t)) {
value_ = static_cast<uint8_t>(value);
} else if (sizeof(Type) <= sizeof(uint16_t)) {
value_ = static_cast<uint16_t>(value);
} else if (sizeof(Type) <= sizeof(uint32_t)) {
value_ = static_cast<uint32_t>(value);
} else {
value_ = static_cast<uint64_t>(value);
}
}
}
static size_t type_rank(const value_type &value);
static std::type_index type_index_from_value(const value_type &value);
static basic_type type_from_value(const value_type &value);
private: private:
value_type value_{std::monostate{}}; std::shared_ptr<base> id_;
}; };
template <typename Target, typename Source>
bool in_range(Source value) {
if constexpr (std::is_signed_v<Source> == std::is_signed_v<Target>) {
return value >= static_cast<Target>(std::numeric_limits<Source>::min()) &&
value <= static_cast<Target>(std::numeric_limits<Source>::max());
} else if constexpr (std::is_signed_v<Source> && !std::is_signed_v<Target>) {
if (value < 0) {
return false;
}
using UnsignedSource = std::make_unsigned_t<Source>;
return static_cast<UnsignedSource>(value) <= std::numeric_limits<Target>::max();
} else {
return value <= static_cast<std::make_unsigned_t<Target>>(std::numeric_limits<Target>::max());
}
}
template <typename Type, std::enable_if_t<is_identifier_supported_v<Type>, int>>
result<Type, error> identifier::as() const {
return std::visit([](const auto &v) -> result<Type, error> {
using StoredType = std::decay_t<decltype(v)>;
if constexpr (std::is_same_v<StoredType, std::monostate>) {
return failure(error{});
} else if constexpr (std::is_same_v<StoredType, Type>) {
return ok<Type>(v);
} else {
return failure(error{});
}
}, value_);
}
template <typename Type, std::enable_if_t<std::is_integral_v<Type> && !std::is_same_v<Type, bool>, int>>
result<Type, error> identifier::convert() const {
return std::visit([](const auto &v) -> result<Type, error> {
using Stored = std::decay_t<decltype(v)>;
if constexpr (std::is_same_v<Stored, std::monostate>) {
return failure(error{});
} else if constexpr (std::is_integral_v<Stored>) {
if (!in_range<Type>(v)) {
return failure(error{});
}
return ok<Type>(static_cast<Type>(v));
} else {
return failure(error{});
}
}, value_);
}
static identifier null_identifier{}; static identifier null_identifier{};
/// @cond MATADOR_DEV /// @cond MATADOR_DEV
@ -254,11 +219,13 @@ struct id_pk_hash {
/// @endcond /// @endcond
} }
namespace std {
template<> template<>
struct std::hash<matador::utils::identifier> { struct hash<matador::utils::identifier> {
size_t operator()(const matador::utils::identifier &id) const noexcept { size_t operator()(const matador::utils::identifier &id) const noexcept {
return id.hash(); return id.hash();
} }
}; // namespace std };
} // namespace std
#endif //MATADOR_IDENTIFIER_HPP #endif //MATADOR_IDENTIFIER_HPP

View File

@ -1,30 +0,0 @@
#ifndef MATADOR_IDENTIFIER_ACCESSOR_HPP
#define MATADOR_IDENTIFIER_ACCESSOR_HPP
#include "matador/utils/identifier.hpp"
#include "matador/utils/result.hpp"
namespace matador::utils {
class identifier_setter : public identifier_serializer {
public:
explicit identifier_setter(identifier &id);
template <typename ValueType>
void set(const ValueType &val) {
id_.serialize(*this, val);
}
void serialize(int16_t &, const field_attributes &) override;
void serialize(int32_t &, const field_attributes &) override;
void serialize(int64_t &, const field_attributes &) override;
void serialize(uint8_t &, const field_attributes &) override;
void serialize(uint16_t &, const field_attributes &) override;
void serialize(uint32_t &, const field_attributes &) override;
void serialize(uint64_t &, const field_attributes &) override;
void serialize(std::string &, const field_attributes &) override;
void serialize(null_type_t &, const field_attributes &) override;
private:
identifier &id_;
};
}
#endif //MATADOR_IDENTIFIER_ACCESSOR_HPP

View File

@ -1,125 +1,104 @@
#ifndef MATADOR_PRIMARY_KEY_ACCESSOR_HPP #ifndef MATADOR_PRIMARY_KEY_ACCESSOR_HPP
#define MATADOR_PRIMARY_KEY_ACCESSOR_HPP #define MATADOR_PRIMARY_KEY_ACCESSOR_HPP
#include "matador/utils/access.hpp"
#include "matador/utils/field_attributes.hpp" #include "matador/utils/field_attributes.hpp"
#include "matador/utils/identifier.hpp"
#include "matador/utils/primary_key_attribute.hpp" #include "matador/utils/primary_key_attribute.hpp"
#include <cstdint> #include <cstdint>
#include <string> #include <string>
#include <utility>
namespace matador::utils { namespace matador::utils {
class foreign_attributes; class foreign_attributes;
namespace detail { namespace detail {
template < typename PrimaryKeyType >
class primary_key_setter { class primary_key_setter {
public: public:
template <typename ObjectType> explicit primary_key_setter(const std::string &name, const PrimaryKeyType& value)
void set(ObjectType &obj, const identifier& pk) { : name_(name)
pk_ = pk; , value_(value){}
access::process(*this, obj);
}
template<typename PrimaryKeyType> void on_primary_key(const char *id, PrimaryKeyType &pk, const utils::primary_key_attribute & = utils::default_pk_attributes) {
void on_primary_key(const char * /*id*/, PrimaryKeyType &pk, const primary_key_attribute & = DefaultPkAttributes) { if (id != nullptr && name_ == id) {
const auto value = pk_.as<PrimaryKeyType>(); pk = static_cast<PrimaryKeyType>(value_);
if (!value) {
// Todo: throw error
} }
pk = value.value();
} }
template<typename ValueType>
static void on_primary_key(const char * /*id*/, ValueType & /*pk*/, const utils::primary_key_attribute & = utils::default_pk_attributes) {}
static void on_revision(const char * /*id*/, uint64_t & /*rev*/) {} static void on_revision(const char * /*id*/, uint64_t & /*rev*/) {}
template<typename T> template<typename T>
static void on_attribute(const char * /*id*/, T &, const field_attributes & = NullAttributes) {} static void on_attribute(const char * /*id*/, T &, const utils::field_attributes & = utils::null_attributes) {}
template<class P> template<class P>
static void on_belongs_to(const char * /*id*/, P &, const foreign_attributes & ) {} static void on_belongs_to(const char * /*id*/, P &, const utils::foreign_attributes & ) {}
template<class P> template<class P>
static void on_has_one(const char * /*id*/, P &, const foreign_attributes & ) {} static void on_has_one(const char * /*id*/, P &, const utils::foreign_attributes & ) {}
template<class C> template<class C>
static void on_has_many(const char * /*id*/, C &, const char * /*join_column*/, const foreign_attributes & ) {} static void on_has_many(const char * /*id*/, C &, const char * /*join_column*/, const utils::foreign_attributes & ) {}
template<class C> template<class C>
static void on_has_many_to_many(const char * /*id*/, C &, const char * /*join_column*/, const char * /*inverse_join_column*/, const foreign_attributes & ) {} static void on_has_many_to_many(const char * /*id*/, C &, const char * /*join_column*/, const char * /*inverse_join_column*/, const utils::foreign_attributes & ) {}
template<class C> template<class C>
static void on_has_many_to_many(const char * /*id*/, C &, const foreign_attributes & ) {} static void on_has_many_to_many(const char * /*id*/, C &, const utils::foreign_attributes & ) {}
private: private:
identifier pk_{}; const std::string &name_;
PrimaryKeyType value_{};
}; };
struct pk_unset_checker { struct pk_unset_checker {
const std::string &name;
bool unset{true}; bool unset{true};
template<class PrimaryKeyType> template<class V>
void on_primary_key(const char * /*id*/, PrimaryKeyType &pk, const primary_key_attribute & = DefaultPkAttributes) { void on_primary_key(const char *id, V &pk, const utils::primary_key_attribute & = utils::default_pk_attributes) {
unset = !identifier_type_traits<PrimaryKeyType>::is_valid(pk); if (id != nullptr && name == id) {
// Your convention: 0 means unset for integer PKs
unset = (static_cast<std::uint64_t>(pk) == 0ULL);
}
} }
static void on_revision(const char * /*id*/, uint64_t & /*rev*/) {} static void on_revision(const char * /*id*/, uint64_t & /*rev*/) {}
template<typename T> template<typename T>
static void on_attribute(const char * /*id*/, T &, const field_attributes & = NullAttributes) {} static void on_attribute(const char * /*id*/, T &, const utils::field_attributes & = utils::null_attributes) {}
template<class P> template<class P>
static void on_belongs_to(const char * /*id*/, P &, const foreign_attributes & ) {} static void on_belongs_to(const char * /*id*/, P &, const utils::foreign_attributes & ) {}
template<class P> template<class P>
static void on_has_one(const char * /*id*/, P &, const foreign_attributes & ) {} static void on_has_one(const char * /*id*/, P &, const utils::foreign_attributes & ) {}
template<class C> template<class C>
static void on_has_many(const char * /*id*/, C &, const char * /*join_column*/, const foreign_attributes & ) {} static void on_has_many(const char * /*id*/, C &, const char * /*join_column*/, const utils::foreign_attributes & ) {}
template<class C> template<class C>
static void on_has_many_to_many(const char * /*id*/, C &, const char * /*join_column*/, const char * /*inverse_join_column*/, const foreign_attributes & ) {} static void on_has_many_to_many(const char * /*id*/, C &, const char * /*join_column*/, const char * /*inverse_join_column*/, const utils::foreign_attributes & ) {}
template<class C> template<class C>
static void on_has_many_to_many(const char * /*id*/, C &, const foreign_attributes & ) {} static void on_has_many_to_many(const char * /*id*/, C &, const utils::foreign_attributes & ) {}
}; };
struct primary_key_getter { struct pk_value_extractor {
std::uint64_t value{0}; std::uint64_t value{0};
template<class PrimaryKeyType> template<class V>
void on_primary_key(const char * /*id*/, PrimaryKeyType &pk, const primary_key_attribute & = DefaultPkAttributes) { void on_primary_key(const char * /*id*/, V &pk, const utils::primary_key_attribute & = utils::default_pk_attributes) {
pk_ = pk; value = static_cast<std::uint64_t>(pk);
} }
static void on_revision(const char * /*id*/, uint64_t & /*rev*/) {} static void on_revision(const char * /*id*/, uint64_t & /*rev*/) {}
template<typename T> template<typename T>
static void on_attribute(const char * /*id*/, T &, const field_attributes & = NullAttributes) {} static void on_attribute(const char * /*id*/, T &, const utils::field_attributes & = utils::null_attributes) {}
template<class P> template<class P>
static void on_belongs_to(const char * /*id*/, P &, const foreign_attributes & ) {} static void on_belongs_to(const char * /*id*/, P &, const utils::foreign_attributes & ) {}
template<class P> template<class P>
static void on_has_one(const char * /*id*/, P &, const foreign_attributes & ) {} static void on_has_one(const char * /*id*/, P &, const utils::foreign_attributes & ) {}
template<class C> template<class C>
static void on_has_many(const char * /*id*/, C &, const char * /*join_column*/, const foreign_attributes & ) {} static void on_has_many(const char * /*id*/, C &, const char * /*join_column*/, const utils::foreign_attributes & ) {}
template<class C> template<class C>
static void on_has_many_to_many(const char * /*id*/, C &, const char * /*join_column*/, const char * /*inverse_join_column*/, const foreign_attributes & ) {} static void on_has_many_to_many(const char * /*id*/, C &, const char * /*join_column*/, const char * /*inverse_join_column*/, const utils::foreign_attributes & ) {}
template<class C> template<class C>
static void on_has_many_to_many(const char * /*id*/, C &, const foreign_attributes & ) {} static void on_has_many_to_many(const char * /*id*/, C &, const utils::foreign_attributes & ) {}
identifier pk_;
}; };
} }
template<typename PrimaryKeyType>
class primary_key_accessor { class primary_key_accessor {
public: public:
template<class Type>
identifier get(const Type &obj) {
access::process(pk_getter_, obj);
return pk_getter_.pk_;
}
template<class Type>
void set(Type &obj, const identifier &pk) {
pk_setter_.set(obj, pk);
}
template<class Type>
bool is_set(const Type &obj) {
access::process(pk_unset_checker_, obj);
return !pk_unset_checker_.unset;
}
private:
detail::primary_key_setter pk_setter_;
detail::pk_unset_checker pk_unset_checker_;
detail::primary_key_getter pk_getter_;
PrimaryKeyType get() const;
PrimaryKeyType
}; };
} }

View File

@ -47,7 +47,7 @@ private:
generator_type generator_ = generator_type::Manual; generator_type generator_ = generator_type::Manual;
}; };
const primary_key_attribute DefaultPkAttributes {}; const primary_key_attribute default_pk_attributes {};
} }
#endif //PRIMARY_KEY_ATTRIBUTE_HPP #endif //PRIMARY_KEY_ATTRIBUTE_HPP

View File

@ -6,6 +6,7 @@
#include <cstdint> #include <cstdint>
namespace matador::utils { namespace matador::utils {
class uuid { class uuid {
public: public:
using uuid_array = std::array<uint32_t, 4>; using uuid_array = std::array<uint32_t, 4>;
@ -38,7 +39,13 @@ private:
// Hash specialization to allow use in unordered containers // Hash specialization to allow use in unordered containers
template <> template <>
struct std::hash<matador::utils::uuid> { struct std::hash<matador::utils::uuid> {
std::size_t operator()(const matador::utils::uuid &u) const noexcept; std::size_t operator()(const matador::utils::uuid& u) const noexcept {
std::size_t h = 0;
for (const uint32_t val : u.data()) {
h ^= std::hash<uint32_t>{}(val) + 0x9e3779b9 + (h << 6) + (h >> 2);
}
return h;
}
}; };
#endif //MATADOR_UUID_HPP #endif //MATADOR_UUID_HPP

View File

@ -22,14 +22,12 @@ add_library(matador-core STATIC
../../include/matador/object/collection_proxy.hpp ../../include/matador/object/collection_proxy.hpp
../../include/matador/object/collection_resolver.hpp ../../include/matador/object/collection_resolver.hpp
../../include/matador/object/collection_resolver_factory.hpp ../../include/matador/object/collection_resolver_factory.hpp
../../include/matador/object/collection_utils.hpp
../../include/matador/object/error_code.hpp ../../include/matador/object/error_code.hpp
../../include/matador/object/foreign_node_completer.hpp ../../include/matador/object/foreign_node_completer.hpp
../../include/matador/object/internal/observer_list_copy_creator.hpp ../../include/matador/object/internal/observer_list_copy_creator.hpp
../../include/matador/object/internal/observer_list_creator.hpp ../../include/matador/object/internal/observer_list_creator.hpp
../../include/matador/object/many_to_many_relation.hpp ../../include/matador/object/many_to_many_relation.hpp
../../include/matador/object/object.hpp ../../include/matador/object/object.hpp
../../include/matador/object/object_cache.hpp
../../include/matador/object/object_generator.hpp ../../include/matador/object/object_generator.hpp
../../include/matador/object/object_info.hpp ../../include/matador/object/object_info.hpp
../../include/matador/object/object_proxy.hpp ../../include/matador/object/object_proxy.hpp
@ -37,7 +35,6 @@ add_library(matador-core STATIC
../../include/matador/object/object_resolver.hpp ../../include/matador/object/object_resolver.hpp
../../include/matador/object/object_resolver_factory.hpp ../../include/matador/object/object_resolver_factory.hpp
../../include/matador/object/observer.hpp ../../include/matador/object/observer.hpp
../../include/matador/object/pk_field_locator.hpp
../../include/matador/object/primary_key_resolver.hpp ../../include/matador/object/primary_key_resolver.hpp
../../include/matador/object/relation_completer.hpp ../../include/matador/object/relation_completer.hpp
../../include/matador/object/relation_endpoint.hpp ../../include/matador/object/relation_endpoint.hpp
@ -66,7 +63,6 @@ add_library(matador-core STATIC
../../include/matador/utils/file.hpp ../../include/matador/utils/file.hpp
../../include/matador/utils/foreign_attributes.hpp ../../include/matador/utils/foreign_attributes.hpp
../../include/matador/utils/identifier.hpp ../../include/matador/utils/identifier.hpp
../../include/matador/utils/identifier_accessor.hpp
../../include/matador/utils/identifier_to_value_converter.hpp ../../include/matador/utils/identifier_to_value_converter.hpp
../../include/matador/utils/leader_follower_thread_pool.hpp ../../include/matador/utils/leader_follower_thread_pool.hpp
../../include/matador/utils/library.hpp ../../include/matador/utils/library.hpp
@ -74,7 +70,6 @@ add_library(matador-core STATIC
../../include/matador/utils/message_bus.hpp ../../include/matador/utils/message_bus.hpp
../../include/matador/utils/os.hpp ../../include/matador/utils/os.hpp
../../include/matador/utils/placeholder.hpp ../../include/matador/utils/placeholder.hpp
../../include/matador/utils/primary_key_accessor.hpp
../../include/matador/utils/primary_key_attribute.hpp ../../include/matador/utils/primary_key_attribute.hpp
../../include/matador/utils/primary_key_generator_type.hpp ../../include/matador/utils/primary_key_generator_type.hpp
../../include/matador/utils/result.hpp ../../include/matador/utils/result.hpp
@ -96,7 +91,6 @@ add_library(matador-core STATIC
object/attribute.cpp object/attribute.cpp
object/basic_object_info.cpp object/basic_object_info.cpp
object/basic_repository.cpp object/basic_repository.cpp
object/collection_utils.cpp
object/error_code.cpp object/error_code.cpp
object/foreign_node_completer.cpp object/foreign_node_completer.cpp
object/object.cpp object/object.cpp
@ -114,7 +108,6 @@ add_library(matador-core STATIC
utils/file.cpp utils/file.cpp
utils/foreign_attributes.cpp utils/foreign_attributes.cpp
utils/identifier.cpp utils/identifier.cpp
utils/identifier_accessor.cpp
utils/identifier_to_value_converter.cpp utils/identifier_to_value_converter.cpp
utils/leader_follower_thread_pool.cpp utils/leader_follower_thread_pool.cpp
utils/library.cpp utils/library.cpp
@ -127,6 +120,11 @@ add_library(matador-core STATIC
utils/uuid.cpp utils/uuid.cpp
utils/value.cpp utils/value.cpp
utils/version.cpp utils/version.cpp
../../include/matador/object/collection_utils.hpp
object/collection_utils.cpp
../../include/matador/object/pk_field_locator.hpp
../../include/matador/object/object_cache.hpp
../../include/matador/utils/primary_key_accessor.hpp
) )
target_link_libraries(matador-core ${CMAKE_DL_LIBS}) target_link_libraries(matador-core ${CMAKE_DL_LIBS})

View File

@ -21,7 +21,7 @@ std::shared_ptr<object> object_generator::acquire_object(basic_repository &repo,
} }
void object_generator::on_revision(const char* id, uint64_t& rev) { void object_generator::on_revision(const char* id, uint64_t& rev) {
access::attribute(*this, id, rev); on_attribute(id, rev);
} }
void object_generator::create_pk_constraint(const std::string& name) const { void object_generator::create_pk_constraint(const std::string& name) const {

View File

@ -10,8 +10,6 @@ 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";
} }

View File

@ -1,234 +1,97 @@
#include "matador/utils/identifier.hpp" #include "matador/utils/identifier.hpp"
#include "matador/utils/value.hpp" #include <cstring>
#include "matador/utils/errors.hpp" #include <stdexcept>
#include <ostream> #include <ostream>
#include <utility>
namespace matador::utils { namespace matador::utils {
size_t detail::hash(const char *value) {
return std::hash<std::string_view>()(std::string_view(value, std::strlen(value)));
}
namespace { bool identifier_type_traits<const char *>::is_valid(const char *value) {
inline const std::type_index& null_type_index() { return value != nullptr && strlen(value) > 0;
static const std::type_index value{typeid(null_type_t)}; }
std::string identifier_type_traits<const char *>::to_string(const char *value) {
return value; return value;
} }
inline const std::type_index& i8_type_index() { identifier::base::base(const std::type_index &ti, const basic_type type)
static const std::type_index value{typeid(int8_t)}; : type_index_(ti)
return value; , type_(type) {
} }
inline const std::type_index& i16_type_index() { identifier::null_pk::null_pk()
static const std::type_index value{typeid(int16_t)}; : base(std::type_index(typeid(null_type_t)), basic_type::Null) {
return value;
} }
inline const std::type_index& i32_type_index() { identifier::base *identifier::null_pk::copy() const {
static const std::type_index value{typeid(int32_t)}; return new null_pk;
return value;
} }
inline const std::type_index& i64_type_index() { bool identifier::null_pk::equal_to(const base &x) const {
static const std::type_index value{typeid(int64_t)}; return type_index_ == x.type_index_;
return value;
} }
inline const std::type_index& u8_type_index() { bool identifier::null_pk::less(const base &x) const {
static const std::type_index value{typeid(uint8_t)}; return type_index_ == x.type_index_;
return value;
} }
inline const std::type_index& u16_type_index() { bool identifier::null_pk::is_valid() const {
static const std::type_index value{typeid(uint16_t)}; return identifier_type_traits<null_type_t>::is_valid();
return value;
} }
inline const std::type_index& u32_type_index() { std::string identifier::null_pk::str() const {
static const std::type_index value{typeid(uint32_t)}; return identifier_type_traits<null_type_t>::to_string();
return value;
} }
inline const std::type_index& u64_type_index() { void identifier::null_pk::serialize(identifier_serializer &s) {
static const std::type_index value{typeid(uint64_t)}; s.serialize(null_, {});
return value;
} }
inline const std::type_index& string_type_index() { size_t identifier::null_pk::hash() const {
static const std::type_index value{typeid(std::string)}; return std::hash<nullptr_t>()(nullptr);
return value;
}
} // namespace
size_t detail::hash(const std::string &value) {
return std::hash<std::string_view>()(std::string_view(value));
} }
identifier::identifier() identifier::identifier()
: value_(std::monostate{}) { : id_(std::make_shared<null_pk>()) {
} }
size_t identifier::type_rank(const value_type &value) { identifier::identifier(const identifier &x)
return value.index(); : id_(x.id_->copy()) {
} }
std::type_index identifier::type_index_from_value(const value_type &value) { identifier &identifier::operator=(const identifier &x) {
return std::visit([](const auto &v) -> std::type_index { if (this == &x) {
using T = std::decay_t<decltype(v)>; return *this;
if constexpr (std::is_same_v<T, std::monostate>) {
return null_type_index();
} else {
return std::type_index(typeid(T));
} }
}, value); id_.reset(x.id_->copy());
}
const std::type_index &identifier::type_index() const {
switch (value_.index()) {
case 0: return null_type_index();
case 1: return i8_type_index();
case 2: return i16_type_index();
case 3: return i32_type_index();
case 4: return i64_type_index();
case 5: return u8_type_index();
case 6: return u16_type_index();
case 7: return u32_type_index();
case 8: return u64_type_index();
case 9: return string_type_index();
default: return null_type_index();
}
}
basic_type identifier::type_from_value(const value_type &value) {
return std::visit([](const auto &v) -> basic_type {
using T = std::decay_t<decltype(v)>;
if constexpr (std::is_same_v<T, std::monostate>) {
return basic_type::Null;
} else {
return data_type_traits<T>::type(1);
}
}, value);
}
identifier::identifier(std::nullptr_t)
: value_(std::monostate{}) {
}
identifier::identifier(const char *value)
: value_(value ? std::string(value) : std::string{}) {
}
identifier & identifier::operator=(const char *value) {
value_ = value ? std::string(value) : std::string{};
return *this; return *this;
} }
result<identifier, error> identifier::from_value(const value &val) { identifier::identifier(identifier &&x) noexcept
identifier id; : id_(std::move(x.id_)) {
if (const auto result = id.assign(val); result.is_error()) { x.clear();
return failure(result.err());
} }
return ok(id); identifier &identifier::operator=(identifier &&x) noexcept {
} id_ = std::move(x.id_);
x.clear();
database_type identifier::to_database_type() const { return *this;
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 id_->equal_to(*x.id_);
} }
bool identifier::operator!=(const identifier &x) const { bool identifier::operator!=(const identifier &x) const {
return !operator==(x); return !operator==(x);
} }
identifier &identifier::operator=(std::nullptr_t) {
value_ = std::monostate{};
return *this;
}
identifier &identifier::operator=(const std::string &value) {
value_ = value;
return *this;
}
identifier &identifier::operator=(const identifier &other) {
if (this != &other) {
value_ = other.value_;
}
return *this;
}
bool identifier::operator<(const identifier &x) const { bool identifier::operator<(const identifier &x) const {
if (value_.index() != x.value_.index()) { return id_->less(*x.id_);
return value_.index() < x.value_.index();
}
return std::visit([](const auto &lhs, const auto &rhs) -> bool {
using L = std::decay_t<decltype(lhs)>;
using R = std::decay_t<decltype(rhs)>;
if constexpr (std::is_same_v<L, R>) {
return lhs < rhs;
} else {
return false;
}
}, value_, x.value_);
} }
bool identifier::operator<=(const identifier &x) const { bool identifier::operator<=(const identifier &x) const {
@ -244,78 +107,79 @@ bool identifier::operator>=(const identifier &x) const {
} }
std::string identifier::str() const { std::string identifier::str() const {
return std::visit([](const auto &v) -> std::string { return id_->str();
using T = std::decay_t<decltype(v)>;
if constexpr (std::is_same_v<T, std::monostate>) {
return identifier_type_traits<null_type_t>::to_string();
} else if constexpr (std::is_same_v<T, std::string>) {
return identifier_type_traits<std::string>::to_string(v);
} else {
return identifier_type_traits<T>::to_string(v);
} }
}, value_);
const std::type_index &identifier::type_index() const {
return id_->type_index_;
} }
basic_type identifier::type() const { basic_type identifier::type() const {
return type_from_value(value_); return id_->type_;
}
identifier identifier::share() const {
return identifier(id_);
}
size_t identifier::use_count() const {
return id_.use_count();
} }
bool identifier::is_integer() const { bool identifier::is_integer() const {
return std::holds_alternative<int8_t>(value_) return id_->type_ >= basic_type::Int8 && id_->type_ <= basic_type::UInt64;
|| std::holds_alternative<int16_t>(value_) }
|| std::holds_alternative<int32_t>(value_)
|| std::holds_alternative<int64_t>(value_) bool identifier::is_floating_point() const {
|| std::holds_alternative<uint8_t>(value_) return id_->type_ == basic_type::Float || id_->type_ == basic_type::Double;
|| std::holds_alternative<uint16_t>(value_) }
|| std::holds_alternative<uint32_t>(value_)
|| std::holds_alternative<uint64_t>(value_); bool identifier::is_bool() const {
return id_->type_ == basic_type::Boolean;
} }
bool identifier::is_varchar() const { bool identifier::is_varchar() const {
return std::holds_alternative<std::string>(value_); return id_->type_ == basic_type::Varchar;
}
bool identifier::is_date() const {
return id_->type_ == basic_type::Date;
}
bool identifier::is_time() const {
return id_->type_ == basic_type::Time;
}
bool identifier::is_timestamp() const {
return id_->type_ == basic_type::DateTime;
}
bool identifier::is_blob() const {
return id_->type_ == basic_type::Blob;
} }
bool identifier::is_null() const { bool identifier::is_null() const {
return std::holds_alternative<std::monostate>(value_); return type_index() == null_identifier.type_index();
} }
bool identifier::is_valid() const { bool identifier::is_valid() const {
return std::visit([](const auto &v) -> bool { return id_->is_valid();
using T = std::decay_t<decltype(v)>;
if constexpr (std::is_same_v<T, std::monostate>) {
return identifier_type_traits<null_type_t>::is_valid();
} else {
return identifier_type_traits<T>::is_valid(v);
}
}, value_);
} }
void identifier::clear() { void identifier::clear() {
value_ = std::monostate{}; id_ = std::make_unique<null_pk>();
} }
void identifier::serialize(identifier_serializer &s) const { void identifier::serialize(identifier_serializer &s) const {
std::visit([&s](const auto &v) { id_->serialize(s);
using T = std::decay_t<decltype(v)>;
if constexpr (std::is_same_v<T, std::monostate>) {
null_type_t n{};
s.serialize(n, {});
} else {
auto tmp = v;
s.serialize(tmp, {});
}
}, value_);
} }
size_t identifier::hash() const { size_t identifier::hash() const {
return std::visit([](const auto &v) -> size_t { return id_->hash();
using T = std::decay_t<decltype(v)>;
if constexpr (std::is_same_v<T, std::monostate>) {
return std::hash<int>{}(0);
} else {
return detail::hash(v);
} }
}, value_);
identifier::identifier(const std::shared_ptr<base> &id)
: id_(id) {
} }
std::ostream &operator<<(std::ostream &out, const identifier &id) { std::ostream &operator<<(std::ostream &out, const identifier &id) {
@ -326,5 +190,4 @@ std::ostream &operator<<(std::ostream &out, const identifier &id) {
size_t id_pk_hash::operator()(const identifier &id) const { size_t id_pk_hash::operator()(const identifier &id) const {
return id.hash(); return id.hash();
} }
}
} // namespace matador::utils

View File

@ -1,38 +0,0 @@
#include "matador/utils/identifier_accessor.hpp"
#include "matador/utils/default_type_traits.hpp"
namespace matador::utils {
identifier_setter::identifier_setter(identifier &id)
: id_(id) {
}
void identifier_setter::serialize(int16_t &val, const field_attributes &) {
if (id_.type() == data_type_traits<int16_t>::type()) {
id_ = val;
}
}
void identifier_setter::serialize(int32_t &, const field_attributes &) {
}
void identifier_setter::serialize(int64_t &, const field_attributes &) {
}
void identifier_setter::serialize(uint8_t &, const field_attributes &) {
}
void identifier_setter::serialize(uint16_t &, const field_attributes &) {
}
void identifier_setter::serialize(uint32_t &, const field_attributes &) {
}
void identifier_setter::serialize(uint64_t &, const field_attributes &) {
}
void identifier_setter::serialize(std::string &, const field_attributes &) {
}
void identifier_setter::serialize(null_type_t &, const field_attributes &) {
}
}

View File

@ -3,6 +3,7 @@
#include <random> #include <random>
namespace matador::utils { namespace matador::utils {
uuid uuid::generate() { uuid uuid::generate() {
std::random_device rd; std::random_device rd;
std::mt19937_64 gen(rd()); std::mt19937_64 gen(rd());
@ -72,11 +73,3 @@ bool operator<(const uuid &lhs, const uuid &rhs) {
return lhs._data < rhs._data; return lhs._data < rhs._data;
} }
} }
std::size_t std::hash<matador::utils::uuid>::operator()(const matador::utils::uuid &u) const noexcept {
std::size_t h = 0;
for (const uint32_t val: u.data()) {
h ^= std::hash<uint32_t>{}(val) + 0x9e3779b9 + (h << 6) + (h >> 2);
}
return h;
}

View File

@ -62,10 +62,6 @@ 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;

View File

@ -10,7 +10,7 @@ using namespace matador::object;
using namespace matador::test; using namespace matador::test;
TEST_CASE_METHOD(SessionFixture, "Test insert object with has many relation", "[session][insert][has_many]") { TEST_CASE_METHOD(SessionFixture, "Test insert object with has many relation", "[session][insert][has_many]") {
const auto result = schema.attach<book>("books") auto result = schema.attach<book>("books")
.and_then( [this] { return schema.attach<author>("authors"); } ) .and_then( [this] { return schema.attach<author>("authors"); } )
.and_then([this] { return schema.create(db); } ); .and_then([this] { return schema.create(db); } );
REQUIRE(result.is_ok()); REQUIRE(result.is_ok());

View File

@ -5,7 +5,6 @@ list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)
add_executable(CoreTests add_executable(CoreTests
../backends/SchemaFixture.hpp ../backends/SchemaFixture.hpp
logger/LoggerTest.cpp logger/LoggerTest.cpp
object/ObjectCacheTest.cpp
object/ObjectTest.cpp object/ObjectTest.cpp
object/PrimaryKeyResolverTest.cpp object/PrimaryKeyResolverTest.cpp
object/RepositoryTest.cpp object/RepositoryTest.cpp
@ -15,13 +14,13 @@ add_executable(CoreTests
utils/DependencyInjectionTest.cpp utils/DependencyInjectionTest.cpp
utils/FieldAttributeTest.cpp utils/FieldAttributeTest.cpp
utils/IdentifierTest.cpp utils/IdentifierTest.cpp
utils/IsDatabasePrimitiveTest.cpp
utils/MessageBusTest.cpp utils/MessageBusTest.cpp
utils/PrimaryKeyAccessorTest.cpp
utils/ResultTest.cpp utils/ResultTest.cpp
utils/StringTest.cpp utils/StringTest.cpp
utils/ThreadPoolTest.cpp utils/ThreadPoolTest.cpp
utils/VersionTest.cpp utils/VersionTest.cpp
utils/IsDatabasePrimitiveTest.cpp
object/ObjectCacheTest.cpp
) )
target_link_libraries(CoreTests matador-core Catch2::Catch2WithMain) target_link_libraries(CoreTests matador-core Catch2::Catch2WithMain)

View File

@ -2,7 +2,6 @@
#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;
@ -11,7 +10,12 @@ TEST_CASE("Test create identifier", "[identifier][create]") {
REQUIRE(id.is_null()); REQUIRE(id.is_null());
REQUIRE(!id.is_integer()); REQUIRE(!id.is_integer());
REQUIRE(!id.is_floating_point());
REQUIRE(!id.is_bool());
REQUIRE(!id.is_varchar()); REQUIRE(!id.is_varchar());
REQUIRE(!id.is_date());
REQUIRE(!id.is_time());
REQUIRE(!id.is_blob());
REQUIRE(!id.is_valid()); REQUIRE(!id.is_valid());
REQUIRE(id.str() == "null"); REQUIRE(id.str() == "null");
} }
@ -84,7 +88,7 @@ TEST_CASE("Test copy identifier" "[identifier][copy]") {
identifier id3 = id1; identifier id3 = id1;
REQUIRE(id1 == id3); REQUIRE(id1 == id3);
REQUIRE(!(id1 < id3)); REQUIRE(id1 < id3);
REQUIRE(id3.is_null()); REQUIRE(id3.is_null());
REQUIRE(id1.hash() == id3.hash()); REQUIRE(id1.hash() == id3.hash());
@ -99,268 +103,16 @@ TEST_CASE("Test move identifier", "[identifier][move]") {
REQUIRE(!id1.is_null()); REQUIRE(!id1.is_null());
const auto id2 = std::move(id1); const auto id2 = std::move(id1);
REQUIRE(!id1.is_null()); REQUIRE(id1.is_null());
REQUIRE(id2.is_integer()); REQUIRE(id2.is_integer());
} }
TEST_CASE("identifier assignment from integer types", "[utils][identifier][assign]") { TEST_CASE("Test share identifier", "[identifier][share]") {
identifier id; const identifier id1{6};
id = int8_t{-5}; REQUIRE(id1.use_count() == 1);
REQUIRE(id.type() == basic_type::Int8);
REQUIRE(id.str() == "-5");
REQUIRE(id.is_integer());
REQUIRE(id.is_valid());
id = int16_t{42}; auto id2 = id1.share();
REQUIRE(id.type() == basic_type::Int16); REQUIRE(id1 == id2);
REQUIRE(id.str() == "42"); REQUIRE(id1.use_count() == 2);
REQUIRE(id.is_integer());
REQUIRE(id.is_valid());
id = uint32_t{123456u};
REQUIRE(id.type() == basic_type::UInt32);
REQUIRE(id.str() == "123456");
REQUIRE(id.is_integer());
REQUIRE(id.is_valid());
}
TEST_CASE("identifier assignment from string type", "[utils][identifier][assign]") {
identifier id;
id = std::string{"hello"};
REQUIRE(id.type() == basic_type::Varchar);
REQUIRE(id.str() == "hello");
REQUIRE(id.is_varchar());
REQUIRE(id.is_valid());
id = std::string{};
REQUIRE(id.type() == basic_type::Varchar);
REQUIRE(id.str().empty());
REQUIRE_FALSE(id.is_valid());
}
TEST_CASE("identifier assignment from const char*", "[utils][identifier][assign]") {
identifier id;
id = "world";
REQUIRE(id.type() == basic_type::Varchar);
REQUIRE(id.str() == "world");
REQUIRE(id.is_varchar());
REQUIRE(id.is_valid());
id = static_cast<const char*>(nullptr);
REQUIRE(id.type() == basic_type::Varchar);
REQUIRE(id.str().empty());
REQUIRE_FALSE(id.is_valid());
}
TEST_CASE("identifier assignment from nullptr", "[utils][identifier][assign]") {
identifier id{42};
REQUIRE(id.is_valid());
REQUIRE_FALSE(id.is_null());
id = nullptr;
REQUIRE(id.is_null());
REQUIRE(id.type() == basic_type::Null);
REQUIRE(id.str() == "null");
REQUIRE_FALSE(id.is_valid());
}
TEST_CASE("identifier reassignment between types", "[utils][identifier][assign]") {
identifier id{uint64_t{7}};
REQUIRE(id.is_integer());
REQUIRE(id.str() == "7");
id = std::string{"abc"};
REQUIRE(id.is_varchar());
REQUIRE(id.str() == "abc");
REQUIRE(id.is_valid());
id = int64_t{99};
REQUIRE(id.is_integer());
REQUIRE(id.str() == "99");
REQUIRE(id.is_valid());
id = nullptr;
REQUIRE(id.is_null());
REQUIRE(id.str() == "null");
}
TEST_CASE("identifier as() returns exact integer type", "[utils][identifier][as]") {
identifier id{int32_t{42}};
const auto as_i32 = id.as<int32_t>();
REQUIRE(as_i32.is_ok());
REQUIRE(*as_i32 == 42);
const auto as_i64 = id.as<int64_t>();
REQUIRE(as_i64.is_error());
}
TEST_CASE("identifier as() returns exact string type", "[utils][identifier][as]") {
identifier id{std::string{"hello"}};
const auto as_string = id.as<std::string>();
REQUIRE(as_string.is_ok());
REQUIRE(*as_string == "hello");
const auto as_i32 = id.as<int32_t>();
REQUIRE(as_i32.is_error());
}
TEST_CASE("identifier as() returns null type failure for null identifier", "[utils][identifier][as]") {
identifier id{nullptr};
const auto as_i32 = id.as<int32_t>();
REQUIRE(as_i32.is_error());
const auto as_string = id.as<std::string>();
REQUIRE(as_string.is_error());
}
TEST_CASE("identifier convert() converts between integer types", "[utils][identifier][convert]") {
identifier id{int32_t{123}};
const auto as_i64 = id.convert<int64_t>();
REQUIRE(as_i64.is_ok());
REQUIRE(*as_i64 == 123);
const auto as_u8 = id.convert<uint8_t>();
REQUIRE(as_u8.is_ok());
REQUIRE(*as_u8 == 123);
}
TEST_CASE("identifier convert() rejects out of range integer conversion", "[utils][identifier][convert]") {
identifier id{int32_t{300}};
const auto as_u8 = id.convert<uint8_t>();
REQUIRE(as_u8.is_error());
}
TEST_CASE("identifier convert() rejects negative to unsigned conversion", "[utils][identifier][convert]") {
identifier id{int32_t{-1}};
const auto as_u32 = id.convert<uint32_t>();
REQUIRE(as_u32.is_error());
}
TEST_CASE("identifier convert() rejects non-integer source types", "[utils][identifier][convert]") {
identifier id{std::string{"123"}};
const auto as_i32 = id.convert<int32_t>();
REQUIRE(as_i32.is_error());
identifier null_id{nullptr};
const auto null_to_i64 = null_id.convert<int64_t>();
REQUIRE(null_to_i64.is_error());
}
TEST_CASE("identifier convert() works with unsigned integer sources", "[utils][identifier][convert]") {
identifier id{uint16_t{500}};
const auto as_i32 = id.convert<int32_t>();
REQUIRE(as_i32.is_ok());
REQUIRE(*as_i32 == 500);
const auto as_u8 = id.convert<uint8_t>();
REQUIRE(as_u8.is_error());
}
TEST_CASE("identifier as() and convert() behave consistently for same integer type", "[utils][identifier][as][convert]") {
identifier id{uint64_t{77}};
const auto as_u64 = id.as<uint64_t>();
REQUIRE(as_u64.is_ok());
REQUIRE(*as_u64 == 77);
const auto conv_u64 = id.convert<uint64_t>();
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");
}
} }

View File

@ -1,68 +0,0 @@
#include <catch2/catch_test_macros.hpp>
#include "matador/utils/identifier.hpp"
#include "matador/utils/primary_key_accessor.hpp"
#include "../test/models/person.hpp"
TEST_CASE("primary_key_accessor detects unset primary key", "[utils][primary_key_accessor]") {
using namespace matador;
utils::primary_key_accessor accessor;
test::person p{};
REQUIRE_FALSE(accessor.is_set(p));
}
TEST_CASE("primary_key_accessor detects set primary key", "[utils][primary_key_accessor]") {
using namespace matador;
utils::primary_key_accessor accessor;
test::person p{};
p.id = 42;
REQUIRE(accessor.is_set(p));
}
TEST_CASE("primary_key_accessor gets integer primary key", "[utils][primary_key_accessor]") {
using namespace matador;
utils::primary_key_accessor accessor;
test::person p{};
p.id = 17;
const auto pk = accessor.get(p);
REQUIRE(pk.is_integer());
REQUIRE(pk.is_valid());
REQUIRE(pk.as<unsigned int>().is_ok());
REQUIRE(*pk.as<unsigned int>() == 17u);
}
TEST_CASE("primary_key_accessor sets integer primary key", "[utils][primary_key_accessor]") {
using namespace matador;
utils::primary_key_accessor accessor;
test::person p{};
accessor.set(p, utils::identifier{123u});
REQUIRE(p.id == 123u);
REQUIRE(accessor.is_set(p));
}
TEST_CASE("primary_key_accessor can round-trip primary key value", "[utils][primary_key_accessor]") {
using namespace matador;
utils::primary_key_accessor accessor;
test::person original{};
original.id = 88u;
const auto pk = accessor.get(original);
test::person copy{};
accessor.set(copy, pk);
REQUIRE(copy.id == 88u);
REQUIRE(accessor.is_set(copy));
}

View File

@ -14,7 +14,7 @@ struct coordinate {
namespace matador::access { namespace matador::access {
template<class Operator> template<class Operator>
void attribute(Operator &op, const char *id, test::coordinate &value, const utils::field_attributes &attr = utils::NullAttributes) { void attribute(Operator &op, const char *id, test::coordinate &value, const utils::field_attributes &attr = utils::null_attributes) {
attribute(op, (std::string(id) + "_x").c_str(), value.x, attr); attribute(op, (std::string(id) + "_x").c_str(), value.x, attr);
attribute(op, (std::string(id) + "_y").c_str(), value.y, attr); attribute(op, (std::string(id) + "_y").c_str(), value.y, attr);
attribute(op, (std::string(id) + "_z").c_str(), value.z, attr); attribute(op, (std::string(id) + "_z").c_str(), value.z, attr);

View File

@ -12,8 +12,6 @@
#include "../backend/test_backend_service.hpp" #include "../backend/test_backend_service.hpp"
#include "../../models/author.hpp"
#include "../../models/book.hpp"
#include "../../models/airplane.hpp" #include "../../models/airplane.hpp"
#include "../../models/flight.hpp" #include "../../models/flight.hpp"
@ -34,8 +32,8 @@ TEST_CASE("insert query builder test", "[query][insert_query_builder]") {
insert_query_builder iqb(scm); insert_query_builder iqb(scm);
const auto a380 = make_object<airplane>(1, "Boeing", "A380" ); const auto a380 = object_ptr(std::make_shared<airplane>(1, "Boeing", "A380" ));
auto build_result = iqb.build(a380); auto build_result = iqb.build<airplane>(a380);
REQUIRE(build_result.is_ok()); REQUIRE(build_result.is_ok());
const auto& stmts = *build_result; const auto& stmts = *build_result;
@ -47,30 +45,3 @@ TEST_CASE("insert query builder test", "[query][insert_query_builder]") {
const auto sql = std::get<executable_query>(step.query).str(db); const auto sql = std::get<executable_query>(step.query).str(db);
REQUIRE(sql == R"(INSERT INTO "airplanes" ("id", "brand", "model") VALUES (1, 'Boeing', 'A380'))"); REQUIRE(sql == R"(INSERT INTO "airplanes" ("id", "brand", "model") VALUES (1, 'Boeing', 'A380'))");
} }
TEST_CASE("Test insert builder has many", "[query][insert_query_builder][has_many]") {
using namespace matador::test;
backend_provider::instance().register_backend("noop", std::make_unique<orm::test_backend_service>());
connection db("noop://noop.db");
schema scm;
const auto result = scm.attach<book>("books")
.and_then( [&scm] { return scm.attach<author>("authors"); } );
REQUIRE(result.is_ok());
auto s_king = make_object<author>(1, "Steven", "King", "21.9.1947", 1956, false);
s_king->books.push_back(make_object<book>(2, "Carrie", object_ptr<author>{}, 1974));
s_king->books.push_back(make_object<book>(3, "The Shining", object_ptr<author>{}, 1977));
s_king->books.push_back(make_object<book>(4, "It", object_ptr<author>{}, 1986));
s_king->books.push_back(make_object<book>(5, "Misery", object_ptr<author>{}, 1987));
s_king->books.push_back(make_object<book>(6, "The Dark Tower: The Gunslinger", object_ptr<author>{}, 1982));
insert_query_builder iqb(scm);
auto build_result = iqb.build(s_king);
REQUIRE(build_result.is_ok());
const auto& stmts = *build_result;
REQUIRE(stmts.size() == 1);
}