added more tests

This commit is contained in:
Sascha Kühl
2025-02-06 16:17:47 +01:00
parent c76aa56440
commit 0b70f5d4ee
68 changed files with 2117 additions and 263 deletions
@@ -9,45 +9,45 @@
#include <vector>
namespace matador::sql {
namespace matador::object {
enum class null_option : uint8_t {
NULLABLE, NOT_NULL
};
class column_definition {
class attribute_definition {
public:
explicit column_definition(const char *name); // NOLINT(*-explicit-constructor)
explicit column_definition(std::string name); // NOLINT(*-explicit-constructor)
explicit attribute_definition(const char *name); // NOLINT(*-explicit-constructor)
explicit attribute_definition(std::string name); // NOLINT(*-explicit-constructor)
column_definition(const column_definition&) = default;
column_definition& operator=(const column_definition&) = default;
column_definition(column_definition&&) noexcept = default;
column_definition& operator=(column_definition&&) noexcept = default;
attribute_definition(const attribute_definition&) = default;
attribute_definition& operator=(const attribute_definition&) = default;
attribute_definition(attribute_definition&&) noexcept = default;
attribute_definition& operator=(attribute_definition&&) noexcept = default;
template<typename Type>
explicit column_definition(std::string name, const utils::field_attributes& attr)
: column_definition(std::move(name), utils::data_type_traits<Type>::type(attr.size()), attr)
explicit attribute_definition(std::string name, const utils::field_attributes& attr)
: attribute_definition(std::move(name), utils::data_type_traits<Type>::type(attr.size()), attr)
{}
template<typename Type>
column_definition(std::string name, const Type &, const utils::field_attributes& attr, null_option null_opt)
: column_definition(std::move(name), utils::data_type_traits<Type>::type(attr.size()), attr, null_opt)
attribute_definition(std::string name, const Type &, const utils::field_attributes& attr, null_option null_opt)
: attribute_definition(std::move(name), utils::data_type_traits<Type>::type(attr.size()), attr, null_opt)
{}
template<size_t SIZE>
column_definition(std::string name, const char (&)[SIZE], const utils::field_attributes& attr, const null_option null_opt)
: column_definition(std::move(name), utils::data_type_traits<const char*>::type(attr.size()), attr, null_opt)
attribute_definition(std::string name, const char (&)[SIZE], const utils::field_attributes& attr, const null_option null_opt)
: attribute_definition(std::move(name), utils::data_type_traits<const char*>::type(attr.size()), attr, null_opt)
{}
column_definition(std::string name, utils::basic_type type, const utils::field_attributes&, null_option null_opt, size_t index = 0);
attribute_definition(std::string name, utils::basic_type type, const utils::field_attributes&, null_option null_opt, size_t index = 0);
template<typename Type>
column_definition(std::string name, std::string ref_table, std::string ref_column, const utils::field_attributes& attr, null_option null_opt)
: column_definition(std::move(name), utils::data_type_traits<Type>::type(attr.size()), ref_table, ref_column, attr, null_opt)
attribute_definition(std::string name, std::string ref_table, std::string ref_column, const utils::field_attributes& attr, null_option null_opt)
: attribute_definition(std::move(name), utils::data_type_traits<Type>::type(attr.size()), ref_table, ref_column, attr, null_opt)
{}
column_definition(std::string name, utils::basic_type type, size_t index, std::string ref_table, std::string ref_column, const utils::field_attributes& attr, null_option null_opt);
attribute_definition(std::string name, utils::basic_type type, size_t index, std::string ref_table, std::string ref_column, const utils::field_attributes& attr, null_option null_opt);
[[nodiscard]] const std::string& name() const;
[[nodiscard]] std::string full_name() const;
@@ -104,7 +104,7 @@ public:
return value_.as<Type>();
}
friend std::ostream& operator<<(std::ostream &out, const column_definition &col);
friend std::ostream& operator<<(std::ostream &out, const attribute_definition &col);
private:
template<class Operator>
@@ -136,39 +136,39 @@ private:
* @param null_opt
* @return A column object with given name
*/
column_definition make_column(const std::string &name, utils::basic_type type, utils::field_attributes attr = utils::null_attributes, null_option null_opt = null_option::NOT_NULL);
attribute_definition make_column(const std::string &name, utils::basic_type type, utils::field_attributes attr = utils::null_attributes, null_option null_opt = null_option::NOT_NULL);
template < typename Type >
column_definition make_column(const std::string &name, utils::field_attributes attr = utils::null_attributes, null_option null_opt = null_option::NOT_NULL)
attribute_definition make_column(const std::string &name, utils::field_attributes attr = utils::null_attributes, null_option null_opt = null_option::NOT_NULL)
{
return make_column(name, utils::data_type_traits<Type>::type(0), attr, null_opt);
}
template <>
column_definition make_column<std::string>(const std::string &name, utils::field_attributes attr, null_option null_opt);
attribute_definition make_column<std::string>(const std::string &name, utils::field_attributes attr, null_option null_opt);
template < typename Type >
column_definition make_pk_column(const std::string &name, size_t size = 0)
attribute_definition make_pk_column(const std::string &name, size_t size = 0)
{
return make_column<Type>(name, { size, utils::constraints::PRIMARY_KEY });
}
template <>
column_definition make_pk_column<std::string>(const std::string &name, size_t size);
attribute_definition make_pk_column<std::string>(const std::string &name, size_t size);
template < typename Type >
column_definition make_fk_column(const std::string &name, size_t size, const std::string &ref_table, const std::string &ref_column)
attribute_definition make_fk_column(const std::string &name, size_t size, const std::string &ref_table, const std::string &ref_column)
{
return {name, utils::data_type_traits<Type>::type(size), ref_table, ref_column, { size, utils::constraints::FOREIGN_KEY }};
}
template < typename Type >
[[maybe_unused]] column_definition make_fk_column(const std::string &name, const std::string &ref_table, const std::string &ref_column)
[[maybe_unused]] attribute_definition make_fk_column(const std::string &name, const std::string &ref_table, const std::string &ref_column)
{
return {name, utils::data_type_traits<Type>::type(0), 0, ref_table, ref_column, { 0, utils::constraints::FOREIGN_KEY }, null_option::NOT_NULL};
}
template <>
column_definition make_fk_column<std::string>(const std::string &name, size_t size, const std::string &ref_table, const std::string &ref_column);
attribute_definition make_fk_column<std::string>(const std::string &name, size_t size, const std::string &ref_table, const std::string &ref_column);
}
#endif //QUERY_COLUMN_DEFINITION_HPP
@@ -0,0 +1,132 @@
#ifndef QUERY_COLUMN_DEFINITION_GENERATOR_HPP
#define QUERY_COLUMN_DEFINITION_GENERATOR_HPP
#include "attribute_definition.hpp"
#include "matador/utils/access.hpp"
#include "matador/utils/data_type_traits.hpp"
#include "matador/utils/field_attributes.hpp"
#include "matador/utils/foreign_attributes.hpp"
#include <typeindex>
#include <vector>
namespace matador::object {
class schema;
class fk_attribute_generator
{
public:
fk_attribute_generator() = default;
template<class Type>
attribute_definition generate(const char *id, Type &x, const std::string &ref_table, const std::string &ref_column)
{
access::process(*this, x);
return attribute_definition{id, type_, 0, ref_table, ref_column, {utils::constraints::FOREIGN_KEY }, null_option::NOT_NULL};
}
template<typename ValueType>
void on_primary_key(const char *, ValueType &/*pk*/, std::enable_if_t<std::is_integral_v<ValueType> && !std::is_same_v<bool, ValueType>>* = nullptr)
{
type_ = utils::data_type_traits<ValueType>::type(0);
}
void on_primary_key(const char * /*id*/, std::string &/*pk*/, size_t size);
void on_revision(const char * /*id*/, unsigned long long &/*rev*/) {}
template < class Type >
void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
void on_attribute(const char * /*id*/, char * /*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template<class Pointer>
void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
template<class Pointer>
void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType>
void on_has_many(ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType>
void on_has_many_to_many(const char *id, ContainerType &c, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType>
void on_has_many_to_many(const char *id, ContainerType &c, const utils::foreign_attributes &/*attr*/) {}
private:
utils::basic_type type_{};
};
class attribute_definition_generator final {
private:
attribute_definition_generator(std::vector<attribute_definition> &columns, const schema &repo);
public:
~attribute_definition_generator() = default;
template < class Type >
static std::vector<attribute_definition> generate(const schema &repo)
{
std::vector<attribute_definition> columns;
attribute_definition_generator gen(columns, repo);
Type obj;
access::process(gen, obj);
return std::move(columns);
}
template < class V >
void on_primary_key(const char *, V &x, std::enable_if_t<std::is_integral_v<V> && !std::is_same_v<bool, V>>* = nullptr);
void on_primary_key(const char *id, std::string &pk, size_t size);
void on_revision(const char *id, unsigned long long &rev);
template<typename Type>
void on_attribute(const char *id, Type &x, const utils::field_attributes &attr = utils::null_attributes);
template<typename Type>
void on_attribute(const char *id, std::optional<Type> &x, const utils::field_attributes &attr = utils::null_attributes);
template<class Pointer>
void on_belongs_to(const char *id, Pointer &x, const utils::foreign_attributes &/*attr*/)
{
const auto [ref_table, ref_column] = determine_foreign_ref(std::type_index(typeid(typename Pointer::value_type)));
columns_.push_back(fk_column_generator_.generate(id, *x, ref_table, ref_column));
}
template<class Pointer>
void on_has_one(const char *id, Pointer &x, const utils::foreign_attributes &/*attr*/)
{
const auto [ref_table, ref_column] = determine_foreign_ref(std::type_index(typeid(typename Pointer::value_type)));
columns_.push_back(fk_column_generator_.generate(id, *x, ref_table, ref_column));
}
template<class ContainerType>
void on_has_many(ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType>
void on_has_many_to_many(const char *id, ContainerType &c, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType>
void on_has_many_to_many(const char *id, ContainerType &c, const utils::foreign_attributes &/*attr*/) {}
private:
std::pair<std::string, std::string> determine_foreign_ref(const std::type_index &ti);
private:
size_t index_ = 0;
std::vector<attribute_definition> &columns_;
const schema &repo_;
fk_attribute_generator fk_column_generator_;
};
template<typename V>
void attribute_definition_generator::on_primary_key(const char *id, V &x, std::enable_if_t<std::is_integral_v<V> && !std::is_same_v<bool, V>>*)
{
on_attribute(id, x, { utils::constraints::PRIMARY_KEY });
}
template<typename Type>
void attribute_definition_generator::on_attribute(const char *id, Type &x, const utils::field_attributes &attr)
{
columns_.emplace_back(id, x, attr, null_option::NOT_NULL);
}
template<typename Type>
void attribute_definition_generator::on_attribute(const char *id, std::optional<Type> &x, const utils::field_attributes &attr)
{
columns_.emplace_back(id, utils::data_type_traits<Type>::type(attr.size()), attr, null_option::NULLABLE);
}
}
#endif //QUERY_COLUMN_DEFINITION_GENERATOR_HPP
+6 -21
View File
@@ -1,6 +1,8 @@
#ifndef BASIC_PROTOTYPE_INFO_HPP
#define BASIC_PROTOTYPE_INFO_HPP
#include "matador/object/object_definition.hpp"
#include <string>
#include <typeindex>
@@ -14,35 +16,18 @@ public:
[[nodiscard]] std::type_index type_index() const;
[[nodiscard]] std::string name() const;
[[nodiscard]] const object_definition& definition() const;
protected:
basic_object_info(schema_node &node, std::type_index type_index);
basic_object_info(schema_node &node, std::type_index type_index, object_definition &&definition);
protected:
schema_node &node_; /**< prototype node of the represented object type */
std::type_index type_index_; /**< type index of the represented object type */
object_definition definition_;
};
template<typename Type>
class object_info final : public basic_object_info {
public:
explicit object_info(schema_node &node)
: basic_object_info(node, typeid(Type)) {}
const Type &prototype() const { return prototype_; }
private:
Type prototype_;
};
template<typename Type>
using object_info_ref = std::reference_wrapper<const object_info<Type>>;
namespace detail {
struct null_type {};
}
using null_info = object_info<detail::null_type>;
using basic_object_info_ref = std::reference_wrapper<const basic_object_info>;
}
@@ -0,0 +1,37 @@
#ifndef QUERY_HAS_MANY_TO_MANY_RELATION_HPP
#define QUERY_HAS_MANY_TO_MANY_RELATION_HPP
#include "matador/object/object_ptr.hpp"
#include "matador/utils/access.hpp"
#include "matador/utils/foreign_attributes.hpp"
namespace matador::object {
template < class LocalType, class ForeignType >
class many_to_many_relation {
public:
many_to_many_relation() = default;
many_to_many_relation(std::string local_name, std::string remote_name)
: local_name_(std::move(local_name))
, remote_name_(std::move(remote_name)) {}
template<class Operator>
void process(Operator &op) {
namespace field = matador::access;
field::belongs_to(op, local_name_.c_str(), local_, utils::default_foreign_attributes);
field::belongs_to(op, remote_name_.c_str(), remote_, utils::default_foreign_attributes);
}
object_ptr<LocalType> local() const { return local_; }
object_ptr<LocalType> remote() const { return remote_; }
private:
std::string local_name_;
std::string remote_name_;
object_ptr<LocalType> local_;
object_ptr<ForeignType> remote_;
};
}
#endif //QUERY_HAS_MANY_TO_MANY_RELATION_HPP
@@ -0,0 +1,70 @@
#ifndef QUERY_TABLE_DEFINITION_HPP
#define QUERY_TABLE_DEFINITION_HPP
#include "matador/object/attribute_definition.hpp"
#include <unordered_map>
namespace matador::object {
class object_definition final {
private:
using column_by_index = std::vector<object::attribute_definition>;
using column_index_pair = std::pair<std::reference_wrapper<object::attribute_definition>, column_by_index::difference_type>;
using column_by_name_map = std::unordered_map<std::string, column_index_pair>;
public:
using iterator = column_by_index::iterator;
using const_iterator = column_by_index::const_iterator;
object_definition() = default;
object_definition(std::initializer_list<object::attribute_definition> columns);
explicit object_definition(const std::vector<object::attribute_definition> &columns);
object_definition(const object_definition &x);
object_definition& operator=(const object_definition &x);
object_definition(object_definition&&) noexcept = default;
object_definition& operator=(object_definition&&) noexcept = default;
~object_definition() = default;
[[nodiscard]] bool has_primary_key() const;
[[nodiscard]] std::optional<object::attribute_definition> primary_key() const;
template < typename Type >
void append(const std::string &name, long size = -1) {
append(make_column<Type>(name, size));
}
void append(attribute_definition col);
[[nodiscard]] const std::vector<object::attribute_definition>& columns() const;
[[nodiscard]] const attribute_definition& at(const std::string &name) const;
[[nodiscard]] const attribute_definition& at(size_t index) const;
iterator find(const std::string &column_name);
[[nodiscard]] const_iterator find(const std::string &column_name) const;
iterator begin();
[[nodiscard]] const_iterator begin() const;
[[nodiscard]] const_iterator cbegin() const;
iterator end();
[[nodiscard]] const_iterator end() const;
[[nodiscard]] const_iterator cend() const;
[[nodiscard]] size_t size() const;
[[nodiscard]] bool empty() const;
void clear();
private:
void init();
void add_to_map(attribute_definition &col, size_t index);
private:
column_by_index columns_;
column_by_name_map columns_by_name_;
int pk_index_{-1};
};
}
#endif //QUERY_TABLE_DEFINITION_HPP
+34
View File
@@ -0,0 +1,34 @@
#ifndef OBJECT_INFO_HPP
#define OBJECT_INFO_HPP
#include "matador/object/basic_object_info.hpp"
#include "matador/object/object_definition.hpp"
namespace matador::object {
class schema_node;
template<typename Type>
class object_info final : public basic_object_info {
public:
explicit object_info(schema_node &node, object_definition &&definition)
: basic_object_info(node, typeid(Type), std::move(definition)) {}
const Type &prototype() const { return prototype_; }
private:
Type prototype_;
};
template<typename Type>
using object_info_ref = std::reference_wrapper<const object_info<Type>>;
namespace detail {
struct null_type {};
}
using null_info = object_info<detail::null_type>;
}
#endif //OBJECT_INFO_HPP
+1
View File
@@ -5,6 +5,7 @@ namespace matador::object {
template <typename Type>
class object_ptr {
public:
using value_type = Type;
Type* operator->() { return ptr; };
Type& operator*() { return *ptr; };
+12
View File
@@ -93,6 +93,18 @@ public:
return utils::ok(result.value()->info<Type>());
}
template <typename Type>
[[nodiscard]] utils::result<basic_object_info_ref, utils::error> basic_info() const {
auto result = find_node(std::type_index(typeid(Type)));
if (!result) {
return utils::failure(result.err());
}
return utils::ok(basic_object_info_ref{result.value()->basic_info()});
}
[[nodiscard]] utils::result<std::pair<std::string, std::string>, utils::error> reference(const std::type_index &type_index) const;
private:
using node_ptr = std::shared_ptr<schema_node>;
using t_node_map = std::unordered_map<std::string, node_ptr>;
+7 -19
View File
@@ -1,13 +1,14 @@
#ifndef SCHEMA_NODE_HPP
#define SCHEMA_NODE_HPP
#include "matador/object/basic_object_info.hpp"
#include "matador/object/attribute_definition_generator.hpp"
#include "matador/object/object_info.hpp"
#include <memory>
#include <string>
namespace matador::object {
class basic_object_info;
class schema;
class schema_node final {
@@ -28,24 +29,11 @@ public:
[[nodiscard]] std::string name() const;
[[nodiscard]] std::type_index type_index() const;
/**
* Appends the given prototype node as a sibling
* on the same level.
*
* @param sibling The new sibling node.
*/
void append(const std::shared_ptr<schema_node> &sibling);
/**
* Inserts the given node to the list of children.
*
* @param child The child node to add.
*/
void insert(const std::shared_ptr<schema_node> &child);
[[nodiscard]] node_ptr next() const;
[[nodiscard]] node_ptr prev() const;
[[nodiscard]] const basic_object_info& basic_info() const;
template <typename Type>
object_info_ref<Type> info() const {
return std::ref(static_cast<const object_info<Type>&>(*info_));
@@ -56,7 +44,7 @@ private:
template < typename Type >
schema_node(schema& tree, std::string name, Type *obj)
: schema_(tree)
, info_(std::make_unique<object_info<Type>>(*this))
, info_(std::make_unique<object_info<Type>>(*this, object_definition(attribute_definition_generator::generate<Type>(schema_))))
, first_child_(std::shared_ptr<schema_node>(new schema_node(tree)))
, last_child_(std::shared_ptr<schema_node>(new schema_node(tree)))
, name_(std::move(name)) {
@@ -69,7 +57,7 @@ private:
friend class schema;
friend class const_schema_node_iterator;
schema &schema_;
object::schema &schema_;
std::unique_ptr<basic_object_info> info_;
std::shared_ptr<schema_node> parent_;
+20 -19
View File
@@ -1,20 +1,21 @@
#ifndef QUERY_SESSION_HPP
#define QUERY_SESSION_HPP
#include "matador/orm/session_query_builder.hpp"
#include "matador/sql/column_generator.hpp"
#include "matador/sql/connection.hpp"
#include "matador/sql/connection_pool.hpp"
// #include "matador/sql/entity_query_builder.hpp"
#include "matador/sql/statement.hpp"
#include "matador/object/object_ptr.hpp"
#include "matador/object/object_definition.hpp"
#include "matador/object/schema.hpp"
#include <unordered_map>
namespace matador::orm {
class dialect;
enum class session_error {
Ok = 0,
NoConnectionAvailable,
@@ -29,9 +30,9 @@ public:
explicit session(sql::connection_pool<sql::connection> &pool);
template<typename Type>
void attach(const std::string &table_name);
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &table_name);
void create_schema();
utils::result<void, utils::error> create_schema() const;
template<typename Type>
object::object_ptr<Type> insert(Type *obj);
@@ -52,7 +53,7 @@ public:
return utils::failure(session_error::UnknownType);
}
entity_query_builder eqb(*schema_);
session_query_builder eqb(*schema_);
auto data = eqb.build<Type>(pk);
if (!data.is_ok()) {
return utils::failure(session_error::FailedToBuildQuery);
@@ -77,7 +78,7 @@ public:
return utils::failure(session_error::UnknownType);
}
entity_query_builder eqb(*schema_);
session_query_builder eqb(*schema_);
auto data = eqb.build<Type>();
if (!data.is_ok()) {
return utils::failure(session_error::FailedToBuildQuery);
@@ -97,7 +98,7 @@ public:
return utils::failure(session_error::UnknownType);
}
entity_query_builder eqb(*schema_);
session_query_builder eqb(*schema_);
auto data = eqb.build<Type>();
if (!data.is_ok()) {
return utils::failure(session_error::FailedToBuildQuery);
@@ -110,12 +111,12 @@ public:
void drop_table();
void drop_table(const std::string &table_name);
[[nodiscard]] sql::query_result<sql::record> fetch(const query_context &q) const;
[[nodiscard]] utils::result<sql::query_result<sql::record>, utils::error> fetch(const sql::query_context &q) const;
// [[nodiscard]] query_result<record> fetch(const std::string &sql) const;
[[nodiscard]] size_t execute(const std::string &sql) const;
[[nodiscard]] sql::statement prepare(query_context q) const;
[[nodiscard]] sql::statement prepare(const sql::query_context& q) const;
[[nodiscard]] std::vector<sql::column_definition> describe_table(const std::string &table_name) const;
[[nodiscard]] std::vector<object::attribute_definition> describe_table(const std::string &table_name) const;
[[nodiscard]] bool table_exists(const std::string &table_name) const;
[[nodiscard]] const sql::dialect& dialect() const;
@@ -123,22 +124,22 @@ public:
private:
friend class query_select;
[[nodiscard]] std::unique_ptr<sql::query_result_impl> fetch(const std::string &sql) const;
// [[nodiscard]] std::unique_ptr<sql::query_result_impl> fetch(const std::string &sql) const;
query_select build_select_query(sql::connection_ptr<sql::connection> &conn, entity_query_data &&data) const;
static query::fetchable_query build_select_query(sql::connection_ptr<sql::connection> &conn, entity_query_data &&data);
private:
sql::connection_pool<sql::connection> &pool_;
const sql::dialect &dialect_;
std::unique_ptr<object::schema> schema_;
mutable std::unordered_map<std::string, table_definition> prototypes_;
mutable std::unordered_map<std::string, object::object_definition> prototypes_;
};
template<typename Type>
void session::attach(const std::string &table_name)
[[nodiscard]] utils::result<void, utils::error> session::attach(const std::string &table_name)
{
schema_->attach<Type>(table_name);
return schema_->attach<Type>(table_name);
}
template<typename Type>
@@ -149,9 +150,9 @@ object::object_ptr<Type> session::insert(Type *obj)
if (!info) {
return {};
}
c->query(*schema_)
.insert()
.into(info->name, column_generator::generate<Type>(*schema_, true))
query::query::insert()
.into(info->name, sql::column_generator::generate<Type>(*schema_, true))
.values(*obj)
.execute();
@@ -0,0 +1,289 @@
#ifndef QUERY_ENTITY_QUERY_BUILDER_HPP
#define QUERY_ENTITY_QUERY_BUILDER_HPP
#include "matador/query/condition.hpp"
#include "matador/query/query.hpp"
#include "matador/query/query_intermediates.hpp"
#include "matador/sql/connection.hpp"
#include "matador/sql/query_context.hpp"
#include "matador/object/schema.hpp"
#include "matador/utils/result.hpp"
#include "matador/utils/value.hpp"
#include <stack>
namespace matador::orm {
struct join_columns
{
std::string join_column;
std::string inverse_join_column;
};
class join_column_collector
{
public:
template<class Type>
join_columns collect()
{
join_columns_ = {};
Type obj;
matador::access::process(*this, obj);
return join_columns_;
}
template < class V >
void on_primary_key(const char * /*id*/, V &, typename std::enable_if<std::is_integral<V>::value && !std::is_same<bool, V>::value>::type* = 0) {}
void on_primary_key(const char * /*id*/, std::string &, size_t) {}
void on_revision(const char * /*id*/, unsigned long long &/*rev*/) {}
template<typename Type>
void on_attribute(const char * /*id*/, Type &, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template<class Pointer>
void on_belongs_to(const char * /*id*/, Pointer &obj, const utils::foreign_attributes &attr) {}
template<class Pointer>
void on_has_one(const char * /*id*/, Pointer &obj, const utils::foreign_attributes &attr) {}
template<class ContainerType>
void on_has_many(ContainerType &, const char *join_column, const utils::foreign_attributes &attr) {}
template<class ContainerType>
void on_has_many_to_many(const char * /*id*/, ContainerType &/*c*/, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &/*attr*/)
{
join_columns_.join_column = join_column;
join_columns_.inverse_join_column = inverse_join_column;
}
template<class ContainerType>
void on_has_many_to_many(const char * /*id*/, ContainerType &/*c*/, const utils::foreign_attributes &/*attr*/) {}
private:
join_columns join_columns_;
};
struct entity_query_data {
std::string root_table_name;
std::string pk_column_;
std::vector<sql::column> columns;
std::vector<query::join_data> joins;
std::unique_ptr<query::basic_condition> where_clause;
};
enum class query_build_error : std::uint8_t {
Ok = 0,
UnknownType,
MissingPrimaryKey,
UnexpectedError
};
class query_builder_exception final : public std::exception
{
public:
explicit query_builder_exception(const query_build_error error) : error_(error) {}
[[nodiscard]] query_build_error error() const { return error_; }
private:
const query_build_error error_;
};
class session_query_builder final
{
public:
explicit session_query_builder(const object::schema &scm)
: schema_(scm) {}
template<class EntityType, typename PrimaryKeyType>
utils::result<entity_query_data, query_build_error> build(const PrimaryKeyType &pk) {
auto info = schema_.info<EntityType>();
if (!info) {
return utils::failure(query_build_error::UnknownType);
}
pk_ = pk;
table_info_stack_.push(info.value());
entity_query_data_ = { info.value().get().name() };
try {
access::process(*this, info.value().get().prototype());
return {utils::ok(std::move(entity_query_data_))};
} catch (const query_builder_exception &ex) {
return {utils::failure(ex.error())};
} catch (...) {
return {utils::failure(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::failure(query_build_error::UnknownType);
}
pk_ = nullptr;
table_info_stack_.push(info.value());
entity_query_data_ = { info->name() };
try {
access::process(*this, info->prototype());
return {utils::ok(std::move(entity_query_data_))};
} catch (const query_builder_exception &ex) {
return {utils::failure(ex.error())};
} catch (...) {
return {utils::failure(query_build_error::UnexpectedError)};
}
}
template < class V >
void on_primary_key(const char *id, V &, std::enable_if_t<std::is_integral_v<V> && !std::is_same_v<bool, V>>* = nullptr)
{
push(id);
if (!is_root_entity()) {
return;
}
if (pk_.is_null()) {
entity_query_data_.pk_column_ = id;
} else if (pk_.is_integer()) {
auto t = std::make_shared<sql::table>(table_info_stack_.top().get().name());
auto v = *pk_.as<V>();
auto c = sql::column{t, id, ""};
auto co = std::make_unique<query::condition<sql::column, V>>(c, query::basic_condition::operand_type::EQUAL, v);
entity_query_data_.where_clause = std::move(co);
// entity_query_data_.where_clause = query::make_condition(c == v);
entity_query_data_.pk_column_ = id;
}
}
void on_primary_key(const char *id, std::string &, size_t);
void on_revision(const char *id, unsigned long long &/*rev*/);
template<typename Type>
void on_attribute(const char *id, Type &, const utils::field_attributes &/*attr*/ = utils::null_attributes)
{
push(id);
}
template<class Pointer>
void on_belongs_to(const char *id, Pointer &obj, const utils::foreign_attributes &attr)
{
on_foreign_object(id, obj, attr);
}
template<class Pointer>
void on_has_one(const char *id, Pointer &obj, const utils::foreign_attributes &attr)
{
on_foreign_object(id, obj, attr);
}
template<class ContainerType>
void on_has_many(ContainerType &, const char *join_column, const utils::foreign_attributes &attr)
{
if (attr.fetch() == utils::fetch_type::EAGER) {
const auto info = schema_.info<typename ContainerType::value_type::value_type>();
if (!info) {
throw query_builder_exception{query_build_error::UnknownType};
}
table_info_stack_.push(info.value());
typename ContainerType::value_type::value_type obj;
matador::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().get().name(), table_info_stack_.top().get().definition().primary_key()->name()}, {info->name, join_column});
}
}
template<class ContainerType>
void on_has_many_to_many(const char *id, ContainerType &c, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &attr)
{
if (attr.fetch() != utils::fetch_type::EAGER) {
return;
}
const auto info = schema_.info<typename ContainerType::value_type::value_type>();
if (!info) {
throw query_builder_exception{query_build_error::UnknownType};
}
table_info_stack_.push(info.value());
typename ContainerType::value_type::value_type obj;
matador::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(sql::column{table_info_stack_.top().get().name(), table_info_stack_.top().get().definition().primary_key()->name()}, {id, join_column});
append_join({id, inverse_join_column}, {info->name, pk->name()});
}
template<class ContainerType>
void on_has_many_to_many(const char *id, ContainerType &c, const utils::foreign_attributes &attr)
{
if (attr.fetch() != utils::fetch_type::EAGER) {
return;
}
const auto info = schema_.info<typename ContainerType::value_type::value_type>();
if (!info) {
throw query_builder_exception{query_build_error::UnknownType};
}
table_info_stack_.push(info.value());
typename ContainerType::value_type::value_type obj;
matador::access::process(*this , obj);
table_info_stack_.pop();
auto pk = info->prototype.primary_key();
if (!pk) {
throw query_builder_exception{query_build_error::MissingPrimaryKey};
}
const auto join_columns = join_column_collector_.collect<typename ContainerType::value_type::value_type>();
append_join({table_info_stack_.top().get().name(), table_info_stack_.top().get().definition().primary_key()->name()}, {id, join_columns.inverse_join_column});
append_join({id, join_columns.join_column}, {info->name, pk->name()});
}
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 sql::column &left, const sql::column &right);
private:
utils::value pk_;
std::stack<std::reference_wrapper<const object::basic_object_info>> table_info_stack_;
const object::schema &schema_;
entity_query_data entity_query_data_;
int column_index{0};
join_column_collector join_column_collector_;
};
template<class Pointer>
void session_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::access::process(*this, obj);
table_info_stack_.pop();
auto pk = info->get().definition().primary_key();
if (!pk) {
throw query_builder_exception{query_build_error::MissingPrimaryKey};
}
append_join(sql::column{table_info_stack_.top().get().name(), id}, sql::column{info->get().name(), pk->name()});
} else {
push(id);
}
}
}
#endif //QUERY_ENTITY_QUERY_BUILDER_HPP
@@ -12,8 +12,8 @@ class query_create_intermediate : public query_intermediate
public:
query_create_intermediate();
executable_query table(const sql::table &table, std::initializer_list<sql::column_definition> columns);
executable_query table(const sql::table &table, const std::vector<sql::column_definition> &columns);
executable_query table(const sql::table &table, std::initializer_list<object::attribute_definition> columns);
executable_query table(const sql::table &table, const std::vector<object::attribute_definition> &columns);
// template<class Type>
// executable_query table(const sql::table &table, const sql::schema &schema)
// {
@@ -8,7 +8,7 @@
#include "matador/query/query_part.hpp"
#include "matador/sql/column.hpp"
#include "matador/sql/column_definition.hpp"
#include "matador/object/attribute_definition.hpp"
#include "matador/sql/table.hpp"
#include "matador/utils/placeholder.hpp"
@@ -286,17 +286,17 @@ private:
class query_create_table_part final : public query_part
{
public:
query_create_table_part(sql::table table, std::vector<sql::column_definition> columns);
query_create_table_part(sql::table table, std::vector<object::attribute_definition> columns);
[[nodiscard]] const sql::table& table() const;
[[nodiscard]] const std::vector<sql::column_definition>& columns() const;
[[nodiscard]] const std::vector<object::attribute_definition>& columns() const;
private:
void accept(query_part_visitor &visitor) override;
private:
sql::table table_;
std::vector<sql::column_definition> columns_;
std::vector<object::attribute_definition> columns_;
};
class query_drop_part final : public query_part
+2 -2
View File
@@ -4,7 +4,7 @@
#include <memory>
#include <vector>
#include "matador/sql/column_definition.hpp"
#include "matador/object/attribute_definition.hpp"
#include "matador/sql/table.hpp"
#include "matador/query/query_part.hpp"
@@ -13,7 +13,7 @@ namespace matador::query {
struct query_data
{
std::vector<std::unique_ptr<query_part>> parts{};
std::vector<sql::column_definition> columns{};
std::vector<object::attribute_definition> columns{};
std::unordered_map<std::string, sql::table> tables{};
};
}
+129
View File
@@ -0,0 +1,129 @@
#ifndef QUERY_COLUMN_GENERATOR_HPP
#define QUERY_COLUMN_GENERATOR_HPP
#include "matador/utils/access.hpp"
#include "matador/utils/field_attributes.hpp"
#include "matador/utils/foreign_attributes.hpp"
#include "matador/sql/column.hpp"
#include "matador/object/schema.hpp"
#include <string>
#include <vector>
#include <stack>
namespace matador::sql {
class column_generator
{
private:
column_generator(std::vector<column> &column_infos,
const object::schema &ts,
const std::string &table_name,
bool force_lazy);
public:
~column_generator() = default;
template < class Type >
static std::vector<column> generate(const object::schema &scm, bool force_lazy = false)
{
const auto info = scm.info<Type>();
if (!info) {
return {};
}
std::vector<column> columns;
column_generator gen(columns, scm, info.value().get().name(), force_lazy);
Type obj;
matador::access::process(gen, obj);
return std::move(columns);
}
template < class V >
void on_primary_key(const char *id, V &, std::enable_if_t<std::is_integral_v<V> && !std::is_same_v<bool, V>>* = nullptr)
{
push(id);
}
void on_primary_key(const char *id, std::string &, size_t);
void on_revision(const char *id, unsigned long long &/*rev*/);
template<typename Type>
void on_attribute(const char *id, Type &, const utils::field_attributes &/*attr*/ = utils::null_attributes)
{
push(id);
}
template<class Pointer>
void on_belongs_to(const char *id, Pointer &, const utils::foreign_attributes &attr)
{
if (attr.fetch() == utils::fetch_type::LAZY || force_lazy_) {
push(id);
} else {
const auto info = table_schema_.info<typename Pointer::value_type>();
if (!info) {
return;
}
table_name_stack_.push(info.value().get().name());
typename Pointer::value_type obj;
matador::access::process(*this, obj);
table_name_stack_.pop();
}
}
template<class Pointer>
void on_has_one(const char *id, Pointer &, const utils::foreign_attributes &attr)
{
if (attr.fetch() == utils::fetch_type::LAZY || force_lazy_) {
push(id);
} else {
const auto info = table_schema_.info<typename Pointer::value_type>();
if (!info) {
return;
}
table_name_stack_.push(info.value().get().name());
typename Pointer::value_type obj;
matador::access::process(*this, obj);
table_name_stack_.pop();
}
}
template<class ContainerType>
void on_has_many(ContainerType &, const char *, const utils::foreign_attributes &attr)
{
if (attr.fetch() == utils::fetch_type::LAZY || force_lazy_) {
return;
}
const auto info = table_schema_.info<typename ContainerType::value_type::value_type>();
if (!info) {
return;
}
table_name_stack_.push(info.value().get().name());
typename ContainerType::value_type::value_type obj;
matador::access::process(*this, obj);
table_name_stack_.pop();
}
template<class ContainerType>
void on_has_many_to_many(const char *id, ContainerType &c, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &attr)
{
}
template<class ContainerType>
void on_has_many_to_many(const char *id, ContainerType &c, const utils::foreign_attributes &attr)
{
}
private:
void push(const std::string &column_name);
private:
std::stack<std::string> table_name_stack_;
std::vector<column> &column_infos_;
const object::schema &table_schema_;
int column_index{0};
bool force_lazy_{false};
};
}
#endif //QUERY_COLUMN_GENERATOR_HPP
+2 -2
View File
@@ -2,7 +2,7 @@
#define QUERY_CONNECTION_HPP
#include "matador/sql/abstract_sql_logger.hpp"
#include "matador/sql/column_definition.hpp"
#include "matador/object/attribute_definition.hpp"
#include "matador/sql/connection_info.hpp"
#include "matador/sql/executor.hpp"
#include "matador/sql/statement.hpp"
@@ -126,7 +126,7 @@ public:
*/
[[nodiscard]] utils::result<void, utils::error> rollback() const;
[[nodiscard]] utils::result<std::vector<column_definition>, utils::error> describe(const std::string &table_name) const;
[[nodiscard]] utils::result<std::vector<object::attribute_definition>, utils::error> describe(const std::string &table_name) const;
[[nodiscard]] utils::result<bool, utils::error> exists(const std::string &schema_name, const std::string &table_name) const;
[[nodiscard]] utils::result<bool, utils::error> exists(const std::string &table_name) const;
@@ -3,7 +3,7 @@
#include <memory>
#include "matador/sql/column_definition.hpp"
#include "matador/object/attribute_definition.hpp"
#include "matador/sql/connection_info.hpp"
#include "matador/sql/query_context.hpp"
#include "matador/utils/error.hpp"
@@ -36,7 +36,7 @@ public:
virtual utils::result<std::unique_ptr<query_result_impl>, utils::error> fetch(const query_context &context) = 0;
virtual utils::result<std::unique_ptr<statement_impl>, utils::error> prepare(const query_context &context) = 0;
virtual utils::result<std::vector<column_definition>, utils::error> describe(const std::string &table) = 0;
virtual utils::result<std::vector<object::attribute_definition>, utils::error> describe(const std::string &table) = 0;
virtual utils::result<bool, utils::error> exists(const std::string &schema_name, const std::string &table_name) = 0;
[[nodiscard]] const class dialect &dialect() const;
@@ -8,7 +8,7 @@
#include "matador/sql/interface/query_result_reader.hpp"
#include "matador/sql/column_definition.hpp"
#include "matador/object/attribute_definition.hpp"
#include <memory>
#include <string>
@@ -61,8 +61,8 @@ private:
class query_result_impl
{
public:
query_result_impl(std::unique_ptr<query_result_reader> &&reader, std::vector<column_definition> &&prototype, size_t column_index = 0);
query_result_impl(std::unique_ptr<query_result_reader> &&reader, const std::vector<column_definition> &prototype, size_t column_index = 0);
query_result_impl(std::unique_ptr<query_result_reader> &&reader, std::vector<object::attribute_definition> &&prototype, size_t column_index = 0);
query_result_impl(std::unique_ptr<query_result_reader> &&reader, const std::vector<object::attribute_definition> &prototype, size_t column_index = 0);
template<typename ValueType>
void on_primary_key(const char *id, ValueType &value, std::enable_if_t<std::is_integral_v<ValueType> && !std::is_same_v<bool, ValueType>>* = nullptr)
@@ -149,11 +149,11 @@ public:
return true;
}
[[nodiscard]] const std::vector<column_definition>& prototype() const;
[[nodiscard]] const std::vector<object::attribute_definition>& prototype() const;
protected:
size_t column_index_ = 0;
std::vector<column_definition> prototype_;
std::vector<object::attribute_definition> prototype_;
std::unique_ptr<query_result_reader> reader_;
detail::pk_reader pk_reader_;
};
@@ -161,7 +161,7 @@ protected:
namespace detail {
template<typename ValueType>
void detail::pk_reader::on_primary_key(const char *id, ValueType &value, std::enable_if_t<std::is_integral_v<ValueType> && !std::is_same_v<bool, ValueType>> *)
void pk_reader::on_primary_key(const char *id, ValueType &value, std::enable_if_t<std::is_integral_v<ValueType> && !std::is_same_v<bool, ValueType>> *)
{
utils::data_type_traits<ValueType>::read_value(reader_, id, column_index_++, value);
}
+2 -2
View File
@@ -1,7 +1,7 @@
#ifndef QUERY_QUERY_DATA_HPP
#define QUERY_QUERY_DATA_HPP
#include "matador/sql/column_definition.hpp"
#include "matador/object/attribute_definition.hpp"
#include "matador/sql/table.hpp"
#include "matador/utils/types.hpp"
@@ -25,7 +25,7 @@ struct query_context
sql_command command{};
std::string command_name;
sql::table table{""};
std::vector<column_definition> prototype;
std::vector<object::attribute_definition> prototype;
std::vector<std::string> result_vars;
std::vector<std::string> bind_vars;
std::vector<utils::database_type> bind_types;
+3 -3
View File
@@ -1,7 +1,7 @@
#ifndef QUERY_QUERY_RESULT_HPP
#define QUERY_QUERY_RESULT_HPP
#include "matador/sql/column_definition.hpp"
#include "matador/object/attribute_definition.hpp"
#include "matador/sql/internal/query_result_impl.hpp"
@@ -111,13 +111,13 @@ private:
namespace detail {
template < typename Type >
Type* create_prototype(const std::vector<column_definition> &/*prototype*/)
Type* create_prototype(const std::vector<object::attribute_definition> &/*prototype*/)
{
return new Type{};
}
template <>
record* create_prototype<record>(const std::vector<column_definition> &prototype);
record* create_prototype<record>(const std::vector<object::attribute_definition> &prototype);
}
+1 -2
View File
@@ -10,8 +10,7 @@ namespace matador::sql {
struct column;
struct table
{
struct table {
table() = default;
table(const char *name); // NOLINT(*-explicit-constructor)
table(std::string name); // NOLINT(*-explicit-constructor)
+1 -1
View File
@@ -27,7 +27,7 @@ inline constraints operator&(constraints a, constraints b)
inline constraints& operator|= (constraints& a, constraints b) { return (constraints&)((int&)a |= (int)b); }
inline constraints& operator&= (constraints& a, constraints b) { return (constraints&)((int&)a &= (int)b); }
inline bool is_constraint_set(constraints source, constraints needle)
inline bool is_constraint_set(const constraints source, const constraints needle)
{
return static_cast<int>(source & needle) > 0;
}
+1 -1
View File
@@ -27,7 +27,7 @@ private:
fetch_type fetch_{fetch_type::LAZY};
};
const utils::foreign_attributes default_foreign_attributes {};
const foreign_attributes default_foreign_attributes {};
}