#ifndef SESSION_INSERT_BUILDER_HPP #define SESSION_INSERT_BUILDER_HPP #include "matador/orm/query_builder_exception.hpp" #include "matador/query/condition.hpp" #include "matador/query/query_intermediates.hpp" #include "matador/object/repository.hpp" #include "matador/utils/cascade_type.hpp" #include "matador/utils/primary_key_attribute.hpp" namespace matador::orm { struct entity_insert_data { sql::table table; std::vector columns; std::vector values; }; enum class insert_build_error : std::uint8_t { Ok = 0, UnknownType, MissingPrimaryKey, UnexpectedError }; class insert_builder_exception final : public std::exception { public: explicit insert_builder_exception(const insert_build_error error) : error_(error) { } [[nodiscard]] insert_build_error error() const { return error_; } private: const insert_build_error error_; }; class session_insert_builder final { public: explicit session_insert_builder(const object::repository &scm) : schema_(scm) { } template utils::result, insert_build_error> build(const EntityType &obj) { auto info = schema_.info(); if (!info) { return utils::failure(insert_build_error::UnknownType); } table_info_stack_.push({info.value()}); entity_insert_data_ = {{sql::table{info.value().get().name()}}}; // processed_tables_.insert({info->get().name(), entity_insert_data_.root_table}); try { access::process(*this, obj); return {utils::ok(std::move(entity_insert_data_))}; } catch (const insert_builder_exception &ex) { return {utils::failure(ex.error())}; } catch (...) { return {utils::failure(insert_build_error::UnexpectedError)}; } } template void on_primary_key(const char *id, V &x, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) { push(id, x); } void on_revision(const char *id, unsigned long long &/*rev*/); template void on_attribute(const char *id, Type &x, const utils::field_attributes &/*attr*/ = utils::null_attributes) { push(id, x); } template void on_belongs_to(const char *id, Pointer &obj, const utils::foreign_attributes &attr) { if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::INSERT)) { return; } const auto info = schema_.info(); if (!info) { throw query_builder_exception{query_build_error::UnknownType}; } } template void on_has_one(const char *id, Pointer &obj, const utils::foreign_attributes &attr) { if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::INSERT)) { return; } const auto info = schema_.info(); if (!info) { throw query_builder_exception{query_build_error::UnknownType}; } } template void on_has_many(const char * /*id*/, ContainerType &, const char *join_column, const utils::foreign_attributes &attr) { } 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) { } template void on_has_many_to_many(const char *id, ContainerType &/*cont*/, const utils::foreign_attributes &attr) { } private: void push(const std::string &column_name, const utils::database_type &value); private: struct table_info { std::reference_wrapper info; }; std::stack table_info_stack_; std::unordered_map > processed_tables_; const object::repository &schema_; std::vector entity_insert_data_; }; } #endif //SESSION_INSERT_BUILDER_HPP