#ifndef MATADOR_GENERATOR_HPP #define MATADOR_GENERATOR_HPP #include #include #include #include #include "matador/object/repository.hpp" #include "matador/query/fk_value_extractor.hpp" #include "matador/query/internal/column_value_pair.hpp" #include "matador/query/table.hpp" #include namespace matador::query::generator { enum class column_generator_options { None = 0, GenerateAlias = 1 << 0, ForceLazy = 1 << 1 }; // template // class enum_flags { // public: // explicit enum_flags(EnumType value) : value_(value) {} // // operator EnumType() const { return value_; } // // enum_flags operator|=(EnumType other) { value_ |= other; return *this; } // enum_flags operator&=(EnumType other) { value_ |= other; return *this; }) // private: // EnumType value_; // }; inline column_generator_options operator|(column_generator_options a, column_generator_options b) { return static_cast(static_cast(a) | static_cast(b)); } inline column_generator_options operator&(column_generator_options a, column_generator_options b) { return static_cast(static_cast(a) & static_cast(b)); } inline column_generator_options& operator|= (column_generator_options& a, column_generator_options b) { return reinterpret_cast(reinterpret_cast(a) |= static_cast(b)); } inline column_generator_options& operator&= (column_generator_options& a, column_generator_options b) { return reinterpret_cast(reinterpret_cast(a) &= static_cast(b)); } inline bool is_column_generator_option_set(const column_generator_options source, const column_generator_options needle) { return static_cast(source & needle) > 0; } constexpr auto default_column_generator_options = column_generator_options::ForceLazy; class column_generator { public: explicit column_generator(const std::string &table_name = "", column_generator_options options = default_column_generator_options); explicit column_generator(const object::repository &repo, const std::string &table_name = "", column_generator_options options = default_column_generator_options); template< class Type > std::vector generate() { Type obj; return generate(obj); } template< class Type > std::vector generate(const Type &obj) { result_.clear(); access::process(*this, obj); return result_; } template < class V > void on_primary_key(const char *id, V &, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) { push(id); } void on_revision(const char *id, uint64_t &/*rev*/); template void on_attribute(const char *id, Type &, const utils::field_attributes &/*attr*/ = utils::null_attributes) { push(id); } template void on_belongs_to(const char *id, Pointer &x, const utils::foreign_attributes &attr) { on_foreign_key(id, x, attr); } template void on_has_one(const char *id, Pointer &x, const utils::foreign_attributes &attr) { on_foreign_key(id, x, attr); } template void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &attr) { if (attr.fetch() == utils::fetch_type::Lazy || is_column_generator_option_set(options_, column_generator_options::ForceLazy)) { return; } if (!repo_) { return; } const auto info = repo_->get().info(); if (!info) { return; } if (seen_tables.count(info->get().name()) == 0) { auto it = seen_tables.insert(info->get().name()).first; table_stack_.push(std::make_shared(info.value().get().name())); typename ContainerType::value_type::value_type obj; access::process(*this, obj); table_stack_.pop(); seen_tables.erase(it); } } template 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) { if (attr.fetch() == utils::fetch_type::Lazy || is_column_generator_option_set(options_, column_generator_options::ForceLazy)) { return; } push(join_column); push(inverse_join_column); } template static void on_has_many_to_many(const char * /*id*/, ContainerType & /*cont*/, const utils::foreign_attributes &/*attr*/) {} private: template void on_foreign_key(const char *id, Pointer &, const utils::foreign_attributes &attr) { if (attr.fetch() == utils::fetch_type::Lazy || is_column_generator_option_set(options_, column_generator_options::ForceLazy)) { push(id); } else { if (!repo_) { return; } const auto info = repo_->get().info(); if (!info) { return; } if (seen_tables.count(info->get().name()) == 0) { auto it = seen_tables.insert(info->get().name()).first; table_stack_.push(std::make_shared
(info.value().get().name())); typename Pointer::value_type obj; access::process(*this, obj); table_stack_.pop(); seen_tables.erase(it); } } } void push(const std::string &column_name); private: std::optional> repo_; std::vector result_; std::stack> table_stack_; std::unordered_set seen_tables; int column_index{0}; column_generator_options options_{false}; }; class placeholder_generator final { public: template< class Type > std::vector generate() { Type obj; return generate(obj); } template< class Type > std::vector generate(const Type &obj) { result_.clear(); access::process(*this, obj); return result_; } template < class V > void on_primary_key(const char * /*id*/, V &/*x*/, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) { result_.emplace_back(utils::_); } 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) { result_.emplace_back(utils::_); } template class Pointer> void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) { result_.emplace_back(utils::_); } template class Pointer> void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) { result_.emplace_back(utils::_); } 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 *, ContainerType &, const char *, const char *, const utils::foreign_attributes &/*attr*/) {} template static void on_has_many_to_many(const char *, ContainerType &, const utils::foreign_attributes &/*attr*/) {} private: std::vector result_; }; enum class column_value_generator_options { None = 0, ValuesAsPlaceHolder = 1 << 0 }; inline column_value_generator_options operator|(column_value_generator_options a, column_value_generator_options b) { return static_cast(static_cast(a) | static_cast(b)); } inline column_value_generator_options operator&(column_value_generator_options a, column_value_generator_options b) { return static_cast(static_cast(a) & static_cast(b)); } inline column_value_generator_options& operator|= (column_value_generator_options& a, column_value_generator_options b) { return reinterpret_cast(reinterpret_cast(a) |= static_cast(b)); } inline column_value_generator_options& operator&= (column_value_generator_options& a, column_value_generator_options b) { return reinterpret_cast(reinterpret_cast(a) &= static_cast(b)); } inline bool is_column_value_generator_option_set(const column_value_generator_options source, const column_value_generator_options needle) { return static_cast(source & needle) > 0; } class column_value_generator final { public: explicit column_value_generator(column_value_generator_options options = column_value_generator_options::None); template< class Type > std::vector generate() { Type obj; return generate(obj); } template< class Type > std::vector generate(const Type &obj) { result_.clear(); access::process(*this, obj); return result_; } template < class V > void on_primary_key(const char *id, V &x, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) { push_back(id, x); } 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) { push_back(id, x); } template class Pointer> void on_belongs_to(const char *id, Pointer &x, const utils::foreign_attributes &/*attr*/) { push_back(id, fk_value_extractor_.extract(*x)); } template class Pointer> void on_has_one(const char *id, Pointer &x, const utils::foreign_attributes &/*attr*/) { push_back(id, fk_value_extractor_.extract(*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 *, ContainerType &, const char *, const char *, const utils::foreign_attributes &/*attr*/) {} template static void on_has_many_to_many(const char *, ContainerType &, const utils::foreign_attributes &/*attr*/) {} template void push_back(const char* id, const Type& value) { if (is_column_value_generator_option_set(options_, column_value_generator_options::ValuesAsPlaceHolder)) { result_.emplace_back(id, utils::_); } else { result_.emplace_back(id, value); } } private: detail::fk_value_extractor fk_value_extractor_{}; std::vector result_; column_value_generator_options options_{column_value_generator_options::None}; }; template std::vector placeholders() { placeholder_generator generator; return generator.generate(); } template std::vector placeholders(const Type &obj) { placeholder_generator generator; return generator.generate(obj); } template std::vector column_value_pairs(const Type &obj, const column_value_generator_options options = column_value_generator_options::None) { column_value_generator generator(options); return generator.generate(obj); } template std::vector column_value_pairs() { Type obj; return column_value_pairs(obj, column_value_generator_options::ValuesAsPlaceHolder); } template std::vector columns(const object::repository &repo, const std::string &table_name = "", const column_generator_options options = default_column_generator_options) { column_generator generator(repo, table_name, options); return generator.generate(); } template std::vector columns(const object::repository &repo, const column_generator_options options) { std::string table_name; if (const auto result = repo.info()) { table_name = result.value().get().name(); } column_generator generator(repo, table_name, options); return generator.generate(); } template std::vector columns(const Type &obj, const object::repository &repo, const std::string &table_name = "", const column_generator_options options = default_column_generator_options) { column_generator generator(repo, table_name, options); return generator.generate(obj); } template std::vector columns(const std::string &table_name = "", const column_generator_options options = default_column_generator_options) { column_generator generator(table_name, options); return generator.generate(); } template std::vector columns(const Type &obj, const std::string &table_name = "", const column_generator_options options = default_column_generator_options) { column_generator generator(table_name, options); return generator.generate(obj); } } #endif //MATADOR_GENERATOR_HPP