From 7ff05f493cd5c51c7df04d355fd08b43171d3033 Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Thu, 22 Aug 2019 18:33:35 +0000 Subject: [PATCH] added: to Model: virtual void set_parent_key_in_childs() for setting a parent key id in child models, it is called after after_insert() method added: SetFieldValueHelper class used for storing primary key values from a parent model git-svn-id: svn://ttmath.org/publicrep/morm/trunk@1204 e52654a7-88a9-db11-a3e9-0013d4bc506e --- samples/Makefile.dep | 9 +- samples/attachment.h | 105 +++++++++++++++++++ samples/person.h | 9 ++ samples/sample01.h | 13 +++ src/Makefile.dep | 36 ++++--- src/model.cpp | 40 +++++++- src/model.h | 161 +++++++++++++++++++++++++++-- src/modelenv.h | 10 ++ src/morm_types.h | 14 +++ src/setfieldvaluehelper.h | 206 ++++++++++++++++++++++++++++++++++++++ 10 files changed, 571 insertions(+), 32 deletions(-) create mode 100644 samples/attachment.h create mode 100644 src/setfieldvaluehelper.h diff --git a/samples/Makefile.dep b/samples/Makefile.dep index 5180171..5d0c610 100644 --- a/samples/Makefile.dep +++ b/samples/Makefile.dep @@ -14,10 +14,11 @@ main.o: ../../morm/src/queryresult.h ../../morm/src/flatconnector.h main.o: ../../morm/src/dbexpression.h ../../morm/src/baseexpression.h main.o: ../../morm/src/modelenv.h ../../morm/src/modeldata.h main.o: ../../morm/src/cursorhelper.h ../../morm/src/finderhelper.h -main.o: ../../morm/src/flatexpression.h ../../morm/src/finder.h -main.o: ../../pikotools/utf8/utf8.h ../../morm/src/cursor.h -main.o: ../../morm/src/jsonexpression.h ../../morm/src/postgresqlexpression.h +main.o: ../../morm/src/setfieldvaluehelper.h ../../morm/src/flatexpression.h +main.o: ../../morm/src/finder.h ../../pikotools/utf8/utf8.h +main.o: ../../morm/src/cursor.h ../../morm/src/jsonexpression.h +main.o: ../../morm/src/postgresqlexpression.h main.o: ../../morm/src/dochtmlexpression.h ../../morm/src/jsonconnector.h main.o: ../../morm/src/postgresqlconnector.h main.o: ../../morm/src/postgresqlqueryresult.h -main.o: ../../morm/src/dochtmlconnector.h person.h language.h +main.o: ../../morm/src/dochtmlconnector.h person.h language.h attachment.h diff --git a/samples/attachment.h b/samples/attachment.h new file mode 100644 index 0000000..a9de982 --- /dev/null +++ b/samples/attachment.h @@ -0,0 +1,105 @@ +/* + * This file is a part of morm + * and is distributed under the 2-Clause BSD licence. + * Author: Tomasz Sowa + */ + +/* + * 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_samples_attachment +#define headerfile_morm_samples_attachment + +#include +#include "morm.h" + + +namespace morm +{ +namespace samples +{ + +/* +CREATE TABLE public.attachment ( + id bigserial, + bigint person_id, + name varchar(64), + content text, + some_flags bool, + created_date timestamp with time zone, + + primary key(id) +); +*/ + + +class Attachment : public morm::Model +{ +public: + + long id; + long person_id; + std::wstring name; + std::string content; + bool some_flags; + PT::Date created_date; + + + void map_fields() + { + field(L"id", id, false, false, true); + field(L"person_id", person_id); + field(L"name", name); + field(L"content", content); + field(L"some_flags", some_flags); + field(L"created_date", created_date); + } + + + void table_name(PT::TextStream & stream) + { + // schema.table_name or just table_name + stream << "public.attachment"; + } + + void after_insert() + { + get_last_sequence(L"public.attachment_id_seq", id); + } + + +}; + + + +} +} + + +#endif + diff --git a/samples/person.h b/samples/person.h index 7e4f1fb..773e7ca 100644 --- a/samples/person.h +++ b/samples/person.h @@ -38,6 +38,8 @@ #include #include "morm.h" #include "language.h" +#include "attachment.h" + namespace morm @@ -67,14 +69,21 @@ public: std::wstring email; Language language; + Attachment attachment; void map_fields() { field(L"id", id, false, false, true); + //field(L"id", id, f::no_insertable | f::no_updatable | f::primary_key); + field(L"first_name", first_name); field(L"last_name", last_name); field(L"email", email); field(L"language_id", language); + + field(L"person_id", attachment, true, true, false); + //field(L"person_id", attachment, f::insertable | f::updatable | f::foreign_key); + //field(L"person_id", attachment, f::insertable, f::updatable, f::foreign_key); } void table_name(PT::TextStream & stream) diff --git a/samples/sample01.h b/samples/sample01.h index ebd6605..1ff2756 100644 --- a/samples/sample01.h +++ b/samples/sample01.h @@ -32,9 +32,11 @@ * */ +#include #include "basesample.h" #include "person.h" #include "language.h" +#include "attachment.h" namespace morm @@ -52,6 +54,9 @@ void make() person.set_connector(model_connector); load_defaults(person); + std::wstring sss = L"cosik"; + person.set_field_value_generic(L"email", L"email", sss); + person.insert(); } @@ -75,6 +80,14 @@ private: person.language.local_name = L"polish"; person.language.code_str = L"en"; person.language.code_int = 200; + + std::time_t t = std::time(0); + + person.attachment.person_id = -1; + person.attachment.created_date.FromTime(t); + person.attachment.name = L"attchment name"; + person.attachment.content = "long binary content"; + person.attachment.some_flags = true; } diff --git a/src/Makefile.dep b/src/Makefile.dep index 4a4f46e..06bb65f 100644 --- a/src/Makefile.dep +++ b/src/Makefile.dep @@ -8,10 +8,10 @@ baseexpression.o: ../../pikotools/convert/inttostr.h baseexpression.o: ../../pikotools/membuffer/membuffer.h baseexpression.o: ../../pikotools/textstream/types.h morm_types.h modelenv.h baseexpression.o: modeldata.h cursorhelper.h queryresult.h finderhelper.h -baseexpression.o: model.h modelconnector.h clearer.h dbconnector.h -baseexpression.o: ../../pikotools/log/log.h ../../pikotools/log/filelog.h -baseexpression.o: flatconnector.h dbexpression.h flatexpression.h -baseexpression.o: ../../pikotools/utf8/utf8.h +baseexpression.o: setfieldvaluehelper.h model.h modelconnector.h clearer.h +baseexpression.o: dbconnector.h ../../pikotools/log/log.h +baseexpression.o: ../../pikotools/log/filelog.h flatconnector.h +baseexpression.o: dbexpression.h flatexpression.h ../../pikotools/utf8/utf8.h clearer.o: clearer.h ../../pikotools/date/date.h clearer.o: ../../pikotools/convert/inttostr.h model.h clearer.o: ../../pikotools/textstream/textstream.h @@ -21,7 +21,7 @@ clearer.o: ../../pikotools/textstream/types.h modelconnector.h dbconnector.h clearer.o: ../../pikotools/log/log.h ../../pikotools/log/filelog.h clearer.o: queryresult.h flatconnector.h dbexpression.h baseexpression.h clearer.o: morm_types.h modelenv.h modeldata.h cursorhelper.h finderhelper.h -clearer.o: flatexpression.h +clearer.o: setfieldvaluehelper.h flatexpression.h dbconnector.o: dbconnector.h ../../pikotools/textstream/textstream.h dbconnector.o: ../../pikotools/space/space.h dbconnector.o: ../../pikotools/textstream/types.h ../../pikotools/date/date.h @@ -30,8 +30,8 @@ dbconnector.o: ../../pikotools/membuffer/membuffer.h dbconnector.o: ../../pikotools/textstream/types.h ../../pikotools/log/log.h dbconnector.o: ../../pikotools/log/filelog.h queryresult.h dbexpression.h dbconnector.o: baseexpression.h morm_types.h modelenv.h modeldata.h -dbconnector.o: cursorhelper.h finderhelper.h model.h modelconnector.h -dbconnector.o: clearer.h flatconnector.h flatexpression.h +dbconnector.o: cursorhelper.h finderhelper.h setfieldvaluehelper.h model.h +dbconnector.o: modelconnector.h clearer.h flatconnector.h flatexpression.h dbconnector.o: ../../pikotools/utf8/utf8.h ../../pikotools/convert/convert.h dbconnector.o: ../../pikotools/convert/inttostr.h dbconnector.o: ../../pikotools/convert/patternreplacer.h @@ -46,6 +46,7 @@ dbexpression.o: ../../pikotools/convert/inttostr.h dbexpression.o: ../../pikotools/membuffer/membuffer.h dbexpression.o: ../../pikotools/textstream/types.h morm_types.h modelenv.h dbexpression.o: modeldata.h cursorhelper.h queryresult.h finderhelper.h +dbexpression.o: setfieldvaluehelper.h dochtmlconnector.o: dochtmlconnector.h flatconnector.h dochtmlconnector.o: ../../pikotools/textstream/textstream.h dochtmlconnector.o: ../../pikotools/space/space.h @@ -56,6 +57,7 @@ dochtmlconnector.o: ../../pikotools/membuffer/membuffer.h dochtmlconnector.o: ../../pikotools/textstream/types.h dochtmlexpression.h dochtmlconnector.o: flatexpression.h baseexpression.h morm_types.h modelenv.h dochtmlconnector.o: modeldata.h cursorhelper.h queryresult.h finderhelper.h +dochtmlconnector.o: setfieldvaluehelper.h dochtmlexpression.o: dochtmlexpression.h flatexpression.h baseexpression.h dochtmlexpression.o: ../../pikotools/textstream/textstream.h dochtmlexpression.o: ../../pikotools/space/space.h @@ -65,7 +67,7 @@ dochtmlexpression.o: ../../pikotools/convert/inttostr.h dochtmlexpression.o: ../../pikotools/membuffer/membuffer.h dochtmlexpression.o: ../../pikotools/textstream/types.h morm_types.h dochtmlexpression.o: modelenv.h modeldata.h cursorhelper.h queryresult.h -dochtmlexpression.o: finderhelper.h +dochtmlexpression.o: finderhelper.h setfieldvaluehelper.h flatconnector.o: flatconnector.h ../../pikotools/textstream/textstream.h flatconnector.o: ../../pikotools/space/space.h flatconnector.o: ../../pikotools/textstream/types.h @@ -74,10 +76,10 @@ flatconnector.o: ../../pikotools/convert/inttostr.h flatconnector.o: ../../pikotools/membuffer/membuffer.h flatconnector.o: ../../pikotools/textstream/types.h flatexpression.h flatconnector.o: baseexpression.h morm_types.h modelenv.h modeldata.h -flatconnector.o: cursorhelper.h queryresult.h finderhelper.h model.h -flatconnector.o: modelconnector.h clearer.h dbconnector.h -flatconnector.o: ../../pikotools/log/log.h ../../pikotools/log/filelog.h -flatconnector.o: dbexpression.h +flatconnector.o: cursorhelper.h queryresult.h finderhelper.h +flatconnector.o: setfieldvaluehelper.h model.h modelconnector.h clearer.h +flatconnector.o: dbconnector.h ../../pikotools/log/log.h +flatconnector.o: ../../pikotools/log/filelog.h dbexpression.h flatexpression.o: flatexpression.h baseexpression.h flatexpression.o: ../../pikotools/textstream/textstream.h flatexpression.o: ../../pikotools/space/space.h @@ -87,6 +89,7 @@ flatexpression.o: ../../pikotools/convert/inttostr.h flatexpression.o: ../../pikotools/membuffer/membuffer.h flatexpression.o: ../../pikotools/textstream/types.h morm_types.h modelenv.h flatexpression.o: modeldata.h cursorhelper.h queryresult.h finderhelper.h +flatexpression.o: setfieldvaluehelper.h jsonconnector.o: jsonconnector.h flatconnector.h jsonconnector.o: ../../pikotools/textstream/textstream.h jsonconnector.o: ../../pikotools/space/space.h @@ -97,6 +100,7 @@ jsonconnector.o: ../../pikotools/membuffer/membuffer.h jsonconnector.o: ../../pikotools/textstream/types.h jsonexpression.h jsonconnector.o: flatexpression.h baseexpression.h morm_types.h modelenv.h jsonconnector.o: modeldata.h cursorhelper.h queryresult.h finderhelper.h +jsonconnector.o: setfieldvaluehelper.h jsonexpression.o: jsonexpression.h flatexpression.h baseexpression.h jsonexpression.o: ../../pikotools/textstream/textstream.h jsonexpression.o: ../../pikotools/space/space.h @@ -106,6 +110,7 @@ jsonexpression.o: ../../pikotools/convert/inttostr.h jsonexpression.o: ../../pikotools/membuffer/membuffer.h jsonexpression.o: ../../pikotools/textstream/types.h morm_types.h modelenv.h jsonexpression.o: modeldata.h cursorhelper.h queryresult.h finderhelper.h +jsonexpression.o: setfieldvaluehelper.h model.o: model.h ../../pikotools/textstream/textstream.h model.o: ../../pikotools/space/space.h ../../pikotools/textstream/types.h model.o: ../../pikotools/date/date.h ../../pikotools/convert/inttostr.h @@ -114,7 +119,7 @@ model.o: ../../pikotools/textstream/types.h modelconnector.h clearer.h model.o: dbconnector.h ../../pikotools/log/log.h model.o: ../../pikotools/log/filelog.h queryresult.h flatconnector.h model.o: dbexpression.h baseexpression.h morm_types.h modelenv.h modeldata.h -model.o: cursorhelper.h finderhelper.h flatexpression.h +model.o: cursorhelper.h finderhelper.h setfieldvaluehelper.h flatexpression.h modelconnector.o: modelconnector.h clearer.h ../../pikotools/date/date.h modelconnector.o: ../../pikotools/convert/inttostr.h dbconnector.h modelconnector.o: ../../pikotools/textstream/textstream.h @@ -137,7 +142,8 @@ postgresqlconnector.o: ../../pikotools/log/filelog.h queryresult.h postgresqlconnector.o: postgresqlqueryresult.h ../../pikotools/utf8/utf8.h postgresqlconnector.o: postgresqlexpression.h dbexpression.h baseexpression.h postgresqlconnector.o: morm_types.h modelenv.h modeldata.h cursorhelper.h -postgresqlconnector.o: finderhelper.h ../../pikotools/convert/strtoint.h +postgresqlconnector.o: finderhelper.h setfieldvaluehelper.h +postgresqlconnector.o: ../../pikotools/convert/strtoint.h postgresqlconnector.o: ../../pikotools/convert/text.h postgresqlconnector.o: ../../pikotools/convert/misc.h postgresqlexpression.o: postgresqlexpression.h dbexpression.h @@ -150,7 +156,7 @@ postgresqlexpression.o: ../../pikotools/convert/inttostr.h postgresqlexpression.o: ../../pikotools/membuffer/membuffer.h postgresqlexpression.o: ../../pikotools/textstream/types.h morm_types.h postgresqlexpression.o: modelenv.h modeldata.h cursorhelper.h queryresult.h -postgresqlexpression.o: finderhelper.h +postgresqlexpression.o: finderhelper.h setfieldvaluehelper.h postgresqlqueryresult.o: postgresqlqueryresult.h queryresult.h queryresult.o: queryresult.h ../../pikotools/utf8/utf8.h queryresult.o: ../../pikotools/textstream/textstream.h diff --git a/src/model.cpp b/src/model.cpp index e8ce949..e12efb1 100644 --- a/src/model.cpp +++ b/src/model.cpp @@ -238,7 +238,12 @@ bool Model::insert(ModelData * model_data, bool insert_whole_tree) model_env = &model_env_local; model_env->model_data = model_data; - return insert_tree(insert_whole_tree); + bool status = insert_tree(insert_whole_tree); + + // what about if an exception was thrown? this pointer will not be null + model_env = nullptr; + + return status; } @@ -272,15 +277,19 @@ bool Model::insert_tree(bool insert_whole_tree) { save_mode = DO_UPDATE_ON_SAVE; // IMPROVE ME check if there is a primary key after_insert(); + set_parent_key_in_childs(); } else { after_insert_failure(); } } + } - // what about if an exception was thrown? this pointer will not be null - model_env = nullptr; + if( insert_whole_tree ) + { + model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_ITERATE_THROUGH_CHILDS_AND_INSERT_XXX; + map_fields(); } return result; @@ -632,5 +641,30 @@ bool Model::is_empty_field(const wchar_t * value) } +bool Model::is_the_same_field(const wchar_t * field1, const wchar_t * field2) +{ + if( !field1 && !field2 ) + return true; + + if( !field1 || !field2 ) + return false; + + bool the_same = false; + + while( *field1 && *field2 ) + { + field1 += 1; + field2 += 1; + } + + if( *field1 == 0 && *field2 == 0 ) + { + the_same = true; + } + + return the_same; +} + + } // namespace diff --git a/src/model.h b/src/model.h index e0a99bd..ee5d0ee 100644 --- a/src/model.h +++ b/src/model.h @@ -132,6 +132,27 @@ public: // set object to default values virtual void clear(); + // IMPROVE ME this will be protected + // add set_field_value() functions for each POD type + template + void set_field_value_generic(const wchar_t * db_field_name, const wchar_t * flat_field_name, const FieldValue & field_value) + { + ModelEnv model_env_local; + model_env = &model_env_local; + model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_SET_FIELD_VALUE; + model_env->field_index = 0; + + SetFieldValueHelper set_field_value_helper; + FieldValueContainer helper_object(field_value); + + set_field_value_helper.add(db_field_name, flat_field_name, &helper_object, false); + model_env->set_field_value_helper = &set_field_value_helper; + + map_fields(); + + // what if an exception was thrown? + model_env = nullptr; + } protected: @@ -272,9 +293,9 @@ protected: field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); } - void field(const wchar_t * field_name, Model & field_value, bool insertable = true, bool updatable = true) + void field(const wchar_t * field_name, Model & field_value, bool insertable = true, bool updatable = true, bool has_foreign_key = true) { - field_model(field_name, field_name, field_value, insertable, updatable, true); + field_model(field_name, field_name, field_value, insertable, updatable, has_foreign_key); } template @@ -394,9 +415,9 @@ protected: } - void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_value, bool insertable = true, bool updatable = true) + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_value, bool insertable = true, bool updatable = true, bool has_foreign_key = true) { - field_model(db_field_name, flat_field_name, field_value, insertable, updatable, true); + field_model(db_field_name, flat_field_name, field_value, insertable, updatable, has_foreign_key); } template @@ -651,6 +672,47 @@ protected: { if( model_connector && model_env ) { + if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_SET_FIELD_VALUE ) + { + if( model_env->set_field_value_helper ) + { + if( model_env->field_index >= 0 && (size_t)model_env->field_index < model_env->set_field_value_helper->size() ) + { + if( is_the_same_field(db_field_name, model_env->set_field_value_helper->get_db_field_name(model_env->field_index)) && + is_the_same_field(flat_field_name, model_env->set_field_value_helper->get_flat_field_name(model_env->field_index)) ) + { + model_env->set_field_value_helper->set_value(model_env->field_index, field_value); + model_env->field_index += 1; + } + } + else + { + // IMPROVE ME + // put some log here + } + } + } + + if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_ITERATE_PRIMARY_KEY_VALUES && is_primary_key ) + { + if( model_env->set_field_value_helper ) + { + if( model_env->field_index >= 0 && (size_t)model_env->field_index < model_env->set_field_value_helper->size() ) + { + FieldValueBase * helper_object = new FieldValueContainer(field_value); + model_env->set_field_value_helper->add_field_value_container(model_env->field_index, helper_object, true); + } + else + { + // IMPROVE ME + // put some log here + } + } + + model_env->field_index += 1; + } + + if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_STRING ) { FlatConnector * flat_connector = model_connector->get_flat_connector(); @@ -827,13 +889,13 @@ protected: field_model_left_join(db_field_name, flat_field_name, field_model, insertable, updatable, has_foreign_key, db_expression); } - if( db_expression->get_work_mode() == MORM_WORK_MODE_MODEL_FIELDS && db_expression->get_output_type() == MORM_OUTPUT_TYPE_DB_INSERT ) + if( db_expression->get_work_mode() == MORM_WORK_MODE_MODEL_FIELDS && db_expression->get_output_type() == MORM_OUTPUT_TYPE_DB_INSERT && has_foreign_key ) { int not_used_object = 0; db_expression->field(db_field_name, not_used_object, insertable, updatable, false, model_env); } - if( db_expression->get_work_mode() == MORM_WORK_MODE_MODEL_VALUES && db_expression->get_output_type() == MORM_OUTPUT_TYPE_DB_INSERT ) + if( db_expression->get_work_mode() == MORM_WORK_MODE_MODEL_VALUES && db_expression->get_output_type() == MORM_OUTPUT_TYPE_DB_INSERT && has_foreign_key ) { db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_INSERT_PRIMARY_KEY); field_model.map_fields(); @@ -902,6 +964,56 @@ protected: } } + void field_model_set_parent_key(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_model) + { + 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) ) + { + int old_connector_mode = model_env->model_connector_mode; + model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_ITERATE_PRIMARY_KEY_VALUES; + + SetFieldValueHelper set_field_value_helper; + set_field_value_helper.add(db_field_name, flat_field_name); // in the future we can have a primary key from more than one column + model_env->set_field_value_helper = &set_field_value_helper; + model_env->field_index = 0; + + map_fields(); + + if( set_field_value_helper.empty() ) + { + // IMPROVE ME + // put some log: there is no a primary key in this model + } + else + if( set_field_value_helper.size() == 1 ) + { + ModelEnv model_env_local; + model_env_local.copy_global_objects(*model_env); + model_env_local.model_connector_mode = MORM_MODEL_CONNECTOR_MODE_SET_FIELD_VALUE; + model_env_local.set_field_value_helper = &set_field_value_helper; + model_env_local.field_index = 0; + field_model.model_env = &model_env_local; + + field_model.map_fields(); + field_model.model_env = nullptr; + + model_env->set_field_value_helper = nullptr; + model_env->model_connector_mode = old_connector_mode; + } + else + { + // IMPROVE ME + // put some log: at the moment we only support a primary key from only one column + } + } + } + } + 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) { @@ -913,11 +1025,27 @@ protected: field_model.model_env = &model_env_local; field_model.set_connector(model_connector); - if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_ITERATE_THROUGH_CHILDS_AND_INSERT ) + if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_SET_PARENT_ID && !has_foreign_key ) { - // IMPROVE ME what about if db_field_name is empty? not iterate in such a case? - field_model.map_fields(); - field_model.insert_tree(true); + field_model_set_parent_key(db_field_name, flat_field_name, field_model); + } + + if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_ITERATE_THROUGH_CHILDS_AND_INSERT && has_foreign_key ) + { + if( !is_empty_field(db_field_name) ) + { + field_model.map_fields(); + field_model.insert_tree(true); + } + } + + if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_ITERATE_THROUGH_CHILDS_AND_INSERT_XXX && !has_foreign_key ) + { + if( !is_empty_field(db_field_name) ) + { + field_model.map_fields(); + field_model.insert_tree(true); + } } if( model_env->model_connector_mode == MORM_MODEL_CONNECTOR_MODE_ITERATE_THROUGH_CHILDS_AND_UPDATE ) @@ -1155,6 +1283,17 @@ protected: } } + + virtual void set_parent_key_in_childs() + { + if( model_env ) + { + model_env->model_connector_mode = MORM_MODEL_CONNECTOR_MODE_SET_PARENT_ID; + map_fields(); + } + } + + public: @@ -1217,9 +1356,11 @@ public: } + protected: virtual bool is_empty_field(const wchar_t * value); + virtual bool is_the_same_field(const wchar_t * field1, const wchar_t * field2); template friend class Finder; template friend class Cursor; diff --git a/src/modelenv.h b/src/modelenv.h index 776d439..d616628 100644 --- a/src/modelenv.h +++ b/src/modelenv.h @@ -38,12 +38,14 @@ #include "modeldata.h" #include "cursorhelper.h" #include "finderhelper.h" +#include "setfieldvaluehelper.h" #include "morm_types.h" namespace morm { + class ModelEnv { public: @@ -58,7 +60,9 @@ public: PT::TextStream table_name; PT::TextStream table_name_short; int table_index; + int field_index; + SetFieldValueHelper * set_field_value_helper; ModelEnv() @@ -80,6 +84,10 @@ public: model_connector_mode = e.model_connector_mode; table_index = e.table_index; doc_field_pointer = e.doc_field_pointer; + set_field_value_helper = e.set_field_value_helper; + field_index = e.field_index; + + // table_name and table_name_short don't have to bo copied } @@ -104,6 +112,8 @@ public: table_name.clear(); table_name_short.clear(); table_index = 0; + set_field_value_helper = nullptr; + field_index = 0; } diff --git a/src/morm_types.h b/src/morm_types.h index 2fc65da..6133404 100644 --- a/src/morm_types.h +++ b/src/morm_types.h @@ -47,10 +47,22 @@ #define MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB_RESULTSET 6 #define MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE 7 +// RENAME TO MORM_MODEL_CONNECTOR_MODE_ITERATE_THROUGH_CHILDS_WITH_FOREIGN_KEY_AND_INSERT #define MORM_MODEL_CONNECTOR_MODE_ITERATE_THROUGH_CHILDS_AND_INSERT 8 + +// RENAME ME MORM_MODEL_CONNECTOR_MODE_ITERATE_THROUGH_CHILDS_WITHOUT_FOREIGN_KEY_AND_INSERT +#define MORM_MODEL_CONNECTOR_MODE_ITERATE_THROUGH_CHILDS_AND_INSERT_XXX 30 + + #define MORM_MODEL_CONNECTOR_MODE_ITERATE_THROUGH_CHILDS_AND_UPDATE 9 #define MORM_MODEL_CONNECTOR_MODE_ITERATE_THROUGH_CHILDS_AND_SAVE 10 +#define MORM_MODEL_CONNECTOR_MODE_SET_PARENT_ID 11 + +#define MORM_MODEL_CONNECTOR_MODE_ITERATE_PRIMARY_KEY_VALUES 12 + +#define MORM_MODEL_CONNECTOR_MODE_SET_FIELD_VALUE 13 + #define MORM_WORK_MODE_MODEL_FIELDS 1 #define MORM_WORK_MODE_MODEL_VALUES 2 @@ -76,6 +88,8 @@ #define MORM_OUTPUT_TYPE_SELECT_COLUMNS 7 #define MORM_OUTPUT_TYPE_JOIN_TABLES 8 +#define MORM_OUTPUT_TYPE_COPY_PARENT_KEY 8 + #define MORM_OUTPUT_TYPE_WHERE_EQ 10 #define MORM_OUTPUT_TYPE_WHERE_LT 11 diff --git a/src/setfieldvaluehelper.h b/src/setfieldvaluehelper.h new file mode 100644 index 0000000..40c2222 --- /dev/null +++ b/src/setfieldvaluehelper.h @@ -0,0 +1,206 @@ +/* + * This file is a part of morm + * and is distributed under the 2-Clause BSD licence. + * Author: Tomasz Sowa + */ + +/* + * 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_setfieldvaluehelper +#define headerfile_morm_setfieldvaluehelper + +#include +#include + + +namespace morm +{ + + +struct FieldValueBase +{ + FieldValueBase() + { + } + + virtual ~FieldValueBase() + { + } + + virtual void set(void * value, const std::type_info & value_type_info) = 0; + +}; + + +template +struct FieldValueContainer : public FieldValueBase +{ + FieldValueContainer(const FieldValue & value) + { + this->value = &value; + } + + void set(void * value, const std::type_info & value_type_info) + { + if( value_type_info == typeid(FieldValue) ) + { + FieldValue * field_value = reinterpret_cast(value); + *field_value = *this->value; + } + } + + const FieldValue * value; + +}; + + + + +class SetFieldValueHelper +{ +public: + + struct Item + { + const wchar_t * db_field_name; + const wchar_t * flat_field_name; + FieldValueBase * field_value_base; + bool auto_remove_field_value_object; + + Item() + { + db_field_name = nullptr; + flat_field_name = nullptr; + field_value_base = nullptr; + auto_remove_field_value_object = false; + } + + ~Item() + { + } + }; + + std::vector item_tab; + + + SetFieldValueHelper() + { + clear(); + } + + + virtual ~SetFieldValueHelper() + { + remove_field_value_base_objects(); + } + + + virtual void remove_field_value_base_objects() + { + for(Item & item : item_tab) + { + if( item.auto_remove_field_value_object ) + { + delete item.field_value_base; + item.field_value_base = nullptr; + } + } + } + + + virtual void clear() + { + item_tab.clear(); + } + + + virtual void add(const wchar_t * db_field_name, const wchar_t * flat_field_name) + { + add(db_field_name, flat_field_name, nullptr, false); + } + + + virtual void add(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValueBase * field_value_base, bool auto_remove_field_value_object) + { + Item item; + item.db_field_name = db_field_name; + item.flat_field_name = flat_field_name; + item.field_value_base = field_value_base; + item.auto_remove_field_value_object = auto_remove_field_value_object; + item_tab.push_back(item); + } + + + virtual size_t size() + { + return item_tab.size(); + } + + virtual bool empty() + { + return item_tab.empty(); + } + + virtual void add_field_value_container(size_t index, FieldValueBase * field_value_base, bool auto_remove_field_value_object) + { + if( item_tab[index].field_value_base && item_tab[index].auto_remove_field_value_object ) + { + delete item_tab[index].field_value_base; + } + + item_tab[index].field_value_base = field_value_base; + item_tab[index].auto_remove_field_value_object = auto_remove_field_value_object; + } + + template + void set_value(size_t index, FieldValue & value) + { + if( item_tab[index].field_value_base ) + { + item_tab[index].field_value_base->set(&value, typeid(value)); + } + } + + + virtual const wchar_t * get_db_field_name(size_t index) + { + return item_tab[index].db_field_name; + } + + + virtual const wchar_t * get_flat_field_name(size_t index) + { + return item_tab[index].flat_field_name; + } + +}; + +} + +#endif