#ifndef QUERY_ENTITY_QUERY_BUILDER_HPP #define QUERY_ENTITY_QUERY_BUILDER_HPP #include "matador/sql/connection.hpp" #include "matador/sql/condition.hpp" #include "matador/sql/query_context.hpp" #include "matador/sql/query.hpp" #include "matador/sql/query_intermediates.hpp" #include "matador/sql/value.hpp" #include namespace matador::sql { struct join_data { table join_table; std::unique_ptr condition; }; struct entity_query_data { std::string root_table_name; std::vector columns; std::vector joins; std::unique_ptr where_clause; }; class entity_query_builder { public: explicit entity_query_builder(const schema &scm) : schema_(scm) {} template std::optional build(const PrimaryKeyType &pk) { const auto info = schema_.info(); if (!info) { return std::nullopt; } pk_ = pk; table_info_stack_.push(info.value()); entity_query_data_ = { info->name }; EntityType obj; matador::utils::access::process(*this, obj); return std::move(entity_query_data_); } template < class V > void on_primary_key(const char *id, V &, typename std::enable_if::value && !std::is_same::value>::type* = 0) { push(id); if (is_root_entity() && pk_.is_integer()) { entity_query_data_.where_clause = make_condition(column{table_info_stack_.top().name, id, ""} == *pk_.as()); } } void on_primary_key(const char *id, std::string &, size_t); void on_revision(const char *id, unsigned long long &/*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 &, const utils::foreign_attributes &attr) { if (attr.fetch() == utils::fetch_type::EAGER) { const auto info = schema_.info(); if (!info) { return; } table_info_stack_.push(info.value()); typename Pointer::value_type obj; matador::utils::access::process(*this , obj); table_info_stack_.pop(); auto pk = info->prototype.primary_key(); if (!pk) { // error, prototype doesn't has a pk return; } append_join({table_info_stack_.top().name, id}, {info->name, pk->name()}); } else { push(id); } } template void on_has_one(const char *id, Pointer &, const utils::foreign_attributes &attr) { if (attr.fetch() == utils::fetch_type::EAGER) { const auto info = schema_.info(); if (!info) { return; } table_info_stack_.push(info.value()); typename Pointer::value_type obj; matador::utils::access::process(*this, obj); table_info_stack_.pop(); auto pk = info->prototype.primary_key(); if (!pk) { // error, prototype doesn't has a pk return; } append_join({table_info_stack_.top().name, id}, {info->name, pk->name()}); } else { push(id); } } template void on_has_many(ContainerType &, const char *join_column, const utils::foreign_attributes &attr) { if (attr.fetch() == utils::fetch_type::EAGER) { const auto info = schema_.info(); if (!info) { return; } table_info_stack_.push(info.value()); typename ContainerType::value_type::value_type obj; matador::utils::access::process(*this , obj); table_info_stack_.pop(); auto pk = info->prototype.primary_key(); if (!pk) { // error, prototype doesn't has a pk return; } append_join({table_info_stack_.top().name, table_info_stack_.top().prototype.primary_key()->name()}, {info->name, join_column}); } } template void on_has_many_to_many(const char *id, ContainerType &c, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &attr) { if (attr.fetch() == utils::fetch_type::EAGER) { const auto info = schema_.info(); if (!info) { return; } table_info_stack_.push(info.value()); typename ContainerType::value_type::value_type obj; matador::utils::access::process(*this , obj); table_info_stack_.pop(); auto pk = info->prototype.primary_key(); if (!pk) { // error, prototype doesn't has a pk return; } append_join({table_info_stack_.top().name, table_info_stack_.top().prototype.primary_key()->name()}, {id, join_column}); append_join({info->name, pk->name()}, {id, inverse_join_column}); } } template void on_has_many_to_many(const char *id, ContainerType &c, const utils::foreign_attributes &/*attr*/) {} private: void push(const std::string &column_name); [[nodiscard]] bool is_root_entity() const; void append_join(const column &left, const column &right); private: value pk_; std::stack table_info_stack_; const schema &schema_; entity_query_data entity_query_data_; int column_index{0}; }; } #endif //QUERY_ENTITY_QUERY_BUILDER_HPP