#ifndef QUERY_COLUMN_DEFINITION_GENERATOR_HPP #define QUERY_COLUMN_DEFINITION_GENERATOR_HPP #include "matador/object/attribute.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 "matador/utils/identifier.hpp" #include "matador/utils/primary_key_attribute.hpp" #include "matador/utils/result.hpp" #include #include #include namespace matador::object { class repository; class fk_attribute_generator { public: fk_attribute_generator() = default; template attribute generate(const char *id, Type &x) { access::process(*this, x); return attribute{id, type_, {utils::constraints::ForeignKey }, null_option_type::NOT_NULL}; } template void on_primary_key(const char *, ValueType &/*pk*/, const utils::primary_key_attribute& attr = utils::default_pk_attributes) { type_ = utils::data_type_traits::type(attr.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_generator final { private: attribute_generator(std::vector &columns, const repository &repo, object &obj); public: ~attribute_generator() = default; template < class Type > static std::vector generate(const repository &repo, object &obj) { Type t; return generate(t, repo, obj); } template < class Type > static std::vector generate(const Type& t, const repository &repo, object &obj) { std::vector columns; attribute_generator gen(columns, repo, obj); access::process(gen, t); return columns; } template < class Type > 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); 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 static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} template void on_foreign_key(const char *id, Pointer &x) { attribute* ref_column; std::type_index ti = typeid(typename Pointer::value_type); if (auto result = determine_foreign_ref(std::type_index(ti))) { ref_column = *result; } else { ref_column = nullptr; 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)); } else { columns_.push_back(fk_column_generator_.generate(id, *x)); } } 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 determine_foreign_ref(const std::type_index &ti) const; void insert_missing_reference_column(const std::type_index &ti, attribute* ref_column) const; template attribute &emplace_attribute(const char *id, const utils::field_attributes& attr, null_option_type null_option) { auto &ref = columns_.emplace_back(id, utils::data_type_traits::type(attr.size()), attr, null_option); ref.owner_ = &obj_; return ref; } void prepare_primary_key(attribute &ref, utils::identifier &&pk) const; private: size_t index_ = 0; std::vector &columns_; const repository &repo_; object &obj_; fk_attribute_generator fk_column_generator_; }; template void attribute_generator::on_primary_key(const char *id, ValueType &x, const utils::primary_key_attribute& attr) { auto &ref = emplace_attribute(id, { attr.size(), utils::constraints::PrimaryKey }, null_option_type::NOT_NULL); prepare_primary_key(ref, utils::identifier(x)); } template void attribute_generator::on_attribute(const char *id, Type &/*x*/, const utils::field_attributes &attr) { std::ignore = emplace_attribute(id, attr, null_option_type::NOT_NULL); } template void attribute_generator::on_attribute(const char *id, std::optional & /*x*/, const utils::field_attributes &attr) { std::ignore = emplace_attribute(id, attr, null_option_type::NULLABLE); } } #endif //QUERY_COLUMN_DEFINITION_GENERATOR_HPP