diff --git a/include/matador/object/object_ptr.hpp b/include/matador/object/object_ptr.hpp index 405de04..c64fdfb 100644 --- a/include/matador/object/object_ptr.hpp +++ b/include/matador/object/object_ptr.hpp @@ -8,24 +8,39 @@ #include namespace matador::object { +struct null_object_ptr_t { + constexpr null_object_ptr_t() = default; +}; + +inline constexpr null_object_ptr_t nullobj{}; + template class object_ptr { public: object_ptr() : proxy_(std::make_shared>()) {} + object_ptr(null_object_ptr_t) {} explicit object_ptr(std::shared_ptr obj) : proxy_(std::make_shared>(obj)) {} explicit object_ptr(std::shared_ptr> obj) : proxy_(std::move(obj)) {} object_ptr(const object_ptr &other) = default; object_ptr(object_ptr &&other) noexcept = default; - object_ptr &operator=(const object_ptr &other) = default; - object_ptr &operator=(object_ptr &&other) = default; + object_ptr& operator=(const object_ptr &other) = default; + object_ptr& operator=(object_ptr &&other) = default; + object_ptr& operator=(null_object_ptr_t) { + proxy_.reset(); + return *this; + } bool operator==(const object_ptr &other) const { return get() == other.get(); } + bool operator==(null_object_ptr_t) const { + return empty(); + } bool operator!=(const object_ptr &other) const { return !operator==(other); } + bool operator!=(null_object_ptr_t) const { return !empty(); } using value_type = Type; diff --git a/include/matador/query/insert_query_builder.hpp b/include/matador/query/insert_query_builder.hpp index a254b9e..2aa68ca 100644 --- a/include/matador/query/insert_query_builder.hpp +++ b/include/matador/query/insert_query_builder.hpp @@ -169,10 +169,6 @@ public: continue; } - if (obj.is_persistent()) { - continue; - } - // Ensure target exists as dependency (deps first) if (obj.is_transient()) { build_for(obj, relation_steps_); @@ -230,10 +226,6 @@ public: continue; } - if (obj.is_persistent()) { - continue; - } - // Ensure target exists as dependency (deps first) if (obj.is_transient()) { build_for(obj, relation_steps_); diff --git a/include/matador/utils/primary_key_attribute.hpp b/include/matador/utils/primary_key_attribute.hpp index 968fc37..7a198f1 100644 --- a/include/matador/utils/primary_key_attribute.hpp +++ b/include/matador/utils/primary_key_attribute.hpp @@ -48,6 +48,7 @@ private: }; const primary_key_attribute DefaultPkAttributes {}; +const primary_key_attribute Identity {generator_type::Identity}; const primary_key_attribute ManualVarChar63 {63}; const primary_key_attribute ManualVarChar127 {127}; const primary_key_attribute ManualVarChar255 {255}; diff --git a/test/backends/SessionInsertHasMany.cpp b/test/backends/SessionInsertHasMany.cpp index b753898..6ef45be 100644 --- a/test/backends/SessionInsertHasMany.cpp +++ b/test/backends/SessionInsertHasMany.cpp @@ -11,6 +11,47 @@ using namespace matador; using namespace matador::object; using namespace matador::test; +namespace matador::test { +struct book_identity; +struct author_identity { + unsigned int id{}; + std::string name; + collection > books; + + author_identity() = default; + explicit author_identity(std::string name) + : name(std::move(name)) {} + + template + void process(Operator &op) { + namespace field = matador::access; + field::primary_key(op, "id", id, utils::Identity); + field::attribute(op, "first_name", name, VarChar63); + field::has_many(op, "books", books, "author_id", utils::CascadeAllFetchLazy); + } +}; + +struct book_identity { + unsigned int id{}; + std::string title; + object_ptr book_author; + unsigned short published_in{}; + + book_identity() = default; + book_identity(std::string title, object_ptr author, const unsigned short published_in) + : title(std::move(title)), book_author(std::move(author)), published_in(published_in) {} + + template + void process(Operator &op) { + namespace field = matador::access; + field::primary_key(op, "id", id, utils::Identity); + field::attribute(op, "title", title, VarChar511); + field::belongs_to(op, "author_id", book_author, utils::CascadeAllFetchEager); + field::attribute(op, "published_in", published_in); + } +}; +} + TEST_CASE_METHOD(SessionFixture, "Test insert object with has many relation", "[session][insert][has_many]") { const auto result = schema.attach("books") .and_then( [this] { return schema.attach("authors"); } ) @@ -22,11 +63,32 @@ TEST_CASE_METHOD(SessionFixture, "Test insert object with has many relation", "[ auto s_king = make_object(1, "Steven", "King", "21.9.1947", 1956, false); - s_king->books.push_back(make_object(2, "Carrie", object_ptr{}, 1974)); - s_king->books.push_back(make_object(3, "The Shining", object_ptr{}, 1977)); - s_king->books.push_back(make_object(4, "It", object_ptr{}, 1986)); - s_king->books.push_back(make_object(5, "Misery", object_ptr{}, 1987)); - s_king->books.push_back(make_object(6, "The Dark Tower: The Gunslinger", object_ptr{}, 1982)); + s_king->books.push_back(make_object(2, "Carrie", nullobj, 1974)); + s_king->books.push_back(make_object(3, "The Shining", nullobj, 1977)); + s_king->books.push_back(make_object(4, "It", nullobj, 1986)); + s_king->books.push_back(make_object(5, "Misery", nullobj, 1987)); + s_king->books.push_back(make_object(6, "The Dark Tower: The Gunslinger", nullobj, 1982)); + + auto res = ses.insert(s_king); + REQUIRE(res.is_ok()); +} + +TEST_CASE_METHOD(SessionFixture, "Test insert object with has many relation with identity", "[session][insert][has_many][identity]") { + const auto result = schema.attach("books") + .and_then( [this] { return schema.attach("authors"); } ) + .and_then([this] { return schema.create(db); } ); + REQUIRE(result.is_ok()); + + orm::session ses({bus, connection::dns, 4}, schema); + schema.initialize(ses); + + auto s_king = make_object("Steven King"); + + s_king->books.push_back(make_object("Carrie", nullobj, 1974)); + s_king->books.push_back(make_object("The Shining", nullobj, 1977)); + s_king->books.push_back(make_object("It", nullobj, 1986)); + s_king->books.push_back(make_object("Misery", nullobj, 1987)); + s_king->books.push_back(make_object("The Dark Tower: The Gunslinger", nullobj, 1982)); auto res = ses.insert(s_king); REQUIRE(res.is_ok()); diff --git a/test/backends/SessionInsertHasManyToManyTest.cpp b/test/backends/SessionInsertHasManyToManyTest.cpp index 4fc2d92..bc66ccd 100644 --- a/test/backends/SessionInsertHasManyToManyTest.cpp +++ b/test/backends/SessionInsertHasManyToManyTest.cpp @@ -5,10 +5,12 @@ #include "connection.hpp" #include "models/recipe.hpp" +#include "models/model_metas.hpp" using namespace matador; using namespace matador::object; using namespace matador::test; +using namespace matador::query::meta; TEST_CASE_METHOD(SessionFixture, "Test insert object with has many to many relation", "[session][insert][has_many_to_many]") { auto result = schema.attach("recipes") @@ -16,6 +18,7 @@ TEST_CASE_METHOD(SessionFixture, "Test insert object with has many to many relat .and_then([this] { return schema.create(db); } ); orm::session ses({bus, connection::dns, 4}, schema); + schema.initialize(ses); std::vector ingredients { make_object(1, "Apple"), @@ -37,4 +40,16 @@ TEST_CASE_METHOD(SessionFixture, "Test insert object with has many to many relat auto res = ses.insert(r); REQUIRE(res.is_ok()); } + + auto recipe_result = ses.find(1); + // auto recipe_result = ses.find(RECIPE.id == 1); + REQUIRE(recipe_result.is_ok()); + + // auto r = *recipe_result->begin(); + auto r = *recipe_result; + std::cout << r->name << " (ingredients: " << r->ingredients.size() << ")" << std::endl; + // REQUIRE(r->name != ""); + for (const auto &ingr: r->ingredients) { + std::cout << " " << ingr->name << std::endl; + } } \ No newline at end of file