merge from branches/join_models

(added possibility to fetch Model objects when they are used as a field in a Model class)




git-svn-id: svn://ttmath.org/publicrep/morm/trunk@1196 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2019-07-20 18:04:37 +00:00
commit 0a324a38ce
25 changed files with 1186 additions and 381 deletions

View File

@ -6,11 +6,12 @@ baseexpression.o: ../../pikotools/textstream/types.h
baseexpression.o: ../../pikotools/date/date.h
baseexpression.o: ../../pikotools/convert/inttostr.h
baseexpression.o: ../../pikotools/membuffer/membuffer.h
baseexpression.o: ../../pikotools/textstream/types.h morm_types.h model.h
baseexpression.o: modelconnector.h clearer.h dbconnector.h
baseexpression.o: ../../pikotools/textstream/types.h morm_types.h modelenv.h
baseexpression.o: modeldata.h cursorhelper.h queryresult.h finderhelper.h
baseexpression.o: model.h modelconnector.h clearer.h dbconnector.h
baseexpression.o: ../../pikotools/log/log.h ../../pikotools/log/filelog.h
baseexpression.o: queryresult.h flatconnector.h dbexpression.h
baseexpression.o: flatexpression.h modeldata.h ../../pikotools/utf8/utf8.h
baseexpression.o: flatconnector.h dbexpression.h flatexpression.h
baseexpression.o: ../../pikotools/utf8/utf8.h
clearer.o: clearer.h ../../pikotools/date/date.h
clearer.o: ../../pikotools/convert/inttostr.h model.h
clearer.o: ../../pikotools/textstream/textstream.h
@ -19,7 +20,8 @@ clearer.o: ../../pikotools/membuffer/membuffer.h
clearer.o: ../../pikotools/textstream/types.h modelconnector.h dbconnector.h
clearer.o: ../../pikotools/log/log.h ../../pikotools/log/filelog.h
clearer.o: queryresult.h flatconnector.h dbexpression.h baseexpression.h
clearer.o: morm_types.h flatexpression.h modeldata.h
clearer.o: morm_types.h modelenv.h modeldata.h cursorhelper.h finderhelper.h
clearer.o: flatexpression.h
dbconnector.o: dbconnector.h ../../pikotools/textstream/textstream.h
dbconnector.o: ../../pikotools/space/space.h
dbconnector.o: ../../pikotools/textstream/types.h ../../pikotools/date/date.h
@ -27,8 +29,9 @@ dbconnector.o: ../../pikotools/convert/inttostr.h
dbconnector.o: ../../pikotools/membuffer/membuffer.h
dbconnector.o: ../../pikotools/textstream/types.h ../../pikotools/log/log.h
dbconnector.o: ../../pikotools/log/filelog.h queryresult.h dbexpression.h
dbconnector.o: baseexpression.h morm_types.h model.h modelconnector.h
dbconnector.o: clearer.h flatconnector.h flatexpression.h modeldata.h
dbconnector.o: baseexpression.h morm_types.h modelenv.h modeldata.h
dbconnector.o: cursorhelper.h finderhelper.h model.h modelconnector.h
dbconnector.o: clearer.h flatconnector.h flatexpression.h
dbconnector.o: ../../pikotools/utf8/utf8.h ../../pikotools/convert/convert.h
dbconnector.o: ../../pikotools/convert/inttostr.h
dbconnector.o: ../../pikotools/convert/patternreplacer.h
@ -41,7 +44,8 @@ dbexpression.o: ../../pikotools/textstream/types.h
dbexpression.o: ../../pikotools/date/date.h
dbexpression.o: ../../pikotools/convert/inttostr.h
dbexpression.o: ../../pikotools/membuffer/membuffer.h
dbexpression.o: ../../pikotools/textstream/types.h morm_types.h
dbexpression.o: ../../pikotools/textstream/types.h morm_types.h modelenv.h
dbexpression.o: modeldata.h cursorhelper.h queryresult.h finderhelper.h
dochtmlconnector.o: dochtmlconnector.h flatconnector.h
dochtmlconnector.o: ../../pikotools/textstream/textstream.h
dochtmlconnector.o: ../../pikotools/space/space.h
@ -50,7 +54,8 @@ dochtmlconnector.o: ../../pikotools/date/date.h
dochtmlconnector.o: ../../pikotools/convert/inttostr.h
dochtmlconnector.o: ../../pikotools/membuffer/membuffer.h
dochtmlconnector.o: ../../pikotools/textstream/types.h dochtmlexpression.h
dochtmlconnector.o: flatexpression.h baseexpression.h morm_types.h
dochtmlconnector.o: flatexpression.h baseexpression.h morm_types.h modelenv.h
dochtmlconnector.o: modeldata.h cursorhelper.h queryresult.h finderhelper.h
dochtmlexpression.o: dochtmlexpression.h flatexpression.h baseexpression.h
dochtmlexpression.o: ../../pikotools/textstream/textstream.h
dochtmlexpression.o: ../../pikotools/space/space.h
@ -59,6 +64,8 @@ dochtmlexpression.o: ../../pikotools/date/date.h
dochtmlexpression.o: ../../pikotools/convert/inttostr.h
dochtmlexpression.o: ../../pikotools/membuffer/membuffer.h
dochtmlexpression.o: ../../pikotools/textstream/types.h morm_types.h
dochtmlexpression.o: modelenv.h modeldata.h cursorhelper.h queryresult.h
dochtmlexpression.o: finderhelper.h
flatconnector.o: flatconnector.h ../../pikotools/textstream/textstream.h
flatconnector.o: ../../pikotools/space/space.h
flatconnector.o: ../../pikotools/textstream/types.h
@ -66,10 +73,11 @@ flatconnector.o: ../../pikotools/date/date.h
flatconnector.o: ../../pikotools/convert/inttostr.h
flatconnector.o: ../../pikotools/membuffer/membuffer.h
flatconnector.o: ../../pikotools/textstream/types.h flatexpression.h
flatconnector.o: baseexpression.h morm_types.h model.h modelconnector.h
flatconnector.o: clearer.h dbconnector.h ../../pikotools/log/log.h
flatconnector.o: ../../pikotools/log/filelog.h queryresult.h dbexpression.h
flatconnector.o: modeldata.h
flatconnector.o: baseexpression.h morm_types.h modelenv.h modeldata.h
flatconnector.o: cursorhelper.h queryresult.h finderhelper.h model.h
flatconnector.o: modelconnector.h clearer.h dbconnector.h
flatconnector.o: ../../pikotools/log/log.h ../../pikotools/log/filelog.h
flatconnector.o: dbexpression.h
flatexpression.o: flatexpression.h baseexpression.h
flatexpression.o: ../../pikotools/textstream/textstream.h
flatexpression.o: ../../pikotools/space/space.h
@ -77,7 +85,8 @@ flatexpression.o: ../../pikotools/textstream/types.h
flatexpression.o: ../../pikotools/date/date.h
flatexpression.o: ../../pikotools/convert/inttostr.h
flatexpression.o: ../../pikotools/membuffer/membuffer.h
flatexpression.o: ../../pikotools/textstream/types.h morm_types.h
flatexpression.o: ../../pikotools/textstream/types.h morm_types.h modelenv.h
flatexpression.o: modeldata.h cursorhelper.h queryresult.h finderhelper.h
jsonconnector.o: jsonconnector.h flatconnector.h
jsonconnector.o: ../../pikotools/textstream/textstream.h
jsonconnector.o: ../../pikotools/space/space.h
@ -86,7 +95,8 @@ jsonconnector.o: ../../pikotools/date/date.h
jsonconnector.o: ../../pikotools/convert/inttostr.h
jsonconnector.o: ../../pikotools/membuffer/membuffer.h
jsonconnector.o: ../../pikotools/textstream/types.h jsonexpression.h
jsonconnector.o: flatexpression.h baseexpression.h morm_types.h
jsonconnector.o: flatexpression.h baseexpression.h morm_types.h modelenv.h
jsonconnector.o: modeldata.h cursorhelper.h queryresult.h finderhelper.h
jsonexpression.o: jsonexpression.h flatexpression.h baseexpression.h
jsonexpression.o: ../../pikotools/textstream/textstream.h
jsonexpression.o: ../../pikotools/space/space.h
@ -94,7 +104,8 @@ jsonexpression.o: ../../pikotools/textstream/types.h
jsonexpression.o: ../../pikotools/date/date.h
jsonexpression.o: ../../pikotools/convert/inttostr.h
jsonexpression.o: ../../pikotools/membuffer/membuffer.h
jsonexpression.o: ../../pikotools/textstream/types.h morm_types.h
jsonexpression.o: ../../pikotools/textstream/types.h morm_types.h modelenv.h
jsonexpression.o: modeldata.h cursorhelper.h queryresult.h finderhelper.h
model.o: model.h ../../pikotools/textstream/textstream.h
model.o: ../../pikotools/space/space.h ../../pikotools/textstream/types.h
model.o: ../../pikotools/date/date.h ../../pikotools/convert/inttostr.h
@ -102,8 +113,8 @@ model.o: ../../pikotools/membuffer/membuffer.h
model.o: ../../pikotools/textstream/types.h modelconnector.h clearer.h
model.o: dbconnector.h ../../pikotools/log/log.h
model.o: ../../pikotools/log/filelog.h queryresult.h flatconnector.h
model.o: dbexpression.h baseexpression.h morm_types.h flatexpression.h
model.o: modeldata.h
model.o: dbexpression.h baseexpression.h morm_types.h modelenv.h modeldata.h
model.o: cursorhelper.h finderhelper.h flatexpression.h
modelconnector.o: modelconnector.h clearer.h ../../pikotools/date/date.h
modelconnector.o: ../../pikotools/convert/inttostr.h dbconnector.h
modelconnector.o: ../../pikotools/textstream/textstream.h
@ -125,7 +136,8 @@ postgresqlconnector.o: ../../pikotools/log/log.h
postgresqlconnector.o: ../../pikotools/log/filelog.h queryresult.h
postgresqlconnector.o: postgresqlqueryresult.h ../../pikotools/utf8/utf8.h
postgresqlconnector.o: postgresqlexpression.h dbexpression.h baseexpression.h
postgresqlconnector.o: morm_types.h ../../pikotools/convert/strtoint.h
postgresqlconnector.o: morm_types.h modelenv.h modeldata.h cursorhelper.h
postgresqlconnector.o: finderhelper.h ../../pikotools/convert/strtoint.h
postgresqlconnector.o: ../../pikotools/convert/text.h
postgresqlconnector.o: ../../pikotools/convert/misc.h
postgresqlexpression.o: postgresqlexpression.h dbexpression.h
@ -137,6 +149,8 @@ postgresqlexpression.o: ../../pikotools/date/date.h
postgresqlexpression.o: ../../pikotools/convert/inttostr.h
postgresqlexpression.o: ../../pikotools/membuffer/membuffer.h
postgresqlexpression.o: ../../pikotools/textstream/types.h morm_types.h
postgresqlexpression.o: modelenv.h modeldata.h cursorhelper.h queryresult.h
postgresqlexpression.o: finderhelper.h
postgresqlqueryresult.o: postgresqlqueryresult.h queryresult.h
queryresult.o: queryresult.h ../../pikotools/utf8/utf8.h
queryresult.o: ../../pikotools/textstream/textstream.h

View File

@ -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
@ -44,9 +44,7 @@ namespace morm
BaseExpression::BaseExpression()
{
out_stream = nullptr;
is_first_field = false;
work_mode = 0;
clear();
}
BaseExpression::~BaseExpression()
@ -54,32 +52,47 @@ BaseExpression::~BaseExpression()
}
void BaseExpression::clear()
{
out_stream = nullptr;
is_first_field = false;
work_mode = 0;
use_prefix = false;
}
void BaseExpression::set_work_mode(int work_mode)
{
this->work_mode = work_mode;
}
void BaseExpression::prepare_to_new_expression()
int BaseExpression::get_work_mode()
{
column_prefix.clear();
out_stream = nullptr;
is_first_field = false;
work_mode = 0;
return work_mode;
}
PT::TextStream * BaseExpression::get_current_stream()
{
return out_stream;
}
void BaseExpression::set_column_prefix(const std::wstring & prefix)
void BaseExpression::allow_to_use_prefix(bool use_prefix)
{
column_prefix = prefix;
this->use_prefix = use_prefix;
}
bool BaseExpression::get_allow_to_use_prefix()
{
return use_prefix;
}
void BaseExpression::generate_from_model(PT::TextStream & stream, Model & model)
{
this->out_stream = &stream;
@ -144,14 +157,80 @@ void BaseExpression::field_after()
}
void BaseExpression::put_field_name(const wchar_t * field_name, bool add_column_prefix)
bool BaseExpression::is_long_field_name(const wchar_t * field_name)
{
bool is_long = false;
while( *field_name != 0 )
{
if( *field_name == '.' )
{
is_long = true;
break;
}
field_name += 1;
}
return is_long;
}
bool BaseExpression::is_long_field_name(const PT::TextStream & field_name)
{
PT::TextStream::const_iterator i = field_name.begin();
bool is_long = false;
while( i != field_name.end() )
{
if( *i == '.' )
{
is_long = true;
break;
}
++i;
}
return is_long;
}
bool BaseExpression::is_long_table_name(const wchar_t * table_name)
{
return is_long_field_name(table_name);
}
bool BaseExpression::is_long_table_name(const PT::TextStream & table_name)
{
return is_long_field_name(table_name);
}
bool BaseExpression::need_to_add_field_prefix(const wchar_t * field_name)
{
return !is_long_field_name(field_name);
}
void BaseExpression::put_field_name(const wchar_t * field_name, ModelEnv * model_env)
{
before_field_name();
if( add_column_prefix && !column_prefix.empty() )
if( use_prefix && model_env )
{
esc(column_prefix, *out_stream);
(*out_stream) << '.';
if( need_to_add_field_prefix(field_name) )
{
esc(model_env->table_name_short, *out_stream);
if( model_env->table_index > 1 )
{
(*out_stream) << model_env->table_index;
}
(*out_stream) << '.';
}
}
esc(field_name, *out_stream);
@ -159,15 +238,30 @@ void BaseExpression::put_field_name(const wchar_t * field_name, bool add_column_
}
void BaseExpression::put_field_doc(Model & model, const void * field_pointer, bool insertable, bool updatable, bool is_primary_key, ModelData * model_data)
void BaseExpression::save_foreign_key(const wchar_t * field_name, ModelEnv * model_env)
{
model.doc_field_pointer = field_pointer;
model.model_data = model_data;
PT::TextStream str;
PT::TextStream * old_out_stream = out_stream;
out_stream = &str;
put_field_name(field_name, model_env);
out_stream = old_out_stream;
if( model_env && model_env->finder_helper )
{
model_env->finder_helper->foreign_keys.emplace_back();
std::string & key_str = model_env->finder_helper->foreign_keys.back();
str.to_string(key_str, false);
}
}
void BaseExpression::put_field_doc(Model & model, const void * field_pointer, bool insertable, bool updatable, bool is_primary_key, ModelEnv * model_env)
{
//model.doc_field_pointer = field_pointer;
model.model_env = model_env;
model.map_doc_fields();
model.model_data = nullptr;
model.doc_field_pointer = nullptr;
model.model_env = nullptr;
//model.doc_field_pointer = nullptr;
}
void BaseExpression::before_field_name()
@ -379,6 +473,16 @@ void BaseExpression::esc(const PT::Date & date, PT::TextStream & stream)
stream << date;
}
void BaseExpression::esc(const PT::TextStream & val, PT::TextStream & stream)
{
PT::TextStream::const_iterator i = val.begin();
for(; i != val.end() ; ++i)
{
esc(*i, stream);
}
}
void BaseExpression::put_type(char val, PT::TextStream & stream)
{

View File

@ -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
@ -38,14 +38,15 @@
#include <list>
#include <set>
#include "textstream/textstream.h"
#include "morm_types.h"
#include "date/date.h"
#include "morm_types.h"
#include "modelenv.h"
namespace morm
{
class Model;
class ModelData;
class ModelConnector;
@ -57,21 +58,25 @@ public:
virtual ~BaseExpression();
virtual void set_work_mode(int work_mode);
virtual void prepare_to_new_expression();
virtual void set_column_prefix(const std::wstring & prefix);
virtual int get_work_mode();
virtual void clear();
virtual void generate_from_model(PT::TextStream & stream, Model & model);
virtual PT::TextStream * get_current_stream();
// rename me
virtual void allow_to_use_prefix(bool use_prefix);
virtual bool get_allow_to_use_prefix();
// give me a better name
virtual void put_field_doc(Model & model, const void * field_pointer, bool insertable, bool updatable, bool is_primary_key, ModelData * model_data);
virtual void put_field_doc(Model & model, const void * field_pointer, bool insertable, bool updatable, bool is_primary_key, ModelEnv * model_env);
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, bool add_column_prefix = true)
void field(const wchar_t * field_name, const FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key, ModelEnv * model_env)
{
if( out_stream && can_field_be_generated(insertable, updatable, is_primary_key) )
{
@ -79,7 +84,12 @@ public:
if( work_mode == MORM_WORK_MODE_MODEL_FIELDS )
{
put_field_name(field_name, add_column_prefix);
put_field_name(field_name, model_env);
}
else
if( work_mode == MORM_WORK_MODE_MODEL_SAVE_FIELDS )
{
save_foreign_key(field_name, model_env);
}
else
if( work_mode == MORM_WORK_MODE_MODEL_VALUES )
@ -89,29 +99,29 @@ public:
else
if( work_mode == MORM_WORK_MODE_MODEL_FIELDS_VALUES )
{
put_field_name(field_name);
put_field_name(field_name, model_env);
put_name_value_separator();
put_field_value(field_value);
}
field_after();
}
}
template<typename FieldValue>
void field_doc(Model & model, const wchar_t * field_name, const FieldValue & field_value,
bool insertable = true, bool updatable = true,
bool is_primary_key = false, bool add_column_prefix = true,
ModelData * model_data = nullptr)
void field_doc(Model & model, const wchar_t * field_name, const FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key, ModelEnv * model_env)
{
if( out_stream )
{
field_before();
put_field_name(field_name, add_column_prefix);
put_field_name(field_name, model_env);
put_name_value_separator();
put_field_doc(model, reinterpret_cast<const void*>(&field_value), insertable, updatable, is_primary_key, model_data);
put_field_doc(model, reinterpret_cast<const void*>(&field_value), insertable, updatable, is_primary_key, model_env);
put_name_value_separator();
put_type(field_value, *out_stream);
@ -121,48 +131,45 @@ 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, bool add_column_prefix = true)
void field_in(PT::TextStream & stream, const wchar_t * field_name, const std::set<FieldValue> & container, ModelEnv * model_env)
{
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, add_column_prefix);
}
*/
template<typename FieldValue>
void field_in(PT::TextStream & stream, const wchar_t * field_name, const std::set<FieldValue> & container)
{
field_in_generic<FieldValue, std::set<FieldValue>>(stream, field_name, container);
field_in_generic<FieldValue, std::set<FieldValue>>(stream, field_name, container, model_env);
}
template<typename FieldValue>
void field_in(PT::TextStream & stream, const wchar_t * field_name, const std::list<FieldValue> & container)
{
field_in_generic<FieldValue, std::list<FieldValue>>(stream, field_name, container);
}
template<typename FieldValue>
void field_in(PT::TextStream & stream, const wchar_t * field_name, const std::vector<FieldValue> & container)
void field_in(PT::TextStream & stream, const wchar_t * field_name, const std::list<FieldValue> & container, ModelEnv * model_env)
{
field_in_generic<FieldValue, std::vector<FieldValue>>(stream, field_name, container);
field_in_generic<FieldValue, std::list<FieldValue>>(stream, field_name, container, model_env);
}
template<typename FieldValue>
void field_in(PT::TextStream & stream, const wchar_t * field_name, const std::vector<FieldValue> & container, ModelEnv * model_env)
{
field_in_generic<FieldValue, std::vector<FieldValue>>(stream, field_name, container, model_env);
}
template<typename ModelContainer>
void field_list(const wchar_t * field_name, ModelContainer & field_value, bool insertable, bool updatable, bool is_primary_key,
ModelConnector * model_connector, int model_connector_mode, ModelData * model_data)
ModelConnector * model_connector, ModelEnv * model_env)
{
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_FIELDS_VALUES )
{
put_field_name(field_name);
put_field_name(field_name, model_env);
put_name_value_separator();
put_field_value_list(field_value, model_connector, model_connector_mode, model_data);
put_field_value_list(field_value, model_connector, model_env);
}
field_after();
@ -170,7 +177,7 @@ public:
}
template<typename ModelClass>
void field_model(const wchar_t * field_name, ModelClass & field_model, bool insertable = true, bool updatable = true, bool is_primary_key = false)
void field_model(const wchar_t * field_name, ModelClass & field_model, bool insertable, bool updatable, bool is_primary_key, ModelEnv * model_env)
{
if( out_stream && can_field_be_generated(insertable, updatable, is_primary_key) )
{
@ -178,7 +185,7 @@ public:
if( work_mode == MORM_WORK_MODE_MODEL_FIELDS )
{
put_field_name(field_name);
put_field_name(field_name, model_env);
}
else
if( work_mode == MORM_WORK_MODE_MODEL_VALUES )
@ -188,7 +195,7 @@ public:
else
if( work_mode == MORM_WORK_MODE_MODEL_FIELDS_VALUES )
{
put_field_name(field_name);
put_field_name(field_name, model_env);
put_name_value_separator();
generate_from_model(field_model);
}
@ -198,10 +205,11 @@ public:
}
template<typename FieldValue>
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)
void field_to_stream(PT::TextStream & stream, const wchar_t * field_name, const FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key,
ModelEnv * model_env)
{
this->out_stream = &stream;
field(field_name, field_value, insertable, updatable, is_primary_key);
field(field_name, field_value, insertable, updatable, is_primary_key, model_env);
this->out_stream = nullptr;
}
@ -231,7 +239,13 @@ public:
//virtual void esc(void* val, PT::TextStream & stream);
virtual void esc(const PT::Date & date, PT::TextStream & stream);
virtual void esc(const PT::TextStream & val,PT::TextStream & stream);
virtual bool is_long_field_name(const wchar_t * field_name);
virtual bool is_long_field_name(const PT::TextStream & table_name);
virtual bool is_long_table_name(const wchar_t * field_name);
virtual bool is_long_table_name(const PT::TextStream & table_name);
@ -240,15 +254,9 @@ protected:
int work_mode; /* what to do: generating fields list, values list or fields-values list */
bool is_first_field;
// niech Stream bedzie jakims interfejsem z operatorami << dla standardowych typow
// albo w pikotoolsach dodać klase bazowa (intefejs) dla streamow
// i dodatkowo dodac loger ktory dziedziczy po niej i dodaje loglevel i endline
// jako metode bazowa dodac format("string", parametry,...)
// przyda sie do formatowania doubli
PT::TextStream * out_stream;
std::wstring column_prefix;
bool use_prefix;
virtual void generate_from_model(Model & model);
@ -260,7 +268,12 @@ protected:
//void field(const wchar_t * field_name, Model & field, bool insertable = true, bool updatable = true);
virtual void put_field_name(const wchar_t * field_name, bool add_column_prefix = true);
virtual bool need_to_add_field_prefix(const wchar_t * field_name);
virtual void put_field_name(const wchar_t * field_name, ModelEnv * model_env);
virtual void save_foreign_key(const wchar_t * field_name, ModelEnv * model_env);
template<typename FieldValue>
void put_field_value(const FieldValue & field_value)
@ -273,49 +286,66 @@ protected:
}
}
virtual void before_field_value_list()
{
}
virtual void after_field_value_list()
{
}
virtual void field_value_list_separator()
{
(*out_stream) << ",";
}
virtual void put_statement_in_starts()
{
(*out_stream) << "(";
}
virtual void put_statement_in_ends()
{
(*out_stream) << ") ";
}
// what about lists with a pod types? e.g. list<int>
template<typename ModelContainer>
void put_field_value_list(ModelContainer & field_value, ModelConnector * model_connector, int model_connector_mode, ModelData * model_data)
void put_field_value_list(ModelContainer & field_value, ModelConnector * model_connector, ModelEnv * model_env)
{
if( out_stream )
if( model_connector && model_env && out_stream )
{
(*out_stream) << "[";// make a virtual method
}
bool is_first = true;
before_field_value_list();
bool is_first = true;
for(auto & m : field_value)
{
if( out_stream )
for(auto & m : field_value)
{
if( !is_first )
{
if( out_stream )
(*out_stream) << ","; // make a virtual method
field_value_list_separator();
}
ModelEnv model_env_local(*model_env);
m.model_env = &model_env_local;
//before_field_value(field_value);
m.set_connector(model_connector);
m.model_connector_mode = model_connector_mode;
m.model_data = model_data;
generate_from_model(m);
m.model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
m.model_data = nullptr;
m.model_env = nullptr;
//after_field_value(field_value);
is_first = false;
}
}
if( out_stream )
{
(*out_stream) << "]";// make a virtual method
after_field_value_list();
}
}
// used in 'in()' statements, may should be renamed?
template<typename FieldValue, typename Container>
void field_in_generic(PT::TextStream & stream, const wchar_t * field_name, const Container & container)
void field_in_generic(PT::TextStream & stream, const wchar_t * field_name, const Container & container, ModelEnv * model_env)
{
// IMPROVE ME
// what about if container is empty?
@ -323,24 +353,24 @@ protected:
this->out_stream = &stream;
field_before();
put_field_name(field_name);
put_field_name(field_name, model_env);
put_name_value_separator();
bool is_first = true;
(*out_stream) << "(";
put_statement_in_starts();
for(const FieldValue & v : container)
{
if( !is_first )
{
(*out_stream) << ",";
field_value_list_separator();
}
put_field_value(v);
is_first = false;
}
(*out_stream) << ") ";
put_statement_in_ends();
field_after();
this->out_stream = nullptr;
}

View File

@ -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
@ -51,7 +51,8 @@ public:
Cursor()
{
set_default_values();
query_result = nullptr;
clear();
}
@ -59,6 +60,7 @@ public:
{
model_connector = c.model_connector;
model_data = c.model_data;
has_autogenerated_select = c.has_autogenerated_select;
query_result = c.query_result;
select_status = c.select_status;
@ -66,6 +68,9 @@ public:
{
query_result->references_count += 1;
}
// helper doesn't have to be copied
cursor_helper.clear();
}
@ -91,7 +96,13 @@ public:
delete query_result;
}
set_default_values();
model_connector = nullptr;
model_data = nullptr;
has_autogenerated_select = false;
cursor_helper.clear();
query_result = nullptr;
select_status = false;
}
@ -119,6 +130,12 @@ public:
}
virtual void set_has_autogenerated_select(bool has_autogenerated_select)
{
this->has_autogenerated_select = has_autogenerated_select;
}
virtual QueryResult * get_query_result()
{
return query_result;
@ -150,9 +167,17 @@ public:
if( db_connector )
{
ModelEnv model_env_local;
result.model_env = &model_env_local;
result.model_env->cursor_helper = &cursor_helper;
try
{
result.model_data = model_data;
cursor_helper.clear();
cursor_helper.query_result = query_result;
cursor_helper.has_autogenerated_select = has_autogenerated_select;
result.model_env->model_data = model_data;
result.before_select();
res = select_status;
@ -161,7 +186,7 @@ public:
if( query_result->cur_row < query_result->result_rows )
{
result.set_save_mode(Model::DO_UPDATE_ON_SAVE); // IMPROVE ME check if there is a primary key
result.map_values_from_query(query_result);
result.map_values_from_query();
result.after_select();
query_result->cur_row += 1;
}
@ -182,7 +207,7 @@ public:
// throw something?
}
result.model_data = nullptr;
result.model_env = nullptr;
}
}
@ -195,7 +220,7 @@ public:
ModelClass model;
get(model);
return std::move(model);
return model;
}
@ -258,17 +283,12 @@ protected:
ModelConnector * model_connector;
ModelData * model_data;
bool has_autogenerated_select;
CursorHelper cursor_helper;
QueryResult * query_result;
bool select_status;
virtual void set_default_values()
{
model_connector = nullptr;
model_data = nullptr;
query_result = nullptr;
select_status = false;
}
template<typename ContainerType>
@ -281,14 +301,23 @@ protected:
result.emplace_back(); // it returns a reference from c++17
ModelClass & added_model = result.back();
ModelEnv model_env_local;
try
{
cursor_helper.clear();
cursor_helper.query_result = query_result;
cursor_helper.has_autogenerated_select = has_autogenerated_select;
added_model.set_connector(model_connector);
added_model.clear();
added_model.model_env = &model_env_local;
added_model.model_env->cursor_helper = &cursor_helper;
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.model_env->model_data = model_data;
added_model.before_select();
added_model.map_values_from_query(query_result);
added_model.map_values_from_query();
added_model.after_select();
}
catch(...)
@ -297,7 +326,7 @@ protected:
// throw or something?
}
added_model.model_data = nullptr;
added_model.model_env = nullptr;
}
return res;

76
src/cursorhelper.h Normal file
View File

@ -0,0 +1,76 @@
/*
* 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) 2019, 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_cursorhelper
#define headerfile_morm_cursorhelper
#include "queryresult.h"
namespace morm
{
class CursorHelper
{
public:
bool has_autogenerated_select;
QueryResult * query_result;
int current_column;
CursorHelper()
{
clear();
}
virtual ~CursorHelper()
{
}
virtual void clear()
{
has_autogenerated_select = false;
query_result = nullptr;
current_column = 0;
}
};
}
#endif

View File

@ -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
@ -49,6 +49,7 @@ DbConnector::DbConnector()
db_expression = nullptr;
expression_allocated = false;
log = nullptr;
log_queries = false;
}
DbConnector::DbConnector(const DbConnector &)
@ -70,12 +71,18 @@ void DbConnector::set_logger(PT::Log * log)
this->log = log;
}
void DbConnector::set_logger(PT::Log & log)
{
this->log = &log;
}
void DbConnector::set_log_queries(bool log_queries)
{
this->log_queries = log_queries;
}
bool DbConnector::query(const PT::TextStream & stream, QueryResult & query_result)
{
@ -151,16 +158,16 @@ DbExpression * DbConnector::get_expression()
}
void DbConnector::generate_select_columns(PT::TextStream & stream, Model & model, const std::wstring & column_prefix)
void DbConnector::generate_select_columns(PT::TextStream & stream, Model & model)
{
allocate_default_expression_if_needed();
if( db_expression )
{
db_expression->prepare_to_new_expression();
db_expression->clear();
db_expression->set_work_mode(MORM_WORK_MODE_MODEL_FIELDS);
db_expression->set_output_type(MORM_OUTPUT_TYPE_SELECT_COLUMNS);
db_expression->set_column_prefix(column_prefix);
db_expression->allow_to_use_prefix(true);
db_expression->generate_from_model(stream, model);
}
}
@ -172,7 +179,9 @@ void DbConnector::generate_insert_query(PT::TextStream & stream, Model & model)
if( db_expression )
{
db_expression->prepare_to_new_expression();
db_expression->clear();
db_expression->allow_to_use_prefix(false);
stream << "insert into ";
model.table_name(stream);
@ -195,7 +204,9 @@ void DbConnector::generate_update_query(PT::TextStream & stream, Model & model)
if( db_expression )
{
db_expression->prepare_to_new_expression();
db_expression->clear();
db_expression->allow_to_use_prefix(false);
stream << "update ";
model.table_name(stream);
@ -218,7 +229,9 @@ void DbConnector::generate_remove_query(PT::TextStream & stream, Model & model)
if( db_expression )
{
db_expression->prepare_to_new_expression();
db_expression->clear();
db_expression->allow_to_use_prefix(false);
stream << "delete from ";
model.table_name(stream);
stream << " where ";

View File

@ -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
@ -57,11 +57,13 @@ public:
virtual void set_logger(PT::Log * log);
virtual void set_logger(PT::Log & log);
virtual void set_log_queries(bool log_queries);
DbExpression * get_expression();
//virtual void clear_last_query_result();
virtual void generate_select_columns(PT::TextStream & stream, Model & model, const std::wstring & column_prefix);
virtual void generate_select_columns(PT::TextStream & stream, Model & model);
virtual void generate_insert_query(PT::TextStream & stream, Model & model);
virtual void generate_update_query(PT::TextStream & stream, Model & model);
virtual void generate_remove_query(PT::TextStream & stream, Model & model);
@ -115,6 +117,11 @@ public:
if( val_str )
{
get_value(val_str, field_value);
if( log && log_queries )
{
(*log) << PT::Log::log3 << "Morm: sequence value: " << field_value << PT::Log::logend;
}
}
}
@ -124,6 +131,7 @@ protected:
DbExpression * db_expression;
bool expression_allocated;
PT::Log * log;
bool log_queries;
virtual void allocate_default_expression() = 0;

View File

@ -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
@ -56,6 +56,12 @@ void DbExpression::set_output_type(int output_type)
}
int DbExpression::get_output_type()
{
return output_type;
}
bool DbExpression::can_field_be_generated(bool insertable, bool updatable, bool is_primary_key)
{
if( output_type == MORM_OUTPUT_TYPE_DB_INSERT )
@ -68,7 +74,7 @@ bool DbExpression::can_field_be_generated(bool insertable, bool updatable, bool
return updatable;
}
else
if( output_type == MORM_OUTPUT_TYPE_DB_PRIMARY_KEY )
if( output_type == MORM_OUTPUT_TYPE_DB_PRIMARY_KEY || output_type == MORM_OUTPUT_TYPE_JOIN_TABLES )
{
return is_primary_key;
}
@ -90,7 +96,7 @@ void DbExpression::field_before()
output_type == MORM_OUTPUT_TYPE_DB_UPDATE ||
output_type == MORM_OUTPUT_TYPE_SELECT_COLUMNS )
{
(*out_stream) << ",";
(*out_stream) << ", ";
}
else
if( output_type == MORM_OUTPUT_TYPE_DB_PRIMARY_KEY )
@ -131,27 +137,32 @@ void DbExpression::put_name_value_separator()
output_type == MORM_OUTPUT_TYPE_WHERE_EQ ||
output_type == MORM_OUTPUT_TYPE_DB_UPDATE)
{
(*out_stream) << " = ";
(*out_stream) << "=";
}
else
if( output_type == MORM_OUTPUT_TYPE_WHERE_NOT_EQ )
{
(*out_stream) << "<>";
}
else
if( output_type == MORM_OUTPUT_TYPE_WHERE_LT )
{
(*out_stream) << " < ";
(*out_stream) << "<";
}
else
if( output_type == MORM_OUTPUT_TYPE_WHERE_GT )
{
(*out_stream) << " > ";
(*out_stream) << ">";
}
else
if( output_type == MORM_OUTPUT_TYPE_WHERE_LE )
{
(*out_stream) << " <= ";
(*out_stream) << "<=";
}
else
if( output_type == MORM_OUTPUT_TYPE_WHERE_GE )
{
(*out_stream) << " >= ";
(*out_stream) << ">=";
}
else
if( output_type == MORM_OUTPUT_TYPE_WHERE_IN )
@ -290,4 +301,40 @@ DbExpression & DbExpression::page(PT::TextStream & stream, size_t page_number, s
return *this;
}
void DbExpression::prepare_short_table_name(const PT::TextStream & table_name, PT::TextStream & short_table_name)
{
short_table_name.clear();
if( is_long_table_name(table_name) )
{
PT::TextStream::const_iterator i = table_name.begin();
bool was_dot = false;
while( i != table_name.end() )
{
if( was_dot )
{
short_table_name << *i;
}
else
if( *i == '.' )
{
was_dot = true;
}
++i;
}
}
if( short_table_name.empty() )
{
short_table_name = table_name;
}
}
}

View File

@ -51,6 +51,7 @@ public:
virtual ~DbExpression();
virtual void set_output_type(int output_type);
virtual int get_output_type();
virtual void prepare_to_where_clause();
@ -61,7 +62,6 @@ public:
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)
{
@ -71,10 +71,15 @@ public:
column_expression += L" as ";
column_expression += new_column_name;
field(column_expression.c_str(), field_value, false, false, false, false);
// put nullptr to ModelEnv* to not allow to use prefix
// or may better remember current value of use_prefix and set it to false for a while?
field(column_expression.c_str(), field_value, false, false, false, nullptr);
}
virtual void prepare_short_table_name(const PT::TextStream & table_name, PT::TextStream & short_table_name);
protected:
int output_type;

View File

@ -39,6 +39,7 @@
#include <list>
#include <set>
#include "model.h"
#include "utf8/utf8.h"
#include "textstream/textstream.h"
#include "dbconnector.h"
#include "modelconnector.h"
@ -115,23 +116,6 @@ public:
protected:
void set_out_stream()
{
if( model_connector )
{
this->out_stream = model_connector->get_stream();
}
else
{
this->out_stream = nullptr;
}
}
public:
Finder<ModelClass> & set_out_stream(PT::TextStream * out_stream)
{
this->out_stream = out_stream;
@ -156,25 +140,18 @@ public:
return was_query_error;
}
std::wstring get_error_msg()
{
return last_query_error;
}
Finder<ModelClass> & prefix(const wchar_t * prefix)
{
column_prefix = prefix;
return *this;
}
Finder<ModelClass> & prepare_to_select()
{
was_query_error = false;
last_query_error.clear();
model_data = nullptr;
column_prefix.clear();
has_autogenerated_select = false;
if( model_connector )
{
@ -182,7 +159,6 @@ public:
{
set_db_expression();
out_stream->clear();
model.set_connector(model_connector);
}
else
{
@ -242,22 +218,36 @@ public:
prepare_to_select();
}
if( model_connector && out_stream )
model.set_connector(model_connector);
finder_helper.clear();
model_env.clear();
model.model_env = &model_env;
model.model_env->model_data = model_data;
model.model_env->finder_helper = &finder_helper;
has_autogenerated_select = true;
if( model_connector && out_stream && db_expression )
{
model.table_name(model.model_env->table_name);
db_expression->prepare_short_table_name(model.model_env->table_name, model.model_env->table_name_short);
model.model_env->table_index = finder_helper.add_join_table(model.model_env->table_name_short);
(*out_stream) << "SELECT ";
model.generate_select_columns(*out_stream, column_prefix);
(*out_stream) << " FROM ";
model.table_name(*out_stream);
if( !column_prefix.empty() )
(*out_stream) << " AS " << column_prefix; // what about escaping?
model.generate_select_columns(*out_stream);
(*out_stream) << " FROM " << model.model_env->table_name << " AS ";
(*out_stream) << model.model_env->table_name_short;
(*out_stream) << " ";
(*out_stream) << finder_helper.join_tables_str;
}
return *this;
}
Finder<ModelClass> & select(ModelData * model_data, bool call_prepare = true)
{
if( call_prepare )
@ -269,6 +259,7 @@ public:
return select(false);
}
Finder<ModelClass> & select(ModelData & model_data, bool call_prepare = true)
{
if( call_prepare )
@ -280,6 +271,7 @@ public:
return select(false);
}
Finder<ModelClass> & where()
{
if( out_stream && db_expression )
@ -333,20 +325,32 @@ public:
if( db_expression )
{
db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_EQ);
db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false);
db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false, &model_env);
}
return *this;
}
template<typename FieldValue>
Finder<ModelClass> & neq(const wchar_t * field_name, const FieldValue & field_value)
{
if( db_expression )
{
db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_NOT_EQ);
db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false, &model_env);
}
return *this;
}
template<typename FieldValue>
Finder<ModelClass> & lt(const wchar_t * field_name, const FieldValue & field_value)
{
if( db_expression )
{
db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_LT);
db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false);
db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false, &model_env);
}
return *this;
@ -359,7 +363,7 @@ public:
if( db_expression )
{
db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_GT);
db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false);
db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false, &model_env);
}
return *this;
@ -372,7 +376,7 @@ public:
if( db_expression )
{
db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_LE);
db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false);
db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false, &model_env);
}
return *this;
@ -385,7 +389,7 @@ public:
if( db_expression )
{
db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_GE);
db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false);
db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false, &model_env);
}
return *this;
@ -399,7 +403,7 @@ public:
if( db_expression )
{
db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_IN);
db_expression->field_in(*out_stream, field_name, container);
db_expression->field_in(*out_stream, field_name, container, &model_env);
}
return *this;
@ -411,7 +415,7 @@ public:
if( db_expression )
{
db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_IN);
db_expression->field_in(*out_stream, field_name, container);
db_expression->field_in(*out_stream, field_name, container, &model_env);
}
return *this;
@ -423,7 +427,7 @@ public:
if( db_expression )
{
db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_IN);
db_expression->field_in(*out_stream, field_name, container);
db_expression->field_in(*out_stream, field_name, container, &model_env);
}
return *this;
@ -495,6 +499,7 @@ public:
{
Cursor<ModelClass> cursor;
cursor.set_model_data(model_data);
cursor.set_has_autogenerated_select(has_autogenerated_select);
if( model_connector && out_stream )
{
@ -544,7 +549,23 @@ public:
std::list<ModelClass> result;
get_list(result, false);
return std::move(result);
return result;
}
protected:
void set_out_stream()
{
if( model_connector )
{
this->out_stream = model_connector->get_stream();
}
else
{
this->out_stream = nullptr;
}
}
@ -559,9 +580,10 @@ private:
ModelClass model;
bool was_query_error;
std::wstring last_query_error;
ModelEnv model_env;
FinderHelper finder_helper;
ModelData * model_data;
std::wstring column_prefix;
bool has_autogenerated_select;
void set_db_expression()
@ -578,6 +600,8 @@ private:
}
};
} // namespace

101
src/finderhelper.h Normal file
View File

@ -0,0 +1,101 @@
/*
* 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) 2019, 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_finderhelper
#define headerfile_morm_finderhelper
#include "queryresult.h"
namespace morm
{
class FinderHelper
{
public:
PT::TextStream join_tables_str;
std::map<std::string, int> join_tables_map;
std::list<std::string> foreign_keys;
FinderHelper()
{
}
virtual ~FinderHelper()
{
}
virtual void clear()
{
join_tables_str.clear();
join_tables_map.clear();
foreign_keys.clear();
}
virtual int add_join_table(const PT::TextStream & table_name)
{
std::string table_name_str;
table_name.to_string(table_name_str);
return add_join_table(table_name_str);
}
virtual int add_join_table(const std::string & table_name)
{
auto res = join_tables_map.insert(std::make_pair(table_name, 1));
if( !res.second )
{
res.first->second += 1;
}
return res.first->second;
}
};
}
#endif

View File

@ -74,7 +74,9 @@ void FlatConnector::to_text(PT::TextStream & stream, Model & model)
if( flat_expression )
{
flat_expression->clear();
flat_expression->set_work_mode(MORM_WORK_MODE_MODEL_FIELDS_VALUES);
flat_expression->allow_to_use_prefix(false);
flat_expression->generate_from_model(stream, model);
}
}

View File

@ -137,6 +137,18 @@ void JSONExpression::put_name_value_separator()
}
void JSONExpression::before_field_value_list()
{
(*out_stream) << "[";
}
void JSONExpression::after_field_value_list()
{
(*out_stream) << "]";
}
void JSONExpression::esc(char val, PT::TextStream & stream)
{
switch( val )

View File

@ -64,15 +64,8 @@ protected:
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)
{
put_field_name(field_name);
(*out_stream) << ":";
put_field_value(field_value);
}
void before_field_value_list();
void after_field_value_list();
void esc(char val, PT::TextStream & stream);

View File

@ -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
@ -41,11 +41,8 @@ namespace morm
Model::Model()
{
model_connector = nullptr;
model_data = nullptr;
doc_field_pointer = nullptr;
model_env = nullptr;
save_mode = DO_INSERT_ON_SAVE;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
query_result = nullptr;
}
@ -53,11 +50,7 @@ Model::Model(const Model & m)
{
model_connector = m.model_connector;
save_mode = m.save_mode;
model_data = nullptr;
doc_field_pointer = nullptr; // does it need to be copied?
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
query_result = nullptr;
model_env = m.model_env; // or just set to null?
}
@ -65,6 +58,7 @@ Model::~Model()
{
}
void Model::set_save_mode(SaveMode save_mode)
{
this->save_mode = save_mode;
@ -105,6 +99,7 @@ void Model::table_name(PT::TextStream & stream)
}
void Model::set_connector(ModelConnector & connector)
{
set_connector(&connector);
@ -136,7 +131,10 @@ void Model::to_text(PT::TextStream & stream, ModelData * model_data, bool clear_
stream.clear();
}
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING;
ModelEnv model_env_local;
model_env = &model_env_local;
model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING;
if( model_connector )
{
@ -144,13 +142,14 @@ void Model::to_text(PT::TextStream & stream, ModelData * model_data, bool clear_
if( flat_connector )
{
this->model_data = model_data;
model_env->model_data = model_data;
flat_connector->to_text(stream, *this);
this->model_data = nullptr;
model_env->model_data = nullptr;
}
}
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
// what about if an exception was thrown? this pointer will not be null
model_env = nullptr;
}
@ -213,7 +212,7 @@ std::string Model::to_string()
void Model::generate_insert_query(PT::TextStream & stream)
{
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
if( model_connector )
{
@ -225,7 +224,7 @@ void Model::generate_insert_query(PT::TextStream & stream)
}
}
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
}
@ -236,8 +235,11 @@ bool Model::insert(ModelData * model_data)
if( model_connector )
{
this->model_data = model_data;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
ModelEnv model_env_local;
model_env = &model_env_local;
model_env->model_data = model_data;
model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
DbConnector * db_connector = model_connector->get_db_connector();
// CHECK ME what if the stream is being used by something other?
@ -260,8 +262,8 @@ bool Model::insert(ModelData * model_data)
}
}
this->model_data = nullptr;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
// what about if an exception was thrown? this pointer will not be null
model_env = nullptr;
}
return result;
@ -277,7 +279,7 @@ bool Model::insert(ModelData & model_data)
void Model::generate_update_query(PT::TextStream & stream)
{
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
if( model_connector )
{
@ -289,7 +291,7 @@ void Model::generate_update_query(PT::TextStream & stream)
}
}
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
}
@ -299,8 +301,11 @@ bool Model::update(ModelData * model_data)
if( model_connector )
{
this->model_data = model_data;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
ModelEnv model_env_local;
model_env = &model_env_local;
model_env->model_data = model_data;
model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
DbConnector * db_connector = model_connector->get_db_connector();
// CHECK ME what if the stream is being used by something other?
@ -318,8 +323,8 @@ bool Model::update(ModelData * model_data)
after_update_failure();
}
this->model_data = nullptr;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
// what about if an exception was thrown? this pointer will not be null
model_env = nullptr;
}
return result;
@ -337,14 +342,14 @@ void Model::generate_remove_query(PT::TextStream & stream)
if( model_connector )
{
DbConnector * db_connector = model_connector->get_db_connector();
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
if( db_connector )
{
db_connector->generate_remove_query(stream, *this);
}
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
}
}
@ -355,8 +360,11 @@ bool Model::remove(ModelData * model_data)
if( model_connector )
{
this->model_data = model_data;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
ModelEnv model_env_local;
model_env = &model_env_local;
model_env->model_data = model_data;
model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
DbConnector * db_connector = model_connector->get_db_connector();
// CHECK ME what if the stream is being used by something other?
@ -379,8 +387,8 @@ bool Model::remove(ModelData * model_data)
}
}
this->model_data = nullptr;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
// what about if an exception was thrown? this pointer will not be null
model_env = nullptr;
}
return result;
@ -426,19 +434,17 @@ bool Model::save(ModelData & model_data)
}
void Model::generate_select_columns(PT::TextStream & stream, const std::wstring & column_prefix)
void Model::generate_select_columns(PT::TextStream & stream)
{
if( model_connector )
if( model_connector && model_env )
{
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL;
DbConnector * db_connector = model_connector->get_db_connector();
if( db_connector )
{
db_connector->generate_select_columns(stream, *this, column_prefix);
db_connector->generate_select_columns(stream, *this);
}
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
}
}
@ -451,7 +457,7 @@ void Model::generate_doc_for_flat(PT::TextStream & stream, bool clear_stream)
stream.clear();
}
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DOC_FOR_FLAT;
model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DOC_FOR_FLAT;
if( model_connector )
{
@ -463,7 +469,7 @@ void Model::generate_doc_for_flat(PT::TextStream & stream, bool clear_stream)
}
}
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
}
@ -474,7 +480,7 @@ void Model::generate_doc_for_db(PT::TextStream & stream, bool clear_stream)
stream.clear();
}
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DOC_FOR_DB;
model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DOC_FOR_DB;
if( model_connector )
{
@ -486,31 +492,32 @@ void Model::generate_doc_for_db(PT::TextStream & stream, bool clear_stream)
}
}
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
}
void Model::map_values_from_query(QueryResult * query_result)
void Model::map_values_from_query()
{
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB_RESULTSET;
this->query_result = query_result;
map_fields();
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
this->query_result = nullptr;
if( model_env )
{
model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB_RESULTSET;
map_fields();
model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
}
}
void Model::clear()
{
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE;
ModelEnv model_env_local;
model_env = &model_env_local;
model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE;
map_fields();
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
model_env = nullptr;
save_mode = DO_INSERT_ON_SAVE;
model_data = nullptr;
}
@ -569,9 +576,30 @@ void Model::after_remove_failure()
int Model::get_connector_mode()
{
return model_connector_mode;
if( model_env )
{
return model_env->model_connector_mode;
}
else
{
return MORM_MODEL_CONNECTOR_MODE_NONE;
}
}
ModelData * Model::get_model_data()
{
if( model_env )
{
return model_env->model_data;
}
else
{
return nullptr;
}
}
bool Model::is_empty_field(const wchar_t * value)
{
return (!value || *value == '\0');

View File

@ -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
@ -41,8 +41,7 @@
#include "modelconnector.h"
#include "dbexpression.h"
#include "flatexpression.h"
#include "queryresult.h"
#include "modeldata.h"
#include "modelenv.h"
@ -97,33 +96,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);
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,14 +131,13 @@ public:
virtual void clear();
protected:
ModelConnector * model_connector;
SaveMode save_mode;
ModelData * model_data;
const void * doc_field_pointer;
int model_connector_mode;
QueryResult * query_result;
ModelEnv * model_env;
Model();
@ -163,8 +161,10 @@ protected:
virtual int get_connector_mode();
// used by Cursor
virtual void map_values_from_query(QueryResult * query_result);
virtual ModelData * get_model_data();
virtual void map_values_from_query();
/////////////////////////////////
@ -269,15 +269,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 +385,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);
}
//////////////////////
@ -631,9 +633,9 @@ protected:
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 )
if( model_connector && model_env )
{
if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING )
if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING )
{
FlatConnector * flat_connector = model_connector->get_flat_connector();
@ -644,12 +646,12 @@ 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(flat_field_name, field_value, insertable, updatable, is_primary_key, model_env);
}
}
}
if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL )
if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL )
{
DbConnector * db_connector = model_connector->get_db_connector();
@ -659,23 +661,33 @@ 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(db_field_name, field_value, insertable, updatable, is_primary_key, model_env);
}
}
}
if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB_RESULTSET )
if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB_RESULTSET )
{
DbConnector * db_connector = model_connector->get_db_connector();
if( db_connector )
{
if( !is_empty_field(db_field_name) )
get_value_by_field_name(db_field_name, field_value);
{
if( model_env->model_data && model_env->cursor_helper && model_env->cursor_helper->has_autogenerated_select )
{
get_value_by_field_index(model_env->cursor_helper->current_column, field_value);
model_env->cursor_helper->current_column += 1;
}
else
{
get_value_by_field_name(db_field_name, field_value);
}
}
}
}
if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE )
if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE )
{
Clearer * clearer = model_connector->get_clearer();
@ -685,7 +697,7 @@ protected:
}
}
if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DOC_FOR_FLAT )
if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DOC_FOR_FLAT )
{
FlatConnector * doc_connector = model_connector->get_doc_connector(); // different connector will be here (doc, flat)
@ -697,7 +709,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_value, insertable, updatable, is_primary_key);
doc_expression->field_doc(*this, flat_field_name, field_value, insertable, updatable, is_primary_key, model_env);
}
}
}
@ -705,70 +717,205 @@ 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_connector )
if( model_env && field_model.model_env && model_env->finder_helper )
{
model_env->finder_helper->foreign_keys.clear();
field_model.model_env->table_index = model_env->finder_helper->add_join_table(field_model.model_env->table_name_short);
model_env->finder_helper->join_tables_str << "LEFT JOIN " << field_model.model_env->table_name
<< " AS " << field_model.model_env->table_name_short;
if( field_model.model_env->table_index > 1 )
model_env->finder_helper->join_tables_str << field_model.model_env->table_index;
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();
model_env->finder_helper->join_tables_str << " ON " << model_env->table_name_short << '.'
<< db_field_name << " = " << field_model.model_env->table_name_short << '.';
if( model_env->finder_helper->foreign_keys.size() == 1 )
{
model_env->finder_helper->join_tables_str << model_env->finder_helper->foreign_keys.front();
}
}
else
{
map_fields();
model_env->finder_helper->join_tables_str << " ON " << model_env->table_name_short << '.';
if( model_env->finder_helper->foreign_keys.size() == 1 )
{
model_env->finder_helper->join_tables_str << model_env->finder_helper->foreign_keys.front();
}
model_env->finder_helper->join_tables_str << " = " << field_model.model_env->table_name_short << '.' << db_field_name;
}
model_env->finder_helper->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);
}
}
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) )
{
field_model.model_env->model_connector_mode = MORM_MODEL_CONNECTOR_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_connector_mode = MORM_MODEL_CONNECTOR_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( db_expression->get_output_type() != MORM_OUTPUT_TYPE_JOIN_TABLES )
{
field_model.map_fields();
}
field_model.model_env->model_connector_mode = MORM_MODEL_CONNECTOR_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_generate_doc_flat(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_model, bool insertable, bool updatable, bool has_foreign_key)
{
FlatConnector * doc_connector = model_connector->get_doc_connector(); // different connector will be here (doc, flat)
if( doc_connector )
{
FlatExpression * doc_expression = doc_connector->get_expression();
// potrzebujemy dwa rozne doce, jeden dla flat drugi dla bazy danych
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, false, model_env);
}
}
}
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) )
{
// we need to test if the object is actually defined, test nulls on primary key?
field_model.before_select();
field_model.set_save_mode(Model::DO_UPDATE_ON_SAVE); // IMPROVE ME check if there is a primary key
field_model.map_values_from_query();
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.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 )
if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING )
{
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) )
{
field_model.model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING;
flat_expression->field_model(flat_field_name, field_model, insertable, updatable, is_primary_key);
field_model.model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
}
}
field_model_generate_flat_string(db_field_name, flat_field_name, field_model, insertable, updatable);
}
if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE )
if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL )
{
Clearer * clearer = model_connector->get_clearer();
if( clearer )
{
clearer->clear_model(field_model);
}
field_model_generate_db_sql(db_field_name, flat_field_name, field_model, insertable, updatable, has_foreign_key);
}
if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DOC_FOR_FLAT )
if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE )
{
FlatConnector * doc_connector = model_connector->get_doc_connector(); // different connector will be here (doc, flat)
if( doc_connector )
{
FlatExpression * doc_expression = doc_connector->get_expression();
// potrzebujemy dwa rozne doce, jeden dla flat drugi dla bazy danych
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);
}
}
field_model_clear_values(db_field_name, flat_field_name, field_model, insertable, updatable, has_foreign_key);
}
field_model.model_data = nullptr;
if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DOC_FOR_FLAT )
{
field_model_generate_doc_flat(db_field_name, flat_field_name, field_model, insertable, updatable, has_foreign_key);
}
if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_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>
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 && model_env )
{
if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING )
if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING )
{
FlatConnector * flat_connector = model_connector->get_flat_connector();
@ -781,12 +928,30 @@ 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_env);
}
}
}
if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE )
if( model_env->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 )
{
// another select will be used (from another Finder)
// we need only columns name
// but columns are defined in the other model
}
}
}
if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE )
{
Clearer * clearer = model_connector->get_clearer();
@ -796,7 +961,7 @@ protected:
}
}
if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DOC_FOR_FLAT )
if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DOC_FOR_FLAT )
{
FlatConnector * doc_connector = model_connector->get_doc_connector(); // different connector will be here (doc, flat)
@ -808,7 +973,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_env);
}
}
}
@ -816,12 +981,32 @@ protected:
}
template<typename FieldValue>
void get_value_by_field_index(int field_index, FieldValue & field_value)
{
if( model_env->cursor_helper && model_env->cursor_helper->query_result )
{
const char * val_str = model_env->cursor_helper->query_result->get_field_string_value(field_index);
if( val_str )
{
DbConnector * db_connector = model_connector->get_db_connector();
if( db_connector )
{
db_connector->get_value(val_str, field_value);
}
}
}
}
template<typename FieldValue>
void get_value_by_field_name(const wchar_t * field_name, FieldValue & field_value)
{
if( query_result )
if( model_env->cursor_helper && model_env->cursor_helper->query_result )
{
const char * val_str = query_result->get_field_string_value(field_name);
const char * val_str = model_env->cursor_helper->query_result->get_field_string_value(field_name);
if( val_str )
{
@ -840,7 +1025,7 @@ protected:
template<typename FieldValue>
void doc_field_generic(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value)
{
if( reinterpret_cast<const void*>(&field_value) == doc_field_pointer && model_connector )
if( reinterpret_cast<const void*>(&field_value) == model_env->doc_field_pointer && model_connector )
{
FlatConnector * doc_connector = model_connector->get_doc_connector();
@ -864,7 +1049,7 @@ protected:
void doc_field_model(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_model)
{
if( reinterpret_cast<const void*>(&field_model) == doc_field_pointer && model_connector )
if( reinterpret_cast<const void*>(&field_model) == model_env->doc_field_pointer && model_connector )
{
FlatConnector * doc_connector = model_connector->get_doc_connector();
@ -889,7 +1074,7 @@ protected:
template<typename ModelContainer>
void doc_field_list(const wchar_t * db_field_name, const wchar_t * flat_field_name, ModelContainer & field_container)
{
if( reinterpret_cast<const void*>(&field_container) == doc_field_pointer && model_connector )
if( reinterpret_cast<const void*>(&field_container) == model_env->doc_field_pointer && model_connector )
{
FlatConnector * doc_connector = model_connector->get_doc_connector();
@ -976,8 +1161,7 @@ protected:
virtual bool is_empty_field(const wchar_t * value);
// template<typename ModelClass> friend class Finder;
template<typename ModelClass> friend class Finder;
template<typename ModelClass> friend class Cursor;
friend class BaseExpression;

View File

@ -36,6 +36,7 @@
#define headerfile_morm_modeldata
namespace morm
{
@ -43,19 +44,14 @@ class ModelData
{
public:
ModelData() {}
virtual ~ModelData() {}
ModelData()
{
}
virtual ~ModelData()
{
}
/*
* may to add:
* std::set<std::wstring> skip_columns;
* and Finder can use this
* also update and insert from Model
* (but what about the same name of columns through the whole objects-tree?
* may we can save the name of the table too?)
*
*
*/
};
}

115
src/modelenv.h Normal file
View File

@ -0,0 +1,115 @@
/*
* 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) 2019, 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_modelenv
#define headerfile_morm_modelenv
#include "modeldata.h"
#include "cursorhelper.h"
#include "finderhelper.h"
#include "morm_types.h"
namespace morm
{
class ModelEnv
{
public:
ModelData * model_data;
FinderHelper * finder_helper;
CursorHelper * cursor_helper;
int model_connector_mode;
const void * doc_field_pointer;
PT::TextStream table_name;
PT::TextStream table_name_short;
int table_index;
ModelEnv()
{
clear();
}
~ModelEnv()
{
}
ModelEnv(const ModelEnv & e)
{
model_data = e.model_data;
finder_helper = e.finder_helper;
cursor_helper = e.cursor_helper;
model_connector_mode = e.model_connector_mode;
table_index = e.table_index;
doc_field_pointer = e.doc_field_pointer;
}
void copy_global_objects(const ModelEnv & e)
{
model_data = e.model_data;
finder_helper = e.finder_helper;
cursor_helper = e.cursor_helper;
model_connector_mode = e.model_connector_mode;
// what about doc_field_pointer?
}
void clear()
{
model_data = nullptr;
finder_helper = nullptr;
cursor_helper = nullptr;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
doc_field_pointer = nullptr;
table_name.clear();
table_name_short.clear();
table_index = 0;
}
};
}
#endif

View File

@ -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
@ -53,6 +53,7 @@
#define MORM_WORK_MODE_MODEL_VALUES 2
#define MORM_WORK_MODE_MODEL_FIELDS_VALUES 3
#define MORM_WORK_MODE_MODEL_SAVE_FIELDS 4
// IMPROVE ME give me a better name
@ -68,12 +69,15 @@
//#define MORM_OUTPUT_TYPE_WHERE_CUSTOM 5
#define MORM_OUTPUT_TYPE_SELECT_COLUMNS 6
#define MORM_OUTPUT_TYPE_WHERE_EQ 7
#define MORM_OUTPUT_TYPE_WHERE_LT 8
#define MORM_OUTPUT_TYPE_WHERE_GT 9
#define MORM_OUTPUT_TYPE_WHERE_LE 10
#define MORM_OUTPUT_TYPE_WHERE_GE 11
#define MORM_OUTPUT_TYPE_WHERE_IN 12
#define MORM_OUTPUT_TYPE_JOIN_TABLES 7
#define MORM_OUTPUT_TYPE_WHERE_EQ 10
#define MORM_OUTPUT_TYPE_WHERE_LT 11
#define MORM_OUTPUT_TYPE_WHERE_GT 12
#define MORM_OUTPUT_TYPE_WHERE_LE 13
#define MORM_OUTPUT_TYPE_WHERE_GE 14
#define MORM_OUTPUT_TYPE_WHERE_IN 15
#define MORM_OUTPUT_TYPE_WHERE_NOT_EQ 16
#define MORM_CONJUNCTION_AND 1

View File

@ -47,7 +47,6 @@ namespace morm
PostgreSQLConnector::PostgreSQLConnector()
{
pg_conn = nullptr;
log_queries = false;
}
@ -77,10 +76,6 @@ void PostgreSQLConnector::allocate_default_expression()
void PostgreSQLConnector::set_log_queries(bool log_queries)
{
this->log_queries = log_queries;
}
QueryResult * PostgreSQLConnector::create_query_result()
@ -97,7 +92,7 @@ bool PostgreSQLConnector::do_query(const char * query_str, PostgreSQLQueryResult
if( log_queries && log )
{
(*log) << PT::Log::log1 << "Morm: query: " << query_str << PT::Log::logend;
(*log) << PT::Log::log3 << "Morm: query: " << query_str << PT::Log::logend;
}
psql_result->psql_result = PQexec(pg_conn, query_str);
@ -115,6 +110,7 @@ bool PostgreSQLConnector::do_query(const char * query_str, PostgreSQLQueryResult
{
psql_result->psql_status = PQresultStatus(psql_result->psql_result);
psql_result->result_rows = static_cast<size_t>(PQntuples(psql_result->psql_result));
psql_result->result_cols = static_cast<size_t>(PQnfields(psql_result->psql_result));
}
if( !psql_result->psql_result || psql_result->psql_status == PGRES_FATAL_ERROR )

View File

@ -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
@ -54,7 +54,6 @@ public:
virtual ~PostgreSQLConnector();
virtual void set_log_queries(bool log_queries);
bool query(const PT::TextStream & stream, QueryResult & query_result);
bool query(const char * query_str, QueryResult & query_result);
@ -86,10 +85,8 @@ public:
protected:
PGconn * pg_conn;
bool log_queries;
PT::TextStream stream;
std::string query_str;
std::string temp_column_name;
std::wstring db_database;
std::wstring db_user;

View File

@ -67,6 +67,23 @@ bool PostgreSQLQueryResult::has_db_result()
}
const char * PostgreSQLQueryResult::get_field_string_value(int column_index)
{
const char * value_str = nullptr;
if( column_index >= 0 && (size_t)column_index < result_cols )
{
if( cur_row < result_rows )
{
value_str = PQgetvalue(psql_result, cur_row, column_index);
}
}
return value_str;
}
const char * PostgreSQLQueryResult::get_field_string_value(const char * column_name)
{
const char * value_str = nullptr;

View File

@ -57,6 +57,7 @@ struct PostgreSQLQueryResult : public QueryResult
virtual bool has_db_result();
const char * get_field_string_value(int column_index);
const char * get_field_string_value(const char * column_name);
int get_column_index(const char * column_name);

View File

@ -56,6 +56,7 @@ QueryResult::~QueryResult()
void QueryResult::clear()
{
result_rows = 0;
result_cols = 0;
cur_row = 0;
status = false;
error_msg.clear();
@ -70,6 +71,12 @@ bool QueryResult::has_db_result()
}
const char * QueryResult::get_field_string_value(int column_index)
{
return nullptr;
}
const char * QueryResult::get_field_string_value(const char * column_name)
{
return nullptr;

View File

@ -45,6 +45,7 @@ struct QueryResult
{
bool status;
size_t result_rows; // how many rows in the result query
size_t result_cols; // how many columns in the result query
size_t cur_row; // used for reading
std::wstring error_msg;
@ -57,6 +58,7 @@ struct QueryResult
virtual void clear();
virtual bool has_db_result();
virtual const char * get_field_string_value(int column_index);
virtual const char * get_field_string_value(const char * column_name);
virtual const char * get_field_string_value(const wchar_t * field_name);