added date_type_t, time_type_t and timestamp, ensure allocated postgres resources are released, split repository into basic_repository and repository.
This commit is contained in:
@@ -67,7 +67,7 @@ private:
|
||||
friend class object_generator;
|
||||
|
||||
std::string name_;
|
||||
std::shared_ptr<object> owner_;
|
||||
std::weak_ptr<object> owner_;
|
||||
utils::basic_type type_{utils::basic_type::Null};
|
||||
utils::field_attributes options_{};
|
||||
null_option_type null_option_{null_option_type::NotNull};
|
||||
|
||||
@@ -58,11 +58,11 @@ public:
|
||||
[[nodiscard]] bool endpoints_empty() const;
|
||||
|
||||
protected:
|
||||
basic_object_info(std::shared_ptr<repository_node> node, std::shared_ptr<class object> &&obj);
|
||||
basic_object_info(const repository_node& node, const std::shared_ptr<class object> &obj);
|
||||
|
||||
protected:
|
||||
std::shared_ptr<class object> object_;
|
||||
std::shared_ptr<repository_node> node_; /**< prototype node of the represented object type */
|
||||
const repository_node& node_; /**< prototype node of the represented object type */
|
||||
t_endpoint_map relation_endpoints_;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
#ifndef MATADOR_BASIC_REPOSITORY_HPP
|
||||
#define MATADOR_BASIC_REPOSITORY_HPP
|
||||
|
||||
#include "matador/object/error_code.hpp"
|
||||
#include "matador/object/object_info.hpp"
|
||||
#include "matador/object/repository_node_iterator.hpp"
|
||||
|
||||
#include "matador/logger/logger.hpp"
|
||||
|
||||
#include "matador/utils/error.hpp"
|
||||
#include "matador/utils/result.hpp"
|
||||
|
||||
#include <typeindex>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace matador::object {
|
||||
utils::error make_error(error_code ec, const std::string &msg);
|
||||
|
||||
class repository_node;
|
||||
class const_repository_node_iterator;
|
||||
|
||||
class basic_repository {
|
||||
public:
|
||||
typedef const_repository_node_iterator const_iterator; /**< Shortcut for the list const iterator. */
|
||||
|
||||
explicit basic_repository(std::string name = "");
|
||||
~basic_repository();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param node Node to attach
|
||||
* @param parent Name of parent node
|
||||
* @return Attached node
|
||||
*/
|
||||
[[nodiscard]] utils::result<repository_node*, utils::error> attach_node(repository_node *node, const std::string &parent);
|
||||
|
||||
/**
|
||||
* Detaches a given node from the schema. If the
|
||||
* node is a parent of other nodes, these nodes are
|
||||
* detached as well.
|
||||
*
|
||||
* @param node Node to detach from schema
|
||||
* @return Result object indicating success or failure
|
||||
*/
|
||||
[[nodiscard]] utils::result<void, utils::error> detach(repository_node *node);
|
||||
|
||||
/**
|
||||
* Return the first schema node.
|
||||
*
|
||||
* @return The first schema node iterator.
|
||||
*/
|
||||
[[nodiscard]] const_iterator begin() const;
|
||||
|
||||
/**
|
||||
* Return the last schema node.
|
||||
*
|
||||
* @return The last schema node iterator.
|
||||
*/
|
||||
[[nodiscard]] const_iterator end() const;
|
||||
|
||||
/**
|
||||
* Returns true if the schema contains
|
||||
* no schema nodes.
|
||||
*
|
||||
* @return True if the schema is empty
|
||||
*/
|
||||
[[nodiscard]] bool empty() const;
|
||||
|
||||
/**
|
||||
* Returns the current number of the schema node.
|
||||
*
|
||||
* @return Number of schema nodes
|
||||
*/
|
||||
[[nodiscard]] size_t size() const;
|
||||
|
||||
/**
|
||||
* Returns the name of the schema.
|
||||
*
|
||||
* @return The name of the schema
|
||||
*/
|
||||
[[nodiscard]] std::string name() const;
|
||||
|
||||
[[nodiscard]] bool contains(const std::string &name) const;
|
||||
[[nodiscard]] bool contains(const std::type_index &index) const;
|
||||
template < typename Type >
|
||||
[[nodiscard]] bool contains() const {
|
||||
return contains(std::type_index(typeid(Type)));
|
||||
}
|
||||
|
||||
|
||||
[[nodiscard]] utils::result<basic_object_info_ref, utils::error> basic_info(const std::type_index& ti) const;
|
||||
[[nodiscard]] utils::result<basic_object_info_ref, utils::error> basic_info(const std::string &name) const;
|
||||
template<typename Type>
|
||||
[[nodiscard]] utils::result<basic_object_info_ref, utils::error> basic_info() const {
|
||||
return basic_info(std::type_index(typeid(Type)));
|
||||
}
|
||||
|
||||
[[nodiscard]] utils::result<attribute*, utils::error> primary_key_attribute(const std::type_index &ti) const;
|
||||
|
||||
void dump(std::ostream &os) const;
|
||||
static void dump(std::ostream &os, const repository_node& node);
|
||||
|
||||
protected:
|
||||
using t_node_map = std::unordered_map<std::string, repository_node*>;
|
||||
using t_type_index_node_map = std::unordered_map<std::type_index, repository_node*>;
|
||||
|
||||
protected:
|
||||
[[nodiscard]] const_iterator find_node(const std::string &name) const;
|
||||
[[nodiscard]] const_iterator find_node(const std::type_index &type_index) const;
|
||||
template<typename Type>
|
||||
[[nodiscard]] const_iterator find_node() const {
|
||||
return find_node(std::type_index(typeid(Type)));
|
||||
}
|
||||
|
||||
[[nodiscard]] bool has_node(const std::string &name) const;
|
||||
[[nodiscard]] bool has_node(const std::type_index &index) const;
|
||||
[[nodiscard]] bool has_node(const repository_node* node) const;
|
||||
|
||||
static void insert_node(repository_node *parent, repository_node *child);
|
||||
void remove_node(repository_node *node);
|
||||
|
||||
[[nodiscard]] bool expecting_relation_node(const std::string &name) const;
|
||||
void expect_relation_node(const std::string &name, const std::type_index &ti);
|
||||
void remove_expected_relation_node(const std::string &name);
|
||||
|
||||
[[nodiscard]] std::shared_ptr<object> provide_object_in_advance(const std::type_index &ti, const std::shared_ptr<object>& obj);
|
||||
[[nodiscard]] bool has_object_for_type(const std::type_index &ti) const;
|
||||
[[nodiscard]] std::shared_ptr<object> object_for_type(const std::type_index &ti) const;
|
||||
void remove_object_for_type(const std::type_index &ti);
|
||||
|
||||
[[nodiscard]] bool is_node_announced(const std::type_index &ti) const;
|
||||
void push_announce_node(const std::type_index &ti, std::unique_ptr<repository_node> &&node);
|
||||
[[nodiscard]] repository_node* announce_node(const std::type_index &ti) const;
|
||||
[[nodiscard]] std::unique_ptr<repository_node> pop_announce_node(const std::type_index &ti);
|
||||
|
||||
protected:
|
||||
friend class object_generator;
|
||||
template < typename NodeType, template<typename> typename ...Observers >
|
||||
friend class foreign_node_completer;
|
||||
template < typename NodeType, template<typename> typename ...Observers >
|
||||
friend class relation_completer;
|
||||
|
||||
std::string name_;
|
||||
repository_node* root_{nullptr};
|
||||
|
||||
t_node_map nodes_by_name_;
|
||||
t_type_index_node_map nodes_by_type_;
|
||||
logger::logger log_;
|
||||
|
||||
std::unordered_map<std::type_index, std::unique_ptr<repository_node>> announced_node_;
|
||||
std::unordered_map<std::type_index, attribute*> missing_references_{};
|
||||
std::unordered_map<std::string, std::type_index> expected_relation_nodes_;
|
||||
std::unordered_map<std::type_index, std::shared_ptr<object>> object_by_type_{};
|
||||
};
|
||||
}
|
||||
#endif //MATADOR_BASIC_REPOSITORY_HPP
|
||||
@@ -1,9 +1,8 @@
|
||||
#ifndef FOREIGN_NODE_COMPLETER_HPP
|
||||
#define FOREIGN_NODE_COMPLETER_HPP
|
||||
|
||||
#include "matador/object/internal/shadow_repository.hpp"
|
||||
#include "matador/object/basic_repository.hpp"
|
||||
#include "matador/object/internal/observer_list_copy_creator.hpp"
|
||||
#include "matador/object/many_to_many_relation.hpp"
|
||||
#include "matador/object/repository_node.hpp"
|
||||
#include "matador/object/join_columns_collector.hpp"
|
||||
#include "matador/object/object_ptr.hpp"
|
||||
@@ -32,13 +31,9 @@ public:
|
||||
*/
|
||||
template<typename NodeType, template<typename> typename ...Observers>
|
||||
class foreign_node_completer final {
|
||||
private:
|
||||
using node_ptr = std::shared_ptr<repository_node>;
|
||||
|
||||
public:
|
||||
static void complete(const std::shared_ptr<repository_node> &node, const std::vector<std::unique_ptr<observer<NodeType>>> &observers) {
|
||||
internal::shadow_repository shadow(node->repo_);
|
||||
foreign_node_completer completer(shadow, observers);
|
||||
static void complete(repository_node *node, const std::vector<std::unique_ptr<observer<NodeType>>> &observers) {
|
||||
foreign_node_completer completer(node->repo_, observers);
|
||||
|
||||
completer.complete_node(node);
|
||||
}
|
||||
@@ -78,12 +73,12 @@ public:
|
||||
static void on_has_many_to_many(const char * /*id*/, CollectionType &/*collection*/, const utils::foreign_attributes &/*attr*/) {}
|
||||
|
||||
private:
|
||||
explicit foreign_node_completer(internal::shadow_repository &shadow, const std::vector<std::unique_ptr<observer<NodeType>>> &observers)
|
||||
: repo_(shadow)
|
||||
explicit foreign_node_completer(basic_repository &repo, const std::vector<std::unique_ptr<observer<NodeType>>> &observers)
|
||||
: repo_(repo)
|
||||
, log_(logger::create_logger("node_completer"))
|
||||
, observers_(observers) {}
|
||||
|
||||
void complete_node(const std::shared_ptr<repository_node> &node) {
|
||||
void complete_node(repository_node *node) {
|
||||
nodes_.push(node);
|
||||
|
||||
NodeType obj;
|
||||
@@ -102,8 +97,8 @@ private:
|
||||
if (repo_.is_node_announced(typeid(Type))) {
|
||||
return;
|
||||
}
|
||||
const auto node = repository_node::make_node<Type>(repo_.repo(), "", []{ return std::make_unique<Type>(); }, std::move(observers));
|
||||
repo_.push_announce_node(typeid(Type), node);
|
||||
auto node = repository_node::make_node<Type>(repo_, "", []{ return std::make_unique<Type>(); }, std::move(observers));
|
||||
repo_.push_announce_node(typeid(Type), std::move(node));
|
||||
// if (auto result = repo_.attach_node(node)) {
|
||||
// foreign_node_completer<Type>::complete(result.value(), {});
|
||||
// }
|
||||
@@ -121,8 +116,8 @@ private:
|
||||
friend class foreign_node_completer;
|
||||
|
||||
private:
|
||||
std::stack<node_ptr> nodes_;
|
||||
internal::shadow_repository &repo_;
|
||||
std::stack<repository_node*> nodes_;
|
||||
basic_repository &repo_;
|
||||
logger::logger log_;
|
||||
join_columns_collector join_columns_collector_{};
|
||||
const std::vector<std::unique_ptr<observer<NodeType>>>& observers_;
|
||||
@@ -153,8 +148,8 @@ void foreign_node_completer<NodeType, Observers...>::on_has_many(const char * /*
|
||||
template<typename NodeType, template<typename> typename ...Observers>
|
||||
void foreign_node_completer<NodeType, Observers...>::register_relation_endpoints(const endpoint_ptr &endpoint,
|
||||
const endpoint_ptr &other_endpoint) {
|
||||
endpoint->node_->info_->register_relation_endpoint(other_endpoint->node_->type_index(), endpoint);
|
||||
other_endpoint->node_->info_->register_relation_endpoint(endpoint->node_->type_index(), other_endpoint);
|
||||
endpoint->node().info_->register_relation_endpoint(other_endpoint->node().type_index(), endpoint);
|
||||
other_endpoint->node().info_->register_relation_endpoint(endpoint->node().type_index(), other_endpoint);
|
||||
link_relation_endpoints(endpoint, other_endpoint);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
#ifndef SHADOW_SCHEMA_HPP
|
||||
#define SHADOW_SCHEMA_HPP
|
||||
|
||||
#include "matador/object/basic_object_info.hpp"
|
||||
|
||||
#include "matador/utils/result.hpp"
|
||||
#include "matador/utils/error.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <typeindex>
|
||||
|
||||
namespace matador::object {
|
||||
class repository;
|
||||
class repository_node;
|
||||
class object;
|
||||
}
|
||||
|
||||
namespace matador::object::internal {
|
||||
class shadow_repository {
|
||||
private:
|
||||
using node_ptr = std::shared_ptr<repository_node>;
|
||||
|
||||
public:
|
||||
explicit shadow_repository(repository& s);
|
||||
|
||||
[[nodiscard]] repository& repo() const;
|
||||
[[nodiscard]] bool contains(const std::type_index& ti) const;
|
||||
[[nodiscard]] utils::result<basic_object_info_ref, utils::error> basic_info(const std::type_index& ti) const;
|
||||
[[nodiscard]] utils::result<node_ptr, utils::error> find_node(const std::type_index &type_index) const;
|
||||
[[nodiscard]] utils::result<node_ptr, utils::error> find_node(const std::string &name) const;
|
||||
[[nodiscard]] utils::result<node_ptr, utils::error> attach_node(const std::shared_ptr<repository_node> &node) const;
|
||||
[[nodiscard]] utils::result<void, utils::error> detach_node(const std::shared_ptr<repository_node> &node) const;
|
||||
|
||||
[[nodiscard]] bool expecting_relation_node(const std::string &name) const;
|
||||
void expect_relation_node(const std::string &name, const std::type_index &ti) const;
|
||||
void remove_expected_relation_node(const std::string &name) const;
|
||||
|
||||
[[nodiscard]] std::shared_ptr<object> provide_object_in_advance(const std::type_index &ti, const std::shared_ptr<object>& obj) const;
|
||||
[[nodiscard]] bool has_object_for_type(const std::type_index &ti) const;
|
||||
[[nodiscard]] std::shared_ptr<object> object_for_type(const std::type_index &ti) const;
|
||||
void remove_object_for_type(const std::type_index &ti) const;
|
||||
|
||||
[[nodiscard]] bool is_node_announced(const std::type_index &ti) const;
|
||||
void push_announce_node(const std::type_index &ti, const node_ptr &node) const;
|
||||
[[nodiscard]] node_ptr announce_node(const std::type_index &ti) const;
|
||||
[[nodiscard]] node_ptr pop_announce_node(const std::type_index &ti) const;
|
||||
|
||||
private:
|
||||
repository& repo_;
|
||||
};
|
||||
}
|
||||
#endif //SHADOW_SCHEMA_HPP
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace matador::object {
|
||||
|
||||
class repository;
|
||||
|
||||
class object {
|
||||
public:
|
||||
explicit object(std::string name);
|
||||
@@ -23,7 +21,6 @@ public:
|
||||
[[nodiscard]] const utils::identifier& primary_key() const;
|
||||
[[nodiscard]] bool has_primary_key() const;
|
||||
|
||||
[[nodiscard]] bool empty() const;
|
||||
[[nodiscard]] const std::string& name() const;
|
||||
|
||||
void update_name(const std::string& name);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef MATADOR_OBJECT_GENERATOR_HPP
|
||||
#define MATADOR_OBJECT_GENERATOR_HPP
|
||||
|
||||
#include "matador/object/internal/shadow_repository.hpp"
|
||||
#include "matador/object/basic_repository.hpp"
|
||||
#include "matador/object/object.hpp"
|
||||
|
||||
#include "matador/utils/access.hpp"
|
||||
@@ -10,8 +10,6 @@
|
||||
#include <memory>
|
||||
|
||||
namespace matador::object {
|
||||
class repository;
|
||||
|
||||
class pk_type_determinator {
|
||||
private:
|
||||
pk_type_determinator() = default;
|
||||
@@ -51,26 +49,26 @@ private:
|
||||
|
||||
class object_generator {
|
||||
private:
|
||||
explicit object_generator(const repository& repo, const std::shared_ptr<object> &object);
|
||||
explicit object_generator(basic_repository& repo, const std::shared_ptr<object> &object);
|
||||
|
||||
public:
|
||||
template < class Type >
|
||||
static std::shared_ptr<object> generate(const repository &repo, const std::string &name) {
|
||||
static std::shared_ptr<object> generate(basic_repository &repo, const std::string &name) {
|
||||
return generate(std::make_unique<Type>(), repo, name);
|
||||
}
|
||||
|
||||
template < class Type >
|
||||
static std::shared_ptr<object> generate(std::unique_ptr<Type>&& t, const repository &repo, const std::string &name) {
|
||||
const internal::shadow_repository shadow_repo(const_cast<repository&>(repo));
|
||||
static std::shared_ptr<object> generate(std::unique_ptr<Type>&& t, basic_repository &repo, const std::string &name) {
|
||||
const std::type_index ti(typeid(Type));
|
||||
if (shadow_repo.has_object_for_type(ti)) {
|
||||
auto obj = shadow_repo.object_for_type(ti);
|
||||
shadow_repo.remove_object_for_type(ti);
|
||||
if (repo.has_object_for_type(ti)) {
|
||||
auto obj = repo.object_for_type(ti);
|
||||
repo.remove_object_for_type(ti);
|
||||
obj->update_name(name);
|
||||
return obj;
|
||||
}
|
||||
|
||||
auto obj = shadow_repo.provide_object_in_advance(ti, std::make_shared<object>(name));
|
||||
auto obj = std::make_shared<object>(name);
|
||||
std::ignore = repo.provide_object_in_advance(ti, obj);
|
||||
object_generator gen(repo, obj);
|
||||
access::process(gen, *t);
|
||||
return obj;
|
||||
@@ -127,9 +125,9 @@ private:
|
||||
template<typename Type>
|
||||
[[nodiscard]] std::shared_ptr<object> fk_object() const;
|
||||
|
||||
static std::shared_ptr<object> acquire_object(repository &repo, const std::type_index &ti, const std::string& name);
|
||||
static std::shared_ptr<object> acquire_object(basic_repository &repo, const std::type_index &ti, const std::string& name);
|
||||
private:
|
||||
const repository &repo_;
|
||||
basic_repository &repo_;
|
||||
std::shared_ptr<object> object_;
|
||||
};
|
||||
|
||||
@@ -137,7 +135,6 @@ template<typename ValueType>
|
||||
void object_generator::on_primary_key(const char *id, ValueType &x, const utils::primary_key_attribute& attr) {
|
||||
auto &ref = emplace_attribute<ValueType>(id, { attr.size(), utils::constraints::PrimaryKey }, null_option_type::NotNull);
|
||||
prepare_primary_key(ref, utils::identifier(x));
|
||||
// create_pk_constraint(id);
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
@@ -167,15 +164,14 @@ void object_generator::create_fk_constraint(const std::string& name) const {
|
||||
template<typename Type>
|
||||
std::shared_ptr<object> object_generator::fk_object() const {
|
||||
const auto ti = std::type_index(typeid(Type));
|
||||
const internal::shadow_repository shadow_repo(const_cast<repository &>(repo_));
|
||||
if (const auto result = shadow_repo.basic_info(ti)) {
|
||||
if (const auto result = repo_.basic_info(ti)) {
|
||||
return result->get().object();
|
||||
}
|
||||
|
||||
if (shadow_repo.has_object_for_type(ti)) {
|
||||
return shadow_repo.object_for_type(ti);
|
||||
if (repo_.has_object_for_type(ti)) {
|
||||
return repo_.object_for_type(ti);
|
||||
}
|
||||
const auto obj = shadow_repo.provide_object_in_advance(ti, std::make_shared<object>(""));
|
||||
const auto obj = repo_.provide_object_in_advance(ti, std::make_shared<object>(""));
|
||||
object_generator gen(repo_, obj);
|
||||
Type t;
|
||||
access::process(gen, t);
|
||||
|
||||
@@ -9,35 +9,20 @@
|
||||
namespace matador::object {
|
||||
class repository_node;
|
||||
|
||||
// template<typename Type>
|
||||
// class observer_ptr {
|
||||
// public:
|
||||
// explicit observer_ptr(std::unique_ptr<observer<Type>> &&o)
|
||||
// : observer_(std::move(o)) {}
|
||||
//
|
||||
// operator bool() const { return observer_ != nullptr; }
|
||||
//
|
||||
// observer<Type> *get() const { return observer_.get(); }
|
||||
// observer<Type> &operator*() const { return *observer_; }
|
||||
// observer<Type> *operator->() const { return observer_.get(); }
|
||||
//
|
||||
// private:
|
||||
// std::unique_ptr<observer<Type>> observer_;
|
||||
// };
|
||||
template<typename Type>
|
||||
class object_info final : public basic_object_info {
|
||||
public:
|
||||
using create_func = std::function<std::unique_ptr<Type>()>;
|
||||
|
||||
object_info(const std::shared_ptr<repository_node>& node,
|
||||
std::shared_ptr<class object> &&obj,
|
||||
object_info(const repository_node& node,
|
||||
const std::shared_ptr<class object> &obj,
|
||||
std::vector<std::unique_ptr<observer<Type>>>&& observers,
|
||||
create_func&& creator)
|
||||
: basic_object_info(node, std::move(obj))
|
||||
: basic_object_info(node, obj)
|
||||
, creator_(std::move(creator))
|
||||
, observers_(std::move(observers)){}
|
||||
|
||||
explicit object_info(const std::shared_ptr<repository_node>& node)
|
||||
explicit object_info(const repository_node& node)
|
||||
: basic_object_info(node, {}) {
|
||||
}
|
||||
|
||||
@@ -46,13 +31,13 @@ public:
|
||||
|
||||
void on_attach() const override {
|
||||
for (auto &observer : observers_) {
|
||||
observer->on_attach(*node_, prototype_);
|
||||
observer->on_attach(node_, prototype_);
|
||||
}
|
||||
}
|
||||
|
||||
void on_detach() const override {
|
||||
for (auto &observer : observers_) {
|
||||
observer->on_detach(*node_, prototype_);
|
||||
observer->on_detach(node_, prototype_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef RELATION_COMPLETER_HPP
|
||||
#define RELATION_COMPLETER_HPP
|
||||
|
||||
#include "matador/object/internal/shadow_repository.hpp"
|
||||
#include "matador/object/basic_repository.hpp"
|
||||
#include "matador/object/foreign_node_completer.hpp"
|
||||
#include "matador/object/many_to_many_relation.hpp"
|
||||
#include "matador/object/join_columns_collector.hpp"
|
||||
@@ -94,15 +94,11 @@ private:
|
||||
*/
|
||||
template<typename Type, template<typename> typename... Observers>
|
||||
class relation_completer final {
|
||||
private:
|
||||
using node_ptr = std::shared_ptr<repository_node>;
|
||||
|
||||
public:
|
||||
using endpoint_ptr = std::shared_ptr<relation_endpoint>;
|
||||
|
||||
static void complete(const std::shared_ptr<repository_node> &node, const std::vector<std::unique_ptr<observer<Type>>> &observers) {
|
||||
internal::shadow_repository shadow(node->repo_);
|
||||
relation_completer completer(shadow, observers);
|
||||
static void complete(repository_node *node, const std::vector<std::unique_ptr<observer<Type>>> &observers) {
|
||||
relation_completer completer(node->repo_, observers);
|
||||
|
||||
completer.complete_node_relations(node);
|
||||
}
|
||||
@@ -131,12 +127,12 @@ public:
|
||||
void on_has_many_to_many(const char *id, CollectionType &collection, const utils::foreign_attributes &attr);
|
||||
|
||||
private:
|
||||
explicit relation_completer(internal::shadow_repository &shadow, const std::vector<std::unique_ptr<observer<Type>>>& observers)
|
||||
: schema_(shadow)
|
||||
explicit relation_completer(basic_repository &repo, const std::vector<std::unique_ptr<observer<Type>>>& observers)
|
||||
: repo_(repo)
|
||||
, log_(logger::create_logger("relation_completer"))
|
||||
, observers_(observers) {}
|
||||
|
||||
void complete_node_relations(const std::shared_ptr<repository_node> &node) {
|
||||
void complete_node_relations(repository_node* node) {
|
||||
nodes_.push(node);
|
||||
|
||||
Type obj;
|
||||
@@ -152,11 +148,11 @@ private:
|
||||
static void link_relation_endpoints(const endpoint_ptr &endpoint,
|
||||
const endpoint_ptr &other_endpoint);
|
||||
|
||||
node_ptr find_node(const std::type_index &ti) const;
|
||||
[[nodiscard]] repository_node* find_node(const std::type_index &ti) const;
|
||||
|
||||
private:
|
||||
std::stack<node_ptr> nodes_;
|
||||
internal::shadow_repository &schema_;
|
||||
std::stack<repository_node*> nodes_;
|
||||
basic_repository &repo_;
|
||||
logger::logger log_;
|
||||
join_columns_collector join_columns_collector_{};
|
||||
const std::vector<std::unique_ptr<observer<Type>>>& observers_;
|
||||
@@ -183,13 +179,13 @@ void relation_completer<Type, Observers...>::on_has_many(const char *id, Collect
|
||||
if (const auto it = foreign_node->info_->find_relation_endpoint(typeid(Type)); it != foreign_node->info().endpoint_end()) {
|
||||
// corresponding belongs_to is available and was called (has_many <-> belongs_to)
|
||||
// complete the relation
|
||||
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasMany, foreign_node);
|
||||
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasMany, *foreign_node);
|
||||
nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
|
||||
link_relation_endpoints(local_endpoint, it->second);
|
||||
} else if (join_column_finder::has_join_column<value_type>(join_column)) {
|
||||
// corresponding belongs_to is available but was not called (has_many <-> belongs_to)
|
||||
// prepare the relation
|
||||
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasMany, foreign_node);
|
||||
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasMany, *foreign_node);
|
||||
nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
|
||||
} else {
|
||||
// A relation table is necessary
|
||||
@@ -198,21 +194,23 @@ void relation_completer<Type, Observers...>::on_has_many(const char *id, Collect
|
||||
// belongs-to relation handles this relation, the many-to-many
|
||||
// relation is maybe detached.
|
||||
log_.debug("node '%s' has has many foreign keys '%s' mapped by '%s'", nodes_.top()->name().c_str(), id, join_column);
|
||||
auto node = repository_node::make_node<relation_value_type>(schema_.repo(), id, [join_column] {
|
||||
auto node = repository_node::make_node<relation_value_type>(repo_, id, [join_column] {
|
||||
return std::make_unique<relation_value_type>("id", join_column);
|
||||
}, {});
|
||||
const auto result = schema_.attach_node(node);
|
||||
const auto result = repo_.attach_node(node.release(), "");
|
||||
if (!result) {
|
||||
// Todo: throw internal error
|
||||
return;
|
||||
}
|
||||
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasMany, node);
|
||||
const auto foreign_endpoint = std::make_shared<relation_endpoint>("id", relation_type::BelongsTo, nodes_.top());
|
||||
|
||||
auto *attached_node = result.value();
|
||||
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasMany, *attached_node);
|
||||
const auto foreign_endpoint = std::make_shared<relation_endpoint>("id", relation_type::BelongsTo, *nodes_.top());
|
||||
nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
|
||||
node->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint);
|
||||
attached_node->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint);
|
||||
link_relation_endpoints(local_endpoint, foreign_endpoint);
|
||||
|
||||
const auto foreign_value_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BelongsTo, foreign_node);
|
||||
const auto foreign_value_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BelongsTo, *foreign_node);
|
||||
node->info_->register_relation_endpoint(typeid(value_type), foreign_value_endpoint);
|
||||
}
|
||||
}
|
||||
@@ -226,20 +224,21 @@ void relation_completer<Type, Observers...>::on_has_many(const char *id, Collect
|
||||
using value_type = typename CollectionType::value_type;
|
||||
using relation_value_type = many_to_relation<Type, value_type>;
|
||||
|
||||
auto node = repository_node::make_node<relation_value_type>(schema_.repo(), id, [join_column] {
|
||||
auto node = repository_node::make_node<relation_value_type>(repo_, id, [join_column] {
|
||||
return std::make_unique<relation_value_type>(join_column, "value");
|
||||
}, {});
|
||||
const auto result = schema_.attach_node(node);
|
||||
const auto result = repo_.attach_node(node.release(), "");
|
||||
if (!result) {
|
||||
// Todo: throw internal exception
|
||||
return;
|
||||
}
|
||||
|
||||
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasMany, node);
|
||||
const auto foreign_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BelongsTo, nodes_.top());
|
||||
auto *attached_node = result.value();
|
||||
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasMany, *attached_node);
|
||||
const auto foreign_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BelongsTo, *nodes_.top());
|
||||
|
||||
nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
|
||||
node->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint);
|
||||
attached_node->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint);
|
||||
link_relation_endpoints(local_endpoint, foreign_endpoint);
|
||||
}
|
||||
|
||||
@@ -250,11 +249,11 @@ void relation_completer<Type, Observers...>::on_has_many_to_many(const char *id,
|
||||
const char *join_column,
|
||||
const char *inverse_join_column,
|
||||
const utils::foreign_attributes &/*attr*/) {
|
||||
if (!schema_.expecting_relation_node(id)) {
|
||||
schema_.expect_relation_node(id, typeid(typename CollectionType::value_type::value_type));
|
||||
if (!repo_.expecting_relation_node(id)) {
|
||||
repo_.expect_relation_node(id, typeid(typename CollectionType::value_type::value_type));
|
||||
} else {
|
||||
attach_relation_node<typename CollectionType::value_type::value_type>(id, join_column, inverse_join_column);
|
||||
schema_.remove_expected_relation_node(id);
|
||||
repo_.remove_expected_relation_node(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,7 +277,7 @@ void relation_completer<Type, Observers...>::on_has_one(const char *id,
|
||||
ForeignPointerType &/*obj*/,
|
||||
const utils::foreign_attributes &/*attr*/) {
|
||||
using value_type = typename ForeignPointerType::value_type;
|
||||
auto foreign_node = find_node(typeid(value_type));
|
||||
const auto foreign_node = find_node(typeid(value_type));
|
||||
if (!foreign_node) {
|
||||
// Todo: throw internal error or attach node
|
||||
return;
|
||||
@@ -286,7 +285,7 @@ void relation_completer<Type, Observers...>::on_has_one(const char *id,
|
||||
|
||||
auto local_it = nodes_.top()->info().find_relation_endpoint(typeid(value_type));
|
||||
if (local_it == nodes_.top()->info().endpoint_end()) {
|
||||
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasOne, foreign_node);
|
||||
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasOne, *foreign_node);
|
||||
local_it = nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
|
||||
}
|
||||
if (const auto foreign_it = foreign_node->info().find_relation_endpoint(typeid(Type)); foreign_it != foreign_node->info().endpoint_end()) {
|
||||
@@ -302,7 +301,7 @@ void relation_completer<Type, Observers...>::on_belongs_to(const char *id,
|
||||
const utils::foreign_attributes & /*attr*/) {
|
||||
using value_type = typename ForeignPointerType::value_type;
|
||||
const auto ti = std::type_index(typeid(value_type));
|
||||
auto foreign_node = find_node(typeid(value_type));
|
||||
const auto foreign_node = find_node(typeid(value_type));
|
||||
if (!foreign_node) {
|
||||
// Todo: throw internal error or attach node
|
||||
return;
|
||||
@@ -313,11 +312,11 @@ void relation_completer<Type, Observers...>::on_belongs_to(const char *id,
|
||||
if (const auto it = foreign_node->info_->find_relation_endpoint(nodes_.top()->type_index()); it != foreign_node->info().endpoint_end()) {
|
||||
// Found corresponding relation endpoint in the foreign node
|
||||
if (it->second->is_has_one()) {
|
||||
const auto endpoint = std::make_shared<relation_endpoint>(id, relation_type::BelongsTo, foreign_node);
|
||||
const auto endpoint = std::make_shared<relation_endpoint>(id, relation_type::BelongsTo, *foreign_node);
|
||||
nodes_.top()->info_->register_relation_endpoint(ti, endpoint);
|
||||
link_relation_endpoints(endpoint, it->second);
|
||||
} else if (it->second->is_has_many()) {
|
||||
const auto endpoint = std::make_shared<relation_endpoint>(id, relation_type::BelongsTo, foreign_node);
|
||||
const auto endpoint = std::make_shared<relation_endpoint>(id, relation_type::BelongsTo, *foreign_node);
|
||||
nodes_.top()->info_->register_relation_endpoint(ti, endpoint);
|
||||
link_relation_endpoints(endpoint, it->second);
|
||||
} else if (it->second->foreign_endpoint()->node().type_index() == typeid(many_to_many_relation<Type, value_type>)) {
|
||||
@@ -326,16 +325,15 @@ void relation_completer<Type, Observers...>::on_belongs_to(const char *id,
|
||||
// "belongs_to"-relation the "many_to_many_relation" can be removed
|
||||
// (detach), and the endpoints must be adjusted
|
||||
const auto foreign_endpoint = it->second->foreign_endpoint();
|
||||
const auto detach_result = schema_.detach_node(foreign_endpoint->node_);
|
||||
const auto detach_result = repo_.detach(foreign_endpoint->node_);
|
||||
foreign_endpoint->node_ = foreign_node;
|
||||
// foreign_endpoint->node_ = nodes_.top();
|
||||
nodes_.top()->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint);
|
||||
} else {
|
||||
// check type
|
||||
}
|
||||
} else {
|
||||
// Relation node was not found, create only endpoint.
|
||||
const auto endpoint = std::make_shared<relation_endpoint>(id, relation_type::BelongsTo, foreign_node);
|
||||
const auto endpoint = std::make_shared<relation_endpoint>(id, relation_type::BelongsTo, *foreign_node);
|
||||
nodes_.top()->info_->register_relation_endpoint(ti, endpoint);
|
||||
}
|
||||
}
|
||||
@@ -343,18 +341,17 @@ void relation_completer<Type, Observers...>::on_belongs_to(const char *id,
|
||||
template<typename Type, template<typename> typename... Observers>
|
||||
template<typename NodeType>
|
||||
void relation_completer<Type, Observers...>::attach_relation_node(const std::string &name, const std::string &join_column, const std::string &inverse_join_column) {
|
||||
using relation_value_type = many_to_many_relation<NodeType, Type>;
|
||||
using relation_value_type = many_to_many_relation<Type, NodeType>;
|
||||
using value_type = NodeType;
|
||||
|
||||
// Check if the object_ptr type is already inserted in the schema (by id)
|
||||
auto foreign_node = find_node(typeid(value_type));
|
||||
const auto foreign_node = find_node(typeid(value_type));
|
||||
if (!foreign_node) {
|
||||
// Todo: throw internal error or attach node
|
||||
return;
|
||||
}
|
||||
|
||||
auto result = schema_.find_node(name);
|
||||
if (result) {
|
||||
if (const auto it = repo_.find_node(name); it != repo_.end()) {
|
||||
return;
|
||||
}
|
||||
// Relation does not exist. Create it.
|
||||
@@ -364,26 +361,27 @@ void relation_completer<Type, Observers...>::attach_relation_node(const std::str
|
||||
|
||||
auto observers = internal::observer_list_copy_creator<Type, relation_value_type, Observers...>::copy_create(observers_);
|
||||
|
||||
auto node = repository_node::make_node<relation_value_type>(schema_.repo(), name, std::move(creator), std::move(observers));
|
||||
result = schema_.attach_node(node);
|
||||
auto node = repository_node::make_node<relation_value_type>(repo_, name, std::move(creator), std::move(observers));
|
||||
auto result = repo_.attach_node(node.release(), "");
|
||||
if (!result) {
|
||||
// Todo: throw internal error
|
||||
return;
|
||||
}
|
||||
|
||||
auto *attached_node = result.value();
|
||||
foreign_node_completer<relation_value_type>::complete(result.value(), {});
|
||||
|
||||
const auto local_endpoint = std::make_shared<relation_endpoint>(name, relation_type::HasMany, node);
|
||||
const auto join_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BelongsTo, nodes_.top());
|
||||
const auto inverse_join_endpoint = std::make_shared<relation_endpoint>(inverse_join_column, relation_type::BelongsTo, foreign_node);
|
||||
const auto foreign_endpoint = std::make_shared<relation_endpoint>(name, relation_type::HasMany, node);
|
||||
const auto local_endpoint = std::make_shared<relation_endpoint>(name, relation_type::HasMany, *attached_node);
|
||||
const auto join_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BelongsTo, *nodes_.top());
|
||||
const auto inverse_join_endpoint = std::make_shared<relation_endpoint>(inverse_join_column, relation_type::BelongsTo, *foreign_node);
|
||||
const auto foreign_endpoint = std::make_shared<relation_endpoint>(name, relation_type::HasMany, *attached_node);
|
||||
// register relation endpoint in local node
|
||||
nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
|
||||
// register relation endpoint in foreign node
|
||||
foreign_node->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint);
|
||||
// register endpoints in relation node
|
||||
node->info_->register_relation_endpoint(nodes_.top()->type_index(), join_endpoint);
|
||||
node->info_->register_relation_endpoint(typeid(value_type), inverse_join_endpoint);
|
||||
attached_node->info_->register_relation_endpoint(nodes_.top()->type_index(), join_endpoint);
|
||||
attached_node->info_->register_relation_endpoint(typeid(value_type), inverse_join_endpoint);
|
||||
// link endpoints
|
||||
link_relation_endpoints(local_endpoint, join_endpoint);
|
||||
link_relation_endpoints(foreign_endpoint, inverse_join_endpoint);
|
||||
@@ -392,8 +390,8 @@ void relation_completer<Type, Observers...>::attach_relation_node(const std::str
|
||||
template<typename Type, template<typename> typename... Observers>
|
||||
void relation_completer<Type, Observers...>::register_relation_endpoints(const endpoint_ptr &endpoint,
|
||||
const endpoint_ptr &other_endpoint) {
|
||||
endpoint->node_->info_->register_relation_endpoint(other_endpoint->node_->type_index(), endpoint);
|
||||
other_endpoint->node_->info_->register_relation_endpoint(endpoint->node_->type_index(), other_endpoint);
|
||||
endpoint->node().info_->register_relation_endpoint(other_endpoint->node().type_index(), endpoint);
|
||||
other_endpoint->node().info_->register_relation_endpoint(endpoint->node().type_index(), other_endpoint);
|
||||
link_relation_endpoints(endpoint, other_endpoint);
|
||||
}
|
||||
|
||||
@@ -404,16 +402,15 @@ void relation_completer<Type, Observers...>::link_relation_endpoints(const endpo
|
||||
}
|
||||
|
||||
template<typename Type, template <typename> class ... Observers>
|
||||
typename relation_completer<Type, Observers...>::node_ptr relation_completer<Type, Observers...>::find_node(const std::type_index &ti) const {
|
||||
node_ptr foreign_node;
|
||||
if (auto result = schema_.find_node(ti); result) {
|
||||
return result.value();
|
||||
repository_node* relation_completer<Type, Observers...>::find_node(const std::type_index &ti) const {
|
||||
if (const auto it = repo_.find_node(ti); it != repo_.end()) {
|
||||
return it.get();
|
||||
}
|
||||
|
||||
if (!schema_.is_node_announced(ti)) {
|
||||
return {};
|
||||
if (!repo_.is_node_announced(ti)) {
|
||||
return nullptr;
|
||||
}
|
||||
return schema_.announce_node(ti);
|
||||
return repo_.announce_node(ti);
|
||||
}
|
||||
}
|
||||
#endif //RELATION_COMPLETER_HPP
|
||||
|
||||
@@ -24,15 +24,13 @@ static const utils::enum_mapper<relation_type> relation_type_enum({
|
||||
|
||||
class relation_endpoint {
|
||||
public:
|
||||
relation_endpoint(std::string field_name, relation_type type, const std::shared_ptr<repository_node>& node);
|
||||
relation_endpoint(std::string field_name, relation_type type, repository_node& node);
|
||||
|
||||
[[nodiscard]] std::string field_name() const;
|
||||
[[nodiscard]] relation_type type() const;
|
||||
[[nodiscard]] std::string type_name() const;
|
||||
[[nodiscard]] const repository_node& node() const;
|
||||
|
||||
[[nodiscard]] std::shared_ptr<repository_node> node_ptr() const;
|
||||
|
||||
[[nodiscard]] bool is_has_one() const;
|
||||
[[nodiscard]] bool is_has_many() const;
|
||||
[[nodiscard]] bool is_belongs_to() const;
|
||||
@@ -48,8 +46,8 @@ private:
|
||||
|
||||
std::string field_name_;
|
||||
relation_type type_;
|
||||
std::shared_ptr<repository_node> node_;
|
||||
std::shared_ptr<relation_endpoint> foreign_endpoint_;
|
||||
repository_node *node_{nullptr};
|
||||
std::weak_ptr<relation_endpoint> foreign_endpoint_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,42 +1,23 @@
|
||||
#ifndef SCHEMA_HPP
|
||||
#define SCHEMA_HPP
|
||||
#ifndef REPOSITORY_HPP
|
||||
#define REPOSITORY_HPP
|
||||
|
||||
#include "matador/logger/log_manager.hpp"
|
||||
#include "matador/object/basic_repository.hpp"
|
||||
|
||||
#include "matador/object/error_code.hpp"
|
||||
#include "matador/object/foreign_node_completer.hpp"
|
||||
#include "matador/object/object_info.hpp"
|
||||
#include "matador/object/observer.hpp"
|
||||
#include "matador/object/relation_completer.hpp"
|
||||
#include "matador/object/repository_node.hpp"
|
||||
#include "matador/object/repository_node_iterator.hpp"
|
||||
|
||||
#include "matador/utils/result.hpp"
|
||||
#include "matador/utils/error.hpp"
|
||||
|
||||
#include "matador/logger/logger.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace matador::object {
|
||||
namespace internal {
|
||||
class shadow_repository;
|
||||
}
|
||||
|
||||
utils::error make_error(error_code ec, const std::string &msg);
|
||||
|
||||
class repository {
|
||||
class repository : public basic_repository {
|
||||
public:
|
||||
typedef const_repository_node_iterator const_iterator; /**< Shortcut for the list const iterator. */
|
||||
|
||||
using node_ptr = std::shared_ptr<repository_node>;
|
||||
|
||||
/**
|
||||
* Creates an empty schema
|
||||
*/
|
||||
explicit repository(std::string name = "");
|
||||
using basic_repository::basic_repository;
|
||||
|
||||
template<typename Type, template<typename> typename... Observers>
|
||||
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, Observers<Type>&&... observers) {
|
||||
@@ -46,12 +27,12 @@ public:
|
||||
template<typename Type, typename SuperType, template<typename> typename... Observers>
|
||||
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, Observers<Type>&&... observers) {
|
||||
const auto ti = std::type_index(typeid(SuperType));
|
||||
auto result = find_node(ti);
|
||||
if (!result) {
|
||||
const auto it = find_node(ti);
|
||||
if (it == end()) {
|
||||
return utils::failure(make_error(error_code::NodeNotFound, "Parent node '" + std::string(ti.name()) + "' not found"));
|
||||
}
|
||||
|
||||
return attach_type<Type, Observers...>(name, (*result)->name(), std::forward<Observers<Type>>(observers)...);
|
||||
return attach_type<Type, Observers...>(name, it->name(), std::forward<Observers<Type>>(observers)...);
|
||||
}
|
||||
|
||||
template<typename Type, template<typename> typename... Observers>
|
||||
@@ -65,20 +46,22 @@ public:
|
||||
obs.reserve(sizeof...(Observers));
|
||||
(obs.push_back(std::unique_ptr<observer<Type>>(new Observers<Type>(std::forward<Observers<Type>>(observers)))), ...);
|
||||
// if the type was not found
|
||||
std::shared_ptr<repository_node> node;
|
||||
std::unique_ptr<repository_node> node;
|
||||
if (is_node_announced(typeid(Type))) {
|
||||
node = pop_announce_node(typeid(Type));
|
||||
node->update_name(name);
|
||||
} else {
|
||||
node = repository_node::make_node<Type>(*this, name, []{ return std::make_unique<Type>(); }, std::move(obs));
|
||||
}
|
||||
if (auto result = attach_node(node, parent); !result) {
|
||||
auto result = attach_node(node.release(), parent);
|
||||
if (!result) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
|
||||
const auto info = node->template info<Type>();
|
||||
foreign_node_completer<Type, Observers...>::complete(node, info.get().observers());
|
||||
relation_completer<Type, Observers...>::complete(node, info.get().observers());
|
||||
repository_node* attached_node = result.value();
|
||||
const auto info = attached_node->template info<Type>();
|
||||
foreign_node_completer<Type, Observers...>::complete(attached_node, info.get().observers());
|
||||
relation_completer<Type, Observers...>::complete(attached_node, info.get().observers());
|
||||
} else if (!has_node(name)) {
|
||||
it->second->update_name(name);
|
||||
nodes_by_name_[name] = it->second;
|
||||
@@ -95,142 +78,16 @@ public:
|
||||
return utils::ok<void>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Detaches a given node from the schema. If the
|
||||
* node is a parent of other nodes, these nodes are
|
||||
* detached as well.
|
||||
*
|
||||
* @param node Node to detach from schema
|
||||
* @return Result object indicating success or failure
|
||||
*/
|
||||
[[nodiscard]] utils::result<void, utils::error> detach(const node_ptr &node);
|
||||
|
||||
/**
|
||||
* Return the first schema node.
|
||||
*
|
||||
* @return The first schema node iterator.
|
||||
*/
|
||||
[[nodiscard]] const_iterator begin() const;
|
||||
|
||||
/**
|
||||
* Return the last schema node.
|
||||
*
|
||||
* @return The last schema node iterator.
|
||||
*/
|
||||
[[nodiscard]] const_iterator end() const;
|
||||
|
||||
/**
|
||||
* Returns true if the schema contains
|
||||
* no schema nodes.
|
||||
*
|
||||
* @return True if the schema is empty
|
||||
*/
|
||||
[[nodiscard]] bool empty() const;
|
||||
|
||||
/**
|
||||
* Returns the current number of the schema node.
|
||||
*
|
||||
* @return Number of schema nodes
|
||||
*/
|
||||
[[nodiscard]] size_t size() const;
|
||||
|
||||
/**
|
||||
* Returns the name of the schema.
|
||||
*
|
||||
* @return The name of the schema
|
||||
*/
|
||||
[[nodiscard]] std::string name() const;
|
||||
|
||||
[[nodiscard]] bool contains(const std::string &name) const;
|
||||
[[nodiscard]] bool contains(const std::type_index &index) const;
|
||||
template < typename Type >
|
||||
[[nodiscard]] bool contains() const {
|
||||
return contains(std::type_index(typeid(Type)));
|
||||
}
|
||||
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] utils::result<object_info_ref<Type>, utils::error> info() const {
|
||||
auto result = find_node(std::type_index(typeid(Type)));
|
||||
if (!result) {
|
||||
return utils::failure(result.err());
|
||||
const auto it = find_node(std::type_index(typeid(Type)));
|
||||
if (it == end()) {
|
||||
return utils::failure(make_error(error_code::NodeNotFound, "Parent node '" + std::string(typeid(Type).name()) + "' not found"));
|
||||
}
|
||||
|
||||
return utils::ok(result.value()->info<Type>());
|
||||
return utils::ok(it->info<Type>());
|
||||
}
|
||||
|
||||
[[nodiscard]] utils::result<basic_object_info_ref, utils::error> basic_info(const std::type_index& ti) const;
|
||||
|
||||
[[nodiscard]] utils::result<basic_object_info_ref, utils::error> basic_info(const std::string &name) const;
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] utils::result<basic_object_info_ref, utils::error> basic_info() const {
|
||||
auto result = find_node(std::type_index(typeid(Type)));
|
||||
if (!result) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
|
||||
return utils::ok(basic_object_info_ref{result.value()->info()});
|
||||
}
|
||||
|
||||
[[nodiscard]] utils::result<attribute*, utils::error> primary_key_attribute(const std::type_index &type_index) const;
|
||||
|
||||
void dump(std::ostream &os) const;
|
||||
static void dump(std::ostream &os, const node_ptr& node);
|
||||
|
||||
private:
|
||||
using t_node_map = std::unordered_map<std::string, node_ptr>;
|
||||
using t_type_index_node_map = std::unordered_map<std::type_index, node_ptr>;
|
||||
|
||||
[[nodiscard]] utils::result<node_ptr, utils::error> attach_node(const node_ptr &node, const std::string &parent);
|
||||
[[nodiscard]] utils::result<node_ptr, utils::error> find_node(const std::string &name) const;
|
||||
[[nodiscard]] utils::result<node_ptr, utils::error> find_node(const std::type_index &type_index) const;
|
||||
template<typename Type>
|
||||
[[nodiscard]] utils::result<node_ptr, utils::error> find_node() const {
|
||||
return find_node(std::type_index(typeid(Type)));
|
||||
}
|
||||
|
||||
[[nodiscard]] bool has_node(const std::string &name) const;
|
||||
[[nodiscard]] bool has_node(const std::type_index &index) const;
|
||||
[[nodiscard]] bool has_node(const node_ptr& node) const;
|
||||
|
||||
static void insert_node(const node_ptr &parent, const node_ptr &child);
|
||||
void remove_node(const node_ptr &node);
|
||||
|
||||
[[nodiscard]] bool expecting_relation_node(const std::string &name) const;
|
||||
void expect_relation_node(const std::string &name, const std::type_index &ti);
|
||||
void remove_expected_relation_node(const std::string &name);
|
||||
|
||||
[[nodiscard]] std::shared_ptr<object> provide_object_in_advance(const std::type_index &ti, const std::shared_ptr<object>& obj);
|
||||
[[nodiscard]] bool has_object_for_type(const std::type_index &ti) const;
|
||||
[[nodiscard]] std::shared_ptr<object> object_for_type(const std::type_index &ti) const;
|
||||
void remove_object_for_type(const std::type_index &ti);
|
||||
|
||||
[[nodiscard]] bool is_node_announced(const std::type_index &ti) const;
|
||||
void push_announce_node(const std::type_index &ti, const node_ptr &node);
|
||||
[[nodiscard]] node_ptr announce_node(const std::type_index &ti);
|
||||
[[nodiscard]] node_ptr pop_announce_node(const std::type_index &ti);
|
||||
|
||||
private:
|
||||
friend class internal::shadow_repository;
|
||||
friend class repository_node;
|
||||
template < typename NodeType, template<typename> typename ...Observers >
|
||||
friend class foreign_node_completer;
|
||||
friend class object_generator;
|
||||
|
||||
std::string name_;
|
||||
std::shared_ptr<repository_node> root_;
|
||||
|
||||
t_node_map nodes_by_name_;
|
||||
t_type_index_node_map nodes_by_type_;
|
||||
logger::logger log_;
|
||||
|
||||
std::unordered_map<std::type_index, std::shared_ptr<repository_node>> announced_node_;
|
||||
std::unordered_map<std::type_index, attribute*> missing_references_;
|
||||
std::unordered_map<std::string, std::type_index> expected_relation_nodes_;
|
||||
std::unordered_map<std::type_index, std::shared_ptr<object>> object_by_type_;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif //SCHEMA_HPP
|
||||
#endif //REPOSITORY_HPP
|
||||
|
||||
@@ -1,34 +1,30 @@
|
||||
#ifndef SCHEMA_NODE_HPP
|
||||
#define SCHEMA_NODE_HPP
|
||||
#ifndef REPOSITORY_NODE_HPP
|
||||
#define REPOSITORY_NODE_HPP
|
||||
|
||||
#include "matador/object/object_generator.hpp"
|
||||
#include "matador/object/object_info.hpp"
|
||||
#include "matador/object/internal/observer_list_creator.hpp"
|
||||
|
||||
#include "matador/utils/error.hpp"
|
||||
#include "matador/utils/result.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace matador::object {
|
||||
|
||||
class basic_object_info;
|
||||
class repository;
|
||||
class basic_repository;
|
||||
|
||||
class repository_node final {
|
||||
public:
|
||||
using node_ptr = std::shared_ptr<repository_node>;
|
||||
using node_ptr = repository_node*;
|
||||
template< typename Type>
|
||||
using creator_func = std::function<std::unique_ptr<Type>()>;
|
||||
|
||||
template < typename Type, template<typename> typename... Observers >
|
||||
static std::shared_ptr<repository_node> make_node(repository& repo,
|
||||
static std::unique_ptr<repository_node> make_node(basic_repository& repo,
|
||||
const std::string& name,
|
||||
creator_func<Type> creator,
|
||||
std::vector<std::unique_ptr<observer<Type>>>&& observers);
|
||||
|
||||
static std::shared_ptr<repository_node> make_null_node(repository& repo);
|
||||
|
||||
explicit repository_node(basic_repository& repo);
|
||||
repository_node(const repository_node& other) = delete;
|
||||
repository_node(repository_node&& other) = default;
|
||||
repository_node& operator=(const repository_node& other) = delete;
|
||||
@@ -50,7 +46,7 @@ public:
|
||||
return std::ref(static_cast<const object_info<Type>&>(*info_));
|
||||
}
|
||||
|
||||
[[nodiscard]] const repository& schema() const;
|
||||
[[nodiscard]] const basic_repository& schema() const;
|
||||
|
||||
[[nodiscard]] bool has_children() const;
|
||||
|
||||
@@ -58,52 +54,52 @@ public:
|
||||
void on_detach() const;
|
||||
|
||||
private:
|
||||
explicit repository_node(repository& repo);
|
||||
repository_node(repository& repo, const std::type_index& ti);
|
||||
repository_node(repository& repo, std::string name, const std::type_index& ti);
|
||||
repository_node(basic_repository& repo, const std::type_index& ti);
|
||||
repository_node(basic_repository& repo, std::string name, const std::type_index& ti);
|
||||
|
||||
void unlink();
|
||||
|
||||
private:
|
||||
friend class repository;
|
||||
friend class basic_repository;
|
||||
template<typename Type, template<typename> typename... Observers>
|
||||
friend class relation_completer;
|
||||
template < typename NodeType, template<typename> typename ...Observers >
|
||||
friend class foreign_node_completer;
|
||||
friend class const_repository_node_iterator;
|
||||
|
||||
repository &repo_;
|
||||
basic_repository &repo_;
|
||||
std::type_index type_index_;
|
||||
std::unique_ptr<basic_object_info> info_;
|
||||
|
||||
std::shared_ptr<repository_node> parent_;
|
||||
std::shared_ptr<repository_node> previous_sibling_;
|
||||
std::shared_ptr<repository_node> next_sibling_;
|
||||
std::shared_ptr<repository_node> first_child_;
|
||||
std::shared_ptr<repository_node> last_child_;
|
||||
repository_node* parent_{nullptr};
|
||||
repository_node* previous_sibling_{nullptr};
|
||||
repository_node* next_sibling_{nullptr};
|
||||
std::unique_ptr<repository_node> first_child_;
|
||||
std::unique_ptr<repository_node> last_child_;
|
||||
|
||||
std::string name_;
|
||||
size_t depth_{0};
|
||||
};
|
||||
|
||||
template<typename Type, template <typename> class ... Observers>
|
||||
std::shared_ptr<repository_node> repository_node::make_node(repository &repo, const std::string &name,
|
||||
creator_func<Type> creator, std::vector<std::unique_ptr<observer<Type>>> &&observers) {
|
||||
std::unique_ptr<repository_node> repository_node::make_node(basic_repository &repo,
|
||||
const std::string &name,
|
||||
creator_func<Type> creator,
|
||||
std::vector<std::unique_ptr<observer<Type>>> &&observers) {
|
||||
const std::type_index ti(typeid(Type));
|
||||
auto node = std::shared_ptr<repository_node>(new repository_node(repo, name, ti));
|
||||
auto node = std::unique_ptr<repository_node>(new repository_node(repo, name, ti));
|
||||
|
||||
internal::observer_list_creator<Type, Observers...>::create_missing(observers);
|
||||
|
||||
auto obj = object_generator::generate<Type>(creator(), repo, name);
|
||||
auto info = std::make_unique<object_info<Type>>(
|
||||
node,
|
||||
std::move(obj),
|
||||
node->info_.reset(std::make_unique<object_info<Type>>(
|
||||
*node,
|
||||
obj,
|
||||
std::move(observers),
|
||||
std::forward<creator_func<Type>>(creator)
|
||||
);
|
||||
node->info_ = std::move(info);
|
||||
).release());
|
||||
|
||||
return node;
|
||||
}
|
||||
}
|
||||
#endif //SCHEMA_NODE_HPP
|
||||
#endif //REPOSITORY_NODE_HPP
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
#ifndef SCHEMA_NODE_ITERATOR_HPP
|
||||
#define SCHEMA_NODE_ITERATOR_HPP
|
||||
|
||||
#include "matador/object/repository_node.hpp"
|
||||
#ifndef REPOSITORY_NODE_ITERATOR_HPP
|
||||
#define REPOSITORY_NODE_ITERATOR_HPP
|
||||
|
||||
#include <iterator>
|
||||
|
||||
namespace matador::object {
|
||||
|
||||
class repository_node;
|
||||
|
||||
class const_repository_node_iterator {
|
||||
public:
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = std::shared_ptr<repository_node>;
|
||||
using value_type = repository_node;
|
||||
using pointer = repository_node*;
|
||||
using reference = value_type;
|
||||
using reference = value_type&;
|
||||
|
||||
/**
|
||||
* Creates an empty iterator
|
||||
@@ -28,7 +28,7 @@ public:
|
||||
*
|
||||
* @param node The schema node of the object
|
||||
*/
|
||||
explicit const_repository_node_iterator(const value_type& node);
|
||||
explicit const_repository_node_iterator(value_type* node);
|
||||
|
||||
/**
|
||||
* Copy from a given const_object_view_iterator.
|
||||
@@ -123,8 +123,8 @@ private:
|
||||
void decrement();
|
||||
|
||||
private:
|
||||
value_type node_{};
|
||||
pointer node_{nullptr};
|
||||
};
|
||||
|
||||
}
|
||||
#endif //SCHEMA_NODE_ITERATOR_HPP
|
||||
#endif //REPOSITORY_NODE_ITERATOR_HPP
|
||||
|
||||
@@ -25,12 +25,12 @@ public:
|
||||
[[nodiscard]] bool is_primary_key_constraint() const;
|
||||
[[nodiscard]] bool is_foreign_key_constraint() const;
|
||||
[[nodiscard]] bool is_unique_constraint() const;
|
||||
[[nodiscard]] const std::string& ref_table_name() const;
|
||||
[[nodiscard]] const std::string& ref_column_name() const;
|
||||
[[nodiscard]] std::string ref_table_name() const;
|
||||
[[nodiscard]] std::string ref_column_name() const;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const restriction& c);
|
||||
|
||||
std::string type_string() const;
|
||||
[[nodiscard]] std::string type_string() const;
|
||||
|
||||
private:
|
||||
friend class constraint_builder;
|
||||
@@ -38,27 +38,9 @@ private:
|
||||
friend class object;
|
||||
|
||||
const class attribute& attr_;
|
||||
std::shared_ptr<object> owner_;
|
||||
std::shared_ptr<object> reference_;
|
||||
std::weak_ptr<object> owner_;
|
||||
std::weak_ptr<object> reference_;
|
||||
utils::constraints options_{utils::constraints::None};
|
||||
};
|
||||
|
||||
// class constraint_builder {
|
||||
// public:
|
||||
// constraint_builder& constraint(std::string name);
|
||||
// constraint_builder& primary_key(std::string name);
|
||||
// constraint_builder& foreign_key(std::string name);
|
||||
// constraint_builder& references(std::string table, std::string column);
|
||||
//
|
||||
// operator class restriction() const;
|
||||
//
|
||||
// private:
|
||||
// std::string constraint_name;
|
||||
// utils::constraints options_{utils::constraints::None};
|
||||
// std::string column_name;
|
||||
// };
|
||||
//
|
||||
// constraint_builder constraint(std::string name);
|
||||
|
||||
}
|
||||
#endif //MATADOR_RESTRICTION_HPP
|
||||
@@ -109,7 +109,7 @@ public:
|
||||
utils::result<sql::query_result<Type>, utils::error> find(query::criteria_ptr clause = {});
|
||||
|
||||
template<typename Type>
|
||||
utils::result<void, utils::error> drop_table();
|
||||
utils::result<void, utils::error> drop_table() const;
|
||||
utils::result<void, utils::error> drop_table(const std::string &table_name) const;
|
||||
|
||||
[[nodiscard]] utils::result<sql::query_result<sql::record>, utils::error> fetch_all(const sql::query_context &q) const;
|
||||
@@ -141,13 +141,13 @@ private:
|
||||
|
||||
template<typename Type>
|
||||
utils::result<object::object_ptr<Type>, utils::error> session::insert(Type *obj) {
|
||||
auto info = schema_.repo().info<Type>();
|
||||
if (!info) {
|
||||
return utils::failure(info.err());
|
||||
const auto it = schema_.find(typeid(Type));
|
||||
if (it == schema_.end()) {
|
||||
return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type."));
|
||||
}
|
||||
|
||||
auto res = query::query::insert()
|
||||
.into(info->get().name(), query::generator::columns<Type>(schema_))
|
||||
.into(it->second.name(), query::generator::columns<Type>(schema_))
|
||||
.values(query::generator::placeholders<Type>())
|
||||
.prepare(*this);
|
||||
if (!res) {
|
||||
@@ -214,15 +214,15 @@ private:
|
||||
|
||||
template<typename Type>
|
||||
utils::result<object::object_ptr<Type>, utils::error> session::update( const object::object_ptr<Type>& obj ) {
|
||||
auto info = schema_.repo().info<Type>();
|
||||
if (!info) {
|
||||
return utils::failure(info.err());
|
||||
const auto it = schema_.find(typeid(Type));
|
||||
if (it == schema_.end()) {
|
||||
return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type."));
|
||||
}
|
||||
using namespace matador::utils;
|
||||
using namespace matador::query;
|
||||
|
||||
const auto col = table_column(info.value().get().primary_key_attribute()->name());
|
||||
auto res = matador::query::query::update(info->get().name())
|
||||
const auto col = table_column(it->second.node().info().primary_key_attribute()->name());
|
||||
auto res = matador::query::query::update(it->second.name())
|
||||
.set(generator::column_value_pairs<Type>())
|
||||
.where(col == _)
|
||||
.prepare(*this);
|
||||
@@ -240,16 +240,16 @@ utils::result<object::object_ptr<Type>, utils::error> session::update( const obj
|
||||
|
||||
template<typename Type>
|
||||
utils::result<void, utils::error> session::remove( const object::object_ptr<Type>& obj ) {
|
||||
auto info = schema_.repo().info<Type>();
|
||||
if (!info) {
|
||||
return utils::failure(info.err());
|
||||
const auto it = schema_.find(typeid(Type));
|
||||
if (it == schema_.end()) {
|
||||
return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type."));
|
||||
}
|
||||
using namespace matador::utils;
|
||||
using namespace matador::query;
|
||||
|
||||
const auto col = table_column(info.value().get().primary_key_attribute()->name());
|
||||
const auto col = table_column(it->second.node().info().primary_key_attribute()->name());
|
||||
auto res = matador::query::query::remove()
|
||||
.from( info->get().name() )
|
||||
.from( it->second.name() )
|
||||
.where(col == _)
|
||||
.prepare(*this);
|
||||
if (!res) {
|
||||
@@ -299,15 +299,15 @@ utils::result<object::object_ptr<Type>, utils::error> session::find(const Primar
|
||||
|
||||
template<typename Type>
|
||||
utils::result<sql::query_result<Type>, utils::error> session::find(query::criteria_ptr clause) {
|
||||
auto info = schema_.repo().info<Type>();
|
||||
if (!info) {
|
||||
const auto it = schema_.find(typeid(Type));
|
||||
if (it == schema_.end()) {
|
||||
return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type."));
|
||||
}
|
||||
|
||||
session_query_builder eqb(schema_, *this);
|
||||
auto data = eqb.build<Type>(std::move(clause));
|
||||
if (!data.is_ok()) {
|
||||
return utils::failure(make_error(error_code::FailedToBuildQuery, "Failed to build query for type " + info->get().name() + "."));
|
||||
return utils::failure(make_error(error_code::FailedToBuildQuery, "Failed to build query for type " + it->second.name() + "."));
|
||||
}
|
||||
|
||||
auto result = build_select_query(data.release()).prepare(*this);
|
||||
@@ -319,13 +319,12 @@ utils::result<sql::query_result<Type>, utils::error> session::find(query::criter
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
utils::result<void, utils::error> session::drop_table() {
|
||||
auto info = schema_.repo().info<Type>();
|
||||
if (info) {
|
||||
return drop_table(info->get().name());
|
||||
utils::result<void, utils::error> session::drop_table() const {
|
||||
const auto it = schema_.find(typeid(Type));
|
||||
if (it == schema_.end()) {
|
||||
return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type."));
|
||||
}
|
||||
|
||||
return utils::failure(info.err());
|
||||
return drop_table(it->second.name());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -278,8 +278,6 @@ private:
|
||||
struct table_info {
|
||||
const object::basic_object_info &info;
|
||||
query::table table;
|
||||
// std::reference_wrapper<const object::basic_object_info> info;
|
||||
// std::shared_ptr<query::table> table;
|
||||
};
|
||||
|
||||
std::stack<table_info> table_info_stack_{};
|
||||
@@ -325,7 +323,7 @@ void session_query_builder::on_foreign_object(const char *id, Pointer &, const u
|
||||
using namespace matador::utils;
|
||||
using namespace matador::query;
|
||||
// create select query
|
||||
auto result = matador::query::query::select(generator::columns<typename Pointer::value_type>(schema_, generator::column_generator_options::ForceLazy))
|
||||
auto result = matador::query::query::select(generator::columns<typename Pointer::value_type>(schema_, foreign_table, generator::column_generator_options::ForceLazy))
|
||||
.from(foreign_table)
|
||||
.where(table_column(&foreign_table, info.primary_key_attribute()->name(), "") == _)
|
||||
.prepare(executor_);
|
||||
|
||||
@@ -38,8 +38,9 @@ public:
|
||||
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 utils::date_type_t& x) override;
|
||||
void write_value(size_t pos, const utils::time_type_t& x) override;
|
||||
void write_value(size_t pos, const utils::timestamp& 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;
|
||||
|
||||
@@ -46,7 +46,7 @@ constexpr auto default_column_generator_options = column_generator_options::Forc
|
||||
class column_generator {
|
||||
public:
|
||||
explicit column_generator(const schema &repo,
|
||||
const std::string &table_name = "",
|
||||
const table* tab,
|
||||
column_generator_options options = default_column_generator_options);
|
||||
|
||||
template< class Type >
|
||||
@@ -88,21 +88,19 @@ public:
|
||||
if (attr.fetch() == utils::fetch_type::Lazy || is_column_generator_option_set(options_, column_generator_options::ForceLazy)) {
|
||||
return;
|
||||
}
|
||||
if (!repo_) {
|
||||
return;
|
||||
}
|
||||
const auto info = repo_->get().repo().info<typename ContainerType::value_type::value_type>();
|
||||
if (!info) {
|
||||
const auto it = repo_.find(typeid(typename ContainerType::value_type::value_type));
|
||||
if (it == repo_.end()) {
|
||||
// Todo: throw exception
|
||||
return;
|
||||
}
|
||||
|
||||
if (seen_tables.count(info->get().name()) == 0) {
|
||||
auto it = seen_tables.insert(info->get().name()).first;
|
||||
table_stack_.push(std::make_shared<table>(info.value().get().name()));
|
||||
if (seen_tables.count(it->second.name()) == 0) {
|
||||
const auto itt = seen_tables.insert(it->second.name()).first;
|
||||
table_stack_.push(&it->second.table());
|
||||
typename ContainerType::value_type::value_type obj;
|
||||
access::process(*this, obj);
|
||||
table_stack_.pop();
|
||||
seen_tables.erase(it);
|
||||
seen_tables.erase(itt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,20 +122,18 @@ private:
|
||||
if (attr.fetch() == utils::fetch_type::Lazy || is_column_generator_option_set(options_, column_generator_options::ForceLazy)) {
|
||||
push(id);
|
||||
} else {
|
||||
if (!repo_) {
|
||||
const auto it = repo_.find(typeid(typename Pointer::value_type));
|
||||
if (it == repo_.end()) {
|
||||
// Todo: throw exception
|
||||
return;
|
||||
}
|
||||
const auto info = repo_->get().repo().info<typename Pointer::value_type>();
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
if (seen_tables.count(info->get().name()) == 0) {
|
||||
auto it = seen_tables.insert(info->get().name()).first;
|
||||
table_stack_.push(std::make_shared<table>(info.value().get().name()));
|
||||
if (seen_tables.count(it->second.name()) == 0) {
|
||||
const auto iit = seen_tables.insert(it->second.name()).first;
|
||||
table_stack_.push(&it->second.table());
|
||||
typename Pointer::value_type obj;
|
||||
access::process(*this, obj);
|
||||
table_stack_.pop();
|
||||
seen_tables.erase(it);
|
||||
seen_tables.erase(iit);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -145,9 +141,9 @@ private:
|
||||
void push(const std::string &column_name);
|
||||
|
||||
private:
|
||||
std::optional<std::reference_wrapper<const schema>> repo_;
|
||||
const schema &repo_;
|
||||
std::vector<table_column> result_;
|
||||
std::stack<std::shared_ptr<table>> table_stack_;
|
||||
std::stack<const table*> table_stack_;
|
||||
std::unordered_set<std::string> seen_tables;
|
||||
int column_index{0};
|
||||
column_generator_options options_{false};
|
||||
@@ -294,29 +290,32 @@ std::vector<internal::column_value_pair> column_value_pairs() {
|
||||
|
||||
template<typename Type>
|
||||
std::vector<table_column> columns(const schema &repo,
|
||||
const std::string &table_name = "",
|
||||
const table &tab,
|
||||
const column_generator_options options = default_column_generator_options) {
|
||||
column_generator generator(repo, table_name, options);
|
||||
column_generator generator(repo, &tab, options);
|
||||
return generator.generate<Type>();
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
std::vector<table_column> columns(const schema &repo,
|
||||
const column_generator_options options) {
|
||||
std::string table_name;
|
||||
if (const auto result = repo.repo().info<Type>()) {
|
||||
table_name = result.value().get().name();
|
||||
}
|
||||
column_generator generator(repo, table_name, options);
|
||||
return generator.generate<Type>();
|
||||
const column_generator_options options = default_column_generator_options) {
|
||||
const auto it = repo.find(typeid(Type));
|
||||
if (it == repo.end()) {
|
||||
return {};
|
||||
}
|
||||
column_generator generator(repo, &it->second.table(), options);
|
||||
return generator.generate<Type>();
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
std::vector<table_column> columns(const Type &obj,
|
||||
const schema &repo,
|
||||
const std::string &table_name = "",
|
||||
const column_generator_options options = default_column_generator_options) {
|
||||
column_generator generator(repo, table_name, options);
|
||||
const schema &repo,
|
||||
const column_generator_options options = default_column_generator_options) {
|
||||
const auto it = repo.find(typeid(Type));
|
||||
if (it == repo.end()) {
|
||||
return {};
|
||||
}
|
||||
column_generator generator(repo, &it->second.table(), options);
|
||||
return generator.generate(obj);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
return into(tab, generator::columns<Type>(scm));
|
||||
}
|
||||
query_into_intermediate into(const table &tab, std::initializer_list<table_column> columns);
|
||||
query_into_intermediate into(const table &tab, std::vector<table_column> &&columns);
|
||||
query_into_intermediate into(const table &tab, const std::vector<table_column> &columns);
|
||||
query_into_intermediate into(const table &tab, const std::vector<std::string> &column_names);
|
||||
query_into_intermediate into(const table &tab);
|
||||
};
|
||||
|
||||
@@ -7,11 +7,6 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace matador {
|
||||
class date;
|
||||
class time;
|
||||
}
|
||||
|
||||
namespace matador::sql {
|
||||
class dialect;
|
||||
struct query_context;
|
||||
@@ -36,8 +31,9 @@ struct basic_type_to_string_visitor
|
||||
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::date_type_t &x) { result = writer->to_string(x); }
|
||||
void operator()(const utils::time_type_t &x) { result = writer->to_string(x); }
|
||||
void operator()(const utils::timestamp &x) { result = writer->to_string(x); }
|
||||
void operator()(const utils::blob &x) { result = writer->to_string(x); }
|
||||
|
||||
attribute_string_writer *writer{};
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace matador::query::internal {
|
||||
|
||||
class column_value_pair {
|
||||
public:
|
||||
column_value_pair(const table_column &col, utils::database_type value);
|
||||
column_value_pair(table_column col, utils::database_type value);
|
||||
column_value_pair(std::string name, utils::database_type value);
|
||||
column_value_pair(const char *name, utils::database_type value);
|
||||
column_value_pair(const char *name, utils::placeholder p);
|
||||
|
||||
@@ -92,9 +92,9 @@ public:
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] utils::result<void, utils::error> drop_table(const sql::connection &conn);
|
||||
[[nodiscard]] utils::result<void, utils::error> drop_table(const std::string &table_name, const sql::connection &conn) const;
|
||||
[[nodiscard]] static utils::result<void, utils::error> drop_table(const std::string &table_name, const sql::connection &conn);
|
||||
|
||||
[[nodiscard]] utils::result<std::vector<object::attribute>, utils::error> describe_table(const std::string &table_name, const sql::connection &conn) const;
|
||||
[[nodiscard]] static utils::result<std::vector<object::attribute>, utils::error> describe_table(const std::string &table_name, const sql::connection &conn) ;
|
||||
[[nodiscard]] utils::result<bool, utils::error> table_exists(const std::string &table_name, const sql::connection &conn) const;
|
||||
|
||||
iterator begin();
|
||||
@@ -127,7 +127,7 @@ private:
|
||||
|
||||
template<typename Type>
|
||||
utils::result<void, utils::error> schema::drop_table(const sql::connection &conn) {
|
||||
auto info = repo_.info<Type>();
|
||||
auto info = repo_.basic_info<Type>();
|
||||
if (info) {
|
||||
return drop_table(info->get().name(), conn);
|
||||
}
|
||||
|
||||
@@ -71,8 +71,9 @@ public:
|
||||
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 utils::date_type_t &x ) override;
|
||||
void write_value(size_t pos, const utils::time_type_t &x ) override;
|
||||
void write_value(size_t pos, const utils::timestamp &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;
|
||||
|
||||
@@ -5,10 +5,6 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace matador {
|
||||
class date;
|
||||
class time;
|
||||
}
|
||||
namespace matador::utils {
|
||||
|
||||
class value;
|
||||
@@ -29,8 +25,9 @@ public:
|
||||
virtual void write_value(size_t pos, const bool &x) = 0;
|
||||
virtual void write_value(size_t pos, const float &x) = 0;
|
||||
virtual void write_value(size_t pos, const double &x) = 0;
|
||||
virtual void write_value(size_t pos, const time &x) = 0;
|
||||
virtual void write_value(size_t pos, const date &x) = 0;
|
||||
virtual void write_value(size_t pos, const date_type_t &x) = 0;
|
||||
virtual void write_value(size_t pos, const time_type_t &x) = 0;
|
||||
virtual void write_value(size_t pos, const timestamp &x) = 0;
|
||||
virtual void write_value(size_t pos, const char *x) = 0;
|
||||
virtual void write_value(size_t pos, const char *x, size_t size) = 0;
|
||||
virtual void write_value(size_t pos, const std::string &x) = 0;
|
||||
|
||||
@@ -6,11 +6,6 @@
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
// namespace matador {
|
||||
//class date;
|
||||
//class time;
|
||||
//}
|
||||
|
||||
namespace matador::utils {
|
||||
|
||||
template < typename Type >
|
||||
@@ -36,8 +31,9 @@ public:
|
||||
void operator()(double &x) { this->convert(x); }
|
||||
void operator()(const char *x) { this->convert(x); }
|
||||
void operator()(std::string &x) { this->convert(x); }
|
||||
// void operator()(date &x) { this->convert(result, x); }
|
||||
// void operator()(time &x) { this->convert(result, x); }
|
||||
void operator()(date_type_t &x) { this->convert(x); }
|
||||
void operator()(time_type_t &x) { this->convert(x); }
|
||||
void operator()(timestamp &x) { this->convert(x); }
|
||||
void operator()(blob &x) { this->convert(x); }
|
||||
|
||||
private:
|
||||
|
||||
@@ -23,6 +23,7 @@ enum class basic_type : uint8_t {
|
||||
Varchar, /*!< Data type varchar */
|
||||
Text, /*!< Data type text */
|
||||
Date, /*!< Data type date */
|
||||
DateTime, /*!< Data type datetime */
|
||||
Time, /*!< Data type time */
|
||||
Blob, /*!< Data type blob */
|
||||
Null, /*!< Data type null */
|
||||
|
||||
@@ -3,39 +3,36 @@
|
||||
|
||||
#include "matador/utils/types.hpp"
|
||||
#include "matador/utils/result.hpp"
|
||||
//#include "matador/utils/date.hpp"
|
||||
//#include "matador/utils/time.hpp"
|
||||
|
||||
//#include "matador/utils/placeholder.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <charconv>
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
/*
|
||||
* Conversion matrix
|
||||
* from> | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64 | bool | float | double | string | date | time | blob | placeholder | null
|
||||
* to | | | | | | | | | | | | | | | | |
|
||||
* ------------+------+-------+-------+-------+-------+--------+--------+--------+------+-------+--------+--------+------+------+------+-------------+-----
|
||||
* int8 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | try | N/A | N/A
|
||||
* int16 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | try | N/A | N/A
|
||||
* int32 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | try | N/A | N/A
|
||||
* int64 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | try | N/A | N/A
|
||||
* uint8 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | try | N/A | N/A
|
||||
* uint16 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | try | N/A | N/A
|
||||
* uint32 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | try | N/A | N/A
|
||||
* uint64 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | try | N/A | N/A
|
||||
* bool | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | N/A | N/A | try | N/A | N/A
|
||||
* float | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | N/A | N/A | try | N/A | N/A
|
||||
* double | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | N/A | N/A | try | N/A | N/A
|
||||
* string | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | N/A | N/A | N/A
|
||||
* date | ok | ok | ok | ok | ok | ok | ok | ok | N/A | N/A | N/A | try | ok | ok | N/A | N/A | N/A
|
||||
* time | ok | ok | ok | ok | ok | ok | ok | ok | N/A | N/A | N/A | try | ok | ok | N/A | N/A | N/A
|
||||
* blob | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | N/A | N/A
|
||||
* placeholder | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | ok | N/A
|
||||
* null | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | ok
|
||||
* from> | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64 | bool | float | double | string | date | time | timestamp | blob | null
|
||||
* to | | | | | | | | | | | | | | | | |
|
||||
* ------------+------+-------+-------+-------+-------+--------+--------+--------+------+-------+--------+--------+------+------+-----------+------+-----
|
||||
* int8 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | ok | try | N/A
|
||||
* int16 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | ok | try | N/A
|
||||
* int32 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | ok | try | N/A
|
||||
* int64 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | ok | try | N/A
|
||||
* uint8 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | ok | try | N/A
|
||||
* uint16 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | ok | try | N/A
|
||||
* uint32 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | ok | try | N/A
|
||||
* uint64 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | ok | try | N/A
|
||||
* bool | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | N/A | N/A | ok | try | N/A
|
||||
* float | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | N/A | N/A | ok | try | N/A
|
||||
* double | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | N/A | N/A | ok | try | N/A
|
||||
* string | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | N/A | N/A
|
||||
* date | ok | ok | ok | ok | ok | ok | ok | ok | N/A | N/A | N/A | try | ok | ok | ok | N/A | N/A
|
||||
* time | ok | ok | ok | ok | ok | ok | ok | ok | N/A | N/A | N/A | try | ok | ok | ok | N/A | N/A
|
||||
* timestamp | ok | ok | ok | ok | ok | ok | ok | ok | N/A | N/A | N/A | try | ok | ok | ok | N/A | N/A
|
||||
* blob | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | N/A
|
||||
* null | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | ok | ok
|
||||
*
|
||||
* from integral to date/time works, value is interpreted as std::chrono::timepoint
|
||||
* from integral to blob works, bytes of integral data will converted to blob
|
||||
@@ -97,7 +94,6 @@ result<DestType, conversion_error> to(const SourceType &source, std::enable_if_t
|
||||
return ok(std::string(buffer.data(), ptr));
|
||||
}
|
||||
|
||||
// return failure({ec, "couldn't convert value to std::string"});
|
||||
return failure(conversion_error::NotConvertable/*, "couldn't convert value to std::string"}*/);
|
||||
}
|
||||
|
||||
@@ -110,7 +106,6 @@ result<DestType, conversion_error> to(const SourceType &source, std::enable_if_t
|
||||
return ok(std::string(buffer.data(), ptr));
|
||||
}
|
||||
|
||||
// return failure({ec, "couldn't convert value to std::string"});
|
||||
return failure(conversion_error::NotConvertable/*, "couldn't convert value to std::string"}*/);
|
||||
}
|
||||
|
||||
@@ -257,6 +252,105 @@ result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_
|
||||
return failure(conversion_error::NotConvertable);
|
||||
}
|
||||
|
||||
template < typename DestType >
|
||||
result<DestType, conversion_error> to(const std::string &source, std::enable_if_t<std::is_same_v<DestType, date_type_t>>* = nullptr) {
|
||||
std::tm result{};
|
||||
std::istringstream iss(source);
|
||||
iss >> std::get_time(&result, "%Y-%m-%d %H:%M:%S");
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
template < typename DestType >
|
||||
result<DestType, conversion_error> to(const std::string &source, std::enable_if_t<std::is_same_v<DestType, time_type_t>>* = nullptr) {
|
||||
std::tm result{};
|
||||
std::istringstream iss(source);
|
||||
iss >> std::get_time(&result, "%Y-%m-%d %H:%M:%S");
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
template < typename DestType >
|
||||
result<DestType, conversion_error> to(const std::string &source, std::enable_if_t<std::is_same_v<DestType, timestamp>>* = nullptr) {
|
||||
std::tm result{};
|
||||
std::istringstream iss(source);
|
||||
iss >> std::get_time(&result, "%Y-%m-%d %H:%M:%S");
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
template < typename DestType, typename SourceType >
|
||||
result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_if_t<std::is_integral_v<DestType> && !std::is_same_v<bool, DestType> && std::is_same_v<date_type_t, SourceType>>* = nullptr) {
|
||||
return failure(conversion_error::NotConvertable);
|
||||
}
|
||||
|
||||
template < typename DestType, typename SourceType >
|
||||
result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_if_t<std::is_integral_v<DestType> && !std::is_same_v<bool, DestType> && std::is_same_v<time_type_t, SourceType>>* = nullptr) {
|
||||
return failure(conversion_error::NotConvertable);
|
||||
}
|
||||
|
||||
template < typename DestType, typename SourceType >
|
||||
result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_if_t<std::is_integral_v<DestType> && !std::is_same_v<bool, DestType> && std::is_same_v<timestamp, SourceType>>* = nullptr) {
|
||||
return failure(conversion_error::NotConvertable);
|
||||
}
|
||||
|
||||
template < typename DestType, typename SourceType >
|
||||
result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_if_t<std::is_same_v<bool, DestType> && std::is_same_v<date_type_t, SourceType>>* = nullptr) {
|
||||
return failure(conversion_error::NotConvertable);
|
||||
}
|
||||
|
||||
template < typename DestType, typename SourceType >
|
||||
result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_if_t<std::is_same_v<bool, DestType> && std::is_same_v<time_type_t, SourceType>>* = nullptr) {
|
||||
return failure(conversion_error::NotConvertable);
|
||||
}
|
||||
|
||||
template < typename DestType, typename SourceType >
|
||||
result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_if_t<std::is_same_v<bool, DestType> && std::is_same_v<timestamp, SourceType>>* = nullptr) {
|
||||
return failure(conversion_error::NotConvertable);
|
||||
}
|
||||
|
||||
template < typename DestType, typename SourceType >
|
||||
result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_if_t<std::is_floating_point_v<DestType> && std::is_same_v<date_type_t, SourceType>>* = nullptr) {
|
||||
return failure(conversion_error::NotConvertable);
|
||||
}
|
||||
|
||||
template < typename DestType, typename SourceType >
|
||||
result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_if_t<std::is_floating_point_v<DestType> && std::is_same_v<time_type_t, SourceType>>* = nullptr) {
|
||||
return failure(conversion_error::NotConvertable);
|
||||
}
|
||||
|
||||
template < typename DestType, typename SourceType >
|
||||
result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_if_t<std::is_floating_point_v<DestType> && std::is_same_v<timestamp, SourceType>>* = nullptr) {
|
||||
return failure(conversion_error::NotConvertable);
|
||||
}
|
||||
|
||||
template < typename DestType, typename SourceType >
|
||||
result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_if_t<std::is_same_v<blob, DestType> && std::is_same_v<date_type_t, SourceType>>* = nullptr) {
|
||||
return failure(conversion_error::NotConvertable);
|
||||
}
|
||||
|
||||
template < typename DestType, typename SourceType >
|
||||
result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_if_t<std::is_same_v<blob, DestType> && std::is_same_v<time_type_t, SourceType>>* = nullptr) {
|
||||
return failure(conversion_error::NotConvertable);
|
||||
}
|
||||
|
||||
template < typename DestType, typename SourceType >
|
||||
result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_if_t<std::is_same_v<blob, DestType> && std::is_same_v<timestamp, SourceType>>* = nullptr) {
|
||||
return failure(conversion_error::NotConvertable);
|
||||
}
|
||||
|
||||
template < typename DestType, typename SourceType >
|
||||
result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_if_t<std::is_same_v<std::string, DestType> && std::is_same_v<date_type_t, SourceType>>* = nullptr) {
|
||||
return failure(conversion_error::NotConvertable);
|
||||
}
|
||||
|
||||
template < typename DestType, typename SourceType >
|
||||
result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_if_t<std::is_same_v<std::string, DestType> && std::is_same_v<time_type_t, SourceType>>* = nullptr) {
|
||||
return failure(conversion_error::NotConvertable);
|
||||
}
|
||||
|
||||
template < typename DestType, typename SourceType >
|
||||
result<DestType, conversion_error> to(const SourceType &/*source*/, std::enable_if_t<std::is_same_v<std::string, DestType> && std::is_same_v<timestamp, SourceType>>* = nullptr) {
|
||||
return failure(conversion_error::NotConvertable);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif //MATADOR_CONVERT_HPP
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <chrono>
|
||||
|
||||
namespace matador::utils {
|
||||
|
||||
@@ -12,21 +13,74 @@ enum class basic_type : uint8_t;
|
||||
|
||||
using byte = unsigned char;
|
||||
using blob = std::vector<byte>;
|
||||
using timestamp = std::chrono::system_clock::time_point;
|
||||
|
||||
struct date_type_t;
|
||||
struct time_type_t;
|
||||
|
||||
using database_type = std::variant<
|
||||
uint8_t, uint16_t, uint32_t, uint64_t,
|
||||
int8_t, int16_t, int32_t, int64_t,
|
||||
float, double,
|
||||
bool,
|
||||
const char*,
|
||||
std::string,
|
||||
blob,
|
||||
nullptr_t>;
|
||||
uint8_t, uint16_t, uint32_t, uint64_t,
|
||||
int8_t, int16_t, int32_t, int64_t,
|
||||
float, double,
|
||||
bool,
|
||||
const char*,
|
||||
std::string,
|
||||
blob,
|
||||
timestamp,
|
||||
date_type_t,
|
||||
time_type_t,
|
||||
nullptr_t>;
|
||||
|
||||
struct null_type_t {};
|
||||
|
||||
struct date_type_t {
|
||||
int32_t year{};
|
||||
uint8_t month{}; // 1-12
|
||||
uint8_t day{};
|
||||
};
|
||||
|
||||
struct time_type_t {
|
||||
uint8_t hour{};
|
||||
uint8_t minute{};
|
||||
uint8_t second{};
|
||||
uint32_t microsecond{};
|
||||
};
|
||||
|
||||
void initialize_by_basic_type(basic_type type, database_type &val);
|
||||
|
||||
|
||||
// Equality
|
||||
constexpr bool operator==(const date_type_t& a, const date_type_t& b) noexcept {
|
||||
return a.year == b.year &&
|
||||
a.month == b.month &&
|
||||
a.day == b.day;
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const date_type_t& a, const date_type_t& b) noexcept;
|
||||
|
||||
// Ordering
|
||||
constexpr bool operator<(const date_type_t& a, const date_type_t& b) noexcept;
|
||||
constexpr bool operator>(const date_type_t& a, const date_type_t& b) noexcept;
|
||||
constexpr bool operator<=(const date_type_t& a, const date_type_t& b) noexcept;
|
||||
constexpr bool operator>=(const date_type_t& a, const date_type_t& b) noexcept;
|
||||
|
||||
|
||||
// Equality
|
||||
constexpr bool operator==(const time_type_t &a, const time_type_t &b) noexcept {
|
||||
return a.hour == b.hour &&
|
||||
a.minute == b.minute &&
|
||||
a.second == b.second &&
|
||||
a.microsecond == b.microsecond;
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const time_type_t& a, const time_type_t& b) noexcept;
|
||||
|
||||
// Ordering
|
||||
constexpr bool operator<(const time_type_t& a, const time_type_t& b) noexcept;
|
||||
constexpr bool operator>(const time_type_t& a, const time_type_t& b) noexcept;
|
||||
constexpr bool operator<=(const time_type_t& a, const time_type_t& b) noexcept;
|
||||
constexpr bool operator>=(const time_type_t& a, const time_type_t& b) noexcept;
|
||||
|
||||
}
|
||||
|
||||
#endif //MATADOR_TYPES_HPP
|
||||
|
||||
Reference in New Issue
Block a user