added sqlite query result and enhanced column generator and value extractor

This commit is contained in:
2023-11-14 20:21:51 +01:00
parent 4ed01a617d
commit d76ac60278
44 changed files with 1052 additions and 192 deletions
+2 -1
View File
@@ -12,7 +12,8 @@ using any_type = std::variant<
bool,
float, double,
const char*,
std::string>;
std::string,
nullptr_t>;
}
#endif //QUERY_ANY_TYPE_HPP
+20 -4
View File
@@ -1,6 +1,7 @@
#ifndef QUERY_COLUMN_HPP
#define QUERY_COLUMN_HPP
#include "matador/sql/any_type.hpp"
#include "matador/sql/types.hpp"
#include "matador/utils/field_attributes.hpp"
@@ -24,16 +25,25 @@ public:
: column(std::move(name), data_type_traits<Type>::builtin_type(attr.size()), attr)
{}
column(std::string name, data_type_t type, utils::field_attributes attr = utils::null_attributes);
template<typename Type>
column(std::string name, std::string ref_table, std::string ref_column, utils::field_attributes attr = utils::null_attributes)
: column(std::move(name), data_type_traits<Type>::builtin_type(attr.size()), ref_table, ref_column, attr)
{}
column(std::string name, data_type_t type, std::string ref_table, std::string ref_column, utils::field_attributes attr = utils::null_attributes);
[[nodiscard]] const std::string& name() const;
[[nodiscard]] const utils::field_attributes& attributes() const;
[[nodiscard]] data_type_t type() const;
[[nodiscard]] const std::string& ref_table() const;
[[nodiscard]] const std::string& ref_column() const;
private:
std::string name_;
utils::field_attributes attributes_;
data_type_t type_{};
std::any value_;
any_type value_;
std::string ref_table_;
std::string ref_column_;
};
/**
@@ -64,13 +74,19 @@ template <>
column make_pk_column<std::string>(const std::string &name, size_t size);
template < typename Type >
column make_fk_column(const std::string &name, size_t size = 0)
column make_fk_column(const std::string &name, size_t size, const std::string &ref_table, const std::string &ref_column)
{
return make_column<Type>(name, { size, utils::constraints::FOREIGN_KEY });
return {name, data_type_traits<Type>::builtin_type(size), ref_table, ref_column, { size, utils::constraints::FOREIGN_KEY }};
}
template < typename Type >
[[maybe_unused]] column 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), ref_table, ref_column, { 0, utils::constraints::FOREIGN_KEY }};
}
template <>
column make_fk_column<std::string>(const std::string &name, size_t size);
column make_fk_column<std::string>(const std::string &name, size_t size, const std::string &ref_table, const std::string &ref_column);
}
#endif //QUERY_COLUMN_HPP
+5 -23
View File
@@ -6,39 +6,23 @@
#include "matador/utils/access.hpp"
#include "matador/utils/field_attributes.hpp"
#include "matador/utils/identifiable.hpp"
#include "matador/utils/identifier.hpp"
#include <vector>
namespace matador::utils {
enum class cascade_type;
class identifiable;
}
namespace matador::sql {
namespace detail {
class null_identifiable : public utils::identifiable
{
public:
void reset(const utils::identifier &) override {};
[[nodiscard]] bool has_primary_key() const override { return false; }
[[nodiscard]] const utils::identifier& primary_key() const override { return id_; }
utils::identifier& primary_key() override { return id_; }
[[nodiscard]] utils::identifier create_identifier() const override { return utils::identifier(id_); }
private:
utils::identifier id_;
};
static null_identifiable null_id;
}
class fk_column_generator : public utils::identifier_serializer
{
public:
fk_column_generator() = default;
column generate(const char *id, utils::identifiable &x);
void serialize(short &i, const utils::field_attributes &attributes) override;
void serialize(int &i, const utils::field_attributes &attributes) override;
void serialize(long &i, const utils::field_attributes &attributes) override;
@@ -51,9 +35,7 @@ public:
void serialize(utils::null_type_t &type, const utils::field_attributes &attributes) override;
private:
utils::identifiable &identifiable_{detail::null_id};
const char *id_{};
column column_;
data_type_t type_{};
};
class column_generator
@@ -47,8 +47,10 @@ public:
void on_belongs_to(const char *id, utils::identifiable &, utils::cascade_type);
void on_has_one(const char *id, utils::identifiable &, utils::cascade_type);
// void on_has_many(const char *, abstract_container &, const char *, const char *, cascade_type) {}
// void on_has_many(const char *, abstract_container &, 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:
std::vector<std::string> &column_names_;
+12 -2
View File
@@ -2,6 +2,7 @@
#define QUERY_CONNECTION_HPP
#include "matador/sql/connection_info.hpp"
#include "matador/sql/connection_impl.hpp"
#include "matador/sql/dialect.hpp"
#include "matador/sql/query_result.hpp"
#include "matador/sql/record.hpp"
@@ -17,6 +18,10 @@ class connection
public:
explicit connection(connection_info info);
explicit connection(const std::string& dns);
connection(const connection &x);
connection& operator=(const connection &x);
connection(connection &&x) noexcept = default;
connection& operator=(connection &&x) noexcept = default;
~connection();
void open();
@@ -24,13 +29,18 @@ public:
[[nodiscard]] bool is_open() const;
[[nodiscard]] const connection_info& info() const;
template<class Type>
query_result<Type> fetch(const std::string &sql)
{
return query_result<Type>(connection_->execute(sql));
}
query_result<record> fetch(const std::string &sql);
std::pair<size_t, std::string> execute(const std::string &sql);
private:
const connection_info connection_info_;
connection_info connection_info_;
bool is_open_{false};
connection_impl *connection_{};
std::unique_ptr<connection_impl> connection_;
};
}
+7 -1
View File
@@ -2,9 +2,14 @@
#define QUERY_CONNECTION_IMPL_HPP
#include "matador/sql/connection_info.hpp"
#include "matador/sql/query_result_impl.hpp"
#include <memory>
namespace matador::sql {
class query_result_impl;
class connection_impl
{
public:
@@ -14,7 +19,8 @@ public:
virtual void close() = 0;
virtual bool is_open() = 0;
virtual void execute(const std::string &stmt) = 0;
virtual size_t execute(const std::string &stmt) = 0;
virtual std::unique_ptr<query_result_impl> fetch(const std::string &stmt) = 0;
virtual void prepare(const std::string &stmt) = 0;
protected:
@@ -0,0 +1,49 @@
#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"
namespace matador::sql::detail {
class fk_value_extractor
{
public:
fk_value_extractor() = default;
template<class Type>
any_type extract(Type &x)
{
matador::utils::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)
{
value_ = pk;
}
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*/, 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:
any_type value_{};
};
}
#endif //QUERY_FK_VALUE_EXTRACTOR_HPP
+54
View File
@@ -0,0 +1,54 @@
#ifndef QUERY_FOREIGN_HPP
#define QUERY_FOREIGN_HPP
#include "matador/utils/identifiable.hpp"
namespace matador::sql {
template < class Type >
class foreign : public utils::identifiable
{
public:
foreign() = default;
explicit foreign(Type *obj)
: obj_(obj) {}
void reset(const utils::identifier &id) override {
id_ = id;
}
[[nodiscard]] bool has_primary_key() const override {
return true;
}
[[nodiscard]] const utils::identifier &primary_key() const override {
return id_;
}
utils::identifier &primary_key() override {
return id_;
}
[[nodiscard]] utils::identifier create_identifier() const override {
return {id_};
}
Type* operator->() { return obj_.get(); }
const Type* operator->() const { return obj_.get(); }
Type& operator*() { return *obj_; }
const Type& operator*() const { return *obj_; }
private:
utils::identifier id_;
std::unique_ptr<Type> obj_;
};
template<class Type, typename... Args>
[[maybe_unused]] foreign<Type> make_foreign(Args&&... args)
{
return foreign(new Type(std::forward<Args>(args)...));
}
}
#endif //QUERY_FOREIGN_HPP
@@ -0,0 +1,67 @@
#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 <vector>
namespace matador::utils {
class identifiable;
}
namespace matador::sql {
class key_value_generator
{
private:
public:
explicit key_value_generator(std::vector<key_value_pair> &result) : result_(result) {}
public:
template < class Type >
static std::vector<key_value_pair> generate(const Type &obj)
{
std::vector<key_value_pair> result;
key_value_generator generator(result);
matador::utils::access::process(generator, obj);
return std::move(result);
}
template < class V >
void on_primary_key(const char *id, V &x, typename std::enable_if<std::is_integral<V>::value && !std::is_same<bool, V>::value>::type* = 0)
{
result_.emplace_back(id, x);
}
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 &x, const utils::field_attributes &/*attr*/ = utils::null_attributes)
{
result_.emplace_back(id, x);
}
template<class Type, template < class ... > class Pointer>
void on_belongs_to(const char *id, Pointer<Type> &x, utils::cascade_type)
{
result_.emplace_back(id, fk_value_extractor_.extract(*x));
}
template<class Type, template < class ... > class Pointer>
void on_has_one(const char *id, Pointer<Type> &x, utils::cascade_type)
{
result_.emplace_back(id, fk_value_extractor_.extract(*x));
}
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:
detail::fk_value_extractor fk_value_extractor_;
std::vector<key_value_pair> &result_;
};
}
#endif //QUERY_KEY_VALUE_GENERATOR_HPP
+3
View File
@@ -103,11 +103,14 @@ public:
query_builder& table(const std::string &table, const std::vector<column> &columns);
query_builder& table(const std::string &table);
query_builder& into(const std::string &table, std::initializer_list<std::string> column_names);
query_builder& into(const std::string &table, const std::vector<std::string> &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);
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);
+21 -3
View File
@@ -4,9 +4,12 @@
#include "matador/sql/column.hpp"
#include "matador/sql/column_generator.hpp"
#include "matador/sql/column_name_generator.hpp"
#include "matador/sql/key_value_generator.hpp"
#include "matador/sql/key_value_pair.hpp"
#include "matador/sql/query_builder.hpp"
#include "matador/sql/query_result.hpp"
#include "matador/sql/record.hpp"
#include "matador/sql/value_extractor.hpp"
#include <string>
@@ -14,7 +17,6 @@ namespace matador::sql {
class basic_condition;
class session;
class query_builder;
class query_intermediate
{
@@ -130,6 +132,11 @@ public:
using query_intermediate::query_intermediate;
query_execute_finish values(std::initializer_list<any_type> values);
template<class Type>
query_execute_finish values(const Type &obj)
{
return {db(), query().values(value_extractor::extract(obj))};
}
};
class query_create_intermediate : query_intermediate
@@ -162,7 +169,13 @@ public:
template<class Type>
query_into_intermediate into(const std::string &table)
{
return into(table, column_name_generator::generate<Type>());
return {db(), query().into(table, column_name_generator::generate<Type>())};
}
template<class Type>
query_execute_finish into(const std::string &table, const Type &obj)
{
return {db(), query().into(table, column_name_generator::generate<Type>())
.values(value_extractor::extract(obj))};
}
};
@@ -188,6 +201,11 @@ public:
using query_intermediate::query_intermediate;
query_set_intermediate set(std::initializer_list<key_value_pair> columns);
template<class Type>
query_set_intermediate set(const Type &obj)
{
return {db(), query().set(key_value_generator::generate(obj))};
}
};
class query_delete_from_intermediate : public query_execute_finish
@@ -203,7 +221,7 @@ class query_delete_intermediate : public query_intermediate
public:
using query_intermediate::query_intermediate;
query_delete_from_intermediate from(const std::string &table, const std::string &as = "");
query_delete_from_intermediate from(const std::string &table);
};
}
+58 -14
View File
@@ -1,6 +1,8 @@
#ifndef QUERY_QUERY_RESULT_HPP
#define QUERY_QUERY_RESULT_HPP
#include "matador/sql/query_result_impl.hpp"
#include <memory>
namespace matador::sql {
@@ -15,13 +17,17 @@ 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 pointer = value_type*; /**< Shortcut for the pointer type. */
using reference = value_type&; /**< Shortcut for the reference type */
public:
query_result_iterator() = default;
explicit query_result_iterator(query_result<Type> &res, Type *obj = nullptr)
: obj_(obj)
explicit query_result_iterator(query_result<Type> &res)
: result_(res)
{}
query_result_iterator(query_result<Type> &res, std::unique_ptr<Type> obj)
: obj_(std::move(obj))
, result_(res)
{}
query_result_iterator(query_result_iterator&& x) noexcept
@@ -48,19 +54,38 @@ public:
return obj_ != rhs.obj_;
}
self& operator++()
{
obj_.reset(result_.create());
result_.bind(*obj_);
if (!result_.fetch(*obj_)) {
obj_.reset();
}
return *this;
}
self operator++(int)
{
const self tmp(result_, obj_);
obj_.reset(result_.create());
result_.bind(*obj_);
if (!result_.fetch(*obj_)) {
obj_.reset();
}
return std::move(tmp);
}
pointer operator->()
{
return obj_.get();
}
reference operator&()
reference operator*()
{
return &obj_.get();
}
std::unique_ptr<Type> operator*()
{
return std::move(obj_);
return *obj_;
}
pointer get()
@@ -73,7 +98,7 @@ public:
return obj_.release();
}
protected:
private:
std::unique_ptr<Type> obj_;
query_result<Type> &result_;
};
@@ -82,13 +107,32 @@ template < typename Type >
class query_result
{
public:
query_result(std::string sql) : sql_(std::move(sql)) {}
using iterator = query_result_iterator<Type>;
[[nodiscard]] const std::string& str() const { return sql_; }
public:
explicit query_result(std::unique_ptr<query_result_impl> impl)
: impl_(std::move(impl)) {}
iterator begin() { return std::move(++iterator(*this)); }
iterator end() { return {}; }
Type begin() { return {}; }
private:
std::string sql_;
friend class query_result_iterator<Type>;
Type* create() { return new Type; }
void bind(const Type &obj)
{
impl_->bind(obj);
}
bool fetch(Type &obj)
{
return impl_->fetch(obj);
}
private:
std::unique_ptr<query_result_impl> impl_;
};
}
+29 -4
View File
@@ -1,15 +1,22 @@
#ifndef QUERY_QUERY_RESULT_IMPL_HPP
#define QUERY_QUERY_RESULT_IMPL_HPP
#include "matador/utils/access.hpp"
#include "matador/utils/field_attributes.hpp"
#include <string>
namespace matador::utils {
class identifiable;
}
namespace matador::sql {
class query_result_impl
{
public:
virtual ~query_result_impl() = default;
virtual void read_value(const char *id, size_t index, char &value) = 0;
virtual void read_value(const char *id, size_t index, short &value) = 0;
virtual void read_value(const char *id, size_t index, int &value) = 0;
@@ -45,11 +52,29 @@ public:
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_belongs_to(const char *id, matador::identifiable_holder &x, cascade_type);
// void on_has_one(const char *id, matador::identifiable_holder &x, cascade_type);
void on_belongs_to(const char *id, utils::identifiable &x, utils::cascade_type);
void on_has_one(const char *id, utils::identifiable &x, utils::cascade_type);
// void on_has_many(const char *, abstract_container &, const char *, const char *, cascade_type) {}
// void on_has_many(const char *, abstract_container &, 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) {}
template<class Type>
void bind(const Type &) {}
template<class Type>
bool fetch(Type &obj)
{
if (!next_row()) {
return false;
}
matador::utils::access::process(*this, obj);
return true;
}
protected:
[[nodiscard]] virtual bool next_row() = 0;
protected:
size_t column_index_ = 0;
+11
View File
@@ -1,6 +1,8 @@
#ifndef QUERY_RECORD_HPP
#define QUERY_RECORD_HPP
#include "matador/utils/access.hpp"
#include "matador/sql/column.hpp"
#include <vector>
@@ -23,6 +25,15 @@ public:
record(std::initializer_list<column> columns);
~record() = default;
template<class Operator>
void process(Operator &op)
{
for(auto &col : columns_) {
// Todo: Find a solution to handle a column with process
int todo{};
matador::utils::access::attribute(op, col.name().c_str(), todo, col.attributes());
}
}
template < typename Type >
void append(const std::string &name, long size = -1)
{
@@ -1,34 +1,26 @@
#ifndef QUERY_VALUE_GENERATOR_HPP
#define QUERY_VALUE_GENERATOR_HPP
#ifndef QUERY_VALUE_EXTRACTOR_HPP
#define QUERY_VALUE_EXTRACTOR_HPP
#include "matador/sql/any_type.hpp"
#include "matador/utils/access.hpp"
#include "matador/utils/field_attributes.hpp"
#include "matador/utils/identifiable.hpp"
#include "matador/sql/fk_value_extractor.hpp"
#include <vector>
namespace matador::utils {
enum class cascade_type;
}
namespace matador::sql {
class value_generator
class value_extractor
{
private:
explicit value_generator(std::vector<any_type> &values);
explicit value_extractor(std::vector<any_type> &values);
public:
~value_generator() = default;
~value_extractor() = default;
template < class Type >
static std::vector<any_type> generate()
static std::vector<any_type> extract(const Type &type)
{
std::vector<any_type> values;
value_generator gen(values);
Type obj;
matador::utils::access::process(gen, obj);
value_extractor gen(values);
matador::utils::access::process(gen, type);
return std::move(values);
}
@@ -46,9 +38,17 @@ public:
}
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);
void on_belongs_to(const char *id, utils::identifiable &x, utils::cascade_type);
void on_has_one(const char *id, utils::identifiable &x, utils::cascade_type);
template<class Type, template < class ... > class Pointer>
void on_belongs_to(const char * /*id*/, Pointer<Type> &x, utils::cascade_type)
{
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, utils::cascade_type)
{
values_.emplace_back(fk_value_extractor_.extract(*x));
}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {}
template<class ContainerType>
@@ -62,9 +62,10 @@ private:
}
private:
detail::fk_value_extractor fk_value_extractor_;
std::vector<any_type> &values_;
};
}
#endif //QUERY_VALUE_GENERATOR_HPP
#endif //QUERY_VALUE_EXTRACTOR_HPP