/* * This file is a part of morm * and is distributed under the 2-Clause BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2018-2019, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #ifndef headerfile_morm_model #define headerfile_morm_model #include #include #include #include "textstream/textstream.h" #include "modelconnector.h" #include "dbexpression.h" #include "flatexpression.h" #include "modelenv.h" namespace morm { class Model { public: enum SaveMode { DO_INSERT_ON_SAVE, DO_UPDATE_ON_SAVE, DO_DELETE_ON_SAVE, DO_NOTHING_ON_SAVE, }; virtual void set_save_mode(SaveMode save_mode); virtual SaveMode get_save_mode(); virtual void mark_to_delete(); virtual void mark_to_remove(); virtual void mark_to_insert(); virtual void mark_to_update(); virtual bool object_exists(); virtual bool found(); void set_connector(ModelConnector & connector); void set_connector(ModelConnector * connector); /* * map fields to names * * */ virtual void map_fields() = 0; virtual void map_doc_fields() {} ; /* * * we can use the object for a different purpose than database (e.g. json) * so let the table_name be non pure-virtual * */ virtual void table_name(PT::TextStream & stream); virtual void to_text(PT::TextStream & stream, ModelData * model_data, bool clear_stream = true); virtual void to_text(PT::TextStream & stream, ModelData & model_data, bool clear_stream = true); virtual void to_text(PT::TextStream & stream, bool clear_stream = true); virtual void to_text(std::string & str, ModelData * model_data, bool clear_string = true); virtual void to_text(std::string & str, ModelData & model_data, bool clear_string = true); virtual void to_text(std::string & str, bool clear_string = true); virtual std::string to_text(); virtual std::string to_string(); virtual void generate_insert_query(PT::TextStream & stream, ModelData * model_data = nullptr); virtual bool insert(ModelData * model_data = nullptr, bool insert_whole_tree = true); virtual bool insert(ModelData & model_data, bool insert_whole_tree = true); virtual void generate_update_query(PT::TextStream & stream, ModelData * model_data = nullptr); virtual bool update(ModelData * model_data = nullptr); virtual bool update(ModelData & model_data); virtual void generate_remove_query(PT::TextStream & stream, ModelData * model_data = nullptr); virtual bool remove(ModelData * model_data = nullptr); virtual bool remove(ModelData & model_data); virtual bool save(ModelData * model_data = nullptr); virtual bool save(ModelData & model_data); virtual void generate_select_columns(PT::TextStream & stream); virtual void generate_doc_for_flat(PT::TextStream & stream, bool clear_stream = true); virtual void generate_doc_for_db(PT::TextStream & stream, bool clear_stream = true); // set object to default values virtual void clear(); // IMPROVE ME this will be protected // add set_field_value() functions for each POD type template void set_field_value_generic(const wchar_t * db_field_name, const wchar_t * flat_field_name, const FieldValue & field_value) { ModelEnv model_env_local; model_env = &model_env_local; model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_SET_FIELD_VALUE; model_env->field_index = 0; SetFieldValueHelper set_field_value_helper; FieldValueContainer helper_object(field_value); set_field_value_helper.add(db_field_name, flat_field_name, &helper_object, false); model_env->set_field_value_helper = &set_field_value_helper; map_fields(); // what if an exception was thrown? model_env = nullptr; } protected: ModelConnector * model_connector; SaveMode save_mode; ModelEnv * model_env; Model(); Model(const Model & m); virtual ~Model(); virtual void before_select(); virtual void before_insert(); virtual void before_update(); virtual void before_remove(); virtual void after_select(); virtual void after_insert(); virtual void after_update(); virtual void after_remove(); virtual void after_select_failure(); virtual void after_insert_failure(); virtual void after_update_failure(); virtual void after_remove_failure(); virtual int get_connector_mode(); virtual ModelData * get_model_data(); virtual bool insert_tree(bool insert_whole_tree); virtual void map_values_from_query(); ///////////////////////////////// void field(const wchar_t * field_name, char & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * field_name, unsigned char & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * field_name, std::wstring & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); } // void field(const wchar_t * field_name, wchar_t * field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) // { // field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); // } void field(const wchar_t * field_name, std::string & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); } // void field(const wchar_t * field_name, char * field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) // { // field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); // } void field(const wchar_t * field_name, bool & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * field_name, short & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * field_name, unsigned short & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * field_name, int & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * field_name, unsigned int & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * field_name, long & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * field_name, unsigned long & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * field_name, long long & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * field_name, unsigned long long & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * field_name, float & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * field_name, double & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * field_name, long double & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); } // void field(const wchar_t * field_name, void * field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) // { // field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); // } void field(const wchar_t * field_name, PT::Date & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * field_name, Model & field_value, bool insertable = true, bool updatable = true, bool has_foreign_key = true) { field_model(field_name, field_name, field_value, insertable, updatable, has_foreign_key); } template void field(const wchar_t * field_name, std::list & field_value, bool insertable = true, bool updatable = true) { ModelClass * list_model_null_pointer = nullptr; field_list(field_name, field_name, field_value, list_model_null_pointer, insertable, updatable); } template void field(const wchar_t * field_name, std::vector & field_value, bool insertable = true, bool updatable = true) { ModelClass * list_model_null_pointer = nullptr; field_list(field_name, field_name, field_value, list_model_null_pointer, insertable, updatable); } ////////////////////// void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, char & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, unsigned char & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, std::wstring & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); } // void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, wchar_t * field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) // { // field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); // } void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, std::string & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); } // void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, char * field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) // { // field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); // } void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, bool & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, short & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, unsigned short & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, int & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, unsigned int & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, long & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, unsigned long & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, long long & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, unsigned long long & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, float & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, double & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, long double & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); } // void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, void * field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) // { // field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); // } void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, PT::Date & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); } void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_value, bool insertable = true, bool updatable = true, bool has_foreign_key = true) { field_model(db_field_name, flat_field_name, field_value, insertable, updatable, has_foreign_key); } template void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, std::list & field_value, bool insertable = true, bool updatable = true) { ModelClass * list_model_null_pointer = nullptr; field_list(db_field_name, flat_field_name, field_value, list_model_null_pointer, insertable, updatable); } template void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, std::vector & field_value, bool insertable = true, bool updatable = true) { ModelClass * list_model_null_pointer = nullptr; field_list(db_field_name, flat_field_name, field_value, list_model_null_pointer, insertable, updatable); } ////////////////////// void doc(const wchar_t * field_name, char & field_value) { doc_field_generic(field_name, field_name, field_value); } void doc(const wchar_t * field_name, unsigned char & field_value) { doc_field_generic(field_name, field_name, field_value); } void doc(const wchar_t * field_name, std::wstring & field_value) { doc_field_generic(field_name, field_name, field_value); } // void doc(const wchar_t * field_name, wchar_t * field_value) // { // doc_field_generic(field_name, field_name, field_value); // } void doc(const wchar_t * field_name, std::string & field_value) { doc_field_generic(field_name, field_name, field_value); } // void doc(const wchar_t * field_name, char * field_value) // { // doc_field_generic(field_name, field_name, field_value); // } void doc(const wchar_t * field_name, bool & field_value) { doc_field_generic(field_name, field_name, field_value); } void doc(const wchar_t * field_name, short & field_value) { doc_field_generic(field_name, field_name, field_value); } void doc(const wchar_t * field_name, unsigned short & field_value) { doc_field_generic(field_name, field_name, field_value); } void doc(const wchar_t * field_name, int & field_value) { doc_field_generic(field_name, field_name, field_value); } void doc(const wchar_t * field_name, unsigned int & field_value) { doc_field_generic(field_name, field_name, field_value); } void doc(const wchar_t * field_name, long & field_value) { doc_field_generic(field_name, field_name, field_value); } void doc(const wchar_t * field_name, unsigned long & field_value) { doc_field_generic(field_name, field_name, field_value); } void doc(const wchar_t * field_name, long long & field_value) { doc_field_generic(field_name, field_name, field_value); } void doc(const wchar_t * field_name, unsigned long long & field_value) { doc_field_generic(field_name, field_name, field_value); } void doc(const wchar_t * field_name, float & field_value) { doc_field_generic(field_name, field_name, field_value); } void doc(const wchar_t * field_name, double & field_value) { doc_field_generic(field_name, field_name, field_value); } void doc(const wchar_t * field_name, long double & field_value) { doc_field_generic(field_name, field_name, field_value); } // void doc(const wchar_t * field_name, void * field_value) // { // doc_field_generic(field_name, field_name, field_value); // } void doc(const wchar_t * field_name, PT::Date & field_value) { doc_field_generic(field_name, field_name, field_value); } void doc(const wchar_t * field_name, Model & field_value) { doc_field_model(field_name, field_name, field_value); } template void doc(const wchar_t * field_name, std::list & field_value) { doc_field_list(field_name, field_name, field_value); } ////////////////////// void doc(const wchar_t * db_field_name, const wchar_t * flat_field_name, char & field_value) { doc_field_generic(db_field_name, flat_field_name, field_value); } void doc(const wchar_t * db_field_name, const wchar_t * flat_field_name, unsigned char & field_value) { doc_field_generic(db_field_name, flat_field_name, field_value); } void doc(const wchar_t * db_field_name, const wchar_t * flat_field_name, std::wstring & field_value) { doc_field_generic(db_field_name, flat_field_name, field_value); } // void doc(const wchar_t * db_field_name, const wchar_t * flat_field_name, wchar_t * field_value) // { // doc_field_generic(db_field_name, flat_field_name, field_value); // } void doc(const wchar_t * db_field_name, const wchar_t * flat_field_name, std::string & field_value) { doc_field_generic(db_field_name, flat_field_name, field_value); } // void doc(const wchar_t * db_field_name, const wchar_t * flat_field_name, char * field_value) // { // doc_field_generic(db_field_name, flat_field_name, field_value); // } void doc(const wchar_t * db_field_name, const wchar_t * flat_field_name, bool & field_value) { doc_field_generic(db_field_name, flat_field_name, field_value); } void doc(const wchar_t * db_field_name, const wchar_t * flat_field_name, short & field_value) { doc_field_generic(db_field_name, flat_field_name, field_value); } void doc(const wchar_t * db_field_name, const wchar_t * flat_field_name, unsigned short & field_value) { doc_field_generic(db_field_name, flat_field_name, field_value); } void doc(const wchar_t * db_field_name, const wchar_t * flat_field_name, int & field_value) { doc_field_generic(db_field_name, flat_field_name, field_value); } void doc(const wchar_t * db_field_name, const wchar_t * flat_field_name, unsigned int & field_value) { doc_field_generic(db_field_name, flat_field_name, field_value); } void doc(const wchar_t * db_field_name, const wchar_t * flat_field_name, long & field_value) { doc_field_generic(db_field_name, flat_field_name, field_value); } void doc(const wchar_t * db_field_name, const wchar_t * flat_field_name, unsigned long & field_value) { doc_field_generic(db_field_name, flat_field_name, field_value); } void doc(const wchar_t * db_field_name, const wchar_t * flat_field_name, long long & field_value) { doc_field_generic(db_field_name, flat_field_name, field_value); } void doc(const wchar_t * db_field_name, const wchar_t * flat_field_name, unsigned long long & field_value) { doc_field_generic(db_field_name, flat_field_name, field_value); } void doc(const wchar_t * db_field_name, const wchar_t * flat_field_name, float & field_value) { doc_field_generic(db_field_name, flat_field_name, field_value); } void doc(const wchar_t * db_field_name, const wchar_t * flat_field_name, double & field_value) { doc_field_generic(db_field_name, flat_field_name, field_value); } void doc(const wchar_t * db_field_name, const wchar_t * flat_field_name, long double & field_value) { doc_field_generic(db_field_name, flat_field_name, field_value); } // void doc(const wchar_t * db_field_name, const wchar_t * flat_field_name, void * field_value) // { // doc_field_generic(db_field_name, flat_field_name, field_value); // } void doc(const wchar_t * db_field_name, const wchar_t * flat_field_name, PT::Date & field_value) { doc_field_generic(db_field_name, flat_field_name, field_value); } void doc(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_value) { doc_field_model(db_field_name, flat_field_name, field_value); } template void doc(const wchar_t * db_field_name, const wchar_t * flat_field_name, std::list & field_value) { doc_field_list(db_field_name, flat_field_name, field_value); } ////////////////////// protected: template void field_generic(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key) { if( model_connector && model_env ) { if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_SET_FIELD_VALUE ) { if( model_env->set_field_value_helper ) { if( model_env->field_index >= 0 && (size_t)model_env->field_index < model_env->set_field_value_helper->size() ) { if( is_the_same_field(db_field_name, model_env->set_field_value_helper->get_db_field_name(model_env->field_index)) && is_the_same_field(flat_field_name, model_env->set_field_value_helper->get_flat_field_name(model_env->field_index)) ) { model_env->set_field_value_helper->set_value(model_env->field_index, field_value); model_env->field_index += 1; } } else { // IMPROVE ME // put some log here } } } if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_ITERATE_PRIMARY_KEY_VALUES && is_primary_key ) { if( model_env->set_field_value_helper ) { if( model_env->field_index >= 0 && (size_t)model_env->field_index < model_env->set_field_value_helper->size() ) { FieldValueBase * helper_object = new FieldValueContainer(field_value); model_env->set_field_value_helper->add_field_value_container(model_env->field_index, helper_object, true); } else { // IMPROVE ME // put some log here } } model_env->field_index += 1; } if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING ) { FlatConnector * flat_connector = model_connector->get_flat_connector(); if( flat_connector ) { FlatExpression * flat_expression = flat_connector->get_expression(); if( flat_expression && !is_empty_field(flat_field_name) ) { // insertable, updatable and is_primary_key are ignored here flat_expression->field(flat_field_name, field_value, insertable, updatable, is_primary_key, model_env); } } } if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL ) { DbConnector * db_connector = model_connector->get_db_connector(); if( db_connector ) { DbExpression * db_expression = db_connector->get_expression(); if( db_expression && !is_empty_field(db_field_name) ) { db_expression->field(db_field_name, field_value, insertable, updatable, is_primary_key, model_env); } } } if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB_RESULTSET ) { DbConnector * db_connector = model_connector->get_db_connector(); if( db_connector ) { if( !is_empty_field(db_field_name) ) { if( model_env->model_data && model_env->cursor_helper && model_env->cursor_helper->has_autogenerated_select ) { get_value_by_field_index(model_env->cursor_helper->current_column, field_value); model_env->cursor_helper->current_column += 1; } else { get_value_by_field_name(db_field_name, field_value); } } } } if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE ) { Clearer * clearer = model_connector->get_clearer(); if( clearer ) { clearer->clear_value(field_value); } } if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DOC_FOR_FLAT ) { FlatConnector * doc_connector = model_connector->get_doc_connector(); // different connector will be here (doc, flat) if( doc_connector ) { FlatExpression * doc_expression = doc_connector->get_expression(); // potrzebujemy dwa rozne doce, jeden dla flat drugi dla bazy danych if( doc_expression && !is_empty_field(flat_field_name) ) { // insertable, updatable and is_primary_key are ignored here doc_expression->field_doc(*this, flat_field_name, field_value, insertable, updatable, is_primary_key, model_env); } } } } } void field_model_left_join(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_model, bool insertable, bool updatable, bool has_foreign_key, DbExpression * db_expression) { if( model_env && field_model.model_env && model_env->finder_helper ) { model_env->finder_helper->foreign_keys.clear(); field_model.model_env->table_index = model_env->finder_helper->add_join_table(field_model.model_env->table_name_short); model_env->finder_helper->join_tables_str << "LEFT JOIN " << field_model.model_env->table_name << " AS " << field_model.model_env->table_name_short; if( field_model.model_env->table_index > 1 ) model_env->finder_helper->join_tables_str << field_model.model_env->table_index; int expr_work_mode = db_expression->get_work_mode(); int expr_output_type = db_expression->get_output_type(); bool expr_allow_prefix = db_expression->get_allow_to_use_prefix(); db_expression->set_work_mode(MORM_WORK_MODE_MODEL_SAVE_FIELDS); db_expression->set_output_type(MORM_OUTPUT_TYPE_JOIN_TABLES); db_expression->allow_to_use_prefix(false); if( has_foreign_key ) { field_model.map_fields(); model_env->finder_helper->join_tables_str << " ON " << model_env->table_name_short << '.' << db_field_name << " = " << field_model.model_env->table_name_short << '.'; if( model_env->finder_helper->foreign_keys.size() == 1 ) { model_env->finder_helper->join_tables_str << model_env->finder_helper->foreign_keys.front(); } } else { map_fields(); model_env->finder_helper->join_tables_str << " ON " << model_env->table_name_short << '.'; if( model_env->finder_helper->foreign_keys.size() == 1 ) { model_env->finder_helper->join_tables_str << model_env->finder_helper->foreign_keys.front(); } model_env->finder_helper->join_tables_str << " = " << field_model.model_env->table_name_short << '.' << db_field_name; } model_env->finder_helper->join_tables_str << ' '; db_expression->set_work_mode(expr_work_mode); db_expression->set_output_type(expr_output_type); db_expression->allow_to_use_prefix(expr_allow_prefix); } } void field_model_generate_flat_string(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_model, bool insertable, bool updatable) { FlatConnector * flat_connector = model_connector->get_flat_connector(); if( flat_connector ) { FlatExpression * flat_expression = flat_connector->get_expression(); if( flat_expression && !is_empty_field(flat_field_name) ) { field_model.model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING; flat_expression->field_model(flat_field_name, field_model, insertable, updatable, false, model_env); } } } void field_model_generate_db_sql(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_model, bool insertable, bool updatable, bool has_foreign_key) { DbConnector * db_connector = model_connector->get_db_connector(); if( db_connector ) { DbExpression * db_expression = db_connector->get_expression(); if( db_expression && !is_empty_field(db_field_name) ) { field_model.model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL; field_model.table_name(field_model.model_env->table_name); db_expression->prepare_short_table_name(field_model.model_env->table_name, field_model.model_env->table_name_short); if( db_expression->get_output_type() == MORM_OUTPUT_TYPE_SELECT_COLUMNS ) { field_model_left_join(db_field_name, flat_field_name, field_model, insertable, updatable, has_foreign_key, db_expression); } if( db_expression->get_work_mode() == MORM_WORK_MODE_MODEL_FIELDS && db_expression->get_output_type() == MORM_OUTPUT_TYPE_DB_INSERT && has_foreign_key ) { int not_used_object = 0; db_expression->field(db_field_name, not_used_object, insertable, updatable, false, model_env); } if( db_expression->get_work_mode() == MORM_WORK_MODE_MODEL_VALUES && db_expression->get_output_type() == MORM_OUTPUT_TYPE_DB_INSERT && has_foreign_key ) { db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_INSERT_PRIMARY_KEY); field_model.map_fields(); db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_INSERT); } if( db_expression->get_output_type() != MORM_OUTPUT_TYPE_JOIN_TABLES && db_expression->get_output_type() != MORM_OUTPUT_TYPE_DB_INSERT && db_expression->get_output_type() != MORM_OUTPUT_TYPE_DB_UPDATE ) { // FIX ME // UPDATE, INSERT, REMOVE for models field_model.map_fields(); } field_model.model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE; } } } void field_model_clear_values(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_model, bool insertable, bool updatable, bool has_foreign_key) { Clearer * clearer = model_connector->get_clearer(); if( clearer ) { clearer->clear_model(field_model); } } void field_model_generate_doc_flat(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_model, bool insertable, bool updatable, bool has_foreign_key) { FlatConnector * doc_connector = model_connector->get_doc_connector(); // different connector will be here (doc, flat) if( doc_connector ) { FlatExpression * doc_expression = doc_connector->get_expression(); // potrzebujemy dwa rozne doce, jeden dla flat drugi dla bazy danych if( doc_expression && !is_empty_field(flat_field_name) ) { // insertable, updatable and is_primary_key are ignored here doc_expression->field_doc(*this, flat_field_name, field_model, insertable, updatable, false, model_env); } } } void field_model_read_values_from_queryresult(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_model, bool insertable, bool updatable, bool has_foreign_key) { DbConnector * db_connector = model_connector->get_db_connector(); if( db_connector ) { if( !is_empty_field(db_field_name) ) { // we need to test if the object is actually defined, test nulls on primary key? field_model.before_select(); field_model.set_save_mode(Model::DO_UPDATE_ON_SAVE); // IMPROVE ME check if there is a primary key field_model.map_values_from_query(); field_model.after_select(); } } } void field_model_set_parent_key(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_model) { DbConnector * db_connector = model_connector->get_db_connector(); if( db_connector ) { DbExpression * db_expression = db_connector->get_expression(); if( db_expression && !is_empty_field(db_field_name) ) { int old_connector_mode = model_env->model_connector_mode; model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_ITERATE_PRIMARY_KEY_VALUES; SetFieldValueHelper set_field_value_helper; set_field_value_helper.add(db_field_name, flat_field_name); // in the future we can have a primary key from more than one column model_env->set_field_value_helper = &set_field_value_helper; model_env->field_index = 0; map_fields(); if( set_field_value_helper.empty() ) { // IMPROVE ME // put some log: there is no a primary key in this model } else if( set_field_value_helper.size() == 1 ) { ModelEnv model_env_local; model_env_local.copy_global_objects(*model_env); model_env_local.model_connector_mode = MORM_MODEL_CONNECTOR_MODE_SET_FIELD_VALUE; model_env_local.set_field_value_helper = &set_field_value_helper; model_env_local.field_index = 0; field_model.model_env = &model_env_local; field_model.map_fields(); field_model.model_env = nullptr; model_env->set_field_value_helper = nullptr; model_env->model_connector_mode = old_connector_mode; } else { // IMPROVE ME // put some log: at the moment we only support a primary key from only one column } } } } void field_model(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_model, bool insertable, bool updatable, bool has_foreign_key) { if( model_connector && model_env ) { ModelEnv model_env_local; model_env_local.copy_global_objects(*model_env); field_model.model_env = &model_env_local; field_model.set_connector(model_connector); if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_SET_PARENT_ID && !has_foreign_key ) { field_model_set_parent_key(db_field_name, flat_field_name, field_model); } if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_ITERATE_THROUGH_CHILDS_AND_INSERT && has_foreign_key ) { if( !is_empty_field(db_field_name) ) { field_model.map_fields(); field_model.insert_tree(true); } } if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_ITERATE_THROUGH_CHILDS_AND_INSERT_XXX && !has_foreign_key ) { if( !is_empty_field(db_field_name) ) { field_model.map_fields(); field_model.insert_tree(true); } } if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_ITERATE_THROUGH_CHILDS_AND_UPDATE ) { // IMPROVE ME what about if db_field_name is empty? not iterate in such a case? //field_model.map_fields(); //field_model.update_tree(true); } if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_ITERATE_THROUGH_CHILDS_AND_SAVE ) { // IMPROVE ME what about if db_field_name is empty? not iterate in such a case? //field_model.map_fields(); //field_model.save_tree(true); } if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING ) { field_model_generate_flat_string(db_field_name, flat_field_name, field_model, insertable, updatable); } if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL ) { field_model_generate_db_sql(db_field_name, flat_field_name, field_model, insertable, updatable, has_foreign_key); } if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE ) { field_model_clear_values(db_field_name, flat_field_name, field_model, insertable, updatable, has_foreign_key); } if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DOC_FOR_FLAT ) { field_model_generate_doc_flat(db_field_name, flat_field_name, field_model, insertable, updatable, has_foreign_key); } if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB_RESULTSET ) { field_model_read_values_from_queryresult(db_field_name, flat_field_name, field_model, insertable, updatable, has_foreign_key); } field_model.model_env = nullptr; } } template void field_list(const wchar_t * db_field_name, const wchar_t * flat_field_name, ModelContainer & field_container, ModelContainerType * model_container_type, bool insertable, bool updatable) { if( model_connector && model_env ) { if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING ) { FlatConnector * flat_connector = model_connector->get_flat_connector(); if( flat_connector ) { FlatExpression * flat_expression = flat_connector->get_expression(); if( flat_expression && !is_empty_field(flat_field_name) ) { // IMPROVE ME // what about model_data and save_mode? // may it should be placed inside some structure? flat_expression->field_list(flat_field_name, field_container, insertable, updatable, false, model_connector, model_env); } } } if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL ) { DbConnector * db_connector = model_connector->get_db_connector(); if( db_connector ) { DbExpression * db_expression = db_connector->get_expression(); if( db_expression && !is_empty_field(db_field_name) && db_expression->get_output_type() != MORM_OUTPUT_TYPE_JOIN_TABLES && db_expression->get_output_type() != MORM_OUTPUT_TYPE_DB_INSERT && db_expression->get_output_type() != MORM_OUTPUT_TYPE_DB_UPDATE ) { // another select will be used (from another Finder) // we need only columns name // but columns are defined in the other model // FIX ME // UPDATE, INSERT, REMOVE for lists } } } if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE ) { Clearer * clearer = model_connector->get_clearer(); if( clearer ) { clearer->clear_container(field_container); } } if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DOC_FOR_FLAT ) { FlatConnector * doc_connector = model_connector->get_doc_connector(); // different connector will be here (doc, flat) if( doc_connector ) { FlatExpression * doc_expression = doc_connector->get_expression(); // potrzebujemy dwa rozne doce, jeden dla flat drugi dla bazy danych if( doc_expression && !is_empty_field(flat_field_name) ) { // insertable, updatable and is_primary_key are ignored here doc_expression->field_doc(*this, flat_field_name, field_container, insertable, updatable, false, model_env); } } } } } template void get_value_by_field_index(int field_index, FieldValue & field_value) { if( model_env->cursor_helper && model_env->cursor_helper->query_result ) { const char * val_str = model_env->cursor_helper->query_result->get_field_string_value(field_index); if( val_str ) { DbConnector * db_connector = model_connector->get_db_connector(); if( db_connector ) { db_connector->get_value(val_str, field_value); } } } } template void get_value_by_field_name(const wchar_t * field_name, FieldValue & field_value) { if( model_env->cursor_helper && model_env->cursor_helper->query_result ) { const char * val_str = model_env->cursor_helper->query_result->get_field_string_value(field_name); if( val_str ) { DbConnector * db_connector = model_connector->get_db_connector(); if( db_connector ) { db_connector->get_value(val_str, field_value); } } } } //// template void doc_field_generic(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value) { if( reinterpret_cast(&field_value) == model_env->doc_field_pointer && model_connector ) { FlatConnector * doc_connector = model_connector->get_doc_connector(); if( doc_connector ) { FlatExpression * doc_expression = doc_connector->get_expression(); if( doc_expression ) { PT::TextStream * out_stream = doc_expression->get_current_stream(); if( out_stream ) { (*out_stream) << flat_field_name; } } } } } void doc_field_model(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_model) { if( reinterpret_cast(&field_model) == model_env->doc_field_pointer && model_connector ) { FlatConnector * doc_connector = model_connector->get_doc_connector(); if( doc_connector ) { FlatExpression * doc_expression = doc_connector->get_expression(); if( doc_expression ) { PT::TextStream * out_stream = doc_expression->get_current_stream(); if( out_stream ) { (*out_stream) << flat_field_name; } } } } } template void doc_field_list(const wchar_t * db_field_name, const wchar_t * flat_field_name, ModelContainer & field_container) { if( reinterpret_cast(&field_container) == model_env->doc_field_pointer && model_connector ) { FlatConnector * doc_connector = model_connector->get_doc_connector(); if( doc_connector ) { FlatExpression * doc_expression = doc_connector->get_expression(); if( doc_expression ) { PT::TextStream * out_stream = doc_expression->get_current_stream(); if( out_stream ) { (*out_stream) << flat_field_name; } } } } } virtual void set_parent_key_in_childs() { if( model_env ) { model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_SET_PARENT_ID; map_fields(); } } public: template void get_last_sequence(const wchar_t * sequence_table_name, FieldValue & field_value) { if( model_connector ) { DbConnector * db_connector = model_connector->get_db_connector(); if( db_connector && !is_empty_field(sequence_table_name) ) { db_connector->get_last_sequence(sequence_table_name, field_value); } } } template void add_field_for_select(const wchar_t * new_column_expression, const wchar_t * new_column_name, const wchar_t * flat_field_name, FieldValue & field_value) { if( model_connector ) { if( get_connector_mode() == MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL ) { DbConnector * db_connector = model_connector->get_db_connector(); if( db_connector ) { DbExpression * db_expression = db_connector->get_expression(); if( db_expression && !is_empty_field(new_column_expression) ) { db_expression->add_field_for_select(new_column_expression, new_column_name, field_value); } } } else if( get_connector_mode() == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING ) { field_generic(L"", flat_field_name, field_value, false, false, false); } else if( get_connector_mode() == MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB_RESULTSET ) { field_generic(new_column_name, L"", field_value, false, false, false); } else if( get_connector_mode() == MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE ) { field_generic(L"", L"", field_value, false, false, false); // the names don't matter here } } } template void add_field_for_select(const wchar_t * new_column_expression, const wchar_t * new_column_name, FieldValue & field_value) { add_field_for_select(new_column_expression, new_column_name, new_column_name, field_value); } protected: virtual bool is_empty_field(const wchar_t * value); virtual bool is_the_same_field(const wchar_t * field1, const wchar_t * field2); template friend class Finder; template friend class Cursor; friend class BaseExpression; }; } // namespace #endif