some work in morm

- support for fetching rows from db
- support for inserting/updating rows



git-svn-id: svn://ttmath.org/publicrep/morm/trunk@1081 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2018-04-16 22:46:25 +00:00
parent 09f31b2803
commit 72b2622d08
17 changed files with 965 additions and 319 deletions

View File

@ -11,7 +11,9 @@ baseexpression.o: ../../pikotools/convert/text.h
baseexpression.o: ../../pikotools/convert/misc.h
baseexpression.o: ../../pikotools/membuffer/membuffer.h
baseexpression.o: ../../pikotools/textstream/types.h morm_types.h model.h
baseexpression.o: modelconnector.h ../../pikotools/utf8/utf8.h
baseexpression.o: modelconnector.h dbconnector.h dbexpression.h
baseexpression.o: flatexpression.h flatconnector.h
baseexpression.o: ../../pikotools/utf8/utf8.h
dbconnector.o: dbconnector.h dbexpression.h baseexpression.h
dbconnector.o: ../../pikotools/textstream/textstream.h
dbconnector.o: ../../pikotools/space/space.h
@ -22,7 +24,8 @@ dbconnector.o: ../../pikotools/convert/strtoint.h
dbconnector.o: ../../pikotools/convert/text.h ../../pikotools/convert/misc.h
dbconnector.o: ../../pikotools/membuffer/membuffer.h
dbconnector.o: ../../pikotools/textstream/types.h morm_types.h model.h
dbconnector.o: modelconnector.h
dbconnector.o: modelconnector.h flatexpression.h flatconnector.h
dbconnector.o: ../../pikotools/utf8/utf8.h
dbexpression.o: dbexpression.h baseexpression.h
dbexpression.o: ../../pikotools/textstream/textstream.h
dbexpression.o: ../../pikotools/space/space.h
@ -42,6 +45,7 @@ finder.o: ../../pikotools/convert/misc.h
finder.o: ../../pikotools/membuffer/membuffer.h
finder.o: ../../pikotools/textstream/types.h modelconnector.h
finder.o: baseexpression.h morm_types.h dbconnector.h dbexpression.h
finder.o: flatexpression.h flatconnector.h
flatconnector.o: flatconnector.h flatexpression.h baseexpression.h
flatconnector.o: ../../pikotools/textstream/textstream.h
flatconnector.o: ../../pikotools/space/space.h
@ -54,7 +58,7 @@ flatconnector.o: ../../pikotools/convert/text.h
flatconnector.o: ../../pikotools/convert/misc.h
flatconnector.o: ../../pikotools/membuffer/membuffer.h
flatconnector.o: ../../pikotools/textstream/types.h morm_types.h model.h
flatconnector.o: modelconnector.h
flatconnector.o: modelconnector.h dbconnector.h dbexpression.h
flatexpression.o: flatexpression.h baseexpression.h
flatexpression.o: ../../pikotools/textstream/textstream.h
flatexpression.o: ../../pikotools/space/space.h
@ -99,7 +103,8 @@ model.o: ../../pikotools/convert/inttostr.h
model.o: ../../pikotools/convert/strtoint.h ../../pikotools/convert/text.h
model.o: ../../pikotools/convert/misc.h ../../pikotools/membuffer/membuffer.h
model.o: ../../pikotools/textstream/types.h modelconnector.h baseexpression.h
model.o: morm_types.h
model.o: morm_types.h dbconnector.h dbexpression.h flatexpression.h
model.o: flatconnector.h
modelconnector.o: modelconnector.h baseexpression.h
modelconnector.o: ../../pikotools/textstream/textstream.h
modelconnector.o: ../../pikotools/space/space.h
@ -111,9 +116,9 @@ modelconnector.o: ../../pikotools/convert/strtoint.h
modelconnector.o: ../../pikotools/convert/text.h
modelconnector.o: ../../pikotools/convert/misc.h
modelconnector.o: ../../pikotools/membuffer/membuffer.h
modelconnector.o: ../../pikotools/textstream/types.h morm_types.h model.h
modelconnector.o: flatconnector.h flatexpression.h dbconnector.h
modelconnector.o: dbexpression.h
modelconnector.o: ../../pikotools/textstream/types.h morm_types.h
modelconnector.o: dbconnector.h dbexpression.h flatexpression.h
modelconnector.o: flatconnector.h model.h
postgresqlconnector.o: postgresqlconnector.h dbconnector.h dbexpression.h
postgresqlconnector.o: baseexpression.h
postgresqlconnector.o: ../../pikotools/textstream/textstream.h
@ -128,6 +133,7 @@ postgresqlconnector.o: ../../pikotools/convert/misc.h
postgresqlconnector.o: ../../pikotools/membuffer/membuffer.h
postgresqlconnector.o: ../../pikotools/textstream/types.h morm_types.h
postgresqlconnector.o: ../../pikotools/utf8/utf8.h postgresqlexpression.h
postgresqlconnector.o: ../../pikotools/convert/strtoint.h
postgresqlexpression.o: postgresqlexpression.h dbexpression.h
postgresqlexpression.o: baseexpression.h
postgresqlexpression.o: ../../pikotools/textstream/textstream.h

View File

@ -63,15 +63,21 @@ void BaseExpression::set_work_mode(int work_mode)
void BaseExpression::generate_from_model(PT::TextStream & stream, Model & model)
{
this->out_stream = &stream;
before_generate_from_model();
model.map_fields();
after_generate_from_model();
generate_from_model(model);
this->out_stream = nullptr;
}
void BaseExpression::generate_from_model(Model & model)
{
if( out_stream )
{
before_generate_from_model();
model.map_fields();
after_generate_from_model();
}
}
void BaseExpression::before_generate_from_model()
{
is_first_field = true;
@ -161,6 +167,14 @@ void BaseExpression::after_field_value(const char *)
{
}
void BaseExpression::before_field_value(const PT::Date &)
{
}
void BaseExpression::after_field_value(const PT::Date &)
{
}
void BaseExpression::put_name_value_separator()
@ -315,7 +329,7 @@ void BaseExpression::esc(void* val, PT::TextStream & stream)
void BaseExpression::esc(const PT::Date & date, PT::TextStream & stream)
{
stream << "'" << date << "'";
stream << date;
}

View File

@ -35,7 +35,7 @@
#ifndef headerfile_morm_baseexpression
#define headerfile_morm_baseexpression
#include <list>
#include "textstream/textstream.h"
#include "morm_types.h"
#include "date/date.h"
@ -86,6 +86,34 @@ public:
}
template<typename ModelClass>
void field_list(const wchar_t * field_name, const std::list<ModelClass> & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false)
{
if( out_stream && can_field_be_generated(insertable, updatable, is_primary_key) )
{
field_before();
// if( work_mode == MORM_WORK_MODE_MODEL_FIELDS )
// {
// put_field_name(field_name);
// }
// else
// if( work_mode == MORM_WORK_MODE_MODEL_VALUES )
// {
// put_field_value(field_value);
// }
// else
if( work_mode == MORM_WORK_MODE_MODEL_FIELDS_VALUES )
{
put_field_name(field_name);
put_name_value_separator();
put_field_value_list(field_value);
}
field_after();
}
}
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)
{
@ -144,6 +172,8 @@ protected:
// generate_from_model();
// }
virtual void generate_from_model(Model & model);
virtual void before_generate_from_model();
virtual void after_generate_from_model();
virtual bool can_field_be_generated(bool insertable, bool updatable, bool is_primary_key);
@ -162,6 +192,38 @@ protected:
after_field_value(field_value);
}
template<typename ModelClass>
void put_field_value_list(const std::list<ModelClass> & field_value)
{
if( out_stream )
{
(*out_stream) << "[";// make a virtual method
}
bool is_first = true;
for(ModelClass m : field_value)
{
if( out_stream )
{
if( !is_first )
{
if( out_stream )
(*out_stream) << ","; // make a virtual method
}
//before_field_value(field_value);
generate_from_model(m);
//after_field_value(field_value);
is_first = false;
}
}
if( out_stream )
{
(*out_stream) << "]";// make a virtual method
}
}
virtual void before_field_name();
virtual void after_field_name();
@ -178,6 +240,9 @@ protected:
virtual void before_field_value(const char *);
virtual void after_field_value(const char *);
virtual void before_field_value(const PT::Date &);
virtual void after_field_value(const PT::Date &);
template<typename FieldValue>
void before_field_value(const FieldValue &)

View File

@ -32,8 +32,10 @@
*
*/
#include <cstdlib>
#include "dbconnector.h"
#include "model.h"
#include "utf8/utf8.h"
namespace morm
@ -45,6 +47,12 @@ DbConnector::DbConnector()
expression_allocated = false;
}
DbConnector::DbConnector(const DbConnector &)
{
db_expression = nullptr;
expression_allocated = false;
}
DbConnector::~DbConnector()
{
@ -100,13 +108,27 @@ bool DbConnector::query_insert(const PT::TextStream & stream)
return false;
}
virtual void DbConnector::map_values_from_query(Model & model)
size_t DbConnector::last_select_size()
{
model.clear();
return 0;
}
void DbConnector::set_current_row_at_beginning()
{
}
void DbConnector::advance_current_row()
{
}
//void DbConnector::map_values_from_query(Model & model)
//{
// model.clear();
//}
DbExpression * DbConnector::get_expression()
{
allocate_default_expression_if_needed();
@ -159,15 +181,12 @@ void DbConnector::generate_update_query(PT::TextStream & stream, Model & model)
stream << "update ";
model.table_name(stream);
stream << " set (";
db_expression->set_work_mode(MORM_WORK_MODE_MODEL_FIELDS);
stream << " set ";
db_expression->set_work_mode(MORM_WORK_MODE_MODEL_FIELDS_VALUES);
db_expression->generate_from_model(stream, model);
stream << ") values (";
db_expression->set_work_mode(MORM_WORK_MODE_MODEL_VALUES);
db_expression->generate_from_model(stream, model);
stream << ") where ";
stream << " where ";
db_expression->set_work_mode(MORM_WORK_MODE_MODEL_FIELDS_VALUES);
db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_PRIMARY_KEY);
db_expression->generate_from_model(stream, model);
@ -176,21 +195,17 @@ void DbConnector::generate_update_query(PT::TextStream & stream, Model & model)
void DbConnector::insert(PT::TextStream & stream, Model & model)
bool DbConnector::insert(PT::TextStream & stream, Model & model)
{
generate_insert_query(stream, model);
// do the real inserting
// query(stream);
// and get autogenerated columns
return query_insert(stream);
}
void DbConnector::update(PT::TextStream & stream, Model & model)
bool DbConnector::update(PT::TextStream & stream, Model & model)
{
generate_update_query(stream, model);
// do the real updating
// query(stream);
// and get autogenerated columns
return query_update(stream);
}
@ -214,7 +229,235 @@ void DbConnector::allocate_default_expression_if_needed()
}
}
const char * DbConnector::get_field_string_value(const wchar_t * field_name)
{
return nullptr;
}
void DbConnector::clear_value(char & field_value)
{
field_value = 0;
}
void DbConnector::clear_value(unsigned char & field_value)
{
field_value = 0;
}
void DbConnector::clear_value(std::wstring & field_value)
{
field_value.clear();
}
void DbConnector::clear_value(std::string & field_value)
{
field_value.clear();
}
void DbConnector::clear_value(bool & field_value)
{
field_value = false;
}
void DbConnector::clear_value(short & field_value)
{
field_value = 0;
}
void DbConnector::clear_value(unsigned short & field_value)
{
field_value = 0;
}
void DbConnector::clear_value(int & field_value)
{
field_value = 0;
}
void DbConnector::clear_value(unsigned int & field_value)
{
field_value = 0;
}
void DbConnector::clear_value(long & field_value)
{
field_value = 0;
}
void DbConnector::clear_value(unsigned long & field_value)
{
field_value = 0;
}
void DbConnector::clear_value(long long & field_value)
{
field_value = 0;
}
void DbConnector::clear_value(unsigned long long & field_value)
{
field_value = 0;
}
void DbConnector::clear_value(float & field_value)
{
field_value = 0.0f;
}
void DbConnector::clear_value(double & field_value)
{
field_value = 0.0;
}
void DbConnector::clear_value(long double & field_value)
{
field_value = 0.0;
}
void DbConnector::clear_value(PT::Date & field_value)
{
field_value.Clear();
}
void DbConnector::get_value(const char * value_str, char & field_value)
{
field_value = *value_str;
value_str += 1;
if( *value_str != 0 )
{
// value has more than one charater, put some error?
}
}
void DbConnector::get_value(const char * value_str, unsigned char & field_value)
{
field_value = *(const unsigned char*)value_str;
value_str += 1;
if( *value_str != 0 )
{
// value has more than one charater, put some error?
}
}
void DbConnector::get_value(const char * value_str, std::wstring & field_value)
{
// CHECKME
// what about \0 in val_str?
// it is escaped somehow?
PT::UTF8ToWide(value_str, field_value);
}
void DbConnector::get_value(const char * value_str, std::string & field_value)
{
field_value = value_str;
}
void DbConnector::get_value(const char * value_str, bool & field_value)
{
// IMPROVE ME
// this 't' is locale dependent
field_value = (value_str[0]=='t' || value_str[0]=='y' || value_str[0]=='1');
}
void DbConnector::get_value(const char * value_str, short & field_value)
{
// IMPROVE ME give some overflow checking
field_value = (short)PT::Toi(value_str, 10);
}
void DbConnector::get_value(const char * value_str, unsigned short & field_value)
{
// IMPROVE ME give some overflow checking
field_value = (unsigned short)PT::Toui(value_str, 10);
}
void DbConnector::get_value(const char * value_str, int & field_value)
{
// IMPROVE ME give some overflow checking
field_value = PT::Toi(value_str, 10);
}
void DbConnector::get_value(const char * value_str, unsigned int & field_value)
{
// IMPROVE ME give some overflow checking
field_value = PT::Toui(value_str, 10);
}
void DbConnector::get_value(const char * value_str, long & field_value)
{
// IMPROVE ME give some overflow checking
field_value = PT::Tol(value_str, 10);
}
void DbConnector::get_value(const char * value_str, unsigned long & field_value)
{
// IMPROVE ME give some overflow checking
field_value = PT::Toul(value_str, 10);
}
void DbConnector::get_value(const char * value_str, long long & field_value)
{
// IMPROVE ME give some overflow checking
field_value = PT::Toll(value_str, 10);
}
void DbConnector::get_value(const char * value_str, unsigned long long & field_value)
{
// IMPROVE ME give some overflow checking
field_value = PT::Toull(value_str, 10);
}
void DbConnector::get_value(const char * value_str, float & field_value)
{
// IMPROVE ME give some overflow checking
field_value = strtof(value_str, 0);
}
void DbConnector::get_value(const char * value_str, double & field_value)
{
// IMPROVE ME give some overflow checking
field_value = strtod(value_str, 0);
}
void DbConnector::get_value(const char * value_str, long double & field_value)
{
// IMPROVE ME give some overflow checking
field_value = strtold(value_str, 0);
}
void DbConnector::get_value(const char * value_str, PT::Date & field_value)
{
// IMPROVE ME give some log if parsing failed
bool res = field_value.Parse(value_str);
}
const char * DbConnector::query_last_sequence(const wchar_t * sequence_table_name)
{
return nullptr;
}
}

View File

@ -50,6 +50,7 @@ class DbConnector
public:
DbConnector();
DbConnector(const DbConnector &);
virtual ~DbConnector();
DbExpression * get_expression();
@ -58,8 +59,11 @@ public:
virtual void generate_insert_query(PT::TextStream & stream, Model & model);
virtual void generate_update_query(PT::TextStream & stream, Model & model);
virtual void insert(PT::TextStream & stream, Model & model);
virtual void update(PT::TextStream & stream, Model & model);
virtual bool insert(PT::TextStream & stream, Model & model);
virtual bool update(PT::TextStream & stream, Model & model);
//void ModelConnector::get_values_from_db(Model & model)
virtual bool query(const PT::TextStream & stream);
//virtual bool query(const std::wstring & query);
@ -71,7 +75,76 @@ public:
virtual bool query_update(const PT::TextStream & stream);
virtual bool query_insert(const PT::TextStream & stream);
virtual void map_values_from_query(Model & model);
virtual size_t last_select_size();
// give me a better name
virtual void set_current_row_at_beginning();
virtual void advance_current_row();
//virtual void map_values_from_query(Model & model);
// these methods should be somewhere else
// flat_parsers (json parser) can use them as well
virtual void clear_value(char & field_value);
virtual void clear_value(unsigned char & field_value);
virtual void clear_value(std::wstring & field_value);
virtual void clear_value(std::string & field_value);
virtual void clear_value(bool & field_value);
virtual void clear_value(short & field_value);
virtual void clear_value(unsigned short & field_value);
virtual void clear_value(int & field_value);
virtual void clear_value(unsigned int & field_value);
virtual void clear_value(long & field_value);
virtual void clear_value(unsigned long & field_value);
virtual void clear_value(long long & field_value);
virtual void clear_value(unsigned long long & field_value);
virtual void clear_value(float & field_value);
virtual void clear_value(double & field_value);
virtual void clear_value(long double & field_value);
virtual void clear_value(PT::Date & field_value);
virtual void get_value(const char * value_str, char & field_value);
virtual void get_value(const char * value_str, unsigned char & field_value);
virtual void get_value(const char * value_str, std::wstring & field_value);
virtual void get_value(const char * value_str, std::string & field_value);
virtual void get_value(const char * value_str, bool & field_value);
virtual void get_value(const char * value_str, short & field_value);
virtual void get_value(const char * value_str, unsigned short & field_value);
virtual void get_value(const char * value_str, int & field_value);
virtual void get_value(const char * value_str, unsigned int & field_value);
virtual void get_value(const char * value_str, long & field_value);
virtual void get_value(const char * value_str, unsigned long & field_value);
virtual void get_value(const char * value_str, long long & field_value);
virtual void get_value(const char * value_str, unsigned long long & field_value);
virtual void get_value(const char * value_str, float & field_value);
virtual void get_value(const char * value_str, double & field_value);
virtual void get_value(const char * value_str, long double & field_value);
virtual void get_value(const char * value_str, PT::Date & field_value);
//virtual void get_value(const char * value_str, void* & field_value);
template<typename FieldValue>
void get_value_by_field_name(const wchar_t * field_name, FieldValue & field_value)
{
const char * val_str = get_field_string_value(field_name);
if( val_str )
{
get_value(val_str, field_value);
}
}
template<typename FieldValue>
void get_last_sequence(const wchar_t * sequence_table_name, FieldValue & field_value)
{
const char * val_str = query_last_sequence(sequence_table_name);
if( val_str )
{
get_value(val_str, field_value);
}
}
protected:
@ -82,6 +155,12 @@ protected:
virtual void allocate_default_expression() = 0;
virtual void allocate_default_expression_if_needed();
virtual void deallocate_expression();
virtual const char * get_field_string_value(const wchar_t * field_name);
virtual const char * query_last_sequence(const wchar_t * sequence_table_name);
};

View File

@ -127,7 +127,8 @@ void DbExpression::field_before()
void DbExpression::put_name_value_separator()
{
if( output_type == MORM_OUTPUT_TYPE_DB_PRIMARY_KEY ||
output_type == MORM_OUTPUT_TYPE_WHERE_EQ )
output_type == MORM_OUTPUT_TYPE_WHERE_EQ ||
output_type == MORM_OUTPUT_TYPE_DB_UPDATE)
{
(*out_stream) << " = ";
}
@ -218,6 +219,16 @@ void DbExpression::after_field_value(const char *)
after_field_value_string();
}
void DbExpression::before_field_value(const PT::Date &)
{
before_field_value_string();
}
void DbExpression::after_field_value(const PT::Date &)
{
after_field_value_string();
}
void DbExpression::prepare_to_where_clause()
{

View File

@ -83,6 +83,8 @@ protected:
void before_field_value(const char *);
void after_field_value(const char *);
void before_field_value(const PT::Date &);
void after_field_value(const PT::Date &);
void put_name_value_separator();

View File

@ -263,8 +263,51 @@ public:
}
void get_list(std::list<ModelClass> & result, bool clear_list = true)
bool get(ModelClass & result)
{
bool res = false;
result.clear();
result.set_object_exists(false);
if( model_connector && out_stream )
{
DbConnector * db_connector = model_connector->get_db_connector();
if( db_connector )
{
res = db_connector->query_select(*out_stream);
if( res )
{
result.set_object_exists(true);
result.set_connector(*model_connector);
result.before_select();
model_connector->map_values_from_query(result);
result.after_select();
}
if( !res )
{
// put some log here?
}
}
}
return res;
}
ModelClass get()
{
get(model);
return model;
}
bool get_list(std::list<ModelClass> & result, bool clear_list = true)
{
bool res = false;
if( clear_list )
{
result.clear();
@ -276,31 +319,40 @@ public:
if( db_connector )
{
bool res = db_connector->query_select(*out_stream);
res = db_connector->query_select(*out_stream);
if( res )
{
//ModelClass model;
//db_connector->map_values_from_query(model);
size_t len = db_connector->last_select_size();
db_connector->set_current_row_at_beginning();
for(size_t i = 0 ; i < len ; ++i)
{
model.clear();
model.set_object_exists(true);
model.set_connector(*model_connector);
model.before_select();
model_connector->map_values_from_query(model);
model.after_select();
result.push_back(model);
db_connector->advance_current_row();
}
}
if( !res )
{
// put some log here?
}
}
}
return res;
}
std::list<ModelClass> get_list()
{
std::list<ModelClass> result;
get_list(result);
get_list(result, false);
return result;
}

View File

@ -119,6 +119,17 @@ void JSONExpression::after_field_value(const std::string &)
after_field_value_string();
}
void JSONExpression::before_field_value(const PT::Date &)
{
before_field_value_string();
}
void JSONExpression::after_field_value(const PT::Date &)
{
after_field_value_string();
}
void JSONExpression::put_name_value_separator()
{

View File

@ -61,6 +61,10 @@ protected:
void after_field_value(const std::string &);
void put_name_value_separator();
void before_field_value(const PT::Date &);
void after_field_value(const PT::Date &);
template<typename FieldValue>
void print_field_name_value(const wchar_t * field_name, const FieldValue & field_value)
{

View File

@ -146,8 +146,40 @@ void Model::update()
void Model::clear()
{
if( model_connector )
{
model_connector->clear_values(*this);
}
morm_object_exists = false;
}
void Model::before_select()
{
}
void Model::before_insert()
{
}
void Model::before_update()
{
}
void Model::after_select()
{
}
void Model::after_insert()
{
}
void Model::after_update()
{
}
} // namespace

View File

@ -89,6 +89,7 @@ public:
// set object to default values
virtual void clear();
protected:
ModelConnector * model_connector;
@ -97,9 +98,16 @@ protected:
Model();
virtual ~Model();
virtual void before_select();
virtual void before_insert();
virtual void before_update();
virtual void after_select();
virtual void after_insert();
virtual void after_update();
template<typename FieldValue>
void field(const wchar_t * field_name, const FieldValue & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false)
void field(const wchar_t * field_name, FieldValue & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false)
{
if( model_connector )
{
@ -107,9 +115,28 @@ protected:
}
}
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 )
{
model_connector->field_list(field_name, field_list, insertable, updatable, is_primary_key);
}
}
template<typename FieldValue>
void get_last_sequence(const wchar_t * sequence_table_name, FieldValue & field_value)
{
if( model_connector )
{
model_connector->get_last_sequence(sequence_table_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

@ -43,9 +43,13 @@ namespace morm
ModelConnector::ModelConnector()
{
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
flat_connector = nullptr;
db_connector = nullptr;
expression_callback = nullptr;
//expression_callback = nullptr;
//db_connector_callback = nullptr;
out_stream = nullptr;
out_stream_allocated = false;
@ -140,14 +144,16 @@ void ModelConnector::to_text(PT::TextStream & stream, Model & model)
{
if( flat_connector )
{
expression_callback = flat_connector->get_expression();
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_EXPRESSION;
//expression_callback = flat_connector->get_expression();
if( expression_callback )
{
//if( expression_callback )
//{
flat_connector->to_text(stream, model);
}
//}
expression_callback = nullptr;
//expression_callback = nullptr;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
}
}
@ -156,14 +162,16 @@ void ModelConnector::generate_select_columns(PT::TextStream & stream, Model & mo
{
if( db_connector )
{
expression_callback = db_connector->get_expression();
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION;
//expression_callback = db_connector->get_expression();
if( expression_callback )
{
//if( expression_callback )
//{
db_connector->generate_select_columns(stream, model);
}
//}
expression_callback = nullptr;
//expression_callback = nullptr;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
}
}
@ -173,14 +181,16 @@ void ModelConnector::generate_insert_query(PT::TextStream & stream, Model & mode
{
if( db_connector )
{
expression_callback = db_connector->get_expression();
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION;
//expression_callback = db_connector->get_expression();
if( expression_callback )
{
//if( expression_callback )
//{
db_connector->generate_insert_query(stream, model);
}
//}
expression_callback = nullptr;
//expression_callback = nullptr;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
}
}
@ -189,14 +199,16 @@ void ModelConnector::generate_update_query(PT::TextStream & stream, Model & mode
{
if( db_connector )
{
expression_callback = db_connector->get_expression();
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION;
//expression_callback = db_connector->get_expression();
if( expression_callback )
{
//if( expression_callback )
//{
db_connector->generate_update_query(stream, model);
}
//}
expression_callback = nullptr;
//expression_callback = nullptr;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
}
}
@ -207,8 +219,16 @@ void ModelConnector::insert(Model & model)
if( db_connector && out_stream )
{
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION;
//db_connector_callback = db_connector;
model.before_insert();
out_stream->clear();
db_connector->insert(*out_stream, model);
model.after_insert();
//db_connector_callback = nullptr;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
}
}
@ -219,11 +239,44 @@ void ModelConnector::update(Model & model)
if( db_connector && out_stream )
{
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION;
//db_connector_callback = db_connector;
model.before_update();
out_stream->clear();
db_connector->update(*out_stream, model);
model.after_update();
//db_connector_callback = nullptr;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
}
}
void ModelConnector::map_values_from_query(Model & model)
{
if( db_connector )
{
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB;
//db_connector_callback = db_connector;
model.map_fields();
//db_connector_callback = nullptr;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
}
}
void ModelConnector::clear_values(Model & model)
{
if( db_connector )
{
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE;
model.map_fields();
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
}
}
}

View File

@ -36,14 +36,15 @@
#define headerfile_morm_modelconnector
#include "baseexpression.h"
//#include "finder.h"
#include "dbconnector.h"
#include "flatexpression.h"
#include "flatconnector.h"
namespace morm
{
class Model;
class FlatConnector;
class DbConnector;
template<typename ModelClass>
class Finder;
@ -81,6 +82,10 @@ public:
virtual void insert(Model & model);
virtual void update(Model & model);
virtual void map_values_from_query(Model & model);
virtual void clear_values(Model & model);
// template<typename ModelClass>
// Finder<ModelClass> & find()
@ -92,13 +97,16 @@ public:
protected:
int model_connector_mode;
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;
//BaseExpression * expression_callback;
//DbConnector * db_connector_callback;
void allocate_default_stream();
void allocate_default_stream_if_needed();
@ -108,12 +116,75 @@ protected:
template<typename FieldValue>
void field(const wchar_t * field_name, FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key)
{
if( expression_callback )
// 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 )
{
expression_callback->field(field_name, field_value, insertable, updatable, is_primary_key);
FlatExpression * flat_expression = flat_connector->get_expression();
if( flat_expression )
{
flat_expression->field(field_name, field_value, insertable, updatable, is_primary_key);
}
}
if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION && db_connector )
{
DbExpression * db_expression = db_connector->get_expression();
if( db_expression )
{
db_expression->field(field_name, field_value, insertable, updatable, is_primary_key);
}
}
if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB && db_connector )
{
db_connector->get_value_by_field_name(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<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 && out_stream )
{
FlatExpression * flat_expression = flat_connector->get_expression();
if( flat_expression )
{
flat_expression->field_list(field_name, field_list, insertable, updatable, is_primary_key);
}
}
}
template<typename FieldValue>
void get_last_sequence(const wchar_t * sequence_table_name, FieldValue & field_value)
{
if( db_connector )
{
db_connector->get_last_sequence(sequence_table_name, field_value);
}
}
/*
* Model is using field() method
*/

View File

@ -35,13 +35,23 @@
#ifndef headerfile_morm_morm_types
#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
// 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_DB 4
#define MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE 5
#define MORM_WORK_MODE_MODEL_FIELDS 1
#define MORM_WORK_MODE_MODEL_VALUES 2
#define MORM_WORK_MODE_MODEL_FIELDS_VALUES 3
// IMPROVE ME give me a better name
#define MORM_WORK_MODE_MODEL_SELECT_FROM_DB 3
//#define MORM_WORK_MODE_MODEL_SELECT_FROM_DB 4
//#define MORM_OUTPUT_TYPE_JSON 1
#define MORM_OUTPUT_TYPE_DB_INSERT 2

View File

@ -38,6 +38,7 @@
#include "postgresqlconnector.h"
#include "utf8/utf8.h"
#include "postgresqlexpression.h"
#include "convert/strtoint.h"
namespace morm
@ -49,6 +50,8 @@ PostgreSQLConnector::PostgreSQLConnector()
log_queries = false;
last_status = PGRES_EMPTY_QUERY;
last_result = nullptr;
last_result_rows = 0;
cur_row = 0;
}
PostgreSQLConnector::~PostgreSQLConnector()
@ -77,6 +80,7 @@ bool PostgreSQLConnector::query(const char * query_str)
// log << log1 << "Db: executing query: " << q << logend;
last_status = PGRES_EMPTY_QUERY; // or something else?
last_result_rows = 0;
last_result = PQexec(pg_conn, query_str);
if( !last_result )
@ -91,6 +95,7 @@ bool PostgreSQLConnector::query(const char * query_str)
if( last_result )
{
last_status = PQresultStatus(last_result);
last_result_rows = static_cast<size_t>(PQntuples(last_result));
}
else
{
@ -102,6 +107,36 @@ return last_result != nullptr;
}
const char * PostgreSQLConnector::query_last_sequence(const wchar_t * sequence_table_name)
{
allocate_default_expression_if_needed();
if( db_expression )
{
stream.clear();
stream << "select currval(E'";
db_expression->esc(sequence_table_name, stream);
stream << "');";
if( query_select(stream) )
{
if( last_result_rows == 1 )
{
return get_value(0, 0);
}
else
{
//log << log1 << "Db: error (currval) for table: " << table << ", " << PQerrorMessage(db_conn->GetPgConn()) << logend;
}
}
}
return nullptr;
}
bool PostgreSQLConnector::query(const PT::TextStream & stream)
{
stream.to_string(query_str);
@ -152,219 +187,18 @@ bool PostgreSQLConnector::query_insert(const PT::TextStream & stream)
//Error PostgreSQLConnector::DoCommand(const char * command)
//{
// PGresult * r = 0;
// Error status = WINIX_ERR_OK;
//
// try
// {
// r = AssertQuery(command);
// AssertResult(r, PGRES_COMMAND_OK);
// }
// catch(const Error & e)
// {
// status = e;
// }
//
// ClearResult(r);
//
//return status;
//}
bool PostgreSQLConnector::is_last_result(ExecStatusType t)
{
return (last_result && PQresultStatus(last_result) == t);
}
void PostgreSQLConnector::map_values_from_query(Model & model)
// to nie tylko dla selectow moze byc uzywane
size_t PostgreSQLConnector::last_select_size()
{
if( db_expression )
{
db_expression->set_work_mode(MORM_WORK_MODE_MODEL_SELECT_FROM_DB);
//db_expression->set_output_type()
}
return last_result_rows;
}
int PostgreSQLConnector::get_column_index(const char * column_name)
{
int c = PQfnumber(last_result, column_name);
// returns -1 if there is no such a column
return c;
}
const char * PostgreSQLConnector::get_value(int row, int col)
{
const char * res = PQgetvalue(last_result, row, col);
// can return a null pointer if there is no such an item in the last result
return res;
}
bool PostgreSQLConnector::get_value(int row, int col, std::string & result, bool clear_string)
{
if( clear_string )
result.clear();
const char * raw_result = get_value(row, col);
if( raw_result )
{
result += raw_result;
}
return raw_result != nullptr;
}
bool PostgreSQLConnector::get_value(int row, int col, std::wstring & result, bool clear_string)
{
if( clear_string )
result.clear();
const char * raw_result = get_value(row, col);
if( raw_result )
{
PT::UTF8ToWide(raw_result, result);
}
return raw_result != nullptr;
}
//void PostgreSQLConnector::get_value_bin(int row, int col, std::string & result, bool clear_string)
//{
// if( clear_string )
// result.clear();
//
// const char * raw_result = get_value(row, col);
//
// if( raw_result )
// {
// int len = PQgetlength(last_result, row, col);
//
// if( len > 0 )
// {
// unescape_bin(raw_result, len, result);
// }
// }
//}
//long PostgreSQLConnector::AssertValueLong(PGresult * r, int row, int col)
//{
// return strtol( AssertValue(r, row, col), 0, 10 );
//}
//
//
//int PostgreSQLConnector::AssertValueInt(PGresult * r, int row, int col)
//{
// return (int)strtol( AssertValue(r, row, col), 0, 10 );
//}
//
//
//bool PostgreSQLConnector::AssertValueBool(PGresult * r, int row, int col)
//{
// const char * s = AssertValue(r, row, col);
// return (s[0]=='t' || s[0]=='y' || s[0]=='1');
//}
//
//
//unsigned long PostgreSQLConnector::AssertValueULong(PGresult * r, int row, int col)
//{
// return strtoul( AssertValue(r, row, col), 0, 10 );
//}
//
//
//unsigned int PostgreSQLConnector::AssertValueUInt(PGresult * r, int row, int col)
//{
// return (unsigned int)strtoul( AssertValue(r, row, col), 0, 10 );
//}
//
//
//
//PT::Date PostgreSQLConnector::AssertValueDate(PGresult * r, int row, int col)
//{
// PT::Date date = AssertValue(r, row, col);
//
//return date;
//}
//
//
//bool PostgreSQLConnector::AssertValueSpace(PGresult * r, int row, int col, PT::Space & space)
//{
// const char * res = AssertValue(r, row, col);
//
// conf_parser.SetSpace(space);
// space.Clear();
//
// PT::SpaceParser::Status status = conf_parser.ParseString(res);
//
// if( status != PT::SpaceParser::ok )
// {
// log << log1 << "Db: a problem with parsing a PT::Space";
//
// if( status == PT::SpaceParser::syntax_error )
// log << ", syntax error at line: " << conf_parser.line;
//
// log << logend;
//
// space.Clear();
// return false;
// }
//
//return true;
//}
//
//
void PostgreSQLConnector::clear_result()
{
if( last_result )
{
PQclear(last_result);
last_result = nullptr;
}
}
bool PostgreSQLConnector::is_null(int row, int col)
{
if( last_result )
{
return PQgetisnull(last_result, row, col) == 1;
}
return true;
}
//int PostgreSQLConnector::Rows(PGresult * r)
//{
// // PQntuples - Returns the number of rows (tuples) in the query result. Because it returns
@ -379,7 +213,6 @@ bool PostgreSQLConnector::is_null(int row, int col)
// return PQnfields(r);
//}
//long PostgreSQLConnector::AffectedRows(PGresult * r)
//{
// // PQcmdTuples - This function returns a string containing the number of rows affected by the SQL
@ -404,27 +237,126 @@ bool PostgreSQLConnector::is_null(int row, int col)
//}
//long PostgreSQLConnector::AssertCurrval(const char * table)
void PostgreSQLConnector::set_current_row_at_beginning()
{
cur_row = 0;
}
void PostgreSQLConnector::advance_current_row()
{
cur_row += 1;
}
int PostgreSQLConnector::get_column_index(const char * column_name)
{
int c = PQfnumber(last_result, column_name);
// returns -1 if there is no such a column
return c;
}
int PostgreSQLConnector::get_column_index(const wchar_t * column_name)
{
// temporary
std::string s; // move me somewhere?
PT::WideToUTF8(column_name, s);
return get_column_index(s.c_str());
}
const char * PostgreSQLConnector::get_value(int row, int col)
{
const char * res = PQgetvalue(last_result, row, col);
// can return a null pointer if there is no such an item in the last result
return res;
}
int PostgreSQLConnector::get_value_length(int row, int col)
{
int len = PQgetlength(last_result, row, col);
return len;
}
//void PostgreSQLConnector::get_value_bin(int row, int col, std::string & result, bool clear_string)
//{
// PGresult * r;
// if( clear_string )
// result.clear();
//
// bquery.Clear();
// bquery << R("select currval(")
// << table
// << R(");");
// const char * raw_result = get_value(row, col);
//
// r = AssertQuery(bquery);
// AssertResult(r, PGRES_TUPLES_OK);
//
// if( Rows(r) != 1 )
// if( raw_result )
// {
// log << log1 << "Db: error (currval) for table: " << table << ", " << PQerrorMessage(db_conn->GetPgConn()) << logend;
// throw Error(WINIX_ERR_DB_ERR_CURRVAL);
// int len = PQgetlength(last_result, row, col);
//
// if( len > 0 )
// {
// unescape_bin(raw_result, len, result);
// }
// }
//}
//bool PostgreSQLConnector::AssertValueSpace(PGresult * r, int row, int col, PT::Space & space)
//{
// const char * res = AssertValue(r, row, col);
//
// conf_parser.SetSpace(space);
// space.Clear();
//
// PT::SpaceParser::Status status = conf_parser.ParseString(res);
//
// if( status != PT::SpaceParser::ok )
// {
// log << log1 << "Db: a problem with parsing a PT::Space";
//
// if( status == PT::SpaceParser::syntax_error )
// log << ", syntax error at line: " << conf_parser.line;
//
// log << logend;
//
// space.Clear();
// return false;
// }
//
//return AssertValueLong(r, 0, 0);
//return true;
//}
//
void PostgreSQLConnector::clear_result()
{
if( last_result )
{
PQclear(last_result);
last_result = nullptr;
last_result_rows = 0;
}
}
bool PostgreSQLConnector::is_null(int row, int col)
{
if( last_result )
{
return PQgetisnull(last_result, row, col) == 1;
}
return true;
}
@ -665,23 +597,27 @@ void PostgreSQLConnector::connect()
{
close();
stream.clear();
stream << "dbname='";
db_expression->esc(db_database, stream);
allocate_default_expression_if_needed();
stream << "' user='";
db_expression->esc(db_user, stream);
if( db_expression )
{
stream.clear();
stream << "dbname='";
db_expression->esc(db_database, stream);
stream << "' password='";
db_expression->esc(db_pass, stream);
stream << "'";
stream << "' user='";
db_expression->esc(db_user, stream);
std::string str;
stream.to_string(str);
pg_conn = PQconnectdb(str.c_str());
stream << "' password='";
db_expression->esc(db_pass, stream);
stream << "'";
overwrite(stream);
std::string str;
stream.to_string(str);
pg_conn = PQconnectdb(str.c_str());
overwrite(stream);
}
// warning! pg_conn can be not null but there cannnot be a connection established
// use PQstatus(pg_conn) to check whether the connection works fine
}
@ -692,13 +628,13 @@ void PostgreSQLConnector::connect()
void PostgreSQLConnector::log_connection_socket()
{
//log << log2 << "Db: connection to the database works fine" << logend;
//log << log3 << "Db: connection socket: " << PQsocket(pg_conn) << logend;
if( pg_conn )
{
std::cout << "Db: connection to the database works fine" << std::endl;
std::cout << "Db: connection socket: " << PQsocket(pg_conn) << std::endl;
//log << log2 << "Db: connection to the database works fine" << logend;
//log << log3 << "Db: connection socket: " << PQsocket(pg_conn) << logend;
//std::cout << "Db: connection to the database works fine" << std::endl;
//std::cout << "Db: connection socket: " << PQsocket(pg_conn) << std::endl;
}
}
@ -707,7 +643,7 @@ void PostgreSQLConnector::wait_for_connection()
if( !pg_conn || PQstatus(pg_conn) != CONNECTION_OK )
{
//log << log3 << "Db: waiting for the db to be ready...." << logend << logsave;
std::cout << "Db: waiting for the db to be ready...." << std::endl;
//std::cout << "Db: waiting for the db to be ready...." << std::endl;
while( !assert_connection(false, false) )
{
@ -726,6 +662,8 @@ void PostgreSQLConnector::close()
{
PQfinish(pg_conn);
pg_conn = nullptr;
last_result = nullptr;
last_result_rows = 0;
}
}
@ -746,7 +684,7 @@ bool was_connection = true;
if( put_log )
{
//log << log2 << "Db: connection to the database is lost, trying to recover" << logend;
std::cout << "Db: connection to the database is lost, trying to recover" << std::endl;
//std::cout << "Db: connection to the database is lost, trying to recover" << std::endl;
}
was_connection = false;
@ -771,7 +709,7 @@ bool was_connection = true;
if( put_log )
{
//log << log1 << "Db: connection to db server cannot be established" << logend;
std::cout << "Db: connection to db server cannot be established" << std::endl;
//std::cout << "Db: connection to db server cannot be established" << std::endl;
}
if( throw_if_no_connection )
@ -789,9 +727,28 @@ void PostgreSQLConnector::set_db_parameters()
if( PQsetClientEncoding(pg_conn, "UTF8") == -1 )
{
//log << log1 << "Db: Can't set the proper client encoding" << logend;
std::cout << "Db: Can't set the proper client encoding" << std::endl;
//std::cout << "Db: Can't set the proper client encoding" << std::endl;
}
}
const char * PostgreSQLConnector::get_field_string_value(const wchar_t * field_name)
{
int c = get_column_index(field_name);
if( c != -1 )
{
if( cur_row < last_result_rows )
{
return get_value(cur_row, c);
}
}
return nullptr;
}
}

View File

@ -64,7 +64,12 @@ public:
bool query_update(const PT::TextStream & stream);
bool query_insert(const PT::TextStream & stream);
void map_values_from_query(Model & model);
// give me a better name
virtual size_t last_select_size();
// give me a better name
virtual void set_current_row_at_beginning();
virtual void advance_current_row();
bool is_last_result(ExecStatusType t);
@ -75,6 +80,7 @@ public:
*
*/
int get_column_index(const char * column_name);
int get_column_index(const wchar_t * column_name);
bool is_null(int row, int col);
@ -84,10 +90,8 @@ public:
*
*/
const char * get_value(int row, int col);
int get_value_length(int row, int col);
bool get_value(int row, int col, std::string & result, bool clear_string = true);
bool get_value(int row, int col, std::wstring & result, bool clear_string = true);
void get_value_bin(int row, int col, std::string & result, bool clear_string = true);
void clear_result();
@ -106,10 +110,12 @@ protected:
PGconn * pg_conn;
PGresult * last_result; // can be null
size_t last_result_rows; // how many rows in the last result query
ExecStatusType last_status;
bool log_queries;
PT::TextStream stream;
std::string query_str;
size_t cur_row;
std::wstring db_database;
std::wstring db_user;
@ -119,6 +125,9 @@ protected:
void allocate_default_expression();
void overwrite(PT::TextStream & stream);
virtual const char * get_field_string_value(const wchar_t * field_name);
const char * query_last_sequence(const wchar_t * sequence_table_name);
};
}