resolve has one progress

This commit is contained in:
Sascha Kühl 2026-05-17 21:46:43 +02:00
parent 57703dfb67
commit 9f54716df2
16 changed files with 86 additions and 46 deletions

View File

@ -3,6 +3,8 @@
#include "matador/object/collection_resolver.hpp" #include "matador/object/collection_resolver.hpp"
#include <memory>
namespace matador::object { namespace matador::object {
class abstract_collection_resolver_factory { class abstract_collection_resolver_factory {
public: public:
@ -29,20 +31,20 @@ class abstract_joined_object_resolver_factory {
public: public:
virtual ~abstract_joined_object_resolver_factory() = default; virtual ~abstract_joined_object_resolver_factory() = default;
[[nodiscard]] virtual std::shared_ptr<abstract_joined_resolver> acquire_joined_object_resolver(const std::type_index &root_type, const std::type_index &element_type, const std::string &collection_name) const = 0; [[nodiscard]] virtual std::shared_ptr<abstract_type_resolver> acquire_joined_object_resolver(const std::type_index &root_type, const std::type_index &element_type, const std::string &collection_name) const = 0;
virtual void register_joined_object_resolver(std::shared_ptr<abstract_joined_resolver> &&resolver) = 0; virtual void register_joined_object_resolver(std::shared_ptr<abstract_type_resolver> &&resolver, const std::type_index& root_type, const std::string& join_column) = 0;
}; };
class joined_object_resolver_factory : public abstract_joined_object_resolver_factory { class joined_object_resolver_factory : public abstract_joined_object_resolver_factory {
public: public:
template<class Type> template<class Type>
[[nodiscard]] std::shared_ptr<joined_object_resolver<Type>> resolver(const std::type_index &root_type, const std::string &collection_name) const { [[nodiscard]] std::shared_ptr<object_resolver<Type>> resolver(const std::type_index &root_type, const std::string &collection_name) const {
const auto res = acquire_joined_object_resolver(root_type, typeid(Type), collection_name); const auto res = acquire_joined_object_resolver(root_type, typeid(Type), collection_name);
if (!res) { if (!res) {
return std::dynamic_pointer_cast<joined_object_resolver<Type>>(res); return std::dynamic_pointer_cast<object_resolver<Type>>(res);
} }
return std::dynamic_pointer_cast<joined_object_resolver<Type>>(res); return std::dynamic_pointer_cast<object_resolver<Type>>(res);
} }
}; };
} }

View File

@ -55,6 +55,7 @@ public:
} }
void reset() { proxy_.reset(); } void reset() { proxy_.reset(); }
void reset(const std::shared_ptr<object_proxy<Type>>& proxy) { proxy_ = proxy; }
operator bool() const { return valid(); } operator bool() const { return valid(); }
[[nodiscard]] bool valid() const { return proxy_ != nullptr && !proxy_->empty(); } [[nodiscard]] bool valid() const { return proxy_ != nullptr && !proxy_->empty(); }

View File

@ -19,11 +19,12 @@ public:
virtual std::shared_ptr<Type> resolve(const utils::identifier& id) = 0; virtual std::shared_ptr<Type> resolve(const utils::identifier& id) = 0;
}; };
template<typename Type> template<typename Type>
class joined_object_resolver : public abstract_joined_resolver { class joined_object_resolver : public abstract_joined_resolver, public object_resolver<Type> {
public: public:
joined_object_resolver(const std::type_index& root_type, const std::string& join_column) : abstract_joined_resolver(root_type, typeid(Type), join_column) {} joined_object_resolver(const std::type_index& root_type, const std::string& join_column)
: abstract_joined_resolver(root_type, typeid(Type), join_column) {}
virtual std::shared_ptr<Type> resolve(const utils::identifier& id) = 0; std::shared_ptr<Type> resolve(const utils::identifier& id) override = 0;
}; };
} }
#endif //MATADOR_OBJECT_LOADER_HPP #endif //MATADOR_OBJECT_LOADER_HPP

View File

@ -103,7 +103,7 @@ public:
[[nodiscard]] const std::unordered_map<std::type_index, std::unique_ptr<sql::object_resolver_producer>>& resolver_producers() const; [[nodiscard]] const std::unordered_map<std::type_index, std::unique_ptr<sql::object_resolver_producer>>& resolver_producers() const;
[[nodiscard]] const std::unordered_map<object::collection_composite_key, std::unique_ptr<sql::collection_resolver_producer>, object::collection_composite_key_hash>& collection_resolver_producers() const; [[nodiscard]] const std::unordered_map<object::collection_composite_key, std::unique_ptr<sql::collection_resolver_producer>, object::collection_composite_key_hash>& collection_resolver_producers() const;
[[nodiscard]] const std::unordered_map<object::collection_composite_key, std::unique_ptr<sql::object_resolver_producer>, object::collection_composite_key_hash>& joined_object_resolver_producers() const; [[nodiscard]] const std::unordered_map<object::collection_composite_key, std::unique_ptr<sql::joined_object_resolver_producer>, object::collection_composite_key_hash>& joined_object_resolver_producers() const;
protected: protected:
template<typename Type> template<typename Type>
@ -114,7 +114,7 @@ protected:
std::unordered_map<std::type_index, schema_node> schema_nodes_; std::unordered_map<std::type_index, schema_node> schema_nodes_;
std::unordered_map<std::type_index, std::unique_ptr<sql::object_resolver_producer>> resolver_producers_; std::unordered_map<std::type_index, std::unique_ptr<sql::object_resolver_producer>> resolver_producers_;
std::unordered_map<object::collection_composite_key, std::unique_ptr<sql::collection_resolver_producer>, object::collection_composite_key_hash> collection_resolver_producers_; std::unordered_map<object::collection_composite_key, std::unique_ptr<sql::collection_resolver_producer>, object::collection_composite_key_hash> collection_resolver_producers_;
std::unordered_map<object::collection_composite_key, std::unique_ptr<sql::object_resolver_producer>, object::collection_composite_key_hash> joined_object_resolver_producers_; std::unordered_map<object::collection_composite_key, std::unique_ptr<sql::joined_object_resolver_producer>, object::collection_composite_key_hash> joined_object_resolver_producers_;
}; };
} }
#endif //MATADOR_BASIC_SCHEMA_HPP #endif //MATADOR_BASIC_SCHEMA_HPP

View File

@ -22,6 +22,17 @@ protected:
sql::statement stmt_; sql::statement stmt_;
}; };
template<typename Type>
class query_joined_object_resolver : public object::joined_object_resolver<Type> {
public:
explicit query_joined_object_resolver(sql::statement &&stmt)
: stmt_(std::move(stmt)) {}
std::shared_ptr<Type> resolve(const utils::identifier &id) override;
protected:
sql::statement stmt_;
};
template<typename Type> template<typename Type>
std::shared_ptr<Type> query_object_resolver<Type>::resolve(const utils::identifier &id) { std::shared_ptr<Type> query_object_resolver<Type>::resolve(const utils::identifier &id) {
sql::identifier_statement_binder binder(stmt_); sql::identifier_statement_binder binder(stmt_);
@ -34,5 +45,16 @@ std::shared_ptr<Type> query_object_resolver<Type>::resolve(const utils::identifi
return *result; return *result;
} }
template<typename Type>
std::shared_ptr<Type> query_joined_object_resolver<Type>::resolve(const utils::identifier &id) {
sql::identifier_statement_binder binder(stmt_);
binder.bind(id);
auto result = stmt_.template fetch_one_raw<Type>();
if (!result) {
return nullptr;
}
return *result;
}
} }
#endif //MATADOR_QUERY_OBJECT_LOADER_HPP #endif //MATADOR_QUERY_OBJECT_LOADER_HPP

View File

@ -45,22 +45,17 @@ template<typename Type>
class query_joined_object_resolver_producer : public sql::joined_object_resolver_producer { class query_joined_object_resolver_producer : public sql::joined_object_resolver_producer {
public: public:
query_joined_object_resolver_producer() = default; query_joined_object_resolver_producer() = default;
query_joined_object_resolver_producer(basic_schema& repo, const table& tab, std::string pk_name, const std::type_index& root_type, std::string join_column) query_joined_object_resolver_producer(basic_schema& repo, const table& tab, std::string pk_name, const std::type_index& root_type, const std::string &join_column)
: joined_object_resolver_producer(root_type, typeid(Type), join_column) : joined_object_resolver_producer(root_type, typeid(Type), join_column)
, repo_(repo) , repo_(repo)
, table_(tab) , table_(tab)
, pk_name_(std::move(pk_name)) {} , pk_name_(std::move(pk_name)) {}
std::shared_ptr<object::abstract_joined_resolver> produce(sql::statement&& stmt) override { std::shared_ptr<object::abstract_type_resolver> produce(sql::statement&& stmt) override {
return std::make_shared<query_object_resolver<Type>>(std::move(stmt)); return std::make_shared<query_object_resolver<Type>>(std::move(stmt));
} }
utils::result<sql::query_context, utils::error> build_query(const sql::dialect& d) override { utils::result<sql::query_context, utils::error> build_query(const sql::dialect& /*d*/) override;
const auto *pk_column = table_[pk_name_];
const auto *join_column = table_[collection_name()];
return utils::ok(sql::query_context{});
}
private: private:
basic_schema& repo_; basic_schema& repo_;
@ -162,9 +157,11 @@ public:
throw query_builder_exception{error_code::MissingPrimaryKey, "Missing primary key"}; throw query_builder_exception{error_code::MissingPrimaryKey, "Missing primary key"};
} }
auto producer = std::make_unique<query_object_resolver_producer<typename Pointer::value_type>>( auto producer = std::make_unique<query_joined_object_resolver_producer<typename Pointer::value_type>>(
schema_, schema_,
it->second.table(), it->second.table(),
it->second.node().info().primary_key_attribute()->name(),
root_type_,
join_column); join_column);
const object::collection_composite_key key{root_type_, typeid(Pointer), join_column}; const object::collection_composite_key key{root_type_, typeid(Pointer), join_column};
schema_.joined_object_resolver_producers_[key] = std::move(producer); schema_.joined_object_resolver_producers_[key] = std::move(producer);
@ -338,8 +335,7 @@ utils::result<void, utils::error> schema::drop_table(const sql::connection &conn
} }
template<typename Type> template<typename Type>
utils::result<sql::query_context, utils::error> query_object_resolver_producer<Type>:: utils::result<sql::query_context, utils::error> query_object_resolver_producer<Type>::build_query(const sql::dialect &d) {
build_query(const sql::dialect &d) {
producer_creator pc(repo_, typeid(Type)); producer_creator pc(repo_, typeid(Type));
Type obj; Type obj;
access::process(pc, obj); access::process(pc, obj);
@ -354,6 +350,22 @@ build_query(const sql::dialect &d) {
return utils::ok(result->compile(d)); return utils::ok(result->compile(d));
} }
template<typename Type>
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_);
const auto *join_column = table_[collection_name()];
const auto result = qb.build<Type>(*join_column == utils::_);
if (!result) {
return utils::failure(result.err());
}
return utils::ok(result->compile(d));
}
template <typename Type> template <typename Type>
void schema_observer<Type>::on_attach(const object::repository_node &node, const Type &/*prototype*/) const { void schema_observer<Type>::on_attach(const object::repository_node &node, const Type &/*prototype*/) const {
primary_key_generator_finder finder; primary_key_generator_finder finder;

View File

@ -32,7 +32,7 @@ class joined_object_resolver_producer {
public: public:
virtual ~joined_object_resolver_producer() = default; virtual ~joined_object_resolver_producer() = default;
virtual utils::result<query_context, utils::error> build_query(const dialect& d) = 0; virtual utils::result<query_context, utils::error> build_query(const dialect& d) = 0;
virtual std::shared_ptr<object::abstract_joined_resolver> produce(statement&& stmt) = 0; virtual std::shared_ptr<object::abstract_type_resolver> produce(statement&& stmt) = 0;
[[nodiscard]] const std::type_index& root_type() const; [[nodiscard]] const std::type_index& root_type() const;
[[nodiscard]] const std::type_index& type() const; [[nodiscard]] const std::type_index& type() const;

View File

@ -130,16 +130,16 @@ void query_result_impl::on_belongs_to(const char*, Pointer& x, const utils::fore
template <class PointerType> template <class PointerType>
void query_result_impl::on_has_one(const char*, object::object_ptr<PointerType>& x, const char *join_column, const utils::foreign_attributes& attr) { void query_result_impl::on_has_one(const char*, object::object_ptr<PointerType>& x, const char *join_column, const utils::foreign_attributes& attr) {
const auto resolver = resolver_->collection_resolver<PointerType>(result_type_, join_column); const auto resolver = resolver_->joined_object_resolver<PointerType>(result_type_, join_column);
if (attr.fetch() == utils::fetch_type::Lazy) { if (attr.fetch() == utils::fetch_type::Lazy) {
x = object::object_ptr<PointerType>(std::make_shared<object::object_proxy<PointerType>>(resolver, id_reader_.read(x, column_index_++))); x.reset(std::make_shared<object::object_proxy<PointerType>>(resolver, utils::identifier{}));
} else { } else {
auto obj = std::make_shared<PointerType>(); auto obj = std::make_shared<PointerType>();
const auto ti = std::type_index(typeid(*x)); const auto ti = std::type_index(typeid(*x));
type_stack_.push(ti); type_stack_.push(ti);
access::process(*this, *obj); access::process(*this, *obj);
type_stack_.pop(); type_stack_.pop();
x = object::object_ptr<PointerType>(std::make_shared<object::object_proxy<PointerType>>(resolver, obj)); x.reset(std::make_shared<object::object_proxy<PointerType>>(resolver, obj));
} }
} }

View File

@ -33,13 +33,13 @@ private:
class producer_joined_object_resolver_factory : public object::joined_object_resolver_factory { class producer_joined_object_resolver_factory : public object::joined_object_resolver_factory {
public: public:
[[nodiscard]] std::shared_ptr<object::abstract_joined_resolver> acquire_joined_object_resolver(const std::type_index& root_type, [[nodiscard]] std::shared_ptr<object::abstract_type_resolver> acquire_joined_object_resolver(const std::type_index& root_type,
const std::type_index& element_type, const std::type_index& element_type,
const std::string& collection_name) const override; const std::string& collection_name) const override;
void register_joined_object_resolver(std::shared_ptr<object::abstract_joined_resolver>&& resolver) override; void register_joined_object_resolver(std::shared_ptr<object::abstract_type_resolver>&& resolver, const std::type_index& root_type, const std::string& join_column) override;
private: private:
std::unordered_map<object::collection_composite_key, std::shared_ptr<object::abstract_joined_resolver>, object::collection_composite_key_hash> resolvers_; std::unordered_map<object::collection_composite_key, std::shared_ptr<object::abstract_type_resolver>, object::collection_composite_key_hash> resolvers_;
}; };
} }
#endif //MATADOR_RESOLVER_FACTORY_HPP #endif //MATADOR_RESOLVER_FACTORY_HPP

View File

@ -17,18 +17,18 @@ public:
} }
template<class Type> template<class Type>
std::shared_ptr<object::collection_resolver<Type>> joined_object_resolver(const std::type_index &root_type, const std::string &join_column) const { std::shared_ptr<object::object_resolver<Type>> joined_object_resolver(const std::type_index &root_type, const std::string &join_column) const {
return joined_object_resolver_factory_.resolver<Type>(root_type, join_column); return joined_object_resolver_factory_.resolver<Type>(root_type, join_column);
} }
void register_object_resolver(std::shared_ptr<object::abstract_type_resolver> &&resolver); void register_object_resolver(std::shared_ptr<object::abstract_type_resolver> &&resolver);
void register_collection_resolver(std::shared_ptr<object::abstract_joined_resolver>&& resolver); void register_collection_resolver(std::shared_ptr<object::abstract_joined_resolver>&& resolver);
void register_joined_object_resolver(std::shared_ptr<object::abstract_type_resolver>&& resolver); void register_joined_object_resolver(std::shared_ptr<object::abstract_type_resolver>&& resolver, const std::type_index& root_type, const std::string& join_column);
private: private:
sql::producer_resolver_factory object_resolver_factory_; producer_resolver_factory object_resolver_factory_;
sql::producer_collection_resolver_factory collection_resolver_factory_; producer_collection_resolver_factory collection_resolver_factory_;
sql::producer_resolver_factory joined_object_resolver_factory_; producer_joined_object_resolver_factory joined_object_resolver_factory_;
}; };
} }
#endif // MATADOR_RESOLVER_SERVICE_HPP #endif // MATADOR_RESOLVER_SERVICE_HPP

View File

@ -1,4 +1,4 @@
#include "matador/object/abstract_collection_resolver.hpp" #include "matador/object/abstract_joined_resolver.hpp"
namespace matador::object { namespace matador::object {
const std::type_index& abstract_joined_resolver::root_type() const { const std::type_index& abstract_joined_resolver::root_type() const {

View File

@ -145,7 +145,7 @@ const std::unordered_map<object::collection_composite_key, std::unique_ptr<sql::
return collection_resolver_producers_; return collection_resolver_producers_;
} }
const std::unordered_map<object::collection_composite_key, std::unique_ptr<sql::object_resolver_producer>, object::collection_composite_key_hash>& basic_schema::joined_object_resolver_producers() const { const std::unordered_map<object::collection_composite_key, std::unique_ptr<sql::joined_object_resolver_producer>, object::collection_composite_key_hash>& basic_schema::joined_object_resolver_producers() const {
return joined_object_resolver_producers_; return joined_object_resolver_producers_;
} }

View File

@ -93,12 +93,12 @@ session::session(session_context&& ctx, const basic_schema &scm)
} }
} }
for (const auto &pair : schema_.joined_object_resolver_producers()) { for (const auto &pair : schema_.joined_object_resolver_producers()) {
auto res = pair.second->build_query(dialect_).and_then([this](sql::query_context&& query_ctx) -> result<sql::statement, error> { auto res = pair.second->build_query(dialect_).and_then([this](sql::query_context&& query_ctx) -> result<sql::statement, error> {
query_ctx.resolver = resolver_service_; query_ctx.resolver = resolver_service_;
return cache_.acquire(query_ctx); return cache_.acquire(query_ctx);
}).and_then([&pair, this](sql::statement&& stmt) -> result<void, error> { }).and_then([&pair, this](sql::statement&& stmt) -> result<void, error> {
resolver_service_->register_collection_resolver(pair.second->produce(std::move(stmt), *resolver_service_)); resolver_service_->register_joined_object_resolver(pair.second->produce(std::move(stmt)), pair.second->root_type(), pair.second->collection_name());
return ok<void>(); return ok<void>();
}).or_else([](const auto &err) { }).or_else([](const auto &err) {

View File

@ -26,9 +26,9 @@ void producer_collection_resolver_factory::register_collection_resolver(std::sha
resolvers_[key] = std::move(resolver); resolvers_[key] = std::move(resolver);
} }
std::shared_ptr<object::abstract_joined_resolver> producer_joined_object_resolver_factory::acquire_joined_object_resolver(const std::type_index& root_type, std::shared_ptr<object::abstract_type_resolver> producer_joined_object_resolver_factory::acquire_joined_object_resolver(const std::type_index& root_type,
const std::type_index& element_type, const std::type_index& element_type,
const std::string& collection_name) const { const std::string& collection_name) const {
const object::collection_composite_key key{root_type, element_type, collection_name}; const object::collection_composite_key key{root_type, element_type, collection_name};
if (const auto it = resolvers_.find(key); it != resolvers_.end()) { if (const auto it = resolvers_.find(key); it != resolvers_.end()) {
return it->second; return it->second;
@ -36,8 +36,8 @@ std::shared_ptr<object::abstract_joined_resolver> producer_joined_object_resolve
return nullptr; return nullptr;
} }
void producer_joined_object_resolver_factory::register_joined_object_resolver(std::shared_ptr<object::abstract_joined_resolver>&& resolver) { void producer_joined_object_resolver_factory::register_joined_object_resolver(std::shared_ptr<object::abstract_type_resolver>&& resolver, const std::type_index& root_type, const std::string& join_column) {
const object::collection_composite_key key{resolver->root_type(), resolver->type(), resolver->collection_name()}; const object::collection_composite_key key{root_type, resolver->type(), join_column};
resolvers_[key] = std::move(resolver); resolvers_[key] = std::move(resolver);
} }
} // namespace matador::sql } // namespace matador::sql

View File

@ -9,7 +9,7 @@ void resolver_service::register_collection_resolver(std::shared_ptr<object::abst
collection_resolver_factory_.register_collection_resolver(std::move(resolver)); collection_resolver_factory_.register_collection_resolver(std::move(resolver));
} }
void resolver_service::register_joined_object_resolver(std::shared_ptr<object::abstract_type_resolver>&& resolver) { void resolver_service::register_joined_object_resolver(std::shared_ptr<object::abstract_type_resolver>&& resolver, const std::type_index& root_type, const std::string& join_column) {
joined_object_resolver_factory_.register_object_resolver(std::move(resolver)); joined_object_resolver_factory_.register_joined_object_resolver(std::move(resolver), root_type, join_column);
} }
} // namespace matador::query } // namespace matador::query

View File

@ -21,7 +21,7 @@ TEST_CASE_METHOD(SessionFixture, "Test insert object with has_one relation", "[s
session ses({bus, connection::dns, 4}, schema); session ses({bus, connection::dns, 4}, schema);
const auto u = make_object<user_identity>("user1", "password"); const auto u = make_object<user_identity>("user1", "password");
const auto us = make_object<user_session_identity>("session1", u); auto us = make_object<user_session_identity>("session1", u);
REQUIRE(u.is_transient()); REQUIRE(u.is_transient());
REQUIRE(us.is_transient()); REQUIRE(us.is_transient());
@ -31,5 +31,7 @@ TEST_CASE_METHOD(SessionFixture, "Test insert object with has_one relation", "[s
const auto user_result = ses.find<user_identity>(u->id); const auto user_result = ses.find<user_identity>(u->id);
REQUIRE(user_result.is_ok()); REQUIRE(user_result.is_ok());
REQUIRE(user_result.value()->session->session_token == "session1"); // REQUIRE(user_result.value()->session->session_token == "session1");
us = user_result.value()->session;
const auto token = us->session_token;
} }