use result in entity_query_builder

This commit is contained in:
Sascha Kühl
2024-04-10 16:13:37 +02:00
parent b7c12d8217
commit 25bcc362f2
9 changed files with 331 additions and 124 deletions
+84 -50
View File
@@ -8,6 +8,8 @@
#include "matador/sql/query_intermediates.hpp"
#include "matador/sql/value.hpp"
#include "matador/utils/result.hpp"
#include <iostream>
namespace matador::sql {
@@ -25,6 +27,24 @@ struct entity_query_data {
std::unique_ptr<basic_condition> where_clause;
};
enum class query_build_error : std::uint8_t {
Ok = 0,
UnknownType,
MissingPrimaryKey,
UnexpectedError
};
class query_builder_exception : public std::exception
{
public:
explicit query_builder_exception(query_build_error error) : error_(error) {}
[[nodiscard]] query_build_error error() const { return error_; }
private:
const query_build_error error_;
};
class entity_query_builder
{
public:
@@ -32,18 +52,45 @@ public:
: schema_(scm) {}
template<class EntityType, typename PrimaryKeyType>
std::optional<entity_query_data> build(const PrimaryKeyType &pk) {
utils::result<entity_query_data, query_build_error> build(const PrimaryKeyType &pk) {
const auto info = schema_.info<EntityType>();
if (!info) {
return std::nullopt;
return utils::error(query_build_error::UnknownType);
}
pk_ = pk;
table_info_stack_.push(info.value());
entity_query_data_ = { info->name };
EntityType obj;
matador::utils::access::process(*this, obj);
try {
matador::utils::access::process(*this, obj);
return std::move(entity_query_data_);
return {utils::ok(std::move(entity_query_data_))};
} catch (const query_builder_exception &ex) {
return {utils::error(ex.error())};
} catch (...) {
return {utils::error(query_build_error::UnexpectedError)};
}
}
template<class EntityType>
utils::result<entity_query_data, query_build_error> build() {
const auto info = schema_.info<EntityType>();
if (!info) {
return utils::error(query_build_error::UnknownType);
}
pk_ = nullptr;
table_info_stack_.push(info.value());
entity_query_data_ = { info->name };
EntityType obj;
try {
matador::utils::access::process(*this, obj);
return {utils::ok(std::move(entity_query_data_))};
} catch (const query_builder_exception &ex) {
return {utils::error(ex.error())};
} catch (...) {
return {utils::error(query_build_error::UnexpectedError)};
}
}
template < class V >
@@ -65,51 +112,15 @@ public:
}
template<class Pointer>
void on_belongs_to(const char *id, Pointer &, const utils::foreign_attributes &attr)
void on_belongs_to(const char *id, Pointer &obj, const utils::foreign_attributes &attr)
{
if (attr.fetch() == utils::fetch_type::EAGER) {
const auto info = schema_.info<typename Pointer::value_type>();
if (!info) {
return;
}
table_info_stack_.push(info.value());
typename Pointer::value_type obj;
matador::utils::access::process(*this , obj);
table_info_stack_.pop();
auto pk = info->prototype.primary_key();
if (!pk) {
// error, prototype doesn't has a pk
return;
}
append_join({table_info_stack_.top().name, id}, {info->name, pk->name()});
} else {
push(id);
}
on_foreign_object(id, obj, attr);
}
template<class Pointer>
void on_has_one(const char *id, Pointer &, const utils::foreign_attributes &attr)
void on_has_one(const char *id, Pointer &obj, const utils::foreign_attributes &attr)
{
if (attr.fetch() == utils::fetch_type::EAGER) {
const auto info = schema_.info<typename Pointer::value_type>();
if (!info) {
return;
}
table_info_stack_.push(info.value());
typename Pointer::value_type obj;
matador::utils::access::process(*this, obj);
table_info_stack_.pop();
auto pk = info->prototype.primary_key();
if (!pk) {
// error, prototype doesn't has a pk
return;
}
append_join({table_info_stack_.top().name, id}, {info->name, pk->name()});
} else {
push(id);
}
on_foreign_object(id, obj, attr);
}
template<class ContainerType>
@@ -118,7 +129,7 @@ public:
if (attr.fetch() == utils::fetch_type::EAGER) {
const auto info = schema_.info<typename ContainerType::value_type::value_type>();
if (!info) {
return;
throw query_builder_exception{query_build_error::UnknownType};
}
table_info_stack_.push(info.value());
typename ContainerType::value_type::value_type obj;
@@ -127,8 +138,7 @@ public:
auto pk = info->prototype.primary_key();
if (!pk) {
// error, prototype doesn't has a pk
return;
throw query_builder_exception{query_build_error::MissingPrimaryKey};
}
append_join({table_info_stack_.top().name, table_info_stack_.top().prototype.primary_key()->name()}, {info->name, join_column});
@@ -141,7 +151,7 @@ public:
if (attr.fetch() == utils::fetch_type::EAGER) {
const auto info = schema_.info<typename ContainerType::value_type::value_type>();
if (!info) {
return;
throw query_builder_exception{query_build_error::UnknownType};
}
table_info_stack_.push(info.value());
typename ContainerType::value_type::value_type obj;
@@ -150,8 +160,7 @@ public:
auto pk = info->prototype.primary_key();
if (!pk) {
// error, prototype doesn't has a pk
return;
throw query_builder_exception{query_build_error::MissingPrimaryKey};
}
append_join({table_info_stack_.top().name, table_info_stack_.top().prototype.primary_key()->name()}, {id, join_column});
@@ -163,6 +172,8 @@ public:
void on_has_many_to_many(const char *id, ContainerType &c, const utils::foreign_attributes &/*attr*/) {}
private:
template<class Pointer>
void on_foreign_object(const char *id, Pointer &, const utils::foreign_attributes &attr);
void push(const std::string &column_name);
[[nodiscard]] bool is_root_entity() const;
void append_join(const column &left, const column &right);
@@ -175,5 +186,28 @@ private:
int column_index{0};
};
template<class Pointer>
void entity_query_builder::on_foreign_object(const char *id, Pointer &, const utils::foreign_attributes &attr)
{
if (attr.fetch() == utils::fetch_type::EAGER) {
const auto info = schema_.info<typename Pointer::value_type>();
if (!info) {
throw query_builder_exception{query_build_error::UnknownType};
}
table_info_stack_.push(info.value());
typename Pointer::value_type obj;
matador::utils::access::process(*this, obj);
table_info_stack_.pop();
auto pk = info->prototype.primary_key();
if (!pk) {
throw query_builder_exception{query_build_error::MissingPrimaryKey};
}
append_join({table_info_stack_.top().name, id}, {info->name, pk->name()});
} else {
push(id);
}
}
}
#endif //QUERY_ENTITY_QUERY_BUILDER_HPP
+30 -30
View File
@@ -40,7 +40,7 @@ protected:
std::shared_ptr<query_data> data_;
};
class query_execute_finish : public query_intermediate
class query_execute : public query_intermediate
{
public:
using query_intermediate::query_intermediate;
@@ -50,7 +50,7 @@ public:
[[nodiscard]] query_context build() const;
};
class query_select_finish : public query_intermediate
class query_select : public query_intermediate
{
protected:
using query_intermediate::query_intermediate;
@@ -96,36 +96,36 @@ private:
class query_offset_intermediate;
class query_limit_intermediate : public query_select_finish
class query_limit_intermediate : public query_select
{
public:
using query_select_finish::query_select_finish;
using query_select::query_select;
query_offset_intermediate offset(size_t offset);
};
class query_offset_intermediate : public query_select_finish
class query_offset_intermediate : public query_select
{
public:
using query_select_finish::query_select_finish;
using query_select::query_select;
query_limit_intermediate limit(size_t limit);
};
class query_order_direction_intermediate : public query_select_finish
class query_order_direction_intermediate : public query_select
{
public:
using query_select_finish::query_select_finish;
using query_select::query_select;
query_limit_intermediate limit(size_t limit);
};
class query_order_by_intermediate;
class query_group_by_intermediate : public query_select_finish
class query_group_by_intermediate : public query_select
{
public:
using query_select_finish::query_select_finish;
using query_select::query_select;
query_order_by_intermediate order_by(const column &col);
};
@@ -139,10 +139,10 @@ public:
query_order_direction_intermediate desc();
};
class query_where_intermediate : public query_select_finish
class query_where_intermediate : public query_select
{
public:
using query_select_finish::query_select_finish;
using query_select::query_select;
query_group_by_intermediate group_by(const column &col);
query_order_by_intermediate order_by(const column &col);
@@ -150,10 +150,10 @@ public:
class query_join_intermediate;
class query_on_intermediate : public query_select_finish
class query_on_intermediate : public query_select
{
public:
using query_select_finish::query_select_finish;
using query_select::query_select;
query_join_intermediate join_left(const table &t);
template<class Condition>
@@ -191,10 +191,10 @@ private:
query_on_intermediate on_clause(std::unique_ptr<basic_condition> &&cond);
};
class query_from_intermediate : public query_select_finish
class query_from_intermediate : public query_select
{
public:
using query_select_finish::query_select_finish;
using query_select::query_select;
query_join_intermediate join_left(const table &t);
template<class Condition>
@@ -244,16 +244,16 @@ class query_into_intermediate : public query_intermediate
public:
using query_intermediate::query_intermediate;
query_execute_finish values(std::initializer_list<any_type> values);
query_execute_finish values(std::vector<any_type> &&values);
query_execute values(std::initializer_list<any_type> values);
query_execute values(std::vector<any_type> &&values);
template<class Type>
query_execute_finish values()
query_execute values()
{
Type obj;
return values(std::move(as_placeholder(obj)));
}
template<class Type>
query_execute_finish values(const Type &obj)
query_execute values(const Type &obj)
{
return values(std::move(value_extractor::extract(obj)));
}
@@ -264,10 +264,10 @@ class query_create_intermediate : public query_start_intermediate
public:
explicit query_create_intermediate(connection &db, const sql::schema &schema);
query_execute_finish table(const sql::table &table, std::initializer_list<column_definition> columns);
query_execute_finish table(const sql::table &table, const std::vector<column_definition> &columns);
query_execute table(const sql::table &table, std::initializer_list<column_definition> columns);
query_execute table(const sql::table &table, const std::vector<column_definition> &columns);
template<class Type>
query_execute_finish table(const sql::table &table)
query_execute table(const sql::table &table)
{
return this->table(table, column_definition_generator::generate<Type>(schema_));
}
@@ -278,7 +278,7 @@ class query_drop_intermediate : query_start_intermediate
public:
explicit query_drop_intermediate(connection &db, const sql::schema &schema);
query_execute_finish table(const sql::table &table);
query_execute table(const sql::table &table);
};
class query_insert_intermediate : public query_start_intermediate
@@ -291,18 +291,18 @@ public:
query_into_intermediate into(const sql::table &table);
};
class query_execute_where_intermediate : public query_execute_finish
class query_execute_where_intermediate : public query_execute
{
public:
using query_execute_finish::query_execute_finish;
using query_execute::query_execute;
query_order_by_intermediate order_by(const column &col);
};
class query_set_intermediate : public query_execute_finish
class query_set_intermediate : public query_execute
{
public:
using query_execute_finish::query_execute_finish;
using query_execute::query_execute;
template<class Condition>
query_execute_where_intermediate where(const Condition &cond)
@@ -328,10 +328,10 @@ public:
}
};
class query_delete_from_intermediate : public query_execute_finish
class query_delete_from_intermediate : public query_execute
{
public:
using query_execute_finish::query_execute_finish;
using query_execute::query_execute;
template<class Condition>
query_execute_where_intermediate where(const Condition &cond)
+61 -18
View File
@@ -14,6 +14,14 @@ namespace matador::sql {
class dialect;
enum class session_error {
Ok = 0,
NoConnectionAvailable,
UnknownType,
FailedToBuildQuery,
FailedToFindObject
};
class session
{
public:
@@ -33,35 +41,68 @@ public:
}
template<typename Type, typename PrimaryKeyType>
std::optional<entity<Type>> find(const PrimaryKeyType &pk) {
utils::result<entity<Type>, session_error> find(const PrimaryKeyType &pk) {
auto c = pool_.acquire();
if (!c.valid()) {
throw std::logic_error("no database connection available");
return utils::error(session_error::NoConnectionAvailable);
}
auto info = schema_->info<Type>();
if (!info) {
return {};
return utils::error(session_error::UnknownType);
}
entity_query_builder eqb(*schema_);
auto data = eqb.build<Type>(pk);
auto q = c->query(*schema_)
.select(data->columns)
.from(data->root_table_name);
for (auto &jd : data->joins) {
q.join_left(jd.join_table)
.on(std::move(jd.condition));
if (!data.is_ok()) {
return utils::error(session_error::FailedToBuildQuery);
}
auto e = q
.where(std::move(data->where_clause))
.template fetch_one<Type>();
if (!e) {
return std::nullopt;
auto obj = build_select_query(c, data.release()).template fetch_one<Type>();
if (!obj) {
return utils::error(session_error::FailedToFindObject);
}
return entity<Type>{ e.release() };
return utils::ok(entity<Type>{ obj.release() });
}
template<typename Type>
utils::result<query_result<Type>, session_error> find() {
auto c = pool_.acquire();
if (!c.valid()) {
return utils::error(session_error::NoConnectionAvailable);
}
auto info = schema_->info<Type>();
if (!info) {
return utils::error(session_error::UnknownType);
}
entity_query_builder eqb(*schema_);
auto data = eqb.build<Type>();
if (!data.is_ok()) {
return utils::error(session_error::FailedToBuildQuery);
}
return utils::ok(build_select_query(c, data.release()).template fetch_all<Type>());
}
template<typename Type>
utils::result<query_from_intermediate, session_error> select() {
auto c = pool_.acquire();
if (!c.valid()) {
return utils::error(session_error::NoConnectionAvailable);
}
auto info = schema_->info<Type>();
if (!info) {
return utils::error(session_error::UnknownType);
}
entity_query_builder eqb(*schema_);
auto data = eqb.build<Type>();
if (!data.is_ok()) {
return utils::error(session_error::FailedToBuildQuery);
}
return utils::ok(build_select_query(c, data.release()).template fetch_all<Type>());
}
template<typename Type>
@@ -79,10 +120,12 @@ public:
const class dialect& dialect() const;
private:
friend class query_select_finish;
friend class query_select;
[[nodiscard]] std::unique_ptr<query_result_impl> fetch(const std::string &sql) const;
query_select build_select_query(connection_ptr<connection> &conn, entity_query_data &&data) const;
private:
connection_pool<connection> &pool_;
const class dialect &dialect_;