#pragma once #include #include "../../types.h" #include "../attributes/attributes.h" namespace cpphibernate { namespace mariadb { struct table_t; struct data_context; struct create_update_context; struct read_context; using read_context_ptr_u = std::unique_ptr; /** * @brief Abstract field class. */ struct field_t { public: size_t id { 0 }; //!< unique id of the field size_t value_id { 0 }; //!< unique id of the value type size_t real_value_id { 0 }; //!< unique id of the real/unwrapped value type bool value_is_nullable { false }; //!< value is stored in a nullable container bool value_is_pointer { false }; //!< value is stored in a pointer container bool value_is_container { false }; //!< value is stored in a container bool value_is_ordered { false }; //!< value is stored in a ordered container (vector, list, ...) bool value_is_auto_incremented { false }; //!< value is a auto incremented field const table_t& table; //!< table this field belongs to const table_t* referenced_table { nullptr }; //!< table that belongs to the value (if exists) std::string name; //!< name of the SQL field std::string type; //!< SQL type name std::string create_arguments; //!< additional arguments for CREATE TABLE command std::string convert_to_open; //!< SQL code to open the "convert to" operation std::string convert_to_close; //!< SQL code to close the "convert to" operation std::string convert_from_open; //!< SQL code to open the "convert from" operation std::string convert_from_close; //!< SQL code to close the "convert from" operation attributes_t attributes; //!< attributes for the field public: /** * @brief Value constructor. Creates a mariadb field from the cpphibernate field. * * @param[in] p_owner Owner of the field. * @param[in] p_schema Cpphibernate schema the mariadb field belongs to. * @param[in] p_table Cpphibernate table the mariadb field belongs to. * @param[in] p_field Cpphibernate field to create mariadb field for. */ template< typename T_schema, typename T_table, typename T_field> inline field_t( const table_t& p_owner, const T_schema& p_schema, const T_table& p_table, const T_field& p_field); /** * @brief Move constructor. */ inline field_t(field_t&& other) = delete; /** * @brief Copy constructor. */ inline field_t(const field_t&) = delete; /** * @brief Destructor. */ virtual ~field_t() = 0; /** * @brief Print the field values to the passed stream. */ std::ostream& print(std::ostream& os) const; public: /** * @brief Get the value of this field from the current dataset. * * @param[in] context Data context to get the dataset from. * * @return Value of the field from the current dataset. */ virtual value_t get(const data_context& context) const; /** * @brief Set a new value of this field in the current dataset. * * @param[in] context Data context to get the dataset from. * @param[in] value Value of the field to assign to the dataset. */ virtual void set(const data_context& context, const value_t& value) const; /** * @brief Check if the value that is represented by this field has the default value. * * @param[in] context Data context to receive the value of the assigned dataset. * * @retval true If the dataset in the context is the default value for this field. * @retval false If the dataset in the context is not the default value for this field. */ virtual bool is_default(const data_context& context) const; /** * @brief Create a new value that is represented by this field. * * @param[in] connection Connection to use to create the value. * * @return New created value for this field. */ virtual std::string generate_value(::cppmariadb::connection& connection) const; public: /** * @brief Execute a create/update operation on the foreign table this field represents (if it is a foreign field) * * @param[in] context Create/Update context with the needed data for the operation. * * @return Key of the created/updated foreign dataset. */ virtual value_t foreign_create_update(const create_update_context& context) const; /** * @brief Create a read context for the foreign key field. * * @param[in] context Read context to inherit new context from. * @param[in] create_fake Create a fake context (not data will be written). * * @return The created read context. */ virtual read_context_ptr_u foreign_read(const read_context& context, bool create_fake) const; /** * @brief Delete all old datasets from the foreign table. * * If we update an exsisting foreign field with a new foreign dataset, the key of this dataset * changes. So we need to delete the old/exsisting foreign dataset from the database. * * @param[in] context Create/Update context with the needed data for the operation. * @param[in] primary_key Primary key of the current database. * @param[in] foreign_key Primary kes of the new foreign dataset. */ void foreign_one_delete( const create_update_context& context, const std::string& primary_key, const value_t& foreign_key) const; /** * @brief Update the foreign dataset. Set the foreign key field to NULL if it matches the passed * primary key of the owner dataset. */ void foreign_many_update( const create_update_context& context, const std::string& primary_key) const; private: /** * @brief Initialize the field. */ void init(); private: using statement_ptr_u = std::unique_ptr<::cppmariadb::statement>; mutable statement_ptr_u _statement_foreign_one_delete_key_known; //!< Statement to delete foreign datasets within an update operation (for known foreign keys) mutable statement_ptr_u _statement_foreign_one_delete_key_unknown; //!< Statement to delete foreign datasets within an update operation (for unknown foreign keys) mutable statement_ptr_u _statement_foreign_many_update; //!< Statement to update foreign many dataset (set foreign key to NULL if primary key of the owner matches) /** * @brief Get the statement to delete foreign datasets within an update operation (for known foreign keys). */ ::cppmariadb::statement& get_statement_foreign_one_delete_key_known() const; /** * @brief Get the statement to delete foreign datasets within an update operation (for unknown foreign keys). */ ::cppmariadb::statement& get_statement_foreign_one_delete_key_unknown() const; /** * @brief Get the statement to update foreign many dataset (set foreign key to NULL if primary key of the owner matches). */ ::cppmariadb::statement& get_statement_foreign_many_update() const; }; using field_ptr_u = std::unique_ptr; namespace __impl { /** * @brief Helper type to build table. */ template struct field_builder; } /** * @brief Predicate to create mariadb table class. */ constexpr decltype(auto) make_field = mp::generic_predicate<__impl::field_builder> { }; } }