1361 lines
47 KiB
C++
1361 lines
47 KiB
C++
/*
|
|
* This file is a part of morm
|
|
* and is distributed under the 2-Clause BSD licence.
|
|
* Author: Tomasz Sowa <t.sowa@ttmath.org>
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 2018-2021, 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 <string>
|
|
#include <list>
|
|
#include <vector>
|
|
#include <typeinfo>
|
|
#include <type_traits>
|
|
|
|
#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 = 0,
|
|
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 set_has_primary_key_set(bool has_primary_key);
|
|
virtual bool get_has_primary_key_set();
|
|
|
|
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);
|
|
ModelConnector * get_connector();
|
|
|
|
/*
|
|
* map fields to names
|
|
*
|
|
*
|
|
*/
|
|
virtual void map_fields() = 0;
|
|
|
|
|
|
|
|
/*
|
|
*
|
|
* 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, bool dump_mode = false);
|
|
virtual void to_text(PT::TextStream & stream, ModelData & model_data, bool clear_stream = true, bool dump_mode = false);
|
|
virtual void to_text(PT::TextStream & stream, bool clear_stream = true, bool dump_mode = false);
|
|
|
|
virtual void to_text(std::string & str, ModelData * model_data, bool clear_string = true, bool dump_mode = false);
|
|
virtual void to_text(std::string & str, ModelData & model_data, bool clear_string = true, bool dump_mode = false);
|
|
virtual void to_text(std::string & str, bool clear_string = true, bool dump_mode = false);
|
|
|
|
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, bool insert_whole_tree = true);
|
|
virtual bool insert(ModelData & model_data, bool insert_whole_tree = true);
|
|
virtual bool insert(bool insert_whole_tree = true);
|
|
|
|
virtual void generate_update_query(PT::TextStream & stream, ModelData * model_data = nullptr);
|
|
virtual bool update(ModelData * model_data, bool update_whole_tree = true);
|
|
virtual bool update(ModelData & model_data, bool update_whole_tree = true);
|
|
virtual bool update(bool update_whole_tree = true);
|
|
|
|
virtual void generate_remove_query(PT::TextStream & stream, ModelData * model_data = nullptr);
|
|
virtual bool remove(ModelData * model_data, bool remove_whole_tree = true);
|
|
virtual bool remove(ModelData & model_data, bool remove_whole_tree = true);
|
|
virtual bool remove(bool remove_whole_tree = true);
|
|
|
|
virtual bool save(ModelData * model_data, bool save_whole_tree = true);
|
|
virtual bool save(ModelData & model_data, bool save_whole_tree = true);
|
|
virtual bool save(bool save_whole_tree = true);
|
|
|
|
|
|
virtual void generate_select_columns(PT::TextStream & stream);
|
|
|
|
// set object to default values
|
|
virtual void clear();
|
|
|
|
// IMPROVE ME this will be protected
|
|
// add set_field_value() functions for each POD type
|
|
template<typename FieldValue>
|
|
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_work_mode = MORM_MODEL_WORK_MODE_SET_FIELD_VALUE;
|
|
model_env->field_index = 0;
|
|
|
|
FieldValueHelper field_value_helper;
|
|
field_value_helper.db_field_name = db_field_name;
|
|
field_value_helper.flat_field_name = flat_field_name;
|
|
field_value_helper.value_object = &field_value;
|
|
field_value_helper.value_type_info = &typeid(field_value);
|
|
|
|
std::vector<FieldValueHelper> helper_tab;
|
|
helper_tab.push_back(field_value_helper);
|
|
model_env->field_value_helper_tab = &helper_tab;
|
|
|
|
map_fields();
|
|
|
|
if( !helper_tab.back().found && model_connector )
|
|
{
|
|
PT::Log * plog = model_connector->get_logger();
|
|
|
|
if( plog )
|
|
{
|
|
(*plog) << "Morm: I cannot find such a property: ";
|
|
put_fields_to_log(*plog, db_field_name, flat_field_name);
|
|
(*plog) << PT::Log::logend;
|
|
}
|
|
}
|
|
|
|
// what if an exception was thrown?
|
|
model_env = nullptr;
|
|
}
|
|
|
|
|
|
protected:
|
|
|
|
ModelConnector * model_connector;
|
|
ModelEnv * model_env;
|
|
SaveMode save_mode;
|
|
bool has_primary_key_set;
|
|
|
|
|
|
|
|
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_work_mode();
|
|
|
|
virtual ModelData * get_model_data();
|
|
|
|
virtual bool insert_tree(bool insert_whole_tree);
|
|
virtual bool update_tree(bool update_whole_tree);
|
|
virtual bool remove_tree(bool remove_whole_tree);
|
|
virtual bool save_tree(bool save_whole_tree);
|
|
|
|
virtual void map_values_from_query();
|
|
|
|
|
|
/////////////////////////////////
|
|
/*
|
|
* IMPLEMENT ME
|
|
* field methods for such field_values: signed char, wchar_t, char16_t, char32_t, std::u16string, std::u32string
|
|
*
|
|
*/
|
|
|
|
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<typename ModelClass>
|
|
void field(const wchar_t * field_name, std::list<ModelClass> & 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<typename ModelClass>
|
|
void field(const wchar_t * field_name, std::vector<ModelClass> & 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<typename ModelClass>
|
|
void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, std::list<ModelClass> & 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<typename ModelClass>
|
|
void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, std::vector<ModelClass> & 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);
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
template<typename FieldValue>
|
|
void field_generic_set_field_value(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_env->field_value_helper_tab )
|
|
{
|
|
if( model_env->field_index >= 0 && (size_t)model_env->field_index < model_env->field_value_helper_tab->size() )
|
|
{
|
|
FieldValueHelper & helper = (*model_env->field_value_helper_tab)[model_env->field_index];
|
|
PT::Log * log = model_connector->get_logger();
|
|
|
|
if( (!helper.compare_db_field_name || is_the_same_field(db_field_name, helper.db_field_name)) &&
|
|
(!helper.compare_flat_field_name || is_the_same_field(flat_field_name, helper.flat_field_name)) )
|
|
{
|
|
if( helper.value_object && helper.value_type_info )
|
|
{
|
|
if( typeid(field_value) == *helper.value_type_info )
|
|
{
|
|
field_value = *(FieldValue*)helper.value_object;
|
|
}
|
|
else
|
|
{
|
|
table_name(model_env->table_name);
|
|
|
|
if( log )
|
|
{
|
|
(*log) << PT::Log::log1 << "Morm: incorrect type of a field in " << model_env->table_name << ", ";
|
|
put_fields_to_log(*log, db_field_name, flat_field_name);
|
|
(*log) << ", type expected " << typeid(field_value).name()
|
|
<< " got " << helper.value_type_info->name() << PT::Log::logend;
|
|
}
|
|
}
|
|
}
|
|
|
|
helper.found = true;
|
|
model_env->field_index += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename FieldValue>
|
|
void field_generic_iterate_primary_key_values(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key)
|
|
{
|
|
if( is_primary_key )
|
|
{
|
|
if( model_env->field_value_helper_tab )
|
|
{
|
|
if( model_env->field_index >= 0 && (size_t)model_env->field_index < model_env->field_value_helper_tab->size() )
|
|
{
|
|
FieldValueHelper & helper = (*model_env->field_value_helper_tab)[model_env->field_index];
|
|
helper.value_object = &field_value;
|
|
helper.value_type_info = &typeid(field_value);
|
|
}
|
|
}
|
|
|
|
model_env->field_index += 1;
|
|
}
|
|
}
|
|
|
|
template<typename FieldValue>
|
|
void field_generic_generate_flat_string(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename FieldValue>
|
|
void field_generic_generate_db_sql(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, bool insertable, bool updatable, bool is_primary_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) )
|
|
{
|
|
db_expression->field(db_field_name, field_value, insertable, updatable, is_primary_key, model_env);
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename FieldValue>
|
|
void field_generic_read_value_from_db_resultset(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key)
|
|
{
|
|
DbConnector * db_connector = model_connector->get_db_connector();
|
|
|
|
if( db_connector )
|
|
{
|
|
if( !is_empty_field(db_field_name) )
|
|
{
|
|
if( model_env->cursor_helper && model_env->cursor_helper->has_autogenerated_select )
|
|
{
|
|
get_value_by_field_index(model_env->cursor_helper->current_column, field_value, is_primary_key);
|
|
model_env->cursor_helper->current_column += 1;
|
|
}
|
|
else
|
|
{
|
|
get_value_by_field_name(db_field_name, field_value, is_primary_key);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename FieldValue>
|
|
void field_generic_clear_value(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key)
|
|
{
|
|
Clearer * clearer = model_connector->get_clearer();
|
|
|
|
if( clearer )
|
|
{
|
|
clearer->clear_value(field_value);
|
|
}
|
|
}
|
|
|
|
|
|
template<typename FieldValue>
|
|
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( is_primary_key )
|
|
{
|
|
model_env->was_primary_key_read = true;
|
|
}
|
|
|
|
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_SET_FIELD_VALUE )
|
|
{
|
|
field_generic_set_field_value(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key);
|
|
}
|
|
|
|
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_ITERATE_PRIMARY_KEY_VALUES )
|
|
{
|
|
field_generic_iterate_primary_key_values(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key);
|
|
}
|
|
|
|
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_GENERATING_FLAT_STRING )
|
|
{
|
|
field_generic_generate_flat_string(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key);
|
|
}
|
|
|
|
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_GENERATING_DB_SQL )
|
|
{
|
|
field_generic_generate_db_sql(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key);
|
|
}
|
|
|
|
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_READING_VALUE_FROM_DB_RESULTSET )
|
|
{
|
|
field_generic_read_value_from_db_resultset(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key);
|
|
}
|
|
|
|
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_CLEARING_VALUE )
|
|
{
|
|
field_generic_clear_value(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* IMPROVE ME there can be more rows in the result set when there are more items on the left hand side of the join
|
|
* this is only in a case when has_foreign_key is false, may it can be ignored? we can use unique index in such a case
|
|
*
|
|
*/
|
|
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();
|
|
PT::TextStream & join_tables_str = model_env->finder_helper->join_tables_str;
|
|
field_model.model_env->table_index = model_env->finder_helper->add_join_table(field_model.model_env->table_name_short);
|
|
|
|
join_tables_str << "LEFT JOIN " << field_model.model_env->table_name << " AS ";
|
|
field_model.put_table_name_with_index(join_tables_str);
|
|
|
|
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();
|
|
|
|
join_tables_str << " ON ";
|
|
put_table_name_with_index(join_tables_str);
|
|
join_tables_str << '.' << db_field_name << " = ";
|
|
field_model.put_table_name_with_index(join_tables_str);
|
|
join_tables_str << '.';
|
|
|
|
// IMPROVE ME at the moment support only for foreign keys consisting of only one column
|
|
if( model_env->finder_helper->foreign_keys.size() == 1 )
|
|
{
|
|
join_tables_str << model_env->finder_helper->foreign_keys.front();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ModelEnv * old_model_env = field_model.model_env;
|
|
map_fields(); // map_fields() will set field_model.model_env to null
|
|
field_model.model_env = old_model_env;
|
|
|
|
join_tables_str << " ON ";
|
|
put_table_name_with_index(join_tables_str);
|
|
join_tables_str << '.';
|
|
|
|
// IMPROVE ME at the moment support only for foreign keys consisting of only one column
|
|
if( model_env->finder_helper->foreign_keys.size() == 1 )
|
|
{
|
|
join_tables_str << model_env->finder_helper->foreign_keys.front();
|
|
}
|
|
|
|
join_tables_str << " = ";
|
|
field_model.put_table_name_with_index(join_tables_str);
|
|
join_tables_str << '.' << db_field_name;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* first we iterate through fields and save primary key values to helper_tab
|
|
*/
|
|
void field_model_save_key(const wchar_t * db_field_name)
|
|
{
|
|
DbConnector * db_connector = model_connector->get_db_connector();
|
|
PT::Log * plog = model_connector->get_logger();
|
|
|
|
if( db_connector )
|
|
{
|
|
DbExpression * db_expression = db_connector->get_expression();
|
|
|
|
if( db_expression && !is_empty_field(db_field_name) && model_env->field_value_helper_tab )
|
|
{
|
|
int old_work_mode = model_env->model_work_mode;
|
|
model_env->model_work_mode = MORM_MODEL_WORK_MODE_ITERATE_PRIMARY_KEY_VALUES;
|
|
model_env->field_index = 0;
|
|
map_fields();
|
|
model_env->model_work_mode = old_work_mode;
|
|
|
|
if( model_env->field_value_helper_tab->empty() && plog )
|
|
{
|
|
(*plog) << "Morm: I cannot find a primary key in " << model_env->table_name << PT::Log::logend;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* now we iterate through fields in field_model and save primary key values from *this object to the specified fields in field_model
|
|
*/
|
|
void field_model_set_parent_key_in_child(const wchar_t * db_field_name, Model & field_model)
|
|
{
|
|
DbConnector * db_connector = model_connector->get_db_connector();
|
|
PT::Log * log = model_connector->get_logger();
|
|
|
|
if( db_connector )
|
|
{
|
|
DbExpression * db_expression = db_connector->get_expression();
|
|
|
|
if( db_expression && !is_empty_field(db_field_name) && model_env->field_value_helper_tab )
|
|
{
|
|
std::vector<FieldValueHelper> & helper_tab = *model_env->field_value_helper_tab;
|
|
|
|
if( (size_t)model_env->field_index == helper_tab.size() )
|
|
{
|
|
ModelEnv model_env_local;
|
|
model_env_local.copy_global_objects(*model_env);
|
|
model_env_local.has_primary_key_set = field_model.has_primary_key_set;
|
|
model_env_local.model_work_mode = MORM_MODEL_WORK_MODE_SET_FIELD_VALUE;
|
|
model_env_local.field_value_helper_tab = &helper_tab;
|
|
model_env_local.field_index = 0;
|
|
field_model.model_env = &model_env_local;
|
|
|
|
field_model.map_fields();
|
|
|
|
if( (size_t)field_model.model_env->field_index != helper_tab.size() && log )
|
|
{
|
|
if( model_env->table_name.empty() )
|
|
table_name(model_env->table_name);
|
|
|
|
if( field_model.model_env->table_name.empty() )
|
|
field_model.table_name(field_model.model_env->table_name);
|
|
|
|
(*log) << PT::Log::log1 << "Morm: primary key in " << model_env->table_name << " consists of " << model_env->field_index << " column(s)"
|
|
<< " but in " << field_model.model_env->table_name << " there are only "
|
|
<< field_model.model_env->field_index << " matching column(s)" << PT::Log::logend;
|
|
}
|
|
|
|
field_model.model_env = nullptr;
|
|
}
|
|
else
|
|
if( log )
|
|
{
|
|
table_name(model_env->table_name);
|
|
|
|
(*log) << PT::Log::log1 << "Morm: primary key in " << model_env->table_name << " consists of incorrect number of columns"
|
|
<< ", expected " << helper_tab.size() << " column(s) but got " << model_env->field_index << PT::Log::logend;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void field_model_set_parent_key(const wchar_t * db_field_name, Model & field_model)
|
|
{
|
|
FieldValueHelper helper;
|
|
helper.db_field_name = db_field_name;
|
|
helper.flat_field_name = nullptr;
|
|
helper.compare_flat_field_name = false;
|
|
|
|
std::vector<FieldValueHelper> helper_tab;
|
|
helper_tab.push_back(helper);
|
|
// only one column at the moment, in the future we can have a primary key from more than one column
|
|
|
|
model_env->field_value_helper_tab = &helper_tab;
|
|
|
|
field_model_save_key(db_field_name);
|
|
field_model_set_parent_key_in_child(db_field_name, field_model);
|
|
|
|
model_env->field_value_helper_tab = nullptr;
|
|
}
|
|
|
|
|
|
void field_model_iterate_through_childs(const wchar_t * db_field_name, Model & field_model)
|
|
{
|
|
if( !is_empty_field(db_field_name) )
|
|
{
|
|
if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_INSERT )
|
|
{
|
|
field_model.insert_tree(true);
|
|
}
|
|
|
|
if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_UPDATE )
|
|
{
|
|
field_model.update_tree(true);
|
|
}
|
|
|
|
if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_REMOVE )
|
|
{
|
|
field_model.remove_tree(true);
|
|
}
|
|
|
|
if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_SAVE )
|
|
{
|
|
field_model.save_tree(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
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) )
|
|
{
|
|
if( model_env->dump_mode || field_model.save_mode == DO_INSERT_ON_SAVE || field_model.save_mode == DO_UPDATE_ON_SAVE )
|
|
{
|
|
field_model.model_env->model_work_mode = MORM_MODEL_WORK_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_work_mode = MORM_MODEL_WORK_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( has_foreign_key )
|
|
{
|
|
if( db_expression->get_work_mode() == MORM_WORK_MODE_MODEL_FIELDS && db_expression->get_output_type() == MORM_OUTPUT_TYPE_DB_INSERT )
|
|
{
|
|
if( insertable )
|
|
{
|
|
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 )
|
|
{
|
|
if( insertable )
|
|
{
|
|
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_work_mode() == MORM_WORK_MODE_MODEL_FIELDS_VALUES && db_expression->get_output_type() == MORM_OUTPUT_TYPE_DB_UPDATE )
|
|
{
|
|
if( updatable )
|
|
{
|
|
std::vector<const wchar_t *> key_fields;
|
|
key_fields.push_back(db_field_name); // at the moment only one key
|
|
|
|
db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_UPDATE_PRIMARY_KEY);
|
|
field_model.model_env->field_index = 0;
|
|
field_model.model_env->set_field_name_helper = &key_fields;
|
|
field_model.map_fields();
|
|
db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_UPDATE);
|
|
|
|
if( (size_t)field_model.model_env->field_index != key_fields.size() )
|
|
{
|
|
// IMPROVEME
|
|
// number of keys are different
|
|
// put error log here
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( db_expression->get_output_type() != MORM_OUTPUT_TYPE_JOIN_TABLES &&
|
|
db_expression->get_output_type() != MORM_OUTPUT_TYPE_DB_PRIMARY_KEY &&
|
|
db_expression->get_output_type() != MORM_OUTPUT_TYPE_DB_INSERT &&
|
|
db_expression->get_output_type() != MORM_OUTPUT_TYPE_DB_UPDATE )
|
|
{
|
|
field_model.map_fields();
|
|
}
|
|
|
|
field_model.model_env->model_work_mode = MORM_MODEL_WORK_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_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) )
|
|
{
|
|
DbExpression * db_expression = db_connector->get_expression();
|
|
|
|
if( db_expression )
|
|
{
|
|
if( model_env->cursor_helper &&
|
|
!model_env->cursor_helper->has_autogenerated_select &&
|
|
model_env->cursor_helper->use_table_prefix_for_fetching_values )
|
|
{
|
|
field_model.prepare_table_names();
|
|
}
|
|
|
|
field_model.before_select();
|
|
field_model.map_values_from_query();
|
|
|
|
if( field_model.found() )
|
|
{
|
|
field_model.after_select();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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.model_env->has_primary_key_set = field_model.has_primary_key_set;
|
|
field_model.set_connector(model_connector);
|
|
|
|
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_SET_PARENT_ID )
|
|
{
|
|
if( !has_foreign_key )
|
|
{
|
|
field_model_set_parent_key(db_field_name, field_model);
|
|
}
|
|
}
|
|
|
|
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_ITERATE_THROUGH_CHILDS_WITH_FOREIGN_KEY )
|
|
{
|
|
if( has_foreign_key )
|
|
{
|
|
field_model_iterate_through_childs(db_field_name, field_model);
|
|
}
|
|
}
|
|
|
|
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_ITERATE_THROUGH_CHILDS_WITHOUT_FOREIGN_KEY )
|
|
{
|
|
if( !has_foreign_key )
|
|
{
|
|
field_model_iterate_through_childs(db_field_name, field_model);
|
|
}
|
|
}
|
|
|
|
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_GENERATING_FLAT_STRING )
|
|
{
|
|
field_model_generate_flat_string(db_field_name, flat_field_name, field_model, insertable, updatable);
|
|
}
|
|
|
|
if( model_env->model_work_mode == MORM_MODEL_WORK_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_work_mode == MORM_MODEL_WORK_MODE_CLEARING_VALUE )
|
|
{
|
|
field_model_clear_values(db_field_name, flat_field_name, field_model, insertable, updatable, has_foreign_key);
|
|
}
|
|
|
|
if( model_env->model_work_mode == MORM_MODEL_WORK_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<typename ModelContainer, typename ModelContainerType>
|
|
void field_list_set_parent_key(const wchar_t * db_field_name, ModelContainer & field_container, ModelContainerType * model_container_type)
|
|
{
|
|
FieldValueHelper helper;
|
|
helper.db_field_name = db_field_name;
|
|
helper.flat_field_name = nullptr;
|
|
helper.compare_flat_field_name = false;
|
|
|
|
std::vector<FieldValueHelper> helper_tab;
|
|
helper_tab.push_back(helper);
|
|
// only one column at the moment, in the future we can have a primary key from more than one column
|
|
|
|
model_env->field_value_helper_tab = &helper_tab;
|
|
field_model_save_key(db_field_name);
|
|
|
|
for(ModelContainerType & child_model : field_container)
|
|
{
|
|
child_model.set_connector(model_connector);
|
|
field_model_set_parent_key_in_child(db_field_name, child_model);
|
|
}
|
|
|
|
model_env->field_value_helper_tab = nullptr;
|
|
}
|
|
|
|
|
|
template<typename ModelContainer, typename ModelContainerType>
|
|
void field_list_iterate_through_childs(const wchar_t * db_field_name, ModelContainer & field_container, ModelContainerType * model_container_type)
|
|
{
|
|
if( !is_empty_field(db_field_name) )
|
|
{
|
|
for(ModelContainerType & child_model : field_container)
|
|
{
|
|
ModelEnv model_env_local;
|
|
model_env_local.copy_global_objects(*model_env);
|
|
|
|
child_model.model_env = &model_env_local;
|
|
child_model.model_env->has_primary_key_set = child_model.has_primary_key_set;
|
|
child_model.set_connector(model_connector);
|
|
|
|
if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_INSERT )
|
|
{
|
|
child_model.insert_tree(true);
|
|
}
|
|
|
|
if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_UPDATE )
|
|
{
|
|
child_model.update_tree(true);
|
|
}
|
|
|
|
if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_REMOVE )
|
|
{
|
|
child_model.remove_tree(true);
|
|
}
|
|
|
|
if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_SAVE )
|
|
{
|
|
child_model.save_tree(true);
|
|
}
|
|
|
|
child_model.model_env = nullptr;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
template<typename ModelContainer>
|
|
void field_list_generate_flat_string(const wchar_t * flat_field_name, ModelContainer & field_container, 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) )
|
|
{
|
|
// insertable and updatable will be ignored there
|
|
flat_expression->field_list(flat_field_name, field_container, insertable, updatable, false, model_connector, model_env);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
template<typename ModelContainer>
|
|
void field_list_clearing_values(ModelContainer & field_container)
|
|
{
|
|
Clearer * clearer = model_connector->get_clearer();
|
|
|
|
if( clearer )
|
|
{
|
|
clearer->clear_container(field_container);
|
|
}
|
|
}
|
|
|
|
|
|
template<typename ModelContainer, typename ModelContainerType>
|
|
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( !is_empty_field(db_field_name) )
|
|
{
|
|
if constexpr (std::is_base_of<Model, ModelContainerType>())
|
|
{
|
|
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_SET_PARENT_ID )
|
|
{
|
|
field_list_set_parent_key(db_field_name, field_container, model_container_type);
|
|
}
|
|
|
|
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_ITERATE_THROUGH_CHILDS_WITHOUT_FOREIGN_KEY )
|
|
{
|
|
field_list_iterate_through_childs(db_field_name, field_container, model_container_type);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PT::Log * plog = model_connector->get_logger();
|
|
|
|
if( plog )
|
|
{
|
|
(*plog) << "Morm: ignoring " << db_field_name << " as this is not a container with Model objects" << PT::Log::logend;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_GENERATING_FLAT_STRING )
|
|
{
|
|
field_list_generate_flat_string(flat_field_name, field_container, insertable, updatable);
|
|
}
|
|
|
|
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_CLEARING_VALUE )
|
|
{
|
|
field_list_clearing_values(field_container);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
template<typename FieldValue>
|
|
void get_value_by_field_index(int field_index, FieldValue & field_value, bool is_primary_key)
|
|
{
|
|
DbConnector * db_connector = model_connector->get_db_connector();
|
|
|
|
if( db_connector && model_env->cursor_helper && model_env->cursor_helper->query_result )
|
|
{
|
|
if( !model_env->cursor_helper->query_result->is_null(field_index) )
|
|
{
|
|
const char * val_str = model_env->cursor_helper->query_result->get_field_string_value(field_index);
|
|
|
|
if( val_str )
|
|
{
|
|
db_connector->get_value(val_str, field_value);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( is_primary_key )
|
|
{
|
|
model_env->has_primary_key_set = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
template<typename FieldValue>
|
|
void get_value_by_field_name(const wchar_t * field_name, FieldValue & field_value, bool is_primary_key)
|
|
{
|
|
DbConnector * db_connector = model_connector->get_db_connector();
|
|
|
|
if( db_connector && model_env->cursor_helper && model_env->cursor_helper->query_result )
|
|
{
|
|
int column_index = -1;
|
|
|
|
if( model_env->cursor_helper->use_table_prefix_for_fetching_values && model_env->finder_helper )
|
|
{
|
|
// CHECK what about escaping field names here?
|
|
|
|
std::wstring table_field_name;
|
|
PT::TextStream table_field_name_str;
|
|
|
|
put_table_name_with_index(table_field_name_str);
|
|
table_field_name_str << '.';
|
|
table_field_name_str << field_name;
|
|
table_field_name_str.to_string(table_field_name);
|
|
column_index = model_env->cursor_helper->query_result->get_column_index(table_field_name.c_str());
|
|
}
|
|
else
|
|
{
|
|
column_index = model_env->cursor_helper->query_result->get_column_index(field_name);
|
|
}
|
|
|
|
if( column_index != -1 && !model_env->cursor_helper->query_result->is_null(column_index) )
|
|
{
|
|
const char * val_str = model_env->cursor_helper->query_result->get_field_string_value(column_index);
|
|
|
|
if( val_str )
|
|
{
|
|
db_connector->get_value(val_str, field_value);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( is_primary_key )
|
|
{
|
|
model_env->has_primary_key_set = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
virtual void set_parent_key_in_childs()
|
|
{
|
|
if( model_env )
|
|
{
|
|
model_env->model_work_mode = MORM_MODEL_WORK_MODE_SET_PARENT_ID;
|
|
map_fields();
|
|
}
|
|
}
|
|
|
|
|
|
public:
|
|
|
|
|
|
template<typename FieldValue>
|
|
bool 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) )
|
|
{
|
|
return db_connector->get_last_sequence(sequence_table_name, field_value);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
template<typename FieldValue>
|
|
bool get_last_sequence_for_primary_key(const wchar_t * sequence_table_name, FieldValue & field_value)
|
|
{
|
|
has_primary_key_set = get_last_sequence(sequence_table_name, field_value);
|
|
return has_primary_key_set;
|
|
}
|
|
|
|
|
|
template<typename FieldValue>
|
|
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 && model_env )
|
|
{
|
|
if( model_env->model_work_mode == MORM_MODEL_WORK_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( model_env->model_work_mode == MORM_MODEL_WORK_MODE_GENERATING_FLAT_STRING )
|
|
{
|
|
field_generic(L"", flat_field_name, field_value, false, false, false);
|
|
}
|
|
else
|
|
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_READING_VALUE_FROM_DB_RESULTSET )
|
|
{
|
|
field_generic(new_column_name, L"", field_value, false, false, false);
|
|
}
|
|
else
|
|
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_CLEARING_VALUE )
|
|
{
|
|
field_generic(L"", L"", field_value, false, false, false); // the names don't matter here
|
|
}
|
|
}
|
|
}
|
|
|
|
// RENAME ME to something like select_field() or field_select()
|
|
template<typename FieldValue>
|
|
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);
|
|
virtual void prepare_table_names(bool prepare_table_index = true);
|
|
virtual void put_table_name_with_index(PT::TextStream & str);
|
|
|
|
|
|
virtual void put_to_log(const wchar_t * str);
|
|
virtual void put_fields_to_log(PT::Log & log, const wchar_t * db_field_name, const wchar_t * flat_field_name);
|
|
|
|
template<typename ModelClass> friend class Finder;
|
|
template<typename ModelClass> friend class Cursor;
|
|
friend class BaseExpression;
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
#endif
|