#ifndef QUERY_COLUMN_DEFINITION_GENERATOR_HPP #define QUERY_COLUMN_DEFINITION_GENERATOR_HPP #include "matador/object/attribute_definition.hpp" #include "matador/utils/access.hpp" #include "matador/utils/data_type_traits.hpp" #include "matador/utils/error.hpp" #include "matador/utils/field_attributes.hpp" #include #include #include namespace matador::object { class schema; class fk_attribute_generator { public: fk_attribute_generator() = default; template attribute_definition generate(const char *id, Type &x, const std::shared_ptr &ref_column) { access::process(*this, x); return attribute_definition{id, type_, 0, ref_column, {utils::constraints::FOREIGN_KEY }, null_option::NOT_NULL}; } template void on_primary_key(const char *, ValueType &/*pk*/, std::enable_if_t && !std::is_same_v>* = nullptr) { type_ = utils::data_type_traits::type(0); } void on_primary_key(const char * /*id*/, std::string &/*pk*/, size_t size); static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {} template < class Type > 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*/ = utils::null_attributes) {} template static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} template static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} template static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {} template static void on_has_many_to_many(const char * /*id*/, ContainerType & /*cont*/, const char * /*join_column*/, const char * /*inverse_join_column*/, const utils::foreign_attributes &/*attr*/) {} template static void on_has_many_to_many(const char * /*id*/, ContainerType & /*cont*/, const utils::foreign_attributes &/*attr*/) {} private: utils::basic_type type_{}; }; class attribute_definition_generator final { private: attribute_definition_generator(std::vector &columns, const schema &repo); public: ~attribute_definition_generator() = default; template < class Type > static std::vector generate(const schema &repo) { std::vector columns; attribute_definition_generator gen(columns, repo); Type obj; access::process(gen, obj); return columns; } template < class Type > static std::vector generate(const Type& obj, const schema &repo) { std::vector columns; attribute_definition_generator gen(columns, repo); access::process(gen, obj); return columns; } template < class V > void on_primary_key(const char *, V &x, std::enable_if_t && !std::is_same_v>* = nullptr); void on_primary_key(const char *id, std::string &pk, size_t size); void on_revision(const char *id, uint64_t &rev); template void on_attribute(const char *id, Type &x, const utils::field_attributes &attr = utils::null_attributes); template void on_attribute(const char *id, std::optional &x, const utils::field_attributes &attr = utils::null_attributes); template void on_belongs_to(const char *id, Pointer &x, const utils::foreign_attributes &/*attr*/) { on_foreign_key(id, x); } template void on_has_one(const char *id, Pointer &x, const utils::foreign_attributes &/*attr*/) { on_foreign_key(id, x); } template void on_foreign_key(const char *id, Pointer &x) { std::shared_ptr ref_column; std::type_index ti = typeid(typename Pointer::value_type); if (const auto result = determine_foreign_ref(std::type_index(ti))) { ref_column = *result; } else { ref_column = std::make_shared(); insert_missing_reference_column(ti, ref_column); } if (x.empty()) { typename Pointer::value_type temp_val; columns_.push_back(fk_column_generator_.generate(id, temp_val, ref_column)); } else { columns_.push_back(fk_column_generator_.generate(id, *x, ref_column)); } } template static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {} template static void on_has_many_to_many(const char * /*id*/, ContainerType & /*cont*/, const char * /*join_column*/, const char * /*inverse_join_column*/, const utils::foreign_attributes &/*attr*/) {} template static void on_has_many_to_many(const char * /*id*/, ContainerType & /*cont*/, const utils::foreign_attributes &/*attr*/) {} private: [[nodiscard]] utils::result, utils::error> determine_foreign_ref(const std::type_index &ti) const; void insert_missing_reference_column(const std::type_index &ti, std::shared_ptr ref_column) const; private: size_t index_ = 0; std::vector &columns_; const schema &repo_; fk_attribute_generator fk_column_generator_; }; template void attribute_definition_generator::on_primary_key(const char *id, V &x, std::enable_if_t && !std::is_same_v>*) { on_attribute(id, x, { utils::constraints::PRIMARY_KEY }); } template void attribute_definition_generator::on_attribute(const char *id, Type &x, const utils::field_attributes &attr) { columns_.emplace_back(id, x, attr, null_option::NOT_NULL); } template void attribute_definition_generator::on_attribute(const char *id, std::optional & /*x*/, const utils::field_attributes &attr) { columns_.emplace_back(id, utils::data_type_traits::type(attr.size()), attr, null_option::NULLABLE); } } #endif //QUERY_COLUMN_DEFINITION_GENERATOR_HPP