initial matador ng commit

This commit is contained in:
2025-02-02 20:37:12 +01:00
parent 19de5714f4
commit ded3daceb3
378 changed files with 14913 additions and 13431 deletions
@@ -0,0 +1,40 @@
#ifndef BASIC_PROTOTYPE_INFO_HPP
#define BASIC_PROTOTYPE_INFO_HPP
#include <typeindex>
namespace matador::object {
class schema_node;
class basic_object_info {
public:
virtual ~basic_object_info() = default;
[[nodiscard]] std::type_index type_index() const;
protected:
basic_object_info(schema_node &node, std::type_index type_index);
protected:
schema_node &node_; /**< prototype node of the represented object type */
std::type_index type_index_; /**< type index of the represented object type */
};
template<typename Type>
class object_info final : public basic_object_info {
public:
explicit object_info(schema_node &node)
: basic_object_info(node, typeid(Type)) {}
};
namespace detail {
struct null_type {};
}
using null_info = object_info<detail::null_type>;
}
#endif //BASIC_PROTOTYPE_INFO_HPP
+32
View File
@@ -0,0 +1,32 @@
#ifndef OBJECT_ERROR_CODE_HPP
#define OBJECT_ERROR_CODE_HPP
#include <cstdint>
#include <system_error>
namespace matador::object {
enum class error_code : uint8_t {
OK = 0,
NodeNotFound = 1,
NodeAlreadyExists = 2,
Failure,
};
class object_category_impl final : public std::error_category
{
public:
[[nodiscard]] const char* name() const noexcept override;
[[nodiscard]] std::string message(int ev) const override;
};
const std::error_category& object_category();
std::error_code make_error_code(error_code e);
std::error_condition make_error_condition(error_code e);
}
template <>
struct std::is_error_code_enum<matador::object::error_code> : true_type {};
#endif //OBJECT_ERROR_CODE_HPP
+63
View File
@@ -0,0 +1,63 @@
#ifndef SCHEMA_HPP
#define SCHEMA_HPP
#include "matador/object/error_code.hpp"
#include "matador/object/schema_node.hpp"
#include "matador/utils/result.hpp"
#include "matador/utils/error.hpp"
#include <memory>
#include <string>
#include <unordered_map>
namespace matador::object {
class schema {
public:
schema();
template <typename Type>
utils::result<void, utils::error> attach(const std::string name, const std::string &parent = "") {
auto node = schema_node::make_node<Type>(*this, name);
attach_node(node, parent);
return utils::ok<void>();
}
template <typename Type, typename ParentType>
utils::result<void, utils::error> attach(const std::string name) {
// auto node = std::make_unique<schema_node>(*this);
return utils::ok<void>();
}
[[nodiscard]] bool empty() const;
[[nodiscard]] size_t size() const;
private:
using t_node_map = std::unordered_map<std::string, std::shared_ptr<schema_node>>;
// type_index -> [name -> prototype]
using t_type_index_node_map = std::unordered_map<std::type_index, t_node_map>;
using node_ptr = std::shared_ptr<schema_node>;
utils::result<std::shared_ptr<schema_node>, utils::error> attach_node(const std::shared_ptr<schema_node> &node,
const std::string &parent);
utils::result<std::shared_ptr<schema_node>, utils::error> find_parent(const std::string &name) const;
utils::result<std::shared_ptr<schema_node>, utils::error> find_node(const std::string &name) const;
utils::result<std::shared_ptr<schema_node>, utils::error> push_back_child(const node_ptr &parent, const node_ptr &child);
bool has_node(const std::type_index& index, const std::string &name) const;
private:
std::shared_ptr<schema_node> root_;
t_node_map node_map_;
t_type_index_node_map type_index_node_map_;
};
}
#endif //SCHEMA_HPP
+75
View File
@@ -0,0 +1,75 @@
#ifndef SCHEMA_NODE_HPP
#define SCHEMA_NODE_HPP
#include "matador/object/basic_object_info.hpp"
#include <memory>
#include <string>
namespace matador::object {
class schema;
class schema_node final {
public:
template < typename Type >
static std::shared_ptr<schema_node> make_node(schema& tree, const std::string& name) {
return std::make_shared<schema_node>(tree, name, static_cast<Type*>(nullptr));
}
schema_node(const schema_node& other) = delete;
schema_node(schema_node&& other) = default;
schema_node& operator=(const schema_node& other) = delete;
schema_node& operator=(schema_node&& other) = delete;
~schema_node() = default;
[[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);
private:
explicit schema_node(schema& tree);
template < typename Type >
schema_node(schema& tree, std::string name, Type *obj)
: schema_(tree)
, info_(std::make_unique<object_info<Type>>(*this))
, first_child_(std::make_shared<schema_node>(tree))
, last_child_(std::make_shared<schema_node>(tree))
, name_(std::move(name)) {
first_child_->next_sibling_ = last_child_;
last_child_->previous_sibling_ = first_child_;
}
private:
friend schema;
schema &schema_;
std::unique_ptr<basic_object_info> info_;
std::shared_ptr<schema_node> parent_;
std::shared_ptr<schema_node> previous_sibling_;
std::shared_ptr<schema_node> next_sibling_;
std::shared_ptr<schema_node> first_child_;
std::shared_ptr<schema_node> last_child_;
std::string name_;
size_t depth_{0};
};
}
#endif //SCHEMA_NODE_HPP
@@ -0,0 +1,63 @@
#ifndef ATTRIBUTE_STRING_WRITER_HPP
#define ATTRIBUTE_STRING_WRITER_HPP
#include "matador/utils/attribute_writer.hpp"
#include <optional>
namespace matador::sql {
class dialect;
class connection_impl;
}
namespace matador::query {
class attribute_string_writer final : public utils::attribute_writer
{
public:
attribute_string_writer(const sql::dialect &d, std::optional<std::reference_wrapper<const sql::connection_impl>> conn);
template<typename Type>
[[nodiscard]] std::string to_string(const Type &value)
{
result_.clear();
write_value(0, value);
return result_;
}
[[nodiscard]] const sql::dialect& dialect() const;
void write_value(size_t pos, const int8_t& x) override;
void write_value(size_t pos, const int16_t& x) override;
void write_value(size_t pos, const int32_t& x) override;
void write_value(size_t pos, const int64_t& x) override;
void write_value(size_t pos, const uint8_t& x) override;
void write_value(size_t pos, const uint16_t& x) override;
void write_value(size_t pos, const uint32_t& x) override;
void write_value(size_t pos, const uint64_t& x) override;
void write_value(size_t pos, const bool& x) override;
void write_value(size_t pos, const float& x) override;
void write_value(size_t pos, const double& x) override;
void write_value(size_t pos, const time& x) override;
void write_value(size_t pos, const date& x) override;
void write_value(size_t pos, const char* x) override;
void write_value(size_t pos, const char* x, size_t size) override;
void write_value(size_t pos, const std::string& x) override;
void write_value(size_t pos, const std::string& x, size_t size) override;
void write_value(size_t pos, const utils::blob& x) override;
void write_value(size_t pos, const utils::value& x, size_t size) override;
private:
std::string result_;
const sql::dialect &dialect_;
std::optional<std::reference_wrapper<const sql::connection_impl>> conn_;
};
// "This is a binary Data string" as binary data:
// MySQL: X'5468697320697320612062616E617279204461746120737472696E67'
// Postgres: E'\\x5468697320697320612062616E617279204461746120737472696E67'
// MSSQL: 0x5468697320697320612062616E617279204461746120737472696E67
// Sqlite: X'5468697320697320612062616E617279204461746120737472696E67'
}
#endif //ATTRIBUTE_STRING_WRITER_HPP
@@ -8,9 +8,11 @@
#include <string>
namespace matador::sql {
class dialect;
class query_context;
struct query_context;
}
namespace matador::query {
class basic_condition
{
@@ -18,7 +20,7 @@ public:
basic_condition() = default;
virtual ~basic_condition() = default;
enum class operand_t : uint8_t
enum class operand_type : uint8_t
{
EQUAL = 0,
NOT_EQUAL,
@@ -33,26 +35,26 @@ public:
LIKE
};
virtual std::string evaluate(const dialect &dialect, query_context &query) const = 0;
virtual std::string evaluate(const sql::dialect &dialect, sql::query_context &query) const = 0;
static std::unordered_map<operand_t, std::string> operands;
static std::unordered_map<operand_type, std::string> operands;
};
class basic_column_condition : public basic_condition
{
public:
column field_;
sql::column field_;
std::string operand;
basic_column_condition(column fld, basic_condition::operand_t op);
basic_column_condition(sql::column fld, operand_type op);
};
class basic_in_condition : public basic_condition
{
public:
column field_;
sql::column field_;
explicit basic_in_condition(column fld);
explicit basic_in_condition(sql::column fld);
[[nodiscard]] virtual size_t size() const = 0;
};
@@ -1,17 +1,17 @@
#ifndef QUERY_CONDITION_HPP
#define QUERY_CONDITION_HPP
#include "matador/sql/any_type_to_string_visitor.hpp"
#include "matador/sql/query_result.hpp"
#include "matador/sql/basic_condition.hpp"
#include "matador/query/basic_condition.hpp"
#include "matador/sql/dialect.hpp"
#include "matador/sql/placeholder.hpp"
#include "matador/sql/query_context.hpp"
#include "matador/utils/placeholder.hpp"
#include <memory>
#include <utility>
namespace matador::sql {
namespace matador::query {
/**
* @class condition
@@ -28,58 +28,55 @@ namespace matador::sql {
/// @cond MATADOR_DEV
class query_select;
template<class L, class R, class Enabled = void>
class condition;
template<>
class condition<column, placeholder, typename std::enable_if<true>::type> : public basic_column_condition
class condition<sql::column, utils::placeholder, std::enable_if_t<true>> final : public basic_column_condition
{
public:
condition(const column &fld, basic_condition::operand_t op, const placeholder &val);
condition(const sql::column &fld, operand_type op, const utils::placeholder &val);
placeholder value;
utils::placeholder value;
std::string evaluate(const dialect &d, query_context &query) const override;
std::string evaluate(const sql::dialect &d, sql::query_context &query) const override;
};
template<class T>
class condition<column, T, typename std::enable_if<
std::is_scalar<T>::value &&
!std::is_enum<T>::value &&
!std::is_same<std::string, T>::value &&
!std::is_same<const char*, T>::value>::type> : public basic_column_condition
class condition<sql::column, T, std::enable_if_t<
std::is_scalar_v<T> &&
!std::is_same_v<std::string, T> &&
!std::is_same_v<const char*, T>>> final : public basic_column_condition
{
public:
condition(const column &fld, basic_condition::operand_t op, T val)
condition(const sql::column &fld, const operand_type op, T val)
: basic_column_condition(fld, op)
, value(val)
{ }
T value;
std::string evaluate(const dialect &d, query_context &query) const override
std::string evaluate(const sql::dialect &d, sql::query_context &query) const override
{
query.bind_vars.emplace_back(field_.name);
return d.prepare_identifier(field_) + " " + operand + " " + std::to_string(value);
return d.prepare_condition(field_) + " " + operand + " " + std::to_string(value);
}
};
template<class T>
class condition<column, T, typename std::enable_if<
std::is_same<std::string, T>::value ||
std::is_same<const char*, T>::value>::type> : public basic_column_condition
class condition<sql::column, T, std::enable_if_t<
std::is_same_v<std::string, T> ||
std::is_same_v<const char*, T>>>final : public basic_column_condition
{
public:
condition(const column &fld, basic_condition::operand_t op, T val)
condition(const sql::column &fld, const operand_type op, T val)
: basic_column_condition(fld, op)
,value(val)
{ }
T value;
std::string evaluate(const dialect &d, query_context &query) const override
std::string evaluate(const sql::dialect &d, sql::query_context &query) const override
{
query.bind_vars.emplace_back(field_.name);
return d.prepare_identifier(field_) + " " + operand + " '" + value + "'";
@@ -87,61 +84,39 @@ public:
};
template<class T>
class condition<column, T, std::enable_if_t<std::is_enum_v<T>>> final : public basic_column_condition
{
public:
condition(const column &fld, basic_condition::operand_t op, T val)
: basic_column_condition(fld, op)
, value(val)
{ }
T value;
std::string evaluate(const dialect &d, query_context &query) const override
{
auto at = data_type_traits<T>::create_value(value);
any_type_to_string_visitor value_to_string(d, query);
std::visit(value_to_string, at);
return value_to_string.result + " " + operand + " " + d.prepare_identifier(field_);
}
};
template<class T>
class condition<T, column, std::enable_if_t<
class condition<T, sql::column, std::enable_if_t<
std::is_scalar_v<T> &&
!std::is_same_v<std::string, T> &&
!std::is_same_v<const char*, T>>> final : public basic_column_condition
{
public:
condition(T val, basic_condition::operand_t op, const column &fld)
condition(T val, const operand_type op, const sql::column &fld)
: basic_column_condition(fld, op)
, value(val)
{ }
T value;
std::string evaluate(const dialect &d, query_context &query) const override
std::string evaluate(const sql::dialect &d, sql::query_context &query) const override
{
return std::to_string(value) + " " + operand + " " + d.prepare_identifier(field_);
}
};
template<class T>
class condition<T, column, typename std::enable_if<
std::is_same<std::string, T>::value ||
std::is_same<const char*, T>::value>::type> : public basic_column_condition
class condition<T, sql::column, std::enable_if_t<
std::is_same_v<std::string, T> ||
std::is_same_v<const char*, T>>> final : public basic_column_condition
{
public:
condition(T val, basic_condition::operand_t op, const column &fld)
condition(T val, const operand_type op, const sql::column &fld)
: basic_column_condition(fld, op)
, value(val)
{ }
T value;
std::string evaluate(const dialect &d, query_context &query) const override
std::string evaluate(const sql::dialect &d, sql::query_context &query) const override
{
return "'" + std::to_string(value) + "' " + operand + " " + d.prepare_identifier(field_);
}
@@ -160,18 +135,18 @@ public:
* @endcode
*/
template < class V >
class condition<column, std::initializer_list<V>> : public basic_in_condition {
class condition<sql::column, std::initializer_list<V>> final : public basic_in_condition {
public:
/**
* @brief Creates an IN condition
*
* Creates an IN condition for the given column and
* Creates an IN condition for the given sql::column and
* the given list of arguments.
*
* @param col Column for the IN condition
* @param args List of arguments
*/
condition(const column &col, const std::initializer_list<V> &args)
condition(const sql::column &col, const std::initializer_list<V> &args)
: basic_in_condition(col), args_(args) {}
/**
@@ -181,9 +156,10 @@ public:
* query string based on the given compile type
*
* @param d The d used to evaluate
* @param query Query to evaluate
* @return A condition IN part of the query
*/
std::string evaluate(const dialect &d, query_context &query) const override {
std::string evaluate(const sql::dialect &d, sql::query_context &query) const override {
auto count = size();
for (size_t i = 0; i < count; ++i) {
query.bind_vars.emplace_back(field_.name);
@@ -220,15 +196,15 @@ private:
/**
* @brief Condition class representing an IN condition
*
* This class represents an query IN condition and evaluates to
* This class represents a query IN condition and evaluates to
* this condition based on the current database d
*
* @code
* WHERE age IN (select age_value from <table>)
* WHERE age IN (select age_value from table)
* @endcode
*/
template <>
class condition<column, query_context> : public basic_column_condition
class condition<sql::column, sql::query_context> final : public basic_column_condition
{
public:
/**
@@ -242,7 +218,7 @@ public:
* @param op Operand of the condition
* @param q The query to be evaluated to the IN arguments
*/
condition(column col, basic_condition::operand_t op, const query_context &q);
condition(sql::column col, operand_type op, sql::query_context &q);
/**
* @brief Evaluates the condition
@@ -251,12 +227,13 @@ public:
* query string based on the given compile type
*
* @param d The d used to evaluate
* @param query Query to evaluate
* @return A condition IN part of the query
*/
std::string evaluate(const dialect &d, query_context &query) const override;
std::string evaluate(const sql::dialect &d, sql::query_context &query) const override;
private:
query_context query_;
sql::query_context &query_;
};
/**
@@ -268,7 +245,7 @@ private:
* @tparam T The type of the boundary values
*/
template < class T >
class condition<column, std::pair<T, T>> : public basic_condition {
class condition<sql::column, std::pair<T, T>> final : public basic_condition {
public:
/**
* @brief Create a new between condition
@@ -276,7 +253,7 @@ public:
* @param col The column for the range check
* @param range The boundary values defining the range
*/
condition(column col, const std::pair<T, T> &range)
condition(sql::column col, const std::pair<T, T> &range)
: field_(std::move(col)), range_(range) {}
/**
@@ -286,16 +263,17 @@ public:
* based on the given compile type
*
* @param d The d used to evaluate
* @param query Query to evaluate
* @return A condition BETWEEN part of the query
*/
std::string evaluate(const dialect &d, query_context &query) const override {
std::string evaluate(const sql::dialect &d, sql::query_context &query) const override {
query.bind_vars.emplace_back(field_.name);
query.bind_vars.emplace_back(field_.name);
return d.prepare_identifier(field_) + " BETWEEN " + std::to_string(range_.first) + " AND " + std::to_string(range_.second);
}
private:
column field_;
sql::column field_;
std::pair<T, T> range_;
};
@@ -312,7 +290,7 @@ private:
* @tparam R2 The right hand type of the right operator
*/
template<class L1, class R1, class L2, class R2>
class condition<condition<L1, R1>, condition<L2, R2>> : public basic_condition
class condition<condition<L1, R1>, condition<L2, R2>> final : public basic_condition
{
public:
/**
@@ -321,31 +299,32 @@ public:
* @param r right hand operator of the condition
* @param op The operand (AND or OR)
*/
condition(condition<L1, R1> &&l, condition<L2, R2> &&r, basic_condition::operand_t op)
condition(condition<L1, R1> &&l, condition<L2, R2> &&r, const operand_type op)
: left(std::move(l)), right(std::move(r)), operand(op) { }
/**
* @brief Evaluates the condition
*
* @param d The d used to evaluate
* @param query Query to evaluate
* @return The evaluated string based on the compile type
*/
std::string evaluate(const dialect &d, query_context &query) const override
std::string evaluate(const sql::dialect &d, sql::query_context &query) const override
{
// ensure the numbering order for host vars
auto cl = left.evaluate(d, query);
auto cr = right.evaluate(d, query);
if (operand == basic_condition::operand_t::AND) {
return "(" + cl + " " + basic_condition::operands[operand] + " " + cr + ")";
if (operand == operand_type::AND) {
return "(" + cl + " " + operands[operand] + " " + cr + ")";
} else {
return cl + " " + basic_condition::operands[operand] + " " + cr;
return cl + " " + operands[operand] + " " + cr;
}
}
private:
condition<L1, R1> left;
condition<L2, R2> right;
basic_condition::operand_t operand;
basic_condition::operand_type operand;
};
/**
@@ -357,7 +336,7 @@ private:
* @tparam R Right hand type of the condition to be negated
*/
template<class L, class R>
class condition<condition<L, R>, void> : public basic_condition
class condition<condition<L, R>, void> final : public basic_condition
{
public:
/**
@@ -365,17 +344,18 @@ public:
* @param c The condition to be negated
*/
condition(const condition<L, R> &c) // NOLINT(*-explicit-constructor)
: cond(c), operand(basic_condition::operands[basic_condition::operand_t::NOT]) { }
: cond(c), operand(operands[operand_type::NOT]) { }
/**
* @brief Evaluates the condition
*
* @param d The d used to evaluate
* @param query The context of the query
* @return The evaluated string based on the compile type
*/
std::string evaluate(const dialect &d, query_context &query) const override
std::string evaluate(const sql::dialect &d, sql::query_context &query) const override
{
return operand + " (" + cond.evaluate(d) + ")";
return operand + " (" + cond.evaluate(d, query) + ")";
}
private:
@@ -384,25 +364,23 @@ private:
};
template<>
class condition<column, column> : public basic_column_condition
class condition<sql::column, sql::column> final : public basic_column_condition
{
public:
condition(const column &a, basic_condition::operand_t op, column b)
condition(const sql::column &a, const operand_type op, sql::column b)
: basic_column_condition(a, op)
, other_column_(std::move(b)) {}
/**
* @brief Evaluates the condition
*
* @param d The d used to evaluate
* @param query The context of the query
* @return The evaluated string based on the compile type
*/
std::string evaluate(const dialect &d, query_context &query) const override
{
return d.prepare_identifier(field_) + " " + operand + " " + d.prepare_identifier(other_column_);
}
std::string evaluate(const sql::dialect &d, sql::query_context &query) const override;
private:
column other_column_;
sql::column other_column_;
};
/**
@@ -430,9 +408,9 @@ private:
* @return The condition object
*/
template < class V >
condition<column, std::initializer_list<V>> in(const column &col, std::initializer_list<V> args)
condition<sql::column, std::initializer_list<V>> in(const sql::column &col, std::initializer_list<V> args)
{
return condition<column, std::initializer_list<V>>(col, args);
return condition<sql::column, std::initializer_list<V>>(col, args);
}
/**
@@ -442,8 +420,7 @@ condition<column, std::initializer_list<V>> in(const column &col, std::initializ
* @param q The query to be executes as sub select
* @return The condition object
*/
condition<column, query_context> in(const column &col, const query_context &q);
condition<column, query_context> in(const column &col, const query_select &q);
condition<sql::column, sql::query_context> in(const sql::column &col, sql::query_context &&q);
/**
* @brief Creates a between condition.
@@ -458,9 +435,9 @@ condition<column, query_context> in(const column &col, const query_select &q);
* @return The condition object
*/
template<class T>
condition<column, std::pair<T, T>> between(const column &col, T low, T high)
condition<sql::column, std::pair<T, T>> between(const sql::column &col, T low, T high)
{
return condition<column, std::pair<T, T>>(col, std::make_pair(low, high));
return condition<sql::column, std::pair<T, T>>(col, std::make_pair(low, high));
}
/**
@@ -473,7 +450,7 @@ condition<column, std::pair<T, T>> between(const column &col, T low, T high)
* @param val The value to the like operator
* @return The like condition object
*/
condition<column, std::string> like(const column &col, const std::string &val);
condition<sql::column, std::string> like(const sql::column &col, const std::string &val);
/**
* @brief Condition equality operator for a column and a value
@@ -487,12 +464,12 @@ condition<column, std::string> like(const column &col, const std::string &val);
* @return The condition object representing the equality operation
*/
template<class T>
condition<column, T> operator==(const column &col, T val)
condition<sql::column, T> operator==(const sql::column &col, T val)
{
return condition<column, T>(col, basic_condition::operand_t::EQUAL, val);
return condition<sql::column, T>(col, basic_condition::operand_type::EQUAL, val);
}
condition<column, column> operator==(const column &a, const column &b);
condition<sql::column, sql::column> operator==(const sql::column &a, const sql::column &b);
/**
* @brief Condition equality method for a column and a query
@@ -504,12 +481,12 @@ condition<column, column> operator==(const column &a, const column &b);
* @param q The query to compare with
* @return The condition object representing the equality operation
*/
condition<column, query_context> equals(const column &col, query_context &q);
condition<sql::column, sql::query_context> equals(const sql::column &col, sql::query_context &q);
/**
* @brief Condition inequality operator for a column and a value
*
* Creates a condition condition object of a column and a value
* Creates a condition object of a column and a value
* checked on inequality.
*
* @tparam T The type of the value
@@ -518,9 +495,9 @@ condition<column, query_context> equals(const column &col, query_context &q);
* @return The condition object representing the inequality operation
*/
template<class T>
condition<column, T> operator!=(const column &col, T val)
condition<sql::column, T> operator!=(const sql::column &col, T val)
{
return condition<column, T>(col, basic_condition::operand_t::NOT_EQUAL, val);
return condition<sql::column, T>(col, basic_condition::operand_type::NOT_EQUAL, val);
}
/**
@@ -535,9 +512,9 @@ condition<column, T> operator!=(const column &col, T val)
* @return The condition object representing the less operation
*/
template<class T>
condition<column, T> operator<(const column &col, T val)
condition<sql::column, T> operator<(const sql::column &col, T val)
{
return condition<column, T>(col, basic_condition::operand_t::LESS, val);
return condition<sql::column, T>(col, basic_condition::operand_type::LESS, val);
}
/**
@@ -552,9 +529,9 @@ condition<column, T> operator<(const column &col, T val)
* @return The condition object representing the less or equal operation
*/
template<class T>
condition<column, T> operator<=(const column &col, T val)
condition<sql::column, T> operator<=(const sql::column &col, T val)
{
return condition<column, T>(col, basic_condition::operand_t::LESS_EQUAL, val);
return condition<sql::column, T>(col, basic_condition::operand_type::LESS_EQUAL, val);
}
/**
@@ -569,9 +546,9 @@ condition<column, T> operator<=(const column &col, T val)
* @return The condition object representing the greater operation
*/
template<class T>
condition<column, T> operator>(const column &col, T val)
condition<sql::column, T> operator>(const sql::column &col, T val)
{
return condition<column, T>(col, basic_condition::operand_t::GREATER, val);
return condition<sql::column, T>(col, basic_condition::operand_type::GREATER, val);
}
/**
@@ -586,9 +563,9 @@ condition<column, T> operator>(const column &col, T val)
* @return The condition object representing the greater or equal operation
*/
template<class T>
condition<column, T> operator>=(const column &col, T val)
condition<sql::column, T> operator>=(const sql::column &col, T val)
{
return condition<column, T>(col, basic_condition::operand_t::GREATER_EQUAL, val);
return condition<sql::column, T>(col, basic_condition::operand_type::GREATER_EQUAL, val);
}
/**
@@ -605,7 +582,7 @@ condition<column, T> operator>=(const column &col, T val)
template<class L1, class R1, class L2, class R2>
condition<condition<L1, R1>, condition<L2, R2>> operator&&(condition<L1, R1> l, condition<L2, R2> r)
{
return condition<condition<L1, R1>, condition<L2, R2>>(std::move(l), std::move(r), basic_condition::operand_t::AND);
return condition<condition<L1, R1>, condition<L2, R2>>(std::move(l), std::move(r), basic_condition::operand_type::AND);
}
/**
@@ -622,7 +599,7 @@ condition<condition<L1, R1>, condition<L2, R2>> operator&&(condition<L1, R1> l,
template<class L1, class R1, class L2, class R2>
condition<condition<L1, R1>, condition<L2, R2>> operator||(condition<L1, R1> l, condition<L2, R2> r)
{
return condition<condition<L1, R1>, condition<L2, R2>>(std::move(l), std::move(r), basic_condition::operand_t::OR);
return condition<condition<L1, R1>, condition<L2, R2>>(std::move(l), std::move(r), basic_condition::operand_type::OR);
}
/**
@@ -1,12 +1,12 @@
#ifndef QUERY_FK_VALUE_EXTRACTOR_HPP
#define QUERY_FK_VALUE_EXTRACTOR_HPP
#include "matador/sql/any_type.hpp"
#include "matador/utils/access.hpp"
#include "matador/utils/field_attributes.hpp"
#include "matador/utils/foreign_attributes.hpp"
#include "matador/utils/types.hpp"
namespace matador::sql::detail {
namespace matador::query::detail {
class fk_value_extractor
{
@@ -14,14 +14,14 @@ public:
fk_value_extractor() = default;
template<class Type>
any_type extract(Type &x)
utils::database_type extract(Type &x)
{
matador::utils::access::process(*this, x);
access::process(*this, x);
return value_;
}
template<typename ValueType>
void on_primary_key(const char *, ValueType &pk, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type* = 0)
void on_primary_key(const char *, ValueType &pk, std::enable_if_t<std::is_integral_v<ValueType> && !std::is_same_v<bool, ValueType>>* = nullptr)
{
value_ = pk;
}
@@ -35,13 +35,17 @@ public:
template<class Pointer>
void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, const char *, const char *, const utils::foreign_attributes &/*attr*/) {}
void on_has_many_to_many(const char *, ContainerType &, 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 *, ContainerType &, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, const utils::foreign_attributes &/*attr*/) {}
private:
any_type value_{};
utils::database_type value_{};
};
}
@@ -0,0 +1,27 @@
#ifndef EXECUTABLE_QUERY_HPP
#define EXECUTABLE_QUERY_HPP
#include "query_intermediate.hpp"
#include "../../utils/error.hpp"
#include "../../utils/result.hpp"
namespace matador::sql {
class executor;
class statement;
}
namespace matador::query {
class executable_query : public query_intermediate {
public:
using query_intermediate::query_intermediate;
[[nodiscard]] utils::result<size_t, utils::error> execute(const sql::executor &exec) const;
[[nodiscard]] utils::result<sql::statement, utils::error> prepare(const sql::executor &exec) const;
[[nodiscard]] std::string str(const sql::executor &exec) const;
};
}
#endif //EXECUTABLE_QUERY_HPP
@@ -0,0 +1,82 @@
#ifndef FETCHABLE_QUERY_HPP
#define FETCHABLE_QUERY_HPP
#include "query_intermediate.hpp"
#include "../query_compiler.hpp"
#include "../../sql/query_result.hpp"
#include "../../sql/record.hpp"
#include "../../utils/error.hpp"
#include "../../utils/result.hpp"
namespace matador::sql {
class executor;
class statement;
}
namespace matador::query {
class fetchable_query : public query_intermediate
{
protected:
using query_intermediate::query_intermediate;
public:
template < class Type >
utils::result<sql::query_result<Type>, utils::error> fetch_all(sql::executor &exec)
{
auto result = fetch(exec);
if (!result.is_ok()) {
return utils::error(result.err());
}
return utils::ok(sql::query_result<Type>(result.release()));
}
[[nodiscard]] utils::result<sql::query_result<sql::record>, utils::error> fetch_all(const sql::executor &exec) const;
template < class Type >
utils::result<std::unique_ptr<Type>, utils::error> fetch_one(const sql::executor &exec)
{
auto result = fetch(exec);
if (!result.is_ok()) {
return utils::error(result.err());
}
auto objects = sql::query_result<Type>(result.release());
auto first = objects.begin();
if (first == objects.end()) {
return utils::ok(std::unique_ptr<Type>{nullptr});
}
return utils::ok(std::unique_ptr<Type>{first.release()});
}
[[nodiscard]] utils::result<std::optional<sql::record>, utils::error> fetch_one(const sql::executor &exec) const;
template<typename Type>
utils::result<std::optional<Type>, utils::error> fetch_value(const sql::executor &exec)
{
const auto result = fetch_one(exec);
if (!result.is_ok()) {
return utils::failure(result.err());
}
if (result->has_value()) {
return utils::ok(std::optional<Type>{result->value().at(0).as<Type>().value()});
}
return utils::ok(std::optional<Type>{std::nullopt});
}
[[nodiscard]] utils::result<sql::statement, utils::error> prepare(const sql::executor &exec) const;
[[nodiscard]] std::string str(const sql::executor &exec) const;
private:
[[nodiscard]] utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetch(const sql::executor &exec) const;
};
}
#endif //FETCHABLE_QUERY_HPP
@@ -0,0 +1,27 @@
#ifndef QUERY_CREATE_INTERMEDIATE_HPP
#define QUERY_CREATE_INTERMEDIATE_HPP
#include "matador/query/intermediates/query_intermediate.hpp"
#include "matador/query/intermediates/executable_query.hpp"
namespace matador::query {
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);
// template<class Type>
// executable_query table(const sql::table &table, const sql::schema &schema)
// {
// return this->table(table, column_definition_generator::generate<Type>(schema));
// }
};
}
#endif //QUERY_CREATE_INTERMEDIATE_HPP
@@ -0,0 +1,29 @@
#ifndef QUERY_DELETE_FROM_INTERMEDIATE_HPP
#define QUERY_DELETE_FROM_INTERMEDIATE_HPP
#include "matador/query/intermediates/executable_query.hpp"
#include "matador/query/basic_condition.hpp"
#include "matador/query/intermediates/query_execute_where_intermediate.hpp"
namespace matador::query {
class query_delete_from_intermediate : public executable_query
{
public:
using executable_query::executable_query;
template<class Condition>
query_execute_where_intermediate where(const Condition &cond)
{
return where_clause(std::make_unique<Condition>(std::move(cond)));
}
private:
query_execute_where_intermediate where_clause(std::unique_ptr<basic_condition> &&cond);
};
}
#endif //QUERY_DELETE_FROM_INTERMEDIATE_HPP
@@ -0,0 +1,20 @@
#ifndef QUERY_DELETE_INTERMEDIATE_HPP
#define QUERY_DELETE_INTERMEDIATE_HPP
#include "matador/query/intermediates/query_intermediate.hpp"
namespace matador::query {
class query_delete_from_intermediate;
class query_delete_intermediate : public query_intermediate
{
public:
query_delete_intermediate();
query_delete_from_intermediate from(const sql::table &table);
};
}
#endif //QUERY_DELETE_INTERMEDIATE_HPP
@@ -0,0 +1,18 @@
#ifndef QUERY_DROP_INTERMEDIATE_HPP
#define QUERY_DROP_INTERMEDIATE_HPP
#include "matador/query/intermediates/executable_query.hpp"
namespace matador::query {
class query_drop_intermediate : query_intermediate
{
public:
query_drop_intermediate();
executable_query table(const sql::table &table);
};
}
#endif //QUERY_DROP_INTERMEDIATE_HPP
@@ -0,0 +1,20 @@
#ifndef QUERY_EXECUTE_LIMIT_INTERMEDIATE_HPP
#define QUERY_EXECUTE_LIMIT_INTERMEDIATE_HPP
#include "matador/query/intermediates/executable_query.hpp"
namespace matador::query {
class query_execute_offset_intermediate;
class query_execute_limit_intermediate : public executable_query
{
public:
using executable_query::executable_query;
query_execute_offset_intermediate offset(size_t offset);
};
}
#endif //QUERY_EXECUTE_LIMIT_INTERMEDIATE_HPP
@@ -0,0 +1,20 @@
#ifndef QUERY_EXECUTE_OFFSET_INTERMEDIATE_HPP
#define QUERY_EXECUTE_OFFSET_INTERMEDIATE_HPP
#include "matador/query/intermediates/executable_query.hpp"
namespace matador::query {
class query_execute_limit_intermediate;
class query_execute_offset_intermediate : public executable_query
{
public:
using executable_query::executable_query;
query_execute_limit_intermediate limit(size_t limit);
};
}
#endif //QUERY_EXECUTE_OFFSET_INTERMEDIATE_HPP
@@ -0,0 +1,21 @@
#ifndef QUERY_EXECUTE_ORDER_BY_INTERMEDIATE_HPP
#define QUERY_EXECUTE_ORDER_BY_INTERMEDIATE_HPP
#include "matador/query/intermediates/query_intermediate.hpp"
namespace matador::query {
class query_execute_order_direction_intermediate;
class query_execute_order_by_intermediate : public query_intermediate
{
public:
using query_intermediate::query_intermediate;
query_execute_order_direction_intermediate asc();
query_execute_order_direction_intermediate desc();
};
}
#endif //QUERY_EXECUTE_ORDER_BY_INTERMEDIATE_HPP
@@ -0,0 +1,20 @@
#ifndef QUERY_EXECUTE_ORDER_DIRECTION_INTERMEDIATE_HPP
#define QUERY_EXECUTE_ORDER_DIRECTION_INTERMEDIATE_HPP
#include "matador/query/intermediates/executable_query.hpp"
namespace matador::query {
class query_execute_limit_intermediate;
class query_execute_order_direction_intermediate : public executable_query
{
public:
using executable_query::executable_query;
query_execute_limit_intermediate limit(size_t limit);
};
}
#endif //QUERY_EXECUTE_ORDER_DIRECTION_INTERMEDIATE_HPP
@@ -0,0 +1,22 @@
#ifndef QUERY_EXECUTE_WHERE_INTERMEDIATE_HPP
#define QUERY_EXECUTE_WHERE_INTERMEDIATE_HPP
#include "matador/query/intermediates/executable_query.hpp"
namespace matador::query {
class query_execute_limit_intermediate;
class query_execute_order_by_intermediate;
class query_execute_where_intermediate : public executable_query
{
public:
using executable_query::executable_query;
query_execute_limit_intermediate limit(size_t limit);
query_execute_order_by_intermediate order_by(const sql::column &col);
};
}
#endif //QUERY_EXECUTE_WHERE_INTERMEDIATE_HPP
@@ -0,0 +1,40 @@
#ifndef QUERY_FROM_INTERMEDIATE_HPP
#define QUERY_FROM_INTERMEDIATE_HPP
#include "matador/query/intermediates/fetchable_query.hpp"
#include "matador/query/join_data.hpp"
#include "matador/query/intermediates/query_where_intermediate.hpp"
namespace matador::query {
class query_join_intermediate;
class query_from_intermediate : public fetchable_query
{
public:
using fetchable_query::fetchable_query;
query_join_intermediate join_left(const sql::table &t);
query_from_intermediate join_left(join_data &data);
query_from_intermediate join_left(std::vector<join_data> &data_vector);
template<class Condition>
query_where_intermediate where(const Condition &cond)
{
return where_clause(std::make_unique<Condition>(std::move(cond)));
}
query_where_intermediate where(std::unique_ptr<basic_condition> &&cond)
{
return where_clause(std::move(cond));
}
query_group_by_intermediate group_by(const sql::column &col);
query_order_by_intermediate order_by(const sql::column &col);
private:
query_where_intermediate where_clause(std::unique_ptr<basic_condition> &&cond);
};
}
#endif //QUERY_FROM_INTERMEDIATE_HPP
@@ -0,0 +1,20 @@
#ifndef QUERY_GROUP_BY_INTERMEDIATE_HPP
#define QUERY_GROUP_BY_INTERMEDIATE_HPP
#include "matador/query/intermediates/fetchable_query.hpp"
namespace matador::query {
class query_order_by_intermediate;
class query_group_by_intermediate : public fetchable_query
{
public:
using fetchable_query::fetchable_query;
query_order_by_intermediate order_by(const sql::column &col);
};
}
#endif //QUERY_GROUP_BY_INTERMEDIATE_HPP
@@ -0,0 +1,27 @@
#ifndef QUERY_INSERT_INTERMEDIATE_HPP
#define QUERY_INSERT_INTERMEDIATE_HPP
#include "matador/query/intermediates/query_intermediate.hpp"
namespace matador::query {
class query_into_intermediate;
class query_insert_intermediate : public query_intermediate
{
public:
query_insert_intermediate();
// template<class Type>
// query_into_intermediate into(const sql::table &table, const sql::schema &schema) {
// return into(table, column_generator::generate<Type>(schema));
// }
query_into_intermediate into(const sql::table &table, std::initializer_list<sql::column> columns);
query_into_intermediate into(const sql::table &table, std::vector<sql::column> &&columns);
query_into_intermediate into(const sql::table &table, const std::vector<std::string> &column_names);
query_into_intermediate into(const sql::table &table);
};
}
#endif //QUERY_INSERT_INTERMEDIATE_HPP
@@ -0,0 +1,21 @@
#ifndef QUERY_INTERMEDIATE_HPP
#define QUERY_INTERMEDIATE_HPP
#include "matador/query/query_data.hpp"
#include <memory>
namespace matador::query {
class query_intermediate {
public:
query_intermediate();
query_intermediate(const std::shared_ptr<query_data> &context); // NOLINT(*-explicit-constructor)
protected:
std::shared_ptr<query_data> context_;
};
}
#endif //QUERY_INTERMEDIATE_HPP
@@ -0,0 +1,43 @@
#ifndef QUERY_INTO_INTERMEDIATE_HPP
#define QUERY_INTO_INTERMEDIATE_HPP
#include "matador/query/intermediates/executable_query.hpp"
#include "matador/query/value_extractor.hpp"
#include "matador/utils/placeholder.hpp"
namespace matador::query {
// template < class Type >
// std::vector<utils::any_type> as_placeholder(const Type &obj)
// {
// placeholder_generator generator;
// access::process(generator, obj);
// return generator.placeholder_values;
// }
class query_into_intermediate : public query_intermediate
{
public:
using query_intermediate::query_intermediate;
executable_query values(std::initializer_list<std::variant<utils::placeholder, utils::database_type>> values);
executable_query values(std::vector<std::variant<utils::placeholder, utils::database_type>> &&values);
// template<class Type>
// executable_query values()
// {
// Type obj;
// return values(std::move(as_placeholder(obj)));
// }
template<class Type>
executable_query values(const Type &obj)
{
return values(std::move(value_extractor::extract(obj)));
}
};
}
#endif //QUERY_INTO_INTERMEDIATE_HPP
@@ -0,0 +1,32 @@
#ifndef QUERY_JOIN_INTERMEDIATE_HPP
#define QUERY_JOIN_INTERMEDIATE_HPP
#include "matador/query/intermediates/query_intermediate.hpp"
#include "matador/query/intermediates/query_from_intermediate.hpp"
namespace matador::query {
using query_on_intermediate = query_from_intermediate;
class query_join_intermediate : public query_intermediate
{
public:
using query_intermediate::query_intermediate;
template<class Condition>
query_on_intermediate on(const Condition &cond)
{
return on_clause(std::make_unique<Condition>(std::move(cond)));
}
query_on_intermediate on(std::unique_ptr<basic_condition> &&cond)
{
return on_clause(std::move(cond));
}
private:
query_on_intermediate on_clause(std::unique_ptr<basic_condition> &&cond);
};
}
#endif //QUERY_JOIN_INTERMEDIATE_HPP
@@ -0,0 +1,20 @@
#ifndef QUERY_LIMIT_INTERMEDIATE_HPP
#define QUERY_LIMIT_INTERMEDIATE_HPP
#include "matador/query/intermediates/fetchable_query.hpp"
namespace matador::query {
class query_offset_intermediate;
class query_limit_intermediate : public fetchable_query
{
public:
using fetchable_query::fetchable_query;
query_offset_intermediate offset(size_t offset);
};
}
#endif //QUERY_LIMIT_INTERMEDIATE_HPP
@@ -0,0 +1,20 @@
#ifndef QUERY_OFFSET_INTERMEDIATE_HPP
#define QUERY_OFFSET_INTERMEDIATE_HPP
#include "matador/query/intermediates/fetchable_query.hpp"
namespace matador::query {
class query_limit_intermediate;
class query_offset_intermediate : public fetchable_query
{
public:
using fetchable_query::fetchable_query;
query_limit_intermediate limit(size_t limit);
};
}
#endif //QUERY_OFFSET_INTERMEDIATE_HPP
@@ -0,0 +1,21 @@
#ifndef QUERY_ORDER_BY_INTERMEDIATE_HPP
#define QUERY_ORDER_BY_INTERMEDIATE_HPP
#include "matador/query/intermediates/query_intermediate.hpp"
namespace matador::query {
class query_order_direction_intermediate;
class query_order_by_intermediate : public query_intermediate
{
public:
using query_intermediate::query_intermediate;
query_order_direction_intermediate asc();
query_order_direction_intermediate desc();
};
}
#endif //QUERY_ORDER_BY_INTERMEDIATE_HPP
@@ -0,0 +1,20 @@
#ifndef QUERY_ORDER_DIRECTION_INTERMEDIATE_HPP
#define QUERY_ORDER_DIRECTION_INTERMEDIATE_HPP
#include "matador/query/intermediates/fetchable_query.hpp"
namespace matador::query {
class query_limit_intermediate;
class query_order_direction_intermediate : public fetchable_query
{
public:
using fetchable_query::fetchable_query;
query_limit_intermediate limit(size_t limit);
};
}
#endif //QUERY_ORDER_DIRECTION_INTERMEDIATE_HPP
@@ -0,0 +1,20 @@
#ifndef QUERY_SELECT_INTERMEDIATE_HPP
#define QUERY_SELECT_INTERMEDIATE_HPP
#include "matador/query/intermediates/query_intermediate.hpp"
namespace matador::query {
class query_from_intermediate;
class query_select_intermediate : public query_intermediate
{
public:
explicit query_select_intermediate(const std::vector<sql::column>& columns);
query_from_intermediate from(const sql::table& t);
};
}
#endif //QUERY_SELECT_INTERMEDIATE_HPP
@@ -0,0 +1,29 @@
#ifndef QUERY_SET_INTERMEDIATE_HPP
#define QUERY_SET_INTERMEDIATE_HPP
#include "matador/query/intermediates/executable_query.hpp"
#include "matador/query/basic_condition.hpp"
#include "matador/query/intermediates/query_execute_where_intermediate.hpp"
namespace matador::query {
class query_set_intermediate : public executable_query
{
public:
using executable_query::executable_query;
template<class Condition>
query_execute_where_intermediate where(const Condition &cond)
{
return where_clause(std::make_unique<Condition>(std::move(cond)));
}
private:
query_execute_where_intermediate where_clause(std::unique_ptr<basic_condition> &&cond);
};
}
#endif //QUERY_SET_INTERMEDIATE_HPP
@@ -0,0 +1,45 @@
#ifndef QUERY_UPDATE_INTERMEDIATE_HPP
#define QUERY_UPDATE_INTERMEDIATE_HPP
#include "matador/query/intermediates/query_intermediate.hpp"
#include "matador/query/intermediates/query_set_intermediate.hpp"
#include "matador/query/key_value_generator.hpp"
#include "matador/query/internal/key_value_pair.hpp"
namespace matador::query {
// template < class Type >
// std::vector<internal::key_value_pair> as_key_value_placeholder(const Type &obj)
// {
// placeholder_key_value_generator generator;
// access::process(generator, obj);
//
// return generator.placeholder_values;
// }
class query_update_intermediate : public query_intermediate
{
public:
explicit query_update_intermediate(const sql::table& table);
query_set_intermediate set(std::initializer_list<internal::key_value_pair> columns);
query_set_intermediate set(std::vector<internal::key_value_pair> &&columns);
// template<class Type>
// query_set_intermediate set()
// {
// Type obj;
// return set(std::move(as_key_value_placeholder(obj)));
// }
template<class Type>
query_set_intermediate set(const Type &obj)
{
return set(key_value_generator::generate(obj));
}
};
}
#endif //QUERY_UPDATE_INTERMEDIATE_HPP
@@ -0,0 +1,22 @@
#ifndef QUERY_WHERE_INTERMEDIATE_HPP
#define QUERY_WHERE_INTERMEDIATE_HPP
#include "matador/query/intermediates/fetchable_query.hpp"
namespace matador::query {
class query_group_by_intermediate;
class query_order_by_intermediate;
class query_where_intermediate : public fetchable_query
{
public:
using fetchable_query::fetchable_query;
query_group_by_intermediate group_by(const sql::column &col);
query_order_by_intermediate order_by(const sql::column &col);
};
}
#endif //QUERY_WHERE_INTERMEDIATE_HPP
@@ -0,0 +1,49 @@
#ifndef QUERY_ANY_TYPE_TO_STRING_VISITOR_HPP
#define QUERY_ANY_TYPE_TO_STRING_VISITOR_HPP
#include "matador/utils/types.hpp"
#include "matador/query/attribute_string_writer.hpp"
#include <string>
namespace matador {
class date;
class time;
}
namespace matador::sql {
class dialect;
struct query_context;
}
namespace matador::query::internal {
struct basic_type_to_string_visitor
{
explicit basic_type_to_string_visitor(attribute_string_writer &writer, sql::query_context &query);
void operator()(const int8_t &x) { result = writer->to_string(x); }
void operator()(const int16_t &x) { result = writer->to_string(x); }
void operator()(const int32_t &x) { result = writer->to_string(x); }
void operator()(const int64_t &x) { result = writer->to_string(x); }
void operator()(const uint8_t &x) { result = writer->to_string(x); }
void operator()(const uint16_t &x) { result = writer->to_string(x); }
void operator()(const uint32_t &x) { result = writer->to_string(x); }
void operator()(const uint64_t &x) { result = writer->to_string(x); }
void operator()(const bool &x) { result = writer->to_string(x); }
void operator()(const float &x) { result = writer->to_string(x); }
void operator()(const double &x) { result = writer->to_string(x); }
void operator()(const char *x) { result = writer->to_string(x); }
void operator()(const std::string &x) { result = writer->to_string(x); }
void operator()(const matador::date &x) { result = writer->to_string(x); }
void operator()(const matador::time &x) { result = writer->to_string(x); }
void operator()(const utils::blob &x) { result = writer->to_string(x); }
attribute_string_writer *writer{};
sql::query_context &query;
std::string result;
};
}
#endif //QUERY_ANY_TYPE_TO_STRING_VISITOR_HPP
@@ -0,0 +1,25 @@
#ifndef QUERY_KEY_VALUE_PAIR_HPP
#define QUERY_KEY_VALUE_PAIR_HPP
#include "matador/sql/column.hpp"
#include "matador/utils/types.hpp"
namespace matador::query::internal {
class key_value_pair {
public:
key_value_pair(const sql::column &col, utils::database_type value);
key_value_pair(std::string name, utils::database_type value);
key_value_pair(const char *name, utils::database_type value);
[[nodiscard]] const std::string& name() const;
[[nodiscard]] const utils::database_type& value() const;
private:
std::string name_;
utils::database_type value_;
};
}
#endif //QUERY_KEY_VALUE_PAIR_HPP
@@ -1,39 +1,41 @@
#ifndef QUERY_QUERY_PARTS_HPP
#define QUERY_QUERY_PARTS_HPP
#include "matador/sql/basic_condition.hpp"
#include "matador/sql/query_part_visitor.hpp"
#include "matador/query/query_part_visitor.hpp"
#include "matador/query/basic_condition.hpp"
#include "matador/query/internal/key_value_pair.hpp"
#include "matador/query/query_part.hpp"
#include "matador/sql/column.hpp"
#include "matador/sql/column_definition.hpp"
#include "matador/sql/key_value_pair.hpp"
#include "matador/sql/query_part.hpp"
#include "matador/sql/table.hpp"
#include "matador/utils/placeholder.hpp"
#include <memory>
namespace matador::sql {
class basic_condition;
namespace matador::query::internal {
/**
* Represents the SQL SELECT part
*/
class query_select_part : public query_part
class query_select_part final : public query_part
{
public:
explicit query_select_part(std::vector<column> columns);
explicit query_select_part(std::vector<sql::column> columns);
void accept(query_part_visitor &visitor) override;
[[nodiscard]] const std::vector<column>& columns() const;
[[nodiscard]] const std::vector<sql::column>& columns() const;
private:
std::vector<column> columns_;
std::vector<sql::column> columns_;
};
/**
* Represents the SQL FROM part
*/
class query_from_part : public query_part
class query_from_part final : public query_part
{
public:
explicit query_from_part(sql::table t);
@@ -47,7 +49,7 @@ private:
sql::table table_;
};
class query_join_part : public query_part
class query_join_part final : public query_part
{
public:
explicit query_join_part(sql::table t);
@@ -61,12 +63,12 @@ private:
sql::table table_;
};
class query_on_part : public query_part
class query_on_part final : public query_part
{
public:
template < class Condition >
explicit query_on_part(const Condition &cond)
: query_part(dialect::token_t::ON)
: query_part(sql::dialect_token::ON)
, condition_(new Condition(cond)) {}
explicit query_on_part(std::unique_ptr<basic_condition> &&cond);
@@ -79,12 +81,12 @@ private:
std::unique_ptr<basic_condition> condition_;
};
class query_where_part : public query_part
class query_where_part final : public query_part
{
public:
template < class Condition >
explicit query_where_part(const Condition &cond)
: query_part(dialect::token_t::WHERE)
: query_part(sql::dialect_token::WHERE)
, condition_(new Condition(cond)) {}
explicit query_where_part(std::unique_ptr<basic_condition> &&cond);
@@ -100,13 +102,13 @@ private:
class query_table_name_part : public query_part
{
protected:
explicit query_table_name_part(sql::dialect::token_t token, std::string table_name);
explicit query_table_name_part(sql::dialect_token token, std::string table_name);
protected:
std::string table_name_;
};
class query_group_by_part : public query_part
class query_group_by_part final : public query_part
{
public:
explicit query_group_by_part(sql::column col);
@@ -120,7 +122,7 @@ private:
sql::column column_;
};
class query_order_by_part : public query_part
class query_order_by_part final : public query_part
{
public:
explicit query_order_by_part(sql::column col);
@@ -134,7 +136,7 @@ private:
sql::column column_;
};
class query_order_by_asc_part : public query_part
class query_order_by_asc_part final : public query_part
{
public:
query_order_by_asc_part();
@@ -143,7 +145,7 @@ private:
void accept(query_part_visitor &visitor) override;
};
class query_order_by_desc_part : public query_part
class query_order_by_desc_part final : public query_part
{
public:
query_order_by_desc_part();
@@ -152,7 +154,7 @@ private:
void accept(query_part_visitor &visitor) override;
};
class query_offset_part : public query_part
class query_offset_part final : public query_part
{
public:
explicit query_offset_part(size_t offset);
@@ -166,7 +168,7 @@ private:
size_t offset_;
};
class query_limit_part : public query_part
class query_limit_part final : public query_part
{
public:
explicit query_limit_part(size_t limit);
@@ -180,7 +182,7 @@ private:
size_t limit_;
};
class query_insert_part : public query_part
class query_insert_part final : public query_part
{
public:
query_insert_part();
@@ -189,39 +191,39 @@ private:
void accept(query_part_visitor &visitor) override;
};
class query_into_part : public query_part
class query_into_part final : public query_part
{
public:
query_into_part(sql::table t, std::vector<sql::column> columns);
[[nodiscard]] const sql::table& table() const;
[[nodiscard]] const std::vector<column>& columns() const;
[[nodiscard]] const std::vector<sql::column>& columns() const;
private:
void accept(query_part_visitor &visitor) override;
private:
sql::table table_;
std::vector<column> columns_;
std::vector<sql::column> columns_;
};
/**
* Represents the SQL VALUES part
*/
class query_values_part : public query_part
class query_values_part final : public query_part
{
public:
explicit query_values_part(std::vector<any_type> &&values);
explicit query_values_part(std::vector<std::variant<utils::placeholder, utils::database_type>> &&values);
[[nodiscard]] const std::vector<any_type>& values() const;
[[nodiscard]] const std::vector<std::variant<utils::placeholder, utils::database_type>>& values() const;
private:
void accept(query_part_visitor &visitor) override;
private:
std::vector<any_type> values_;
std::vector<std::variant<utils::placeholder, utils::database_type>> values_;
};
class query_update_part : public query_part
class query_update_part final : public query_part
{
public:
explicit query_update_part(sql::table table);
@@ -235,21 +237,21 @@ private:
sql::table table_;
};
class query_set_part : public query_part
class query_set_part final : public query_part
{
public:
explicit query_set_part(const std::vector<sql::key_value_pair>& key_value_pairs);
explicit query_set_part(const std::vector<internal::key_value_pair>& key_value_pairs);
[[nodiscard]] const std::vector<sql::key_value_pair>& key_values() const;
[[nodiscard]] const std::vector<internal::key_value_pair>& key_values() const;
private:
void accept(query_part_visitor &visitor) override;
private:
std::vector<sql::key_value_pair> key_value_pairs_;
std::vector<internal::key_value_pair> key_value_pairs_;
};
class query_delete_part : public query_part
class query_delete_part final : public query_part
{
public:
query_delete_part();
@@ -258,10 +260,10 @@ private:
void accept(query_part_visitor &visitor) override;
};
class query_delete_from_part : public query_part
class query_delete_from_part final : public query_part
{
public:
query_delete_from_part(sql::table table);
explicit query_delete_from_part(sql::table table);
[[nodiscard]] const sql::table& table() const;
@@ -272,7 +274,7 @@ private:
sql::table table_;
};
class query_create_part : public query_part
class query_create_part final : public query_part
{
public:
query_create_part();
@@ -281,7 +283,7 @@ private:
void accept(query_part_visitor &visitor) override;
};
class query_create_table_part : public query_part
class query_create_table_part final : public query_part
{
public:
query_create_table_part(sql::table table, std::vector<sql::column_definition> columns);
@@ -297,7 +299,7 @@ private:
std::vector<sql::column_definition> columns_;
};
class query_drop_part : public query_part
class query_drop_part final : public query_part
{
public:
query_drop_part();
@@ -306,7 +308,7 @@ private:
void accept(query_part_visitor &visitor) override;
};
class query_drop_table_part : public query_part
class query_drop_table_part final : public query_part
{
public:
explicit query_drop_table_part(sql::table table);
+19
View File
@@ -0,0 +1,19 @@
#ifndef JOIN_DATA_HPP
#define JOIN_DATA_HPP
#include "matador/query/basic_condition.hpp"
#include "matador/sql/table.hpp"
#include <memory>
namespace matador::query {
struct join_data
{
std::shared_ptr<sql::table> join_table;
std::unique_ptr<basic_condition> condition;
};
}
#endif //JOIN_DATA_HPP
@@ -1,28 +1,30 @@
#ifndef QUERY_KEY_VALUE_GENERATOR_HPP
#define QUERY_KEY_VALUE_GENERATOR_HPP
#include "matador/sql/fk_value_extractor.hpp"
#include "matador/sql/key_value_pair.hpp"
#include "matador/query/fk_value_extractor.hpp"
#include "matador/query/internal/key_value_pair.hpp"
#include "matador/utils/foreign_attributes.hpp"
#include <vector>
namespace matador::sql {
namespace matador::query {
class key_value_generator
{
private:
public:
explicit key_value_generator(std::vector<key_value_pair> &result) : result_(result) {}
explicit key_value_generator(std::vector<internal::key_value_pair> &result) : result_(result) {}
public:
template < class Type >
static std::vector<key_value_pair> generate(const Type &obj)
static std::vector<internal::key_value_pair> generate(const Type &obj)
{
std::vector<key_value_pair> result;
std::vector<internal::key_value_pair> result;
key_value_generator generator(result);
matador::utils::access::process(generator, obj);
access::process(generator, obj);
return std::move(result);
return result;
}
template < class V >
@@ -56,7 +58,7 @@ public:
private:
detail::fk_value_extractor fk_value_extractor_;
std::vector<key_value_pair> &result_;
std::vector<internal::key_value_pair> &result_;
};
}
+35
View File
@@ -0,0 +1,35 @@
#ifndef QUERY_QUERY_HPP
#define QUERY_QUERY_HPP
#include "matador/query/query_intermediates.hpp"
namespace matador::sql {
class connection;
}
namespace matador::query {
sql::column alias(const std::string &column, const std::string &as);
sql::column alias(sql::column &&col, const std::string &as);
sql::column count(const std::string &column);
sql::column count_all();
class query
{
public:
[[nodiscard]] static query_create_intermediate create();
[[nodiscard]] static query_drop_intermediate drop();
[[nodiscard]] static query_select_intermediate select(std::initializer_list<sql::column> columns);
[[nodiscard]] static query_select_intermediate select(const std::vector<sql::column>& columns);
[[nodiscard]] static query_select_intermediate select(const std::vector<std::string> &column_names);
[[nodiscard]] static query_select_intermediate select(std::vector<sql::column> columns, std::initializer_list<sql::column> additional_columns);
// template<class Type>
// [[nodiscard]] static query_select_intermediate select(const sql::schema &schema) {
// return select(sql::column_generator::generate<Type>(schema));
// }
[[nodiscard]] static query_insert_intermediate insert();
[[nodiscard]] static query_update_intermediate update(const sql::table &table);
[[nodiscard]] static query_delete_intermediate remove();
};
}
#endif //QUERY_QUERY_HPP
+65
View File
@@ -0,0 +1,65 @@
#ifndef QUERY_QUERY_COMPILER_HPP
#define QUERY_QUERY_COMPILER_HPP
#include "matador/query/query_part_visitor.hpp"
#include "matador/query/query_data.hpp"
#include "matador/sql/query_context.hpp"
namespace matador::sql {
class connection_impl;
class dialect;
}
namespace matador::query {
struct query_data;
class query_compiler final : public query_part_visitor
{
public:
sql::query_context compile(const query_data &data,
const sql::dialect &d,
std::optional<std::reference_wrapper<const sql::connection_impl>> conn);
protected:
void visit(internal::query_select_part &select_part) override;
void visit(internal::query_from_part &from_part) override;
void visit(internal::query_join_part &join_part) override;
void visit(internal::query_on_part &on_part) override;
void visit(internal::query_where_part &where_part) override;
void visit(internal::query_group_by_part &group_by_part) override;
void visit(internal::query_order_by_part &order_by_part) override;
void visit(internal::query_order_by_asc_part &order_by_asc_part) override;
void visit(internal::query_order_by_desc_part &order_by_desc_part) override;
void visit(internal::query_offset_part &offset_part) override;
void visit(internal::query_limit_part &limit_part) override;
void visit(internal::query_insert_part &insert_part) override;
void visit(internal::query_into_part &into_part) override;
void visit(internal::query_values_part &values_part) override;
void visit(internal::query_update_part &update_part) override;
void visit(internal::query_set_part &set_part) override;
void visit(internal::query_delete_part &delete_part) override;
void visit(internal::query_delete_from_part &delete_from_part) override;
void visit(internal::query_create_part &create_part) override;
void visit(internal::query_create_table_part &create_table_part) override;
void visit(internal::query_drop_part &drop_part) override;
void visit(internal::query_drop_table_part &drop_table_part) override;
static std::string build_table_name(sql::dialect_token token, const sql::dialect &d, const sql::table& t);
protected:
const query_data *data_{};
sql::query_context query_;
size_t table_index{0};
const sql::dialect *dialect_{nullptr};
std::optional<std::reference_wrapper<const sql::connection_impl>> connection_{};
};
}
#endif //QUERY_QUERY_COMPILER_HPP
+21
View File
@@ -0,0 +1,21 @@
#ifndef QUERY_DATA_HPP
#define QUERY_DATA_HPP
#include <memory>
#include <vector>
#include "matador/sql/column_definition.hpp"
#include "matador/sql/table.hpp"
#include "matador/query/query_part.hpp"
namespace matador::query {
struct query_data
{
std::vector<std::unique_ptr<query_part>> parts{};
std::vector<sql::column_definition> columns{};
std::unordered_map<std::string, sql::table> tables{};
};
}
#endif //QUERY_DATA_HPP
@@ -0,0 +1,30 @@
#ifndef QUERY_QUERY_INTERMEDIATES_HPP
#define QUERY_QUERY_INTERMEDIATES_HPP
#include "matador/query/intermediates/executable_query.hpp"
#include "matador/query/intermediates/fetchable_query.hpp"
#include "matador/query/intermediates/query_create_intermediate.hpp"
#include "matador/query/intermediates/query_delete_from_intermediate.hpp"
#include "matador/query/intermediates/query_delete_intermediate.hpp"
#include "matador/query/intermediates/query_drop_intermediate.hpp"
#include "matador/query/intermediates/query_execute_limit_intermediate.hpp"
#include "matador/query/intermediates/query_execute_offset_intermediate.hpp"
#include "matador/query/intermediates/query_execute_order_by_intermediate.hpp"
#include "matador/query/intermediates/query_execute_order_direction_intermediate.hpp"
#include "matador/query/intermediates/query_execute_where_intermediate.hpp"
#include "matador/query/intermediates/query_from_intermediate.hpp"
#include "matador/query/intermediates/query_group_by_intermediate.hpp"
#include "matador/query/intermediates/query_insert_intermediate.hpp"
#include "matador/query/intermediates/query_intermediate.hpp"
#include "matador/query/intermediates/query_into_intermediate.hpp"
#include "matador/query/intermediates/query_join_intermediate.hpp"
#include "matador/query/intermediates/query_limit_intermediate.hpp"
#include "matador/query/intermediates/query_offset_intermediate.hpp"
#include "matador/query/intermediates/query_order_by_intermediate.hpp"
#include "matador/query/intermediates/query_order_direction_intermediate.hpp"
#include "matador/query/intermediates/query_select_intermediate.hpp"
#include "matador/query/intermediates/query_set_intermediate.hpp"
#include "matador/query/intermediates/query_update_intermediate.hpp"
#include "matador/query/intermediates/query_where_intermediate.hpp"
#endif //QUERY_QUERY_INTERMEDIATES_HPP
@@ -1,25 +1,25 @@
#ifndef QUERY_QUERY_PART_HPP
#define QUERY_QUERY_PART_HPP
#include "matador/sql/dialect.hpp"
#include "matador/sql/dialect_token.hpp"
namespace matador::sql {
namespace matador::query {
class query_part_visitor;
class query_part
{
protected:
explicit query_part(sql::dialect::token_t token);
explicit query_part(sql::dialect_token token);
public:
virtual ~query_part() = default;
virtual void accept(query_part_visitor &visitor) = 0;
[[nodiscard]] dialect::token_t token() const;
[[nodiscard]] sql::dialect_token token() const;
protected:
sql::dialect::token_t token_;
sql::dialect_token token_;
};
}
@@ -0,0 +1,67 @@
#ifndef QUERY_QUERY_PART_VISITOR_HPP
#define QUERY_QUERY_PART_VISITOR_HPP
namespace matador::query {
namespace internal {
class query_select_part;
class query_from_part;
class query_join_part;
class query_on_part;
class query_where_part;
class query_group_by_part;
class query_order_by_part;
class query_order_by_asc_part;
class query_order_by_desc_part;
class query_offset_part;
class query_limit_part;
class query_insert_part;
class query_into_part;
class query_values_part;
class query_update_part;
class query_set_part;
class query_delete_part;
class query_delete_from_part;
class query_create_part;
class query_create_table_part;
class query_drop_part;
class query_drop_table_part;
}
class query_part_visitor
{
public:
virtual ~query_part_visitor() = default;
virtual void visit(internal::query_select_part &select_part) = 0;
virtual void visit(internal::query_from_part &from_part) = 0;
virtual void visit(internal::query_join_part &join_part) = 0;
virtual void visit(internal::query_on_part &on_part) = 0;
virtual void visit(internal::query_where_part &where_part) = 0;
virtual void visit(internal::query_group_by_part &group_by_part) = 0;
virtual void visit(internal::query_order_by_part &order_by_part) = 0;
virtual void visit(internal::query_order_by_asc_part &order_by_asc_part) = 0;
virtual void visit(internal::query_order_by_desc_part &order_by_desc_part) = 0;
virtual void visit(internal::query_offset_part &offset_part) = 0;
virtual void visit(internal::query_limit_part &limit_part) = 0;
virtual void visit(internal::query_insert_part &insert_part) = 0;
virtual void visit(internal::query_into_part &into_part) = 0;
virtual void visit(internal::query_values_part &values_part) = 0;
virtual void visit(internal::query_update_part &update_part) = 0;
virtual void visit(internal::query_set_part &set_part) = 0;
virtual void visit(internal::query_delete_part &delete_part) = 0;
virtual void visit(internal::query_delete_from_part &delete_from_part) = 0;
virtual void visit(internal::query_create_part &create_part) = 0;
virtual void visit(internal::query_create_table_part &create_table_part) = 0;
virtual void visit(internal::query_drop_part &drop_part) = 0;
virtual void visit(internal::query_drop_table_part &drop_table_part) = 0;
};
}
#endif //QUERY_QUERY_PART_VISITOR_HPP
+94
View File
@@ -0,0 +1,94 @@
#ifndef QUERY_VALUE_EXTRACTOR_HPP
#define QUERY_VALUE_EXTRACTOR_HPP
#include "matador/query/fk_value_extractor.hpp"
#include "matador/utils/attribute_writer.hpp"
#include "matador/utils/default_type_traits.hpp"
#include <vector>
namespace matador::query {
class value_extractor final : public utils::attribute_writer
{
private:
explicit value_extractor(std::vector<utils::database_type> &values);
public:
template < class Type >
static std::vector<utils::database_type> extract(const Type &type)
{
std::vector<utils::database_type> values;
value_extractor gen(values);
access::process(gen, type);
return values;
}
template<typename ValueType>
void on_primary_key(const char *, ValueType &x, std::enable_if_t<std::is_integral_v<ValueType> && !std::is_same_v<bool, ValueType>>* = nullptr)
{
utils::data_type_traits<ValueType>::bind_value(*this, 0, x);
}
void on_primary_key(const char *id, std::string &pk, size_t size);
void on_revision(const char *id, uint64_t &rev);
template < class Type >
void on_attribute(const char *, Type &x, const utils::field_attributes &/*attr*/ = utils::null_attributes)
{
utils::data_type_traits<Type>::bind_value(*this, 0, x);
}
void on_attribute(const char *id, char *x, const utils::field_attributes &/*attr*/ = utils::null_attributes);
void on_attribute(const char *id, std::string &x, const utils::field_attributes &/*attr*/ = utils::null_attributes);
template<class Type, template < class ... > class Pointer>
void on_belongs_to(const char * /*id*/, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/)
{
values_.emplace_back(fk_value_extractor_.extract(*x));
}
template<class Type, template < class ... > class Pointer>
void on_has_one(const char * /*id*/, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/)
{
values_.emplace_back(fk_value_extractor_.extract(*x));
}
template<class ContainerType>
void on_has_many(const char * /*id*/, 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*/) {}
public:
void write_value(size_t pos, const int8_t &x) override;
void write_value(size_t pos, const int16_t &x) override;
void write_value(size_t pos, const int32_t &x) override;
void write_value(size_t pos, const int64_t &x) override;
void write_value(size_t pos, const uint8_t &x) override;
void write_value(size_t pos, const uint16_t &x) override;
void write_value(size_t pos, const uint32_t &x) override;
void write_value(size_t pos, const uint64_t &x) override;
void write_value(size_t pos, const bool &x) override;
void write_value(size_t pos, const float &x) override;
void write_value(size_t pos, const double &x) override;
void write_value(size_t pos, const time &x ) override;
void write_value(size_t pos, const date &x ) override;
void write_value(size_t pos, const char *x) override;
void write_value(size_t pos, const char *x, size_t size) override;
void write_value(size_t pos, const std::string &x) override;
void write_value(size_t pos, const std::string &x, size_t size) override;
void write_value(size_t pos, const utils::blob &x) override;
void write_value(size_t pos, const utils::value &x, size_t size) override;
private:
detail::fk_value_extractor fk_value_extractor_;
std::vector<utils::database_type> &values_;
};
}
#endif //QUERY_VALUE_EXTRACTOR_HPP
@@ -0,0 +1,86 @@
#ifndef MATADOR_BASIC_SQL_LOGGER_HPP
#define MATADOR_BASIC_SQL_LOGGER_HPP
#include <string>
namespace matador::sql {
/**
* @brief Base class for sql logging
*
* This class acts as a base class to
* implement a concrete logger for sql
* statements.
*
* It provides interfaces to handle
* the establishing and closing of
* a database connection as well as
* when a sql statement is about to
* execute or going to be prepared.
*/
class abstract_sql_logger
{
public:
virtual ~abstract_sql_logger() = default;
/**
* Is called when a connection to a database is
* going to be established
*/
virtual void on_connect() = 0;
/**
* Is called when a connection is going to be closed
*/
virtual void on_close() = 0;
/**
* Is called when a sql statement is going to
* be executed
*
* @param stmt SQL statement to be executed
*/
virtual void on_execute(const std::string &stmt) = 0;
/**
* Is called when a sql statement is going to
* be prepared
*
* @param stmt SQL statement to be prepared
*/
virtual void on_prepare(const std::string &stmt) = 0;
};
/**
* Implements the basic_sql_logger to do no
* logging at all.
* This is used as the default logger for all
* connections and statements.
*/
class null_sql_logger final : public abstract_sql_logger
{
public:
/**
* No logging on establishing a connection.
*/
void on_connect() override { }
/**
* No logging on closing a connection.
*/
void on_close() override { }
/**
* No logging on executing a statement.
*/
void on_execute(const std::string &) override { }
/**
* No logging on preparing a statement.
*/
void on_prepare(const std::string &) override { }
};
}
#endif //MATADOR_BASIC_SQL_LOGGER_HPP
-36
View File
@@ -1,36 +0,0 @@
#ifndef QUERY_ANY_TYPE_HPP
#define QUERY_ANY_TYPE_HPP
#include "matador/sql/placeholder.hpp"
#include "matador/utils/types.hpp"
#include <string>
#include <variant>
namespace matador::sql {
using any_db_type = std::variant<
long long,
unsigned long long,
double,
bool,
const char*,
std::string,
utils::blob,
placeholder,
nullptr_t>;
using any_type = std::variant<
char, short, int, long, long long,
unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long,
float, double,
bool,
const char*,
std::string,
utils::blob,
placeholder,
nullptr_t>;
}
#endif //QUERY_ANY_TYPE_HPP
@@ -1,53 +0,0 @@
#ifndef QUERY_ANY_TYPE_TO_STRING_VISITOR_HPP
#define QUERY_ANY_TYPE_TO_STRING_VISITOR_HPP
#include "matador/utils/types.hpp"
#include "matador/sql/placeholder.hpp"
#include <string>
namespace matador::sql {
class dialect;
class query_context;
struct any_type_to_string_visitor
{
explicit any_type_to_string_visitor(const dialect &d, query_context &query);
void operator()(char &x) { to_string(x); }
void operator()(short &x) { to_string(x); }
void operator()(int &x) { to_string(x); }
void operator()(long &x) { to_string(x); }
void operator()(long long &x) { to_string(x); }
void operator()(unsigned char &x) { to_string(x); }
void operator()(unsigned short &x) { to_string(x); }
void operator()(unsigned int &x) { to_string(x); }
void operator()(unsigned long &x) { to_string(x); }
void operator()(unsigned long long &x) { to_string(x); }
void operator()(bool &x) { to_string(x); }
void operator()(float &x) { to_string(x); }
void operator()(double &x) { to_string(x); }
void operator()(const char *x) { to_string(x); }
void operator()(std::string &x) { to_string(x); }
void operator()(utils::blob &x) { to_string(x); }
void operator()(placeholder &x) { to_string(x); }
template<typename Type>
void to_string(Type &val)
{
result = std::to_string(val);
}
void to_string(const char *val);
void to_string(std::string &val);
void to_string(utils::blob &val);
void to_string(placeholder &val);
const dialect &d;
query_context &query;
std::string result;
};
}
#endif //QUERY_ANY_TYPE_TO_STRING_VISITOR_HPP
@@ -1,38 +0,0 @@
#ifndef QUERY_ANY_TYPE_TO_VISITOR_HPP
#define QUERY_ANY_TYPE_TO_VISITOR_HPP
#include "matador/sql/convert.hpp"
#include <string>
namespace matador::sql {
struct placeholder;
template < typename Type >
struct any_type_to_visitor
{
void operator()(char &x) { convert(result, x); }
void operator()(short &x) { convert(result, x); }
void operator()(int &x) { convert(result, x); }
void operator()(long &x) { convert(result, x); }
void operator()(long long &x) { convert(result, x); }
void operator()(unsigned char &x) { convert(result, x); }
void operator()(unsigned short &x) { convert(result, x); }
void operator()(unsigned int &x) { convert(result, x); }
void operator()(unsigned long &x) { convert(result, x); }
void operator()(unsigned long long &x) { convert(result, x); }
void operator()(bool &x) { convert(result, x); }
void operator()(float &x) { convert(result, x); }
void operator()(double &x) { convert(result, x); }
void operator()(const char *x) { convert(result, x); }
void operator()(std::string &x) { convert(result, x); }
void operator()(utils::blob &x) { convert(result, x); }
void operator()(placeholder &/*x*/) {}
Type result{};
};
}
#endif //QUERY_ANY_TYPE_TO_VISITOR_HPP
+18 -26
View File
@@ -6,7 +6,6 @@
#include <memory>
#include <string>
#include <unordered_map>
#include <unordered_set>
namespace matador::sql {
@@ -20,28 +19,31 @@ private:
backend_provider();
public:
struct basic_backend_service {
virtual ~basic_backend_service() = default;
[[nodiscard]] virtual connection_impl* create(const connection_info&) = 0;
virtual void destroy(connection_impl*) = 0;
[[nodiscard]] virtual const sql::dialect* dialect() const = 0;
};
static backend_provider& instance();
connection_impl* create_connection(const std::string &connection_type, const connection_info &info);
void destroy_connection(const std::string &connection_type, connection_impl *c);
const dialect& connection_dialect(const std::string &connection_type);
private:
struct basic_backend_context {
virtual ~basic_backend_context() = default;
[[nodiscard]] virtual connection_impl* create(const connection_info&) = 0;
virtual void destroy(connection_impl*) = 0;
[[nodiscard]] virtual const sql::dialect* dialect() const = 0;
};
void register_backend(const std::string &connection_type, std::unique_ptr<basic_backend_service> &&service);
class backend_context final : public basic_backend_context {
private:
class backend_service final : public basic_backend_service {
public:
explicit backend_context(const std::string &connection_type);
backend_context(const backend_context&) = delete;
backend_context& operator=(const backend_context&) = delete;
backend_context(backend_context&&) noexcept = default;
backend_context& operator=(backend_context&&) noexcept = default;
~backend_context() override;
explicit backend_service(const std::string &connection_type);
backend_service(const backend_service&) = delete;
backend_service& operator=(const backend_service&) = delete;
backend_service(backend_service&&) noexcept = default;
backend_service& operator=(backend_service&&) noexcept = default;
~backend_service() override;
[[nodiscard]] connection_impl* create(const connection_info&) override;
void destroy(connection_impl *conn) override;
@@ -58,18 +60,8 @@ private:
utils::library lib;
};
class noop_backend_context final : public basic_backend_context {
public:
connection_impl *create(const connection_info &info) override;
void destroy(connection_impl *impl) override;
[[nodiscard]] const sql::dialect *dialect() const override;
private:
std::unordered_set<std::unique_ptr<connection_impl>> noop_connections_;
};
private:
using backends_t = std::unordered_map<std::string, std::unique_ptr<basic_backend_context>>;
using backends_t = std::unordered_map<std::string, std::unique_ptr<basic_backend_service>>;
backends_t backends_;
};
}
+9 -6
View File
@@ -1,6 +1,8 @@
#ifndef QUERY_COLUMN_HPP
#define QUERY_COLUMN_HPP
#include <functional>
#include <memory>
#include <string>
namespace matador::sql {
@@ -18,20 +20,21 @@ enum class sql_function_t {
struct column
{
column(const char *name); // NOLINT(*-explicit-constructor)
column(std::string name); // NOLINT(*-explicit-constructor)
column(const char *name, const std::string& as = ""); // NOLINT(*-explicit-constructor)
explicit column(std::string name, std::string as = ""); // NOLINT(*-explicit-constructor)
column(sql_function_t func, std::string name); // NOLINT(*-explicit-constructor)
column(std::string table_name, std::string name, std::string as = "");
column(std::string table_name, const char* name, std::string as = "");
column(struct table &t, const char* name, std::string as = "");
column(const struct table &t, std::string name, std::string as = "");
column(const std::shared_ptr<table> &t, std::string name, std::string as = "");
[[nodiscard]] bool equals(const column &x) const;
column& as(std::string a);
[[nodiscard]] bool is_function() const;
[[nodiscard]] bool has_alias() const;
std::string table;
std::shared_ptr<table> table_;
using table_ref = std::reference_wrapper<const table>;
std::string name;
std::string alias;
sql_function_t function_{sql_function_t::NONE};
+39 -38
View File
@@ -1,13 +1,12 @@
#ifndef QUERY_COLUMN_DEFINITION_HPP
#define QUERY_COLUMN_DEFINITION_HPP
#include "matador/sql/any_type.hpp"
#include "matador/sql/any_type_to_visitor.hpp"
#include "matador/sql/data_type_traits.hpp"
#include "matador/utils/basic_type_converter.hpp"
#include "matador/utils/basic_types.hpp"
#include "matador/utils/default_type_traits.hpp"
#include "matador/utils/field_attributes.hpp"
#include "matador/utils/value.hpp"
#include <optional>
#include <vector>
namespace matador::sql {
@@ -27,42 +26,51 @@ public:
column_definition& operator=(column_definition&&) noexcept = default;
template<typename Type>
explicit column_definition(std::string name, utils::field_attributes attr)
: column_definition(std::move(name), data_type_traits<Type>::builtin_type(attr.size()), attr)
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)
{}
template<typename Type>
column_definition(std::string name, const Type &, utils::field_attributes attr, null_option null_opt)
: column_definition(std::move(name), data_type_traits<Type>::builtin_type(attr.size()), attr, null_opt)
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)
{}
column_definition(std::string name, data_type_t type, utils::field_attributes attr, null_option null_opt, size_t index = 0);
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)
{}
column_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, utils::field_attributes attr, null_option null_opt)
: column_definition(std::move(name), data_type_traits<Type>::builtin_type(attr.size()), ref_table, ref_column, attr, null_opt)
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)
{}
column_definition(std::string name, data_type_t type, size_t index, std::string ref_table, std::string ref_column, utils::field_attributes attr, null_option 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);
[[nodiscard]] const std::string& name() const;
[[nodiscard]] std::string full_name() const;
[[nodiscard]] std::string table_name() const;
[[nodiscard]] int index() const;
[[nodiscard]] const utils::field_attributes& attributes() const;
[[nodiscard]] bool is_nullable() const;
[[nodiscard]] data_type_t type() const;
[[nodiscard]] utils::basic_type type() const;
[[nodiscard]] const std::string& ref_table() const;
[[nodiscard]] const std::string& ref_column() const;
[[nodiscard]] bool is_foreign_reference() const;
[[nodiscard]] bool is_integer() const;
[[nodiscard]] bool is_floating_point() const;
[[nodiscard]] bool is_bool() const;
[[nodiscard]] bool is_string() const;
[[nodiscard]] bool is_varchar() const;
[[nodiscard]] bool is_date() const;
[[nodiscard]] bool is_time() const;
[[nodiscard]] bool is_blob() const;
[[nodiscard]] bool is_null() const;
[[nodiscard]] bool is_unknown() const;
void type(data_type_t type);
void type(utils::basic_type type);
template< typename Type >
[[nodiscard]] bool is_type_of() const {
@@ -74,35 +82,26 @@ public:
template<typename Type>
void set(const Type &value, const utils::field_attributes &attr = utils::null_attributes)
{
type_ = data_type_traits<Type>::builtin_type(attr.size());
attributes_ = attr;
value_ = value;
}
void set(const std::string &value, const utils::field_attributes &attr)
{
type_ = data_type_traits<std::string>::builtin_type(attr.size());
attributes_ = attr;
value_ = value;
attributes_ = attr;
}
void set(const char *value, const utils::field_attributes &attr)
{
type_ = data_type_traits<std::string>::builtin_type(attr.size());
value_ = std::string(value);
attributes_ = attr;
value_ = value;
}
template<class Type>
Type as() const
std::optional<Type> as() const
{
const Type* ptr= std::get_if<Type>(&value_);
if (ptr) {
return *ptr;
}
any_type_to_visitor<Type> visitor;
std::visit(visitor, const_cast<any_type&>(value_));
return visitor.result;
return value_.as<Type>();
}
friend std::ostream& operator<<(std::ostream &out, const column_definition &col);
@@ -111,20 +110,20 @@ private:
template<class Operator>
void process(Operator &op)
{
op.on_attribute(name_.c_str(), value_, type_, attributes_);
op.on_attribute(name_.c_str(), value_, attributes_);
}
using data_type_index = std::vector<data_type_t>;
using data_type_index = std::vector<utils::basic_type>;
private:
static const data_type_index data_type_index_;
std::string name_;
std::string table_;
int index_{-1};
utils::field_attributes attributes_;
null_option null_option_{null_option::NOT_NULL};
data_type_t type_{data_type_t::type_unknown};
any_type value_;
utils::value value_;
std::string ref_table_;
std::string ref_column_;
};
@@ -132,15 +131,17 @@ private:
/**
* User defined literal to have a shortcut creating a column object
* @param name Name of the column
* @param len Length of the column name
* @param type
* @param attr Length of the column name
* @param null_opt
* @return A column object with given name
*/
column_definition make_column(const std::string &name, data_type_t type, utils::field_attributes attr = utils::null_attributes, null_option null_opt = null_option::NOT_NULL);
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);
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)
{
return make_column(name, data_type_traits<Type>::builtin_type(0), attr, null_opt);
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);
@@ -157,13 +158,13 @@ column_definition make_pk_column<std::string>(const std::string &name, size_t si
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)
{
return {name, data_type_traits<Type>::builtin_type(size), ref_table, ref_column, { size, utils::constraints::FOREIGN_KEY }};
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)
{
return {name, data_type_traits<Type>::builtin_type(0), 0, ref_table, ref_column, { 0, utils::constraints::FOREIGN_KEY }, null_option::NOT_NULL};
return {name, utils::data_type_traits<Type>::type(0), 0, ref_table, ref_column, { 0, utils::constraints::FOREIGN_KEY }, null_option::NOT_NULL};
}
template <>
@@ -1,133 +0,0 @@
#ifndef QUERY_COLUMN_DEFINITION_GENERATOR_HPP
#define QUERY_COLUMN_DEFINITION_GENERATOR_HPP
#include "matador/sql/column_definition.hpp"
#include "matador/sql/data_type_traits.hpp"
#include "matador/utils/access.hpp"
#include "matador/utils/field_attributes.hpp"
#include "matador/utils/foreign_attributes.hpp"
#include <typeindex>
#include <vector>
namespace matador::sql {
class schema;
class fk_column_generator
{
public:
fk_column_generator() = default;
template<class Type>
column_definition generate(const char *id, Type &x, const std::string &ref_table, const std::string &ref_column)
{
utils::access::process(*this, x);
return column_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*/, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type* = 0)
{
type_ = data_type_traits<ValueType>::builtin_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:
data_type_t type_{};
};
class column_definition_generator
{
private:
column_definition_generator(std::vector<column_definition> &columns, const schema &repo);
public:
~column_definition_generator() = default;
template < class Type >
static std::vector<column_definition> generate(const schema &repo)
{
std::vector<column_definition> columns;
column_definition_generator gen(columns, repo);
Type obj;
matador::utils::access::process(gen, obj);
return std::move(columns);
}
template < class V >
void on_primary_key(const char *, V &x, 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 &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<column_definition> &columns_;
const schema &repo_;
fk_column_generator fk_column_generator_;
};
template<typename V>
void column_definition_generator::on_primary_key(const char *id, V &x, typename std::enable_if<std::is_integral<V>::value && !std::is_same<bool, V>::value>::type*)
{
on_attribute(id, x, { utils::constraints::PRIMARY_KEY });
}
template<typename Type>
void column_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 column_definition_generator::on_attribute(const char *id, std::optional<Type> &x, const utils::field_attributes &attr)
{
columns_.emplace_back(id, data_type_traits<Type>::builtin_type(attr.size()), attr, null_option::NULLABLE);
}
}
#endif //QUERY_COLUMN_DEFINITION_GENERATOR_HPP
-128
View File
@@ -1,128 +0,0 @@
#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/sql/schema.hpp"
#include <string>
#include <vector>
#include <stack>
namespace matador::sql {
class column_generator
{
private:
column_generator(std::vector<column> &column_infos,
const sql::schema &ts,
const std::string &table_name,
bool force_lazy);
public:
~column_generator() = default;
template < class Type >
static std::vector<column> generate(const sql::schema &ts, bool force_lazy = false)
{
const auto info = ts.info<Type>();
if (!info) {
return {};
}
std::vector<column> columns;
column_generator gen(columns, ts, info.value().name, force_lazy);
Type obj;
matador::utils::access::process(gen, obj);
return std::move(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)
{
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().name);
typename Pointer::value_type obj;
matador::utils::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().name);
typename Pointer::value_type obj;
matador::utils::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().name);
typename ContainerType::value_type::value_type obj;
matador::utils::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 sql::schema &table_schema_;
int column_index{0};
bool force_lazy_{false};
};
}
#endif //QUERY_COLUMN_GENERATOR_HPP
+126 -31
View File
@@ -1,58 +1,153 @@
#ifndef QUERY_CONNECTION_HPP
#define QUERY_CONNECTION_HPP
#include "matador/sql/abstract_sql_logger.hpp"
#include "matador/sql/column_definition.hpp"
#include "matador/sql/connection_info.hpp"
#include "matador/sql/connection_impl.hpp"
#include "matador/sql/dialect.hpp"
#include "matador/sql/query.hpp"
#include "matador/sql/query_context.hpp"
#include "matador/sql/query_result.hpp"
#include "matador/sql/record.hpp"
#include "matador/sql/executor.hpp"
#include "matador/sql/statement.hpp"
#include "matador/utils/logger.hpp"
#include <string>
namespace matador::sql {
class schema;
class connection_impl;
class connection
{
/**
* @brief The connection class represents a connection to a database.
*/
class connection final : public executor {
public:
explicit connection(connection_info info);
explicit connection(const std::string& dns);
/**
* @brief Creates a database connection from a connection info data.
*
* @param info The database connection info data
* @param sql_logger The logging handler
*/
explicit connection(connection_info info,
const std::shared_ptr<abstract_sql_logger> &sql_logger = std::make_shared<null_sql_logger>());
/**
* @brief Creates a database connection from a connection string.
*
* @param dns The database connection string
* @param sql_logger The logging handler
*/
explicit connection(const std::string &dns,
const std::shared_ptr<abstract_sql_logger> &sql_logger = std::make_shared<null_sql_logger>());
/**
* Copies a given connection
*
* @param x The connection to copy
*/
connection(const connection &x);
connection& operator=(const connection &x);
/**
* Assigns from the given connection
*
* @param x The connection to assign
* @return The reference to the assigned connection
*/
connection &operator=(const connection &x);
/**
* Copy moves a given connection
*
* @param x The connection to copy move
*/
connection(connection &&x) noexcept = default;
~connection();
/**
* Assigns moves from the given connection
*
* @param x The connection to assign move
* @return The reference to the assigned connection
*/
connection& operator=(connection &&x) noexcept;
void open();
void close();
[[nodiscard]] bool is_open() const;
[[nodiscard]] const connection_info& info() const;
~connection() override;
[[nodiscard]] std::vector<sql::column_definition> describe(const std::string &table_name) const;
[[nodiscard]] bool exists(const std::string &schema_name, const std::string &table_name) const;
[[nodiscard]] bool exists(const std::string &table_name) const;
/**
* @brief Opens the database connection for the given dns.
*
* Opens the database connection. If database connection
* couldn't be opened an exception is thrown.
*/
[[nodiscard]] utils::result<void, utils::error> open() const;
/**
* @brief Closes the database connection.
*
* Closes the database connection.
*/
[[nodiscard]] utils::result<void, utils::error> close() const;
/**
* @brief Returns true if database connection is open.
*
* Returns true if database connection is open
*
* @return True on open database connection.
*/
[[nodiscard]] utils::result<bool, utils::error> is_open() const;
sql::query query(const sql::schema &schema) const;
/**
* Returns the connection info data of the
* current database connection.
*
* @return Returns the connection info data
*/
[[nodiscard]] const connection_info &info() const;
/**
* @brief Return the database type of the connection.
*
* Returns the database type of the connection which is
* currently one of
* - mssql
* - mysql
* - sqlite
* - postgres
*
* @return The database type string
*/
[[nodiscard]] std::string type() const;
query_result<record> fetch(const query_context &q) const;
[[nodiscard]] std::unique_ptr<query_result_impl> fetch(const std::string &sql) const;
[[nodiscard]] size_t execute(const std::string &sql) const;
/**
* @brief Starts a transaction by calling the
* underlying database backends transaction begin
* statement.
*/
[[nodiscard]] utils::result<void, utils::error> begin() const;
statement prepare(query_context &&query) const;
/**
* @brief Commits a transaction by calling the
* underlying database backends transaction commit
* statement.
*/
[[nodiscard]] utils::result<void, utils::error> commit() const;
const class dialect& dialect() const;
/**
* @brief Rollback a transaction by calling the
* underlying database backends transaction rollback/abort
* statement.
*/
[[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<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;
[[nodiscard]] utils::result<size_t, utils::error> execute(const std::string &sql) const;
[[nodiscard]] utils::result<std::unique_ptr<query_result_impl>, utils::error> fetch(const query_context &ctx) const override;
[[nodiscard]] utils::result<size_t, utils::error> execute(const query_context &ctx) const override;
[[nodiscard]] utils::result<statement, utils::error> prepare(const query_context &ctx) const override;
[[nodiscard]] std::string str( const query_context& ctx ) const override;
[[nodiscard]] const class dialect &dialect() const override;
private:
friend class fetchable_query;
friend class session;
connection_info connection_info_;
std::unique_ptr<connection_impl> connection_;
utils::logger logger_;
const class dialect &dialect_;
std::shared_ptr<abstract_sql_logger> logger_ = std::make_shared<null_sql_logger>();
};
}
#endif //QUERY_CONNECTION_HPP
-42
View File
@@ -1,42 +0,0 @@
#ifndef QUERY_CONNECTION_IMPL_HPP
#define QUERY_CONNECTION_IMPL_HPP
#include "matador/sql/connection_info.hpp"
#include "matador/sql/query_result_impl.hpp"
#include "matador/sql/query_context.hpp"
#include "matador/sql/record.hpp"
#include "matador/sql/statement_impl.hpp"
#include <memory>
namespace matador::sql {
class query_result_impl;
class connection_impl
{
public:
virtual ~connection_impl() = default;
virtual void open() = 0;
virtual void close() = 0;
virtual bool is_open() = 0;
virtual size_t execute(const std::string &stmt) = 0;
virtual std::unique_ptr<query_result_impl> fetch(const std::string &stmt) = 0;
virtual std::unique_ptr<statement_impl> prepare(query_context context) = 0;
virtual std::vector<sql::column_definition> describe(const std::string &table) = 0;
virtual bool exists(const std::string &schema_name, const std::string &table_name) = 0;
protected:
explicit connection_impl(const connection_info &info);
[[nodiscard]] const connection_info &info() const;
private:
const connection_info & info_;
};
}
#endif //QUERY_CONNECTION_IMPL_HPP
+54 -11
View File
@@ -1,23 +1,66 @@
#ifndef QUERY_CONNECTION_INFO_HPP
#define QUERY_CONNECTION_INFO_HPP
#include "matador/utils/access.hpp"
#include <string>
namespace matador::sql {
struct connection_info
{
std::string type;
std::string user;
std::string password;
std::string hostname;
unsigned short port{};
std::string database;
std::string driver;
/**
* This class contains all information
* about a database connection consisting
* of
* - database type
* - username
* - password
* - hostname
* - port
* - database name
* - driver
*/
struct connection_info {
std::string type{}; /**< Type of the database i.e. sqlite or mysql. */
std::string user{}; /**< Username to login. */
std::string password{}; /**< Password for login. */
std::string hostname{}; /**< Hostname of the database. */
unsigned short port{}; /**< Port of the database server. */
std::string database{}; /**< Name of the database to use */
std::string driver{}; /**< Driver to use. This is used by th mssql/odbc backends. */
static connection_info parse(const std::string &info, unsigned short default_port = 0, const std::string &default_driver = "");
template < class Operator >
void process(Operator &op)
{
namespace field = matador::access;
field::attribute(op, "type", type);
field::attribute(op, "user", user);
field::attribute(op, "password", password);
field::attribute(op, "hostname", hostname);
field::attribute(op, "port", port);
field::attribute(op, "database", database);
field::attribute(op, "driver", driver);
}
/**
* This parses database uri into a connection_info object.
*
* @param info The database uri
* @param default_port The default port to use
* @param default_driver The default driver to use
* @return A connection_info object
*/
static connection_info parse(const std::string &info,
unsigned short default_port = 0,
const std::string &default_driver = "");
/**
* Convert a connection_info object
* into a database uri.
*
* @param ci The connection_info object to convert
* @return The corresponding database uri
*/
static std::string to_string(const connection_info &ci);
};
}
#endif //QUERY_CONNECTION_INFO_HPP
-188
View File
@@ -1,188 +0,0 @@
#ifndef QUERY_CONNECTION_POOL_HPP
#define QUERY_CONNECTION_POOL_HPP
#include "matador/sql/connection_info.hpp"
#include <chrono>
#include <mutex>
#include <string>
#include <optional>
#include <condition_variable>
#include <thread>
#include <unordered_map>
namespace matador::sql {
template < class Connection >
class connection_pool;
template < class Connection >
using IdConnection = std::pair<size_t, Connection>;
template < class Connection >
class connection_ptr
{
public:
connection_ptr(IdConnection<Connection> *c, connection_pool<Connection> *pool)
: connection_(c), pool_(pool) {}
~connection_ptr();
connection_ptr(const connection_ptr &) = delete;
connection_ptr& operator=(const connection_ptr &) = delete;
connection_ptr(connection_ptr &&x) noexcept
: connection_(x.connection_)
, pool_(x.pool_)
{
x.connection_ = nullptr;
x.pool_ = nullptr;
}
connection_ptr& operator=(connection_ptr &&x) noexcept
{
if (this == &x) {
return *this;
}
std::swap(connection_, x.connection_);
std::swap(pool_, x.pool_);
return *this;
}
Connection* operator->() { return &connection_->second; }
Connection& operator*() { return connection_->second; }
[[nodiscard]] std::optional<size_t> id() const
{
if (connection_) {
return connection_->first;
} else {
return std::nullopt;
}
}
[[nodiscard]] bool valid() const { return connection_ != nullptr; }
private:
friend class connection_pool<Connection>;
IdConnection<Connection> *connection_{};
connection_pool<Connection> *pool_{};
};
template < class Connection >
class connection_pool
{
public:
using connection_pointer = connection_ptr<Connection>;
public:
connection_pool(const std::string &dns, size_t count)
: info_(connection_info::parse(dns)) {
connection_repo_.reserve(count);
while (count) {
connection_repo_.emplace_back(count, info_);
auto &conn = connection_repo_.back();
idle_connections_.emplace(conn.first, &conn);
conn.second.open();
--count;
}
}
connection_pointer acquire() {
std::unique_lock<std::mutex> lock(mutex_);
while (idle_connections_.empty()) {
cv.wait(lock);
}
return get_next_connection();
}
connection_pointer try_acquire() {
std::unique_lock<std::mutex> lock(mutex_);
if (idle_connections_.empty()) {
return {nullptr, this};
}
return get_next_connection();
}
connection_pointer acquire(size_t id) {
using namespace std::chrono_literals;
pointer next_connection{nullptr};
auto try_count{0};
std::unique_lock<std::mutex> lock(mutex_);
do {
if (auto it = idle_connections_.find(id); it != idle_connections_.end()) {
next_connection = it->second;
auto node = idle_connections_.extract(it);
inuse_connections_.insert(std::move(node));
} else {
lock.unlock();
std::this_thread::sleep_for(100ms);
lock.lock();
}
} while(try_count++ < 5);
return {next_connection, this};
}
void release(IdConnection<Connection> *c) {
if (c == nullptr) {
return;
}
std::unique_lock<std::mutex> lock(mutex_);
if (auto it = inuse_connections_.find(c->first); it != inuse_connections_.end()) {
auto node = inuse_connections_.extract(it);
idle_connections_.insert(std::move(node));
}
}
void release(connection_ptr<Connection> &c) {
release(c.connection_);
c.connection_ = nullptr;
}
std::size_t size() const { return connection_repo_.size(); }
std::size_t idle() const {
std::lock_guard<std::mutex> guard(mutex_);
return idle_connections_.size();
}
std::size_t inuse() const {
std::lock_guard<std::mutex> guard(mutex_);
return inuse_connections_.size();
}
const connection_info &info() const {
return info_;
}
private:
connection_pointer get_next_connection() {
pointer next_connection{nullptr};
for (auto &item : idle_connections_) {
next_connection = item.second;
auto node = idle_connections_.extract(item.first);
inuse_connections_.insert(std::move(node));
break;
}
return {next_connection, this};
}
private:
mutable std::mutex mutex_;
std::condition_variable cv;
std::vector<IdConnection<Connection>> connection_repo_;
using pointer = IdConnection<Connection>*;
using connection_map = std::unordered_map<size_t, pointer>;
connection_map inuse_connections_;
connection_map idle_connections_;
const connection_info info_;
};
template<class Connection>
connection_ptr<Connection>::~connection_ptr() {
pool_->release(connection_);
}
}
#endif //QUERY_CONNECTION_POOL_HPP
-124
View File
@@ -1,124 +0,0 @@
#ifndef QUERY_CONVERT_HPP
#define QUERY_CONVERT_HPP
#include "matador/utils/types.hpp"
#include <array>
#include <charconv>
#include <stdexcept>
#include <string>
#include <type_traits>
namespace matador::sql {
template < typename DestType, typename SourceType >
void convert(DestType &dest, SourceType source, typename std::enable_if<std::is_same<DestType, SourceType>::value>::type* = nullptr)
{
dest = source;
}
template < typename DestType, typename SourceType >
void convert(DestType &dest, SourceType source, typename std::enable_if<std::is_integral<DestType>::value && std::is_arithmetic<SourceType>::value && !std::is_same<DestType, SourceType>::value>::type* = nullptr)
{
dest = static_cast<DestType>(source);
}
template < typename DestType, typename SourceType >
void convert(DestType &dest, SourceType source, typename std::enable_if<std::is_floating_point<DestType>::value && std::is_arithmetic<SourceType>::value && !std::is_same<DestType, SourceType>::value>::type* = nullptr)
{
dest = static_cast<DestType>(source);
}
void convert(std::string &dest, bool source);
template < typename SourceType >
void convert(std::string &dest, SourceType source, typename std::enable_if<std::is_integral<SourceType>::value && !std::is_same<bool, SourceType>::value>::type* = nullptr)
{
std::array<char, 128> buffer{};
auto [ptr, ec] = std::to_chars(buffer.data(), buffer.data() + buffer.size(), source, 10);
if (ec == std::errc{}) {
dest.assign(buffer.data(), ptr);
} else {
throw std::logic_error("couldn't convert value to std::string");
}
}
template < typename SourceType >
void convert(std::string &dest, SourceType source, typename std::enable_if<std::is_floating_point<SourceType>::value>::type* = nullptr)
{
std::array<char, 128> buffer{};
auto [ptr, ec] = std::to_chars(buffer.data(), buffer.data() + buffer.size(), source);
if (ec == std::errc{}) {
dest.assign(buffer.data(), ptr);
} else {
throw std::logic_error("couldn't convert value to std::string");
}
}
template < typename SourceType >
void convert(utils::blob &dest, SourceType source, typename std::enable_if<!std::is_same<utils::blob, SourceType>::value>::type* = nullptr)
{
throw std::logic_error("couldn't convert value to matador::utils::blob");
}
void convert(std::string &dest, const char* source);
unsigned long long to_unsigned_long_long(const char *source);
template < typename DestType >
void convert(DestType &dest, const std::string &source, typename std::enable_if<std::is_integral<DestType>::value && std::is_unsigned<DestType>::value>::type* = nullptr)
{
dest = to_unsigned_long_long(source.c_str());
}
template < typename DestType >
void convert(DestType &dest, const char *source, typename std::enable_if<std::is_integral<DestType>::value && std::is_unsigned<DestType>::value>::type* = nullptr)
{
dest = to_unsigned_long_long(source);
}
long long to_long_long(const char *source);
template < typename DestType >
void convert(DestType &dest, const std::string &source, typename std::enable_if<std::is_integral<DestType>::value && std::is_signed<DestType>::value>::type* = nullptr)
{
dest = to_long_long(source.c_str());
}
template < typename DestType >
void convert(DestType &dest, const char *source, typename std::enable_if<std::is_integral<DestType>::value && std::is_signed<DestType>::value>::type* = nullptr)
{
dest = to_long_long(source);
}
long double to_double(const char *source);
template < typename DestType >
void convert(DestType &dest, const std::string &source, typename std::enable_if<std::is_floating_point<DestType>::value>::type* = nullptr)
{
dest = to_double(source.c_str());
}
template < typename DestType >
void convert(DestType &dest, const char *source, typename std::enable_if<std::is_floating_point<DestType>::value>::type* = nullptr)
{
dest = to_double(source);
}
template < typename DestType >
void convert(DestType &dest, bool source, typename std::enable_if<std::is_floating_point<DestType>::value>::type* = nullptr)
{
dest = static_cast<DestType>(source);
}
template < typename DestType >
void convert(DestType &dest, const utils::blob &data)
{
throw std::logic_error("couldn't convert matador::utils::blob into destination type");
}
void convert(utils::blob &dest, const utils::blob &data);
}
#endif //QUERY_CONVERT_HPP
-257
View File
@@ -1,257 +0,0 @@
#ifndef QUERY_DATA_TYPE_TRAITS_HPP
#define QUERY_DATA_TYPE_TRAITS_HPP
#include "matador/sql/any_type.hpp"
#include "matador/utils/types.hpp"
#include <cstdint>
#include <string>
namespace matador::sql {
class query_result_reader;
class parameter_binder;
class result_parameter_binder;
/**
* @brief Enumeration type of all supported builtin data types
*/
enum class data_type_t : uint8_t {
type_char = 0, /*!< Data type char */
type_short, /*!< Data type short */
type_int, /*!< Data type int */
type_long, /*!< Data type long */
type_long_long, /*!< Data type long long */
type_unsigned_char, /*!< Data type unsigned char */
type_unsigned_short, /*!< Data type unsigned short */
type_unsigned_int, /*!< Data type unsigned int */
type_unsigned_long, /*!< Data type unsigned long */
type_unsigned_long_long, /*!< Data type unsigned long long */
type_float, /*!< Data type float */
type_double, /*!< Data type double */
type_bool, /*!< Data type bool */
type_char_pointer, /*!< Data type character pointer */
type_varchar, /*!< Data type varchar */
type_text, /*!< Data type text */
type_date, /*!< Data type date */
type_time, /*!< Data type time */
type_blob, /*!< Data type blob */
type_null, /*!< Data type null */
type_unknown /*!< Data type unknown */
};
/**
* @tparam T The type of the traits
* @brief Type traits for database types
*
* This class is used to determine and
* provide the correct size information
* for a data type
*/
template < class Type, class Enable = void >
struct data_type_traits;
/// @cond MATADOR_DEV
template <> struct data_type_traits<nullptr_t, void>
{
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_null; }
static void read_value(query_result_reader &reader, const char *id, size_t index, nullptr_t &/*value*/);
static void bind_value(parameter_binder &binder, size_t index, nullptr_t &/*value*/);
static void bind_result_value(result_parameter_binder &binder, size_t index, nullptr_t &/*value*/);
inline static any_type create_value(const char &value) { return value; }
};
template <> struct data_type_traits<char, void>
{
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_char; }
static void read_value(query_result_reader &reader, const char *id, size_t index, char &value);
static void bind_value(parameter_binder &binder, size_t index, char &value);
static void bind_result_value(result_parameter_binder &binder, size_t index, char &value);
inline static any_type create_value(const char &value) { return value; }
};
template <> struct data_type_traits<short, void>
{
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_short; }
static void read_value(query_result_reader &reader, const char *id, size_t index, short &value);
static void bind_value(parameter_binder &binder, size_t index, short &value);
static void bind_result_value(result_parameter_binder &binder, size_t index, short &value);
inline static any_type create_value(const short &value) { return value; }
};
template <> struct data_type_traits<int, void>
{
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_int; }
static void read_value(query_result_reader &reader, const char *id, size_t index, int &value);
static void bind_value(parameter_binder &binder, size_t index, int &value);
static void bind_result_value(result_parameter_binder &binder, size_t index, int &value);
inline static any_type create_value(const int &value) { return value; }
};
template <> struct data_type_traits<long, void>
{
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_long; }
static void read_value(query_result_reader &reader, const char *id, size_t index, long &value);
static void bind_value(parameter_binder &binder, size_t index, long &value);
static void bind_result_value(result_parameter_binder &binder, size_t index, long &value);
inline static any_type create_value(const long &value) { return value; }
};
template <> struct data_type_traits<long long, void>
{
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_long_long; }
static void read_value(query_result_reader &reader, const char *id, size_t index, long long &value);
static void bind_value(parameter_binder &binder, size_t index, long long &value);
static void bind_result_value(result_parameter_binder &binder, size_t index, long long &value);
inline static any_type create_value(const long long &value) { return value; }
};
template <> struct data_type_traits<unsigned char, void>
{
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_unsigned_char; }
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned char &value);
static void bind_value(parameter_binder &binder, size_t index, unsigned char &value);
static void bind_result_value(result_parameter_binder &binder, size_t index, unsigned char &value);
inline static any_type create_value(const unsigned char &value) { return value; }
};
template <> struct data_type_traits<unsigned short, void>
{
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_unsigned_short; }
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned short &value);
static void bind_value(parameter_binder &binder, size_t index, unsigned short &value);
static void bind_result_value(result_parameter_binder &binder, size_t index, unsigned short &value);
inline static any_type create_value(const unsigned short &value) { return value; }
};
template <> struct data_type_traits<unsigned int, void>
{
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_unsigned_int; }
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned int &value);
static void bind_value(parameter_binder &binder, size_t index, unsigned int &value);
static void bind_result_value(result_parameter_binder &binder, size_t index, unsigned int &value);
inline static any_type create_value(const unsigned int &value) { return value; }
};
template <> struct data_type_traits<unsigned long, void>
{
inline static data_type_t builtin_type(std::size_t /*size*/ = 0) { return data_type_t::type_unsigned_long; }
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned long &value);
static void bind_value(parameter_binder &binder, size_t index, unsigned long &value);
static void bind_result_value(result_parameter_binder &binder, size_t index, unsigned long &value);
inline static any_type create_value(const unsigned long &value) { return value; }
};
template <> struct data_type_traits<unsigned long long, void>
{
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_unsigned_long_long; }
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned long long &value);
static void bind_value(parameter_binder &binder, size_t index, unsigned long long &value);
static void bind_result_value(result_parameter_binder &binder, size_t index, unsigned long long &value);
inline static any_type create_value(const unsigned long long &value) { return value; }
};
template <> struct data_type_traits<bool, void>
{
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_bool; }
static void read_value(query_result_reader &reader, const char *id, size_t index, bool &value);
static void bind_value(parameter_binder &binder, size_t index, bool &value);
static void bind_result_value(result_parameter_binder &binder, size_t index, bool &value);
inline static any_type create_value(const bool &value) { return value; }
};
template <> struct data_type_traits<float, void>
{
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_float; }
static void read_value(query_result_reader &reader, const char *id, size_t index, float &value);
static void bind_result_value(result_parameter_binder &binder, size_t index, float &value);
static void bind_value(parameter_binder &binder, size_t index, float &value);
inline static any_type create_value(const float &value) { return value; }
};
template <> struct data_type_traits<double, void>
{
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_double; }
static void read_value(query_result_reader &reader, const char *id, size_t index, double &value);
static void bind_result_value(result_parameter_binder &binder, size_t index, double &value);
static void bind_value(parameter_binder &binder, size_t index, double &value);
inline static any_type create_value(const double &value) { return value; }
};
template <> struct data_type_traits<const char*, void>
{
inline static data_type_t builtin_type(std::size_t size) { return size == 0 ? data_type_t::type_text : data_type_t::type_char_pointer; }
static void read_value(query_result_reader &reader, const char *id, size_t index, const char* value, size_t size);
static void bind_value(parameter_binder &binder, size_t index, const char *value, size_t size = 0);
static void bind_result_value(result_parameter_binder &binder, size_t index, const char *value, size_t size = 0);
inline static any_type create_value(const char *value) { return value; }
};
template <> struct data_type_traits<char*, void>
{
inline static data_type_t builtin_type(std::size_t size) { return size == 0 ? data_type_t::type_text : data_type_t::type_varchar; }
static void read_value(query_result_reader &reader, const char *id, size_t index, char *value, size_t size);
static void bind_value(parameter_binder &binder, size_t index, char *value, size_t size = 0);
static void bind_result_value(result_parameter_binder &binder, size_t index, char *value, size_t size = 0);
inline static any_type create_value(const char *value) { return value; }
};
template <> struct data_type_traits<std::string, void>
{
inline static data_type_t builtin_type(std::size_t size) { return size == 0 ? data_type_t::type_text : data_type_t::type_varchar; }
static void read_value(query_result_reader &reader, const char *id, size_t index, std::string &value, size_t size);
static void bind_value(parameter_binder &binder, size_t index, std::string &value, size_t size = 0);
static void bind_result_value(result_parameter_binder &binder, size_t index, std::string &value, size_t size = 0);
inline static any_type create_value(const std::string &value) { return value; }
};
template <> struct data_type_traits<utils::blob, void>
{
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_blob; }
static void read_value(query_result_reader &reader, const char *id, size_t index, utils::blob &value);
static void bind_value(parameter_binder &binder, size_t index, utils::blob &value);
static void bind_result_value(result_parameter_binder &binder, size_t index, utils::blob &value);
inline static any_type create_value(const utils::blob &value) { return value; }
};
//template <> struct data_type_traits<matador::date>
//{
// inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_date; }
// inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_date; }
// inline static unsigned long size() { return 255; }
// inline static const char* name() { return "matador::date"; }
//};
//
//template <> struct data_type_traits<matador::time>
//{
// inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_time; }
// inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_time; }
// inline static unsigned long size() { return 255; }
// inline static const char* name() { return "matador::time"; }
//};
template < typename EnumType >
struct data_type_traits<EnumType, std::enable_if_t<std::is_enum_v<EnumType>>>
{
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_int; }
static void read_value(query_result_reader &reader, const char *id, size_t index, EnumType &value)
{
data_type_traits<int>::read_value(reader, id, index, reinterpret_cast<int&>(value));
}
static void bind_value(parameter_binder &binder, size_t index, EnumType &value)
{
data_type_traits<int>::bind_value(binder, index, static_cast<int&>(value));
}
static void bind_result_value(result_parameter_binder &binder, size_t index, EnumType &value)
{
data_type_traits<int>::bind_result_value(binder, index, static_cast<int&>(value));
}
static any_type create_value(const EnumType &value) {
return static_cast<int>(value);
}
};
/// @endcond
}
#endif //QUERY_DATA_TYPE_TRAITS_HPP
+101 -119
View File
@@ -2,9 +2,12 @@
#define QUERY_DIALECT_HPP
#include "matador/sql/column.hpp"
#include "matador/sql/data_type_traits.hpp"
#include "matador/sql/dialect_token.hpp"
#include "matador/utils/basic_types.hpp"
#include "matador/utils/types.hpp"
#include "matador/utils/string.hpp"
#include <cstdint>
#include <functional>
#include <string>
#include <unordered_map>
@@ -12,54 +15,11 @@
namespace matador::sql {
class connection_impl;
class dialect final
{
public:
enum class token_t : uint8_t
{
CREATE = 0,
DROP,
REMOVE,
INSERT,
UPDATE,
SELECT,
TABLE,
VALUES,
INSERT_VALUES,
COLUMNS,
COLUMN,
FROM,
JOIN,
ON,
INTO,
WHERE,
WHERE_CLAUSE,
AND,
OR,
LIKE,
ORDER_BY,
GROUP_BY,
ASC,
DESC,
LIMIT,
AS,
OFFSET,
DISTINCT,
SET,
UPDATE_VALUES,
NOT_NULL,
PRIMARY_KEY,
BEGIN,
COMMIT,
ROLLBACK,
START_QUOTE,
END_QUOTE,
STRING_QUOTE,
BEGIN_BINARY_DATA,
END_BINARY_DATA,
NONE
};
/**
* Holding enums concerning escaping identifiers
*/
@@ -68,26 +28,32 @@ public:
ESCAPE_CLOSING_BRACKET /**< The escape quotes differ; escape the closing one */
};
using token_to_string_map = std::unordered_map<token_t, std::string>;
using data_type_to_string_map = std::unordered_map<data_type_t, std::string>;
using token_to_string_map = std::unordered_map<dialect_token, std::string>;
using data_type_to_string_map = std::unordered_map<utils::basic_type, std::string>;
using sql_func_to_string_map = std::unordered_map<sql_function_t, std::string>;
using next_placeholder_func = std::function<std::string(size_t)>;
using to_escaped_string_func = std::function<std::string(const utils::blob &)>;
public:
[[nodiscard]] const std::string& token_at(token_t token) const;
[[nodiscard]] const std::string& data_type_at(data_type_t type) const;
[[nodiscard]] const std::string& token_at(dialect_token token) const;
[[nodiscard]] const std::string& data_type_at(utils::basic_type type) const;
/**
* Prepare sql dialect identifier for execution
* and escape quotes and quote the identifier
* string
*
* @param str The identifier string to be prepared
* @return The prepared string
*/
* Prepare sql dialect identifier for execution
* and escape quotes and quote the identifier
* string
*
* @param col The identifier string to be prepared
* @return The prepared string
*/
[[nodiscard]] std::string prepare_identifier(const column &col) const;
[[nodiscard]] std::string prepare_identifier_string(const std::string &col) const;
[[nodiscard]] std::string prepare_condition(const column &col) const;
[[nodiscard]] const std::string& to_string(bool val) const;
void bool_strings(const std::string &true_string, const std::string &false_string);
/**
* Prepare string literal
@@ -123,7 +89,17 @@ public:
*
* @return How the identifier quotes should be escaped
*/
[[nodiscard]] virtual escape_identifier_t identifier_escape_type() const;
[[nodiscard]] escape_identifier_t identifier_escape_type() const;
/**
* Sets the identifier escape type. Possibilities are
* opening and closing escape characters are the same
* (ESCAPE_BOTH_SAME) or using a special closing
* escape character (ESCAPE_CLOSING_BRACKET)
*
* @param escape_identifier Identifier escape type
*/
void identifier_escape_type(escape_identifier_t escape_identifier);
/**
* Generates a next placeholder string. default is
@@ -133,6 +109,8 @@ public:
*/
[[nodiscard]] std::string next_placeholder(const std::vector<std::string> &bind_vars) const;
[[nodiscard]] std::string to_escaped_string(const utils::blob &value, const connection_impl *conn = nullptr) const;
/**
* Returns the default schema name.
*
@@ -147,73 +125,73 @@ private:
friend class dialect_builder;
next_placeholder_func placeholder_func_ = [](size_t) { return "?"; };
// to_escaped_string_func to_escaped_string_func_ = [](const utils::blob &val) { return utils::to_string(val); };
escape_identifier_t identifier_escape_type_ = escape_identifier_t::ESCAPE_BOTH_SAME;
std::string default_schema_name_;
// std::unique_ptr<query_compiler> compiler_;
token_to_string_map tokens_ {
{token_t::CREATE, "CREATE"},
{token_t::DROP, "DROP"},
{token_t::REMOVE, "DELETE"},
{token_t::INSERT, "INSERT"},
{token_t::TABLE, "TABLE"},
{token_t::INTO, "INTO"},
{token_t::VALUES, "VALUES"},
{token_t::UPDATE, "UPDATE"},
{token_t::SELECT, "SELECT"},
{token_t::COLUMNS, "COLUMNS"},
{token_t::COLUMN, "COLUMN"},
{token_t::FROM, "FROM"},
{token_t::JOIN, "INNER JOIN"},
{token_t::ON, "ON"},
{token_t::WHERE, "WHERE"},
{token_t::AND, "AND"},
{token_t::OR, "OR"},
{token_t::LIKE, "LIKE"},
{token_t::ORDER_BY, "ORDER BY"},
{token_t::GROUP_BY, "GROUP BY"},
{token_t::ASC, "ASC"},
{token_t::DESC, "DESC"},
{token_t::OFFSET, "OFFSET"},
{token_t::LIMIT, "LIMIT"},
{token_t::AS, "AS"},
{token_t::OFFSET, "OFFSET"},
{token_t::DISTINCT, "DISTINCT"},
{token_t::SET, "SET"},
{token_t::NOT_NULL, "NOT NULL"},
{token_t::PRIMARY_KEY, "PRIMARY KEY"},
{token_t::BEGIN, "BEGIN TRANSACTION"},
{token_t::COMMIT, "COMMIT TRANSACTION"},
{token_t::ROLLBACK, "ROLLBACK TRANSACTION"},
{token_t::START_QUOTE, "\""},
{token_t::END_QUOTE, "\""},
{token_t::STRING_QUOTE, "'"},
{token_t::BEGIN_BINARY_DATA, "X'"},
{token_t::END_BINARY_DATA, "'"},
{token_t::NONE, ""}
{dialect_token::CREATE, "CREATE"},
{dialect_token::DROP, "DROP"},
{dialect_token::REMOVE, "DELETE"},
{dialect_token::INSERT, "INSERT"},
{dialect_token::TABLE, "TABLE"},
{dialect_token::INTO, "INTO"},
{dialect_token::VALUES, "VALUES"},
{dialect_token::UPDATE, "UPDATE"},
{dialect_token::SELECT, "SELECT"},
{dialect_token::COLUMNS, "COLUMNS"},
{dialect_token::COLUMN, "COLUMN"},
{dialect_token::FROM, "FROM"},
{dialect_token::JOIN, "LEFT JOIN"},
{dialect_token::ON, "ON"},
{dialect_token::WHERE, "WHERE"},
{dialect_token::AND, "AND"},
{dialect_token::OR, "OR"},
{dialect_token::LIKE, "LIKE"},
{dialect_token::ORDER_BY, "ORDER BY"},
{dialect_token::GROUP_BY, "GROUP BY"},
{dialect_token::ASC, "ASC"},
{dialect_token::DESC, "DESC"},
{dialect_token::OFFSET, "OFFSET"},
{dialect_token::LIMIT, "LIMIT"},
{dialect_token::AS, "AS"},
{dialect_token::OFFSET, "OFFSET"},
{dialect_token::DISTINCT, "DISTINCT"},
{dialect_token::SET, "SET"},
{dialect_token::NOT_NULL, "NOT NULL"},
{dialect_token::PRIMARY_KEY, "PRIMARY KEY"},
{dialect_token::BEGIN, "BEGIN TRANSACTION"},
{dialect_token::COMMIT, "COMMIT TRANSACTION"},
{dialect_token::ROLLBACK, "ROLLBACK TRANSACTION"},
{dialect_token::START_QUOTE, "\""},
{dialect_token::END_QUOTE, "\""},
{dialect_token::STRING_QUOTE, "'"},
{dialect_token::BEGIN_BINARY_DATA, "X'"},
{dialect_token::END_BINARY_DATA, "'"},
{dialect_token::NONE, ""}
};
data_type_to_string_map data_types_ {
{data_type_t::type_char, "TINYINT"},
{data_type_t::type_short, "SMALLINT"},
{data_type_t::type_int, "INTEGER"},
{data_type_t::type_long, "BIGINT"},
{data_type_t::type_long_long, "BIGINT"},
{data_type_t::type_unsigned_char, "TINYINT"},
{data_type_t::type_unsigned_short, "INTEGER"},
{data_type_t::type_unsigned_int, "BIGINT"},
{data_type_t::type_unsigned_long, "BIGINT"},
{data_type_t::type_unsigned_long_long, "BIGINT"},
{data_type_t::type_float, "FLOAT"},
{data_type_t::type_double, "DOUBLE"},
{data_type_t::type_bool, "BOOLEAN"},
{data_type_t::type_char_pointer, "VARCHAR"},
{data_type_t::type_varchar, "VARCHAR"},
{data_type_t::type_text, "TEXT"},
{data_type_t::type_date, "DATE"},
{data_type_t::type_time, "DATETIME"},
{data_type_t::type_blob, "BLOB"},
{data_type_t::type_null, "NULL"},
{data_type_t::type_unknown, "UNKNOWN"}
{utils::basic_type::type_int8, "TINYINT"},
{utils::basic_type::type_int16, "SMALLINT"},
{utils::basic_type::type_int32, "INTEGER"},
{utils::basic_type::type_int64, "BIGINT"},
{utils::basic_type::type_uint8, "TINYINT"},
{utils::basic_type::type_uint16, "INTEGER"},
{utils::basic_type::type_uint32, "BIGINT"},
{utils::basic_type::type_uint64, "BIGINT"},
{utils::basic_type::type_float, "FLOAT"},
{utils::basic_type::type_double, "DOUBLE"},
{utils::basic_type::type_bool, "BOOLEAN"},
{utils::basic_type::type_varchar, "VARCHAR"},
{utils::basic_type::type_text, "TEXT"},
{utils::basic_type::type_date, "DATE"},
{utils::basic_type::type_time, "DATETIME"},
{utils::basic_type::type_blob, "BLOB"},
{utils::basic_type::type_null, "NULL"}
};
sql_func_to_string_map sql_func_map_ {
@@ -224,6 +202,10 @@ private:
{sql_function_t::MIN, "MIN" },
{sql_function_t::MAX, "MAX" },
};
std::array<std::string, 2> bool_strings_ {
"0", "1"
};
};
}
+1
View File
@@ -16,6 +16,7 @@ public:
dialect_builder& with_data_type_replace_map(const dialect::data_type_to_string_map &data_type_replace_map);
dialect_builder& with_placeholder_func(const dialect::next_placeholder_func &func);
dialect_builder& with_default_schema_name(const std::string &schema_name);
dialect_builder& with_bool_strings(const std::string &true_string, const std::string &false_string);
dialect build();
+54
View File
@@ -0,0 +1,54 @@
#ifndef DIALECT_TOKEN_HPP
#define DIALECT_TOKEN_HPP
#include <cstdint>
namespace matador::sql {
enum class dialect_token : uint8_t
{
CREATE = 0,
DROP,
REMOVE,
INSERT,
UPDATE,
SELECT,
TABLE,
VALUES,
INSERT_VALUES,
COLUMNS,
COLUMN,
FROM,
JOIN,
ON,
INTO,
WHERE,
WHERE_CLAUSE,
AND,
OR,
LIKE,
ORDER_BY,
GROUP_BY,
ASC,
DESC,
LIMIT,
AS,
OFFSET,
DISTINCT,
SET,
UPDATE_VALUES,
NOT_NULL,
PRIMARY_KEY,
BEGIN,
COMMIT,
ROLLBACK,
START_QUOTE,
END_QUOTE,
STRING_QUOTE,
BEGIN_BINARY_DATA,
END_BINARY_DATA,
NONE
};
}
#endif //DIALECT_TOKEN_HPP
-49
View File
@@ -1,49 +0,0 @@
#ifndef QUERY_ENTITY_HPP
#define QUERY_ENTITY_HPP
#include <memory>
namespace matador::sql {
template < class Type >
class entity
{
public:
using value_type = Type;
using pointer = value_type*;
using reference = value_type&;
entity() = default;
explicit entity(Type *obj)
: obj_(obj) {}
entity(const entity&) = default;
entity& operator=(const entity&) = default;
entity(entity&&) noexcept = default;
entity& operator=(entity&&) noexcept = default;
~entity() = default;
void reset(Type *obj) { obj_.reset(obj); }
pointer operator->() { return obj_.get(); }
const value_type* operator->() const { return obj_.get(); }
reference operator*() { return *obj_; }
const value_type& operator*() const { return *obj_; }
pointer get() { return obj_.get(); }
const value_type* get() const { return obj_.get(); }
operator bool() const { return obj_.get() != nullptr; } // NOLINT(*-explicit-constructor)
private:
std::shared_ptr<value_type> obj_;
};
template<class Type, typename... Args>
[[maybe_unused]] entity<Type> make_entity(Args&&... args)
{
return entity(new Type(std::forward<Args>(args)...));
}
}
#endif //QUERY_ENTITY_HPP
@@ -1,283 +0,0 @@
#ifndef QUERY_ENTITY_QUERY_BUILDER_HPP
#define QUERY_ENTITY_QUERY_BUILDER_HPP
#include "matador/sql/connection.hpp"
#include "matador/sql/condition.hpp"
#include "matador/sql/query_context.hpp"
#include "matador/sql/query.hpp"
#include "matador/sql/query_intermediates.hpp"
#include "matador/sql/value.hpp"
#include "matador/utils/result.hpp"
#include <iostream>
namespace matador::sql {
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::utils::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<column> columns;
std::vector<join_data> joins;
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:
explicit entity_query_builder(const schema &scm)
: schema_(scm) {}
template<class EntityType, typename PrimaryKeyType>
utils::result<entity_query_data, query_build_error> build(const PrimaryKeyType &pk) {
const auto info = schema_.info<EntityType>();
if (!info) {
return utils::error(query_build_error::UnknownType);
}
pk_ = pk;
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 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 >
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)
{
push(id);
if (!is_root_entity()) {
return;
}
if (pk_.is_null()) {
entity_query_data_.pk_column_ = id;
} else if (pk_.is_integer()) {
entity_query_data_.where_clause = make_condition(column{table_info_stack_.top().name, id, ""} == *pk_.as<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::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, table_info_stack_.top().prototype.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::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, table_info_stack_.top().prototype.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::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};
}
const auto join_columns = join_column_collector_.collect<typename ContainerType::value_type::value_type>();
append_join({table_info_stack_.top().name, table_info_stack_.top().prototype.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 column &left, const column &right);
private:
value pk_;
std::stack<table_info> table_info_stack_;
const schema &schema_;
entity_query_data entity_query_data_;
int column_index{0};
join_column_collector join_column_collector_;
};
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
+43
View File
@@ -0,0 +1,43 @@
#ifndef SQL_ERROR_CODE_HPP
#define SQL_ERROR_CODE_HPP
#include <cstdint>
#include <system_error>
namespace matador::sql {
enum class error_code : uint8_t {
OK = 0,
INVALID_QUERY,
UNKNOWN_TABLE,
UNKNOWN_COLUMN,
BIND_FAILED,
EXECUTE_FAILED,
FETCH_FAILED,
PREPARE_FAILED,
DESCRIBE_FAILED,
TABLE_EXISTS_FAILED,
RETRIEVE_DATA_FAILED,
RESET_FAILED,
OPEN_ERROR,
CLOSE_ERROR,
FAILURE
};
class sql_category_impl final : public std::error_category
{
public:
[[nodiscard]] const char* name() const noexcept override;
[[nodiscard]] std::string message(int ev) const override;
};
const std::error_category& sql_category();
std::error_code make_error_code(error_code e);
std::error_condition make_error_condition(error_code e);
}
template <>
struct std::is_error_code_enum<matador::sql::error_code> : true_type {};
#endif //SQL_ERROR_CODE_HPP
+28
View File
@@ -0,0 +1,28 @@
#ifndef EXECUTOR_HPP
#define EXECUTOR_HPP
#include "matador/utils/error.hpp"
#include "matador/utils/result.hpp"
#include <memory>
namespace matador::sql {
struct query_context;
class query_result_impl;
class statement;
class executor {
public:
virtual ~executor();
[[nodiscard]] virtual const class dialect& dialect() const = 0;
[[nodiscard]] virtual utils::result<size_t, utils::error> execute(const query_context &ctx) const = 0;
[[nodiscard]] virtual utils::result<std::unique_ptr<query_result_impl>, utils::error> fetch(const query_context &ctx) const = 0;
[[nodiscard]] virtual utils::result<statement, utils::error> prepare(const query_context &ctx) const = 0;
[[nodiscard]] virtual std::string str(const query_context &ctx) const = 0;
};
}
#endif //EXECUTOR_HPP
+12 -11
View File
@@ -1,23 +1,27 @@
#ifndef QUERY_FIELD_HPP
#define QUERY_FIELD_HPP
#include "matador/sql/value.hpp"
#include "matador/utils/value.hpp"
#include "matador/utils/basic_types.hpp"
#include <optional>
#include <string>
namespace matador::sql {
class field
{
/**
*
*/
class field {
public:
explicit field(std::string name);
template<typename Type>
field(std::string name, Type value, size_t size = 0, int index = -1)
field(std::string name, Type value, const size_t size = 0, const int index = -1)
: name_(std::move(name))
, index_(index)
, value_(value, size) {}
field(std::string name, data_type_t data_type, size_t size = 0, int index = -1);
field(std::string name, utils::basic_type dt, size_t size = 0, int index = -1);
field(const field &x) = default;
field& operator=(const field &x) = default;
field(field &&x) noexcept;
@@ -35,8 +39,7 @@ public:
[[nodiscard]] int index() const;
template<class Type>
std::optional<Type> as() const
{
std::optional<Type> as() const {
return value_.as<Type>();
}
@@ -49,14 +52,12 @@ public:
[[nodiscard]] bool is_varchar() const;
[[nodiscard]] bool is_blob() const;
[[nodiscard]] bool is_null() const;
[[nodiscard]] bool is_unknown() const;
friend std::ostream& operator<<(std::ostream &out, const field &col);
private:
template<class Operator>
void process(Operator &op)
{
void process(Operator &op) {
op.on_attribute(name_.c_str(), value_, value_.size());
}
@@ -66,7 +67,7 @@ private:
std::string name_;
int index_{-1};
value value_;
utils::value value_;
};
}
@@ -1,38 +0,0 @@
#ifndef QUERY_HAS_MANY_TO_MANY_RELATION_HPP
#define QUERY_HAS_MANY_TO_MANY_RELATION_HPP
#include "matador/sql/entity.hpp"
#include "matador/utils/access.hpp"
#include "matador/utils/foreign_attributes.hpp"
namespace matador::sql {
template < class LocalType, class ForeignType >
class has_many_to_many_relation
{
public:
has_many_to_many_relation() = default;
has_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::utils::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);
}
entity<LocalType> local() const { return local_; }
entity<LocalType> remote() const { return remote_; }
private:
std::string local_name_;
std::string remote_name_;
sql::entity<LocalType> local_;
sql::entity<ForeignType> remote_;
};
}
#endif //QUERY_HAS_MANY_TO_MANY_RELATION_HPP
@@ -0,0 +1,57 @@
#ifndef QUERY_CONNECTION_IMPL_HPP
#define QUERY_CONNECTION_IMPL_HPP
#include <memory>
#include "matador/sql/column_definition.hpp"
#include "matador/sql/connection_info.hpp"
#include "matador/sql/query_context.hpp"
#include "matador/utils/error.hpp"
#include "matador/utils/result.hpp"
#include "matador/utils/version.hpp"
namespace matador::utils {
using blob = std::vector<unsigned char>;
}
namespace matador::sql {
class query_result_impl;
class statement_impl;
class connection_impl
{
public:
virtual ~connection_impl() = default;
virtual utils::result<void, utils::error> open() = 0;
virtual utils::result<void, utils::error> close() = 0;
[[nodiscard]] virtual utils::result<bool, utils::error> is_open() const = 0;
[[nodiscard]] virtual utils::result<bool, utils::error> is_valid() const = 0;
[[nodiscard]] virtual utils::result<utils::version, utils::error> client_version() const = 0;
[[nodiscard]] virtual utils::result<utils::version, utils::error> server_version() const = 0;
virtual utils::result<size_t, utils::error> execute(const std::string &stmt) = 0;
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<bool, utils::error> exists(const std::string &schema_name, const std::string &table_name) = 0;
[[nodiscard]] const class dialect &dialect() const;
[[nodiscard]] virtual std::string to_escaped_string(const utils::blob &value) const = 0;
protected:
explicit connection_impl(const connection_info &info);
[[nodiscard]] const connection_info &info() const;
private:
std::reference_wrapper<const connection_info> info_;
std::reference_wrapper<const class dialect> dialect_;
};
}
#endif //QUERY_CONNECTION_IMPL_HPP
@@ -6,23 +6,21 @@
#include <string>
#include <cstring>
namespace matador::sql {
namespace matador::sql::interface {
class parameter_binder
{
public:
virtual ~parameter_binder() = default;
virtual void bind(size_t pos, char) = 0;
virtual void bind(size_t pos, short) = 0;
virtual void bind(size_t pos, int) = 0;
virtual void bind(size_t pos, long) = 0;
virtual void bind(size_t pos, long long) = 0;
virtual void bind(size_t pos, unsigned char) = 0;
virtual void bind(size_t pos, unsigned short) = 0;
virtual void bind(size_t pos, unsigned int) = 0;
virtual void bind(size_t pos, unsigned long) = 0;
virtual void bind(size_t pos, unsigned long long) = 0;
virtual void bind(size_t pos, int8_t) = 0;
virtual void bind(size_t pos, int16_t) = 0;
virtual void bind(size_t pos, int32_t) = 0;
virtual void bind(size_t pos, int64_t) = 0;
virtual void bind(size_t pos, uint8_t) = 0;
virtual void bind(size_t pos, uint16_t) = 0;
virtual void bind(size_t pos, uint32_t) = 0;
virtual void bind(size_t pos, uint64_t) = 0;
virtual void bind(size_t pos, bool) = 0;
virtual void bind(size_t pos, float) = 0;
virtual void bind(size_t pos, double) = 0;
@@ -0,0 +1,35 @@
#ifndef QUERY_QUERY_RESULT_READER_HPP
#define QUERY_QUERY_RESULT_READER_HPP
#include "matador/sql/internal/object_result_binder.hpp"
#include "matador/utils/attribute_reader.hpp"
#include "matador/utils/error.hpp"
#include "matador/utils/result.hpp"
namespace matador::sql {
class query_result_reader : public utils::attribute_reader
{
public:
[[nodiscard]] virtual size_t column_count() const = 0;
[[nodiscard]] virtual const char* column(size_t index) const = 0;
[[nodiscard]] virtual utils::result<bool, utils::error> fetch() = 0;
[[nodiscard]] virtual size_t start_column_index() const = 0;
template<class Type>
void bind(Type &obj) {
object_binder_.reset();
object_binder_.bind(obj, result_binder());
}
protected:
virtual attribute_reader& result_binder() = 0;
private:
// detail::empty_binder empty_result_binder_;
object_result_binder object_binder_;
};
}
#endif //QUERY_QUERY_RESULT_READER_HPP
@@ -0,0 +1,62 @@
#ifndef QUERY_STATEMENT_IMPL_HPP
#define QUERY_STATEMENT_IMPL_HPP
#include "matador/sql/query_context.hpp"
#include "matador/sql/internal/query_result_impl.hpp"
#include "matador/sql/object_parameter_binder.hpp"
#include "matador/utils/data_type_traits.hpp"
#include <memory>
namespace matador::sql {
class sql_error;
class statement_impl
{
protected:
explicit statement_impl(query_context query);
public:
virtual ~statement_impl() = default;
virtual utils::result<size_t, utils::error> execute() = 0;
virtual utils::result<std::unique_ptr<query_result_impl>, utils::error> fetch() = 0;
template < class Type >
void bind_object(Type &obj)
{
object_parameter_binder object_binder_;
object_binder_.reset(start_index());
object_binder_.bind(obj, binder());
}
template < class Type >
void bind(const size_t pos, Type &val)
{
utils::data_type_traits<Type>::bind_value(binder(), adjust_index(pos), val);
}
void bind(size_t pos, const char *value, size_t size);
void bind(size_t pos, std::string &val, size_t size);
virtual void reset() = 0;
[[nodiscard]] const std::vector<std::string>& bind_vars() const;
[[nodiscard]] bool is_valid_host_var(const std::string &host_var, size_t pos) const;
protected:
virtual utils::attribute_writer& binder() = 0;
[[nodiscard]] virtual size_t start_index() const;
[[nodiscard]] virtual size_t adjust_index(size_t index) const;
protected:
friend class statement;
query_context query_;
};
}
#endif //QUERY_STATEMENT_IMPL_HPP
@@ -0,0 +1,137 @@
#ifndef MATADOR_OBJECT_RESULT_BINDER_HPP
#define MATADOR_OBJECT_RESULT_BINDER_HPP
#include "matador/utils/attribute_reader.hpp"
#include "matador/utils/default_type_traits.hpp"
#include "matador/utils/access.hpp"
#include "matador/utils/field_attributes.hpp"
#include "matador/utils/foreign_attributes.hpp"
namespace matador::sql {
namespace detail {
class fk_result_binder
{
public:
template<class Type>
void bind(Type &obj, const char *id, size_t column_index, utils::attribute_reader &binder)
{
binder_ = &binder;
index_ = column_index;
id_ = id;
access::process(*this, obj);
id_ = nullptr;
binder_ = nullptr;
}
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);
void on_primary_key(const char *id, std::string &value, 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) {}
template < class Pointer >
void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
template < class Pointer >
void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
template<class ContainerType>
void on_has_many(const char * /*id*/,
ContainerType &/*c*/,
const char * /*join_column*/,
const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
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::attribute_reader *binder_{};
size_t index_{0};
const char *id_{};
};
}
class object_result_binder {
public:
template<class Type>
void bind(Type &obj, utils::attribute_reader &binder) {
binder_ = &binder;
access::process(*this, obj);
binder_ = nullptr;
}
void reset();
template < class Type >
void on_primary_key(const char *id, Type &val, std::enable_if_t<std::is_integral_v<Type> && !std::is_same_v<bool, Type>>* = nullptr)
{
utils::data_type_traits<Type>::read_value(*binder_, id, index_++, val);
}
void on_primary_key(const char *id, std::string &, size_t size);
void on_revision(const char *id, uint64_t &/*rev*/);
template<typename Type>
void on_attribute(const char *id, Type &val, const utils::field_attributes &/*attr*/ = utils::null_attributes)
{
utils::data_type_traits<Type>::read_value(*binder_, id, index_++, val);
}
void on_attribute(const char *id, char *value, const utils::field_attributes &attr = utils::null_attributes);
void on_attribute(const char *id, std::string &value, const utils::field_attributes &attr = utils::null_attributes);
void on_attribute(const char *id, utils::value &val, const utils::field_attributes &attr = utils::null_attributes);
template<class Type, template < class ... > class Pointer>
void on_belongs_to(const char *id, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes)
{
fk_result_binder_.bind(*x, id, index_++, *binder_);
}
template<class Type, template < class ... > class Pointer>
void on_has_one(const char *id, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes)
{
fk_result_binder_.bind(*x, id, index_++, *binder_);
}
template<class ContainerType>
void on_has_many(const char * /*id*/,
ContainerType &/*c*/,
const char * /*join_column*/,
const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
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::attribute_reader *binder_{};
size_t index_{0};
detail::fk_result_binder fk_result_binder_;
};
namespace detail {
template<typename ValueType>
void fk_result_binder::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(*binder_, id_, index_++, value);
}
}
}
#endif //MATADOR_OBJECT_RESULT_BINDER_HPP
@@ -4,18 +4,20 @@
#include "matador/utils/access.hpp"
#include "matador/utils/field_attributes.hpp"
#include "matador/utils/foreign_attributes.hpp"
#include "matador/utils/default_type_traits.hpp"
#include "matador/sql/interface/query_result_reader.hpp"
#include "matador/sql/any_type.hpp"
#include "matador/sql/query_result_reader.hpp"
#include "matador/sql/column_definition.hpp"
#include "matador/sql/data_type_traits.hpp"
#include <memory>
#include <string>
namespace matador::sql {
namespace matador::utils {
class value;
}
namespace matador::sql {
namespace detail {
class pk_reader
@@ -24,14 +26,14 @@ public:
explicit pk_reader(query_result_reader &reader);
template<class Type>
void read(Type &obj, size_t column_index)
void read(Type &obj, const size_t column_index)
{
column_index_ = column_index;
utils::access::process(*this, obj);
access::process(*this, obj);
}
template<typename ValueType>
void on_primary_key(const char *id, ValueType &value, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type* = 0);
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);
void on_primary_key(const char *id, std::string &value, size_t size);
void on_revision(const char * /*id*/, unsigned long long &/*rev*/) {}
@@ -43,7 +45,7 @@ public:
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*/) {}
void on_has_many(const char * /*id*/, 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>
@@ -59,66 +61,91 @@ private:
class query_result_impl
{
public:
query_result_impl(std::unique_ptr<query_result_reader> &&reader, std::vector<column_definition> prototype);
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);
template<typename ValueType>
void on_primary_key(const char *id, ValueType &value, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type* = 0)
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)
{
data_type_traits<ValueType>::read_value(*reader_, id, column_index_++, value);
utils::data_type_traits<ValueType>::read_value(*reader_, id, column_index_++, value);
}
void on_primary_key(const char *id, std::string &value, size_t size);
void on_revision(const char *id, unsigned long long &rev);
void on_revision(const char *id, uint64_t &rev);
template < class Type >
void on_attribute(const char *id, Type &x, const utils::field_attributes &/*attr*/ = utils::null_attributes)
{
data_type_traits<Type>::read_value(*reader_, id, column_index_++, x);
utils::data_type_traits<Type>::read_value(*reader_, id, column_index_++, x);
}
void on_attribute(const char *id, char *value, const utils::field_attributes &attr = utils::null_attributes);
void on_attribute(const char *id, std::string &value, const utils::field_attributes &attr = utils::null_attributes);
void on_attribute(const char *id, value &val, const utils::field_attributes &attr = utils::null_attributes);
void on_attribute(const char *id, utils::value &val, 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)
{
if (!x.get()) {
x.reset(new typename Pointer::value_type);
if (x.empty()) {
x = new typename Pointer::value_type;
}
if (attr.fetch() == utils::fetch_type::LAZY) {
pk_reader_.read(*x, column_index_++);
} else {
utils::access::process(*this, *x);
access::process(*this, *x);
}
}
template < class Pointer >
void on_has_one(const char * /*id*/, Pointer &x, const utils::foreign_attributes &attr)
{
if (!x.get()) {
x.reset(new typename Pointer::value_type);
if (x.empty()) {
x = new typename Pointer::value_type;
}
if (attr.fetch() == utils::fetch_type::LAZY) {
pk_reader_.read(*x, column_index_++);
} else {
utils::access::process(*this, *x);
access::process(*this, *x);
}
}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, const char *, const char *, const utils::foreign_attributes &/*attr*/) {}
void on_has_many_to_many(const char *, ContainerType &, 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 *, ContainerType &, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType>
void on_has_many(const char * /*id*/, ContainerType &cont, const char * /*join_column*/, const utils::foreign_attributes &attr) {
if ( attr.fetch() == utils::fetch_type::LAZY ) {
// pk_reader_.read(*id, column_index_++);
} else {
auto obj = std::make_unique<typename ContainerType::value_type::value_type>();
// typename ContainerType::value_type x(new typename ContainerType::value_type::value_type);
access::process(*this, *obj);
auto ptr = typename ContainerType::value_type(obj.release());
const auto pk = ptr.primary_key();
if (ptr.primary_key().is_valid()) {
cont.push_back(ptr);
}
}
}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, const utils::foreign_attributes &/*attr*/) {}
template<class Type>
void bind(const Type &) {}
void bind(const Type &obj)
{
reader_->bind(obj);
}
template<class Type>
bool fetch(Type &obj)
{
column_index_ = 0;
if (!reader_->fetch()) {
column_index_ = reader_->start_column_index();
auto fetched = reader_->fetch();
if (!fetched.is_ok()) {
return false;
}
matador::utils::access::process(*this, obj);
if (!*fetched) {
return false;
}
access::process(*this, obj);
return true;
}
@@ -134,9 +161,9 @@ protected:
namespace detail {
template<typename ValueType>
void detail::pk_reader::on_primary_key(const char *id, ValueType &value, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type *)
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>> *)
{
data_type_traits<ValueType>::read_value(reader_, id, column_index_++, value);
utils::data_type_traits<ValueType>::read_value(reader_, id, column_index_++, value);
}
}
-25
View File
@@ -1,25 +0,0 @@
#ifndef QUERY_KEY_VALUE_PAIR_HPP
#define QUERY_KEY_VALUE_PAIR_HPP
#include "matador/sql/any_type.hpp"
#include "matador/sql/column.hpp"
namespace matador::sql {
class key_value_pair
{
public:
key_value_pair(const sql::column &col, any_type value);
key_value_pair(std::string name, any_type value);
key_value_pair(const char *name, any_type value);
[[nodiscard]] const std::string& name() const;
[[nodiscard]] const any_type& value() const;
private:
std::string name_;
any_type value_;
};
}
#endif //QUERY_KEY_VALUE_PAIR_HPP
-26
View File
@@ -1,26 +0,0 @@
#ifndef QUERY_NOOP_CONNECTION_HPP
#define QUERY_NOOP_CONNECTION_HPP
#include "matador/sql/connection_impl.hpp"
namespace matador::sql {
class noop_connection final : public connection_impl
{
public:
explicit noop_connection(const connection_info &info);
void open() override;
void close() override;
bool is_open() override;
size_t execute(const std::string &stmt) override;
std::unique_ptr<query_result_impl> fetch(const std::string &stmt) override;
std::unique_ptr<statement_impl> prepare(query_context context) override;
std::vector<sql::column_definition> describe(const std::string &table) override;
bool exists(const std::string &schema_name, const std::string &table_name) override;
private:
bool is_open_{false};
};
}
#endif //QUERY_NOOP_CONNECTION_HPP
+57 -29
View File
@@ -1,49 +1,61 @@
#ifndef QUERY_OBJECT_PARAMETER_BINDER_HPP
#define QUERY_OBJECT_PARAMETER_BINDER_HPP
#include "matador/sql/parameter_binder.hpp"
#include "matador/sql/data_type_traits.hpp"
#include "matador/utils/attribute_writer.hpp"
#include "matador/utils/default_type_traits.hpp"
#include "matador/utils/access.hpp"
#include "matador/utils/cascade_type.hpp"
#include "matador/utils/field_attributes.hpp"
#include "matador/utils/foreign_attributes.hpp"
#include <string>
namespace matador::sql {
namespace detail {
class fk_binder
{
public:
explicit fk_binder(parameter_binder &binder);
template<class Type>
void bind(Type &obj, size_t column_index)
void bind(Type &obj, const size_t column_index, utils::attribute_writer &binder)
{
binder_ = &binder;
index_ = column_index;
utils::access::process(*this, obj);
access::process(*this, obj);
binder_ = nullptr;
}
template<typename ValueType>
void on_primary_key(const char *id, ValueType &value, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type* = 0);
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);
void on_primary_key(const char *id, std::string &value, 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) {}
template < class Pointer >
void on_belongs_to(const char * /*id*/, Pointer &/*x*/, utils::cascade_type) {}
void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
template < class Pointer >
void on_has_one(const char * /*id*/, Pointer &/*x*/, utils::cascade_type) {}
void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {}
void on_has_many(const char * /*id*/,
ContainerType &/*c*/,
const char * /*join_column*/,
const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, utils::cascade_type) {}
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:
parameter_binder &binder_;
utils::attribute_writer *binder_{};
size_t index_{0};
};
@@ -52,41 +64,57 @@ private:
class object_parameter_binder
{
public:
explicit object_parameter_binder(parameter_binder &binder);
template<class Type>
void bind(Type &obj, utils::attribute_writer &binder) {
binder_ = &binder;
access::process(*this, obj);
binder_ = nullptr;
}
void reset();
void reset(size_t start_index);
template < class Type >
void on_primary_key(const char *id, Type &val, typename std::enable_if<std::is_integral<Type>::value && !std::is_same<bool, Type>::value>::type* = 0)
void on_primary_key(const char * /*id*/, Type &val, std::enable_if_t<std::is_integral_v<Type> && !std::is_same_v<bool, Type>>* = nullptr)
{
data_type_traits<Type>::bind_value(binder_, index_++, val);
utils::data_type_traits<Type>::bind_value(*binder_, index_++, val);
}
void on_primary_key(const char *id, std::string &, size_t size);
void on_revision(const char *id, unsigned long long &/*rev*/);
void on_revision(const char *id, uint64_t &/*rev*/);
template<typename Type>
void on_attribute(const char *id, Type &val, const utils::field_attributes &/*attr*/ = utils::null_attributes)
void on_attribute(const char * /*id*/, Type &val, const utils::field_attributes &/*attr*/ = utils::null_attributes)
{
data_type_traits<Type>::bind_value(binder_, index_++, val);
utils::data_type_traits<Type>::bind_value(*binder_, index_++, val);
}
template<class Type, template < class ... > class Pointer>
void on_belongs_to(const char *id, Pointer<Type> &x, utils::cascade_type)
void on_belongs_to(const char * /*id*/, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes)
{
fk_binder_.bind(index_++, x);
fk_binder_.bind(*x, index_++, *binder_);
}
template<class Type, template < class ... > class Pointer>
void on_has_one(const char *id, Pointer<Type> &x, utils::cascade_type)
void on_has_one(const char * /*id*/, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes)
{
fk_binder_.bind(index_++, x);
fk_binder_.bind(*x, index_++, *binder_);
}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {}
void on_has_many(const char * /*id*/,
ContainerType &/*c*/,
const char * /*join_column*/,
const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, utils::cascade_type) {}
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:
parameter_binder &binder_;
utils::attribute_writer *binder_{};
size_t index_{0};
detail::fk_binder fk_binder_;
};
@@ -94,9 +122,9 @@ private:
namespace detail {
template<typename ValueType>
void fk_binder::on_primary_key(const char *id, ValueType &value, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type *)
void fk_binder::on_primary_key(const char * /*id*/, ValueType &value, std::enable_if_t<std::is_integral_v<ValueType> && !std::is_same_v<bool, ValueType>> *)
{
data_type_traits<ValueType>::bind_value(binder_, index_++, value);
utils::data_type_traits<ValueType>::bind_value(*binder_, index_++, value);
}
}
@@ -1,49 +0,0 @@
#ifndef QUERY_PLACEHOLDER_GENERATOR_HPP
#define QUERY_PLACEHOLDER_GENERATOR_HPP
#include "matador/sql/any_type.hpp"
#include "matador/utils/cascade_type.hpp"
#include "matador/utils/field_attributes.hpp"
#include <vector>
namespace matador::sql {
class placeholder_generator
{
public:
template < class V >
void on_primary_key(const char *id, V &val, typename std::enable_if<std::is_integral<V>::value && !std::is_same<bool, V>::value>::type* = 0)
{
placeholder_values.emplace_back(_);
}
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 &val, const utils::field_attributes &/*attr*/ = utils::null_attributes)
{
placeholder_values.emplace_back(_);
}
template<class Type, template < class ... > class Pointer>
void on_belongs_to(const char *id, Pointer<Type> &x, utils::cascade_type)
{
placeholder_values.emplace_back(_);
}
template<class Type, template < class ... > class Pointer>
void on_has_one(const char *id, Pointer<Type> &x, utils::cascade_type)
{
placeholder_values.emplace_back(_);
}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, utils::cascade_type) {}
std::vector<any_type> placeholder_values;
};
}
#endif //QUERY_PLACEHOLDER_GENERATOR_HPP
-32
View File
@@ -1,32 +0,0 @@
#ifndef QUERY_QUERY_HPP
#define QUERY_QUERY_HPP
#include "matador/sql/query_intermediates.hpp"
namespace matador::sql {
class connection;
class query
{
public:
explicit query(connection &db, const sql::schema &schema);
query(const query &) = delete;
query& operator=(const query &) = delete;
query_create_intermediate create();
query_drop_intermediate drop();
query_select_intermediate select(std::initializer_list<column> columns);
query_select_intermediate select(const std::vector<column>& columns);
query_select_intermediate select(std::vector<column> columns, std::initializer_list<column> additional_columns);
query_insert_intermediate insert();
query_update_intermediate update(const sql::table &table);
query_delete_intermediate remove();
private:
connection &connection_;
const sql::schema &schema_;
};
}
#endif //QUERY_QUERY_HPP
-89
View File
@@ -1,89 +0,0 @@
@startuml
scale 800 width
state Query
state Create
Create : Create database table
state Drop
Drop : Drop database table
state Select
Select: Query rows
Select: Add columns
state Insert
Insert: Insert rows
state Update
Update: Update rows
Update: Set table name
state Delete
Delete: Delete items from table
state Table
Table: Set table name
state Into
Into: Set table name
Into: Add columns
state From
From: Set table name
state Join
Join: Set table
Join: Set join type (inner left, right, outer)
state Where
Where: Add where clause
state Set
Set: Set column value pairs
state Values
Values: Set values
state On:
On: Set Expression
state GroupBy
GroupBy: Add column names
state OrderBy
OrderBy: Add expression
state Limit
Limit: Add number of max result elements
[*] --> Query
Query --> Create
Query --> Drop
Query --> Select
Query --> Insert
Query --> Update
Query --> Delete
Create --> Table
Drop --> Table
Select --> From
Insert --> Into
Delete --> From
Into --> Values
Update --> Set
Set -> Where
From --> Where
From --> OrderBy
From --> GroupBy
From --> Join
Join --> On
On --> Where
Where --> GroupBy
Where --> OrderBy
Where --> Limit
GroupBy --> OrderBy
OrderBy --> Limit
Table --> [*]
Values ---> [*]
Where --> [*]
Set --> [*]
From --> [*]
Limit --> [*]
OrderBy --> [*]
GroupBy --> [*]
@enduml
-176
View File
@@ -1,176 +0,0 @@
#ifndef QUERY_QUERY_BUILDER_HPP
#define QUERY_QUERY_BUILDER_HPP
#include "matador/sql/basic_condition.hpp"
#include "matador/sql/column_definition.hpp"
#include "matador/sql/column.hpp"
#include "matador/sql/dialect.hpp"
#include "matador/sql/key_value_pair.hpp"
#include "matador/sql/query_context.hpp"
#include "matador/sql/record.hpp"
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
namespace matador::sql {
namespace detail {
struct any_type_to_string_visitor
{
explicit any_type_to_string_visitor(const dialect &d, query_context &query);
void operator()(char &x) { to_string(x); }
void operator()(short &x) { to_string(x); }
void operator()(int &x) { to_string(x); }
void operator()(long &x) { to_string(x); }
void operator()(long long &x) { to_string(x); }
void operator()(unsigned char &x) { to_string(x); }
void operator()(unsigned short &x) { to_string(x); }
void operator()(unsigned int &x) { to_string(x); }
void operator()(unsigned long &x) { to_string(x); }
void operator()(unsigned long long &x) { to_string(x); }
void operator()(bool &x) { to_string(x); }
void operator()(float &x) { to_string(x); }
void operator()(double &x) { to_string(x); }
void operator()(const char *x) { to_string(x); }
void operator()(std::string &x) { to_string(x); }
void operator()(utils::blob &x) { to_string(x); }
void operator()(placeholder &x) { to_string(x); }
template<typename Type>
void to_string(Type &val)
{
result = std::to_string(val);
}
void to_string(const char *val);
void to_string(std::string &val);
void to_string(utils::blob &val);
void to_string(placeholder &val);
const dialect &d;
query_context &query;
std::string result;
};
}
column alias(const std::string &column, const std::string &as);
column alias(column &&col, const std::string &as);
column count(const std::string &column);
column count_all();
enum class join_type_t {
INNER, OUTER, LEFT, RIGHT
};
class query_builder
{
private:
enum class state_t {
QUERY_INIT,
QUERY_CREATE,
QUERY_TABLE_CREATE,
QUERY_TABLE_DROP,
QUERY_DROP,
QUERY_SELECT,
QUERY_INSERT,
QUERY_UPDATE,
QUERY_DELETE,
QUERY_SET,
QUERY_FROM,
QUERY_JOIN,
QUERY_ON,
QUERY_INTO,
QUERY_WHERE,
QUERY_VALUES,
QUERY_ORDER_BY,
QUERY_ORDER_DIRECTION,
QUERY_GROUP_BY,
QUERY_OFFSET,
QUERY_LIMIT,
QUERY_FINISH
};
enum class command_t {
UNKNOWN, /**< Unknown query command */
CREATE, /**< Create query command */
DROP, /**< Drop query command */
SELECT, /**< Select query command */
INSERT, /**< Insert query command */
UPDATE, /**< Update query command */
REMOVE /**< Remove query command */
};
struct query_part
{
query_part(dialect::token_t t, std::string p)
: token(t), part(std::move(p)) {}
dialect::token_t token;
std::string part;
};
public:
explicit query_builder(const dialect &d);
query_builder& create();
query_builder& drop();
query_builder& select(std::initializer_list<column> columns);
query_builder& select(const std::vector<column> &columns);
query_builder& insert();
query_builder& update(const std::string &table);
query_builder& remove();
query_builder& table(const std::string &table, std::initializer_list<column_definition> columns);
query_builder& table(const std::string &table, const std::vector<column_definition> &columns);
query_builder& table(const std::string &table);
query_builder& into(const std::string &table, std::initializer_list<column> column_names);
query_builder& into(const std::string &table, const std::vector<column> &column_names);
query_builder& values(std::initializer_list<any_type> values);
query_builder& values(const std::vector<any_type> &values);
query_builder& from(const std::string &table, const std::string &as = "");
query_builder& join(const std::string &table, join_type_t, const std::string &as = "");
query_builder& on(const std::string &column, const std::string &join_column);
query_builder& set(std::initializer_list<key_value_pair> key_values);
query_builder& set(const std::vector<key_value_pair> &key_values);
query_builder& where(const basic_condition &cond);
query_builder& order_by(const std::string &column);
query_builder& group_by(const std::string &column);
query_builder& asc();
query_builder& desc();
query_builder& offset(size_t count);
query_builder& limit(size_t count);
query_context compile();
private:
void transition_to(state_t next);
void initialize(command_t cmd, state_t state);
private:
const dialect &dialect_;
command_t command_{command_t::UNKNOWN};
state_t state_{state_t::QUERY_INIT};
std::vector<query_part> query_parts_;
detail::any_type_to_string_visitor value_to_string_;
query_context query_;
using query_state_set = std::unordered_set<state_t>;
using query_state_transition_map = std::unordered_map<state_t, query_state_set>;
using query_state_to_string_map = std::unordered_map<state_t, std::string>;
using query_command_to_string_map = std::unordered_map<command_t, std::string>;
static query_state_transition_map transitions_;
static query_state_to_string_map state_strings_;
static query_command_to_string_map command_strings_;
};
}
#endif //QUERY_QUERY_BUILDER_HPP
-59
View File
@@ -1,59 +0,0 @@
#ifndef QUERY_QUERY_COMPILER_HPP
#define QUERY_QUERY_COMPILER_HPP
#include "matador/sql/query_part_visitor.hpp"
#include "matador/sql/query_parts.hpp"
#include "matador/sql/query_context.hpp"
#include <typeindex>
#include <string>
namespace matador::sql {
class dialect;
struct query_data;
class query_compiler : public query_part_visitor
{
public:
explicit query_compiler(const sql::dialect& d);
query_context compile(const query_data *data);
private:
void visit(query_select_part &select_part) override;
void visit(query_from_part &from_part) override;
void visit(query_join_part &join_part) override;
void visit(query_on_part &on_part) override;
void visit(query_where_part &where_part) override;
void visit(query_group_by_part &group_by_part) override;
void visit(query_order_by_part &order_by_part) override;
void visit(query_order_by_asc_part &order_by_asc_part) override;
void visit(query_order_by_desc_part &order_by_desc_part) override;
void visit(query_offset_part &offset_part) override;
void visit(query_limit_part &limit_part) override;
void visit(query_insert_part &insert_part) override;
void visit(query_into_part &into_part) override;
void visit(query_values_part &values_part) override;
void visit(query_update_part &update_part) override;
void visit(query_set_part &set_part) override;
void visit(query_delete_part &delete_part) override;
void visit(query_delete_from_part &delete_from_part) override;
void visit(query_create_part &create_part) override;
void visit(query_create_table_part &create_table_part) override;
void visit(query_drop_part &drop_part) override;
void visit(query_drop_table_part &drop_table_part) override;
private:
const sql::dialect &dialect_;
query_context query_;
};
}
#endif //QUERY_QUERY_COMPILER_HPP
+21 -3
View File
@@ -1,21 +1,39 @@
#ifndef QUERY_QUERY_CONTEXT_HPP
#define QUERY_QUERY_CONTEXT_HPP
#ifndef QUERY_QUERY_DATA_HPP
#define QUERY_QUERY_DATA_HPP
#include "matador/sql/column_definition.hpp"
#include "matador/sql/table.hpp"
#include "matador/utils/types.hpp"
namespace matador::sql {
enum class sql_command {
SQL_CMD_UNKNOWN,
SQL_CMD_CREATE,
SQL_CMD_UPDATE,
SQL_CMD_INSERT,
SQL_CMD_DELETE,
SQL_CMD_SELECT,
SQL_CMD_DROP,
SQL_CMD_ALTER
};
struct query_context
{
std::string sql;
sql_command command{};
std::string command_name;
sql::table table{""};
std::vector<column_definition> prototype;
std::vector<std::string> result_vars;
std::vector<std::string> bind_vars;
std::vector<utils::database_type> bind_types;
std::unordered_map<std::string, std::string> column_aliases;
std::unordered_map<std::string, std::string> table_aliases;
};
}
#endif //QUERY_QUERY_CONTEXT_HPP
#endif //QUERY_QUERY_DATA_HPP
-23
View File
@@ -1,23 +0,0 @@
#ifndef QUERY_QUERY_DATA_HPP
#define QUERY_QUERY_DATA_HPP
#include "matador/sql/query_part.hpp"
#include "matador/sql/table.hpp"
#include <memory>
#include <vector>
namespace matador::sql {
class query_part;
struct query_data
{
// SqlCommands command;
std::vector<std::unique_ptr<query_part>> parts;
std::vector<column_definition> columns;
};
}
#endif //QUERY_QUERY_DATA_HPP
-24
View File
@@ -1,24 +0,0 @@
#ifndef QUERY_QUERY_HELPER_HPP
#define QUERY_QUERY_HELPER_HPP
#include "matador/utils/macro_map.hpp"
#include "matador/sql/table.hpp"
#include "matador/sql/column.hpp"
#include <string>
#include <ostream>
#define FIELD(x) const sql::column x{*this, #x, ""};
#define QUERY_HELPER(C, ...) \
namespace matador::qh { \
namespace internal { \
struct C##_query : sql::table { \
C##_query() : table(#C) {} \
MAP(FIELD, __VA_ARGS__) \
}; } \
static const internal:: C##_query C; \
}
#endif //QUERY_QUERY_HELPER_HPP
-344
View File
@@ -1,344 +0,0 @@
#ifndef QUERY_QUERY_INTERMEDIATES_HPP
#define QUERY_QUERY_INTERMEDIATES_HPP
#include "matador/sql/column_definition.hpp"
#include "matador/sql/column_definition_generator.hpp"
#include "matador/sql/column_generator.hpp"
#include "matador/sql/key_value_generator.hpp"
#include "matador/sql/key_value_pair.hpp"
#include "matador/sql/placeholder_generator.hpp"
#include "matador/sql/query_result.hpp"
#include "matador/sql/query_data.hpp"
#include "matador/sql/record.hpp"
#include "matador/sql/statement.hpp"
#include "matador/sql/schema.hpp"
#include "matador/sql/value_extractor.hpp"
#include <string>
namespace matador::sql {
class basic_condition;
class connection;
class basic_query_intermediate
{
public:
explicit basic_query_intermediate(connection &db, const sql::schema &schema);
protected:
connection &connection_;
const sql::schema &schema_;
};
class query_intermediate : public basic_query_intermediate
{
public:
query_intermediate(connection &db, const sql::schema &schema, const std::shared_ptr<query_data> &data);
protected:
std::shared_ptr<query_data> data_;
};
class query_execute : public query_intermediate
{
public:
using query_intermediate::query_intermediate;
size_t execute();
statement prepare();
[[nodiscard]] query_context build() const;
};
class query_select : public query_intermediate
{
protected:
using query_intermediate::query_intermediate;
public:
template < class Type >
query_result<Type> fetch_all()
{
return query_result<Type>(fetch());
}
query_result<record> fetch_all();
template < class Type >
std::unique_ptr<Type> fetch_one()
{
auto result = query_result<Type>(fetch());
auto first = result.begin();
if (first == result.end()) {
return nullptr;
}
return std::unique_ptr<Type>{first.release()};
}
std::optional<record> fetch_one();
template<typename Type>
std::optional<Type> fetch_value()
{
const auto result = fetch_one();
if (result.has_value()) {
return result.value().at(0).as<Type>().value();
}
return std::nullopt;
}
statement prepare();
[[nodiscard]] query_context build() const;
private:
std::unique_ptr<query_result_impl> fetch();
};
class query_offset_intermediate;
class query_limit_intermediate : public query_select
{
public:
using query_select::query_select;
query_offset_intermediate offset(size_t offset);
};
class query_offset_intermediate : public query_select
{
public:
using query_select::query_select;
query_limit_intermediate limit(size_t limit);
};
class query_order_direction_intermediate : public query_select
{
public:
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
{
public:
using query_select::query_select;
query_order_by_intermediate order_by(const column &col);
};
class query_order_by_intermediate : public query_intermediate
{
public:
using query_intermediate::query_intermediate;
query_order_direction_intermediate asc();
query_order_direction_intermediate desc();
};
class query_where_intermediate : public query_select
{
public:
using query_select::query_select;
query_group_by_intermediate group_by(const column &col);
query_order_by_intermediate order_by(const column &col);
};
class query_join_intermediate;
struct join_data
{
table join_table;
std::unique_ptr<basic_condition> condition;
};
class query_from_intermediate : public query_select
{
public:
using query_select::query_select;
query_join_intermediate join_left(const table &t);
query_from_intermediate join_left(join_data &data);
query_from_intermediate join_left(std::vector<join_data> &data_vector);
template<class Condition>
query_where_intermediate where(const Condition &cond)
{
return where_clause(std::make_unique<Condition>(std::move(cond)));
}
query_where_intermediate where(std::unique_ptr<basic_condition> &&cond)
{
return where_clause(std::move(cond));
}
query_group_by_intermediate group_by(const column &col);
query_order_by_intermediate order_by(const column &col);
private:
query_where_intermediate where_clause(std::unique_ptr<basic_condition> &&cond);
};
using query_on_intermediate = query_from_intermediate;
class query_join_intermediate : public query_intermediate
{
public:
using query_intermediate::query_intermediate;
template<class Condition>
query_on_intermediate on(const Condition &cond)
{
return on_clause(std::make_unique<Condition>(std::move(cond)));
}
query_on_intermediate on(std::unique_ptr<basic_condition> &&cond)
{
return on_clause(std::move(cond));
}
private:
query_on_intermediate on_clause(std::unique_ptr<basic_condition> &&cond);
};
class query_start_intermediate : public basic_query_intermediate
{
public:
explicit query_start_intermediate(connection &db, const sql::schema &schema);
protected:
std::shared_ptr<query_data> data_ { std::make_shared<query_data>() };
};
class query_select_intermediate : public query_start_intermediate
{
public:
query_select_intermediate(connection &db, const sql::schema &schema, const std::vector<column>& columns);
query_from_intermediate from(const table& t);
};
template < class Type >
std::vector<any_type> as_placeholder(const Type &obj)
{
placeholder_generator generator;
matador::utils::access::process(generator, obj);
return generator.placeholder_values;
}
class query_into_intermediate : public query_intermediate
{
public:
using query_intermediate::query_intermediate;
query_execute values(std::initializer_list<any_type> values);
query_execute values(std::vector<any_type> &&values);
template<class Type>
query_execute values()
{
Type obj;
return values(std::move(as_placeholder(obj)));
}
template<class Type>
query_execute values(const Type &obj)
{
return values(std::move(value_extractor::extract(obj)));
}
};
class query_create_intermediate : public query_start_intermediate
{
public:
explicit query_create_intermediate(connection &db, const sql::schema &schema);
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 table(const sql::table &table)
{
return this->table(table, column_definition_generator::generate<Type>(schema_));
}
};
class query_drop_intermediate : query_start_intermediate
{
public:
explicit query_drop_intermediate(connection &db, const sql::schema &schema);
query_execute table(const sql::table &table);
};
class query_insert_intermediate : public query_start_intermediate
{
public:
explicit query_insert_intermediate(connection &db, const sql::schema &schema);
query_into_intermediate into(const sql::table &table, std::initializer_list<column> column_names);
query_into_intermediate into(const sql::table &table, std::vector<column> &&column_names);
query_into_intermediate into(const sql::table &table);
};
class query_execute_where_intermediate : public query_execute
{
public:
using query_execute::query_execute;
query_order_by_intermediate order_by(const column &col);
};
class query_set_intermediate : public query_execute
{
public:
using query_execute::query_execute;
template<class Condition>
query_execute_where_intermediate where(const Condition &cond)
{
return where_clause(std::make_unique<Condition>(std::move(cond)));
}
private:
query_execute_where_intermediate where_clause(std::unique_ptr<basic_condition> &&cond);
};
class query_update_intermediate : public query_start_intermediate
{
public:
query_update_intermediate(connection &db, const sql::schema &schema, const sql::table& table);
query_set_intermediate set(std::initializer_list<key_value_pair> columns);
query_set_intermediate set(std::vector<key_value_pair> &&columns);
template<class Type>
query_set_intermediate set(const Type &obj)
{
return set(key_value_generator::generate(obj));
}
};
class query_delete_from_intermediate : public query_execute
{
public:
using query_execute::query_execute;
template<class Condition>
query_execute_where_intermediate where(const Condition &cond)
{
return where_clause(std::make_unique<Condition>(std::move(cond)));
}
private:
query_execute_where_intermediate where_clause(std::unique_ptr<basic_condition> &&cond);
};
class query_delete_intermediate : public query_start_intermediate
{
public:
explicit query_delete_intermediate(connection &db, const sql::schema &schema);
query_delete_from_intermediate from(const sql::table &table);
};
}
#endif //QUERY_QUERY_INTERMEDIATES_HPP
@@ -1,65 +0,0 @@
#ifndef QUERY_QUERY_PART_VISITOR_HPP
#define QUERY_QUERY_PART_VISITOR_HPP
namespace matador::sql {
class query_select_part;
class query_from_part;
class query_join_part;
class query_on_part;
class query_where_part;
class query_group_by_part;
class query_order_by_part;
class query_order_by_asc_part;
class query_order_by_desc_part;
class query_offset_part;
class query_limit_part;
class query_insert_part;
class query_into_part;
class query_values_part;
class query_update_part;
class query_set_part;
class query_delete_part;
class query_delete_from_part;
class query_create_part;
class query_create_table_part;
class query_drop_part;
class query_drop_table_part;
class query_part_visitor
{
public:
virtual ~query_part_visitor() = default;
virtual void visit(query_select_part &select_part) = 0;
virtual void visit(query_from_part &from_part) = 0;
virtual void visit(query_join_part &join_part) = 0;
virtual void visit(query_on_part &on_part) = 0;
virtual void visit(query_where_part &where_part) = 0;
virtual void visit(query_group_by_part &group_by_part) = 0;
virtual void visit(query_order_by_part &order_by_part) = 0;
virtual void visit(query_order_by_asc_part &order_by_asc_part) = 0;
virtual void visit(query_order_by_desc_part &order_by_desc_part) = 0;
virtual void visit(query_offset_part &offset_part) = 0;
virtual void visit(query_limit_part &limit_part) = 0;
virtual void visit(query_insert_part &insert_part) = 0;
virtual void visit(query_into_part &into_part) = 0;
virtual void visit(query_values_part &values_part) = 0;
virtual void visit(query_update_part &update_part) = 0;
virtual void visit(query_set_part &set_part) = 0;
virtual void visit(query_delete_part &delete_part) = 0;
virtual void visit(query_delete_from_part &delete_from_part) = 0;
virtual void visit(query_create_part &create_part) = 0;
virtual void visit(query_create_table_part &create_table_part) = 0;
virtual void visit(query_drop_part &drop_part) = 0;
virtual void visit(query_drop_table_part &drop_table_part) = 0;
};
}
#endif //QUERY_QUERY_PART_VISITOR_HPP
+26 -24
View File
@@ -1,7 +1,9 @@
#ifndef QUERY_QUERY_RESULT_HPP
#define QUERY_QUERY_RESULT_HPP
#include "matador/sql/query_result_impl.hpp"
#include "matador/sql/column_definition.hpp"
#include "matador/sql/internal/query_result_impl.hpp"
#include <functional>
#include <memory>
@@ -20,7 +22,7 @@ public:
using iterator_category = std::forward_iterator_tag;
using value_type = Type;
using difference_type = std::ptrdiff_t;
using self = query_result_iterator<Type>; /**< Shortcut for this class. */
using self = query_result_iterator; /**< Shortcut for this class. */
using pointer = value_type*; /**< Shortcut for the pointer type. */
using reference = value_type&; /**< Shortcut for the reference type */
@@ -78,7 +80,7 @@ public:
obj_.reset();
}
return std::move(tmp);
return tmp;
}
pointer operator->()
@@ -119,43 +121,43 @@ record* create_prototype<record>(const std::vector<column_definition> &prototype
}
template < typename Type >
class query_result
{
template<typename Type>
class query_result final {
public:
using iterator = query_result_iterator<Type>;
using creator_func = std::function<Type*()>;
public:
explicit query_result(std::unique_ptr<query_result_impl> impl)
explicit query_result(std::unique_ptr<query_result_impl> &&impl)
: impl_(std::move(impl)) {}
query_result(std::unique_ptr<query_result_impl> impl, std::vector<column_definition> record_prototype)
: record_prototype_(std::move(record_prototype))
, impl_(std::move(impl)) {}
iterator begin() { return std::move(++iterator(this)); }
iterator end() { return {}; }
private:
friend class query_result_iterator<Type>;
Type* create() { return detail::create_prototype<Type>(record_prototype_); }
Type* create();
void bind(const Type& obj);
bool fetch(Type& obj);
void bind(const Type &obj)
{
impl_->bind(obj);
}
bool fetch(Type &obj)
{
return impl_->fetch(obj);
}
private:
std::vector<column_definition> record_prototype_;
protected:
std::unique_ptr<query_result_impl> impl_;
};
template<typename Type>
Type *query_result<Type>::create() {
return detail::create_prototype<Type>(impl_->prototype());
}
template<typename Type>
void query_result<Type>::bind(const Type &obj) {
impl_->bind(obj);
}
template<typename Type>
bool query_result<Type>::fetch(Type &obj) {
return impl_->fetch(obj);
}
} // namespace matador::sql
#endif //QUERY_QUERY_RESULT_HPP
@@ -1,43 +0,0 @@
#ifndef QUERY_QUERY_RESULT_READER_HPP
#define QUERY_QUERY_RESULT_READER_HPP
#include "matador/sql/any_type.hpp"
#include "matador/sql/data_type_traits.hpp"
namespace matador::sql {
class value;
class query_result_reader
{
public:
virtual ~query_result_reader() = default;
[[nodiscard]] virtual size_t column_count() const = 0;
[[nodiscard]] virtual const char* column(size_t index) const = 0;
[[nodiscard]] virtual bool fetch() = 0;
virtual void read_value(const char *id, size_t index, char &value);
virtual void read_value(const char *id, size_t index, short &value);
virtual void read_value(const char *id, size_t index, int &value);
virtual void read_value(const char *id, size_t index, long &value);
virtual void read_value(const char *id, size_t index, long long &value);
virtual void read_value(const char *id, size_t index, unsigned char &value);
virtual void read_value(const char *id, size_t index, unsigned short &value);
virtual void read_value(const char *id, size_t index, unsigned int &value);
virtual void read_value(const char *id, size_t index, unsigned long &value);
virtual void read_value(const char *id, size_t index, unsigned long long &value);
virtual void read_value(const char *id, size_t index, bool &value);
virtual void read_value(const char *id, size_t index, float &value);
virtual void read_value(const char *id, size_t index, double &value);
// virtual void read_value(const char *id, size_t index, matador::time &value);
// virtual void read_value(const char *id, size_t index, matador::date &value);
virtual void read_value(const char *id, size_t index, char *value, size_t s);
virtual void read_value(const char *id, size_t index, std::string &value);
virtual void read_value(const char *id, size_t index, std::string &value, size_t s);
virtual void read_value(const char *id, size_t index, utils::blob &value);
virtual void read_value(const char *id, size_t index, value &val, size_t size);
};
}
#endif //QUERY_QUERY_RESULT_READER_HPP
+10
View File
@@ -47,6 +47,16 @@ public:
[[nodiscard]] const field& at(const column &col) const;
[[nodiscard]] const field& at(size_t index) const;
template<class Type>
std::optional<Type> at(const column &col) const
{
return at(col).as<Type>();
}
template<class Type>
std::optional<Type> at(size_t index) const
{
return at(index).as<Type>();
}
iterator find(const std::string &column_name);
[[nodiscard]] const_iterator find(const std::string &column_name) const;
@@ -1,133 +0,0 @@
#ifndef QUERY_RESULT_PARAMETER_BINDER_HPP
#define QUERY_RESULT_PARAMETER_BINDER_HPP
#include "matador/utils/access.hpp"
#include "matador/utils/cascade_type.hpp"
#include "matador/utils/field_attributes.hpp"
#include "matador/sql/any_type.hpp"
#include "matador/sql/data_type_traits.hpp"
#include <string>
namespace matador::sql {
class result_parameter_binder;
namespace detail {
class fk_result_binder
{
public:
explicit fk_result_binder(result_parameter_binder &result_binder);
template<class Type>
void bind_result(Type &obj, size_t column_index)
{
column_index_ = column_index;
utils::access::process(*this, obj);
}
template<typename ValueType>
void on_primary_key(const char *id, ValueType &value, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type* = 0);
void on_primary_key(const char *id, std::string &value, 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) {}
template < class Pointer >
void on_belongs_to(const char * /*id*/, Pointer &/*x*/, utils::cascade_type) {}
template < class Pointer >
void on_has_one(const char * /*id*/, Pointer &/*x*/, utils::cascade_type) {}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, utils::cascade_type) {}
private:
size_t column_index_{};
result_parameter_binder &result_binder_;
};
}
class result_parameter_binder
{
public:
template<typename ValueType>
void on_primary_key(const char * /*id*/, ValueType &value, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type* = 0)
{
data_type_traits<ValueType>::bind_result_value(*this, column_index_++, value);
}
void on_primary_key(const char *id, std::string &value, 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)
{
data_type_traits<Type>::bind_result_value(*this, column_index_++, x);
}
void on_attribute(const char *id, char *value, const utils::field_attributes &attr = utils::null_attributes);
void on_attribute(const char *id, std::string &value, const utils::field_attributes &attr = utils::null_attributes);
void on_attribute(const char *id, any_type &value, data_type_t type, const utils::field_attributes &attr = utils::null_attributes);
template < class Pointer >
void on_belongs_to(const char * /*id*/, Pointer &x, utils::cascade_type)
{
if (!x.get()) {
x.reset(new typename Pointer::value_type);
}
fk_result_binder_.bind_result(*x, column_index_++);
}
template < class Pointer >
void on_has_one(const char * /*id*/, Pointer &x, utils::cascade_type)
{
if (!x.get()) {
x.reset(new typename Pointer::value_type);
}
fk_result_binder_.bind_result(*x, column_index_++);
}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, utils::cascade_type) {}
virtual void bind_result_value(size_t index, char &value) {}
virtual void bind_result_value(size_t index, short &value) {}
virtual void bind_result_value(size_t index, int &value) {}
virtual void bind_result_value(size_t index, long &value) {}
virtual void bind_result_value(size_t index, long long &value) {}
virtual void bind_result_value(size_t index, unsigned char &value) {}
virtual void bind_result_value(size_t index, unsigned short &value) {}
virtual void bind_result_value(size_t index, unsigned int &value) {}
virtual void bind_result_value(size_t index, unsigned long &value) {}
virtual void bind_result_value(size_t index, unsigned long long &value) {}
virtual void bind_result_value(size_t index, bool &value) {}
virtual void bind_result_value(size_t index, float &value) {}
virtual void bind_result_value(size_t index, double &value) {}
// virtual void bind_result_value(size_t index, matador::time &value) {}
// virtual void bind_result_value(size_t index, matador::date &value) {}
virtual void bind_result_value(size_t index, char *value, size_t s) {}
virtual void bind_result_value(size_t index, std::string &value) {}
virtual void bind_result_value(size_t index, std::string &value, size_t s) {}
virtual void bind_result_value(size_t index, any_type &value, data_type_t type, size_t size) {}
private:
size_t column_index_{};
detail::fk_result_binder fk_result_binder_;
};
namespace detail {
template<typename ValueType>
void fk_result_binder::on_primary_key(const char * /*id*/, ValueType &value, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type *)
{
data_type_traits<ValueType>::bind_result_value(result_binder_, column_index_++, value);
}
}
}
#endif //QUERY_RESULT_PARAMETER_BINDER_HPP
-89
View File
@@ -1,89 +0,0 @@
#ifndef QUERY_SCHEMA_HPP
#define QUERY_SCHEMA_HPP
#include "matador/sql/column_definition_generator.hpp"
#include "matador/sql/table_definition.hpp"
#include <optional>
#include <string>
#include <typeindex>
#include <unordered_map>
namespace matador::sql {
class connection;
struct table_info
{
std::string name;
table_definition prototype;
};
class schema
{
public:
using repository = std::unordered_map<std::type_index, table_info>;
using repository_by_name = std::unordered_map<std::string, std::reference_wrapper<table_info>>;
using iterator = repository::iterator;
using const_iterator = repository::const_iterator;
schema() = delete;
explicit schema(std::string name);
schema(const schema&) = delete;
schema& operator=(const schema&) = delete;
schema(schema&&) noexcept = default;
schema& operator=(schema&&) noexcept = default;
[[nodiscard]] std::string name() const;
void create(connection &c);
template<typename Type>
const table_info& attach(const std::string &table_name)
{
return attach(std::type_index(typeid(Type)), table_info{table_name, table_definition{column_definition_generator::generate<Type>(*this)}});
}
const table_info& attach(std::type_index ti, const table_info& table);
template<typename Type>
[[nodiscard]] std::optional<table_info> info() const
{
return info(std::type_index(typeid(Type)));
}
[[nodiscard]] std::optional<table_info> info(std::type_index ti) const;
[[nodiscard]] std::optional<table_info> info(const std::string &name) const;
template<typename Type>
[[nodiscard]] std::pair<std::string, std::string> reference() const
{
return reference(std::type_index(typeid(Type)));
}
[[nodiscard]] std::pair<std::string, std::string> reference(const std::type_index &ti) const;
template<typename Type>
[[nodiscard]] bool exists() const
{
return exists(std::type_index(typeid(Type)));
}
[[nodiscard]] bool exists(const std::type_index &ti) const;
iterator begin();
[[nodiscard]] const_iterator begin() const;
iterator end();
[[nodiscard]] const_iterator end() const;
[[nodiscard]] bool empty() const;
private:
std::string name_;
repository repository_;
repository_by_name repository_by_name_;
};
}
#endif //QUERY_SCHEMA_HPP
-170
View File
@@ -1,170 +0,0 @@
#ifndef QUERY_SESSION_HPP
#define QUERY_SESSION_HPP
#include "matador/sql/connection.hpp"
#include "matador/sql/connection_pool.hpp"
#include "matador/sql/entity.hpp"
#include "matador/sql/entity_query_builder.hpp"
#include "matador/sql/statement.hpp"
#include "matador/sql/schema.hpp"
#include <unordered_map>
namespace matador::sql {
class dialect;
enum class session_error {
Ok = 0,
NoConnectionAvailable,
UnknownType,
FailedToBuildQuery,
FailedToFindObject
};
class session
{
public:
explicit session(connection_pool<connection> &pool);
template<typename Type>
void attach(const std::string &table_name);
void create_schema();
template<typename Type>
entity<Type> insert(Type *obj);
template< class Type, typename... Args >
entity<Type> insert(Args&&... args) {
return insert(new Type(std::forward<Args>(args)...));
}
template<typename Type, typename PrimaryKeyType>
utils::result<entity<Type>, session_error> find(const PrimaryKeyType &pk) {
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>(pk);
if (!data.is_ok()) {
return utils::error(session_error::FailedToBuildQuery);
}
auto obj = build_select_query(c, data.release()).template fetch_one<Type>();
if (!obj) {
return utils::error(session_error::FailedToFindObject);
}
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>
void drop_table();
void drop_table(const std::string &table_name);
[[nodiscard]] query_result<record> fetch(const query_context &q) const;
// [[nodiscard]] query_result<record> fetch(const std::string &sql) const;
[[nodiscard]] size_t execute(const std::string &sql) const;
statement prepare(query_context q) const;
std::vector<sql::column_definition> describe_table(const std::string &table_name) const;
bool table_exists(const std::string &table_name) const;
const class dialect& dialect() const;
private:
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_;
std::unique_ptr<schema> schema_;
mutable std::unordered_map<std::string, table_definition> prototypes_;
};
template<typename Type>
void session::attach(const std::string &table_name)
{
schema_->attach<Type>(table_name);
}
template<typename Type>
entity<Type> session::insert(Type *obj)
{
auto c = pool_.acquire();
auto info = schema_->info<Type>();
if (!info) {
return {};
}
c->query(*schema_)
.insert()
.into(info->name, column_generator::generate<Type>(*schema_, true))
.values(*obj)
.execute();
return entity{obj};
}
template<typename Type>
void session::drop_table()
{
auto info = schema_->info<Type>();
if (info) {
return drop_table(info.name);
}
}
}
#endif //QUERY_SESSION_HPP
+150 -33
View File
@@ -1,57 +1,174 @@
#ifndef QUERY_STATEMENT_HPP
#define QUERY_STATEMENT_HPP
#include "matador/sql/object_parameter_binder.hpp"
#include "matador/sql/abstract_sql_logger.hpp"
#include "matador/sql/query_result.hpp"
#include "matador/sql/statement_impl.hpp"
#include "matador/utils/logger.hpp"
#include "matador/sql/interface/statement_impl.hpp"
#include "matador/utils/error.hpp"
#include "matador/utils/result.hpp"
#include <memory>
namespace matador::sql {
namespace detail {
template<class Type>
class identifier_binder;
}
class statement
{
class statement_impl;
class statement {
public:
explicit statement(std::unique_ptr<statement_impl> impl, const utils::logger &logger);
/**
* Creates a statement initialized from the
* given statement implementation object holding
* the implementation for the selected database
*
* @param impl The statement implementation object
* @param logger The logger handler to write sql log messages to
*/
explicit statement(std::unique_ptr<statement_impl> impl,
const std::shared_ptr<abstract_sql_logger> &logger = std::make_shared<null_sql_logger>());
/**
* Copy move constructor for statement
*
* @param x The statement to move from
*/
statement(statement &&x) noexcept
: statement_(std::move(x.statement_))
, logger_(std::move(x.logger_)) {
}
template < typename Type >
statement& bind(size_t pos, const Type &value)
{
statement_->bind(pos, value);
/**
* Assignment move constructor for statement
*
* @param x The statement to move from
* @return Reference to this
*/
statement &operator=(statement &&x) noexcept {
statement_ = std::move(x.statement_);
logger_ = std::move(x.logger_);
return *this;
}
statement& bind(size_t pos, const char *value);
statement& bind(size_t pos, std::string &val, size_t size);
template < class Type >
statement& bind(const Type &obj)
{
object_binder_.reset();
matador::utils::access::process(object_binder_, obj);
return *this;
}
size_t execute();
statement &bind(size_t pos, const char *value);
statement &bind(size_t pos, std::string &val, size_t size);
/**
* Bind an object to the statement starting
* at the given position index.
*
* @param obj The object to bind
* @return The next index to bind
*/
template<class Type>
query_result<Type> fetch()
{
logger_.info(statement_->query_.sql);
return query_result<Type>(statement_->fetch());
}
query_result<record> fetch();
statement &bind(const Type &obj);
template<typename Type>
statement &bind(size_t pos, Type &value);
void reset();
/**
* Executes the prepared statement and returns
* the number of affected rows.
*
* @return The number of affected rows
*/
[[nodiscard]] utils::result<size_t, utils::error> execute() const;
/**
* Fetches the result of the prepared
* statement. If prepared statement was not
* a SELECT statement an empty query result set
* is returned.
*
* @tparam Type Type of the fetched result
* @return The query result set
*/
template<class Type>
utils::result<query_result<Type>, utils::error> fetch();
/**
* Fetches the result of the prepared
* statement. The type is record representing an
* unknown variable type.
* If prepared statement was not
* a SELECT statement an empty query result set
* is returned.
*
* @return The query result set
*/
[[nodiscard]] utils::result<query_result<record>, utils::error> fetch() const;
/**
* Fetches the first result of a prepared statement.
* If prepared statement is empty or not
* a SELECT statement a nullptr is returned.
*
* @tparam Type Type of the fetched result
* @return The query result set
*/
template<class Type>
utils::result<std::unique_ptr<Type>, utils::error> fetch_one();
/**
* Fetches the first result of a prepared statement.
* The type is record representing an unknown variable type.
* If prepared statement is empty or not
* a SELECT statement a nullptr is returned.
*
* @return The query result set
*/
[[nodiscard]] utils::result<std::optional<record>, utils::error> fetch_one() const;
/**
* Resets the prepared statement to
* reuse it.
*/
void reset() const;
private:
template<class Type>
friend class detail::identifier_binder;
private:
std::unique_ptr<statement_impl> statement_;
const utils::logger &logger_;
object_parameter_binder object_binder_;
std::shared_ptr<abstract_sql_logger> logger_;
};
template<typename Type>
statement &statement::bind(size_t pos, Type &value) {
statement_->bind(pos, value);
return *this;
}
template<class Type>
statement &statement::bind(const Type &obj) {
statement_->bind_object(obj);
return *this;
}
template<class Type>
utils::result<query_result<Type>, utils::error> statement::fetch() {
return statement_->fetch().and_then([](std::unique_ptr<query_result_impl> &&value) {
return utils::ok(query_result<Type>(std::forward<decltype(value)>(value)));
});
// if (!result.is_ok()) {
// return utils::error(result.err());
// }
// return query_result<Type>(result.release());
}
template<class Type>
utils::result<std::unique_ptr<Type>, utils::error> statement::fetch_one() {
auto result = statement_->fetch();
if (!result.is_ok()) {
return utils::failure(result.err());
}
auto records = query_result<Type>(result.release());
auto first = records.begin();
if (first == records.end()) {
return utils::ok(std::unique_ptr<Type>{nullptr});
}
return utils::ok(std::unique_ptr<Type>{first.release()});
}
}
#endif //QUERY_STATEMENT_HPP
-37
View File
@@ -1,37 +0,0 @@
#ifndef QUERY_STATEMENT_CACHE_HPP
#define QUERY_STATEMENT_CACHE_HPP
#include "matador/sql/statement.hpp"
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
namespace matador::sql {
class connection;
struct cache_info
{
statement statement_;
// std::unique_ptr<statement> statement_;
size_t connection_id_;
};
class statement_cache
{
public:
statement& acquire(query_context &&context, const connection &conn);
void release(const statement &stmt);
private:
mutable std::mutex mutex_;
size_t max_cache_size_{256};
std::hash<std::string> hash_;
using statement_map = std::unordered_map<size_t, cache_info>;
statement_map statement_map_;
};
}
#endif //QUERY_STATEMENT_CACHE_HPP
-46
View File
@@ -1,46 +0,0 @@
#ifndef QUERY_STATEMENT_IMPL_HPP
#define QUERY_STATEMENT_IMPL_HPP
#include "matador/sql/query_context.hpp"
#include "matador/sql/query_result_impl.hpp"
#include "matador/sql/parameter_binder.hpp"
#include "matador/sql/data_type_traits.hpp"
#include <memory>
namespace matador::sql {
class statement_impl
{
protected:
explicit statement_impl(query_context query);
public:
virtual ~statement_impl() = default;
virtual size_t execute() = 0;
virtual std::unique_ptr<query_result_impl> fetch() = 0;
template < class Type >
void bind(size_t pos, Type &val)
{
data_type_traits<Type>::bind_value(binder(), pos, val);
}
void bind(size_t pos, const char *value, size_t size);
void bind(size_t pos, std::string &val, size_t size);
virtual void reset() = 0;
protected:
virtual parameter_binder& binder() = 0;
protected:
friend class statement;
query_context query_;
};
}
#endif //QUERY_STATEMENT_IMPL_HPP
+15 -13
View File
@@ -3,32 +3,32 @@
#include "matador/sql/column.hpp"
#include <typeindex>
#include <string>
#include <vector>
namespace matador::sql {
struct column;
struct table
{
table(const char *name, std::string as = "") // NOLINT(*-explicit-constructor)
: name(name), alias(std::move(as)) {}
table(std::string name, std::string as = "") // NOLINT(*-explicit-constructor)
: name(std::move(name))
, alias(std::move(as)) {}
table() = default;
table(const char *name); // NOLINT(*-explicit-constructor)
table(std::string name); // NOLINT(*-explicit-constructor)
table(const char *name, std::string as); // NOLINT(*-explicit-constructor)
table(std::string name, std::string as); // NOLINT(*-explicit-constructor)
table(std::string name, std::string as, const std::vector<column> &columns)
: name(std::move(name))
, alias(std::move(as))
, columns(columns) {}
table& as(const std::string &a) {
alias = a;
return *this;
}
table& as(const std::string &a);
[[nodiscard]] table as(const std::string &a) const {
return { name, a, columns };
}
[[nodiscard]] bool operator==(const table &x) const;
[[nodiscard]] table as(const std::string &a) const;
[[nodiscard]] bool has_alias() const;
std::string name;
std::string alias;
@@ -36,6 +36,8 @@ struct table
std::vector<column> columns;
};
table operator "" _tab(const char *name, size_t len);
}
#endif //QUERY_TABLE_HPP
-73
View File
@@ -1,73 +0,0 @@
#ifndef QUERY_TABLE_DEFINITION_HPP
#define QUERY_TABLE_DEFINITION_HPP
#include "matador/sql/column.hpp"
#include "matador/sql/column_definition.hpp"
#include <unordered_map>
namespace matador::sql {
class table_definition final
{
private:
using column_by_index = std::vector<column_definition>;
using column_index_pair = std::pair<std::reference_wrapper<column_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;
table_definition() = default;
table_definition(std::initializer_list<column_definition> columns);
explicit table_definition(const std::vector<column_definition> &columns);
table_definition(const table_definition &x);
table_definition& operator=(const table_definition &x);
table_definition(table_definition&&) noexcept = default;
table_definition& operator=(table_definition&&) noexcept = default;
~table_definition() = default;
[[nodiscard]] bool has_primary_key() const;
[[nodiscard]] std::optional<column_definition> primary_key() const;
template < typename Type >
void append(const std::string &name, long size = -1)
{
append(make_column<Type>(name, size));
}
void append(column_definition col);
[[nodiscard]] const std::vector<column_definition>& columns() const;
[[nodiscard]] const column_definition& at(const column &col) const;
[[nodiscard]] const column_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(column_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
-84
View File
@@ -1,84 +0,0 @@
#ifndef QUERY_TO_VALUE_HPP
#define QUERY_TO_VALUE_HPP
#include <cerrno>
#include <climits>
#include <cstring>
#include <cfloat>
#include <cstdlib>
#include <stdexcept>
#include <type_traits>
namespace matador::sql {
template < class Type >
void to_value(Type &value, const char *str, typename std::enable_if<std::is_integral<Type>::value && std::is_signed<Type>::value>::type* = nullptr)
{
if (strlen(str) == 0) {
return;
}
char *end;
errno = 0;
auto result = strtoll(str, &end, 10);
// Check for various possible errors
if ((errno == ERANGE && (result == LLONG_MAX || result == LLONG_MIN)) || (errno != 0 && result == 0)) {
throw std::logic_error(strerror(errno));
// Handle error
} else if (end == str) {
// No digits found
throw std::logic_error("failed to convert value to signed number: no digits were found");
}
value = static_cast<Type>(result);
}
template < class Type >
void to_value(Type &value, const char *str, typename std::enable_if<std::is_integral<Type>::value && std::is_unsigned<Type>::value>::type* = nullptr)
{
if (strlen(str) == 0) {
return;
}
char *end;
errno = 0;
auto result = strtoull(str, &end, 10);
// Check for various possible errors
if ((errno == ERANGE && (result == LLONG_MAX || result == LLONG_MIN)) || (errno != 0 && result == 0)) {
throw std::logic_error(strerror(errno));
// Handle error
} else if (end == str) {
// No digits found
throw std::logic_error("failed to convert value to unsigned number: no digits were found");
}
value = static_cast<Type>(result);
}
template < class Type >
void to_value(Type &value, const char *str, typename std::enable_if<std::is_floating_point<Type>::value>::type* = nullptr)
{
if (strlen(str) == 0) {
return;
}
char *end;
errno = 0;
auto result = strtold(str, &end);
// Check for various possible errors
if ((errno == ERANGE && (result == LDBL_MAX || result == LDBL_MIN)) || (errno != 0 && result == 0)) {
throw std::logic_error(strerror(errno));
// Handle error
} else if (end == str) {
// No digits found
throw std::logic_error("failed to convert value to floating point number: no digits were found");
}
value = static_cast<Type>(result);
}
}
#endif //QUERY_TO_VALUE_HPP

Some files were not shown because too many files have changed in this diff Show More