From fd1cc7debe03ff4c73680ce31d90fd82b2651652 Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Sun, 22 Apr 2018 21:04:50 +0000 Subject: [PATCH] added: Model::ModelData base class to use with Finder, Model.update(), Model.insert() and Model.remove() added: Model.add_field_for_select() method git-svn-id: svn://ttmath.org/publicrep/morm/trunk@1092 e52654a7-88a9-db11-a3e9-0013d4bc506e --- src/baseexpression.h | 10 ++++- src/dbexpression.cpp | 6 +++ src/dbexpression.h | 11 +++++ src/finder.h | 64 ++++++++++++++++++++++----- src/model.cpp | 73 +++++++++++++++++++++++++++---- src/model.h | 84 +++++++++++++++++++++++++++++++++--- src/modelconnector.cpp | 22 ++++++---- src/modelconnector.h | 66 +++++++++++++++++----------- src/morm_types.h | 8 ++-- src/postgresqlexpression.cpp | 5 +++ src/postgresqlexpression.h | 1 + 11 files changed, 287 insertions(+), 63 deletions(-) diff --git a/src/baseexpression.h b/src/baseexpression.h index 52a9d8d..9b5cf9f 100644 --- a/src/baseexpression.h +++ b/src/baseexpression.h @@ -86,6 +86,14 @@ public: } } + template + void field(const PT::TextStream & field_name, const FieldValue & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + { + std::wstring field_name_str; // field() methods can be called recursively, so don't make it as class object + field_name.to_string(field_name_str); + + return field(field_name_str.c_str(), field_value, insertable, updatable, is_primary_key); + } template void field_in(PT::TextStream & stream, const wchar_t * field_name, const std::set & container) @@ -135,7 +143,7 @@ public: template - void field(PT::TextStream & stream, const wchar_t * field_name, const FieldValue & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + void field_to_stream(PT::TextStream & stream, const wchar_t * field_name, const FieldValue & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { this->out_stream = &stream; field(field_name, field_value, insertable, updatable, is_primary_key); diff --git a/src/dbexpression.cpp b/src/dbexpression.cpp index 4f4e67d..f7ba295 100644 --- a/src/dbexpression.cpp +++ b/src/dbexpression.cpp @@ -284,4 +284,10 @@ DbExpression & DbExpression::group_end(PT::TextStream & stream) } +DbExpression & DbExpression::page(PT::TextStream & stream, size_t page_number, size_t page_size) +{ + stream << " limit " << page_number << "," << page_size << " "; + return *this; +} + } diff --git a/src/dbexpression.h b/src/dbexpression.h index 2e10766..f9b5341 100644 --- a/src/dbexpression.h +++ b/src/dbexpression.h @@ -59,6 +59,17 @@ public: virtual DbExpression & group_and(PT::TextStream & stream); virtual DbExpression & group_end(PT::TextStream & stream); + virtual DbExpression & page(PT::TextStream & stream, size_t page_number, size_t page_size); + + + template + void add_field_for_select(const wchar_t * new_column_expression, const wchar_t * new_column_name, FieldValue & field_value) + { + PT::TextStream column_expression; + column_expression << new_column_expression << " as " << new_column_name; + + field(column_expression, field_value, false, false); + } protected: diff --git a/src/finder.h b/src/finder.h index e221b55..cb64c2c 100644 --- a/src/finder.h +++ b/src/finder.h @@ -60,6 +60,7 @@ public: out_stream = nullptr; db_expression = nullptr; was_query_error = false; + model_data = nullptr; } @@ -69,6 +70,7 @@ public: this->model_connector = nullptr; db_expression = nullptr; was_query_error = false; + model_data = nullptr; } Finder(ModelConnector & model_connector) @@ -77,6 +79,7 @@ public: out_stream = nullptr; db_expression = nullptr; was_query_error = false; + model_data = nullptr; } Finder(ModelConnector * model_connector) @@ -85,6 +88,7 @@ public: out_stream = nullptr; db_expression = nullptr; was_query_error = false; + model_data = nullptr; } Finder(PT::TextStream & out_stream, ModelConnector & model_connector) @@ -93,6 +97,7 @@ public: this->model_connector = &model_connector; db_expression = nullptr; was_query_error = false; + model_data = nullptr; } Finder(PT::TextStream & out_stream, ModelConnector * model_connector) @@ -101,6 +106,7 @@ public: this->model_connector = model_connector; db_expression = nullptr; was_query_error = false; + model_data = nullptr; } @@ -146,6 +152,7 @@ public: { was_query_error = false; last_query_error.clear(); + model_data = nullptr; if( model_connector ) { @@ -178,9 +185,12 @@ public: - Finder & select() + Finder & select(bool call_prepare = true) { - prepare_to_select(); + if( call_prepare ) + { + prepare_to_select(); + } if( model_connector && out_stream ) { @@ -194,7 +204,19 @@ public: return *this; } + Finder & select(Model::ModelData * model_data) + { + prepare_to_select(); + this->model_data = model_data; + return select(false); + } + Finder & select(Model::ModelData & model_data) + { + prepare_to_select(); + this->model_data = &model_data; + return select(false); + } Finder & where() { @@ -249,7 +271,7 @@ public: if( db_expression ) { db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_EQ); - db_expression->field(*out_stream, field_name, field_value, false, false, false); + db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false); } return *this; @@ -262,7 +284,7 @@ public: if( db_expression ) { db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_LT); - db_expression->field(*out_stream, field_name, field_value, false, false, false); + db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false); } return *this; @@ -275,7 +297,7 @@ public: if( db_expression ) { db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_GT); - db_expression->field(*out_stream, field_name, field_value, false, false, false); + db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false); } return *this; @@ -288,7 +310,7 @@ public: if( db_expression ) { db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_LE); - db_expression->field(*out_stream, field_name, field_value, false, false, false); + db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false); } return *this; @@ -301,7 +323,7 @@ public: if( db_expression ) { db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_GE); - db_expression->field(*out_stream, field_name, field_value, false, false, false); + db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false); } return *this; @@ -345,11 +367,28 @@ public: return *this; } - Finder & raw_sql(const char * sql) + Finder & page(size_t page_number, size_t page_size) + { + if( out_stream && db_expression ) + { + db_expression->page(*out_stream, page_number, page_size); + } + + return *this; + } + + + Finder & raw(const char * sql, bool add_spaces = true) { if( out_stream ) { - (*out_stream) << " " << sql << " "; + if( add_spaces ) + (*out_stream) << ' '; + + (*out_stream) << sql; + + if( add_spaces ) + (*out_stream) << ' '; } return *this; @@ -372,12 +411,13 @@ public: { try { + result.model_data = model_data; result.before_select(); res = db_connector->query_select(*out_stream); if( res ) { - result.set_save_mode(Model::DO_UPDATE_ON_SAVE); + result.set_save_mode(Model::DO_UPDATE_ON_SAVE); // IMPROVE ME check if there is a primary key model_connector->map_values_from_query(result); result.after_select(); } @@ -438,7 +478,8 @@ public: added_model.set_connector(model_connector); added_model.clear(); - added_model.set_save_mode(Model::DO_UPDATE_ON_SAVE); + added_model.set_save_mode(Model::DO_UPDATE_ON_SAVE); // IMPROVE ME check if there is a primary key + added_model.model_data = model_data; added_model.before_select(); model_connector->map_values_from_query(added_model); added_model.after_select(); @@ -484,6 +525,7 @@ private: ModelClass model; bool was_query_error; std::wstring last_query_error; + Model::ModelData * model_data; void set_db_expression() { diff --git a/src/model.cpp b/src/model.cpp index 3a817a3..434aea6 100644 --- a/src/model.cpp +++ b/src/model.cpp @@ -41,6 +41,7 @@ namespace morm Model::Model() { model_connector = nullptr; + model_data = nullptr; save_mode = DO_INSERT_ON_SAVE; } @@ -181,15 +182,30 @@ void Model::generate_insert_query(PT::TextStream & stream) } -void Model::insert() +bool Model::insert(ModelData * model_data) { + bool result = false; + if( model_connector ) { + this->model_data = model_data; + if( model_connector->insert(*this) ) { - save_mode = DO_UPDATE_ON_SAVE; + save_mode = DO_UPDATE_ON_SAVE; // IMPROVE ME check if there is a primary key + result = true; } + + this->model_data = nullptr; } + + return result; +} + + +bool Model::insert(ModelData & model_data) +{ + return insert(&model_data); } @@ -202,12 +218,24 @@ void Model::generate_update_query(PT::TextStream & stream) } -void Model::update() +bool Model::update(ModelData * model_data) { + bool result = false; + if( model_connector ) { - model_connector->update(*this); + this->model_data = model_data; + result = model_connector->update(*this); + this->model_data = nullptr; } + + return result; +} + + +bool Model::update(ModelData & model_data) +{ + return update(&model_data); } @@ -220,37 +248,63 @@ void Model::generate_remove_query(PT::TextStream & stream) } -void Model::remove() +bool Model::remove(ModelData * model_data) { + bool result = false; + if( model_connector ) { + this->model_data = model_data; + if( model_connector->remove(*this) ) { save_mode = DO_INSERT_ON_SAVE; + result = true; } + + this->model_data = nullptr; } + + return result; } -void Model::save() +bool Model::remove(ModelData & model_data) { + return remove(&model_data); +} + + +bool Model::save(ModelData * model_data) +{ + bool result = false; + switch( save_mode ) { case DO_DELETE_ON_SAVE: - remove(); + result = remove(model_data); break; case DO_INSERT_ON_SAVE: - insert(); + result = insert(model_data); break; case DO_UPDATE_ON_SAVE: - update(); + result = update(model_data); break; case DO_NOTHING_ON_SAVE: + // may return true? break; } + + return result; +} + + +bool Model::save(ModelData & model_data) +{ + return save(&model_data); } @@ -262,6 +316,7 @@ void Model::clear() } save_mode = DO_INSERT_ON_SAVE; + model_data = nullptr; } diff --git a/src/model.h b/src/model.h index 4390a1e..7833d99 100644 --- a/src/model.h +++ b/src/model.h @@ -51,6 +51,14 @@ class Model { public: + class ModelData + { + public: + + ModelData() {} + virtual ~ModelData() {} + }; + enum SaveMode { DO_INSERT_ON_SAVE, @@ -103,15 +111,19 @@ public: virtual std::string to_string(); virtual void generate_insert_query(PT::TextStream & stream); - virtual void insert(); + virtual bool insert(ModelData * model_data = nullptr); + virtual bool insert(ModelData & model_data); virtual void generate_update_query(PT::TextStream & stream); - virtual void update(); + virtual bool update(ModelData * model_data = nullptr); + virtual bool update(ModelData & model_data); virtual void generate_remove_query(PT::TextStream & stream); - virtual void remove(); + virtual bool remove(ModelData * model_data = nullptr); + virtual bool remove(ModelData & model_data); - virtual void save(); + virtual bool save(ModelData * model_data = nullptr); + virtual bool save(ModelData & model_data); // set object to default values @@ -122,6 +134,7 @@ protected: ModelConnector * model_connector; SaveMode save_mode; + ModelData * model_data; Model(); virtual ~Model(); @@ -148,7 +161,34 @@ protected: { if( model_connector ) { - model_connector->field(field_name, field_value, insertable, updatable, is_primary_key); + model_connector->field(field_name, field_name, field_value, insertable, updatable, is_primary_key); + } + } + + template + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + { + if( model_connector ) + { + model_connector->field(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); + } + } + + template + void field(const PT::TextStream & field_name, FieldValue & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + { + if( model_connector ) + { + model_connector->field(field_name, field_name, field_value, insertable, updatable, is_primary_key); + } + } + + template + void field(const PT::TextStream & db_field_name, const PT::TextStream & flat_field_name, FieldValue & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + { + if( model_connector ) + { + model_connector->field(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); } } @@ -170,10 +210,44 @@ protected: } } + + template + void add_field_for_select(const wchar_t * new_column_expression, const wchar_t * new_column_name, const wchar_t * flat_field_name, FieldValue & field_value) + { + if( model_connector ) + { + if( get_connector_mode() == MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL ) + { + model_connector->add_field_for_select(new_column_expression, new_column_name, field_value); + } + else + if( get_connector_mode() == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING ) + { + model_connector->field(L"", flat_field_name, field_value, false, false, false); + } + else + if( get_connector_mode() == MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB_RESULTSET ) + { + model_connector->field(new_column_name, L"", field_value, false, false, false); + } + else + if( get_connector_mode() == MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE ) + { + model_connector->field(L"", L"", field_value, false, false, false); // the names don't matter here + } + } + } + + template + void add_field_for_select(const wchar_t * new_column_expression, const wchar_t * new_column_name, FieldValue & field_value) + { + add_field_for_select(new_column_expression, new_column_name, new_column_name, field_value); + } //void field(const wchar_t * field_name, Model & field, bool insertable = true, bool updatable = true); template friend class Finder; friend class ModelConnector; + }; } // namespace diff --git a/src/modelconnector.cpp b/src/modelconnector.cpp index 3bcb225..4950044 100644 --- a/src/modelconnector.cpp +++ b/src/modelconnector.cpp @@ -174,7 +174,7 @@ void ModelConnector::to_text(PT::TextStream & stream, Model & model) { if( flat_connector ) { - model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_EXPRESSION; + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING; //expression_callback = flat_connector->get_expression(); //if( expression_callback ) @@ -192,7 +192,7 @@ void ModelConnector::generate_select_columns(PT::TextStream & stream, Model & mo { if( db_connector ) { - model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION; + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL; //expression_callback = db_connector->get_expression(); //if( expression_callback ) @@ -211,7 +211,7 @@ void ModelConnector::generate_insert_query(PT::TextStream & stream, Model & mode { if( db_connector ) { - model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION; + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL; //expression_callback = db_connector->get_expression(); //if( expression_callback ) @@ -229,7 +229,7 @@ void ModelConnector::generate_update_query(PT::TextStream & stream, Model & mode { if( db_connector ) { - model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION; + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL; //expression_callback = db_connector->get_expression(); //if( expression_callback ) @@ -247,7 +247,7 @@ void ModelConnector::generate_remove_query(PT::TextStream & stream, Model & mode { if( db_connector ) { - model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION; + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL; db_connector->generate_remove_query(stream, model); model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE; } @@ -264,7 +264,7 @@ bool ModelConnector::insert(Model & model) if( db_connector && out_stream ) { - model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION; + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL; //db_connector_callback = db_connector; model.before_insert(); @@ -291,7 +291,7 @@ bool ModelConnector::update(Model & model) if( db_connector && out_stream ) { - model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION; + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL; //db_connector_callback = db_connector; model.before_update(); @@ -320,7 +320,7 @@ bool ModelConnector::remove(Model & model) if( db_connector && out_stream ) { - model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION; + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL; //db_connector_callback = db_connector; model.before_remove(); @@ -348,7 +348,7 @@ void ModelConnector::map_values_from_query(Model & model) if( db_connector ) { - model_connector_mode = MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB; + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB_RESULTSET; //db_connector_callback = db_connector; model.map_fields(); //db_connector_callback = nullptr; @@ -368,6 +368,10 @@ void ModelConnector::clear_values(Model & model) } +bool ModelConnector::is_empty_field(const wchar_t * value) +{ + return (!value || *value == '\0'); +} } diff --git a/src/modelconnector.h b/src/modelconnector.h index 1673ecc..0dfa45b 100644 --- a/src/modelconnector.h +++ b/src/modelconnector.h @@ -121,43 +121,33 @@ protected: template - void field(const wchar_t * field_name, FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key) + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key) { - // may we need only db_connector_callback? - -// if( expression_callback ) -// { -// expression_callback->field(field_name, field_value, insertable, updatable, is_primary_key); -// } - -// if( db_connector_callback ) -// { -// db_connector_callback->get_value_by_field_name(field_name, field_value); -// } - - if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_EXPRESSION && flat_connector ) + if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING && flat_connector ) { FlatExpression * flat_expression = flat_connector->get_expression(); - if( flat_expression ) + if( flat_expression && !is_empty_field(flat_field_name) ) { - flat_expression->field(field_name, field_value, insertable, updatable, is_primary_key); + // insertable, updatable and is_primary_key are ignored here + flat_expression->field(flat_field_name, field_value, insertable, updatable, is_primary_key); } } - if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION && db_connector ) + if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL && db_connector ) { DbExpression * db_expression = db_connector->get_expression(); - if( db_expression ) + if( db_expression && !is_empty_field(db_field_name) ) { - db_expression->field(field_name, field_value, insertable, updatable, is_primary_key); + db_expression->field(db_field_name, field_value, insertable, updatable, is_primary_key); } } - if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB && db_connector ) + if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB_RESULTSET && db_connector ) { - db_connector->get_value_by_field_name(field_name, field_value); + if( !is_empty_field(db_field_name) ) + db_connector->get_value_by_field_name(db_field_name, field_value); } if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE && db_connector ) @@ -167,37 +157,65 @@ protected: } } + + template + void field(const PT::TextStream & db_field_name, const PT::TextStream & flat_field_name, FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key) + { + std::wstring db_field, flat_field; // field() methods from model connector can be called recursively, so don't make it as class objects + + db_field_name.to_string(db_field); + flat_field_name.to_string(flat_field); + + field(db_field.c_str(), flat_field.c_str(), field_value, insertable, updatable, is_primary_key); + } + template void field_list(const wchar_t * field_name, std::list & field_list, bool insertable = true, bool updatable = true, bool is_primary_key = false) { - if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_EXPRESSION && flat_connector ) + if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING && flat_connector ) { FlatExpression * flat_expression = flat_connector->get_expression(); - if( flat_expression ) + if( flat_expression && !is_empty_field(field_name) ) { flat_expression->field_list(field_name, field_list, insertable, updatable, is_primary_key); } } } + template + void add_field_for_select(const wchar_t * new_column_expression, const wchar_t * new_column_name, FieldValue & field_value) + { + if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL && db_connector ) + { + DbExpression * db_expression = db_connector->get_expression(); + + if( db_expression && !is_empty_field(new_column_expression) ) + { + db_expression->add_field_for_select(new_column_expression, new_column_name, field_value); + } + } + } template void get_last_sequence(const wchar_t * sequence_table_name, FieldValue & field_value) { - if( db_connector ) + if( db_connector && !is_empty_field(sequence_table_name) ) { db_connector->get_last_sequence(sequence_table_name, field_value); } } + virtual bool is_empty_field(const wchar_t * value); + /* * Model is using field() method */ friend class Model; template friend class Finder; + }; } diff --git a/src/morm_types.h b/src/morm_types.h index 9434a5d..1549849 100644 --- a/src/morm_types.h +++ b/src/morm_types.h @@ -36,13 +36,13 @@ #define headerfile_morm_morm_types #define MORM_MODEL_CONNECTOR_MODE_NONE 0 -#define MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_EXPRESSION 1 -#define MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION 2 +#define MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING 1 +#define MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_SQL 2 // not used at the moment, there are not any flat parsers (json parser) -#define MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_FLAT 3 +#define MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_FLAT_STRING 3 -#define MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB 4 +#define MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB_RESULTSET 4 #define MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE 5 diff --git a/src/postgresqlexpression.cpp b/src/postgresqlexpression.cpp index 1dc08ae..34a2fde 100644 --- a/src/postgresqlexpression.cpp +++ b/src/postgresqlexpression.cpp @@ -116,6 +116,11 @@ void PostgreSQLExpression::esc(char val, PT::TextStream & stream) } +DbExpression & PostgreSQLExpression::page(PT::TextStream & stream, size_t page_number, size_t page_size) +{ + stream << " offset " << page_number << " limit " << page_size << " "; + return *this; +} } diff --git a/src/postgresqlexpression.h b/src/postgresqlexpression.h index 7f9131d..562eca6 100644 --- a/src/postgresqlexpression.h +++ b/src/postgresqlexpression.h @@ -46,6 +46,7 @@ class PostgreSQLExpression : public DbExpression public: void esc(char val, PT::TextStream & stream); + DbExpression & page(PT::TextStream & stream, size_t page_number, size_t page_size); protected: