added: Model::ModelData base class to use with Finder, Model.update(), Model.insert() and Model.remove()

added: Model.add_field_for_select() method 




git-svn-id: svn://ttmath.org/publicrep/morm/trunk@1092 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2018-04-22 21:04:50 +00:00
parent 4c0d203fc8
commit fd1cc7debe
11 changed files with 287 additions and 63 deletions

View File

@ -86,6 +86,14 @@ public:
}
}
template<typename FieldValue>
void field(const PT::TextStream & field_name, const FieldValue & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false)
{
std::wstring field_name_str; // field() methods can be called recursively, so don't make it as class object
field_name.to_string(field_name_str);
return field(field_name_str.c_str(), field_value, insertable, updatable, is_primary_key);
}
template<typename FieldValue>
void field_in(PT::TextStream & stream, const wchar_t * field_name, const std::set<FieldValue> & container)
@ -135,7 +143,7 @@ public:
template<typename FieldValue>
void field(PT::TextStream & stream, const wchar_t * field_name, const FieldValue & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false)
void field_to_stream(PT::TextStream & stream, const wchar_t * field_name, const FieldValue & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false)
{
this->out_stream = &stream;
field(field_name, field_value, insertable, updatable, is_primary_key);

View File

@ -284,4 +284,10 @@ DbExpression & DbExpression::group_end(PT::TextStream & stream)
}
DbExpression & DbExpression::page(PT::TextStream & stream, size_t page_number, size_t page_size)
{
stream << " limit " << page_number << "," << page_size << " ";
return *this;
}
}

View File

@ -59,6 +59,17 @@ public:
virtual DbExpression & group_and(PT::TextStream & stream);
virtual DbExpression & group_end(PT::TextStream & stream);
virtual DbExpression & page(PT::TextStream & stream, size_t page_number, size_t page_size);
template<typename FieldValue>
void add_field_for_select(const wchar_t * new_column_expression, const wchar_t * new_column_name, FieldValue & field_value)
{
PT::TextStream column_expression;
column_expression << new_column_expression << " as " << new_column_name;
field(column_expression, field_value, false, false);
}
protected:

View File

@ -60,6 +60,7 @@ public:
out_stream = nullptr;
db_expression = nullptr;
was_query_error = false;
model_data = nullptr;
}
@ -69,6 +70,7 @@ public:
this->model_connector = nullptr;
db_expression = nullptr;
was_query_error = false;
model_data = nullptr;
}
Finder(ModelConnector & model_connector)
@ -77,6 +79,7 @@ public:
out_stream = nullptr;
db_expression = nullptr;
was_query_error = false;
model_data = nullptr;
}
Finder(ModelConnector * model_connector)
@ -85,6 +88,7 @@ public:
out_stream = nullptr;
db_expression = nullptr;
was_query_error = false;
model_data = nullptr;
}
Finder(PT::TextStream & out_stream, ModelConnector & model_connector)
@ -93,6 +97,7 @@ public:
this->model_connector = &model_connector;
db_expression = nullptr;
was_query_error = false;
model_data = nullptr;
}
Finder(PT::TextStream & out_stream, ModelConnector * model_connector)
@ -101,6 +106,7 @@ public:
this->model_connector = model_connector;
db_expression = nullptr;
was_query_error = false;
model_data = nullptr;
}
@ -146,6 +152,7 @@ public:
{
was_query_error = false;
last_query_error.clear();
model_data = nullptr;
if( model_connector )
{
@ -178,9 +185,12 @@ public:
Finder<ModelClass> & select()
Finder<ModelClass> & select(bool call_prepare = true)
{
prepare_to_select();
if( call_prepare )
{
prepare_to_select();
}
if( model_connector && out_stream )
{
@ -194,7 +204,19 @@ public:
return *this;
}
Finder<ModelClass> & select(Model::ModelData * model_data)
{
prepare_to_select();
this->model_data = model_data;
return select(false);
}
Finder<ModelClass> & select(Model::ModelData & model_data)
{
prepare_to_select();
this->model_data = &model_data;
return select(false);
}
Finder<ModelClass> & where()
{
@ -249,7 +271,7 @@ public:
if( db_expression )
{
db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_EQ);
db_expression->field(*out_stream, field_name, field_value, false, false, false);
db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false);
}
return *this;
@ -262,7 +284,7 @@ public:
if( db_expression )
{
db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_LT);
db_expression->field(*out_stream, field_name, field_value, false, false, false);
db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false);
}
return *this;
@ -275,7 +297,7 @@ public:
if( db_expression )
{
db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_GT);
db_expression->field(*out_stream, field_name, field_value, false, false, false);
db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false);
}
return *this;
@ -288,7 +310,7 @@ public:
if( db_expression )
{
db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_LE);
db_expression->field(*out_stream, field_name, field_value, false, false, false);
db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false);
}
return *this;
@ -301,7 +323,7 @@ public:
if( db_expression )
{
db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_GE);
db_expression->field(*out_stream, field_name, field_value, false, false, false);
db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false);
}
return *this;
@ -345,11 +367,28 @@ public:
return *this;
}
Finder<ModelClass> & raw_sql(const char * sql)
Finder<ModelClass> & page(size_t page_number, size_t page_size)
{
if( out_stream && db_expression )
{
db_expression->page(*out_stream, page_number, page_size);
}
return *this;
}
Finder<ModelClass> & raw(const char * sql, bool add_spaces = true)
{
if( out_stream )
{
(*out_stream) << " " << sql << " ";
if( add_spaces )
(*out_stream) << ' ';
(*out_stream) << sql;
if( add_spaces )
(*out_stream) << ' ';
}
return *this;
@ -372,12 +411,13 @@ public:
{
try
{
result.model_data = model_data;
result.before_select();
res = db_connector->query_select(*out_stream);
if( res )
{
result.set_save_mode(Model::DO_UPDATE_ON_SAVE);
result.set_save_mode(Model::DO_UPDATE_ON_SAVE); // IMPROVE ME check if there is a primary key
model_connector->map_values_from_query(result);
result.after_select();
}
@ -438,7 +478,8 @@ public:
added_model.set_connector(model_connector);
added_model.clear();
added_model.set_save_mode(Model::DO_UPDATE_ON_SAVE);
added_model.set_save_mode(Model::DO_UPDATE_ON_SAVE); // IMPROVE ME check if there is a primary key
added_model.model_data = model_data;
added_model.before_select();
model_connector->map_values_from_query(added_model);
added_model.after_select();
@ -484,6 +525,7 @@ private:
ModelClass model;
bool was_query_error;
std::wstring last_query_error;
Model::ModelData * model_data;
void set_db_expression()
{

View File

@ -41,6 +41,7 @@ namespace morm
Model::Model()
{
model_connector = nullptr;
model_data = nullptr;
save_mode = DO_INSERT_ON_SAVE;
}
@ -181,15 +182,30 @@ void Model::generate_insert_query(PT::TextStream & stream)
}
void Model::insert()
bool Model::insert(ModelData * model_data)
{
bool result = false;
if( model_connector )
{
this->model_data = model_data;
if( model_connector->insert(*this) )
{
save_mode = DO_UPDATE_ON_SAVE;
save_mode = DO_UPDATE_ON_SAVE; // IMPROVE ME check if there is a primary key
result = true;
}
this->model_data = nullptr;
}
return result;
}
bool Model::insert(ModelData & model_data)
{
return insert(&model_data);
}
@ -202,12 +218,24 @@ void Model::generate_update_query(PT::TextStream & stream)
}
void Model::update()
bool Model::update(ModelData * model_data)
{
bool result = false;
if( model_connector )
{
model_connector->update(*this);
this->model_data = model_data;
result = model_connector->update(*this);
this->model_data = nullptr;
}
return result;
}
bool Model::update(ModelData & model_data)
{
return update(&model_data);
}
@ -220,37 +248,63 @@ void Model::generate_remove_query(PT::TextStream & stream)
}
void Model::remove()
bool Model::remove(ModelData * model_data)
{
bool result = false;
if( model_connector )
{
this->model_data = model_data;
if( model_connector->remove(*this) )
{
save_mode = DO_INSERT_ON_SAVE;
result = true;
}
this->model_data = nullptr;
}
return result;
}
void Model::save()
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:
remove();
result = remove(model_data);
break;
case DO_INSERT_ON_SAVE:
insert();
result = insert(model_data);
break;
case DO_UPDATE_ON_SAVE:
update();
result = update(model_data);
break;
case DO_NOTHING_ON_SAVE:
// may return true?
break;
}
return result;
}
bool Model::save(ModelData & model_data)
{
return save(&model_data);
}
@ -262,6 +316,7 @@ void Model::clear()
}
save_mode = DO_INSERT_ON_SAVE;
model_data = nullptr;
}

View File

@ -51,6 +51,14 @@ class Model
{
public:
class ModelData
{
public:
ModelData() {}
virtual ~ModelData() {}
};
enum SaveMode
{
DO_INSERT_ON_SAVE,
@ -103,15 +111,19 @@ public:
virtual std::string to_string();
virtual void generate_insert_query(PT::TextStream & stream);
virtual void insert();
virtual bool insert(ModelData * model_data = nullptr);
virtual bool insert(ModelData & model_data);
virtual void generate_update_query(PT::TextStream & stream);
virtual void update();
virtual bool update(ModelData * model_data = nullptr);
virtual bool update(ModelData & model_data);
virtual void generate_remove_query(PT::TextStream & stream);
virtual void remove();
virtual bool remove(ModelData * model_data = nullptr);
virtual bool remove(ModelData & model_data);
virtual void save();
virtual bool save(ModelData * model_data = nullptr);
virtual bool save(ModelData & model_data);
// set object to default values
@ -122,6 +134,7 @@ protected:
ModelConnector * model_connector;
SaveMode save_mode;
ModelData * model_data;
Model();
virtual ~Model();
@ -148,7 +161,34 @@ protected:
{
if( model_connector )
{
model_connector->field(field_name, field_value, insertable, updatable, is_primary_key);
model_connector->field(field_name, field_name, field_value, insertable, updatable, is_primary_key);
}
}
template<typename FieldValue>
void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false)
{
if( model_connector )
{
model_connector->field(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key);
}
}
template<typename FieldValue>
void field(const PT::TextStream & field_name, FieldValue & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false)
{
if( model_connector )
{
model_connector->field(field_name, field_name, field_value, insertable, updatable, is_primary_key);
}
}
template<typename FieldValue>
void field(const PT::TextStream & db_field_name, const PT::TextStream & flat_field_name, FieldValue & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false)
{
if( model_connector )
{
model_connector->field(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key);
}
}
@ -170,10 +210,44 @@ protected:
}
}
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 )
{
if( get_connector_mode() == MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL )
{
model_connector->add_field_for_select(new_column_expression, new_column_name, field_value);
}
else
if( get_connector_mode() == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING )
{
model_connector->field(L"", flat_field_name, field_value, false, false, false);
}
else
if( get_connector_mode() == MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB_RESULTSET )
{
model_connector->field(new_column_name, L"", field_value, false, false, false);
}
else
if( get_connector_mode() == MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE )
{
model_connector->field(L"", L"", field_value, false, false, false); // the names don't matter here
}
}
}
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);
}
//void field(const wchar_t * field_name, Model & field, bool insertable = true, bool updatable = true);
template<typename ModelClass> friend class Finder;
friend class ModelConnector;
};
} // namespace

View File

@ -174,7 +174,7 @@ void ModelConnector::to_text(PT::TextStream & stream, Model & model)
{
if( flat_connector )
{
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_EXPRESSION;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING;
//expression_callback = flat_connector->get_expression();
//if( expression_callback )
@ -192,7 +192,7 @@ void ModelConnector::generate_select_columns(PT::TextStream & stream, Model & mo
{
if( db_connector )
{
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
//expression_callback = db_connector->get_expression();
//if( expression_callback )
@ -211,7 +211,7 @@ void ModelConnector::generate_insert_query(PT::TextStream & stream, Model & mode
{
if( db_connector )
{
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
//expression_callback = db_connector->get_expression();
//if( expression_callback )
@ -229,7 +229,7 @@ void ModelConnector::generate_update_query(PT::TextStream & stream, Model & mode
{
if( db_connector )
{
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
//expression_callback = db_connector->get_expression();
//if( expression_callback )
@ -247,7 +247,7 @@ void ModelConnector::generate_remove_query(PT::TextStream & stream, Model & mode
{
if( db_connector )
{
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
db_connector->generate_remove_query(stream, model);
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
}
@ -264,7 +264,7 @@ bool ModelConnector::insert(Model & model)
if( db_connector && out_stream )
{
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
//db_connector_callback = db_connector;
model.before_insert();
@ -291,7 +291,7 @@ bool ModelConnector::update(Model & model)
if( db_connector && out_stream )
{
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
//db_connector_callback = db_connector;
model.before_update();
@ -320,7 +320,7 @@ bool ModelConnector::remove(Model & model)
if( db_connector && out_stream )
{
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
//db_connector_callback = db_connector;
model.before_remove();
@ -348,7 +348,7 @@ void ModelConnector::map_values_from_query(Model & model)
if( db_connector )
{
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB_RESULTSET;
//db_connector_callback = db_connector;
model.map_fields();
//db_connector_callback = nullptr;
@ -368,6 +368,10 @@ void ModelConnector::clear_values(Model & model)
}
bool ModelConnector::is_empty_field(const wchar_t * value)
{
return (!value || *value == '\0');
}
}

View File

@ -121,43 +121,33 @@ protected:
template<typename FieldValue>
void field(const wchar_t * field_name, FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key)
void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key)
{
// may we need only db_connector_callback?
// if( expression_callback )
// {
// expression_callback->field(field_name, field_value, insertable, updatable, is_primary_key);
// }
// if( db_connector_callback )
// {
// db_connector_callback->get_value_by_field_name(field_name, field_value);
// }
if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_EXPRESSION && flat_connector )
if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING && flat_connector )
{
FlatExpression * flat_expression = flat_connector->get_expression();
if( flat_expression )
if( flat_expression && !is_empty_field(flat_field_name) )
{
flat_expression->field(field_name, field_value, insertable, updatable, is_primary_key);
// 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_EXPRESSION && db_connector )
if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL && db_connector )
{
DbExpression * db_expression = db_connector->get_expression();
if( db_expression )
if( db_expression && !is_empty_field(db_field_name) )
{
db_expression->field(field_name, field_value, insertable, updatable, is_primary_key);
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 && db_connector )
if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB_RESULTSET && db_connector )
{
db_connector->get_value_by_field_name(field_name, field_value);
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 )
@ -167,37 +157,65 @@ protected:
}
}
template<typename FieldValue>
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<typename ModelClass>
void field_list(const wchar_t * field_name, std::list<ModelClass> & field_list, bool insertable = true, bool updatable = true, bool is_primary_key = false)
{
if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_EXPRESSION && flat_connector )
if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING && flat_connector )
{
FlatExpression * flat_expression = flat_connector->get_expression();
if( flat_expression )
if( flat_expression && !is_empty_field(field_name) )
{
flat_expression->field_list(field_name, field_list, insertable, updatable, is_primary_key);
}
}
}
template<typename FieldValue>
void add_field_for_select(const wchar_t * new_column_expression, const wchar_t * new_column_name, FieldValue & field_value)
{
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<typename FieldValue>
void get_last_sequence(const wchar_t * sequence_table_name, FieldValue & field_value)
{
if( db_connector )
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<typename ModelClass> friend class Finder;
};
}

View File

@ -36,13 +36,13 @@
#define headerfile_morm_morm_types
#define MORM_MODEL_CONNECTOR_MODE_NONE 0
#define MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_EXPRESSION 1
#define MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION 2
#define MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING 1
#define MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL 2
// not used at the moment, there are not any flat parsers (json parser)
#define MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_FLAT 3
#define MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_FLAT_STRING 3
#define MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB 4
#define MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB_RESULTSET 4
#define MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE 5

View File

@ -116,6 +116,11 @@ void PostgreSQLExpression::esc(char val, PT::TextStream & stream)
}
DbExpression & PostgreSQLExpression::page(PT::TextStream & stream, size_t page_number, size_t page_size)
{
stream << " offset " << page_number << " limit " << page_size << " ";
return *this;
}
}

View File

@ -46,6 +46,7 @@ class PostgreSQLExpression : public DbExpression
public:
void esc(char val, PT::TextStream & stream);
DbExpression & page(PT::TextStream & stream, size_t page_number, size_t page_size);
protected: