collection_resolver progress
This commit is contained in:
parent
602b77e67b
commit
bcec740d60
|
|
@ -111,7 +111,8 @@ utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> postgres_co
|
|||
|
||||
return utils::ok(std::make_unique<sql::query_result_impl>(std::make_unique<postgres_result_reader>(res),
|
||||
std::move(prototype),
|
||||
context.resolver));
|
||||
context.resolver,
|
||||
context.result_type));
|
||||
}
|
||||
|
||||
std::string postgres_connection::generate_statement_name(const sql::query_context &query) {
|
||||
|
|
|
|||
|
|
@ -60,7 +60,10 @@ utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> postgres_st
|
|||
return utils::failure(make_error(sql::error_code::FETCH_FAILED, res, db_, "Failed to fetch statement", query_.sql));
|
||||
}
|
||||
|
||||
return utils::ok(std::make_unique<sql::query_result_impl>(std::make_unique<postgres_result_reader>(res), query_.prototype, query_.resolver));
|
||||
return utils::ok(std::make_unique<sql::query_result_impl>(std::make_unique<postgres_result_reader>(res),
|
||||
query_.prototype,
|
||||
query_.resolver,
|
||||
query_.result_type));
|
||||
}
|
||||
|
||||
std::unique_ptr<utils::attribute_writer> postgres_statement::create_binder() const {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
#include "matador/object/repository.hpp"
|
||||
#include "matador/object/collection.hpp"
|
||||
|
||||
#include "matador/sql/resolver_service.hpp"
|
||||
|
||||
#include "matador/logger/log_manager.hpp"
|
||||
|
||||
|
|
@ -131,6 +134,12 @@ int main() {
|
|||
// logger::default_min_log_level(logger::log_level::LVL_DEBUG);
|
||||
// logger::add_log_sink(logger::create_stdout_sink());
|
||||
|
||||
sql::resolver_service rs;
|
||||
|
||||
std::weak_ptr cr = rs.collection_resolver<object::object_ptr<names>>( typeid(person), "names" );
|
||||
utils::identifier id{1};
|
||||
|
||||
object::collection_proxy cp(cr, id);
|
||||
{
|
||||
// has_many with builtin-type
|
||||
object::repository repo;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
#ifndef MATADOR_NET_OS_HPP
|
||||
#define MATADOR_NET_OS_HPP
|
||||
|
||||
#include "matador/net/export.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#if _WIN32
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
#ifndef MATADOR_COLLECTION_PROXY_HPP
|
||||
#define MATADOR_COLLECTION_PROXY_HPP
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "matador/object/collection_resolver.hpp"
|
||||
|
||||
#include "matador/utils/identifier.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
namespace matador::object {
|
||||
|
|
@ -33,13 +34,15 @@ public:
|
|||
return owner_id_;
|
||||
}
|
||||
const std::vector<Type>& items() const {
|
||||
resolve();
|
||||
return items_;
|
||||
}
|
||||
std::vector<Type>& items() {
|
||||
resolve();
|
||||
return items_;
|
||||
}
|
||||
private:
|
||||
void resolve() const {
|
||||
void resolve() {
|
||||
if (loaded_) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -53,6 +56,7 @@ private:
|
|||
}
|
||||
|
||||
items_ = resolver->resolve(owner_id_);
|
||||
loaded_ = true;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class collection_resolver_factory : public abstract_collection_resolver_factory
|
|||
public:
|
||||
template<class Type>
|
||||
[[nodiscard]] std::shared_ptr<collection_resolver<Type>> resolver(const std::type_index &root_type, const std::string &collection_name) const {
|
||||
const auto res = acquire_collection_resolver(typeid(Type), root_type, collection_name);
|
||||
const auto res = acquire_collection_resolver(root_type, typeid(Type), collection_name);
|
||||
if (!res) {
|
||||
return std::dynamic_pointer_cast<collection_resolver<Type>>(res);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ protected:
|
|||
public:
|
||||
template < class Type >
|
||||
utils::result<sql::query_result<Type>, utils::error> fetch_all(sql::executor &exec) {
|
||||
auto result = fetch(exec);
|
||||
auto result = fetch(exec, typeid(Type));
|
||||
if (!result.is_ok()) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
|
|
@ -40,9 +40,8 @@ public:
|
|||
[[nodiscard]] utils::result<sql::query_result<sql::record>, utils::error> fetch_all(const sql::executor &exec) const;
|
||||
|
||||
template < class Type >
|
||||
utils::result<object::object_ptr<Type>, utils::error> fetch_one(sql::executor &exec)
|
||||
{
|
||||
auto result = fetch(exec);
|
||||
utils::result<object::object_ptr<Type>, utils::error> fetch_one(sql::executor &exec) {
|
||||
auto result = fetch(exec, typeid(Type));
|
||||
if (!result.is_ok()) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
|
|
@ -83,7 +82,7 @@ public:
|
|||
[[nodiscard]] sql::query_context compile(const sql::dialect &d) const;
|
||||
|
||||
private:
|
||||
[[nodiscard]] utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetch(const sql::executor &exec) const;
|
||||
[[nodiscard]] utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetch(const sql::executor &exec, const std::type_index& index) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,6 @@
|
|||
#include "matador/sql/internal/identifier_statement_binder.hpp"
|
||||
#include "matador/sql/statement.hpp"
|
||||
|
||||
#include "matador/query/table.hpp"
|
||||
#include "matador/query/select_query_builder.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
class executor;
|
||||
}
|
||||
|
|
@ -17,47 +14,33 @@ namespace matador::query {
|
|||
template<typename Type>
|
||||
class query_collection_resolver : public object::collection_resolver<Type> {
|
||||
public:
|
||||
explicit query_collection_resolver(const basic_schema &repo, sql::executor& exec, const table &tab, std::string pk_name, const std::type_index& root_type, std::string join_column)
|
||||
explicit query_collection_resolver(sql::statement &&stmt, const std::type_index& root_type, std::string join_column)
|
||||
: object::collection_resolver<Type>(root_type, join_column)
|
||||
, executor_(exec)
|
||||
, schema_(repo)
|
||||
, table_(tab)
|
||||
, pk_name_(std::move(pk_name))
|
||||
, join_column_(std::move(join_column))
|
||||
, stmt_(std::move(stmt))
|
||||
{}
|
||||
|
||||
std::vector<Type> resolve(const utils::identifier &id) override;
|
||||
protected:
|
||||
sql::executor& executor_;
|
||||
const basic_schema &schema_;
|
||||
const table &table_;
|
||||
std::string pk_name_;
|
||||
std::string join_column_;
|
||||
sql::statement stmt_;
|
||||
std::type_index index{typeid(Type)};
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
std::vector<Type> query_collection_resolver<Type>::resolve(const utils::identifier &id) {
|
||||
const auto *pk_column = table_[pk_name_];
|
||||
const auto *join_column = table_[join_column_];
|
||||
|
||||
auto stmt = query::select({*pk_column})
|
||||
.from(table_)
|
||||
.where(*join_column == id)
|
||||
.prepare(executor_);
|
||||
|
||||
if (!stmt) {
|
||||
return {};
|
||||
}
|
||||
|
||||
sql::identifier_statement_binder binder(*stmt);
|
||||
sql::identifier_statement_binder binder(stmt_);
|
||||
binder.bind(id);
|
||||
|
||||
auto result = stmt->template fetch_one_raw<Type>();
|
||||
auto result = stmt_.fetch();
|
||||
if (!result) {
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
std::vector<Type> out;
|
||||
for (const auto &i: *result) {
|
||||
// Todo: convert the first value of record into an utils::identifier
|
||||
// then create a object_proxy<Type>(resolver, identifier)
|
||||
// out.emplace_back(resolver, identifier);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
#endif //MATADOR_QUERY_CONTAINER_RESOLVER_HPP
|
||||
|
|
@ -51,7 +51,19 @@ public:
|
|||
{}
|
||||
|
||||
std::shared_ptr<object::abstract_collection_resolver> produce(sql::executor &exec) override {
|
||||
return std::make_shared<query_collection_resolver<Type>>(repo_, exec, table_, std::move(pk_name_), root_type(), collection_name());
|
||||
const auto *pk_column = table_[pk_name_];
|
||||
const auto *join_column = table_[collection_name()];
|
||||
|
||||
auto stmt = query::select({*pk_column})
|
||||
.from(table_)
|
||||
.where(*join_column == utils::_)
|
||||
.prepare(exec);
|
||||
|
||||
if (!stmt) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return std::make_shared<query_collection_resolver<Type>>(stmt.release(), root_type(), collection_name());
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -201,13 +213,13 @@ public:
|
|||
throw query_builder_exception{query_build_error::MissingPrimaryKey};
|
||||
}
|
||||
|
||||
auto producer = std::make_unique<query_collection_resolver_producer<typename CollectionType::value_type::value_type>>(
|
||||
auto producer = std::make_unique<query_collection_resolver_producer<typename CollectionType::value_type>>(
|
||||
schema_,
|
||||
it->second.table(),
|
||||
it->second.node().info().primary_key_attribute()->name(),
|
||||
root_type_,
|
||||
join_column);
|
||||
const sql::composite_key key{root_type_, typeid(typename CollectionType::value_type::value_type), join_column};
|
||||
const sql::composite_key key{root_type_, typeid(typename CollectionType::value_type), join_column};
|
||||
schema_.collection_resolver_producers_[key] = std::move(producer);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ public:
|
|||
query_result_impl(std::unique_ptr<query_result_reader> &&reader,
|
||||
std::vector<object::attribute> prototype,
|
||||
const std::shared_ptr<resolver_service>& resolver,
|
||||
const std::type_index& result_type,
|
||||
size_t column_index = 0);
|
||||
|
||||
template<typename ValueType>
|
||||
|
|
@ -127,13 +128,12 @@ 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) {
|
||||
using value_type = typename CollectionType::value_type::value_type;
|
||||
auto resolver = resolver_->collection_resolver<value_type>(type_stack_.top(), join_column);
|
||||
auto resolver = resolver_->collection_resolver<typename CollectionType::value_type>(result_type_, join_column);
|
||||
auto object_resolver = resolver_->object_resolver<value_type>();
|
||||
|
||||
std::vector<typename CollectionType::value_type> objects;
|
||||
if (attr.fetch() == utils::fetch_type::Lazy) {
|
||||
|
||||
// pk_reader_.read(*id, column_index_++);
|
||||
cont.reset(std::make_shared<object::collection_proxy<typename CollectionType::value_type>>(resolver, current_pk_));
|
||||
} else {
|
||||
const auto ti = std::type_index(typeid(value_type));
|
||||
auto obj = std::make_shared<typename CollectionType::value_type::value_type>();
|
||||
|
|
@ -227,7 +227,8 @@ protected:
|
|||
size_t column_index_ = 0;
|
||||
std::vector<object::attribute> prototype_;
|
||||
std::unique_ptr<query_result_reader> reader_;
|
||||
std::shared_ptr<sql::resolver_service> resolver_;
|
||||
std::shared_ptr<resolver_service> resolver_;
|
||||
const std::type_index result_type_;
|
||||
internal::identifier_reader id_reader_;
|
||||
detail::pk_reader pk_reader_;
|
||||
std::stack<std::type_index> type_stack_;
|
||||
|
|
|
|||
|
|
@ -41,7 +41,9 @@ struct query_context {
|
|||
std::vector<object::attribute> prototype{};
|
||||
std::vector<std::string> bind_vars{};
|
||||
std::vector<utils::database_type> bind_types{};
|
||||
// Data for resolving query result
|
||||
std::shared_ptr<resolver_service> resolver{};
|
||||
std::type_index result_type = typeid(void);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "matador/utils/types.hpp"
|
||||
#include "matador/utils/result.hpp"
|
||||
#include "matador/utils/os.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <charconv>
|
||||
|
|
@ -467,18 +468,20 @@ template < typename DestType>
|
|||
result<DestType, conversion_error> to(const timestamp_type_t &source, std::enable_if_t<std::is_same_v<time_type_t, DestType>>* = nullptr) {
|
||||
const std::time_t tt = std::chrono::system_clock::to_time_t(source);
|
||||
|
||||
const std::tm* result = std::localtime(&tt);
|
||||
std::tm result;
|
||||
matador::os::localtime(tt, result);
|
||||
|
||||
return ok(time_type_t{static_cast<uint8_t>(result->tm_hour), static_cast<uint8_t>(result->tm_min), static_cast<uint8_t>(result->tm_sec)});
|
||||
return ok(time_type_t{static_cast<uint8_t>(result.tm_hour), static_cast<uint8_t>(result.tm_min), static_cast<uint8_t>(result.tm_sec)});
|
||||
}
|
||||
|
||||
template < typename DestType>
|
||||
result<DestType, conversion_error> to(const timestamp_type_t &source, std::enable_if_t<std::is_same_v<date_type_t, DestType>>* = nullptr) {
|
||||
const std::time_t tt = std::chrono::system_clock::to_time_t(source);
|
||||
|
||||
const std::tm* result = std::localtime(&tt);
|
||||
std::tm result;
|
||||
matador::os::localtime(tt, result);
|
||||
|
||||
return ok(date_type_t{result->tm_year + 1900, static_cast<uint8_t>(result->tm_mon + 1), static_cast<uint8_t>(result->tm_mday)});
|
||||
return ok(date_type_t{result.tm_year + 1900, static_cast<uint8_t>(result.tm_mon + 1), static_cast<uint8_t>(result.tm_mday)});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,6 +98,14 @@ int sprintf(char* str, size_t s, const char* format, ARGS const&... args)
|
|||
|
||||
MATADOR_UTILS_API char* strerror(int err, char* errbuf, size_t bufsize);
|
||||
|
||||
/**
|
||||
* Multi platform version of localtime
|
||||
*
|
||||
* @param in time_t value to be converted
|
||||
* @param out converted value
|
||||
*/
|
||||
MATADOR_UTILS_API void localtime(const time_t &in, struct tm &out);
|
||||
|
||||
/// @endcond
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
#include "matador/utils/os.hpp"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include <ctime>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
|
|
@ -357,4 +359,16 @@ char* strerror(int err, char* errbuf, size_t bufsize)
|
|||
#endif
|
||||
}
|
||||
|
||||
void localtime(const time_t &in, struct tm &out) {
|
||||
#if defined(__unix__)
|
||||
localtime_r(&in, &out);
|
||||
#elif defined(_MSC_VER)
|
||||
errno_t err = localtime_s(&out, &in);
|
||||
#else
|
||||
static std::mutex mtx;
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
out = *std::localtime(&in);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ sql::record *create_prototype(const std::vector<object::attribute> &prototype) {
|
|||
}
|
||||
utils::result<sql::query_result<sql::record>, utils::error> fetchable_query::fetch_all(const sql::executor &exec) const {
|
||||
query_builder compiler;
|
||||
const auto ctx = compiler.compile(*context_, exec.dialect(), std::nullopt);
|
||||
auto ctx = compiler.compile(*context_, exec.dialect(), std::nullopt);
|
||||
ctx.resolver = exec.resolver();
|
||||
return exec.fetch(ctx)
|
||||
.and_then([](auto &&res) {
|
||||
const auto prototype = res->prototype();
|
||||
|
|
@ -67,9 +68,10 @@ sql::query_context fetchable_query::compile(const sql::dialect &d) const {
|
|||
return compiler.compile(*context_, d, std::nullopt);
|
||||
}
|
||||
|
||||
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetchable_query::fetch(const sql::executor &exec) const {
|
||||
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetchable_query::fetch(const sql::executor &exec, const std::type_index& index) const {
|
||||
auto ctx = compile(exec.dialect());
|
||||
ctx.resolver = exec.resolver();
|
||||
ctx.result_type = index;
|
||||
return exec.fetch(ctx);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,12 +9,14 @@ detail::pk_reader::pk_reader(query_result_reader &reader)
|
|||
|
||||
query_result_impl::query_result_impl(std::unique_ptr<query_result_reader> &&reader,
|
||||
std::vector<object::attribute> prototype,
|
||||
const std::shared_ptr<sql::resolver_service>& resolver,
|
||||
const std::shared_ptr<resolver_service>& resolver,
|
||||
const std::type_index& result_type,
|
||||
const size_t column_index)
|
||||
: column_index_(column_index)
|
||||
, prototype_(std::move(prototype))
|
||||
, reader_(std::move(reader))
|
||||
, resolver_(resolver)
|
||||
, result_type_(result_type)
|
||||
, id_reader_(*reader_)
|
||||
, pk_reader_(*reader_) {
|
||||
}
|
||||
|
|
|
|||
2
todo.md
2
todo.md
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
- move `prepare_*` methods from `dialect` to `query_compiler`
|
||||
- add `session_insert_builder` and `session_update_builder` (returning multiple statements)
|
||||
- finish fetch eager has-many/belongs-to relations
|
||||
- finish fetch eager many-to-many relations
|
||||
- implement lazy loading
|
||||
- implement polymorphic class hierarchies
|
||||
- finish `schema_repository` classes (move add/drop from `session` to `schema`)
|
||||
|
|
|
|||
Loading…
Reference in New Issue