From f52fba1f246b7254c9c4e18be3a4272896768ebc Mon Sep 17 00:00:00 2001 From: zussel Date: Thu, 5 Jan 2017 15:32:51 +0100 Subject: [PATCH 01/61] started with issue #74 belongs_to --- include/oos/object/attribute_serializer.hpp | 5 ++ include/oos/object/belongs_to.hpp | 6 ++ include/oos/object/object_ptr.hpp | 26 ++++++ include/oos/object/object_store.hpp | 8 ++ src/object/CMakeLists.txt | 2 +- test/Item.hpp | 99 ++++++--------------- test/object/ObjectStoreTestUnit.cpp | 11 +++ test/object/ObjectStoreTestUnit.hpp | 1 + 8 files changed, 86 insertions(+), 72 deletions(-) create mode 100644 include/oos/object/belongs_to.hpp diff --git a/include/oos/object/attribute_serializer.hpp b/include/oos/object/attribute_serializer.hpp index 3960e685a..93bb45722 100644 --- a/include/oos/object/attribute_serializer.hpp +++ b/include/oos/object/attribute_serializer.hpp @@ -311,6 +311,11 @@ class attribute_writer : public basic_attribute_serializer success_ = true; } + template < class V > + void serialize(const char *, belongs_to &, cascade_type) + { + } + template < class V > void serialize(const char *id, has_one &x, cascade_type) { diff --git a/include/oos/object/belongs_to.hpp b/include/oos/object/belongs_to.hpp new file mode 100644 index 000000000..7e87859c2 --- /dev/null +++ b/include/oos/object/belongs_to.hpp @@ -0,0 +1,6 @@ +#ifndef OOS_BELONGS_TO_HPP +#define OOS_BELONGS_TO_HPP + +#include "oos/object/object_ptr.hpp" + +#endif //OOS_BELONGS_TO_HPP diff --git a/include/oos/object/object_ptr.hpp b/include/oos/object/object_ptr.hpp index 064df67bd..ac6d2ab0a 100644 --- a/include/oos/object/object_ptr.hpp +++ b/include/oos/object/object_ptr.hpp @@ -158,6 +158,18 @@ std::string has_one::classname_ = typeid(T).name(); template < class T > std::unique_ptr has_one::identifier_(identifier_resolver::resolve()); +template < class T > +class belongs_to +{ +public: + belongs_to() {} + /** + * Copies has_one from object_ptr + * + * @param x The object_ptr to copy + */ + belongs_to(const object_ptr &x); +}; /** * @brief The object_ptr holds a pointer to an serializable. @@ -219,6 +231,14 @@ class object_ptr : public object_holder : object_holder(false, x.proxy_) {} + /** + * @brief Creates an object_ptr from the given has_one object + * @param x The has_one object to created the object_ptr from + */ + object_ptr(const belongs_to &) + : object_holder(false, nullptr) + {} + /** * Assign operator. * @@ -336,6 +356,12 @@ has_one& has_one::operator=(const object_ptr &x) return *this; } +template < class T > +belongs_to::belongs_to(const object_ptr &) +{ + +} + } #endif /* OBJECT_PTR_HPP */ diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index fe94206b9..d41a4bad8 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -264,6 +264,8 @@ class node_analyzer { void serialize(const char *, V &) { } void serialize(const char *, char *, size_t) { } template + void serialize(const char *id, belongs_to &x, cascade_type); + template void serialize(const char *id, has_one &x, cascade_type); template class C> void serialize(const char *, has_many &, const char *, const char *); @@ -1157,6 +1159,12 @@ void node_analyzer::serialize(V &x) oos::access::serialize(*this, x); } +template class ON_ATTACH> +template +void node_analyzer::serialize(const char *, belongs_to &, cascade_type) +{ +} + template class ON_ATTACH> template void node_analyzer::serialize(const char *id, has_one &x, cascade_type) diff --git a/src/object/CMakeLists.txt b/src/object/CMakeLists.txt index 65ae858db..67db15006 100644 --- a/src/object/CMakeLists.txt +++ b/src/object/CMakeLists.txt @@ -50,7 +50,7 @@ SET(HEADER ${CMAKE_SOURCE_DIR}/include/oos/object/has_many_item.hpp ${CMAKE_SOURCE_DIR}/include/oos/object/basic_has_many_item.hpp ${CMAKE_SOURCE_DIR}/include/oos/object/identifier_proxy_map.hpp - ${CMAKE_SOURCE_DIR}/include/oos/object/object_proxy_accessor.hpp) + ${CMAKE_SOURCE_DIR}/include/oos/object/object_proxy_accessor.hpp ../../include/oos/object/belongs_to.hpp) ADD_LIBRARY(oos-object SHARED ${SOURCES} ${HEADER}) diff --git a/test/Item.hpp b/test/Item.hpp index 988ec225a..92a17cb29 100644 --- a/test/Item.hpp +++ b/test/Item.hpp @@ -21,6 +21,7 @@ #include "oos/utils/base_class.hpp" #include "oos/object/object_ptr.hpp" #include "oos/object/has_one.hpp" +#include "oos/object/belongs_to.hpp" #include "oos/object/has_many.hpp" #include "oos/utils/time.hpp" @@ -293,7 +294,7 @@ class person { private: oos::identifier id_; - oos::varchar<256> name_; + oos::varchar<255> name_; oos::date birthdate_; unsigned int height_ = 0; @@ -333,99 +334,55 @@ class person unsigned int height() const { return height_; } void height(unsigned int height) { height_ = height; } }; -/* + class department; class employee : public person { -public: - typedef oos::object_ref dep_ref; - private: - dep_ref dep_; + oos::belongs_to department_; public: employee() {} - employee(const std::string &name_) : person(name_) {} - employee(const std::string &name_, const dep_ref &dep) - : person(name_) - , dep_(dep) + employee(const std::string &name) : person(name, oos::date(17, 12, 1983), 183) {} + employee(const std::string &name, const oos::object_ptr &dep) + : person(name, oos::date(17, 12, 1983), 183) + , department_(dep) {} - virtual void deserialize(oos::deserializer &deserializer) - { - person::deserialize(deserializer); - deserializer.read("department", dep_); - } - virtual void serialize(oos::serializer &serializer) const + template < class SERIALIZER > + void serialize(SERIALIZER &serializer) { - person::serialize(serializer); - serializer.write("department", dep_); + serializer.serialize(*oos::base_class(this)); + serializer.serialize("department", department_); } - dep_ref dep() const { return dep_; } - void dep(const dep_ref &d) { dep_ = d; } + oos::object_ptr dep() { return department_; } + void dep(const oos::object_ptr &d) { department_ = d; } }; -class department : public oos::serializable +struct department { -public: - typedef oos::object_ref emp_ref; - typedef oos::object_list emp_list_t; - typedef emp_list_t::size_type size_type; - typedef emp_list_t::iterator iterator; - typedef emp_list_t::const_iterator const_iterator; + oos::identifier id; + std::string name; + oos::has_many employees; -private: - oos::identifier id_; - std::string name_; - emp_list_t emp_list_; - -public: - department() - : emp_list_(&employee::dep) - {} - department(const std::string &name) - : name_(name) - , emp_list_(&employee::dep) + department() {} + department(const std::string &n) + : name(n) {} - virtual ~department() {} + ~department() {} - virtual void deserialize(oos::deserializer &deserializer) - { - deserializer.read("id", id_); - deserializer.read("name", name_); - deserializer.read("employee_department", emp_list_); - } - virtual void serialize(oos::serializer &serializer) const - { - serializer.write("id", id_); - serializer.write("name", name_); - serializer.write("employee_department", emp_list_); - } - - unsigned long id() const { return id_.value(); } - std::string name() const { return name_; } - void name(const std::string &name) { name_ = name; } - - void add(const emp_ref &b) + template < class SERIALIZER > + void serialize(SERIALIZER &serializer) { - emp_list_.push_back(b); + serializer.serialize("id", id); + serializer.serialize("name", name); + serializer.serialize("employee", employees, "department", "employee_id"); } - - iterator begin() { return emp_list_.begin(); } - const_iterator begin() const { return emp_list_.begin(); } - - iterator end() { return emp_list_.end(); } - const_iterator end() const { return emp_list_.end(); } - - iterator erase(iterator i) { return emp_list_.erase(i); } - - size_type size() const { return emp_list_.size(); } - bool empty() const { return emp_list_.empty(); } }; -*/ + class course; class student : public person diff --git a/test/object/ObjectStoreTestUnit.cpp b/test/object/ObjectStoreTestUnit.cpp index 2761adaf2..f9abf3451 100644 --- a/test/object/ObjectStoreTestUnit.cpp +++ b/test/object/ObjectStoreTestUnit.cpp @@ -42,6 +42,7 @@ ObjectStoreTestUnit::ObjectStoreTestUnit() add_test("pk", std::bind(&ObjectStoreTestUnit::test_primary_key, this), "object proxy primary key test"); add_test("has_many", std::bind(&ObjectStoreTestUnit::test_has_many, this), "has many test"); // add_test("has_many_to_many", std::bind(&ObjectStoreTestUnit::test_has_many_to_many, this), "has many to many test"); +// add_test("belongs_to", std::bind(&ObjectStoreTestUnit::test_belongs_to, this), "test belongs to behaviour"); add_test("on_attach", std::bind(&ObjectStoreTestUnit::test_on_attach, this), "test on attach callback"); } @@ -1054,6 +1055,16 @@ struct on_attach> : public on_attach_base } }; +void ObjectStoreTestUnit::test_belongs_to() +{ + ostore_.attach("person"); + ostore_.attach("employee"); + ostore_.attach("department"); + + // expected prototypes + // person, employee and department +} + void ObjectStoreTestUnit::test_on_attach() { ostore_.attach("book", false, nullptr); diff --git a/test/object/ObjectStoreTestUnit.hpp b/test/object/ObjectStoreTestUnit.hpp index 79759dc7b..2e4b80873 100644 --- a/test/object/ObjectStoreTestUnit.hpp +++ b/test/object/ObjectStoreTestUnit.hpp @@ -42,6 +42,7 @@ class ObjectStoreTestUnit : public oos::unit_test void test_primary_key(); void test_has_many(); void test_has_many_to_many(); + void test_belongs_to(); void test_on_attach(); private: From 4d17cf4b7bd4ed95ded39631313a19d43a905970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Fri, 6 Jan 2017 07:09:10 +0100 Subject: [PATCH 02/61] belongs to progress --- include/oos/object/attribute_serializer.hpp | 16 +- include/oos/object/belongs_to.hpp | 232 ++++++++++++++++++ include/oos/object/has_one.hpp | 252 ++++++++++++++++++++ include/oos/object/object_holder.hpp | 51 ++-- include/oos/object/object_ptr.hpp | 188 ++------------- include/oos/object/object_serializer.hpp | 36 +++ include/oos/object/object_store.hpp | 68 +++++- include/oos/orm/identifier_binder.hpp | 5 +- include/oos/orm/relation_resolver.hpp | 37 +++ 9 files changed, 674 insertions(+), 211 deletions(-) diff --git a/include/oos/object/attribute_serializer.hpp b/include/oos/object/attribute_serializer.hpp index 93bb45722..3509889f9 100644 --- a/include/oos/object/attribute_serializer.hpp +++ b/include/oos/object/attribute_serializer.hpp @@ -312,8 +312,19 @@ class attribute_writer : public basic_attribute_serializer } template < class V > - void serialize(const char *, belongs_to &, cascade_type) + void serialize(const char *id, belongs_to &x, cascade_type) { + if (id_ != id) { + return; + } + std::stringstream to; + if (x.has_primary_key()) { + x.primary_key()->print(to); + } else { + to << x.id(); + } + to_ = to.str(); + success_ = true; } template < class V > @@ -331,6 +342,7 @@ class attribute_writer : public basic_attribute_serializer to_ = to.str(); success_ = true; } + void serialize(const char*, abstract_has_many&, const char*, const char*) {} private: @@ -388,6 +400,8 @@ class attribute_writer void serialize(const char*, date&) {} void serialize(const char*, time&) {} template < class V > + void serialize(const char*, belongs_to &, cascade_type) {} + template < class V > void serialize(const char*, has_one &, cascade_type) {} void serialize(const char*, abstract_has_many&, const char*, const char*) {} template < class V > diff --git a/include/oos/object/belongs_to.hpp b/include/oos/object/belongs_to.hpp index 7e87859c2..186dbad6a 100644 --- a/include/oos/object/belongs_to.hpp +++ b/include/oos/object/belongs_to.hpp @@ -3,4 +3,236 @@ #include "oos/object/object_ptr.hpp" +namespace oos { +namespace detail { +class object_inserter; +class object_deleter; +} +/** + * @brief The belongs_to holds a pointer to an serializable. + * @tparam T The type of the serializable. + * + * The belongs_to holds a pointer to an object. The + * belongs_to is a wrapper class for the object class + * It has a reference count mechanism. + * The objects inserted into the object_store are returned + * as a belongs_to and should be used through the + * belongs_to class. + */ +template < class T > +class belongs_to : public identifiable_holder +{ +public: + typedef T object_type; /**< Shortcut for template type. */ + typedef belongs_to self; /**< Shortcut for self class. */ + +public: + /** + * Create an empty belongs_to + */ + belongs_to() {} + + /** + * Create an hs_one from an object + * + * @param obj The object. + */ + belongs_to(object_type *obj) : optr_(obj) {} + + /** + * Create an belongs_to from an object_proxy + * + * @param proxy The object_proxy. + */ + belongs_to(object_proxy *proxy) : optr_(proxy) {} + + /** + * Copies belongs_to from object_ptr + * + * @param optr The object_ptr to copy + */ + belongs_to(const object_ptr &optr) : optr_(optr) {} + + /** + * Copies belongs_to from belongs_to + * + * @param x The belongs_to to copy + */ + belongs_to(const self &x) : optr_(x.optr_) {} + + /** + * Assigns belongs_to from belongs_to + * + * @param x The belongs_to to assign + * @return Reference to assigned belongs_to + */ + belongs_to& operator=(const self &x) + { + reset(x.optr_); + return *this; + } + + /** + * Assigns belongs_to from object_ptr + * + * @param optr The object_ptr to assign + * @return Reference to assigned belongs_to + */ + belongs_to& operator=(const object_ptr &optr) + { + reset(optr); + return *this; + } + + /** + * Resets this with given object_ptr + * + * @param optr object_ptr to reset + */ + void reset(const object_ptr &optr) + { + reset(optr.proxy_, optr.cascade_); + } + + /** + * Resets belongs_to from given object_proxy and + * cascade_type. + * + * @param proxy object_proxy to be set + * @param cascade cascade_type to be set + */ + void reset(object_proxy *proxy, cascade_type cascade) + { + optr_.reset(proxy, cascade); + } + + void reset(const std::shared_ptr &id) override + { + optr_.reset(id); + } + + //@{ + /** + * @brief Return the pointer to the object of type T. + * + * Return the pointer to the object of type T. If there + * isn't a valid object nullptr is returned. + * + * @return The pointer to the object of type T. + */ + T* operator->() + { + return optr_.get(); + } + + const T* operator->() const + { + return optr_.get(); + } + + T* get() + { + return optr_.get(); + } + + const T* get() const + { + return optr_.get(); + } + //@} + + /** + * Return the type string of the serializable + * + * @return The type string of the serializable. + */ + const char* type() const + { + return optr_.type(); + } + + /** + * Returns the object id. + * + * @return The id of the object. + */ + unsigned long id() const + { + return optr_.id(); + } + + /** + * Returns the underlying object_ptr + * + * @return The underlying object_ptr + */ + object_ptr optr() const + { + return optr_; + } + + /** + * Creates a new identifier, represented by the identifier + * of the underlaying type. + * + * @return A new identifier. + */ + basic_identifier* create_identifier() const override + { + return optr_.create_identifier(); + } + + /** + * Returns true if the underlying object + * is inserted in an object_store + * + * @return True if object is inserted. + */ + bool is_inserted() const + { + return optr_.is_inserted(); + } + + /** + * Returns true if serializable has a primary key + * + * @return true if serializable has a primary key + */ + bool has_primary_key() const override + { + return optr_.has_primary_key(); + } + + /** + * Gets the primary key of the foreign serializable + * + * @return The primary key of the foreign serializable + */ + std::shared_ptr primary_key() const override + { + return optr_.primary_key(); + } + +private: + friend class detail::object_deleter; + friend class detail::object_inserter; + +private: + object_ptr optr_; +}; + +template < class T > +object_ptr::object_ptr(const belongs_to &x) + : object_holder(false, x.optr().proxy_) +{} + +template < class T > +object_ptr& object_ptr::operator=(belongs_to &x) +{ + reset(x.optr().proxy_); + return *this; +} + +} + #endif //OOS_BELONGS_TO_HPP diff --git a/include/oos/object/has_one.hpp b/include/oos/object/has_one.hpp index 7d9a1d288..e19ca5f58 100644 --- a/include/oos/object/has_one.hpp +++ b/include/oos/object/has_one.hpp @@ -7,4 +7,256 @@ #include "oos/object/object_ptr.hpp" +namespace oos { +namespace detail { +class object_inserter; +class object_deleter; +} + +/** + * @brief The has_one holds a pointer to an serializable. + * @tparam T The type of the serializable. + * + * The has_one holds a pointer to an object. The + * has_one is a wrapper class for the object class + * It has a reference count mechanism. + * The objects inserted into the object_store are returned + * as a has_one and should be used through the + * has_one class. + */ +template < class T > +class has_one : public identifiable_holder +{ +public: + typedef T object_type; /**< Shortcut for template type. */ + typedef has_one self; /**< Shortcut for self class. */ + +public: + /** + * Create an empty has_one + */ + has_one() {} + + /** + * Create an hs_one from an object + * + * @param obj The object. + */ + has_one(object_type *obj) : optr_(obj) {} + + /** + * Create an has_one from an object_proxy + * + * @param proxy The object_proxy. + */ + has_one(object_proxy *proxy) : optr_(proxy) {} + + /** + * Copies has_one from object_ptr + * + * @param optr The object_ptr to copy + */ + has_one(const object_ptr &optr) : optr_(optr) {} + + /** + * Copies has_one from has_one + * + * @param x The has_one to copy + */ + has_one(const self &x) : optr_(x.optr_) {} + + /** + * Assigns has_one from has_one + * + * @param x The has_one to assign + * @return Reference to assigned has_one + */ + has_one& operator=(const self &x) + { + reset(x.optr_); + return *this; + } + + /** + * Assigns has_one from object_ptr + * + * @param optr The object_ptr to assign + * @return Reference to assigned has_one + */ + has_one& operator=(const object_ptr &optr) + { + reset(optr); + return *this; + } + + /** + * Resets this with given object_ptr + * + * @param optr object_ptr to reset + */ + void reset(const object_ptr &optr) + { + reset(optr.proxy_, optr.cascade_); + } + + /** + * Resets has_one from given object_proxy and + * cascade_type. + * + * @param proxy object_proxy to be set + * @param cascade cascade_type to be set + */ + void reset(object_proxy *proxy, cascade_type cascade) + { + optr_.reset(proxy, cascade); + } + + void reset(const std::shared_ptr &id) override + { + optr_.reset(id); + } + + //@{ + /** + * @brief Return the pointer to the object of type T. + * + * Return the pointer to the object of type T. If there + * isn't a valid object nullptr is returned. + * + * @return The pointer to the object of type T. + */ + T* operator->() + { + return optr_.get(); + } + + const T* operator->() const + { + return optr_.get(); + } + + T* get() + { + return optr_.get(); + } + + const T* get() const + { + return optr_.get(); + } + //@} + + /** + * Returns the raw object pointer + * + * @return The raw object pointer. + */ + void* ptr() + { + return optr_.ptr(); + } + + /** + * Returns the raw object pointer + * + * @return The raw object pointer. + */ + const void* ptr() const + { + return optr_.ptr(); + } + + /** + * Return the type string of the serializable + * + * @return The type string of the serializable. + */ + const char* type() const + { + return optr_.type(); + } + + /** + * Returns the object id. + * + * @return The id of the object. + */ + unsigned long id() const + { + return optr_.id(); + } + + /** + * Returns the underlying object_ptr + * + * @return The underlying object_ptr + */ + object_ptr optr() const + { + return optr_; + } + + /** + * Creates a new identifier, represented by the identifier + * of the underlaying type. + * + * @return A new identifier. + */ + basic_identifier* create_identifier() const override + { + return optr_.create_identifier(); + } + + /** + * Returns true if the underlying object + * is inserted in an object_store + * + * @return True if object is inserted. + */ + bool is_inserted() const + { + return optr_.is_inserted(); + } + + /** + * Returns true if serializable has a primary key + * + * @return true if serializable has a primary key + */ + bool has_primary_key() const override + { + return optr_.has_primary_key(); + } + + /** + * Gets the primary key of the foreign serializable + * + * @return The primary key of the foreign serializable + */ + std::shared_ptr primary_key() const override + { + return optr_.primary_key(); + } + +private: + friend class detail::object_deleter; + friend class detail::object_inserter; + +private: + object_ptr optr_; +}; + +template < class T > +object_ptr::object_ptr(const has_one &x) + : object_holder(false, x.optr().proxy_) +{} + +template < class T > +object_ptr& object_ptr::operator=(has_one &x) +{ + reset(x.optr().proxy_); + return *this; +} + +} #endif //OOS_HAS_ONE_HPP diff --git a/include/oos/object/object_holder.hpp b/include/oos/object/object_holder.hpp index ab5c3a89d..a08f8a627 100644 --- a/include/oos/object/object_holder.hpp +++ b/include/oos/object/object_holder.hpp @@ -38,11 +38,11 @@ class object_store; /** * @class object_holder - * @brief Base class for the serializable pointer and reference class + * @brief Base class for the object pointer and reference class * - * This is the base class for the serializable pointer + * This is the base class for the object pointer * and reference class. The class holds the proxy - * of the serializable and the id of the serializable. + * of the object and the id of the object. */ class OOS_OBJECT_API object_holder : public identifiable_holder { @@ -51,7 +51,7 @@ class OOS_OBJECT_API object_holder : public identifiable_holder * @brief Creates and empty base pointer. * * Creates and empty base pointer. The boolean - * tells the class if the serializable is handled + * tells the class if the object is handled * as a reference or an pointer. The difference * is that the reference couldn't be deleted * from the object_store and the pointer can. @@ -82,7 +82,7 @@ class OOS_OBJECT_API object_holder : public identifiable_holder * boolean tells the object_holder if it should be * handled as an internal. * - * @param is_internal If true the serializable is handled as an internal. + * @param is_internal If true the object is handled as an internal. * @param op The object_proxy of the object_holder */ object_holder(bool is_internal, object_proxy *op); @@ -131,24 +131,24 @@ class OOS_OBJECT_API object_holder : public identifiable_holder void reset(const std::shared_ptr &id); /** - * Returns if the serializable is loaded. + * Returns if the object is loaded. * - * @return True if the serializable is loaded. + * @return True if the object is loaded. */ bool is_loaded() const; /** - * Returns the serializable id. + * Returns the object id. * - * @return The id of the serializable. + * @return The id of the object. */ unsigned long id() const; /** - * Sets the serializable id. If a proxy + * Sets the object id. If a proxy * is set an exception is thrown. * - * @param i The new serializable id + * @param i The new object id */ void id(unsigned long i); @@ -159,30 +159,30 @@ class OOS_OBJECT_API object_holder : public identifiable_holder object_store* store() const; /** - * Returns the serializable + * Returns the raw object pointer * - * @return The serializable. + * @return The raw object pointer. */ void* ptr(); /** - * Returns the serializable + * Returns the raw object pointer * - * @return The serializable. + * @return The raw object pointer. */ const void* ptr() const; /** - * Returns the serializable + * Returns the object pointer * - * @return The serializable. + * @return The object pointer. */ void* lookup_object(); /** - * Returns the serializable + * Returns the object pointer * - * @return The serializable. + * @return The object pointer. */ void* lookup_object() const; @@ -205,16 +205,16 @@ class OOS_OBJECT_API object_holder : public identifiable_holder bool is_inserted() const; /** - * Returns true if serializable has a primary key + * Returns true if object has a primary key * - * @return true if serializable has a primary key + * @return true if object has a primary key */ bool has_primary_key() const; /** - * Gets the primary key of the foreign serializable + * Gets the primary key of the foreign object * - * @return The primary key of the foreign serializable + * @return The primary key of the foreign object */ virtual std::shared_ptr primary_key() const; @@ -233,10 +233,10 @@ class OOS_OBJECT_API object_holder : public identifiable_holder virtual const char* type() const = 0; /** - * Prints the underlaying serializable + * Prints the underlaying object * * @param out The output stream to write on. - * @param x The serializable pointer to print. + * @param x The object pointer to print. * @return The output stream. */ friend OOS_OBJECT_API std::ostream& operator<<(std::ostream &out, const object_holder &x); @@ -257,6 +257,7 @@ class OOS_OBJECT_API object_holder : public identifiable_holder template < class T > friend class object_ptr; template < class T > friend class has_one; + template < class T > friend class belongs_to; object_proxy *proxy_ = nullptr; cascade_type cascade_ = cascade_type::NONE; diff --git a/include/oos/object/object_ptr.hpp b/include/oos/object/object_ptr.hpp index ac6d2ab0a..bbb475e51 100644 --- a/include/oos/object/object_ptr.hpp +++ b/include/oos/object/object_ptr.hpp @@ -22,154 +22,14 @@ #include "oos/object/object_holder.hpp" #include "oos/object/transaction.hpp" #include "oos/utils/identifier_resolver.hpp" -#include "oos/object/has_one.hpp" #include #include namespace oos { -namespace detail { -class result_impl; -} - -template < class T > class object_ptr; - -/** - * @brief The has_one holds a pointer to an serializable. - * @tparam T The type of the serializable. - * - * The has_one holds a pointer to an object. The - * has_one is a wrapper class for the object class - * It has a reference count mechanism. - * The objects inserted into the object_store are returned - * as a has_one and should be used through the - * has_one class. - */ -template < class T > -class has_one : public object_holder -{ -public: - typedef has_one self; /**< Shortcut for self class. */ - -public: - /** - * Create an empty has_one - */ - has_one() - : object_holder(true) - {} - - /** - * Create an hs_one from an object - * - * @param o The object. - */ - has_one(T *o) - : object_holder(true, new object_proxy(o)) - {} - - /** - * Create an has_one from an object_proxy - * - * @param proxy The object_proxy. - */ - has_one(object_proxy *proxy) - : object_holder(true, proxy) - {} - - /** - * Copies has_one from object_ptr - * - * @param x The object_ptr to copy - */ - has_one(const object_ptr &x); - - /** - * Assigns has_one from object_ptr - * - * @param x The object_ptr to assign - * @return Reference to assigned has_one - */ - has_one& operator=(const object_ptr &x); - - //@{ - /** - * @brief Return the pointer to the object of type T. - * - * Return the pointer to the object of type T. If there - * isn't a valid object nullptr is returned. - * - * @return The pointer to the object of type T. - */ - T* operator->() - { - return get(); - } - - const T* operator->() const - { - return get(); - } - - T* get() - { - return static_cast(proxy_->obj()); - } - - const T* get() const - { - return static_cast(proxy_->obj()); - } - //@} - - /** - * Return the type string of the serializable - * - * @return The type string of the serializable. - */ - const char* type() const - { - return classname_.c_str(); - } - - /** - * Creates a new identifier, represented by the identifier - * of the underlaying type. - * - * @return A new identifier. - */ - basic_identifier* create_identifier() const - { - return self::identifier_->clone(); - } - -private: - friend class object_deleter; - -private: - static std::string classname_; - static std::unique_ptr identifier_; -}; - -template < class T > -std::string has_one::classname_ = typeid(T).name(); - -template < class T > -std::unique_ptr has_one::identifier_(identifier_resolver::resolve()); - -template < class T > -class belongs_to -{ -public: - belongs_to() {} - /** - * Copies has_one from object_ptr - * - * @param x The object_ptr to copy - */ - belongs_to(const object_ptr &x); -}; +template < class T > class has_one; +template < class T > class belongs_to; /** * @brief The object_ptr holds a pointer to an serializable. @@ -227,17 +87,13 @@ class object_ptr : public object_holder * @brief Creates an object_ptr from the given has_one object * @param x The has_one object to created the object_ptr from */ - object_ptr(const has_one &x) - : object_holder(false, x.proxy_) - {} + object_ptr(const has_one &x); /** * @brief Creates an object_ptr from the given has_one object * @param x The has_one object to created the object_ptr from */ - object_ptr(const belongs_to &) - : object_holder(false, nullptr) - {} + object_ptr(const belongs_to &); /** * Assign operator. @@ -255,11 +111,15 @@ class object_ptr : public object_holder * @param x The has_one object to created the object_ptr from * @return A reference to the created object_ptr */ - self& operator=(has_one &x) - { - reset(x.proxy_); - return *this; - } + self& operator=(has_one &x); + + /** + * @brief Copy assignes an object_ptr from the given belongs_to object + * @param x The belongs_to object to created the object_ptr from + * @return A reference to the created object_ptr + */ + self& operator=(belongs_to &x); + /** * Return the type string of the object * @@ -333,6 +193,9 @@ class object_ptr : public object_holder } private: + friend class has_one; + friend class belongs_to; + static std::string classname_; static std::unique_ptr identifier_; }; @@ -343,25 +206,6 @@ std::string object_ptr::classname_ = typeid(T).name(); template < class T > std::unique_ptr object_ptr::identifier_(identifier_resolver::resolve()); - -template < class T > -has_one::has_one(const object_ptr &x) - : object_holder(true, x.proxy_) -{} - -template < class T > -has_one& has_one::operator=(const object_ptr &x) -{ - reset(x.proxy_, x.cascade_); - return *this; -} - -template < class T > -belongs_to::belongs_to(const object_ptr &) -{ - -} - } #endif /* OBJECT_PTR_HPP */ diff --git a/include/oos/object/object_serializer.hpp b/include/oos/object/object_serializer.hpp index 656ba2fd5..c0974c6fa 100644 --- a/include/oos/object/object_serializer.hpp +++ b/include/oos/object/object_serializer.hpp @@ -37,6 +37,7 @@ #include "oos/utils/identifier.hpp" #include "oos/object/has_one.hpp" +#include "oos/object/belongs_to.hpp" #include "oos/object/basic_has_many.hpp" #include @@ -161,6 +162,41 @@ class OOS_OBJECT_API object_serializer } } + template < class T > + void serialize(const char* id, belongs_to &x, cascade_type cascade) + { + if (restore) { + /*************** + * + * extract id and type of serializable from buffer + * try to find serializable on serializable store + * if found check type if wrong type throw error + * else create serializable and set extracted id + * insert serializable into serializable store + * + ***************/ + // Todo: correct implementation + + unsigned long oid = 0; + serialize(id, oid); + std::string type; + serialize(id, type); + + if (oid > 0) { + object_proxy *oproxy = find_proxy(oid); + if (!oproxy) { + oproxy = new object_proxy(new T, oid, ostore_); + insert_proxy(oproxy); + } + x.reset(oproxy, cascade); + } + } else { + unsigned long oid = x.id(); + serialize(id, oid); + serialize(id, const_cast(x.type()), strlen(x.type())); + } + } + template < class T > void serialize(const char* id, has_one &x, cascade_type cascade) { diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index d41a4bad8..2b971010d 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -22,6 +22,7 @@ #include "oos/object/object_exception.hpp" #include "oos/object/object_observer.hpp" #include "oos/object/has_one.hpp" +#include "oos/object/belongs_to.hpp" #include "oos/object/object_serializer.hpp" #include "oos/object/basic_has_many.hpp" #include "oos/object/transaction.hpp" @@ -123,8 +124,8 @@ class OOS_OBJECT_API object_inserter { void serialize(const char *, T &) { } void serialize(const char *, char *, size_t) { } -// template < class T > -// void serialize(const char *, object_ptr &x) + template + void serialize(const char *, belongs_to &x, cascade_type cascade); template void serialize(const char *, has_one &x, cascade_type cascade); @@ -235,6 +236,8 @@ class OOS_OBJECT_API object_deleter { void serialize(const char *, T &) { } void serialize(const char *, char *, size_t) { } + template + void serialize(const char *, belongs_to &x, cascade_type cascade); template void serialize(const char *, has_one &x, cascade_type cascade); template class C> @@ -1250,32 +1253,60 @@ void object_inserter::serialize(T &x) oos::access::serialize(*this, x); } +template +void object_inserter::serialize(const char *, belongs_to &x, cascade_type cascade) { + if (x.is_inserted() || (x.optr().proxy_ && x.optr().proxy_->obj() == nullptr)) { + return; + } + x.optr_.is_inserted_ = true; + x.optr_.cascade_ = cascade; + // object was seen by inserter stop inserting + if (!object_proxies_.insert(x.optr_.proxy_).second) { + return; + } + + if (!x.optr_.proxy_) { + return; + } + + if (x.id()) { + // do the pointer count + object_proxy_stack_.push(x.optr_.proxy_); + oos::access::serialize(*this, *(T*)x.optr_.ptr()); + object_proxy_stack_.pop(); + } else { + // new object + ostore_.insert(x.optr_.proxy_, notify_); + } + ++(*x.optr_.proxy_); +} + template void object_inserter::serialize(const char *, has_one &x, cascade_type cascade) { - if (x.is_inserted() || (x.proxy_ && x.proxy_->obj() == nullptr)) { + if (x.is_inserted() || (x.optr().proxy_ && x.optr().proxy_->obj() == nullptr)) { return; } - x.is_inserted_ = true; - x.cascade_ = cascade; + x.optr_.is_inserted_ = true; + x.optr_.cascade_ = cascade; // object was seen by inserter stop inserting - if (!object_proxies_.insert(x.proxy_).second) { + if (!object_proxies_.insert(x.optr_.proxy_).second) { return; } - if (!x.proxy_) { + if (!x.optr_.proxy_) { return; } if (x.id()) { // do the pointer count - object_proxy_stack_.push(x.proxy_); + object_proxy_stack_.push(x.optr_.proxy_); oos::access::serialize(*this, *(T*)x.ptr()); object_proxy_stack_.pop(); } else { // new object - ostore_.insert(x.proxy_, notify_); + ostore_.insert(x.optr_.proxy_, notify_); } - ++(*x.proxy_); + ++(*x.optr_.proxy_); } template class C> @@ -1328,13 +1359,28 @@ bool object_deleter::is_deletable(object_proxy *proxy, T *o) { return check_object_count_map(); } +template +void object_deleter::serialize(const char *, belongs_to &x, cascade_type cascade) { + if (!x.optr().ptr()) { + return; + } + std::pair ret = object_count_map.insert( + std::make_pair(x.optr().proxy_->id(), t_object_count(x.optr().proxy_, true, (T*)x.optr().proxy_->obj())) + ); + --ret.first->second.reference_counter; + if (cascade & cascade_type::REMOVE) { + ret.first->second.ignore = false; + oos::access::serialize(*this, *(T*)x.optr().ptr()); + } +} + template void object_deleter::serialize(const char *, has_one &x, cascade_type cascade) { if (!x.ptr()) { return; } std::pair ret = object_count_map.insert( - std::make_pair(x.proxy_->id(), t_object_count(x.proxy_, true, (T*)x.proxy_->obj())) + std::make_pair(x.optr().proxy_->id(), t_object_count(x.optr().proxy_, true, (T*)x.optr().proxy_->obj())) ); --ret.first->second.reference_counter; if (cascade & cascade_type::REMOVE) { diff --git a/include/oos/orm/identifier_binder.hpp b/include/oos/orm/identifier_binder.hpp index 2d1a92aae..a064ac208 100644 --- a/include/oos/orm/identifier_binder.hpp +++ b/include/oos/orm/identifier_binder.hpp @@ -37,8 +37,9 @@ class identifier_binder template < class V > void serialize(const char *, identifier &x); - template < class V, typename = typename std::enable_if::value>::type > - void serialize(const char *, V &, cascade_type) { } +// template < class V, typename = typename std::enable_if::value>::type > + template < class HAS_ONE > + void serialize(const char *, HAS_ONE &, cascade_type) { } void serialize(const char *, char *, size_t) { } diff --git a/include/oos/orm/relation_resolver.hpp b/include/oos/orm/relation_resolver.hpp index cf3b24f79..5a167269f 100644 --- a/include/oos/orm/relation_resolver.hpp +++ b/include/oos/orm/relation_resolver.hpp @@ -51,6 +51,43 @@ class relation_resolver void serialize(const char *, char *, size_t) { } + template < class V > + void serialize(const char *, belongs_to &x, cascade_type cascade) + { + std::shared_ptr pk = x.primary_key(); + if (!pk) { + return; + } + + // get node of object type + prototype_iterator node = store_->find(x.type()); + + object_proxy *proxy = node->find_proxy(pk); + if (proxy) { + /** + * find proxy in node map + * if proxy can be found object was + * already read - replace proxy + */ + x.reset(proxy, cascade); + } else { + /** + * if proxy can't be found we create + * a proxy and store it in tables + * proxy map. it will be used when + * table is read. + */ + proxy = new object_proxy(pk, (T*)nullptr, node.get()); + basic_table::t_table_map::iterator j = table_.find_table(node->type()); + + if (j == table_.end_table()) { + throw_object_exception("unknown table " << node->type()); + } + j->second->identifier_proxy_map_.insert(std::make_pair(pk, proxy)); + x.reset(proxy, cascade); + } + } + template < class V > void serialize(const char *, has_one &x, cascade_type cascade) { From 48359541eaeff6fc10f799a34d0876dd738dd7e9 Mon Sep 17 00:00:00 2001 From: zussel Date: Fri, 6 Jan 2017 10:22:47 +0100 Subject: [PATCH 03/61] merged object_ptr, has_one and belongs_to into object_pointer class --- include/oos/object/belongs_to.hpp | 227 +------------------- include/oos/object/has_one.hpp | 248 +--------------------- include/oos/object/object_holder.hpp | 6 +- include/oos/object/object_holder_type.hpp | 17 ++ include/oos/object/object_proxy.hpp | 4 +- include/oos/object/object_ptr.hpp | 93 ++++---- include/oos/object/object_store.hpp | 42 ++-- src/object/CMakeLists.txt | 2 +- 8 files changed, 90 insertions(+), 549 deletions(-) create mode 100644 include/oos/object/object_holder_type.hpp diff --git a/include/oos/object/belongs_to.hpp b/include/oos/object/belongs_to.hpp index 186dbad6a..c32777cfb 100644 --- a/include/oos/object/belongs_to.hpp +++ b/include/oos/object/belongs_to.hpp @@ -4,234 +4,9 @@ #include "oos/object/object_ptr.hpp" namespace oos { -namespace detail { -class object_inserter; -class object_deleter; -} -/** - * @brief The belongs_to holds a pointer to an serializable. - * @tparam T The type of the serializable. - * - * The belongs_to holds a pointer to an object. The - * belongs_to is a wrapper class for the object class - * It has a reference count mechanism. - * The objects inserted into the object_store are returned - * as a belongs_to and should be used through the - * belongs_to class. - */ -template < class T > -class belongs_to : public identifiable_holder -{ -public: - typedef T object_type; /**< Shortcut for template type. */ - typedef belongs_to self; /**< Shortcut for self class. */ - -public: - /** - * Create an empty belongs_to - */ - belongs_to() {} - - /** - * Create an hs_one from an object - * - * @param obj The object. - */ - belongs_to(object_type *obj) : optr_(obj) {} - - /** - * Create an belongs_to from an object_proxy - * - * @param proxy The object_proxy. - */ - belongs_to(object_proxy *proxy) : optr_(proxy) {} - - /** - * Copies belongs_to from object_ptr - * - * @param optr The object_ptr to copy - */ - belongs_to(const object_ptr &optr) : optr_(optr) {} - - /** - * Copies belongs_to from belongs_to - * - * @param x The belongs_to to copy - */ - belongs_to(const self &x) : optr_(x.optr_) {} - - /** - * Assigns belongs_to from belongs_to - * - * @param x The belongs_to to assign - * @return Reference to assigned belongs_to - */ - belongs_to& operator=(const self &x) - { - reset(x.optr_); - return *this; - } - - /** - * Assigns belongs_to from object_ptr - * - * @param optr The object_ptr to assign - * @return Reference to assigned belongs_to - */ - belongs_to& operator=(const object_ptr &optr) - { - reset(optr); - return *this; - } - - /** - * Resets this with given object_ptr - * - * @param optr object_ptr to reset - */ - void reset(const object_ptr &optr) - { - reset(optr.proxy_, optr.cascade_); - } - - /** - * Resets belongs_to from given object_proxy and - * cascade_type. - * - * @param proxy object_proxy to be set - * @param cascade cascade_type to be set - */ - void reset(object_proxy *proxy, cascade_type cascade) - { - optr_.reset(proxy, cascade); - } - - void reset(const std::shared_ptr &id) override - { - optr_.reset(id); - } - - //@{ - /** - * @brief Return the pointer to the object of type T. - * - * Return the pointer to the object of type T. If there - * isn't a valid object nullptr is returned. - * - * @return The pointer to the object of type T. - */ - T* operator->() - { - return optr_.get(); - } - - const T* operator->() const - { - return optr_.get(); - } - - T* get() - { - return optr_.get(); - } - - const T* get() const - { - return optr_.get(); - } - //@} - - /** - * Return the type string of the serializable - * - * @return The type string of the serializable. - */ - const char* type() const - { - return optr_.type(); - } - - /** - * Returns the object id. - * - * @return The id of the object. - */ - unsigned long id() const - { - return optr_.id(); - } - - /** - * Returns the underlying object_ptr - * - * @return The underlying object_ptr - */ - object_ptr optr() const - { - return optr_; - } - - /** - * Creates a new identifier, represented by the identifier - * of the underlaying type. - * - * @return A new identifier. - */ - basic_identifier* create_identifier() const override - { - return optr_.create_identifier(); - } - - /** - * Returns true if the underlying object - * is inserted in an object_store - * - * @return True if object is inserted. - */ - bool is_inserted() const - { - return optr_.is_inserted(); - } - - /** - * Returns true if serializable has a primary key - * - * @return true if serializable has a primary key - */ - bool has_primary_key() const override - { - return optr_.has_primary_key(); - } - - /** - * Gets the primary key of the foreign serializable - * - * @return The primary key of the foreign serializable - */ - std::shared_ptr primary_key() const override - { - return optr_.primary_key(); - } - -private: - friend class detail::object_deleter; - friend class detail::object_inserter; - -private: - object_ptr optr_; -}; template < class T > -object_ptr::object_ptr(const belongs_to &x) - : object_holder(false, x.optr().proxy_) -{} - -template < class T > -object_ptr& object_ptr::operator=(belongs_to &x) -{ - reset(x.optr().proxy_); - return *this; -} +using belongs_to = object_pointer; } diff --git a/include/oos/object/has_one.hpp b/include/oos/object/has_one.hpp index e19ca5f58..f2cc6a6e1 100644 --- a/include/oos/object/has_one.hpp +++ b/include/oos/object/has_one.hpp @@ -8,255 +8,9 @@ #include "oos/object/object_ptr.hpp" namespace oos { -namespace detail { -class object_inserter; -class object_deleter; -} -/** - * @brief The has_one holds a pointer to an serializable. - * @tparam T The type of the serializable. - * - * The has_one holds a pointer to an object. The - * has_one is a wrapper class for the object class - * It has a reference count mechanism. - * The objects inserted into the object_store are returned - * as a has_one and should be used through the - * has_one class. - */ template < class T > -class has_one : public identifiable_holder -{ -public: - typedef T object_type; /**< Shortcut for template type. */ - typedef has_one self; /**< Shortcut for self class. */ - -public: - /** - * Create an empty has_one - */ - has_one() {} - - /** - * Create an hs_one from an object - * - * @param obj The object. - */ - has_one(object_type *obj) : optr_(obj) {} - - /** - * Create an has_one from an object_proxy - * - * @param proxy The object_proxy. - */ - has_one(object_proxy *proxy) : optr_(proxy) {} - - /** - * Copies has_one from object_ptr - * - * @param optr The object_ptr to copy - */ - has_one(const object_ptr &optr) : optr_(optr) {} - - /** - * Copies has_one from has_one - * - * @param x The has_one to copy - */ - has_one(const self &x) : optr_(x.optr_) {} - - /** - * Assigns has_one from has_one - * - * @param x The has_one to assign - * @return Reference to assigned has_one - */ - has_one& operator=(const self &x) - { - reset(x.optr_); - return *this; - } - - /** - * Assigns has_one from object_ptr - * - * @param optr The object_ptr to assign - * @return Reference to assigned has_one - */ - has_one& operator=(const object_ptr &optr) - { - reset(optr); - return *this; - } - - /** - * Resets this with given object_ptr - * - * @param optr object_ptr to reset - */ - void reset(const object_ptr &optr) - { - reset(optr.proxy_, optr.cascade_); - } - - /** - * Resets has_one from given object_proxy and - * cascade_type. - * - * @param proxy object_proxy to be set - * @param cascade cascade_type to be set - */ - void reset(object_proxy *proxy, cascade_type cascade) - { - optr_.reset(proxy, cascade); - } - - void reset(const std::shared_ptr &id) override - { - optr_.reset(id); - } - - //@{ - /** - * @brief Return the pointer to the object of type T. - * - * Return the pointer to the object of type T. If there - * isn't a valid object nullptr is returned. - * - * @return The pointer to the object of type T. - */ - T* operator->() - { - return optr_.get(); - } - - const T* operator->() const - { - return optr_.get(); - } - - T* get() - { - return optr_.get(); - } - - const T* get() const - { - return optr_.get(); - } - //@} - - /** - * Returns the raw object pointer - * - * @return The raw object pointer. - */ - void* ptr() - { - return optr_.ptr(); - } - - /** - * Returns the raw object pointer - * - * @return The raw object pointer. - */ - const void* ptr() const - { - return optr_.ptr(); - } - - /** - * Return the type string of the serializable - * - * @return The type string of the serializable. - */ - const char* type() const - { - return optr_.type(); - } - - /** - * Returns the object id. - * - * @return The id of the object. - */ - unsigned long id() const - { - return optr_.id(); - } - - /** - * Returns the underlying object_ptr - * - * @return The underlying object_ptr - */ - object_ptr optr() const - { - return optr_; - } - - /** - * Creates a new identifier, represented by the identifier - * of the underlaying type. - * - * @return A new identifier. - */ - basic_identifier* create_identifier() const override - { - return optr_.create_identifier(); - } - - /** - * Returns true if the underlying object - * is inserted in an object_store - * - * @return True if object is inserted. - */ - bool is_inserted() const - { - return optr_.is_inserted(); - } - - /** - * Returns true if serializable has a primary key - * - * @return true if serializable has a primary key - */ - bool has_primary_key() const override - { - return optr_.has_primary_key(); - } - - /** - * Gets the primary key of the foreign serializable - * - * @return The primary key of the foreign serializable - */ - std::shared_ptr primary_key() const override - { - return optr_.primary_key(); - } - -private: - friend class detail::object_deleter; - friend class detail::object_inserter; - -private: - object_ptr optr_; -}; - -template < class T > -object_ptr::object_ptr(const has_one &x) - : object_holder(false, x.optr().proxy_) -{} - -template < class T > -object_ptr& object_ptr::operator=(has_one &x) -{ - reset(x.optr().proxy_); - return *this; -} +using has_one = object_pointer; } #endif //OOS_HAS_ONE_HPP diff --git a/include/oos/object/object_holder.hpp b/include/oos/object/object_holder.hpp index a08f8a627..28c9b61b9 100644 --- a/include/oos/object/object_holder.hpp +++ b/include/oos/object/object_holder.hpp @@ -22,6 +22,8 @@ #include "oos/utils/cascade_type.hpp" #include "oos/utils/identifiable_holder.hpp" +#include "oos/object/object_holder_type.hpp" + #include namespace oos { @@ -255,9 +257,7 @@ class OOS_OBJECT_API object_holder : public identifiable_holder // Todo: replace private access of proxy with call to reset friend class table_reader; - template < class T > friend class object_ptr; - template < class T > friend class has_one; - template < class T > friend class belongs_to; + template < class T, object_holder_type OPT > friend class object_pointer; object_proxy *proxy_ = nullptr; cascade_type cascade_ = cascade_type::NONE; diff --git a/include/oos/object/object_holder_type.hpp b/include/oos/object/object_holder_type.hpp new file mode 100644 index 000000000..9a755d925 --- /dev/null +++ b/include/oos/object/object_holder_type.hpp @@ -0,0 +1,17 @@ +// +// Created by sascha on 1/6/17. +// + +#ifndef OOS_OBJECT_HOLDER_TYPE_HPP +#define OOS_OBJECT_HOLDER_TYPE_HPP + +namespace oos { + +enum class object_holder_type { + OBJECT_PTR, + HAS_ONE, + BELONGS_TO +}; + +} +#endif //OOS_OBJECT_HOLDER_TYPE_HPP diff --git a/include/oos/object/object_proxy.hpp b/include/oos/object/object_proxy.hpp index 4f95b4371..a0a5fd730 100644 --- a/include/oos/object/object_proxy.hpp +++ b/include/oos/object/object_proxy.hpp @@ -34,6 +34,7 @@ #include "oos/utils/identifier_resolver.hpp" #include "oos/object/prototype_node.hpp" +#include "oos/object/object_holder_type.hpp" #include #include @@ -352,8 +353,7 @@ class OOS_OBJECT_API object_proxy friend class table_reader; friend class restore_visitor; friend class object_holder; - template < class T > friend class object_ptr; - template < class T > friend class has_one; + template < class T, object_holder_type OHT > friend class object_pointer; typedef void (*deleter)(void*); typedef const char* (*namer)(); diff --git a/include/oos/object/object_ptr.hpp b/include/oos/object/object_ptr.hpp index bbb475e51..8de1c2d5e 100644 --- a/include/oos/object/object_ptr.hpp +++ b/include/oos/object/object_ptr.hpp @@ -28,72 +28,69 @@ namespace oos { -template < class T > class has_one; -template < class T > class belongs_to; - /** - * @brief The object_ptr holds a pointer to an serializable. + * @brief The object_pointer holds a pointer to an serializable. * @tparam T The type of the serializable. * - * The object_ptr holds a pointer to an object. The - * object_ptr is a wrapper class for the object class + * The object_pointer holds a pointer to an object. The + * object_pointer is a wrapper class for the object class * It has a reference count mechanism. * The objects inserted into the object_store are returned - * as a object_ptr and should be used through the - * object_ptr class. + * as a object_pointer and should be used through the + * object_pointer class. */ -template < class T > -class object_ptr : public object_holder +template < class T, object_holder_type OPT > +class object_pointer : public object_holder { public: typedef T object_type; /**< Shortcut for serializable type. */ - typedef object_ptr self; /**< Shortcut for self class. */ + typedef object_pointer self; /**< Shortcut for self class. */ public: /** - * Create an empty object_ptr + * Create an empty object_pointer */ - object_ptr() - : object_holder(false) + object_pointer() + : object_holder(OPT == object_holder_type::HAS_ONE || OPT == object_holder_type::BELONGS_TO) {} /** - * Copies object_ptr + * Copies object_pointer * - * @param x The object_ptr to copy + * @param x The object_pointer to copy */ - object_ptr(const self &x) + object_pointer(const self &x) : object_holder(x.is_internal_, x.proxy_) {} /** - * Create an object_ptr from an object + * Create an object_pointer from an object * * @param o The object. */ - object_ptr(T *o) - : object_holder(false, new object_proxy(o)) + object_pointer(T *o) + : object_holder(OPT == object_holder_type::HAS_ONE || OPT == object_holder_type::BELONGS_TO, new object_proxy(o)) {} /** - * Create an object_ptr from an object_proxy + * Create an object_pointer from an object_proxy * * @param proxy The object_proxy. */ - explicit object_ptr(object_proxy *proxy) - : object_holder(false, proxy) + explicit object_pointer(object_proxy *proxy) + : object_holder(OPT == object_holder_type::HAS_ONE || OPT == object_holder_type::BELONGS_TO, proxy) {} /** - * @brief Creates an object_ptr from the given has_one object - * @param x The has_one object to created the object_ptr from - */ - object_ptr(const has_one &x); - - /** - * @brief Creates an object_ptr from the given has_one object - * @param x The has_one object to created the object_ptr from + * @brief Creates an object_pointer from the given object_pointer object + * + * @param x The object_pointer object to created the object_pointer from */ - object_ptr(const belongs_to &); + template < object_holder_type OOPT > + object_pointer(const object_pointer &x) + : object_holder(OPT == object_holder_type::HAS_ONE || OPT == object_holder_type::BELONGS_TO) + { + reset(x.proxy_, x.cascade_); + } /** * Assign operator. @@ -107,18 +104,16 @@ class object_ptr : public object_holder } /** - * @brief Copy assignes an object_ptr from the given has_one object - * @param x The has_one object to created the object_ptr from - * @return A reference to the created object_ptr + * @brief Copy assignes an object_pointer from the given has_one object + * @param x The has_one object to created the object_pointer from + * @return A reference to the created object_pointer */ - self& operator=(has_one &x); - - /** - * @brief Copy assignes an object_ptr from the given belongs_to object - * @param x The belongs_to object to created the object_ptr from - * @return A reference to the created object_ptr - */ - self& operator=(belongs_to &x); + template < object_holder_type OOPT > + self& operator=(object_pointer &x) + { + reset(x.proxy_, x.cascade_); + return *this; + } /** * Return the type string of the object @@ -193,18 +188,18 @@ class object_ptr : public object_holder } private: - friend class has_one; - friend class belongs_to; - static std::string classname_; static std::unique_ptr identifier_; }; template < class T > -std::string object_ptr::classname_ = typeid(T).name(); +using object_ptr = object_pointer; -template < class T > -std::unique_ptr object_ptr::identifier_(identifier_resolver::resolve()); +template < class T, object_holder_type OPT > +std::string object_pointer::classname_ = typeid(T).name(); + +template < class T, object_holder_type OPT > +std::unique_ptr object_pointer::identifier_(identifier_resolver::resolve()); } diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index 2b971010d..96e065531 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -1255,58 +1255,58 @@ void object_inserter::serialize(T &x) template void object_inserter::serialize(const char *, belongs_to &x, cascade_type cascade) { - if (x.is_inserted() || (x.optr().proxy_ && x.optr().proxy_->obj() == nullptr)) { + if (x.is_inserted() || (x.proxy_ && x.proxy_->obj() == nullptr)) { return; } - x.optr_.is_inserted_ = true; - x.optr_.cascade_ = cascade; + x.is_inserted_ = true; + x.cascade_ = cascade; // object was seen by inserter stop inserting - if (!object_proxies_.insert(x.optr_.proxy_).second) { + if (!object_proxies_.insert(x.proxy_).second) { return; } - if (!x.optr_.proxy_) { + if (!x.proxy_) { return; } if (x.id()) { // do the pointer count - object_proxy_stack_.push(x.optr_.proxy_); - oos::access::serialize(*this, *(T*)x.optr_.ptr()); + object_proxy_stack_.push(x.proxy_); + oos::access::serialize(*this, *(T*)x.ptr()); object_proxy_stack_.pop(); } else { // new object - ostore_.insert(x.optr_.proxy_, notify_); + ostore_.insert(x.proxy_, notify_); } - ++(*x.optr_.proxy_); + ++(*x.proxy_); } template void object_inserter::serialize(const char *, has_one &x, cascade_type cascade) { - if (x.is_inserted() || (x.optr().proxy_ && x.optr().proxy_->obj() == nullptr)) { + if (x.is_inserted() || (x.proxy_ && x.proxy_->obj() == nullptr)) { return; } - x.optr_.is_inserted_ = true; - x.optr_.cascade_ = cascade; + x.is_inserted_ = true; + x.cascade_ = cascade; // object was seen by inserter stop inserting - if (!object_proxies_.insert(x.optr_.proxy_).second) { + if (!object_proxies_.insert(x.proxy_).second) { return; } - if (!x.optr_.proxy_) { + if (!x.proxy_) { return; } if (x.id()) { // do the pointer count - object_proxy_stack_.push(x.optr_.proxy_); + object_proxy_stack_.push(x.proxy_); oos::access::serialize(*this, *(T*)x.ptr()); object_proxy_stack_.pop(); } else { // new object - ostore_.insert(x.optr_.proxy_, notify_); + ostore_.insert(x.proxy_, notify_); } - ++(*x.optr_.proxy_); + ++(*x.proxy_); } template class C> @@ -1361,16 +1361,16 @@ bool object_deleter::is_deletable(object_proxy *proxy, T *o) { template void object_deleter::serialize(const char *, belongs_to &x, cascade_type cascade) { - if (!x.optr().ptr()) { + if (!x.ptr()) { return; } std::pair ret = object_count_map.insert( - std::make_pair(x.optr().proxy_->id(), t_object_count(x.optr().proxy_, true, (T*)x.optr().proxy_->obj())) + std::make_pair(x.proxy_->id(), t_object_count(x.proxy_, true, (T*)x.proxy_->obj())) ); --ret.first->second.reference_counter; if (cascade & cascade_type::REMOVE) { ret.first->second.ignore = false; - oos::access::serialize(*this, *(T*)x.optr().ptr()); + oos::access::serialize(*this, *(T*)x.ptr()); } } @@ -1380,7 +1380,7 @@ void object_deleter::serialize(const char *, has_one &x, cascade_type cascade return; } std::pair ret = object_count_map.insert( - std::make_pair(x.optr().proxy_->id(), t_object_count(x.optr().proxy_, true, (T*)x.optr().proxy_->obj())) + std::make_pair(x.proxy_->id(), t_object_count(x.proxy_, true, (T*)x.proxy_->obj())) ); --ret.first->second.reference_counter; if (cascade & cascade_type::REMOVE) { diff --git a/src/object/CMakeLists.txt b/src/object/CMakeLists.txt index 67db15006..41b3eabe1 100644 --- a/src/object/CMakeLists.txt +++ b/src/object/CMakeLists.txt @@ -50,7 +50,7 @@ SET(HEADER ${CMAKE_SOURCE_DIR}/include/oos/object/has_many_item.hpp ${CMAKE_SOURCE_DIR}/include/oos/object/basic_has_many_item.hpp ${CMAKE_SOURCE_DIR}/include/oos/object/identifier_proxy_map.hpp - ${CMAKE_SOURCE_DIR}/include/oos/object/object_proxy_accessor.hpp ../../include/oos/object/belongs_to.hpp) + ${CMAKE_SOURCE_DIR}/include/oos/object/object_proxy_accessor.hpp ../../include/oos/object/belongs_to.hpp ../../include/oos/object/object_holder_type.hpp) ADD_LIBRARY(oos-object SHARED ${SOURCES} ${HEADER}) From eafe6e30b8a09948ee1dc24039b3c7e554edd1b6 Mon Sep 17 00:00:00 2001 From: zussel Date: Fri, 6 Jan 2017 14:38:39 +0100 Subject: [PATCH 04/61] belongs_to progress --- belongs_to.txt | 55 ++++++++++++++++++++++++++++ include/oos/object/object_holder.hpp | 13 +++++++ include/oos/object/object_store.hpp | 1 + src/object/object_holder.cpp | 10 +++++ test/Item.hpp | 6 ++- test/object/ObjectStoreTestUnit.cpp | 39 ++++++++++++++++++-- 6 files changed, 119 insertions(+), 5 deletions(-) create mode 100644 belongs_to.txt diff --git a/belongs_to.txt b/belongs_to.txt new file mode 100644 index 000000000..fb34ba778 --- /dev/null +++ b/belongs_to.txt @@ -0,0 +1,55 @@ +has_many <-> belongs_to + +struct employee +{ + oos::belongs_to dep; + + template < class S > + void serialize(S &s) + { + s.serialize("department", dep); + } +}; + +struct department +{ + oos::has_many emps; + + template < class S > + void serialize(S &s) + { + s.serialize("employee", emps); + } +}; + + +auto george = ostore.insert(new employee("george")); +auto insurance = ostore.insert(new department("insurance")); + +insurance->emps.push_back(george); + + +Analyze phase +============= + +Case 1: Department attached first + +- attach department +- prototype "employee" not found; prepare new +- mark as has many relation for "department" member "employees" + +- attach employee +- prototype "employee found" +- if employee contains belongs_to for "department" tie prototypes +- else throw error + +Case 2: Employee attached first + +- attach employee +- prototype "department" not found: prepare new +- mark as belongs relation for "employee" member "department" + +- attach department +- prototype "department" found +- if department contains has_many for "employee" tie prototypes +- else throw error diff --git a/include/oos/object/object_holder.hpp b/include/oos/object/object_holder.hpp index 28c9b61b9..91ac9d0a3 100644 --- a/include/oos/object/object_holder.hpp +++ b/include/oos/object/object_holder.hpp @@ -132,6 +132,19 @@ class OOS_OBJECT_API object_holder : public identifiable_holder */ void reset(const std::shared_ptr &id); + /** + * Clears the currently set object + */ + void clear(); + + /** + * Returns true if object_holder doesn't + * holds an object + * + * @return True if object_holder doesn't holds an object + */ + bool empty() const; + /** * Returns if the object is loaded. * diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index 96e065531..41b608b5d 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -1166,6 +1166,7 @@ template class ON_ATTACH> template void node_analyzer::serialize(const char *, belongs_to &, cascade_type) { + // find } template class ON_ATTACH> diff --git a/src/object/object_holder.cpp b/src/object/object_holder.cpp index 19195f8a0..4b3e6bde5 100644 --- a/src/object/object_holder.cpp +++ b/src/object/object_holder.cpp @@ -99,6 +99,16 @@ void object_holder::reset(object_proxy *proxy, cascade_type cascade) } } +void object_holder::clear() +{ + reset(nullptr, cascade_type::ALL); +} + +bool object_holder::empty() const +{ + return proxy_ == nullptr; +} + void object_holder::reset(const std::shared_ptr &id) { if (proxy_ && !proxy_->pk()->is_same_type(*id)) { diff --git a/test/Item.hpp b/test/Item.hpp index 92a17cb29..855a771ce 100644 --- a/test/Item.hpp +++ b/test/Item.hpp @@ -364,7 +364,7 @@ class employee : public person struct department { oos::identifier id; - std::string name; + oos::varchar<255> name; oos::has_many employees; department() {} @@ -379,7 +379,9 @@ struct department { serializer.serialize("id", id); serializer.serialize("name", name); - serializer.serialize("employee", employees, "department", "employee_id"); + serializer.serialize("employee" , employees, "department", "id"); + // name of table, container, name of member + // to serialize } }; diff --git a/test/object/ObjectStoreTestUnit.cpp b/test/object/ObjectStoreTestUnit.cpp index f9abf3451..90650705b 100644 --- a/test/object/ObjectStoreTestUnit.cpp +++ b/test/object/ObjectStoreTestUnit.cpp @@ -42,7 +42,7 @@ ObjectStoreTestUnit::ObjectStoreTestUnit() add_test("pk", std::bind(&ObjectStoreTestUnit::test_primary_key, this), "object proxy primary key test"); add_test("has_many", std::bind(&ObjectStoreTestUnit::test_has_many, this), "has many test"); // add_test("has_many_to_many", std::bind(&ObjectStoreTestUnit::test_has_many_to_many, this), "has many to many test"); -// add_test("belongs_to", std::bind(&ObjectStoreTestUnit::test_belongs_to, this), "test belongs to behaviour"); + add_test("belongs_to", std::bind(&ObjectStoreTestUnit::test_belongs_to, this), "test belongs to behaviour"); add_test("on_attach", std::bind(&ObjectStoreTestUnit::test_on_attach, this), "test on attach callback"); } @@ -1058,11 +1058,44 @@ struct on_attach> : public on_attach_base void ObjectStoreTestUnit::test_belongs_to() { ostore_.attach("person"); - ostore_.attach("employee"); ostore_.attach("department"); + ostore_.attach("employee"); // expected prototypes // person, employee and department + + auto george = ostore_.insert(new employee("george")); + auto jane = ostore_.insert(new employee("jane")); + auto dep = ostore_.insert(new department("insurance")); + + UNIT_ASSERT_TRUE(dep->employees.empty(), "there must be no employees"); + UNIT_ASSERT_TRUE(george->dep().empty(), "there must not be an department"); + UNIT_ASSERT_TRUE(jane->dep().empty(), "there must not be an department"); + + // department is automatically set + dep->employees.push_back(george); + + UNIT_ASSERT_EQUAL(dep->employees.size(), 1UL, "there must be one employee"); + UNIT_ASSERT_EQUAL(dep->employees.front()->name(), "george", "expected name must be george"); + UNIT_ASSERT_FALSE(george->dep().empty(), "department must not be empty"); + UNIT_ASSERT_EQUAL(george->dep()->name, dep->name, "names must be equal"); + + // jane is automatically added to deps employee list + jane->dep(dep); + + UNIT_ASSERT_EQUAL(dep->employees.size(), 2UL, "there must be one employee"); + + // remove george + auto i = dep->employees.begin(); + i = dep->employees.erase(i); + + UNIT_ASSERT_EQUAL(dep->employees.size(), 1UL, "there must be one employee"); + UNIT_ASSERT_EQUAL(dep->employees.front()->name(), "jane", "expected name must be jane"); + UNIT_ASSERT_TRUE(george->dep().empty(), "there must be no department"); + + jane->dep().clear(); + + UNIT_ASSERT_TRUE(dep->employees.empty(), "there must be no employees"); } void ObjectStoreTestUnit::test_on_attach() @@ -1070,7 +1103,7 @@ void ObjectStoreTestUnit::test_on_attach() ostore_.attach("book", false, nullptr); ostore_.attach("book_list", false, nullptr); - UNIT_ASSERT_EQUAL(3UL, table_names.size(), "size mustbe three"); + UNIT_ASSERT_EQUAL(3UL, table_names.size(), "size must be three"); UNIT_ASSERT_EQUAL("book", table_names[0], "type must be book"); UNIT_ASSERT_EQUAL("book_list", table_names[1], "type must be book_list"); From e3b10235eff4969b7837e71659d99229ee81cfa6 Mon Sep 17 00:00:00 2001 From: zussel Date: Fri, 6 Jan 2017 16:36:47 +0100 Subject: [PATCH 05/61] updated belongs_to strategy --- belongs_to.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/belongs_to.txt b/belongs_to.txt index fb34ba778..29fc5f834 100644 --- a/belongs_to.txt +++ b/belongs_to.txt @@ -53,3 +53,16 @@ Case 2: Employee attached first - prototype "department" found - if department contains has_many for "employee" tie prototypes - else throw error + +Business phase +============== + +Case 1: emplyoee sets a department + +- employee gets object type "department" with member name "employees" from prototype +- employee is added to departments employees container + +Case 2: department adds an employee + +- department gets object type "employee" with member name "department" from prototype +- department is set for employee From 433ce3672644a864e318549f96a5598676f9f8cd Mon Sep 17 00:00:00 2001 From: zussel Date: Fri, 6 Jan 2017 16:37:16 +0100 Subject: [PATCH 06/61] removed obsolete relation analyzing in prototype_node --- include/oos/object/basic_has_many.hpp | 7 --- include/oos/object/object_proxy.hpp | 3 +- include/oos/object/object_store.hpp | 53 +++++-------------- include/oos/object/prototype_node.hpp | 74 --------------------------- src/object/object_proxy.cpp | 42 --------------- src/object/prototype_node.cpp | 74 +++++++++++++-------------- test/object/PrototypeTreeTest.cpp | 51 ------------------ test/object/PrototypeTreeTest.hpp | 1 - 8 files changed, 52 insertions(+), 253 deletions(-) diff --git a/include/oos/object/basic_has_many.hpp b/include/oos/object/basic_has_many.hpp index 482d06198..014ac586d 100644 --- a/include/oos/object/basic_has_many.hpp +++ b/include/oos/object/basic_has_many.hpp @@ -154,13 +154,6 @@ class basic_has_many : public abstract_has_many */ void append(const typename iterator::internal_type &item) { container_.push_back(item); } - /** - * @brief Returns true if the container uses a join table - * - * @return True if the container uses a join table - */ - bool has_join_table() const { return true; } - protected: /// @cond OOS_DEV diff --git a/include/oos/object/object_proxy.hpp b/include/oos/object/object_proxy.hpp index a0a5fd730..712108758 100644 --- a/include/oos/object/object_proxy.hpp +++ b/include/oos/object/object_proxy.hpp @@ -378,13 +378,12 @@ class OOS_OBJECT_API object_proxy namer namer_; /**< The object classname function */ unsigned long oid = 0; /**< The id of the concrete or expected object. */ - unsigned long reference_counter_ = 0; object_store *ostore_ = nullptr; /**< The object_store to which the object_proxy belongs. */ prototype_node *node_ = nullptr; /**< The prototype_node containing the type of the object. */ - typedef std::set ptr_set_t; /**< Shortcut to the object_base_ptr_set. */ + typedef std::set ptr_set_t; /**< Shortcut to the object_holder set. */ ptr_set_t ptr_set_; /**< This set contains every object_holder pointing to this object_proxy. */ std::shared_ptr primary_key_ = nullptr; diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index 41b608b5d..7f1cdc702 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -1142,14 +1142,6 @@ object_store::iterator object_store::initialize(prototype_node *node, const ON_A T obj; oos::access::serialize(analyzer, obj); - while (!node->foreign_key_ids.empty()) { - auto i = node->foreign_key_ids.front(); - node->foreign_key_ids.pop_front(); - prototype_node *foreign_node = i.first; - std::shared_ptr fk(node->id_->clone()); - foreign_node->foreign_keys.insert(std::make_pair(i.second, fk)); - } - return prototype_iterator(node); } @@ -1171,56 +1163,39 @@ void node_analyzer::serialize(const char *, belongs_to &, casca template class ON_ATTACH> template -void node_analyzer::serialize(const char *id, has_one &x, cascade_type) +void node_analyzer::serialize(const char *, has_one &x, cascade_type) { prototype_iterator node = node_.tree()->find(x.type()); if (node == node_.tree()->end()) { // if there is no such prototype node // prepare insertion of new node node = node_.tree()->template prepare_attach(); - if (node_.tree()->temp_container_) { - node->prepare_foreign_key(&node_, node_.tree()->temp_container_->item_field().c_str()); - } else { - node->prepare_foreign_key(&node_, id); - } } else if (!node->has_primary_key()) { throw_object_exception("serializable of type '" << x.type() << "' has no primary key"); - } else { - // node is inserted/attached; store it in nodes foreign key map - std::shared_ptr fk(node->id()->clone()); - node_.register_foreign_key(id, fk); } } template class ON_ATTACH> template class C> -void node_analyzer::serialize(const char *id, has_many &x, const char *, const char *) +void node_analyzer::serialize(const char *id, has_many &, const char *, const char *) //void node_analyzer::serialize(const char *id, has_many &x, const char */*owner_field*/, const char */*item_field*/) { // item column column names // x.owner_field(owner_field); // x.item_field(item_field); - // Todo: distinguish between join table and no join table - if (x.has_join_table()) { - // attach relation table for has many relation - // check if has many item is already attached - // true: check owner and item field - // false: attach it - prototype_iterator pi = node_.tree()->find(id); - if (pi == node_.tree()->end()) { - pi = node_.tree()->template attach::item_type, ON_ATTACH>(id, false, nullptr, on_attach_); - } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { - // prototype is of type has_many_item - throw_object_exception("many to many relations are not supported by now"); - } else { - // throw exception - throw_object_exception("prototype already inserted: " << pi->type()); - } - // insert the relation - // add container node to item node - pi->register_relation(node_.type(), &node_, id); + // attach relation table for has many relation + // check if has many item is already attached + // true: check owner and item field + // false: attach it + prototype_iterator pi = node_.tree()->find(id); + if (pi == node_.tree()->end()) { + pi = node_.tree()->template attach::item_type, ON_ATTACH>(id, false, nullptr, on_attach_); + } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { + // prototype is of type has_many_item + throw_object_exception("many to many relations are not supported by now"); } else { - throw object_exception("has_many without join table not supported"); + // throw exception + throw_object_exception("prototype already inserted: " << pi->type()); } } diff --git a/include/oos/object/prototype_node.hpp b/include/oos/object/prototype_node.hpp index f2596025e..52dcc5073 100644 --- a/include/oos/object/prototype_node.hpp +++ b/include/oos/object/prototype_node.hpp @@ -254,40 +254,6 @@ class OOS_OBJECT_API prototype_node */ basic_identifier* id() const; - /** - * @brief Returns the count of relations - * @return The count of relations - */ - size_t relation_count() const; - - /** - * @brief Returns true if a relation with the given name exists - * - * Returns true if a relation with the given name exists in the - * object prototype. - * - * @param relation_name The name of the relation to be checked - * @return True if a relation with the given name exists - */ - bool has_relation(const std::string &relation_name) const; - - /** - * @brief Returns the count of foreign keys - * @return The count of foreign keys - */ - size_t foreign_key_count() const; - - /** - * @brief Returns true if a foreign key with the given name exists - * - * Returns true if a foreign key with the given name exists in the - * object prototype. - * - * @param foreign_key_name The name of the foreign key to be checked - * @return True if a relation with the given name exists - */ - bool has_foreign_key(const std::string &foreign_key_name) const; - /** * @brief Returns true if the node represents an abstract object * @return True if the node represents an abstract object @@ -301,14 +267,6 @@ class OOS_OBJECT_API prototype_node */ std::type_index type_index() const; - /// @cond OOS_DEV - - void register_foreign_key(const char *id, const std::shared_ptr &foreign_key); - void register_relation(const char *type, prototype_node *node, const char *id); - void prepare_foreign_key(prototype_node *master_node, const char *id); - - /// @endcond - /** * Prints the node in graphviz layout to the stream. * @@ -360,15 +318,6 @@ class OOS_OBJECT_API prototype_node template < class T > friend class object_view_iterator; - /* - * The field_prototype_map_t contains a map - * of all foreign key field relations, where each value - * is a pair of the foreign prototype and its - * corresponding field - */ - typedef std::pair prototype_field_info_t; /**< Shortcut for prototype fieldname pair. */ - typedef std::map field_prototype_map_t; /**< Holds the fieldname and the prototype_node. */ - object_store *tree_ = nullptr; /**< The prototype tree to which the node belongs */ // tree links @@ -378,14 +327,6 @@ class OOS_OBJECT_API prototype_node std::unique_ptr first; /**< The first children node */ std::unique_ptr last; /**< The last children node */ - /* this map holds information about - * all prototypes in which this prototype - * is used as a child item (to many - * relation). The string tells the name - * of the attribute - */ - field_prototype_map_t relations; /**< Map holding relation information for type. */ - object_proxy *op_first = nullptr; /**< The marker of the first list node. */ object_proxy *op_marker = nullptr; /**< The marker of the last list node of the own elements. */ object_proxy *op_last = nullptr; /**< The marker of the last list node of all elements. */ @@ -408,21 +349,6 @@ class OOS_OBJECT_API prototype_node * a primary key prototype to clone from */ std::unique_ptr id_; - - /** - * a list of prototype_node and ids for - * which the relation map is yet to be filled - * once the object type is really inserted - * this list is processed - */ - typedef std::list > t_node_id_list; - t_node_id_list foreign_key_ids; /**< The foreign key id list */ - - /** - * a list of all foreign keys inside nodes object - */ - typedef std::unordered_map > t_foreign_key_map; - t_foreign_key_map foreign_keys; /**< The foreign key map */ }; } diff --git a/src/object/object_proxy.cpp b/src/object/object_proxy.cpp index 4394afdbb..53e1b8c22 100644 --- a/src/object/object_proxy.cpp +++ b/src/object/object_proxy.cpp @@ -27,10 +27,6 @@ object_proxy::object_proxy(const std::shared_ptr &pk) : primary_key_(pk) {} -//object_proxy::object_proxy(unsigned long i) -// : oid(i) -//{} - object_proxy::~object_proxy() { if (ostore_ && id() > 0) { @@ -85,34 +81,6 @@ void object_proxy::unlink() node_ = 0; } -//void object_proxy::link_ref() -//{ -// if (obj_) { -// ++ref_count_; -// } -//} -// -//void object_proxy::unlink_ref() -//{ -// if (obj_) { -// --ref_count_; -// } -//} -// -//void object_proxy::link_ptr() -//{ -// if (obj_) { -// ++ptr_count_; -// } -//} -// -//void object_proxy::unlink_ptr() -//{ -// if (obj_) { -// --ptr_count_; -// } -//} - unsigned long object_proxy::operator++() { return ++reference_counter_; @@ -148,16 +116,6 @@ object_proxy *object_proxy::prev() const return prev_; } -//unsigned long object_proxy::ref_count() const -//{ -// return ref_count_; -//} -// -//unsigned long object_proxy::ptr_count() const -//{ -// return ptr_count_; -//} - unsigned long object_proxy::reference_count() const { return reference_counter_; diff --git a/src/object/prototype_node.cpp b/src/object/prototype_node.cpp index 376f0fa95..178061983 100644 --- a/src/object/prototype_node.cpp +++ b/src/object/prototype_node.cpp @@ -329,25 +329,25 @@ basic_identifier *prototype_node::id() const return id_.get(); } -size_t prototype_node::relation_count() const -{ - return relations.size(); -} - -bool prototype_node::has_relation(const std::string &relation_name) const -{ - return relations.find(relation_name) != relations.end(); -} - -size_t prototype_node::foreign_key_count() const -{ - return foreign_keys.size(); -} - -bool prototype_node::has_foreign_key(const std::string &foreign_key_name) const -{ - return foreign_keys.find(foreign_key_name) != foreign_keys.end(); -} +//size_t prototype_node::relation_count() const +//{ +// return relations.size(); +//} +// +//bool prototype_node::has_relation(const std::string &relation_name) const +//{ +// return relations.find(relation_name) != relations.end(); +//} + +//size_t prototype_node::foreign_key_count() const +//{ +// return foreign_keys.size(); +//} +// +//bool prototype_node::has_foreign_key(const std::string &foreign_key_name) const +//{ +// return foreign_keys.find(foreign_key_name) != foreign_keys.end(); +//} bool prototype_node::is_abstract() const { @@ -359,20 +359,20 @@ std::type_index prototype_node::type_index() const return type_index_; } -void prototype_node::register_foreign_key(const char *id, const std::shared_ptr &foreign_key) -{ - foreign_keys.insert(std::make_pair(id, foreign_key)); -} +//void prototype_node::register_foreign_key(const char *id, const std::shared_ptr &foreign_key) +//{ +// foreign_keys.insert(std::make_pair(id, foreign_key)); +//} -void prototype_node::register_relation(const char *type, prototype_node *node, const char *id) -{ - relations.insert(std::make_pair(type, std::make_pair(node, id))); -} +//void prototype_node::register_relation(const char *type, prototype_node *node, const char *id) +//{ +// relations.insert(std::make_pair(type, std::make_pair(node, id))); +//} -void prototype_node::prepare_foreign_key(prototype_node *master_node, const char *id) -{ - foreign_key_ids.push_back(std::make_pair(master_node, id)); -} +//void prototype_node::prepare_foreign_key(prototype_node *master_node, const char *id) +//{ +// foreign_key_ids.push_back(std::make_pair(master_node, id)); +//} object_proxy *prototype_node::find_proxy(const std::shared_ptr &pk) { @@ -440,12 +440,12 @@ std::ostream& operator <<(std::ostream &os, const prototype_node &pn) os << "|{relations}"; // list relations - prototype_node::field_prototype_map_t::const_iterator first = pn.relations.begin(); - prototype_node::field_prototype_map_t::const_iterator last = pn.relations.end(); - while (first != last) { - os << "|{parent node type|" << first->first << "|node|" << first->second.first->type() << "|foreign field|" << first->second.second << "}"; - ++first; - } +// prototype_node::field_prototype_map_t::const_iterator first = pn.relations.begin(); +// prototype_node::field_prototype_map_t::const_iterator last = pn.relations.end(); +// while (first != last) { +// os << "|{parent node type|" << first->first << "|node|" << first->second.first->type() << "|foreign field|" << first->second.second << "}"; +// ++first; +// } os << "}\"]\n"; return os; } diff --git a/test/object/PrototypeTreeTest.cpp b/test/object/PrototypeTreeTest.cpp index 9576553f9..6d9d9959f 100644 --- a/test/object/PrototypeTreeTest.cpp +++ b/test/object/PrototypeTreeTest.cpp @@ -23,7 +23,6 @@ PrototypeTreeTestUnit::PrototypeTreeTestUnit() add_test("child_of", std::bind(&PrototypeTreeTestUnit::test_child_of, this), "test child of element"); add_test("traverse", std::bind(&PrototypeTreeTestUnit::test_traverse, this), "test traversing the prototype tree"); add_test("const_traverse", std::bind(&PrototypeTreeTestUnit::test_const_traverse, this), "test const traversing the prototype tree"); - add_test("relations", std::bind(&PrototypeTreeTestUnit::test_relations, this), "test relations"); } void PrototypeTreeTestUnit::test_empty() @@ -242,53 +241,3 @@ void PrototypeTreeTestUnit::test_const_traverse() UNIT_ASSERT_TRUE(first == ptree.begin(), "expected prototype iterator to be begin()"); } - -void PrototypeTreeTestUnit::test_relations() -{ - object_store ptree; - - object_store::const_iterator children_vector_node = ptree.attach("children_vector"); - object_store::const_iterator master_node = ptree.attach("master"); - object_store::const_iterator child_node = ptree.attach("child"); - - // get the relation table for children - // holding id of children_vector (container) - // and id of child (value) - object_store::const_iterator children_node = ptree.find("children"); - - UNIT_ASSERT_EQUAL(child_node->relation_count(), 0UL, "relations must be empty"); - UNIT_ASSERT_EQUAL(child_node->foreign_key_count(), 0UL, "foreign keys must be empty"); - - UNIT_ASSERT_EQUAL(children_vector_node->relation_count(), 0UL, "relations must be empty"); - UNIT_ASSERT_EQUAL(children_vector_node->foreign_key_count(), 0UL, "foreign keys must be empty"); - - UNIT_ASSERT_EQUAL(master_node->relation_count(), 0UL, "relations must be empty"); - UNIT_ASSERT_GREATER(master_node->foreign_key_count(), 0UL, "foreign key must not be empty"); - UNIT_ASSERT_EQUAL(master_node->foreign_key_count(), 1UL, "there must be one foreign key"); - -// prototype_node::t_foreign_key_map::const_iterator j = master_node->foreign_keys.find("child"); - UNIT_ASSERT_TRUE(master_node->has_foreign_key("child"), "iterator must not be end"); -// UNIT_ASSERT_FALSE(j == master_node->foreign_keys.end(), "iterator must not be end"); - - UNIT_ASSERT_NOT_EQUAL(children_node->relation_count(), 0UL, "relations must not be empty"); - UNIT_ASSERT_EQUAL(children_node->relation_count(), 1UL, "there must be one relation"); -// prototype_node::field_prototype_map_t::const_iterator i = children_node->relations.find("children_vector"); - UNIT_ASSERT_TRUE(children_node->has_relation("children_vector"), "iterator must not be end"); -// UNIT_ASSERT_FALSE(i == children_node->relations.end(), "iterator must not be end"); - - UNIT_ASSERT_NOT_EQUAL(children_node->foreign_key_count(), 0UL, "foreign keys must not be empty"); - // Todo: foreign key maybe take the id of the parent node in account - UNIT_ASSERT_EQUAL(children_node->foreign_key_count(), 1UL, "there must be one foreign keys"); -// UNIT_ASSERT_EQUAL(children_node->foreign_key_count(), 2UL, "there must be two foreign keys"); -// j = children_node->foreign_keys.find("container"); -// UNIT_ASSERT_TRUE(children_node->has_foreign_key("owner_id"), "iterator must not be end"); -// j = children_node->foreign_keys.find("value"); -// UNIT_ASSERT_FALSE(children_node->has_foreign_key("item_id"), "foreign item key must not be 'item_id'"); -// UNIT_ASSERT_TRUE(children_node->has_foreign_key("child_id"), "foreign item key must be 'child_id'"); - - std::ofstream out("graph.dot", ios::out | ios::trunc); - - ptree.dump(out); - - out.close(); -} diff --git a/test/object/PrototypeTreeTest.hpp b/test/object/PrototypeTreeTest.hpp index 65f2af602..46dfd447d 100644 --- a/test/object/PrototypeTreeTest.hpp +++ b/test/object/PrototypeTreeTest.hpp @@ -20,7 +20,6 @@ class PrototypeTreeTestUnit : public oos::unit_test void test_child_of(); void test_traverse(); void test_const_traverse(); - void test_relations(); }; #endif /* PROTOTYPE_TREE_TESTUNIT_HPP */ From 8bac3c7bfc62590d2200322f38b59b99bb9843a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Sun, 8 Jan 2017 22:23:29 +0100 Subject: [PATCH 07/61] replaced is_internal with object_holder_type --- include/oos/object/has_many_vector.hpp | 18 ++++++++---- include/oos/object/object_holder.hpp | 13 +++++++-- include/oos/object/object_ptr.hpp | 10 +++---- src/object/object_holder.cpp | 39 +++++++++++++++++++------- 4 files changed, 56 insertions(+), 24 deletions(-) diff --git a/include/oos/object/has_many_vector.hpp b/include/oos/object/has_many_vector.hpp index d6ee84ac1..3f24fe837 100644 --- a/include/oos/object/has_many_vector.hpp +++ b/include/oos/object/has_many_vector.hpp @@ -603,12 +603,21 @@ class has_many : public basic_has_many iterator insert(iterator pos, const value_type &value) { // create new has_many - if (indexed_) { - - } item_type *item = create_item(value); relation_type iptr(item); if (this->ostore_) { + // if (foreign object has belongs to with owner type) { + prototype_node *foreign_node_; + +// auto i = foreign_node_->belongs_to_map.find(this->owner_->node()->type_index()); +// if (i != foreign_node_->belongs_to_map.end()) { +// prototype_node::relation_info info = i->second; +// this->ostore_->insert(value); +// oos::set(value, info->foreign_field, this->owner_); +// } + // insert value + // set owner into value + // } else { this->ostore_->insert(iptr); this->mark_modified_owner_(*this->ostore_, this->owner_); } @@ -709,9 +718,6 @@ class has_many : public basic_has_many { return new item_type(this->owner_field_, this->item_field_, this->owner_id_, value); } - -private: - bool indexed_ = false; }; } diff --git a/include/oos/object/object_holder.hpp b/include/oos/object/object_holder.hpp index 91ac9d0a3..8a227a221 100644 --- a/include/oos/object/object_holder.hpp +++ b/include/oos/object/object_holder.hpp @@ -61,7 +61,7 @@ class OOS_OBJECT_API object_holder : public identifiable_holder * @param is_internal True if the pointer is used internal, which means * it is used to describe an entity. */ - explicit object_holder(bool is_internal); + explicit object_holder(object_holder_type holder_type); /** * Copies from another object_holder @@ -87,7 +87,7 @@ class OOS_OBJECT_API object_holder : public identifiable_holder * @param is_internal If true the object is handled as an internal. * @param op The object_proxy of the object_holder */ - object_holder(bool is_internal, object_proxy *op); + object_holder(object_holder_type holder_type, object_proxy *op); /** * Destroys the object_holder @@ -211,6 +211,11 @@ class OOS_OBJECT_API object_holder : public identifiable_holder */ bool is_internal() const; + bool is_belongs_to() const; + + bool is_has_one() const; + + bool is_object_ptr() const; /** * Returns true if the underlying object * is inserted in an object_store @@ -247,6 +252,8 @@ class OOS_OBJECT_API object_holder : public identifiable_holder */ virtual const char* type() const = 0; + object_holder_type holder_type() const; + /** * Prints the underlaying object * @@ -274,7 +281,7 @@ class OOS_OBJECT_API object_holder : public identifiable_holder object_proxy *proxy_ = nullptr; cascade_type cascade_ = cascade_type::NONE; - bool is_internal_ = false; + object_holder_type type_; bool is_inserted_ = false; unsigned long oid_ = 0; }; diff --git a/include/oos/object/object_ptr.hpp b/include/oos/object/object_ptr.hpp index 8de1c2d5e..a57862d8e 100644 --- a/include/oos/object/object_ptr.hpp +++ b/include/oos/object/object_ptr.hpp @@ -51,7 +51,7 @@ class object_pointer : public object_holder * Create an empty object_pointer */ object_pointer() - : object_holder(OPT == object_holder_type::HAS_ONE || OPT == object_holder_type::BELONGS_TO) + : object_holder(OPT) {} /** * Copies object_pointer @@ -59,7 +59,7 @@ class object_pointer : public object_holder * @param x The object_pointer to copy */ object_pointer(const self &x) - : object_holder(x.is_internal_, x.proxy_) + : object_holder(x.type_, x.proxy_) {} /** @@ -68,7 +68,7 @@ class object_pointer : public object_holder * @param o The object. */ object_pointer(T *o) - : object_holder(OPT == object_holder_type::HAS_ONE || OPT == object_holder_type::BELONGS_TO, new object_proxy(o)) + : object_holder(OPT, new object_proxy(o)) {} /** @@ -77,7 +77,7 @@ class object_pointer : public object_holder * @param proxy The object_proxy. */ explicit object_pointer(object_proxy *proxy) - : object_holder(OPT == object_holder_type::HAS_ONE || OPT == object_holder_type::BELONGS_TO, proxy) + : object_holder(OPT, proxy) {} /** @@ -87,7 +87,7 @@ class object_pointer : public object_holder */ template < object_holder_type OOPT > object_pointer(const object_pointer &x) - : object_holder(OPT == object_holder_type::HAS_ONE || OPT == object_holder_type::BELONGS_TO) + : object_holder(OPT) { reset(x.proxy_, x.cascade_); } diff --git a/src/object/object_holder.cpp b/src/object/object_holder.cpp index 4b3e6bde5..1d1c13440 100644 --- a/src/object/object_holder.cpp +++ b/src/object/object_holder.cpp @@ -8,8 +8,8 @@ namespace oos { -object_holder::object_holder(bool is_internal) - : is_internal_(is_internal) +object_holder::object_holder(object_holder_type holder_type) + : type_(holder_type) {} object_holder::object_holder(const object_holder &x) @@ -31,9 +31,9 @@ object_holder::operator=(const object_holder &x) return *this; } -object_holder::object_holder(bool is_internal, object_proxy *op) +object_holder::object_holder(object_holder_type holder_type, object_proxy *op) : proxy_(op) - , is_internal_(is_internal) + , type_(holder_type) , oid_(0) { if (proxy_) { @@ -45,7 +45,7 @@ object_holder::object_holder(bool is_internal, object_proxy *op) object_holder::~object_holder() { if (proxy_) { - if (is_internal_ && is_inserted_) { + if (is_internal() && is_inserted_) { --(*proxy_); } proxy_->remove(this); @@ -76,7 +76,7 @@ void object_holder::reset(object_proxy *proxy, cascade_type cascade) } if (proxy_) { oid_ = 0; - if (is_internal_ && is_inserted_ && proxy_->ostore_) { + if (is_internal() && is_inserted_ && proxy_->ostore_) { --(*proxy_); } proxy_->remove(this); @@ -92,7 +92,7 @@ void object_holder::reset(object_proxy *proxy, cascade_type cascade) cascade_ = cascade; if (proxy_) { oid_ = proxy_->id(); - if (is_internal_ && is_inserted_ && proxy_->ostore_) { + if (is_internal() && is_inserted_ && proxy_->ostore_) { ++(*proxy_); } proxy_->add(this); @@ -171,10 +171,24 @@ void*object_holder::lookup_object() const return proxy_ ? proxy_->obj() : nullptr; } -bool -object_holder::is_internal() const +bool object_holder::is_belongs_to() const +{ + return type_ == object_holder_type::BELONGS_TO; +} + +bool object_holder::is_has_one() const +{ + return type_ == object_holder_type::HAS_ONE; +} + +bool object_holder::is_object_ptr() const { - return is_internal_; + return type_ == object_holder_type::OBJECT_PTR; +} + +bool object_holder::is_internal() const +{ + return type_ == object_holder_type::BELONGS_TO || type_ == object_holder_type::HAS_ONE; } bool object_holder::is_inserted() const @@ -197,6 +211,11 @@ unsigned long object_holder::reference_count() const return (proxy_ ? proxy_->reference_counter_ : 0UL); } +object_holder_type object_holder::holder_type() const +{ + return type_; +} + std::ostream& operator<<(std::ostream &out, const object_holder &x) { if (x.proxy_) { From 9aca6b0fd3ed39e7378b7b6259ae7a413791fb06 Mon Sep 17 00:00:00 2001 From: zussel Date: Mon, 9 Jan 2017 17:32:43 +0100 Subject: [PATCH 08/61] belongs to progress --- include/oos/object/basic_has_many.hpp | 4 +- include/oos/object/has_many_vector.hpp | 95 +++++++---- include/oos/object/node_analyzer.hpp | 58 +++++++ include/oos/object/object_deleter.hpp | 135 ++++++++++++++++ include/oos/object/object_inserter.hpp | 90 +++++++++++ include/oos/object/object_store.hpp | 214 +------------------------ include/oos/object/prototype_node.hpp | 17 ++ src/object/CMakeLists.txt | 2 +- src/object/prototype_node.cpp | 20 +-- 9 files changed, 375 insertions(+), 260 deletions(-) create mode 100644 include/oos/object/node_analyzer.hpp create mode 100644 include/oos/object/object_deleter.hpp create mode 100644 include/oos/object/object_inserter.hpp diff --git a/include/oos/object/basic_has_many.hpp b/include/oos/object/basic_has_many.hpp index 014ac586d..dc5580e7a 100644 --- a/include/oos/object/basic_has_many.hpp +++ b/include/oos/object/basic_has_many.hpp @@ -63,6 +63,8 @@ class basic_has_many : public abstract_has_many typedef typename container_type::size_type size_type; /**< Shortcut to size type */ typedef typename container_type::iterator container_iterator; /**< Shortcut to container iterator */ + typedef std::function mark_modified_owner_func; /**< Shortcut to mark modified owner function */ + public: /** * @brief Returns the begin iterator of the container @@ -163,7 +165,7 @@ class basic_has_many : public abstract_has_many object_proxy *owner_ = nullptr; std::shared_ptr owner_id_; - std::function mark_modified_owner_; + mark_modified_owner_func mark_modified_owner_; container_type container_; diff --git a/include/oos/object/has_many_vector.hpp b/include/oos/object/has_many_vector.hpp index 3f24fe837..bd3ad5a40 100644 --- a/include/oos/object/has_many_vector.hpp +++ b/include/oos/object/has_many_vector.hpp @@ -62,13 +62,13 @@ class has_many_iterator typedef has_many_iterator_traits traits; typedef typename traits::item_type item_type; typedef typename traits::internal_type internal_type; - typedef typename traits::relation_type relation_type; typedef typename traits::container_type container_type; public: - typedef has_many_iterator self; /**< Shortcut value self */ + typedef has_many_iterator self; /**< Shortcut value self */ typedef typename traits::value_type value_type; /**< Shortcut value type */ - typedef typename traits::difference_type difference_type; /**< Shortcut to the difference type*/ + typedef typename traits::relation_type relation_type; /**< Shortcut to the relation type */ + typedef typename traits::difference_type difference_type; /**< Shortcut to the difference type */ typedef typename traits::container_iterator container_iterator; /**< Shortcut to the internal container iterator */ typedef typename traits::const_container_iterator const_container_iterator; /**< Shortcut to the internal const container iterator */ @@ -548,6 +548,49 @@ class const_has_many_iterator const_container_iterator iter_; }; +namespace detail { +template class C, class Enabled = void> +class has_many_inserter; + +template class C> +class has_many_inserter::value>::type> +{ +public: + typedef T value_type; + typedef typename has_many_iterator_traits::relation_type relation_type; + typedef typename basic_has_many::mark_modified_owner_func mark_modified_owner_func; + + void insert(object_store &store, const relation_type &rtype, object_proxy &owner, const mark_modified_owner_func &mark_modified_owner) + { + prototype_iterator foreign_node_ = store.find(typeid(T).name()); + + auto i = foreign_node_->belongs_to_map_.find(owner.node()->type_index()); + if (i != foreign_node_->belongs_to_map_.end()) { + store.insert(rtype->value()); + } else { + store.insert(rtype); + mark_modified_owner(store, &owner); + } + + } +}; + +template class C> +class has_many_inserter::value>::type> +{ +public: + typedef T value_type; + typedef typename has_many_iterator_traits::relation_type relation_type; + typedef typename basic_has_many::mark_modified_owner_func mark_modified_owner_func; + + void insert(object_store &store, const relation_type &rtype, object_proxy &owner, const mark_modified_owner_func &mark_modified_owner) + { + store.insert(rtype); + mark_modified_owner(store, &owner); + } +}; +} + /** * @brief Has many relation class using a std::vector as container * @@ -606,8 +649,17 @@ class has_many : public basic_has_many item_type *item = create_item(value); relation_type iptr(item); if (this->ostore_) { + inserter_.insert(*this->ostore_, iptr, *this->owner_, this->mark_modified_owner_); // if (foreign object has belongs to with owner type) { - prototype_node *foreign_node_; +// prototype_iterator foreign_node_ = this->ostore_->find(typeid(T).name()); +// +// auto i = foreign_node_->belongs_to_map_.find(this->owner_->node()->type_index()); +// if (i != foreign_node_->belongs_to_map_.end()) { +// this->ostore_->insert(value); +// } else { +// this->ostore_->insert(iptr); +// this->mark_modified_owner_(*this->ostore_, this->owner_); +// } // auto i = foreign_node_->belongs_to_map.find(this->owner_->node()->type_index()); // if (i != foreign_node_->belongs_to_map.end()) { @@ -618,8 +670,8 @@ class has_many : public basic_has_many // insert value // set owner into value // } else { - this->ostore_->insert(iptr); - this->mark_modified_owner_(*this->ostore_, this->owner_); +// this->ostore_->insert(iptr); +// this->mark_modified_owner_(*this->ostore_, this->owner_); } return iterator(this->container_.insert(pos.iter_, iptr)); } @@ -634,34 +686,6 @@ class has_many : public basic_has_many insert(this->end(), value); } - /** - * @brief Returns the element at specified location index. - * - * Returns the element at specified location index. - * No bounds checking is performed. - * - * @param index Indx of the element to return - * @return The requested element. - */ - value_type operator[](size_type index) - { - return this->container_[index]->value(); - } - - /** - * @brief Returns the const element at specified location index. - * - * Returns the const element at specified location index. - * No bounds checking is performed. - * - * @param index Indx of the element to return - * @return The requested const element. - */ - const value_type operator[](size_type index) const - { - return this->container_[index]->value(); - } - /** * @brief Clears the vector */ @@ -718,6 +742,9 @@ class has_many : public basic_has_many { return new item_type(this->owner_field_, this->item_field_, this->owner_id_, value); } + +private: + detail::has_many_inserter inserter_; }; } diff --git a/include/oos/object/node_analyzer.hpp b/include/oos/object/node_analyzer.hpp new file mode 100644 index 000000000..7c1741f03 --- /dev/null +++ b/include/oos/object/node_analyzer.hpp @@ -0,0 +1,58 @@ +#ifndef OOS_NODE_ANALYZER_HPP +#define OOS_NODE_ANALYZER_HPP + +#include "oos/object/has_one.hpp" +#include "oos/object/belongs_to.hpp" +#include "oos/object/basic_has_many.hpp" + +namespace oos { + +class prototype_node; + +namespace detail { + +template < class T, template < class ... > class ON_ATTACH > +class node_analyzer { +public: + node_analyzer(prototype_node &node, const ON_ATTACH &on_attach) + : node_(node) + , on_attach_(on_attach) + { } + + ~node_analyzer() { } + + template + void serialize(V &x); + template + void serialize(const char *, V &) { } + void serialize(const char *, char *, size_t) { } + template + void serialize(const char *id, belongs_to &x, cascade_type); + template + void serialize(const char *id, has_one &x, cascade_type); + template class C> + void serialize(const char *, has_many &, const char *, const char *); + +private: + prototype_node &node_; + ON_ATTACH on_attach_; +}; + +struct basic_on_attach {}; + +template < class T > +struct null_on_attach : public basic_on_attach +{ + null_on_attach() {} + template < class V > + null_on_attach(const null_on_attach &) {} + null_on_attach& operator=(const null_on_attach &) { return *this; } + template < class V > + null_on_attach& operator=(const null_on_attach &) { return *this; } + + void operator()(prototype_node*) const {} +}; + +} +} +#endif //OOS_NODE_ANALYZER_HPP diff --git a/include/oos/object/object_deleter.hpp b/include/oos/object/object_deleter.hpp new file mode 100644 index 000000000..c133696e2 --- /dev/null +++ b/include/oos/object/object_deleter.hpp @@ -0,0 +1,135 @@ +#ifndef OOS_OBJECT_DELETER_HPP +#define OOS_OBJECT_DELETER_HPP + +#include "oos/object/has_one.hpp" +#include "oos/object/belongs_to.hpp" +#include "oos/object/basic_has_many.hpp" + +#ifdef _MSC_VER +#ifdef oos_object_EXPORTS + #define OOS_OBJECT_API __declspec(dllexport) + #define EXPIMP_OBJECT_TEMPLATE + #else + #define OOS_OBJECT_API __declspec(dllimport) + #define EXPIMP_OBJECT_TEMPLATE extern + #endif + #pragma warning(disable: 4251) + #pragma warning(disable: 4355) +#else +#define OOS_OBJECT_API +#endif + +namespace oos { + +class object_proxy; + +namespace detail { + +/** + * @cond OOS_DEV + * @class object_deleter + * @brief Checks if an serializable could be deleted + * + * This class checks wether a given serializable or a + * given object_list_base and their children objects + * could be deleted or not. + * If the check was successful, all the deletable serializable + * can be accepted via the iterators. + */ +class OOS_OBJECT_API object_deleter { + private: + struct OOS_OBJECT_API t_object_count { + typedef void (*t_remove_func)(object_proxy*, bool); + template < class T > + t_object_count(object_proxy *oproxy, bool ignr = true, T* = nullptr) + : proxy(oproxy) + , reference_counter(oproxy->reference_count()) + , ignore(ignr) + , remove_func(&remove_object) + {} + + void remove(bool notify); + + template + static void remove_object(object_proxy *proxy, bool notify); + + object_proxy *proxy; + unsigned long reference_counter; + bool ignore; + + t_remove_func remove_func; + }; + + private: + typedef std::map t_object_count_map; + + public: + typedef t_object_count_map::iterator iterator; + /**< Shortcut the serializable map iterator */ + typedef t_object_count_map::const_iterator const_iterator; /**< Shortcut the serializable map const_iterator */ + + /** + * Creates an instance of the object_deleter + */ + object_deleter() { } + + ~object_deleter() { } + + /** + * Checks wether the given serializable is deletable. + * + * @param proxy The object_proxy to be checked. + * @return True if the serializable could be deleted. + */ + template + bool is_deletable(object_proxy *proxy, T *o); + + /** + * Checks wether the given object_container is deletable. + * + * @param ovector The object_container to be checked. + * @return True if the object_container could be deleted. + */ +// bool is_deletable(object_container &oc); + + /** + * @brief Returns the first deletable serializable. + * + * If the check was made and was successful this + * returns the first deletable serializable. + */ + iterator begin(); + + /** + * @brief Returns the first deletable serializable. + * + * If the check was made and was successful this + * returns the last deletable serializable. + */ + iterator end(); + + template + void serialize(T &x) { oos::access::serialize(*this, x); } + + template + void serialize(const char *, T &) { } + void serialize(const char *, char *, size_t) { } + + template + void serialize(const char *, belongs_to &x, cascade_type cascade); + template + void serialize(const char *, has_one &x, cascade_type cascade); + template class C> + void serialize(const char *, basic_has_many &, const char *, const char *); + template + void serialize(const char *id, identifier &x); + + bool check_object_count_map() const; + + private: + t_object_count_map object_count_map; +}; + +} +} +#endif //OOS_OBJECT_DELETER_HPP diff --git a/include/oos/object/object_inserter.hpp b/include/oos/object/object_inserter.hpp new file mode 100644 index 000000000..d5122a3ad --- /dev/null +++ b/include/oos/object/object_inserter.hpp @@ -0,0 +1,90 @@ +#ifndef OOS_OBJECT_INSERTER_HPP +#define OOS_OBJECT_INSERTER_HPP + +#include "oos/object/has_one.hpp" +#include "oos/object/belongs_to.hpp" +#include "oos/object/basic_has_many.hpp" + +#include + +#ifdef _MSC_VER +#ifdef oos_object_EXPORTS + #define OOS_OBJECT_API __declspec(dllexport) + #define EXPIMP_OBJECT_TEMPLATE + #else + #define OOS_OBJECT_API __declspec(dllimport) + #define EXPIMP_OBJECT_TEMPLATE extern + #endif + #pragma warning(disable: 4251) + #pragma warning(disable: 4355) +#else +#define OOS_OBJECT_API +#endif + +namespace oos { +namespace detail { + +/** + * @cond OOS_DEV + * @class object_inserter + * @brief Creates objects and object_lists + * + * When an serializable is inserted into the serializable store + * subsequently other serializable must be created and + * inserted into the serializable store. + * This class does these tasks. + */ +class OOS_OBJECT_API object_inserter { + public: + /** + * @brief Creates an object_inserter instance. + * + * An object_inserter instance ist created for a + * given object_store. The notify flag tells the + * object_inserter wether the observers should be + * notified or not. + * + * @param ostore The object_store. + */ + object_inserter(object_store &ostore); + + ~object_inserter(); + + template + void insert(object_proxy *proxy, T *o, bool notify); + + void reset(); + + template + void serialize(T &x); + + template + void serialize(const char *, T &) { } + void serialize(const char *, char *, size_t) { } + + template + void serialize(const char *, belongs_to &x, cascade_type cascade); + template + void serialize(const char *, has_one &x, cascade_type cascade); + + template class C> + void serialize(const char *id, basic_has_many &x, const char *owner_field, const char *item_field); + + private: + typedef std::set t_object_proxy_set; + + t_object_proxy_set object_proxies_; + + std::stack object_proxy_stack_; + + object_store &ostore_; + + std::function modified_marker_; + + bool notify_ = false; +}; + +} +} + +#endif //OOS_OBJECT_INSERTER_HPP diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index 7f1cdc702..f3859091e 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -21,6 +21,9 @@ #include "oos/object/prototype_iterator.hpp" #include "oos/object/object_exception.hpp" #include "oos/object/object_observer.hpp" +#include "oos/object/object_inserter.hpp" +#include "oos/object/object_deleter.hpp" +#include "oos/object/node_analyzer.hpp" #include "oos/object/has_one.hpp" #include "oos/object/belongs_to.hpp" #include "oos/object/object_serializer.hpp" @@ -86,213 +89,6 @@ class OOS_OBJECT_API modified_marker t_marker marker_; }; -/** - * @cond OOS_DEV - * @class object_inserter - * @brief Creates objects and object_lists - * - * When an serializable is inserted into the serializable store - * subsequently other serializable must be created and - * inserted into the serializable store. - * This class does these tasks. - */ -class OOS_OBJECT_API object_inserter { -public: - /** - * @brief Creates an object_inserter instance. - * - * An object_inserter instance ist created for a - * given object_store. The notify flag tells the - * object_inserter wether the observers should be - * notified or not. - * - * @param ostore The object_store. - */ - object_inserter(object_store &ostore); - - ~object_inserter(); - - template - void insert(object_proxy *proxy, T *o, bool notify); - - void reset(); - - template - void serialize(T &x); - - template - void serialize(const char *, T &) { } - void serialize(const char *, char *, size_t) { } - - template - void serialize(const char *, belongs_to &x, cascade_type cascade); - template - void serialize(const char *, has_one &x, cascade_type cascade); - - template class C> - void serialize(const char *id, basic_has_many &x, const char *owner_field, const char *item_field); - -private: - typedef std::set t_object_proxy_set; - - t_object_proxy_set object_proxies_; - - std::stack object_proxy_stack_; - - object_store &ostore_; - - std::function modified_marker_; - - bool notify_ = false; -}; - -/** - * @cond OOS_DEV - * @class object_deleter - * @brief Checks if an serializable could be deleted - * - * This class checks wether a given serializable or a - * given object_list_base and their children objects - * could be deleted or not. - * If the check was successful, all the deletable serializable - * can be accepted via the iterators. - */ -class OOS_OBJECT_API object_deleter { -private: - struct OOS_OBJECT_API t_object_count { - typedef void (*t_remove_func)(object_proxy*, bool); - template < class T > - t_object_count(object_proxy *oproxy, bool ignr = true, T* = nullptr) - : proxy(oproxy) - , reference_counter(oproxy->reference_count()) - , ignore(ignr) - , remove_func(&remove_object) - {} - - void remove(bool notify); - - template - static void remove_object(object_proxy *proxy, bool notify); - - object_proxy *proxy; - unsigned long reference_counter; - bool ignore; - - t_remove_func remove_func; - }; - -private: - typedef std::map t_object_count_map; - -public: - typedef t_object_count_map::iterator iterator; - /**< Shortcut the serializable map iterator */ - typedef t_object_count_map::const_iterator const_iterator; /**< Shortcut the serializable map const_iterator */ - - /** - * Creates an instance of the object_deleter - */ - object_deleter() { } - - ~object_deleter() { } - - /** - * Checks wether the given serializable is deletable. - * - * @param proxy The object_proxy to be checked. - * @return True if the serializable could be deleted. - */ - template - bool is_deletable(object_proxy *proxy, T *o); - - /** - * Checks wether the given object_container is deletable. - * - * @param ovector The object_container to be checked. - * @return True if the object_container could be deleted. - */ -// bool is_deletable(object_container &oc); - - /** - * @brief Returns the first deletable serializable. - * - * If the check was made and was successful this - * returns the first deletable serializable. - */ - iterator begin(); - - /** - * @brief Returns the first deletable serializable. - * - * If the check was made and was successful this - * returns the last deletable serializable. - */ - iterator end(); - - template - void serialize(T &x) { oos::access::serialize(*this, x); } - - template - void serialize(const char *, T &) { } - void serialize(const char *, char *, size_t) { } - - template - void serialize(const char *, belongs_to &x, cascade_type cascade); - template - void serialize(const char *, has_one &x, cascade_type cascade); - template class C> - void serialize(const char *, basic_has_many &, const char *, const char *); - template - void serialize(const char *id, identifier &x); - - bool check_object_count_map() const; - -private: - t_object_count_map object_count_map; -}; - -template < class T, template < class ... > class ON_ATTACH > -class node_analyzer { -public: - node_analyzer(prototype_node &node, const ON_ATTACH &on_attach) - : node_(node) - , on_attach_(on_attach) - { } - - ~node_analyzer() { } - - template - void serialize(V &x); - template - void serialize(const char *, V &) { } - void serialize(const char *, char *, size_t) { } - template - void serialize(const char *id, belongs_to &x, cascade_type); - template - void serialize(const char *id, has_one &x, cascade_type); - template class C> - void serialize(const char *, has_many &, const char *, const char *); - -private: - prototype_node &node_; - ON_ATTACH on_attach_; -}; - -struct basic_on_attach {}; - -template < class T > -struct null_on_attach : public basic_on_attach -{ - null_on_attach() {} - template < class V > - null_on_attach(const null_on_attach &) {} - null_on_attach& operator=(const null_on_attach &) { return *this; } - template < class V > - null_on_attach& operator=(const null_on_attach &) { return *this; } - - void operator()(prototype_node*) const {} -}; - } /// @endcond @@ -1156,9 +952,9 @@ void node_analyzer::serialize(V &x) template class ON_ATTACH> template -void node_analyzer::serialize(const char *, belongs_to &, cascade_type) +void node_analyzer::serialize(const char *id, belongs_to &, cascade_type) { - // find + node_.register_belongs_to(std::type_index(typeid(V)), id); } template class ON_ATTACH> diff --git a/include/oos/object/prototype_node.hpp b/include/oos/object/prototype_node.hpp index 52dcc5073..3e4dae12a 100644 --- a/include/oos/object/prototype_node.hpp +++ b/include/oos/object/prototype_node.hpp @@ -47,6 +47,10 @@ namespace oos { class object_store; class object_proxy; +namespace detail { +template < class T, template class C, class Enabled > +class has_many_inserter; +} /** * @class prototype_node * @brief Holds the prototype of a concrete serializable. @@ -68,6 +72,9 @@ class OOS_OBJECT_API prototype_node prototype_node(const prototype_node&) = delete; prototype_node& operator=(const prototype_node&) = delete; +public: + typedef std::unordered_map relation_map; + public: prototype_node(); @@ -285,6 +292,8 @@ class OOS_OBJECT_API prototype_node */ object_proxy* find_proxy(const std::shared_ptr &pk); + void register_belongs_to(const std::type_index &tindex, const std::string &field); + private: /** @@ -317,6 +326,10 @@ class OOS_OBJECT_API prototype_node friend class const_object_view_iterator; template < class T > friend class object_view_iterator; + template < class T, template class C > + friend class has_many; + template < class T, template class C, class Enabled > + friend class detail::has_many_inserter; object_store *tree_ = nullptr; /**< The prototype tree to which the node belongs */ @@ -349,6 +362,10 @@ class OOS_OBJECT_API prototype_node * a primary key prototype to clone from */ std::unique_ptr id_; + + relation_map belongs_to_map_; + relation_map has_one_map_; + relation_map has_many_map_; }; } diff --git a/src/object/CMakeLists.txt b/src/object/CMakeLists.txt index 41b3eabe1..d3040f9d6 100644 --- a/src/object/CMakeLists.txt +++ b/src/object/CMakeLists.txt @@ -50,7 +50,7 @@ SET(HEADER ${CMAKE_SOURCE_DIR}/include/oos/object/has_many_item.hpp ${CMAKE_SOURCE_DIR}/include/oos/object/basic_has_many_item.hpp ${CMAKE_SOURCE_DIR}/include/oos/object/identifier_proxy_map.hpp - ${CMAKE_SOURCE_DIR}/include/oos/object/object_proxy_accessor.hpp ../../include/oos/object/belongs_to.hpp ../../include/oos/object/object_holder_type.hpp) + ${CMAKE_SOURCE_DIR}/include/oos/object/object_proxy_accessor.hpp ../../include/oos/object/belongs_to.hpp ../../include/oos/object/object_holder_type.hpp ../../include/oos/object/object_inserter.hpp ../../include/oos/object/object_deleter.hpp ../../include/oos/object/node_analyzer.hpp) ADD_LIBRARY(oos-object SHARED ${SOURCES} ${HEADER}) diff --git a/src/object/prototype_node.cpp b/src/object/prototype_node.cpp index 178061983..c4d075300 100644 --- a/src/object/prototype_node.cpp +++ b/src/object/prototype_node.cpp @@ -359,21 +359,6 @@ std::type_index prototype_node::type_index() const return type_index_; } -//void prototype_node::register_foreign_key(const char *id, const std::shared_ptr &foreign_key) -//{ -// foreign_keys.insert(std::make_pair(id, foreign_key)); -//} - -//void prototype_node::register_relation(const char *type, prototype_node *node, const char *id) -//{ -// relations.insert(std::make_pair(type, std::make_pair(node, id))); -//} - -//void prototype_node::prepare_foreign_key(prototype_node *master_node, const char *id) -//{ -// foreign_key_ids.push_back(std::make_pair(master_node, id)); -//} - object_proxy *prototype_node::find_proxy(const std::shared_ptr &pk) { detail::t_identifier_map::iterator i = std::find_if(id_map_.begin(), id_map_.end(), [pk](const detail::t_identifier_map::value_type &x) { @@ -383,6 +368,11 @@ object_proxy *prototype_node::find_proxy(const std::shared_ptr return (i != id_map_.end() ? i->second : nullptr); } +void prototype_node::register_belongs_to(const std::type_index &tindex, const std::string &field) +{ + belongs_to_map_.insert(std::make_pair(tindex, field)); +} + /* * adjust the marker of all predeccessor nodes * self and last marker From 963bc7fd5517ac86125fbb3d2599fa3d8fbd4de8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Mon, 9 Jan 2017 22:39:46 +0100 Subject: [PATCH 09/61] belongs to progress --- include/oos/object/has_many_vector.hpp | 3 ++- test/Item.hpp | 2 +- test/object/ObjectStoreTestUnit.cpp | 4 ++-- test/object/ObjectStoreTestUnit.hpp | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/include/oos/object/has_many_vector.hpp b/include/oos/object/has_many_vector.hpp index bd3ad5a40..5c0b7d25c 100644 --- a/include/oos/object/has_many_vector.hpp +++ b/include/oos/object/has_many_vector.hpp @@ -268,6 +268,7 @@ class has_many_iterator friend class basic_has_many; friend class object_serializer; friend class detail::object_inserter; + friend class detail::object_deleter; relation_type relation_item() const { return *iter_; } @@ -324,12 +325,12 @@ class const_has_many_iterator typedef const_has_many_iterator_traits traits; typedef typename traits::item_type item_type; typedef typename traits::internal_type internal_type; - typedef typename traits::relation_type relation_type; typedef typename traits::container_type container_type; public: typedef const_has_many_iterator self; /**< Shortcut value self */ typedef typename traits::value_type value_type; /**< Shortcut value type */ + typedef typename traits::relation_type relation_type; typedef typename traits::difference_type difference_type; /**< Shortcut to the difference type*/ typedef typename traits::container_iterator container_iterator; /**< Shortcut to the internal container iterator */ typedef typename traits::const_container_iterator const_container_iterator; /**< Shortcut to the internal const container iterator */ diff --git a/test/Item.hpp b/test/Item.hpp index 855a771ce..a5d9b8161 100644 --- a/test/Item.hpp +++ b/test/Item.hpp @@ -354,7 +354,7 @@ class employee : public person void serialize(SERIALIZER &serializer) { serializer.serialize(*oos::base_class(this)); - serializer.serialize("department", department_); + serializer.serialize("department", department_, oos::cascade_type::ALL); } oos::object_ptr dep() { return department_; } diff --git a/test/object/ObjectStoreTestUnit.cpp b/test/object/ObjectStoreTestUnit.cpp index 90650705b..7fa164bd6 100644 --- a/test/object/ObjectStoreTestUnit.cpp +++ b/test/object/ObjectStoreTestUnit.cpp @@ -16,7 +16,7 @@ using namespace std; ObjectStoreTestUnit::ObjectStoreTestUnit() : unit_test("store", "ObjectStore Test Unit") { - add_test("version", std::bind(&ObjectStoreTestUnit::version_test, this), "test oos version"); + add_test("version", std::bind(&ObjectStoreTestUnit::test_version, this), "test oos version"); add_test("optr", std::bind(&ObjectStoreTestUnit::optr_test, this), "test optr behaviour"); add_test("expression", std::bind(&ObjectStoreTestUnit::expression_test, this), "test object expressions"); add_test("set", std::bind(&ObjectStoreTestUnit::set_test, this), "access object values via set interface"); @@ -101,7 +101,7 @@ struct item_counter : public std::unary_function Date: Tue, 10 Jan 2017 11:44:53 +0100 Subject: [PATCH 10/61] split object-inserter, deleter and node analyzer into seperate files --- include/oos/object/node_analyzer.tpp | 61 ++++++ include/oos/object/object_deleter.tpp | 90 +++++++++ include/oos/object/object_inserter.tpp | 120 ++++++++++++ include/oos/object/object_store.hpp | 250 +------------------------ src/object/CMakeLists.txt | 13 +- src/object/object_deleter.cpp | 40 ++++ src/object/object_inserter.cpp | 20 ++ src/object/object_store.cpp | 68 ------- 8 files changed, 346 insertions(+), 316 deletions(-) create mode 100644 include/oos/object/node_analyzer.tpp create mode 100644 include/oos/object/object_deleter.tpp create mode 100644 include/oos/object/object_inserter.tpp create mode 100644 src/object/object_deleter.cpp create mode 100644 src/object/object_inserter.cpp diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp new file mode 100644 index 000000000..3cb3c5958 --- /dev/null +++ b/include/oos/object/node_analyzer.tpp @@ -0,0 +1,61 @@ +#include "oos/object/node_analyzer.hpp" +#include "oos/object/prototype_iterator.hpp" +#include "oos/object/object_store.hpp" + +namespace oos { +namespace detail { + +template class ON_ATTACH> +template +void node_analyzer::serialize(V &x) +{ + oos::access::serialize(*this, x); +} + +template class ON_ATTACH> +template +void node_analyzer::serialize(const char *id, belongs_to &, cascade_type) +{ + node_.register_belongs_to(std::type_index(typeid(V)), id); +} + +template class ON_ATTACH> +template +void node_analyzer::serialize(const char *, has_one &x, cascade_type) +{ + prototype_iterator node = node_.tree()->find(x.type()); + if (node == node_.tree()->end()) { + // if there is no such prototype node + // prepare insertion of new node + node = node_.tree()->template prepare_attach(); + } else if (!node->has_primary_key()) { + throw_object_exception("serializable of type '" << x.type() << "' has no primary key"); + } +} + +template class ON_ATTACH> +template class C> +void node_analyzer::serialize(const char *id, has_many &, const char *, const char *) +//void node_analyzer::serialize(const char *id, has_many &x, const char */*owner_field*/, const char */*item_field*/) +{ + // item column column names +// x.owner_field(owner_field); +// x.item_field(item_field); + // attach relation table for has many relation + // check if has many item is already attached + // true: check owner and item field + // false: attach it + prototype_iterator pi = node_.tree()->find(id); + if (pi == node_.tree()->end()) { + pi = node_.tree()->template attach::item_type, ON_ATTACH>(id, false, nullptr, on_attach_); + } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { + // prototype is of type has_many_item + throw_object_exception("many to many relations are not supported by now"); + } else { + // throw exception + throw_object_exception("prototype already inserted: " << pi->type()); + } +} + +} +} \ No newline at end of file diff --git a/include/oos/object/object_deleter.tpp b/include/oos/object/object_deleter.tpp new file mode 100644 index 000000000..425a0c895 --- /dev/null +++ b/include/oos/object/object_deleter.tpp @@ -0,0 +1,90 @@ +#include "oos/object/object_deleter.hpp" +#include "oos/object/object_store.hpp" +namespace oos { +namespace detail { + +template +void object_deleter::t_object_count::remove_object(object_proxy *proxy, bool notify) +{ + proxy->ostore()->remove(proxy, notify, false); +} + +template +bool object_deleter::is_deletable(object_proxy *proxy, T *o) { + object_count_map.clear(); + object_count_map.insert(std::make_pair(proxy->id(), t_object_count(proxy, false, (T*)proxy->obj()))); + + // start collecting information + oos::access::serialize(*this, *o); + + return check_object_count_map(); +} + +template +void object_deleter::serialize(const char *, belongs_to &x, cascade_type cascade) { + if (!x.ptr()) { + return; + } + std::pair ret = object_count_map.insert( + std::make_pair(x.proxy_->id(), t_object_count(x.proxy_, true, (T*)x.proxy_->obj())) + ); + --ret.first->second.reference_counter; + if (cascade & cascade_type::REMOVE) { + ret.first->second.ignore = false; + oos::access::serialize(*this, *(T*)x.ptr()); + } +} + +template +void object_deleter::serialize(const char *, has_one &x, cascade_type cascade) { + if (!x.ptr()) { + return; + } + std::pair ret = object_count_map.insert( + std::make_pair(x.proxy_->id(), t_object_count(x.proxy_, true, (T*)x.proxy_->obj())) + ); + --ret.first->second.reference_counter; + if (cascade & cascade_type::REMOVE) { + ret.first->second.ignore = false; + oos::access::serialize(*this, *(T*)x.ptr()); + } +} + +template class C> +void object_deleter::serialize(const char *, basic_has_many &x, const char *, const char *) +{ + typename basic_has_many::iterator first = x.begin(); + typename basic_has_many::iterator last = x.end(); + while (first != last) { + // Todo: get the real holder: on join table get has_many_item + typename basic_has_many::relation_type iptr = first.relation_item(); + ++first; + object_proxy *proxy = iptr.proxy_; + std::pair ret = object_count_map.insert( + std::make_pair(proxy->id(), t_object_count(proxy, false, (T*)proxy->obj())) + ); + /********** + * + * object is already in list and will + * be ignored on deletion so set + * ignore flag to false because this + * node must be deleted + * + **********/ + if (!ret.second && ret.first->second.ignore) { + ret.first->second.ignore = false; + } + + oos::access::serialize(*this, *iptr); + } +} + +template +void object_deleter::serialize(const char *id, identifier &x) +{ + T val = x.value(); + serialize(id, val); +} + +} +} \ No newline at end of file diff --git a/include/oos/object/object_inserter.tpp b/include/oos/object/object_inserter.tpp new file mode 100644 index 000000000..92ced2000 --- /dev/null +++ b/include/oos/object/object_inserter.tpp @@ -0,0 +1,120 @@ +#include "oos/object/object_inserter.hpp" + +namespace oos { +namespace detail { + +template +void object_inserter::insert(object_proxy *proxy, T *o, bool notify) +{ + + notify_ = notify; + + object_proxy_stack_.push(proxy); + + modified_marker_ = [](object_store &store, object_proxy *oproxy) { + store.mark_modified(oproxy); + }; + + if (proxy->obj()) { + oos::access::serialize(*this, *o); + } + object_proxy_stack_.pop(); +} + +template +void object_inserter::serialize(T &x) +{ + oos::access::serialize(*this, x); +} + +template +void object_inserter::serialize(const char *, belongs_to &x, cascade_type cascade) { + if (x.is_inserted() || (x.proxy_ && x.proxy_->obj() == nullptr)) { + return; + } + x.is_inserted_ = true; + x.cascade_ = cascade; + // object was seen by inserter stop inserting + if (!object_proxies_.insert(x.proxy_).second) { + return; + } + + if (!x.proxy_) { + return; + } + + if (x.id()) { + // do the pointer count + object_proxy_stack_.push(x.proxy_); + oos::access::serialize(*this, *(T*)x.ptr()); + object_proxy_stack_.pop(); + } else { + // new object + ostore_.insert(x.proxy_, notify_); + } + ++(*x.proxy_); +} + +template +void object_inserter::serialize(const char *, has_one &x, cascade_type cascade) { + if (x.is_inserted() || (x.proxy_ && x.proxy_->obj() == nullptr)) { + return; + } + x.is_inserted_ = true; + x.cascade_ = cascade; + // object was seen by inserter stop inserting + if (!object_proxies_.insert(x.proxy_).second) { + return; + } + + if (!x.proxy_) { + return; + } + + if (x.id()) { + // do the pointer count + object_proxy_stack_.push(x.proxy_); + oos::access::serialize(*this, *(T*)x.ptr()); + object_proxy_stack_.pop(); + } else { + // new object + ostore_.insert(x.proxy_, notify_); + } + ++(*x.proxy_); +} + +template class C> +void object_inserter::serialize(const char *, basic_has_many &x, const char*, const char*) +{ + // initialize the has many relation + // set identifier + // relation table name + // owner column name + // item column name + if (object_proxy_stack_.empty()) { + throw object_exception("no owner for has many relation"); + } + + if (x.ostore_) { + return; + } + object_proxy *proxy = object_proxy_stack_.top(); + x.owner_id_ = proxy->pk(); + x.owner_ = proxy; + x.ostore_ = &ostore_; + x.mark_modified_owner_ = modified_marker_; + + typename basic_has_many::iterator first = x.begin(); + typename basic_has_many::iterator last = x.end(); + + while (first != last) { + typename basic_has_many::relation_type i = (first++).relation_item(); + if (!i.is_inserted()) { + // item is not in store, insert it + ostore_.insert(i, false); + } + } +} + +} +} \ No newline at end of file diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index f3859091e..6a7df8424 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -943,262 +943,18 @@ object_store::iterator object_store::initialize(prototype_node *node, const ON_A namespace detail { -template class ON_ATTACH> -template < class V > -void node_analyzer::serialize(V &x) -{ - oos::access::serialize(*this, x); -} - -template class ON_ATTACH> -template -void node_analyzer::serialize(const char *id, belongs_to &, cascade_type) -{ - node_.register_belongs_to(std::type_index(typeid(V)), id); -} - -template class ON_ATTACH> -template -void node_analyzer::serialize(const char *, has_one &x, cascade_type) -{ - prototype_iterator node = node_.tree()->find(x.type()); - if (node == node_.tree()->end()) { - // if there is no such prototype node - // prepare insertion of new node - node = node_.tree()->template prepare_attach(); - } else if (!node->has_primary_key()) { - throw_object_exception("serializable of type '" << x.type() << "' has no primary key"); - } -} - -template class ON_ATTACH> -template class C> -void node_analyzer::serialize(const char *id, has_many &, const char *, const char *) -//void node_analyzer::serialize(const char *id, has_many &x, const char */*owner_field*/, const char */*item_field*/) -{ - // item column column names -// x.owner_field(owner_field); -// x.item_field(item_field); - // attach relation table for has many relation - // check if has many item is already attached - // true: check owner and item field - // false: attach it - prototype_iterator pi = node_.tree()->find(id); - if (pi == node_.tree()->end()) { - pi = node_.tree()->template attach::item_type, ON_ATTACH>(id, false, nullptr, on_attach_); - } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { - // prototype is of type has_many_item - throw_object_exception("many to many relations are not supported by now"); - } else { - // throw exception - throw_object_exception("prototype already inserted: " << pi->type()); - } -} - template < class T > void modified_marker::marker_func(object_store &store, object_proxy &proxy) { store.mark_modified(&proxy); } -template -void object_inserter::insert(object_proxy *proxy, T *o, bool notify) -{ - - notify_ = notify; - - object_proxy_stack_.push(proxy); - - modified_marker_ = [](object_store &store, object_proxy *oproxy) { - store.mark_modified(oproxy); - }; - - if (proxy->obj()) { - oos::access::serialize(*this, *o); - } - object_proxy_stack_.pop(); -} - -template -void object_inserter::serialize(T &x) -{ - oos::access::serialize(*this, x); } -template -void object_inserter::serialize(const char *, belongs_to &x, cascade_type cascade) { - if (x.is_inserted() || (x.proxy_ && x.proxy_->obj() == nullptr)) { - return; - } - x.is_inserted_ = true; - x.cascade_ = cascade; - // object was seen by inserter stop inserting - if (!object_proxies_.insert(x.proxy_).second) { - return; - } - - if (!x.proxy_) { - return; - } - - if (x.id()) { - // do the pointer count - object_proxy_stack_.push(x.proxy_); - oos::access::serialize(*this, *(T*)x.ptr()); - object_proxy_stack_.pop(); - } else { - // new object - ostore_.insert(x.proxy_, notify_); - } - ++(*x.proxy_); } -template -void object_inserter::serialize(const char *, has_one &x, cascade_type cascade) { - if (x.is_inserted() || (x.proxy_ && x.proxy_->obj() == nullptr)) { - return; - } - x.is_inserted_ = true; - x.cascade_ = cascade; - // object was seen by inserter stop inserting - if (!object_proxies_.insert(x.proxy_).second) { - return; - } - - if (!x.proxy_) { - return; - } - - if (x.id()) { - // do the pointer count - object_proxy_stack_.push(x.proxy_); - oos::access::serialize(*this, *(T*)x.ptr()); - object_proxy_stack_.pop(); - } else { - // new object - ostore_.insert(x.proxy_, notify_); - } - ++(*x.proxy_); -} - -template class C> -void object_inserter::serialize(const char *, basic_has_many &x, const char*, const char*) -{ - // initialize the has many relation - // set identifier - // relation table name - // owner column name - // item column name - if (object_proxy_stack_.empty()) { - throw object_exception("no owner for has many relation"); - } - - if (x.ostore_) { - return; - } - object_proxy *proxy = object_proxy_stack_.top(); - x.owner_id_ = proxy->pk(); - x.owner_ = proxy; - x.ostore_ = &ostore_; - x.mark_modified_owner_ = modified_marker_; - - typename basic_has_many::iterator first = x.begin(); - typename basic_has_many::iterator last = x.end(); - - while (first != last) { - typename basic_has_many::relation_type i = (first++).relation_item(); - if (!i.is_inserted()) { - // item is not in store, insert it - ostore_.insert(i, false); - } - } -} - -template -void object_deleter::t_object_count::remove_object(object_proxy *proxy, bool notify) -{ - proxy->ostore()->remove(proxy, notify, false); -} - -template -bool object_deleter::is_deletable(object_proxy *proxy, T *o) { - object_count_map.clear(); - object_count_map.insert(std::make_pair(proxy->id(), t_object_count(proxy, false, (T*)proxy->obj()))); - - // start collecting information - oos::access::serialize(*this, *o); - - return check_object_count_map(); -} - -template -void object_deleter::serialize(const char *, belongs_to &x, cascade_type cascade) { - if (!x.ptr()) { - return; - } - std::pair ret = object_count_map.insert( - std::make_pair(x.proxy_->id(), t_object_count(x.proxy_, true, (T*)x.proxy_->obj())) - ); - --ret.first->second.reference_counter; - if (cascade & cascade_type::REMOVE) { - ret.first->second.ignore = false; - oos::access::serialize(*this, *(T*)x.ptr()); - } -} - -template -void object_deleter::serialize(const char *, has_one &x, cascade_type cascade) { - if (!x.ptr()) { - return; - } - std::pair ret = object_count_map.insert( - std::make_pair(x.proxy_->id(), t_object_count(x.proxy_, true, (T*)x.proxy_->obj())) - ); - --ret.first->second.reference_counter; - if (cascade & cascade_type::REMOVE) { - ret.first->second.ignore = false; - oos::access::serialize(*this, *(T*)x.ptr()); - } -} - -template class C> -void object_deleter::serialize(const char *, basic_has_many &x, const char *, const char *) -{ - typename basic_has_many::iterator first = x.begin(); - typename basic_has_many::iterator last = x.end(); - while (first != last) { - // Todo: get the real holder: on join table get has_many_item - typename basic_has_many::relation_type iptr = first.relation_item(); - ++first; - object_proxy *proxy = iptr.proxy_; - std::pair ret = object_count_map.insert( - std::make_pair(proxy->id(), t_object_count(proxy, false, (T*)proxy->obj())) - ); - /********** - * - * object is already in list and will - * be ignored on deletion so set - * ignore flag to false because this - * node must be deleted - * - **********/ - if (!ret.second && ret.first->second.ignore) { - ret.first->second.ignore = false; - } - - oos::access::serialize(*this, *iptr); - } -} - -template -void object_deleter::serialize(const char *id, identifier &x) -{ - T val = x.value(); - serialize(id, val); -} - -} - -} +#include "oos/object/node_analyzer.tpp" +#include "oos/object/object_inserter.tpp" +#include "oos/object/object_deleter.tpp" #endif /* OBJECT_STORE_HPP */ diff --git a/src/object/CMakeLists.txt b/src/object/CMakeLists.txt index d3040f9d6..c5f968232 100644 --- a/src/object/CMakeLists.txt +++ b/src/object/CMakeLists.txt @@ -14,6 +14,8 @@ SET(SOURCES delete_action.cpp basic_has_many_item.cpp object_proxy_accessor.cpp + object_deleter.cpp + object_inserter.cpp ) SET(HEADER @@ -50,7 +52,16 @@ SET(HEADER ${CMAKE_SOURCE_DIR}/include/oos/object/has_many_item.hpp ${CMAKE_SOURCE_DIR}/include/oos/object/basic_has_many_item.hpp ${CMAKE_SOURCE_DIR}/include/oos/object/identifier_proxy_map.hpp - ${CMAKE_SOURCE_DIR}/include/oos/object/object_proxy_accessor.hpp ../../include/oos/object/belongs_to.hpp ../../include/oos/object/object_holder_type.hpp ../../include/oos/object/object_inserter.hpp ../../include/oos/object/object_deleter.hpp ../../include/oos/object/node_analyzer.hpp) + ${CMAKE_SOURCE_DIR}/include/oos/object/object_proxy_accessor.hpp + ${CMAKE_SOURCE_DIR}/include/oos/object/belongs_to.hpp + ${CMAKE_SOURCE_DIR}/include/oos/object/object_holder_type.hpp + ${CMAKE_SOURCE_DIR}/include/oos/object/object_inserter.hpp + ${CMAKE_SOURCE_DIR}/include/oos/object/object_inserter.tpp + ${CMAKE_SOURCE_DIR}/include/oos/object/object_deleter.hpp + ${CMAKE_SOURCE_DIR}/include/oos/object/object_deleter.tpp + ${CMAKE_SOURCE_DIR}/include/oos/object/node_analyzer.hpp + ${CMAKE_SOURCE_DIR}/include/oos/object/node_analyzer.tpp +) ADD_LIBRARY(oos-object SHARED ${SOURCES} ${HEADER}) diff --git a/src/object/object_deleter.cpp b/src/object/object_deleter.cpp new file mode 100644 index 000000000..921baa747 --- /dev/null +++ b/src/object/object_deleter.cpp @@ -0,0 +1,40 @@ +#include "oos/object/object_deleter.hpp" + +namespace oos { +namespace detail { + +void object_deleter::t_object_count::remove(bool notify) +{ + remove_func(proxy, notify); +} + +object_deleter::iterator object_deleter::begin() +{ + return object_count_map.begin(); +} + +object_deleter::iterator object_deleter::end() +{ + return object_count_map.end(); +} + +bool object_deleter::check_object_count_map() const +{ + // check the reference and pointer counter of collected objects + const_iterator first = object_count_map.begin(); + const_iterator last = object_count_map.end(); + while (first != last) { + if (first->second.ignore) { + ++first; + } else if (first->second.reference_counter == 0) { +// } else if (first->second.ref_count == 0 && first->second.ptr_count == 0) { + ++first; + } else { + return false; + } + } + return true; +} + +} +} diff --git a/src/object/object_inserter.cpp b/src/object/object_inserter.cpp new file mode 100644 index 000000000..61f1f94bc --- /dev/null +++ b/src/object/object_inserter.cpp @@ -0,0 +1,20 @@ +#include "oos/object/object_inserter.hpp" + +namespace oos { +namespace detail { + +object_inserter::object_inserter(object_store &ostore) + : ostore_(ostore) { } + +object_inserter::~object_inserter() { } + +void object_inserter::reset() +{ + object_proxies_.clear(); + while (!object_proxy_stack_.empty()) { + object_proxy_stack_.pop(); + } +} + +} +} diff --git a/src/object/object_store.cpp b/src/object/object_store.cpp index 2b8649265..3bb382b09 100644 --- a/src/object/object_store.cpp +++ b/src/object/object_store.cpp @@ -17,32 +17,13 @@ #include "oos/object/object_store.hpp" -#include #include -#include using namespace std; using namespace std::placeholders; namespace oos { -namespace detail { - -object_inserter::object_inserter(object_store &ostore) - : ostore_(ostore) { } - -object_inserter::~object_inserter() { } - -void object_inserter::reset() -{ - object_proxies_.clear(); - while (!object_proxy_stack_.empty()) { - object_proxy_stack_.pop(); - } -} - -} - object_store::object_store() : first_(new prototype_node) , last_(new prototype_node) @@ -407,54 +388,5 @@ bool object_store::has_transaction() const return !transactions_.empty(); } -//transaction& object_store::begin_transaction() -//{ -// transactions_.push(transaction(*this)); -// return transactions_.top(); -//} - -//transaction& object_store::begin_transaction(const std::shared_ptr &obsvr) -//{ -// transaction tr(*this, obsvr); -// tr.begin(); -// return transactions_.top(); -//} - -namespace detail { - -void object_deleter::t_object_count::remove(bool notify) -{ - remove_func(proxy, notify); -} - -object_deleter::iterator object_deleter::begin() -{ - return object_count_map.begin(); -} - -object_deleter::iterator object_deleter::end() -{ - return object_count_map.end(); -} - -bool object_deleter::check_object_count_map() const -{ - // check the reference and pointer counter of collected objects - const_iterator first = object_count_map.begin(); - const_iterator last = object_count_map.end(); - while (first != last) { - if (first->second.ignore) { - ++first; - } else if (first->second.reference_counter == 0) { -// } else if (first->second.ref_count == 0 && first->second.ptr_count == 0) { - ++first; - } else { - return false; - } - } - return true; -} - -} } From 189b911555167fb1e191eaa22ab18c9cb7855e4f Mon Sep 17 00:00:00 2001 From: zussel Date: Tue, 10 Jan 2017 17:27:04 +0100 Subject: [PATCH 11/61] belongs_to progress --- include/oos/object/attribute_serializer.hpp | 88 ++++++++++++++++----- include/oos/object/generic_access.hpp | 4 +- include/oos/object/has_many_vector.hpp | 3 + include/oos/object/node_analyzer.tpp | 20 ++++- include/oos/object/prototype_node.hpp | 22 +++++- src/object/prototype_node.cpp | 9 ++- test/object/ObjectStoreTestUnit.cpp | 65 ++++++++------- test/object/ObjectStoreTestUnit.hpp | 28 +++---- 8 files changed, 167 insertions(+), 72 deletions(-) diff --git a/include/oos/object/attribute_serializer.hpp b/include/oos/object/attribute_serializer.hpp index 3509889f9..c5bf49dd1 100644 --- a/include/oos/object/attribute_serializer.hpp +++ b/include/oos/object/attribute_serializer.hpp @@ -67,8 +67,6 @@ class attribute_reader : public basic_attribute_serializer , from_(from) {} - ~attribute_reader() {} - template < class V > void serialize(const char *id, V &to, typename std::enable_if< std::is_arithmetic::value && std::is_arithmetic::value >::type* = 0) { @@ -100,25 +98,42 @@ class attribute_reader : public basic_attribute_serializer const T &from_; }; -//template < class T > -//class attribute_reader::value || std::is_base_of::value>::type> -//{ -//public: -// attribute_reader(const std::string &id, const T &from) -// : basic_attribute_serializer(id) -// , from_(from) -// {} -// -// ~attribute_reader() {} -// -// template < class V > -// void serialize(const char *id, ) -// void serialize(const char *id, char *x) { -// -// } -//private: -// const T &from_; -//}; +template < class T > +class attribute_reader> : public basic_attribute_serializer +{ +public: + attribute_reader(const std::string &id, const object_ptr &from) + : basic_attribute_serializer(id) + , from_(from) + {} + + template < class V > + void serialize(V &obj) + { + access::serialize(*this, obj); + } + + template < class V > + void serialize(const char *, V &) {} + void serialize(const char *, char*, size_t) {} + + template < class V > + void serialize(const char *, belongs_to &x, cascade_type, typename std::enable_if::value>::type* = 0) + { + x = from_; + } + template < class V > + void serialize(const char *, has_one &x, cascade_type, typename std::enable_if::value>::type* = 0) + { + x = from_; + } + + template < class HAS_MANY > + void serialize(const char *, HAS_MANY &, const char *, const char *) {} + +private: + const object_ptr &from_; +}; template <> class attribute_reader : public basic_attribute_serializer @@ -222,6 +237,37 @@ class attribute_writer : public basic_attribute_serializer size_t precision_; }; +template < class T > +class attribute_writer> : public basic_attribute_serializer +{ +public: + attribute_writer(const std::string &id, object_ptr &to) + : basic_attribute_serializer(id) + , to_(to) + {} + + template < class V > + void serialize(const char *, V &) {} + void serialize(const char *, char*, size_t) {} + + template < class V > + void serialize(const char *, belongs_to &x, cascade_type, typename std::enable_if::value>::type* = 0) + { + to_ = x; + } + template < class V > + void serialize(const char *, has_one &x, cascade_type, typename std::enable_if::value>::type* = 0) + { + to_ = x; + } + + template < class HAS_MANY > + void serialize(const char *, HAS_MANY &, const char *, const char *) {} + +private: + object_ptr &to_; +}; + template <> class attribute_writer : public basic_attribute_serializer { diff --git a/include/oos/object/generic_access.hpp b/include/oos/object/generic_access.hpp index 04ded72eb..fe28c84f5 100644 --- a/include/oos/object/generic_access.hpp +++ b/include/oos/object/generic_access.hpp @@ -24,7 +24,7 @@ namespace oos { * @return True if the operation succeeds. */ -template < typename O, class T, typename std::enable_if::value>::type* = nullptr > +template < typename O, class T > bool set(O *obj, const std::string &name, const T &val) { return set(*obj, name, val); @@ -42,7 +42,7 @@ bool set(O *obj, const std::string &name, const T &val) * @param val The new value for the member. * @return True if the operation succeeds. */ -template < typename O, class T, typename std::enable_if::value>::type* = nullptr > +template < typename O, class T > bool set(O &obj, const std::string &name, const T &val) { attribute_reader reader(name, val); diff --git a/include/oos/object/has_many_vector.hpp b/include/oos/object/has_many_vector.hpp index 5c0b7d25c..36bbfd228 100644 --- a/include/oos/object/has_many_vector.hpp +++ b/include/oos/object/has_many_vector.hpp @@ -7,6 +7,7 @@ #include "oos/object/basic_has_many.hpp" #include "oos/object/object_store.hpp" +#include "oos/object/generic_access.hpp" #include @@ -568,6 +569,8 @@ class has_many_inserter::value> auto i = foreign_node_->belongs_to_map_.find(owner.node()->type_index()); if (i != foreign_node_->belongs_to_map_.end()) { store.insert(rtype->value()); + // set owner into value + i->second.set_owner(rtype->value().ptr(), i->second.name, &owner); } else { store.insert(rtype); mark_modified_owner(store, &owner); diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index 3cb3c5958..37826ba85 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -1,6 +1,7 @@ #include "oos/object/node_analyzer.hpp" #include "oos/object/prototype_iterator.hpp" #include "oos/object/object_store.hpp" +#include "oos/object/generic_access.hpp" namespace oos { namespace detail { @@ -14,9 +15,23 @@ void node_analyzer::serialize(V &x) template class ON_ATTACH> template -void node_analyzer::serialize(const char *id, belongs_to &, cascade_type) +void node_analyzer::serialize(const char *id, belongs_to &x, cascade_type) { - node_.register_belongs_to(std::type_index(typeid(V)), id); + prototype_iterator node = node_.tree()->find(x.type()); + if (node != node_.tree()->end()) { + // check if created from has_many + // check if node has_many relation for id (id == tablename) + auto i = node->has_many_map_.find(id); + if (i != node->has_many_map_.end()) { + // yes, node found! + // Todo: check if node is for has many item + // detach has_many_item node + node_.tree()->detach(i->second); + } + } + node_.register_belongs_to(std::type_index(typeid(V)), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { + oos::set(static_cast(obj), field, object_ptr(owner)); + })); } template class ON_ATTACH> @@ -48,6 +63,7 @@ void node_analyzer::serialize(const char *id, has_many &, c prototype_iterator pi = node_.tree()->find(id); if (pi == node_.tree()->end()) { pi = node_.tree()->template attach::item_type, ON_ATTACH>(id, false, nullptr, on_attach_); + node_.register_has_many(node_.type(), pi.get()); } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item throw_object_exception("many to many relations are not supported by now"); diff --git a/include/oos/object/prototype_node.hpp b/include/oos/object/prototype_node.hpp index 3e4dae12a..74cdcfcd6 100644 --- a/include/oos/object/prototype_node.hpp +++ b/include/oos/object/prototype_node.hpp @@ -50,6 +50,8 @@ class object_proxy; namespace detail { template < class T, template class C, class Enabled > class has_many_inserter; +template < class T, template < class ... > class ON_ATTACH > +class node_analyzer; } /** * @class prototype_node @@ -73,7 +75,18 @@ class OOS_OBJECT_API prototype_node prototype_node& operator=(const prototype_node&) = delete; public: - typedef std::unordered_map relation_map; + struct relation_info + { + typedef std::function set_owner_func; + relation_info(const std::string &n, const set_owner_func &func) + : name(n), set_owner(func) + {} + std::string name; + std::function set_owner; + }; + + typedef std::unordered_map relation_map; + typedef std::unordered_map has_many_map; public: prototype_node(); @@ -292,7 +305,8 @@ class OOS_OBJECT_API prototype_node */ object_proxy* find_proxy(const std::shared_ptr &pk); - void register_belongs_to(const std::type_index &tindex, const std::string &field); + void register_belongs_to(const std::type_index &tindex, const prototype_node::relation_info &relation_info); + void register_has_many(const std::string &field, prototype_node *node); private: @@ -330,6 +344,8 @@ class OOS_OBJECT_API prototype_node friend class has_many; template < class T, template class C, class Enabled > friend class detail::has_many_inserter; + template < class T, template < class ... > class ON_ATTACH > + friend class detail::node_analyzer; object_store *tree_ = nullptr; /**< The prototype tree to which the node belongs */ @@ -365,7 +381,7 @@ class OOS_OBJECT_API prototype_node relation_map belongs_to_map_; relation_map has_one_map_; - relation_map has_many_map_; + has_many_map has_many_map_; }; } diff --git a/src/object/prototype_node.cpp b/src/object/prototype_node.cpp index c4d075300..2aa480d57 100644 --- a/src/object/prototype_node.cpp +++ b/src/object/prototype_node.cpp @@ -368,9 +368,14 @@ object_proxy *prototype_node::find_proxy(const std::shared_ptr return (i != id_map_.end() ? i->second : nullptr); } -void prototype_node::register_belongs_to(const std::type_index &tindex, const std::string &field) +void prototype_node::register_belongs_to(const std::type_index &tindex, const prototype_node::relation_info &relation_info) { - belongs_to_map_.insert(std::make_pair(tindex, field)); + belongs_to_map_.insert(std::make_pair(tindex, relation_info)); +} + +void prototype_node::register_has_many(const std::string &field, prototype_node *node) +{ + has_many_map_.insert(std::make_pair(field, node)); } /* diff --git a/test/object/ObjectStoreTestUnit.cpp b/test/object/ObjectStoreTestUnit.cpp index 7fa164bd6..95bb2813f 100644 --- a/test/object/ObjectStoreTestUnit.cpp +++ b/test/object/ObjectStoreTestUnit.cpp @@ -17,22 +17,22 @@ ObjectStoreTestUnit::ObjectStoreTestUnit() : unit_test("store", "ObjectStore Test Unit") { add_test("version", std::bind(&ObjectStoreTestUnit::test_version, this), "test oos version"); - add_test("optr", std::bind(&ObjectStoreTestUnit::optr_test, this), "test optr behaviour"); - add_test("expression", std::bind(&ObjectStoreTestUnit::expression_test, this), "test object expressions"); - add_test("set", std::bind(&ObjectStoreTestUnit::set_test, this), "access object values via set interface"); - add_test("get", std::bind(&ObjectStoreTestUnit::get_test, this), "access object values via get interface"); + add_test("optr", std::bind(&ObjectStoreTestUnit::test_optr, this), "test optr behaviour"); + add_test("expression", std::bind(&ObjectStoreTestUnit::test_expression, this), "test object expressions"); + add_test("set", std::bind(&ObjectStoreTestUnit::test_set, this), "access object values via set interface"); + add_test("get", std::bind(&ObjectStoreTestUnit::test_get, this), "access object values via get interface"); add_test("serializer", std::bind(&ObjectStoreTestUnit::test_serializer, this), "serializer test"); add_test("identifier_serializer", std::bind(&ObjectStoreTestUnit::test_identifier_serializer, this), "identifier serializer test"); - add_test("reference_counter", std::bind(&ObjectStoreTestUnit::reference_counter, this), "reference counter test"); - add_test("simple", std::bind(&ObjectStoreTestUnit::simple_object, this), "create and delete one object"); - add_test("with_sub", std::bind(&ObjectStoreTestUnit::object_with_sub_object, this), "create and delete object with sub object"); - add_test("multiple_simple", std::bind(&ObjectStoreTestUnit::multiple_simple_objects, this), "create and delete multiple objects"); - add_test("multiple_object_with_sub", std::bind(&ObjectStoreTestUnit::multiple_object_with_sub_objects, this), "create and delete multiple objects with sub object"); - add_test("delete", std::bind(&ObjectStoreTestUnit::delete_object, this), "object deletion test"); - add_test("hierarchy", std::bind(&ObjectStoreTestUnit::hierarchy, this), "object hierarchy test"); - add_test("view", std::bind(&ObjectStoreTestUnit::view_test, this), "object view test"); - add_test("clear", std::bind(&ObjectStoreTestUnit::clear_test, this), "object store clear test"); - add_test("generic", std::bind(&ObjectStoreTestUnit::generic_test, this), "generic object access test"); + add_test("reference_counter", std::bind(&ObjectStoreTestUnit::test_reference_counter, this), "reference counter test"); + add_test("simple", std::bind(&ObjectStoreTestUnit::test_simple_object, this), "create and delete one object"); + add_test("with_sub", std::bind(&ObjectStoreTestUnit::test_object_with_sub_object, this), "create and delete object with sub object"); + add_test("multiple_simple", std::bind(&ObjectStoreTestUnit::test_multiple_simple_objects, this), "create and delete multiple objects"); + add_test("multiple_object_with_sub", std::bind(&ObjectStoreTestUnit::test_multiple_object_with_sub_objects, this), "create and delete multiple objects with sub object"); + add_test("delete", std::bind(&ObjectStoreTestUnit::test_delete_object, this), "object deletion test"); + add_test("hierarchy", std::bind(&ObjectStoreTestUnit::test_hierarchy, this), "object hierarchy test"); + add_test("view", std::bind(&ObjectStoreTestUnit::test_view, this), "object view test"); + add_test("clear", std::bind(&ObjectStoreTestUnit::test_clear, this), "object store clear test"); + add_test("generic", std::bind(&ObjectStoreTestUnit::test_generic, this), "generic object access test"); add_test("structure", std::bind(&ObjectStoreTestUnit::test_structure, this), "object transient structure test"); add_test("structure_cyclic", std::bind(&ObjectStoreTestUnit::test_structure_cyclic, this), "object transient cyclic structure test"); add_test("structure_container", std::bind(&ObjectStoreTestUnit::test_structure_container, this), "object transient container structure test"); @@ -113,7 +113,7 @@ ObjectStoreTestUnit::test_version() } -void ObjectStoreTestUnit::optr_test() +void ObjectStoreTestUnit::test_optr() { typedef object_ptr item_ptr; @@ -131,7 +131,7 @@ void ObjectStoreTestUnit::optr_test() } void -ObjectStoreTestUnit::expression_test() +ObjectStoreTestUnit::test_expression() { typedef object_ptr > object_item_ptr; typedef object_ptr item_ptr; @@ -308,7 +308,7 @@ void ObjectStoreTestUnit::test_identifier_serializer() } } -void ObjectStoreTestUnit::reference_counter() +void ObjectStoreTestUnit::test_reference_counter() { Item *i = new Item("Item", 7); @@ -341,7 +341,7 @@ void ObjectStoreTestUnit::reference_counter() void -ObjectStoreTestUnit::set_test() +ObjectStoreTestUnit::test_set() { oos::date dt(15, 9, 1972); oos::time t(2008, 12, 27, 13, 6, 57, 4711); @@ -392,7 +392,7 @@ ObjectStoreTestUnit::set_test() } void -ObjectStoreTestUnit::get_test() +ObjectStoreTestUnit::test_get() { test_pair c('c'); test_pair b(true); @@ -461,7 +461,7 @@ ObjectStoreTestUnit::get_test() } void -ObjectStoreTestUnit::simple_object() +ObjectStoreTestUnit::test_simple_object() { Item *a = ostore_.create(); @@ -479,7 +479,7 @@ ObjectStoreTestUnit::simple_object() } void -ObjectStoreTestUnit::object_with_sub_object() +ObjectStoreTestUnit::test_object_with_sub_object() { ObjectItem *s = ostore_.create>(); @@ -502,7 +502,7 @@ ObjectStoreTestUnit::object_with_sub_object() } void -ObjectStoreTestUnit::multiple_simple_objects() +ObjectStoreTestUnit::test_multiple_simple_objects() { typedef object_ptr item_ptr; @@ -523,7 +523,7 @@ ObjectStoreTestUnit::multiple_simple_objects() } void -ObjectStoreTestUnit::multiple_object_with_sub_objects() +ObjectStoreTestUnit::test_multiple_object_with_sub_objects() { typedef object_ptr > ows_ptr; @@ -544,7 +544,7 @@ ObjectStoreTestUnit::multiple_object_with_sub_objects() } void -ObjectStoreTestUnit::delete_object() +ObjectStoreTestUnit::test_delete_object() { typedef ObjectItem TestItem; typedef object_ptr test_item_ptr; @@ -577,7 +577,7 @@ ObjectStoreTestUnit::delete_object() } void -ObjectStoreTestUnit::hierarchy() +ObjectStoreTestUnit::test_hierarchy() { ostore_.attach("ITEM_A"); ostore_.attach("ITEM_B"); @@ -673,7 +673,7 @@ ObjectStoreTestUnit::hierarchy() } void -ObjectStoreTestUnit::view_test() +ObjectStoreTestUnit::test_view() { for (int i = 0; i < 10; ++i) { std::stringstream str; @@ -699,7 +699,7 @@ ObjectStoreTestUnit::view_test() } void -ObjectStoreTestUnit::clear_test() +ObjectStoreTestUnit::test_clear() { for (int i = 0; i < 10; ++i) { std::stringstream str; @@ -735,7 +735,7 @@ ObjectStoreTestUnit::clear_test() } void -ObjectStoreTestUnit::generic_test() +ObjectStoreTestUnit::test_generic() { test_pair c('c'); test_pair b(true); @@ -829,6 +829,15 @@ ObjectStoreTestUnit::generic_test() oos::set(*item, "val_time", timeval.expected); oos::get(*item, "val_time", timeval.result); UNIT_ASSERT_EQUAL(timeval.result, timeval.expected, "not expected result value"); + + master m1("master 1"); + + object_ptr c1(new child("child 1")); + object_ptr child_result; + + oos::set(m1, "child", c1); + oos::get(m1, "child", child_result); + UNIT_ASSERT_EQUAL(c1->name, child_result->name, "not expected result value"); } void ObjectStoreTestUnit::test_structure() diff --git a/test/object/ObjectStoreTestUnit.hpp b/test/object/ObjectStoreTestUnit.hpp index 72cb0bb0f..8a34bb599 100644 --- a/test/object/ObjectStoreTestUnit.hpp +++ b/test/object/ObjectStoreTestUnit.hpp @@ -17,22 +17,22 @@ class ObjectStoreTestUnit : public oos::unit_test virtual void finalize(); void test_version(); - void optr_test(); - void expression_test(); - void set_test(); - void get_test(); + void test_optr(); + void test_expression(); + void test_set(); + void test_get(); void test_serializer(); void test_identifier_serializer(); - void reference_counter(); - void simple_object(); - void object_with_sub_object(); - void multiple_simple_objects(); - void multiple_object_with_sub_objects(); - void delete_object(); - void hierarchy(); - void view_test(); - void clear_test(); - void generic_test(); + void test_reference_counter(); + void test_simple_object(); + void test_object_with_sub_object(); + void test_multiple_simple_objects(); + void test_multiple_object_with_sub_objects(); + void test_delete_object(); + void test_hierarchy(); + void test_view(); + void test_clear(); + void test_generic(); void test_structure(); void test_structure_cyclic(); void test_structure_container(); From 5f507b8ed23c019ca5beb7beb13f8978a4b79fb2 Mon Sep 17 00:00:00 2001 From: zussel Date: Wed, 11 Jan 2017 16:09:30 +0100 Subject: [PATCH 12/61] belongs_to progress --- include/oos/object/attribute_serializer.hpp | 35 +++++++++++++++++++++ include/oos/object/delete_action.hpp | 1 - include/oos/object/generic_access.hpp | 15 ++++++++- include/oos/object/has_many_vector.hpp | 25 +-------------- include/oos/object/node_analyzer.tpp | 5 +++ include/oos/object/object_holder.hpp | 1 + include/oos/object/object_inserter.hpp | 4 +-- include/oos/object/object_inserter.tpp | 3 ++ include/oos/object/prototype_node.hpp | 5 +++ src/object/object_holder.cpp | 2 ++ src/object/object_proxy.cpp | 2 +- src/object/prototype_node.cpp | 10 ++++++ test/object/ObjectStoreTestUnit.cpp | 2 +- 13 files changed, 80 insertions(+), 30 deletions(-) diff --git a/include/oos/object/attribute_serializer.hpp b/include/oos/object/attribute_serializer.hpp index c5bf49dd1..cd3303fd1 100644 --- a/include/oos/object/attribute_serializer.hpp +++ b/include/oos/object/attribute_serializer.hpp @@ -121,11 +121,13 @@ class attribute_reader> : public basic_attribute_serializer void serialize(const char *, belongs_to &x, cascade_type, typename std::enable_if::value>::type* = 0) { x = from_; + this->success_ = true; } template < class V > void serialize(const char *, has_one &x, cascade_type, typename std::enable_if::value>::type* = 0) { x = from_; + this->success_ = true; } template < class HAS_MANY > @@ -135,6 +137,39 @@ class attribute_reader> : public basic_attribute_serializer const object_ptr &from_; }; +template < class T > +class has_many_attribute_reader : public basic_attribute_serializer +{ +public: + has_many_attribute_reader(const std::string &id, const object_ptr &from) + : basic_attribute_serializer(id) + , from_(from) + {} + + template < class V > + void serialize(V &obj) + { + access::serialize(*this, obj); + } + + template < class V > + void serialize(const char *, V &) {} + void serialize(const char *, char*, size_t) {} + + template < class HAS_ONE > + void serialize(const char *, HAS_ONE &, cascade_type) { } + + template class C> + void serialize(const char *, has_many &x, const char *, const char *, typename std::enable_if::value>::type* = 0) + { + x.push_back(from_); + this->success_ = true; + } + +private: + const T &from_; +}; + template <> class attribute_reader : public basic_attribute_serializer { diff --git a/include/oos/object/delete_action.hpp b/include/oos/object/delete_action.hpp index 702f0c3de..0af10e599 100644 --- a/include/oos/object/delete_action.hpp +++ b/include/oos/object/delete_action.hpp @@ -103,7 +103,6 @@ class OOS_OBJECT_API delete_action : public action template < class T, class S > static void restore_delete(byte_buffer &buffer, delete_action *act, object_store *store, S &serializer) { - // TODO: pass object store instance // check if there is an serializable with id in // serializable store object_proxy *proxy = action::find_proxy(store, act->id()); diff --git a/include/oos/object/generic_access.hpp b/include/oos/object/generic_access.hpp index fe28c84f5..67da41cec 100644 --- a/include/oos/object/generic_access.hpp +++ b/include/oos/object/generic_access.hpp @@ -23,13 +23,18 @@ namespace oos { * @param val The new value for the member. * @return True if the operation succeeds. */ - template < typename O, class T > bool set(O *obj, const std::string &name, const T &val) { return set(*obj, name, val); } +template < typename O, class T > +bool append(O *obj, const std::string &name, const T &val) +{ + return append(*obj, name, val); +} + /** * Sets a value of an object member identified by * the given name. The object is passed by reference. @@ -50,6 +55,14 @@ bool set(O &obj, const std::string &name, const T &val) return reader.success(); } +template < typename O, class T > +bool append(O &obj, const std::string &name, const T &val) +{ + has_many_attribute_reader reader(name, val); + oos::access::serialize(reader, obj); + return reader.success(); +} + /** * Sets string value of a member identified by * the given name. The value is passed as a diff --git a/include/oos/object/has_many_vector.hpp b/include/oos/object/has_many_vector.hpp index 36bbfd228..a1120f56d 100644 --- a/include/oos/object/has_many_vector.hpp +++ b/include/oos/object/has_many_vector.hpp @@ -573,9 +573,8 @@ class has_many_inserter::value> i->second.set_owner(rtype->value().ptr(), i->second.name, &owner); } else { store.insert(rtype); - mark_modified_owner(store, &owner); } - + mark_modified_owner(store, &owner); } }; @@ -654,28 +653,6 @@ class has_many : public basic_has_many relation_type iptr(item); if (this->ostore_) { inserter_.insert(*this->ostore_, iptr, *this->owner_, this->mark_modified_owner_); - // if (foreign object has belongs to with owner type) { -// prototype_iterator foreign_node_ = this->ostore_->find(typeid(T).name()); -// -// auto i = foreign_node_->belongs_to_map_.find(this->owner_->node()->type_index()); -// if (i != foreign_node_->belongs_to_map_.end()) { -// this->ostore_->insert(value); -// } else { -// this->ostore_->insert(iptr); -// this->mark_modified_owner_(*this->ostore_, this->owner_); -// } - -// auto i = foreign_node_->belongs_to_map.find(this->owner_->node()->type_index()); -// if (i != foreign_node_->belongs_to_map.end()) { -// prototype_node::relation_info info = i->second; -// this->ostore_->insert(value); -// oos::set(value, info->foreign_field, this->owner_); -// } - // insert value - // set owner into value - // } else { -// this->ostore_->insert(iptr); -// this->mark_modified_owner_(*this->ostore_, this->owner_); } return iterator(this->container_.insert(pos.iter_, iptr)); } diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index 37826ba85..ecdf2453b 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -64,6 +64,11 @@ void node_analyzer::serialize(const char *id, has_many &, c if (pi == node_.tree()->end()) { pi = node_.tree()->template attach::item_type, ON_ATTACH>(id, false, nullptr, on_attach_); node_.register_has_many(node_.type(), pi.get()); + + auto f = [](void *obj, const std::string &field, oos::object_proxy *owner) { + oos::append(static_cast(obj), field, object_ptr(owner)); + }; + } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item throw_object_exception("many to many relations are not supported by now"); diff --git a/include/oos/object/object_holder.hpp b/include/oos/object/object_holder.hpp index 8a227a221..933571eaa 100644 --- a/include/oos/object/object_holder.hpp +++ b/include/oos/object/object_holder.hpp @@ -280,6 +280,7 @@ class OOS_OBJECT_API object_holder : public identifiable_holder template < class T, object_holder_type OPT > friend class object_pointer; object_proxy *proxy_ = nullptr; + object_proxy *owner_ = nullptr; // only set if holder type is BELONGS_TO or HAS_MANY cascade_type cascade_ = cascade_type::NONE; object_holder_type type_; bool is_inserted_ = false; diff --git a/include/oos/object/object_inserter.hpp b/include/oos/object/object_inserter.hpp index d5122a3ad..eba86d209 100644 --- a/include/oos/object/object_inserter.hpp +++ b/include/oos/object/object_inserter.hpp @@ -35,7 +35,7 @@ namespace detail { * This class does these tasks. */ class OOS_OBJECT_API object_inserter { - public: +public: /** * @brief Creates an object_inserter instance. * @@ -70,7 +70,7 @@ class OOS_OBJECT_API object_inserter { template class C> void serialize(const char *id, basic_has_many &x, const char *owner_field, const char *item_field); - private: +private: typedef std::set t_object_proxy_set; t_object_proxy_set object_proxies_; diff --git a/include/oos/object/object_inserter.tpp b/include/oos/object/object_inserter.tpp index 92ced2000..568dddf2f 100644 --- a/include/oos/object/object_inserter.tpp +++ b/include/oos/object/object_inserter.tpp @@ -1,4 +1,5 @@ #include "oos/object/object_inserter.hpp" +#include "oos/object/object_store.hpp" namespace oos { namespace detail { @@ -34,6 +35,7 @@ void object_inserter::serialize(const char *, belongs_to &x, cascade_type cas } x.is_inserted_ = true; x.cascade_ = cascade; + x.owner_ = object_proxy_stack_.top(); // object was seen by inserter stop inserting if (!object_proxies_.insert(x.proxy_).second) { return; @@ -62,6 +64,7 @@ void object_inserter::serialize(const char *, has_one &x, cascade_type cascad } x.is_inserted_ = true; x.cascade_ = cascade; + x.owner_ = object_proxy_stack_.top(); // object was seen by inserter stop inserting if (!object_proxies_.insert(x.proxy_).second) { return; diff --git a/include/oos/object/prototype_node.hpp b/include/oos/object/prototype_node.hpp index 74cdcfcd6..e3ad7de90 100644 --- a/include/oos/object/prototype_node.hpp +++ b/include/oos/object/prototype_node.hpp @@ -331,8 +331,13 @@ class OOS_OBJECT_API prototype_node */ void adjust_left_marker(prototype_node *root, object_proxy *old_proxy, object_proxy *new_proxy); + void notify_delete_relation(object_proxy *owner, object_proxy *proxy); + + void notify_insert_relation(object_proxy *owner, object_proxy *proxy); + private: friend class prototype_tree; + friend class object_holder; friend class object_store; template < class T > friend class object_view; diff --git a/src/object/object_holder.cpp b/src/object/object_holder.cpp index 1d1c13440..c8bb8b865 100644 --- a/src/object/object_holder.cpp +++ b/src/object/object_holder.cpp @@ -78,6 +78,7 @@ void object_holder::reset(object_proxy *proxy, cascade_type cascade) oid_ = 0; if (is_internal() && is_inserted_ && proxy_->ostore_) { --(*proxy_); + proxy_->node_->notify_delete_relation(owner_, proxy); } proxy_->remove(this); /* @@ -94,6 +95,7 @@ void object_holder::reset(object_proxy *proxy, cascade_type cascade) oid_ = proxy_->id(); if (is_internal() && is_inserted_ && proxy_->ostore_) { ++(*proxy_); + proxy_->node_->notify_insert_relation(owner_, proxy); } proxy_->add(this); } diff --git a/src/object/object_proxy.cpp b/src/object/object_proxy.cpp index 53e1b8c22..45c953abf 100644 --- a/src/object/object_proxy.cpp +++ b/src/object/object_proxy.cpp @@ -38,7 +38,7 @@ object_proxy::~object_proxy() } ostore_ = 0; for (ptr_set_t::iterator i = ptr_set_.begin(); i != ptr_set_.end(); ++i) { - (*i)->proxy_ = 0; + (*i)->proxy_ = nullptr; } } diff --git a/src/object/prototype_node.cpp b/src/object/prototype_node.cpp index 2aa480d57..d9dc0fd44 100644 --- a/src/object/prototype_node.cpp +++ b/src/object/prototype_node.cpp @@ -445,4 +445,14 @@ std::ostream& operator <<(std::ostream &os, const prototype_node &pn) return os; } +void prototype_node::notify_delete_relation(object_proxy *owner, object_proxy *proxy) +{ + std::cout << "(" << type_ << ") deleting one relation [" << proxy->node()->type() << "] for owner [" << owner->node()->type() << "]\n"; +} + +void prototype_node::notify_insert_relation(object_proxy *owner, object_proxy *proxy) +{ + std::cout << "(" << type_ << ") inserting one relation [" << proxy->node()->type() << "] for owner [" << owner->node()->type() << "]\n"; +} + } diff --git a/test/object/ObjectStoreTestUnit.cpp b/test/object/ObjectStoreTestUnit.cpp index 95bb2813f..a435420c1 100644 --- a/test/object/ObjectStoreTestUnit.cpp +++ b/test/object/ObjectStoreTestUnit.cpp @@ -1092,7 +1092,7 @@ void ObjectStoreTestUnit::test_belongs_to() // jane is automatically added to deps employee list jane->dep(dep); - UNIT_ASSERT_EQUAL(dep->employees.size(), 2UL, "there must be one employee"); + UNIT_ASSERT_EQUAL(dep->employees.size(), 2UL, "there must be two employees"); // remove george auto i = dep->employees.begin(); From ae2cae8352b2dbce54a24b0fa164e5edac593f55 Mon Sep 17 00:00:00 2001 From: zussel Date: Thu, 12 Jan 2017 16:18:58 +0100 Subject: [PATCH 13/61] node analyzer has many progress --- include/oos/object/attribute_serializer.hpp | 48 ++++++++++++++++++--- include/oos/object/node_analyzer.hpp | 7 ++- include/oos/object/node_analyzer.tpp | 28 +++++++++++- 3 files changed, 75 insertions(+), 8 deletions(-) diff --git a/include/oos/object/attribute_serializer.hpp b/include/oos/object/attribute_serializer.hpp index cd3303fd1..1c19702a8 100644 --- a/include/oos/object/attribute_serializer.hpp +++ b/include/oos/object/attribute_serializer.hpp @@ -58,7 +58,7 @@ class basic_attribute_serializer * with given name must be found and the value must * be convertible into the objects attribute. */ -template < class T, class Enable = void > +template < class T > class attribute_reader : public basic_attribute_serializer { public: @@ -115,7 +115,7 @@ class attribute_reader> : public basic_attribute_serializer template < class V > void serialize(const char *, V &) {} - void serialize(const char *, char*, size_t) {} + void serialize(const char *, char*, std::size_t) {} template < class V > void serialize(const char *, belongs_to &x, cascade_type, typename std::enable_if::value>::type* = 0) @@ -137,11 +137,14 @@ class attribute_reader> : public basic_attribute_serializer const object_ptr &from_; }; +template < class T, class Enabled = void > +class has_many_attribute_reader; + template < class T > -class has_many_attribute_reader : public basic_attribute_serializer +class has_many_attribute_reader::value>::type> : public basic_attribute_serializer { public: - has_many_attribute_reader(const std::string &id, const object_ptr &from) + has_many_attribute_reader(const std::string &id, const T &from) : basic_attribute_serializer(id) , from_(from) {} @@ -154,13 +157,13 @@ class has_many_attribute_reader : public basic_attribute_serializer template < class V > void serialize(const char *, V &) {} - void serialize(const char *, char*, size_t) {} + void serialize(const char *, char*, std::size_t) {} template < class HAS_ONE > void serialize(const char *, HAS_ONE &, cascade_type) { } template class C> - void serialize(const char *, has_many &x, const char *, const char *, typename std::enable_if::value>::type* = 0) + void serialize(const char *, has_many &x, const char *, const char *) { x.push_back(from_); this->success_ = true; @@ -170,6 +173,39 @@ class has_many_attribute_reader : public basic_attribute_serializer const T &from_; }; +template < class T > +class has_many_attribute_reader> : public basic_attribute_serializer +{ +public: + has_many_attribute_reader(const std::string &id, const object_ptr &from) + : basic_attribute_serializer(id) + , from_(from) + {} + + template < class V > + void serialize(V &obj) + { + access::serialize(*this, obj); + } + + template < class V > + void serialize(const char *, V &) {} + void serialize(const char *, char*, std::size_t) {} + + template < class HAS_ONE > + void serialize(const char *, HAS_ONE &, cascade_type) { } + + template class C> + void serialize(const char *, has_many &x, const char *, const char *) + { + x.push_back(from_); + this->success_ = true; + } + +private: + const object_ptr &from_; +}; + template <> class attribute_reader : public basic_attribute_serializer { diff --git a/include/oos/object/node_analyzer.hpp b/include/oos/object/node_analyzer.hpp index 7c1741f03..fa6f45f5f 100644 --- a/include/oos/object/node_analyzer.hpp +++ b/include/oos/object/node_analyzer.hpp @@ -31,7 +31,12 @@ class node_analyzer { template void serialize(const char *id, has_one &x, cascade_type); template class C> - void serialize(const char *, has_many &, const char *, const char *); + void serialize(const char *, has_many &, const char *, const char *, + typename std::enable_if::value>::type* = 0); + + template class C> + void serialize(const char *, has_many &, const char *, const char *, + typename std::enable_if::value>::type* = 0); private: prototype_node &node_; diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index ecdf2453b..c39a0d07c 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -50,7 +50,8 @@ void node_analyzer::serialize(const char *, has_one &x, cascad template class ON_ATTACH> template class C> -void node_analyzer::serialize(const char *id, has_many &, const char *, const char *) +void node_analyzer::serialize(const char *id, has_many &, const char *, const char *, + typename std::enable_if::value>::type*) //void node_analyzer::serialize(const char *id, has_many &x, const char */*owner_field*/, const char */*item_field*/) { // item column column names @@ -78,5 +79,30 @@ void node_analyzer::serialize(const char *id, has_many &, c } } +template class ON_ATTACH> +template class C> +void node_analyzer::serialize(const char *id, has_many &, const char *, const char *, + typename std::enable_if::value>::type*) +//void node_analyzer::serialize(const char *id, has_many &x, const char */*owner_field*/, const char */*item_field*/) +{ + // item column column names +// x.owner_field(owner_field); +// x.item_field(item_field); + // attach relation table for has many relation + // check if has many item is already attached + // true: check owner and item field + // false: attach it + prototype_iterator pi = node_.tree()->find(id); + if (pi == node_.tree()->end()) { + pi = node_.tree()->template attach::item_type, ON_ATTACH>(id, false, nullptr, on_attach_); + } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { + // prototype is of type has_many_item + throw_object_exception("many to many relations are not supported by now"); + } else { + // throw exception + throw_object_exception("prototype already inserted: " << pi->type()); + } +} + } } \ No newline at end of file From 71503d4044c9ffcbd20ad78384d8dbd93e95ce67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Thu, 12 Jan 2017 22:38:15 +0100 Subject: [PATCH 14/61] belongs_to progress --- include/oos/object/node_analyzer.tpp | 19 +++++++++++-------- include/oos/object/prototype_node.hpp | 10 +++++----- src/object/prototype_node.cpp | 13 ++----------- 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index c39a0d07c..4a435f397 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -21,17 +21,23 @@ void node_analyzer::serialize(const char *id, belongs_to &x, c if (node != node_.tree()->end()) { // check if created from has_many // check if node has_many relation for id (id == tablename) - auto i = node->has_many_map_.find(id); + auto i = node->has_many_map_.find(node->type_index()); if (i != node->has_many_map_.end()) { // yes, node found! // Todo: check if node is for has many item // detach has_many_item node - node_.tree()->detach(i->second); + node_.tree()->detach(i->second.node); + node = node_.tree()->template prepare_attach(); } + } else { + node = node_.tree()->template prepare_attach(); + } + if (!node->has_primary_key()) { + throw_object_exception("serializable of type '" << x.type() << "' has no primary key"); } node_.register_belongs_to(std::type_index(typeid(V)), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { oos::set(static_cast(obj), field, object_ptr(owner)); - })); + }, node.get())); } template class ON_ATTACH> @@ -64,12 +70,9 @@ void node_analyzer::serialize(const char *id, has_many &, c prototype_iterator pi = node_.tree()->find(id); if (pi == node_.tree()->end()) { pi = node_.tree()->template attach::item_type, ON_ATTACH>(id, false, nullptr, on_attach_); - node_.register_has_many(node_.type(), pi.get()); - - auto f = [](void *obj, const std::string &field, oos::object_proxy *owner) { + node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { oos::append(static_cast(obj), field, object_ptr(owner)); - }; - + }, pi.get())); } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item throw_object_exception("many to many relations are not supported by now"); diff --git a/include/oos/object/prototype_node.hpp b/include/oos/object/prototype_node.hpp index e3ad7de90..165b95988 100644 --- a/include/oos/object/prototype_node.hpp +++ b/include/oos/object/prototype_node.hpp @@ -78,15 +78,15 @@ class OOS_OBJECT_API prototype_node struct relation_info { typedef std::function set_owner_func; - relation_info(const std::string &n, const set_owner_func &func) - : name(n), set_owner(func) + relation_info(const std::string &n, const set_owner_func &func, prototype_node *pn) + : name(n), set_owner(func), node(pn) {} std::string name; std::function set_owner; + prototype_node *node; }; typedef std::unordered_map relation_map; - typedef std::unordered_map has_many_map; public: prototype_node(); @@ -306,7 +306,7 @@ class OOS_OBJECT_API prototype_node object_proxy* find_proxy(const std::shared_ptr &pk); void register_belongs_to(const std::type_index &tindex, const prototype_node::relation_info &relation_info); - void register_has_many(const std::string &field, prototype_node *node); + void register_has_many(const std::type_index &tindex, const prototype_node::relation_info &relation_info); private: @@ -386,7 +386,7 @@ class OOS_OBJECT_API prototype_node relation_map belongs_to_map_; relation_map has_one_map_; - has_many_map has_many_map_; + relation_map has_many_map_; }; } diff --git a/src/object/prototype_node.cpp b/src/object/prototype_node.cpp index d9dc0fd44..545592043 100644 --- a/src/object/prototype_node.cpp +++ b/src/object/prototype_node.cpp @@ -373,9 +373,9 @@ void prototype_node::register_belongs_to(const std::type_index &tindex, const pr belongs_to_map_.insert(std::make_pair(tindex, relation_info)); } -void prototype_node::register_has_many(const std::string &field, prototype_node *node) +void prototype_node::register_has_many(const std::type_index &tindex, const prototype_node::relation_info &relation_info) { - has_many_map_.insert(std::make_pair(field, node)); + has_many_map_.insert(std::make_pair(tindex, relation_info)); } /* @@ -432,15 +432,6 @@ std::ostream& operator <<(std::ostream &os, const prototype_node &pn) iop = iop->next(); } os << "|{size|" << i << "}"; - - os << "|{relations}"; - // list relations -// prototype_node::field_prototype_map_t::const_iterator first = pn.relations.begin(); -// prototype_node::field_prototype_map_t::const_iterator last = pn.relations.end(); -// while (first != last) { -// os << "|{parent node type|" << first->first << "|node|" << first->second.first->type() << "|foreign field|" << first->second.second << "}"; -// ++first; -// } os << "}\"]\n"; return os; } From d6597efa6acd23be900c0244c940e07a4bfabebd Mon Sep 17 00:00:00 2001 From: zussel Date: Fri, 13 Jan 2017 16:38:05 +0100 Subject: [PATCH 15/61] belongs_to progress: insertion --- include/oos/object/has_many_vector.hpp | 22 +++++------ include/oos/object/node_analyzer.hpp | 2 + include/oos/object/node_analyzer.tpp | 19 ++++++++- include/oos/object/object_store.hpp | 15 +++++++- include/oos/object/prototype_node.hpp | 16 ++++---- src/object/object_holder.cpp | 7 +++- src/object/object_store.cpp | 53 ++++++++++++++++++++++++++ src/object/prototype_node.cpp | 10 ----- test/object/ObjectStoreTestUnit.cpp | 18 +++++++++ 9 files changed, 128 insertions(+), 34 deletions(-) diff --git a/include/oos/object/has_many_vector.hpp b/include/oos/object/has_many_vector.hpp index a1120f56d..f1c360ba6 100644 --- a/include/oos/object/has_many_vector.hpp +++ b/include/oos/object/has_many_vector.hpp @@ -564,17 +564,17 @@ class has_many_inserter::value> void insert(object_store &store, const relation_type &rtype, object_proxy &owner, const mark_modified_owner_func &mark_modified_owner) { - prototype_iterator foreign_node_ = store.find(typeid(T).name()); - - auto i = foreign_node_->belongs_to_map_.find(owner.node()->type_index()); - if (i != foreign_node_->belongs_to_map_.end()) { - store.insert(rtype->value()); - // set owner into value - i->second.set_owner(rtype->value().ptr(), i->second.name, &owner); - } else { - store.insert(rtype); - } - mark_modified_owner(store, &owner); + prototype_iterator foreign_node_ = store.find(typeid(T).name()); + + auto i = foreign_node_->belongs_to_map_.find(owner.node()->type_index()); + if (i != foreign_node_->belongs_to_map_.end()) { + store.insert(rtype->value()); + // set owner into value + store.notify_relation_insert(i->second, rtype->value().ptr() /*owner*/, &owner /*value*/); + } else { + store.insert(rtype); + } + mark_modified_owner(store, &owner); } }; diff --git a/include/oos/object/node_analyzer.hpp b/include/oos/object/node_analyzer.hpp index fa6f45f5f..b7806f8db 100644 --- a/include/oos/object/node_analyzer.hpp +++ b/include/oos/object/node_analyzer.hpp @@ -21,6 +21,8 @@ class node_analyzer { ~node_analyzer() { } + void analyze(); + template void serialize(V &x); template diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index 4a435f397..fa3fd3f44 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -6,6 +6,16 @@ namespace oos { namespace detail { + +template class ON_ATTACH> +void node_analyzer::analyze() +{ +// std::cout << "START analyzing " << node_.type() << "\n"; + T obj; + oos::access::serialize(*this, obj); +// std::cout << "FINISHED analyzing " << node_.type() << "\n"; +} + template class ON_ATTACH> template void node_analyzer::serialize(V &x) @@ -17,6 +27,7 @@ template class ON_ATTACH> template void node_analyzer::serialize(const char *id, belongs_to &x, cascade_type) { +// std::cout << "analyzing belongs_to field " << id << " (typeid: " << typeid(V).name() << ")\n"; prototype_iterator node = node_.tree()->find(x.type()); if (node != node_.tree()->end()) { // check if created from has_many @@ -27,7 +38,7 @@ void node_analyzer::serialize(const char *id, belongs_to &x, c // Todo: check if node is for has many item // detach has_many_item node node_.tree()->detach(i->second.node); - node = node_.tree()->template prepare_attach(); + i->second.node = nullptr; } } else { node = node_.tree()->template prepare_attach(); @@ -37,6 +48,8 @@ void node_analyzer::serialize(const char *id, belongs_to &x, c } node_.register_belongs_to(std::type_index(typeid(V)), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { oos::set(static_cast(obj), field, object_ptr(owner)); + }, [](void *obj, const std::string &field, oos::object_proxy *owner) { + std::cout << "TODO: insert value for field [" << field << "]\n"; }, node.get())); } @@ -44,6 +57,7 @@ template class ON_ATTACH> template void node_analyzer::serialize(const char *, has_one &x, cascade_type) { +// std::cout << "analyzing has_one field " << id << " (typeid: " << typeid(V).name() << ")\n"; prototype_iterator node = node_.tree()->find(x.type()); if (node == node_.tree()->end()) { // if there is no such prototype node @@ -60,6 +74,7 @@ void node_analyzer::serialize(const char *id, has_many &, c typename std::enable_if::value>::type*) //void node_analyzer::serialize(const char *id, has_many &x, const char */*owner_field*/, const char */*item_field*/) { +// std::cout << "analyzing has_many field " << id << " (typeid: " << typeid(V).name() << ")\n"; // item column column names // x.owner_field(owner_field); // x.item_field(item_field); @@ -72,6 +87,8 @@ void node_analyzer::serialize(const char *id, has_many &, c pi = node_.tree()->template attach::item_type, ON_ATTACH>(id, false, nullptr, on_attach_); node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { oos::append(static_cast(obj), field, object_ptr(owner)); + }, [](void *obj, const std::string &field, oos::object_proxy *owner) { + std::cout << "TODO: remove value for field [" << field << "]\n"; }, pi.get())); } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index 6a7df8424..2ceeeb8de 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -651,6 +651,11 @@ class OOS_OBJECT_API object_store */ sequencer_impl_ptr exchange_sequencer(const sequencer_impl_ptr &seq); + void notify_relation_insert(prototype_node::relation_info &info, void *owner, object_proxy *value); + void notify_relation_insert(prototype_node &node, void *owner, object_proxy *value); + void notify_relation_remove(prototype_node::relation_info &info, void *owner, object_proxy *value); + void notify_relation_remove(prototype_node &node, void *owner, object_proxy *value); + transaction current_transaction(); bool has_transaction() const; @@ -767,6 +772,10 @@ class OOS_OBJECT_API object_store void push_transaction(const transaction &tr); void pop_transaction(); + bool is_relation_notification_enabled(); + void enable_relation_notification(); + void disable_relation_notification(); + private: typedef std::unordered_map t_prototype_map; // typeid -> [name -> prototype] @@ -799,6 +808,9 @@ class OOS_OBJECT_API object_store abstract_has_many *temp_container_ = nullptr; std::stack transactions_; + + // relation notification related + bool relation_notification_ = true; }; template class ON_ATTACH, typename Enabled > @@ -935,8 +947,7 @@ object_store::iterator object_store::initialize(prototype_node *node, const ON_A // Check if nodes serializable has 'to-many' relations // Analyze primary and foreign keys of node detail::node_analyzer analyzer(*node, on_attach); - T obj; - oos::access::serialize(analyzer, obj); + analyzer.analyze(); return prototype_iterator(node); } diff --git a/include/oos/object/prototype_node.hpp b/include/oos/object/prototype_node.hpp index 165b95988..7f264ec5e 100644 --- a/include/oos/object/prototype_node.hpp +++ b/include/oos/object/prototype_node.hpp @@ -77,12 +77,16 @@ class OOS_OBJECT_API prototype_node public: struct relation_info { - typedef std::function set_owner_func; - relation_info(const std::string &n, const set_owner_func &func, prototype_node *pn) - : name(n), set_owner(func), node(pn) + typedef std::function modify_value_func; + relation_info(const std::string &n, + const modify_value_func &insert_func, + const modify_value_func &remove_func, + prototype_node *pn) + : name(n), insert_value(insert_func), remove_value(remove_func), node(pn) {} std::string name; - std::function set_owner; + std::function insert_value; + std::function remove_value; prototype_node *node; }; @@ -331,10 +335,6 @@ class OOS_OBJECT_API prototype_node */ void adjust_left_marker(prototype_node *root, object_proxy *old_proxy, object_proxy *new_proxy); - void notify_delete_relation(object_proxy *owner, object_proxy *proxy); - - void notify_insert_relation(object_proxy *owner, object_proxy *proxy); - private: friend class prototype_tree; friend class object_holder; diff --git a/src/object/object_holder.cpp b/src/object/object_holder.cpp index c8bb8b865..eb9c2e771 100644 --- a/src/object/object_holder.cpp +++ b/src/object/object_holder.cpp @@ -4,6 +4,7 @@ #include "oos/object/object_holder.hpp" #include "oos/object/object_proxy.hpp" +#include "oos/object/object_store.hpp" #include "oos/object/object_exception.hpp" namespace oos { @@ -78,7 +79,8 @@ void object_holder::reset(object_proxy *proxy, cascade_type cascade) oid_ = 0; if (is_internal() && is_inserted_ && proxy_->ostore_) { --(*proxy_); - proxy_->node_->notify_delete_relation(owner_, proxy); + proxy_->ostore_->notify_relation_remove(*proxy_->node_, proxy->obj_, owner_); +// proxy_->node_->notify_delete_relation(owner_, proxy); } proxy_->remove(this); /* @@ -95,7 +97,8 @@ void object_holder::reset(object_proxy *proxy, cascade_type cascade) oid_ = proxy_->id(); if (is_internal() && is_inserted_ && proxy_->ostore_) { ++(*proxy_); - proxy_->node_->notify_insert_relation(owner_, proxy); + proxy_->ostore_->notify_relation_insert(*proxy_->node_, proxy->obj_, owner_); +// proxy_->node_->notify_insert_relation(owner_, proxy); } proxy_->add(this); } diff --git a/src/object/object_store.cpp b/src/object/object_store.cpp index 3bb382b09..5c02d159b 100644 --- a/src/object/object_store.cpp +++ b/src/object/object_store.cpp @@ -283,6 +283,44 @@ sequencer_impl_ptr object_store::exchange_sequencer(const sequencer_impl_ptr &se return seq_.exchange_sequencer(seq); } +void object_store::notify_relation_insert(prototype_node::relation_info &info, void *owner, object_proxy *value) +{ + if (!is_relation_notification_enabled()) { + return; + } + disable_relation_notification(); + info.insert_value(owner, info.name, value); + enable_relation_notification(); +} + +void object_store::notify_relation_insert(prototype_node &node, void *owner, object_proxy *value) +{ + auto i = node.has_many_map_.find(node.type_index()); + if (i == node.has_many_map_.end()) { + return; + } + notify_relation_insert(i->second, owner, value); +} + +void object_store::notify_relation_remove(prototype_node::relation_info &info, void *owner, object_proxy *value) +{ + if (!is_relation_notification_enabled()) { + return; + } + disable_relation_notification(); + info.remove_value(owner, info.name, value); + enable_relation_notification(); +} + +void object_store::notify_relation_remove(prototype_node &node, void *owner, object_proxy *value) +{ + auto i = node.has_many_map_.find(node.type_index()); + if (i == node.has_many_map_.end()) { + return; + } + notify_relation_remove(i->second, owner, value); +} + prototype_node* object_store::find_prototype_node(const char *type) const { // check for null if (type == 0) { @@ -378,6 +416,21 @@ void object_store::pop_transaction() transactions_.pop(); } +bool object_store::is_relation_notification_enabled() +{ + return relation_notification_; +} + +void object_store::enable_relation_notification() +{ + relation_notification_ = true; +} + +void object_store::disable_relation_notification() +{ + relation_notification_ = false; +} + transaction object_store::current_transaction() { return transactions_.top(); diff --git a/src/object/prototype_node.cpp b/src/object/prototype_node.cpp index 545592043..9c65da2cb 100644 --- a/src/object/prototype_node.cpp +++ b/src/object/prototype_node.cpp @@ -436,14 +436,4 @@ std::ostream& operator <<(std::ostream &os, const prototype_node &pn) return os; } -void prototype_node::notify_delete_relation(object_proxy *owner, object_proxy *proxy) -{ - std::cout << "(" << type_ << ") deleting one relation [" << proxy->node()->type() << "] for owner [" << owner->node()->type() << "]\n"; -} - -void prototype_node::notify_insert_relation(object_proxy *owner, object_proxy *proxy) -{ - std::cout << "(" << type_ << ") inserting one relation [" << proxy->node()->type() << "] for owner [" << owner->node()->type() << "]\n"; -} - } diff --git a/test/object/ObjectStoreTestUnit.cpp b/test/object/ObjectStoreTestUnit.cpp index a435420c1..d51d7031d 100644 --- a/test/object/ObjectStoreTestUnit.cpp +++ b/test/object/ObjectStoreTestUnit.cpp @@ -838,6 +838,22 @@ ObjectStoreTestUnit::test_generic() oos::set(m1, "child", c1); oos::get(m1, "child", child_result); UNIT_ASSERT_EQUAL(c1->name, child_result->name, "not expected result value"); + + children_vector cv("children vector"); + + UNIT_ASSERT_TRUE(cv.children.empty(), "vector must be empty"); + oos::append(cv, "children", c1); + UNIT_ASSERT_FALSE(cv.children.empty(), "vector must not be empty"); + // Todo: oos::remove, oos::begin, oos::end, oos::size, oos::empty for generic access has_many + // see: https://tartanllama.github.io/c++/2017/01/03/deduction-on-the-left/ for begin and end +// oos::remove(cv, "children", c1); +// UNIT_ASSERT_TRUE(cv.children.empty(), "vector must be empty"); +// +// auto i = oos::begin(cv, "children"); +// auto i = oos::end(cv, "children"); +// +// auto size = oos::size(cv, "children"); +// bool is_empty = oos::empty(cv, "children"); } void ObjectStoreTestUnit::test_structure() @@ -1066,6 +1082,8 @@ struct on_attach> : public on_attach_base void ObjectStoreTestUnit::test_belongs_to() { + std::cout << "\n"; + ostore_.attach("person"); ostore_.attach("department"); ostore_.attach("employee"); From 05c99fafc8a301550cdce426c1bdcd24651aeadd Mon Sep 17 00:00:00 2001 From: zussel Date: Fri, 13 Jan 2017 16:52:57 +0100 Subject: [PATCH 16/61] belongs_to test adaptions --- test/object/ObjectStoreTestUnit.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/test/object/ObjectStoreTestUnit.cpp b/test/object/ObjectStoreTestUnit.cpp index d51d7031d..619486e59 100644 --- a/test/object/ObjectStoreTestUnit.cpp +++ b/test/object/ObjectStoreTestUnit.cpp @@ -1082,8 +1082,6 @@ struct on_attach> : public on_attach_base void ObjectStoreTestUnit::test_belongs_to() { - std::cout << "\n"; - ostore_.attach("person"); ostore_.attach("department"); ostore_.attach("employee"); @@ -1113,16 +1111,16 @@ void ObjectStoreTestUnit::test_belongs_to() UNIT_ASSERT_EQUAL(dep->employees.size(), 2UL, "there must be two employees"); // remove george - auto i = dep->employees.begin(); - i = dep->employees.erase(i); - - UNIT_ASSERT_EQUAL(dep->employees.size(), 1UL, "there must be one employee"); - UNIT_ASSERT_EQUAL(dep->employees.front()->name(), "jane", "expected name must be jane"); - UNIT_ASSERT_TRUE(george->dep().empty(), "there must be no department"); - - jane->dep().clear(); - - UNIT_ASSERT_TRUE(dep->employees.empty(), "there must be no employees"); +// auto i = dep->employees.begin(); +// i = dep->employees.erase(i); +// +// UNIT_ASSERT_EQUAL(dep->employees.size(), 1UL, "there must be one employee"); +// UNIT_ASSERT_EQUAL(dep->employees.front()->name(), "jane", "expected name must be jane"); +// UNIT_ASSERT_TRUE(george->dep().empty(), "there must be no department"); +// +// jane->dep().clear(); +// +// UNIT_ASSERT_TRUE(dep->employees.empty(), "there must be no employees"); } void ObjectStoreTestUnit::test_on_attach() From bb05719bc38c756b382cc0a12c2d1bf2871fe3ce Mon Sep 17 00:00:00 2001 From: zussel Date: Fri, 13 Jan 2017 17:38:47 +0100 Subject: [PATCH 17/61] hans_many remove and remove_if progress --- include/oos/object/has_many_list.hpp | 13 ++++++++++++ include/oos/object/has_many_vector.hpp | 11 ++++++++++ test/object/HasManyListUnitTest.cpp | 28 ++++++++++++++++++++++++++ test/object/HasManyListUnitTest.hpp | 2 ++ 4 files changed, 54 insertions(+) diff --git a/include/oos/object/has_many_list.hpp b/include/oos/object/has_many_list.hpp index 008fc66b4..e4cc90cc9 100644 --- a/include/oos/object/has_many_list.hpp +++ b/include/oos/object/has_many_list.hpp @@ -508,6 +508,19 @@ class has_many : public basic_has_many insert(this->end(), value); } + iterator remove(const value_type &value) + { + return std::remove_if(this->begin(), this->end(), [&value](const typename base::internal_type &x) { + return x->value() == value; + }); + } + + template < class P > + iterator remove_if(P predicate) + { + return std::remove_if(this->begin(), this->end(), predicate); + } + /** * @brief Clears the list */ diff --git a/include/oos/object/has_many_vector.hpp b/include/oos/object/has_many_vector.hpp index f1c360ba6..198ea9f5e 100644 --- a/include/oos/object/has_many_vector.hpp +++ b/include/oos/object/has_many_vector.hpp @@ -667,6 +667,17 @@ class has_many : public basic_has_many insert(this->end(), value); } + iterator remove(const value_type &value) + { + return std::remove(this->begin(), this->end(), value); + } + + template < class P > + iterator remove_if(P predicate) + { + return std::remove_if(this->begin(), this->end(), predicate); + } + /** * @brief Clears the vector */ diff --git a/test/object/HasManyListUnitTest.cpp b/test/object/HasManyListUnitTest.cpp index 357aa8c4f..930e51ecf 100644 --- a/test/object/HasManyListUnitTest.cpp +++ b/test/object/HasManyListUnitTest.cpp @@ -14,6 +14,8 @@ HasManyListUnitTest::HasManyListUnitTest() { add_test("join", std::bind(&HasManyListUnitTest::test_join_table, this), "test list join table"); add_test("const_iterator", std::bind(&HasManyListUnitTest::test_const_iterator, this), "test list const iterator"); + add_test("remove_scalar", std::bind(&HasManyListUnitTest::test_remove_scalar, this), "test list remove scalar elements"); + add_test("remove_object", std::bind(&HasManyListUnitTest::test_remove_object, this), "test list remove object elements"); add_test("erase_scalar", std::bind(&HasManyListUnitTest::test_erase_scalar, this), "test list erase scalar elements"); add_test("erase_object", std::bind(&HasManyListUnitTest::test_erase_object, this), "test list erase object elements"); add_test("int", std::bind(&HasManyListUnitTest::test_integer, this), "test list of ints"); @@ -162,6 +164,32 @@ void HasManyListUnitTest::test_erase_object() UNIT_ASSERT_EQUAL(i->name, "i4", "name must be 'i4'"); } +void HasManyListUnitTest::test_remove_scalar() +{ + object_store store; + + store.attach("many_ints"); + + object_ptr mptr = store.insert(new many_ints); + + mptr->ints.push_back(1); + + UNIT_ASSERT_EQUAL(1U, mptr->ints.size(), "size should be 1 (one)"); + + mptr->ints.push_back(7); + mptr->ints.push_back(90); + + UNIT_ASSERT_EQUAL(3U, mptr->ints.size(), "size should be 3 (three)"); + + mptr->ints.remove(1); + + UNIT_ASSERT_EQUAL(2U, mptr->ints.size(), "size should be 3 (three)"); +} + +void HasManyListUnitTest::test_remove_object() +{ + +} void HasManyListUnitTest::test_integer() { diff --git a/test/object/HasManyListUnitTest.hpp b/test/object/HasManyListUnitTest.hpp index a91849ab4..1144681e4 100644 --- a/test/object/HasManyListUnitTest.hpp +++ b/test/object/HasManyListUnitTest.hpp @@ -17,6 +17,8 @@ class HasManyListUnitTest : public oos::unit_test void test_const_iterator(); void test_erase_scalar(); void test_erase_object(); + void test_remove_scalar(); + void test_remove_object(); void test_integer(); }; From f0697b83942b229bd677e7565022ccd2aaf4e6f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Sat, 14 Jan 2017 23:12:57 +0100 Subject: [PATCH 18/61] added remove and remove_if for has_may list --- include/oos/object/has_many_list.hpp | 35 +++++++++++++++++++++++----- include/oos/object/node_analyzer.tpp | 4 ++-- test/object/HasManyListUnitTest.cpp | 8 ++++++- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/include/oos/object/has_many_list.hpp b/include/oos/object/has_many_list.hpp index e4cc90cc9..c0a2d09f9 100644 --- a/include/oos/object/has_many_list.hpp +++ b/include/oos/object/has_many_list.hpp @@ -85,6 +85,8 @@ class has_many_iterator */ has_many_iterator(const self &iter) : iter_(iter.iter_) {} + has_many_iterator(self &&iter) = default; + has_many_iterator& operator=(self &&iter) = default; /** * @brief Creates a has many iterator from given internal container iterator * @@ -298,6 +300,11 @@ class const_has_many_iterator */ const_has_many_iterator(const has_many_iterator &iter) : iter_(iter.iter_) {} + const_has_many_iterator(const self &iter) : iter_(iter.iter_) {} + + const_has_many_iterator(self &&iter) = default; + const_has_many_iterator& operator=(self &&iter) = default; + /** * @brief Copy assigns a new const has many iterator * @@ -508,17 +515,33 @@ class has_many : public basic_has_many insert(this->end(), value); } - iterator remove(const value_type &value) + void remove(const value_type &value) { - return std::remove_if(this->begin(), this->end(), [&value](const typename base::internal_type &x) { - return x->value() == value; - }); + iterator first = this->begin(); + iterator last = this->end(); + while (first != last) { + iterator next = first; + ++next; + if (*first == value) { + erase(first); + } + first = next; + } } template < class P > - iterator remove_if(P predicate) + void remove_if(P predicate) { - return std::remove_if(this->begin(), this->end(), predicate); + iterator first = this->begin(); + iterator last = this->end(); + while (first != last) { + iterator next = first; + ++next; + if (predicate(*first)) { + erase(first); + } + first = next; + } } /** diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index fa3fd3f44..cb28457b3 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -48,7 +48,7 @@ void node_analyzer::serialize(const char *id, belongs_to &x, c } node_.register_belongs_to(std::type_index(typeid(V)), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { oos::set(static_cast(obj), field, object_ptr(owner)); - }, [](void *obj, const std::string &field, oos::object_proxy *owner) { + }, [](void */*obj*/, const std::string &field, oos::object_proxy */*owner*/) { std::cout << "TODO: insert value for field [" << field << "]\n"; }, node.get())); } @@ -87,7 +87,7 @@ void node_analyzer::serialize(const char *id, has_many &, c pi = node_.tree()->template attach::item_type, ON_ATTACH>(id, false, nullptr, on_attach_); node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { oos::append(static_cast(obj), field, object_ptr(owner)); - }, [](void *obj, const std::string &field, oos::object_proxy *owner) { + }, [](void */*obj*/, const std::string &field, oos::object_proxy */*owner*/) { std::cout << "TODO: remove value for field [" << field << "]\n"; }, pi.get())); } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { diff --git a/test/object/HasManyListUnitTest.cpp b/test/object/HasManyListUnitTest.cpp index 930e51ecf..b24e4fd10 100644 --- a/test/object/HasManyListUnitTest.cpp +++ b/test/object/HasManyListUnitTest.cpp @@ -183,7 +183,13 @@ void HasManyListUnitTest::test_remove_scalar() mptr->ints.remove(1); - UNIT_ASSERT_EQUAL(2U, mptr->ints.size(), "size should be 3 (three)"); + UNIT_ASSERT_EQUAL(2U, mptr->ints.size(), "size should be 2 (two)"); + + mptr->ints.remove_if([](const int &val) { + return val == 90; + }); + + UNIT_ASSERT_EQUAL(1U, mptr->ints.size(), "size should be 1 (one)"); } void HasManyListUnitTest::test_remove_object() From bf07696c52f6ca6787769dc6feb1e636ce73422d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Sun, 15 Jan 2017 22:55:45 +0100 Subject: [PATCH 19/61] has many remove progress --- include/oos/object/has_many_item.hpp | 11 +++++++++ include/oos/object/has_many_list.hpp | 7 +++--- include/oos/object/has_many_vector.hpp | 33 +++++++++++++++----------- test/object/HasManyListUnitTest.cpp | 28 ++++++++++++++++++++++ test/object/HasManyVectorUnitTest.cpp | 27 +++++++++++++++++++++ test/object/HasManyVectorUnitTest.hpp | 2 ++ test/object/ObjectStoreTestUnit.cpp | 2 +- 7 files changed, 91 insertions(+), 19 deletions(-) diff --git a/include/oos/object/has_many_item.hpp b/include/oos/object/has_many_item.hpp index d522da469..dbdf26a7a 100644 --- a/include/oos/object/has_many_item.hpp +++ b/include/oos/object/has_many_item.hpp @@ -17,6 +17,12 @@ namespace oos { /// @cond OOS_DEV +template < class T, template class C > +class has_many_iterator; + +template < class T, template class C > +class const_has_many_iterator; + /** * @class has_many_item * @brief Holds item and owner id of a has many relation @@ -59,6 +65,11 @@ class has_many_item::value>::type } private: + template < class V, template class C > + friend class has_many_iterator; + template < class V, template class C > + friend class const_has_many_iterator; + has_one item_; }; diff --git a/include/oos/object/has_many_list.hpp b/include/oos/object/has_many_list.hpp index c0a2d09f9..a94f7e07a 100644 --- a/include/oos/object/has_many_list.hpp +++ b/include/oos/object/has_many_list.hpp @@ -194,12 +194,11 @@ class has_many_iterator /** * Return the current value * represented by the iterator - * + * * @return The current value */ - value_type operator->() const { return get(); } - value_type operator*() const { return get(); } - value_type get() const { return (*iter_)->value(); } + value_type operator->() const { return (*iter_)->item_; } + value_type& operator*() const { return (*iter_)->item_; } //@} private: diff --git a/include/oos/object/has_many_vector.hpp b/include/oos/object/has_many_vector.hpp index 198ea9f5e..0cd60e79d 100644 --- a/include/oos/object/has_many_vector.hpp +++ b/include/oos/object/has_many_vector.hpp @@ -258,9 +258,8 @@ class has_many_iterator * * @return The current value */ - value_type operator->() const { return (*iter_)->value(); } - value_type operator*() const { return (*iter_)->value(); } - value_type get() const { return (*iter_)->value(); } + value_type operator->() const { return (*iter_)->item_; } + value_type& operator*() const { return (*iter_)->item_; } //@} private: @@ -667,17 +666,6 @@ class has_many : public basic_has_many insert(this->end(), value); } - iterator remove(const value_type &value) - { - return std::remove(this->begin(), this->end(), value); - } - - template < class P > - iterator remove_if(P predicate) - { - return std::remove_if(this->begin(), this->end(), predicate); - } - /** * @brief Clears the vector */ @@ -686,6 +674,23 @@ class has_many : public basic_has_many erase(this->begin(), this->end()); } + iterator remove(const value_type &value) + { + iterator first = this->begin(); + iterator last = this->end(); + first = std::find(first, last, value); + if (first != last) + for(iterator i = first; ++i != last; ) + if (!(*i == value)) + *first++ = std::move(*i); + return first; + } + + template < class P > + void remove_if(P predicate) + { + + } /** * @brief Remove the element at given position. * diff --git a/test/object/HasManyListUnitTest.cpp b/test/object/HasManyListUnitTest.cpp index b24e4fd10..05066475b 100644 --- a/test/object/HasManyListUnitTest.cpp +++ b/test/object/HasManyListUnitTest.cpp @@ -194,7 +194,35 @@ void HasManyListUnitTest::test_remove_scalar() void HasManyListUnitTest::test_remove_object() { + object_store store; + + store.attach("item"); + store.attach("owner"); + + object_ptr o = store.insert(new owner("hans")); + object_ptr i1 = store.insert(new item("i1")); + object_ptr i2 = store.insert(new item("i2")); + + UNIT_ASSERT_EQUAL("i1", i1->name, "name should be 'i1'"); + + o->items.push_back(i1); + + UNIT_ASSERT_EQUAL(1U, o->items.size(), "size should be 1 (one)"); + + o->items.push_back(i2); + + UNIT_ASSERT_EQUAL(2U, o->items.size(), "size should be 2 (two)"); + + o->items.remove(i2); + + UNIT_ASSERT_EQUAL(1U, o->items.size(), "size should be 1 (one)"); + + o->items.remove_if([&i1](const object_ptr &x) { + return i1 == x; + }); + UNIT_ASSERT_EQUAL(0U, o->items.size(), "size should be 0 (zero)"); + UNIT_ASSERT_TRUE(o->items.empty(), "list should be empty"); } void HasManyListUnitTest::test_integer() diff --git a/test/object/HasManyVectorUnitTest.cpp b/test/object/HasManyVectorUnitTest.cpp index 594353c79..bff8e48fa 100644 --- a/test/object/HasManyVectorUnitTest.cpp +++ b/test/object/HasManyVectorUnitTest.cpp @@ -14,6 +14,8 @@ HasManyVectorUnitTest::HasManyVectorUnitTest() { add_test("join", std::bind(&HasManyVectorUnitTest::test_join_table, this), "test vector join table"); add_test("const_iterator", std::bind(&HasManyVectorUnitTest::test_const_iterator, this), "test vector const iterator"); + add_test("remove_scalar", std::bind(&HasManyVectorUnitTest::test_remove_scalar, this), "test vector remove scalar elements"); + add_test("remove_object", std::bind(&HasManyVectorUnitTest::test_remove_object, this), "test vector remove object elements"); add_test("erase_scalar", std::bind(&HasManyVectorUnitTest::test_erase_scalar, this), "test vector erase scalar elements"); add_test("erase_object", std::bind(&HasManyVectorUnitTest::test_erase_object, this), "test vector erase object elements"); add_test("int", std::bind(&HasManyVectorUnitTest::test_integer, this), "test vector of ints"); @@ -154,6 +156,31 @@ void HasManyVectorUnitTest::test_erase_object() UNIT_ASSERT_EQUAL(i->name, "i4", "name must be 'i4'"); } +void HasManyVectorUnitTest::test_remove_scalar() +{ + object_store store; + + store.attach("many_ints"); + + object_ptr mptr = store.insert(new many_ints); + + mptr->ints.push_back(1); + + UNIT_ASSERT_EQUAL(1U, mptr->ints.size(), "size should be 1 (one)"); + + mptr->ints.push_back(7); + mptr->ints.push_back(90); + + UNIT_ASSERT_EQUAL(3U, mptr->ints.size(), "size should be 3 (three)"); + + mptr->ints.remove(7); +} + +void HasManyVectorUnitTest::test_remove_object() +{ + +} + void HasManyVectorUnitTest::test_integer() { object_store store; diff --git a/test/object/HasManyVectorUnitTest.hpp b/test/object/HasManyVectorUnitTest.hpp index 7f94ffd27..963b64f84 100644 --- a/test/object/HasManyVectorUnitTest.hpp +++ b/test/object/HasManyVectorUnitTest.hpp @@ -77,6 +77,8 @@ class HasManyVectorUnitTest : public oos::unit_test void test_const_iterator(); void test_erase_scalar(); void test_erase_object(); + void test_remove_scalar(); + void test_remove_object(); void test_integer(); }; diff --git a/test/object/ObjectStoreTestUnit.cpp b/test/object/ObjectStoreTestUnit.cpp index 619486e59..3cd3c0b77 100644 --- a/test/object/ObjectStoreTestUnit.cpp +++ b/test/object/ObjectStoreTestUnit.cpp @@ -162,7 +162,7 @@ ObjectStoreTestUnit::test_expression() std::unique_ptr exp(make_expression(z == 4)); - object_ptr> optr = itemlist->begin().get(); + object_ptr> optr = *itemlist->begin(); (*exp)(optr); From cbff4ba665e073c94a076c386cba2a05ca76090d Mon Sep 17 00:00:00 2001 From: zussel Date: Mon, 16 Jan 2017 15:27:37 +0100 Subject: [PATCH 20/61] added has many remove and remove if --- include/oos/object/has_many_item.hpp | 5 ++++ include/oos/object/has_many_list.hpp | 2 +- include/oos/object/has_many_vector.hpp | 38 ++++++++++++++++++-------- include/oos/object/object_ptr.hpp | 11 ++++++++ test/object/HasManyVectorUnitTest.cpp | 23 ++++++++++++++++ 5 files changed, 67 insertions(+), 12 deletions(-) diff --git a/include/oos/object/has_many_item.hpp b/include/oos/object/has_many_item.hpp index dbdf26a7a..ecbad938d 100644 --- a/include/oos/object/has_many_item.hpp +++ b/include/oos/object/has_many_item.hpp @@ -115,6 +115,11 @@ class has_many_item::value>::type > return item_; } private: + template < class V, template class C > + friend class has_many_iterator; + template < class V, template class C > + friend class const_has_many_iterator; + T item_; }; diff --git a/include/oos/object/has_many_list.hpp b/include/oos/object/has_many_list.hpp index a94f7e07a..3bd608119 100644 --- a/include/oos/object/has_many_list.hpp +++ b/include/oos/object/has_many_list.hpp @@ -198,7 +198,7 @@ class has_many_iterator * @return The current value */ value_type operator->() const { return (*iter_)->item_; } - value_type& operator*() const { return (*iter_)->item_; } + value_type operator*() const { return (*iter_)->item_; } //@} private: diff --git a/include/oos/object/has_many_vector.hpp b/include/oos/object/has_many_vector.hpp index 0cd60e79d..23904559d 100644 --- a/include/oos/object/has_many_vector.hpp +++ b/include/oos/object/has_many_vector.hpp @@ -10,6 +10,7 @@ #include "oos/object/generic_access.hpp" #include +#include namespace oos { @@ -259,7 +260,7 @@ class has_many_iterator * @return The current value */ value_type operator->() const { return (*iter_)->item_; } - value_type& operator*() const { return (*iter_)->item_; } + value_type operator*() const { return (*iter_)->item_; } //@} private: @@ -272,6 +273,11 @@ class has_many_iterator relation_type relation_item() const { return *iter_; } + void move(self &i) + { + *iter_ = std::move(*i.iter_); + } + container_iterator iter_; }; @@ -676,21 +682,31 @@ class has_many : public basic_has_many iterator remove(const value_type &value) { - iterator first = this->begin(); - iterator last = this->end(); - first = std::find(first, last, value); - if (first != last) - for(iterator i = first; ++i != last; ) - if (!(*i == value)) - *first++ = std::move(*i); - return first; + return remove_if([&value](const value_type &val) { + return val == value; + }); } template < class P > - void remove_if(P predicate) + iterator remove_if(P predicate) { - + iterator first = this->begin(); + iterator last = this->end(); + first = std::find_if(first, last, predicate); + if (first == last) { + return first; + } else { + iterator result = first; + for (; first != last; ++first) { + if (!predicate(*first)) { + result.move(first); + ++result; + } + } + return erase(result, this->end()); + } } + /** * @brief Remove the element at given position. * diff --git a/include/oos/object/object_ptr.hpp b/include/oos/object/object_ptr.hpp index a57862d8e..07ce20890 100644 --- a/include/oos/object/object_ptr.hpp +++ b/include/oos/object/object_ptr.hpp @@ -103,6 +103,17 @@ class object_pointer : public object_holder return *this; } + /** + * @brief Copy assignes an object_pointer from the given has_one object + * @param x The has_one object to created the object_pointer from + * @return A reference to the created object_pointer + */ + self& operator=(const self &x) + { + reset(x.proxy_, x.cascade_); + return *this; + } + /** * @brief Copy assignes an object_pointer from the given has_one object * @param x The has_one object to created the object_pointer from diff --git a/test/object/HasManyVectorUnitTest.cpp b/test/object/HasManyVectorUnitTest.cpp index bff8e48fa..5623aa3fc 100644 --- a/test/object/HasManyVectorUnitTest.cpp +++ b/test/object/HasManyVectorUnitTest.cpp @@ -174,11 +174,34 @@ void HasManyVectorUnitTest::test_remove_scalar() UNIT_ASSERT_EQUAL(3U, mptr->ints.size(), "size should be 3 (three)"); mptr->ints.remove(7); + + UNIT_ASSERT_EQUAL(2U, mptr->ints.size(), "size should be 2 (two)"); } void HasManyVectorUnitTest::test_remove_object() { + object_store store; + + store.attach("item"); + store.attach("owner"); + + object_ptr o = store.insert(new owner("hans")); + object_ptr i1 = store.insert(new item("i1")); + object_ptr i2 = store.insert(new item("i2")); + + UNIT_ASSERT_EQUAL("i1", i1->name, "name should be 'i1'"); + + o->items.push_back(i1); + + UNIT_ASSERT_EQUAL(1U, o->items.size(), "size should be 1 (one)"); + o->items.push_back(i2); + + UNIT_ASSERT_EQUAL(2U, o->items.size(), "size should be 2 (two)"); + + o->items.remove(i1); + + UNIT_ASSERT_EQUAL(1U, o->items.size(), "size should be 1 (one)"); } void HasManyVectorUnitTest::test_integer() From 953234d02d2c3435dcff36f4dd41648202166433 Mon Sep 17 00:00:00 2001 From: zussel Date: Mon, 16 Jan 2017 17:01:28 +0100 Subject: [PATCH 21/61] added quiet flag to test suite --- include/oos/unit/test_suite.hpp | 11 ++++++++- include/oos/unit/unit_test.hpp | 9 ++++--- src/unit/test_suite.cpp | 44 ++++++++++++++++++++++++--------- src/unit/unit_test.cpp | 21 ++++++++++------ test/unit/TestSuiteTestUnit.cpp | 4 +++ 5 files changed, 66 insertions(+), 23 deletions(-) diff --git a/include/oos/unit/test_suite.hpp b/include/oos/unit/test_suite.hpp index 945931b9d..0986f7268 100644 --- a/include/oos/unit/test_suite.hpp +++ b/include/oos/unit/test_suite.hpp @@ -146,6 +146,7 @@ class OOS_UNIT_API test_suite test_suite_cmd cmd = UNKNOWN; /**< Test suite command to be executed */ bool initialized = false; /**< Indicates wether the suite is initialized or not */ bool brief = false; /**< If true for LIST command only a brief list is printed */ + bool quiet = false; /**< If true no output is written to stdout */ std::vector unit_args; /**< Vector of test unit arguments */ }; @@ -157,10 +158,11 @@ class OOS_UNIT_API test_suite struct unit_executer : public std::unary_function { - unit_executer(summary &s); + unit_executer(summary &s, bool q); void operator()(test_suite::value_type &x); bool succeeded; + bool quiet; summary &summary_; }; @@ -290,6 +292,13 @@ class OOS_UNIT_API test_suite */ const test_suite_args& test_args() const; + /** + * Disables any output + * + * @param q If true a output is disabled + */ + void quiet(bool q = true); + private: test_suite_args args_; t_unit_test_map unit_test_map_; diff --git a/include/oos/unit/unit_test.hpp b/include/oos/unit/unit_test.hpp index a458f6412..06b26b065 100644 --- a/include/oos/unit/unit_test.hpp +++ b/include/oos/unit/unit_test.hpp @@ -292,8 +292,10 @@ class OOS_UNIT_API unit_test * * Each test method of the test_unit is * executed. + * + * @param quiet If true no output is written to stdout */ - bool execute(); + bool execute(bool quiet = false); /** * @brief Executes a concrete test method. @@ -303,8 +305,9 @@ class OOS_UNIT_API unit_test * a warning is displayed. * * @param test Name of the test to execute. + * @param quiet If true no output is written to stdout */ - bool execute(const std::string &test); + bool execute(const std::string &test, bool quiet = false); /** * @brief List all tests. @@ -877,7 +880,7 @@ class OOS_UNIT_API unit_test } test_func_info; private: - void execute(test_func_info &test_info); + void execute(test_func_info &test_info, bool quiet); private: std::string name_; diff --git a/src/unit/test_suite.cpp b/src/unit/test_suite.cpp index eabdd6840..6f23e6b56 100644 --- a/src/unit/test_suite.cpp +++ b/src/unit/test_suite.cpp @@ -15,15 +15,18 @@ void test_suite::register_unit(unit_test *utest) unit_test_map_.insert(std::make_pair(utest->name(), unit_test_ptr(utest))); } -test_suite::unit_executer::unit_executer(summary &sum) +test_suite::unit_executer::unit_executer(summary &sum, bool q) : succeeded(true) + , quiet(q) , summary_(sum) {} void test_suite::unit_executer::operator()(test_suite::value_type &x) { - std::cout << "[" << x.second->caption() << "]\n"; - bool result = x.second->execute(); + if (!quiet) { + std::cout << "[" << x.second->caption() << "]\n"; + } + bool result = x.second->execute(quiet); std::for_each(x.second->test_func_infos_.begin(), x.second->test_func_infos_.end(), [this](const unit_test::test_func_info &info) { summary_.evaluate(info); }); @@ -124,7 +127,9 @@ bool test_suite::run() if (args_.initialized) { switch (args_.cmd) { case LIST: - std::for_each(unit_test_map_.begin(), unit_test_map_.end(), unit_lister(std::cout, args_.brief)); + if (!args_.quiet) { + std::for_each(unit_test_map_.begin(), unit_test_map_.end(), unit_lister(std::cout, args_.brief)); + } break; case EXECUTE: summary_.reset(); @@ -136,13 +141,17 @@ bool test_suite::run() result = succeeded; } } - std::cout << summary_; + if (!args_.quiet) { + std::cout << summary_; + } return result; } else { // execute all test units - unit_executer ue(summary_); + unit_executer ue(summary_, args_.quiet); std::for_each(unit_test_map_.begin(), unit_test_map_.end(), std::ref(ue)); - std::cout << summary_; + if (!args_.quiet) { + std::cout << summary_; + } return ue.succeeded; } default: @@ -158,11 +167,15 @@ bool test_suite::run(const std::string &unit) { t_unit_test_map::const_iterator i = unit_test_map_.find(unit); if (i == unit_test_map_.end()) { - std::cout << "couldn't find test unit [" << unit << "]\n"; + if (!args_.quiet) { + std::cout << "couldn't find test unit [" << unit << "]\n"; + } return false; } else { - std::cout << "[" << i->second->caption() << "]\n"; - bool succeeded = i->second->execute(); + if (!args_.quiet) { + std::cout << "[" << i->second->caption() << "]\n"; + } + bool succeeded = i->second->execute(args_.quiet); std::for_each(i->second->test_func_infos_.begin(), i->second->test_func_infos_.end(), [this](const unit_test::test_func_info &info) { summary_.evaluate(info); }); @@ -190,10 +203,12 @@ bool test_suite::run(const std::string &unit, const std::string &test) { t_unit_test_map::const_iterator i = unit_test_map_.find(unit); if (i == unit_test_map_.end()) { - std::cout << "couldn't find test unit [" << unit << "]\n"; + if (!args_.quiet) { + std::cout << "couldn't find test unit [" << unit << "]\n"; + } return false; } else { - bool succeeded = i->second->execute(test); + bool succeeded = i->second->execute(test, args_.quiet); auto j = std::find_if(i->second->test_func_infos_.begin(), i->second->test_func_infos_.end(), [test](const unit_test::t_test_func_info_vector::value_type &x) { return x.name == test; }); @@ -236,6 +251,11 @@ const test_suite::test_suite_args& test_suite::test_args() const return args_; } +void test_suite::quiet(bool q) +{ + args_.quiet = q; +} + std::ostream& operator<<(std::ostream& out, const test_suite::summary &s) { out << "summary for " << s.tests << " tests with " << s.asserts << " asserts: (succeeded: " << s.succeeded << "), (failures: " << s.failures << "), (errors: " << s.errors << ")\n"; diff --git a/src/unit/unit_test.cpp b/src/unit/unit_test.cpp index 7844ca1a4..e8855d6ea 100644 --- a/src/unit/unit_test.cpp +++ b/src/unit/unit_test.cpp @@ -47,12 +47,12 @@ std::string unit_test::caption() const return caption_; } -bool unit_test::execute() +bool unit_test::execute(bool quiet) { // execute each test bool succeeded = true; std::for_each(test_func_infos_.begin(), test_func_infos_.end(), [&](t_test_func_info_vector::value_type &info) { - execute(info); + execute(info, quiet); if (succeeded && !info.succeeded) { succeeded = false; } @@ -60,17 +60,19 @@ bool unit_test::execute() return succeeded; } -bool unit_test::execute(const std::string &test) +bool unit_test::execute(const std::string &test, bool quiet) { t_test_func_info_vector::iterator i = std::find_if(test_func_infos_.begin(), test_func_infos_.end(), [test](const t_test_func_info_vector::value_type &x) { return x.name == test; }); if (i == test_func_infos_.end()) { - std::cout << "couldn't find test [" << test << "] of unit [" << caption_ << "]\n"; + if (!quiet) { + std::cout << "couldn't find test [" << test << "] of unit [" << caption_ << "]\n"; + } return false; } else { - execute(*i); + execute(*i, quiet); return i->succeeded; } } @@ -142,10 +144,12 @@ void unit_test::info(const std::string &msg) std::cout << "INFO: " << msg; } -void unit_test::execute(test_func_info &test_info) +void unit_test::execute(test_func_info &test_info, bool quiet) { initialize(); - std::cout << std::left << std::setw(70) << test_info.caption << " ... " << std::flush; + if (!quiet) { + std::cout << std::left << std::setw(70) << test_info.caption << " ... " << std::flush; + } long dur(0L); try { @@ -164,6 +168,9 @@ void unit_test::execute(test_func_info &test_info) test_info.message = ex.what(); } finalize(); + if (quiet) { + return; + } if (test_info.succeeded) { std::cout << "PASS (" << test_info.assertion_count + test_info.error_count << " assertions) (" << (double)(dur)/1000.0 << "ms)\n"; } else { diff --git a/test/unit/TestSuiteTestUnit.cpp b/test/unit/TestSuiteTestUnit.cpp index b0300febf..907f0fce9 100644 --- a/test/unit/TestSuiteTestUnit.cpp +++ b/test/unit/TestSuiteTestUnit.cpp @@ -80,6 +80,7 @@ bool TestSuiteTestUnit::test_list() }; ts.init(2, argv1); + ts.quiet(); const oos::test_suite::test_suite_args &args = ts.test_args(); @@ -121,6 +122,7 @@ bool TestSuiteTestUnit::test_method() }; ts.init(3, argv); + ts.quiet(); const oos::test_suite::test_suite_args &args = ts.test_args(); @@ -153,6 +155,7 @@ bool TestSuiteTestUnit::test_unit() }; ts.init(3, argv); + ts.quiet(); const oos::test_suite::test_suite_args &args = ts.test_args(); @@ -180,6 +183,7 @@ bool TestSuiteTestUnit::test_suite() }; ts.init(3, argv); + ts.quiet(); const oos::test_suite::test_suite_args &args = ts.test_args(); From 472031e7dd5659f4647ccaa978f01980df57443b Mon Sep 17 00:00:00 2001 From: zussel Date: Mon, 16 Jan 2017 17:01:47 +0100 Subject: [PATCH 22/61] added generic remove for has many --- include/oos/object/attribute_serializer.hpp | 67 +++++++++++++++++++++ include/oos/object/generic_access.hpp | 20 +++++- include/oos/object/node_analyzer.tpp | 6 +- test/object/ObjectStoreTestUnit.cpp | 4 +- 4 files changed, 89 insertions(+), 8 deletions(-) diff --git a/include/oos/object/attribute_serializer.hpp b/include/oos/object/attribute_serializer.hpp index 1c19702a8..1468314f8 100644 --- a/include/oos/object/attribute_serializer.hpp +++ b/include/oos/object/attribute_serializer.hpp @@ -339,6 +339,73 @@ class attribute_writer> : public basic_attribute_serializer object_ptr &to_; }; +template < class T, class Enabled = void > +class has_many_attribute_writer; + +template < class T > +class has_many_attribute_writer::value>::type> : public basic_attribute_serializer +{ +public: + has_many_attribute_writer(const std::string &id, const T &to) + : basic_attribute_serializer(id) + , to_(to) + {} + + template < class V > + void serialize(V &obj) + { + access::serialize(*this, obj); + } + + template < class V > + void serialize(const char *, V &) {} + void serialize(const char *, char*, size_t) {} + + template < class HAS_ONE > + void serialize(const char *, HAS_ONE &, cascade_type) {} + + template class C> + void serialize(const char *, has_many &x, const char *, const char *) + { + x.remove(to_); + this->success_ = true; + } +private: + const T &to_; +}; + +template < class T > +class has_many_attribute_writer> : public basic_attribute_serializer +{ +public: + has_many_attribute_writer(const std::string &id, const object_ptr &to) + : basic_attribute_serializer(id) + , to_(to) + {} + + template < class V > + void serialize(V &obj) + { + access::serialize(*this, obj); + } + + template < class V > + void serialize(const char *, V &) {} + void serialize(const char *, char*, size_t) {} + + template < class HAS_ONE > + void serialize(const char *, HAS_ONE &, cascade_type) {} + + template class C> + void serialize(const char *, has_many &x, const char *, const char *) + { + x.remove(to_); + this->success_ = true; + } +private: + const object_ptr &to_; +}; + template <> class attribute_writer : public basic_attribute_serializer { diff --git a/include/oos/object/generic_access.hpp b/include/oos/object/generic_access.hpp index 67da41cec..b9c14fd24 100644 --- a/include/oos/object/generic_access.hpp +++ b/include/oos/object/generic_access.hpp @@ -35,6 +35,12 @@ bool append(O *obj, const std::string &name, const T &val) return append(*obj, name, val); } +template < typename O, class T > +bool remove(O *obj, const std::string &name, const T &val) +{ + return remove(*obj, name, val); +} + /** * Sets a value of an object member identified by * the given name. The object is passed by reference. @@ -58,9 +64,17 @@ bool set(O &obj, const std::string &name, const T &val) template < typename O, class T > bool append(O &obj, const std::string &name, const T &val) { - has_many_attribute_reader reader(name, val); - oos::access::serialize(reader, obj); - return reader.success(); + has_many_attribute_reader writer(name, val); + oos::access::serialize(writer, obj); + return writer.success(); +} + +template < typename O, class T > +bool remove(O &obj, const std::string &name, const T &val) +{ + has_many_attribute_writer writer(name, val); + oos::access::serialize(writer, obj); + return writer.success(); } /** diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index cb28457b3..7518890ff 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -49,7 +49,7 @@ void node_analyzer::serialize(const char *id, belongs_to &x, c node_.register_belongs_to(std::type_index(typeid(V)), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { oos::set(static_cast(obj), field, object_ptr(owner)); }, [](void */*obj*/, const std::string &field, oos::object_proxy */*owner*/) { - std::cout << "TODO: insert value for field [" << field << "]\n"; + std::cout << "TODO: clear value for field [" << field << "]\n"; }, node.get())); } @@ -87,8 +87,8 @@ void node_analyzer::serialize(const char *id, has_many &, c pi = node_.tree()->template attach::item_type, ON_ATTACH>(id, false, nullptr, on_attach_); node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { oos::append(static_cast(obj), field, object_ptr(owner)); - }, [](void */*obj*/, const std::string &field, oos::object_proxy */*owner*/) { - std::cout << "TODO: remove value for field [" << field << "]\n"; + }, [](void *obj, const std::string &field, oos::object_proxy *owner) { + oos::remove(static_cast(obj), field, object_ptr(owner)); }, pi.get())); } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item diff --git a/test/object/ObjectStoreTestUnit.cpp b/test/object/ObjectStoreTestUnit.cpp index 3cd3c0b77..7bf857bb2 100644 --- a/test/object/ObjectStoreTestUnit.cpp +++ b/test/object/ObjectStoreTestUnit.cpp @@ -844,10 +844,10 @@ ObjectStoreTestUnit::test_generic() UNIT_ASSERT_TRUE(cv.children.empty(), "vector must be empty"); oos::append(cv, "children", c1); UNIT_ASSERT_FALSE(cv.children.empty(), "vector must not be empty"); + oos::remove(cv, "children", c1); + UNIT_ASSERT_TRUE(cv.children.empty(), "vector must be empty"); // Todo: oos::remove, oos::begin, oos::end, oos::size, oos::empty for generic access has_many // see: https://tartanllama.github.io/c++/2017/01/03/deduction-on-the-left/ for begin and end -// oos::remove(cv, "children", c1); -// UNIT_ASSERT_TRUE(cv.children.empty(), "vector must be empty"); // // auto i = oos::begin(cv, "children"); // auto i = oos::end(cv, "children"); From aaf5421f6a9d4e320d6e4e9a5093216dcaaa6cc8 Mon Sep 17 00:00:00 2001 From: zussel Date: Mon, 16 Jan 2017 17:34:01 +0100 Subject: [PATCH 23/61] started has_many_deleter --- include/oos/object/has_many_vector.hpp | 48 ++++++++++++++++++++++++-- include/oos/object/prototype_node.hpp | 4 +++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/include/oos/object/has_many_vector.hpp b/include/oos/object/has_many_vector.hpp index 23904559d..032d97947 100644 --- a/include/oos/object/has_many_vector.hpp +++ b/include/oos/object/has_many_vector.hpp @@ -270,6 +270,7 @@ class has_many_iterator friend class object_serializer; friend class detail::object_inserter; friend class detail::object_deleter; + friend class detail::has_many_deleter; relation_type relation_item() const { return *iter_; } @@ -599,6 +600,49 @@ class has_many_inserter::value>: }; } +namespace detail { +template class C, class Enabled = void> +class has_many_deleter; + +template class C> +class has_many_deleter::value>::type> +{ +public: + typedef T value_type; + typedef typename has_many_iterator_traits::relation_type relation_type; + typedef typename basic_has_many::mark_modified_owner_func mark_modified_owner_func; + + void remove(object_store &store, relation_type &rtype, object_proxy &owner) + { + prototype_iterator foreign_node_ = store.find(typeid(T).name()); + + auto i = foreign_node_->belongs_to_map_.find(owner.node()->type_index()); + if (i != foreign_node_->belongs_to_map_.end()) { + auto val = rtype->value(); + store.remove(val); + // set owner into value + store.notify_relation_remove(i->second, rtype->value().ptr() /*owner*/, &owner /*value*/); + } else { + store.remove(rtype); + } + } +}; + +template class C> +class has_many_deleter::value>::type> +{ +public: + typedef T value_type; + typedef typename has_many_iterator_traits::relation_type relation_type; + typedef typename basic_has_many::mark_modified_owner_func mark_modified_owner_func; + + void remove(object_store &store, relation_type &rtype, object_proxy &owner) + { + store.remove(rtype); + } +}; +} + /** * @brief Has many relation class using a std::vector as container * @@ -719,8 +763,7 @@ class has_many : public basic_has_many iterator erase(iterator i) { if (this->ostore_) { - relation_type iptr = i.relation_item(); - this->ostore_->remove(iptr); + deleter_.remove(*this->ostore_, i.relation_item(), *this->owner_); } container_iterator ci = this->container_.erase(i.iter_); return iterator(ci); @@ -758,6 +801,7 @@ class has_many : public basic_has_many private: detail::has_many_inserter inserter_; + detail::has_many_deleter deleter_; }; } diff --git a/include/oos/object/prototype_node.hpp b/include/oos/object/prototype_node.hpp index 7f264ec5e..9d2c34420 100644 --- a/include/oos/object/prototype_node.hpp +++ b/include/oos/object/prototype_node.hpp @@ -50,6 +50,8 @@ class object_proxy; namespace detail { template < class T, template class C, class Enabled > class has_many_inserter; +template < class T, template class C, class Enabled > +class has_many_deleter; template < class T, template < class ... > class ON_ATTACH > class node_analyzer; } @@ -349,6 +351,8 @@ class OOS_OBJECT_API prototype_node friend class has_many; template < class T, template class C, class Enabled > friend class detail::has_many_inserter; + template < class T, template class C, class Enabled > + friend class detail::has_many_deleter; template < class T, template < class ... > class ON_ATTACH > friend class detail::node_analyzer; From 2f55fb1071fbab688b69abcfb18e6658fd6905f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Mon, 16 Jan 2017 22:39:51 +0100 Subject: [PATCH 24/61] belongs_to progress --- include/oos/object/has_many_vector.hpp | 14 +++++++++----- include/oos/object/node_analyzer.tpp | 4 ++-- include/oos/utils/serializer.hpp | 2 +- src/object/object_deleter.cpp | 1 - test/Item.hpp | 2 +- test/object/ObjectStoreTestUnit.cpp | 13 +++++++++---- 6 files changed, 22 insertions(+), 14 deletions(-) diff --git a/include/oos/object/has_many_vector.hpp b/include/oos/object/has_many_vector.hpp index 032d97947..14825f196 100644 --- a/include/oos/object/has_many_vector.hpp +++ b/include/oos/object/has_many_vector.hpp @@ -14,6 +14,10 @@ namespace oos { +namespace detail { +template class C, class Enabled > +class has_many_deleter; +} /// @cond OOS_DEV template < class T > @@ -270,7 +274,8 @@ class has_many_iterator friend class object_serializer; friend class detail::object_inserter; friend class detail::object_deleter; - friend class detail::has_many_deleter; + template class C, class Enabled> + friend class detail::has_many_deleter; relation_type relation_item() const { return *iter_; } @@ -610,7 +615,6 @@ class has_many_deleter::value>: public: typedef T value_type; typedef typename has_many_iterator_traits::relation_type relation_type; - typedef typename basic_has_many::mark_modified_owner_func mark_modified_owner_func; void remove(object_store &store, relation_type &rtype, object_proxy &owner) { @@ -634,9 +638,8 @@ class has_many_deleter::value>:: public: typedef T value_type; typedef typename has_many_iterator_traits::relation_type relation_type; - typedef typename basic_has_many::mark_modified_owner_func mark_modified_owner_func; - void remove(object_store &store, relation_type &rtype, object_proxy &owner) + void remove(object_store &store, relation_type &rtype, object_proxy &) { store.remove(rtype); } @@ -763,7 +766,8 @@ class has_many : public basic_has_many iterator erase(iterator i) { if (this->ostore_) { - deleter_.remove(*this->ostore_, i.relation_item(), *this->owner_); + relation_type iptr(*i.iter_); + deleter_.remove(*this->ostore_, iptr, *this->owner_); } container_iterator ci = this->container_.erase(i.iter_); return iterator(ci); diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index 7518890ff..98d74ccc2 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -48,8 +48,8 @@ void node_analyzer::serialize(const char *id, belongs_to &x, c } node_.register_belongs_to(std::type_index(typeid(V)), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { oos::set(static_cast(obj), field, object_ptr(owner)); - }, [](void */*obj*/, const std::string &field, oos::object_proxy */*owner*/) { - std::cout << "TODO: clear value for field [" << field << "]\n"; + }, [](void *obj, const std::string &field, oos::object_proxy *) { + oos::set(static_cast(obj), field, object_ptr()); }, node.get())); } diff --git a/include/oos/utils/serializer.hpp b/include/oos/utils/serializer.hpp index f32985634..627179a3f 100644 --- a/include/oos/utils/serializer.hpp +++ b/include/oos/utils/serializer.hpp @@ -20,7 +20,7 @@ #include "oos/utils/cascade_type.hpp" #include "oos/utils/varchar.hpp" -#include "access.hpp" +#include "oos/utils/access.hpp" #include #include diff --git a/src/object/object_deleter.cpp b/src/object/object_deleter.cpp index 921baa747..715ccbd66 100644 --- a/src/object/object_deleter.cpp +++ b/src/object/object_deleter.cpp @@ -27,7 +27,6 @@ bool object_deleter::check_object_count_map() const if (first->second.ignore) { ++first; } else if (first->second.reference_counter == 0) { -// } else if (first->second.ref_count == 0 && first->second.ptr_count == 0) { ++first; } else { return false; diff --git a/test/Item.hpp b/test/Item.hpp index a5d9b8161..08f2fc96c 100644 --- a/test/Item.hpp +++ b/test/Item.hpp @@ -354,7 +354,7 @@ class employee : public person void serialize(SERIALIZER &serializer) { serializer.serialize(*oos::base_class(this)); - serializer.serialize("department", department_, oos::cascade_type::ALL); + serializer.serialize("department", department_, oos::cascade_type::NONE); } oos::object_ptr dep() { return department_; } diff --git a/test/object/ObjectStoreTestUnit.cpp b/test/object/ObjectStoreTestUnit.cpp index 7bf857bb2..56dca5485 100644 --- a/test/object/ObjectStoreTestUnit.cpp +++ b/test/object/ObjectStoreTestUnit.cpp @@ -839,6 +839,10 @@ ObjectStoreTestUnit::test_generic() oos::get(m1, "child", child_result); UNIT_ASSERT_EQUAL(c1->name, child_result->name, "not expected result value"); + oos::set(m1, "child", object_ptr()); + oos::get(m1, "child", child_result); + UNIT_ASSERT_TRUE(child_result.get() == nullptr, "not expected result value"); + children_vector cv("children vector"); UNIT_ASSERT_TRUE(cv.children.empty(), "vector must be empty"); @@ -1111,10 +1115,11 @@ void ObjectStoreTestUnit::test_belongs_to() UNIT_ASSERT_EQUAL(dep->employees.size(), 2UL, "there must be two employees"); // remove george -// auto i = dep->employees.begin(); -// i = dep->employees.erase(i); -// -// UNIT_ASSERT_EQUAL(dep->employees.size(), 1UL, "there must be one employee"); + auto i = dep->employees.begin(); + i = dep->employees.erase(i); + + UNIT_ASSERT_EQUAL(dep->employees.size(), 1UL, "there must be one employee"); + UNIT_ASSERT_TRUE(jane->dep().empty(), "there must not be an department"); // UNIT_ASSERT_EQUAL(dep->employees.front()->name(), "jane", "expected name must be jane"); // UNIT_ASSERT_TRUE(george->dep().empty(), "there must be no department"); // From 7f5f8d30933057b2a9df67dfd04b41139843bf1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Tue, 17 Jan 2017 22:25:00 +0100 Subject: [PATCH 25/61] belongs_to progress --- include/oos/object/has_many_vector.hpp | 2 +- src/object/object_holder.cpp | 2 +- test/Item.hpp | 2 +- test/object/ObjectStoreTestUnit.cpp | 13 ++++++------- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/include/oos/object/has_many_vector.hpp b/include/oos/object/has_many_vector.hpp index 14825f196..097219be7 100644 --- a/include/oos/object/has_many_vector.hpp +++ b/include/oos/object/has_many_vector.hpp @@ -623,7 +623,7 @@ class has_many_deleter::value>: auto i = foreign_node_->belongs_to_map_.find(owner.node()->type_index()); if (i != foreign_node_->belongs_to_map_.end()) { auto val = rtype->value(); - store.remove(val); +// store.remove(val); // set owner into value store.notify_relation_remove(i->second, rtype->value().ptr() /*owner*/, &owner /*value*/); } else { diff --git a/src/object/object_holder.cpp b/src/object/object_holder.cpp index eb9c2e771..acc26902c 100644 --- a/src/object/object_holder.cpp +++ b/src/object/object_holder.cpp @@ -79,7 +79,7 @@ void object_holder::reset(object_proxy *proxy, cascade_type cascade) oid_ = 0; if (is_internal() && is_inserted_ && proxy_->ostore_) { --(*proxy_); - proxy_->ostore_->notify_relation_remove(*proxy_->node_, proxy->obj_, owner_); + proxy_->ostore_->notify_relation_remove(*proxy_->node_, proxy_->obj_, owner_); // proxy_->node_->notify_delete_relation(owner_, proxy); } proxy_->remove(this); diff --git a/test/Item.hpp b/test/Item.hpp index 08f2fc96c..8c0db2c9a 100644 --- a/test/Item.hpp +++ b/test/Item.hpp @@ -339,7 +339,7 @@ class department; class employee : public person { -private: +public: oos::belongs_to department_; public: diff --git a/test/object/ObjectStoreTestUnit.cpp b/test/object/ObjectStoreTestUnit.cpp index 56dca5485..9cae64c4f 100644 --- a/test/object/ObjectStoreTestUnit.cpp +++ b/test/object/ObjectStoreTestUnit.cpp @@ -1119,13 +1119,12 @@ void ObjectStoreTestUnit::test_belongs_to() i = dep->employees.erase(i); UNIT_ASSERT_EQUAL(dep->employees.size(), 1UL, "there must be one employee"); - UNIT_ASSERT_TRUE(jane->dep().empty(), "there must not be an department"); -// UNIT_ASSERT_EQUAL(dep->employees.front()->name(), "jane", "expected name must be jane"); -// UNIT_ASSERT_TRUE(george->dep().empty(), "there must be no department"); -// -// jane->dep().clear(); -// -// UNIT_ASSERT_TRUE(dep->employees.empty(), "there must be no employees"); + UNIT_ASSERT_TRUE(george->dep().empty(), "there must not be an department"); + UNIT_ASSERT_EQUAL(dep->employees.front()->name(), "jane", "expected name must be jane"); + + jane->department_.clear(); + + UNIT_ASSERT_TRUE(dep->employees.empty(), "there must be no employees"); } void ObjectStoreTestUnit::test_on_attach() From 4161468f67ead9baf4800dae18a641c32810a0eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Wed, 18 Jan 2017 22:02:42 +0100 Subject: [PATCH 26/61] added detach for persistence --- include/oos/object/has_many_vector.hpp | 4 +- include/oos/object/node_analyzer.hpp | 7 ++++ include/oos/object/object_store.hpp | 35 ++++++++++++++--- include/oos/orm/persistence.hpp | 26 ++++++++++++- src/object/object_store.cpp | 17 --------- src/orm/persistence.cpp | 11 ++++++ test/orm/OrmTestUnit.cpp | 52 ++++++++++++++++++++++++++ test/orm/OrmTestUnit.hpp | 1 + 8 files changed, 126 insertions(+), 27 deletions(-) diff --git a/include/oos/object/has_many_vector.hpp b/include/oos/object/has_many_vector.hpp index 097219be7..bcb13b37d 100644 --- a/include/oos/object/has_many_vector.hpp +++ b/include/oos/object/has_many_vector.hpp @@ -790,8 +790,8 @@ class has_many : public basic_has_many iterator i = start; if (this->ostore_) { while (i != end) { - typename base::relation_type iptr = (i++).relation_item(); - this->ostore_->remove(iptr); + relation_type iptr = (i++).relation_item(); + deleter_.remove(*this->ostore_, iptr, *this->owner_); } } return iterator(this->container_.erase(start.iter_, end.iter_)); diff --git a/include/oos/object/node_analyzer.hpp b/include/oos/object/node_analyzer.hpp index b7806f8db..d363bd62a 100644 --- a/include/oos/object/node_analyzer.hpp +++ b/include/oos/object/node_analyzer.hpp @@ -60,6 +60,13 @@ struct null_on_attach : public basic_on_attach void operator()(prototype_node*) const {} }; +struct null_on_detach : public basic_on_attach +{ + null_on_detach() {} + + void operator()(prototype_node*) const {} +}; + } } #endif //OOS_NODE_ANALYZER_HPP diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index 2ceeeb8de..5865e47e2 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -143,7 +143,7 @@ class OOS_OBJECT_API object_store /** * Inserts a new object prototype into the prototype tree. The prototype - * constist of a unique type name. To know where the new + * consists of a unique type name. To know where the new * prototype is inserted into the hierarchy the type name of the parent * node is also given. * parameter. @@ -159,7 +159,7 @@ class OOS_OBJECT_API object_store /** * Inserts a new object prototype into the prototype tree. The prototype - * constist of a unique type name (generated from typeid). To know where the new + * consists of a unique type name (generated from typeid). To know where the new * prototype is inserted into the hierarchy the type name of the parent * node is also given. * @@ -173,7 +173,7 @@ class OOS_OBJECT_API object_store /** * Inserts a new object prototype into the prototype tree. The prototype - * constist of a unique type name (generated from typeid). To know where the new + * consists of a unique type name (generated from typeid). To know where the new * prototype is inserted into the hierarchy the typeid of the parent * node is also given. * @@ -186,12 +186,13 @@ class OOS_OBJECT_API object_store prototype_iterator prepare_attach(bool abstract = false); /** - * Removes an serializable prototype from the prototype tree. All children + * Removes an object prototype from the prototype tree. All children * nodes and all objects are also removed. * * @param type The name of the type to remove. */ - void detach(const char *type); + template < class ON_DETACH = detail::null_on_detach > + void detach(const char *type, const ON_DETACH &on_detach = ON_DETACH()); /** * Erase a prototype node identified @@ -201,7 +202,8 @@ class OOS_OBJECT_API object_store * @param i The prototype iterator to be erased * @return The successor of the erased iterator */ - iterator detach(const prototype_iterator &i); + template < class ON_DETACH = detail::null_on_detach > + iterator detach(const prototype_iterator &i, const ON_DETACH &on_detach = ON_DETACH()); /** * Finds the typename to the given class. @@ -905,6 +907,27 @@ prototype_iterator object_store::prepare_attach(bool abstract) return prepare_attach(abstract, typeid(T).name()); } +template < class ON_DETACH > +void object_store::detach(const char *type, const ON_DETACH &on_detach) +{ + prototype_node *node = find_prototype_node(type); + if (!node) { + throw object_exception("unknown prototype type"); + } + on_detach(node); + remove_prototype_node(node, node->depth == 0); +} + +template < class ON_DETACH > +object_store::iterator object_store::detach(const prototype_iterator &i, const ON_DETACH &on_detach) +{ + if (i == end() || i.get() == nullptr) { + throw object_exception("invalid prototype iterator"); + } + on_detach(i.get()); + return remove_prototype_node(i.get(), i->depth == 0); +} + template prototype_node *object_store::acquire(const char *type, bool abstract) { diff --git a/include/oos/orm/persistence.hpp b/include/oos/orm/persistence.hpp index 03017f967..1a0c905c6 100644 --- a/include/oos/orm/persistence.hpp +++ b/include/oos/orm/persistence.hpp @@ -72,7 +72,7 @@ class OOS_ORM_API persistence /** * Inserts a new object prototype into the prototype tree. The prototype - * constist of a unique type name. To know where the new + * consists of a unique type name. To know where the new * prototype is inserted into the hierarchy the type name of the parent * node is also given. * @@ -87,7 +87,7 @@ class OOS_ORM_API persistence /** * Inserts a new object prototype into the prototype tree. The prototype - * constist of a unique type name. To know where the new + * consists of a unique type name. To know where the new * prototype is inserted into the hierarchy the type name of the parent * node is also given. * parameter. @@ -101,6 +101,14 @@ class OOS_ORM_API persistence template void attach(const char *type, bool abstract = false); + /** + * Removes an object prototype from the prototype tree. All children + * nodes and all objects are also removed. + * + * @param type The name of the type to remove. + */ + void detach(const char *type); + /** * Checks if the given entity as * table exists @@ -304,6 +312,10 @@ persistence_on_attach::persistence_on_attach(const persistence_on_attach & template void persistence_on_attach::operator()(prototype_node *node) const { + if (persistence_.get().tables_.find(node->type()) != persistence_.get().tables_.end()) { + return; + } + std::cout << "node type: " << node->type() << "\n"; persistence_.get().tables_.insert(std::make_pair(node->type(), std::make_shared>(node, persistence_))); } @@ -324,12 +336,22 @@ void persistence_on_attach>::operator()(prototype_node *node) c if (persistence_.get().tables_.find(node->type()) != persistence_.get().tables_.end()) { return; } + std::cout << "node relation type: " << node->type() << "\n"; persistence_.get().tables_.insert(std::make_pair( node->type(), std::make_shared>( node, persistence_, relation_, owner_type_, relation_id_, owner_id_column_, item_id_column_ ))); } +struct persistence_on_detach : public basic_persistence_on_attach +{ + using basic_persistence_on_attach::basic_persistence_on_attach; + + persistence_on_detach(persistence &p) : basic_persistence_on_attach(p) {} + + void operator()(prototype_node *node) const; +}; + /// @endcond } diff --git a/src/object/object_store.cpp b/src/object/object_store.cpp index 5c02d159b..854ad4a6b 100644 --- a/src/object/object_store.cpp +++ b/src/object/object_store.cpp @@ -42,23 +42,6 @@ object_store::~object_store() delete first_; } -void object_store::detach(const char *type) -{ - prototype_node *node = find_prototype_node(type); - if (!node) { - throw object_exception("unknown prototype type"); - } - remove_prototype_node(node, node->depth == 0); -} - -object_store::iterator object_store::detach(const prototype_iterator &i) -{ - if (i == end() || i.get() == nullptr) { - throw object_exception("invalid prototype iterator"); - } - return remove_prototype_node(i.get(), i->depth == 0); -} - object_store::iterator object_store::find(const char *type) { prototype_node *node = find_prototype_node(type); diff --git a/src/orm/persistence.cpp b/src/orm/persistence.cpp index cd778f626..40195cf10 100644 --- a/src/orm/persistence.cpp +++ b/src/orm/persistence.cpp @@ -19,6 +19,11 @@ persistence::~persistence() connection_.close(); } +void persistence::detach(const char *type) +{ + store_.detach(type, detail::persistence_on_detach(*this)); +} + void persistence::create() { for (t_table_map::value_type &val : tables_) { @@ -78,5 +83,11 @@ const connection &persistence::conn() const { return connection_; } +namespace detail { +void persistence_on_detach::operator()(prototype_node *node) const +{ +} + +} } \ No newline at end of file diff --git a/test/orm/OrmTestUnit.cpp b/test/orm/OrmTestUnit.cpp index 4e3c4e3d9..f74178e5c 100644 --- a/test/orm/OrmTestUnit.cpp +++ b/test/orm/OrmTestUnit.cpp @@ -28,6 +28,7 @@ OrmTestUnit::OrmTestUnit(const std::string &prefix, const std::string &dns) add_test("load_has_many", std::bind(&OrmTestUnit::test_load_has_many, this), "test orm load has many from table"); add_test("load_has_many_int", std::bind(&OrmTestUnit::test_load_has_many_int, this), "test orm load has many int from table"); add_test("has_many_delete", std::bind(&OrmTestUnit::test_has_many_delete, this), "test orm has many delete item"); + add_test("belongs_to", std::bind(&OrmTestUnit::test_belongs_to, this), "test orm belongs to"); } void OrmTestUnit::test_create() @@ -442,3 +443,54 @@ void OrmTestUnit::test_has_many_delete() p.drop(); } + +void OrmTestUnit::test_belongs_to() +{ + oos::persistence p(dns_); + + p.attach("person"); + p.attach("department"); + p.attach("employee"); + +// p.create(); +// +// oos::session s(p); +// +// auto george = s.insert(new employee("george")); +// auto jane = s.insert(new employee("jane")); +// auto dep = s.insert(new department("insurance")); +// +// UNIT_ASSERT_TRUE(dep->employees.empty(), "there must be no employees"); +// UNIT_ASSERT_TRUE(george->dep().empty(), "there must not be an department"); +// UNIT_ASSERT_TRUE(jane->dep().empty(), "there must not be an department"); +// +// // department is automatically set +// s.push_back(dep->employees, george); +// +// UNIT_ASSERT_EQUAL(dep->employees.size(), 1UL, "there must be one employee"); +// UNIT_ASSERT_EQUAL(dep->employees.front()->name(), "george", "expected name must be george"); +// UNIT_ASSERT_FALSE(george->dep().empty(), "department must not be empty"); +// UNIT_ASSERT_EQUAL(george->dep()->name, dep->name, "names must be equal"); +// +// // jane is automatically added to deps employee list +// jane->dep(dep); +// s.update(jane); +// +// UNIT_ASSERT_EQUAL(dep->employees.size(), 2UL, "there must be two employees"); +// +// // remove george +// auto i = dep->employees.begin(); +// i = dep->employees.erase(i); +// s.update(dep); +// +// UNIT_ASSERT_EQUAL(dep->employees.size(), 1UL, "there must be one employee"); +// UNIT_ASSERT_TRUE(george->dep().empty(), "there must not be an department"); +// UNIT_ASSERT_EQUAL(dep->employees.front()->name(), "jane", "expected name must be jane"); +// +// jane->department_.clear(); +// s.update(jane); +// +// UNIT_ASSERT_TRUE(dep->employees.empty(), "there must be no employees"); +// +// p.drop(); +} diff --git a/test/orm/OrmTestUnit.hpp b/test/orm/OrmTestUnit.hpp index dbc928fb1..975b6045c 100644 --- a/test/orm/OrmTestUnit.hpp +++ b/test/orm/OrmTestUnit.hpp @@ -23,6 +23,7 @@ class OrmTestUnit : public oos::unit_test void test_load_has_many(); void test_load_has_many_int(); void test_has_many_delete(); + void test_belongs_to(); private: std::string dns_; From f36232aa3b3897f458b38f5ad54247a8bac205b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Thu, 19 Jan 2017 22:17:29 +0100 Subject: [PATCH 27/61] introduced object store observer and persistence observer --- include/oos/object/node_analyzer.hpp | 28 +----- include/oos/object/node_analyzer.tpp | 32 +++---- include/oos/object/object_observer.hpp | 73 --------------- include/oos/object/object_store.hpp | 86 +++++++++-------- include/oos/object/object_store_observer.hpp | 98 ++++++++++++++++++++ include/oos/object/prototype_node.hpp | 2 +- include/oos/orm/persistence.hpp | 4 +- include/oos/orm/persistence_observer.hpp | 24 +++++ src/object/CMakeLists.txt | 2 +- src/object/object_store.cpp | 43 ++++++++- src/orm/CMakeLists.txt | 4 +- src/orm/persistence_observer.cpp | 29 ++++++ 12 files changed, 259 insertions(+), 166 deletions(-) delete mode 100644 include/oos/object/object_observer.hpp create mode 100644 include/oos/object/object_store_observer.hpp create mode 100644 include/oos/orm/persistence_observer.hpp create mode 100644 src/orm/persistence_observer.cpp diff --git a/include/oos/object/node_analyzer.hpp b/include/oos/object/node_analyzer.hpp index d363bd62a..9f6d54e0c 100644 --- a/include/oos/object/node_analyzer.hpp +++ b/include/oos/object/node_analyzer.hpp @@ -11,12 +11,11 @@ class prototype_node; namespace detail { -template < class T, template < class ... > class ON_ATTACH > +template < class T > class node_analyzer { public: - node_analyzer(prototype_node &node, const ON_ATTACH &on_attach) + explicit node_analyzer(prototype_node &node) : node_(node) - , on_attach_(on_attach) { } ~node_analyzer() { } @@ -42,29 +41,6 @@ class node_analyzer { private: prototype_node &node_; - ON_ATTACH on_attach_; -}; - -struct basic_on_attach {}; - -template < class T > -struct null_on_attach : public basic_on_attach -{ - null_on_attach() {} - template < class V > - null_on_attach(const null_on_attach &) {} - null_on_attach& operator=(const null_on_attach &) { return *this; } - template < class V > - null_on_attach& operator=(const null_on_attach &) { return *this; } - - void operator()(prototype_node*) const {} -}; - -struct null_on_detach : public basic_on_attach -{ - null_on_detach() {} - - void operator()(prototype_node*) const {} }; } diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index 98d74ccc2..e4b98d94c 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -7,8 +7,8 @@ namespace oos { namespace detail { -template class ON_ATTACH> -void node_analyzer::analyze() +template +void node_analyzer::analyze() { // std::cout << "START analyzing " << node_.type() << "\n"; T obj; @@ -16,16 +16,16 @@ void node_analyzer::analyze() // std::cout << "FINISHED analyzing " << node_.type() << "\n"; } -template class ON_ATTACH> +template template -void node_analyzer::serialize(V &x) +void node_analyzer::serialize(V &x) { oos::access::serialize(*this, x); } -template class ON_ATTACH> +template template -void node_analyzer::serialize(const char *id, belongs_to &x, cascade_type) +void node_analyzer::serialize(const char *id, belongs_to &x, cascade_type) { // std::cout << "analyzing belongs_to field " << id << " (typeid: " << typeid(V).name() << ")\n"; prototype_iterator node = node_.tree()->find(x.type()); @@ -53,9 +53,9 @@ void node_analyzer::serialize(const char *id, belongs_to &x, c }, node.get())); } -template class ON_ATTACH> +template template -void node_analyzer::serialize(const char *, has_one &x, cascade_type) +void node_analyzer::serialize(const char *, has_one &x, cascade_type) { // std::cout << "analyzing has_one field " << id << " (typeid: " << typeid(V).name() << ")\n"; prototype_iterator node = node_.tree()->find(x.type()); @@ -68,11 +68,11 @@ void node_analyzer::serialize(const char *, has_one &x, cascad } } -template class ON_ATTACH> +template template class C> -void node_analyzer::serialize(const char *id, has_many &, const char *, const char *, +void node_analyzer::serialize(const char *id, has_many &, const char *, const char *, typename std::enable_if::value>::type*) -//void node_analyzer::serialize(const char *id, has_many &x, const char */*owner_field*/, const char */*item_field*/) +//void node_analyzer::serialize(const char *id, has_many &x, const char */*owner_field*/, const char */*item_field*/) { // std::cout << "analyzing has_many field " << id << " (typeid: " << typeid(V).name() << ")\n"; // item column column names @@ -84,7 +84,7 @@ void node_analyzer::serialize(const char *id, has_many &, c // false: attach it prototype_iterator pi = node_.tree()->find(id); if (pi == node_.tree()->end()) { - pi = node_.tree()->template attach::item_type, ON_ATTACH>(id, false, nullptr, on_attach_); + pi = node_.tree()->template attach::item_type>(id, false, nullptr); node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { oos::append(static_cast(obj), field, object_ptr(owner)); }, [](void *obj, const std::string &field, oos::object_proxy *owner) { @@ -99,11 +99,11 @@ void node_analyzer::serialize(const char *id, has_many &, c } } -template class ON_ATTACH> +template template class C> -void node_analyzer::serialize(const char *id, has_many &, const char *, const char *, +void node_analyzer::serialize(const char *id, has_many &, const char *, const char *, typename std::enable_if::value>::type*) -//void node_analyzer::serialize(const char *id, has_many &x, const char */*owner_field*/, const char */*item_field*/) +//void node_analyzer::serialize(const char *id, has_many &x, const char */*owner_field*/, const char */*item_field*/) { // item column column names // x.owner_field(owner_field); @@ -114,7 +114,7 @@ void node_analyzer::serialize(const char *id, has_many &, c // false: attach it prototype_iterator pi = node_.tree()->find(id); if (pi == node_.tree()->end()) { - pi = node_.tree()->template attach::item_type, ON_ATTACH>(id, false, nullptr, on_attach_); + pi = node_.tree()->template attach::item_type>(id, false, nullptr); } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item throw_object_exception("many to many relations are not supported by now"); diff --git a/include/oos/object/object_observer.hpp b/include/oos/object/object_observer.hpp deleted file mode 100644 index 709f52201..000000000 --- a/include/oos/object/object_observer.hpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * This file is part of OpenObjectStore OOS. - * - * OpenObjectStore OOS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OpenObjectStore OOS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with OpenObjectStore OOS. If not, see . - */ - -#ifndef OBJECT_OBSERVER_HPP -#define OBJECT_OBSERVER_HPP - -namespace oos { - -class serializer; -class object_proxy; - -/** - * @class object_observer - * @brief Base class for serializable observer classes - * - * When interessted to observe insert, update and - * delete actions an observer class instance must be - * registered with serializable store. - * Use this class as base class for all observer classes. - */ -class OOS_OBJECT_API object_observer -{ -public: - virtual ~object_observer() {} - - /** - * @brief Called on serializable insertion. - * - * Called when an serializable is inserted - * into the object_store. - * - * @param proxy The proxy of the inserted serializable. - */ - virtual void on_insert(object_proxy *proxy) = 0; - - /** - * @brief Called on serializable update. - * - * Called when an serializable is updated - * in the object_store. - * - * @param proxy The proxy of the updated serializable. - */ - virtual void on_update(object_proxy *proxy) = 0; - - /** - * @brief Called on serializable deletion. - * - * Called when an serializable is deleted - * from the object_store. - * - * @param proxy The proxy of the deleted serializable. - */ - virtual void on_delete(object_proxy *proxy) = 0; -}; - -} - -#endif /* OBJECT_OBSERVER_HPP */ diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index 5865e47e2..773d85983 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -20,7 +20,7 @@ #include "oos/object/prototype_iterator.hpp" #include "oos/object/object_exception.hpp" -#include "oos/object/object_observer.hpp" +#include "oos/object/object_store_observer.hpp" #include "oos/object/object_inserter.hpp" #include "oos/object/object_deleter.hpp" #include "oos/object/node_analyzer.hpp" @@ -138,8 +138,8 @@ class OOS_OBJECT_API object_store * @param parent The name of the parent type. * @return Returns new inserted prototype iterator. */ - template< class T, template < class ... > class ON_ATTACH = detail::null_on_attach, typename = typename std::enable_if>::value>::type > - prototype_iterator attach(const char *type, bool abstract = false, const char *parent = nullptr, const ON_ATTACH &on_attach = ON_ATTACH()); + template< class T > + prototype_iterator attach(const char *type, bool abstract = false, const char *parent = nullptr); /** * Inserts a new object prototype into the prototype tree. The prototype @@ -154,8 +154,8 @@ class OOS_OBJECT_API object_store * @param abstract Indicates if the producers serializable is treated as an abstract node. * @return Returns new inserted prototype iterator. */ - template class ON_ATTACH = detail::null_on_attach, typename = typename std::enable_if>::value>::type > - prototype_iterator attach(const char *type, bool abstract = false, const ON_ATTACH &on_attach = ON_ATTACH()); + template + prototype_iterator attach(const char *type, bool abstract = false); /** * Inserts a new object prototype into the prototype tree. The prototype @@ -191,8 +191,7 @@ class OOS_OBJECT_API object_store * * @param type The name of the type to remove. */ - template < class ON_DETACH = detail::null_on_detach > - void detach(const char *type, const ON_DETACH &on_detach = ON_DETACH()); + void detach(const char *type); /** * Erase a prototype node identified @@ -202,8 +201,7 @@ class OOS_OBJECT_API object_store * @param i The prototype iterator to be erased * @return The successor of the erased iterator */ - template < class ON_DETACH = detail::null_on_detach > - iterator detach(const prototype_iterator &i, const ON_DETACH &on_detach = ON_DETACH()); + iterator detach(const prototype_iterator &i); /** * Finds the typename to the given class. @@ -445,6 +443,11 @@ class OOS_OBJECT_API object_store // insert element into hash map for fast lookup object_map_.insert(std::make_pair(proxy->id(), proxy)); + // call observers + std::for_each(observers_.begin(), observers_.end(), [proxy](object_store_observer *observer) { + observer->on_insert(proxy); + }); + return proxy; } @@ -536,6 +539,11 @@ class OOS_OBJECT_API object_store proxy->node()->remove(proxy); + // call observers + std::for_each(observers_.begin(), observers_.end(), [proxy](object_store_observer *observer) { + observer->on_delete(proxy); + }); + if (notify && !transactions_.empty()) { // notify transaction transactions_.top().on_delete(proxy); @@ -653,6 +661,9 @@ class OOS_OBJECT_API object_store */ sequencer_impl_ptr exchange_sequencer(const sequencer_impl_ptr &seq); + void register_observer(object_store_observer *observer); + void unregister_observer(object_store_observer *observer); + void notify_relation_insert(prototype_node::relation_info &info, void *owner, object_proxy *value); void notify_relation_insert(prototype_node &node, void *owner, object_proxy *value); void notify_relation_remove(prototype_node::relation_info &info, void *owner, object_proxy *value); @@ -764,8 +775,8 @@ class OOS_OBJECT_API object_store * @param node The node to initialize * @return iterator representing the prototype node */ - template class ON_ATTACH> - iterator initialize(prototype_node *node, const ON_ATTACH &on_attach); + template< class T > + iterator initialize(prototype_node *node); // object_proxy *initialze_proxy(object_proxy *oproxy, prototype_iterator &node, bool notify); @@ -800,8 +811,8 @@ class OOS_OBJECT_API object_store sequencer seq_; - typedef std::list t_observer_list; - t_observer_list observer_list_; + typedef std::list t_observer_list; + t_observer_list observers_; detail::object_deleter object_deleter_; detail::object_inserter object_inserter_; @@ -815,8 +826,8 @@ class OOS_OBJECT_API object_store bool relation_notification_ = true; }; -template class ON_ATTACH, typename Enabled > -object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent, const ON_ATTACH &on_attach) +template +object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent) { // set node to root node prototype_node *parent_node = find_parent(parent); @@ -852,15 +863,23 @@ object_store::iterator object_store::attach(const char *type, bool abstract, con prototype_map_.insert(std::make_pair(node->type_, node))/*.first*/; typeid_prototype_map_[typeid(T).name()].insert(std::make_pair(node->type_, node)); - on_attach(node); + // call observers + std::for_each(observers_.begin(), observers_.end(), [node](object_store_observer *observer) { + observer->on_attach(node); + }); + + // call observers + std::for_each(observers_.begin(), observers_.end(), [node](object_store_observer *observer) { + observer->on_attach(node); + }); - return initialize(node, on_attach); + return initialize(node); } -template class ON_ATTACH, typename Enabled > -object_store::iterator object_store::attach(const char *type, bool abstract, const ON_ATTACH &on_attach) +template +object_store::iterator object_store::attach(const char *type, bool abstract) { - return attach(type, abstract, typeid(S).name(), on_attach); + return attach(type, abstract, typeid(S).name()); } template @@ -907,27 +926,6 @@ prototype_iterator object_store::prepare_attach(bool abstract) return prepare_attach(abstract, typeid(T).name()); } -template < class ON_DETACH > -void object_store::detach(const char *type, const ON_DETACH &on_detach) -{ - prototype_node *node = find_prototype_node(type); - if (!node) { - throw object_exception("unknown prototype type"); - } - on_detach(node); - remove_prototype_node(node, node->depth == 0); -} - -template < class ON_DETACH > -object_store::iterator object_store::detach(const prototype_iterator &i, const ON_DETACH &on_detach) -{ - if (i == end() || i.get() == nullptr) { - throw object_exception("invalid prototype iterator"); - } - on_detach(i.get()); - return remove_prototype_node(i.get(), i->depth == 0); -} - template prototype_node *object_store::acquire(const char *type, bool abstract) { @@ -964,12 +962,12 @@ prototype_node *object_store::acquire(const char *type, bool abstract) return node; } -template class ON_ATTACH> -object_store::iterator object_store::initialize(prototype_node *node, const ON_ATTACH &on_attach) +template +object_store::iterator object_store::initialize(prototype_node *node) { // Check if nodes serializable has 'to-many' relations // Analyze primary and foreign keys of node - detail::node_analyzer analyzer(*node, on_attach); + detail::node_analyzer analyzer(*node); analyzer.analyze(); return prototype_iterator(node); diff --git a/include/oos/object/object_store_observer.hpp b/include/oos/object/object_store_observer.hpp new file mode 100644 index 000000000..1f7316945 --- /dev/null +++ b/include/oos/object/object_store_observer.hpp @@ -0,0 +1,98 @@ +/* + * This file is part of OpenObjectStore OOS. + * + * OpenObjectStore OOS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * OpenObjectStore OOS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenObjectStore OOS. If not, see . + */ + +#ifndef OBJECT_STORE_OBSERVER_HPP +#define OBJECT_STORE_OBSERVER_HPP + +namespace oos { + +class object_proxy; +class prototype_node; + +/** + * @class object_store_observer + * @brief Base class for object observer classes + * + * When interested to observe + * - attach (prototype_node) + * - detach (prototype_node) + * - insert (object) + * - update (object) + * - delete (object) + * actions an observer class instance must be + * registered with object store. + * Use this class as base class for all observer classes. + */ +class object_store_observer +{ +public: + virtual ~object_store_observer() {} + + /** + * @brief Called on prototype_node attach + * + * When a prototype node is attached to the object store + * this is called after the attaching succeeded. + * + * @param node The attached prototype node + */ + virtual void on_attach(prototype_node *node) = 0; + + /** + * @brief Called on prototype_node detach + * + * When a prototype node is detached from the object store + * this is called before the detaching succeeded. + * + * @param node The to be detached prototype node + */ + virtual void on_detach(prototype_node *node) = 0; + + /** + * @brief Called on object insertion. + * + * Called when an object is inserted + * into the object_store. + * + * @param proxy The proxy of the inserted object. + */ + virtual void on_insert(object_proxy *proxy) = 0; + + /** + * @brief Called on object update. + * + * Called when an object is updated + * in the object_store. + * + * @param proxy The proxy of the updated object. + */ + virtual void on_update(object_proxy *proxy) = 0; + + /** + * @brief Called on object deletion. + * + * Called when an object is deleted + * from the object_store. + * + * @param proxy The proxy of the deleted object. + */ + virtual void on_delete(object_proxy *proxy) = 0; +}; + +} + +#endif /* OBJECT_STORE_OBSERVER_HPP */ diff --git a/include/oos/object/prototype_node.hpp b/include/oos/object/prototype_node.hpp index 9d2c34420..954abb7df 100644 --- a/include/oos/object/prototype_node.hpp +++ b/include/oos/object/prototype_node.hpp @@ -52,7 +52,7 @@ template < class T, template class C, class Enabled > class has_many_inserter; template < class T, template class C, class Enabled > class has_many_deleter; -template < class T, template < class ... > class ON_ATTACH > +template < class T > class node_analyzer; } /** diff --git a/include/oos/orm/persistence.hpp b/include/oos/orm/persistence.hpp index 1a0c905c6..d22af922f 100644 --- a/include/oos/orm/persistence.hpp +++ b/include/oos/orm/persistence.hpp @@ -359,13 +359,13 @@ struct persistence_on_detach : public basic_persistence_on_attach template void persistence::attach(const char *type, bool abstract, const char *parent) { - store_.attach(type, abstract, parent, detail::persistence_on_attach(*this)); + store_.attach(type, abstract, parent); } template void persistence::attach(const char *type, bool abstract) { - store_.attach(type, abstract, detail::persistence_on_attach(*this)); + store_.attach(type, abstract); } } diff --git a/include/oos/orm/persistence_observer.hpp b/include/oos/orm/persistence_observer.hpp new file mode 100644 index 000000000..cca48bf7f --- /dev/null +++ b/include/oos/orm/persistence_observer.hpp @@ -0,0 +1,24 @@ +#ifndef OOS_PERSISTENCE_OBSERVER_HPP +#define OOS_PERSISTENCE_OBSERVER_HPP + +#include "oos/object/object_store_observer.hpp" + +namespace oos { + +class persistence_observer : public object_store_observer +{ +public: + void on_attach(prototype_node *node) override; + + void on_detach(prototype_node *node) override; + + void on_insert(object_proxy *proxy) override; + + void on_update(object_proxy *proxy) override; + + void on_delete(object_proxy *proxy) override; + +}; + +} +#endif //OOS_PERSISTENCE_OBSERVER_HPP diff --git a/src/object/CMakeLists.txt b/src/object/CMakeLists.txt index c5f968232..c4bc1fba6 100644 --- a/src/object/CMakeLists.txt +++ b/src/object/CMakeLists.txt @@ -29,7 +29,7 @@ SET(HEADER ${CMAKE_SOURCE_DIR}/include/oos/object/object_proxy.hpp ${CMAKE_SOURCE_DIR}/include/oos/object/object_serializer.hpp ${CMAKE_SOURCE_DIR}/include/oos/object/prototype_node.hpp - ${CMAKE_SOURCE_DIR}/include/oos/object/object_observer.hpp + ${CMAKE_SOURCE_DIR}/include/oos/object/object_store_observer.hpp ${CMAKE_SOURCE_DIR}/include/oos/object/object_expression.hpp ${CMAKE_SOURCE_DIR}/include/oos/object/attribute_serializer.hpp ${CMAKE_SOURCE_DIR}/include/oos/object/prototype_iterator.hpp diff --git a/src/object/object_store.cpp b/src/object/object_store.cpp index 854ad4a6b..c02b8c8c5 100644 --- a/src/object/object_store.cpp +++ b/src/object/object_store.cpp @@ -42,6 +42,25 @@ object_store::~object_store() delete first_; } +void object_store::detach(const char *type) +{ + prototype_node *node = find_prototype_node(type); + if (!node) { + throw object_exception("unknown prototype type"); + } + + remove_prototype_node(node, node->depth == 0); +} + +object_store::iterator object_store::detach(const prototype_iterator &i) +{ + if (i == end() || i.get() == nullptr) { + throw object_exception("invalid prototype iterator"); + } + + return remove_prototype_node(i.get(), i->depth == 0); +} + object_store::iterator object_store::find(const char *type) { prototype_node *node = find_prototype_node(type); @@ -266,6 +285,22 @@ sequencer_impl_ptr object_store::exchange_sequencer(const sequencer_impl_ptr &se return seq_.exchange_sequencer(seq); } +void object_store::register_observer(object_store_observer *observer) +{ + if (std::find(observers_.begin(), observers_.end(), observer) == observers_.end()) { + observers_.push_back(observer); + } +} + +void object_store::unregister_observer(object_store_observer *observer) +{ + auto i = std::find(observers_.begin(), observers_.end(), observer); + if (i != observers_.end()) { + delete *i; + observers_.erase(i); + } +} + void object_store::notify_relation_insert(prototype_node::relation_info &info, void *owner, object_proxy *value) { if (!is_relation_notification_enabled()) { @@ -341,7 +376,13 @@ prototype_node* object_store::find_prototype_node(const char *type) const { } } -prototype_node* object_store::remove_prototype_node(prototype_node *node, bool is_root) { +prototype_node* object_store::remove_prototype_node(prototype_node *node, bool is_root) +{ + // call observers + std::for_each(observers_.begin(), observers_.end(), [node](object_store_observer *observer) { + observer->on_detach(node); + }); + // remove (and delete) from tree (deletes subsequently all child nodes // for each child call remove_prototype(child); prototype_node *next = node->next_node(node); diff --git a/src/orm/CMakeLists.txt b/src/orm/CMakeLists.txt index 74c0c0d6d..7f70abae8 100644 --- a/src/orm/CMakeLists.txt +++ b/src/orm/CMakeLists.txt @@ -1,7 +1,7 @@ SET(SOURCES persistence.cpp session.cpp - basic_table.cpp) + basic_table.cpp persistence_observer.cpp) SET(HEADER ${CMAKE_SOURCE_DIR}/include/oos/orm/persistence.hpp @@ -12,7 +12,7 @@ SET(HEADER ${CMAKE_SOURCE_DIR}/include/oos/orm/identifier_column_resolver.hpp ${CMAKE_SOURCE_DIR}/include/oos/orm/relation_table.hpp ${CMAKE_SOURCE_DIR}/include/oos/orm/relation_resolver.hpp - ${CMAKE_SOURCE_DIR}/include/oos/orm/relation_item_appender.hpp) + ${CMAKE_SOURCE_DIR}/include/oos/orm/relation_item_appender.hpp ../../include/oos/orm/persistence_observer.hpp) ADD_LIBRARY(oos-orm SHARED ${SOURCES} ${HEADER}) diff --git a/src/orm/persistence_observer.cpp b/src/orm/persistence_observer.cpp new file mode 100644 index 000000000..5efe2b5b9 --- /dev/null +++ b/src/orm/persistence_observer.cpp @@ -0,0 +1,29 @@ +#include "oos/orm/persistence_observer.hpp" + +namespace oos { + +void persistence_observer::on_attach(prototype_node *node) +{ + +} + +void persistence_observer::on_detach(prototype_node *node) +{ + +} + +void persistence_observer::on_update(object_proxy *) +{ + +} + +void persistence_observer::on_insert(object_proxy *) +{ + +} + +void persistence_observer::on_delete(object_proxy *) +{ + +} +} \ No newline at end of file From 0786761d91767b7dd1e30e81ba6cfad69053c3d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Mon, 23 Jan 2017 22:47:57 +0100 Subject: [PATCH 28/61] object store observer progress --- include/oos/object/object_store.hpp | 56 ++-- include/oos/object/object_store_observer.hpp | 17 +- include/oos/object/prototype_node.hpp | 22 +- include/oos/orm/persistence.hpp | 261 +++++++++---------- include/oos/orm/persistence_observer.hpp | 19 +- src/object/object_store.cpp | 21 -- src/object/prototype_node.cpp | 4 +- src/orm/CMakeLists.txt | 2 +- src/orm/persistence.cpp | 9 +- src/orm/persistence_observer.cpp | 29 --- test/object/ObjectStoreTestUnit.cpp | 63 ----- 11 files changed, 193 insertions(+), 310 deletions(-) delete mode 100644 src/orm/persistence_observer.cpp diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index 773d85983..fe1cb1fa0 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -138,7 +138,7 @@ class OOS_OBJECT_API object_store * @param parent The name of the parent type. * @return Returns new inserted prototype iterator. */ - template< class T > + template< class T, template < class V = T > class ... O > prototype_iterator attach(const char *type, bool abstract = false, const char *parent = nullptr); /** @@ -154,7 +154,7 @@ class OOS_OBJECT_API object_store * @param abstract Indicates if the producers serializable is treated as an abstract node. * @return Returns new inserted prototype iterator. */ - template + template class ... O > prototype_iterator attach(const char *type, bool abstract = false); /** @@ -443,11 +443,6 @@ class OOS_OBJECT_API object_store // insert element into hash map for fast lookup object_map_.insert(std::make_pair(proxy->id(), proxy)); - // call observers - std::for_each(observers_.begin(), observers_.end(), [proxy](object_store_observer *observer) { - observer->on_insert(proxy); - }); - return proxy; } @@ -539,11 +534,6 @@ class OOS_OBJECT_API object_store proxy->node()->remove(proxy); - // call observers - std::for_each(observers_.begin(), observers_.end(), [proxy](object_store_observer *observer) { - observer->on_delete(proxy); - }); - if (notify && !transactions_.empty()) { // notify transaction transactions_.top().on_delete(proxy); @@ -661,9 +651,6 @@ class OOS_OBJECT_API object_store */ sequencer_impl_ptr exchange_sequencer(const sequencer_impl_ptr &seq); - void register_observer(object_store_observer *observer); - void unregister_observer(object_store_observer *observer); - void notify_relation_insert(prototype_node::relation_info &info, void *owner, object_proxy *value); void notify_relation_insert(prototype_node &node, void *owner, object_proxy *value); void notify_relation_remove(prototype_node::relation_info &info, void *owner, object_proxy *value); @@ -690,14 +677,14 @@ class OOS_OBJECT_API object_store private: - template < class T, typename = typename std::enable_if< std::is_same>::value >::type > - prototype_iterator attach(const char *id, abstract_has_many *container) - { - temp_container_ = container; - prototype_iterator i = attach(id); - temp_container_ = nullptr; - return i; - } +// template < class T, template < class V = T > class ... O, typename = typename std::enable_if< std::is_same>::value >::type > +// prototype_iterator attach(const char *id, abstract_has_many *container) +// { +// temp_container_ = container; +// prototype_iterator i = attach(id); +// temp_container_ = nullptr; +// return i; +// } /** * Clears a prototype_node and its @@ -811,9 +798,6 @@ class OOS_OBJECT_API object_store sequencer seq_; - typedef std::list t_observer_list; - t_observer_list observers_; - detail::object_deleter object_deleter_; detail::object_inserter object_inserter_; @@ -826,7 +810,7 @@ class OOS_OBJECT_API object_store bool relation_notification_ = true; }; -template +template class ... O > object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent) { // set node to root node @@ -863,23 +847,13 @@ object_store::iterator object_store::attach(const char *type, bool abstract, con prototype_map_.insert(std::make_pair(node->type_, node))/*.first*/; typeid_prototype_map_[typeid(T).name()].insert(std::make_pair(node->type_, node)); - // call observers - std::for_each(observers_.begin(), observers_.end(), [node](object_store_observer *observer) { - observer->on_attach(node); - }); - - // call observers - std::for_each(observers_.begin(), observers_.end(), [node](object_store_observer *observer) { - observer->on_attach(node); - }); - return initialize(node); } -template +template class ... O > object_store::iterator object_store::attach(const char *type, bool abstract) { - return attach(type, abstract, typeid(S).name()); + return attach(type, abstract, typeid(S).name()); } template @@ -897,7 +871,7 @@ prototype_iterator object_store::prepare_attach(bool abstract, const char *paren return prototype_iterator(i->second); } - std::unique_ptr node(new prototype_node(this, "", typeid(T), abstract)); + std::unique_ptr node(new prototype_node(this, "", new T, typeid(T), abstract)); node->initialize(this, "", abstract); @@ -957,7 +931,7 @@ prototype_node *object_store::acquire(const char *type, bool abstract) /* insert new prototype and add to * typeid map */ - node = new prototype_node(this, type, typeid(T), abstract); + node = new prototype_node(this, type, new T, typeid(T), abstract); } return node; } diff --git a/include/oos/object/object_store_observer.hpp b/include/oos/object/object_store_observer.hpp index 1f7316945..5096010d6 100644 --- a/include/oos/object/object_store_observer.hpp +++ b/include/oos/object/object_store_observer.hpp @@ -23,8 +23,17 @@ namespace oos { class object_proxy; class prototype_node; +/** + * Base class for all object store observer + */ +struct basic_object_store_observer +{ + virtual ~basic_object_store_observer() {} +}; + /** * @class object_store_observer + * @tparam T Type of the object store observer * @brief Base class for object observer classes * * When interested to observe @@ -37,10 +46,10 @@ class prototype_node; * registered with object store. * Use this class as base class for all observer classes. */ -class object_store_observer +template < class T > +class object_store_observer : public basic_object_store_observer { public: - virtual ~object_store_observer() {} /** * @brief Called on prototype_node attach @@ -50,7 +59,7 @@ class object_store_observer * * @param node The attached prototype node */ - virtual void on_attach(prototype_node *node) = 0; + virtual void on_attach(prototype_node *node, T *prototype) = 0; /** * @brief Called on prototype_node detach @@ -60,7 +69,7 @@ class object_store_observer * * @param node The to be detached prototype node */ - virtual void on_detach(prototype_node *node) = 0; + virtual void on_detach(prototype_node *node, T *prototype) = 0; /** * @brief Called on object insertion. diff --git a/include/oos/object/prototype_node.hpp b/include/oos/object/prototype_node.hpp index 954abb7df..54a10caa8 100644 --- a/include/oos/object/prototype_node.hpp +++ b/include/oos/object/prototype_node.hpp @@ -35,6 +35,7 @@ #include "oos/utils/identifier.hpp" #include "oos/object/identifier_proxy_map.hpp" +#include "oos/object/object_store_observer.hpp" #include #include @@ -109,13 +110,16 @@ class OOS_OBJECT_API prototype_node * @param typeinfo The typeinfo of this node. * @param abstract Tells the node if its prototype is abstract. */ - prototype_node(object_store *tree, const char *type, const std::type_info &typeinfo, bool abstract = false) + template < class T > + prototype_node(object_store *tree, const char *type, T *proto, const std::type_info &typeinfo, bool abstract = false) : tree_(tree) , first(new prototype_node) , last(new prototype_node) , type_(type) , abstract_(abstract) , type_index_(typeinfo) + , deleter_(&destroy) + , prototype(proto) { first->next = last.get(); last->prev = first.get(); @@ -337,6 +341,17 @@ class OOS_OBJECT_API prototype_node */ void adjust_left_marker(prototype_node *root, object_proxy *old_proxy, object_proxy *new_proxy); + typedef std::list t_observer_list; + typedef void (*deleter)(void*, t_observer_list&); + + template + static void destroy(void* p, t_observer_list &ol) + { + delete (T*)p; + for(auto i : ol) { + delete (object_store_observer*)i; + } + } private: friend class prototype_tree; friend class object_holder; @@ -378,6 +393,11 @@ class OOS_OBJECT_API prototype_node std::type_index type_index_; /**< type index of the represented object type */ + t_observer_list observer_list; + deleter deleter_; + + void* prototype = nullptr; + /** * Holds the primary keys of all proxies in this node */ diff --git a/include/oos/orm/persistence.hpp b/include/oos/orm/persistence.hpp index d22af922f..fe01d7d26 100644 --- a/include/oos/orm/persistence.hpp +++ b/include/oos/orm/persistence.hpp @@ -216,141 +216,132 @@ namespace detail { /// @cond OOS_DEV -struct basic_persistence_on_attach : public detail::basic_on_attach -{ - basic_persistence_on_attach(persistence &p) : persistence_(p) {} - basic_persistence_on_attach(const basic_persistence_on_attach &x) : persistence_(x.persistence_) {} - basic_persistence_on_attach& operator=(const basic_persistence_on_attach &x) { persistence_ = x.persistence_; return *this; } - - std::reference_wrapper persistence_; -}; - -template < class T > -struct persistence_on_attach : public basic_persistence_on_attach -{ - using basic_persistence_on_attach::basic_persistence_on_attach; - - persistence_on_attach(persistence &p) : basic_persistence_on_attach(p) {} - - template < class V > - persistence_on_attach(const persistence_on_attach &x); - - template < class V > - persistence_on_attach& operator=(const persistence_on_attach &x) { persistence_ = x.persistence_; return *this; } - - void operator()(prototype_node *node) const; -}; - -//template <> -template < class T > -struct persistence_on_attach> : public basic_persistence_on_attach -{ - using basic_persistence_on_attach::basic_persistence_on_attach; - - typedef has_many_item relation_type; - - persistence_on_attach(persistence &p) : basic_persistence_on_attach(p) {} - - persistence_on_attach(const persistence_on_attach &x) - : basic_persistence_on_attach(x) - , relation_(x.relation_) - { } - - template < class V > - persistence_on_attach(const persistence_on_attach &x); - - template < class V > - persistence_on_attach& operator=(const persistence_on_attach &x) { persistence_ = x.persistence_; return *this; } - - void operator()(prototype_node *node) const; - - - template < class V > - void serialize(T &obj) - { - oos::access::serialize(*this, obj); - } - - template < class V > - void serialize(const char *, identifier &) - { - std::shared_ptr id(new identifier); - id->as_value(true); - relation_.owner(id); - } - - template < class V > - void serialize(const char*, V &) {} - - template < class V > - void serialize(const char*, V &, size_t) {} - - template < class HAS_ONE > - void serialize(const char*, HAS_ONE &, cascade_type) {} - - template < class HAS_MANY > - void serialize(const char *id, HAS_MANY &, const char *owner_field, const char *item_field) - { - owner_id_column_.assign(owner_field); - item_id_column_.assign(item_field); - relation_id_.assign(id); - } - - relation_type relation_; - std::string owner_type_; - std::string relation_id_; - std::string owner_id_column_; - std::string item_id_column_; -}; - -template -template -persistence_on_attach::persistence_on_attach(const persistence_on_attach &x) - : basic_persistence_on_attach(x.persistence_) -{ } - -template -void persistence_on_attach::operator()(prototype_node *node) const -{ - if (persistence_.get().tables_.find(node->type()) != persistence_.get().tables_.end()) { - return; - } - std::cout << "node type: " << node->type() << "\n"; - persistence_.get().tables_.insert(std::make_pair(node->type(), std::make_shared>(node, persistence_))); -} - -template -template -persistence_on_attach>::persistence_on_attach(const persistence_on_attach &x) - : basic_persistence_on_attach(x.persistence_) -{ - V owner; - owner_type_ = persistence_.get().store().find(typeid(V).name())->type(); - oos::access::serialize(*this, owner); -} - -//template <> -template -void persistence_on_attach>::operator()(prototype_node *node) const -{ - if (persistence_.get().tables_.find(node->type()) != persistence_.get().tables_.end()) { - return; - } - std::cout << "node relation type: " << node->type() << "\n"; - persistence_.get().tables_.insert(std::make_pair( - node->type(), std::make_shared>( - node, persistence_, relation_, owner_type_, relation_id_, owner_id_column_, item_id_column_ - ))); -} - -struct persistence_on_detach : public basic_persistence_on_attach -{ - using basic_persistence_on_attach::basic_persistence_on_attach; - - persistence_on_detach(persistence &p) : basic_persistence_on_attach(p) {} - - void operator()(prototype_node *node) const; -}; +//struct basic_persistence_on_attach : public detail::basic_on_attach +//{ +// basic_persistence_on_attach(persistence &p) : persistence_(p) {} +// basic_persistence_on_attach(const basic_persistence_on_attach &x) : persistence_(x.persistence_) {} +// basic_persistence_on_attach& operator=(const basic_persistence_on_attach &x) { persistence_ = x.persistence_; return *this; } +// +// std::reference_wrapper persistence_; +//}; +// +//template < class T > +//struct persistence_on_attach : public basic_persistence_on_attach +//{ +// using basic_persistence_on_attach::basic_persistence_on_attach; +// +// persistence_on_attach(persistence &p) : basic_persistence_on_attach(p) {} +// +// template < class V > +// persistence_on_attach(const persistence_on_attach &x); +// +// template < class V > +// persistence_on_attach& operator=(const persistence_on_attach &x) { persistence_ = x.persistence_; return *this; } +// +// void operator()(prototype_node *node) const; +//}; +// +////template <> +//template < class T > +//struct persistence_on_attach> : public basic_persistence_on_attach +//{ +// using basic_persistence_on_attach::basic_persistence_on_attach; +// +// typedef has_many_item relation_type; +// +// persistence_on_attach(persistence &p) : basic_persistence_on_attach(p) {} +// +// persistence_on_attach(const persistence_on_attach &x) +// : basic_persistence_on_attach(x) +// , relation_(x.relation_) +// { } +// +// template < class V > +// persistence_on_attach(const persistence_on_attach &x); +// +// template < class V > +// persistence_on_attach& operator=(const persistence_on_attach &x) { persistence_ = x.persistence_; return *this; } +// +// void operator()(prototype_node *node) const; +// +// +// template < class V > +// void serialize(T &obj) +// { +// oos::access::serialize(*this, obj); +// } +// +// template < class V > +// void serialize(const char *, identifier &) +// { +// std::shared_ptr id(new identifier); +// id->as_value(true); +// relation_.owner(id); +// } +// +// template < class V > +// void serialize(const char*, V &) {} +// +// template < class V > +// void serialize(const char*, V &, size_t) {} +// +// template < class HAS_ONE > +// void serialize(const char*, HAS_ONE &, cascade_type) {} +// +// template < class HAS_MANY > +// void serialize(const char *id, HAS_MANY &, const char *owner_field, const char *item_field) +// { +// owner_id_column_.assign(owner_field); +// item_id_column_.assign(item_field); +// relation_id_.assign(id); +// } +// +// relation_type relation_; +// std::string owner_type_; +// std::string relation_id_; +// std::string owner_id_column_; +// std::string item_id_column_; +//}; +// +//template +//template +//persistence_on_attach::persistence_on_attach(const persistence_on_attach &x) +// : basic_persistence_on_attach(x.persistence_) +//{ } +// +//template +//void persistence_on_attach::operator()(prototype_node *node) const +//{ +// if (persistence_.get().tables_.find(node->type()) != persistence_.get().tables_.end()) { +// return; +// } +// std::cout << "node type: " << node->type() << "\n"; +// persistence_.get().tables_.insert(std::make_pair(node->type(), std::make_shared>(node, persistence_))); +//} +// +//template +//template +//persistence_on_attach>::persistence_on_attach(const persistence_on_attach &x) +// : basic_persistence_on_attach(x.persistence_) +//{ +// V owner; +// owner_type_ = persistence_.get().store().find(typeid(V).name())->type(); +// oos::access::serialize(*this, owner); +//} +// +////template <> +//template +//void persistence_on_attach>::operator()(prototype_node *node) const +//{ +// if (persistence_.get().tables_.find(node->type()) != persistence_.get().tables_.end()) { +// return; +// } +// std::cout << "node relation type: " << node->type() << "\n"; +// persistence_.get().tables_.insert(std::make_pair( +// node->type(), std::make_shared>( +// node, persistence_, relation_, owner_type_, relation_id_, owner_id_column_, item_id_column_ +// ))); +//} /// @endcond diff --git a/include/oos/orm/persistence_observer.hpp b/include/oos/orm/persistence_observer.hpp index cca48bf7f..e923b0bfe 100644 --- a/include/oos/orm/persistence_observer.hpp +++ b/include/oos/orm/persistence_observer.hpp @@ -5,18 +5,25 @@ namespace oos { -class persistence_observer : public object_store_observer +template < class T > +class persistence_observer : public object_store_observer { public: - void on_attach(prototype_node *node) override; + void on_attach(prototype_node *node, T *proto) override + { - void on_detach(prototype_node *node) override; + } - void on_insert(object_proxy *proxy) override; + void on_detach(prototype_node *node, T *proto) override + { - void on_update(object_proxy *proxy) override; + } - void on_delete(object_proxy *proxy) override; + void on_insert(object_proxy *proxy) override {} + + void on_update(object_proxy *proxy) override {} + + void on_delete(object_proxy *proxy) override {} }; diff --git a/src/object/object_store.cpp b/src/object/object_store.cpp index c02b8c8c5..3cc7e3ed0 100644 --- a/src/object/object_store.cpp +++ b/src/object/object_store.cpp @@ -285,22 +285,6 @@ sequencer_impl_ptr object_store::exchange_sequencer(const sequencer_impl_ptr &se return seq_.exchange_sequencer(seq); } -void object_store::register_observer(object_store_observer *observer) -{ - if (std::find(observers_.begin(), observers_.end(), observer) == observers_.end()) { - observers_.push_back(observer); - } -} - -void object_store::unregister_observer(object_store_observer *observer) -{ - auto i = std::find(observers_.begin(), observers_.end(), observer); - if (i != observers_.end()) { - delete *i; - observers_.erase(i); - } -} - void object_store::notify_relation_insert(prototype_node::relation_info &info, void *owner, object_proxy *value) { if (!is_relation_notification_enabled()) { @@ -378,11 +362,6 @@ prototype_node* object_store::find_prototype_node(const char *type) const { prototype_node* object_store::remove_prototype_node(prototype_node *node, bool is_root) { - // call observers - std::for_each(observers_.begin(), observers_.end(), [node](object_store_observer *observer) { - observer->on_detach(node); - }); - // remove (and delete) from tree (deletes subsequently all child nodes // for each child call remove_prototype(child); prototype_node *next = node->next_node(node); diff --git a/src/object/prototype_node.cpp b/src/object/prototype_node.cpp index 9c65da2cb..f091b55b2 100644 --- a/src/object/prototype_node.cpp +++ b/src/object/prototype_node.cpp @@ -30,7 +30,9 @@ prototype_node::prototype_node() {} prototype_node::~prototype_node() -{} +{ + deleter_(prototype, observer_list); +} void prototype_node::initialize(object_store *tree, const char *type, bool abstract) { diff --git a/src/orm/CMakeLists.txt b/src/orm/CMakeLists.txt index 7f70abae8..b5bd23a98 100644 --- a/src/orm/CMakeLists.txt +++ b/src/orm/CMakeLists.txt @@ -1,7 +1,7 @@ SET(SOURCES persistence.cpp session.cpp - basic_table.cpp persistence_observer.cpp) + basic_table.cpp) SET(HEADER ${CMAKE_SOURCE_DIR}/include/oos/orm/persistence.hpp diff --git a/src/orm/persistence.cpp b/src/orm/persistence.cpp index 40195cf10..39794c459 100644 --- a/src/orm/persistence.cpp +++ b/src/orm/persistence.cpp @@ -21,7 +21,7 @@ persistence::~persistence() void persistence::detach(const char *type) { - store_.detach(type, detail::persistence_on_detach(*this)); + store_.detach(type); } void persistence::create() @@ -83,11 +83,4 @@ const connection &persistence::conn() const { return connection_; } -namespace detail { -void persistence_on_detach::operator()(prototype_node *node) const -{ - -} - -} } \ No newline at end of file diff --git a/src/orm/persistence_observer.cpp b/src/orm/persistence_observer.cpp deleted file mode 100644 index 5efe2b5b9..000000000 --- a/src/orm/persistence_observer.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "oos/orm/persistence_observer.hpp" - -namespace oos { - -void persistence_observer::on_attach(prototype_node *node) -{ - -} - -void persistence_observer::on_detach(prototype_node *node) -{ - -} - -void persistence_observer::on_update(object_proxy *) -{ - -} - -void persistence_observer::on_insert(object_proxy *) -{ - -} - -void persistence_observer::on_delete(object_proxy *) -{ - -} -} \ No newline at end of file diff --git a/test/object/ObjectStoreTestUnit.cpp b/test/object/ObjectStoreTestUnit.cpp index 9cae64c4f..d24563611 100644 --- a/test/object/ObjectStoreTestUnit.cpp +++ b/test/object/ObjectStoreTestUnit.cpp @@ -43,7 +43,6 @@ ObjectStoreTestUnit::ObjectStoreTestUnit() add_test("has_many", std::bind(&ObjectStoreTestUnit::test_has_many, this), "has many test"); // add_test("has_many_to_many", std::bind(&ObjectStoreTestUnit::test_has_many_to_many, this), "has many to many test"); add_test("belongs_to", std::bind(&ObjectStoreTestUnit::test_belongs_to, this), "test belongs to behaviour"); - add_test("on_attach", std::bind(&ObjectStoreTestUnit::test_on_attach, this), "test on attach callback"); } struct basic_test_pair @@ -1034,56 +1033,6 @@ void ObjectStoreTestUnit::test_has_many_to_many() std::vector table_names = {}; -struct on_attach_base : public oos::detail::basic_on_attach -{ - std::string name; - on_attach_base() {} - on_attach_base(const std::string &n) : name(n) {} - on_attach_base& operator=(const on_attach_base &x) { name = x.name; return *this; } -}; - -template < class T > -struct on_attach : public on_attach_base -{ - using on_attach_base::on_attach_base; - - on_attach() {} - - template < class V > - on_attach(const on_attach &x) : on_attach_base(x.name) {} - - template < class V > - on_attach& operator=(const on_attach &x) - { - name = x.name; return *this; - } - - void operator()(prototype_node *node) const - { - table_names.push_back(node->type()); - } -}; - -//template <> -template < class T > -struct on_attach> : public on_attach_base -{ - using on_attach_base::on_attach_base; - - typedef has_many_item type; - - template < class V > - on_attach(const on_attach &x) : on_attach_base(x.name) {} - - template < class V > - on_attach& operator=(const on_attach &x) { name = x.name; return *this; } - - void operator()(prototype_node *node) const - { - table_names.push_back(node->type()); - } -}; - void ObjectStoreTestUnit::test_belongs_to() { ostore_.attach("person"); @@ -1127,15 +1076,3 @@ void ObjectStoreTestUnit::test_belongs_to() UNIT_ASSERT_TRUE(dep->employees.empty(), "there must be no employees"); } -void ObjectStoreTestUnit::test_on_attach() -{ - ostore_.attach("book", false, nullptr); - ostore_.attach("book_list", false, nullptr); - - UNIT_ASSERT_EQUAL(3UL, table_names.size(), "size must be three"); - - UNIT_ASSERT_EQUAL("book", table_names[0], "type must be book"); - UNIT_ASSERT_EQUAL("book_list", table_names[1], "type must be book_list"); - UNIT_ASSERT_EQUAL("books", table_names[2], "type must be books"); -} - From 32dfa1b6ea9e8f05c56faacf2ed1359263266dfb Mon Sep 17 00:00:00 2001 From: zussel Date: Tue, 24 Jan 2017 17:46:24 +0100 Subject: [PATCH 29/61] observer progress --- include/oos/object/node_analyzer.hpp | 11 +- include/oos/object/node_analyzer.tpp | 54 ++++---- include/oos/object/object_store.hpp | 91 ++++++++----- include/oos/object/object_store_observer.hpp | 25 +++- include/oos/object/prototype_node.hpp | 59 ++++++++- include/oos/orm/persistence.hpp | 37 +++--- include/oos/orm/persistence_observer.hpp | 33 +++-- include/oos/orm/persistence_observer.tpp | 37 ++++++ src/object/object_store.cpp | 4 + src/object/prototype_node.cpp | 4 +- src/orm/CMakeLists.txt | 5 +- test/object/ObjectStoreTestUnit.cpp | 129 +++++++++++++------ test/object/ObjectStoreTestUnit.hpp | 3 +- 13 files changed, 355 insertions(+), 137 deletions(-) create mode 100644 include/oos/orm/persistence_observer.tpp diff --git a/include/oos/object/node_analyzer.hpp b/include/oos/object/node_analyzer.hpp index 9f6d54e0c..e0d0b3f8a 100644 --- a/include/oos/object/node_analyzer.hpp +++ b/include/oos/object/node_analyzer.hpp @@ -11,11 +11,11 @@ class prototype_node; namespace detail { -template < class T > +template < class T, template < class V = T > class ... O > class node_analyzer { public: - explicit node_analyzer(prototype_node &node) - : node_(node) + explicit node_analyzer(prototype_node &node, O*... observer) + : node_(node), observer_(observer...) { } ~node_analyzer() { } @@ -39,8 +39,13 @@ class node_analyzer { void serialize(const char *, has_many &, const char *, const char *, typename std::enable_if::value>::type* = 0); +private: + template < class IT, std::size_t... Is > + prototype_iterator attach(object_store &store, const char *id, const std::tuple*...>& tuple, std::index_sequence); + private: prototype_node &node_; + std::tuple*...> observer_; }; } diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index e4b98d94c..04c1a1715 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -7,8 +7,8 @@ namespace oos { namespace detail { -template -void node_analyzer::analyze() +template class ... O> +void node_analyzer::analyze() { // std::cout << "START analyzing " << node_.type() << "\n"; T obj; @@ -16,16 +16,16 @@ void node_analyzer::analyze() // std::cout << "FINISHED analyzing " << node_.type() << "\n"; } -template +template class ... O> template -void node_analyzer::serialize(V &x) +void node_analyzer::serialize(V &x) { oos::access::serialize(*this, x); } -template +template class ... O> template -void node_analyzer::serialize(const char *id, belongs_to &x, cascade_type) +void node_analyzer::serialize(const char *id, belongs_to &x, cascade_type) { // std::cout << "analyzing belongs_to field " << id << " (typeid: " << typeid(V).name() << ")\n"; prototype_iterator node = node_.tree()->find(x.type()); @@ -53,9 +53,9 @@ void node_analyzer::serialize(const char *id, belongs_to &x, cascade_type }, node.get())); } -template +template class ... O> template -void node_analyzer::serialize(const char *, has_one &x, cascade_type) +void node_analyzer::serialize(const char *, has_one &x, cascade_type) { // std::cout << "analyzing has_one field " << id << " (typeid: " << typeid(V).name() << ")\n"; prototype_iterator node = node_.tree()->find(x.type()); @@ -68,23 +68,19 @@ void node_analyzer::serialize(const char *, has_one &x, cascade_type) } } -template +template class ... O> template class C> -void node_analyzer::serialize(const char *id, has_many &, const char *, const char *, +void node_analyzer::serialize(const char *id, has_many &, const char *, const char *, typename std::enable_if::value>::type*) -//void node_analyzer::serialize(const char *id, has_many &x, const char */*owner_field*/, const char */*item_field*/) { -// std::cout << "analyzing has_many field " << id << " (typeid: " << typeid(V).name() << ")\n"; - // item column column names -// x.owner_field(owner_field); -// x.item_field(item_field); // attach relation table for has many relation // check if has many item is already attached // true: check owner and item field // false: attach it prototype_iterator pi = node_.tree()->find(id); if (pi == node_.tree()->end()) { - pi = node_.tree()->template attach::item_type>(id, false, nullptr); + pi = this->attach::item_type>(*node_.tree(), id, observer_, std::index_sequence_for*...>()); +// pi = node_.tree()->template attach::item_type, O...>(id, false, nullptr, observer_); node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { oos::append(static_cast(obj), field, object_ptr(owner)); }, [](void *obj, const std::string &field, oos::object_proxy *owner) { @@ -93,28 +89,30 @@ void node_analyzer::serialize(const char *id, has_many &, const char * } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item throw_object_exception("many to many relations are not supported by now"); + } else if (pi->belongs_to_map_.find(node_.type_index_) != pi->belongs_to_map_.end()) { + // found corresponding belongs_to + node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { + oos::append(static_cast(obj), field, object_ptr(owner)); + }, [](void *obj, const std::string &field, oos::object_proxy *owner) { + oos::remove(static_cast(obj), field, object_ptr(owner)); + }, pi.get())); } else { - // throw exception throw_object_exception("prototype already inserted: " << pi->type()); } } -template +template class ... O> template class C> -void node_analyzer::serialize(const char *id, has_many &, const char *, const char *, +void node_analyzer::serialize(const char *id, has_many &, const char *, const char *, typename std::enable_if::value>::type*) -//void node_analyzer::serialize(const char *id, has_many &x, const char */*owner_field*/, const char */*item_field*/) { - // item column column names -// x.owner_field(owner_field); -// x.item_field(item_field); // attach relation table for has many relation // check if has many item is already attached // true: check owner and item field // false: attach it prototype_iterator pi = node_.tree()->find(id); if (pi == node_.tree()->end()) { - pi = node_.tree()->template attach::item_type>(id, false, nullptr); + pi = node_.tree()->template attach::item_type, O...>(id, false, nullptr, observer_); } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item throw_object_exception("many to many relations are not supported by now"); @@ -124,5 +122,13 @@ void node_analyzer::serialize(const char *id, has_many &, const char * } } +template class ... O> +template +prototype_iterator node_analyzer::attach(object_store &store, const char *id, const std::tuple*...>& observer, std::index_sequence) +{ + store.template attach(id, false, nullptr, std::get(observer)...); + return prototype_iterator(); +} + } } \ No newline at end of file diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index fe1cb1fa0..49e99571e 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -138,8 +138,14 @@ class OOS_OBJECT_API object_store * @param parent The name of the parent type. * @return Returns new inserted prototype iterator. */ - template< class T, template < class V = T > class ... O > - prototype_iterator attach(const char *type, bool abstract = false, const char *parent = nullptr); +// template< class T, template < class V = T > class ... O > +// prototype_iterator attach(const char *type, bool abstract = false, const char *parent = nullptr); + + template class ... O > + prototype_iterator attach(const char *type, O*... observer); + + template class ... O > + prototype_iterator attach(const char *type, bool abstract = false, const char *parent = nullptr, O*... observer); /** * Inserts a new object prototype into the prototype tree. The prototype @@ -154,8 +160,14 @@ class OOS_OBJECT_API object_store * @param abstract Indicates if the producers serializable is treated as an abstract node. * @return Returns new inserted prototype iterator. */ +// template class ... O > +// prototype_iterator attach(const char *type, bool abstract = false); + template class ... O > - prototype_iterator attach(const char *type, bool abstract = false); + prototype_iterator attach(const char *type, O*... observer); + + template class ... O > + prototype_iterator attach(const char *type, bool abstract = false, O*... observer); /** * Inserts a new object prototype into the prototype tree. The prototype @@ -756,17 +768,6 @@ class OOS_OBJECT_API object_store template prototype_node *acquire(const char *type, bool abstract); - /** - * Initializes a prototype node - * - * @param node The node to initialize - * @return iterator representing the prototype node - */ - template< class T > - iterator initialize(prototype_node *node); - -// object_proxy *initialze_proxy(object_proxy *oproxy, prototype_iterator &node, bool notify); - prototype_node* find_parent(const char *name) const; void push_transaction(const transaction &tr); @@ -776,6 +777,22 @@ class OOS_OBJECT_API object_store void enable_relation_notification(); void disable_relation_notification(); + template< class T > + void create_observer(prototype_node *) {} + + template< class T, template < class V = T > class HEAD > + void create_observer(prototype_node *node, HEAD* observer) + { + node->register_observer(observer); + } + + template< class T, template < class V = T > class HEAD, template < class V = T > class ... TAIL > + void create_observer(prototype_node *node, HEAD* observer, TAIL*... observer_list) + { + node->register_observer(observer); + create_observer(node, observer_list...); + } + private: typedef std::unordered_map t_prototype_map; // typeid -> [name -> prototype] @@ -811,7 +828,13 @@ class OOS_OBJECT_API object_store }; template class ... O > -object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent) +object_store::iterator object_store::attach(const char *type, O*... observer) +{ + return attach(type, false, nullptr, observer...); +} + +template class ... O > +object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent, O*... observer) { // set node to root node prototype_node *parent_node = find_parent(parent); @@ -842,18 +865,39 @@ object_store::iterator object_store::attach(const char *type, bool abstract, con } } + create_observer(node, observer...); + // store prototype in map // Todo: check return value prototype_map_.insert(std::make_pair(node->type_, node))/*.first*/; typeid_prototype_map_[typeid(T).name()].insert(std::make_pair(node->type_, node)); - return initialize(node); + // Check if nodes serializable has 'to-many' relations + // Analyze primary and foreign keys of node + detail::node_analyzer analyzer(*node, observer...); + analyzer.analyze(); + + node->on_attach(); + + return prototype_iterator(node); +} + +//template class ... O > +//object_store::iterator object_store::attach(const char *type, bool abstract, O*... observer) +//{ +// return iterator(); +//} + +template class ... O > +object_store::iterator object_store::attach(const char *type, O*... observer) +{ + return attach(type, false, observer...); } template class ... O > -object_store::iterator object_store::attach(const char *type, bool abstract) +object_store::iterator object_store::attach(const char *type, bool abstract, O*... observer) { - return attach(type, abstract, typeid(S).name()); + return attach(type, abstract, typeid(S).name(), observer...); } template @@ -936,17 +980,6 @@ prototype_node *object_store::acquire(const char *type, bool abstract) return node; } -template -object_store::iterator object_store::initialize(prototype_node *node) -{ - // Check if nodes serializable has 'to-many' relations - // Analyze primary and foreign keys of node - detail::node_analyzer analyzer(*node); - analyzer.analyze(); - - return prototype_iterator(node); -} - namespace detail { template < class T > diff --git a/include/oos/object/object_store_observer.hpp b/include/oos/object/object_store_observer.hpp index 5096010d6..550849765 100644 --- a/include/oos/object/object_store_observer.hpp +++ b/include/oos/object/object_store_observer.hpp @@ -26,9 +26,20 @@ class prototype_node; /** * Base class for all object store observer */ -struct basic_object_store_observer +class basic_object_store_observer { +protected: + basic_object_store_observer(const std::type_index &tindex) + : type_index_(tindex) + {} + +public: virtual ~basic_object_store_observer() {} + + const std::type_index& index() const { return type_index_; } + +private: + std::type_index type_index_; }; /** @@ -51,6 +62,8 @@ class object_store_observer : public basic_object_store_observer { public: + object_store_observer() : basic_object_store_observer(std::type_index(typeid(T))) {} + /** * @brief Called on prototype_node attach * @@ -59,7 +72,7 @@ class object_store_observer : public basic_object_store_observer * * @param node The attached prototype node */ - virtual void on_attach(prototype_node *node, T *prototype) = 0; + virtual void on_attach(prototype_node &node, T &prototype) = 0; /** * @brief Called on prototype_node detach @@ -69,7 +82,7 @@ class object_store_observer : public basic_object_store_observer * * @param node The to be detached prototype node */ - virtual void on_detach(prototype_node *node, T *prototype) = 0; + virtual void on_detach(prototype_node &node, T &prototype) = 0; /** * @brief Called on object insertion. @@ -79,7 +92,7 @@ class object_store_observer : public basic_object_store_observer * * @param proxy The proxy of the inserted object. */ - virtual void on_insert(object_proxy *proxy) = 0; + virtual void on_insert(object_proxy &proxy) = 0; /** * @brief Called on object update. @@ -89,7 +102,7 @@ class object_store_observer : public basic_object_store_observer * * @param proxy The proxy of the updated object. */ - virtual void on_update(object_proxy *proxy) = 0; + virtual void on_update(object_proxy &proxy) = 0; /** * @brief Called on object deletion. @@ -99,7 +112,7 @@ class object_store_observer : public basic_object_store_observer * * @param proxy The proxy of the deleted object. */ - virtual void on_delete(object_proxy *proxy) = 0; + virtual void on_delete(object_proxy &proxy) = 0; }; } diff --git a/include/oos/object/prototype_node.hpp b/include/oos/object/prototype_node.hpp index 54a10caa8..a14c6c313 100644 --- a/include/oos/object/prototype_node.hpp +++ b/include/oos/object/prototype_node.hpp @@ -53,7 +53,7 @@ template < class T, template class C, class Enabled > class has_many_inserter; template < class T, template class C, class Enabled > class has_many_deleter; -template < class T > +template < class T, template < class V = T > class ... O > class node_analyzer; } /** @@ -119,6 +119,7 @@ class OOS_OBJECT_API prototype_node , abstract_(abstract) , type_index_(typeinfo) , deleter_(&destroy) + , notifier_(¬ify_observer) , prototype(proto) { first->next = last.get(); @@ -320,6 +321,8 @@ class OOS_OBJECT_API prototype_node private: + enum notification_type { ATTACH, DETACH, INSERT, UPDATE, DELETE }; + /** * @internal * @@ -341,8 +344,18 @@ class OOS_OBJECT_API prototype_node */ void adjust_left_marker(prototype_node *root, object_proxy *old_proxy, object_proxy *new_proxy); + void register_observer(basic_object_store_observer *obs) + { + if (type_index_ != obs->index()) { + std::cout << "not same type\n"; + throw std::runtime_error("not same type"); + } + observer_list.push_back(obs); + } + typedef std::list t_observer_list; typedef void (*deleter)(void*, t_observer_list&); + typedef void (*notifier)(notification_type, prototype_node&, void*, basic_object_store_observer*); template static void destroy(void* p, t_observer_list &ol) @@ -352,6 +365,47 @@ class OOS_OBJECT_API prototype_node delete (object_store_observer*)i; } } + + void on_attach() + { + notify(ATTACH); + } + + void on_detach() + { + notify(DETACH); + } + + void notify(notification_type t) { + if (!notifier_) { + return; + } + for (auto i : observer_list) { + notifier_(t, *this, prototype, i); + } + } + + template < typename T > + static void notify_observer(notification_type t, prototype_node &pt, void *p, basic_object_store_observer *obs) + { + switch (t) { + case ATTACH: + static_cast*>(obs)->on_attach(pt, *(T*)p); + break; + case DETACH: + static_cast*>(obs)->on_detach(pt, *(T*)p); + break; + case INSERT: + break; + case UPDATE: + break; + case DELETE: + break; + default: + break; + } + } + private: friend class prototype_tree; friend class object_holder; @@ -394,7 +448,8 @@ class OOS_OBJECT_API prototype_node std::type_index type_index_; /**< type index of the represented object type */ t_observer_list observer_list; - deleter deleter_; + deleter deleter_ = nullptr; + notifier notifier_ = nullptr; void* prototype = nullptr; diff --git a/include/oos/orm/persistence.hpp b/include/oos/orm/persistence.hpp index fe01d7d26..d3a14bf4d 100644 --- a/include/oos/orm/persistence.hpp +++ b/include/oos/orm/persistence.hpp @@ -24,23 +24,13 @@ #include "oos/orm/table.hpp" #include "oos/orm/relation_table.hpp" +#include "oos/orm/persistence_observer.hpp" #include #include namespace oos { -namespace detail { - -/// @cond OOS_DEV - -template < class T > -struct persistence_on_attach; - -/// @endcond - -} - /** * @brief Represents the persistence layer for a database and an object_store * @@ -68,6 +58,7 @@ class OOS_ORM_API persistence * @param dns The database connection string */ explicit persistence(const std::string &dns); + ~persistence(); /** @@ -116,7 +107,7 @@ class OOS_ORM_API persistence * @tparam T entity type class * @return True if table exists */ - template < class T > + template bool exists() { t_table_map::iterator i = tables_.find(store_.type()); @@ -178,32 +169,33 @@ class OOS_ORM_API persistence * * @return A reference to the object_store. */ - object_store& store(); + object_store &store(); /** * @brief Return a const reference to the underlaying object_store * * @return A const reference to the object_store. */ - const object_store& store() const; + const object_store &store() const; /** * @brief Return a reference to the underlaying database connection * * @return A reference to the database connection. */ - connection& conn(); + connection &conn(); /** * @brief Return a const reference to the underlaying database connection * * @return A const reference to the database connection. */ - const connection& conn() const; + const connection &conn() const; private: - template < class T > - friend struct detail::persistence_on_attach; + template + friend + class persistence_observer; private: connection connection_; @@ -346,17 +338,22 @@ namespace detail { /// @endcond } +} + +#include "oos/orm/persistence_observer.tpp" + +namespace oos { template void persistence::attach(const char *type, bool abstract, const char *parent) { - store_.attach(type, abstract, parent); + store_.attach(type, abstract, parent, new persistence_observer(*this)); } template void persistence::attach(const char *type, bool abstract) { - store_.attach(type, abstract); + store_.attach(type, abstract, new persistence_observer(*this)); } } diff --git a/include/oos/orm/persistence_observer.hpp b/include/oos/orm/persistence_observer.hpp index e923b0bfe..dfb553db7 100644 --- a/include/oos/orm/persistence_observer.hpp +++ b/include/oos/orm/persistence_observer.hpp @@ -2,29 +2,44 @@ #define OOS_PERSISTENCE_OBSERVER_HPP #include "oos/object/object_store_observer.hpp" +#include "oos/object/has_many_item.hpp" namespace oos { +class persistence; + template < class T > class persistence_observer : public object_store_observer { public: - void on_attach(prototype_node *node, T *proto) override - { + persistence_observer(persistence &p) : persistence_(p) {} - } + void on_attach(prototype_node &node, T &proto) override; + void on_detach(prototype_node &node, T &proto) override; - void on_detach(prototype_node *node, T *proto) override - { + void on_insert(object_proxy &) override {} + void on_update(object_proxy &) override {} + void on_delete(object_proxy &) override {} - } +private: + persistence& persistence_; +}; - void on_insert(object_proxy *proxy) override {} +template < class T > +class persistence_observer> : public object_store_observer> +{ +public: + persistence_observer(persistence &p) : persistence_(p) {} - void on_update(object_proxy *proxy) override {} + void on_attach(prototype_node &node, has_many_item &proto) override; + void on_detach(prototype_node &node, has_many_item &proto) override; - void on_delete(object_proxy *proxy) override {} + void on_insert(object_proxy &) override {} + void on_update(object_proxy &) override {} + void on_delete(object_proxy &) override {} +private: + persistence& persistence_; }; } diff --git a/include/oos/orm/persistence_observer.tpp b/include/oos/orm/persistence_observer.tpp new file mode 100644 index 000000000..7148729bd --- /dev/null +++ b/include/oos/orm/persistence_observer.tpp @@ -0,0 +1,37 @@ +#include "oos/orm/persistence_observer.hpp" +#include "oos/orm/persistence.hpp" + +namespace oos { +template +void persistence_observer::on_attach(prototype_node &node, T &proto) +{ + if (persistence_.tables_.find(node.type()) != persistence_.tables_.end()) { + return; + } + std::cout << "node type: " << node.type() << "\n"; + persistence_.tables_.insert(std::make_pair(node.type(), std::make_shared>(&node, persistence_))); + +} + +template +void persistence_observer::on_detach(prototype_node &node, T &proto) +{ + +} + +template +void persistence_observer>::on_attach(prototype_node &node, oos::has_many_item &proto) +{ + if (persistence_.tables_.find(node.type()) != persistence_.tables_.end()) { + return; + } + std::cout << "node type: " << node.type() << "\n"; +} + +template +void persistence_observer>::on_detach(prototype_node &node, oos::has_many_item &proto) +{ + +} + +} \ No newline at end of file diff --git a/src/object/object_store.cpp b/src/object/object_store.cpp index 3cc7e3ed0..cd6ee8941 100644 --- a/src/object/object_store.cpp +++ b/src/object/object_store.cpp @@ -49,6 +49,8 @@ void object_store::detach(const char *type) throw object_exception("unknown prototype type"); } + node->on_detach(); + remove_prototype_node(node, node->depth == 0); } @@ -58,6 +60,8 @@ object_store::iterator object_store::detach(const prototype_iterator &i) throw object_exception("invalid prototype iterator"); } + i->on_detach(); + return remove_prototype_node(i.get(), i->depth == 0); } diff --git a/src/object/prototype_node.cpp b/src/object/prototype_node.cpp index f091b55b2..ec46376d5 100644 --- a/src/object/prototype_node.cpp +++ b/src/object/prototype_node.cpp @@ -31,7 +31,9 @@ prototype_node::prototype_node() prototype_node::~prototype_node() { - deleter_(prototype, observer_list); + if (deleter_) { + deleter_(prototype, observer_list); + } } void prototype_node::initialize(object_store *tree, const char *type, bool abstract) diff --git a/src/orm/CMakeLists.txt b/src/orm/CMakeLists.txt index b5bd23a98..475018b98 100644 --- a/src/orm/CMakeLists.txt +++ b/src/orm/CMakeLists.txt @@ -12,7 +12,10 @@ SET(HEADER ${CMAKE_SOURCE_DIR}/include/oos/orm/identifier_column_resolver.hpp ${CMAKE_SOURCE_DIR}/include/oos/orm/relation_table.hpp ${CMAKE_SOURCE_DIR}/include/oos/orm/relation_resolver.hpp - ${CMAKE_SOURCE_DIR}/include/oos/orm/relation_item_appender.hpp ../../include/oos/orm/persistence_observer.hpp) + ${CMAKE_SOURCE_DIR}/include/oos/orm/relation_item_appender.hpp + ${CMAKE_SOURCE_DIR}/include/oos/orm/persistence_observer.hpp + ${CMAKE_SOURCE_DIR}/include/oos/orm/persistence_observer.tpp +) ADD_LIBRARY(oos-orm SHARED ${SOURCES} ${HEADER}) diff --git a/test/object/ObjectStoreTestUnit.cpp b/test/object/ObjectStoreTestUnit.cpp index d24563611..c58938ed4 100644 --- a/test/object/ObjectStoreTestUnit.cpp +++ b/test/object/ObjectStoreTestUnit.cpp @@ -43,6 +43,7 @@ ObjectStoreTestUnit::ObjectStoreTestUnit() add_test("has_many", std::bind(&ObjectStoreTestUnit::test_has_many, this), "has many test"); // add_test("has_many_to_many", std::bind(&ObjectStoreTestUnit::test_has_many_to_many, this), "has many to many test"); add_test("belongs_to", std::bind(&ObjectStoreTestUnit::test_belongs_to, this), "test belongs to behaviour"); + add_test("observer", std::bind(&ObjectStoreTestUnit::test_observer, this), "test observer functionality"); } struct basic_test_pair @@ -77,16 +78,7 @@ struct test_pair : public basic_test_pair size_t size; }; -void -ObjectStoreTestUnit::initialize() -{ - ostore_.attach("item"); - ostore_.attach >("object_item"); - ostore_.attach("object_item_ptr_list"); -} - -void -ObjectStoreTestUnit::finalize() +void ObjectStoreTestUnit::finalize() { ostore_.clear(true); } @@ -99,8 +91,7 @@ struct item_counter : public std::unary_function("item"); + typedef object_ptr item_ptr; item_ptr item_null; @@ -129,9 +122,12 @@ void ObjectStoreTestUnit::test_optr() UNIT_ASSERT_NOT_NULL(item.store(), "item must be internal"); } -void -ObjectStoreTestUnit::test_expression() +void ObjectStoreTestUnit::test_expression() { + ostore_.attach("item"); + ostore_.attach >("object_item"); + ostore_.attach("object_item_ptr_list"); + typedef object_ptr > object_item_ptr; typedef object_ptr item_ptr; typedef object_ptr itemlist_ptr; @@ -203,8 +199,7 @@ ObjectStoreTestUnit::test_expression() UNIT_ASSERT_EQUAL((*j)->get_string(), "ObjectItem", "couldn't find item 'ObjectItem'"); } -void -ObjectStoreTestUnit::test_serializer() +void ObjectStoreTestUnit::test_serializer() { char c = 'c'; float f = 1.55f; @@ -309,6 +304,9 @@ void ObjectStoreTestUnit::test_identifier_serializer() void ObjectStoreTestUnit::test_reference_counter() { + ostore_.attach("item"); + ostore_.attach >("object_item"); + Item *i = new Item("Item", 7); typedef object_ptr item_ptr; @@ -339,8 +337,7 @@ void ObjectStoreTestUnit::test_reference_counter() } -void -ObjectStoreTestUnit::test_set() +void ObjectStoreTestUnit::test_set() { oos::date dt(15, 9, 1972); oos::time t(2008, 12, 27, 13, 6, 57, 4711); @@ -390,8 +387,7 @@ ObjectStoreTestUnit::test_set() // UNIT_ASSERT_EQUAL("elefant", i.get_string(), "invalid value"); } -void -ObjectStoreTestUnit::test_get() +void ObjectStoreTestUnit::test_get() { test_pair c('c'); test_pair b(true); @@ -459,9 +455,10 @@ ObjectStoreTestUnit::test_get() UNIT_ASSERT_EQUAL(timeval.result, timeval.expected, "invalid value"); } -void -ObjectStoreTestUnit::test_simple_object() +void ObjectStoreTestUnit::test_simple_object() { + ostore_.attach("item"); + Item *a = ostore_.create(); UNIT_ASSERT_NOT_NULL(a, "couldn't create object of type "); @@ -477,9 +474,11 @@ ObjectStoreTestUnit::test_simple_object() ostore_.remove(simple); } -void -ObjectStoreTestUnit::test_object_with_sub_object() +void ObjectStoreTestUnit::test_object_with_sub_object() { + ostore_.attach("item"); + ostore_.attach >("object_item"); + ObjectItem *s = ostore_.create>(); UNIT_ASSERT_NOT_NULL(s, "couldn't create object of type "); @@ -500,9 +499,10 @@ ObjectStoreTestUnit::test_object_with_sub_object() ostore_.remove(ows); } -void -ObjectStoreTestUnit::test_multiple_simple_objects() +void ObjectStoreTestUnit::test_multiple_simple_objects() { + ostore_.attach("item"); + typedef object_ptr item_ptr; size_t elem_size = 10; @@ -521,9 +521,11 @@ ObjectStoreTestUnit::test_multiple_simple_objects() UNIT_ASSERT_EQUAL(elem_size, simple_view.size(), "expected size of view isn't 10"); } -void -ObjectStoreTestUnit::test_multiple_object_with_sub_objects() +void ObjectStoreTestUnit::test_multiple_object_with_sub_objects() { + ostore_.attach("item"); + ostore_.attach >("object_item"); + typedef object_ptr > ows_ptr; // create 10 objects @@ -542,9 +544,11 @@ ObjectStoreTestUnit::test_multiple_object_with_sub_objects() UNIT_ASSERT_EQUAL(elem_size, withsub_view.size(), "expected size of view isn't 10"); } -void -ObjectStoreTestUnit::test_delete_object() +void ObjectStoreTestUnit::test_delete_object() { + ostore_.attach("item"); + ostore_.attach >("object_item"); + typedef ObjectItem TestItem; typedef object_ptr test_item_ptr; typedef object_ptr item_ptr; @@ -575,9 +579,9 @@ ObjectStoreTestUnit::test_delete_object() ostore_.remove(item); } -void -ObjectStoreTestUnit::test_hierarchy() +void ObjectStoreTestUnit::test_hierarchy() { + ostore_.attach("item"); ostore_.attach("ITEM_A"); ostore_.attach("ITEM_B"); ostore_.attach("ITEM_C"); @@ -671,9 +675,10 @@ ObjectStoreTestUnit::test_hierarchy() } } -void -ObjectStoreTestUnit::test_view() +void ObjectStoreTestUnit::test_view() { + ostore_.attach("item"); + for (int i = 0; i < 10; ++i) { std::stringstream str; str << "Item " << i+1; @@ -697,9 +702,10 @@ ObjectStoreTestUnit::test_view() UNIT_ASSERT_GREATER(item->id(), 0UL, "invalid item"); } -void -ObjectStoreTestUnit::test_clear() +void ObjectStoreTestUnit::test_clear() { + ostore_.attach("item"); + for (int i = 0; i < 10; ++i) { std::stringstream str; str << "Item " << i+1; @@ -733,8 +739,7 @@ ObjectStoreTestUnit::test_clear() UNIT_ASSERT_TRUE(first == last, "prototype iterator must be the same"); } -void -ObjectStoreTestUnit::test_generic() +void ObjectStoreTestUnit::test_generic() { test_pair c('c'); test_pair b(true); @@ -861,6 +866,9 @@ ObjectStoreTestUnit::test_generic() void ObjectStoreTestUnit::test_structure() { + ostore_.attach("item"); + ostore_.attach >("object_item"); + typedef ObjectItem object_item_t; typedef object_ptr object_item_ptr; typedef object_ptr item_ptr; @@ -961,6 +969,8 @@ void ObjectStoreTestUnit::test_structure_container() void ObjectStoreTestUnit::test_transient_optr() { + ostore_.attach("item"); + typedef object_ptr item_ptr; item_ptr item(new Item("item", 5)); @@ -972,6 +982,8 @@ void ObjectStoreTestUnit::test_transient_optr() void ObjectStoreTestUnit::test_insert() { + ostore_.attach("item"); + UNIT_ASSERT_EXCEPTION(ostore_.insert((Item *)nullptr), object_exception, "object is null", "null shouldn't be insertable"); std::unique_ptr ic(new ItemC); @@ -984,6 +996,8 @@ void ObjectStoreTestUnit::test_insert() void ObjectStoreTestUnit::test_remove() { + ostore_.attach("item"); + typedef object_ptr item_ptr; item_ptr item; @@ -1031,8 +1045,6 @@ void ObjectStoreTestUnit::test_has_many_to_many() UNIT_ASSERT_EQUAL(4UL, ostore_.size(), "unexpected size"); } -std::vector table_names = {}; - void ObjectStoreTestUnit::test_belongs_to() { ostore_.attach("person"); @@ -1076,3 +1088,40 @@ void ObjectStoreTestUnit::test_belongs_to() UNIT_ASSERT_TRUE(dep->employees.empty(), "there must be no employees"); } +template < class T > +struct logger : public object_store_observer +{ + void on_attach(prototype_node &node, T &) override + { + std::cout << "attaching node " << node.type() << "\n"; + } + + void on_detach(prototype_node &node, T &) override + { + std::cout << "detaching node " << node.type() << "\n"; + } + + void on_insert(object_proxy &proxy) override + { + std::cout << "inserting proxy " << &proxy << "\n"; + } + + void on_update(object_proxy &proxy) override + { + std::cout << "updating proxy " << &proxy << "\n"; + } + + void on_delete(object_proxy &proxy) override + { + std::cout << "deleting proxy " << &proxy << "\n"; + } +}; + +void ObjectStoreTestUnit::test_observer() +{ + ostore_.attach("person", new logger); + ostore_.attach("employee", new logger); + ostore_.attach("department", new logger); + ostore_.attach("book", new logger); + ostore_.attach("book_list", new logger); +} diff --git a/test/object/ObjectStoreTestUnit.hpp b/test/object/ObjectStoreTestUnit.hpp index 8a34bb599..6161d8c6c 100644 --- a/test/object/ObjectStoreTestUnit.hpp +++ b/test/object/ObjectStoreTestUnit.hpp @@ -13,7 +13,6 @@ class ObjectStoreTestUnit : public oos::unit_test public: ObjectStoreTestUnit(); - virtual void initialize(); virtual void finalize(); void test_version(); @@ -43,7 +42,7 @@ class ObjectStoreTestUnit : public oos::unit_test void test_has_many(); void test_has_many_to_many(); void test_belongs_to(); - void test_on_attach(); + void test_observer(); private: oos::object_store ostore_; From 848036e0d7422f6e648249157edd51d6c60a5870 Mon Sep 17 00:00:00 2001 From: zussel Date: Wed, 25 Jan 2017 17:37:56 +0100 Subject: [PATCH 30/61] observer progress --- include/oos/object/node_analyzer.tpp | 10 ++++++---- include/oos/object/object_store.hpp | 10 ++++++++++ test/object/ObjectStoreTestUnit.cpp | 14 +++++++++++--- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index 04c1a1715..3afb4ad4d 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -37,7 +37,9 @@ void node_analyzer::serialize(const char *id, belongs_to &x, cascad // yes, node found! // Todo: check if node is for has many item // detach has_many_item node - node_.tree()->detach(i->second.node); + if (i->second.node != nullptr) { + node_.tree()->detach(i->second.node); + } i->second.node = nullptr; } } else { @@ -112,7 +114,8 @@ void node_analyzer::serialize(const char *id, has_many &, const // false: attach it prototype_iterator pi = node_.tree()->find(id); if (pi == node_.tree()->end()) { - pi = node_.tree()->template attach::item_type, O...>(id, false, nullptr, observer_); + pi = this->attach::item_type>(*node_.tree(), id, observer_, std::index_sequence_for*...>()); +// pi = node_.tree()->template attach::item_type, O...>(id, false, nullptr, observer_); } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item throw_object_exception("many to many relations are not supported by now"); @@ -126,8 +129,7 @@ template class ... O> template prototype_iterator node_analyzer::attach(object_store &store, const char *id, const std::tuple*...>& observer, std::index_sequence) { - store.template attach(id, false, nullptr, std::get(observer)...); - return prototype_iterator(); + return store.template attach(id, false, nullptr, std::get(observer)...); } } diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index 49e99571e..3bd394cf5 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -147,6 +147,9 @@ class OOS_OBJECT_API object_store template class ... O > prototype_iterator attach(const char *type, bool abstract = false, const char *parent = nullptr, O*... observer); + template + object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent, const std::initializer_list*> &observer); + /** * Inserts a new object prototype into the prototype tree. The prototype * consists of a unique type name. To know where the new @@ -836,6 +839,7 @@ object_store::iterator object_store::attach(const char *type, O*... observer) template class ... O > object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent, O*... observer) { + return attach(type, abstract, parent, { observer... }); // set node to root node prototype_node *parent_node = find_parent(parent); /* @@ -882,6 +886,12 @@ object_store::iterator object_store::attach(const char *type, bool abstract, con return prototype_iterator(node); } +template +object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent, const std::initializer_list*> &observer) +{ + return iterator(); +}; + //template class ... O > //object_store::iterator object_store::attach(const char *type, bool abstract, O*... observer) //{ diff --git a/test/object/ObjectStoreTestUnit.cpp b/test/object/ObjectStoreTestUnit.cpp index c58938ed4..6eb35f301 100644 --- a/test/object/ObjectStoreTestUnit.cpp +++ b/test/object/ObjectStoreTestUnit.cpp @@ -1119,9 +1119,17 @@ struct logger : public object_store_observer void ObjectStoreTestUnit::test_observer() { +// ostore_.attach("person", new logger); +// ostore_.attach("employee", new logger); +// ostore_.attach("department", new logger); +// ostore_.attach("book", new logger); +// ostore_.attach("book_list", new logger); +// +// ostore_.clear(true); + ostore_.attach("person", new logger); - ostore_.attach("employee", new logger); ostore_.attach("department", new logger); - ostore_.attach("book", new logger); - ostore_.attach("book_list", new logger); + ostore_.attach("employee", new logger); +// ostore_.attach("book", new logger); +// ostore_.attach("book_list", new logger); } From 6b417d4b0654dcb23e6daf4380aa528b6aff3c8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Wed, 25 Jan 2017 23:29:09 +0100 Subject: [PATCH 31/61] observer progress --- include/oos/object/node_analyzer.hpp | 12 ++-- include/oos/object/node_analyzer.tpp | 35 +++++------ include/oos/object/object_store.hpp | 88 ++++++++++++--------------- include/oos/object/prototype_node.hpp | 4 +- 4 files changed, 59 insertions(+), 80 deletions(-) diff --git a/include/oos/object/node_analyzer.hpp b/include/oos/object/node_analyzer.hpp index e0d0b3f8a..cc9d96be0 100644 --- a/include/oos/object/node_analyzer.hpp +++ b/include/oos/object/node_analyzer.hpp @@ -11,11 +11,11 @@ class prototype_node; namespace detail { -template < class T, template < class V = T > class ... O > +template < class T, template < class U = T > class O > class node_analyzer { public: - explicit node_analyzer(prototype_node &node, O*... observer) - : node_(node), observer_(observer...) + explicit node_analyzer(prototype_node &node, const std::initializer_list*> &observer) + : node_(node), observer_(observer) { } ~node_analyzer() { } @@ -39,13 +39,9 @@ class node_analyzer { void serialize(const char *, has_many &, const char *, const char *, typename std::enable_if::value>::type* = 0); -private: - template < class IT, std::size_t... Is > - prototype_iterator attach(object_store &store, const char *id, const std::tuple*...>& tuple, std::index_sequence); - private: prototype_node &node_; - std::tuple*...> observer_; + const std::initializer_list*> &observer_; }; } diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index 3afb4ad4d..0bcdde5bc 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -7,8 +7,8 @@ namespace oos { namespace detail { -template class ... O> -void node_analyzer::analyze() +template class O> +void node_analyzer::analyze() { // std::cout << "START analyzing " << node_.type() << "\n"; T obj; @@ -16,16 +16,16 @@ void node_analyzer::analyze() // std::cout << "FINISHED analyzing " << node_.type() << "\n"; } -template class ... O> +template class O> template -void node_analyzer::serialize(V &x) +void node_analyzer::serialize(V &x) { oos::access::serialize(*this, x); } -template class ... O> +template class O> template -void node_analyzer::serialize(const char *id, belongs_to &x, cascade_type) +void node_analyzer::serialize(const char *id, belongs_to &x, cascade_type) { // std::cout << "analyzing belongs_to field " << id << " (typeid: " << typeid(V).name() << ")\n"; prototype_iterator node = node_.tree()->find(x.type()); @@ -55,9 +55,9 @@ void node_analyzer::serialize(const char *id, belongs_to &x, cascad }, node.get())); } -template class ... O> +template class O> template -void node_analyzer::serialize(const char *, has_one &x, cascade_type) +void node_analyzer::serialize(const char *, has_one &x, cascade_type) { // std::cout << "analyzing has_one field " << id << " (typeid: " << typeid(V).name() << ")\n"; prototype_iterator node = node_.tree()->find(x.type()); @@ -70,9 +70,9 @@ void node_analyzer::serialize(const char *, has_one &x, cascade_typ } } -template class ... O> +template class O> template class C> -void node_analyzer::serialize(const char *id, has_many &, const char *, const char *, +void node_analyzer::serialize(const char *id, has_many &, const char *, const char *, typename std::enable_if::value>::type*) { // attach relation table for has many relation @@ -81,7 +81,7 @@ void node_analyzer::serialize(const char *id, has_many &, const // false: attach it prototype_iterator pi = node_.tree()->find(id); if (pi == node_.tree()->end()) { - pi = this->attach::item_type>(*node_.tree(), id, observer_, std::index_sequence_for*...>()); + pi = node_.tree()->attach::item_type>(id, false, nullptr, observer_); // pi = node_.tree()->template attach::item_type, O...>(id, false, nullptr, observer_); node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { oos::append(static_cast(obj), field, object_ptr(owner)); @@ -103,9 +103,9 @@ void node_analyzer::serialize(const char *id, has_many &, const } } -template class ... O> +template class O> template class C> -void node_analyzer::serialize(const char *id, has_many &, const char *, const char *, +void node_analyzer::serialize(const char *id, has_many &, const char *, const char *, typename std::enable_if::value>::type*) { // attach relation table for has many relation @@ -114,7 +114,7 @@ void node_analyzer::serialize(const char *id, has_many &, const // false: attach it prototype_iterator pi = node_.tree()->find(id); if (pi == node_.tree()->end()) { - pi = this->attach::item_type>(*node_.tree(), id, observer_, std::index_sequence_for*...>()); + pi = node_.tree()->attach::item_type>(id, false, nullptr, observer_); // pi = node_.tree()->template attach::item_type, O...>(id, false, nullptr, observer_); } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item @@ -125,12 +125,5 @@ void node_analyzer::serialize(const char *id, has_many &, const } } -template class ... O> -template -prototype_iterator node_analyzer::attach(object_store &store, const char *id, const std::tuple*...>& observer, std::index_sequence) -{ - return store.template attach(id, false, nullptr, std::get(observer)...); -} - } } \ No newline at end of file diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index 3bd394cf5..8c84175eb 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -141,14 +141,11 @@ class OOS_OBJECT_API object_store // template< class T, template < class V = T > class ... O > // prototype_iterator attach(const char *type, bool abstract = false, const char *parent = nullptr); - template class ... O > - prototype_iterator attach(const char *type, O*... observer); + template class O > + prototype_iterator attach(const char *type, std::initializer_list*> observer = {}); - template class ... O > - prototype_iterator attach(const char *type, bool abstract = false, const char *parent = nullptr, O*... observer); - - template - object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent, const std::initializer_list*> &observer); + template class O > + object_store::iterator attach(const char *type, bool abstract, const char *parent, std::initializer_list*> observer = {}); /** * Inserts a new object prototype into the prototype tree. The prototype @@ -166,11 +163,11 @@ class OOS_OBJECT_API object_store // template class ... O > // prototype_iterator attach(const char *type, bool abstract = false); - template class ... O > - prototype_iterator attach(const char *type, O*... observer); + template class O > + prototype_iterator attach(const char *type, std::initializer_list*> observer = {}); - template class ... O > - prototype_iterator attach(const char *type, bool abstract = false, O*... observer); + template class O > + prototype_iterator attach(const char *type, bool abstract = false, std::initializer_list*> observer = {}); /** * Inserts a new object prototype into the prototype tree. The prototype @@ -830,16 +827,15 @@ class OOS_OBJECT_API object_store bool relation_notification_ = true; }; -template class ... O > -object_store::iterator object_store::attach(const char *type, O*... observer) +template class O > +object_store::iterator object_store::attach(const char *type, std::initializer_list*> observer) { - return attach(type, false, nullptr, observer...); + return attach(type, false, nullptr, observer); } -template class ... O > -object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent, O*... observer) +template class O > +object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent, std::initializer_list*> observer) { - return attach(type, abstract, parent, { observer... }); // set node to root node prototype_node *parent_node = find_parent(parent); /* @@ -849,36 +845,36 @@ object_store::iterator object_store::attach(const char *type, bool abstract, con prototype_node *node = nullptr; t_prototype_map::iterator i = prepared_prototype_map_.find(name); if (i != prepared_prototype_map_.end()) { - // found a prepared node - node = i->second; - node->type_.assign(type); - prepared_prototype_map_.erase(i); + // found a prepared node + node = i->second; + node->type_.assign(type); + prepared_prototype_map_.erase(i); } else { - node = acquire(type, abstract); - // insert node - if (parent_node != nullptr) { - parent_node->insert(node); - } else { - last_->prev->append(node); - } - // Analyze primary and foreign keys of node - basic_identifier *id = identifier_resolver::resolve(); - if (id) { - id->isolate(); - node->id_.reset(id); - } + node = acquire(type, abstract); + // insert node + if (parent_node != nullptr) { + parent_node->insert(node); + } else { + last_->prev->append(node); + } + // Analyze primary and foreign keys of node + basic_identifier *id = identifier_resolver::resolve(); + if (id) { + id->isolate(); + node->id_.reset(id); + } } - create_observer(node, observer...); +// create_observer(node, observer...); // store prototype in map // Todo: check return value prototype_map_.insert(std::make_pair(node->type_, node))/*.first*/; typeid_prototype_map_[typeid(T).name()].insert(std::make_pair(node->type_, node)); - // Check if nodes serializable has 'to-many' relations + // Check if nodes object has 'to-many' relations // Analyze primary and foreign keys of node - detail::node_analyzer analyzer(*node, observer...); + detail::node_analyzer analyzer(*node, observer); analyzer.analyze(); node->on_attach(); @@ -886,28 +882,22 @@ object_store::iterator object_store::attach(const char *type, bool abstract, con return prototype_iterator(node); } -template -object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent, const std::initializer_list*> &observer) -{ - return iterator(); -}; - //template class ... O > //object_store::iterator object_store::attach(const char *type, bool abstract, O*... observer) //{ // return iterator(); //} -template class ... O > -object_store::iterator object_store::attach(const char *type, O*... observer) +template class O > +object_store::iterator object_store::attach(const char *type, std::initializer_list*> observer) { - return attach(type, false, observer...); + return attach(type, false, observer); } -template class ... O > -object_store::iterator object_store::attach(const char *type, bool abstract, O*... observer) +template class O > +object_store::iterator object_store::attach(const char *type, bool abstract, std::initializer_list*> observer) { - return attach(type, abstract, typeid(S).name(), observer...); + return attach(type, abstract, typeid(S).name(), observer); } template diff --git a/include/oos/object/prototype_node.hpp b/include/oos/object/prototype_node.hpp index a14c6c313..813953327 100644 --- a/include/oos/object/prototype_node.hpp +++ b/include/oos/object/prototype_node.hpp @@ -53,7 +53,7 @@ template < class T, template class C, class Enabled > class has_many_inserter; template < class T, template class C, class Enabled > class has_many_deleter; -template < class T, template < class V = T > class ... O > +template < class T, template < class U = T > class O > class node_analyzer; } /** @@ -422,7 +422,7 @@ class OOS_OBJECT_API prototype_node friend class detail::has_many_inserter; template < class T, template class C, class Enabled > friend class detail::has_many_deleter; - template < class T, template < class ... > class ON_ATTACH > + template < class T, template < class U = T > class O > friend class detail::node_analyzer; object_store *tree_ = nullptr; /**< The prototype tree to which the node belongs */ From 9de1581b771bd17ff141fba10c24e3c427baff86 Mon Sep 17 00:00:00 2001 From: zussel Date: Thu, 26 Jan 2017 16:02:13 +0100 Subject: [PATCH 32/61] observer progress --- include/oos/object/node_analyzer.hpp | 57 +++++++++- include/oos/object/node_analyzer.tpp | 130 +++++++++++++++++++++- include/oos/object/object_store.hpp | 136 ++++++++++++++--------- include/oos/object/prototype_node.hpp | 2 +- include/oos/orm/persistence.hpp | 4 +- include/oos/orm/persistence_observer.hpp | 18 +++ include/oos/orm/persistence_observer.tpp | 12 +- test/object/ObjectStoreTestUnit.cpp | 24 ++-- 8 files changed, 300 insertions(+), 83 deletions(-) diff --git a/include/oos/object/node_analyzer.hpp b/include/oos/object/node_analyzer.hpp index cc9d96be0..8454fda3e 100644 --- a/include/oos/object/node_analyzer.hpp +++ b/include/oos/object/node_analyzer.hpp @@ -11,11 +11,25 @@ class prototype_node; namespace detail { -template < class T, template < class U = T > class O > -class node_analyzer { +class basic_node_analyzer +{ public: - explicit node_analyzer(prototype_node &node, const std::initializer_list*> &observer) - : node_(node), observer_(observer) + explicit basic_node_analyzer(prototype_node &node) + : node_(node) + { } + +protected: + prototype_node &node_; +}; + +template < class T > struct observer_dummy {}; + +template < class T, template < class U = T > class O = observer_dummy > +class node_analyzer : public basic_node_analyzer +{ +public: + explicit node_analyzer(prototype_node &node, const std::vector*> &observer) + : basic_node_analyzer(node), observer_(observer) { } ~node_analyzer() { } @@ -27,6 +41,7 @@ class node_analyzer { template void serialize(const char *, V &) { } void serialize(const char *, char *, size_t) { } + template void serialize(const char *id, belongs_to &x, cascade_type); template @@ -40,8 +55,38 @@ class node_analyzer { typename std::enable_if::value>::type* = 0); private: - prototype_node &node_; - const std::initializer_list*> &observer_; + const std::vector*> &observer_; +}; + +template < class T > +class node_analyzer : public basic_node_analyzer +{ +public: + explicit node_analyzer(prototype_node &node) + : basic_node_analyzer(node) + { } + + ~node_analyzer() { } + + void analyze(); + + template + void serialize(V &x); + template + void serialize(const char *, V &) { } + void serialize(const char *, char *, size_t) { } + template + void serialize(const char *id, belongs_to &x, cascade_type); + template + void serialize(const char *id, has_one &x, cascade_type); + template class C> + void serialize(const char *, has_many &, const char *, const char *, + typename std::enable_if::value>::type* = 0); + + template class C> + void serialize(const char *, has_many &, const char *, const char *, + typename std::enable_if::value>::type* = 0); + }; } diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index 0bcdde5bc..716a2fe47 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -81,8 +81,8 @@ void node_analyzer::serialize(const char *id, has_many &, const cha // false: attach it prototype_iterator pi = node_.tree()->find(id); if (pi == node_.tree()->end()) { - pi = node_.tree()->attach::item_type>(id, false, nullptr, observer_); -// pi = node_.tree()->template attach::item_type, O...>(id, false, nullptr, observer_); + std::initializer_list::item_type>*> has_many_item_observer; + pi = node_.tree()->attach::item_type>(id, false, nullptr, has_many_item_observer); node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { oos::append(static_cast(obj), field, object_ptr(owner)); }, [](void *obj, const std::string &field, oos::object_proxy *owner) { @@ -114,7 +114,131 @@ void node_analyzer::serialize(const char *id, has_many &, const cha // false: attach it prototype_iterator pi = node_.tree()->find(id); if (pi == node_.tree()->end()) { - pi = node_.tree()->attach::item_type>(id, false, nullptr, observer_); + std::vector::item_type>*> has_many_item_observer; + for (auto o : observer_) { + has_many_item_observer.push_back(new O::item_type>(o)); + } + pi = node_.tree()->attach::item_type>(id, false, nullptr, has_many_item_observer); + } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { + // prototype is of type has_many_item + throw_object_exception("many to many relations are not supported by now"); + } else { + // throw exception + throw_object_exception("prototype already inserted: " << pi->type()); + } +} + +/* + * no observer version + */ +template +void node_analyzer::analyze() +{ +// std::cout << "START analyzing " << node_.type() << "\n"; + T obj; + oos::access::serialize(*this, obj); +// std::cout << "FINISHED analyzing " << node_.type() << "\n"; +} + +template +template +void node_analyzer::serialize(V &x) +{ + oos::access::serialize(*this, x); +} + +template +template +void node_analyzer::serialize(const char *id, belongs_to &x, cascade_type) +{ +// std::cout << "analyzing belongs_to field " << id << " (typeid: " << typeid(V).name() << ")\n"; + prototype_iterator node = node_.tree()->find(x.type()); + if (node != node_.tree()->end()) { + // check if created from has_many + // check if node has_many relation for id (id == tablename) + auto i = node->has_many_map_.find(node->type_index()); + if (i != node->has_many_map_.end()) { + // yes, node found! + // Todo: check if node is for has many item + // detach has_many_item node + if (i->second.node != nullptr) { + node_.tree()->detach(i->second.node); + } + i->second.node = nullptr; + } + } else { + node = node_.tree()->template prepare_attach(); + } + if (!node->has_primary_key()) { + throw_object_exception("serializable of type '" << x.type() << "' has no primary key"); + } + node_.register_belongs_to(std::type_index(typeid(V)), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { + oos::set(static_cast(obj), field, object_ptr(owner)); + }, [](void *obj, const std::string &field, oos::object_proxy *) { + oos::set(static_cast(obj), field, object_ptr()); + }, node.get())); +} + +template +template +void node_analyzer::serialize(const char *, has_one &x, cascade_type) +{ +// std::cout << "analyzing has_one field " << id << " (typeid: " << typeid(V).name() << ")\n"; + prototype_iterator node = node_.tree()->find(x.type()); + if (node == node_.tree()->end()) { + // if there is no such prototype node + // prepare insertion of new node + node = node_.tree()->template prepare_attach(); + } else if (!node->has_primary_key()) { + throw_object_exception("serializable of type '" << x.type() << "' has no primary key"); + } +} + +template +template class C> +void node_analyzer::serialize(const char *id, has_many &, const char *, const char *, + typename std::enable_if::value>::type*) +{ + // attach relation table for has many relation + // check if has many item is already attached + // true: check owner and item field + // false: attach it + prototype_iterator pi = node_.tree()->find(id); + if (pi == node_.tree()->end()) { + pi = node_.tree()->attach::item_type>(id, false, nullptr); +// pi = node_.tree()->template attach::item_type, O...>(id, false, nullptr, observer_); + node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { + oos::append(static_cast(obj), field, object_ptr(owner)); + }, [](void *obj, const std::string &field, oos::object_proxy *owner) { + oos::remove(static_cast(obj), field, object_ptr(owner)); + }, pi.get())); + } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { + // prototype is of type has_many_item + throw_object_exception("many to many relations are not supported by now"); + } else if (pi->belongs_to_map_.find(node_.type_index_) != pi->belongs_to_map_.end()) { + // found corresponding belongs_to + node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { + oos::append(static_cast(obj), field, object_ptr(owner)); + }, [](void *obj, const std::string &field, oos::object_proxy *owner) { + oos::remove(static_cast(obj), field, object_ptr(owner)); + }, pi.get())); + } else { + throw_object_exception("prototype already inserted: " << pi->type()); + } +} + +template +template class C> +void node_analyzer::serialize(const char *id, has_many &, const char *, const char *, + typename std::enable_if::value>::type*) +{ + // attach relation table for has many relation + // check if has many item is already attached + // true: check owner and item field + // false: attach it + prototype_iterator pi = node_.tree()->find(id); + if (pi == node_.tree()->end()) { + pi = node_.tree()->attach::item_type>(id, false, nullptr); // pi = node_.tree()->template attach::item_type, O...>(id, false, nullptr, observer_); } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index 8c84175eb..42deb9ac4 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -142,10 +142,16 @@ class OOS_OBJECT_API object_store // prototype_iterator attach(const char *type, bool abstract = false, const char *parent = nullptr); template class O > - prototype_iterator attach(const char *type, std::initializer_list*> observer = {}); + prototype_iterator attach(const char *type, std::initializer_list*> observer); + + template + prototype_iterator attach(const char *type, bool abstract = false, const char *parent = nullptr); + + template class O > + object_store::iterator attach(const char *type, bool abstract, const char *parent, std::initializer_list*> observer); template class O > - object_store::iterator attach(const char *type, bool abstract, const char *parent, std::initializer_list*> observer = {}); + object_store::iterator attach(const char *type, bool abstract, const char *parent, const std::vector*> &observer); /** * Inserts a new object prototype into the prototype tree. The prototype @@ -164,10 +170,13 @@ class OOS_OBJECT_API object_store // prototype_iterator attach(const char *type, bool abstract = false); template class O > - prototype_iterator attach(const char *type, std::initializer_list*> observer = {}); + prototype_iterator attach(const char *type, std::initializer_list*> observer); + + template + prototype_iterator attach(const char *type, bool abstract = false); template class O > - prototype_iterator attach(const char *type, bool abstract = false, std::initializer_list*> observer = {}); + prototype_iterator attach(const char *type, bool abstract, std::initializer_list*> observer); /** * Inserts a new object prototype into the prototype tree. The prototype @@ -756,6 +765,9 @@ class OOS_OBJECT_API object_store */ prototype_node *remove_prototype_node(prototype_node *node, bool is_root); + template < class T > + prototype_node* attach_node(const char *type, bool abstract, const char *parent); + /** * Get or create a prototype node * @@ -777,22 +789,6 @@ class OOS_OBJECT_API object_store void enable_relation_notification(); void disable_relation_notification(); - template< class T > - void create_observer(prototype_node *) {} - - template< class T, template < class V = T > class HEAD > - void create_observer(prototype_node *node, HEAD* observer) - { - node->register_observer(observer); - } - - template< class T, template < class V = T > class HEAD, template < class V = T > class ... TAIL > - void create_observer(prototype_node *node, HEAD* observer, TAIL*... observer_list) - { - node->register_observer(observer); - create_observer(node, observer_list...); - } - private: typedef std::unordered_map t_prototype_map; // typeid -> [name -> prototype] @@ -833,8 +829,52 @@ object_store::iterator object_store::attach(const char *type, std::initializer_l return attach(type, false, nullptr, observer); } +template +object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent) +{ + prototype_node *node = attach_node(type, abstract, parent); + + // store prototype in map + // Todo: check return value + prototype_map_.insert(std::make_pair(node->type_, node))/*.first*/; + typeid_prototype_map_[typeid(T).name()].insert(std::make_pair(node->type_, node)); + + // Check if nodes object has 'to-many' relations + // Analyze primary and foreign keys of node + detail::node_analyzer analyzer(*node); + analyzer.analyze(); + + node->on_attach(); + + return prototype_iterator(node); +} + template class O > object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent, std::initializer_list*> observer) +{ + return attach(type, abstract, parent, std::vector*>(observer)); +} + +template class O> +object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent, const std::vector*> &observer) +{ + prototype_node *node = attach_node(type, abstract, parent); + + for(auto o : observer) { + node->register_observer(o); + } + // Check if nodes object has 'to-many' relations + // Analyze primary and foreign keys of node + detail::node_analyzer analyzer(*node, observer); + analyzer.analyze(); + + node->on_attach(); + + return prototype_iterator(node); +} + +template < class T > +prototype_node* object_store::attach_node(const char *type, bool abstract, const char *parent) { // set node to root node prototype_node *parent_node = find_parent(parent); @@ -845,48 +885,38 @@ object_store::iterator object_store::attach(const char *type, bool abstract, con prototype_node *node = nullptr; t_prototype_map::iterator i = prepared_prototype_map_.find(name); if (i != prepared_prototype_map_.end()) { - // found a prepared node - node = i->second; - node->type_.assign(type); - prepared_prototype_map_.erase(i); + // found a prepared node + node = i->second; + node->type_.assign(type); + prepared_prototype_map_.erase(i); } else { - node = acquire(type, abstract); - // insert node - if (parent_node != nullptr) { - parent_node->insert(node); - } else { - last_->prev->append(node); - } - // Analyze primary and foreign keys of node - basic_identifier *id = identifier_resolver::resolve(); - if (id) { - id->isolate(); - node->id_.reset(id); - } + node = acquire(type, abstract); + // insert node + if (parent_node != nullptr) { + parent_node->insert(node); + } else { + last_->prev->append(node); + } + // Analyze primary and foreign keys of node + basic_identifier *id = identifier_resolver::resolve(); + if (id) { + id->isolate(); + node->id_.reset(id); + } } - -// create_observer(node, observer...); - // store prototype in map // Todo: check return value prototype_map_.insert(std::make_pair(node->type_, node))/*.first*/; typeid_prototype_map_[typeid(T).name()].insert(std::make_pair(node->type_, node)); - // Check if nodes object has 'to-many' relations - // Analyze primary and foreign keys of node - detail::node_analyzer analyzer(*node, observer); - analyzer.analyze(); - - node->on_attach(); - - return prototype_iterator(node); + return node; } -//template class ... O > -//object_store::iterator object_store::attach(const char *type, bool abstract, O*... observer) -//{ -// return iterator(); -//} +template +object_store::iterator object_store::attach(const char *type, bool abstract) +{ + return attach(type, abstract, typeid(S).name()); +} template class O > object_store::iterator object_store::attach(const char *type, std::initializer_list*> observer) diff --git a/include/oos/object/prototype_node.hpp b/include/oos/object/prototype_node.hpp index 813953327..8148d6d10 100644 --- a/include/oos/object/prototype_node.hpp +++ b/include/oos/object/prototype_node.hpp @@ -53,7 +53,7 @@ template < class T, template class C, class Enabled > class has_many_inserter; template < class T, template class C, class Enabled > class has_many_deleter; -template < class T, template < class U = T > class O > +template < class T, template < class V = T > class O > class node_analyzer; } /** diff --git a/include/oos/orm/persistence.hpp b/include/oos/orm/persistence.hpp index d3a14bf4d..2714e8fff 100644 --- a/include/oos/orm/persistence.hpp +++ b/include/oos/orm/persistence.hpp @@ -347,13 +347,13 @@ namespace oos { template void persistence::attach(const char *type, bool abstract, const char *parent) { - store_.attach(type, abstract, parent, new persistence_observer(*this)); + store_.attach(type, abstract, parent, { new persistence_observer(*this) }); } template void persistence::attach(const char *type, bool abstract) { - store_.attach(type, abstract, new persistence_observer(*this)); + store_.attach(type, abstract, { new persistence_observer(*this) }); } } diff --git a/include/oos/orm/persistence_observer.hpp b/include/oos/orm/persistence_observer.hpp index dfb553db7..157a91cef 100644 --- a/include/oos/orm/persistence_observer.hpp +++ b/include/oos/orm/persistence_observer.hpp @@ -12,6 +12,12 @@ template < class T > class persistence_observer : public object_store_observer { public: + + template < class V > + persistence_observer(const persistence_observer *x) + : persistence_ (x->persistence_) + {} + persistence_observer(persistence &p) : persistence_(p) {} void on_attach(prototype_node &node, T &proto) override; @@ -22,6 +28,9 @@ class persistence_observer : public object_store_observer void on_delete(object_proxy &) override {} private: + template < class V > + friend class persistence_observer; + persistence& persistence_; }; @@ -29,8 +38,14 @@ template < class T > class persistence_observer> : public object_store_observer> { public: + persistence_observer(persistence &p) : persistence_(p) {} + template < class V > + persistence_observer(const persistence_observer *x) + : persistence_ (x->persistence_) + {} + void on_attach(prototype_node &node, has_many_item &proto) override; void on_detach(prototype_node &node, has_many_item &proto) override; @@ -39,6 +54,9 @@ class persistence_observer> : public object_store_observer void on_delete(object_proxy &) override {} private: + template < class V > + friend class persistence_observer; + persistence& persistence_; }; diff --git a/include/oos/orm/persistence_observer.tpp b/include/oos/orm/persistence_observer.tpp index 7148729bd..0a48c2926 100644 --- a/include/oos/orm/persistence_observer.tpp +++ b/include/oos/orm/persistence_observer.tpp @@ -3,7 +3,7 @@ namespace oos { template -void persistence_observer::on_attach(prototype_node &node, T &proto) +void persistence_observer::on_attach(prototype_node &node, T &/*proto*/) { if (persistence_.tables_.find(node.type()) != persistence_.tables_.end()) { return; @@ -14,13 +14,13 @@ void persistence_observer::on_attach(prototype_node &node, T &proto) } template -void persistence_observer::on_detach(prototype_node &node, T &proto) +void persistence_observer::on_detach(prototype_node &node, T &) { - + std::cout << "detach node type: " << node.type() << "\n"; } template -void persistence_observer>::on_attach(prototype_node &node, oos::has_many_item &proto) +void persistence_observer>::on_attach(prototype_node &node, oos::has_many_item &) { if (persistence_.tables_.find(node.type()) != persistence_.tables_.end()) { return; @@ -29,9 +29,9 @@ void persistence_observer>::on_attach(prototype_node &node } template -void persistence_observer>::on_detach(prototype_node &node, oos::has_many_item &proto) +void persistence_observer>::on_detach(prototype_node &node, oos::has_many_item &) { - + std::cout << "detach node type: " << node.type() << "\n"; } } \ No newline at end of file diff --git a/test/object/ObjectStoreTestUnit.cpp b/test/object/ObjectStoreTestUnit.cpp index 6eb35f301..380649c3d 100644 --- a/test/object/ObjectStoreTestUnit.cpp +++ b/test/object/ObjectStoreTestUnit.cpp @@ -1119,17 +1119,17 @@ struct logger : public object_store_observer void ObjectStoreTestUnit::test_observer() { -// ostore_.attach("person", new logger); -// ostore_.attach("employee", new logger); -// ostore_.attach("department", new logger); -// ostore_.attach("book", new logger); -// ostore_.attach("book_list", new logger); -// -// ostore_.clear(true); + ostore_.attach("person", { new logger }); + ostore_.attach("employee", { new logger }); + ostore_.attach("department", { new logger }); + ostore_.attach("book", { new logger }); + ostore_.attach("book_list", { new logger }); + + ostore_.clear(true); - ostore_.attach("person", new logger); - ostore_.attach("department", new logger); - ostore_.attach("employee", new logger); -// ostore_.attach("book", new logger); -// ostore_.attach("book_list", new logger); + ostore_.attach("person", { new logger }); + ostore_.attach("department", { new logger }); + ostore_.attach("employee", { new logger }); + ostore_.attach("book", { new logger }); + ostore_.attach("book_list", { new logger }); } From a57f44c1833eb4f278e23abbc9c5e48f648176cf Mon Sep 17 00:00:00 2001 From: zussel Date: Thu, 26 Jan 2017 16:20:28 +0100 Subject: [PATCH 33/61] observer progress --- include/oos/object/node_analyzer.tpp | 5 ++++- test/object/ObjectStoreTestUnit.cpp | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index 716a2fe47..37d4e53de 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -81,7 +81,10 @@ void node_analyzer::serialize(const char *id, has_many &, const cha // false: attach it prototype_iterator pi = node_.tree()->find(id); if (pi == node_.tree()->end()) { - std::initializer_list::item_type>*> has_many_item_observer; + std::vector::item_type>*> has_many_item_observer; + for (auto o : observer_) { + has_many_item_observer.push_back(new O::item_type>(o)); + } pi = node_.tree()->attach::item_type>(id, false, nullptr, has_many_item_observer); node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { oos::append(static_cast(obj), field, object_ptr(owner)); diff --git a/test/object/ObjectStoreTestUnit.cpp b/test/object/ObjectStoreTestUnit.cpp index 380649c3d..be26cc21c 100644 --- a/test/object/ObjectStoreTestUnit.cpp +++ b/test/object/ObjectStoreTestUnit.cpp @@ -1091,6 +1091,9 @@ void ObjectStoreTestUnit::test_belongs_to() template < class T > struct logger : public object_store_observer { + logger() {} + template < class V > + logger(const logger *) {} void on_attach(prototype_node &node, T &) override { std::cout << "attaching node " << node.type() << "\n"; From 178308ad6ee0506f54b90d7db456d23687996c3b Mon Sep 17 00:00:00 2001 From: zussel Date: Fri, 27 Jan 2017 11:36:31 +0100 Subject: [PATCH 34/61] changes --- include/oos/object/node_analyzer.tpp | 28 ++++++++++++++++++++---- include/oos/object/prototype_node.hpp | 8 +++++++ include/oos/orm/persistence_observer.tpp | 6 ++++- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index 37d4e53de..39998ca6a 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -72,7 +72,7 @@ void node_analyzer::serialize(const char *, has_one &x, cascade_type) template class O> template class C> -void node_analyzer::serialize(const char *id, has_many &, const char *, const char *, +void node_analyzer::serialize(const char *id, has_many &, const char *owner_column, const char *item_column, typename std::enable_if::value>::type*) { // attach relation table for has many relation @@ -86,6 +86,11 @@ void node_analyzer::serialize(const char *id, has_many &, const cha has_many_item_observer.push_back(new O::item_type>(o)); } pi = node_.tree()->attach::item_type>(id, false, nullptr, has_many_item_observer); + pi->relation_node_info_.owner_type_.assign(node_.type()); + pi->relation_node_info_.relation_id_.assign(id); + pi->relation_node_info_.owner_id_column_.assign(owner_column); + pi->relation_node_info_.item_id_column_.assign(item_column); + pi->is_relation_node_ = true; node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { oos::append(static_cast(obj), field, object_ptr(owner)); }, [](void *obj, const std::string &field, oos::object_proxy *owner) { @@ -108,7 +113,7 @@ void node_analyzer::serialize(const char *id, has_many &, const cha template class O> template class C> -void node_analyzer::serialize(const char *id, has_many &, const char *, const char *, +void node_analyzer::serialize(const char *id, has_many &, const char *owner_column, const char *item_column, typename std::enable_if::value>::type*) { // attach relation table for has many relation @@ -122,6 +127,11 @@ void node_analyzer::serialize(const char *id, has_many &, const cha has_many_item_observer.push_back(new O::item_type>(o)); } pi = node_.tree()->attach::item_type>(id, false, nullptr, has_many_item_observer); + pi->relation_node_info_.owner_type_.assign(node_.type()); + pi->relation_node_info_.relation_id_.assign(id); + pi->relation_node_info_.owner_id_column_.assign(owner_column); + pi->relation_node_info_.item_id_column_.assign(item_column); + pi->is_relation_node_ = true; } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item throw_object_exception("many to many relations are not supported by now"); @@ -199,7 +209,7 @@ void node_analyzer::serialize(const char *, has_one &x, cascade_type) template template class C> -void node_analyzer::serialize(const char *id, has_many &, const char *, const char *, +void node_analyzer::serialize(const char *id, has_many &, const char *owner_column, const char *item_column, typename std::enable_if::value>::type*) { // attach relation table for has many relation @@ -209,6 +219,11 @@ void node_analyzer::serialize(const char *id, has_many &, const char * prototype_iterator pi = node_.tree()->find(id); if (pi == node_.tree()->end()) { pi = node_.tree()->attach::item_type>(id, false, nullptr); + pi->relation_node_info_.owner_type_.assign(node_.type()); + pi->relation_node_info_.relation_id_.assign(id); + pi->relation_node_info_.owner_id_column_.assign(owner_column); + pi->relation_node_info_.item_id_column_.assign(item_column); + pi->is_relation_node_ = true; // pi = node_.tree()->template attach::item_type, O...>(id, false, nullptr, observer_); node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { oos::append(static_cast(obj), field, object_ptr(owner)); @@ -232,7 +247,7 @@ void node_analyzer::serialize(const char *id, has_many &, const char * template template class C> -void node_analyzer::serialize(const char *id, has_many &, const char *, const char *, +void node_analyzer::serialize(const char *id, has_many &, const char *owner_column, const char *item_column, typename std::enable_if::value>::type*) { // attach relation table for has many relation @@ -242,6 +257,11 @@ void node_analyzer::serialize(const char *id, has_many &, const char * prototype_iterator pi = node_.tree()->find(id); if (pi == node_.tree()->end()) { pi = node_.tree()->attach::item_type>(id, false, nullptr); + pi->relation_node_info_.owner_type_.assign(node_.type()); + pi->relation_node_info_.relation_id_.assign(id); + pi->relation_node_info_.owner_id_column_.assign(owner_column); + pi->relation_node_info_.item_id_column_.assign(item_column); + pi->is_relation_node_ = true; // pi = node_.tree()->template attach::item_type, O...>(id, false, nullptr, observer_); } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item diff --git a/include/oos/object/prototype_node.hpp b/include/oos/object/prototype_node.hpp index 8148d6d10..356174ef9 100644 --- a/include/oos/object/prototype_node.hpp +++ b/include/oos/object/prototype_node.hpp @@ -95,6 +95,14 @@ class OOS_OBJECT_API prototype_node typedef std::unordered_map relation_map; + struct relation_node_info + { + std::string owner_type_; + std::string relation_id_; + std::string owner_id_column_; + std::string item_id_column_; + }; + public: prototype_node(); diff --git a/include/oos/orm/persistence_observer.tpp b/include/oos/orm/persistence_observer.tpp index 0a48c2926..54822f405 100644 --- a/include/oos/orm/persistence_observer.tpp +++ b/include/oos/orm/persistence_observer.tpp @@ -25,7 +25,11 @@ void persistence_observer>::on_attach(prototype_node &node if (persistence_.tables_.find(node.type()) != persistence_.tables_.end()) { return; } - std::cout << "node type: " << node.type() << "\n"; + std::cout << "node relation type: " << node.type() << "\n"; + persistence_.tables_.insert(std::make_pair( + node.type(), std::make_shared>( + node, persistence_, relation_, node. owner_type_, relation_id_, owner_id_column_, item_id_column_ + ))); } template From 6c3bba032979152b73e7655b89b4bfac46a2c2d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Mon, 30 Jan 2017 07:29:07 +0100 Subject: [PATCH 35/61] belongs_to progress --- include/oos/object/prototype_node.hpp | 19 +++++++++++++++++++ include/oos/orm/persistence_observer.hpp | 7 ++++--- include/oos/orm/persistence_observer.tpp | 23 ++++++++++++++++++++++- src/object/prototype_node.cpp | 10 ++++++++++ 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/include/oos/object/prototype_node.hpp b/include/oos/object/prototype_node.hpp index 356174ef9..67d2c10df 100644 --- a/include/oos/object/prototype_node.hpp +++ b/include/oos/object/prototype_node.hpp @@ -306,6 +306,22 @@ class OOS_OBJECT_API prototype_node */ std::type_index type_index() const; + /** + * Returns true if this node represents a relation + * node (has_many_item). + * + * @return True if this node represents a relation node. + */ + bool is_relation_node() const; + + /** + * Returns the relation node info. This struct contains + * only valid data if this node represents a n relation + * node (has_many_item). + * @return + */ + const relation_node_info& node_info() const; + /** * Prints the node in graphviz layout to the stream. * @@ -474,6 +490,9 @@ class OOS_OBJECT_API prototype_node relation_map belongs_to_map_; relation_map has_one_map_; relation_map has_many_map_; + + bool is_relation_node_ = false; + relation_node_info relation_node_info_; }; } diff --git a/include/oos/orm/persistence_observer.hpp b/include/oos/orm/persistence_observer.hpp index 157a91cef..82b95fa93 100644 --- a/include/oos/orm/persistence_observer.hpp +++ b/include/oos/orm/persistence_observer.hpp @@ -41,10 +41,10 @@ class persistence_observer> : public object_store_observer persistence_observer(persistence &p) : persistence_(p) {} + typedef has_many_item relation_type; + template < class V > - persistence_observer(const persistence_observer *x) - : persistence_ (x->persistence_) - {} + persistence_observer(const persistence_observer *x); void on_attach(prototype_node &node, has_many_item &proto) override; void on_detach(prototype_node &node, has_many_item &proto) override; @@ -58,6 +58,7 @@ class persistence_observer> : public object_store_observer friend class persistence_observer; persistence& persistence_; + relation_type relation_; }; } diff --git a/include/oos/orm/persistence_observer.tpp b/include/oos/orm/persistence_observer.tpp index 54822f405..8df902452 100644 --- a/include/oos/orm/persistence_observer.tpp +++ b/include/oos/orm/persistence_observer.tpp @@ -16,7 +16,22 @@ void persistence_observer::on_attach(prototype_node &node, T &/*proto*/) template void persistence_observer::on_detach(prototype_node &node, T &) { + auto i = persistence_.tables_.find(node.type()); + if (i == persistence_.tables_.end()) { + return; + } std::cout << "detach node type: " << node.type() << "\n"; + persistence_.tables_.erase(i); +} + +template +template < class V > +persistence_observer>::persistence_observer(const persistence_observer *x) + : persistence_ (x->persistence_) +{ + V owner; + prototype_iterator owner_node = persistence_.store().find(typeid(V).name()); + relation_.owner(std::shared_ptr(owner_node->id())); } template @@ -28,14 +43,20 @@ void persistence_observer>::on_attach(prototype_node &node std::cout << "node relation type: " << node.type() << "\n"; persistence_.tables_.insert(std::make_pair( node.type(), std::make_shared>( - node, persistence_, relation_, node. owner_type_, relation_id_, owner_id_column_, item_id_column_ + &node, persistence_, relation_, node.node_info().owner_type_, node.node_info().relation_id_, + node.node_info().owner_id_column_, node.node_info().item_id_column_ ))); } template void persistence_observer>::on_detach(prototype_node &node, oos::has_many_item &) { + auto i = persistence_.tables_.find(node.type()); + if (i == persistence_.tables_.end()) { + return; + } std::cout << "detach node type: " << node.type() << "\n"; + persistence_.tables_.erase(i); } } \ No newline at end of file diff --git a/src/object/prototype_node.cpp b/src/object/prototype_node.cpp index ec46376d5..a75fd2dd1 100644 --- a/src/object/prototype_node.cpp +++ b/src/object/prototype_node.cpp @@ -414,6 +414,16 @@ void prototype_node::adjust_right_marker(prototype_node *root, object_proxy* old } } +bool prototype_node::is_relation_node() const +{ + return is_relation_node_; +} + +const prototype_node::relation_node_info &prototype_node::node_info() const +{ + return relation_node_info_; +} + std::ostream& operator <<(std::ostream &os, const prototype_node &pn) { if (pn.parent) { From da023885b96d76f3262c3b69a7b11556eb1401e1 Mon Sep 17 00:00:00 2001 From: zussel Date: Tue, 31 Jan 2017 17:31:34 +0100 Subject: [PATCH 36/61] attach node restructuring --- include/oos/object/node_analyzer.hpp | 13 ++- include/oos/object/node_analyzer.tpp | 134 ++++++++++++---------- include/oos/object/object_store.hpp | 134 +++++++++++----------- include/oos/object/prototype_iterator.hpp | 2 +- src/object/prototype_iterator.cpp | 1 - 5 files changed, 149 insertions(+), 135 deletions(-) diff --git a/include/oos/object/node_analyzer.hpp b/include/oos/object/node_analyzer.hpp index 8454fda3e..cab1e1a29 100644 --- a/include/oos/object/node_analyzer.hpp +++ b/include/oos/object/node_analyzer.hpp @@ -14,12 +14,13 @@ namespace detail { class basic_node_analyzer { public: - explicit basic_node_analyzer(prototype_node &node) - : node_(node) + explicit basic_node_analyzer(prototype_node &node, object_store &store) + : node_(node), store_(store) { } protected: prototype_node &node_; + object_store &store_; }; template < class T > struct observer_dummy {}; @@ -28,8 +29,8 @@ template < class T, template < class U = T > class O = observer_dummy > class node_analyzer : public basic_node_analyzer { public: - explicit node_analyzer(prototype_node &node, const std::vector*> &observer) - : basic_node_analyzer(node), observer_(observer) + explicit node_analyzer(prototype_node &node, object_store &store, const std::vector*> &observer) + : basic_node_analyzer(node, store), observer_(observer) { } ~node_analyzer() { } @@ -62,8 +63,8 @@ template < class T > class node_analyzer : public basic_node_analyzer { public: - explicit node_analyzer(prototype_node &node) - : basic_node_analyzer(node) + explicit node_analyzer(prototype_node &node, object_store &store) + : basic_node_analyzer(node, store) { } ~node_analyzer() { } diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index 39998ca6a..52817da67 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -28,8 +28,8 @@ template void node_analyzer::serialize(const char *id, belongs_to &x, cascade_type) { // std::cout << "analyzing belongs_to field " << id << " (typeid: " << typeid(V).name() << ")\n"; - prototype_iterator node = node_.tree()->find(x.type()); - if (node != node_.tree()->end()) { + prototype_iterator node = store_.find(x.type()); + if (node != store_.end()) { // check if created from has_many // check if node has_many relation for id (id == tablename) auto i = node->has_many_map_.find(node->type_index()); @@ -38,16 +38,16 @@ void node_analyzer::serialize(const char *id, belongs_to &x, cascade_t // Todo: check if node is for has many item // detach has_many_item node if (i->second.node != nullptr) { - node_.tree()->detach(i->second.node); + store_.detach(i->second.node); } i->second.node = nullptr; } - } else { - node = node_.tree()->template prepare_attach(); - } - if (!node->has_primary_key()) { - throw_object_exception("serializable of type '" << x.type() << "' has no primary key"); +// } else { +// node = node_.tree()->template prepare_attach(); } +// if (!node->has_primary_key()) { +// throw_object_exception("serializable of type '" << x.type() << "' has no primary key"); +// } node_.register_belongs_to(std::type_index(typeid(V)), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { oos::set(static_cast(obj), field, object_ptr(owner)); }, [](void *obj, const std::string &field, oos::object_proxy *) { @@ -57,17 +57,17 @@ void node_analyzer::serialize(const char *id, belongs_to &x, cascade_t template class O> template -void node_analyzer::serialize(const char *, has_one &x, cascade_type) +void node_analyzer::serialize(const char *, has_one &, cascade_type) { // std::cout << "analyzing has_one field " << id << " (typeid: " << typeid(V).name() << ")\n"; - prototype_iterator node = node_.tree()->find(x.type()); - if (node == node_.tree()->end()) { - // if there is no such prototype node - // prepare insertion of new node - node = node_.tree()->template prepare_attach(); - } else if (!node->has_primary_key()) { - throw_object_exception("serializable of type '" << x.type() << "' has no primary key"); - } +// prototype_iterator node = node_.tree()->find(x.type()); +// if (node == node_.tree()->end()) { +// // if there is no such prototype node +// // prepare insertion of new node +// node = node_.tree()->template prepare_attach(); +// } else if (!node->has_primary_key()) { +// throw_object_exception("serializable of type '" << x.type() << "' has no primary key"); +// } } template class O> @@ -79,13 +79,13 @@ void node_analyzer::serialize(const char *id, has_many &, const cha // check if has many item is already attached // true: check owner and item field // false: attach it - prototype_iterator pi = node_.tree()->find(id); - if (pi == node_.tree()->end()) { + prototype_iterator pi = store_.find(id); + if (pi == store_.end()) { std::vector::item_type>*> has_many_item_observer; for (auto o : observer_) { has_many_item_observer.push_back(new O::item_type>(o)); } - pi = node_.tree()->attach::item_type>(id, false, nullptr, has_many_item_observer); + pi = store_.attach::item_type>(id, false, nullptr, has_many_item_observer); pi->relation_node_info_.owner_type_.assign(node_.type()); pi->relation_node_info_.relation_id_.assign(id); pi->relation_node_info_.owner_id_column_.assign(owner_column); @@ -99,15 +99,20 @@ void node_analyzer::serialize(const char *id, has_many &, const cha } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item throw_object_exception("many to many relations are not supported by now"); - } else if (pi->belongs_to_map_.find(node_.type_index_) != pi->belongs_to_map_.end()) { - // found corresponding belongs_to - node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { - oos::append(static_cast(obj), field, object_ptr(owner)); - }, [](void *obj, const std::string &field, oos::object_proxy *owner) { - oos::remove(static_cast(obj), field, object_ptr(owner)); - }, pi.get())); } else { - throw_object_exception("prototype already inserted: " << pi->type()); + // found corresponding belongs_to + auto j = pi->belongs_to_map_.find(node_.type_index_); + if (j != pi->belongs_to_map_.end()) { + // set missing node + j->second.node = &node_; + node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { + oos::append(static_cast(obj), field, object_ptr(owner)); + }, [](void *obj, const std::string &field, oos::object_proxy *owner) { + oos::remove(static_cast(obj), field, object_ptr(owner)); + }, pi.get())); + } else { + throw_object_exception("prototype already inserted: " << pi->type()); + } } } @@ -120,13 +125,13 @@ void node_analyzer::serialize(const char *id, has_many &, const cha // check if has many item is already attached // true: check owner and item field // false: attach it - prototype_iterator pi = node_.tree()->find(id); - if (pi == node_.tree()->end()) { + prototype_iterator pi = store_.find(id); + if (pi == store_.end()) { std::vector::item_type>*> has_many_item_observer; for (auto o : observer_) { has_many_item_observer.push_back(new O::item_type>(o)); } - pi = node_.tree()->attach::item_type>(id, false, nullptr, has_many_item_observer); + pi = store_.attach::item_type>(id, false, nullptr, has_many_item_observer); pi->relation_node_info_.owner_type_.assign(node_.type()); pi->relation_node_info_.relation_id_.assign(id); pi->relation_node_info_.owner_id_column_.assign(owner_column); @@ -165,8 +170,8 @@ template void node_analyzer::serialize(const char *id, belongs_to &x, cascade_type) { // std::cout << "analyzing belongs_to field " << id << " (typeid: " << typeid(V).name() << ")\n"; - prototype_iterator node = node_.tree()->find(x.type()); - if (node != node_.tree()->end()) { + prototype_iterator node = store_.find(x.type()); + if (node != store_.end()) { // check if created from has_many // check if node has_many relation for id (id == tablename) auto i = node->has_many_map_.find(node->type_index()); @@ -175,16 +180,16 @@ void node_analyzer::serialize(const char *id, belongs_to &x, cascade_type // Todo: check if node is for has many item // detach has_many_item node if (i->second.node != nullptr) { - node_.tree()->detach(i->second.node); + store_.detach(i->second.node); } i->second.node = nullptr; } - } else { - node = node_.tree()->template prepare_attach(); - } - if (!node->has_primary_key()) { - throw_object_exception("serializable of type '" << x.type() << "' has no primary key"); +// } else { +// node = node_.tree()->template prepare_attach(); } +// if (!node->has_primary_key()) { +// throw_object_exception("serializable of type '" << x.type() << "' has no primary key"); +// } node_.register_belongs_to(std::type_index(typeid(V)), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { oos::set(static_cast(obj), field, object_ptr(owner)); }, [](void *obj, const std::string &field, oos::object_proxy *) { @@ -194,17 +199,17 @@ void node_analyzer::serialize(const char *id, belongs_to &x, cascade_type template template -void node_analyzer::serialize(const char *, has_one &x, cascade_type) +void node_analyzer::serialize(const char *, has_one &, cascade_type) { // std::cout << "analyzing has_one field " << id << " (typeid: " << typeid(V).name() << ")\n"; - prototype_iterator node = node_.tree()->find(x.type()); - if (node == node_.tree()->end()) { - // if there is no such prototype node - // prepare insertion of new node - node = node_.tree()->template prepare_attach(); - } else if (!node->has_primary_key()) { - throw_object_exception("serializable of type '" << x.type() << "' has no primary key"); - } +// prototype_iterator node = node_.tree()->find(x.type()); +// if (node == node_.tree()->end()) { +// // if there is no such prototype node +// // prepare insertion of new node +// node = node_.tree()->template prepare_attach(); +// } else if (!node->has_primary_key()) { +// throw_object_exception("serializable of type '" << x.type() << "' has no primary key"); +// } } template @@ -216,9 +221,9 @@ void node_analyzer::serialize(const char *id, has_many &, const char * // check if has many item is already attached // true: check owner and item field // false: attach it - prototype_iterator pi = node_.tree()->find(id); - if (pi == node_.tree()->end()) { - pi = node_.tree()->attach::item_type>(id, false, nullptr); + prototype_iterator pi = store_.find(id); + if (pi == store_.end()) { + pi = store_.attach::item_type>(id, false, nullptr); pi->relation_node_info_.owner_type_.assign(node_.type()); pi->relation_node_info_.relation_id_.assign(id); pi->relation_node_info_.owner_id_column_.assign(owner_column); @@ -233,15 +238,20 @@ void node_analyzer::serialize(const char *id, has_many &, const char * } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item throw_object_exception("many to many relations are not supported by now"); - } else if (pi->belongs_to_map_.find(node_.type_index_) != pi->belongs_to_map_.end()) { - // found corresponding belongs_to - node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { - oos::append(static_cast(obj), field, object_ptr(owner)); - }, [](void *obj, const std::string &field, oos::object_proxy *owner) { - oos::remove(static_cast(obj), field, object_ptr(owner)); - }, pi.get())); } else { - throw_object_exception("prototype already inserted: " << pi->type()); + // found corresponding belongs_to + auto j = pi->belongs_to_map_.find(node_.type_index_); + if (j != pi->belongs_to_map_.end()) { + // set missing node + j->second.node = &node_; + node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { + oos::append(static_cast(obj), field, object_ptr(owner)); + }, [](void *obj, const std::string &field, oos::object_proxy *owner) { + oos::remove(static_cast(obj), field, object_ptr(owner)); + }, pi.get())); + } else { + throw_object_exception("prototype already inserted: " << pi->type()); + } } } @@ -254,9 +264,9 @@ void node_analyzer::serialize(const char *id, has_many &, const char * // check if has many item is already attached // true: check owner and item field // false: attach it - prototype_iterator pi = node_.tree()->find(id); - if (pi == node_.tree()->end()) { - pi = node_.tree()->attach::item_type>(id, false, nullptr); + prototype_iterator pi = store_.find(id); + if (pi == store_.end()) { + pi = store_.attach::item_type>(id, false, nullptr); pi->relation_node_info_.owner_type_.assign(node_.type()); pi->relation_node_info_.relation_id_.assign(id); pi->relation_node_info_.owner_id_column_.assign(owner_column); diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index 42deb9ac4..bf25ae63c 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -189,8 +189,8 @@ class OOS_OBJECT_API object_store * @param parent The name of the parent type. * @return Returns new inserted prototype iterator. */ - template - prototype_iterator prepare_attach(bool abstract = false, const char *parent = nullptr); +// template +// prototype_iterator prepare_attach(bool abstract = false, const char *parent = nullptr); /** * Inserts a new object prototype into the prototype tree. The prototype @@ -203,8 +203,8 @@ class OOS_OBJECT_API object_store * @param abstract Indicates if the producers serializable is treated as an abstract node. * @return Returns new inserted prototype iterator. */ - template - prototype_iterator prepare_attach(bool abstract = false); +// template +// prototype_iterator prepare_attach(bool abstract = false); /** * Removes an object prototype from the prototype tree. All children @@ -766,7 +766,7 @@ class OOS_OBJECT_API object_store prototype_node *remove_prototype_node(prototype_node *node, bool is_root); template < class T > - prototype_node* attach_node(const char *type, bool abstract, const char *parent); + prototype_node* attach_node(prototype_node *node, const char *parent); /** * Get or create a prototype node @@ -804,7 +804,7 @@ class OOS_OBJECT_API object_store t_typeid_prototype_map typeid_prototype_map_; // prepared prototype nodes - t_prototype_map prepared_prototype_map_; +// t_prototype_map prepared_prototype_map_; typedef std::unordered_map t_object_proxy_map; t_object_proxy_map object_map_; @@ -832,7 +832,7 @@ object_store::iterator object_store::attach(const char *type, std::initializer_l template object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent) { - prototype_node *node = attach_node(type, abstract, parent); + prototype_node *node = acquire(type, abstract); // store prototype in map // Todo: check return value @@ -841,9 +841,10 @@ object_store::iterator object_store::attach(const char *type, bool abstract, con // Check if nodes object has 'to-many' relations // Analyze primary and foreign keys of node - detail::node_analyzer analyzer(*node); + detail::node_analyzer analyzer(*node, *this); analyzer.analyze(); + attach_node(node, parent); node->on_attach(); return prototype_iterator(node); @@ -858,39 +859,42 @@ object_store::iterator object_store::attach(const char *type, bool abstract, con template class O> object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent, const std::vector*> &observer) { - prototype_node *node = attach_node(type, abstract, parent); + prototype_node *node = acquire(type, abstract); + for(auto o : observer) { node->register_observer(o); } // Check if nodes object has 'to-many' relations // Analyze primary and foreign keys of node - detail::node_analyzer analyzer(*node, observer); + detail::node_analyzer analyzer(*node, *this, observer); analyzer.analyze(); + attach_node(node, parent); + node->on_attach(); return prototype_iterator(node); } template < class T > -prototype_node* object_store::attach_node(const char *type, bool abstract, const char *parent) +prototype_node* object_store::attach_node(prototype_node *node, const char *parent) { // set node to root node prototype_node *parent_node = find_parent(parent); /* * try to insert new prototype node */ - const char *name = typeid(T).name(); - prototype_node *node = nullptr; - t_prototype_map::iterator i = prepared_prototype_map_.find(name); - if (i != prepared_prototype_map_.end()) { - // found a prepared node - node = i->second; - node->type_.assign(type); - prepared_prototype_map_.erase(i); - } else { - node = acquire(type, abstract); +// const char *name = typeid(T).name(); +// prototype_node *node = nullptr; +// t_prototype_map::iterator i = prepared_prototype_map_.find(name); +// if (i != prepared_prototype_map_.end()) { +// // found a prepared node +// node = i->second; +// node->type_.assign(type); +// prepared_prototype_map_.erase(i); +// } else { +// node = acquire(type, abstract); // insert node if (parent_node != nullptr) { parent_node->insert(node); @@ -903,7 +907,7 @@ prototype_node* object_store::attach_node(const char *type, bool abstract, const id->isolate(); node->id_.reset(id); } - } +// } // store prototype in map // Todo: check return value prototype_map_.insert(std::make_pair(node->type_, node))/*.first*/; @@ -930,49 +934,49 @@ object_store::iterator object_store::attach(const char *type, bool abstract, std return attach(type, abstract, typeid(S).name(), observer); } -template -prototype_iterator object_store::prepare_attach(bool abstract, const char *parent) -{ - prototype_node *parent_node = find_parent(parent); - - if (typeid_prototype_map_.find(typeid(T).name()) != typeid_prototype_map_.end()) { - throw_object_exception("attach: object type " << typeid(T).name() << " already in attached"); - } - - t_prototype_map::iterator i = prepared_prototype_map_.find(typeid(T).name()); - if (i != prepared_prototype_map_.end()) { - // there is already a prepared node for this type - return prototype_iterator(i->second); - } - - std::unique_ptr node(new prototype_node(this, "", new T, typeid(T), abstract)); - - node->initialize(this, "", abstract); - - if (parent_node != nullptr) { - parent_node->insert(node.get()); - } else { - last_->prev->append(node.get()); - } - - // store only in prepared prototype map - // Todo: check return value - prepared_prototype_map_.insert(std::make_pair(typeid(T).name(), node.get())); - // Analyze primary and foreign keys of node - std::unique_ptr id(identifier_resolver::resolve()); - if (id) { - id->isolate(); - node->id_.reset(id.release()); - } - - return prototype_iterator(node.release()); -} - -template -prototype_iterator object_store::prepare_attach(bool abstract) -{ - return prepare_attach(abstract, typeid(T).name()); -} +//template +//prototype_iterator object_store::prepare_attach(bool abstract, const char *parent) +//{ +// prototype_node *parent_node = find_parent(parent); +// +// if (typeid_prototype_map_.find(typeid(T).name()) != typeid_prototype_map_.end()) { +// throw_object_exception("attach: object type " << typeid(T).name() << " already in attached"); +// } +// +// t_prototype_map::iterator i = prepared_prototype_map_.find(typeid(T).name()); +// if (i != prepared_prototype_map_.end()) { +// // there is already a prepared node for this type +// return prototype_iterator(i->second); +// } +// +// std::unique_ptr node(new prototype_node(this, "", new T, typeid(T), abstract)); +// +// node->initialize(this, "", abstract); +// +// if (parent_node != nullptr) { +// parent_node->insert(node.get()); +// } else { +// last_->prev->append(node.get()); +// } +// +// // store only in prepared prototype map +// // Todo: check return value +// prepared_prototype_map_.insert(std::make_pair(typeid(T).name(), node.get())); +// // Analyze primary and foreign keys of node +// std::unique_ptr id(identifier_resolver::resolve()); +// if (id) { +// id->isolate(); +// node->id_.reset(id.release()); +// } +// +// return prototype_iterator(node.release()); +//} +// +//template +//prototype_iterator object_store::prepare_attach(bool abstract) +//{ +// return prepare_attach(abstract, typeid(T).name()); +//} template prototype_node *object_store::acquire(const char *type, bool abstract) diff --git a/include/oos/object/prototype_iterator.hpp b/include/oos/object/prototype_iterator.hpp index 628de6c0f..7f76142f7 100644 --- a/include/oos/object/prototype_iterator.hpp +++ b/include/oos/object/prototype_iterator.hpp @@ -144,7 +144,7 @@ void decrement(); private: friend class const_prototype_iterator; -pointer node_; +pointer node_ = nullptr; }; class OOS_OBJECT_API const_prototype_iterator diff --git a/src/object/prototype_iterator.cpp b/src/object/prototype_iterator.cpp index 868ca1b9f..b431a9dcc 100644 --- a/src/object/prototype_iterator.cpp +++ b/src/object/prototype_iterator.cpp @@ -6,7 +6,6 @@ namespace oos { prototype_iterator::prototype_iterator() - : node_(0) {} prototype_iterator::prototype_iterator(prototype_iterator::pointer node) From 4b934ee45bd5f6a25314809476d008bd9b47d898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Tue, 31 Jan 2017 22:52:11 +0100 Subject: [PATCH 37/61] store attach progress --- include/oos/object/node_analyzer.hpp | 1 + include/oos/object/node_analyzer.tpp | 1 + include/oos/object/object_store.hpp | 7 +++++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/oos/object/node_analyzer.hpp b/include/oos/object/node_analyzer.hpp index cab1e1a29..78236c5e0 100644 --- a/include/oos/object/node_analyzer.hpp +++ b/include/oos/object/node_analyzer.hpp @@ -20,6 +20,7 @@ class basic_node_analyzer protected: prototype_node &node_; + prototype_node *same_node = nullptr; object_store &store_; }; diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index 52817da67..5372bb85d 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -154,6 +154,7 @@ void node_analyzer::analyze() { // std::cout << "START analyzing " << node_.type() << "\n"; T obj; + same_node = store_.find_prototype_node(node_.type_.c_str()); oos::access::serialize(*this, obj); // std::cout << "FINISHED analyzing " << node_.type() << "\n"; } diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index bf25ae63c..3db64eb41 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -832,7 +832,8 @@ object_store::iterator object_store::attach(const char *type, std::initializer_l template object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent) { - prototype_node *node = acquire(type, abstract); +// prototype_node *node = acquire(type, abstract); + prototype_node *node = new prototype_node(this, type, new T, typeid(T), abstract); // store prototype in map // Todo: check return value @@ -845,6 +846,7 @@ object_store::iterator object_store::attach(const char *type, bool abstract, con analyzer.analyze(); attach_node(node, parent); + node->on_attach(); return prototype_iterator(node); @@ -859,7 +861,8 @@ object_store::iterator object_store::attach(const char *type, bool abstract, con template class O> object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent, const std::vector*> &observer) { - prototype_node *node = acquire(type, abstract); +// prototype_node *node = acquire(type, abstract); + prototype_node *node = new prototype_node(this, type, new T, typeid(T), abstract); for(auto o : observer) { From f64387104a5d22bfbce75fe33894904310173908 Mon Sep 17 00:00:00 2001 From: zussel Date: Wed, 1 Feb 2017 16:50:47 +0100 Subject: [PATCH 38/61] has many transaction update --- include/oos/object/has_many_vector.hpp | 7 +-- include/oos/object/node_analyzer.hpp | 1 - include/oos/object/node_analyzer.tpp | 65 ++++++++++++++++---------- include/oos/object/object_holder.hpp | 8 ++++ include/oos/object/object_store.hpp | 16 +++++-- include/oos/object/prototype_node.hpp | 6 +-- include/oos/object/transaction.hpp | 2 +- include/oos/orm/table.hpp | 1 + include/oos/sql/statement.hpp | 2 +- src/object/object_holder.cpp | 4 +- src/object/object_store.cpp | 64 +++++++++++++++++++------ test/orm/OrmTestUnit.cpp | 8 ++-- 12 files changed, 127 insertions(+), 57 deletions(-) diff --git a/include/oos/object/has_many_vector.hpp b/include/oos/object/has_many_vector.hpp index bcb13b37d..ed885c2f1 100644 --- a/include/oos/object/has_many_vector.hpp +++ b/include/oos/object/has_many_vector.hpp @@ -579,9 +579,10 @@ class has_many_inserter::value> auto i = foreign_node_->belongs_to_map_.find(owner.node()->type_index()); if (i != foreign_node_->belongs_to_map_.end()) { - store.insert(rtype->value()); +// store.insert(rtype->value()); // set owner into value - store.notify_relation_insert(i->second, rtype->value().ptr() /*owner*/, &owner /*value*/); + store.on_update_relation_owner(i->second, rtype->value().proxy_ /*owner*/, &owner /*value*/); +// store.notify_relation_insert(i->second, rtype->value().ptr() /*owner*/, &owner /*value*/); } else { store.insert(rtype); } @@ -625,7 +626,7 @@ class has_many_deleter::value>: auto val = rtype->value(); // store.remove(val); // set owner into value - store.notify_relation_remove(i->second, rtype->value().ptr() /*owner*/, &owner /*value*/); + store.on_remove_relation_owner(i->second, rtype->value().proxy_ /*owner*/, &owner /*value*/); } else { store.remove(rtype); } diff --git a/include/oos/object/node_analyzer.hpp b/include/oos/object/node_analyzer.hpp index 78236c5e0..cab1e1a29 100644 --- a/include/oos/object/node_analyzer.hpp +++ b/include/oos/object/node_analyzer.hpp @@ -20,7 +20,6 @@ class basic_node_analyzer protected: prototype_node &node_; - prototype_node *same_node = nullptr; object_store &store_; }; diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index 5372bb85d..4f0151dd2 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -48,10 +48,13 @@ void node_analyzer::serialize(const char *id, belongs_to &x, cascade_t // if (!node->has_primary_key()) { // throw_object_exception("serializable of type '" << x.type() << "' has no primary key"); // } - node_.register_belongs_to(std::type_index(typeid(V)), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { - oos::set(static_cast(obj), field, object_ptr(owner)); - }, [](void *obj, const std::string &field, oos::object_proxy *) { - oos::set(static_cast(obj), field, object_ptr()); + object_store &store = store_; + node_.register_belongs_to(std::type_index(typeid(V)), prototype_node::relation_info(id, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { + store.mark_modified(proxy); + oos::set(proxy->obj(), field, object_ptr(owner)); + }, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *) { + store.mark_modified(proxy); + oos::set(proxy->obj(), field, object_ptr()); }, node.get())); } @@ -79,6 +82,7 @@ void node_analyzer::serialize(const char *id, has_many &, const cha // check if has many item is already attached // true: check owner and item field // false: attach it + object_store &store = store_; prototype_iterator pi = store_.find(id); if (pi == store_.end()) { std::vector::item_type>*> has_many_item_observer; @@ -91,10 +95,12 @@ void node_analyzer::serialize(const char *id, has_many &, const cha pi->relation_node_info_.owner_id_column_.assign(owner_column); pi->relation_node_info_.item_id_column_.assign(item_column); pi->is_relation_node_ = true; - node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { - oos::append(static_cast(obj), field, object_ptr(owner)); - }, [](void *obj, const std::string &field, oos::object_proxy *owner) { - oos::remove(static_cast(obj), field, object_ptr(owner)); + node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { + store.mark_modified(proxy); + oos::append(proxy->obj(), field, object_ptr(owner)); + }, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { + store.mark_modified(proxy); + oos::remove(proxy->obj(), field, object_ptr(owner)); }, pi.get())); } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item @@ -105,10 +111,12 @@ void node_analyzer::serialize(const char *id, has_many &, const cha if (j != pi->belongs_to_map_.end()) { // set missing node j->second.node = &node_; - node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { - oos::append(static_cast(obj), field, object_ptr(owner)); - }, [](void *obj, const std::string &field, oos::object_proxy *owner) { - oos::remove(static_cast(obj), field, object_ptr(owner)); + node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { + store.mark_modified(proxy); + oos::append(proxy->obj(), field, object_ptr(owner)); + }, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { + store.mark_modified(proxy); + oos::remove(proxy->obj(), field, object_ptr(owner)); }, pi.get())); } else { throw_object_exception("prototype already inserted: " << pi->type()); @@ -154,7 +162,6 @@ void node_analyzer::analyze() { // std::cout << "START analyzing " << node_.type() << "\n"; T obj; - same_node = store_.find_prototype_node(node_.type_.c_str()); oos::access::serialize(*this, obj); // std::cout << "FINISHED analyzing " << node_.type() << "\n"; } @@ -191,10 +198,13 @@ void node_analyzer::serialize(const char *id, belongs_to &x, cascade_type // if (!node->has_primary_key()) { // throw_object_exception("serializable of type '" << x.type() << "' has no primary key"); // } - node_.register_belongs_to(std::type_index(typeid(V)), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { - oos::set(static_cast(obj), field, object_ptr(owner)); - }, [](void *obj, const std::string &field, oos::object_proxy *) { - oos::set(static_cast(obj), field, object_ptr()); + object_store &store = store_; + node_.register_belongs_to(std::type_index(typeid(V)), prototype_node::relation_info(id, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { + store.mark_modified(proxy); + oos::set(proxy->obj(), field, object_ptr(owner)); + }, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *) { + store.mark_modified(proxy); + oos::set(proxy->obj(), field, object_ptr()); }, node.get())); } @@ -222,6 +232,7 @@ void node_analyzer::serialize(const char *id, has_many &, const char * // check if has many item is already attached // true: check owner and item field // false: attach it + object_store &store = store_; prototype_iterator pi = store_.find(id); if (pi == store_.end()) { pi = store_.attach::item_type>(id, false, nullptr); @@ -231,10 +242,12 @@ void node_analyzer::serialize(const char *id, has_many &, const char * pi->relation_node_info_.item_id_column_.assign(item_column); pi->is_relation_node_ = true; // pi = node_.tree()->template attach::item_type, O...>(id, false, nullptr, observer_); - node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { - oos::append(static_cast(obj), field, object_ptr(owner)); - }, [](void *obj, const std::string &field, oos::object_proxy *owner) { - oos::remove(static_cast(obj), field, object_ptr(owner)); + node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { + store.mark_modified(proxy); + oos::append(proxy->obj(), field, object_ptr(owner)); + }, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { + store.mark_modified(proxy); + oos::remove(proxy->obj(), field, object_ptr(owner)); }, pi.get())); } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item @@ -245,10 +258,12 @@ void node_analyzer::serialize(const char *id, has_many &, const char * if (j != pi->belongs_to_map_.end()) { // set missing node j->second.node = &node_; - node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [](void *obj, const std::string &field, oos::object_proxy *owner) { - oos::append(static_cast(obj), field, object_ptr(owner)); - }, [](void *obj, const std::string &field, oos::object_proxy *owner) { - oos::remove(static_cast(obj), field, object_ptr(owner)); + node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { + store.mark_modified(proxy); + oos::append(proxy->obj(), field, object_ptr(owner)); + }, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { + store.mark_modified(proxy); + oos::remove(proxy->obj(), field, object_ptr(owner)); }, pi.get())); } else { throw_object_exception("prototype already inserted: " << pi->type()); diff --git a/include/oos/object/object_holder.hpp b/include/oos/object/object_holder.hpp index 933571eaa..d36d4f55a 100644 --- a/include/oos/object/object_holder.hpp +++ b/include/oos/object/object_holder.hpp @@ -32,6 +32,10 @@ namespace detail { class object_inserter; class object_deleter; class object_proxy_accessor; +template class C, class Enabled> +class has_many_inserter; +template class C, class Enabled> +class has_many_deleter; } class basic_identifier; @@ -271,6 +275,10 @@ class OOS_OBJECT_API object_holder : public identifiable_holder friend class object_store; friend class object_container; friend class detail::object_proxy_accessor; + template class C, class Enabled > + friend class detail::has_many_inserter; + template class C, class Enabled > + friend class detail::has_many_deleter; // Todo: change interface to remove friend friend class session; diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index 3db64eb41..b90f0fce7 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -672,10 +672,18 @@ class OOS_OBJECT_API object_store */ sequencer_impl_ptr exchange_sequencer(const sequencer_impl_ptr &seq); - void notify_relation_insert(prototype_node::relation_info &info, void *owner, object_proxy *value); - void notify_relation_insert(prototype_node &node, void *owner, object_proxy *value); - void notify_relation_remove(prototype_node::relation_info &info, void *owner, object_proxy *value); - void notify_relation_remove(prototype_node &node, void *owner, object_proxy *value); + void on_update_relation_owner(prototype_node::relation_info &info, object_proxy *owner, object_proxy *value); + + void on_remove_relation_owner(prototype_node::relation_info &info, object_proxy *owner, object_proxy *value); + + void on_append_relation_item(prototype_node &node, object_proxy *owner, object_proxy *value); + + void on_remove_relation_item(prototype_node &node, object_proxy *owner, object_proxy *value); + +// void notify_relation_insert(prototype_node::relation_info &info, void *owner, object_proxy *value); +// void notify_relation_insert(prototype_node &node, void *owner, object_proxy *value); +// void notify_relation_remove(prototype_node::relation_info &info, void *owner, object_proxy *value); +// void notify_relation_remove(prototype_node &node, void *owner, object_proxy *value); transaction current_transaction(); bool has_transaction() const; diff --git a/include/oos/object/prototype_node.hpp b/include/oos/object/prototype_node.hpp index 67d2c10df..710354489 100644 --- a/include/oos/object/prototype_node.hpp +++ b/include/oos/object/prototype_node.hpp @@ -80,7 +80,7 @@ class OOS_OBJECT_API prototype_node public: struct relation_info { - typedef std::function modify_value_func; + typedef std::function modify_value_func; relation_info(const std::string &n, const modify_value_func &insert_func, const modify_value_func &remove_func, @@ -88,8 +88,8 @@ class OOS_OBJECT_API prototype_node : name(n), insert_value(insert_func), remove_value(remove_func), node(pn) {} std::string name; - std::function insert_value; - std::function remove_value; + std::function insert_value; + std::function remove_value; prototype_node *node; }; diff --git a/include/oos/object/transaction.hpp b/include/oos/object/transaction.hpp index ece5155fd..5e1230948 100644 --- a/include/oos/object/transaction.hpp +++ b/include/oos/object/transaction.hpp @@ -289,7 +289,7 @@ void transaction::on_update(object_proxy *proxy) std::shared_ptr ua(new update_action(proxy, (T*)proxy->obj())); backup(ua, proxy); } else { - // An serializable with that id already exists + // An object with that id already exists // do nothing because the serializable is already // backed up } diff --git a/include/oos/orm/table.hpp b/include/oos/orm/table.hpp index 057336844..fdc994ed2 100644 --- a/include/oos/orm/table.hpp +++ b/include/oos/orm/table.hpp @@ -137,6 +137,7 @@ class table : public basic_table insert_ = q.insert().prepare(conn); column id = detail::identifier_column_resolver::resolve(); update_ = q.update().where(id == 1).prepare(conn); + std::cout << "UPDATE: " << update_.str() << "\n"; delete_ = q.remove().where(id == 1).prepare(conn); select_ = q.select().prepare(conn); } diff --git a/include/oos/sql/statement.hpp b/include/oos/sql/statement.hpp index a78335650..3cb069fee 100644 --- a/include/oos/sql/statement.hpp +++ b/include/oos/sql/statement.hpp @@ -117,7 +117,7 @@ class statement */ result execute() { - //std::cout << "SQL: " << p->str() << '\n'; + std::cout << "SQL: " << p->str() << '\n'; //std::cout.flush(); return result(p->execute()); } diff --git a/src/object/object_holder.cpp b/src/object/object_holder.cpp index acc26902c..c2ce6a779 100644 --- a/src/object/object_holder.cpp +++ b/src/object/object_holder.cpp @@ -79,7 +79,7 @@ void object_holder::reset(object_proxy *proxy, cascade_type cascade) oid_ = 0; if (is_internal() && is_inserted_ && proxy_->ostore_) { --(*proxy_); - proxy_->ostore_->notify_relation_remove(*proxy_->node_, proxy_->obj_, owner_); + proxy_->ostore_->on_remove_relation_item(*proxy_->node_, proxy_, owner_); // proxy_->node_->notify_delete_relation(owner_, proxy); } proxy_->remove(this); @@ -97,7 +97,7 @@ void object_holder::reset(object_proxy *proxy, cascade_type cascade) oid_ = proxy_->id(); if (is_internal() && is_inserted_ && proxy_->ostore_) { ++(*proxy_); - proxy_->ostore_->notify_relation_insert(*proxy_->node_, proxy->obj_, owner_); + proxy_->ostore_->on_append_relation_item(*proxy_->node_, proxy_, owner_); // proxy_->node_->notify_insert_relation(owner_, proxy); } proxy_->add(this); diff --git a/src/object/object_store.cpp b/src/object/object_store.cpp index cd6ee8941..304e1ce6e 100644 --- a/src/object/object_store.cpp +++ b/src/object/object_store.cpp @@ -289,7 +289,7 @@ sequencer_impl_ptr object_store::exchange_sequencer(const sequencer_impl_ptr &se return seq_.exchange_sequencer(seq); } -void object_store::notify_relation_insert(prototype_node::relation_info &info, void *owner, object_proxy *value) +void object_store::on_update_relation_owner(prototype_node::relation_info &info, object_proxy *owner, object_proxy *value) { if (!is_relation_notification_enabled()) { return; @@ -299,16 +299,7 @@ void object_store::notify_relation_insert(prototype_node::relation_info &info, v enable_relation_notification(); } -void object_store::notify_relation_insert(prototype_node &node, void *owner, object_proxy *value) -{ - auto i = node.has_many_map_.find(node.type_index()); - if (i == node.has_many_map_.end()) { - return; - } - notify_relation_insert(i->second, owner, value); -} - -void object_store::notify_relation_remove(prototype_node::relation_info &info, void *owner, object_proxy *value) +void object_store::on_remove_relation_owner(prototype_node::relation_info &info, object_proxy *owner, object_proxy *value) { if (!is_relation_notification_enabled()) { return; @@ -318,15 +309,62 @@ void object_store::notify_relation_remove(prototype_node::relation_info &info, v enable_relation_notification(); } -void object_store::notify_relation_remove(prototype_node &node, void *owner, object_proxy *value) +void object_store::on_append_relation_item(prototype_node &node, object_proxy *owner, object_proxy *value) { auto i = node.has_many_map_.find(node.type_index()); if (i == node.has_many_map_.end()) { return; } - notify_relation_remove(i->second, owner, value); + on_update_relation_owner(i->second, owner, value); } +void object_store::on_remove_relation_item(prototype_node &node, object_proxy *owner, object_proxy *value) +{ + auto i = node.has_many_map_.find(node.type_index()); + if (i == node.has_many_map_.end()) { + return; + } + on_remove_relation_owner(i->second, owner, value); +} + +//void object_store::notify_relation_insert(prototype_node::relation_info &info, void *owner, object_proxy *value) +//{ +// if (!is_relation_notification_enabled()) { +// return; +// } +// disable_relation_notification(); +// info.insert_value(owner, info.name, value); +// enable_relation_notification(); +//} +// +//void object_store::notify_relation_insert(prototype_node &node, void *owner, object_proxy *value) +//{ +// auto i = node.has_many_map_.find(node.type_index()); +// if (i == node.has_many_map_.end()) { +// return; +// } +// notify_relation_insert(i->second, owner, value); +//} +// +//void object_store::notify_relation_remove(prototype_node::relation_info &info, void *owner, object_proxy *value) +//{ +// if (!is_relation_notification_enabled()) { +// return; +// } +// disable_relation_notification(); +// info.remove_value(owner, info.name, value); +// enable_relation_notification(); +//} +// +//void object_store::notify_relation_remove(prototype_node &node, void *owner, object_proxy *value) +//{ +// auto i = node.has_many_map_.find(node.type_index()); +// if (i == node.has_many_map_.end()) { +// return; +// } +// notify_relation_remove(i->second, owner, value); +//} + prototype_node* object_store::find_prototype_node(const char *type) const { // check for null if (type == 0) { diff --git a/test/orm/OrmTestUnit.cpp b/test/orm/OrmTestUnit.cpp index f74178e5c..e5d2cc265 100644 --- a/test/orm/OrmTestUnit.cpp +++ b/test/orm/OrmTestUnit.cpp @@ -452,8 +452,8 @@ void OrmTestUnit::test_belongs_to() p.attach("department"); p.attach("employee"); -// p.create(); -// + p.create(); + // oos::session s(p); // // auto george = s.insert(new employee("george")); @@ -491,6 +491,6 @@ void OrmTestUnit::test_belongs_to() // s.update(jane); // // UNIT_ASSERT_TRUE(dep->employees.empty(), "there must be no employees"); -// -// p.drop(); + + p.drop(); } From 84033cec4b63a3d6748a968842aeb2b930c613c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Wed, 1 Feb 2017 23:32:14 +0100 Subject: [PATCH 39/61] orm belongs to progress --- include/oos/object/has_many_vector.hpp | 1 - include/oos/orm/table.hpp | 1 + src/sql/value_column_serializer.cpp | 2 + test/orm/OrmTestUnit.cpp | 70 +++++++++++++------------- 4 files changed, 38 insertions(+), 36 deletions(-) diff --git a/include/oos/object/has_many_vector.hpp b/include/oos/object/has_many_vector.hpp index ed885c2f1..6e1ce586a 100644 --- a/include/oos/object/has_many_vector.hpp +++ b/include/oos/object/has_many_vector.hpp @@ -623,7 +623,6 @@ class has_many_deleter::value>: auto i = foreign_node_->belongs_to_map_.find(owner.node()->type_index()); if (i != foreign_node_->belongs_to_map_.end()) { - auto val = rtype->value(); // store.remove(val); // set owner into value store.on_remove_relation_owner(i->second, rtype->value().proxy_ /*owner*/, &owner /*value*/); diff --git a/include/oos/orm/table.hpp b/include/oos/orm/table.hpp index fdc994ed2..e4f4cd957 100644 --- a/include/oos/orm/table.hpp +++ b/include/oos/orm/table.hpp @@ -135,6 +135,7 @@ class table : public basic_table { query q(name()); insert_ = q.insert().prepare(conn); + std::cout << "INSERT: " << insert_.str() << "\n"; column id = detail::identifier_column_resolver::resolve(); update_ = q.update().where(id == 1).prepare(conn); std::cout << "UPDATE: " << update_.str() << "\n"; diff --git a/src/sql/value_column_serializer.cpp b/src/sql/value_column_serializer.cpp index 5f78ed528..cf69aaffb 100644 --- a/src/sql/value_column_serializer.cpp +++ b/src/sql/value_column_serializer.cpp @@ -107,6 +107,8 @@ void value_column_serializer::serialize(const char *id, identifiable_holder &x, { if (x.has_primary_key()) { x.primary_key()->serialize(id, *this); + } else { + cols_->push_back(std::make_shared>(id, new null_value)); } } diff --git a/test/orm/OrmTestUnit.cpp b/test/orm/OrmTestUnit.cpp index e5d2cc265..db120749c 100644 --- a/test/orm/OrmTestUnit.cpp +++ b/test/orm/OrmTestUnit.cpp @@ -454,43 +454,43 @@ void OrmTestUnit::test_belongs_to() p.create(); -// oos::session s(p); -// -// auto george = s.insert(new employee("george")); -// auto jane = s.insert(new employee("jane")); -// auto dep = s.insert(new department("insurance")); -// -// UNIT_ASSERT_TRUE(dep->employees.empty(), "there must be no employees"); -// UNIT_ASSERT_TRUE(george->dep().empty(), "there must not be an department"); -// UNIT_ASSERT_TRUE(jane->dep().empty(), "there must not be an department"); -// -// // department is automatically set -// s.push_back(dep->employees, george); -// -// UNIT_ASSERT_EQUAL(dep->employees.size(), 1UL, "there must be one employee"); -// UNIT_ASSERT_EQUAL(dep->employees.front()->name(), "george", "expected name must be george"); -// UNIT_ASSERT_FALSE(george->dep().empty(), "department must not be empty"); -// UNIT_ASSERT_EQUAL(george->dep()->name, dep->name, "names must be equal"); -// -// // jane is automatically added to deps employee list -// jane->dep(dep); -// s.update(jane); -// -// UNIT_ASSERT_EQUAL(dep->employees.size(), 2UL, "there must be two employees"); -// -// // remove george -// auto i = dep->employees.begin(); -// i = dep->employees.erase(i); -// s.update(dep); -// -// UNIT_ASSERT_EQUAL(dep->employees.size(), 1UL, "there must be one employee"); -// UNIT_ASSERT_TRUE(george->dep().empty(), "there must not be an department"); -// UNIT_ASSERT_EQUAL(dep->employees.front()->name(), "jane", "expected name must be jane"); + oos::session s(p); + + auto george = s.insert(new employee("george")); + auto jane = s.insert(new employee("jane")); + auto dep = s.insert(new department("insurance")); + + UNIT_ASSERT_TRUE(dep->employees.empty(), "there must be no employees"); + UNIT_ASSERT_TRUE(george->dep().empty(), "there must not be an department"); + UNIT_ASSERT_TRUE(jane->dep().empty(), "there must not be an department"); + + // department is automatically set + s.push_back(dep->employees, george); + + UNIT_ASSERT_EQUAL(dep->employees.size(), 1UL, "there must be one employee"); + UNIT_ASSERT_EQUAL(dep->employees.front()->name(), "george", "expected name must be george"); + UNIT_ASSERT_FALSE(george->dep().empty(), "department must not be empty"); + UNIT_ASSERT_EQUAL(george->dep()->name, dep->name, "names must be equal"); + + // jane is automatically added to deps employee list + jane->dep(dep); + s.update(jane); + + UNIT_ASSERT_EQUAL(dep->employees.size(), 2UL, "there must be two employees"); + + // remove george + auto i = dep->employees.begin(); + i = dep->employees.erase(i); + s.update(dep); + + UNIT_ASSERT_EQUAL(dep->employees.size(), 1UL, "there must be one employee"); + UNIT_ASSERT_TRUE(george->dep().empty(), "there must not be an department"); + UNIT_ASSERT_EQUAL(dep->employees.front()->name(), "jane", "expected name must be jane"); // -// jane->department_.clear(); -// s.update(jane); + jane->department_.clear(); + s.update(jane); // -// UNIT_ASSERT_TRUE(dep->employees.empty(), "there must be no employees"); + UNIT_ASSERT_TRUE(dep->employees.empty(), "there must be no employees"); p.drop(); } From 46834091513c59a56890651fbc1617ef989ae839 Mon Sep 17 00:00:00 2001 From: zussel Date: Thu, 2 Feb 2017 11:01:06 +0100 Subject: [PATCH 40/61] belongs_to progress --- include/oos/db/mysql/mysql_statement.hpp | 20 +++--- include/oos/orm/persistence_observer.tpp | 8 +-- include/oos/orm/table.hpp | 4 +- include/oos/sql/statement.hpp | 2 +- src/db/mysql/mysql_statement.cpp | 81 +++++++++++++++--------- src/db/sqlite/sqlite_statement.cpp | 2 + test/orm/OrmTestUnit.cpp | 26 ++++---- 7 files changed, 83 insertions(+), 60 deletions(-) diff --git a/include/oos/db/mysql/mysql_statement.hpp b/include/oos/db/mysql/mysql_statement.hpp index b8df29b5c..fe1c1d8ca 100644 --- a/include/oos/db/mysql/mysql_statement.hpp +++ b/include/oos/db/mysql/mysql_statement.hpp @@ -76,8 +76,9 @@ class mysql_statement : public oos::detail::statement_impl private: template < class T > - void bind_value(MYSQL_BIND &bind, enum_field_types type, T value) + void bind_value(std::size_t index, enum_field_types type, T value) { + MYSQL_BIND &bind = host_array[index]; if (bind.buffer == nullptr) { // allocating memory bind.buffer = new char[sizeof(T)]; @@ -85,19 +86,22 @@ class mysql_statement : public oos::detail::statement_impl *static_cast(bind.buffer) = value; bind.buffer_type = type; bind.buffer_length = sizeof(T); - bind.is_null = 0; + is_null_vector[index] = false; + bind.is_null = &is_null_vector[index]; bind.is_unsigned = std::is_unsigned::value; } - void bind_value(MYSQL_BIND &bind, enum_field_types type, char x); - void bind_value(MYSQL_BIND &bind, enum_field_types type, unsigned char x); - void bind_value(MYSQL_BIND &bind, enum_field_types type, const oos::date &x); - void bind_value(MYSQL_BIND &bind, enum_field_types type, const oos::time &x); - void bind_value(MYSQL_BIND &bind, enum_field_types type, const char *value, size_t size); + void bind_value(std::size_t index, enum_field_types type, char x); + void bind_value(std::size_t index, enum_field_types type, unsigned char x); + void bind_value(std::size_t index, enum_field_types type, const oos::date &x); + void bind_value(std::size_t index, enum_field_types type, const oos::time &x); + void bind_value(std::size_t index, enum_field_types type, const char *value, size_t size); + + void bind_null(std::size_t index); private: size_t result_size; size_t host_size; - std::vector length_vector; + std::vector is_null_vector; MYSQL_STMT *stmt_ = nullptr; MYSQL_BIND *host_array = nullptr; }; diff --git a/include/oos/orm/persistence_observer.tpp b/include/oos/orm/persistence_observer.tpp index 8df902452..d10a7a4bd 100644 --- a/include/oos/orm/persistence_observer.tpp +++ b/include/oos/orm/persistence_observer.tpp @@ -8,7 +8,7 @@ void persistence_observer::on_attach(prototype_node &node, T &/*proto*/) if (persistence_.tables_.find(node.type()) != persistence_.tables_.end()) { return; } - std::cout << "node type: " << node.type() << "\n"; +// std::cout << "node type: " << node.type() << "\n"; persistence_.tables_.insert(std::make_pair(node.type(), std::make_shared>(&node, persistence_))); } @@ -20,7 +20,7 @@ void persistence_observer::on_detach(prototype_node &node, T &) if (i == persistence_.tables_.end()) { return; } - std::cout << "detach node type: " << node.type() << "\n"; +// std::cout << "detach node type: " << node.type() << "\n"; persistence_.tables_.erase(i); } @@ -40,7 +40,7 @@ void persistence_observer>::on_attach(prototype_node &node if (persistence_.tables_.find(node.type()) != persistence_.tables_.end()) { return; } - std::cout << "node relation type: " << node.type() << "\n"; +// std::cout << "node relation type: " << node.type() << "\n"; persistence_.tables_.insert(std::make_pair( node.type(), std::make_shared>( &node, persistence_, relation_, node.node_info().owner_type_, node.node_info().relation_id_, @@ -55,7 +55,7 @@ void persistence_observer>::on_detach(prototype_node &node if (i == persistence_.tables_.end()) { return; } - std::cout << "detach node type: " << node.type() << "\n"; +// std::cout << "detach node type: " << node.type() << "\n"; persistence_.tables_.erase(i); } diff --git a/include/oos/orm/table.hpp b/include/oos/orm/table.hpp index e4f4cd957..ed6725718 100644 --- a/include/oos/orm/table.hpp +++ b/include/oos/orm/table.hpp @@ -135,10 +135,10 @@ class table : public basic_table { query q(name()); insert_ = q.insert().prepare(conn); - std::cout << "INSERT: " << insert_.str() << "\n"; +// std::cout << "INSERT: " << insert_.str() << "\n"; column id = detail::identifier_column_resolver::resolve(); update_ = q.update().where(id == 1).prepare(conn); - std::cout << "UPDATE: " << update_.str() << "\n"; +// std::cout << "UPDATE: " << update_.str() << "\n"; delete_ = q.remove().where(id == 1).prepare(conn); select_ = q.select().prepare(conn); } diff --git a/include/oos/sql/statement.hpp b/include/oos/sql/statement.hpp index 3cb069fee..95d772638 100644 --- a/include/oos/sql/statement.hpp +++ b/include/oos/sql/statement.hpp @@ -117,7 +117,7 @@ class statement */ result execute() { - std::cout << "SQL: " << p->str() << '\n'; +// std::cout << "SQL: " << p->str() << '\n'; //std::cout.flush(); return result(p->execute()); } diff --git a/src/db/mysql/mysql_statement.cpp b/src/db/mysql/mysql_statement.cpp index bff2a6c9c..8fe175081 100644 --- a/src/db/mysql/mysql_statement.cpp +++ b/src/db/mysql/mysql_statement.cpp @@ -46,7 +46,7 @@ mysql_statement::mysql_statement(mysql_connection &db, const oos::sql &stmt) if (host_size) { host_array = new MYSQL_BIND[host_size]; memset(host_array, 0, host_size * sizeof(MYSQL_BIND)); - length_vector.assign(host_size, 0); + is_null_vector.assign(host_size, false); } int res = mysql_stmt_prepare(stmt_, str().c_str(), (unsigned long)str().size()); @@ -104,87 +104,87 @@ detail::result_impl* mysql_statement::execute() void mysql_statement::serialize(const char *, char &x) { - bind_value(host_array[host_index], MYSQL_TYPE_TINY, x); + bind_value(host_index, MYSQL_TYPE_TINY, x); ++host_index; } void mysql_statement::serialize(const char *, short &x) { - bind_value(host_array[host_index], MYSQL_TYPE_SHORT, x); + bind_value(host_index, MYSQL_TYPE_SHORT, x); ++host_index; } void mysql_statement::serialize(const char *, int &x) { - bind_value(host_array[host_index], MYSQL_TYPE_LONG, x); + bind_value(host_index, MYSQL_TYPE_LONG, x); ++host_index; } void mysql_statement::serialize(const char *, long &x) { - //bind_value(host_array[host_index], MYSQL_TYPE_LONGLONG, x); - bind_value(host_array[host_index], MYSQL_TYPE_LONG, x); + //bind_value(host_index, MYSQL_TYPE_LONGLONG, x); + bind_value(host_index, MYSQL_TYPE_LONG, x); ++host_index; } void mysql_statement::serialize(const char *, unsigned char &x) { - bind_value(host_array[host_index], MYSQL_TYPE_TINY, x); + bind_value(host_index, MYSQL_TYPE_TINY, x); ++host_index; } void mysql_statement::serialize(const char *, unsigned short &x) { - bind_value(host_array[host_index], MYSQL_TYPE_SHORT, x); + bind_value(host_index, MYSQL_TYPE_SHORT, x); ++host_index; } void mysql_statement::serialize(const char *, unsigned int &x) { - bind_value(host_array[host_index], MYSQL_TYPE_LONG, x); + bind_value(host_index, MYSQL_TYPE_LONG, x); ++host_index; } void mysql_statement::serialize(const char *, unsigned long &x) { - //bind_value(host_array[host_index], MYSQL_TYPE_LONGLONG, x); - bind_value(host_array[host_index], MYSQL_TYPE_LONG, x); + //bind_value(host_index, MYSQL_TYPE_LONGLONG, x); + bind_value(host_index, MYSQL_TYPE_LONG, x); ++host_index; } void mysql_statement::serialize(const char *, bool &x) { - bind_value(host_array[host_index], MYSQL_TYPE_TINY, x); + bind_value(host_index, MYSQL_TYPE_TINY, x); ++host_index; } void mysql_statement::serialize(const char *, float &x) { - bind_value(host_array[host_index], MYSQL_TYPE_FLOAT, x); + bind_value(host_index, MYSQL_TYPE_FLOAT, x); ++host_index; } void mysql_statement::serialize(const char *, double &x) { - bind_value(host_array[host_index], MYSQL_TYPE_DOUBLE, x); + bind_value(host_index, MYSQL_TYPE_DOUBLE, x); ++host_index; } void mysql_statement::serialize(const char *, char *x, size_t s) { - bind_value(host_array[host_index], MYSQL_TYPE_VAR_STRING, x, s); + bind_value(host_index, MYSQL_TYPE_VAR_STRING, x, s); ++host_index; } void mysql_statement::serialize(const char *, std::string &x) { - bind_value(host_array[host_index], MYSQL_TYPE_STRING, x.data(), x.size()); + bind_value(host_index, MYSQL_TYPE_STRING, x.data(), x.size()); ++host_index; } void mysql_statement::serialize(const char *, oos::date &x) { - bind_value(host_array[host_index], MYSQL_TYPE_DATE, x); + bind_value(host_index, MYSQL_TYPE_DATE, x); ++host_index; } @@ -195,16 +195,16 @@ void mysql_statement::serialize(const char *, oos::time &x) // doesn't support fractional seconds // so we use a datetime string here std::string tstr = to_string(x, "%FT%T"); - bind_value(host_array[host_index], MYSQL_TYPE_VAR_STRING, tstr.c_str(), tstr.size()); + bind_value(host_index, MYSQL_TYPE_VAR_STRING, tstr.c_str(), tstr.size()); #else - bind_value(host_array[host_index], MYSQL_TYPE_TIMESTAMP, x); + bind_value(host_index, MYSQL_TYPE_TIMESTAMP, x); #endif ++host_index; } void mysql_statement::serialize(const char *, varchar_base &x) { - bind_value(host_array[host_index], MYSQL_TYPE_VAR_STRING, x.c_str(), x.size()); + bind_value(host_index, MYSQL_TYPE_VAR_STRING, x.c_str(), x.size()); ++host_index; } @@ -217,11 +217,14 @@ void mysql_statement::serialize(const char *id, identifiable_holder &x, cascade_ { if (x.has_primary_key()) { x.primary_key()->serialize(id, *this); + } else { + bind_null(host_index++); } } -void mysql_statement::bind_value(MYSQL_BIND &bind, enum_field_types, char x) +void mysql_statement::bind_value(std::size_t index, enum_field_types, char x) { + MYSQL_BIND &bind = host_array[index]; if (bind.buffer == nullptr) { size_t s = sizeof(char); bind.buffer = new char[s]; @@ -229,11 +232,13 @@ void mysql_statement::bind_value(MYSQL_BIND &bind, enum_field_types, char x) } *static_cast(bind.buffer) = x; bind.buffer_type = MYSQL_TYPE_VAR_STRING; - bind.is_null = 0; + is_null_vector[index] = false; + bind.is_null = &is_null_vector[index]; } -void mysql_statement::bind_value(MYSQL_BIND &bind, enum_field_types, unsigned char x) +void mysql_statement::bind_value(std::size_t index, enum_field_types, unsigned char x) { + MYSQL_BIND &bind = host_array[index]; if (bind.buffer == nullptr) { size_t s = sizeof(unsigned char); bind.buffer = new unsigned char[s]; @@ -241,11 +246,13 @@ void mysql_statement::bind_value(MYSQL_BIND &bind, enum_field_types, unsigned ch } *static_cast(bind.buffer) = x; bind.buffer_type = MYSQL_TYPE_VAR_STRING; - bind.is_null = 0; + is_null_vector[index] = false; + bind.is_null = &is_null_vector[index]; } -void mysql_statement::bind_value(MYSQL_BIND &bind, enum_field_types type, const oos::date &x) +void mysql_statement::bind_value(std::size_t index, enum_field_types type, const oos::date &x) { + MYSQL_BIND &bind = host_array[index]; if (bind.buffer == nullptr) { size_t s = sizeof(MYSQL_TIME); bind.buffer = new char[s]; @@ -254,7 +261,8 @@ void mysql_statement::bind_value(MYSQL_BIND &bind, enum_field_types type, const memset(bind.buffer, 0, sizeof(MYSQL_TIME)); bind.buffer_type = type; bind.length = 0; - bind.is_null = 0; + is_null_vector[index] = false; + bind.is_null = &is_null_vector[index]; MYSQL_TIME *mt = static_cast(bind.buffer); mt->day = (unsigned int)x.day(); mt->month = (unsigned int)x.month(); @@ -262,8 +270,9 @@ void mysql_statement::bind_value(MYSQL_BIND &bind, enum_field_types type, const mt->time_type = MYSQL_TIMESTAMP_DATE; } -void mysql_statement::bind_value(MYSQL_BIND &bind, enum_field_types type, const oos::time &x) +void mysql_statement::bind_value(std::size_t index, enum_field_types type, const oos::time &x) { + MYSQL_BIND &bind = host_array[index]; if (bind.buffer == nullptr) { size_t s = sizeof(MYSQL_TIME); bind.buffer = new char[s]; @@ -272,7 +281,8 @@ void mysql_statement::bind_value(MYSQL_BIND &bind, enum_field_types type, const memset(bind.buffer, 0, sizeof(MYSQL_TIME)); bind.buffer_type = type; bind.length = 0; - bind.is_null = 0; + is_null_vector[index] = false; + bind.is_null = &is_null_vector[index]; MYSQL_TIME *mt = static_cast(bind.buffer); mt->day = (unsigned int)x.day(); mt->month = (unsigned int)x.month(); @@ -284,9 +294,10 @@ void mysql_statement::bind_value(MYSQL_BIND &bind, enum_field_types type, const mt->time_type = MYSQL_TIMESTAMP_DATETIME; } -void mysql_statement::bind_value(MYSQL_BIND &bind, enum_field_types type, const char *value, size_t) +void mysql_statement::bind_value(std::size_t index, enum_field_types type, const char *value, size_t) { - size_t len(strlen(value) + 1); + MYSQL_BIND &bind = host_array[index]; + std::size_t len(strlen(value) + 1); if (bind.buffer_length < len) { // reallocate memory delete [] static_cast(bind.buffer); @@ -305,7 +316,15 @@ void mysql_statement::bind_value(MYSQL_BIND &bind, enum_field_types type, const strncpy(static_cast(bind.buffer), value, len); #endif bind.buffer_type = type; - bind.is_null = 0; + is_null_vector[index] = false; + bind.is_null = &is_null_vector[index]; +} + +void mysql_statement::bind_null(std::size_t index) +{ + MYSQL_BIND &bind = host_array[index]; + is_null_vector[index] = true; + bind.is_null = &is_null_vector[index]; } } diff --git a/src/db/sqlite/sqlite_statement.cpp b/src/db/sqlite/sqlite_statement.cpp index d985951be..29aa228b4 100644 --- a/src/db/sqlite/sqlite_statement.cpp +++ b/src/db/sqlite/sqlite_statement.cpp @@ -196,6 +196,8 @@ void sqlite_statement::serialize(const char *id, identifiable_holder &x, cascade { if (x.has_primary_key()) { x.primary_key()->serialize(id, *this); + } else { + sqlite3_bind_null(stmt_, (int)++host_index); } } diff --git a/test/orm/OrmTestUnit.cpp b/test/orm/OrmTestUnit.cpp index db120749c..07c40abc1 100644 --- a/test/orm/OrmTestUnit.cpp +++ b/test/orm/OrmTestUnit.cpp @@ -18,17 +18,17 @@ OrmTestUnit::OrmTestUnit(const std::string &prefix, const std::string &dns) : unit_test(prefix + "_orm", prefix + " orm test unit") , dns_(dns) { - add_test("create", std::bind(&OrmTestUnit::test_create, this), "test orm create table"); - add_test("insert", std::bind(&OrmTestUnit::test_insert, this), "test orm insert into table"); - add_test("select", std::bind(&OrmTestUnit::test_select, this), "test orm select a table"); - add_test("update", std::bind(&OrmTestUnit::test_update, this), "test orm update on table"); - add_test("delete", std::bind(&OrmTestUnit::test_delete, this), "test orm delete from table"); - add_test("load", std::bind(&OrmTestUnit::test_load, this), "test orm load from table"); - add_test("load_has_one", std::bind(&OrmTestUnit::test_load_has_one, this), "test orm load has one relation from table"); - add_test("load_has_many", std::bind(&OrmTestUnit::test_load_has_many, this), "test orm load has many from table"); - add_test("load_has_many_int", std::bind(&OrmTestUnit::test_load_has_many_int, this), "test orm load has many int from table"); - add_test("has_many_delete", std::bind(&OrmTestUnit::test_has_many_delete, this), "test orm has many delete item"); - add_test("belongs_to", std::bind(&OrmTestUnit::test_belongs_to, this), "test orm belongs to"); + add_test("create", std::bind(&OrmTestUnit::test_create, this), "test create table"); + add_test("insert", std::bind(&OrmTestUnit::test_insert, this), "test insert into table"); + add_test("select", std::bind(&OrmTestUnit::test_select, this), "test select a table"); + add_test("update", std::bind(&OrmTestUnit::test_update, this), "test update on table"); + add_test("delete", std::bind(&OrmTestUnit::test_delete, this), "test delete from table"); + add_test("load", std::bind(&OrmTestUnit::test_load, this), "test load from table"); + add_test("load_has_one", std::bind(&OrmTestUnit::test_load_has_one, this), "test load has one relation from table"); + add_test("load_has_many", std::bind(&OrmTestUnit::test_load_has_many, this), "test load has many from table"); + add_test("load_has_many_int", std::bind(&OrmTestUnit::test_load_has_many_int, this), "test load has many int from table"); + add_test("has_many_delete", std::bind(&OrmTestUnit::test_has_many_delete, this), "test has many delete item"); + add_test("belongs_to", std::bind(&OrmTestUnit::test_belongs_to, this), "test belongs to"); } void OrmTestUnit::test_create() @@ -479,9 +479,7 @@ void OrmTestUnit::test_belongs_to() UNIT_ASSERT_EQUAL(dep->employees.size(), 2UL, "there must be two employees"); // remove george - auto i = dep->employees.begin(); - i = dep->employees.erase(i); - s.update(dep); + s.erase(dep->employees, dep->employees.begin()); UNIT_ASSERT_EQUAL(dep->employees.size(), 1UL, "there must be one employee"); UNIT_ASSERT_TRUE(george->dep().empty(), "there must not be an department"); From 175be7bd3d533dcaf1f7bef5065c7783665fbb49 Mon Sep 17 00:00:00 2001 From: zussel Date: Thu, 2 Feb 2017 13:04:14 +0100 Subject: [PATCH 41/61] belongs to todos --- belongs_to.md | 78 ++++++++++++++++++++++++ belongs_to.txt | 68 --------------------- include/oos/object/node_analyzer.tpp | 10 ++- include/oos/orm/persistence_observer.tpp | 6 +- 4 files changed, 90 insertions(+), 72 deletions(-) create mode 100644 belongs_to.md delete mode 100644 belongs_to.txt diff --git a/belongs_to.md b/belongs_to.md new file mode 100644 index 000000000..f8d766c4a --- /dev/null +++ b/belongs_to.md @@ -0,0 +1,78 @@ +has_many <-> belongs_to +=================================================== + +``` +struct employee +{ + oos::belongs_to dep; + + template < class S > + void serialize(S &s) + { + s.serialize("department", dep); + } +}; + +struct department +{ + oos::has_many emps; + + template < class S > + void serialize(S &s) + { + s.serialize("employee", emps); + } +}; + +auto george = ostore.insert(new employee("george")); +auto insurance = ostore.insert(new department("insurance")); + +insurance->emps.push_back(george); + +``` + +Analyze phase +============= + +__Case 1: Department attached first__ + + * attach department + * prototype "employee" not found; prepare new + * mark as has many relation for "department" member "employees" + * attach employee + * prototype "employee found" + * if employee contains belongs_to for "department" tie prototypes + * else throw error + +__Case 2: Employee attached first__ + + * attach employee + * prototype "department" not found: prepare new + * mark as belongs relation for "employee" member "department" + * attach department + * prototype "department" found + * if department contains has_many for "employee" tie prototypes + * else throw error + +Business phase +============== + +__Case 1: emplyoee sets a department__ + + * employee gets object type "department" with member name "employees" from prototype + * employee is added to departments employees container + +__Case 2: department adds an employee__ + + * department gets object type "employee" with member name "department" from prototype + * department is set for employee + + +TODO +==== + +1. Add ```object_store::attach(prototype_node, parent, [observer])``` +2. Add static + * ```prototype_node::make_node()``` + * ```prototype_node::make_relation_node()``` +3. Adjust ```node_anaylzer``` diff --git a/belongs_to.txt b/belongs_to.txt deleted file mode 100644 index 29fc5f834..000000000 --- a/belongs_to.txt +++ /dev/null @@ -1,68 +0,0 @@ -has_many <-> belongs_to - -struct employee -{ - oos::belongs_to dep; - - template < class S > - void serialize(S &s) - { - s.serialize("department", dep); - } -}; - -struct department -{ - oos::has_many emps; - - template < class S > - void serialize(S &s) - { - s.serialize("employee", emps); - } -}; - - -auto george = ostore.insert(new employee("george")); -auto insurance = ostore.insert(new department("insurance")); - -insurance->emps.push_back(george); - - -Analyze phase -============= - -Case 1: Department attached first - -- attach department -- prototype "employee" not found; prepare new -- mark as has many relation for "department" member "employees" - -- attach employee -- prototype "employee found" -- if employee contains belongs_to for "department" tie prototypes -- else throw error - -Case 2: Employee attached first - -- attach employee -- prototype "department" not found: prepare new -- mark as belongs relation for "employee" member "department" - -- attach department -- prototype "department" found -- if department contains has_many for "employee" tie prototypes -- else throw error - -Business phase -============== - -Case 1: emplyoee sets a department - -- employee gets object type "department" with member name "employees" from prototype -- employee is added to departments employees container - -Case 2: department adds an employee - -- department gets object type "employee" with member name "department" from prototype -- department is set for employee diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index 4f0151dd2..09d718835 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -89,7 +89,15 @@ void node_analyzer::serialize(const char *id, has_many &, const cha for (auto o : observer_) { has_many_item_observer.push_back(new O::item_type>(o)); } - pi = store_.attach::item_type>(id, false, nullptr, has_many_item_observer); + prototype_node *node = new prototype_node(&store_, id, new typename has_many::item_type, typeid(typename has_many::item_type), false); + node->relation_node_info_.owner_type_.assign(node_.type()); + node->relation_node_info_.relation_id_.assign(id); + node->relation_node_info_.owner_id_column_.assign(owner_column); + node->relation_node_info_.item_id_column_.assign(item_column); + node->is_relation_node_ = true; + +// pi = store_.attach::item_type>(id, false, nullptr, has_many_item_observer); + pi->relation_node_info_.owner_type_.assign(node_.type()); pi->relation_node_info_.relation_id_.assign(id); pi->relation_node_info_.owner_id_column_.assign(owner_column); diff --git a/include/oos/orm/persistence_observer.tpp b/include/oos/orm/persistence_observer.tpp index d10a7a4bd..2c656da9c 100644 --- a/include/oos/orm/persistence_observer.tpp +++ b/include/oos/orm/persistence_observer.tpp @@ -29,9 +29,9 @@ template < class V > persistence_observer>::persistence_observer(const persistence_observer *x) : persistence_ (x->persistence_) { - V owner; - prototype_iterator owner_node = persistence_.store().find(typeid(V).name()); - relation_.owner(std::shared_ptr(owner_node->id())); + std::shared_ptr id(identifier_resolver::resolve()); + id->as_value(true); + relation_.owner(id); } template From 3a04b33e4c72e6b3285b62f3faea62311292351f Mon Sep 17 00:00:00 2001 From: zussel Date: Thu, 2 Feb 2017 15:48:18 +0100 Subject: [PATCH 42/61] added more attach methods accepting a node --- include/oos/object/object_store.hpp | 59 ++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index b90f0fce7..dd5f26c95 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -148,10 +148,13 @@ class OOS_OBJECT_API object_store prototype_iterator attach(const char *type, bool abstract = false, const char *parent = nullptr); template class O > - object_store::iterator attach(const char *type, bool abstract, const char *parent, std::initializer_list*> observer); + prototype_iterator attach(const char *type, bool abstract, const char *parent, const std::vector*> &observer); template class O > - object_store::iterator attach(const char *type, bool abstract, const char *parent, const std::vector*> &observer); + prototype_iterator attach(const char *type, bool abstract, const char *parent, std::initializer_list*> observer); + + template class O > + prototype_iterator attach(const char *type, std::initializer_list*> observer); /** * Inserts a new object prototype into the prototype tree. The prototype @@ -159,25 +162,24 @@ class OOS_OBJECT_API object_store * prototype is inserted into the hierarchy the type name of the parent * node is also given. * parameter. - * + * * @tparam T The type of the prototype node * @tparam S The type of the parent prototype node * @param type The unique name of the type. * @param abstract Indicates if the producers serializable is treated as an abstract node. * @return Returns new inserted prototype iterator. */ -// template class ... O > -// prototype_iterator attach(const char *type, bool abstract = false); - - template class O > - prototype_iterator attach(const char *type, std::initializer_list*> observer); - template prototype_iterator attach(const char *type, bool abstract = false); template class O > prototype_iterator attach(const char *type, bool abstract, std::initializer_list*> observer); + template < class T > + prototype_iterator attach(prototype_node *node, const char *parent = nullptr); + + template < class T, template < class V = T > class O > + prototype_iterator attach(prototype_node *node, const char *parent, std::vector*> observer); /** * Inserts a new object prototype into the prototype tree. The prototype * consists of a unique type name (generated from typeid). To know where the new @@ -843,11 +845,6 @@ object_store::iterator object_store::attach(const char *type, bool abstract, con // prototype_node *node = acquire(type, abstract); prototype_node *node = new prototype_node(this, type, new T, typeid(T), abstract); - // store prototype in map - // Todo: check return value - prototype_map_.insert(std::make_pair(node->type_, node))/*.first*/; - typeid_prototype_map_[typeid(T).name()].insert(std::make_pair(node->type_, node)); - // Check if nodes object has 'to-many' relations // Analyze primary and foreign keys of node detail::node_analyzer analyzer(*node, *this); @@ -873,6 +870,7 @@ object_store::iterator object_store::attach(const char *type, bool abstract, con prototype_node *node = new prototype_node(this, type, new T, typeid(T), abstract); + return attach(node, parent, observer); for(auto o : observer) { node->register_observer(o); } @@ -945,6 +943,39 @@ object_store::iterator object_store::attach(const char *type, bool abstract, std return attach(type, abstract, typeid(S).name(), observer); } +template < class T > +prototype_iterator object_store::attach(prototype_node *node, const char *parent) +{ + // Check if nodes object has 'to-many' relations + // Analyze primary and foreign keys of node + detail::node_analyzer analyzer(*node, *this); + analyzer.analyze(); + + attach_node(node, parent); + + node->on_attach(); + + return prototype_iterator(node); +} + +template < class T, template < class V = T > class O > +prototype_iterator object_store::attach(prototype_node *node, const char *parent, std::vector*> observer) +{ + for(auto o : observer) { + node->register_observer(o); + } + // Check if nodes object has 'to-many' relations + // Analyze primary and foreign keys of node + detail::node_analyzer analyzer(*node, *this, observer); + analyzer.analyze(); + + attach_node(node, parent); + + node->on_attach(); + + return prototype_iterator(node); +} + //template //prototype_iterator object_store::prepare_attach(bool abstract, const char *parent) //{ From 401ad8610daa2afdef06e1ec74cbfbaeea49696b Mon Sep 17 00:00:00 2001 From: zussel Date: Fri, 3 Feb 2017 15:33:05 +0100 Subject: [PATCH 43/61] node analyzer progress --- include/oos/object/node_analyzer.hpp | 10 +++ include/oos/object/node_analyzer.tpp | 116 +++++++++----------------- include/oos/object/object_store.hpp | 7 +- include/oos/object/prototype_node.hpp | 35 +++++++- 4 files changed, 85 insertions(+), 83 deletions(-) diff --git a/include/oos/object/node_analyzer.hpp b/include/oos/object/node_analyzer.hpp index cab1e1a29..962bba4c6 100644 --- a/include/oos/object/node_analyzer.hpp +++ b/include/oos/object/node_analyzer.hpp @@ -18,6 +18,16 @@ class basic_node_analyzer : node_(node), store_(store) { } +protected: + template < class V, class T > + void process_belongs_to(const char *id, belongs_to &x); + + template < class V, class T > + void process_has_one(const char *id, has_one &x); + + template < class V, class T > + void process_has_many(const char *id, has_one &x); + protected: prototype_node &node_; object_store &store_; diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index 09d718835..898858c81 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -6,28 +6,9 @@ namespace oos { namespace detail { - -template class O> -void node_analyzer::analyze() -{ -// std::cout << "START analyzing " << node_.type() << "\n"; - T obj; - oos::access::serialize(*this, obj); -// std::cout << "FINISHED analyzing " << node_.type() << "\n"; -} - -template class O> -template -void node_analyzer::serialize(V &x) +template +void basic_node_analyzer::process_belongs_to(const char *id, belongs_to &x) { - oos::access::serialize(*this, x); -} - -template class O> -template -void node_analyzer::serialize(const char *id, belongs_to &x, cascade_type) -{ -// std::cout << "analyzing belongs_to field " << id << " (typeid: " << typeid(V).name() << ")\n"; prototype_iterator node = store_.find(x.type()); if (node != store_.end()) { // check if created from has_many @@ -42,12 +23,7 @@ void node_analyzer::serialize(const char *id, belongs_to &x, cascade_t } i->second.node = nullptr; } -// } else { -// node = node_.tree()->template prepare_attach(); } -// if (!node->has_primary_key()) { -// throw_object_exception("serializable of type '" << x.type() << "' has no primary key"); -// } object_store &store = store_; node_.register_belongs_to(std::type_index(typeid(V)), prototype_node::relation_info(id, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { store.mark_modified(proxy); @@ -58,9 +34,8 @@ void node_analyzer::serialize(const char *id, belongs_to &x, cascade_t }, node.get())); } -template class O> -template -void node_analyzer::serialize(const char *, has_one &, cascade_type) +template +void basic_node_analyzer::process_has_one(const char *, has_one &) { // std::cout << "analyzing has_one field " << id << " (typeid: " << typeid(V).name() << ")\n"; // prototype_iterator node = node_.tree()->find(x.type()); @@ -73,6 +48,34 @@ void node_analyzer::serialize(const char *, has_one &, cascade_type) // } } +template class O> +void node_analyzer::analyze() +{ + T obj; + oos::access::serialize(*this, obj); +} + +template class O> +template +void node_analyzer::serialize(V &x) +{ + oos::access::serialize(*this, x); +} + +template class O> +template +void node_analyzer::serialize(const char *id, belongs_to &x, cascade_type) +{ + this->process_belongs_to(id, x); +} + +template class O> +template +void node_analyzer::serialize(const char *id, has_one &x, cascade_type) +{ + this->process_has_one(id, x); +} + template class O> template class C> void node_analyzer::serialize(const char *id, has_many &, const char *owner_column, const char *item_column, @@ -89,7 +92,9 @@ void node_analyzer::serialize(const char *id, has_many &, const cha for (auto o : observer_) { has_many_item_observer.push_back(new O::item_type>(o)); } - prototype_node *node = new prototype_node(&store_, id, new typename has_many::item_type, typeid(typename has_many::item_type), false); + +// this->cre + prototype_node *node = new prototype_node(&store_, id, new typename has_many::item_type, false); node->relation_node_info_.owner_type_.assign(node_.type()); node->relation_node_info_.relation_id_.assign(id); node->relation_node_info_.owner_id_column_.assign(owner_column); @@ -153,9 +158,6 @@ void node_analyzer::serialize(const char *id, has_many &, const cha pi->relation_node_info_.owner_id_column_.assign(owner_column); pi->relation_node_info_.item_id_column_.assign(item_column); pi->is_relation_node_ = true; - } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { - // prototype is of type has_many_item - throw_object_exception("many to many relations are not supported by now"); } else { // throw exception throw_object_exception("prototype already inserted: " << pi->type()); @@ -168,10 +170,8 @@ void node_analyzer::serialize(const char *id, has_many &, const cha template void node_analyzer::analyze() { -// std::cout << "START analyzing " << node_.type() << "\n"; T obj; oos::access::serialize(*this, obj); -// std::cout << "FINISHED analyzing " << node_.type() << "\n"; } template @@ -185,50 +185,14 @@ template template void node_analyzer::serialize(const char *id, belongs_to &x, cascade_type) { -// std::cout << "analyzing belongs_to field " << id << " (typeid: " << typeid(V).name() << ")\n"; - prototype_iterator node = store_.find(x.type()); - if (node != store_.end()) { - // check if created from has_many - // check if node has_many relation for id (id == tablename) - auto i = node->has_many_map_.find(node->type_index()); - if (i != node->has_many_map_.end()) { - // yes, node found! - // Todo: check if node is for has many item - // detach has_many_item node - if (i->second.node != nullptr) { - store_.detach(i->second.node); - } - i->second.node = nullptr; - } -// } else { -// node = node_.tree()->template prepare_attach(); - } -// if (!node->has_primary_key()) { -// throw_object_exception("serializable of type '" << x.type() << "' has no primary key"); -// } - object_store &store = store_; - node_.register_belongs_to(std::type_index(typeid(V)), prototype_node::relation_info(id, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { - store.mark_modified(proxy); - oos::set(proxy->obj(), field, object_ptr(owner)); - }, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *) { - store.mark_modified(proxy); - oos::set(proxy->obj(), field, object_ptr()); - }, node.get())); + this->process_belongs_to(id, x); } template template -void node_analyzer::serialize(const char *, has_one &, cascade_type) +void node_analyzer::serialize(const char *id, has_one &x, cascade_type) { -// std::cout << "analyzing has_one field " << id << " (typeid: " << typeid(V).name() << ")\n"; -// prototype_iterator node = node_.tree()->find(x.type()); -// if (node == node_.tree()->end()) { -// // if there is no such prototype node -// // prepare insertion of new node -// node = node_.tree()->template prepare_attach(); -// } else if (!node->has_primary_key()) { -// throw_object_exception("serializable of type '" << x.type() << "' has no primary key"); -// } + this->process_has_one(id, x); } template @@ -249,7 +213,6 @@ void node_analyzer::serialize(const char *id, has_many &, const char * pi->relation_node_info_.owner_id_column_.assign(owner_column); pi->relation_node_info_.item_id_column_.assign(item_column); pi->is_relation_node_ = true; -// pi = node_.tree()->template attach::item_type, O...>(id, false, nullptr, observer_); node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { store.mark_modified(proxy); oos::append(proxy->obj(), field, object_ptr(owner)); @@ -297,9 +260,6 @@ void node_analyzer::serialize(const char *id, has_many &, const char * pi->relation_node_info_.item_id_column_.assign(item_column); pi->is_relation_node_ = true; // pi = node_.tree()->template attach::item_type, O...>(id, false, nullptr, observer_); - } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { - // prototype is of type has_many_item - throw_object_exception("many to many relations are not supported by now"); } else { // throw exception throw_object_exception("prototype already inserted: " << pi->type()); diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index dd5f26c95..ec4cb2f82 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -700,6 +700,7 @@ class OOS_OBJECT_API object_store friend class object_holder; friend class object_proxy; friend class prototype_node; + friend class detail::basic_node_analyzer; template < class T, template < class ... > class ON_ATTACH > friend class detail::node_analyzer; friend class transaction; @@ -843,7 +844,7 @@ template object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent) { // prototype_node *node = acquire(type, abstract); - prototype_node *node = new prototype_node(this, type, new T, typeid(T), abstract); + prototype_node *node = new prototype_node(this, type, new T, abstract); // Check if nodes object has 'to-many' relations // Analyze primary and foreign keys of node @@ -867,7 +868,7 @@ template class O> object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent, const std::vector*> &observer) { // prototype_node *node = acquire(type, abstract); - prototype_node *node = new prototype_node(this, type, new T, typeid(T), abstract); + prototype_node *node = new prototype_node(this, type, new T, abstract); return attach(node, parent, observer); @@ -1051,7 +1052,7 @@ prototype_node *object_store::acquire(const char *type, bool abstract) /* insert new prototype and add to * typeid map */ - node = new prototype_node(this, type, new T, typeid(T), abstract); + node = new prototype_node(this, type, new T, abstract); } return node; } diff --git a/include/oos/object/prototype_node.hpp b/include/oos/object/prototype_node.hpp index 710354489..c0b59bc1a 100644 --- a/include/oos/object/prototype_node.hpp +++ b/include/oos/object/prototype_node.hpp @@ -53,6 +53,7 @@ template < class T, template class C, class Enabled > class has_many_inserter; template < class T, template class C, class Enabled > class has_many_deleter; +class basic_node_analyzer; template < class T, template < class V = T > class O > class node_analyzer; } @@ -104,6 +105,15 @@ class OOS_OBJECT_API prototype_node }; public: + + template < class T > + prototype_node* make_node(object_store *store, const char *type, bool abstract = false); + + template < class T > + prototype_node* make_relation_node(object_store *store, const char *type, bool abstract, + const char *owner_type, const char *relation_id, + const char *owner_column, const char *item_column); + prototype_node(); /** @@ -119,13 +129,13 @@ class OOS_OBJECT_API prototype_node * @param abstract Tells the node if its prototype is abstract. */ template < class T > - prototype_node(object_store *tree, const char *type, T *proto, const std::type_info &typeinfo, bool abstract = false) + prototype_node(object_store *tree, const char *type, T *proto, bool abstract = false) : tree_(tree) , first(new prototype_node) , last(new prototype_node) , type_(type) , abstract_(abstract) - , type_index_(typeinfo) + , type_index_(typeid(T)) , deleter_(&destroy) , notifier_(¬ify_observer) , prototype(proto) @@ -446,6 +456,7 @@ class OOS_OBJECT_API prototype_node friend class detail::has_many_inserter; template < class T, template class C, class Enabled > friend class detail::has_many_deleter; + friend class detail::basic_node_analyzer; template < class T, template < class U = T > class O > friend class detail::node_analyzer; @@ -495,6 +506,26 @@ class OOS_OBJECT_API prototype_node relation_node_info relation_node_info_; }; +template +prototype_node *prototype_node::make_node(object_store *store, const char *type, bool abstract) +{ + return new prototype_node(store, type, new T, abstract); +} + +template +prototype_node *prototype_node::make_relation_node(object_store *store, const char *type, bool abstract, + const char *owner_type, const char *relation_id, + const char *owner_column, const char *item_column) +{ + prototype_node *node = make_node(store, type, abstract); + node->relation_node_info_.owner_type_.assign(owner_type); + node->relation_node_info_.relation_id_.assign(relation_id); + node->relation_node_info_.owner_id_column_.assign(owner_column); + node->relation_node_info_.item_id_column_.assign(item_column); + node->is_relation_node_ = true; + return node; +} + } #endif /* PROTOTYPE_NODE_HPP */ From 87944c424d399447bb865ff514998e56734a7bb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Sat, 4 Feb 2017 11:45:11 +0100 Subject: [PATCH 44/61] more query update tests --- include/oos/object/node_analyzer.hpp | 2 +- include/oos/object/node_analyzer.tpp | 100 ++++++++----------- include/oos/object/object_store.hpp | 25 +---- include/oos/object/prototype_node.hpp | 4 +- include/oos/orm/relation_resolver.hpp | 2 +- include/oos/sql/query.hpp | 18 +++- include/oos/sql/statement.hpp | 3 +- test/orm/OrmTestUnit.cpp | 2 +- test/sql/QueryTestUnit.cpp | 137 ++++++++++++++++---------- test/sql/QueryTestUnit.hpp | 1 + 10 files changed, 150 insertions(+), 144 deletions(-) diff --git a/include/oos/object/node_analyzer.hpp b/include/oos/object/node_analyzer.hpp index 962bba4c6..304e5874d 100644 --- a/include/oos/object/node_analyzer.hpp +++ b/include/oos/object/node_analyzer.hpp @@ -26,7 +26,7 @@ class basic_node_analyzer void process_has_one(const char *id, has_one &x); template < class V, class T > - void process_has_many(const char *id, has_one &x); + void register_has_many(const char *id, prototype_node *node); protected: prototype_node &node_; diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index 898858c81..fa69f074a 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -48,6 +48,19 @@ void basic_node_analyzer::process_has_one(const char *, has_one &) // } } +template +void basic_node_analyzer::register_has_many(const char *id, prototype_node *node) +{ + object_store &store = store_; + node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { + store.mark_modified(proxy); + oos::append(proxy->obj(), field, object_ptr(owner)); + }, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { + store.mark_modified(proxy); + oos::remove(proxy->obj(), field, object_ptr(owner)); + }, node)); +} + template class O> void node_analyzer::analyze() { @@ -85,7 +98,6 @@ void node_analyzer::serialize(const char *id, has_many &, const cha // check if has many item is already attached // true: check owner and item field // false: attach it - object_store &store = store_; prototype_iterator pi = store_.find(id); if (pi == store_.end()) { std::vector::item_type>*> has_many_item_observer; @@ -93,28 +105,11 @@ void node_analyzer::serialize(const char *id, has_many &, const cha has_many_item_observer.push_back(new O::item_type>(o)); } -// this->cre - prototype_node *node = new prototype_node(&store_, id, new typename has_many::item_type, false); - node->relation_node_info_.owner_type_.assign(node_.type()); - node->relation_node_info_.relation_id_.assign(id); - node->relation_node_info_.owner_id_column_.assign(owner_column); - node->relation_node_info_.item_id_column_.assign(item_column); - node->is_relation_node_ = true; + prototype_node *node = prototype_node::make_relation_node::item_type>(&store_, id, false, node_.type(), id, owner_column, item_column); -// pi = store_.attach::item_type>(id, false, nullptr, has_many_item_observer); + pi = store_.attach::item_type>(node, nullptr, has_many_item_observer); - pi->relation_node_info_.owner_type_.assign(node_.type()); - pi->relation_node_info_.relation_id_.assign(id); - pi->relation_node_info_.owner_id_column_.assign(owner_column); - pi->relation_node_info_.item_id_column_.assign(item_column); - pi->is_relation_node_ = true; - node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { - store.mark_modified(proxy); - oos::append(proxy->obj(), field, object_ptr(owner)); - }, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { - store.mark_modified(proxy); - oos::remove(proxy->obj(), field, object_ptr(owner)); - }, pi.get())); + this->register_has_many(id, pi.get()); } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item throw_object_exception("many to many relations are not supported by now"); @@ -124,13 +119,7 @@ void node_analyzer::serialize(const char *id, has_many &, const cha if (j != pi->belongs_to_map_.end()) { // set missing node j->second.node = &node_; - node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { - store.mark_modified(proxy); - oos::append(proxy->obj(), field, object_ptr(owner)); - }, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { - store.mark_modified(proxy); - oos::remove(proxy->obj(), field, object_ptr(owner)); - }, pi.get())); + this->register_has_many(id, pi.get()); } else { throw_object_exception("prototype already inserted: " << pi->type()); } @@ -152,12 +141,10 @@ void node_analyzer::serialize(const char *id, has_many &, const cha for (auto o : observer_) { has_many_item_observer.push_back(new O::item_type>(o)); } - pi = store_.attach::item_type>(id, false, nullptr, has_many_item_observer); - pi->relation_node_info_.owner_type_.assign(node_.type()); - pi->relation_node_info_.relation_id_.assign(id); - pi->relation_node_info_.owner_id_column_.assign(owner_column); - pi->relation_node_info_.item_id_column_.assign(item_column); - pi->is_relation_node_ = true; + + prototype_node *node = prototype_node::make_relation_node::item_type>(&store_, id, false, node_.type(), id, owner_column, item_column); + + pi = store_.attach::item_type>(node, nullptr, has_many_item_observer); } else { // throw exception throw_object_exception("prototype already inserted: " << pi->type()); @@ -204,22 +191,13 @@ void node_analyzer::serialize(const char *id, has_many &, const char * // check if has many item is already attached // true: check owner and item field // false: attach it - object_store &store = store_; prototype_iterator pi = store_.find(id); if (pi == store_.end()) { - pi = store_.attach::item_type>(id, false, nullptr); - pi->relation_node_info_.owner_type_.assign(node_.type()); - pi->relation_node_info_.relation_id_.assign(id); - pi->relation_node_info_.owner_id_column_.assign(owner_column); - pi->relation_node_info_.item_id_column_.assign(item_column); - pi->is_relation_node_ = true; - node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { - store.mark_modified(proxy); - oos::append(proxy->obj(), field, object_ptr(owner)); - }, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { - store.mark_modified(proxy); - oos::remove(proxy->obj(), field, object_ptr(owner)); - }, pi.get())); + prototype_node *node = prototype_node::make_relation_node::item_type>(&store_, id, false, node_.type(), id, owner_column, item_column); + + pi = store_.attach::item_type>(node, nullptr); + + this->register_has_many(id, pi.get()); } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item throw_object_exception("many to many relations are not supported by now"); @@ -229,13 +207,7 @@ void node_analyzer::serialize(const char *id, has_many &, const char * if (j != pi->belongs_to_map_.end()) { // set missing node j->second.node = &node_; - node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { - store.mark_modified(proxy); - oos::append(proxy->obj(), field, object_ptr(owner)); - }, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { - store.mark_modified(proxy); - oos::remove(proxy->obj(), field, object_ptr(owner)); - }, pi.get())); + this->register_has_many(id, pi.get()); } else { throw_object_exception("prototype already inserted: " << pi->type()); } @@ -253,12 +225,18 @@ void node_analyzer::serialize(const char *id, has_many &, const char * // false: attach it prototype_iterator pi = store_.find(id); if (pi == store_.end()) { - pi = store_.attach::item_type>(id, false, nullptr); - pi->relation_node_info_.owner_type_.assign(node_.type()); - pi->relation_node_info_.relation_id_.assign(id); - pi->relation_node_info_.owner_id_column_.assign(owner_column); - pi->relation_node_info_.item_id_column_.assign(item_column); - pi->is_relation_node_ = true; + prototype_node *node = prototype_node::make_relation_node::item_type>(&store_, id, false, node_.type(), id, owner_column, item_column); + + pi = store_.attach::item_type>(node, nullptr); +// +// this->register_has_many(id, pi.get()); + +// pi = store_.attach::item_type>(id, false, nullptr); +// pi->relation_node_info_.owner_type_.assign(node_.type()); +// pi->relation_node_info_.relation_id_.assign(id); +// pi->relation_node_info_.owner_id_column_.assign(owner_column); +// pi->relation_node_info_.item_id_column_.assign(item_column); +// pi->is_relation_node_ = true; // pi = node_.tree()->template attach::item_type, O...>(id, false, nullptr, observer_); } else { // throw exception diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index ec4cb2f82..2555b5009 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -846,16 +846,7 @@ object_store::iterator object_store::attach(const char *type, bool abstract, con // prototype_node *node = acquire(type, abstract); prototype_node *node = new prototype_node(this, type, new T, abstract); - // Check if nodes object has 'to-many' relations - // Analyze primary and foreign keys of node - detail::node_analyzer analyzer(*node, *this); - analyzer.analyze(); - - attach_node(node, parent); - - node->on_attach(); - - return prototype_iterator(node); + return attach(node, parent); } template class O > @@ -870,21 +861,7 @@ object_store::iterator object_store::attach(const char *type, bool abstract, con // prototype_node *node = acquire(type, abstract); prototype_node *node = new prototype_node(this, type, new T, abstract); - return attach(node, parent, observer); - for(auto o : observer) { - node->register_observer(o); - } - // Check if nodes object has 'to-many' relations - // Analyze primary and foreign keys of node - detail::node_analyzer analyzer(*node, *this, observer); - analyzer.analyze(); - - attach_node(node, parent); - - node->on_attach(); - - return prototype_iterator(node); } template < class T > diff --git a/include/oos/object/prototype_node.hpp b/include/oos/object/prototype_node.hpp index c0b59bc1a..a358a4ce6 100644 --- a/include/oos/object/prototype_node.hpp +++ b/include/oos/object/prototype_node.hpp @@ -107,10 +107,10 @@ class OOS_OBJECT_API prototype_node public: template < class T > - prototype_node* make_node(object_store *store, const char *type, bool abstract = false); + static prototype_node* make_node(object_store *store, const char *type, bool abstract = false); template < class T > - prototype_node* make_relation_node(object_store *store, const char *type, bool abstract, + static prototype_node* make_relation_node(object_store *store, const char *type, bool abstract, const char *owner_type, const char *relation_id, const char *owner_column, const char *item_column); diff --git a/include/oos/orm/relation_resolver.hpp b/include/oos/orm/relation_resolver.hpp index 5a167269f..1d147b048 100644 --- a/include/oos/orm/relation_resolver.hpp +++ b/include/oos/orm/relation_resolver.hpp @@ -147,7 +147,7 @@ class relation_resolver */ if (j->second->is_loaded()) { // relation table is loaded - std::cout << "Todo: relation table [" << id << "/" << j->second->name() << "] loaded; append all elements for owner " << *id_ << "\n"; +// std::cout << "Todo: relation table [" << id << "/" << j->second->name() << "] loaded; append all elements for owner " << *id_ << "\n"; auto i = table_.has_many_relations_.find(id); // get relation items for id/relation if (i != table_.has_many_relations_.end()) { diff --git a/include/oos/sql/query.hpp b/include/oos/sql/query.hpp index e09b70ae9..4630202e9 100644 --- a/include/oos/sql/query.hpp +++ b/include/oos/sql/query.hpp @@ -515,6 +515,13 @@ class query : public detail::basic_query reset_query(query_command); return *this; } + result execute() + { + if (!conn_.is_open()) { + throw std::logic_error("connection is not open"); + } + return execute(conn_); + } /** * Executes the current query and * returns a new result serializable. @@ -523,11 +530,20 @@ class query : public detail::basic_query */ result execute(connection &conn) { -// std::cout << "SQL: " << conn.dialect()->direct(sql_) << '\n'; + std::cout << "SQL: " << conn.dialect()->direct(sql_) << '\n'; // std::cout.flush(); return conn.execute(sql_); } + statement prepare() + { + if (!conn_.is_open()) { + throw std::logic_error("connection is not open"); + } + return prepare(conn_); + + } + /** * Creates and returns a prepared * statement based on the current query. diff --git a/include/oos/sql/statement.hpp b/include/oos/sql/statement.hpp index 95d772638..ca1516b8e 100644 --- a/include/oos/sql/statement.hpp +++ b/include/oos/sql/statement.hpp @@ -117,7 +117,7 @@ class statement */ result execute() { -// std::cout << "SQL: " << p->str() << '\n'; + std::cout << "SQL: " << p->str() << '\n'; //std::cout.flush(); return result(p->execute()); } @@ -257,6 +257,7 @@ class statement */ result execute() { + std::cout << "SQL: " << p->str() << '\n'; return result(p->execute(), prototype_); } diff --git a/test/orm/OrmTestUnit.cpp b/test/orm/OrmTestUnit.cpp index 07c40abc1..2a36d59f8 100644 --- a/test/orm/OrmTestUnit.cpp +++ b/test/orm/OrmTestUnit.cpp @@ -100,7 +100,7 @@ void OrmTestUnit::test_select() for (std::string name : names) { auto pptr = s.insert(new person(name, oos::date(18, 5, 1980), 180)); - UNIT_EXPECT_GREATER(pptr->id(), 0UL, "is must be greater zero"); + UNIT_EXPECT_GREATER(pptr->id(), 0UL, "is must be greater zero"); } auto view = s.select(); diff --git a/test/sql/QueryTestUnit.cpp b/test/sql/QueryTestUnit.cpp index bfd32ef0d..058765100 100644 --- a/test/sql/QueryTestUnit.cpp +++ b/test/sql/QueryTestUnit.cpp @@ -23,6 +23,7 @@ QueryTestUnit::QueryTestUnit(const std::string &name, const std::string &msg, co add_test("bind_tablename", std::bind(&QueryTestUnit::test_bind_tablename, this), "test bind tablenames"); add_test("describe", std::bind(&QueryTestUnit::test_describe, this), "test describe table"); add_test("identifier", std::bind(&QueryTestUnit::test_identifier, this), "test sql identifier"); + add_test("update", std::bind(&QueryTestUnit::test_update, this), "test direct sql update statement"); add_test("create", std::bind(&QueryTestUnit::test_create, this), "test direct sql create statement"); add_test("create_anonymous", std::bind(&QueryTestUnit::test_anonymous_create, this), "test direct sql create statement via row (anonymous)"); add_test("insert_anonymous", std::bind(&QueryTestUnit::test_anonymous_insert, this), "test direct sql insert statement via row (anonymous)"); @@ -375,6 +376,56 @@ void QueryTestUnit::test_create() res = q.drop().execute(connection_); } +void QueryTestUnit::test_update() +{ + connection_.open(); + + query q(connection_, "person"); + + // create item table and insert item + result res(q.create().execute()); + + std::vector names({ "hans", "otto", "georg", "hilde" }); + + unsigned long id(0); + for (std::string name : names) { + person p(name, oos::date(12, 3, 1980), 180); + p.id(++id); + q.insert(p).execute(); + } + + column name("name"); + res = q.select().where(name == "hans").execute(); + + auto first = res.begin(); + auto last = res.end(); + + while (first != last) { + std::unique_ptr item(first.release()); + + UNIT_ASSERT_EQUAL(item->name(), "hans", "expected name must be 'Hans'"); + UNIT_ASSERT_EQUAL(item->height(), 180U, "expected height must be 180"); + UNIT_ASSERT_EQUAL(item->birthdate(), oos::date(12, 3, 1980), "expected birthdate is 12.3.1980"); + + ++first; + } + + person hans("hans", oos::date(15, 6, 1990), 165); + hans.id(1); + column idcol("id"); + q.update(hans).where(idcol == 1).execute(); + + res = q.select().where(name == "hans").execute(); + + for (auto i : res) { + UNIT_ASSERT_EQUAL(i->name(), "hans", "expected name must be 'Hans'"); + UNIT_ASSERT_EQUAL(i->height(), 165U, "expected height must be 180"); + UNIT_ASSERT_EQUAL(i->birthdate(), oos::date(15, 6, 1990), "expected birthdate is 12.3.1980"); + } + + q.drop().execute(); +} + void QueryTestUnit::test_anonymous_create() { connection_.open(); @@ -514,23 +565,27 @@ void QueryTestUnit::test_statement_update() { connection_.open(); - query q("item"); + query q(connection_, "person"); - statement stmt(q.create().prepare(connection_)); + statement stmt(q.create().prepare()); - result res(stmt.execute()); + result res(stmt.execute()); - oos::identifier id(23); - auto itime = time_val_; - Item hans("Hans", 4711); - hans.id(id.value()); - hans.set_time(itime); - stmt = q.insert(hans).prepare(connection_); + std::vector names({ "hans", "otto", "georg", "hilde" }); - stmt.bind(0, &hans); - res = stmt.execute(); + unsigned long id(0); + for (std::string name : names) { + person p(name, oos::date(12, 3, 1980), 180); + p.id(++id); + stmt = q.insert(p).prepare(); + stmt.bind(0, &p); + stmt.execute(); + } - stmt = q.select().prepare(connection_); + column name("name"); + stmt = q.select().where(name == "").prepare(); + std::string hname("hans"); + stmt.bind(0, hname); res = stmt.execute(); // UNIT_ASSERT_EQUAL(res.size(), 1UL, "expected size must be one (1)"); @@ -539,52 +594,30 @@ void QueryTestUnit::test_statement_update() auto last = res.end(); while (first != last) { - std::unique_ptr item(first.release()); - UNIT_ASSERT_EQUAL(item->id(), 23UL, "expected id must be 23"); - UNIT_ASSERT_EQUAL(item->get_string(), "Hans", "expected name must be 'Hans'"); - UNIT_EXPECT_EQUAL(item->get_int(), 4711, "expected integer must be 4711"); - UNIT_EXPECT_EQUAL(item->get_time(), itime, "expected time is invalid"); + std::unique_ptr p(first.release()); + UNIT_EXPECT_EQUAL(p->id(), 1UL, "expected id must be 1"); + UNIT_ASSERT_EQUAL(p->name(), "hans", "expected name must be 'hans'"); + UNIT_ASSERT_EQUAL(p->height(), 180U, "expected height must be 180"); + UNIT_ASSERT_EQUAL(p->birthdate(), oos::date(12, 3, 1980), "expected birthdate is 12.3.1980"); ++first; } // auto id_cond = id_condition_builder::build(); oos::column idcol("id"); - int i815 = 815; - stmt = q.update({{"val_int", i815}}).where(idcol == 7).prepare(connection_); - size_t pos = 0; - pos = stmt.bind(pos, i815); - unsigned long hid = hans.id(); - stmt.bind(pos, hid); - - res = stmt.execute(); - - stmt = q.select().prepare(connection_); - res = stmt.execute(); - -// UNIT_ASSERT_EQUAL(res.size(), 1UL, "expected size must be one (1)"); - - first = res.begin(); - last = res.end(); - - while (first != last) { - std::unique_ptr item(first.release()); - UNIT_EXPECT_EQUAL(item->id(), 23UL, "expected id must be 23"); - UNIT_ASSERT_EQUAL(item->get_string(), "Hans", "expected name must be 'Hans'"); - UNIT_EXPECT_EQUAL(item->get_int(), 815, "expected integer must be 815"); - UNIT_EXPECT_EQUAL(item->get_time(), itime, "expected time is invalid"); - ++first; - } + person hans("hans", oos::date(15, 6, 1990), 165); + hans.id(1); - hans.set_int(4711); - stmt = q.update(hans).where(idcol == 7).prepare(connection_); - pos = 0; + stmt = q.update(hans).where(idcol == 7).prepare(); + size_t pos = 0; pos = stmt.bind(pos, &hans); + unsigned long hid = 1; stmt.bind(pos, hid); res = stmt.execute(); - stmt = q.select().prepare(connection_); + stmt = q.select().where(name == "").prepare(); + stmt.bind(0, hname); res = stmt.execute(); // UNIT_ASSERT_EQUAL(res.size(), 1UL, "expected size must be one (1)"); @@ -593,15 +626,15 @@ void QueryTestUnit::test_statement_update() last = res.end(); while (first != last) { - std::unique_ptr item(first.release()); - UNIT_EXPECT_EQUAL(item->id(), 23UL, "expected id must be 23"); - UNIT_EXPECT_EQUAL(item->get_string(), "Hans", "expected name must be 'Hans'"); - UNIT_EXPECT_EQUAL(item->get_int(), 4711, "expected integer must be 4711"); - UNIT_EXPECT_EQUAL(item->get_time(), itime, "expected time is invalid"); + std::unique_ptr p(first.release()); + UNIT_EXPECT_EQUAL(p->id(), 1UL, "expected id must be 1"); + UNIT_ASSERT_EQUAL(p->name(), "hans", "expected name must be 'hans'"); + UNIT_ASSERT_EQUAL(p->height(), 165U, "expected height must be 180"); + UNIT_ASSERT_EQUAL(p->birthdate(), oos::date(15, 6, 1990), "expected birthdate is 12.3.1980"); ++first; } - stmt = q.drop().prepare(connection_); + stmt = q.drop().prepare(); res = stmt.execute(); diff --git a/test/sql/QueryTestUnit.hpp b/test/sql/QueryTestUnit.hpp index 5fe7a3a2e..077711e48 100644 --- a/test/sql/QueryTestUnit.hpp +++ b/test/sql/QueryTestUnit.hpp @@ -30,6 +30,7 @@ class QueryTestUnit : public oos::unit_test void test_describe(); void test_identifier(); void test_create(); + void test_update(); void test_anonymous_create(); void test_anonymous_insert(); void test_anonymous_update(); From 9cba472abc357dbdd6726e312bc8c1d72e805c81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Sat, 4 Feb 2017 15:54:43 +0100 Subject: [PATCH 45/61] fixed sqlite prepared statement date parsing --- include/oos/db/mysql/mysql_statement.hpp | 1 + include/oos/sql/query.hpp | 2 +- include/oos/sql/statement.hpp | 4 ++-- include/oos/utils/string.hpp | 2 +- src/db/mysql/mysql_statement.cpp | 3 +++ src/db/sqlite/sqlite_prepared_result.cpp | 5 +++-- 6 files changed, 11 insertions(+), 6 deletions(-) diff --git a/include/oos/db/mysql/mysql_statement.hpp b/include/oos/db/mysql/mysql_statement.hpp index fe1c1d8ca..3c5062268 100644 --- a/include/oos/db/mysql/mysql_statement.hpp +++ b/include/oos/db/mysql/mysql_statement.hpp @@ -78,6 +78,7 @@ class mysql_statement : public oos::detail::statement_impl template < class T > void bind_value(std::size_t index, enum_field_types type, T value) { +// std::cout << "binding [" << value << "] (index: " << index << ")\n"; MYSQL_BIND &bind = host_array[index]; if (bind.buffer == nullptr) { // allocating memory diff --git a/include/oos/sql/query.hpp b/include/oos/sql/query.hpp index 4630202e9..3f7adc087 100644 --- a/include/oos/sql/query.hpp +++ b/include/oos/sql/query.hpp @@ -530,7 +530,7 @@ class query : public detail::basic_query */ result execute(connection &conn) { - std::cout << "SQL: " << conn.dialect()->direct(sql_) << '\n'; +// std::cout << "SQL: " << conn.dialect()->direct(sql_) << '\n'; // std::cout.flush(); return conn.execute(sql_); } diff --git a/include/oos/sql/statement.hpp b/include/oos/sql/statement.hpp index ca1516b8e..7152ebb95 100644 --- a/include/oos/sql/statement.hpp +++ b/include/oos/sql/statement.hpp @@ -117,7 +117,7 @@ class statement */ result execute() { - std::cout << "SQL: " << p->str() << '\n'; +// std::cout << "SQL: " << p->str() << '\n'; //std::cout.flush(); return result(p->execute()); } @@ -257,7 +257,7 @@ class statement */ result execute() { - std::cout << "SQL: " << p->str() << '\n'; +// std::cout << "SQL: " << p->str() << '\n'; return result(p->execute(), prototype_); } diff --git a/include/oos/utils/string.hpp b/include/oos/utils/string.hpp index c822de689..3586a4b11 100644 --- a/include/oos/utils/string.hpp +++ b/include/oos/utils/string.hpp @@ -70,7 +70,7 @@ struct OOS_UTILS_API date_format /** * date format string representing the ISO8601 format */ - static constexpr const char* ISO8601 = "%F"; + static constexpr const char* ISO8601 = "%Y-%m-%d"; #endif }; diff --git a/src/db/mysql/mysql_statement.cpp b/src/db/mysql/mysql_statement.cpp index 8fe175081..7e71ac6e4 100644 --- a/src/db/mysql/mysql_statement.cpp +++ b/src/db/mysql/mysql_statement.cpp @@ -215,6 +215,7 @@ void mysql_statement::serialize(const char *id, basic_identifier &x) void mysql_statement::serialize(const char *id, identifiable_holder &x, cascade_type) { +// std::cout << "binding [" << id << "] (index: " << host_index << ")\n"; if (x.has_primary_key()) { x.primary_key()->serialize(id, *this); } else { @@ -252,6 +253,7 @@ void mysql_statement::bind_value(std::size_t index, enum_field_types, unsigned c void mysql_statement::bind_value(std::size_t index, enum_field_types type, const oos::date &x) { +// std::cout << "binding [" << x << "] (index: " << index << ")\n"; MYSQL_BIND &bind = host_array[index]; if (bind.buffer == nullptr) { size_t s = sizeof(MYSQL_TIME); @@ -296,6 +298,7 @@ void mysql_statement::bind_value(std::size_t index, enum_field_types type, const void mysql_statement::bind_value(std::size_t index, enum_field_types type, const char *value, size_t) { +// std::cout << "binding [" << value << "] (index: " << index << ")\n"; MYSQL_BIND &bind = host_array[index]; std::size_t len(strlen(value) + 1); if (bind.buffer_length < len) { diff --git a/src/db/sqlite/sqlite_prepared_result.cpp b/src/db/sqlite/sqlite_prepared_result.cpp index 5c3af2fb9..4269bce0b 100644 --- a/src/db/sqlite/sqlite_prepared_result.cpp +++ b/src/db/sqlite/sqlite_prepared_result.cpp @@ -3,6 +3,7 @@ #include "oos/utils/date.hpp" #include "oos/utils/time.hpp" #include "oos/utils/varchar.hpp" +#include "oos/utils/string.hpp" #include "oos/utils/basic_identifier.hpp" #include @@ -158,9 +159,9 @@ void sqlite_prepared_result::serialize(const char *, char *x, size_t s) void sqlite_prepared_result::serialize(const char *id, oos::date &x) { - double val = 0; + std::string val; serialize(id, val); - x.set(static_cast(val)); + x = oos::date::parse(val, date_format::ISO8601); } void sqlite_prepared_result::serialize(const char *id, oos::time &x) From 0dd4b788635129fbac5d98ac409ef22ecaeabdcb Mon Sep 17 00:00:00 2001 From: zussel Date: Sun, 5 Feb 2017 22:30:37 +0100 Subject: [PATCH 46/61] belongs to for win progress --- include/oos/object/attribute_serializer.hpp | 12 +++++++++++- include/oos/object/prototype_node.hpp | 10 ++++++++-- test/Item.hpp | 2 +- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/include/oos/object/attribute_serializer.hpp b/include/oos/object/attribute_serializer.hpp index 1468314f8..fd3866c51 100644 --- a/include/oos/object/attribute_serializer.hpp +++ b/include/oos/object/attribute_serializer.hpp @@ -276,7 +276,7 @@ class attribute_writer : public basic_attribute_serializer ~attribute_writer() {} template < class V > - void serialize(const char *id, V &from, typename std::enable_if< std::is_arithmetic::value && std::is_arithmetic::value >::type* = 0) + void serialize(const char *id, V &from, typename std::enable_if< std::is_arithmetic::value && std::is_arithmetic::value && !std::is_same::value>::type* = 0) { if (id_ != id) { return; @@ -285,6 +285,16 @@ class attribute_writer : public basic_attribute_serializer success_ = true; } + template < class V > + void serialize(const char *id, V &from, typename std::enable_if::value && std::is_same::value>::type* = 0) + { + if (id_ != id) { + return; + } + to_ = (from ? 1 : 0); + success_ = true; + } + template < class V > void serialize(const char *id, V &from, typename std::enable_if::value && std::is_same::value >::type* = 0) { diff --git a/include/oos/object/prototype_node.hpp b/include/oos/object/prototype_node.hpp index a358a4ce6..67e9dfb9a 100644 --- a/include/oos/object/prototype_node.hpp +++ b/include/oos/object/prototype_node.hpp @@ -355,7 +355,13 @@ class OOS_OBJECT_API prototype_node private: - enum notification_type { ATTACH, DETACH, INSERT, UPDATE, DELETE }; + enum notification_type { + ATTACH, + DETACH, + INSERT, + UPDATE, + REMOVE + }; /** * @internal @@ -433,7 +439,7 @@ class OOS_OBJECT_API prototype_node break; case UPDATE: break; - case DELETE: + case REMOVE: break; default: break; diff --git a/test/Item.hpp b/test/Item.hpp index 8c0db2c9a..ede3ae61a 100644 --- a/test/Item.hpp +++ b/test/Item.hpp @@ -335,7 +335,7 @@ class person void height(unsigned int height) { height_ = height; } }; -class department; +struct department; class employee : public person { From efdb933fd6093842002434e2ef24463a1a8e2210 Mon Sep 17 00:00:00 2001 From: zussel Date: Mon, 6 Feb 2017 22:31:00 +0100 Subject: [PATCH 47/61] fixed vs compile --- include/oos/object/attribute_serializer.hpp | 69 +++++++++++++++++++-- include/oos/object/has_many_vector.hpp | 22 +++++++ 2 files changed, 87 insertions(+), 4 deletions(-) diff --git a/include/oos/object/attribute_serializer.hpp b/include/oos/object/attribute_serializer.hpp index fd3866c51..c386d5bdf 100644 --- a/include/oos/object/attribute_serializer.hpp +++ b/include/oos/object/attribute_serializer.hpp @@ -68,7 +68,7 @@ class attribute_reader : public basic_attribute_serializer {} template < class V > - void serialize(const char *id, V &to, typename std::enable_if< std::is_arithmetic::value && std::is_arithmetic::value >::type* = 0) + void serialize(const char *id, V &to, typename std::enable_if::value && std::is_arithmetic::value && !std::is_same::value>::type* = 0) { if (id_ != id) { return; @@ -77,6 +77,16 @@ class attribute_reader : public basic_attribute_serializer this->success_ = true; } + template < class V > + void serialize(const char *id, V &to, typename std::enable_if::value && std::is_same::value>::type* = 0) + { + if (id_ != id) { + return; + } + to = from_ > 0; + this->success_ = true; + } + template < class V > void serialize(const char *id, V &to, typename std::enable_if::value && std::is_same::value >::type* = 0) { @@ -87,7 +97,7 @@ class attribute_reader : public basic_attribute_serializer this->success_ = true; } template < class V > - void serialize(const char *, V &, typename std::enable_if<(!std::is_arithmetic::value || !std::is_arithmetic::value) && !std::is_same::value >::type* = 0) {} + void serialize(const char *, V &, typename std::enable_if<(!std::is_arithmetic::value || !std::is_arithmetic::value) && !std::is_same::value >::type* = 0) {} void serialize(const char *, char*, size_t) {} template < class HAS_ONE > void serialize(const char *, HAS_ONE &, cascade_type) {} @@ -98,6 +108,57 @@ class attribute_reader : public basic_attribute_serializer const T &from_; }; +template <> +class attribute_reader : public basic_attribute_serializer +{ +public: + attribute_reader(const std::string &id, bool from) + : basic_attribute_serializer(id) + , from_(from) + {} + + template < class V > + void serialize(const char *id, V &to, typename std::enable_if::value && !std::is_same::value>::type* = 0) + { + if (id_ != id) { + return; + } + to = (from_ > 0); + this->success_ = true; + } + + template < class V > + void serialize(const char *id, V &to, typename std::enable_if::value>::type* = 0) + { + if (id_ != id) { + return; + } + to = (from_ > 0.0f); + this->success_ = true; + } + + template < class V > + void serialize(const char *id, V &to, typename std::enable_if::value && std::is_same::value>::type* = 0) + { + if (id_ != id) { + return; + } + to = from_; + this->success_ = true; + } + + template < class V > + void serialize(const char *, V &, typename std::enable_if::value>::type* = 0) {} + void serialize(const char *, char*, size_t) {} + template < class HAS_ONE > + void serialize(const char *, HAS_ONE &, cascade_type) {} + template < class HAS_MANY > + void serialize(const char *, HAS_MANY &, const char *, const char *) {} + +private: + bool from_; +}; + template < class T > class attribute_reader> : public basic_attribute_serializer { @@ -276,7 +337,7 @@ class attribute_writer : public basic_attribute_serializer ~attribute_writer() {} template < class V > - void serialize(const char *id, V &from, typename std::enable_if< std::is_arithmetic::value && std::is_arithmetic::value && !std::is_same::value>::type* = 0) + void serialize(const char *id, V &from, typename std::enable_if< std::is_arithmetic::value && std::is_arithmetic::value && !std::is_same::value>::type* = 0) { if (id_ != id) { return; @@ -286,7 +347,7 @@ class attribute_writer : public basic_attribute_serializer } template < class V > - void serialize(const char *id, V &from, typename std::enable_if::value && std::is_same::value>::type* = 0) + void serialize(const char *id, V &from, typename std::enable_if::value && std::is_arithmetic::value && std::is_same::value>::type* = 0) { if (id_ != id) { return; diff --git a/include/oos/object/has_many_vector.hpp b/include/oos/object/has_many_vector.hpp index 6e1ce586a..363a6dced 100644 --- a/include/oos/object/has_many_vector.hpp +++ b/include/oos/object/has_many_vector.hpp @@ -133,6 +133,17 @@ class has_many_iterator */ bool operator!=(const self &i) const { return !this->operator==(i); } + /** + * @brief Compares less than iterator with another iterator. + * + * Compares iterator with another iterator. If other iterator isn't + * less than this iterator true es returned. + * + * @param i The iterator to compare with + * @return True if iterators isn't less than this itertor + */ + bool operator<(const self &i) const { return iter_ < i.iter_; } + /** * @brief Returns the difference of two iterators a and b. * @@ -424,6 +435,17 @@ class const_has_many_iterator */ bool operator!=(const self &i) const { return !this->operator==(i); } + /** + * @brief Compares less than iterator with another iterator. + * + * Compares iterator with another iterator. If other iterator isn't + * less than this iterator true es returned. + * + * @param i The iterator to compare with + * @return True if iterators isn't less than this itertor + */ + bool operator<(const self &i) const { return iter_ < i.iter_; } + /** * @brief Pre increments self * From a196542479823d40f2ae3f04b95b590984140f66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Thu, 9 Feb 2017 21:42:55 +0100 Subject: [PATCH 48/61] added inserter and deleter to has many list --- include/oos/object/basic_has_many.hpp | 6 + include/oos/object/has_many_list.hpp | 132 +++++++++++++++++--- include/oos/object/has_many_vector.hpp | 47 +++---- include/oos/object/object_store.hpp | 166 ++++++++----------------- src/object/object_store.cpp | 39 ------ 5 files changed, 191 insertions(+), 199 deletions(-) diff --git a/include/oos/object/basic_has_many.hpp b/include/oos/object/basic_has_many.hpp index dc5580e7a..571faa26e 100644 --- a/include/oos/object/basic_has_many.hpp +++ b/include/oos/object/basic_has_many.hpp @@ -14,6 +14,12 @@ namespace oos { namespace detail { class object_inserter; + +template class C, class Enabled = void> +class has_many_deleter; + +template class C, class Enabled = void> +class has_many_inserter; } /// @cond OOS_DEV diff --git a/include/oos/object/has_many_list.hpp b/include/oos/object/has_many_list.hpp index 3bd608119..503cab8d5 100644 --- a/include/oos/object/has_many_list.hpp +++ b/include/oos/object/has_many_list.hpp @@ -130,6 +130,16 @@ class has_many_iterator */ bool operator!=(const self &i) const { return !this->operator==(i); } + /** + * @brief Compares less than iterator with another iterator. + * + * Compares iterator with another iterator. If other iterator isn't + * less than this iterator true es returned. + * + * @param i The iterator to compare with + * @return True if iterators isn't less than this itertor + */ + bool operator<(const self &i) const { return iter_ < i.iter_; } /** * @brief Returns the difference of two iterators a and b. * @@ -354,6 +364,16 @@ class const_has_many_iterator */ bool operator!=(const self &i) const { return !this->operator==(i); } + /** + * @brief Compares less than iterator with another iterator. + * + * Compares iterator with another iterator. If other iterator isn't + * less than this iterator true es returned. + * + * @param i The iterator to compare with + * @return True if iterators isn't less than this itertor + */ + bool operator<(const self &i) const { return iter_ < i.iter_; } /** * @brief Pre increments self * @@ -428,6 +448,83 @@ class const_has_many_iterator const_container_iterator iter_; }; +namespace detail { + +template +class has_many_inserter::value>::type> +{ +public: + typedef T value_type; + typedef typename has_many_iterator_traits::relation_type relation_type; + typedef typename basic_has_many::mark_modified_owner_func mark_modified_owner_func; + + void insert(object_store &store, const relation_type &rtype, object_proxy &owner, const mark_modified_owner_func &mark_modified_owner) + { + prototype_iterator foreign_node_ = store.find(typeid(T).name()); + + auto i = foreign_node_->belongs_to_map_.find(owner.node()->type_index()); + if (i != foreign_node_->belongs_to_map_.end()) { + // set owner into value + store.on_update_relation_owner(i->second, rtype->value().proxy_ /*owner*/, &owner /*value*/); + } else { + store.insert(rtype); + } + mark_modified_owner(store, &owner); + } +}; + +template +class has_many_inserter::value>::type> +{ +public: + typedef T value_type; + typedef typename has_many_iterator_traits::relation_type relation_type; + typedef typename basic_has_many::mark_modified_owner_func mark_modified_owner_func; + + void insert(object_store &store, const relation_type &rtype, object_proxy &owner, const mark_modified_owner_func &mark_modified_owner) + { + store.insert(rtype); + mark_modified_owner(store, &owner); + } +}; + +template +class has_many_deleter::value>::type> +{ +public: + typedef T value_type; + typedef typename has_many_iterator_traits::relation_type relation_type; + + void remove(object_store &store, relation_type &rtype, object_proxy &owner) + { + prototype_iterator foreign_node_ = store.find(typeid(T).name()); + + auto i = foreign_node_->belongs_to_map_.find(owner.node()->type_index()); + if (i != foreign_node_->belongs_to_map_.end()) { +// store.remove(val); + // set owner into value + store.on_remove_relation_owner(i->second, rtype->value().proxy_ /*owner*/, &owner /*value*/); + } else { + store.remove(rtype); + } + } +}; + +template +class has_many_deleter::value>::type> +{ +public: + typedef T value_type; + typedef typename has_many_iterator_traits::relation_type relation_type; + + void remove(object_store &store, relation_type &rtype, object_proxy &) + { + store.remove(rtype); + } +}; + +} + /** * @brief Has many relation class using a std::list as container * @@ -487,11 +584,10 @@ class has_many : public basic_has_many item_type *item = this->create_item(value); relation_type iptr(item); if (this->ostore_) { - this->ostore_->insert(iptr); - this->mark_modified_owner_(*this->ostore_, this->owner_); + inserter_.insert(*this->ostore_, iptr, *this->owner_, this->mark_modified_owner_); } - container_iterator i = pos.iter_; - return iterator(this->container_.insert(i, iptr)); +// container_iterator i = pos.iter_; + return iterator(this->container_.insert(pos.iter_, iptr)); } /** @@ -514,6 +610,14 @@ class has_many : public basic_has_many insert(this->end(), value); } + /** + * @brief Clears the list + */ + void clear() + { + erase(this->begin(), this->end()); + } + void remove(const value_type &value) { iterator first = this->begin(); @@ -543,14 +647,6 @@ class has_many : public basic_has_many } } - /** - * @brief Clears the list - */ - void clear() - { - erase(this->begin(), this->end()); - } - /** * @brief Erase the element at given position. * @@ -562,8 +658,8 @@ class has_many : public basic_has_many iterator erase(iterator i) { if (this->ostore_) { - relation_type iptr = i.relation_item(); - this->ostore_->remove(iptr); + relation_type iptr(*i.iter_); + deleter_.remove(*this->ostore_, iptr, *this->owner_); } container_iterator ci = this->container_.erase(i.iter_); return iterator(ci); @@ -586,8 +682,8 @@ class has_many : public basic_has_many iterator i = start; if (this->ostore_) { while (i != end) { - typename base::relation_type iptr = (i++).relation_item(); - this->ostore_->remove(iptr); + relation_type iptr = (i++).relation_item(); + deleter_.remove(*this->ostore_, iptr, *this->owner_); } } return iterator(this->container_.erase(start.iter_, end.iter_)); @@ -598,6 +694,10 @@ class has_many : public basic_has_many { return new item_type(this->owner_field_, this->item_field_, this->owner_id_, value); } + +private: + detail::has_many_inserter inserter_; + detail::has_many_deleter deleter_; }; } diff --git a/include/oos/object/has_many_vector.hpp b/include/oos/object/has_many_vector.hpp index 363a6dced..74ac5297b 100644 --- a/include/oos/object/has_many_vector.hpp +++ b/include/oos/object/has_many_vector.hpp @@ -14,10 +14,6 @@ namespace oos { -namespace detail { -template class C, class Enabled > -class has_many_deleter; -} /// @cond OOS_DEV template < class T > @@ -91,6 +87,8 @@ class has_many_iterator */ has_many_iterator(const self &iter) : iter_(iter.iter_) {} + has_many_iterator(self &&iter) = default; + has_many_iterator& operator=(self &&iter) = default; /** * @brief Creates a has many iterator from given internal container iterator * @@ -385,6 +383,10 @@ class const_has_many_iterator */ const_has_many_iterator(const has_many_iterator &iter) : iter_(iter.iter_) {} + const_has_many_iterator(const self &iter) : iter_(iter.iter_) {} + + const_has_many_iterator(self &&iter) = default; + const_has_many_iterator& operator=(self &&iter) = default; /** * @brief Copy assigns a new const has many iterator * @@ -584,16 +586,14 @@ class const_has_many_iterator }; namespace detail { -template class C, class Enabled = void> -class has_many_inserter; -template class C> -class has_many_inserter::value>::type> +template +class has_many_inserter::value>::type> { public: typedef T value_type; - typedef typename has_many_iterator_traits::relation_type relation_type; - typedef typename basic_has_many::mark_modified_owner_func mark_modified_owner_func; + typedef typename has_many_iterator_traits::relation_type relation_type; + typedef typename basic_has_many::mark_modified_owner_func mark_modified_owner_func; void insert(object_store &store, const relation_type &rtype, object_proxy &owner, const mark_modified_owner_func &mark_modified_owner) { @@ -601,10 +601,8 @@ class has_many_inserter::value> auto i = foreign_node_->belongs_to_map_.find(owner.node()->type_index()); if (i != foreign_node_->belongs_to_map_.end()) { -// store.insert(rtype->value()); // set owner into value store.on_update_relation_owner(i->second, rtype->value().proxy_ /*owner*/, &owner /*value*/); -// store.notify_relation_insert(i->second, rtype->value().ptr() /*owner*/, &owner /*value*/); } else { store.insert(rtype); } @@ -612,13 +610,13 @@ class has_many_inserter::value> } }; -template class C> -class has_many_inserter::value>::type> +template +class has_many_inserter::value>::type> { public: typedef T value_type; - typedef typename has_many_iterator_traits::relation_type relation_type; - typedef typename basic_has_many::mark_modified_owner_func mark_modified_owner_func; + typedef typename has_many_iterator_traits::relation_type relation_type; + typedef typename basic_has_many::mark_modified_owner_func mark_modified_owner_func; void insert(object_store &store, const relation_type &rtype, object_proxy &owner, const mark_modified_owner_func &mark_modified_owner) { @@ -626,18 +624,13 @@ class has_many_inserter::value>: mark_modified_owner(store, &owner); } }; -} - -namespace detail { -template class C, class Enabled = void> -class has_many_deleter; -template class C> -class has_many_deleter::value>::type> +template +class has_many_deleter::value>::type> { public: typedef T value_type; - typedef typename has_many_iterator_traits::relation_type relation_type; + typedef typename has_many_iterator_traits::relation_type relation_type; void remove(object_store &store, relation_type &rtype, object_proxy &owner) { @@ -654,12 +647,12 @@ class has_many_deleter::value>: } }; -template class C> -class has_many_deleter::value>::type> +template +class has_many_deleter::value>::type> { public: typedef T value_type; - typedef typename has_many_iterator_traits::relation_type relation_type; + typedef typename has_many_iterator_traits::relation_type relation_type; void remove(object_store &store, relation_type &rtype, object_proxy &) { diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index 2555b5009..1144942d0 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -126,21 +126,6 @@ class OOS_OBJECT_API object_store */ ~object_store(); - /** - * Inserts a new object prototype into the prototype tree. The prototype - * constist of a unique type name. To know where the new - * prototype is inserted into the hierarchy the type name of the parent - * node is also given. - * - * @tparam T The type of the prototype node - * @param type The unique name of the type. - * @param abstract Indicates if the producers serializable is treated as an abstract node. - * @param parent The name of the parent type. - * @return Returns new inserted prototype iterator. - */ -// template< class T, template < class V = T > class ... O > -// prototype_iterator attach(const char *type, bool abstract = false, const char *parent = nullptr); - template class O > prototype_iterator attach(const char *type, std::initializer_list*> observer); @@ -180,33 +165,6 @@ class OOS_OBJECT_API object_store template < class T, template < class V = T > class O > prototype_iterator attach(prototype_node *node, const char *parent, std::vector*> observer); - /** - * Inserts a new object prototype into the prototype tree. The prototype - * consists of a unique type name (generated from typeid). To know where the new - * prototype is inserted into the hierarchy the type name of the parent - * node is also given. - * - * @tparam T The type of the prototype node - * @param abstract Indicates if the producers serializable is treated as an abstract node. - * @param parent The name of the parent type. - * @return Returns new inserted prototype iterator. - */ -// template -// prototype_iterator prepare_attach(bool abstract = false, const char *parent = nullptr); - - /** - * Inserts a new object prototype into the prototype tree. The prototype - * consists of a unique type name (generated from typeid). To know where the new - * prototype is inserted into the hierarchy the typeid of the parent - * node is also given. - * - * @tparam T The type of the prototype node - * @tparam S The type of the parent prototype node - * @param abstract Indicates if the producers serializable is treated as an abstract node. - * @return Returns new inserted prototype iterator. - */ -// template -// prototype_iterator prepare_attach(bool abstract = false); /** * Removes an object prototype from the prototype tree. All children @@ -682,11 +640,6 @@ class OOS_OBJECT_API object_store void on_remove_relation_item(prototype_node &node, object_proxy *owner, object_proxy *value); -// void notify_relation_insert(prototype_node::relation_info &info, void *owner, object_proxy *value); -// void notify_relation_insert(prototype_node &node, void *owner, object_proxy *value); -// void notify_relation_remove(prototype_node::relation_info &info, void *owner, object_proxy *value); -// void notify_relation_remove(prototype_node &node, void *owner, object_proxy *value); - transaction current_transaction(); bool has_transaction() const; @@ -800,6 +753,9 @@ class OOS_OBJECT_API object_store void enable_relation_notification(); void disable_relation_notification(); + template < class T > + void validate(prototype_node *node); + private: typedef std::unordered_map t_prototype_map; // typeid -> [name -> prototype] @@ -814,9 +770,6 @@ class OOS_OBJECT_API object_store // typeid to prototype node map t_typeid_prototype_map typeid_prototype_map_; - // prepared prototype nodes -// t_prototype_map prepared_prototype_map_; - typedef std::unordered_map t_object_proxy_map; t_object_proxy_map object_map_; @@ -833,6 +786,34 @@ class OOS_OBJECT_API object_store // relation notification related bool relation_notification_ = true; }; +template < class T > +void object_store::validate(prototype_node *node) +{ + // try to find node in prepared map + const char *name = typeid(T).name(); + t_prototype_map::iterator i = prototype_map_.find(node->type_); + if (i != prototype_map_.end()) { + throw_object_exception("prototype already inserted: " << node->type_.c_str()); + } + // try to find by typeid name + i = prototype_map_.find(name); + if (i != prototype_map_.end()) { + throw_object_exception("prototype already inserted: " << node->type_.c_str()); + } + /* + * no typeid found, seems to be + * a new type + * to be sure check in typeid map + */ + t_typeid_prototype_map::iterator j = typeid_prototype_map_.find(name); + if (j != typeid_prototype_map_.end() && j->second.find(node->type_) != j->second.end()) { + /* unexpected found the + * typeid check for type + * throw exception + */ + throw object_exception("unexpectly found prototype"); + } +} template class O > object_store::iterator object_store::attach(const char *type, std::initializer_list*> observer) @@ -872,29 +853,18 @@ prototype_node* object_store::attach_node(prototype_node *node, const char *pare /* * try to insert new prototype node */ -// const char *name = typeid(T).name(); -// prototype_node *node = nullptr; -// t_prototype_map::iterator i = prepared_prototype_map_.find(name); -// if (i != prepared_prototype_map_.end()) { -// // found a prepared node -// node = i->second; -// node->type_.assign(type); -// prepared_prototype_map_.erase(i); -// } else { -// node = acquire(type, abstract); - // insert node - if (parent_node != nullptr) { - parent_node->insert(node); - } else { - last_->prev->append(node); - } - // Analyze primary and foreign keys of node - basic_identifier *id = identifier_resolver::resolve(); - if (id) { - id->isolate(); - node->id_.reset(id); - } -// } + // insert node + if (parent_node != nullptr) { + parent_node->insert(node); + } else { + last_->prev->append(node); + } + // Analyze primary and foreign keys of node + basic_identifier *id = identifier_resolver::resolve(); + if (id) { + id->isolate(); + node->id_.reset(id); + } // store prototype in map // Todo: check return value prototype_map_.insert(std::make_pair(node->type_, node))/*.first*/; @@ -929,10 +899,13 @@ prototype_iterator object_store::attach(prototype_node *node, const char *parent detail::node_analyzer analyzer(*node, *this); analyzer.analyze(); + validate(node); + attach_node(node, parent); node->on_attach(); + return prototype_iterator(node); } @@ -947,57 +920,16 @@ prototype_iterator object_store::attach(prototype_node *node, const char *parent detail::node_analyzer analyzer(*node, *this, observer); analyzer.analyze(); + validate(node); + attach_node(node, parent); node->on_attach(); + return prototype_iterator(node); } -//template -//prototype_iterator object_store::prepare_attach(bool abstract, const char *parent) -//{ -// prototype_node *parent_node = find_parent(parent); -// -// if (typeid_prototype_map_.find(typeid(T).name()) != typeid_prototype_map_.end()) { -// throw_object_exception("attach: object type " << typeid(T).name() << " already in attached"); -// } -// -// t_prototype_map::iterator i = prepared_prototype_map_.find(typeid(T).name()); -// if (i != prepared_prototype_map_.end()) { -// // there is already a prepared node for this type -// return prototype_iterator(i->second); -// } -// -// std::unique_ptr node(new prototype_node(this, "", new T, typeid(T), abstract)); -// -// node->initialize(this, "", abstract); -// -// if (parent_node != nullptr) { -// parent_node->insert(node.get()); -// } else { -// last_->prev->append(node.get()); -// } -// -// // store only in prepared prototype map -// // Todo: check return value -// prepared_prototype_map_.insert(std::make_pair(typeid(T).name(), node.get())); -// // Analyze primary and foreign keys of node -// std::unique_ptr id(identifier_resolver::resolve()); -// if (id) { -// id->isolate(); -// node->id_.reset(id.release()); -// } -// -// return prototype_iterator(node.release()); -//} -// -//template -//prototype_iterator object_store::prepare_attach(bool abstract) -//{ -// return prepare_attach(abstract, typeid(T).name()); -//} - template prototype_node *object_store::acquire(const char *type, bool abstract) { diff --git a/src/object/object_store.cpp b/src/object/object_store.cpp index 304e1ce6e..8a48bb8d6 100644 --- a/src/object/object_store.cpp +++ b/src/object/object_store.cpp @@ -115,7 +115,6 @@ void object_store::clear(bool full) while (first != last) { (first++)->clear(false); } -// prototype_tree_.begin()->clear(true); } object_map_.clear(); } @@ -327,44 +326,6 @@ void object_store::on_remove_relation_item(prototype_node &node, object_proxy *o on_remove_relation_owner(i->second, owner, value); } -//void object_store::notify_relation_insert(prototype_node::relation_info &info, void *owner, object_proxy *value) -//{ -// if (!is_relation_notification_enabled()) { -// return; -// } -// disable_relation_notification(); -// info.insert_value(owner, info.name, value); -// enable_relation_notification(); -//} -// -//void object_store::notify_relation_insert(prototype_node &node, void *owner, object_proxy *value) -//{ -// auto i = node.has_many_map_.find(node.type_index()); -// if (i == node.has_many_map_.end()) { -// return; -// } -// notify_relation_insert(i->second, owner, value); -//} -// -//void object_store::notify_relation_remove(prototype_node::relation_info &info, void *owner, object_proxy *value) -//{ -// if (!is_relation_notification_enabled()) { -// return; -// } -// disable_relation_notification(); -// info.remove_value(owner, info.name, value); -// enable_relation_notification(); -//} -// -//void object_store::notify_relation_remove(prototype_node &node, void *owner, object_proxy *value) -//{ -// auto i = node.has_many_map_.find(node.type_index()); -// if (i == node.has_many_map_.end()) { -// return; -// } -// notify_relation_remove(i->second, owner, value); -//} - prototype_node* object_store::find_prototype_node(const char *type) const { // check for null if (type == 0) { From 697d431255173061bced4484b1dacb90748e79a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Sun, 12 Feb 2017 22:18:33 +0100 Subject: [PATCH 49/61] many to many preparations --- include/oos/object/has_many_list.hpp | 9 +++-- include/oos/object/has_many_vector.hpp | 8 ++-- include/oos/object/node_analyzer.tpp | 54 +++++++++++++++----------- include/oos/object/prototype_node.hpp | 17 ++++++-- src/object/object_store.cpp | 8 ++-- src/object/prototype_node.cpp | 4 +- test/object/ObjectStoreTestUnit.cpp | 2 +- 7 files changed, 60 insertions(+), 42 deletions(-) diff --git a/include/oos/object/has_many_list.hpp b/include/oos/object/has_many_list.hpp index 503cab8d5..c7c4f191d 100644 --- a/include/oos/object/has_many_list.hpp +++ b/include/oos/object/has_many_list.hpp @@ -462,8 +462,8 @@ class has_many_inserter { prototype_iterator foreign_node_ = store.find(typeid(T).name()); - auto i = foreign_node_->belongs_to_map_.find(owner.node()->type_index()); - if (i != foreign_node_->belongs_to_map_.end()) { + auto i = foreign_node_->relation_info_map_.find(owner.node()->type_index()); + if (i != foreign_node_->relation_info_map_.end()) { // set owner into value store.on_update_relation_owner(i->second, rtype->value().proxy_ /*owner*/, &owner /*value*/); } else { @@ -499,8 +499,9 @@ class has_many_deleter: { prototype_iterator foreign_node_ = store.find(typeid(T).name()); - auto i = foreign_node_->belongs_to_map_.find(owner.node()->type_index()); - if (i != foreign_node_->belongs_to_map_.end()) { + auto i = foreign_node_->relation_info_map_.find(owner.node()->type_index()); + if (i != foreign_node_->relation_info_map_ + .end()) { // store.remove(val); // set owner into value store.on_remove_relation_owner(i->second, rtype->value().proxy_ /*owner*/, &owner /*value*/); diff --git a/include/oos/object/has_many_vector.hpp b/include/oos/object/has_many_vector.hpp index 74ac5297b..3fb581a53 100644 --- a/include/oos/object/has_many_vector.hpp +++ b/include/oos/object/has_many_vector.hpp @@ -599,8 +599,8 @@ class has_many_inserterbelongs_to_map_.find(owner.node()->type_index()); - if (i != foreign_node_->belongs_to_map_.end()) { + auto i = foreign_node_->relation_info_map_.find(owner.node()->type_index()); + if (i != foreign_node_->relation_info_map_.end()) { // set owner into value store.on_update_relation_owner(i->second, rtype->value().proxy_ /*owner*/, &owner /*value*/); } else { @@ -636,8 +636,8 @@ class has_many_deleterbelongs_to_map_.find(owner.node()->type_index()); - if (i != foreign_node_->belongs_to_map_.end()) { + auto i = foreign_node_->relation_info_map_.find(owner.node()->type_index()); + if (i != foreign_node_->relation_info_map_.end()) { // store.remove(val); // set owner into value store.on_remove_relation_owner(i->second, rtype->value().proxy_ /*owner*/, &owner /*value*/); diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index fa69f074a..c0420507a 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -13,8 +13,8 @@ void basic_node_analyzer::process_belongs_to(const char *id, belongs_to &x) if (node != store_.end()) { // check if created from has_many // check if node has_many relation for id (id == tablename) - auto i = node->has_many_map_.find(node->type_index()); - if (i != node->has_many_map_.end()) { + auto i = node->relation_info_map_.find(node->type_index()); + if (i != node->relation_info_map_.end() && i->second.type == prototype_node::relation_info::HAS_MANY) { // yes, node found! // Todo: check if node is for has many item // detach has_many_item node @@ -25,7 +25,10 @@ void basic_node_analyzer::process_belongs_to(const char *id, belongs_to &x) } } object_store &store = store_; - node_.register_belongs_to(std::type_index(typeid(V)), prototype_node::relation_info(id, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { + node_.register_belongs_to(std::type_index(typeid(V)), + prototype_node::relation_info(id, + prototype_node::relation_info::BELONGS_TO, + [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { store.mark_modified(proxy); oos::set(proxy->obj(), field, object_ptr(owner)); }, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *) { @@ -52,7 +55,10 @@ template void basic_node_analyzer::register_has_many(const char *id, prototype_node *node) { object_store &store = store_; - node_.register_has_many(node_.type_index(), prototype_node::relation_info(id, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { + node_.register_has_many(node_.type_index(), + prototype_node::relation_info(id, + prototype_node::relation_info::HAS_MANY, + [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { store.mark_modified(proxy); oos::append(proxy->obj(), field, object_ptr(owner)); }, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { @@ -115,13 +121,15 @@ void node_analyzer::serialize(const char *id, has_many &, const cha throw_object_exception("many to many relations are not supported by now"); } else { // found corresponding belongs_to - auto j = pi->belongs_to_map_.find(node_.type_index_); - if (j != pi->belongs_to_map_.end()) { + auto j = pi->relation_info_map_.find(node_.type_index_); + if (j == pi->relation_info_map_.end()) { + throw_object_exception("prototype already inserted: " << pi->type()); + } else if (j->second.type == prototype_node::relation_info::BELONGS_TO) { // set missing node j->second.node = &node_; this->register_has_many(id, pi.get()); - } else { - throw_object_exception("prototype already inserted: " << pi->type()); + } else if (j->second.type == prototype_node::relation_info::HAS_MANY) { + // handle has many } } } @@ -200,16 +208,26 @@ void node_analyzer::serialize(const char *id, has_many &, const char * this->register_has_many(id, pi.get()); } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item - throw_object_exception("many to many relations are not supported by now"); + throw_object_exception("prototype already inserted"); + } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { + // prototype is of type has_many_item + throw_object_exception("prototype already inserted"); } else { // found corresponding belongs_to - auto j = pi->belongs_to_map_.find(node_.type_index_); - if (j != pi->belongs_to_map_.end()) { + auto j = pi->relation_info_map_.find(node_.type_index_); + if (j == pi->relation_info_map_.end()) { + // check for has many item + std::type_index ti(typeid(typename has_many::item_type)); + if (ti == pi->type_index()) { + std::cout << "serialize has many: found type " << ti.name() << "\n"; + } + throw_object_exception("prototype already inserted: " << pi->type()); + } else if (j->second.type == prototype_node::relation_info::BELONGS_TO) { // set missing node j->second.node = &node_; this->register_has_many(id, pi.get()); - } else { - throw_object_exception("prototype already inserted: " << pi->type()); + } else if (j->second.type == prototype_node::relation_info::HAS_MANY) { + // handle has many } } } @@ -228,16 +246,6 @@ void node_analyzer::serialize(const char *id, has_many &, const char * prototype_node *node = prototype_node::make_relation_node::item_type>(&store_, id, false, node_.type(), id, owner_column, item_column); pi = store_.attach::item_type>(node, nullptr); -// -// this->register_has_many(id, pi.get()); - -// pi = store_.attach::item_type>(id, false, nullptr); -// pi->relation_node_info_.owner_type_.assign(node_.type()); -// pi->relation_node_info_.relation_id_.assign(id); -// pi->relation_node_info_.owner_id_column_.assign(owner_column); -// pi->relation_node_info_.item_id_column_.assign(item_column); -// pi->is_relation_node_ = true; -// pi = node_.tree()->template attach::item_type, O...>(id, false, nullptr, observer_); } else { // throw exception throw_object_exception("prototype already inserted: " << pi->type()); diff --git a/include/oos/object/prototype_node.hpp b/include/oos/object/prototype_node.hpp index 67e9dfb9a..b773bd23b 100644 --- a/include/oos/object/prototype_node.hpp +++ b/include/oos/object/prototype_node.hpp @@ -81,14 +81,20 @@ class OOS_OBJECT_API prototype_node public: struct relation_info { + enum relation_type { + BELONGS_TO, HAS_ONE, HAS_MANY + }; + typedef std::function modify_value_func; relation_info(const std::string &n, + relation_type t, const modify_value_func &insert_func, const modify_value_func &remove_func, prototype_node *pn) - : name(n), insert_value(insert_func), remove_value(remove_func), node(pn) + : name(n), type(t), insert_value(insert_func), remove_value(remove_func), node(pn) {} std::string name; + relation_type type; std::function insert_value; std::function remove_value; prototype_node *node; @@ -142,6 +148,7 @@ class OOS_OBJECT_API prototype_node { first->next = last.get(); last->prev = first.get(); + std::cout << "creating node " << type << "/" << type_index_.name() << "\n"; } @@ -504,9 +511,11 @@ class OOS_OBJECT_API prototype_node */ std::unique_ptr id_; - relation_map belongs_to_map_; - relation_map has_one_map_; - relation_map has_many_map_; +// relation_map belongs_to_map_; +// relation_map has_one_map_; +// relation_map has_many_map_; + + relation_map relation_info_map_; bool is_relation_node_ = false; relation_node_info relation_node_info_; diff --git a/src/object/object_store.cpp b/src/object/object_store.cpp index 8a48bb8d6..c2a3f07e6 100644 --- a/src/object/object_store.cpp +++ b/src/object/object_store.cpp @@ -310,8 +310,8 @@ void object_store::on_remove_relation_owner(prototype_node::relation_info &info, void object_store::on_append_relation_item(prototype_node &node, object_proxy *owner, object_proxy *value) { - auto i = node.has_many_map_.find(node.type_index()); - if (i == node.has_many_map_.end()) { + auto i = node.relation_info_map_.find(node.type_index()); + if (i == node.relation_info_map_.end()) { return; } on_update_relation_owner(i->second, owner, value); @@ -319,8 +319,8 @@ void object_store::on_append_relation_item(prototype_node &node, object_proxy *o void object_store::on_remove_relation_item(prototype_node &node, object_proxy *owner, object_proxy *value) { - auto i = node.has_many_map_.find(node.type_index()); - if (i == node.has_many_map_.end()) { + auto i = node.relation_info_map_.find(node.type_index()); + if (i == node.relation_info_map_.end()) { return; } on_remove_relation_owner(i->second, owner, value); diff --git a/src/object/prototype_node.cpp b/src/object/prototype_node.cpp index a75fd2dd1..7ab445036 100644 --- a/src/object/prototype_node.cpp +++ b/src/object/prototype_node.cpp @@ -374,12 +374,12 @@ object_proxy *prototype_node::find_proxy(const std::shared_ptr void prototype_node::register_belongs_to(const std::type_index &tindex, const prototype_node::relation_info &relation_info) { - belongs_to_map_.insert(std::make_pair(tindex, relation_info)); + relation_info_map_.insert(std::make_pair(tindex, relation_info)); } void prototype_node::register_has_many(const std::type_index &tindex, const prototype_node::relation_info &relation_info) { - has_many_map_.insert(std::make_pair(tindex, relation_info)); + relation_info_map_.insert(std::make_pair(tindex, relation_info)); } /* diff --git a/test/object/ObjectStoreTestUnit.cpp b/test/object/ObjectStoreTestUnit.cpp index be26cc21c..8be6b1ea3 100644 --- a/test/object/ObjectStoreTestUnit.cpp +++ b/test/object/ObjectStoreTestUnit.cpp @@ -41,7 +41,7 @@ ObjectStoreTestUnit::ObjectStoreTestUnit() add_test("remove", std::bind(&ObjectStoreTestUnit::test_remove, this), "object remove test"); add_test("pk", std::bind(&ObjectStoreTestUnit::test_primary_key, this), "object proxy primary key test"); add_test("has_many", std::bind(&ObjectStoreTestUnit::test_has_many, this), "has many test"); -// add_test("has_many_to_many", std::bind(&ObjectStoreTestUnit::test_has_many_to_many, this), "has many to many test"); + add_test("has_many_to_many", std::bind(&ObjectStoreTestUnit::test_has_many_to_many, this), "has many to many test"); add_test("belongs_to", std::bind(&ObjectStoreTestUnit::test_belongs_to, this), "test belongs to behaviour"); add_test("observer", std::bind(&ObjectStoreTestUnit::test_observer, this), "test observer functionality"); } From 146f3cf633c1a6cda7e2314bef17fda348221049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Mon, 13 Feb 2017 23:44:49 +0100 Subject: [PATCH 50/61] many to many progress --- include/oos/object/has_many_vector.hpp | 7 ++++++- include/oos/object/node_analyzer.hpp | 2 +- include/oos/object/node_analyzer.tpp | 22 +++++++++++----------- test/Item.hpp | 4 ++++ test/object/ObjectStoreTestUnit.cpp | 7 +++++++ 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/include/oos/object/has_many_vector.hpp b/include/oos/object/has_many_vector.hpp index 3fb581a53..d91e66e91 100644 --- a/include/oos/object/has_many_vector.hpp +++ b/include/oos/object/has_many_vector.hpp @@ -604,7 +604,12 @@ class has_many_insertersecond, rtype->value().proxy_ /*owner*/, &owner /*value*/); } else { - store.insert(rtype); + i = owner.node()->relation_info_map_.find(std::type_index(typeid(relation_type))); + if (i != owner.node()->relation_info_map_.end()) { +// store.on_append_relation_item() + } else { + store.insert(rtype); + } } mark_modified_owner(store, &owner); } diff --git a/include/oos/object/node_analyzer.hpp b/include/oos/object/node_analyzer.hpp index 304e5874d..41f134b83 100644 --- a/include/oos/object/node_analyzer.hpp +++ b/include/oos/object/node_analyzer.hpp @@ -26,7 +26,7 @@ class basic_node_analyzer void process_has_one(const char *id, has_one &x); template < class V, class T > - void register_has_many(const char *id, prototype_node *node); + void register_has_many(const std::type_index &typeindex, const char *id, prototype_node *node); protected: prototype_node &node_; diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index c0420507a..83a311263 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -52,10 +52,10 @@ void basic_node_analyzer::process_has_one(const char *, has_one &) } template -void basic_node_analyzer::register_has_many(const char *id, prototype_node *node) +void basic_node_analyzer::register_has_many(const std::type_index &typeindex, const char *id, prototype_node *node) { object_store &store = store_; - node_.register_has_many(node_.type_index(), + node_.register_has_many(typeindex, prototype_node::relation_info(id, prototype_node::relation_info::HAS_MANY, [&store](object_proxy *proxy, const std::string &field, oos::object_proxy *owner) { @@ -115,10 +115,13 @@ void node_analyzer::serialize(const char *id, has_many &, const cha pi = store_.attach::item_type>(node, nullptr, has_many_item_observer); - this->register_has_many(id, pi.get()); + this->register_has_many(pi->type_index(), id, pi.get()); } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item throw_object_exception("many to many relations are not supported by now"); + } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { + std::cout << "serialize has many: found type " << pi->type_index().name() << "\n"; + this->register_has_many(std::type_index(typeid(typename has_many::item_type)), id, pi.get()); } else { // found corresponding belongs_to auto j = pi->relation_info_map_.find(node_.type_index_); @@ -127,7 +130,7 @@ void node_analyzer::serialize(const char *id, has_many &, const cha } else if (j->second.type == prototype_node::relation_info::BELONGS_TO) { // set missing node j->second.node = &node_; - this->register_has_many(id, pi.get()); + this->register_has_many(pi->type_index(), id, pi.get()); } else if (j->second.type == prototype_node::relation_info::HAS_MANY) { // handle has many } @@ -205,27 +208,24 @@ void node_analyzer::serialize(const char *id, has_many &, const char * pi = store_.attach::item_type>(node, nullptr); - this->register_has_many(id, pi.get()); + this->register_has_many(pi->type_index(), id, pi.get()); } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item throw_object_exception("prototype already inserted"); } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item - throw_object_exception("prototype already inserted"); + std::cout << "serialize has many: found type " << pi->type_index().name() << "\n"; + this->register_has_many(std::type_index(typeid(typename has_many::item_type)), id, pi.get()); } else { // found corresponding belongs_to auto j = pi->relation_info_map_.find(node_.type_index_); if (j == pi->relation_info_map_.end()) { // check for has many item - std::type_index ti(typeid(typename has_many::item_type)); - if (ti == pi->type_index()) { - std::cout << "serialize has many: found type " << ti.name() << "\n"; - } throw_object_exception("prototype already inserted: " << pi->type()); } else if (j->second.type == prototype_node::relation_info::BELONGS_TO) { // set missing node j->second.node = &node_; - this->register_has_many(id, pi.get()); + this->register_has_many(pi->type_index(), id, pi.get()); } else if (j->second.type == prototype_node::relation_info::HAS_MANY) { // handle has many } diff --git a/test/Item.hpp b/test/Item.hpp index ede3ae61a..5f4df94aa 100644 --- a/test/Item.hpp +++ b/test/Item.hpp @@ -390,6 +390,9 @@ class course; class student : public person { public: + student() {} + student(const std::string &name, const oos::date &bdate = oos::date(), unsigned h = 170) : person(name, bdate, h) {} + template < class SERIALIZER > void serialize(SERIALIZER &serializer) { @@ -405,6 +408,7 @@ class course public: course() {} + course(const std::string &t) : title(t) {} template < class SERIALIZER > void serialize(SERIALIZER &serializer) diff --git a/test/object/ObjectStoreTestUnit.cpp b/test/object/ObjectStoreTestUnit.cpp index 8be6b1ea3..b97b0feb2 100644 --- a/test/object/ObjectStoreTestUnit.cpp +++ b/test/object/ObjectStoreTestUnit.cpp @@ -1043,6 +1043,13 @@ void ObjectStoreTestUnit::test_has_many_to_many() ostore_.attach("course"); UNIT_ASSERT_EQUAL(4UL, ostore_.size(), "unexpected size"); + + auto george = ostore_.insert(new student("george")); + auto jane = ostore_.insert(new student("jane")); + auto algebra = ostore_.insert(new course("algebra")); + auto art = ostore_.insert(new course("art")); + + art->students.push_back(jane); } void ObjectStoreTestUnit::test_belongs_to() From 4460ba39fbedc75cecc0045cd3f38f24990d6e61 Mon Sep 17 00:00:00 2001 From: zussel Date: Tue, 14 Feb 2017 15:16:23 +0100 Subject: [PATCH 51/61] adjusted mssql datatype for varchar --- src/db/mssql/mssql_statement.cpp | 8 +++++--- test/sql/QueryTestUnit.cpp | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/db/mssql/mssql_statement.cpp b/src/db/mssql/mssql_statement.cpp index f530e7ef7..844350761 100644 --- a/src/db/mssql/mssql_statement.cpp +++ b/src/db/mssql/mssql_statement.cpp @@ -358,7 +358,7 @@ void mssql_statement::bind_value(const char *val, size_t size, size_t index) host_data_.push_back(v); - SQLRETURN ret = SQLBindParameter(stmt_, (SQLUSMALLINT)index, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARCHAR, size, 0, v->data, v->len, NULL); + SQLRETURN ret = SQLBindParameter(stmt_, (SQLUSMALLINT)index, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, size, 0, v->data, v->len, NULL); throw_error(ret, SQL_HANDLE_STMT, stmt_, "mssql", "couldn't bind parameter"); } @@ -458,9 +458,11 @@ int mssql_statement::type2sql(data_type type) case data_type::type_double: return SQL_DOUBLE; case data_type::type_char_pointer: - return SQL_LONGVARCHAR; + return SQL_VARCHAR; + //return SQL_LONGVARCHAR; case data_type::type_varchar: - return SQL_LONGVARCHAR; + return SQL_VARCHAR; + //return SQL_LONGVARCHAR; case data_type::type_text: return SQL_LONGVARCHAR; case data_type::type_date: diff --git a/test/sql/QueryTestUnit.cpp b/test/sql/QueryTestUnit.cpp index 058765100..8f53adc11 100644 --- a/test/sql/QueryTestUnit.cpp +++ b/test/sql/QueryTestUnit.cpp @@ -584,7 +584,7 @@ void QueryTestUnit::test_statement_update() column name("name"); stmt = q.select().where(name == "").prepare(); - std::string hname("hans"); + oos::varchar<255> hname("hans"); stmt.bind(0, hname); res = stmt.execute(); From 59bd30efc70f5a90eccdd3b8488cb9b1e60870ec Mon Sep 17 00:00:00 2001 From: zussel Date: Tue, 14 Feb 2017 17:32:10 +0100 Subject: [PATCH 52/61] many to many progress --- include/oos/object/has_many_vector.hpp | 11 ++++++----- include/oos/object/node_analyzer.tpp | 6 ++++-- include/oos/object/object_store.hpp | 2 +- include/oos/object/prototype_node.hpp | 2 +- test/object/ObjectStoreTestUnit.cpp | 7 +++++++ 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/include/oos/object/has_many_vector.hpp b/include/oos/object/has_many_vector.hpp index d91e66e91..c43a4d8a2 100644 --- a/include/oos/object/has_many_vector.hpp +++ b/include/oos/object/has_many_vector.hpp @@ -604,12 +604,13 @@ class has_many_insertersecond, rtype->value().proxy_ /*owner*/, &owner /*value*/); } else { - i = owner.node()->relation_info_map_.find(std::type_index(typeid(relation_type))); - if (i != owner.node()->relation_info_map_.end()) { -// store.on_append_relation_item() - } else { - store.insert(rtype); + i = foreign_node_->relation_info_map_.find(foreign_node_->type_index()); +// i = owner.node()->relation_info_map_.find(std::type_index(typeid(T))); +// if (i != owner.node()->relation_info_map_.end()) { + if (i != foreign_node_->relation_info_map_.end()) { + store.on_append_relation_item(*foreign_node_, rtype->value().proxy_, &owner); } + store.insert(rtype); } mark_modified_owner(store, &owner); } diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index 83a311263..028e738c0 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -208,14 +208,16 @@ void node_analyzer::serialize(const char *id, has_many &, const char * pi = store_.attach::item_type>(node, nullptr); - this->register_has_many(pi->type_index(), id, pi.get()); + this->register_has_many(node_.type_index(), id, pi.get()); } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item throw_object_exception("prototype already inserted"); } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item std::cout << "serialize has many: found type " << pi->type_index().name() << "\n"; - this->register_has_many(std::type_index(typeid(typename has_many::item_type)), id, pi.get()); + this->register_has_many(node_.type_index(), id, pi.get()); + std::cout << "registering node type id " << typeid(typename has_many::item_type).name() << "\n"; + store_.typeid_prototype_map_[typeid(typename has_many::item_type).name()].insert(std::make_pair(pi->type_, pi.get())); } else { // found corresponding belongs_to auto j = pi->relation_info_map_.find(node_.type_index_); diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index 1144942d0..97aa84d1e 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -387,7 +387,7 @@ class OOS_OBJECT_API object_store } iterator node = find(proxy->classname()); if (node == end()) { - throw object_exception("couldn't find object type"); + throw_object_exception("couldn't find object type: " << proxy->classname()); } // check if proxy/object is already inserted if (proxy->ostore() != nullptr && proxy->id() > 0) { diff --git a/include/oos/object/prototype_node.hpp b/include/oos/object/prototype_node.hpp index b773bd23b..b885d2e61 100644 --- a/include/oos/object/prototype_node.hpp +++ b/include/oos/object/prototype_node.hpp @@ -148,7 +148,7 @@ class OOS_OBJECT_API prototype_node { first->next = last.get(); last->prev = first.get(); - std::cout << "creating node " << type << "/" << type_index_.name() << "\n"; +// std::cout << "creating node " << type << "/" << type_index_.name() << "\n"; } diff --git a/test/object/ObjectStoreTestUnit.cpp b/test/object/ObjectStoreTestUnit.cpp index b97b0feb2..7b7b3a69d 100644 --- a/test/object/ObjectStoreTestUnit.cpp +++ b/test/object/ObjectStoreTestUnit.cpp @@ -1050,6 +1050,13 @@ void ObjectStoreTestUnit::test_has_many_to_many() auto art = ostore_.insert(new course("art")); art->students.push_back(jane); + + std::cout << "jane course count " << jane->courses.size() << "\n"; + + jane->courses.erase(jane->courses.begin()); + + std::cout << "jane course count " << jane->courses.size() << "\n"; + std::cout << "art students count " << art->students.size() << "\n"; } void ObjectStoreTestUnit::test_belongs_to() From 4c3d4ae5d4b0b3d9955bbe2dd826dd3e78956544 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Tue, 14 Feb 2017 22:23:29 +0100 Subject: [PATCH 53/61] node analyzing progress --- include/oos/object/has_many_vector.hpp | 7 +- include/oos/object/node_analyzer.hpp | 3 + include/oos/object/node_analyzer.tpp | 113 ++++++++++++++++--------- include/oos/object/object_store.hpp | 2 +- test/object/ObjectStoreTestUnit.cpp | 14 +-- 5 files changed, 88 insertions(+), 51 deletions(-) diff --git a/include/oos/object/has_many_vector.hpp b/include/oos/object/has_many_vector.hpp index c43a4d8a2..8813ef936 100644 --- a/include/oos/object/has_many_vector.hpp +++ b/include/oos/object/has_many_vector.hpp @@ -605,8 +605,6 @@ class has_many_insertersecond, rtype->value().proxy_ /*owner*/, &owner /*value*/); } else { i = foreign_node_->relation_info_map_.find(foreign_node_->type_index()); -// i = owner.node()->relation_info_map_.find(std::type_index(typeid(T))); -// if (i != owner.node()->relation_info_map_.end()) { if (i != foreign_node_->relation_info_map_.end()) { store.on_append_relation_item(*foreign_node_, rtype->value().proxy_, &owner); } @@ -644,10 +642,13 @@ class has_many_deleterrelation_info_map_.find(owner.node()->type_index()); if (i != foreign_node_->relation_info_map_.end()) { -// store.remove(val); // set owner into value store.on_remove_relation_owner(i->second, rtype->value().proxy_ /*owner*/, &owner /*value*/); } else { + i = foreign_node_->relation_info_map_.find(foreign_node_->type_index()); + if (i != foreign_node_->relation_info_map_.end()) { + store.on_remove_relation_item(*foreign_node_, rtype->value().proxy_, &owner); + } store.remove(rtype); } } diff --git a/include/oos/object/node_analyzer.hpp b/include/oos/object/node_analyzer.hpp index 41f134b83..7a3b006d1 100644 --- a/include/oos/object/node_analyzer.hpp +++ b/include/oos/object/node_analyzer.hpp @@ -25,6 +25,9 @@ class basic_node_analyzer template < class V, class T > void process_has_one(const char *id, has_one &x); + template < class V, class T, template class C > + void process_has_many(const prototype_iterator &pi, const char *id, has_many &x); + template < class V, class T > void register_has_many(const std::type_index &typeindex, const char *id, prototype_node *node); diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index 028e738c0..ed724d396 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -51,6 +51,31 @@ void basic_node_analyzer::process_has_one(const char *, has_one &) // } } +template class C> +void basic_node_analyzer::process_has_many(const prototype_iterator &pi, const char *id, has_many &) +{ + if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { + // prototype is of type has_many_item + std::cout << "serialize has many: found type " << pi->type_index().name() << "\n"; + this->register_has_many(node_.type_index(), id, pi.get()); + std::cout << "registering node type id " << typeid(typename has_many::item_type).name() << "\n"; + store_.typeid_prototype_map_[typeid(typename has_many::item_type).name()].insert(std::make_pair(pi->type_, pi.get())); + } else { + // found corresponding belongs_to + auto j = pi->relation_info_map_.find(node_.type_index_); + if (j == pi->relation_info_map_.end()) { + // check for has many item + throw_object_exception("prototype already inserted: " << pi->type()); + } else if (j->second.type == prototype_node::relation_info::BELONGS_TO) { + // set missing node + j->second.node = &node_; + this->register_has_many(pi->type_index(), id, pi.get()); + } else if (j->second.type == prototype_node::relation_info::HAS_MANY) { + // handle has many + } + } +} + template void basic_node_analyzer::register_has_many(const std::type_index &typeindex, const char *id, prototype_node *node) { @@ -97,7 +122,7 @@ void node_analyzer::serialize(const char *id, has_one &x, cascade_type template class O> template class C> -void node_analyzer::serialize(const char *id, has_many &, const char *owner_column, const char *item_column, +void node_analyzer::serialize(const char *id, has_many &x, const char *owner_column, const char *item_column, typename std::enable_if::value>::type*) { // attach relation table for has many relation @@ -116,25 +141,28 @@ void node_analyzer::serialize(const char *id, has_many &, const cha pi = store_.attach::item_type>(node, nullptr, has_many_item_observer); this->register_has_many(pi->type_index(), id, pi.get()); - } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { - // prototype is of type has_many_item - throw_object_exception("many to many relations are not supported by now"); - } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { - std::cout << "serialize has many: found type " << pi->type_index().name() << "\n"; - this->register_has_many(std::type_index(typeid(typename has_many::item_type)), id, pi.get()); } else { - // found corresponding belongs_to - auto j = pi->relation_info_map_.find(node_.type_index_); - if (j == pi->relation_info_map_.end()) { - throw_object_exception("prototype already inserted: " << pi->type()); - } else if (j->second.type == prototype_node::relation_info::BELONGS_TO) { - // set missing node - j->second.node = &node_; - this->register_has_many(pi->type_index(), id, pi.get()); - } else if (j->second.type == prototype_node::relation_info::HAS_MANY) { - // handle has many - } + this->process_has_many(pi, id, x); } +// if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { +// // prototype is of type has_many_item +// throw_object_exception("many to many relations are not supported by now"); +// } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { +// std::cout << "serialize has many: found type " << pi->type_index().name() << "\n"; +// this->register_has_many(std::type_index(typeid(typename has_many::item_type)), id, pi.get()); +// } else { +// // found corresponding belongs_to +// auto j = pi->relation_info_map_.find(node_.type_index_); +// if (j == pi->relation_info_map_.end()) { +// throw_object_exception("prototype already inserted: " << pi->type()); +// } else if (j->second.type == prototype_node::relation_info::BELONGS_TO) { +// // set missing node +// j->second.node = &node_; +// this->register_has_many(pi->type_index(), id, pi.get()); +// } else if (j->second.type == prototype_node::relation_info::HAS_MANY) { +// // handle has many +// } +// } } template class O> @@ -195,7 +223,7 @@ void node_analyzer::serialize(const char *id, has_one &x, cascade_type) template template class C> -void node_analyzer::serialize(const char *id, has_many &, const char *owner_column, const char *item_column, +void node_analyzer::serialize(const char *id, has_many &x, const char *owner_column, const char *item_column, typename std::enable_if::value>::type*) { // attach relation table for has many relation @@ -209,29 +237,34 @@ void node_analyzer::serialize(const char *id, has_many &, const char * pi = store_.attach::item_type>(node, nullptr); this->register_has_many(node_.type_index(), id, pi.get()); - } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { - // prototype is of type has_many_item - throw_object_exception("prototype already inserted"); - } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { - // prototype is of type has_many_item - std::cout << "serialize has many: found type " << pi->type_index().name() << "\n"; - this->register_has_many(node_.type_index(), id, pi.get()); - std::cout << "registering node type id " << typeid(typename has_many::item_type).name() << "\n"; - store_.typeid_prototype_map_[typeid(typename has_many::item_type).name()].insert(std::make_pair(pi->type_, pi.get())); } else { - // found corresponding belongs_to - auto j = pi->relation_info_map_.find(node_.type_index_); - if (j == pi->relation_info_map_.end()) { - // check for has many item - throw_object_exception("prototype already inserted: " << pi->type()); - } else if (j->second.type == prototype_node::relation_info::BELONGS_TO) { - // set missing node - j->second.node = &node_; - this->register_has_many(pi->type_index(), id, pi.get()); - } else if (j->second.type == prototype_node::relation_info::HAS_MANY) { - // handle has many - } + this->process_has_many(pi, id, x); } +// if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { +// // prototype is of type has_many_item +// throw_object_exception("prototype already inserted"); +// } else { +// if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { +// // prototype is of type has_many_item +// std::cout << "serialize has many: found type " << pi->type_index().name() << "\n"; +// this->register_has_many(node_.type_index(), id, pi.get()); +// std::cout << "registering node type id " << typeid(typename has_many::item_type).name() << "\n"; +// store_.typeid_prototype_map_[typeid(typename has_many::item_type).name()].insert(std::make_pair(pi->type_, pi.get())); +// } else { +// // found corresponding belongs_to +// auto j = pi->relation_info_map_.find(node_.type_index_); +// if (j == pi->relation_info_map_.end()) { +// // check for has many item +// throw_object_exception("prototype already inserted: " << pi->type()); +// } else if (j->second.type == prototype_node::relation_info::BELONGS_TO) { +// // set missing node +// j->second.node = &node_; +// this->register_has_many(pi->type_index(), id, pi.get()); +// } else if (j->second.type == prototype_node::relation_info::HAS_MANY) { +// // handle has many +// } +// } +// } } template diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index 97aa84d1e..209b8d895 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -387,7 +387,7 @@ class OOS_OBJECT_API object_store } iterator node = find(proxy->classname()); if (node == end()) { - throw_object_exception("couldn't find object type: " << proxy->classname()); + throw_object_exception("couldn't find object type"); } // check if proxy/object is already inserted if (proxy->ostore() != nullptr && proxy->id() > 0) { diff --git a/test/object/ObjectStoreTestUnit.cpp b/test/object/ObjectStoreTestUnit.cpp index 7b7b3a69d..a80de68d7 100644 --- a/test/object/ObjectStoreTestUnit.cpp +++ b/test/object/ObjectStoreTestUnit.cpp @@ -1136,17 +1136,17 @@ struct logger : public object_store_observer void ObjectStoreTestUnit::test_observer() { - ostore_.attach("person", { new logger }); - ostore_.attach("employee", { new logger }); - ostore_.attach("department", { new logger }); - ostore_.attach("book", { new logger }); - ostore_.attach("book_list", { new logger }); +// ostore_.attach("person", { new logger }); +// ostore_.attach("employee", { new logger }); +// ostore_.attach("department", { new logger }); +// ostore_.attach("book", { new logger }); +// ostore_.attach("book_list", { new logger }); ostore_.clear(true); ostore_.attach("person", { new logger }); ostore_.attach("department", { new logger }); ostore_.attach("employee", { new logger }); - ostore_.attach("book", { new logger }); - ostore_.attach("book_list", { new logger }); +// ostore_.attach("book", { new logger }); +// ostore_.attach("book_list", { new logger }); } From b95c3e14b5e7e20fcc84b6ce0967fe24e7e52759 Mon Sep 17 00:00:00 2001 From: zussel Date: Wed, 15 Feb 2017 13:14:02 +0100 Subject: [PATCH 54/61] mssql parameter size adjustments for sqlcolumns --- src/db/mssql/mssql_connection.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/db/mssql/mssql_connection.cpp b/src/db/mssql/mssql_connection.cpp index 7a9d60018..a850ee55a 100644 --- a/src/db/mssql/mssql_connection.cpp +++ b/src/db/mssql/mssql_connection.cpp @@ -224,7 +224,8 @@ std::vector mssql_connection::describe(const std::string &table) #else strcpy((char*)buf, table.c_str()); #endif - SQLColumns(stmt, NULL, 0, NULL, 0, buf, SQL_NTS, NULL, 0); + ret = SQLColumns(stmt, NULL, 0, NULL, 0, buf, SQL_NTS, NULL, 0); + throw_error(ret, SQL_HANDLE_STMT, stmt, "mssql", "error on executing column description"); //std::unique_ptr res(static_cast(execute(stmt))); // bind to columns we need (column name, data type of column and index) @@ -238,22 +239,22 @@ std::vector mssql_connection::describe(const std::string &table) // column name ret = SQLBindCol(stmt, 4, SQL_C_CHAR, column, sizeof(column), &indicator[0]); - throw_error(ret, SQL_HANDLE_DBC, connection_, "mssql", "error on sql columns statement (column)"); + throw_error(ret, SQL_HANDLE_STMT, stmt, "mssql", "error on sql columns statement (column)"); // data type - ret = SQLBindCol(stmt, 5, SQL_C_LONG, &data_type, sizeof(data_type), &indicator[1]); - throw_error(ret, SQL_HANDLE_DBC, connection_, "mssql", "error on sql columns statement (data type)"); + ret = SQLBindCol(stmt, 5, SQL_C_SSHORT, &data_type, sizeof(data_type), &indicator[1]); + throw_error(ret, SQL_HANDLE_STMT, stmt, "mssql", "error on sql columns statement (data type)"); // type name ret = SQLBindCol(stmt, 6, SQL_C_CHAR, type, sizeof(type), &indicator[2]); - throw_error(ret, SQL_HANDLE_DBC, connection_, "mssql", "error on sql columns statement (type name)"); + throw_error(ret, SQL_HANDLE_STMT, stmt, "mssql", "error on sql columns statement (type name)"); // size - ret = SQLBindCol(stmt, 7, SQL_C_LONG, &size, sizeof(size), &indicator[3]); - throw_error(ret, SQL_HANDLE_DBC, connection_, "mssql", "error on sql columns statement (data size)"); + ret = SQLBindCol(stmt, 7, SQL_C_SLONG, &size, sizeof(size), &indicator[3]); + throw_error(ret, SQL_HANDLE_STMT, stmt, "mssql", "error on sql columns statement (data size)"); // nullable - ret = SQLBindCol(stmt, 11, SQL_C_LONG, ¬_null, 0, &indicator[4]); - throw_error(ret, SQL_HANDLE_DBC, connection_, "mssql", "error on sql columns statement (not null)"); + ret = SQLBindCol(stmt, 11, SQL_C_SSHORT, ¬_null, 0, &indicator[4]); + throw_error(ret, SQL_HANDLE_STMT, stmt, "mssql", "error on sql columns statement (not null)"); // index (1 based) - ret = SQLBindCol(stmt, 17, SQL_C_LONG, &pos, 0, &indicator[5]); - throw_error(ret, SQL_HANDLE_DBC, connection_, "mssql", "error on sql columns statement (pos)"); + ret = SQLBindCol(stmt, 17, SQL_C_SLONG, &pos, 0, &indicator[5]); + throw_error(ret, SQL_HANDLE_STMT, stmt, "mssql", "error on sql columns statement (pos)"); std::vector fields; From e60fe79a2540c63a1d6a541d53e3fb09b9e7bad0 Mon Sep 17 00:00:00 2001 From: zussel Date: Wed, 15 Feb 2017 13:14:36 +0100 Subject: [PATCH 55/61] register correct prototype node when serializing has_many --- include/oos/object/node_analyzer.tpp | 48 +--------------------------- 1 file changed, 1 insertion(+), 47 deletions(-) diff --git a/include/oos/object/node_analyzer.tpp b/include/oos/object/node_analyzer.tpp index ed724d396..13b6ec377 100644 --- a/include/oos/object/node_analyzer.tpp +++ b/include/oos/object/node_analyzer.tpp @@ -56,9 +56,7 @@ void basic_node_analyzer::process_has_many(const prototype_iterator &pi, const c { if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { // prototype is of type has_many_item - std::cout << "serialize has many: found type " << pi->type_index().name() << "\n"; this->register_has_many(node_.type_index(), id, pi.get()); - std::cout << "registering node type id " << typeid(typename has_many::item_type).name() << "\n"; store_.typeid_prototype_map_[typeid(typename has_many::item_type).name()].insert(std::make_pair(pi->type_, pi.get())); } else { // found corresponding belongs_to @@ -140,29 +138,10 @@ void node_analyzer::serialize(const char *id, has_many &x, const ch pi = store_.attach::item_type>(node, nullptr, has_many_item_observer); - this->register_has_many(pi->type_index(), id, pi.get()); + this->register_has_many(node_.type_index(), id, pi.get()); } else { this->process_has_many(pi, id, x); } -// if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { -// // prototype is of type has_many_item -// throw_object_exception("many to many relations are not supported by now"); -// } else if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { -// std::cout << "serialize has many: found type " << pi->type_index().name() << "\n"; -// this->register_has_many(std::type_index(typeid(typename has_many::item_type)), id, pi.get()); -// } else { -// // found corresponding belongs_to -// auto j = pi->relation_info_map_.find(node_.type_index_); -// if (j == pi->relation_info_map_.end()) { -// throw_object_exception("prototype already inserted: " << pi->type()); -// } else if (j->second.type == prototype_node::relation_info::BELONGS_TO) { -// // set missing node -// j->second.node = &node_; -// this->register_has_many(pi->type_index(), id, pi.get()); -// } else if (j->second.type == prototype_node::relation_info::HAS_MANY) { -// // handle has many -// } -// } } template class O> @@ -240,31 +219,6 @@ void node_analyzer::serialize(const char *id, has_many &x, const char } else { this->process_has_many(pi, id, x); } -// if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { -// // prototype is of type has_many_item -// throw_object_exception("prototype already inserted"); -// } else { -// if (pi->type_index() == std::type_index(typeid(typename has_many::item_type))) { -// // prototype is of type has_many_item -// std::cout << "serialize has many: found type " << pi->type_index().name() << "\n"; -// this->register_has_many(node_.type_index(), id, pi.get()); -// std::cout << "registering node type id " << typeid(typename has_many::item_type).name() << "\n"; -// store_.typeid_prototype_map_[typeid(typename has_many::item_type).name()].insert(std::make_pair(pi->type_, pi.get())); -// } else { -// // found corresponding belongs_to -// auto j = pi->relation_info_map_.find(node_.type_index_); -// if (j == pi->relation_info_map_.end()) { -// // check for has many item -// throw_object_exception("prototype already inserted: " << pi->type()); -// } else if (j->second.type == prototype_node::relation_info::BELONGS_TO) { -// // set missing node -// j->second.node = &node_; -// this->register_has_many(pi->type_index(), id, pi.get()); -// } else if (j->second.type == prototype_node::relation_info::HAS_MANY) { -// // handle has many -// } -// } -// } } template From 021fe066f3d49d0de8dcdf5ea0ede4d4780a08a1 Mon Sep 17 00:00:00 2001 From: zussel Date: Wed, 15 Feb 2017 13:14:56 +0100 Subject: [PATCH 56/61] handle potential memory leak when creating prototype node --- include/oos/object/object_store.hpp | 55 +++-------------------------- 1 file changed, 4 insertions(+), 51 deletions(-) diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index 209b8d895..68dd43893 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -732,18 +732,6 @@ class OOS_OBJECT_API object_store template < class T > prototype_node* attach_node(prototype_node *node, const char *parent); - /** - * Get or create a prototype node - * - * @param producer The producer of the concrete object - * @param type The type name of the node - * @param abstract indicates wether the representing object is abstract - * @tparam T Type of the node - * @return The prototype node - */ - template - prototype_node *acquire(const char *type, bool abstract); - prototype_node* find_parent(const char *name) const; void push_transaction(const transaction &tr); @@ -789,6 +777,7 @@ class OOS_OBJECT_API object_store template < class T > void object_store::validate(prototype_node *node) { + std::unique_ptr nptr(node); // try to find node in prepared map const char *name = typeid(T).name(); t_prototype_map::iterator i = prototype_map_.find(node->type_); @@ -813,6 +802,7 @@ void object_store::validate(prototype_node *node) */ throw object_exception("unexpectly found prototype"); } + nptr.release(); } template class O > @@ -824,7 +814,6 @@ object_store::iterator object_store::attach(const char *type, std::initializer_l template object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent) { -// prototype_node *node = acquire(type, abstract); prototype_node *node = new prototype_node(this, type, new T, abstract); return attach(node, parent); @@ -839,7 +828,6 @@ object_store::iterator object_store::attach(const char *type, bool abstract, con template class O> object_store::iterator object_store::attach(const char *type, bool abstract, const char *parent, const std::vector*> &observer) { -// prototype_node *node = acquire(type, abstract); prototype_node *node = new prototype_node(this, type, new T, abstract); return attach(node, parent, observer); @@ -848,6 +836,7 @@ object_store::iterator object_store::attach(const char *type, bool abstract, con template < class T > prototype_node* object_store::attach_node(prototype_node *node, const char *parent) { + std::unique_ptr nptr(node); // set node to root node prototype_node *parent_node = find_parent(parent); /* @@ -870,7 +859,7 @@ prototype_node* object_store::attach_node(prototype_node *node, const char *pare prototype_map_.insert(std::make_pair(node->type_, node))/*.first*/; typeid_prototype_map_[typeid(T).name()].insert(std::make_pair(node->type_, node)); - return node; + return nptr.release(); } template @@ -930,42 +919,6 @@ prototype_iterator object_store::attach(prototype_node *node, const char *parent return prototype_iterator(node); } -template -prototype_node *object_store::acquire(const char *type, bool abstract) -{ - // try to find node in prepared map - const char *name = typeid(T).name(); - prototype_node *node = nullptr; - t_prototype_map::iterator i = prototype_map_.find(type); - if (i != prototype_map_.end()) { - throw_object_exception("prototype already inserted: " << type); - } - // try to find by typeid name - i = prototype_map_.find(name); - if (i != prototype_map_.end()) { - throw_object_exception("prototype already inserted: " << type); - } - /* - * no typeid found, seems to be - * a new type - * to be sure check in typeid map - */ - t_typeid_prototype_map::iterator j = typeid_prototype_map_.find(name); - if (j != typeid_prototype_map_.end() && j->second.find(type) != j->second.end()) { - /* unexpected found the - * typeid check for type - * throw exception - */ - throw object_exception("unexpectly found prototype"); - } else { - /* insert new prototype and add to - * typeid map - */ - node = new prototype_node(this, type, new T, abstract); - } - return node; -} - namespace detail { template < class T > From 716460a9c4a557af3b1d30195ce9db30e982da4a Mon Sep 17 00:00:00 2001 From: zussel Date: Wed, 15 Feb 2017 13:15:26 +0100 Subject: [PATCH 57/61] enhanced observer and has_many_to_many test --- test/object/ObjectStoreTestUnit.cpp | 103 ++++++++++++++++++++-------- 1 file changed, 75 insertions(+), 28 deletions(-) diff --git a/test/object/ObjectStoreTestUnit.cpp b/test/object/ObjectStoreTestUnit.cpp index a80de68d7..c6b266827 100644 --- a/test/object/ObjectStoreTestUnit.cpp +++ b/test/object/ObjectStoreTestUnit.cpp @@ -1049,14 +1049,38 @@ void ObjectStoreTestUnit::test_has_many_to_many() auto algebra = ostore_.insert(new course("algebra")); auto art = ostore_.insert(new course("art")); + UNIT_ASSERT_TRUE(george->courses.empty(), "georges courses must be empty"); + UNIT_ASSERT_TRUE(jane->courses.empty(), "janes courses must be empty"); + UNIT_ASSERT_TRUE(algebra->students.empty(), "there must be no students in algebra"); + UNIT_ASSERT_TRUE(art->students.empty(), "there must be no students in art"); + art->students.push_back(jane); - std::cout << "jane course count " << jane->courses.size() << "\n"; + UNIT_ASSERT_FALSE(art->students.empty(), "there must not be students in art"); + UNIT_ASSERT_EQUAL(art->students.size(), 1UL, "there must be one student in art course"); + UNIT_ASSERT_EQUAL(art->students.front()->name(), jane->name(), "arts student must be jane"); + UNIT_ASSERT_FALSE(jane->courses.empty(), "janes courses must not be empty"); + UNIT_ASSERT_EQUAL(jane->courses.size(), 1UL, "jane must've took one course"); + UNIT_ASSERT_EQUAL(jane->courses.front()->title, art->title, "janes course must be art"); jane->courses.erase(jane->courses.begin()); - - std::cout << "jane course count " << jane->courses.size() << "\n"; - std::cout << "art students count " << art->students.size() << "\n"; + + UNIT_ASSERT_TRUE(jane->courses.empty(), "janes courses must be empty"); + UNIT_ASSERT_TRUE(art->students.empty(), "there must be no students in art"); + + george->courses.push_back(algebra); + + UNIT_ASSERT_FALSE(algebra->students.empty(), "there must not be students in algebra"); + UNIT_ASSERT_EQUAL(algebra->students.size(), 1UL, "there must be one student in algebra course"); + UNIT_ASSERT_EQUAL(algebra->students.front()->name(), george->name(), "algebras student must be george"); + UNIT_ASSERT_FALSE(george->courses.empty(), "georges courses must not be empty"); + UNIT_ASSERT_EQUAL(george->courses.size(), 1UL, "george must've took one course"); + UNIT_ASSERT_EQUAL(george->courses.front()->title, algebra->title, "georges course must be algebra"); + + algebra->students.clear(); + + UNIT_ASSERT_TRUE(george->courses.empty(), "georges courses must be empty"); + UNIT_ASSERT_TRUE(algebra->students.empty(), "there must be no students in algebra"); } void ObjectStoreTestUnit::test_belongs_to() @@ -1102,51 +1126,74 @@ void ObjectStoreTestUnit::test_belongs_to() UNIT_ASSERT_TRUE(dep->employees.empty(), "there must be no employees"); } +struct basic_logger +{ + static std::vector nodes; +}; + +std::vector basic_logger::nodes = std::vector(); + template < class T > -struct logger : public object_store_observer +struct logger : public object_store_observer, public basic_logger { logger() {} + template < class V > logger(const logger *) {} void on_attach(prototype_node &node, T &) override { - std::cout << "attaching node " << node.type() << "\n"; + nodes.push_back(node.type()); } void on_detach(prototype_node &node, T &) override { - std::cout << "detaching node " << node.type() << "\n"; - } - - void on_insert(object_proxy &proxy) override - { - std::cout << "inserting proxy " << &proxy << "\n"; + nodes.push_back(node.type()); } - void on_update(object_proxy &proxy) override - { - std::cout << "updating proxy " << &proxy << "\n"; - } - - void on_delete(object_proxy &proxy) override - { - std::cout << "deleting proxy " << &proxy << "\n"; - } + void on_insert(object_proxy &) override {} + void on_update(object_proxy &) override {} + void on_delete(object_proxy &) override {} }; void ObjectStoreTestUnit::test_observer() { -// ostore_.attach("person", { new logger }); -// ostore_.attach("employee", { new logger }); -// ostore_.attach("department", { new logger }); -// ostore_.attach("book", { new logger }); -// ostore_.attach("book_list", { new logger }); + ostore_.attach("person", { new logger }); + ostore_.attach("employee", { new logger }); + ostore_.attach("department", { new logger }); + ostore_.attach("book", { new logger }); + ostore_.attach("book_list", { new logger }); + + std::vector result({ + "person", + "employee", + "department", + "book", + "books", + "book_list" + }); + + UNIT_ASSERT_TRUE(basic_logger::nodes == result, "vectors must be equal"); + + basic_logger::nodes.clear(); ostore_.clear(true); ostore_.attach("person", { new logger }); ostore_.attach("department", { new logger }); ostore_.attach("employee", { new logger }); -// ostore_.attach("book", { new logger }); -// ostore_.attach("book_list", { new logger }); + ostore_.attach("book_list", { new logger }); + ostore_.attach("book", { new logger }); + + result = { + "person", + "employee", + "department", + "employee", + "employee", + "books", + "book_list", + "book" + }; + + UNIT_ASSERT_TRUE(basic_logger::nodes == result, "vectors must be equal"); } From c1bc5b6ecf377be457f1c7712ca9b7b021320c75 Mon Sep 17 00:00:00 2001 From: zussel Date: Wed, 15 Feb 2017 14:49:39 +0100 Subject: [PATCH 58/61] fixed clang issues --- include/oos/object/object_store.hpp | 2 +- src/utils/date.cpp | 2 +- src/utils/time.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/oos/object/object_store.hpp b/include/oos/object/object_store.hpp index 68dd43893..4375d3a21 100644 --- a/include/oos/object/object_store.hpp +++ b/include/oos/object/object_store.hpp @@ -654,7 +654,7 @@ class OOS_OBJECT_API object_store friend class object_proxy; friend class prototype_node; friend class detail::basic_node_analyzer; - template < class T, template < class ... > class ON_ATTACH > + template < class T, template < class U = T > class O > friend class detail::node_analyzer; friend class transaction; template < class T, template class C > diff --git a/src/utils/date.cpp b/src/utils/date.cpp index 6fe0edfd9..84089969a 100644 --- a/src/utils/date.cpp +++ b/src/utils/date.cpp @@ -171,7 +171,7 @@ date date::parse(const std::string &dstr, const char *format) { struct tm t; detail::strptime(dstr.c_str(), format, &t); - return std::move(date(t.tm_mday, t.tm_mon + 1, t.tm_year + 1900)); + return date(t.tm_mday, t.tm_mon + 1, t.tm_year + 1900); } void date::set(const char *datestr, const char *format) diff --git a/src/utils/time.cpp b/src/utils/time.cpp index 69d32d7d7..5ad85f2b2 100644 --- a/src/utils/time.cpp +++ b/src/utils/time.cpp @@ -191,7 +191,7 @@ time time::parse(const std::string &tstr, const char *format) tv.tv_sec = mktime(&tm); tv.tv_usec = usec; #endif - return std::move(oos::time(tv)); + return oos::time(tv); } void time::set(int year, int month, int day, int hour, int min, int sec, long millis) From 529b181407aafaae2ba6eb54dce38b8b3a40319e Mon Sep 17 00:00:00 2001 From: zussel Date: Wed, 15 Feb 2017 16:17:24 +0100 Subject: [PATCH 59/61] reenabled tmp iterator in list --- include/oos/object/has_many_list.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/oos/object/has_many_list.hpp b/include/oos/object/has_many_list.hpp index c7c4f191d..33402fa10 100644 --- a/include/oos/object/has_many_list.hpp +++ b/include/oos/object/has_many_list.hpp @@ -587,8 +587,8 @@ class has_many : public basic_has_many if (this->ostore_) { inserter_.insert(*this->ostore_, iptr, *this->owner_, this->mark_modified_owner_); } -// container_iterator i = pos.iter_; - return iterator(this->container_.insert(pos.iter_, iptr)); + container_iterator i = pos.iter_; + return iterator(this->container_.insert(i, iptr)); } /** From f97839d3c049d841f5cabd5512d5fa9889f03f28 Mon Sep 17 00:00:00 2001 From: zussel Date: Wed, 15 Feb 2017 21:43:33 +0100 Subject: [PATCH 60/61] removed default move constructors for has many list --- include/oos/object/has_many_list.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/oos/object/has_many_list.hpp b/include/oos/object/has_many_list.hpp index 33402fa10..b841d2c81 100644 --- a/include/oos/object/has_many_list.hpp +++ b/include/oos/object/has_many_list.hpp @@ -85,8 +85,8 @@ class has_many_iterator */ has_many_iterator(const self &iter) : iter_(iter.iter_) {} - has_many_iterator(self &&iter) = default; - has_many_iterator& operator=(self &&iter) = default; + //has_many_iterator(self &&iter) = default; + //has_many_iterator& operator=(self &&iter) = default; /** * @brief Creates a has many iterator from given internal container iterator * @@ -311,8 +311,8 @@ class const_has_many_iterator const_has_many_iterator(const self &iter) : iter_(iter.iter_) {} - const_has_many_iterator(self &&iter) = default; - const_has_many_iterator& operator=(self &&iter) = default; + //const_has_many_iterator(self &&iter) = default; + //const_has_many_iterator& operator=(self &&iter) = default; /** * @brief Copy assigns a new const has many iterator From 7937a829eedb4aa1cfde03e938a172d4b7e163e3 Mon Sep 17 00:00:00 2001 From: zussel Date: Thu, 16 Feb 2017 10:31:34 +0100 Subject: [PATCH 61/61] removed has many iterator move constructors --- include/oos/object/has_many_vector.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/oos/object/has_many_vector.hpp b/include/oos/object/has_many_vector.hpp index 8813ef936..525c19252 100644 --- a/include/oos/object/has_many_vector.hpp +++ b/include/oos/object/has_many_vector.hpp @@ -87,8 +87,8 @@ class has_many_iterator */ has_many_iterator(const self &iter) : iter_(iter.iter_) {} - has_many_iterator(self &&iter) = default; - has_many_iterator& operator=(self &&iter) = default; + //has_many_iterator(self &&iter) = default; + //has_many_iterator& operator=(self &&iter) = default; /** * @brief Creates a has many iterator from given internal container iterator * @@ -385,8 +385,8 @@ class const_has_many_iterator const_has_many_iterator(const self &iter) : iter_(iter.iter_) {} - const_has_many_iterator(self &&iter) = default; - const_has_many_iterator& operator=(self &&iter) = default; + //const_has_many_iterator(self &&iter) = default; + //const_has_many_iterator& operator=(self &&iter) = default; /** * @brief Copy assigns a new const has many iterator *