added: support for generating LEFT JOIN statement in Finder
(the primary key should consist of only one column at the moment) git-svn-id: svn://ttmath.org/publicrep/morm/branches/join_models@1186 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
163
src/model.h
163
src/model.h
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018, Tomasz Sowa
|
||||
* Copyright (c) 2018-2019, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -97,33 +97,33 @@ public:
|
||||
*/
|
||||
virtual void table_name(PT::TextStream & stream);
|
||||
|
||||
virtual void to_text(PT::TextStream & stream, ModelData * model_data = nullptr, 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, 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 = nullptr, 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, 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);
|
||||
virtual void generate_insert_query(PT::TextStream & stream); // FIX ME needed model_data
|
||||
virtual bool insert(ModelData * model_data = nullptr);
|
||||
virtual bool insert(ModelData & model_data);
|
||||
|
||||
virtual void generate_update_query(PT::TextStream & stream);
|
||||
virtual void generate_update_query(PT::TextStream & stream); // FIX ME needed model_data
|
||||
virtual bool update(ModelData * model_data = nullptr);
|
||||
virtual bool update(ModelData & model_data);
|
||||
|
||||
virtual void generate_remove_query(PT::TextStream & stream);
|
||||
virtual void generate_remove_query(PT::TextStream & stream); // FIX ME needed model_data
|
||||
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, const std::wstring & column_prefix);
|
||||
virtual void generate_select_columns(PT::TextStream & stream, const std::wstring & column_prefix, ModelData * model_data);
|
||||
|
||||
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);
|
||||
@@ -132,6 +132,12 @@ public:
|
||||
virtual void clear();
|
||||
|
||||
|
||||
// will be changed
|
||||
void clear_table_index()
|
||||
{
|
||||
table_index = 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
ModelConnector * model_connector;
|
||||
@@ -140,6 +146,7 @@ protected:
|
||||
const void * doc_field_pointer;
|
||||
int model_connector_mode;
|
||||
QueryResult * query_result;
|
||||
int table_index;
|
||||
|
||||
|
||||
Model();
|
||||
@@ -269,15 +276,16 @@ protected:
|
||||
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 is_primary_key = false)
|
||||
void field(const wchar_t * field_name, Model & field_value, bool insertable = true, bool updatable = true)
|
||||
{
|
||||
field_model(field_name, field_name, field_value, insertable, updatable, is_primary_key);
|
||||
field_model(field_name, field_name, field_value, insertable, updatable, true);
|
||||
}
|
||||
|
||||
template<typename ModelClass>
|
||||
void field(const wchar_t * field_name, std::list<ModelClass> & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false)
|
||||
void field(const wchar_t * field_name, std::list<ModelClass> & field_value, bool insertable = true, bool updatable = true)
|
||||
{
|
||||
field_list(field_name, field_name, field_value, insertable, updatable, is_primary_key);
|
||||
ModelClass * list_model_null_pointer = nullptr;
|
||||
field_list(field_name, field_name, field_value, list_model_null_pointer, insertable, updatable);
|
||||
}
|
||||
|
||||
|
||||
@@ -384,15 +392,16 @@ protected:
|
||||
}
|
||||
|
||||
|
||||
void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false)
|
||||
void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_value, bool insertable = true, bool updatable = true)
|
||||
{
|
||||
field_model(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key);
|
||||
field_model(db_field_name, flat_field_name, field_value, insertable, updatable, true);
|
||||
}
|
||||
|
||||
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, bool is_primary_key = false)
|
||||
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)
|
||||
{
|
||||
field_list(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key);
|
||||
ModelClass * list_model_null_pointer = nullptr;
|
||||
field_list(db_field_name, flat_field_name, field_value, list_model_null_pointer, insertable, updatable);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
@@ -644,7 +653,7 @@ protected:
|
||||
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);
|
||||
flat_expression->field(-1, flat_field_name, field_value, insertable, updatable, is_primary_key, true, model_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -659,7 +668,7 @@ protected:
|
||||
|
||||
if( db_expression && !is_empty_field(db_field_name) )
|
||||
{
|
||||
db_expression->field(db_field_name, field_value, insertable, updatable, is_primary_key);
|
||||
db_expression->field(table_index, db_field_name, field_value, insertable, updatable, is_primary_key, true, model_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -705,14 +714,64 @@ protected:
|
||||
}
|
||||
|
||||
|
||||
void field_model(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_model, bool insertable, bool updatable, bool is_primary_key)
|
||||
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_data )
|
||||
{
|
||||
model_data->morm_current_max_column += 1;
|
||||
model_data->morm_foreign_keys.clear();
|
||||
field_model.table_index = model_data->morm_current_max_column;
|
||||
|
||||
model_data->morm_finder_join_tables << "LEFT JOIN ";
|
||||
field_model.table_name(model_data->morm_finder_join_tables);
|
||||
model_data->morm_finder_join_tables << " AS t" << (model_data->morm_current_max_column);
|
||||
|
||||
int expr_work_mode = db_expression->get_work_mode();
|
||||
int expr_output_type = db_expression->get_output_type();
|
||||
|
||||
db_expression->set_work_mode(MORM_WORK_MODE_MODEL_SAVE_FIELDS);
|
||||
db_expression->set_output_type(MORM_OUTPUT_TYPE_JOIN_TABLES);
|
||||
|
||||
if( has_foreign_key )
|
||||
{
|
||||
field_model.map_fields();
|
||||
|
||||
model_data->morm_finder_join_tables << " ON t" << table_index << '.' << db_field_name;
|
||||
model_data->morm_finder_join_tables << " = ";
|
||||
|
||||
if( !model_data->morm_foreign_keys.empty() )
|
||||
{
|
||||
model_data->morm_finder_join_tables << model_data->morm_foreign_keys.front();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
map_fields();
|
||||
|
||||
model_data->morm_finder_join_tables << " ON ";
|
||||
|
||||
if( !model_data->morm_foreign_keys.empty() )
|
||||
{
|
||||
model_data->morm_finder_join_tables << model_data->morm_foreign_keys.front();
|
||||
}
|
||||
|
||||
model_data->morm_finder_join_tables << " = t" << (model_data->morm_current_max_column) << '.' << db_field_name;
|
||||
}
|
||||
|
||||
model_data->morm_finder_join_tables << ' ';
|
||||
db_expression->set_work_mode(expr_work_mode);
|
||||
db_expression->set_output_type(expr_output_type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 )
|
||||
{
|
||||
field_model.set_connector(model_connector);
|
||||
field_model.model_data = model_data;
|
||||
|
||||
// IMPLEMENTME what about db?
|
||||
if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING )
|
||||
{
|
||||
FlatConnector * flat_connector = model_connector->get_flat_connector();
|
||||
@@ -724,7 +783,36 @@ protected:
|
||||
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);
|
||||
flat_expression->field_model(flat_field_name, field_model, insertable, updatable, false);
|
||||
field_model.model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( 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) )
|
||||
{
|
||||
field_model.model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
|
||||
|
||||
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_output_type() != MORM_OUTPUT_TYPE_JOIN_TABLES )
|
||||
{
|
||||
field_model.model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
|
||||
field_model.map_fields();
|
||||
field_model.model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
|
||||
}
|
||||
|
||||
field_model.model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
|
||||
}
|
||||
}
|
||||
@@ -752,7 +840,7 @@ protected:
|
||||
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, is_primary_key);
|
||||
doc_expression->field_doc(*this, flat_field_name, field_model, insertable, updatable, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -762,10 +850,9 @@ protected:
|
||||
}
|
||||
|
||||
|
||||
template<typename ModelContainer>
|
||||
void field_list(const wchar_t * db_field_name, const wchar_t * flat_field_name, ModelContainer & field_container, bool insertable, bool updatable, bool is_primary_key)
|
||||
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)
|
||||
{
|
||||
// IMPLEMENTME what about db?
|
||||
if( model_connector )
|
||||
{
|
||||
if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING )
|
||||
@@ -781,11 +868,31 @@ protected:
|
||||
// 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, is_primary_key, model_connector, model_connector_mode, model_data);
|
||||
flat_expression->field_list(flat_field_name, field_container, insertable, updatable, false, model_connector, model_connector_mode, model_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( 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 )
|
||||
{
|
||||
ModelContainerType model_type;
|
||||
|
||||
model_type.model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
|
||||
field_model(db_field_name, flat_field_name, model_type, insertable, updatable, false);
|
||||
model_type.model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE )
|
||||
{
|
||||
Clearer * clearer = model_connector->get_clearer();
|
||||
@@ -808,7 +915,7 @@ protected:
|
||||
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, is_primary_key, model_data);
|
||||
doc_expression->field_doc(*this, flat_field_name, field_container, insertable, updatable, false, model_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user