/* * 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. * */ #include "model.h" namespace morm { Model::Model() { model_connector = nullptr; model_env = nullptr; save_mode = DO_INSERT_ON_SAVE; } Model::Model(const Model & m) { model_connector = m.model_connector; save_mode = m.save_mode; model_env = m.model_env; // or just set to null? } Model::~Model() { } void Model::set_save_mode(SaveMode save_mode) { this->save_mode = save_mode; } Model::SaveMode Model::get_save_mode() { return save_mode; } void Model::mark_to_delete() { save_mode = DO_DELETE_ON_SAVE; } void Model::mark_to_remove() { save_mode = DO_DELETE_ON_SAVE; } void Model::mark_to_insert() { save_mode = DO_INSERT_ON_SAVE; } void Model::mark_to_update() { save_mode = DO_UPDATE_ON_SAVE; } void Model::table_name(PT::TextStream & stream) { } void Model::set_connector(ModelConnector & connector) { set_connector(&connector); } void Model::set_connector(ModelConnector * connector) { model_connector = connector; } bool Model::object_exists() { return save_mode == DO_UPDATE_ON_SAVE; } bool Model::found() { return save_mode == DO_UPDATE_ON_SAVE; } void Model::to_text(PT::TextStream & stream, ModelData * model_data, bool clear_stream) { if( clear_stream ) { stream.clear(); } ModelEnv model_env_local; model_env = &model_env_local; model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING; if( model_connector ) { FlatConnector * flat_connector = model_connector->get_flat_connector(); if( flat_connector ) { model_env->model_data = model_data; flat_connector->to_text(stream, *this); model_env->model_data = nullptr; } } // what about if an exception was thrown? this pointer will not be null model_env = nullptr; } void Model::to_text(PT::TextStream & stream, ModelData & model_data, bool clear_stream) { to_text(stream, &model_data, clear_stream); } void Model::to_text(PT::TextStream & stream, bool clear_stream) { to_text(stream, nullptr, clear_stream); } void Model::to_text(std::string & str, ModelData * model_data, bool clear_string) { if( model_connector ) { // CHECK ME what if the stream is being used by something other? PT::TextStream * out_stream = model_connector->get_stream(); if( out_stream ) { to_text(*out_stream, model_data, true); out_stream->to_string(str, clear_string); } } } void Model::to_text(std::string & str, ModelData & model_data, bool clear_string) { to_text(str, &model_data, clear_string); } void Model::to_text(std::string & str, bool clear_string) { to_text(str, nullptr, clear_string); } std::string Model::to_text() { std::string str; to_text(str, false); return str; } std::string Model::to_string() { return to_text(); } void Model::generate_insert_query(PT::TextStream & stream, ModelData * model_data) { ModelEnv model_env_local; model_env = &model_env_local; model_env->model_data = model_data; model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL; if( model_connector ) { DbConnector * db_connector = model_connector->get_db_connector(); if( db_connector ) { db_connector->generate_insert_query(stream, *this); } } // what about if an exception was thrown? this pointer will not be null model_env = nullptr; } bool Model::insert(ModelData * model_data, bool insert_whole_tree) { ModelEnv model_env_local; model_env = &model_env_local; model_env->model_data = model_data; bool status = insert_tree(insert_whole_tree); // what about if an exception was thrown? this pointer will not be null model_env = nullptr; return status; } // has ModelEnv set bool Model::insert_tree(bool insert_whole_tree) { bool result = false; if( insert_whole_tree ) { model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_ITERATE_THROUGH_CHILDS_AND_INSERT; map_fields(); } if( model_connector ) { model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL; DbConnector * db_connector = model_connector->get_db_connector(); // CHECK ME what if the stream is being used by something other? PT::TextStream * out_stream = model_connector->get_stream(); if( db_connector && out_stream ) { before_insert(); out_stream->clear(); result = db_connector->insert(*out_stream, *this); if( result ) { save_mode = DO_UPDATE_ON_SAVE; // IMPROVE ME check if there is a primary key after_insert(); set_parent_key_in_childs(); } else { after_insert_failure(); } } } if( insert_whole_tree ) { model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_ITERATE_THROUGH_CHILDS_AND_INSERT_XXX; map_fields(); } return result; } bool Model::insert(ModelData & model_data, bool insert_whole_tree) { return insert(&model_data, insert_whole_tree); } void Model::generate_update_query(PT::TextStream & stream, ModelData * model_data) { ModelEnv model_env_local; model_env = &model_env_local; model_env->model_data = model_data; model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL; if( model_connector ) { DbConnector * db_connector = model_connector->get_db_connector(); if( db_connector ) { db_connector->generate_update_query(stream, *this); } } // what about if an exception was thrown? this pointer will not be null model_env = nullptr; } bool Model::update(ModelData * model_data) { bool result = false; if( model_connector ) { ModelEnv model_env_local; model_env = &model_env_local; model_env->model_data = model_data; model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL; DbConnector * db_connector = model_connector->get_db_connector(); // CHECK ME what if the stream is being used by something other? PT::TextStream * out_stream = model_connector->get_stream(); if( db_connector && out_stream ) { before_update(); out_stream->clear(); result = db_connector->update(*out_stream, *this); if( result ) after_update(); else after_update_failure(); } // what about if an exception was thrown? this pointer will not be null model_env = nullptr; } return result; } bool Model::update(ModelData & model_data) { return update(&model_data); } void Model::generate_remove_query(PT::TextStream & stream, ModelData * model_data) { ModelEnv model_env_local; model_env = &model_env_local; model_env->model_data = model_data; model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL; if( model_connector ) { DbConnector * db_connector = model_connector->get_db_connector(); if( db_connector ) { db_connector->generate_remove_query(stream, *this); } } // what about if an exception was thrown? this pointer will not be null model_env = nullptr; } bool Model::remove(ModelData * model_data) { bool result = false; if( model_connector ) { ModelEnv model_env_local; model_env = &model_env_local; model_env->model_data = model_data; model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL; DbConnector * db_connector = model_connector->get_db_connector(); // CHECK ME what if the stream is being used by something other? PT::TextStream * out_stream = model_connector->get_stream(); if( db_connector && out_stream ) { before_remove(); out_stream->clear(); result = db_connector->remove(*out_stream, *this); if( result ) { save_mode = DO_INSERT_ON_SAVE; after_remove(); } else { after_remove_failure(); } } // what about if an exception was thrown? this pointer will not be null model_env = nullptr; } return result; } bool Model::remove(ModelData & model_data) { return remove(&model_data); } bool Model::save(ModelData * model_data) { bool result = false; switch( save_mode ) { case DO_DELETE_ON_SAVE: result = remove(model_data); break; case DO_INSERT_ON_SAVE: result = insert(model_data); break; case DO_UPDATE_ON_SAVE: result = update(model_data); break; case DO_NOTHING_ON_SAVE: result = true; break; } return result; } bool Model::save(ModelData & model_data) { return save(&model_data); } void Model::generate_select_columns(PT::TextStream & stream) { if( model_connector && model_env ) { model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL; DbConnector * db_connector = model_connector->get_db_connector(); if( db_connector ) { db_connector->generate_select_columns(stream, *this); } } } void Model::generate_doc_for_flat(PT::TextStream & stream, bool clear_stream) { if( clear_stream ) { stream.clear(); } model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DOC_FOR_FLAT; if( model_connector ) { FlatConnector * flat_connector = model_connector->get_doc_connector(); // different connector will be here if( flat_connector ) { flat_connector->to_text(stream, *this); } } model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE; } void Model::generate_doc_for_db(PT::TextStream & stream, bool clear_stream) { if( clear_stream ) { stream.clear(); } model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DOC_FOR_DB; if( model_connector ) { FlatConnector * flat_connector = model_connector->get_doc_connector(); // different connector will be here if( flat_connector ) { flat_connector->to_text(stream, *this); } } model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE; } void Model::map_values_from_query() { if( model_env ) { model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB_RESULTSET; map_fields(); model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE; } } void Model::clear() { ModelEnv model_env_local; model_env = &model_env_local; model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE; map_fields(); model_env = nullptr; save_mode = DO_INSERT_ON_SAVE; } void Model::before_select() { } void Model::before_insert() { } void Model::before_update() { } void Model::before_remove() { } void Model::after_select() { } void Model::after_insert() { } void Model::after_update() { } void Model::after_remove() { } void Model::after_select_failure() { } void Model::after_insert_failure() { } void Model::after_update_failure() { } void Model::after_remove_failure() { } int Model::get_connector_mode() { if( model_env ) { return model_env->model_connector_mode; } else { return MORM_MODEL_CONNECTOR_MODE_NONE; } } ModelData * Model::get_model_data() { if( model_env ) { return model_env->model_data; } else { return nullptr; } } bool Model::is_empty_field(const wchar_t * value) { return (!value || *value == '\0'); } bool Model::is_the_same_field(const wchar_t * field1, const wchar_t * field2) { if( !field1 && !field2 ) return true; if( !field1 || !field2 ) return false; bool the_same = false; while( *field1 && *field2 ) { field1 += 1; field2 += 1; } if( *field1 == 0 && *field2 == 0 ) { the_same = true; } return the_same; } } // namespace