Compare commits
11 Commits
d8e43c1f95
...
df480edb05
| Author | SHA1 | Date |
|---|---|---|
|
|
df480edb05 | |
|
|
6da0620169 | |
|
|
f897363297 | |
|
|
77c72ca23f | |
|
|
5379324519 | |
|
|
f32594d9fd | |
|
|
3781bd0b66 | |
|
|
cfbee7781d | |
|
|
ee025ea49e | |
|
|
9f7a0c8625 | |
|
|
7b5123df16 |
|
|
@ -6,15 +6,18 @@
|
|||
#include "matador/utils/base_class.hpp"
|
||||
|
||||
namespace work::models::admin {
|
||||
struct LdapUserDirectory;
|
||||
|
||||
struct LdapGroupSchemaSettings : core::Model {
|
||||
std::string group_object_filter;
|
||||
std::string user_member_attribute;
|
||||
matador::object::object_ptr<LdapUserDirectory> ldap_user_directory;
|
||||
|
||||
template<typename Operator>
|
||||
void process( Operator& op ) {
|
||||
namespace field = matador::access;
|
||||
field::process( op, *matador::base_class<Model>( this ) );
|
||||
field::has_one(op, "ldap_user_directory", ldap_user_directory, matador::utils::default_foreign_attributes);
|
||||
field::attribute( op, "group_object_filter", group_object_filter, 511 );
|
||||
field::attribute( op, "user_member_attribute", user_member_attribute, 511 );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,16 +6,19 @@
|
|||
#include "matador/utils/base_class.hpp"
|
||||
|
||||
namespace work::models::admin {
|
||||
struct LdapUserDirectory;
|
||||
|
||||
struct LdapImportSettings : core::Model {
|
||||
std::string default_role;
|
||||
unsigned int sync_interval;
|
||||
unsigned int network_timeout;
|
||||
matador::object::object_ptr<LdapUserDirectory> ldap_user_directory;
|
||||
|
||||
template<typename Operator>
|
||||
void process( Operator& op ) {
|
||||
namespace field = matador::access;
|
||||
field::process( op, *matador::base_class<Model>( this ) );
|
||||
field::has_one(op, "ldap_user_directory", ldap_user_directory, matador::utils::default_foreign_attributes);
|
||||
field::attribute( op, "default_role", default_role, 511 );
|
||||
field::attribute( op, "sync_interval", sync_interval );
|
||||
field::attribute( op, "network_timeout", network_timeout );
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
#ifndef LDAP_USER_DIRECTORY_HPP
|
||||
#define LDAP_USER_DIRECTORY_HPP
|
||||
|
||||
#include "LdapUserSchemaSettings.hpp"
|
||||
#include "LdapGroupSchemaSettings.hpp"
|
||||
#include "LdapImportSettings.hpp"
|
||||
#include "UserDirectory.hpp"
|
||||
|
||||
#include "matador/object/collection.hpp"
|
||||
|
|
@ -13,14 +16,24 @@ struct LdapUserDirectory : UserDirectory {
|
|||
std::string schema_base_dn;
|
||||
std::string additional_user_base_dn;
|
||||
std::string additional_group_base_dn;
|
||||
matador::object::object_ptr<LdapUserSchemaSettings> user_schema_settings;
|
||||
matador::object::object_ptr<LdapGroupSchemaSettings> group_schema_settings;
|
||||
matador::object::object_ptr<LdapImportSettings> import_settings;
|
||||
matador::object::collection<std::string> users;
|
||||
matador::object::collection<std::string> groups;
|
||||
|
||||
|
||||
template<typename Operator>
|
||||
void process( Operator& op ) {
|
||||
namespace field = matador::access;
|
||||
field::process( op, *matador::base_class<UserDirectory>( this ) );
|
||||
field::attribute( op, "schema_base_dn", schema_base_dn, 511 );
|
||||
field::attribute( op, "additional_user_base_dn", additional_user_base_dn, 511 );
|
||||
field::attribute( op, "additional_group_base_dn", additional_group_base_dn, 511 );
|
||||
field::belongs_to( op, "user_schema_settings", user_schema_settings, matador::utils::default_foreign_attributes );
|
||||
field::belongs_to( op, "group_schema_settings", group_schema_settings, matador::utils::default_foreign_attributes );
|
||||
field::belongs_to( op, "import_settings", import_settings, matador::utils::default_foreign_attributes );
|
||||
field::has_many( op, "ldap_users", users, "users_id", matador::utils::default_foreign_attributes );
|
||||
field::has_many( op, "ldap_groups", groups, "groups_id", matador::utils::default_foreign_attributes );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,22 +5,26 @@
|
|||
|
||||
#include "matador/utils/base_class.hpp"
|
||||
|
||||
|
||||
namespace work::models::admin {
|
||||
struct LdapUserDirectory;
|
||||
|
||||
struct LdapUserSchemaSettings : core::Model {
|
||||
std::string user_object_filter;
|
||||
std::string user_unique_id_attribute;
|
||||
std::string user_member_of_attribute;
|
||||
std::string user_name_attribute;
|
||||
matador::object::object_ptr<LdapUserDirectory> ldap_user_directory;
|
||||
|
||||
template<typename Operator>
|
||||
void process( Operator& op ) {
|
||||
namespace field = matador::access;
|
||||
field::process( op, *matador::base_class<Model>( this ) );
|
||||
field::attribute( op, "user_object_filter", user_object_filter, 511 );
|
||||
field::attribute( op, "user_unique_id_attribute", user_unique_id_attribute, 511 );
|
||||
field::attribute( op, "user_member_of_attribute", user_member_of_attribute, 511 );
|
||||
field::attribute( op, "user_name_attribute", user_name_attribute, 511 );
|
||||
field::process(op, *matador::base_class<Model>( this ));
|
||||
field::has_one(op, "ldap_user_directory", ldap_user_directory, matador::utils::default_foreign_attributes);
|
||||
field::attribute(op, "user_object_filter", user_object_filter, 511);
|
||||
field::attribute(op, "user_unique_id_attribute", user_unique_id_attribute, 511);
|
||||
field::attribute(op, "user_member_of_attribute", user_member_of_attribute, 511);
|
||||
field::attribute(op, "user_name_attribute", user_name_attribute, 511);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -16,24 +16,24 @@ namespace matador::net {
|
|||
*/
|
||||
class tcp {
|
||||
public:
|
||||
typedef peer_base<tcp> peer; /**< Shortcut to a tcp based peer */
|
||||
typedef socket_stream<tcp> socket; /**< Shortcut to a tcp based socket */
|
||||
typedef socket_acceptor<tcp> acceptor; /**< Shortcut to a tcp based acceptor */
|
||||
typedef address_resolver<tcp> resolver; /**< Shortcut to a tcp based address resolver */
|
||||
typedef peer_base<tcp> peer; /**< Shortcut to a tcp-based peer */
|
||||
typedef socket_stream<tcp> socket; /**< Shortcut to a tcp-based socket */
|
||||
typedef socket_acceptor<tcp> acceptor; /**< Shortcut to a tcp-based acceptor */
|
||||
typedef address_resolver<tcp> resolver; /**< Shortcut to a tcp-based address resolver */
|
||||
|
||||
/**
|
||||
* Returns the type of the socket
|
||||
*
|
||||
* @return Type of the socket
|
||||
*/
|
||||
int type() const { return SOCK_STREAM; }
|
||||
static int type() { return SOCK_STREAM; }
|
||||
|
||||
/**
|
||||
* Returns the socket protocol
|
||||
*
|
||||
* @return Socket protocol
|
||||
*/
|
||||
int protocol() const { return IPPROTO_TCP; }
|
||||
static int protocol() { return IPPROTO_TCP; }
|
||||
|
||||
/**
|
||||
* Returns the socket family
|
||||
|
|
@ -59,7 +59,7 @@ public:
|
|||
static tcp v6() { return tcp(PF_INET6); }
|
||||
|
||||
private:
|
||||
explicit tcp(int family)
|
||||
explicit tcp(const int family)
|
||||
: family_(family)
|
||||
{}
|
||||
|
||||
|
|
@ -74,24 +74,24 @@ private:
|
|||
class OOS_NET_API udp
|
||||
{
|
||||
public:
|
||||
typedef peer_base<udp> peer; /**< Shortcut to a udp based peer */
|
||||
typedef socket_stream<udp> socket; /**< Shortcut to a udp based socket */
|
||||
typedef socket_acceptor<udp> acceptor; /**< Shortcut to a udp based acceptor */
|
||||
typedef address_resolver<udp> resolver; /**< Shortcut to a udp based address resolver */
|
||||
typedef peer_base<udp> peer; /**< Shortcut to an udp-based peer */
|
||||
typedef socket_stream<udp> socket; /**< Shortcut to an udp-based socket */
|
||||
typedef socket_acceptor<udp> acceptor; /**< Shortcut to an udp-based acceptor */
|
||||
typedef address_resolver<udp> resolver; /**< Shortcut to an udp-based address resolver */
|
||||
|
||||
/**
|
||||
* Returns the type of the socket
|
||||
*
|
||||
* @return Type of the socket
|
||||
*/
|
||||
int type() const { return SOCK_DGRAM; }
|
||||
static int type() { return SOCK_DGRAM; }
|
||||
|
||||
/**
|
||||
* Returns the socket protocol
|
||||
*
|
||||
* @return Socket protocol
|
||||
*/
|
||||
int protocol() const { return IPPROTO_UDP; }
|
||||
static int protocol() { return IPPROTO_UDP; }
|
||||
|
||||
/**
|
||||
* Returns the socket family
|
||||
|
|
@ -117,7 +117,7 @@ public:
|
|||
static udp v6() { return udp(PF_INET6); }
|
||||
|
||||
private:
|
||||
explicit udp(int family)
|
||||
explicit udp(const int family)
|
||||
: family_(family)
|
||||
{}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include <cstring>
|
||||
|
||||
namespace matador {
|
||||
namespace matador::net {
|
||||
|
||||
/**
|
||||
* The peer_base class acts like the holder
|
||||
|
|
@ -25,7 +25,7 @@ template < class P >
|
|||
class peer_base
|
||||
{
|
||||
public:
|
||||
typedef P protocol_type; /**< Short to protocol type */
|
||||
typedef P protocol_type; /**< Short to a protocol-type */
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
|
|
@ -48,9 +48,8 @@ public:
|
|||
* @param addr Address to create the peer from
|
||||
* @param port Port of the endpoint
|
||||
*/
|
||||
peer_base(address addr, unsigned short port)
|
||||
: addr_(std::move(addr))
|
||||
{
|
||||
peer_base(address addr, const unsigned short port)
|
||||
: addr_(std::move(addr)) {
|
||||
addr_.port(port);
|
||||
}
|
||||
|
||||
|
|
@ -60,8 +59,7 @@ public:
|
|||
* @param x Peer to copy from
|
||||
*/
|
||||
peer_base(const peer_base &x)
|
||||
: addr_(x.addr_)
|
||||
{}
|
||||
: addr_(x.addr_) {}
|
||||
|
||||
/**
|
||||
* Move creates a peer from a given peer
|
||||
|
|
@ -69,8 +67,7 @@ public:
|
|||
* @param x Peer to move from
|
||||
*/
|
||||
peer_base(peer_base &&x) noexcept
|
||||
: addr_(std::move(x.addr_))
|
||||
{}
|
||||
: addr_(std::move(x.addr_)) {}
|
||||
|
||||
/**
|
||||
* Copy assigns a given peer to this peer
|
||||
|
|
@ -78,8 +75,7 @@ public:
|
|||
* @param x Peer to assign
|
||||
* @return The assigned peer
|
||||
*/
|
||||
peer_base& operator=(const peer_base &x)
|
||||
{
|
||||
peer_base& operator=(const peer_base &x) {
|
||||
addr_ = x.addr_;
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -90,8 +86,7 @@ public:
|
|||
* @param x The peer to move assign
|
||||
* @return The moved peer
|
||||
*/
|
||||
peer_base& operator=(peer_base &&x) noexcept
|
||||
{
|
||||
peer_base& operator=(peer_base &&x) noexcept {
|
||||
addr_ = std::move(x.addr_);
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -114,13 +109,8 @@ public:
|
|||
*
|
||||
* @return The current IP protocol
|
||||
*/
|
||||
protocol_type protocol() const
|
||||
{
|
||||
if (addr_.is_v4()) {
|
||||
return protocol_type::v4();
|
||||
} else {
|
||||
return protocol_type::v6();
|
||||
}
|
||||
protocol_type protocol() const {
|
||||
return addr_.is_v4() ? protocol_type::v4() : protocol_type::v6();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -128,8 +118,7 @@ public:
|
|||
*
|
||||
* @return The raw pointer to the sockaddr structure
|
||||
*/
|
||||
sockaddr* data()
|
||||
{
|
||||
sockaddr* data() {
|
||||
return addr_.addr();
|
||||
}
|
||||
|
||||
|
|
@ -138,8 +127,7 @@ public:
|
|||
*
|
||||
* @return The raw pointer to the sockaddr structure
|
||||
*/
|
||||
const sockaddr* data() const
|
||||
{
|
||||
const sockaddr* data() const {
|
||||
return addr_.addr();
|
||||
}
|
||||
|
||||
|
|
@ -148,8 +136,7 @@ public:
|
|||
*
|
||||
* @return The size of the underlying sockaddr structure
|
||||
*/
|
||||
size_t size() const
|
||||
{
|
||||
size_t size() const {
|
||||
return addr_.size();
|
||||
}
|
||||
|
||||
|
|
@ -158,8 +145,7 @@ public:
|
|||
*
|
||||
* @return A reference to the address
|
||||
*/
|
||||
address& addr()
|
||||
{
|
||||
address& addr() {
|
||||
return addr_;
|
||||
}
|
||||
|
||||
|
|
@ -168,8 +154,7 @@ public:
|
|||
*
|
||||
* @return A reference to the address
|
||||
*/
|
||||
const address& addr() const
|
||||
{
|
||||
const address& addr() const {
|
||||
return addr_;
|
||||
}
|
||||
|
||||
|
|
@ -179,20 +164,19 @@ public:
|
|||
*
|
||||
* @return Returns a string representation of the peer
|
||||
*/
|
||||
std::string to_string() const
|
||||
{
|
||||
char addstr[INET6_ADDRSTRLEN + 8];
|
||||
std::string to_string() const {
|
||||
char address_str[INET6_ADDRSTRLEN + 8];
|
||||
const char *name;
|
||||
if (addr().is_v4()) {
|
||||
name = os::inet_ntop(addr_.addr()->sa_family, &addr_.addr_v4()->sin_addr, addstr, INET6_ADDRSTRLEN);
|
||||
name = os::inet_ntop(addr_.addr()->sa_family, &addr_.addr_v4()->sin_addr, address_str, INET6_ADDRSTRLEN);
|
||||
} else {
|
||||
name = os::inet_ntop(addr_.addr()->sa_family, &addr_.addr_v6()->sin6_addr, addstr, INET6_ADDRSTRLEN);
|
||||
name = os::inet_ntop(addr_.addr()->sa_family, &addr_.addr_v6()->sin6_addr, address_str, INET6_ADDRSTRLEN);
|
||||
}
|
||||
|
||||
size_t pos = strlen(name);
|
||||
const size_t pos = strlen(name);
|
||||
|
||||
snprintf(addstr+pos, INET6_ADDRSTRLEN+8-pos, ":%d", addr_.port());
|
||||
return addstr;
|
||||
snprintf(address_str + pos, INET6_ADDRSTRLEN+8-pos, ":%d", addr_.port());
|
||||
return address_str;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <chrono>
|
||||
#include <queue>
|
||||
#include <list>
|
||||
#include <shared_mutex>
|
||||
|
||||
namespace matador::net {
|
||||
|
||||
|
|
@ -56,8 +57,8 @@ public:
|
|||
void run();
|
||||
void handle_events();
|
||||
void shutdown();
|
||||
bool is_running() const { return running_; }
|
||||
select_fdsets fdsets() const;
|
||||
[[nodiscard]] bool is_running() const { return running_; }
|
||||
select_fdsets fd_sets() const;
|
||||
void mark_handler_for_delete(const handler_ptr& h);
|
||||
void activate_handler(const handler_ptr& h, event_type ev);
|
||||
void deactivate_handler(const handler_ptr& h, event_type ev);
|
||||
|
|
@ -65,7 +66,7 @@ public:
|
|||
|
||||
private:
|
||||
struct TimerEvent {
|
||||
time_t timeout;
|
||||
time_t timeout{};
|
||||
handler_weak_ptr handler;
|
||||
|
||||
bool operator>(const TimerEvent& other) const {
|
||||
|
|
@ -89,7 +90,7 @@ private:
|
|||
|
||||
HandlerEntry* find_handler_entry(const handler_ptr& h);
|
||||
void remove_handler_entry(const handler_ptr& h);
|
||||
void update_handler_events(HandlerEntry* entry, event_type ev, bool activate);
|
||||
static void update_handler_events(HandlerEntry* entry, event_type ev, bool activate);
|
||||
|
||||
private:
|
||||
handler_map handlers_;
|
||||
|
|
@ -100,12 +101,13 @@ private:
|
|||
|
||||
mutable std::shared_mutex handlers_mutex_;
|
||||
std::mutex timers_mutex_;
|
||||
std::condition_variable shutdown_cv_;
|
||||
std::condition_variable_any shutdown_cv_;
|
||||
// std::condition_variable shutdown_cv_;
|
||||
|
||||
logger log_;
|
||||
logger::logger log_;
|
||||
Statistics stats_;
|
||||
|
||||
leader_follower_thread_pool thread_pool_;
|
||||
utils::leader_follower_thread_pool thread_pool_;
|
||||
socket_interrupter interrupter_;
|
||||
|
||||
static constexpr std::chrono::seconds CLEANUP_INTERVAL{60};
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "matador/net/fdset.hpp"
|
||||
|
||||
namespace matador {
|
||||
namespace matador::net {
|
||||
|
||||
/**
|
||||
* This class represents three fd sets
|
||||
|
|
|
|||
|
|
@ -25,8 +25,7 @@ namespace matador {
|
|||
* @tparam P Protocol type
|
||||
*/
|
||||
template < class P >
|
||||
class socket_base
|
||||
{
|
||||
class socket_base {
|
||||
public:
|
||||
typedef P protocol_type; /**< Shortcut to the protocol type */
|
||||
typedef typename P::peer peer_type; /**< Shortcut to the peer type */
|
||||
|
|
@ -42,7 +41,7 @@ public:
|
|||
/**
|
||||
* Creates a socket with the given peer
|
||||
*
|
||||
* @param peer Peer used to initialize the socket
|
||||
* @param peer Peer used to initialise the socket
|
||||
*/
|
||||
explicit socket_base(const peer_type &peer);
|
||||
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ socket_type connect(socket_stream<P> &stream, const char* hostname, unsigned sho
|
|||
do {
|
||||
conn_fd = ::socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||
if (!is_valid_socket(conn_fd)) {
|
||||
// error, try next one
|
||||
// error, try the next one
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -220,7 +220,7 @@ socket_type connect(socket_stream<P> &stream, const char* hostname, unsigned sho
|
|||
// throw_logic_error("couldn't execute: " << strerror(errno));
|
||||
}
|
||||
|
||||
// bind error, close and try next one
|
||||
// bind error, close and try the next one
|
||||
os::shutdown(conn_fd, os::shutdown_type::READ_WRITE);
|
||||
} while ( (res = res->ai_next) != nullptr);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "matador/net/ip.hpp"
|
||||
|
||||
// #include "matador/logger/logger.hpp"
|
||||
#include "matador/logger/logger.hpp"
|
||||
|
||||
#include <array>
|
||||
|
||||
|
|
@ -23,10 +23,10 @@ public:
|
|||
bool reset();
|
||||
|
||||
private:
|
||||
matador::tcp::socket server_;
|
||||
matador::tcp::socket client_;
|
||||
tcp::socket server_;
|
||||
tcp::socket client_;
|
||||
|
||||
// matador::logger log_;
|
||||
logger::logger log_;
|
||||
|
||||
std::array<char, 1> indicator_ = { { 0 } };
|
||||
std::array<char, 1> consumer_ = {};
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "matador/utils/data_type_traits.hpp"
|
||||
#include "matador/utils/error.hpp"
|
||||
#include "matador/utils/field_attributes.hpp"
|
||||
#include "matador/utils/primary_key_attribute.hpp"
|
||||
|
||||
|
||||
#include <memory>
|
||||
|
|
@ -29,10 +30,9 @@ public:
|
|||
}
|
||||
|
||||
template<typename ValueType>
|
||||
void on_primary_key(const char *, ValueType &/*pk*/, std::enable_if_t<std::is_integral_v<ValueType> && !std::is_same_v<bool, ValueType>>* = nullptr) {
|
||||
type_ = utils::data_type_traits<ValueType>::type(0);
|
||||
void on_primary_key(const char *, ValueType &/*pk*/, const utils::primary_key_attribute& attr = utils::default_pk_attributes) {
|
||||
type_ = utils::data_type_traits<ValueType>::type(attr.size());
|
||||
}
|
||||
void on_primary_key(const char * /*id*/, std::string &/*pk*/, size_t size);
|
||||
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
|
||||
template < class Type >
|
||||
static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
||||
|
|
@ -77,9 +77,8 @@ public:
|
|||
return columns;
|
||||
}
|
||||
|
||||
template < class V >
|
||||
void on_primary_key(const char *, V &x, std::enable_if_t<std::is_integral_v<V> && !std::is_same_v<bool, V>>* = nullptr);
|
||||
void on_primary_key(const char *id, std::string &pk, size_t size);
|
||||
template < class Type >
|
||||
void on_primary_key(const char *, Type &x, const utils::primary_key_attribute& attr = utils::default_pk_attributes);
|
||||
void on_revision(const char *id, uint64_t &rev);
|
||||
|
||||
template<typename Type>
|
||||
|
|
@ -94,7 +93,7 @@ public:
|
|||
}
|
||||
template<class Pointer>
|
||||
void on_has_one(const char *id, Pointer &x, const utils::foreign_attributes &/*attr*/) {
|
||||
on_foreign_key(id, x);
|
||||
// on_foreign_key(id, x);
|
||||
}
|
||||
|
||||
template <class Pointer>
|
||||
|
|
@ -133,10 +132,9 @@ private:
|
|||
fk_attribute_generator fk_column_generator_;
|
||||
};
|
||||
|
||||
template<typename V>
|
||||
void attribute_definition_generator::on_primary_key(const char *id, V &x, std::enable_if_t<std::is_integral_v<V> && !std::is_same_v<bool, V>>*)
|
||||
{
|
||||
on_attribute(id, x, { utils::constraints::PRIMARY_KEY });
|
||||
template<typename ValueType>
|
||||
void attribute_definition_generator::on_primary_key(const char *id, ValueType &x, const utils::primary_key_attribute& attr) {
|
||||
on_attribute(id, x, { attr.size(), utils::constraints::PRIMARY_KEY });
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
#include "matador/object/join_columns_collector.hpp"
|
||||
#include "matador/object/object_ptr.hpp"
|
||||
|
||||
#include "matador/utils/primary_key_attribute.hpp"
|
||||
|
||||
#include "matador/logger/log_manager.hpp"
|
||||
|
||||
#include <stack>
|
||||
|
|
@ -33,8 +35,7 @@ public:
|
|||
}
|
||||
|
||||
template<class PrimaryKeyType>
|
||||
static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, std::enable_if_t<std::is_integral_v<PrimaryKeyType> && !std::is_same_v<bool, PrimaryKeyType>> * = nullptr) {}
|
||||
static void on_primary_key(const char * /*id*/, std::string &/*pk*/, size_t /*size*/) {}
|
||||
static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {}
|
||||
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
|
||||
template<typename AttributeType>
|
||||
static void on_attribute(const char * /*id*/, AttributeType &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "matador/utils/access.hpp"
|
||||
#include "matador/utils/field_attributes.hpp"
|
||||
#include "matador/utils/primary_key_attribute.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
|
@ -24,8 +25,7 @@ public:
|
|||
return join_columns_;
|
||||
}
|
||||
template < class V >
|
||||
void on_primary_key(const char * /*id*/, V &, std::enable_if_t<std::is_integral_v<V> && !std::is_same_v<bool, V>>* = nullptr) {}
|
||||
static void on_primary_key(const char * /*id*/, std::string &, size_t) {}
|
||||
static void on_primary_key(const char * /*id*/, V &, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {}
|
||||
static void on_revision(const char * /*id*/, unsigned long long &/*rev*/) {}
|
||||
template<typename Type>
|
||||
static void on_attribute(const char * /*id*/, Type &, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "matador/utils/field_attributes.hpp"
|
||||
#include "matador/utils/foreign_attributes.hpp"
|
||||
#include "matador/utils/identifier.hpp"
|
||||
#include "matador/utils/primary_key_attribute.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
|
@ -42,14 +43,12 @@ public:
|
|||
}
|
||||
|
||||
template < class Type >
|
||||
void on_primary_key(const char *id, Type &pk, std::enable_if_t<std::is_integral_v<Type> && !std::is_same_v<bool, Type>>* = nullptr) {
|
||||
void on_primary_key(const char *id, Type &pk, const utils::primary_key_attribute& attr = utils::default_pk_attributes) {
|
||||
primary_key_info_.pk_column_name = id;
|
||||
primary_key_info_.type = utils::data_type_traits<Type>::type();
|
||||
primary_key_info_.type = utils::data_type_traits<Type>::type(attr.size());
|
||||
primary_key_info_.pk = pk;
|
||||
}
|
||||
|
||||
void on_primary_key(const char *id, const std::string &pk, size_t size);
|
||||
|
||||
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
|
||||
template<typename Type>
|
||||
static void on_attribute(const char * /*id*/, Type &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#include "matador/logger/log_manager.hpp"
|
||||
|
||||
#include "matador/utils/primary_key_attribute.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <stack>
|
||||
#include <utility>
|
||||
|
|
@ -27,8 +29,7 @@ public:
|
|||
}
|
||||
|
||||
template<class PrimaryKeyType>
|
||||
static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, std::enable_if_t<std::is_integral_v<PrimaryKeyType> && !std::is_same_v<bool, PrimaryKeyType>> * = nullptr) {}
|
||||
static void on_primary_key(const char * /*id*/, std::string &/*pk*/, size_t /*size*/) {}
|
||||
static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {}
|
||||
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
|
||||
template<typename AttributeType>
|
||||
static void on_attribute(const char * /*id*/, AttributeType &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
||||
|
|
@ -106,8 +107,7 @@ public:
|
|||
}
|
||||
|
||||
template<class PrimaryKeyType>
|
||||
static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, std::enable_if_t<std::is_integral_v<PrimaryKeyType> && !std::is_same_v<bool, PrimaryKeyType>> * = nullptr) {}
|
||||
static void on_primary_key(const char * /*id*/, std::string &/*pk*/, size_t /*size*/) {}
|
||||
static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {}
|
||||
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
|
||||
template<typename AttributeType>
|
||||
static void on_attribute(const char * /*id*/, AttributeType &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
||||
|
|
@ -155,18 +155,6 @@ private:
|
|||
join_columns_collector join_columns_collector_{};
|
||||
};
|
||||
|
||||
inline void dump(std::ostream &os, const std::shared_ptr<schema_node> &node) {
|
||||
os << "node [" << node->name() << "] (" /*<< node->type_index().name()*/ << ")\n";
|
||||
for (auto it = node->info().endpoint_begin(); it != node->info().endpoint_end(); ++it) {
|
||||
os << " " << node->name() << "::" << it->second->field_name() << " (" << it->second->type_name() << ")";
|
||||
if (it->second->foreign_endpoint()) {
|
||||
os << " <---> " << it->second->node().name() << "::" << it->second->foreign_endpoint()->field_name() << " (" << it->second->foreign_endpoint()->type_name() << ")\n";
|
||||
} else {
|
||||
os << " -> " << it->second->node().type_index().name() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
template<typename Type>
|
||||
template<class CollectionType>
|
||||
void relation_completer<Type>::on_has_many(const char *id, CollectionType &,
|
||||
|
|
@ -199,7 +187,6 @@ void relation_completer<Type>::on_has_many(const char *id, CollectionType &,
|
|||
nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
|
||||
} else {
|
||||
// A relation table is necessary
|
||||
// } else if (const auto endpoint = nodes_.top()->info().find_relation_endpoint(typeid(relation_value_type)); endpoint == nodes_.top()->info().endpoint_end()) {
|
||||
// Endpoint was not found.
|
||||
// Always attach a many-to-many relation type. If later a
|
||||
// belongs-to relation handles this relation, the many-to-many
|
||||
|
|
@ -221,77 +208,7 @@ void relation_completer<Type>::on_has_many(const char *id, CollectionType &,
|
|||
|
||||
const auto foreign_value_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BELONGS_TO, foreign_node);
|
||||
result.value()->info_->register_relation_endpoint(typeid(value_type), foreign_value_endpoint);
|
||||
|
||||
// dump( std::cout, nodes_.top() );
|
||||
// dump( std::cout, result.value() );
|
||||
// if (const auto detach_result = schema_.detach_node(foreign_node); !detach_result) {
|
||||
// // Todo: throw internal error
|
||||
// return;
|
||||
// }
|
||||
}
|
||||
// } else {
|
||||
// if (const auto rit = foreign_node->info_->find_relation_endpoint(nodes_.top()->type_index());
|
||||
// rit != foreign_node->info().endpoint_end()) {
|
||||
// if (rit->second->is_belongs_to()) {
|
||||
// rit->second->node_ = foreign_node;
|
||||
// const auto localEndpoint = std::make_shared<relation_endpoint>(id, relation_type::HAS_MANY, nodes_.top());
|
||||
// nodes_.top()->info_->register_relation_endpoint(nodes_.top()->type_index(), localEndpoint);
|
||||
// link_relation_endpoints(localEndpoint, rit->second);
|
||||
// } else {
|
||||
// // Todo: throw internal error relation node has invalid type
|
||||
// }
|
||||
// } else {
|
||||
// // Todo: throw internal error couldn't find relation node
|
||||
// }
|
||||
// }
|
||||
|
||||
// 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::HAS_MANY, result.value());
|
||||
// local_it = nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
|
||||
// }
|
||||
// auto foreign_it = result.value()->info().find_relation_endpoint(typeid(value_type));
|
||||
// if (foreign_it == result.value()->info().endpoint_end()) {
|
||||
// const auto foreign_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BELONGS_TO, nodes_.top());
|
||||
// foreign_it = result.value()->info_->register_relation_endpoint(typeid(Type), foreign_endpoint);
|
||||
// }
|
||||
// link_relation_endpoints(local_it->second, foreign_it->second);
|
||||
|
||||
/*
|
||||
if (const auto endpoint = nodes_.top()->info().find_relation_endpoint(typeid(relation_value_type)); endpoint == nodes_.top()->info().endpoint_end()) {
|
||||
// Endpoint was not found
|
||||
log_.debug("node '%s' has has many foreign keys '%s' mapped by '%s'", nodes_.top()->name().c_str(), id, join_column);
|
||||
result = schema_node::make_relation_node<relation_value_type>(
|
||||
schema_.schema(), id, [join_column] {
|
||||
return std::make_unique<relation_value_type>("id", join_column);
|
||||
});
|
||||
if (!result) {
|
||||
// Todo: throw internal error
|
||||
return;
|
||||
}
|
||||
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HAS_MANY, nodes_.top());
|
||||
const auto foreign_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BELONGS_TO, result.value());
|
||||
nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
|
||||
foreign_endpoint->node_->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint);
|
||||
link_relation_endpoints(local_endpoint, foreign_endpoint);
|
||||
} else {
|
||||
const auto &foreign_node = result.value();
|
||||
if (const auto rit = foreign_node->info_->find_relation_endpoint(nodes_.top()->type_index());
|
||||
rit != foreign_node->info().endpoint_end()) {
|
||||
if (rit->second->is_belongs_to()) {
|
||||
rit->second->node_ = foreign_node;
|
||||
const auto localEndpoint = std::make_shared<relation_endpoint>(id, relation_type::HAS_MANY, nodes_.top());
|
||||
nodes_.top()->info_->register_relation_endpoint(nodes_.top()->type_index(), localEndpoint);
|
||||
link_relation_endpoints(localEndpoint, rit->second);
|
||||
} else {
|
||||
// Todo: throw internal error relation node has invalid type
|
||||
}
|
||||
} else {
|
||||
// Todo: throw internal error couldn't find relation node
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
|
|
@ -310,10 +227,9 @@ void relation_completer<Type>::on_has_many(const char *id, CollectionType &, con
|
|||
|
||||
if (!result) {
|
||||
// Todo: throw internal exception
|
||||
return;
|
||||
}
|
||||
|
||||
// const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HAS_MANY, nodes_.top());
|
||||
// const auto foreign_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BELONGS_TO, result.value());
|
||||
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HAS_MANY, result.value());
|
||||
const auto foreign_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BELONGS_TO, nodes_.top());
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include "matador/object/schema.hpp"
|
||||
|
||||
#include "matador/utils/cascade_type.hpp"
|
||||
#include "matador/utils/primary_key_attribute.hpp"
|
||||
|
||||
namespace matador::orm {
|
||||
struct entity_insert_data {
|
||||
|
|
@ -62,11 +63,10 @@ public:
|
|||
}
|
||||
|
||||
template<class V>
|
||||
void on_primary_key(const char *id, V &x, std::enable_if_t<std::is_integral_v<V> && !std::is_same_v<bool, V>> * = nullptr) {
|
||||
void on_primary_key(const char *id, V &x, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {
|
||||
push(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>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "matador/object/join_columns_collector.hpp"
|
||||
#include "matador/object/schema.hpp"
|
||||
|
||||
#include "matador/utils/primary_key_attribute.hpp"
|
||||
#include "matador/utils/result.hpp"
|
||||
#include "matador/utils/value.hpp"
|
||||
|
||||
|
|
@ -76,7 +77,7 @@ public:
|
|||
}
|
||||
|
||||
template < class V >
|
||||
void on_primary_key(const char *id, V &, std::enable_if_t<std::is_integral_v<V> && !std::is_same_v<bool, V>>* = nullptr)
|
||||
void on_primary_key(const char *id, V &, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes)
|
||||
{
|
||||
push(id);
|
||||
if (!is_root_entity()) {
|
||||
|
|
@ -90,10 +91,11 @@ public:
|
|||
auto co = std::make_unique<query::condition<sql::column, V>>(c, query::basic_condition::operand_type::EQUAL, v);
|
||||
entity_query_data_.where_clause = std::move(co);
|
||||
entity_query_data_.pk_column_name = id;
|
||||
} else if (pk_.is_varchar()) {
|
||||
// Todo: handle varchar primary key
|
||||
}
|
||||
}
|
||||
|
||||
void on_primary_key(const char *id, std::string &, size_t);
|
||||
void on_revision(const char *id, unsigned long long &/*rev*/);
|
||||
|
||||
template<typename Type>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "matador/utils/access.hpp"
|
||||
#include "matador/utils/field_attributes.hpp"
|
||||
#include "matador/utils/foreign_attributes.hpp"
|
||||
#include "matador/utils/primary_key_attribute.hpp"
|
||||
#include "matador/utils/types.hpp"
|
||||
|
||||
namespace matador::query::detail {
|
||||
|
|
@ -21,26 +22,23 @@ public:
|
|||
}
|
||||
|
||||
template<typename ValueType>
|
||||
void on_primary_key(const char *, ValueType &pk, std::enable_if_t<std::is_integral_v<ValueType> && !std::is_same_v<bool, ValueType>>* = nullptr)
|
||||
{
|
||||
void on_primary_key(const char *, ValueType &pk, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {
|
||||
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*/) {}
|
||||
static 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) {}
|
||||
static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
||||
static void on_attribute(const char * /*id*/, char * /*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
||||
template<class Pointer>
|
||||
void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
|
||||
static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
|
||||
template<class Pointer>
|
||||
void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
|
||||
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
|
||||
template<class ContainerType>
|
||||
void on_has_many_to_many(const char *, ContainerType &, const char * /*join_column*/, const char * /*inverse_join_column*/, const utils::foreign_attributes &/*attr*/) {}
|
||||
static void on_has_many_to_many(const char *, ContainerType &, const char * /*join_column*/, const char * /*inverse_join_column*/, const utils::foreign_attributes &/*attr*/) {}
|
||||
template<class ContainerType>
|
||||
void on_has_many_to_many(const char *, ContainerType &, const utils::foreign_attributes &/*attr*/) {}
|
||||
static void on_has_many_to_many(const char *, ContainerType &, const utils::foreign_attributes &/*attr*/) {}
|
||||
template<class ContainerType>
|
||||
void on_has_many(const char *, ContainerType &, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {}
|
||||
|
||||
static void on_has_many(const char *, ContainerType &, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {}
|
||||
|
||||
private:
|
||||
utils::database_type value_{};
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "matador/query/internal/key_value_pair.hpp"
|
||||
|
||||
#include "matador/utils/foreign_attributes.hpp"
|
||||
#include "matador/utils/primary_key_attribute.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -28,11 +29,9 @@ public:
|
|||
}
|
||||
|
||||
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)
|
||||
{
|
||||
void on_primary_key(const char *id, V &x, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {
|
||||
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>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "matador/utils/attribute_writer.hpp"
|
||||
#include "matador/utils/default_type_traits.hpp"
|
||||
#include "matador/utils/primary_key_attribute.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -25,11 +26,9 @@ public:
|
|||
}
|
||||
|
||||
template<typename ValueType>
|
||||
void on_primary_key(const char *, ValueType &x, std::enable_if_t<std::is_integral_v<ValueType> && !std::is_same_v<bool, ValueType>>* = nullptr)
|
||||
{
|
||||
utils::data_type_traits<ValueType>::bind_value(*this, 0, x);
|
||||
void on_primary_key(const char *, ValueType &x, const utils::primary_key_attribute& attr = utils::default_pk_attributes) {
|
||||
utils::data_type_traits<ValueType>::bind_value(*this, 0, x, attr.size());
|
||||
}
|
||||
void on_primary_key(const char *id, std::string &pk, size_t size);
|
||||
void on_revision(const char *id, uint64_t &rev);
|
||||
template < class Type >
|
||||
void on_attribute(const char *, Type &x, const utils::field_attributes &/*attr*/ = utils::null_attributes) {
|
||||
|
|
@ -48,17 +47,17 @@ public:
|
|||
values_.emplace_back(fk_value_extractor_.extract(*x));
|
||||
}
|
||||
template<class ContainerType>
|
||||
void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {}
|
||||
static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {}
|
||||
template<class ContainerType>
|
||||
void on_has_many_to_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const char * /*join_column*/,
|
||||
const char * /*inverse_join_column*/,
|
||||
const utils::foreign_attributes &/*attr*/) {}
|
||||
static void on_has_many_to_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const char * /*join_column*/,
|
||||
const char * /*inverse_join_column*/,
|
||||
const utils::foreign_attributes &/*attr*/) {}
|
||||
template<class ContainerType>
|
||||
void on_has_many_to_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const utils::foreign_attributes &/*attr*/) {}
|
||||
static void on_has_many_to_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const utils::foreign_attributes &/*attr*/) {}
|
||||
|
||||
public:
|
||||
void write_value(size_t pos, const int8_t &x) override;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "matador/utils/access.hpp"
|
||||
#include "matador/utils/field_attributes.hpp"
|
||||
#include "matador/utils/foreign_attributes.hpp"
|
||||
#include "matador/utils/primary_key_attribute.hpp"
|
||||
|
||||
#include "matador/sql/column.hpp"
|
||||
|
||||
|
|
@ -52,13 +53,12 @@ public:
|
|||
}
|
||||
|
||||
template < class V >
|
||||
void on_primary_key(const char *id, V &, std::enable_if_t<std::is_integral_v<V> && !std::is_same_v<bool, V>>* = nullptr) {
|
||||
void on_primary_key(const char *id, V &, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {
|
||||
if (has_many_to_many_) {
|
||||
return;
|
||||
}
|
||||
push(id);
|
||||
}
|
||||
void on_primary_key(const char *id, std::string &, size_t);
|
||||
void on_revision(const char *id, unsigned long long &/*rev*/);
|
||||
|
||||
template<typename Type>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "matador/utils/access.hpp"
|
||||
#include "matador/utils/field_attributes.hpp"
|
||||
#include "matador/utils/foreign_attributes.hpp"
|
||||
#include "matador/utils/primary_key_attribute.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
|
|
@ -27,32 +28,31 @@ public:
|
|||
}
|
||||
|
||||
template<typename ValueType>
|
||||
void on_primary_key(const char *id, ValueType &value, std::enable_if_t<std::is_integral_v<ValueType> && !std::is_same_v<bool, ValueType>>* = nullptr);
|
||||
void on_primary_key(const char *id, std::string &value, size_t size);
|
||||
void on_revision(const char * /*id*/, unsigned long long &/*rev*/) {}
|
||||
void on_primary_key(const char *id, ValueType &value, const utils::primary_key_attribute& attr = utils::default_pk_attributes);
|
||||
static 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) {}
|
||||
static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
||||
template < class Pointer >
|
||||
void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
|
||||
static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
|
||||
template < class Pointer >
|
||||
void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
|
||||
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
|
||||
|
||||
template<class ContainerType>
|
||||
void on_has_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const char * /*join_column*/,
|
||||
const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
|
||||
static void on_has_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const char * /*join_column*/,
|
||||
const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
|
||||
template<class ContainerType>
|
||||
void on_has_many_to_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const char * /*join_column*/,
|
||||
const char * /*inverse_join_column*/,
|
||||
const utils::foreign_attributes &/*attr*/) {}
|
||||
static void on_has_many_to_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const char * /*join_column*/,
|
||||
const char * /*inverse_join_column*/,
|
||||
const utils::foreign_attributes &/*attr*/) {}
|
||||
template<class ContainerType>
|
||||
void on_has_many_to_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const utils::foreign_attributes &/*attr*/) {}
|
||||
static void on_has_many_to_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const utils::foreign_attributes &/*attr*/) {}
|
||||
|
||||
private:
|
||||
utils::attribute_reader *binder_{};
|
||||
|
|
@ -74,16 +74,13 @@ public:
|
|||
void reset();
|
||||
|
||||
template < class Type >
|
||||
void on_primary_key(const char *id, Type &val, std::enable_if_t<std::is_integral_v<Type> && !std::is_same_v<bool, Type>>* = nullptr)
|
||||
{
|
||||
utils::data_type_traits<Type>::read_value(*binder_, id, index_++, val);
|
||||
void on_primary_key(const char *id, Type &val, const utils::primary_key_attribute& attr = utils::default_pk_attributes) {
|
||||
utils::data_type_traits<Type>::read_value(*binder_, id, index_++, val, attr.size());
|
||||
}
|
||||
void on_primary_key(const char *id, std::string &, size_t size);
|
||||
void on_revision(const char *id, uint64_t &/*rev*/);
|
||||
|
||||
template<typename Type>
|
||||
void on_attribute(const char *id, Type &val, const utils::field_attributes &/*attr*/ = utils::null_attributes)
|
||||
{
|
||||
void on_attribute(const char *id, Type &val, const utils::field_attributes &/*attr*/ = utils::null_attributes) {
|
||||
utils::data_type_traits<Type>::read_value(*binder_, id, index_++, val);
|
||||
}
|
||||
void on_attribute(const char *id, char *value, const utils::field_attributes &attr = utils::null_attributes);
|
||||
|
|
@ -91,30 +88,28 @@ public:
|
|||
void on_attribute(const char *id, utils::value &val, const utils::field_attributes &attr = utils::null_attributes);
|
||||
|
||||
template<class Type, template < class ... > class Pointer>
|
||||
void on_belongs_to(const char *id, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes)
|
||||
{
|
||||
void on_belongs_to(const char *id, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {
|
||||
fk_result_binder_.bind(*x, id, index_++, *binder_);
|
||||
}
|
||||
template<class Type, template < class ... > class Pointer>
|
||||
void on_has_one(const char *id, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes)
|
||||
{
|
||||
void on_has_one(const char *id, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {
|
||||
fk_result_binder_.bind(*x, id, index_++, *binder_);
|
||||
}
|
||||
template<class ContainerType>
|
||||
void on_has_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const char * /*join_column*/,
|
||||
const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
|
||||
static void on_has_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const char * /*join_column*/,
|
||||
const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
|
||||
template<class ContainerType>
|
||||
void on_has_many_to_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const char * /*join_column*/,
|
||||
const char * /*inverse_join_column*/,
|
||||
const utils::foreign_attributes &/*attr*/) {}
|
||||
static void on_has_many_to_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const char * /*join_column*/,
|
||||
const char * /*inverse_join_column*/,
|
||||
const utils::foreign_attributes &/*attr*/) {}
|
||||
template<class ContainerType>
|
||||
void on_has_many_to_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const utils::foreign_attributes &/*attr*/) {}
|
||||
static void on_has_many_to_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const utils::foreign_attributes &/*attr*/) {}
|
||||
|
||||
private:
|
||||
utils::attribute_reader *binder_{};
|
||||
|
|
@ -125,9 +120,8 @@ private:
|
|||
namespace detail {
|
||||
|
||||
template<typename ValueType>
|
||||
void fk_result_binder::on_primary_key(const char * /*id*/, ValueType &value, std::enable_if_t<std::is_integral_v<ValueType> && !std::is_same_v<bool, ValueType>> *)
|
||||
{
|
||||
utils::data_type_traits<ValueType>::read_value(*binder_, id_, index_++, value);
|
||||
void fk_result_binder::on_primary_key(const char * /*id*/, ValueType &value, const utils::primary_key_attribute& attr) {
|
||||
utils::data_type_traits<ValueType>::read_value(*binder_, id_, index_++, value, attr.size());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include "matador/utils/foreign_attributes.hpp"
|
||||
#include "matador/utils/default_type_traits.hpp"
|
||||
#include "matador/utils/identifier.hpp"
|
||||
#include "matador/utils/primary_key_attribute.hpp"
|
||||
|
||||
#include "matador/sql/interface/query_result_reader.hpp"
|
||||
#include "matador/sql/internal/query_result_pk_resolver.hpp"
|
||||
|
|
@ -37,9 +38,7 @@ public:
|
|||
}
|
||||
|
||||
template<typename ValueType>
|
||||
void on_primary_key(const char *id, ValueType &value,
|
||||
std::enable_if_t<std::is_integral_v<ValueType> && !std::is_same_v<bool, ValueType>> * = nullptr);
|
||||
void on_primary_key(const char *id, std::string &value, size_t size);
|
||||
void on_primary_key(const char *id, ValueType &value, const utils::primary_key_attribute& attr = utils::default_pk_attributes);
|
||||
void on_revision(const char * /*id*/, unsigned long long &/*rev*/) { ++column_index_; }
|
||||
|
||||
template<class Type>
|
||||
|
|
@ -52,21 +51,20 @@ public:
|
|||
}
|
||||
|
||||
template<class Pointer>
|
||||
void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) { ++column_index_; }
|
||||
|
||||
template<class ContainerType>
|
||||
void on_has_many(const char * /*id*/, ContainerType &, const char * /*join_column*/,
|
||||
const utils::foreign_attributes &/*attr*/) {
|
||||
void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {
|
||||
++column_index_;
|
||||
}
|
||||
|
||||
template<class ContainerType>
|
||||
void on_has_many_to_many(const char *id, ContainerType &c, const char * /*join_column*/,
|
||||
const char * /*inverse_join_column*/, const utils::foreign_attributes &/*attr*/) {
|
||||
}
|
||||
static void on_has_many(const char * /*id*/, ContainerType &, const char * /*join_column*/,
|
||||
const utils::foreign_attributes &/*attr*/) {}
|
||||
|
||||
template<class ContainerType>
|
||||
void on_has_many_to_many(const char *id, ContainerType &c, const utils::foreign_attributes &/*attr*/) {
|
||||
}
|
||||
static void on_has_many_to_many(const char *id, ContainerType &c, const char * /*join_column*/,
|
||||
const char * /*inverse_join_column*/, const utils::foreign_attributes &/*attr*/) {}
|
||||
|
||||
template<class ContainerType>
|
||||
static void on_has_many_to_many(const char *id, ContainerType &c, const utils::foreign_attributes &/*attr*/) {}
|
||||
|
||||
private:
|
||||
size_t column_index_{};
|
||||
|
|
@ -82,16 +80,14 @@ public:
|
|||
const std::vector<object::attribute_definition> &prototype, size_t column_index = 0);
|
||||
|
||||
template<typename ValueType>
|
||||
void on_primary_key(const char *id, ValueType &value,
|
||||
std::enable_if_t<std::is_integral_v<ValueType> && !std::is_same_v<bool, ValueType>> * = nullptr) {
|
||||
utils::data_type_traits<ValueType>::read_value(*reader_, id, column_index_++, value);
|
||||
void on_primary_key(const char *id, ValueType &value, const utils::primary_key_attribute& attr = utils::default_pk_attributes) {
|
||||
utils::data_type_traits<ValueType>::read_value(*reader_, id, column_index_++, value, attr.size());
|
||||
if (type_stack_.size() == 1) {
|
||||
last_pk_ = current_pk_;
|
||||
current_pk_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
void on_primary_key(const char *id, std::string &value, size_t size);
|
||||
void on_revision(const char *id, uint64_t &rev);
|
||||
|
||||
template<class Type>
|
||||
|
|
@ -228,9 +224,8 @@ protected:
|
|||
|
||||
namespace detail {
|
||||
template<typename ValueType>
|
||||
void pk_reader::on_primary_key(const char *id, ValueType &value,
|
||||
std::enable_if_t<std::is_integral_v<ValueType> && !std::is_same_v<bool, ValueType>> *) {
|
||||
utils::data_type_traits<ValueType>::read_value(reader_, id, column_index_++, value);
|
||||
void pk_reader::on_primary_key(const char *id, ValueType &value, const utils::primary_key_attribute& attr) {
|
||||
utils::data_type_traits<ValueType>::read_value(reader_, id, column_index_++, value, attr.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "matador/utils/field_attributes.hpp"
|
||||
#include "matador/utils/foreign_attributes.hpp"
|
||||
#include "matador/utils/identifier.hpp"
|
||||
#include "matador/utils/primary_key_attribute.hpp"
|
||||
|
||||
#include "matador/sql/interface/query_result_reader.hpp"
|
||||
|
||||
|
|
@ -27,15 +28,14 @@ public:
|
|||
}
|
||||
|
||||
template<typename ValueType>
|
||||
void on_primary_key(const char *id, ValueType &/*value*/, std::enable_if_t<std::is_integral_v<ValueType> && !std::is_same_v<bool, ValueType>>* = nullptr) {
|
||||
void on_primary_key(const char *id, ValueType &/*value*/, const utils::primary_key_attribute& attr = utils::default_pk_attributes) {
|
||||
if (!type_stack_.empty()) {
|
||||
return;
|
||||
}
|
||||
ValueType value;
|
||||
utils::data_type_traits<ValueType>::read_value(reader_, id, column_index_++, value);
|
||||
utils::data_type_traits<ValueType>::read_value(reader_, id, column_index_++, value, attr.size());
|
||||
pk_ = value;
|
||||
}
|
||||
void on_primary_key(const char *id, std::string &value, size_t size);
|
||||
void on_revision(const char * /*id*/, unsigned long long &/*rev*/) { ++column_index_; }
|
||||
|
||||
template < class Type >
|
||||
|
|
@ -48,11 +48,11 @@ public:
|
|||
void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &attr) { on_foreign_key<typename Pointer::value_type>(attr.fetch() ); }
|
||||
|
||||
template<class ContainerType>
|
||||
void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {}
|
||||
static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {}
|
||||
template<class ContainerType>
|
||||
void on_has_many_to_many(const char *id, ContainerType &c, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &/*attr*/) {}
|
||||
static void on_has_many_to_many(const char *id, ContainerType &c, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &/*attr*/) {}
|
||||
template<class ContainerType>
|
||||
void on_has_many_to_many(const char *id, ContainerType &c, const utils::foreign_attributes &/*attr*/) {}
|
||||
static void on_has_many_to_many(const char *id, ContainerType &c, const utils::foreign_attributes &/*attr*/) {}
|
||||
|
||||
private:
|
||||
template<class Type>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "matador/utils/access.hpp"
|
||||
#include "matador/utils/field_attributes.hpp"
|
||||
#include "matador/utils/foreign_attributes.hpp"
|
||||
#include "matador/utils/primary_key_attribute.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
|
@ -27,32 +28,31 @@ public:
|
|||
}
|
||||
|
||||
template<typename ValueType>
|
||||
void on_primary_key(const char *id, ValueType &value, std::enable_if_t<std::is_integral_v<ValueType> && !std::is_same_v<bool, ValueType>>* = nullptr);
|
||||
void on_primary_key(const char *id, std::string &value, size_t size);
|
||||
void on_revision(const char * /*id*/, unsigned long long &/*rev*/) {}
|
||||
void on_primary_key(const char *id, ValueType &value, const utils::primary_key_attribute& attr = utils::default_pk_attributes);
|
||||
static 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) {}
|
||||
static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
||||
template < class Pointer >
|
||||
void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
|
||||
static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
|
||||
template < class Pointer >
|
||||
void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
|
||||
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
|
||||
|
||||
template<class ContainerType>
|
||||
void on_has_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const char * /*join_column*/,
|
||||
const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
|
||||
static void on_has_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const char * /*join_column*/,
|
||||
const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
|
||||
template<class ContainerType>
|
||||
void on_has_many_to_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const char * /*join_column*/,
|
||||
const char * /*inverse_join_column*/,
|
||||
const utils::foreign_attributes &/*attr*/) {}
|
||||
static void on_has_many_to_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const char * /*join_column*/,
|
||||
const char * /*inverse_join_column*/,
|
||||
const utils::foreign_attributes &/*attr*/) {}
|
||||
template<class ContainerType>
|
||||
void on_has_many_to_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const utils::foreign_attributes &/*attr*/) {}
|
||||
static void on_has_many_to_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const utils::foreign_attributes &/*attr*/) {}
|
||||
|
||||
private:
|
||||
utils::attribute_writer *binder_{};
|
||||
|
|
@ -74,44 +74,39 @@ public:
|
|||
void reset(size_t start_index);
|
||||
|
||||
template < class Type >
|
||||
void on_primary_key(const char * /*id*/, Type &val, std::enable_if_t<std::is_integral_v<Type> && !std::is_same_v<bool, Type>>* = nullptr)
|
||||
{
|
||||
utils::data_type_traits<Type>::bind_value(*binder_, index_++, val);
|
||||
void on_primary_key(const char * /*id*/, Type &val, const utils::primary_key_attribute& attr = utils::default_pk_attributes) {
|
||||
utils::data_type_traits<Type>::bind_value(*binder_, index_++, val, attr.size());
|
||||
}
|
||||
void on_primary_key(const char *id, std::string &, size_t size);
|
||||
void on_revision(const char *id, uint64_t &/*rev*/);
|
||||
|
||||
template<typename Type>
|
||||
void on_attribute(const char * /*id*/, Type &val, const utils::field_attributes &/*attr*/ = utils::null_attributes)
|
||||
{
|
||||
void on_attribute(const char * /*id*/, Type &val, const utils::field_attributes &/*attr*/ = utils::null_attributes) {
|
||||
utils::data_type_traits<Type>::bind_value(*binder_, index_++, val);
|
||||
}
|
||||
|
||||
template<class Type, template < class ... > class Pointer>
|
||||
void on_belongs_to(const char * /*id*/, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes)
|
||||
{
|
||||
void on_belongs_to(const char * /*id*/, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {
|
||||
fk_binder_.bind(*x, index_++, *binder_);
|
||||
}
|
||||
template<class Type, template < class ... > class Pointer>
|
||||
void on_has_one(const char * /*id*/, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes)
|
||||
{
|
||||
void on_has_one(const char * /*id*/, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {
|
||||
fk_binder_.bind(*x, index_++, *binder_);
|
||||
}
|
||||
template<class ContainerType>
|
||||
void on_has_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const char * /*join_column*/,
|
||||
const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
|
||||
static void on_has_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const char * /*join_column*/,
|
||||
const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
|
||||
template<class ContainerType>
|
||||
void on_has_many_to_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const char * /*join_column*/,
|
||||
const char * /*inverse_join_column*/,
|
||||
const utils::foreign_attributes &/*attr*/) {}
|
||||
static void on_has_many_to_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const char * /*join_column*/,
|
||||
const char * /*inverse_join_column*/,
|
||||
const utils::foreign_attributes &/*attr*/) {}
|
||||
template<class ContainerType>
|
||||
void on_has_many_to_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const utils::foreign_attributes &/*attr*/) {}
|
||||
static void on_has_many_to_many(const char * /*id*/,
|
||||
ContainerType &/*c*/,
|
||||
const utils::foreign_attributes &/*attr*/) {}
|
||||
|
||||
private:
|
||||
utils::attribute_writer *binder_{};
|
||||
|
|
@ -122,9 +117,8 @@ private:
|
|||
namespace detail {
|
||||
|
||||
template<typename ValueType>
|
||||
void fk_binder::on_primary_key(const char * /*id*/, ValueType &value, std::enable_if_t<std::is_integral_v<ValueType> && !std::is_same_v<bool, ValueType>> *)
|
||||
{
|
||||
utils::data_type_traits<ValueType>::bind_value(*binder_, index_++, value);
|
||||
void fk_binder::on_primary_key(const char * /*id*/, ValueType &value, const utils::primary_key_attribute& attr) {
|
||||
utils::data_type_traits<ValueType>::bind_value(*binder_, index_++, value, attr.size());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ class container;
|
|||
namespace utils {
|
||||
class field_attributes;
|
||||
class foreign_attributes;
|
||||
class primary_key_attribute;
|
||||
}
|
||||
|
||||
namespace access {
|
||||
|
|
@ -29,13 +30,13 @@ void process(Operator &op, const Type &object) {
|
|||
}
|
||||
|
||||
template< class Operator, class Type >
|
||||
void primary_key(Operator &op, const char *id, Type &value) {
|
||||
op.on_primary_key(id, value);
|
||||
void primary_key(Operator &op, const char *id, Type &value, const utils::primary_key_attribute &attr) {
|
||||
op.on_primary_key(id, value, attr);
|
||||
}
|
||||
|
||||
template< class Operator >
|
||||
void primary_key(Operator &op, const char *id, std::string &value, size_t size ) {
|
||||
op.on_primary_key(id, value, size);
|
||||
template< class Operator, class Type >
|
||||
void primary_key(Operator &op, const char *id, Type &value) {
|
||||
op.on_primary_key(id, value);
|
||||
}
|
||||
|
||||
template<class Operator>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ namespace matador {
|
|||
* @tparam B The base class type
|
||||
* @tparam D The class type of the derived class
|
||||
* @param derived The derived object
|
||||
* @return The casted object
|
||||
* @return The cast object
|
||||
*/
|
||||
template < class B, class D>
|
||||
const B* base_class(const D *derived)
|
||||
|
|
@ -27,7 +27,7 @@ const B* base_class(const D *derived)
|
|||
* @tparam B The base class type
|
||||
* @tparam D The class type of the derived class
|
||||
* @param derived The derived object
|
||||
* @return The casted object
|
||||
* @return The cast object
|
||||
*/
|
||||
template < class B, class D>
|
||||
B* base_class(D *derived)
|
||||
|
|
|
|||
|
|
@ -5,13 +5,11 @@ namespace matador::utils {
|
|||
|
||||
enum class constraints : unsigned char {
|
||||
NONE = 0,
|
||||
// NOT_NULL = 1 << 0,
|
||||
INDEX = 1 << 1,
|
||||
UNIQUE = 1 << 2,
|
||||
PRIMARY_KEY = 1 << 3,
|
||||
FOREIGN_KEY = 1 << 4,
|
||||
DEFAULT = 1 << 5
|
||||
// UNIQUE_NOT_NULL = UNIQUE | NOT_NULL
|
||||
INDEX = 1 << 0,
|
||||
UNIQUE = 1 << 1,
|
||||
PRIMARY_KEY = 1 << 2,
|
||||
FOREIGN_KEY = 1 << 3,
|
||||
DEFAULT = 1 << 4
|
||||
};
|
||||
|
||||
inline constraints operator|(constraints a, constraints b) { return static_cast<constraints>(static_cast<unsigned int>(a) | static_cast<unsigned int>(b)); }
|
||||
|
|
|
|||
|
|
@ -13,85 +13,85 @@ namespace matador::utils {
|
|||
template <> struct data_type_traits<nullptr_t, void>
|
||||
{
|
||||
static basic_type type(std::size_t /*size*/) { return basic_type::type_null; }
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, nullptr_t &/*value*/);
|
||||
static void bind_value(attribute_writer &binder, size_t index, nullptr_t &/*value*/);
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, nullptr_t &/*value*/, size_t /*size*/ = 0);
|
||||
static void bind_value(attribute_writer &binder, size_t index, nullptr_t &/*value*/, size_t /*size*/ = 0);
|
||||
};
|
||||
|
||||
template <> struct data_type_traits<int8_t, void>
|
||||
{
|
||||
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::type_int8; }
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, int8_t &value);
|
||||
static void bind_value(attribute_writer &binder, size_t index, const int8_t &value);
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, int8_t &value, size_t /*size*/ = 0);
|
||||
static void bind_value(attribute_writer &binder, size_t index, const int8_t &value, size_t /*size*/ = 0);
|
||||
};
|
||||
|
||||
template <> struct data_type_traits<int16_t, void>
|
||||
{
|
||||
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::type_int16; }
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, int16_t &value);
|
||||
static void bind_value(attribute_writer &binder, size_t index, const int16_t &value);
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, int16_t &value, size_t /*size*/ = 0);
|
||||
static void bind_value(attribute_writer &binder, size_t index, const int16_t &value, size_t /*size*/ = 0);
|
||||
};
|
||||
|
||||
template <> struct data_type_traits<int32_t, void>
|
||||
{
|
||||
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::type_int32; }
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, int32_t &value);
|
||||
static void bind_value(attribute_writer &binder, size_t index, const int32_t &value);
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, int32_t &value, size_t /*size*/ = 0);
|
||||
static void bind_value(attribute_writer &binder, size_t index, const int32_t &value, size_t /*size*/ = 0);
|
||||
};
|
||||
|
||||
template <> struct data_type_traits<int64_t, void>
|
||||
{
|
||||
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::type_int64; }
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, int64_t &value);
|
||||
static void bind_value(attribute_writer &binder, size_t index, const int64_t &value);
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, int64_t &value, size_t /*size*/ = 0);
|
||||
static void bind_value(attribute_writer &binder, size_t index, const int64_t &value, size_t /*size*/ = 0);
|
||||
};
|
||||
|
||||
template <> struct data_type_traits<uint8_t, void>
|
||||
{
|
||||
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::type_uint8; }
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, uint8_t &value);
|
||||
static void bind_value(attribute_writer &binder, size_t index, const uint8_t &value);
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, uint8_t &value, size_t /*size*/ = 0);
|
||||
static void bind_value(attribute_writer &binder, size_t index, const uint8_t &value, size_t /*size*/ = 0);
|
||||
};
|
||||
|
||||
template <> struct data_type_traits<uint16_t, void>
|
||||
{
|
||||
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::type_uint16; }
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, uint16_t &value);
|
||||
static void bind_value(attribute_writer &binder, size_t index, const uint16_t &value);
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, uint16_t &value, size_t /*size*/ = 0);
|
||||
static void bind_value(attribute_writer &binder, size_t index, const uint16_t &value, size_t /*size*/ = 0);
|
||||
};
|
||||
|
||||
template <> struct data_type_traits<uint32_t, void>
|
||||
{
|
||||
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::type_uint32; }
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, uint32_t &value);
|
||||
static void bind_value(attribute_writer &binder, size_t index, const uint32_t &value);
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, uint32_t &value, size_t /*size*/ = 0);
|
||||
static void bind_value(attribute_writer &binder, size_t index, const uint32_t &value, size_t /*size*/ = 0);
|
||||
};
|
||||
|
||||
template <> struct data_type_traits<uint64_t, void>
|
||||
{
|
||||
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::type_uint64; }
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, uint64_t &value);
|
||||
static void bind_value(attribute_writer &binder, size_t index, const uint64_t &value);
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, uint64_t &value, size_t /*size*/ = 0);
|
||||
static void bind_value(attribute_writer &binder, size_t index, const uint64_t &value, size_t /*size*/ = 0);
|
||||
};
|
||||
|
||||
template <> struct data_type_traits<bool, void>
|
||||
{
|
||||
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::type_bool; }
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, bool &value);
|
||||
static void bind_value(attribute_writer &binder, size_t index, const bool &value);
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, bool &value, size_t /*size*/ = 0);
|
||||
static void bind_value(attribute_writer &binder, size_t index, const bool &value, size_t /*size*/ = 0);
|
||||
};
|
||||
|
||||
template <> struct data_type_traits<float, void>
|
||||
{
|
||||
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::type_float; }
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, float &value);
|
||||
static void bind_value(attribute_writer &binder, size_t index, const float &value);
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, float &value, size_t /*size*/ = 0);
|
||||
static void bind_value(attribute_writer &binder, size_t index, const float &value, size_t /*size*/ = 0);
|
||||
};
|
||||
|
||||
template <> struct data_type_traits<double, void>
|
||||
{
|
||||
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::type_double; }
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, double &value);
|
||||
static void bind_value(attribute_writer &binder, size_t index, const double &value);
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, double &value, size_t /*size*/ = 0);
|
||||
static void bind_value(attribute_writer &binder, size_t index, const double &value, size_t /*size*/ = 0);
|
||||
};
|
||||
|
||||
template <> struct data_type_traits<const char*, void>
|
||||
|
|
@ -131,8 +131,8 @@ template <> struct data_type_traits<std::string, void>
|
|||
template <> struct data_type_traits<utils::blob, void>
|
||||
{
|
||||
static basic_type type(std::size_t /*size*/) { return basic_type::type_blob; }
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, utils::blob &value);
|
||||
static void bind_value(attribute_writer &binder, size_t index, utils::blob &value);
|
||||
static void read_value(attribute_reader &reader, const char *id, size_t index, utils::blob &value, size_t /*size*/ = 0);
|
||||
static void bind_value(attribute_writer &binder, size_t index, utils::blob &value, size_t /*size*/ = 0);
|
||||
};
|
||||
|
||||
//template <> struct data_type_traits<matador::date, void>
|
||||
|
|
@ -153,13 +153,11 @@ template < typename EnumType >
|
|||
struct data_type_traits<EnumType, std::enable_if_t<std::is_enum_v<EnumType>>>
|
||||
{
|
||||
static basic_type type(std::size_t /*size*/ = 0) { return basic_type::type_int32; }
|
||||
static void read_value(attribute_reader &reader, const char *id, const size_t index, EnumType &value)
|
||||
{
|
||||
data_type_traits<int>::read_value(reader, id, index, reinterpret_cast<int&>(value));
|
||||
static void read_value(attribute_reader &reader, const char *id, const size_t index, EnumType &value, const size_t size = 0) {
|
||||
data_type_traits<int>::read_value(reader, id, index, reinterpret_cast<int&>(value), size);
|
||||
}
|
||||
static void bind_value(attribute_writer &binder, const size_t index, EnumType &value)
|
||||
{
|
||||
data_type_traits<int>::bind_value(binder, index, static_cast<int &>(value));
|
||||
static void bind_value(attribute_writer &binder, const size_t index, EnumType &value, const size_t size = 0) {
|
||||
data_type_traits<int>::bind_value(binder, index, static_cast<int &>(value), size);
|
||||
}
|
||||
};
|
||||
/// @endcond
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ public:
|
|||
|
||||
friend std::ostream& operator<<(std::ostream &out, const error &err);
|
||||
|
||||
[[nodiscard]] std::string error_code() const;
|
||||
[[nodiscard]] std::string message() const;
|
||||
[[nodiscard]] std::string category() const;
|
||||
[[nodiscard]] std::error_code ec() const;
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ namespace matador::utils {
|
|||
|
||||
/**
|
||||
* This class represents field attributes in
|
||||
* form of size and constraints for a database
|
||||
* the form of size and constraints for a database
|
||||
* field (column)
|
||||
*
|
||||
* Currently the size is only applied
|
||||
* Currently, the size is only applied
|
||||
* to a field of type string leading
|
||||
* to VARCHAR(size).
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef PRIMARY_KEY_ATTRIBUTE_HPP
|
||||
#define PRIMARY_KEY_ATTRIBUTE_HPP
|
||||
|
||||
#include "matador/utils/primary_key_generator_type.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace matador::utils {
|
||||
|
|
@ -18,6 +20,8 @@ public:
|
|||
* @param size Size of the attribute
|
||||
*/
|
||||
primary_key_attribute(size_t size); // NOLINT(*-explicit-constructor)
|
||||
primary_key_attribute(generator_type generator); // NOLINT(*-explicit-constructor)
|
||||
primary_key_attribute(size_t size, generator_type generator);
|
||||
~primary_key_attribute() = default;
|
||||
primary_key_attribute(const primary_key_attribute &) = default;
|
||||
primary_key_attribute(primary_key_attribute &&) = default;
|
||||
|
|
@ -25,6 +29,7 @@ public:
|
|||
primary_key_attribute &operator=(primary_key_attribute &&) = default;
|
||||
|
||||
primary_key_attribute& operator=(size_t size);
|
||||
primary_key_attribute& operator=(generator_type generator);
|
||||
|
||||
/**
|
||||
* Returns the size of the field
|
||||
|
|
@ -33,9 +38,18 @@ public:
|
|||
*/
|
||||
[[nodiscard]] size_t size() const;
|
||||
|
||||
/**
|
||||
* Returns the generator type of the field
|
||||
*
|
||||
* @return Generator type of the field
|
||||
*/
|
||||
[[nodiscard]] generator_type generator() const;
|
||||
private:
|
||||
size_t size_ = 0;
|
||||
generator_type generator_ = generator_type::MANUALLY;
|
||||
};
|
||||
|
||||
const primary_key_attribute default_pk_attributes {};
|
||||
|
||||
}
|
||||
#endif //PRIMARY_KEY_ATTRIBUTE_HPP
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef PRIMARY_KEY_GENERATOR_TYPE_HPP
|
||||
#define PRIMARY_KEY_GENERATOR_TYPE_HPP
|
||||
|
||||
namespace matador::utils {
|
||||
enum class generator_type {
|
||||
MANUALLY,
|
||||
AUTO,
|
||||
IDENTITY,
|
||||
SEQUENCE,
|
||||
TABLE
|
||||
};
|
||||
}
|
||||
#endif //PRIMARY_KEY_GENERATOR_TYPE_HPP
|
||||
|
|
@ -57,6 +57,7 @@ add_library(matador-core STATIC
|
|||
../../include/matador/utils/os.hpp
|
||||
../../include/matador/utils/placeholder.hpp
|
||||
../../include/matador/utils/primary_key_attribute.hpp
|
||||
../../include/matador/utils/primary_key_generator_type.hpp
|
||||
../../include/matador/utils/result.hpp
|
||||
../../include/matador/utils/singleton.hpp
|
||||
../../include/matador/utils/string.hpp
|
||||
|
|
@ -79,7 +80,6 @@ add_library(matador-core STATIC
|
|||
object/foreign_node_completer.cpp
|
||||
object/internal/shadow_schema.cpp
|
||||
object/object_definition.cpp
|
||||
object/primary_key_resolver.cpp
|
||||
object/relation_endpoint.cpp
|
||||
object/schema.cpp
|
||||
object/schema_node.cpp
|
||||
|
|
|
|||
|
|
@ -14,9 +14,6 @@ void init()
|
|||
{
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData; // if this doesn't work
|
||||
//WSAData wsaData; // then try this instead
|
||||
|
||||
// MAKEWORD(1,1) for Winsock 1.1, MAKEWORD(2,0) for Winsock 2.0:
|
||||
|
||||
if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0) {
|
||||
fprintf(stderr, "WSAStartup failed.\n");
|
||||
|
|
|
|||
|
|
@ -1,342 +1,248 @@
|
|||
#include "matador/net/reactor.hpp"
|
||||
#include "matador/net/handler.hpp"
|
||||
|
||||
#include "matador/logger/log_manager.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <cerrno>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <system_error>
|
||||
|
||||
namespace matador {
|
||||
namespace matador::net {
|
||||
|
||||
reactor::reactor()
|
||||
: sentinel_(std::shared_ptr<handler>(nullptr))
|
||||
, log_(create_logger("Reactor"))
|
||||
, thread_pool_(4, [this]() { handle_events(); })
|
||||
{
|
||||
}
|
||||
reactor::~reactor()
|
||||
{
|
||||
log_.debug("destroying reactor");
|
||||
thread_pool_.shutdown();
|
||||
: log_(logger::create_logger("Reactor"))
|
||||
, thread_pool_(4, [this]() { handle_events(); }) {
|
||||
}
|
||||
|
||||
void reactor::register_handler(const handler_ptr& h, event_type et)
|
||||
{
|
||||
h->register_reactor(this);
|
||||
h->open();
|
||||
|
||||
std::lock_guard<std::mutex> l(mutex_);
|
||||
auto it = find_handler_type(h);
|
||||
|
||||
if (it == handlers_.end()) {
|
||||
handlers_.emplace_back(h, et);
|
||||
} else if (it->first != h) {
|
||||
throw std::logic_error("given handler isn't expected handler");
|
||||
} else {
|
||||
it->second = it->second | et;
|
||||
}
|
||||
interrupt_without_lock();
|
||||
}
|
||||
|
||||
void reactor::unregister_handler(const handler_ptr& h, event_type)
|
||||
{
|
||||
std::lock_guard<std::mutex> l(mutex_);
|
||||
auto it = find_handler_type(h);
|
||||
|
||||
if (it != handlers_.end()) {
|
||||
(*it).first->close();
|
||||
handlers_.erase(it);
|
||||
}
|
||||
interrupt_without_lock();
|
||||
}
|
||||
|
||||
void reactor::schedule_timer(const std::shared_ptr<handler>& h, time_t offset, time_t interval)
|
||||
{
|
||||
h->register_reactor(this);
|
||||
|
||||
std::lock_guard<std::mutex> l(mutex_);
|
||||
auto it = find_handler_type(h);
|
||||
|
||||
if (it == handlers_.end()) {
|
||||
handlers_.emplace_back(h, event_type::TIMEOUT_MASK);
|
||||
}
|
||||
|
||||
h->schedule(offset, interval);
|
||||
}
|
||||
|
||||
void reactor::cancel_timer(const std::shared_ptr<handler>& h)
|
||||
{
|
||||
std::lock_guard<std::mutex> l(mutex_);
|
||||
auto it = find_handler_type(h);
|
||||
|
||||
if (it != handlers_.end()) {
|
||||
handlers_.erase(it);
|
||||
}
|
||||
|
||||
h->cancel_timer();
|
||||
}
|
||||
|
||||
void reactor::run()
|
||||
{
|
||||
// log_.info("start dispatching all clients");
|
||||
thread_pool_.start();
|
||||
|
||||
{
|
||||
// log_.info("waiting for reactor shutdown");
|
||||
std::unique_lock<std::mutex> l(mutex_);
|
||||
shutdown_.wait(l, [this]() { return shutdown_requested_.load(); });
|
||||
cleanup();
|
||||
}
|
||||
// log_.info("all clients dispatched; shutting down");
|
||||
thread_pool_.stop();
|
||||
}
|
||||
|
||||
void reactor::handle_events()
|
||||
{
|
||||
// std::cout << this << " start handle events\n" << std::flush;
|
||||
|
||||
// log_.info("handle events");
|
||||
|
||||
running_ = true;
|
||||
time_t timeout;
|
||||
select_fdsets fd_sets;
|
||||
prepare_select_bits(timeout, fd_sets);
|
||||
|
||||
// std::cout << this << " fd sets r: " << fd_sets.read_set().count() << ", w: " << fd_sets.write_set().count() << ", e: " << fd_sets.except_set().count() << ", max: " << fd_sets.maxp1() << "\n" << std::flush;
|
||||
|
||||
// log_.debug("fds [r: %d, w: %d, e: %d]",
|
||||
// fdsets_.read_set().count(),
|
||||
// fdsets_.write_set().count(),
|
||||
// fdsets_.except_set().count());
|
||||
|
||||
// if (timeout != (std::numeric_limits<time_t>::max)()) {
|
||||
// log_.debug("next timeout in %d sec", timeout);
|
||||
// }
|
||||
struct timeval tselect{};
|
||||
struct timeval* p = nullptr;
|
||||
if (timeout < (std::numeric_limits<time_t>::max)()) {
|
||||
tselect.tv_sec = timeout;
|
||||
tselect.tv_usec = 0;
|
||||
p = &tselect;
|
||||
// std::cout << this << " next timeout in " << p->tv_sec << " seconds\n" << std::flush;
|
||||
}
|
||||
|
||||
if (!has_clients_to_handle(timeout, fd_sets)) {
|
||||
// std::cout << this << " no clients to handle; returning\n" << std::flush;
|
||||
// log_.info("no clients to handle, exiting");
|
||||
return;
|
||||
}
|
||||
|
||||
int ret;
|
||||
while ((ret = select(p, fd_sets)) < 0) {
|
||||
// std::cout << this << " select returned with error " << ret << "\n" << std::flush;
|
||||
if(errno != EINTR) {
|
||||
char error_buffer[1024];
|
||||
log_.warn("select failed: %s", os::strerror(errno, error_buffer, 1024));
|
||||
shutdown();
|
||||
} else {
|
||||
return;
|
||||
reactor::~reactor() {
|
||||
if (is_running()) {
|
||||
try {
|
||||
shutdown();
|
||||
} catch (const std::exception& e) {
|
||||
log_.error("Error during shutdown: %s", e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// std::cout << this << " select returned with active requests " << ret << "\n" << std::flush;
|
||||
|
||||
bool interrupted = is_interrupted(fd_sets);
|
||||
|
||||
if (interrupted) {
|
||||
if (!shutdown_requested_) {
|
||||
// std::cout << this << " reactor was interrupted - promote new leader\n" << std::flush;
|
||||
// log_.info("reactor was interrupted");
|
||||
thread_pool_.promote_new_leader();
|
||||
return;
|
||||
} else {
|
||||
// std::cout << this << " reactor was interrupted for shutdown\n" << std::flush;
|
||||
// log_.info("shutting down");
|
||||
// cleanup();
|
||||
shutdown_.notify_one();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
time_t now = ::time(nullptr);
|
||||
t_handler_type handler_type = resolve_next_handler(now, fd_sets);
|
||||
|
||||
if (handler_type.first) {
|
||||
deactivate_handler(handler_type.first, handler_type.second);
|
||||
// std::cout << this << " handling client " << handler_type.first->name() << " - promoting new leader\n" << std::flush;
|
||||
|
||||
thread_pool_.promote_new_leader();
|
||||
// log_.info("start handling event");
|
||||
// handle event
|
||||
if (handler_type.second == event_type::WRITE_MASK) {
|
||||
on_write_mask(handler_type.first);
|
||||
} else if (handler_type.second == event_type::READ_MASK) {
|
||||
on_read_mask(handler_type.first);
|
||||
} else if (handler_type.second == event_type::TIMEOUT_MASK) {
|
||||
on_timeout(handler_type.first, now);
|
||||
} else {
|
||||
// log_.info("unknown event type");
|
||||
}
|
||||
activate_handler(handler_type.first, handler_type.second);
|
||||
remove_deleted();
|
||||
} else {
|
||||
// no handler found
|
||||
// log_.info("no handler found");
|
||||
thread_pool_.promote_new_leader();
|
||||
}
|
||||
}
|
||||
|
||||
void reactor::shutdown()
|
||||
{
|
||||
if (!is_running()) {
|
||||
return;
|
||||
}
|
||||
// shutdown the reactor properly
|
||||
log_.info("shutting down reactor");
|
||||
shutdown_requested_ = true;
|
||||
interrupt();
|
||||
void reactor::register_handler(const handler_ptr& h, event_type type) {
|
||||
if (!h) {
|
||||
throw std::invalid_argument("Null handler");
|
||||
}
|
||||
|
||||
std::unique_lock lock(handlers_mutex_);
|
||||
|
||||
auto* raw_ptr = h.get();
|
||||
if (handlers_.find(raw_ptr) != handlers_.end()) {
|
||||
throw std::runtime_error("Handler already registered");
|
||||
}
|
||||
|
||||
safe_handler_operation(h, "register", [&] {
|
||||
h->register_reactor(this);
|
||||
h->open();
|
||||
handlers_.emplace(raw_ptr, std::make_unique<HandlerEntry>(h, type));
|
||||
});
|
||||
|
||||
interrupter_.interrupt();
|
||||
}
|
||||
|
||||
bool reactor::is_running() const
|
||||
{
|
||||
return running_;
|
||||
void reactor::unregister_handler(const handler_ptr& h, event_type type) {
|
||||
if (!h) return;
|
||||
|
||||
std::unique_lock lock(handlers_mutex_);
|
||||
|
||||
if (find_handler_entry(h)) {
|
||||
safe_handler_operation(h, "unregister", [&] {
|
||||
h->close();
|
||||
remove_handler_entry(h);
|
||||
});
|
||||
}
|
||||
|
||||
interrupter_.interrupt();
|
||||
}
|
||||
|
||||
void reactor::schedule_timer(const handler_ptr& h, time_t offset, time_t interval) {
|
||||
if (!h) return;
|
||||
|
||||
std::unique_lock lock(handlers_mutex_);
|
||||
auto* entry = find_handler_entry(h);
|
||||
|
||||
if (!entry) {
|
||||
entry = handlers_.emplace(h.get(),
|
||||
std::make_unique<HandlerEntry>(h, event_type::TIMEOUT_MASK)).first->second.get();
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> timer_lock(timers_mutex_);
|
||||
time_t now = std::time(nullptr);
|
||||
entry->next_timeout = now + offset;
|
||||
entry->interval = interval;
|
||||
|
||||
timers_.push(TimerEvent{entry->next_timeout, h});
|
||||
|
||||
interrupter_.interrupt();
|
||||
}
|
||||
|
||||
void reactor::cancel_timer(const handler_ptr& h) {
|
||||
if (!h) return;
|
||||
|
||||
std::unique_lock lock(handlers_mutex_);
|
||||
if (auto* entry = find_handler_entry(h)) {
|
||||
entry->next_timeout = 0;
|
||||
entry->interval = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void reactor::run() {
|
||||
running_ = true;
|
||||
thread_pool_.start();
|
||||
|
||||
{
|
||||
std::unique_lock lock(handlers_mutex_);
|
||||
shutdown_cv_.wait(lock, [this] { return shutdown_requested_.load(); });
|
||||
cleanup_deleted_handlers();
|
||||
}
|
||||
|
||||
thread_pool_.stop();
|
||||
running_ = false;
|
||||
}
|
||||
|
||||
void reactor::handle_events() {
|
||||
time_t timeout;
|
||||
select_fdsets fd_sets;
|
||||
|
||||
prepare_select_bits(timeout, fd_sets);
|
||||
|
||||
if (!fd_sets.maxp1() && timeout == (std::numeric_limits<time_t>::max)()) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct timeval select_timeout{};
|
||||
struct timeval* timeout_ptr = nullptr;
|
||||
|
||||
if (timeout < (std::numeric_limits<time_t>::max)()) {
|
||||
select_timeout.tv_sec = timeout;
|
||||
select_timeout.tv_usec = 0;
|
||||
timeout_ptr = &select_timeout;
|
||||
}
|
||||
|
||||
try {
|
||||
if (int result = perform_select(timeout_ptr, fd_sets); result < 0) {
|
||||
if (errno != EINTR) {
|
||||
throw std::system_error(errno, std::system_category(), "select failed");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
time_t now = std::time(nullptr);
|
||||
|
||||
if (check_interruption(fd_sets)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (process_events(fd_sets, now)) {
|
||||
thread_pool_.promote_new_leader();
|
||||
}
|
||||
|
||||
process_timers(now);
|
||||
|
||||
if (now - last_cleanup_ >= CLEANUP_INTERVAL.count()) {
|
||||
cleanup_deleted_handlers();
|
||||
last_cleanup_ = now;
|
||||
}
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
log_.error("Error in handle_events: %s", e.what());
|
||||
stats_.errors_++;
|
||||
}
|
||||
}
|
||||
|
||||
void reactor::shutdown() {
|
||||
if (!running_) return;
|
||||
|
||||
log_.info("Initiating reactor shutdown");
|
||||
shutdown_requested_ = true;
|
||||
interrupter_.interrupt();
|
||||
shutdown_cv_.notify_all();
|
||||
}
|
||||
|
||||
void reactor::mark_handler_for_delete(const handler_ptr& h) {
|
||||
if (!h) return;
|
||||
|
||||
std::unique_lock lock(handlers_mutex_);
|
||||
if (auto* entry = find_handler_entry(h)) {
|
||||
entry->marked_for_deletion = true;
|
||||
}
|
||||
}
|
||||
|
||||
void reactor::safe_handler_operation(const handler_ptr& h, const std::string& op_name, const std::function<void()>& operation) {
|
||||
try {
|
||||
operation();
|
||||
} catch (const std::exception& e) {
|
||||
log_.error("Error during %s operation: %s", op_name.c_str(), e.what());
|
||||
++stats_.errors_;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
reactor::HandlerEntry* reactor::find_handler_entry(const handler_ptr& h) {
|
||||
const auto it = handlers_.find(h.get());
|
||||
return it != handlers_.end() ? it->second.get() : nullptr;
|
||||
}
|
||||
|
||||
void reactor::remove_handler_entry(const handler_ptr& h) {
|
||||
handlers_.erase(h.get());
|
||||
}
|
||||
|
||||
void reactor::update_handler_events(HandlerEntry* entry, const event_type ev, const bool activate) {
|
||||
if (!entry) return;
|
||||
|
||||
if (activate) {
|
||||
entry->events |= ev;
|
||||
} else {
|
||||
entry->events &= ~ev;
|
||||
}
|
||||
}
|
||||
|
||||
void reactor::prepare_select_bits(time_t& timeout, select_fdsets& fd_sets) const
|
||||
{
|
||||
std::lock_guard<std::mutex> l(mutex_);
|
||||
fd_sets.reset();
|
||||
time_t now = ::time(nullptr);
|
||||
timeout = (std::numeric_limits<time_t>::max)();
|
||||
std::lock_guard l(handlers_mutex_);
|
||||
fd_sets.reset();
|
||||
const time_t now = ::time(nullptr);
|
||||
timeout = (std::numeric_limits<time_t>::max)();
|
||||
|
||||
// set interrupter fd
|
||||
fd_sets.read_set().set(interrupter_.socket_id());
|
||||
// set interrupter fd
|
||||
fd_sets.read_set().set(interrupter_.socket_id());
|
||||
|
||||
for (const auto &h : handlers_) {
|
||||
if (h.first == nullptr) {
|
||||
continue;
|
||||
for (const auto & [hndlr, entry] : handlers_) {
|
||||
if (hndlr == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (hndlr->is_ready_read() && is_event_type_set(entry->events, event_type::READ_MASK)) {
|
||||
fd_sets.read_set().set(hndlr->handle());
|
||||
}
|
||||
if (hndlr->is_ready_write() && is_event_type_set(entry->events, event_type::WRITE_MASK)) {
|
||||
fd_sets.write_set().set(hndlr->handle());
|
||||
}
|
||||
if (hndlr->next_timeout() > 0 && is_event_type_set(entry->events, event_type::TIMEOUT_MASK)) {
|
||||
timeout = (std::min)(timeout, hndlr->next_timeout() <= now ? 0 : (hndlr->next_timeout() - now));
|
||||
}
|
||||
}
|
||||
if (h.first->is_ready_read() && is_event_type_set(h.second, event_type::READ_MASK)) {
|
||||
fd_sets.read_set().set(h.first->handle());
|
||||
}
|
||||
if (h.first->is_ready_write() && is_event_type_set(h.second, event_type::WRITE_MASK)) {
|
||||
fd_sets.write_set().set(h.first->handle());
|
||||
}
|
||||
if (h.first->next_timeout() > 0 && is_event_type_set(h.second, event_type::TIMEOUT_MASK)) {
|
||||
timeout = (std::min)(timeout, h.first->next_timeout() <= now ? 0 : (h.first->next_timeout() - now));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void reactor::remove_deleted()
|
||||
{
|
||||
while (!handlers_to_delete_.empty()) {
|
||||
auto h = handlers_to_delete_.front();
|
||||
handlers_to_delete_.pop_front();
|
||||
auto fi = std::find_if(handlers_.begin(), handlers_.end(), [&h](const t_handler_type &ht) {
|
||||
return ht.first.get() == h.get();
|
||||
});
|
||||
|
||||
if (fi != handlers_.end()) {
|
||||
log_.debug("removing handler %d", fi->first->handle());
|
||||
handlers_.erase(fi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void reactor::cleanup()
|
||||
{
|
||||
while (!handlers_.empty()) {
|
||||
auto hndlr = handlers_.front();
|
||||
handlers_.pop_front();
|
||||
hndlr.first->close();
|
||||
}
|
||||
}
|
||||
|
||||
int reactor::select(struct timeval *timeout, select_fdsets& fd_sets)
|
||||
{
|
||||
log_.debug("calling select; waiting for io events");
|
||||
return ::select(
|
||||
static_cast<int>(fd_sets.maxp1()) + 1,
|
||||
fd_sets.read_set().get(),
|
||||
fd_sets.write_set().get(),
|
||||
fd_sets.except_set().get(),
|
||||
timeout
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
//void reactor::process_handler(int /*ret*/)
|
||||
//{
|
||||
// handlers_.emplace_back(sentinel_, event_type::NONE_MASK);
|
||||
// time_t now = ::time(nullptr);
|
||||
// while (handlers_.front().first != nullptr) {
|
||||
// auto h = handlers_.front();
|
||||
// handlers_.pop_front();
|
||||
// handlers_.push_back(h);
|
||||
// // check for read/accept
|
||||
// if (h.first->handle() > 0 && fdsets_.write_set().is_set(h.first->handle())) {
|
||||
// on_write_mask(h.first);
|
||||
// }
|
||||
// if (h.first->handle() > 0 && fdsets_.read_set().is_set(h.first->handle())) {
|
||||
// on_read_mask(h.first);
|
||||
// }
|
||||
// if (h.first->next_timeout() > 0 && h.first->next_timeout() <= now) {
|
||||
// on_timeout(h.first, now);
|
||||
// }
|
||||
// }
|
||||
// handlers_.pop_front();
|
||||
//}
|
||||
|
||||
reactor::t_handler_type reactor::resolve_next_handler(time_t now, select_fdsets& fd_sets)
|
||||
{
|
||||
std::lock_guard<std::mutex> l(mutex_);
|
||||
for (auto &h : handlers_) {
|
||||
if (h.first->handle() > 0 && fd_sets.write_set().is_set(h.first->handle())) {
|
||||
return std::make_pair(h.first, event_type::WRITE_MASK);
|
||||
std::lock_guard l(handlers_mutex_);
|
||||
for (auto & [hndlr, entry] : handlers_) {
|
||||
if (hndlr->handle() > 0 && fd_sets.write_set().is_set(hndlr->handle())) {
|
||||
return std::make_pair(hndlr, event_type::WRITE_MASK);
|
||||
}
|
||||
if (h.first->handle() > 0 && fd_sets.read_set().is_set(h.first->handle())) {
|
||||
return std::make_pair(h.first, event_type::READ_MASK);
|
||||
if (hndlr->handle() > 0 && fd_sets.read_set().is_set(hndlr->handle())) {
|
||||
return std::make_pair(hndlr, event_type::READ_MASK);
|
||||
}
|
||||
if (h.first->next_timeout() > 0 && h.first->next_timeout() <= now) {
|
||||
return std::make_pair(h.first, event_type::TIMEOUT_MASK);
|
||||
if (hndlr->next_timeout() > 0 && hndlr->next_timeout() <= now) {
|
||||
return std::make_pair(hndlr, event_type::TIMEOUT_MASK);
|
||||
}
|
||||
}
|
||||
return std::make_pair(nullptr, event_type::NONE_MASK);
|
||||
}
|
||||
|
||||
void reactor::on_read_mask(const handler_ptr& handler)
|
||||
{
|
||||
// log_.debug("read bit for handler %d is set; handle input", h->handle());
|
||||
// std::cout << this << " (handler " << h.get() << "): handle read\n" << std::flush;
|
||||
handler->on_input();
|
||||
}
|
||||
|
||||
void reactor::on_write_mask(const handler_ptr& handler)
|
||||
{
|
||||
// log_.debug("write bit for handler %d is set; handle output", h->handle());
|
||||
// std::cout << this << " (handler " << h.get() << "): handle write\n" << std::flush;
|
||||
handler->on_output();
|
||||
}
|
||||
|
||||
void reactor::on_except_mask(const handler_ptr& /*handler*/)
|
||||
{
|
||||
// std::cout << this << " (handler " << h.get() << "): handle exception\n" << std::flush;
|
||||
|
||||
}
|
||||
|
||||
void reactor::on_timeout(const handler_ptr &h, time_t now)
|
||||
{
|
||||
// log_.debug("timeout expired for handler %d; handle timeout", h->handle());
|
||||
// std::cout << this << " (handler " << h.get() << "): handle timeout\n" << std::flush;
|
||||
h->calculate_next_timeout(now);
|
||||
h->on_timeout();
|
||||
}
|
||||
|
||||
select_fdsets reactor::fdsets() const
|
||||
select_fdsets reactor::fd_sets() const
|
||||
{
|
||||
time_t timeout;
|
||||
select_fdsets fd_sets;
|
||||
|
|
@ -344,68 +250,24 @@ select_fdsets reactor::fdsets() const
|
|||
return fd_sets;
|
||||
}
|
||||
|
||||
void reactor::mark_handler_for_delete(const handler_ptr& h)
|
||||
{
|
||||
std::lock_guard<std::mutex> l(mutex_);
|
||||
handlers_to_delete_.push_back(h);
|
||||
}
|
||||
|
||||
bool reactor::is_interrupted(select_fdsets& fd_sets)
|
||||
{
|
||||
std::lock_guard<std::mutex> l(mutex_);
|
||||
if (fd_sets.read_set().is_set(interrupter_.socket_id())) {
|
||||
log_.debug("interrupt byte received; resetting interrupter");
|
||||
if (shutdown_requested_) {
|
||||
running_ = false;
|
||||
}
|
||||
return interrupter_.reset();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool reactor::has_clients_to_handle(time_t timeout, select_fdsets& fd_sets) const {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
return fd_sets.maxp1() > 0 || timeout != (std::numeric_limits<time_t>::max)();
|
||||
}
|
||||
|
||||
std::list<reactor::t_handler_type>::iterator reactor::find_handler_type(const reactor::handler_ptr &h)
|
||||
{
|
||||
return std::find_if(handlers_.begin(), handlers_.end(), [&h](const t_handler_type &ht) {
|
||||
return ht.first.get() == h.get();
|
||||
});
|
||||
}
|
||||
|
||||
void reactor::activate_handler(const reactor::handler_ptr &h, event_type ev)
|
||||
{
|
||||
std::lock_guard<std::mutex> l(mutex_);
|
||||
auto it = find_handler_type(h);
|
||||
if (it == handlers_.end()) {
|
||||
std::lock_guard l(handlers_mutex_);
|
||||
const auto it = find_handler_entry(h);
|
||||
if (!it) {
|
||||
return;
|
||||
}
|
||||
it->second |= ev;
|
||||
it->events |= ev;
|
||||
}
|
||||
|
||||
void reactor::deactivate_handler(const reactor::handler_ptr &h, event_type ev)
|
||||
{
|
||||
std::lock_guard<std::mutex> l(mutex_);
|
||||
auto it = find_handler_type(h);
|
||||
if (it == handlers_.end()) {
|
||||
std::lock_guard l(handlers_mutex_);
|
||||
const auto it = find_handler_entry(h);
|
||||
if (!it) {
|
||||
return;
|
||||
}
|
||||
it->second &= ~ev;
|
||||
it->events &= ~ev;
|
||||
}
|
||||
|
||||
void reactor::interrupt()
|
||||
{
|
||||
log_.trace("interrupting reactor");
|
||||
std::lock_guard<std::mutex> l(mutex_);
|
||||
interrupter_.interrupt();
|
||||
}
|
||||
|
||||
void reactor::interrupt_without_lock()
|
||||
{
|
||||
log_.trace("interrupting reactor");
|
||||
interrupter_.interrupt();
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace matador
|
||||
|
|
@ -8,11 +8,11 @@
|
|||
#include <netinet/tcp.h>
|
||||
#endif
|
||||
|
||||
namespace matador {
|
||||
namespace matador::net {
|
||||
|
||||
socket_interrupter::socket_interrupter()
|
||||
: client_(tcp::v4())
|
||||
, log_(create_logger("SocketInterrupter"))
|
||||
, log_(logger::create_logger("SocketInterrupter"))
|
||||
{
|
||||
/*
|
||||
* setup acceptor
|
||||
|
|
|
|||
|
|
@ -8,11 +8,6 @@ attribute_definition_generator::attribute_definition_generator(std::vector<objec
|
|||
, repo_(repo)
|
||||
{}
|
||||
|
||||
void attribute_definition_generator::on_primary_key(const char *id, std::string &pk, size_t size)
|
||||
{
|
||||
on_attribute(id, pk, { size, utils::constraints::PRIMARY_KEY });
|
||||
}
|
||||
|
||||
void attribute_definition_generator::on_revision(const char *id, uint64_t &rev)
|
||||
{
|
||||
on_attribute(id, rev);
|
||||
|
|
@ -26,9 +21,4 @@ void attribute_definition_generator::insert_missing_reference_column(const std::
|
|||
const_cast<schema&>(repo_).missing_references_.insert({ti, ref_column});
|
||||
}
|
||||
|
||||
void fk_attribute_generator::on_primary_key(const char *, std::string &, const size_t size)
|
||||
{
|
||||
type_ = utils::data_type_traits<std::string>::type(size);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
#include "matador/object/primary_key_resolver.hpp"
|
||||
|
||||
namespace matador::object {
|
||||
void primary_key_resolver::on_primary_key(const char *id, const std::string &pk, size_t /*size*/) {
|
||||
primary_key_info_.pk_column_name = id;
|
||||
primary_key_info_.type = utils::basic_type::type_varchar;
|
||||
primary_key_info_.pk = pk;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -5,159 +5,129 @@
|
|||
|
||||
namespace matador::utils {
|
||||
|
||||
void data_type_traits<nullptr_t>::read_value(attribute_reader &/*reader*/, const char * /*id*/, size_t /*index*/, nullptr_t &/*value*/)
|
||||
void data_type_traits<nullptr_t>::read_value(attribute_reader &/*reader*/, const char * /*id*/, size_t /*index*/, nullptr_t &/*value*/, const size_t /*size*/)
|
||||
{}
|
||||
|
||||
void data_type_traits<nullptr_t>::bind_value(attribute_writer &/*binder*/, size_t /*index*/, nullptr_t &/*value*/)
|
||||
void data_type_traits<nullptr_t>::bind_value(attribute_writer &/*binder*/, size_t /*index*/, nullptr_t &/*value*/, const size_t /*size*/)
|
||||
{}
|
||||
|
||||
void data_type_traits<int8_t>::read_value(attribute_reader &reader, const char *id, const size_t index, int8_t &value)
|
||||
{
|
||||
void data_type_traits<int8_t>::read_value(attribute_reader &reader, const char *id, const size_t index, int8_t &value, const size_t /*size*/) {
|
||||
reader.read_value(id, index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<int8_t>::bind_value(attribute_writer &binder, const size_t index, const int8_t &value)
|
||||
{
|
||||
void data_type_traits<int8_t>::bind_value(attribute_writer &binder, const size_t index, const int8_t &value, const size_t /*size*/) {
|
||||
binder.write_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<int16_t>::read_value(attribute_reader &reader, const char *id, const size_t index, int16_t &value)
|
||||
{
|
||||
void data_type_traits<int16_t>::read_value(attribute_reader &reader, const char *id, const size_t index, int16_t &value, const size_t /*size*/) {
|
||||
reader.read_value(id, index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<int16_t>::bind_value(attribute_writer &binder, const size_t index, const int16_t &value)
|
||||
{
|
||||
void data_type_traits<int16_t>::bind_value(attribute_writer &binder, const size_t index, const int16_t &value, const size_t /*size*/) {
|
||||
binder.write_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<int32_t>::read_value(attribute_reader &reader, const char *id, const size_t index, int32_t &value)
|
||||
{
|
||||
void data_type_traits<int32_t>::read_value(attribute_reader &reader, const char *id, const size_t index, int32_t &value, const size_t /*size*/) {
|
||||
reader.read_value(id, index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<int32_t>::bind_value(attribute_writer &binder, const size_t index, const int32_t &value)
|
||||
{
|
||||
void data_type_traits<int32_t>::bind_value(attribute_writer &binder, const size_t index, const int32_t &value, const size_t /*size*/) {
|
||||
binder.write_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<int64_t>::read_value(attribute_reader &reader, const char *id, const size_t index, int64_t &value)
|
||||
{
|
||||
void data_type_traits<int64_t>::read_value(attribute_reader &reader, const char *id, const size_t index, int64_t &value, const size_t /*size*/) {
|
||||
reader.read_value(id, index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<int64_t>::bind_value(attribute_writer &binder, const size_t index, const int64_t &value)
|
||||
{
|
||||
void data_type_traits<int64_t>::bind_value(attribute_writer &binder, const size_t index, const int64_t &value, const size_t /*size*/) {
|
||||
binder.write_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<uint8_t>::read_value(attribute_reader &reader, const char *id, const size_t index, uint8_t &value)
|
||||
{
|
||||
void data_type_traits<uint8_t>::read_value(attribute_reader &reader, const char *id, const size_t index, uint8_t &value, const size_t /*size*/) {
|
||||
reader.read_value(id, index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<uint8_t>::bind_value(attribute_writer &binder, const size_t index, const uint8_t &value)
|
||||
{
|
||||
void data_type_traits<uint8_t>::bind_value(attribute_writer &binder, const size_t index, const uint8_t &value, const size_t /*size*/) {
|
||||
binder.write_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<uint16_t>::read_value(attribute_reader &reader, const char *id, const size_t index, uint16_t &value)
|
||||
{
|
||||
void data_type_traits<uint16_t>::read_value(attribute_reader &reader, const char *id, const size_t index, uint16_t &value, const size_t /*size*/) {
|
||||
reader.read_value(id, index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<uint16_t>::bind_value(attribute_writer &binder, const size_t index, const uint16_t &value)
|
||||
{
|
||||
void data_type_traits<uint16_t>::bind_value(attribute_writer &binder, const size_t index, const uint16_t &value, const size_t /*size*/) {
|
||||
binder.write_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<uint32_t>::read_value(attribute_reader &reader, const char *id, const size_t index, uint32_t &value)
|
||||
{
|
||||
void data_type_traits<uint32_t>::read_value(attribute_reader &reader, const char *id, const size_t index, uint32_t &value, const size_t /*size*/) {
|
||||
reader.read_value(id, index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<uint32_t>::bind_value(attribute_writer &binder, const size_t index, const uint32_t &value)
|
||||
{
|
||||
void data_type_traits<uint32_t>::bind_value(attribute_writer &binder, const size_t index, const uint32_t &value, const size_t /*size*/) {
|
||||
binder.write_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<uint64_t>::read_value(attribute_reader &reader, const char *id, const size_t index, uint64_t &value)
|
||||
{
|
||||
void data_type_traits<uint64_t>::read_value(attribute_reader &reader, const char *id, const size_t index, uint64_t &value, const size_t /*size*/) {
|
||||
reader.read_value(id, index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<uint64_t>::bind_value(attribute_writer &binder, const size_t index, const uint64_t &value)
|
||||
{
|
||||
void data_type_traits<uint64_t>::bind_value(attribute_writer &binder, const size_t index, const uint64_t &value, const size_t /*size*/) {
|
||||
binder.write_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<bool>::read_value(attribute_reader &reader, const char *id, const size_t index, bool &value)
|
||||
{
|
||||
void data_type_traits<bool>::read_value(attribute_reader &reader, const char *id, const size_t index, bool &value, const size_t /*size*/) {
|
||||
reader.read_value(id, index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<bool>::bind_value(attribute_writer &binder, const size_t index, const bool &value)
|
||||
{
|
||||
void data_type_traits<bool>::bind_value(attribute_writer &binder, const size_t index, const bool &value, const size_t /*size*/) {
|
||||
binder.write_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<float>::read_value(attribute_reader &reader, const char *id, const size_t index, float &value)
|
||||
{
|
||||
void data_type_traits<float>::read_value(attribute_reader &reader, const char *id, const size_t index, float &value, const size_t /*size*/) {
|
||||
reader.read_value(id, index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<float>::bind_value(attribute_writer &binder, const size_t index, const float &value)
|
||||
{
|
||||
void data_type_traits<float>::bind_value(attribute_writer &binder, const size_t index, const float &value, const size_t /*size*/) {
|
||||
binder.write_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<double>::read_value(attribute_reader &reader, const char *id, const size_t index, double &value)
|
||||
{
|
||||
void data_type_traits<double>::read_value(attribute_reader &reader, const char *id, const size_t index, double &value, const size_t /*size*/) {
|
||||
reader.read_value(id, index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<double>::bind_value(attribute_writer &binder, const size_t index, const double &value)
|
||||
{
|
||||
void data_type_traits<double>::bind_value(attribute_writer &binder, const size_t index, const double &value, const size_t /*size*/) {
|
||||
binder.write_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<const char*>::read_value(attribute_reader &reader, const char *id, const size_t index, const char* value, const size_t size)
|
||||
{
|
||||
void data_type_traits<const char*>::read_value(attribute_reader &reader, const char *id, const size_t index, const char* value, const size_t size) {
|
||||
reader.read_value(id, index, const_cast<char*>(value), size);
|
||||
}
|
||||
|
||||
void data_type_traits<const char *>::bind_value(attribute_writer &binder, const size_t index, const char *value, const size_t size)
|
||||
{
|
||||
void data_type_traits<const char *>::bind_value(attribute_writer &binder, const size_t index, const char *value, const size_t size) {
|
||||
binder.write_value(index, value, size);
|
||||
}
|
||||
|
||||
void data_type_traits<char*>::read_value(attribute_reader &reader, const char *id, const size_t index, char* value, const size_t size)
|
||||
{
|
||||
void data_type_traits<char*>::read_value(attribute_reader &reader, const char *id, const size_t index, char* value, const size_t size) {
|
||||
reader.read_value(id, index, value, size);
|
||||
}
|
||||
|
||||
void data_type_traits<char *>::bind_value(attribute_writer &binder, const size_t index, const char *value, const size_t size)
|
||||
{
|
||||
void data_type_traits<char *>::bind_value(attribute_writer &binder, const size_t index, const char *value, const size_t size) {
|
||||
binder.write_value(index, value, size);
|
||||
}
|
||||
|
||||
void data_type_traits<std::string>::read_value(attribute_reader &reader, const char *id, size_t index, std::string &value, size_t size)
|
||||
{
|
||||
void data_type_traits<std::string>::read_value(attribute_reader &reader, const char *id, const size_t index, std::string &value, const size_t size) {
|
||||
reader.read_value(id, index, value, size);
|
||||
}
|
||||
|
||||
void data_type_traits<std::string>::bind_value(attribute_writer &binder, size_t index, std::string &value, size_t size)
|
||||
{
|
||||
void data_type_traits<std::string>::bind_value(attribute_writer &binder, const size_t index, std::string &value, const size_t size) {
|
||||
binder.write_value(index, value, size);
|
||||
}
|
||||
|
||||
void data_type_traits<utils::blob, void>::read_value(attribute_reader &reader, const char *id, size_t index, utils::blob &value)
|
||||
{
|
||||
void data_type_traits<blob>::read_value(attribute_reader &reader, const char *id, const size_t index, utils::blob &value, const size_t /*size*/) {
|
||||
reader.read_value(id, index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<utils::blob, void>::bind_value(attribute_writer &binder, size_t index, utils::blob &value)
|
||||
{
|
||||
void data_type_traits<blob>::bind_value(attribute_writer &binder, const size_t index, utils::blob &value, const size_t /*size*/) {
|
||||
binder.write_value(index, value);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,12 @@
|
|||
#include <algorithm>
|
||||
|
||||
namespace matador::utils {
|
||||
std::string error::error_code() const {
|
||||
return ec_.message();
|
||||
}
|
||||
|
||||
std::string error::message() const {
|
||||
return ec_.message();;
|
||||
return error_message_;
|
||||
}
|
||||
|
||||
std::string error::category() const {
|
||||
|
|
|
|||
|
|
@ -2,14 +2,31 @@
|
|||
|
||||
namespace matador::utils {
|
||||
primary_key_attribute::primary_key_attribute(const size_t size)
|
||||
: size_(size) {}
|
||||
: size_( size ) {}
|
||||
|
||||
primary_key_attribute::primary_key_attribute(const generator_type generator)
|
||||
: generator_( generator ) {}
|
||||
|
||||
primary_key_attribute::primary_key_attribute(const size_t size, const generator_type generator)
|
||||
: size_( size )
|
||||
, generator_( generator ) {}
|
||||
|
||||
primary_key_attribute& primary_key_attribute::operator=(const size_t size) {
|
||||
size_ = size;
|
||||
return *this;
|
||||
size_ = size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
primary_key_attribute& primary_key_attribute::operator=(const generator_type generator) {
|
||||
generator_ = generator;
|
||||
return *this;
|
||||
}
|
||||
|
||||
size_t primary_key_attribute::size() const {
|
||||
return size_;
|
||||
return size_;
|
||||
}
|
||||
|
||||
generator_type primary_key_attribute::generator() const {
|
||||
return generator_;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -71,7 +71,6 @@ add_library(matador-orm STATIC
|
|||
query/attribute_string_writer.cpp
|
||||
query/basic_condition.cpp
|
||||
query/condition.cpp
|
||||
query/fk_value_extractor.cpp
|
||||
query/intermediates/executable_query.cpp
|
||||
query/intermediates/fetchable_query.cpp
|
||||
query/intermediates/query_create_intermediate.cpp
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ utils::result<void, utils::error> session::create_schema() const {
|
|||
for ( const auto& [sql, command] : ctx.additional_commands ) {
|
||||
fk_sql_commands.push_back( sql );
|
||||
}
|
||||
std::cout << ctx.sql << std::endl;
|
||||
if (auto result = c->execute(ctx.sql); !result) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
|
|
@ -65,6 +66,7 @@ utils::result<void, utils::error> session::create_schema() const {
|
|||
|
||||
// execute additional commands (e.g. ALTER TABLE ADD FK)
|
||||
for (const auto &sql: fk_sql_commands) {
|
||||
std::cout << sql << std::endl;
|
||||
if (auto result = c->execute(sql); !result) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
#include "matador/orm/session_insert_builder.hpp"
|
||||
|
||||
namespace matador::orm {
|
||||
void session_insert_builder::on_primary_key(const char* id, std::string& value, size_t) {
|
||||
push(id, value);
|
||||
}
|
||||
|
||||
void session_insert_builder::on_revision(const char* id, unsigned long long& x) {
|
||||
push(id, x);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,14 +3,6 @@
|
|||
#include <iostream>
|
||||
|
||||
namespace matador::orm {
|
||||
void session_query_builder::on_primary_key(const char *id, std::string &, size_t) {
|
||||
push(id);
|
||||
if (!is_root_entity()) {
|
||||
const auto b = pk_.is_varchar();
|
||||
std::cout << "is matching primary key: " << std::boolalpha << b << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void session_query_builder::on_revision(const char *id, unsigned long long &/*rev*/) {
|
||||
push(id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
#include "matador/query/fk_value_extractor.hpp"
|
||||
|
||||
namespace matador::query::detail {
|
||||
|
||||
void fk_value_extractor::on_primary_key(const char *, std::string &pk, size_t)
|
||||
{
|
||||
value_ = pk;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -7,11 +7,6 @@ namespace matador::sql {
|
|||
detail::pk_reader::pk_reader(query_result_reader &reader)
|
||||
: reader_(reader) {}
|
||||
|
||||
void detail::pk_reader::on_primary_key(const char *id, std::string &value, size_t size)
|
||||
{
|
||||
utils::data_type_traits<std::string>::read_value(reader_, id, column_index_++, value, size);
|
||||
}
|
||||
|
||||
query_result_impl::query_result_impl(std::unique_ptr<query_result_reader> &&reader, std::vector<object::attribute_definition> &&prototype, const size_t column_index)
|
||||
: column_index_(column_index)
|
||||
, prototype_(std::move(prototype))
|
||||
|
|
@ -26,11 +21,6 @@ query_result_impl::query_result_impl(std::unique_ptr<query_result_reader> &&read
|
|||
, pk_reader_(*reader_)
|
||||
{}
|
||||
|
||||
void query_result_impl::on_primary_key(const char *id, std::string &value, size_t size)
|
||||
{
|
||||
utils::data_type_traits<std::string>::read_value(*reader_, id, column_index_++, value, size);
|
||||
}
|
||||
|
||||
void query_result_impl::on_revision(const char *id, uint64_t &rev)
|
||||
{
|
||||
utils::data_type_traits<uint64_t>::read_value(*reader_, id, column_index_++, rev);
|
||||
|
|
|
|||
|
|
@ -4,13 +4,7 @@
|
|||
|
||||
namespace matador::query {
|
||||
|
||||
void key_value_generator::on_primary_key(const char *id, std::string &x, size_t)
|
||||
{
|
||||
result_.emplace_back(id, x);
|
||||
}
|
||||
|
||||
void key_value_generator::on_revision(const char *id, unsigned long long int &x)
|
||||
{
|
||||
void key_value_generator::on_revision(const char *id, unsigned long long int &x) {
|
||||
result_.emplace_back(id, x);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -275,8 +275,8 @@ void query_compiler::visit(internal::query_create_table_part &create_table_part)
|
|||
}
|
||||
for (const auto &[column, reference_column]: context.foreign_contexts) {
|
||||
// ALTER TABLE Orders ADD CONSTRAINT FK_PersonOrder FOREIGN KEY (PersonID) REFERENCES Persons(PersonID);
|
||||
std::string fk_cmd = "ALTER TABLE " + query_.table.name + " ADD";
|
||||
fk_cmd += " CONSTRAINT FK_" + create_table_part.table().name;
|
||||
std::string fk_cmd = "ALTER TABLE " + dialect_->prepare_identifier_string(query_.table.name) + " ADD";
|
||||
fk_cmd += " CONSTRAINT FK_" + query_.table.name;
|
||||
fk_cmd += "_" + column;
|
||||
fk_cmd += " FOREIGN KEY (" + dialect_->prepare_identifier_string(column) + ")";
|
||||
fk_cmd += " REFERENCES " + reference_column->table_name() + "(" + reference_column->name() + ")";
|
||||
|
|
|
|||
|
|
@ -6,11 +6,6 @@ value_extractor::value_extractor(std::vector<utils::database_type> &values)
|
|||
: values_(values)
|
||||
{}
|
||||
|
||||
void value_extractor::on_primary_key(const char *, std::string &pk, size_t s)
|
||||
{
|
||||
utils::data_type_traits<std::string>::bind_value(*this, 0, pk, s);
|
||||
}
|
||||
|
||||
void value_extractor::on_revision(const char *, uint64_t &rev)
|
||||
{
|
||||
utils::data_type_traits<uint64_t>::bind_value(*this, 0, rev);
|
||||
|
|
|
|||
|
|
@ -18,14 +18,6 @@ column_generator::column_generator(std::vector<column> &column_infos,
|
|||
seen_tables.insert(table_name);
|
||||
}
|
||||
|
||||
void column_generator::on_primary_key(const char *id, std::string &, size_t)
|
||||
{
|
||||
if (has_many_to_many_) {
|
||||
return;
|
||||
}
|
||||
push(id);
|
||||
}
|
||||
|
||||
void column_generator::on_revision(const char *id, unsigned long long int &)
|
||||
{
|
||||
if (has_many_to_many_) {
|
||||
|
|
|
|||
|
|
@ -4,25 +4,11 @@
|
|||
|
||||
namespace matador::sql {
|
||||
|
||||
namespace detail {
|
||||
|
||||
void fk_result_binder::on_primary_key(const char * /*id*/, std::string &value, const size_t size)
|
||||
{
|
||||
utils::data_type_traits<std::string>::read_value(*binder_, id_, index_++, value, size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void object_result_binder::reset()
|
||||
{
|
||||
index_ = 0;
|
||||
}
|
||||
|
||||
void object_result_binder::on_primary_key(const char *id, std::string &value, const size_t size)
|
||||
{
|
||||
utils::data_type_traits<std::string>::read_value(*binder_, id, index_++, value, size);
|
||||
}
|
||||
|
||||
void object_result_binder::on_revision(const char *id, uint64_t &value)
|
||||
{
|
||||
utils::data_type_traits<uint64_t>::read_value(*binder_, id, index_++, value);
|
||||
|
|
|
|||
|
|
@ -3,15 +3,6 @@
|
|||
#include "matador/utils/value.hpp"
|
||||
|
||||
namespace matador::sql::internal {
|
||||
void query_result_pk_resolver::on_primary_key(const char* id, std::string& /*value*/, const size_t size) {
|
||||
if (!type_stack_.empty()) {
|
||||
return;
|
||||
}
|
||||
std::string value;
|
||||
utils::data_type_traits<std::string>::read_value(reader_, id, column_index_++, value, size);
|
||||
pk_ = value;
|
||||
}
|
||||
|
||||
void query_result_pk_resolver::on_attribute(const char *id, const utils::value &x, const utils::field_attributes &attr) {
|
||||
if (is_constraint_set(attr.options(), utils::constraints::PRIMARY_KEY)) {
|
||||
if (x.is_integer()) {
|
||||
|
|
|
|||
|
|
@ -3,25 +3,11 @@
|
|||
|
||||
namespace matador::sql {
|
||||
|
||||
namespace detail {
|
||||
|
||||
void fk_binder::on_primary_key(const char * /*id*/, std::string &value, size_t /*size*/)
|
||||
{
|
||||
utils::data_type_traits<std::string>::bind_value(*binder_, index_++, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void object_parameter_binder::reset(const size_t start_index)
|
||||
{
|
||||
index_ = start_index;
|
||||
}
|
||||
|
||||
void object_parameter_binder::on_primary_key(const char * /*id*/, std::string &val, const size_t size)
|
||||
{
|
||||
utils::data_type_traits<std::string>::bind_value(*binder_, index_++, val, size);
|
||||
}
|
||||
|
||||
void object_parameter_binder::on_revision(const char * /*id*/, uint64_t &rev)
|
||||
{
|
||||
utils::data_type_traits<uint64_t>::bind_value(*binder_, index_++, rev);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,266 @@
|
|||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/matchers/catch_matchers_all.hpp>
|
||||
|
||||
#include "matador/net/reactor.hpp"
|
||||
#include "matador/net/handler.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
namespace {
|
||||
|
||||
class MockHandler : public matador::net::handler {
|
||||
public:
|
||||
explicit MockHandler(int fd = 1) : fd_(fd) {
|
||||
reset_counters();
|
||||
}
|
||||
|
||||
void reset_counters() {
|
||||
read_count = 0;
|
||||
write_count = 0;
|
||||
timeout_count = 0;
|
||||
close_count = 0;
|
||||
}
|
||||
|
||||
socket_type handle() const override { return fd_; }
|
||||
bool is_ready_read() const override { return ready_read_; }
|
||||
bool is_ready_write() const override { return ready_write_; }
|
||||
|
||||
void on_input() override { ++read_count; }
|
||||
void on_output() override { ++write_count; }
|
||||
void on_timeout() override { ++timeout_count; }
|
||||
void close() override { ++close_count; }
|
||||
|
||||
void set_ready_states(bool read, bool write) {
|
||||
ready_read_ = read;
|
||||
ready_write_ = write;
|
||||
}
|
||||
|
||||
static std::atomic<int> read_count;
|
||||
static std::atomic<int> write_count;
|
||||
static std::atomic<int> timeout_count;
|
||||
static std::atomic<int> close_count;
|
||||
|
||||
private:
|
||||
int fd_;
|
||||
bool ready_read_{false};
|
||||
bool ready_write_{false};
|
||||
};
|
||||
|
||||
std::atomic<int> MockHandler::read_count{0};
|
||||
std::atomic<int> MockHandler::write_count{0};
|
||||
std::atomic<int> MockHandler::timeout_count{0};
|
||||
std::atomic<int> MockHandler::close_count{0};
|
||||
|
||||
class ReactorTestFixture {
|
||||
protected:
|
||||
void SetUp() {
|
||||
MockHandler::read_count = 0;
|
||||
MockHandler::write_count = 0;
|
||||
MockHandler::timeout_count = 0;
|
||||
MockHandler::close_count = 0;
|
||||
}
|
||||
|
||||
matador::net::reactor reactor_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
SCENARIO_METHOD(ReactorTestFixture, "Reactor Handler Registration", "[reactor]") {
|
||||
GIVEN("A reactor and a handler") {
|
||||
auto handler = std::make_shared<MockHandler>();
|
||||
|
||||
WHEN("Registering handler for read events") {
|
||||
reactor_.register_handler(handler, matador::net::event_type::READ_MASK);
|
||||
|
||||
THEN("Handler should be registered") {
|
||||
auto fdsets = reactor_.fd_sets();
|
||||
REQUIRE(fdsets.read_set().is_set(handler->handle()));
|
||||
REQUIRE_FALSE(fdsets.write_set().is_set(handler->handle()));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("Registering handler for write events") {
|
||||
handler->set_ready_states(false, true);
|
||||
reactor_.register_handler(handler, matador::net::event_type::WRITE_MASK);
|
||||
|
||||
THEN("Handler should be registered for write") {
|
||||
auto fdsets = reactor_.fd_sets();
|
||||
REQUIRE(fdsets.write_set().is_set(handler->handle()));
|
||||
REQUIRE_FALSE(fdsets.read_set().is_set(handler->handle()));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("Registering null handler") {
|
||||
THEN("Should throw exception") {
|
||||
REQUIRE_THROWS_AS(
|
||||
reactor_.register_handler(nullptr, matador::net::event_type::READ_MASK),
|
||||
std::invalid_argument
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO_METHOD(ReactorTestFixture, "Reactor Handler Unregistration", "[reactor]") {
|
||||
GIVEN("A reactor with registered handler") {
|
||||
auto handler = std::make_shared<MockHandler>();
|
||||
reactor_.register_handler(handler, matador::event_type::READ_MASK);
|
||||
|
||||
WHEN("Unregistering the handler") {
|
||||
reactor_.unregister_handler(handler, matador::event_type::READ_MASK);
|
||||
|
||||
THEN("Handler should be unregistered") {
|
||||
auto fdsets = reactor_.fdsets();
|
||||
REQUIRE_FALSE(fdsets.read_set().is_set(handler->handle()));
|
||||
REQUIRE(MockHandler::close_count == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO_METHOD(ReactorTestFixture, "Reactor Timer Operations", "[reactor]") {
|
||||
GIVEN("A reactor and a handler") {
|
||||
auto handler = std::make_shared<MockHandler>();
|
||||
|
||||
WHEN("Scheduling a timer") {
|
||||
reactor_.schedule_timer(handler, 1, 0);
|
||||
|
||||
THEN("Timer should be scheduled") {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1500));
|
||||
reactor_.handle_events();
|
||||
REQUIRE(MockHandler::timeout_count == 1);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("Scheduling a repeating timer") {
|
||||
reactor_.schedule_timer(handler, 1, 1);
|
||||
|
||||
THEN("Timer should fire multiple times") {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(3500));
|
||||
reactor_.handle_events();
|
||||
REQUIRE(MockHandler::timeout_count >= 2);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("Cancelling a timer") {
|
||||
reactor_.schedule_timer(handler, 2, 0);
|
||||
reactor_.cancel_timer(handler);
|
||||
|
||||
THEN("Timer should not fire") {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(2500));
|
||||
reactor_.handle_events();
|
||||
REQUIRE(MockHandler::timeout_count == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO_METHOD(ReactorTestFixture, "Reactor Event Handling", "[reactor]") {
|
||||
GIVEN("A reactor with registered handlers") {
|
||||
auto read_handler = std::make_shared<MockHandler>(1);
|
||||
auto write_handler = std::make_shared<MockHandler>(2);
|
||||
|
||||
read_handler->set_ready_states(true, false);
|
||||
write_handler->set_ready_states(false, true);
|
||||
|
||||
reactor_.register_handler(read_handler, matador::event_type::READ_MASK);
|
||||
reactor_.register_handler(write_handler, matador::event_type::WRITE_MASK);
|
||||
|
||||
WHEN("Handling events") {
|
||||
std::thread reactor_thread([this]() {
|
||||
reactor_.run();
|
||||
});
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
THEN("Events should be processed") {
|
||||
REQUIRE(MockHandler::read_count > 0);
|
||||
REQUIRE(MockHandler::write_count > 0);
|
||||
}
|
||||
|
||||
reactor_.shutdown();
|
||||
reactor_thread.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO_METHOD(ReactorTestFixture, "Reactor Shutdown Behavior", "[reactor]") {
|
||||
GIVEN("A running reactor") {
|
||||
auto handler = std::make_shared<MockHandler>();
|
||||
reactor_.register_handler(handler, matador::event_type::READ_MASK);
|
||||
|
||||
std::thread reactor_thread([this]() {
|
||||
reactor_.run();
|
||||
});
|
||||
|
||||
WHEN("Shutting down the reactor") {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
reactor_.shutdown();
|
||||
reactor_thread.join();
|
||||
|
||||
THEN("Reactor should stop cleanly") {
|
||||
REQUIRE_FALSE(reactor_.is_running());
|
||||
REQUIRE(MockHandler::close_count == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO_METHOD(ReactorTestFixture, "Reactor Stress Test", "[reactor][stress]") {
|
||||
GIVEN("A reactor with multiple handlers") {
|
||||
std::vector<std::shared_ptr<MockHandler>> handlers;
|
||||
const int NUM_HANDLERS = 100;
|
||||
|
||||
for (int i = 0; i < NUM_HANDLERS; ++i) {
|
||||
auto handler = std::make_shared<MockHandler>(i + 1);
|
||||
handler->set_ready_states(true, true);
|
||||
handlers.push_back(handler);
|
||||
reactor_.register_handler(handler,
|
||||
matador::event_type::READ_MASK | matador::event_type::WRITE_MASK);
|
||||
}
|
||||
|
||||
WHEN("Running under load") {
|
||||
std::thread reactor_thread([this]() {
|
||||
reactor_.run();
|
||||
});
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||
|
||||
THEN("Should handle events without issues") {
|
||||
REQUIRE(MockHandler::read_count > 0);
|
||||
REQUIRE(MockHandler::write_count > 0);
|
||||
REQUIRE(reactor_.is_running());
|
||||
}
|
||||
|
||||
reactor_.shutdown();
|
||||
reactor_thread.join();
|
||||
|
||||
THEN("Should clean up properly") {
|
||||
REQUIRE(MockHandler::close_count == NUM_HANDLERS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO_METHOD(ReactorTestFixture, "Reactor Error Handling", "[reactor]") {
|
||||
GIVEN("A reactor with faulty handler") {
|
||||
class FaultyHandler : public MockHandler {
|
||||
void on_input() override { throw std::runtime_error("Simulated error"); }
|
||||
};
|
||||
|
||||
auto handler = std::make_shared<FaultyHandler>();
|
||||
handler->set_ready_states(true, false);
|
||||
|
||||
WHEN("Handling events with error") {
|
||||
reactor_.register_handler(handler, matador::event_type::READ_MASK);
|
||||
|
||||
THEN("Should handle error gracefully") {
|
||||
reactor_.handle_events();
|
||||
REQUIRE(reactor_.get_statistics().errors_ > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -58,5 +58,5 @@ TEST_CASE("Test version parsing", "[version][parse]") {
|
|||
|
||||
const auto v3 = version::from_string("a.b.c");
|
||||
REQUIRE(v3.is_error());
|
||||
REQUIRE(v3.err().message() == "Invalid version string");
|
||||
REQUIRE(v3.err().error_code() == "Invalid version string");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ struct product {
|
|||
namespace field = matador::access;
|
||||
using namespace matador::utils;
|
||||
field::primary_key(op, "product_name", product_name, 255);
|
||||
field::has_one(op, "supplier_id", supplier, utils::cascade_type::ALL);
|
||||
field::has_one(op, "category_id", category, utils::cascade_type::ALL);
|
||||
field::belongs_to(op, "supplier_id", supplier, utils::cascade_type::ALL);
|
||||
field::belongs_to(op, "category_id", category, utils::cascade_type::ALL);
|
||||
field::attribute(op, "quantity_per_unit", quantity_per_unit, 255);
|
||||
field::attribute(op, "unit_price", unit_price);
|
||||
field::attribute(op, "units_in_stock", units_in_stock);
|
||||
|
|
|
|||
|
|
@ -12,9 +12,6 @@
|
|||
|
||||
#include "matador/utils/placeholder.hpp"
|
||||
|
||||
// #include "models/author.hpp"
|
||||
// #include "models/book.hpp"
|
||||
|
||||
using namespace matador::test;
|
||||
using namespace matador::object;
|
||||
using namespace matador::sql;
|
||||
|
|
@ -31,15 +28,17 @@ TEST_CASE_METHOD(QueryFixture, "Test create table sql statement string", "[query
|
|||
|
||||
REQUIRE(result == R"##(CREATE TABLE "person" ("id" BIGINT NOT NULL, "name" VARCHAR(255) NOT NULL, "age" INTEGER NOT NULL, CONSTRAINT PK_person PRIMARY KEY (id)))##");
|
||||
|
||||
result = query::create()
|
||||
auto ctx = query::create()
|
||||
.table("person", {
|
||||
make_pk_column<uint32_t>("id"),
|
||||
make_column<std::string>("name", {255, constraints::UNIQUE}, null_option::NOT_NULL),
|
||||
make_column<unsigned short>("age"),
|
||||
make_fk_column<uint32_t>("address", "address", "id")
|
||||
}).str(*db);
|
||||
}).compile(*db);
|
||||
|
||||
REQUIRE(result == R"##(CREATE TABLE "person" ("id" BIGINT NOT NULL, "name" VARCHAR(255) NOT NULL UNIQUE, "age" INTEGER NOT NULL, "address" BIGINT NOT NULL, CONSTRAINT PK_person PRIMARY KEY (id), CONSTRAINT FK_person_address FOREIGN KEY (address) REFERENCES address(id)))##");
|
||||
REQUIRE(ctx.sql == R"##(CREATE TABLE "person" ("id" BIGINT NOT NULL, "name" VARCHAR(255) NOT NULL UNIQUE, "age" INTEGER NOT NULL, "address" BIGINT NOT NULL, CONSTRAINT PK_person PRIMARY KEY (id)))##");
|
||||
REQUIRE(ctx.additional_commands.size() == 1);
|
||||
REQUIRE(ctx.additional_commands[0].sql == R"##(ALTER TABLE "person" ADD CONSTRAINT FK_person_address FOREIGN KEY ("address") REFERENCES address(id))##");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(QueryFixture, "Test drop table sql statement string", "[query]") {
|
||||
|
|
|
|||
Loading…
Reference in New Issue