delete has many to many progress
This commit is contained in:
parent
73bd6f641c
commit
68d67b17b7
|
|
@ -7,13 +7,11 @@
|
||||||
|
|
||||||
#include "matador/query/basic_schema.hpp"
|
#include "matador/query/basic_schema.hpp"
|
||||||
#include "matador/query/error_code.hpp"
|
#include "matador/query/error_code.hpp"
|
||||||
#include "matador/query/execute_step.hpp"
|
#include "matador/query/delete_step.hpp"
|
||||||
#include "matador/query/query_contexts.hpp"
|
#include "matador/query/query_contexts.hpp"
|
||||||
#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/statement.hpp"
|
#include "matador/sql/statement.hpp"
|
||||||
|
|
||||||
#include "matador/utils/error.hpp"
|
#include "matador/utils/error.hpp"
|
||||||
|
|
@ -22,61 +20,10 @@
|
||||||
#include "matador/utils/result.hpp"
|
#include "matador/utils/result.hpp"
|
||||||
|
|
||||||
namespace matador::query {
|
namespace matador::query {
|
||||||
template<typename ObjectType>
|
|
||||||
class delete_step_object final : public execute_step {
|
|
||||||
public:
|
|
||||||
delete_step_object(sql::query_context ctx, const object::object_ptr<ObjectType> &ptr)
|
|
||||||
: execute_step(std::move(ctx))
|
|
||||||
, ptr_(ptr) {}
|
|
||||||
|
|
||||||
utils::result<void, utils::error> prepare(sql::executor &/*conn*/) override {
|
|
||||||
id_ = ptr_.primary_key();
|
|
||||||
return utils::ok<void>();
|
|
||||||
}
|
|
||||||
|
|
||||||
utils::result<void, utils::error> execute(sql::statement &stmt) override {
|
|
||||||
if (!ptr_) {
|
|
||||||
return utils::failure(utils::error{error_code::InvalidObject, "Object is null"});
|
|
||||||
}
|
|
||||||
|
|
||||||
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::ok<void>();
|
|
||||||
}
|
|
||||||
|
|
||||||
utils::result<void, utils::error> finalize(object::object_cache &cache, const resolver_service_ptr& /*resolver_service*/) override {
|
|
||||||
if (!ptr_) {
|
|
||||||
return utils::failure(utils::error{error_code::InvalidObject, "Object is null"});
|
|
||||||
}
|
|
||||||
|
|
||||||
cache.erase<ObjectType>(id_);
|
|
||||||
ptr_.change_state(object::object_state::Transient);
|
|
||||||
|
|
||||||
return utils::ok<void>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
object::object_ptr<ObjectType> ptr_;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct delete_context {
|
|
||||||
const basic_schema &schema_;
|
|
||||||
const std::unordered_map<std::type_index, query_contexts> &contexts_by_type_;
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<execute_step>> steps_{};
|
|
||||||
std::vector<std::unique_ptr<execute_step>> relation_steps_{};
|
|
||||||
std::unordered_set<std::pair<std::type_index, const void *>, entity_visit_key_hash> visited_{};
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename ObjectType>
|
template<typename ObjectType>
|
||||||
class delete_step_processor {
|
class delete_step_processor {
|
||||||
public:
|
public:
|
||||||
explicit delete_step_processor(delete_context &ctx)
|
explicit delete_step_processor(query_builder_context &ctx)
|
||||||
: ctx_(ctx) {}
|
: ctx_(ctx) {}
|
||||||
|
|
||||||
utils::result<void, utils::error> build(object::object_ptr<ObjectType> ptr, const bool as_relation_step = false) {
|
utils::result<void, utils::error> build(object::object_ptr<ObjectType> ptr, const bool as_relation_step = false) {
|
||||||
|
|
@ -97,8 +44,7 @@ public:
|
||||||
return utils::failure(utils::error{error_code::UnknownType, "Unknown type"});
|
return utils::failure(utils::error{error_code::UnknownType, "Unknown type"});
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &info = it->second.node().info();
|
if (const auto &info = it->second.node().info(); !info.has_primary_key()) {
|
||||||
if (!info.has_primary_key()) {
|
|
||||||
return utils::failure(utils::error{error_code::MissingPrimaryKey, "Type " + info.name() + " has no primary key"});
|
return utils::failure(utils::error{error_code::MissingPrimaryKey, "Type " + info.name() + " has no primary key"});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,19 +123,50 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ForeignType>
|
template<class ForeignType>
|
||||||
void on_has_many_to_many(const char * /*id*/,
|
void on_has_many_to_many(const char *id,
|
||||||
object::collection<object::object_ptr<ForeignType>> &objects,
|
object::collection<object::object_ptr<ForeignType>> &objects,
|
||||||
const char * /*join_column*/,
|
const char *join_column,
|
||||||
const char * /*inverse_join_column*/,
|
const char *inverse_join_column,
|
||||||
const utils::foreign_attributes &attr) {
|
const utils::foreign_attributes &attr) {
|
||||||
on_many_to_many_objects(objects, attr);
|
if (id == nullptr || join_column == nullptr || inverse_join_column == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using relation_value_type = object::many_to_many_relation<ObjectType, ForeignType>;
|
||||||
|
const std::type_index foreign_type{typeid(ForeignType)};
|
||||||
|
const std::type_index local_type{typeid(ObjectType)};
|
||||||
|
on_many_to_many_objects<relation_value_type>(
|
||||||
|
id,
|
||||||
|
objects,
|
||||||
|
attr,
|
||||||
|
[foreign_type, local_type](const char* relation_name) -> processing_many_to_many_key {
|
||||||
|
return {std::string{relation_name}, local_type, foreign_type};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ForeignType>
|
template<class ForeignType>
|
||||||
void on_has_many_to_many(const char * /*id*/,
|
void on_has_many_to_many(const char *id,
|
||||||
object::collection<object::object_ptr<ForeignType>> &objects,
|
object::collection<object::object_ptr<ForeignType>> &objects,
|
||||||
const utils::foreign_attributes &attr) {
|
const utils::foreign_attributes &attr) {
|
||||||
on_many_to_many_objects(objects, attr);
|
if (id == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
object::join_columns_collector collector;
|
||||||
|
if (auto join_columns = collector.collect<ForeignType>(); join_columns.join_column.empty() || join_columns.inverse_join_column.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using relation_value_type = object::many_to_many_relation<ForeignType, ObjectType>;
|
||||||
|
const std::type_index foreign_type{typeid(ForeignType)};
|
||||||
|
const std::type_index local_type{typeid(ObjectType)};
|
||||||
|
on_many_to_many_objects<relation_value_type>(
|
||||||
|
id,
|
||||||
|
objects,
|
||||||
|
attr,
|
||||||
|
[foreign_type, local_type](const char* relation_name) -> processing_many_to_many_key {
|
||||||
|
return {std::string{relation_name}, foreign_type, local_type};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -207,28 +184,52 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ForeignType>
|
template<class LocalType, class ForeignType, class RelationKeyFactory>
|
||||||
void on_many_to_many_objects(object::collection<object::object_ptr<ForeignType>> &objects,
|
void on_many_to_many_objects(const char *id,
|
||||||
const utils::foreign_attributes &attr) {
|
object::collection<object::object_ptr<ForeignType>> &objects,
|
||||||
|
const utils::foreign_attributes &attr,
|
||||||
|
RelationKeyFactory make_relation_key) {
|
||||||
if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Remove)) {
|
if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Remove)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto key = make_relation_key(id);
|
||||||
|
if (ctx_.processing_many_to_many_relations_.find(key) != ctx_.processing_many_to_many_relations_.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto it = ctx_.schema_.find(std::string{id});
|
||||||
|
if (it == ctx_.schema_.end()) {
|
||||||
|
throw query_builder_exception(error_code::UnknownType, "Unknown type for relation " + std::string{id});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::type_index(typeid(LocalType)) != it->second.node().info().type_index()) {
|
||||||
|
throw query_builder_exception(error_code::InvalidRelationType, "Invalid relation type for " + std::string{id});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const auto cit = ctx_.contexts_by_type_.find(it->second.node().info().type_index()); cit == ctx_.contexts_by_type_.end()) {
|
||||||
|
throw query_builder_exception(error_code::UnknownType, "No query contexts for type " + it->second.node().name());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ignore = ctx_.processing_many_to_many_relations_.insert(key);
|
||||||
|
std::vector<std::unique_ptr<execute_step>> delete_relation_steps;
|
||||||
delete_step_processor<ForeignType> processor{ctx_};
|
delete_step_processor<ForeignType> processor{ctx_};
|
||||||
for (auto &obj : objects) {
|
for (auto &obj : objects) {
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = processor.build(obj, true);
|
if (obj.is_persistent()) {
|
||||||
if (!result) {
|
auto result = processor.build(obj, true);
|
||||||
throw query_builder_exception(result.release_error());
|
if (!result) {
|
||||||
|
throw query_builder_exception(result.release_error());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
delete_context &ctx_;
|
query_builder_context &ctx_;
|
||||||
object::object_ptr<ObjectType> ptr_;
|
object::object_ptr<ObjectType> ptr_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -245,7 +246,7 @@ public:
|
||||||
return utils::failure(utils::error{error_code::UnknownType, "Unknown type for delete query"});
|
return utils::failure(utils::error{error_code::UnknownType, "Unknown type for delete query"});
|
||||||
}
|
}
|
||||||
|
|
||||||
delete_context ctx{schema_, contexts_by_type_};
|
query_builder_context ctx{schema_, contexts_by_type_};
|
||||||
delete_step_processor<ObjectType> processor{ctx};
|
delete_step_processor<ObjectType> processor{ctx};
|
||||||
|
|
||||||
const auto result = processor.build(ptr);
|
const auto result = processor.build(ptr);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
#ifndef MATADOR_DELETE_STEP_HPP
|
||||||
|
#define MATADOR_DELETE_STEP_HPP
|
||||||
|
|
||||||
|
#include "matador/query/error_code.hpp"
|
||||||
|
#include "matador/query/execute_step.hpp"
|
||||||
|
|
||||||
|
#include "matador/sql/internal/identifier_statement_binder.hpp"
|
||||||
|
#include "matador/sql/statement.hpp"
|
||||||
|
|
||||||
|
#include "matador/object/object_ptr.hpp"
|
||||||
|
|
||||||
|
namespace matador::query {
|
||||||
|
template<typename ObjectType>
|
||||||
|
class delete_step_object final : public execute_step {
|
||||||
|
public:
|
||||||
|
delete_step_object(sql::query_context ctx, const object::object_ptr<ObjectType> &ptr)
|
||||||
|
: execute_step(std::move(ctx))
|
||||||
|
, ptr_(ptr) {}
|
||||||
|
|
||||||
|
utils::result<void, utils::error> prepare(sql::executor &/*conn*/) override {
|
||||||
|
id_ = ptr_.primary_key();
|
||||||
|
return utils::ok<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::result<void, utils::error> execute(sql::statement &stmt) override {
|
||||||
|
if (!ptr_) {
|
||||||
|
return utils::failure(utils::error{error_code::InvalidObject, "Object is null"});
|
||||||
|
}
|
||||||
|
|
||||||
|
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::ok<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::result<void, utils::error> finalize(object::object_cache &cache, const resolver_service_ptr& /*resolver_service*/) override {
|
||||||
|
if (!ptr_) {
|
||||||
|
return utils::failure(utils::error{error_code::InvalidObject, "Object is null"});
|
||||||
|
}
|
||||||
|
|
||||||
|
cache.erase<ObjectType>(id_);
|
||||||
|
ptr_.change_state(object::object_state::Transient);
|
||||||
|
|
||||||
|
return utils::ok<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
object::object_ptr<ObjectType> ptr_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename ObjectType>
|
||||||
|
class delete_step_relation : public execute_step {
|
||||||
|
public:
|
||||||
|
delete_step_relation(sql::query_context ctx, const object::object_ptr<ObjectType>& ptr)
|
||||||
|
: execute_step(std::move(ctx))
|
||||||
|
, ptr_(ptr) {}
|
||||||
|
|
||||||
|
utils::result<void, utils::error> prepare(sql::executor &) override {
|
||||||
|
return utils::ok<void>();
|
||||||
|
}
|
||||||
|
utils::result<void, utils::error> execute(sql::statement &stmt) override {
|
||||||
|
stmt.bind(*ptr_);
|
||||||
|
if (const auto exec_result = stmt.execute(); !exec_result.is_ok()) {
|
||||||
|
return utils::failure(exec_result.err());
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils::ok<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::result<void, utils::error> finalize(object::object_cache& /*cache*/, const resolver_service_ptr& /*resolver_service*/) override {
|
||||||
|
return utils::ok<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
object::object_ptr<ObjectType> ptr_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //MATADOR_DELETE_STEP_HPP
|
||||||
|
|
@ -56,49 +56,10 @@ private:
|
||||||
std::string join_column_;
|
std::string join_column_;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct processing_many_to_many_key {
|
|
||||||
std::string id;
|
|
||||||
std::type_index local_type{typeid(void)};
|
|
||||||
std::type_index foreign_type{typeid(void)};
|
|
||||||
bool operator==(processing_many_to_many_key const &other) const {
|
|
||||||
return local_type == other.local_type && foreign_type == other.foreign_type && id == other.id;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class LocalType, typename ForeignType>
|
|
||||||
static processing_many_to_many_key make_processing_many_to_many_key(const std::string &id) {
|
|
||||||
return {id, std::type_index(typeid(LocalType)), std::type_index(typeid(ForeignType))};
|
|
||||||
}
|
|
||||||
|
|
||||||
struct processing_many_to_many_key_hash {
|
|
||||||
size_t operator()(const processing_many_to_many_key &p) const noexcept {
|
|
||||||
size_t seed = std::hash<std::type_index>{}(p.local_type);
|
|
||||||
|
|
||||||
const size_t foreign_hash = std::hash<std::type_index>{}(p.foreign_type);
|
|
||||||
seed ^= foreign_hash + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);
|
|
||||||
|
|
||||||
const size_t id_hash = std::hash<std::string>{}(p.id);
|
|
||||||
seed ^= id_hash + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);
|
|
||||||
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct insert_context {
|
|
||||||
const basic_schema &schema_;
|
|
||||||
const std::unordered_map<std::type_index, query_contexts> &contexts_by_type_;
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<execute_step>> steps_{};
|
|
||||||
std::vector<std::unique_ptr<execute_step>> relation_steps_{};
|
|
||||||
std::unordered_set<std::pair<std::type_index, const void *>, entity_visit_key_hash> visited_{};
|
|
||||||
std::unordered_set<processing_many_to_many_key, processing_many_to_many_key_hash> processing_many_to_many_relations_{};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
template < typename ObjectType >
|
template < typename ObjectType >
|
||||||
class insert_step_processor {
|
class insert_step_processor {
|
||||||
public:
|
public:
|
||||||
explicit insert_step_processor(insert_context &ctx)
|
explicit insert_step_processor(query_builder_context &ctx)
|
||||||
: ctx_{ctx}
|
: ctx_{ctx}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
@ -247,7 +208,6 @@ public:
|
||||||
attr,
|
attr,
|
||||||
[foreign_type, local_type](const char* relation_name) -> processing_many_to_many_key {
|
[foreign_type, local_type](const char* relation_name) -> processing_many_to_many_key {
|
||||||
return {std::string{relation_name}, local_type, foreign_type};
|
return {std::string{relation_name}, local_type, foreign_type};
|
||||||
// return make_processing_many_to_many_key<ObjectType, ForeignType>(relation_name);
|
|
||||||
},
|
},
|
||||||
[this, join_column, inverse_join_column](const auto &obj) {
|
[this, join_column, inverse_join_column](const auto &obj) {
|
||||||
return object::make_object<relation_value_type>(join_column, inverse_join_column, ptr_, obj);
|
return object::make_object<relation_value_type>(join_column, inverse_join_column, ptr_, obj);
|
||||||
|
|
@ -275,7 +235,6 @@ public:
|
||||||
attr,
|
attr,
|
||||||
[foreign_type, local_type](const char* relation_name) -> processing_many_to_many_key {
|
[foreign_type, local_type](const char* relation_name) -> processing_many_to_many_key {
|
||||||
return {std::string{relation_name}, foreign_type, local_type};
|
return {std::string{relation_name}, foreign_type, local_type};
|
||||||
return make_processing_many_to_many_key<ForeignType, ObjectType>(relation_name);
|
|
||||||
},
|
},
|
||||||
[this, join_columns = std::move(join_columns)](const auto &obj) {
|
[this, join_columns = std::move(join_columns)](const auto &obj) {
|
||||||
return object::make_object<relation_value_type>(join_columns.inverse_join_column, join_columns.join_column, obj, ptr_);
|
return object::make_object<relation_value_type>(join_columns.inverse_join_column, join_columns.join_column, obj, ptr_);
|
||||||
|
|
@ -297,12 +256,12 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class LocalType, class ForeignType, class RelationKeyFactory, class RelationFactory>
|
template<class LocalType, class ForeignType, class RelationKeyFactory, class RelationFactory>
|
||||||
void insert_many_to_many_relations(const char *id,
|
void insert_many_to_many_relations(const char *id,
|
||||||
object::collection<object::object_ptr<ForeignType>> &objects,
|
object::collection<object::object_ptr<ForeignType>> &objects,
|
||||||
const utils::foreign_attributes &attr,
|
const utils::foreign_attributes &attr,
|
||||||
RelationKeyFactory make_relation_key,
|
RelationKeyFactory make_relation_key,
|
||||||
RelationFactory make_relation) {
|
RelationFactory make_relation) {
|
||||||
if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Insert)) {
|
if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Insert)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -343,7 +302,7 @@ private:
|
||||||
|
|
||||||
auto rel = make_relation(obj);
|
auto rel = make_relation(obj);
|
||||||
|
|
||||||
access::process(*this, *rel);
|
// access::process(*this, *rel);
|
||||||
|
|
||||||
insert_relation_steps.push_back(std::make_unique<insert_step_relation<LocalType>>(cit->second.insert, rel));
|
insert_relation_steps.push_back(std::make_unique<insert_step_relation<LocalType>>(cit->second.insert, rel));
|
||||||
}
|
}
|
||||||
|
|
@ -365,7 +324,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
insert_context& ctx_;
|
query_builder_context& ctx_;
|
||||||
object::object_ptr<ObjectType> ptr_;
|
object::object_ptr<ObjectType> ptr_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -382,7 +341,7 @@ public:
|
||||||
return utils::failure(utils::error{error_code::UnknownType, "Unknown type for insert query"});
|
return utils::failure(utils::error{error_code::UnknownType, "Unknown type for insert query"});
|
||||||
}
|
}
|
||||||
|
|
||||||
insert_context ctx{schema_, contexts_by_type_};
|
query_builder_context ctx{schema_, contexts_by_type_};
|
||||||
insert_step_processor<ObjectType> processor{ctx};
|
insert_step_processor<ObjectType> processor{ctx};
|
||||||
|
|
||||||
const auto result = processor.build(ptr);
|
const auto result = processor.build(ptr);
|
||||||
|
|
|
||||||
|
|
@ -18,5 +18,43 @@ struct entity_visit_key_hash {
|
||||||
return h1 ^ (h2 + 0x9e3779b97f4a7c15ULL + (h1 << 6) + (h1 >> 2));
|
return h1 ^ (h2 + 0x9e3779b97f4a7c15ULL + (h1 << 6) + (h1 >> 2));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct processing_many_to_many_key {
|
||||||
|
std::string id;
|
||||||
|
std::type_index local_type{typeid(void)};
|
||||||
|
std::type_index foreign_type{typeid(void)};
|
||||||
|
bool operator==(processing_many_to_many_key const &other) const {
|
||||||
|
return local_type == other.local_type && foreign_type == other.foreign_type && id == other.id;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class LocalType, typename ForeignType>
|
||||||
|
static processing_many_to_many_key make_processing_many_to_many_key(const std::string &id) {
|
||||||
|
return {id, std::type_index(typeid(LocalType)), std::type_index(typeid(ForeignType))};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct processing_many_to_many_key_hash {
|
||||||
|
size_t operator()(const processing_many_to_many_key &p) const noexcept {
|
||||||
|
size_t seed = std::hash<std::type_index>{}(p.local_type);
|
||||||
|
|
||||||
|
const size_t foreign_hash = std::hash<std::type_index>{}(p.foreign_type);
|
||||||
|
seed ^= foreign_hash + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);
|
||||||
|
|
||||||
|
const size_t id_hash = std::hash<std::string>{}(p.id);
|
||||||
|
seed ^= id_hash + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);
|
||||||
|
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct query_builder_context {
|
||||||
|
const basic_schema &schema_;
|
||||||
|
const std::unordered_map<std::type_index, query_contexts> &contexts_by_type_;
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<execute_step>> steps_{};
|
||||||
|
std::vector<std::unique_ptr<execute_step>> relation_steps_{};
|
||||||
|
std::unordered_set<std::pair<std::type_index, const void *>, entity_visit_key_hash> visited_{};
|
||||||
|
std::unordered_set<processing_many_to_many_key, processing_many_to_many_key_hash> processing_many_to_many_relations_{};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
#endif //MATADOR_QUERY_BUILDER_UTILS_HPP
|
#endif //MATADOR_QUERY_BUILDER_UTILS_HPP
|
||||||
|
|
|
||||||
|
|
@ -352,10 +352,6 @@ utils::result<sql::query_context, utils::error> query_object_resolver_producer<T
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
utils::result<sql::query_context, utils::error> query_joined_object_resolver_producer<Type>::build_query(const sql::dialect &d) {
|
utils::result<sql::query_context, utils::error> query_joined_object_resolver_producer<Type>::build_query(const sql::dialect &d) {
|
||||||
// producer_creator pc(repo_, typeid(Type));
|
|
||||||
// Type obj;
|
|
||||||
// access::process(pc, obj);
|
|
||||||
|
|
||||||
select_query_builder qb(repo_);
|
select_query_builder qb(repo_);
|
||||||
const auto *join_column = table_[collection_name()];
|
const auto *join_column = table_[collection_name()];
|
||||||
const auto result = qb.build<Type>(*join_column == utils::_);
|
const auto result = qb.build<Type>(*join_column == utils::_);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef MATADOR_SCHEMA_UTILS_HPP
|
||||||
|
#define MATADOR_SCHEMA_UTILS_HPP
|
||||||
|
|
||||||
|
#include "matador/query/query_contexts.hpp"
|
||||||
|
#include "matador/query/basic_schema.hpp"
|
||||||
|
|
||||||
|
namespace matador::sql {
|
||||||
|
class dialect;
|
||||||
|
}
|
||||||
|
namespace matador::query {
|
||||||
|
query_contexts to_query_contexts(const schema_node &node, const sql::dialect &d);
|
||||||
|
}
|
||||||
|
#endif //MATADOR_SCHEMA_UTILS_HPP
|
||||||
|
|
@ -3,11 +3,10 @@
|
||||||
|
|
||||||
#include "matador/sql/abstract_sql_logger.hpp"
|
#include "matador/sql/abstract_sql_logger.hpp"
|
||||||
#include "matador/sql/error_code.hpp"
|
#include "matador/sql/error_code.hpp"
|
||||||
|
#include "matador/sql/execute_result.hpp"
|
||||||
#include "matador/sql/query_result.hpp"
|
#include "matador/sql/query_result.hpp"
|
||||||
#include "matador/sql/interface/statement_proxy.hpp"
|
#include "matador/sql/interface/statement_proxy.hpp"
|
||||||
|
|
||||||
#include "matador/object/basic_repository.hpp"
|
|
||||||
|
|
||||||
#include "matador/utils/error.hpp"
|
#include "matador/utils/error.hpp"
|
||||||
#include "matador/utils/result.hpp"
|
#include "matador/utils/result.hpp"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,10 @@ add_library(matador-orm STATIC
|
||||||
../../include/matador/query/criteria/logical_criteria.hpp
|
../../include/matador/query/criteria/logical_criteria.hpp
|
||||||
../../include/matador/query/criteria_evaluator.hpp
|
../../include/matador/query/criteria_evaluator.hpp
|
||||||
../../include/matador/query/database.hpp
|
../../include/matador/query/database.hpp
|
||||||
|
../../include/matador/query/delete_query_builder.hpp
|
||||||
|
../../include/matador/query/delete_step.hpp
|
||||||
../../include/matador/query/error_code.hpp
|
../../include/matador/query/error_code.hpp
|
||||||
|
../../include/matador/query/execute_step.hpp
|
||||||
../../include/matador/query/expression/abstract_column_expression.hpp
|
../../include/matador/query/expression/abstract_column_expression.hpp
|
||||||
../../include/matador/query/expression/binary_column_expression.hpp
|
../../include/matador/query/expression/binary_column_expression.hpp
|
||||||
../../include/matador/query/expression/column_expression.hpp
|
../../include/matador/query/expression/column_expression.hpp
|
||||||
|
|
@ -31,7 +34,7 @@ add_library(matador-orm STATIC
|
||||||
../../include/matador/query/identity_pk_generator.hpp
|
../../include/matador/query/identity_pk_generator.hpp
|
||||||
../../include/matador/query/insert_query_builder.hpp
|
../../include/matador/query/insert_query_builder.hpp
|
||||||
../../include/matador/query/insert_query_builder.hpp
|
../../include/matador/query/insert_query_builder.hpp
|
||||||
../../include/matador/query/execute_step.hpp
|
../../include/matador/query/insert_step.hpp
|
||||||
../../include/matador/query/intermediates/executable_query.hpp
|
../../include/matador/query/intermediates/executable_query.hpp
|
||||||
../../include/matador/query/intermediates/fetchable_query.hpp
|
../../include/matador/query/intermediates/fetchable_query.hpp
|
||||||
../../include/matador/query/intermediates/query_alter_intermediate.hpp
|
../../include/matador/query/intermediates/query_alter_intermediate.hpp
|
||||||
|
|
@ -71,6 +74,7 @@ add_library(matador-orm STATIC
|
||||||
../../include/matador/query/meta_table_macro.hpp
|
../../include/matador/query/meta_table_macro.hpp
|
||||||
../../include/matador/query/query.hpp
|
../../include/matador/query/query.hpp
|
||||||
../../include/matador/query/query_builder.hpp
|
../../include/matador/query/query_builder.hpp
|
||||||
|
../../include/matador/query/query_builder_utils.hpp
|
||||||
../../include/matador/query/query_collection_resolver.hpp
|
../../include/matador/query/query_collection_resolver.hpp
|
||||||
../../include/matador/query/query_column.hpp
|
../../include/matador/query/query_column.hpp
|
||||||
../../include/matador/query/query_contexts.hpp
|
../../include/matador/query/query_contexts.hpp
|
||||||
|
|
@ -80,6 +84,7 @@ add_library(matador-orm STATIC
|
||||||
../../include/matador/query/query_part.hpp
|
../../include/matador/query/query_part.hpp
|
||||||
../../include/matador/query/query_utils.hpp
|
../../include/matador/query/query_utils.hpp
|
||||||
../../include/matador/query/schema.hpp
|
../../include/matador/query/schema.hpp
|
||||||
|
../../include/matador/query/schema_utils.hpp
|
||||||
../../include/matador/query/select_query_builder.hpp
|
../../include/matador/query/select_query_builder.hpp
|
||||||
../../include/matador/query/sequence_pk_generator.hpp
|
../../include/matador/query/sequence_pk_generator.hpp
|
||||||
../../include/matador/query/session.hpp
|
../../include/matador/query/session.hpp
|
||||||
|
|
@ -104,9 +109,9 @@ add_library(matador-orm STATIC
|
||||||
../../include/matador/sql/interface/query_result_reader.hpp
|
../../include/matador/sql/interface/query_result_reader.hpp
|
||||||
../../include/matador/sql/interface/statement_impl.hpp
|
../../include/matador/sql/interface/statement_impl.hpp
|
||||||
../../include/matador/sql/interface/statement_proxy.hpp
|
../../include/matador/sql/interface/statement_proxy.hpp
|
||||||
../../include/matador/sql/internal/joined_collection_resolver_producer.hpp
|
|
||||||
../../include/matador/sql/internal/identifier_reader.hpp
|
../../include/matador/sql/internal/identifier_reader.hpp
|
||||||
../../include/matador/sql/internal/identifier_statement_binder.hpp
|
../../include/matador/sql/internal/identifier_statement_binder.hpp
|
||||||
|
../../include/matador/sql/internal/joined_collection_resolver_producer.hpp
|
||||||
../../include/matador/sql/internal/object_resolver_producer.hpp
|
../../include/matador/sql/internal/object_resolver_producer.hpp
|
||||||
../../include/matador/sql/internal/object_result_binder.hpp
|
../../include/matador/sql/internal/object_result_binder.hpp
|
||||||
../../include/matador/sql/internal/pk_reader.hpp
|
../../include/matador/sql/internal/pk_reader.hpp
|
||||||
|
|
@ -188,6 +193,7 @@ add_library(matador-orm STATIC
|
||||||
query/query_part.cpp
|
query/query_part.cpp
|
||||||
query/query_utils.cpp
|
query/query_utils.cpp
|
||||||
query/schema.cpp
|
query/schema.cpp
|
||||||
|
query/schema_utils.cpp
|
||||||
query/select_query_builder.cpp
|
query/select_query_builder.cpp
|
||||||
query/sequence_pk_generator.cpp
|
query/sequence_pk_generator.cpp
|
||||||
query/session.cpp
|
query/session.cpp
|
||||||
|
|
@ -208,9 +214,9 @@ add_library(matador-orm STATIC
|
||||||
sql/interface/query_result_reader.cpp
|
sql/interface/query_result_reader.cpp
|
||||||
sql/interface/statement_impl.cpp
|
sql/interface/statement_impl.cpp
|
||||||
sql/interface/statement_proxy.cpp
|
sql/interface/statement_proxy.cpp
|
||||||
sql/internal/joined_collection_resolver_producer.cpp
|
|
||||||
sql/internal/identifier_reader.cpp
|
sql/internal/identifier_reader.cpp
|
||||||
sql/internal/identifier_statement_binder.cpp
|
sql/internal/identifier_statement_binder.cpp
|
||||||
|
sql/internal/joined_collection_resolver_producer.cpp
|
||||||
sql/internal/object_resolver_producer.cpp
|
sql/internal/object_resolver_producer.cpp
|
||||||
sql/internal/object_result_binder.cpp
|
sql/internal/object_result_binder.cpp
|
||||||
sql/internal/query_result_pk_resolver.cpp
|
sql/internal/query_result_pk_resolver.cpp
|
||||||
|
|
@ -221,9 +227,6 @@ add_library(matador-orm STATIC
|
||||||
sql/resolver_service.cpp
|
sql/resolver_service.cpp
|
||||||
sql/statement.cpp
|
sql/statement.cpp
|
||||||
sql/statement_cache.cpp
|
sql/statement_cache.cpp
|
||||||
../../include/matador/query/delete_query_builder.hpp
|
|
||||||
../../include/matador/query/query_builder_utils.hpp
|
|
||||||
../../include/matador/query/insert_step.hpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(matador-orm
|
target_include_directories(matador-orm
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
#include "matador/query/schema_utils.hpp"
|
||||||
|
#include "matador/query/query.hpp"
|
||||||
|
#include "matador/query/criteria.hpp"
|
||||||
|
|
||||||
|
using namespace matador::utils;
|
||||||
|
|
||||||
|
namespace matador::query {
|
||||||
|
query_contexts to_query_contexts(const schema_node& node, const sql::dialect &d) {
|
||||||
|
query_contexts queries;
|
||||||
|
|
||||||
|
// SELECT all
|
||||||
|
queries.select_all = select(node.table())
|
||||||
|
.from(node.name())
|
||||||
|
.compile(d);
|
||||||
|
if (node.table().has_primary_key()) {
|
||||||
|
// SELECT one
|
||||||
|
queries.select_one = select(node.table())
|
||||||
|
.from(node.name())
|
||||||
|
.where(*node.table().primary_key_column() == _)
|
||||||
|
.compile(d);
|
||||||
|
// UPDATE one
|
||||||
|
auto update_set = query::update(node.table());
|
||||||
|
for (const auto &col: node.table().columns()) {
|
||||||
|
update_set.set(col, _);
|
||||||
|
}
|
||||||
|
queries.update_one = update_set.where(*node.table().primary_key_column() == _)
|
||||||
|
.compile(d);
|
||||||
|
// DELETE one
|
||||||
|
queries.delete_one = query::remove()
|
||||||
|
.from(node.name())
|
||||||
|
.where(*node.table().primary_key_column() == _)
|
||||||
|
.compile(d);
|
||||||
|
}
|
||||||
|
// INSERT one
|
||||||
|
std::vector<table_column> columns;
|
||||||
|
for (const auto &col: node.table().columns()) {
|
||||||
|
if (col.is_primary_key() && utils::is_constraint_set(col.attributes().options(), constraints::Identity)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
columns.push_back(col);
|
||||||
|
}
|
||||||
|
if (node.pk_generator().type() == utils::generator_type::Identity) {
|
||||||
|
queries.insert = query::insert()
|
||||||
|
.into(node.name(), columns)
|
||||||
|
.values(generator::placeholders(columns.size()))
|
||||||
|
.returning(node.table().primary_key_column()->as(node.table().primary_key_column()->column_name()))
|
||||||
|
.compile(d);
|
||||||
|
} else {
|
||||||
|
queries.insert = query::insert()
|
||||||
|
.into(node.name(), columns)
|
||||||
|
.values(generator::placeholders(columns.size()))
|
||||||
|
.compile(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
return queries;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,9 +3,8 @@
|
||||||
#include "matador/sql/backend_provider.hpp"
|
#include "matador/sql/backend_provider.hpp"
|
||||||
#include "matador/sql/dialect.hpp"
|
#include "matador/sql/dialect.hpp"
|
||||||
|
|
||||||
#include "matador/query/query.hpp"
|
|
||||||
#include "matador/query/generator.hpp"
|
|
||||||
#include "matador/query/basic_schema.hpp"
|
#include "matador/query/basic_schema.hpp"
|
||||||
|
#include "matador/query/schema_utils.hpp"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
|
@ -23,51 +22,7 @@ session::session(session_context&& ctx, const basic_schema &scm)
|
||||||
, resolver_service_(ctx.resolver_service) {
|
, resolver_service_(ctx.resolver_service) {
|
||||||
using namespace matador::utils;
|
using namespace matador::utils;
|
||||||
for (const auto &[type, node] : schema_) {
|
for (const auto &[type, node] : schema_) {
|
||||||
query_contexts queries;
|
query_contexts queries = to_query_contexts(node, dialect_);
|
||||||
|
|
||||||
// SELECT all
|
|
||||||
queries.select_all = select(node.table())
|
|
||||||
.from(node.name())
|
|
||||||
.compile(dialect_);
|
|
||||||
if (node.table().has_primary_key()) {
|
|
||||||
// SELECT one
|
|
||||||
queries.select_one = select(node.table())
|
|
||||||
.from(node.name())
|
|
||||||
.where(*node.table().primary_key_column() == _)
|
|
||||||
.compile(dialect_);
|
|
||||||
// UPDATE one
|
|
||||||
auto update_set = query::update(node.table());
|
|
||||||
for (const auto &col: node.table().columns()) {
|
|
||||||
update_set.set(col, _);
|
|
||||||
}
|
|
||||||
queries.update_one = update_set.where(*node.table().primary_key_column() == _)
|
|
||||||
.compile(dialect_);
|
|
||||||
// DELETE one
|
|
||||||
queries.delete_one = query::remove()
|
|
||||||
.from(node.name())
|
|
||||||
.where(*node.table().primary_key_column() == _)
|
|
||||||
.compile(dialect_);
|
|
||||||
}
|
|
||||||
// INSERT one
|
|
||||||
std::vector<table_column> columns;
|
|
||||||
for (const auto &col: node.table().columns()) {
|
|
||||||
if (col.is_primary_key() && utils::is_constraint_set(col.attributes().options(), constraints::Identity)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
columns.push_back(col);
|
|
||||||
}
|
|
||||||
if (node.pk_generator().type() == utils::generator_type::Identity) {
|
|
||||||
queries.insert = query::insert()
|
|
||||||
.into(node.name(), columns)
|
|
||||||
.values(generator::placeholders(columns.size()))
|
|
||||||
.returning(node.table().primary_key_column()->as(node.table().primary_key_column()->column_name()))
|
|
||||||
.compile(dialect_);
|
|
||||||
} else {
|
|
||||||
queries.insert = query::insert()
|
|
||||||
.into(node.name(), columns)
|
|
||||||
.values(generator::placeholders(columns.size()))
|
|
||||||
.compile(dialect_);
|
|
||||||
}
|
|
||||||
|
|
||||||
queries.insert.resolver = resolver_service_;
|
queries.insert.resolver = resolver_service_;
|
||||||
queries.update_one.resolver = resolver_service_;
|
queries.update_one.resolver = resolver_service_;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ CPMAddPackage("gh:catchorg/Catch2@3.14.0")
|
||||||
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)
|
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)
|
||||||
|
|
||||||
add_executable(OrmTests
|
add_executable(OrmTests
|
||||||
|
../utils/RecordingObserver.cpp
|
||||||
|
../utils/RecordingObserver.hpp
|
||||||
backend/test_backend_service.cpp
|
backend/test_backend_service.cpp
|
||||||
backend/test_backend_service.hpp
|
backend/test_backend_service.hpp
|
||||||
backend/test_connection.cpp
|
backend/test_connection.cpp
|
||||||
|
|
@ -16,6 +18,7 @@ add_executable(OrmTests
|
||||||
query/ColumnExpressionTest.cpp
|
query/ColumnExpressionTest.cpp
|
||||||
query/ColumnGeneratorTest.cpp
|
query/ColumnGeneratorTest.cpp
|
||||||
query/CriteriaTests.cpp
|
query/CriteriaTests.cpp
|
||||||
|
query/DeleteQueryBuilderTest.cpp
|
||||||
query/GeneratorTests.cpp
|
query/GeneratorTests.cpp
|
||||||
query/InsertQueryBuilderTest.cpp
|
query/InsertQueryBuilderTest.cpp
|
||||||
query/QueryBuilderTest.cpp
|
query/QueryBuilderTest.cpp
|
||||||
|
|
@ -32,8 +35,6 @@ add_executable(OrmTests
|
||||||
sql/StatementCacheTest.cpp
|
sql/StatementCacheTest.cpp
|
||||||
utils/auto_reset_event.cpp
|
utils/auto_reset_event.cpp
|
||||||
utils/auto_reset_event.hpp
|
utils/auto_reset_event.hpp
|
||||||
../utils/RecordingObserver.hpp
|
|
||||||
../utils/RecordingObserver.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(OrmTests matador-orm matador-core Catch2::Catch2WithMain)
|
target_link_libraries(OrmTests matador-orm matador-core Catch2::Catch2WithMain)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
|
#include "matador/object/object_ptr.hpp"
|
||||||
|
|
||||||
|
#include "matador/sql/backend_provider.hpp"
|
||||||
|
#include "matador/sql/connection.hpp"
|
||||||
|
#include "matador/sql/interface/connection_impl.hpp"
|
||||||
|
|
||||||
|
#include "matador/query/schema.hpp"
|
||||||
|
|
||||||
|
#include "matador/query/delete_query_builder.hpp"
|
||||||
|
|
||||||
|
#include "QueryFixture.hpp"
|
||||||
|
|
||||||
|
#include "../../models/author.hpp"
|
||||||
|
#include "../../models/book.hpp"
|
||||||
|
#include "../../models/airplane.hpp"
|
||||||
|
#include "../../models/flight.hpp"
|
||||||
|
#include "../../models/recipe.hpp"
|
||||||
|
|
||||||
|
using namespace matador::object;
|
||||||
|
using namespace matador::sql;
|
||||||
|
using namespace matador::query;
|
||||||
|
using namespace matador::utils;
|
||||||
|
using namespace matador::test;
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(QueryFixture, "delete query builder test", "[query][delete_query_builder]") {
|
||||||
|
schema scm;
|
||||||
|
auto result = scm.attach<airplane>("airplanes")
|
||||||
|
.and_then( [&scm] { return scm.attach<flight>("flights"); } );
|
||||||
|
REQUIRE(result);
|
||||||
|
|
||||||
|
const auto contexts_by_type = to_contexts_by_name(scm, db->dialect());
|
||||||
|
delete_query_builder<airplane> dqb(scm, contexts_by_type);
|
||||||
|
|
||||||
|
const auto a380 = make_object<airplane>(1, "Boeing", "A380" );
|
||||||
|
auto build_result = dqb.build(a380);
|
||||||
|
REQUIRE(build_result.is_ok());
|
||||||
|
|
||||||
|
const auto& stmts = *build_result;
|
||||||
|
REQUIRE(stmts.size() == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(QueryFixture, "Test delete builder has many", "[query][delete_query_builder][has_many]") {
|
||||||
|
schema scm;
|
||||||
|
const auto result = scm.attach<book>("books")
|
||||||
|
.and_then( [&scm] { return scm.attach<author>("authors"); } );
|
||||||
|
REQUIRE(result.is_ok());
|
||||||
|
|
||||||
|
auto s_king = make_object<author>(1, "Steven", "King", "21.9.1947", 1956, false);
|
||||||
|
|
||||||
|
s_king->books.push_back(make_object<book>(2, "Carrie", object_ptr<author>{}, 1974));
|
||||||
|
s_king->books.push_back(make_object<book>(3, "The Shining", object_ptr<author>{}, 1977));
|
||||||
|
s_king->books.push_back(make_object<book>(4, "It", object_ptr<author>{}, 1986));
|
||||||
|
s_king->books.push_back(make_object<book>(5, "Misery", object_ptr<author>{}, 1987));
|
||||||
|
s_king->books.push_back(make_object<book>(6, "The Dark Tower: The Gunslinger", object_ptr<author>{}, 1982));
|
||||||
|
|
||||||
|
const auto contexts_by_type = to_contexts_by_name(scm, db->dialect());
|
||||||
|
delete_query_builder<author> dqb(scm, contexts_by_type);
|
||||||
|
|
||||||
|
auto build_result = dqb.build(s_king);
|
||||||
|
REQUIRE(build_result.is_ok());
|
||||||
|
|
||||||
|
const auto& stmts = *build_result;
|
||||||
|
REQUIRE_FALSE(stmts.empty());
|
||||||
|
REQUIRE(stmts.size() == 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(QueryFixture, "Test delete builder has many to many", "[query][delete_query_builder][many_to_many]") {
|
||||||
|
schema scm;
|
||||||
|
const auto result = scm.attach<recipe>("recipes")
|
||||||
|
.and_then( [&scm] { return scm.attach<ingredient>("ingredients"); } );
|
||||||
|
REQUIRE(result.is_ok());
|
||||||
|
|
||||||
|
const std::vector ingredients {
|
||||||
|
make_object<ingredient>(1, "Apple"),
|
||||||
|
make_object<ingredient>(2, "Strawberry"),
|
||||||
|
make_object<ingredient>(3, "Pineapple"),
|
||||||
|
make_object<ingredient>(4, "Sugar"),
|
||||||
|
make_object<ingredient>(5, "Flour"),
|
||||||
|
make_object<ingredient>(6, "Butter"),
|
||||||
|
make_object<ingredient>(7, "Beans")
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector recipes {
|
||||||
|
make_object<recipe>(1, "Apple Pie", std::vector{ingredients[0], ingredients[3], ingredients[4]}),
|
||||||
|
make_object<recipe>(2, "Strawberry Cake", std::vector{ingredients[5], ingredients[6]}),
|
||||||
|
make_object<recipe>(3, "Pineapple Pie", std::vector{ingredients[0], ingredients[1], ingredients[2]})
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto contexts_by_type = to_contexts_by_name(scm, db->dialect());
|
||||||
|
delete_query_builder<recipe> dqb(scm, contexts_by_type);
|
||||||
|
|
||||||
|
auto build_result = dqb.build(recipes[0]);
|
||||||
|
REQUIRE(build_result.is_ok());
|
||||||
|
|
||||||
|
const auto& stmts = *build_result;
|
||||||
|
REQUIRE_FALSE(stmts.empty());
|
||||||
|
REQUIRE(stmts.size() == 7);
|
||||||
|
}
|
||||||
|
|
@ -6,13 +6,11 @@
|
||||||
#include "matador/sql/connection.hpp"
|
#include "matador/sql/connection.hpp"
|
||||||
#include "matador/sql/interface/connection_impl.hpp"
|
#include "matador/sql/interface/connection_impl.hpp"
|
||||||
|
|
||||||
#include "matador/query/query_contexts.hpp"
|
|
||||||
#include "matador/query/query.hpp"
|
|
||||||
#include "matador/query/schema.hpp"
|
#include "matador/query/schema.hpp"
|
||||||
|
|
||||||
#include "matador/query/insert_query_builder.hpp"
|
#include "matador/query/insert_query_builder.hpp"
|
||||||
|
|
||||||
#include "../backend/test_backend_service.hpp"
|
#include "QueryFixture.hpp"
|
||||||
|
|
||||||
#include "../../models/author.hpp"
|
#include "../../models/author.hpp"
|
||||||
#include "../../models/book.hpp"
|
#include "../../models/book.hpp"
|
||||||
|
|
@ -24,58 +22,15 @@ using namespace matador::object;
|
||||||
using namespace matador::sql;
|
using namespace matador::sql;
|
||||||
using namespace matador::query;
|
using namespace matador::query;
|
||||||
using namespace matador::utils;
|
using namespace matador::utils;
|
||||||
|
using namespace matador::test;
|
||||||
|
|
||||||
std::unordered_map<std::type_index, query_contexts> to_contexts_by_name(const schema& scm, const dialect& d) {
|
TEST_CASE_METHOD(QueryFixture, "insert query builder test", "[query][insert_query_builder]") {
|
||||||
std::unordered_map<std::type_index, query_contexts> contexts_by_type;
|
|
||||||
for (const auto &[type, node] : scm) {
|
|
||||||
query_contexts queries;
|
|
||||||
|
|
||||||
// SELECT all
|
|
||||||
queries.select_all = select(node.table())
|
|
||||||
.from(node.name())
|
|
||||||
.compile(d);
|
|
||||||
if (node.table().has_primary_key()) {
|
|
||||||
// SELECT one
|
|
||||||
queries.select_one = select(node.table())
|
|
||||||
.from(node.name())
|
|
||||||
.where(*node.table().primary_key_column() == _)
|
|
||||||
.compile(d);
|
|
||||||
// UPDATE one
|
|
||||||
auto update_set = update(node.table());
|
|
||||||
for (const auto &col: node.table().columns()) {
|
|
||||||
update_set.set(col, _);
|
|
||||||
}
|
|
||||||
queries.update_one = update_set.where(*node.table().primary_key_column() == _)
|
|
||||||
.compile(d);
|
|
||||||
// DELETE one
|
|
||||||
queries.delete_one = remove()
|
|
||||||
.from(node.name())
|
|
||||||
.where(*node.table().primary_key_column() == _)
|
|
||||||
.compile(d);
|
|
||||||
}
|
|
||||||
// INSERT one
|
|
||||||
queries.insert = insert()
|
|
||||||
.into(node.name(), node.table())
|
|
||||||
.values(generator::placeholders(node.table().columns().size()))
|
|
||||||
.compile(d);
|
|
||||||
|
|
||||||
contexts_by_type[node.node().type_index()] = queries;
|
|
||||||
}
|
|
||||||
|
|
||||||
return contexts_by_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("insert query builder test", "[query][insert_query_builder]") {
|
|
||||||
using namespace matador::test;
|
|
||||||
backend_provider::instance().register_backend("noop", std::make_unique<orm::test_backend_service>());
|
|
||||||
connection db("noop://noop.db");
|
|
||||||
|
|
||||||
schema scm;
|
schema scm;
|
||||||
auto result = scm.attach<airplane>("airplanes")
|
auto result = scm.attach<airplane>("airplanes")
|
||||||
.and_then( [&scm] { return scm.attach<flight>("flights"); } );
|
.and_then( [&scm] { return scm.attach<flight>("flights"); } );
|
||||||
REQUIRE(result);
|
REQUIRE(result);
|
||||||
|
|
||||||
const auto contexts_by_type = to_contexts_by_name(scm, db.dialect());
|
const auto contexts_by_type = to_contexts_by_name(scm, db->dialect());
|
||||||
insert_query_builder<airplane> iqb(scm, contexts_by_type);
|
insert_query_builder<airplane> iqb(scm, contexts_by_type);
|
||||||
|
|
||||||
const auto a380 = make_object<airplane>(1, "Boeing", "A380" );
|
const auto a380 = make_object<airplane>(1, "Boeing", "A380" );
|
||||||
|
|
@ -86,11 +41,7 @@ TEST_CASE("insert query builder test", "[query][insert_query_builder]") {
|
||||||
REQUIRE(stmts.size() == 1);
|
REQUIRE(stmts.size() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Test insert builder has many", "[query][insert_query_builder][has_many]") {
|
TEST_CASE_METHOD(QueryFixture, "Test insert builder has many", "[query][insert_query_builder][has_many]") {
|
||||||
using namespace matador::test;
|
|
||||||
backend_provider::instance().register_backend("noop", std::make_unique<orm::test_backend_service>());
|
|
||||||
connection db("noop://noop.db");
|
|
||||||
|
|
||||||
schema scm;
|
schema scm;
|
||||||
const auto result = scm.attach<book>("books")
|
const auto result = scm.attach<book>("books")
|
||||||
.and_then( [&scm] { return scm.attach<author>("authors"); } );
|
.and_then( [&scm] { return scm.attach<author>("authors"); } );
|
||||||
|
|
@ -104,7 +55,7 @@ TEST_CASE("Test insert builder has many", "[query][insert_query_builder][has_man
|
||||||
s_king->books.push_back(make_object<book>(5, "Misery", object_ptr<author>{}, 1987));
|
s_king->books.push_back(make_object<book>(5, "Misery", object_ptr<author>{}, 1987));
|
||||||
s_king->books.push_back(make_object<book>(6, "The Dark Tower: The Gunslinger", object_ptr<author>{}, 1982));
|
s_king->books.push_back(make_object<book>(6, "The Dark Tower: The Gunslinger", object_ptr<author>{}, 1982));
|
||||||
|
|
||||||
const auto contexts_by_type = to_contexts_by_name(scm, db.dialect());
|
const auto contexts_by_type = to_contexts_by_name(scm, db->dialect());
|
||||||
insert_query_builder<author> iqb(scm, contexts_by_type);
|
insert_query_builder<author> iqb(scm, contexts_by_type);
|
||||||
|
|
||||||
auto build_result = iqb.build(s_king);
|
auto build_result = iqb.build(s_king);
|
||||||
|
|
@ -115,11 +66,7 @@ TEST_CASE("Test insert builder has many", "[query][insert_query_builder][has_man
|
||||||
REQUIRE(stmts.size() == 6);
|
REQUIRE(stmts.size() == 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Test insert builder has many to many", "[query][insert_query_builder][many_to_many]") {
|
TEST_CASE_METHOD(QueryFixture, "Test insert builder has many to many", "[query][insert_query_builder][many_to_many]") {
|
||||||
using namespace matador::test;
|
|
||||||
backend_provider::instance().register_backend("noop", std::make_unique<orm::test_backend_service>());
|
|
||||||
connection db("noop://noop.db");
|
|
||||||
|
|
||||||
schema scm;
|
schema scm;
|
||||||
const auto result = scm.attach<recipe>("recipes")
|
const auto result = scm.attach<recipe>("recipes")
|
||||||
.and_then( [&scm] { return scm.attach<ingredient>("ingredients"); } );
|
.and_then( [&scm] { return scm.attach<ingredient>("ingredients"); } );
|
||||||
|
|
@ -141,7 +88,7 @@ TEST_CASE("Test insert builder has many to many", "[query][insert_query_builder]
|
||||||
make_object<recipe>(3, "Pineapple Pie", std::vector{ingredients[0], ingredients[1], ingredients[2]})
|
make_object<recipe>(3, "Pineapple Pie", std::vector{ingredients[0], ingredients[1], ingredients[2]})
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto contexts_by_type = to_contexts_by_name(scm, db.dialect());
|
const auto contexts_by_type = to_contexts_by_name(scm, db->dialect());
|
||||||
insert_query_builder<recipe> iqb(scm, contexts_by_type);
|
insert_query_builder<recipe> iqb(scm, contexts_by_type);
|
||||||
|
|
||||||
auto build_result = iqb.build(recipes[0]);
|
auto build_result = iqb.build(recipes[0]);
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@
|
||||||
|
|
||||||
#include "matador/sql/interface/connection_impl.hpp"
|
#include "matador/sql/interface/connection_impl.hpp"
|
||||||
|
|
||||||
|
#include "matador/query/basic_schema.hpp"
|
||||||
|
#include "matador/query/schema_utils.hpp"
|
||||||
|
|
||||||
namespace matador::test {
|
namespace matador::test {
|
||||||
|
|
||||||
QueryFixture::QueryFixture() {
|
QueryFixture::QueryFixture() {
|
||||||
|
|
@ -12,4 +15,12 @@ QueryFixture::QueryFixture() {
|
||||||
db = std::make_unique<sql::connection>("noop://noop.db");
|
db = std::make_unique<sql::connection>("noop://noop.db");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unordered_map<std::type_index, query::query_contexts> QueryFixture::to_contexts_by_name(const query::basic_schema& scm, const sql::dialect& d) {
|
||||||
|
std::unordered_map<std::type_index, query::query_contexts> contexts_by_type;
|
||||||
|
for (const auto &[type, node] : scm) {
|
||||||
|
contexts_by_type[node.node().type_index()] = to_query_contexts(node, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
return contexts_by_type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,8 +3,14 @@
|
||||||
|
|
||||||
#include "matador/sql/connection.hpp"
|
#include "matador/sql/connection.hpp"
|
||||||
|
|
||||||
|
#include "matador/query/query_contexts.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
namespace matador::query {
|
||||||
|
class basic_schema;
|
||||||
|
}
|
||||||
|
|
||||||
namespace matador::test {
|
namespace matador::test {
|
||||||
|
|
||||||
class QueryFixture {
|
class QueryFixture {
|
||||||
|
|
@ -12,6 +18,9 @@ public:
|
||||||
QueryFixture();
|
QueryFixture();
|
||||||
~QueryFixture() = default;
|
~QueryFixture() = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static std::unordered_map<std::type_index, query::query_contexts> to_contexts_by_name(const query::basic_schema& scm, const sql::dialect& d) ;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::unique_ptr<sql::connection> db;
|
std::unique_ptr<sql::connection> db;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue