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/date/date.h
baseexpression.o: ../../pikotools/convert/inttostr.h baseexpression.o: ../../pikotools/convert/inttostr.h
baseexpression.o: ../../pikotools/membuffer/membuffer.h baseexpression.o: ../../pikotools/membuffer/membuffer.h
baseexpression.o: ../../pikotools/textstream/types.h morm_types.h model.h baseexpression.o: ../../pikotools/textstream/types.h morm_types.h modelenv.h
baseexpression.o: modelconnector.h clearer.h dbconnector.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: ../../pikotools/log/log.h ../../pikotools/log/filelog.h
baseexpression.o: queryresult.h flatconnector.h dbexpression.h baseexpression.o: flatconnector.h dbexpression.h flatexpression.h
baseexpression.o: flatexpression.h modeldata.h ../../pikotools/utf8/utf8.h baseexpression.o: ../../pikotools/utf8/utf8.h
clearer.o: clearer.h ../../pikotools/date/date.h clearer.o: clearer.h ../../pikotools/date/date.h
clearer.o: ../../pikotools/convert/inttostr.h model.h clearer.o: ../../pikotools/convert/inttostr.h model.h
clearer.o: ../../pikotools/textstream/textstream.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/textstream/types.h modelconnector.h dbconnector.h
clearer.o: ../../pikotools/log/log.h ../../pikotools/log/filelog.h clearer.o: ../../pikotools/log/log.h ../../pikotools/log/filelog.h
clearer.o: queryresult.h flatconnector.h dbexpression.h baseexpression.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: dbconnector.h ../../pikotools/textstream/textstream.h
dbconnector.o: ../../pikotools/space/space.h dbconnector.o: ../../pikotools/space/space.h
dbconnector.o: ../../pikotools/textstream/types.h ../../pikotools/date/date.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/membuffer/membuffer.h
dbconnector.o: ../../pikotools/textstream/types.h ../../pikotools/log/log.h dbconnector.o: ../../pikotools/textstream/types.h ../../pikotools/log/log.h
dbconnector.o: ../../pikotools/log/filelog.h queryresult.h dbexpression.h dbconnector.o: ../../pikotools/log/filelog.h queryresult.h dbexpression.h
dbconnector.o: baseexpression.h morm_types.h model.h modelconnector.h dbconnector.o: baseexpression.h morm_types.h modelenv.h modeldata.h
dbconnector.o: clearer.h flatconnector.h flatexpression.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/utf8/utf8.h ../../pikotools/convert/convert.h
dbconnector.o: ../../pikotools/convert/inttostr.h dbconnector.o: ../../pikotools/convert/inttostr.h
dbconnector.o: ../../pikotools/convert/patternreplacer.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/date/date.h
dbexpression.o: ../../pikotools/convert/inttostr.h dbexpression.o: ../../pikotools/convert/inttostr.h
dbexpression.o: ../../pikotools/membuffer/membuffer.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: dochtmlconnector.h flatconnector.h
dochtmlconnector.o: ../../pikotools/textstream/textstream.h dochtmlconnector.o: ../../pikotools/textstream/textstream.h
dochtmlconnector.o: ../../pikotools/space/space.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/convert/inttostr.h
dochtmlconnector.o: ../../pikotools/membuffer/membuffer.h dochtmlconnector.o: ../../pikotools/membuffer/membuffer.h
dochtmlconnector.o: ../../pikotools/textstream/types.h dochtmlexpression.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: dochtmlexpression.h flatexpression.h baseexpression.h
dochtmlexpression.o: ../../pikotools/textstream/textstream.h dochtmlexpression.o: ../../pikotools/textstream/textstream.h
dochtmlexpression.o: ../../pikotools/space/space.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/convert/inttostr.h
dochtmlexpression.o: ../../pikotools/membuffer/membuffer.h dochtmlexpression.o: ../../pikotools/membuffer/membuffer.h
dochtmlexpression.o: ../../pikotools/textstream/types.h morm_types.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: flatconnector.h ../../pikotools/textstream/textstream.h
flatconnector.o: ../../pikotools/space/space.h flatconnector.o: ../../pikotools/space/space.h
flatconnector.o: ../../pikotools/textstream/types.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/convert/inttostr.h
flatconnector.o: ../../pikotools/membuffer/membuffer.h flatconnector.o: ../../pikotools/membuffer/membuffer.h
flatconnector.o: ../../pikotools/textstream/types.h flatexpression.h flatconnector.o: ../../pikotools/textstream/types.h flatexpression.h
flatconnector.o: baseexpression.h morm_types.h model.h modelconnector.h flatconnector.o: baseexpression.h morm_types.h modelenv.h modeldata.h
flatconnector.o: clearer.h dbconnector.h ../../pikotools/log/log.h flatconnector.o: cursorhelper.h queryresult.h finderhelper.h model.h
flatconnector.o: ../../pikotools/log/filelog.h queryresult.h dbexpression.h flatconnector.o: modelconnector.h clearer.h dbconnector.h
flatconnector.o: modeldata.h flatconnector.o: ../../pikotools/log/log.h ../../pikotools/log/filelog.h
flatconnector.o: dbexpression.h
flatexpression.o: flatexpression.h baseexpression.h flatexpression.o: flatexpression.h baseexpression.h
flatexpression.o: ../../pikotools/textstream/textstream.h flatexpression.o: ../../pikotools/textstream/textstream.h
flatexpression.o: ../../pikotools/space/space.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/date/date.h
flatexpression.o: ../../pikotools/convert/inttostr.h flatexpression.o: ../../pikotools/convert/inttostr.h
flatexpression.o: ../../pikotools/membuffer/membuffer.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: jsonconnector.h flatconnector.h
jsonconnector.o: ../../pikotools/textstream/textstream.h jsonconnector.o: ../../pikotools/textstream/textstream.h
jsonconnector.o: ../../pikotools/space/space.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/convert/inttostr.h
jsonconnector.o: ../../pikotools/membuffer/membuffer.h jsonconnector.o: ../../pikotools/membuffer/membuffer.h
jsonconnector.o: ../../pikotools/textstream/types.h jsonexpression.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: jsonexpression.h flatexpression.h baseexpression.h
jsonexpression.o: ../../pikotools/textstream/textstream.h jsonexpression.o: ../../pikotools/textstream/textstream.h
jsonexpression.o: ../../pikotools/space/space.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/date/date.h
jsonexpression.o: ../../pikotools/convert/inttostr.h jsonexpression.o: ../../pikotools/convert/inttostr.h
jsonexpression.o: ../../pikotools/membuffer/membuffer.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: model.h ../../pikotools/textstream/textstream.h
model.o: ../../pikotools/space/space.h ../../pikotools/textstream/types.h model.o: ../../pikotools/space/space.h ../../pikotools/textstream/types.h
model.o: ../../pikotools/date/date.h ../../pikotools/convert/inttostr.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: ../../pikotools/textstream/types.h modelconnector.h clearer.h
model.o: dbconnector.h ../../pikotools/log/log.h model.o: dbconnector.h ../../pikotools/log/log.h
model.o: ../../pikotools/log/filelog.h queryresult.h flatconnector.h model.o: ../../pikotools/log/filelog.h queryresult.h flatconnector.h
model.o: dbexpression.h baseexpression.h morm_types.h flatexpression.h model.o: dbexpression.h baseexpression.h morm_types.h modelenv.h modeldata.h
model.o: modeldata.h model.o: cursorhelper.h finderhelper.h flatexpression.h
modelconnector.o: modelconnector.h clearer.h ../../pikotools/date/date.h modelconnector.o: modelconnector.h clearer.h ../../pikotools/date/date.h
modelconnector.o: ../../pikotools/convert/inttostr.h dbconnector.h modelconnector.o: ../../pikotools/convert/inttostr.h dbconnector.h
modelconnector.o: ../../pikotools/textstream/textstream.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: ../../pikotools/log/filelog.h queryresult.h
postgresqlconnector.o: postgresqlqueryresult.h ../../pikotools/utf8/utf8.h postgresqlconnector.o: postgresqlqueryresult.h ../../pikotools/utf8/utf8.h
postgresqlconnector.o: postgresqlexpression.h dbexpression.h baseexpression.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/text.h
postgresqlconnector.o: ../../pikotools/convert/misc.h postgresqlconnector.o: ../../pikotools/convert/misc.h
postgresqlexpression.o: postgresqlexpression.h dbexpression.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/convert/inttostr.h
postgresqlexpression.o: ../../pikotools/membuffer/membuffer.h postgresqlexpression.o: ../../pikotools/membuffer/membuffer.h
postgresqlexpression.o: ../../pikotools/textstream/types.h morm_types.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 postgresqlqueryresult.o: postgresqlqueryresult.h queryresult.h
queryresult.o: queryresult.h ../../pikotools/utf8/utf8.h queryresult.o: queryresult.h ../../pikotools/utf8/utf8.h
queryresult.o: ../../pikotools/textstream/textstream.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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -44,9 +44,7 @@ namespace morm
BaseExpression::BaseExpression() BaseExpression::BaseExpression()
{ {
out_stream = nullptr; clear();
is_first_field = false;
work_mode = 0;
} }
BaseExpression::~BaseExpression() 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) void BaseExpression::set_work_mode(int work_mode)
{ {
this->work_mode = work_mode; this->work_mode = work_mode;
} }
void BaseExpression::prepare_to_new_expression() int BaseExpression::get_work_mode()
{ {
column_prefix.clear(); return work_mode;
out_stream = nullptr;
is_first_field = false;
work_mode = 0;
} }
PT::TextStream * BaseExpression::get_current_stream() PT::TextStream * BaseExpression::get_current_stream()
{ {
return out_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) void BaseExpression::generate_from_model(PT::TextStream & stream, Model & model)
{ {
this->out_stream = &stream; 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(); before_field_name();
if( add_column_prefix && !column_prefix.empty() ) if( use_prefix && model_env )
{ {
esc(column_prefix, *out_stream); if( need_to_add_field_prefix(field_name) )
(*out_stream) << '.'; {
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); esc(field_name, *out_stream);
@ -159,15 +238,30 @@ void BaseExpression::put_field_name(const wchar_t * field_name, bool add_column_
} }
void BaseExpression::save_foreign_key(const wchar_t * field_name, ModelEnv * model_env)
void BaseExpression::put_field_doc(Model & model, const void * field_pointer, bool insertable, bool updatable, bool is_primary_key, ModelData * model_data)
{ {
model.doc_field_pointer = field_pointer; PT::TextStream str;
model.model_data = model_data; 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.map_doc_fields();
model.model_data = nullptr; model.model_env = nullptr;
model.doc_field_pointer = nullptr; //model.doc_field_pointer = nullptr;
} }
void BaseExpression::before_field_name() void BaseExpression::before_field_name()
@ -379,6 +473,16 @@ void BaseExpression::esc(const PT::Date & date, PT::TextStream & stream)
stream << date; 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) 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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -38,14 +38,15 @@
#include <list> #include <list>
#include <set> #include <set>
#include "textstream/textstream.h" #include "textstream/textstream.h"
#include "morm_types.h"
#include "date/date.h" #include "date/date.h"
#include "morm_types.h"
#include "modelenv.h"
namespace morm namespace morm
{ {
class Model; class Model;
class ModelData;
class ModelConnector; class ModelConnector;
@ -57,21 +58,25 @@ public:
virtual ~BaseExpression(); virtual ~BaseExpression();
virtual void set_work_mode(int work_mode); virtual void set_work_mode(int work_mode);
virtual void prepare_to_new_expression(); virtual int get_work_mode();
virtual void set_column_prefix(const std::wstring & prefix);
virtual void clear();
virtual void generate_from_model(PT::TextStream & stream, Model & model); virtual void generate_from_model(PT::TextStream & stream, Model & model);
virtual PT::TextStream * get_current_stream(); 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 // 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> 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) ) 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 ) 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 else
if( work_mode == MORM_WORK_MODE_MODEL_VALUES ) if( work_mode == MORM_WORK_MODE_MODEL_VALUES )
@ -89,29 +99,29 @@ public:
else else
if( work_mode == MORM_WORK_MODE_MODEL_FIELDS_VALUES ) 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_name_value_separator();
put_field_value(field_value); put_field_value(field_value);
} }
field_after(); field_after();
} }
} }
template<typename FieldValue> template<typename FieldValue>
void field_doc(Model & model, const wchar_t * field_name, const FieldValue & field_value, 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)
bool insertable = true, bool updatable = true,
bool is_primary_key = false, bool add_column_prefix = true,
ModelData * model_data = nullptr)
{ {
if( out_stream ) if( out_stream )
{ {
field_before(); field_before();
put_field_name(field_name, add_column_prefix); put_field_name(field_name, model_env);
put_name_value_separator(); 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_name_value_separator();
put_type(field_value, *out_stream); put_type(field_value, *out_stream);
@ -121,48 +131,45 @@ public:
} }
/*
template<typename FieldValue> 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_in_generic<FieldValue, std::set<FieldValue>>(stream, field_name, container, model_env);
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);
} }
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> 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> template<typename ModelContainer>
void field_list(const wchar_t * field_name, ModelContainer & field_value, bool insertable, bool updatable, bool is_primary_key, 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) ) if( out_stream && can_field_be_generated(insertable, updatable, is_primary_key) )
{ {
field_before(); 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 ) 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_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(); field_after();
@ -170,7 +177,7 @@ public:
} }
template<typename ModelClass> 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) ) 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 ) if( work_mode == MORM_WORK_MODE_MODEL_FIELDS )
{ {
put_field_name(field_name); put_field_name(field_name, model_env);
} }
else else
if( work_mode == MORM_WORK_MODE_MODEL_VALUES ) if( work_mode == MORM_WORK_MODE_MODEL_VALUES )
@ -188,7 +195,7 @@ public:
else else
if( work_mode == MORM_WORK_MODE_MODEL_FIELDS_VALUES ) 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_name_value_separator();
generate_from_model(field_model); generate_from_model(field_model);
} }
@ -198,10 +205,11 @@ public:
} }
template<typename FieldValue> 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; 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; this->out_stream = nullptr;
} }
@ -231,7 +239,13 @@ public:
//virtual void esc(void* val, PT::TextStream & stream); //virtual void esc(void* val, PT::TextStream & stream);
virtual void esc(const PT::Date & date, 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 */ int work_mode; /* what to do: generating fields list, values list or fields-values list */
bool is_first_field; 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; PT::TextStream * out_stream;
bool use_prefix;
std::wstring column_prefix;
virtual void generate_from_model(Model & model); 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); //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> template<typename FieldValue>
void put_field_value(const FieldValue & field_value) 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> // what about lists with a pod types? e.g. list<int>
template<typename ModelContainer> 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)
for(auto & m : field_value)
{
if( out_stream )
{ {
if( !is_first ) if( !is_first )
{ {
if( out_stream ) field_value_list_separator();
(*out_stream) << ","; // make a virtual method
} }
ModelEnv model_env_local(*model_env);
m.model_env = &model_env_local;
//before_field_value(field_value); //before_field_value(field_value);
m.set_connector(model_connector); m.set_connector(model_connector);
m.model_connector_mode = model_connector_mode;
m.model_data = model_data;
generate_from_model(m); generate_from_model(m);
m.model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE; m.model_env = nullptr;
m.model_data = nullptr;
//after_field_value(field_value); //after_field_value(field_value);
is_first = false; is_first = false;
} }
}
if( out_stream ) after_field_value_list();
{
(*out_stream) << "]";// make a virtual method
} }
} }
// used in 'in()' statements, may should be renamed? // used in 'in()' statements, may should be renamed?
template<typename FieldValue, typename Container> 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 // IMPROVE ME
// what about if container is empty? // what about if container is empty?
@ -323,24 +353,24 @@ protected:
this->out_stream = &stream; this->out_stream = &stream;
field_before(); field_before();
put_field_name(field_name); put_field_name(field_name, model_env);
put_name_value_separator(); put_name_value_separator();
bool is_first = true; bool is_first = true;
(*out_stream) << "("; put_statement_in_starts();
for(const FieldValue & v : container) for(const FieldValue & v : container)
{ {
if( !is_first ) if( !is_first )
{ {
(*out_stream) << ","; field_value_list_separator();
} }
put_field_value(v); put_field_value(v);
is_first = false; is_first = false;
} }
(*out_stream) << ") "; put_statement_in_ends();
field_after(); field_after();
this->out_stream = nullptr; this->out_stream = nullptr;
} }

View File

@ -5,7 +5,7 @@
*/ */
/* /*
* Copyright (c) 2018, Tomasz Sowa * Copyright (c) 2018-2019, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -51,7 +51,8 @@ public:
Cursor() Cursor()
{ {
set_default_values(); query_result = nullptr;
clear();
} }
@ -59,6 +60,7 @@ public:
{ {
model_connector = c.model_connector; model_connector = c.model_connector;
model_data = c.model_data; model_data = c.model_data;
has_autogenerated_select = c.has_autogenerated_select;
query_result = c.query_result; query_result = c.query_result;
select_status = c.select_status; select_status = c.select_status;
@ -66,6 +68,9 @@ public:
{ {
query_result->references_count += 1; query_result->references_count += 1;
} }
// helper doesn't have to be copied
cursor_helper.clear();
} }
@ -91,7 +96,13 @@ public:
delete query_result; 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() virtual QueryResult * get_query_result()
{ {
return query_result; return query_result;
@ -150,9 +167,17 @@ public:
if( db_connector ) if( db_connector )
{ {
ModelEnv model_env_local;
result.model_env = &model_env_local;
result.model_env->cursor_helper = &cursor_helper;
try 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(); result.before_select();
res = select_status; res = select_status;
@ -161,7 +186,7 @@ public:
if( query_result->cur_row < query_result->result_rows ) 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.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(); result.after_select();
query_result->cur_row += 1; query_result->cur_row += 1;
} }
@ -182,7 +207,7 @@ public:
// throw something? // throw something?
} }
result.model_data = nullptr; result.model_env = nullptr;
} }
} }
@ -195,7 +220,7 @@ public:
ModelClass model; ModelClass model;
get(model); get(model);
return std::move(model); return model;
} }
@ -258,17 +283,12 @@ protected:
ModelConnector * model_connector; ModelConnector * model_connector;
ModelData * model_data; ModelData * model_data;
bool has_autogenerated_select;
CursorHelper cursor_helper;
QueryResult * query_result; QueryResult * query_result;
bool select_status; bool select_status;
virtual void set_default_values()
{
model_connector = nullptr;
model_data = nullptr;
query_result = nullptr;
select_status = false;
}
template<typename ContainerType> template<typename ContainerType>
@ -281,14 +301,23 @@ protected:
result.emplace_back(); // it returns a reference from c++17 result.emplace_back(); // it returns a reference from c++17
ModelClass & added_model = result.back(); ModelClass & added_model = result.back();
ModelEnv model_env_local;
try 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.set_connector(model_connector);
added_model.clear(); 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.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.before_select();
added_model.map_values_from_query(query_result); added_model.map_values_from_query();
added_model.after_select(); added_model.after_select();
} }
catch(...) catch(...)
@ -297,7 +326,7 @@ protected:
// throw or something? // throw or something?
} }
added_model.model_data = nullptr; added_model.model_env = nullptr;
} }
return res; 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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -49,6 +49,7 @@ DbConnector::DbConnector()
db_expression = nullptr; db_expression = nullptr;
expression_allocated = false; expression_allocated = false;
log = nullptr; log = nullptr;
log_queries = false;
} }
DbConnector::DbConnector(const DbConnector &) DbConnector::DbConnector(const DbConnector &)
@ -70,12 +71,18 @@ void DbConnector::set_logger(PT::Log * log)
this->log = log; this->log = log;
} }
void DbConnector::set_logger(PT::Log & log) void DbConnector::set_logger(PT::Log & log)
{ {
this->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) 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(); allocate_default_expression_if_needed();
if( db_expression ) 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_work_mode(MORM_WORK_MODE_MODEL_FIELDS);
db_expression->set_output_type(MORM_OUTPUT_TYPE_SELECT_COLUMNS); 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); db_expression->generate_from_model(stream, model);
} }
} }
@ -172,7 +179,9 @@ void DbConnector::generate_insert_query(PT::TextStream & stream, Model & model)
if( db_expression ) if( db_expression )
{ {
db_expression->prepare_to_new_expression(); db_expression->clear();
db_expression->allow_to_use_prefix(false);
stream << "insert into "; stream << "insert into ";
model.table_name(stream); model.table_name(stream);
@ -195,7 +204,9 @@ void DbConnector::generate_update_query(PT::TextStream & stream, Model & model)
if( db_expression ) if( db_expression )
{ {
db_expression->prepare_to_new_expression(); db_expression->clear();
db_expression->allow_to_use_prefix(false);
stream << "update "; stream << "update ";
model.table_name(stream); model.table_name(stream);
@ -218,7 +229,9 @@ void DbConnector::generate_remove_query(PT::TextStream & stream, Model & model)
if( db_expression ) if( db_expression )
{ {
db_expression->prepare_to_new_expression(); db_expression->clear();
db_expression->allow_to_use_prefix(false);
stream << "delete from "; stream << "delete from ";
model.table_name(stream); model.table_name(stream);
stream << " where "; stream << " where ";

View File

@ -5,7 +5,7 @@
*/ */
/* /*
* Copyright (c) 2018, Tomasz Sowa * Copyright (c) 2018-2019, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * 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_logger(PT::Log & log); virtual void set_logger(PT::Log & log);
virtual void set_log_queries(bool log_queries);
DbExpression * get_expression(); DbExpression * get_expression();
//virtual void clear_last_query_result(); //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_insert_query(PT::TextStream & stream, Model & model);
virtual void generate_update_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); virtual void generate_remove_query(PT::TextStream & stream, Model & model);
@ -115,6 +117,11 @@ public:
if( val_str ) if( val_str )
{ {
get_value(val_str, field_value); 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; DbExpression * db_expression;
bool expression_allocated; bool expression_allocated;
PT::Log * log; PT::Log * log;
bool log_queries;
virtual void allocate_default_expression() = 0; 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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * 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) bool DbExpression::can_field_be_generated(bool insertable, bool updatable, bool is_primary_key)
{ {
if( output_type == MORM_OUTPUT_TYPE_DB_INSERT ) 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; return updatable;
} }
else 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; return is_primary_key;
} }
@ -90,7 +96,7 @@ void DbExpression::field_before()
output_type == MORM_OUTPUT_TYPE_DB_UPDATE || output_type == MORM_OUTPUT_TYPE_DB_UPDATE ||
output_type == MORM_OUTPUT_TYPE_SELECT_COLUMNS ) output_type == MORM_OUTPUT_TYPE_SELECT_COLUMNS )
{ {
(*out_stream) << ","; (*out_stream) << ", ";
} }
else else
if( output_type == MORM_OUTPUT_TYPE_DB_PRIMARY_KEY ) 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_WHERE_EQ ||
output_type == MORM_OUTPUT_TYPE_DB_UPDATE) output_type == MORM_OUTPUT_TYPE_DB_UPDATE)
{ {
(*out_stream) << " = "; (*out_stream) << "=";
}
else
if( output_type == MORM_OUTPUT_TYPE_WHERE_NOT_EQ )
{
(*out_stream) << "<>";
} }
else else
if( output_type == MORM_OUTPUT_TYPE_WHERE_LT ) if( output_type == MORM_OUTPUT_TYPE_WHERE_LT )
{ {
(*out_stream) << " < "; (*out_stream) << "<";
} }
else else
if( output_type == MORM_OUTPUT_TYPE_WHERE_GT ) if( output_type == MORM_OUTPUT_TYPE_WHERE_GT )
{ {
(*out_stream) << " > "; (*out_stream) << ">";
} }
else else
if( output_type == MORM_OUTPUT_TYPE_WHERE_LE ) if( output_type == MORM_OUTPUT_TYPE_WHERE_LE )
{ {
(*out_stream) << " <= "; (*out_stream) << "<=";
} }
else else
if( output_type == MORM_OUTPUT_TYPE_WHERE_GE ) if( output_type == MORM_OUTPUT_TYPE_WHERE_GE )
{ {
(*out_stream) << " >= "; (*out_stream) << ">=";
} }
else else
if( output_type == MORM_OUTPUT_TYPE_WHERE_IN ) 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; 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 ~DbExpression();
virtual void set_output_type(int output_type); virtual void set_output_type(int output_type);
virtual int get_output_type();
virtual void prepare_to_where_clause(); 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); virtual DbExpression & page(PT::TextStream & stream, size_t page_number, size_t page_size);
template<typename FieldValue> template<typename FieldValue>
void add_field_for_select(const wchar_t * new_column_expression, const wchar_t * new_column_name, FieldValue & field_value) 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 += L" as ";
column_expression += new_column_name; 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: protected:
int output_type; int output_type;

View File

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

View File

@ -64,15 +64,8 @@ protected:
void before_field_value(const PT::Date &); void before_field_value(const PT::Date &);
void after_field_value(const PT::Date &); void after_field_value(const PT::Date &);
void before_field_value_list();
template<typename FieldValue> void after_field_value_list();
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 esc(char val, PT::TextStream & stream); 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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -41,11 +41,8 @@ namespace morm
Model::Model() Model::Model()
{ {
model_connector = nullptr; model_connector = nullptr;
model_data = nullptr; model_env = nullptr;
doc_field_pointer = nullptr;
save_mode = DO_INSERT_ON_SAVE; 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; model_connector = m.model_connector;
save_mode = m.save_mode; save_mode = m.save_mode;
model_env = m.model_env; // or just set to null?
model_data = nullptr;
doc_field_pointer = nullptr; // does it need to be copied?
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
query_result = nullptr;
} }
@ -65,6 +58,7 @@ Model::~Model()
{ {
} }
void Model::set_save_mode(SaveMode save_mode) void Model::set_save_mode(SaveMode save_mode)
{ {
this->save_mode = save_mode; this->save_mode = save_mode;
@ -105,6 +99,7 @@ void Model::table_name(PT::TextStream & stream)
} }
void Model::set_connector(ModelConnector & connector) void Model::set_connector(ModelConnector & connector)
{ {
set_connector(&connector); set_connector(&connector);
@ -136,7 +131,10 @@ void Model::to_text(PT::TextStream & stream, ModelData * model_data, bool clear_
stream.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 ) if( model_connector )
{ {
@ -144,13 +142,14 @@ void Model::to_text(PT::TextStream & stream, ModelData * model_data, bool clear_
if( flat_connector ) if( flat_connector )
{ {
this->model_data = model_data; model_env->model_data = model_data;
flat_connector->to_text(stream, *this); 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) 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 ) 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 ) if( model_connector )
{ {
this->model_data = model_data; ModelEnv model_env_local;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL; 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(); DbConnector * db_connector = model_connector->get_db_connector();
// CHECK ME what if the stream is being used by something other? // 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; // what about if an exception was thrown? this pointer will not be null
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE; model_env = nullptr;
} }
return result; return result;
@ -277,7 +279,7 @@ bool Model::insert(ModelData & model_data)
void Model::generate_update_query(PT::TextStream & stream) 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 ) 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 ) if( model_connector )
{ {
this->model_data = model_data; ModelEnv model_env_local;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL; 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(); DbConnector * db_connector = model_connector->get_db_connector();
// CHECK ME what if the stream is being used by something other? // 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(); after_update_failure();
} }
this->model_data = nullptr; // what about if an exception was thrown? this pointer will not be null
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE; model_env = nullptr;
} }
return result; return result;
@ -337,14 +342,14 @@ void Model::generate_remove_query(PT::TextStream & stream)
if( model_connector ) if( model_connector )
{ {
DbConnector * db_connector = model_connector->get_db_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 ) if( db_connector )
{ {
db_connector->generate_remove_query(stream, *this); 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 ) if( model_connector )
{ {
this->model_data = model_data; ModelEnv model_env_local;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL; 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(); DbConnector * db_connector = model_connector->get_db_connector();
// CHECK ME what if the stream is being used by something other? // 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; // what about if an exception was thrown? this pointer will not be null
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE; model_env = nullptr;
} }
return result; 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(); DbConnector * db_connector = model_connector->get_db_connector();
if( 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(); 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 ) 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(); 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 ) 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; if( model_env )
this->query_result = query_result; {
model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB_RESULTSET;
map_fields(); map_fields();
model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE; }
this->query_result = nullptr;
} }
void Model::clear() 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(); map_fields();
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE; model_env = nullptr;
save_mode = DO_INSERT_ON_SAVE; save_mode = DO_INSERT_ON_SAVE;
model_data = nullptr;
} }
@ -569,9 +576,30 @@ void Model::after_remove_failure()
int Model::get_connector_mode() 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) bool Model::is_empty_field(const wchar_t * value)
{ {
return (!value || *value == '\0'); return (!value || *value == '\0');

View File

@ -5,7 +5,7 @@
*/ */
/* /*
* Copyright (c) 2018, Tomasz Sowa * Copyright (c) 2018-2019, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -41,8 +41,7 @@
#include "modelconnector.h" #include "modelconnector.h"
#include "dbexpression.h" #include "dbexpression.h"
#include "flatexpression.h" #include "flatexpression.h"
#include "queryresult.h" #include "modelenv.h"
#include "modeldata.h"
@ -97,33 +96,33 @@ public:
*/ */
virtual void table_name(PT::TextStream & stream); 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(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 void to_text(std::string & str, bool clear_string = true);
virtual std::string to_text(); virtual std::string to_text();
virtual std::string to_string(); 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 = nullptr);
virtual bool insert(ModelData & model_data); 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 = nullptr);
virtual bool update(ModelData & model_data); 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 = nullptr);
virtual bool remove(ModelData & model_data); virtual bool remove(ModelData & model_data);
virtual bool save(ModelData * model_data = nullptr); virtual bool save(ModelData * model_data = nullptr);
virtual bool save(ModelData & model_data); 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_flat(PT::TextStream & stream, bool clear_stream = true);
virtual void generate_doc_for_db(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(); virtual void clear();
protected: protected:
ModelConnector * model_connector; ModelConnector * model_connector;
SaveMode save_mode; SaveMode save_mode;
ModelData * model_data; ModelEnv * model_env;
const void * doc_field_pointer;
int model_connector_mode;
QueryResult * query_result;
Model(); Model();
@ -163,8 +161,10 @@ protected:
virtual int get_connector_mode(); virtual int get_connector_mode();
// used by Cursor virtual ModelData * get_model_data();
virtual void map_values_from_query(QueryResult * query_result);
virtual void map_values_from_query();
///////////////////////////////// /////////////////////////////////
@ -269,15 +269,16 @@ protected:
field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); 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> 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> 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> 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) 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(); FlatConnector * flat_connector = model_connector->get_flat_connector();
@ -644,12 +646,12 @@ protected:
if( flat_expression && !is_empty_field(flat_field_name) ) if( flat_expression && !is_empty_field(flat_field_name) )
{ {
// insertable, updatable and is_primary_key are ignored here // 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(); DbConnector * db_connector = model_connector->get_db_connector();
@ -659,23 +661,33 @@ protected:
if( db_expression && !is_empty_field(db_field_name) ) 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(); DbConnector * db_connector = model_connector->get_db_connector();
if( db_connector ) if( db_connector )
{ {
if( !is_empty_field(db_field_name) ) 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(); 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) 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) ) if( doc_expression && !is_empty_field(flat_field_name) )
{ {
// insertable, updatable and is_primary_key are ignored here // 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.set_connector(model_connector);
field_model.model_data = model_data;
// IMPLEMENTME what about db? if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING )
if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING )
{ {
FlatConnector * flat_connector = model_connector->get_flat_connector(); field_model_generate_flat_string(db_field_name, flat_field_name, field_model, insertable, updatable);
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;
}
}
} }
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(); field_model_generate_db_sql(db_field_name, flat_field_name, field_model, insertable, updatable, has_foreign_key);
if( clearer )
{
clearer->clear_model(field_model);
}
} }
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) field_model_clear_values(db_field_name, flat_field_name, field_model, insertable, updatable, has_foreign_key);
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.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> template<typename ModelContainer, typename ModelContainerType>
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) 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 && model_env )
if( model_connector )
{ {
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(); FlatConnector * flat_connector = model_connector->get_flat_connector();
@ -781,12 +928,30 @@ protected:
// IMPROVE ME // IMPROVE ME
// what about model_data and save_mode? // what about model_data and save_mode?
// may it should be placed inside some structure? // 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(); 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) 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) ) if( doc_expression && !is_empty_field(flat_field_name) )
{ {
// insertable, updatable and is_primary_key are ignored here // 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> template<typename FieldValue>
void get_value_by_field_name(const wchar_t * field_name, FieldValue & field_value) 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 ) if( val_str )
{ {
@ -840,7 +1025,7 @@ protected:
template<typename FieldValue> template<typename FieldValue>
void doc_field_generic(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value) 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(); 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) 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(); FlatConnector * doc_connector = model_connector->get_doc_connector();
@ -889,7 +1074,7 @@ protected:
template<typename ModelContainer> template<typename ModelContainer>
void doc_field_list(const wchar_t * db_field_name, const wchar_t * flat_field_name, ModelContainer & field_container) 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(); FlatConnector * doc_connector = model_connector->get_doc_connector();
@ -976,8 +1161,7 @@ protected:
virtual bool is_empty_field(const wchar_t * value); 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; template<typename ModelClass> friend class Cursor;
friend class BaseExpression; friend class BaseExpression;

View File

@ -36,6 +36,7 @@
#define headerfile_morm_modeldata #define headerfile_morm_modeldata
namespace morm namespace morm
{ {
@ -43,19 +44,14 @@ class ModelData
{ {
public: public:
ModelData() {} ModelData()
virtual ~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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * 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_VALUES 2
#define MORM_WORK_MODE_MODEL_FIELDS_VALUES 3 #define MORM_WORK_MODE_MODEL_FIELDS_VALUES 3
#define MORM_WORK_MODE_MODEL_SAVE_FIELDS 4
// IMPROVE ME give me a better name // IMPROVE ME give me a better name
@ -68,12 +69,15 @@
//#define MORM_OUTPUT_TYPE_WHERE_CUSTOM 5 //#define MORM_OUTPUT_TYPE_WHERE_CUSTOM 5
#define MORM_OUTPUT_TYPE_SELECT_COLUMNS 6 #define MORM_OUTPUT_TYPE_SELECT_COLUMNS 6
#define MORM_OUTPUT_TYPE_WHERE_EQ 7 #define MORM_OUTPUT_TYPE_JOIN_TABLES 7
#define MORM_OUTPUT_TYPE_WHERE_LT 8
#define MORM_OUTPUT_TYPE_WHERE_GT 9 #define MORM_OUTPUT_TYPE_WHERE_EQ 10
#define MORM_OUTPUT_TYPE_WHERE_LE 10 #define MORM_OUTPUT_TYPE_WHERE_LT 11
#define MORM_OUTPUT_TYPE_WHERE_GE 11 #define MORM_OUTPUT_TYPE_WHERE_GT 12
#define MORM_OUTPUT_TYPE_WHERE_IN 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 #define MORM_CONJUNCTION_AND 1

View File

@ -47,7 +47,6 @@ namespace morm
PostgreSQLConnector::PostgreSQLConnector() PostgreSQLConnector::PostgreSQLConnector()
{ {
pg_conn = nullptr; 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() QueryResult * PostgreSQLConnector::create_query_result()
@ -97,7 +92,7 @@ bool PostgreSQLConnector::do_query(const char * query_str, PostgreSQLQueryResult
if( log_queries && log ) 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); 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->psql_status = PQresultStatus(psql_result->psql_result);
psql_result->result_rows = static_cast<size_t>(PQntuples(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 ) 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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -54,7 +54,6 @@ public:
virtual ~PostgreSQLConnector(); virtual ~PostgreSQLConnector();
virtual void set_log_queries(bool log_queries);
bool query(const PT::TextStream & stream, QueryResult & query_result); bool query(const PT::TextStream & stream, QueryResult & query_result);
bool query(const char * query_str, QueryResult & query_result); bool query(const char * query_str, QueryResult & query_result);
@ -86,10 +85,8 @@ public:
protected: protected:
PGconn * pg_conn; PGconn * pg_conn;
bool log_queries;
PT::TextStream stream; PT::TextStream stream;
std::string query_str; std::string query_str;
std::string temp_column_name;
std::wstring db_database; std::wstring db_database;
std::wstring db_user; 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 * PostgreSQLQueryResult::get_field_string_value(const char * column_name)
{ {
const char * value_str = nullptr; const char * value_str = nullptr;

View File

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

View File

@ -56,6 +56,7 @@ QueryResult::~QueryResult()
void QueryResult::clear() void QueryResult::clear()
{ {
result_rows = 0; result_rows = 0;
result_cols = 0;
cur_row = 0; cur_row = 0;
status = false; status = false;
error_msg.clear(); 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) const char * QueryResult::get_field_string_value(const char * column_name)
{ {
return nullptr; return nullptr;

View File

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