has many primitive collection resolver

This commit is contained in:
Sascha Kühl 2026-05-11 20:54:48 +02:00
parent a714cd2a53
commit 68eb2b6a6e
4 changed files with 94 additions and 4 deletions

View File

@ -31,6 +31,46 @@ protected:
std::shared_ptr<object::object_resolver<typename Type::value_type>> resolver_;
};
template<typename Type>
class query_collection_primitive_resolver : public object::collection_resolver<Type> {
public:
explicit query_collection_primitive_resolver(sql::statement &&stmt,
const std::type_index& root_type,
std::string join_column//,
/*const std::shared_ptr<object::object_resolver<typename Type::value_type>> &resolver*/)
: object::collection_resolver<Type>(root_type, join_column)
, stmt_(std::move(stmt))
// , resolver_(resolver)
{}
std::vector<Type> resolve(const utils::identifier &id) override {
sql::identifier_statement_binder binder(stmt_);
binder.bind(id);
auto result = stmt_.fetch();
if (!result) {
return {};
}
std::vector<Type> out;
for (auto &r : *result) {
// Todo: convert the first value of record into an utils::identifier
// then create a object_proxy<Type>(resolver, identifier)
if (r.size() != 1) {
continue;
}
auto val = r.at<Type>(0);
if (val.has_value()) {
out.push_back(*val);
}
}
return out;
}
protected:
sql::statement stmt_;
std::type_index index{typeid(Type)};
// std::shared_ptr<object::object_resolver<typename Type::value_type>> resolver_;
};
struct value_to_identifier{
void operator()(const int8_t &x) { assign(x); }
void operator()(const int16_t &x) { assign(x); }

View File

@ -54,6 +54,41 @@ private:
std::string pk_name_;
};
template<typename Type>
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<sql::query_context, utils::error> 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<object::abstract_collection_resolver> produce(sql::statement&& stmt, const sql::resolver_service& rs) override {
// const auto object_resolver = rs.object_resolver<typename Type::value_type>();
return std::make_shared<query_collection_primitive_resolver<Type>>(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<class CollectionType>
void on_has_many(const char * /*id*/, CollectionType &/*cont*/, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/, std::enable_if_t<!object::is_object_ptr<typename CollectionType::value_type>::value> * = nullptr) {}
void on_has_many(const char *id, CollectionType &/*cont*/, const char *join_column, const utils::foreign_attributes &/*attr*/, std::enable_if_t<!object::is_object_ptr<typename CollectionType::value_type>::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<query_collection_primitive_resolver_producer<typename CollectionType::value_type>>(
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<class CollectionType>
void on_has_many_to_many(const char *id, CollectionType &, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &/*attr*/) {

View File

@ -1,5 +1,3 @@
#include <utility>
#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<std::string> expected_colors{"red", "green", "blue"};
for (const auto &cstr: clist->colors) {
REQUIRE(std::find(expected_colors.begin(), expected_colors.end(), cstr) != expected_colors.end());
}
}