add possibility of calculating how many rows there were before LIMIT was applied
The Finder has get_rows_counter() method which returns how many rows there were before LIMIT clause was applied. The select(...) method should be called with Select::with_rows_counter flag in such a case. while here: - change the semantic of Finder, now the select(...) method takes a morm::Select flags, and we have such flags: - Select::no_auto_generated_columns - do not generate columns from models - with_rows_counter - add an additional column for the rows counter - remove Finder::prepare_to_select() - now use select(...) with no_auto_generated_columns flag
This commit is contained in:
parent
4e8f3af8fc
commit
43dfbd5d5a
|
@ -22,9 +22,9 @@
|
|||
./main.o: ../src/cursorhelper.h ../src/finderhelper.h
|
||||
./main.o: ../src/fieldvaluehelper.h ../src/wrapper.h ../src/spacewrapper.h
|
||||
./main.o: ../src/baseobjectwrapper.h ../src/modelcontainerwrapper.h
|
||||
./main.o: ../../pikotools/src/convert/text.h ../src/flatexpression.h
|
||||
./main.o: ../src/finder.h ../src/cursor.h ../src/jsonexpression.h
|
||||
./main.o: ../src/postgresqlexpression.h ../src/jsonconnector.h
|
||||
./main.o: ../src/postgresqlconnector.h ../src/postgresqlqueryresult.h
|
||||
./main.o: ../src/transaction.h person.h language.h attachment.h type.h
|
||||
./main.o: attachment2.h
|
||||
./main.o: ../src/select.h ../../pikotools/src/convert/text.h
|
||||
./main.o: ../src/flatexpression.h ../src/finder.h ../src/cursor.h
|
||||
./main.o: ../src/jsonexpression.h ../src/postgresqlexpression.h
|
||||
./main.o: ../src/jsonconnector.h ../src/postgresqlconnector.h
|
||||
./main.o: ../src/postgresqlqueryresult.h ../src/transaction.h person.h
|
||||
./main.o: language.h attachment.h type.h attachment2.h
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
./baseexpression.o: ../../pikotools/src/log/log.h
|
||||
./baseexpression.o: ../../pikotools/src/log/filelog.h finderhelper.h
|
||||
./baseexpression.o: fieldvaluehelper.h wrapper.h spacewrapper.h
|
||||
./baseexpression.o: baseobjectwrapper.h modelcontainerwrapper.h ft.h
|
||||
./baseexpression.o: baseobjectwrapper.h modelcontainerwrapper.h select.h ft.h
|
||||
./baseexpression.o: ../../pikotools/src/convert/text.h model.h
|
||||
./baseexpression.o: modelconnector.h clearer.h dbconnector.h flatconnector.h
|
||||
./baseexpression.o: dbexpression.h flatexpression.h
|
||||
|
@ -40,8 +40,8 @@
|
|||
./clearer.o: dbexpression.h baseexpression.h morm_types.h modelenv.h
|
||||
./clearer.o: modeldata.h cursorhelper.h finderhelper.h fieldvaluehelper.h
|
||||
./clearer.o: wrapper.h spacewrapper.h baseobjectwrapper.h
|
||||
./clearer.o: modelcontainerwrapper.h ../../pikotools/src/convert/text.h
|
||||
./clearer.o: flatexpression.h
|
||||
./clearer.o: modelcontainerwrapper.h select.h
|
||||
./clearer.o: ../../pikotools/src/convert/text.h flatexpression.h
|
||||
./dbconnector.o: ../../pikotools/src/space/spaceparser.h
|
||||
./dbconnector.o: ../../pikotools/src/space/space.h
|
||||
./dbconnector.o: ../../pikotools/src/textstream/types.h
|
||||
|
@ -63,9 +63,10 @@
|
|||
./dbconnector.o: dbexpression.h baseexpression.h morm_types.h modelenv.h
|
||||
./dbconnector.o: modeldata.h cursorhelper.h finderhelper.h fieldvaluehelper.h
|
||||
./dbconnector.o: wrapper.h spacewrapper.h baseobjectwrapper.h
|
||||
./dbconnector.o: modelcontainerwrapper.h ../../pikotools/src/convert/text.h
|
||||
./dbconnector.o: model.h modelconnector.h clearer.h flatconnector.h
|
||||
./dbconnector.o: flatexpression.h ../../pikotools/src/convert/convert.h
|
||||
./dbconnector.o: modelcontainerwrapper.h select.h
|
||||
./dbconnector.o: ../../pikotools/src/convert/text.h model.h modelconnector.h
|
||||
./dbconnector.o: clearer.h flatconnector.h flatexpression.h
|
||||
./dbconnector.o: ../../pikotools/src/convert/convert.h
|
||||
./dbconnector.o: ../../pikotools/src/convert/inttostr.h
|
||||
./dbconnector.o: ../../pikotools/src/convert/patternreplacer.h
|
||||
./dbconnector.o: ../../pikotools/src/convert/strtoint.h
|
||||
|
@ -90,8 +91,9 @@
|
|||
./dbexpression.o: ../../pikotools/src/log/log.h
|
||||
./dbexpression.o: ../../pikotools/src/log/filelog.h finderhelper.h
|
||||
./dbexpression.o: fieldvaluehelper.h wrapper.h spacewrapper.h
|
||||
./dbexpression.o: baseobjectwrapper.h modelcontainerwrapper.h ft.h
|
||||
./dbexpression.o: ../../pikotools/src/convert/text.h
|
||||
./dbexpression.o: baseobjectwrapper.h modelcontainerwrapper.h select.h ft.h
|
||||
./dbexpression.o: ../../pikotools/src/convert/text.h model.h modelconnector.h
|
||||
./dbexpression.o: clearer.h dbconnector.h flatconnector.h flatexpression.h
|
||||
./flatconnector.o: flatconnector.h
|
||||
./flatconnector.o: ../../pikotools/src/textstream/textstream.h
|
||||
./flatconnector.o: ../../pikotools/src/textstream/stream.h
|
||||
|
@ -110,7 +112,7 @@
|
|||
./flatconnector.o: cursorhelper.h queryresult.h ../../pikotools/src/log/log.h
|
||||
./flatconnector.o: ../../pikotools/src/log/filelog.h finderhelper.h
|
||||
./flatconnector.o: fieldvaluehelper.h wrapper.h spacewrapper.h
|
||||
./flatconnector.o: baseobjectwrapper.h modelcontainerwrapper.h ft.h
|
||||
./flatconnector.o: baseobjectwrapper.h modelcontainerwrapper.h select.h ft.h
|
||||
./flatconnector.o: ../../pikotools/src/convert/text.h model.h
|
||||
./flatconnector.o: modelconnector.h clearer.h dbconnector.h dbexpression.h
|
||||
./flatexpression.o: flatexpression.h baseexpression.h
|
||||
|
@ -131,7 +133,7 @@
|
|||
./flatexpression.o: ../../pikotools/src/log/log.h
|
||||
./flatexpression.o: ../../pikotools/src/log/filelog.h finderhelper.h
|
||||
./flatexpression.o: fieldvaluehelper.h wrapper.h spacewrapper.h
|
||||
./flatexpression.o: baseobjectwrapper.h modelcontainerwrapper.h ft.h
|
||||
./flatexpression.o: baseobjectwrapper.h modelcontainerwrapper.h select.h ft.h
|
||||
./flatexpression.o: ../../pikotools/src/convert/text.h
|
||||
./jsonconnector.o: jsonconnector.h flatconnector.h
|
||||
./jsonconnector.o: ../../pikotools/src/textstream/textstream.h
|
||||
|
@ -152,7 +154,7 @@
|
|||
./jsonconnector.o: ../../pikotools/src/log/log.h
|
||||
./jsonconnector.o: ../../pikotools/src/log/filelog.h finderhelper.h
|
||||
./jsonconnector.o: fieldvaluehelper.h wrapper.h spacewrapper.h
|
||||
./jsonconnector.o: baseobjectwrapper.h modelcontainerwrapper.h ft.h
|
||||
./jsonconnector.o: baseobjectwrapper.h modelcontainerwrapper.h select.h ft.h
|
||||
./jsonconnector.o: ../../pikotools/src/convert/text.h
|
||||
./jsonexpression.o: jsonexpression.h flatexpression.h baseexpression.h
|
||||
./jsonexpression.o: ../../pikotools/src/textstream/textstream.h
|
||||
|
@ -172,7 +174,7 @@
|
|||
./jsonexpression.o: ../../pikotools/src/log/log.h
|
||||
./jsonexpression.o: ../../pikotools/src/log/filelog.h finderhelper.h
|
||||
./jsonexpression.o: fieldvaluehelper.h wrapper.h spacewrapper.h
|
||||
./jsonexpression.o: baseobjectwrapper.h modelcontainerwrapper.h ft.h
|
||||
./jsonexpression.o: baseobjectwrapper.h modelcontainerwrapper.h select.h ft.h
|
||||
./jsonexpression.o: ../../pikotools/src/convert/text.h
|
||||
./jsonexpression.o: ../../pikotools/src/convert/misc.h
|
||||
./jsonexpression.o: ../../pikotools/src/convert/text.h
|
||||
|
@ -194,8 +196,8 @@
|
|||
./model.o: dbexpression.h baseexpression.h morm_types.h modelenv.h
|
||||
./model.o: modeldata.h cursorhelper.h finderhelper.h fieldvaluehelper.h
|
||||
./model.o: wrapper.h spacewrapper.h baseobjectwrapper.h
|
||||
./model.o: modelcontainerwrapper.h ../../pikotools/src/convert/text.h
|
||||
./model.o: flatexpression.h
|
||||
./model.o: modelcontainerwrapper.h select.h
|
||||
./model.o: ../../pikotools/src/convert/text.h flatexpression.h
|
||||
./modelconnector.o: modelconnector.h clearer.h
|
||||
./modelconnector.o: ../../pikotools/src/date/date.h
|
||||
./modelconnector.o: ../../pikotools/src/convert/inttostr.h
|
||||
|
@ -233,7 +235,7 @@
|
|||
./postgresqlconnector.o: dbexpression.h baseexpression.h morm_types.h
|
||||
./postgresqlconnector.o: modelenv.h modeldata.h cursorhelper.h finderhelper.h
|
||||
./postgresqlconnector.o: fieldvaluehelper.h wrapper.h spacewrapper.h
|
||||
./postgresqlconnector.o: baseobjectwrapper.h modelcontainerwrapper.h
|
||||
./postgresqlconnector.o: baseobjectwrapper.h modelcontainerwrapper.h select.h
|
||||
./postgresqlconnector.o: ../../pikotools/src/convert/text.h
|
||||
./postgresqlconnector.o: ../../pikotools/src/convert/strtoint.h
|
||||
./postgresqlconnector.o: ../../pikotools/src/convert/text.h
|
||||
|
@ -257,8 +259,8 @@
|
|||
./postgresqlexpression.o: ../../pikotools/src/log/log.h
|
||||
./postgresqlexpression.o: ../../pikotools/src/log/filelog.h finderhelper.h
|
||||
./postgresqlexpression.o: fieldvaluehelper.h wrapper.h spacewrapper.h
|
||||
./postgresqlexpression.o: baseobjectwrapper.h modelcontainerwrapper.h ft.h
|
||||
./postgresqlexpression.o: ../../pikotools/src/convert/text.h
|
||||
./postgresqlexpression.o: baseobjectwrapper.h modelcontainerwrapper.h
|
||||
./postgresqlexpression.o: select.h ft.h ../../pikotools/src/convert/text.h
|
||||
./postgresqlqueryresult.o: postgresqlqueryresult.h queryresult.h
|
||||
./postgresqlqueryresult.o: ../../pikotools/src/log/log.h
|
||||
./postgresqlqueryresult.o: ../../pikotools/src/textstream/textstream.h
|
||||
|
|
|
@ -126,6 +126,7 @@ void BaseExpression::generate_from_model(Model & model)
|
|||
before_generate_from_model();
|
||||
dump_additional_info(model);
|
||||
model.fields();
|
||||
add_additional_columns(model);
|
||||
after_generate_from_model();
|
||||
}
|
||||
}
|
||||
|
@ -141,6 +142,11 @@ void BaseExpression::dump_additional_info(Model & model)
|
|||
}
|
||||
|
||||
|
||||
void BaseExpression::add_additional_columns(Model & model)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void BaseExpression::before_generate_from_model()
|
||||
{
|
||||
is_first_field = true;
|
||||
|
|
|
@ -334,6 +334,7 @@ protected:
|
|||
|
||||
virtual void save_foreign_key(const wchar_t * field_name, const FT & field_type, ModelEnv * model_env);
|
||||
virtual void dump_additional_info(Model & model);
|
||||
virtual void add_additional_columns(Model & model);
|
||||
|
||||
template<typename FieldValue>
|
||||
void put_field_value(const FieldValue & field_value, const FT & field_type)
|
||||
|
|
72
src/cursor.h
72
src/cursor.h
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018-2021, Tomasz Sowa
|
||||
* Copyright (c) 2018-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -64,6 +64,8 @@ public:
|
|||
use_table_prefix_for_fetching = c.use_table_prefix_for_fetching;
|
||||
query_result = c.query_result;
|
||||
select_status = c.select_status;
|
||||
select_flags = c.select_flags;
|
||||
rows_counter = c.rows_counter;
|
||||
|
||||
if( query_result )
|
||||
{
|
||||
|
@ -106,6 +108,8 @@ public:
|
|||
finder_helper.clear();
|
||||
query_result = nullptr;
|
||||
select_status = false;
|
||||
select_flags = Select::default_type;
|
||||
rows_counter = 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -145,6 +149,18 @@ public:
|
|||
}
|
||||
|
||||
|
||||
virtual void set_select_flags(const Select & select_flags)
|
||||
{
|
||||
this->select_flags = select_flags;
|
||||
}
|
||||
|
||||
|
||||
virtual void set_rows_counter_column_name(const std::wstring & column_name)
|
||||
{
|
||||
this->rows_counter_column_name = column_name;
|
||||
}
|
||||
|
||||
|
||||
virtual QueryResult * get_query_result()
|
||||
{
|
||||
return query_result;
|
||||
|
@ -164,6 +180,23 @@ public:
|
|||
}
|
||||
|
||||
|
||||
virtual void prepare_model_env_for_new_object(ModelEnv & model_env)
|
||||
{
|
||||
model_env.cursor_helper = &cursor_helper;
|
||||
model_env.finder_helper = &finder_helper;
|
||||
model_env.select_flags = select_flags;
|
||||
model_env.rows_counter = 0;
|
||||
|
||||
if( model_env.select_flags.is_with_rows_counter() )
|
||||
{
|
||||
if( cursor_helper.current_row == 0 )
|
||||
{
|
||||
model_env.rows_counter_column_name = rows_counter_column_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
virtual bool get(ModelClass & result)
|
||||
{
|
||||
bool res = false;
|
||||
|
@ -177,20 +210,21 @@ public:
|
|||
|
||||
if( db_connector )
|
||||
{
|
||||
ModelEnv model_env_local;
|
||||
result.model_env = &model_env_local;
|
||||
result.model_env->cursor_helper = &cursor_helper;
|
||||
result.model_env->finder_helper = &finder_helper;
|
||||
result.model_env->model = &result;
|
||||
|
||||
try
|
||||
{
|
||||
ModelEnv model_env_local;
|
||||
result.model_env = &model_env_local;
|
||||
result.model_env->model = &result;
|
||||
result.model_env->model_data = model_data;
|
||||
|
||||
finder_helper.clear(); // at the moment used only for calculating table prefixes (indices)
|
||||
cursor_helper.clear();
|
||||
cursor_helper.query_result = query_result;
|
||||
cursor_helper.has_autogenerated_select = has_autogenerated_select;
|
||||
cursor_helper.use_table_prefix_for_fetching_values = use_table_prefix_for_fetching;
|
||||
result.model_env->model_data = model_data;
|
||||
cursor_helper.current_row = 0;
|
||||
|
||||
prepare_model_env_for_new_object(model_env_local);
|
||||
|
||||
if( !cursor_helper.has_autogenerated_select && cursor_helper.use_table_prefix_for_fetching_values )
|
||||
{
|
||||
|
@ -205,6 +239,7 @@ public:
|
|||
if( query_result->cur_row < query_result->result_rows )
|
||||
{
|
||||
result.map_values_from_query();
|
||||
rows_counter = model_env_local.rows_counter;
|
||||
|
||||
if( result.found() )
|
||||
{
|
||||
|
@ -273,6 +308,7 @@ public:
|
|||
return get_list_generic(result, clear_list);
|
||||
}
|
||||
|
||||
|
||||
virtual std::vector<ModelClass> get_vector()
|
||||
{
|
||||
std::vector<ModelClass> result;
|
||||
|
@ -282,6 +318,12 @@ public:
|
|||
}
|
||||
|
||||
|
||||
virtual size_t get_rows_counter()
|
||||
{
|
||||
return rows_counter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -293,6 +335,9 @@ protected:
|
|||
FinderHelper finder_helper; // may CursorHelper and FinderHelper should be one class?
|
||||
QueryResult * query_result;
|
||||
bool select_status;
|
||||
Select select_flags;
|
||||
size_t rows_counter;
|
||||
std::wstring rows_counter_column_name;
|
||||
|
||||
|
||||
|
||||
|
@ -359,15 +404,15 @@ protected:
|
|||
cursor_helper.query_result = query_result;
|
||||
cursor_helper.has_autogenerated_select = has_autogenerated_select;
|
||||
cursor_helper.use_table_prefix_for_fetching_values = use_table_prefix_for_fetching;
|
||||
cursor_helper.current_row = query_result->cur_row;
|
||||
|
||||
added_model.set_connector(model_connector);
|
||||
added_model.clear();
|
||||
|
||||
prepare_model_env_for_new_object(model_env_local);
|
||||
added_model.model_env = &model_env_local;
|
||||
added_model.model_env->cursor_helper = &cursor_helper;
|
||||
added_model.model_env->finder_helper = &finder_helper;
|
||||
added_model.model_env->model_data = model_data;
|
||||
added_model.model_env->model = &added_model;
|
||||
added_model.model_env->model_data = model_data;
|
||||
|
||||
if( !cursor_helper.has_autogenerated_select && cursor_helper.use_table_prefix_for_fetching_values )
|
||||
{
|
||||
|
@ -377,6 +422,11 @@ protected:
|
|||
added_model.before_select();
|
||||
added_model.map_values_from_query();
|
||||
|
||||
if( model_env_local.select_flags.is_with_rows_counter() && query_result->cur_row == 0 )
|
||||
{
|
||||
rows_counter = model_env_local.rows_counter;
|
||||
}
|
||||
|
||||
if( added_model.found() )
|
||||
{
|
||||
added_model.after_select();
|
||||
|
|
|
@ -48,6 +48,7 @@ public:
|
|||
bool has_autogenerated_select;
|
||||
QueryResult * query_result;
|
||||
int current_column;
|
||||
size_t current_row;
|
||||
|
||||
// used if has_autogenerated_select is equal false
|
||||
// if use_table_prefix_for_fetching_values is true we find a column in such a form: table.column_name instead of just column_name
|
||||
|
@ -71,6 +72,7 @@ public:
|
|||
has_autogenerated_select = false;
|
||||
query_result = nullptr;
|
||||
current_column = 0;
|
||||
current_row = 0;
|
||||
use_table_prefix_for_fetching_values = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -468,6 +468,7 @@ void DbConnector::generate_remove_query(pt::TextStream & stream, Model & model)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
bool DbConnector::insert(pt::TextStream & stream, Model & model)
|
||||
{
|
||||
std::unique_ptr<QueryResult> query_result_ptr(create_query_result());
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
*/
|
||||
|
||||
#include "dbexpression.h"
|
||||
#include "model.h"
|
||||
|
||||
|
||||
namespace morm
|
||||
|
@ -295,11 +296,58 @@ DbExpression & DbExpression::group_end(pt::TextStream & stream)
|
|||
|
||||
DbExpression & DbExpression::page(pt::TextStream & stream, size_t page_number, size_t page_size)
|
||||
{
|
||||
stream << " limit " << page_number << "," << page_size << " ";
|
||||
stream << " LIMIT " << page_number << "," << page_size << " ";
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void DbExpression::generate_rows_counter_column_name(ModelEnv & model_env, pt::TextStream & str)
|
||||
{
|
||||
str << model_env.table_name;
|
||||
|
||||
if( model_env.table_index > 1 )
|
||||
{
|
||||
str << model_env.table_index;
|
||||
}
|
||||
|
||||
str << DbExpression::COLUMN_ROWS_COUNTER_POSTFIX;
|
||||
}
|
||||
|
||||
|
||||
void DbExpression::add_additional_columns(Model & model)
|
||||
{
|
||||
if( model.model_env )
|
||||
{
|
||||
if( model.model_env->select_flags.is_with_rows_counter() )
|
||||
{
|
||||
add_rows_counter_column(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DbExpression::add_rows_counter_column(Model & model)
|
||||
{
|
||||
if( out_stream && model.model_env )
|
||||
{
|
||||
field_before();
|
||||
(*out_stream) << "COUNT(*) OVER() AS ";
|
||||
|
||||
pt::TextStream str;
|
||||
generate_rows_counter_column_name(*model.model_env, str);
|
||||
|
||||
if( !model.model_env->has_autogenerated_select )
|
||||
{
|
||||
str.to_str(model.model_env->rows_counter_column_name);
|
||||
}
|
||||
|
||||
before_field_name();
|
||||
esc(str, *out_stream);
|
||||
after_field_name();
|
||||
|
||||
field_after();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018-2021, Tomasz Sowa
|
||||
* Copyright (c) 2018-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -50,6 +50,10 @@ public:
|
|||
DbExpression();
|
||||
virtual ~DbExpression();
|
||||
|
||||
|
||||
constexpr static const char * COLUMN_ROWS_COUNTER_POSTFIX = "_autoadded_rows_counter";
|
||||
|
||||
|
||||
virtual void set_output_type(int output_type);
|
||||
virtual int get_output_type();
|
||||
|
||||
|
@ -68,12 +72,13 @@ public:
|
|||
std::wstring column_expression; // field() methods can be called recursively, so don't make it as class object
|
||||
|
||||
column_expression = new_column_expression;
|
||||
column_expression += L" as ";
|
||||
column_expression += L" AS ";
|
||||
column_expression += new_column_name;
|
||||
|
||||
field(column_expression.c_str(), field_value, field_type, model_env);
|
||||
}
|
||||
|
||||
virtual void generate_rows_counter_column_name(ModelEnv & model_env, pt::TextStream & str);
|
||||
|
||||
|
||||
protected:
|
||||
|
@ -97,12 +102,12 @@ protected:
|
|||
void before_field_name();
|
||||
void after_field_name();
|
||||
|
||||
|
||||
private:
|
||||
void add_additional_columns(Model & model);
|
||||
|
||||
void before_field_value_string(const FT & field_type);
|
||||
void after_field_value_string(const FT & field_type);
|
||||
|
||||
virtual void add_rows_counter_column(Model & model);
|
||||
|
||||
};
|
||||
|
||||
|
|
307
src/finder.h
307
src/finder.h
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018-2021, Tomasz Sowa
|
||||
* Copyright (c) 2018-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -44,6 +44,7 @@
|
|||
#include "dbconnector.h"
|
||||
#include "modelconnector.h"
|
||||
#include "cursor.h"
|
||||
#include "select.h"
|
||||
|
||||
|
||||
namespace morm
|
||||
|
@ -52,7 +53,6 @@ namespace morm
|
|||
template<typename ModelClass>
|
||||
class Finder
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
|
||||
|
@ -113,10 +113,27 @@ public:
|
|||
model_data = nullptr;
|
||||
}
|
||||
|
||||
Finder<ModelClass> & set_connector(ModelConnector * model_connector)
|
||||
{
|
||||
this->model_connector = model_connector;
|
||||
set_out_stream();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Finder<ModelClass> & set_connector(ModelConnector & model_connector)
|
||||
{
|
||||
this->model_connector = &model_connector;
|
||||
set_out_stream();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Finder<ModelClass> & set_stream(pt::TextStream * out_stream)
|
||||
{
|
||||
this->out_stream = out_stream;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Finder<ModelClass> & set_out_stream(pt::TextStream * out_stream)
|
||||
Finder<ModelClass> & set_stream(pt::TextStream & out_stream)
|
||||
{
|
||||
this->out_stream = out_stream;
|
||||
return *this;
|
||||
|
@ -147,143 +164,19 @@ public:
|
|||
}
|
||||
|
||||
|
||||
Finder<ModelClass> & prepare_to_select()
|
||||
Finder<ModelClass> & select(const Select & select_flags = Select::default_type)
|
||||
{
|
||||
was_query_error = false;
|
||||
last_query_error.clear();
|
||||
has_autogenerated_select = false;
|
||||
use_table_prefix_for_fetching = false;
|
||||
start_new_select(select_flags);
|
||||
|
||||
if( model_connector )
|
||||
if( !select_flags.is_no_auto_generated_columns() )
|
||||
{
|
||||
if( out_stream )
|
||||
{
|
||||
set_db_expression();
|
||||
out_stream->clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
was_query_error = true;
|
||||
last_query_error = L"out stream object is required";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
was_query_error = true;
|
||||
last_query_error = L"model connector object is required";
|
||||
}
|
||||
|
||||
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;
|
||||
model.model_env->model = &model;
|
||||
model.table();
|
||||
model.model_env->add_table_name_to_finder_helper();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Finder<ModelClass> & select(ModelConnector & model_connector)
|
||||
{
|
||||
this->model_connector = &model_connector;
|
||||
set_out_stream();
|
||||
|
||||
return select();
|
||||
}
|
||||
|
||||
Finder<ModelClass> & select(ModelConnector * model_connector)
|
||||
{
|
||||
this->model_connector = model_connector;
|
||||
set_out_stream();
|
||||
|
||||
return select();
|
||||
}
|
||||
|
||||
Finder<ModelClass> & select(pt::TextStream & out_stream, ModelConnector & model_connector)
|
||||
{
|
||||
this->out_stream = &out_stream;
|
||||
this->model_connector = &model_connector;
|
||||
|
||||
return select();
|
||||
}
|
||||
|
||||
Finder<ModelClass> & select(pt::TextStream & out_stream, ModelConnector * model_connector)
|
||||
{
|
||||
this->out_stream = &out_stream;
|
||||
this->model_connector = model_connector;
|
||||
|
||||
return select();
|
||||
}
|
||||
|
||||
|
||||
Finder<ModelClass> & select(bool call_prepare = true)
|
||||
{
|
||||
if( call_prepare )
|
||||
{
|
||||
prepare_to_select();
|
||||
}
|
||||
|
||||
has_autogenerated_select = true;
|
||||
|
||||
if( model_connector && out_stream && db_expression )
|
||||
{
|
||||
(*out_stream) << "SELECT ";
|
||||
model.generate_select_columns(*out_stream);
|
||||
(*out_stream) << " FROM ";
|
||||
|
||||
if( !model.model_env->schema_name.empty() )
|
||||
{
|
||||
db_expression->schema_table_to_stream(*out_stream, model.model_env->schema_name, model.model_env->table_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
db_expression->table_to_stream(*out_stream, model.model_env->table_name);
|
||||
}
|
||||
|
||||
(*out_stream) << " AS ";
|
||||
db_expression->table_to_stream(*out_stream, model.model_env->table_name);
|
||||
|
||||
if( !finder_helper.join_tables_str.empty() )
|
||||
{
|
||||
(*out_stream) << " ";
|
||||
(*out_stream) << finder_helper.join_tables_str;
|
||||
}
|
||||
generate_standard_select();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Finder<ModelClass> & select(ModelData * model_data, bool call_prepare = true)
|
||||
{
|
||||
if( call_prepare )
|
||||
{
|
||||
prepare_to_select();
|
||||
}
|
||||
|
||||
this->model_data = model_data;
|
||||
return select(false);
|
||||
}
|
||||
|
||||
|
||||
Finder<ModelClass> & select(ModelData & model_data, bool call_prepare = true)
|
||||
{
|
||||
if( call_prepare )
|
||||
{
|
||||
prepare_to_select();
|
||||
}
|
||||
|
||||
this->model_data = &model_data;
|
||||
return select(false);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* used if we are not using auto generated selects
|
||||
*/
|
||||
|
@ -763,8 +656,19 @@ public:
|
|||
{
|
||||
Cursor<ModelClass> cursor;
|
||||
cursor.set_model_data(model_data);
|
||||
cursor.set_has_autogenerated_select(has_autogenerated_select);
|
||||
cursor.set_has_autogenerated_select(model_env.has_autogenerated_select);
|
||||
cursor.use_table_prefix(use_table_prefix_for_fetching);
|
||||
cursor.set_select_flags(model_env.select_flags);
|
||||
|
||||
if( model_env.select_flags.is_with_rows_counter() )
|
||||
{
|
||||
if( model_env.rows_counter_column_name.empty() )
|
||||
{
|
||||
generate_rows_counter_column_name(model_env);
|
||||
}
|
||||
|
||||
cursor.set_rows_counter_column_name(model_env.rows_counter_column_name);
|
||||
}
|
||||
|
||||
if( model_connector && out_stream )
|
||||
{
|
||||
|
@ -789,7 +693,9 @@ public:
|
|||
bool get(ModelClass & result)
|
||||
{
|
||||
Cursor<ModelClass> cursor = get_cursor();
|
||||
return cursor.get(result);
|
||||
bool status = cursor.get(result);
|
||||
model_env.rows_counter = cursor.get_rows_counter();
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
@ -805,7 +711,9 @@ public:
|
|||
bool get_list(std::list<ModelClass> & result, bool clear_list = true)
|
||||
{
|
||||
Cursor<ModelClass> cursor = get_cursor();
|
||||
return cursor.get_list(result, clear_list);
|
||||
bool status = cursor.get_list(result, clear_list);
|
||||
model_env.rows_counter = cursor.get_rows_counter();
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
@ -821,7 +729,9 @@ public:
|
|||
bool get_vector(std::vector<ModelClass> & result, bool clear_vector = true)
|
||||
{
|
||||
Cursor<ModelClass> cursor = get_cursor();
|
||||
return cursor.get_vector(result, clear_vector);
|
||||
bool status = cursor.get_vector(result, clear_vector);
|
||||
model_env.rows_counter = cursor.get_rows_counter();
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
@ -834,9 +744,89 @@ public:
|
|||
}
|
||||
|
||||
|
||||
size_t get_rows_counter()
|
||||
{
|
||||
return model_env.rows_counter;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
void set_out_stream()
|
||||
|
||||
|
||||
virtual void start_new_select(const Select & select_flags = Select::default_type)
|
||||
{
|
||||
was_query_error = false;
|
||||
last_query_error.clear();
|
||||
use_table_prefix_for_fetching = false;
|
||||
|
||||
if( model_connector )
|
||||
{
|
||||
if( out_stream )
|
||||
{
|
||||
set_db_expression();
|
||||
out_stream->clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
was_query_error = true;
|
||||
last_query_error = L"out stream object is required";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
was_query_error = true;
|
||||
last_query_error = L"model connector object is required";
|
||||
}
|
||||
|
||||
model.set_connector(model_connector);
|
||||
|
||||
finder_helper.clear();
|
||||
model_env.clear();
|
||||
model_env.select_flags = select_flags;
|
||||
model_env.has_autogenerated_select = false;
|
||||
model_env.model_data = model_data;
|
||||
model_env.finder_helper = &finder_helper;
|
||||
model_env.model = &model;
|
||||
|
||||
model.model_env = &model_env;
|
||||
model.table();
|
||||
model.model_env->add_table_name_to_finder_helper();
|
||||
}
|
||||
|
||||
|
||||
virtual void generate_standard_select()
|
||||
{
|
||||
if( model_connector && out_stream && db_expression && model.model_env )
|
||||
{
|
||||
model.model_env->has_autogenerated_select = true;
|
||||
|
||||
(*out_stream) << "SELECT ";
|
||||
model.generate_select_columns(*out_stream);
|
||||
(*out_stream) << " FROM ";
|
||||
|
||||
if( !model.model_env->schema_name.empty() )
|
||||
{
|
||||
db_expression->schema_table_to_stream(*out_stream, model.model_env->schema_name, model.model_env->table_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
db_expression->table_to_stream(*out_stream, model.model_env->table_name);
|
||||
}
|
||||
|
||||
(*out_stream) << " AS ";
|
||||
db_expression->table_to_stream(*out_stream, model.model_env->table_name);
|
||||
|
||||
if( !finder_helper.join_tables_str.empty() )
|
||||
{
|
||||
(*out_stream) << " ";
|
||||
(*out_stream) << finder_helper.join_tables_str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
virtual void set_out_stream()
|
||||
{
|
||||
if( model_connector )
|
||||
{
|
||||
|
@ -849,6 +839,47 @@ protected:
|
|||
}
|
||||
|
||||
|
||||
virtual void generate_rows_counter_column_name(ModelEnv & model_env, pt::TextStream & str)
|
||||
{
|
||||
if( model_env.has_autogenerated_select )
|
||||
{
|
||||
/*
|
||||
* if the column name is empty put a short string which will not allocate dynamic memory
|
||||
* (special optimisation in std::string - a short static buffer)
|
||||
*
|
||||
* we need a non empty string for field(...) method to work correctly
|
||||
* (if the column name was empty then the field(...) would skip the column)
|
||||
* (we need the field(...) to correctly advance cursor_helper->current_column)
|
||||
*/
|
||||
str << L"morm";
|
||||
}
|
||||
else
|
||||
{
|
||||
if( model_connector )
|
||||
{
|
||||
DbConnector * db_connector = model_connector->get_db_connector();
|
||||
|
||||
if( db_connector )
|
||||
{
|
||||
DbExpression * db_expression = db_connector->get_expression();
|
||||
|
||||
if( db_expression )
|
||||
{
|
||||
db_expression->generate_rows_counter_column_name(model_env, str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
virtual void generate_rows_counter_column_name(ModelEnv & model_env)
|
||||
{
|
||||
pt::TextStream str;
|
||||
generate_rows_counter_column_name(model_env, str);
|
||||
str.to_str(model_env.rows_counter_column_name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
@ -863,10 +894,10 @@ private:
|
|||
ModelEnv model_env;
|
||||
FinderHelper finder_helper;
|
||||
ModelData * model_data;
|
||||
bool has_autogenerated_select;
|
||||
bool use_table_prefix_for_fetching;
|
||||
|
||||
|
||||
|
||||
void set_db_expression()
|
||||
{
|
||||
if( model_connector )
|
||||
|
@ -896,6 +927,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename Container>
|
||||
void field_in(const wchar_t * table_name, int table_index, const wchar_t * field_name, const Container & container)
|
||||
{
|
||||
|
@ -911,7 +943,6 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
12
src/ft.h
12
src/ft.h
|
@ -100,6 +100,18 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
FT & operator=(FieldType type)
|
||||
{
|
||||
this->type = static_cast<int>(type);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FT & operator=(int type)
|
||||
{
|
||||
this->type = type;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool is_flag_set(int flag_mask) const
|
||||
{
|
||||
return (type & flag_mask) != 0;
|
||||
|
|
|
@ -934,6 +934,7 @@ void Model::map_values_from_query()
|
|||
model_env->was_primary_key_read = false; // whether or not there was at least one column with primary_key flag
|
||||
model_env->has_primary_key_set = true; // whether all primary_columns were different than null
|
||||
fields();
|
||||
map_additional_columns_from_query();
|
||||
model_env->model_work_mode = MORM_MODEL_WORK_MODE_NONE;
|
||||
|
||||
if( model_env->was_primary_key_read && model_env->has_primary_key_set )
|
||||
|
@ -950,6 +951,40 @@ void Model::map_values_from_query()
|
|||
}
|
||||
|
||||
|
||||
void Model::map_additional_columns_from_query()
|
||||
{
|
||||
if( model_env )
|
||||
{
|
||||
if( model_env->select_flags.is_with_rows_counter() )
|
||||
{
|
||||
map_rows_counter_from_query();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Model::map_rows_counter_from_query()
|
||||
{
|
||||
if( model_env && model_env->cursor_helper )
|
||||
{
|
||||
/*
|
||||
* take the value only from the first row, the value should be the same on every row
|
||||
*/
|
||||
if( model_env->cursor_helper->current_row == 0 )
|
||||
{
|
||||
field(model_env->rows_counter_column_name.c_str(), L"", model_env->rows_counter);
|
||||
}
|
||||
else
|
||||
{
|
||||
if( model_env->cursor_helper && model_env->cursor_helper->has_autogenerated_select )
|
||||
{
|
||||
model_env->cursor_helper->current_column += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Model::clear()
|
||||
{
|
||||
|
|
|
@ -350,6 +350,8 @@ protected:
|
|||
virtual void save_tree(bool save_whole_tree);
|
||||
|
||||
virtual void map_values_from_query();
|
||||
virtual void map_additional_columns_from_query();
|
||||
virtual void map_rows_counter_from_query();
|
||||
|
||||
virtual bool db_query(const char * raw_sql);
|
||||
virtual bool db_query(const std::string & raw_sql);
|
||||
|
@ -1642,6 +1644,7 @@ protected:
|
|||
template<typename ModelClass> friend class Finder;
|
||||
template<typename ModelClass> friend class Cursor;
|
||||
friend class BaseExpression;
|
||||
friend class DbExpression;
|
||||
friend class DbConnector;
|
||||
friend class FlatConnector;
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "fieldvaluehelper.h"
|
||||
#include "morm_types.h"
|
||||
#include "wrapper.h"
|
||||
#include "select.h"
|
||||
|
||||
|
||||
#ifdef MORM_HAS_EZC_LIBRARY
|
||||
|
@ -106,6 +107,11 @@ public:
|
|||
#endif
|
||||
|
||||
bool status;
|
||||
bool has_autogenerated_select;
|
||||
Select select_flags;
|
||||
size_t rows_counter;
|
||||
std::wstring rows_counter_column_name;
|
||||
|
||||
|
||||
|
||||
ModelEnv()
|
||||
|
@ -142,6 +148,10 @@ public:
|
|||
was_field_found = e.was_field_found;
|
||||
wrapper = e.wrapper;
|
||||
status = e.status;
|
||||
has_autogenerated_select = e.has_autogenerated_select;
|
||||
select_flags = e.select_flags;
|
||||
rows_counter = e.rows_counter;
|
||||
rows_counter_column_name = e.rows_counter_column_name;
|
||||
|
||||
#ifdef MORM_HAS_EZC_LIBRARY
|
||||
ezc_fun_info = e.ezc_fun_info;
|
||||
|
@ -194,6 +204,10 @@ public:
|
|||
was_field_found = false;
|
||||
wrapper.clear();
|
||||
status = true;
|
||||
has_autogenerated_select = false;
|
||||
select_flags = Select::default_type;
|
||||
rows_counter = 0;
|
||||
rows_counter_column_name.clear();
|
||||
|
||||
#ifdef MORM_HAS_EZC_LIBRARY
|
||||
ezc_fun_info = nullptr;
|
||||
|
@ -215,7 +229,6 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ void PostgreSQLExpression::esc(const pt::Date & date, pt::TextStream & stream, c
|
|||
|
||||
DbExpression & PostgreSQLExpression::page(pt::TextStream & stream, size_t page_number, size_t page_size)
|
||||
{
|
||||
stream << " offset " << page_number << " limit " << page_size << " ";
|
||||
stream << " OFFSET " << page_number << " LIMIT " << page_size << " ";
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* 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) 2022, 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_src_select
|
||||
#define headerfile_morm_src_select
|
||||
|
||||
namespace morm
|
||||
{
|
||||
|
||||
/*
|
||||
* additional arguments for Finder::select method
|
||||
*/
|
||||
class Select
|
||||
{
|
||||
public:
|
||||
|
||||
enum SelectType
|
||||
{
|
||||
default_type = 0,
|
||||
no_auto_generated_columns = 1,
|
||||
with_rows_counter = 2,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* type can be a superposition from SelectType values
|
||||
*/
|
||||
int type;
|
||||
|
||||
|
||||
|
||||
Select()
|
||||
{
|
||||
type = 0;
|
||||
}
|
||||
|
||||
Select(const Select & select_type)
|
||||
{
|
||||
this->type = select_type.type;
|
||||
}
|
||||
|
||||
Select(SelectType select_type)
|
||||
{
|
||||
this->type = static_cast<int>(select_type);
|
||||
}
|
||||
|
||||
Select(int type)
|
||||
{
|
||||
this->type = type;
|
||||
}
|
||||
|
||||
Select & operator=(const Select & select_type)
|
||||
{
|
||||
type = select_type.type;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Select & operator=(SelectType select_type)
|
||||
{
|
||||
this->type = static_cast<int>(select_type);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Select & operator=(int type)
|
||||
{
|
||||
this->type = type;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool is_flag_set(int flag_mask) const
|
||||
{
|
||||
return (type & flag_mask) != 0;
|
||||
}
|
||||
|
||||
|
||||
bool is_with_rows_counter() const
|
||||
{
|
||||
return is_flag_set(with_rows_counter);
|
||||
}
|
||||
|
||||
|
||||
bool is_no_auto_generated_columns() const
|
||||
{
|
||||
return is_flag_set(no_auto_generated_columns);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue