/* * This file is a part of morm * and is distributed under the 2-Clause BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2018, 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_modelconnector #define headerfile_morm_modelconnector #include "baseexpression.h" #include "dbconnector.h" #include "flatexpression.h" #include "flatconnector.h" #include "logger/logger.h" namespace morm { class Model; template class Finder; class ModelConnector { public: ModelConnector(); virtual ~ModelConnector(); virtual void set_logger(PT::Logger * logger); virtual void set_logger(PT::Logger & logger); // FIX ME // add c-copy ctr (allocate a new stream and expression) virtual bool was_db_error(); virtual std::wstring get_db_error(); virtual void set_stream(PT::TextStream & stream); virtual PT::TextStream * get_stream(); virtual void set_flat_connector(FlatConnector & flat_connector); virtual void set_db_connector(DbConnector & db_connector); virtual DbConnector * get_db_connector(); virtual void set_db_expression_output_type(int output_type); virtual void to_text(PT::TextStream & stream, Model & model); virtual void generate_select_columns(PT::TextStream & stream, Model & model, const std::wstring & column_prefix); virtual void generate_insert_query(PT::TextStream & stream, Model & model); virtual void generate_update_query(PT::TextStream & stream, Model & model); virtual void generate_remove_query(PT::TextStream & stream, Model & model); virtual bool insert(Model & model); virtual bool update(Model & model); virtual bool remove(Model & model); virtual void map_values_from_query(Model & model); virtual void clear_values(Model & model); template void clear_values(std::list & list) { list.clear(); } virtual void set_connector_for_childs(Model & model); // template // Finder & find() // { // allocate_default_stream_if_needed(); // return Finder(this); // } protected: PT::Logger * logger; FlatConnector * flat_connector; DbConnector * db_connector; PT::TextStream * out_stream; // IMPROVE ME give here an interface to the base stream (implement him) bool out_stream_allocated; //BaseExpression * expression_callback; //DbConnector * db_connector_callback; void allocate_default_stream(); void allocate_default_stream_if_needed(); void deallocate_stream(); 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, int model_connector_mode) { if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING && 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); } } if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL && 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); } } if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB_RESULTSET && db_connector ) { if( !is_empty_field(db_field_name) ) db_connector->get_value_by_field_name(db_field_name, field_value); } if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE && db_connector ) { // IMPROVE ME those clearing should be moved to a better place db_connector->clear_value(field_value); } } /* template void field(const PT::TextStream & db_field_name, const PT::TextStream & flat_field_name, FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key) { std::wstring db_field, flat_field; // field() methods from model connector can be called recursively, so don't make it as class objects db_field_name.to_string(db_field); flat_field_name.to_string(flat_field); field(db_field.c_str(), flat_field.c_str(), field_value, insertable, updatable, is_primary_key); } */ template //void field_list(const wchar_t * field_name, std::list & field_list, bool insertable = true, bool updatable = true, bool is_primary_key = false) void field_list(const wchar_t * db_field_name, const wchar_t * flat_field_name, std::list & field_list, bool insertable, bool updatable, bool is_primary_key, int model_connector_mode) { // IMPLEMENTME what about db? if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING && flat_connector ) { FlatExpression * flat_expression = flat_connector->get_expression(); if( flat_expression && !is_empty_field(flat_field_name) ) { flat_expression->field_list(flat_field_name, field_list, insertable, updatable, is_primary_key, model_connector_mode); } } if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE ) { field_list.clear(); } if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_SETTING_CONNECTOR_FOR_CHILDS ) { // IMPROVE ME // it would be better to set the connector when an operation is needed } } template //void field_model(const wchar_t * field_name, ModelClass & field_model, bool insertable = true, bool updatable = true, bool is_primary_key = false) void field_model(const wchar_t * db_field_name, const wchar_t * flat_field_name, ModelClass & field_model, bool insertable, bool updatable, bool is_primary_key, int model_connector_mode) { // IMPLEMENTME what about db? if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING && flat_connector ) { FlatExpression * flat_expression = flat_connector->get_expression(); if( flat_expression && !is_empty_field(flat_field_name) ) { field_model.model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING; flat_expression->field_model(flat_field_name, field_model, insertable, updatable, is_primary_key); field_model.model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE; } } if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE ) { field_model.clear(); } if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_SETTING_CONNECTOR_FOR_CHILDS ) { field_model.set_connector(this); } } template void add_field_for_select(const wchar_t * new_column_expression, const wchar_t * new_column_name, FieldValue & field_value, int model_connector_mode) { if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL && 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); } } } template void get_last_sequence(const wchar_t * sequence_table_name, FieldValue & field_value) { if( db_connector && !is_empty_field(sequence_table_name) ) { db_connector->get_last_sequence(sequence_table_name, field_value); } } virtual bool is_empty_field(const wchar_t * value); /* * Model is using field() method */ friend class Model; template friend class Finder; }; } #endif