diff --git a/include/matador/object/abstract_collection_resolver.hpp b/include/matador/object/abstract_collection_resolver.hpp index d5482b5..84d2ded 100644 --- a/include/matador/object/abstract_collection_resolver.hpp +++ b/include/matador/object/abstract_collection_resolver.hpp @@ -13,7 +13,7 @@ public: [[nodiscard]] const std::type_index& type() const; [[nodiscard]] const std::string& collection_name() const; - protected: +protected: explicit abstract_collection_resolver(const std::type_index& root_type, const std::type_index& type, std::string collection_name); public: diff --git a/include/matador/query/query_collection_resolver.hpp b/include/matador/query/query_collection_resolver.hpp index 6e854ff..e2dfacc 100644 --- a/include/matador/query/query_collection_resolver.hpp +++ b/include/matador/query/query_collection_resolver.hpp @@ -31,6 +31,46 @@ protected: std::shared_ptr> resolver_; }; +template +class query_collection_primitive_resolver : public object::collection_resolver { +public: + explicit query_collection_primitive_resolver(sql::statement &&stmt, + const std::type_index& root_type, + std::string join_column//, + /*const std::shared_ptr> &resolver*/) + : object::collection_resolver(root_type, join_column) + , stmt_(std::move(stmt)) + // , resolver_(resolver) + {} + + std::vector resolve(const utils::identifier &id) override { + sql::identifier_statement_binder binder(stmt_); + binder.bind(id); + + auto result = stmt_.fetch(); + if (!result) { + return {}; + } + std::vector out; + for (auto &r : *result) { + // Todo: convert the first value of record into an utils::identifier + // then create a object_proxy(resolver, identifier) + if (r.size() != 1) { + continue; + } + auto val = r.at(0); + if (val.has_value()) { + out.push_back(*val); + } + } + return out; + } +protected: + sql::statement stmt_; + std::type_index index{typeid(Type)}; + // std::shared_ptr> resolver_; +}; + struct value_to_identifier{ void operator()(const int8_t &x) { assign(x); } void operator()(const int16_t &x) { assign(x); } diff --git a/include/matador/query/schema.hpp b/include/matador/query/schema.hpp index 557b2e3..45721e8 100644 --- a/include/matador/query/schema.hpp +++ b/include/matador/query/schema.hpp @@ -54,6 +54,41 @@ private: std::string pk_name_; }; +template +class query_collection_primitive_resolver_producer : public sql::collection_resolver_producer { +public: + query_collection_primitive_resolver_producer() = default; + query_collection_primitive_resolver_producer(const basic_schema& repo, const table& tab, std::string value_name, const std::type_index& root_type, std::string join_column) + : collection_resolver_producer(root_type, typeid(Type), std::move(join_column)) + , repo_(repo) + , table_(tab) + , value_name_(std::move(value_name)) + {} + + utils::result build_query(const sql::dialect& d) override { + const auto *value_column = table_[value_name_]; + const auto *join_column = table_[collection_name()]; + + const auto stmt = select({*value_column}) + .from(table_) + .where(*join_column == utils::_) + .compile(d); + + return utils::ok(stmt); + } + + std::shared_ptr produce(sql::statement&& stmt, const sql::resolver_service& rs) override { + // const auto object_resolver = rs.object_resolver(); + + return std::make_shared>(std::move(stmt), root_type(), collection_name()/*, object_resolver*/); + } + +private: + const basic_schema& repo_; + const table& table_; + std::string value_name_; +}; + class producer_creator final { public: producer_creator(basic_schema& schema, const std::type_index& root_type) @@ -94,7 +129,20 @@ public: } template - void on_has_many(const char * /*id*/, CollectionType &/*cont*/, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/, std::enable_if_t::value> * = nullptr) {} + void on_has_many(const char *id, CollectionType &/*cont*/, const char *join_column, const utils::foreign_attributes &/*attr*/, std::enable_if_t::value> * = nullptr) { + const auto it = schema_.find(id); + if (it == schema_.end()) { + throw query_builder_exception{error_code::UnknownType, "Unknown type" + std::string{id}}; + } + auto producer = std::make_unique>( + schema_, + it->second.table(), + "value", + root_type_, + join_column); + const object::collection_composite_key key{root_type_, typeid(typename CollectionType::value_type), join_column}; + schema_.collection_resolver_producers_[key] = std::move(producer); + } template void on_has_many_to_many(const char *id, CollectionType &, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &/*attr*/) { diff --git a/test/backends/SessionInsertHasMany.cpp b/test/backends/SessionInsertHasMany.cpp index b8e0085..4502cb2 100644 --- a/test/backends/SessionInsertHasMany.cpp +++ b/test/backends/SessionInsertHasMany.cpp @@ -1,5 +1,3 @@ -#include - #include "catch2/catch_test_macros.hpp" #include "SessionFixture.hpp" @@ -207,4 +205,8 @@ TEST_CASE_METHOD(SessionFixture, "Test insert object with has many primitive rel auto clist = *colorlist_result; REQUIRE(clist.is_persistent()); REQUIRE(clist->colors.size() == 3); + std::vector expected_colors{"red", "green", "blue"}; + for (const auto &cstr: clist->colors) { + REQUIRE(std::find(expected_colors.begin(), expected_colors.end(), cstr) != expected_colors.end()); + } } \ No newline at end of file