Compare commits

...

4 Commits

7 changed files with 149 additions and 64 deletions

View File

@ -25,6 +25,8 @@ set(TEST_SOURCES
../../../test/backends/SequenceFixture.cpp ../../../test/backends/SequenceFixture.cpp
../../../test/backends/SequenceFixture.hpp ../../../test/backends/SequenceFixture.hpp
../../../test/backends/SequenceTest.cpp ../../../test/backends/SequenceTest.cpp
../../../test/backends/SessionDeleteHasMany.cpp
../../../test/backends/SessionDeleteHasManyToMany.cpp
../../../test/backends/SessionFixture.cpp ../../../test/backends/SessionFixture.cpp
../../../test/backends/SessionFixture.hpp ../../../test/backends/SessionFixture.hpp
../../../test/backends/SessionInsertBelongsTo.cpp ../../../test/backends/SessionInsertBelongsTo.cpp
@ -46,7 +48,6 @@ set(TEST_SOURCES
../../../test/models/user.hpp ../../../test/models/user.hpp
../../../test/utils/RecordPrinter.cpp ../../../test/utils/RecordPrinter.cpp
../../../test/utils/RecordPrinter.hpp ../../../test/utils/RecordPrinter.hpp
../../../test/backends/SessionDeleteHasMany.cpp
) )
set(LIBRARY_TEST_TARGET PostgresTests) set(LIBRARY_TEST_TARGET PostgresTests)

View File

@ -12,6 +12,7 @@
#include "matador/query/query_builder_exception.hpp" #include "matador/query/query_builder_exception.hpp"
#include "matador/query/query_builder_utils.hpp" #include "matador/query/query_builder_utils.hpp"
#include "matador/sql/internal/identifier_statement_binder.hpp"
#include "matador/sql/execute_result.hpp" #include "matador/sql/execute_result.hpp"
#include "matador/sql/statement.hpp" #include "matador/sql/statement.hpp"
@ -38,7 +39,10 @@ public:
return utils::failure(utils::error{error_code::InvalidObject, "Object is null"}); return utils::failure(utils::error{error_code::InvalidObject, "Object is null"});
} }
if (const auto result = stmt.bind(0, id_).execute(); !result.is_ok()) { sql::identifier_statement_binder binder(stmt, 0);
binder.bind(id_);
if (const auto result = stmt.execute(); !result.is_ok()) {
return utils::failure(result.err()); return utils::failure(result.err());
} }

View File

@ -11,8 +11,6 @@
#include "matador/object/attribute.hpp" #include "matador/object/attribute.hpp"
#include "matador/object/restriction.hpp" #include "matador/object/restriction.hpp"
#include <list>
namespace matador::query { namespace matador::query {
class table; class table;
class query_create_table_columns_intermediate : public executable_query { class query_create_table_columns_intermediate : public executable_query {

View File

@ -66,6 +66,10 @@ TEST_CASE_METHOD(SessionFixture, "Test delete object with has many relation", "[
REQUIRE(author_result->is_persistent()); REQUIRE(author_result->is_persistent());
REQUIRE(author_result.value()->books.size() == 5); REQUIRE(author_result.value()->books.size() == 5);
const auto id = s_king->id;
auto del_res = ses.remove(s_king); auto del_res = ses.remove(s_king);
REQUIRE(del_res); REQUIRE(del_res);
author_result = ses.find<author>(id);
REQUIRE_FALSE(author_result);
} }

View File

@ -0,0 +1,80 @@
#include "catch2/catch_test_macros.hpp"
#include "SessionFixture.hpp"
#include "connection.hpp"
#include "matador/query/session.hpp"
#include "models/recipe.hpp"
using namespace matador::test;
using namespace matador::query;
using namespace matador::object;
namespace matador::test {
template<typename AuthorType>
void validate_author_state(const object_ptr<AuthorType>& ptr, object_state expected_state) {
REQUIRE(ptr.is_state(expected_state));
for (auto &b: ptr->books) {
REQUIRE(b.is_state(expected_state));
}
}
}
namespace matador::utils {
template < typename ValueType >
std::ostream& operator<<(std::ostream& os, const result<ValueType, error>& value) {
if (value) {
return os;
}
return os << "Error: " << value.err();
}
std::ostream& operator<<(std::ostream& os, const result<void, error>& value) {
if (value) {
return os;
}
return os << "Error: " << value.err();
}
}
TEST_CASE_METHOD(SessionFixture, "Test delete object with has many to many relation", "[session][delete][has_many_to_many]") {
auto result = schema.attach<recipe_sequence>("recipes")
.and_then( [this] { return schema.attach<ingredient_sequence>("ingredients"); } )
.and_then([this] { return schema.create(db); } );
session ses({bus, connection::dns, 4}, schema);
std::vector ingredients {
make_object<ingredient_sequence>("Apple"),
make_object<ingredient_sequence>("Strawberry"),
make_object<ingredient_sequence>("Pineapple"),
make_object<ingredient_sequence>("Sugar"),
make_object<ingredient_sequence>("Flour"),
make_object<ingredient_sequence>("Butter"),
make_object<ingredient_sequence>("Beans")
};
std::vector recipes {
make_object<recipe_sequence>("Apple Pie", std::vector{ingredients[0], ingredients[3], ingredients[4]}),
make_object<recipe_sequence>("Strawberry Cake", std::vector{ingredients[5], ingredients[6]}),
make_object<recipe_sequence>("Pineapple Pie", std::vector{ingredients[0], ingredients[1], ingredients[2]})
};
for (auto &r: recipes) {
REQUIRE(r.is_transient());
auto res = ses.insert(r);
REQUIRE(res.is_ok());
REQUIRE(res->is_persistent());
}
auto recipe_result = ses.find<recipe_sequence>(1);
REQUIRE(recipe_result.is_ok());
REQUIRE(recipe_result->is_persistent());
REQUIRE(recipe_result.value()->ingredients.size() == 3);
const auto ing_result = ses.find<ingredient_sequence>(ingredients[0]->id);
REQUIRE(ing_result.is_ok());
REQUIRE(ing_result.value()->recipes.size() == 2);
}

View File

@ -14,66 +14,6 @@ using namespace matador::object;
using namespace matador::test; using namespace matador::test;
using namespace matador::query::meta; using namespace matador::query::meta;
namespace matador::test {
template<const utils::primary_key_attribute &PkAttribute>
struct recipe_pk_generator;
template<const utils::primary_key_attribute &PkAttribute>
struct ingredient_pk_generator {
unsigned int id{};
std::string name;
collection<object_ptr<recipe_pk_generator<PkAttribute>>> recipes{};
ingredient_pk_generator() = default;
explicit ingredient_pk_generator(std::string name)
: name(std::move(name)) {
}
ingredient_pk_generator(std::string name, std::vector<object_ptr<recipe_pk_generator<PkAttribute>>> recps)
: name(std::move(name))
, recipes(std::move(recps)){}
template<class Operator>
void process(Operator &op) {
namespace field = matador::access;
field::primary_key(op, "id", id, PkAttribute);
field::attribute(op, "name", name, UniqueVarChar255);
field::has_many_to_many(op, "recipe_ingredients", recipes, "ingredient_id", "recipe_id", utils::CascadeAllFetchEager);
}
};
template<const utils::primary_key_attribute &PkAttribute>
struct recipe_pk_generator {
unsigned int id{};
std::string name;
collection<object_ptr<ingredient_pk_generator<PkAttribute>>> ingredients{};
recipe_pk_generator() = default;
explicit recipe_pk_generator(std::string name)
: name(std::move(name)) {
}
recipe_pk_generator(std::string name, std::vector<object_ptr<ingredient_pk_generator<PkAttribute>>> ings)
: name(std::move(name))
, ingredients(std::move(ings)){}
template<class Operator>
void process(Operator &op) {
namespace field = matador::access;
field::primary_key(op, "id", id, PkAttribute);
field::attribute(op, "name", name, UniqueVarChar255);
field::has_many_to_many(op, "recipe_ingredients", ingredients, utils::CascadeAllFetchLazy);
}
};
using ingredient_identity = ingredient_pk_generator<utils::Identity>;
using ingredient_table = ingredient_pk_generator<utils::Table>;
using ingredient_sequence = ingredient_pk_generator<utils::Sequence>;
using recipe_identity = recipe_pk_generator<utils::Identity>;
using recipe_table = recipe_pk_generator<utils::Table>;
using recipe_sequence = recipe_pk_generator<utils::Sequence>;
}
TEST_CASE_METHOD(SessionFixture, "Test insert object with has many to many relation", "[session][insert][has_many_to_many]") { TEST_CASE_METHOD(SessionFixture, "Test insert object with has many to many relation", "[session][insert][has_many_to_many]") {
auto result = schema.attach<recipe>("recipes") auto result = schema.attach<recipe>("recipes")
.and_then( [this] { return schema.attach<ingredient>("ingredients"); } ) .and_then( [this] { return schema.attach<ingredient>("ingredients"); } )

View File

@ -57,6 +57,64 @@ struct recipe {
field::has_many_to_many(op, "recipe_ingredients", ingredients, utils::CascadeAllFetchLazy); field::has_many_to_many(op, "recipe_ingredients", ingredients, utils::CascadeAllFetchLazy);
} }
}; };
template<const utils::primary_key_attribute &PkAttribute>
struct recipe_pk_generator;
template<const utils::primary_key_attribute &PkAttribute>
struct ingredient_pk_generator {
unsigned int id{};
std::string name;
object::collection<object::object_ptr<recipe_pk_generator<PkAttribute>>> recipes{};
ingredient_pk_generator() = default;
explicit ingredient_pk_generator(std::string name)
: name(std::move(name)) {
}
ingredient_pk_generator(std::string name, std::vector<object::object_ptr<recipe_pk_generator<PkAttribute>>> recps)
: name(std::move(name))
, recipes(std::move(recps)){}
template<class Operator>
void process(Operator &op) {
namespace field = matador::access;
field::primary_key(op, "id", id, PkAttribute);
field::attribute(op, "name", name, UniqueVarChar255);
field::has_many_to_many(op, "recipe_ingredients", recipes, "ingredient_id", "recipe_id", utils::CascadeAllFetchEager);
}
};
template<const utils::primary_key_attribute &PkAttribute>
struct recipe_pk_generator {
unsigned int id{};
std::string name;
object::collection<object::object_ptr<ingredient_pk_generator<PkAttribute>>> ingredients{};
recipe_pk_generator() = default;
explicit recipe_pk_generator(std::string name)
: name(std::move(name)) {
}
recipe_pk_generator(std::string name, std::vector<object::object_ptr<ingredient_pk_generator<PkAttribute>>> ings)
: name(std::move(name))
, ingredients(std::move(ings)){}
template<class Operator>
void process(Operator &op) {
namespace field = matador::access;
field::primary_key(op, "id", id, PkAttribute);
field::attribute(op, "name", name, UniqueVarChar255);
field::has_many_to_many(op, "recipe_ingredients", ingredients, utils::CascadeAllFetchLazy);
}
};
using ingredient_identity = ingredient_pk_generator<utils::Identity>;
using ingredient_table = ingredient_pk_generator<utils::Table>;
using ingredient_sequence = ingredient_pk_generator<utils::Sequence>;
using recipe_identity = recipe_pk_generator<utils::Identity>;
using recipe_table = recipe_pk_generator<utils::Table>;
using recipe_sequence = recipe_pk_generator<utils::Sequence>;
} }
#endif //QUERY_RECIPE_HPP #endif //QUERY_RECIPE_HPP