Compare commits
239
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24677d61df | ||
|
|
5da70ba3a5 | ||
|
|
c880728093 | ||
|
|
78b30f9742 | ||
|
|
b19d0fd3ca | ||
|
|
730ab05213 | ||
|
|
6ecda781f5 | ||
|
|
d4865e4d10 | ||
|
|
06f6166f05 | ||
|
|
89b795c488 | ||
|
|
1b98eb4019 | ||
|
|
47fd6d68e4 | ||
|
|
34a5cfcc88 | ||
|
|
705d361aaa | ||
|
|
87bd2f8b89 | ||
|
|
8914c06833 | ||
|
|
34a9a8aa4a | ||
|
|
12f8590634 | ||
|
|
cea7b97f2b | ||
|
|
bd06034ebf | ||
|
|
68d67b17b7 | ||
|
|
73bd6f641c | ||
|
|
98d58d8e60 | ||
|
|
b22a830d18 | ||
|
|
85e6ee4b93 | ||
|
|
2e1b583741 | ||
|
|
6701031007 | ||
|
|
57f57956de | ||
|
|
141d798a41 | ||
|
|
cc0bcbeb61 | ||
|
|
5ec7c13420 | ||
|
|
ddf19bbf07 | ||
|
|
194e139e8b | ||
|
|
6629a71f6e | ||
|
|
72019bc1e7 | ||
|
|
7216f07c9f | ||
|
|
aa8da1f76f | ||
|
|
627af1d1a8 | ||
|
|
0f3028c5c7 | ||
|
|
25405de2e0 | ||
|
|
e58b7b9b0d | ||
|
|
052ff657c1 | ||
|
|
08a28b1627 | ||
|
|
60f03246dc | ||
|
|
caacdfa34a | ||
|
|
8c8423bf64 | ||
|
|
820b5432b2 | ||
|
|
bf99642af4 | ||
|
|
9f54716df2 | ||
|
|
57703dfb67 | ||
|
|
22f6f71412 | ||
|
|
1cdd83cb31 | ||
|
|
e3618c60e3 | ||
|
|
ceb7795d9c | ||
|
|
68eb2b6a6e | ||
|
|
a714cd2a53 | ||
|
|
1e08996087 | ||
|
|
5e6ba3666e | ||
|
|
3d4a61749b | ||
|
|
3658664eb9 | ||
|
|
8753042b3c | ||
|
|
85d297995d | ||
|
|
e6adffc264 | ||
|
|
95cd363097 | ||
|
|
9c37e989ba | ||
|
|
e7523e2bba | ||
|
|
37855dc6fb | ||
|
|
433b0e40e1 | ||
|
|
3fb23e167e | ||
|
|
8e1dbe2ccd | ||
|
|
96c6c78cb8 | ||
|
|
1a22c70320 | ||
|
|
75d5cba6c3 | ||
|
|
656d045ccf | ||
|
|
3a82f4891a | ||
|
|
a34a3dc266 | ||
|
|
b6456356b4 | ||
|
|
9b25f7f556 | ||
|
|
78eb5d04cd | ||
|
|
59e1533cca | ||
|
|
f144b26dbb | ||
|
|
d734d647ed | ||
|
|
0a0e3752ea | ||
|
|
a0326632ab | ||
|
|
f03664d60a | ||
|
|
53ac6810d9 | ||
|
|
f62f3e626b | ||
|
|
d59b41d06c | ||
|
|
57246d8742 | ||
|
|
1806e2670c | ||
|
|
9e4660c4ee | ||
|
|
f4e984a288 | ||
|
|
855c9295fb | ||
|
|
40dfc30dae | ||
|
|
920fdc68ed | ||
|
|
f751541bdd | ||
|
|
833cb64352 | ||
|
|
597965b62f | ||
|
|
fedce38270 | ||
|
|
3fc08fb7ff | ||
|
|
ee8ce62687 | ||
|
|
905ee019d7 | ||
|
|
907bcf90a6 | ||
|
|
6b2db17f58 | ||
|
|
6423bd505b | ||
|
|
7996608f62 | ||
|
|
53b10fd1f9 | ||
|
|
86c9e6b1cd | ||
|
|
6bdf281eab | ||
|
|
801fbdd187 | ||
|
|
2aff0cabbb | ||
|
|
9b4738a5ff | ||
|
|
bc8158a6ca | ||
|
|
d9eaa2009f | ||
|
|
85c56584be | ||
|
|
1e78430855 | ||
|
|
626eae1ac8 | ||
|
|
0157233b02 | ||
|
|
cab3e508bb | ||
|
|
d50a8f2b76 | ||
|
|
e45c38b229 | ||
|
|
a2c5bca709 | ||
|
|
cfd2a9c423 | ||
|
|
1deaab116c | ||
|
|
02d6ac514c | ||
|
|
4377f2fab1 | ||
|
|
6c3af53dfa | ||
|
|
36168b2e33 | ||
|
|
e5072741f0 | ||
|
|
0876535b44 | ||
|
|
38dc42ade8 | ||
|
|
5668f1060b | ||
|
|
80426c5293 | ||
|
|
ac75bb6e3a | ||
|
|
ae7c1f510f | ||
|
|
a2a6448e03 | ||
|
|
f38be4c6d9 | ||
|
|
9065355ee0 | ||
|
|
746fd9e8d2 | ||
|
|
4c63322024 | ||
|
|
881e93e0f6 | ||
|
|
40b163ac39 | ||
|
|
99677b0e21 | ||
|
|
d9f9712487 | ||
|
|
c1620d620e | ||
|
|
cf977a32aa | ||
|
|
54e6786ceb | ||
|
|
a498efd21d | ||
|
|
c0e0499204 | ||
|
|
018e27a22a | ||
|
|
11bba90ded | ||
|
|
1a1ecd1613 | ||
|
|
520b2bab49 | ||
|
|
e7e66f44e2 | ||
|
|
4d886f0343 | ||
|
|
73abd61eba | ||
|
|
b2d5db2702 | ||
|
|
621c3703fd | ||
|
|
f9333158e2 | ||
|
|
c838e9dd7b | ||
|
|
0d3ab09c14 | ||
|
|
bcec740d60 | ||
|
|
602b77e67b | ||
|
|
6205ae81c9 | ||
|
|
b6cabbe3ed | ||
|
|
1cf39d0ef1 | ||
|
|
046c1d8ed2 | ||
|
|
64f2d6899a | ||
|
|
d69c0a5769 | ||
|
|
36a160e1c7 | ||
|
|
4b015c8ced | ||
|
|
15f959b24e | ||
|
|
d13ccc861e | ||
|
|
686b1ddb7a | ||
|
|
b331ef6923 | ||
|
|
328d164c05 | ||
|
|
ac514c3765 | ||
|
|
623a64b610 | ||
|
|
4c899ae2f2 | ||
|
|
5dae396842 | ||
|
|
bc1d5effd3 | ||
|
|
340fa5fd28 | ||
|
|
1143710f8d | ||
|
|
7626331866 | ||
|
|
db8e137c11 | ||
|
|
b9f5819be5 | ||
|
|
ac53526a27 | ||
|
|
930b9d1aa4 | ||
|
|
0bf945cd13 | ||
|
|
c6747074f5 | ||
|
|
f30c250a20 | ||
|
|
41f6c9f516 | ||
|
|
dfd31cdf35 | ||
|
|
099b72be05 | ||
|
|
9155927f89 | ||
|
|
f46d9b21a2 | ||
|
|
456a410946 | ||
|
|
c48bd4f9d6 | ||
|
|
0c6b5a0a93 | ||
|
|
f07a360da2 | ||
|
|
a79d50e6e8 | ||
|
|
7cb64515bd | ||
|
|
e768497cfd | ||
|
|
b9d35cbd4e | ||
|
|
ab2d39407c | ||
|
|
d104222fdd | ||
|
|
5e2d2ddde5 | ||
|
|
6307850721 | ||
|
|
9eec5b64fb | ||
|
|
4a19322ef8 | ||
|
|
9418f28348 | ||
|
|
348f3a16d0 | ||
|
|
9ba58eb05b | ||
|
|
758ea96ea4 | ||
|
|
79c46bbd38 | ||
|
|
571cfd52ae | ||
|
|
f842efb611 | ||
|
|
5afb616205 | ||
|
|
9b7b74524f | ||
|
|
c4f8731262 | ||
|
|
4fcbe9c064 | ||
|
|
d4a8801cd2 | ||
|
|
108eca4e53 | ||
|
|
d4ef97ef5a | ||
|
|
263c202c69 | ||
|
|
3b0b9615ca | ||
|
|
2fcb504b9a | ||
|
|
2e354b435c | ||
|
|
98da0884f1 | ||
|
|
d2f1bc0b8e | ||
|
|
980cabe94f | ||
|
|
bbe65f2a57 | ||
|
|
f6aa100435 | ||
|
|
e74424aaaa | ||
|
|
19eb54df8d | ||
|
|
bfbbd4c589 | ||
|
|
c156ab5e74 | ||
|
|
422df82b7c | ||
|
|
19b7044773 |
@@ -0,0 +1,2 @@
|
|||||||
|
# Generated by CLion for Google
|
||||||
|
BasedOnStyle: Google
|
||||||
+1
-1
@@ -30,7 +30,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|||||||
set(CMAKE_CXX_FLAGS_RELEASE "${GCC_CLANG_COMMON_FLAGS_RELEASE}")
|
set(CMAKE_CXX_FLAGS_RELEASE "${GCC_CLANG_COMMON_FLAGS_RELEASE}")
|
||||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||||
message(STATUS "MSVC detected - Adding compiler flags")
|
message(STATUS "MSVC detected - Adding compiler flags")
|
||||||
# set(CMAKE_CXX_FLAGS "/W3 /EHsc /bigobj")
|
set(CMAKE_CXX_FLAGS "/W3 /EHsc /bigobj")
|
||||||
# set(CMAKE_CXX_FLAGS_DEBUG "/MDd /Od /Zi /D_DEBUG /DDEBUG")
|
# set(CMAKE_CXX_FLAGS_DEBUG "/MDd /Od /Zi /D_DEBUG /DDEBUG")
|
||||||
# set(CMAKE_CXX_FLAGS_RELEASE "/O1 /DNDEBUG")
|
# set(CMAKE_CXX_FLAGS_RELEASE "/O1 /DNDEBUG")
|
||||||
add_compile_options(/Zc:preprocessor)
|
add_compile_options(/Zc:preprocessor)
|
||||||
|
|||||||
@@ -31,24 +31,28 @@ public:
|
|||||||
[[nodiscard]] utils::result<utils::version, utils::error> client_version() const override;
|
[[nodiscard]] utils::result<utils::version, utils::error> client_version() const override;
|
||||||
[[nodiscard]] utils::result<utils::version, utils::error> server_version() const override;
|
[[nodiscard]] utils::result<utils::version, utils::error> server_version() const override;
|
||||||
|
|
||||||
utils::result<size_t, utils::error> execute(const std::string &stmt) override;
|
utils::result<sql::execute_result, utils::error> execute(const sql::query_context &context) override;
|
||||||
utils::result<std::unique_ptr<sql::statement_impl>, utils::error> prepare(const sql::query_context &context) override;
|
utils::result<std::unique_ptr<sql::statement_impl>, utils::error> prepare(const sql::query_context &context) override;
|
||||||
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetch(const sql::query_context &context) override;
|
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetch(const sql::query_context &ctx) override;
|
||||||
|
|
||||||
utils::result<std::vector<object::attribute>, utils::error> describe(const std::string& table) override;
|
utils::result<std::vector<object::attribute>, utils::error> describe(const std::string& table) override;
|
||||||
utils::result<bool, utils::error> exists(const std::string &schema_name, const std::string &table_name) override;
|
utils::result<bool, utils::error> exists(const std::string &schema_name, const std::string &table_name) override;
|
||||||
|
|
||||||
[[nodiscard]] std::string to_escaped_string( const utils::blob& value ) const override;
|
utils::result<bool, utils::error> sequence_exists(const std::string &schema_name, const std::string &sequence_name) override;
|
||||||
|
|
||||||
|
[[nodiscard]] std::string to_escaped_string( const utils::blob_type_t& value ) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] static std::string generate_statement_name(const sql::query_context &query) ;
|
[[nodiscard]] static std::string generate_statement_name(const sql::query_context &ctx) ;
|
||||||
|
|
||||||
|
[[nodiscard]] utils::result<sql::execute_result, utils::error> execute(const std::string &stmt) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PGconn *conn_{nullptr};
|
PGconn *conn_{nullptr};
|
||||||
|
|
||||||
using string_to_int_map = std::unordered_map<std::string, unsigned long>;
|
using hash_to_string_map = std::unordered_map<size_t, std::string>;
|
||||||
|
|
||||||
static string_to_int_map statement_name_map_;
|
static hash_to_string_map statement_name_map_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,13 +31,14 @@ public:
|
|||||||
void write_value(size_t pos, const bool &x) override;
|
void write_value(size_t pos, const bool &x) override;
|
||||||
void write_value(size_t pos, const float &x) override;
|
void write_value(size_t pos, const float &x) override;
|
||||||
void write_value(size_t pos, const double &x) override;
|
void write_value(size_t pos, const double &x) override;
|
||||||
void write_value(size_t pos, const time &x ) override;
|
void write_value(size_t pos, const utils::date_type_t &x ) override;
|
||||||
void write_value(size_t pos, const date &x ) override;
|
void write_value(size_t pos, const utils::time_type_t &x ) override;
|
||||||
|
void write_value(size_t pos, const utils::timestamp_type_t &x ) override;
|
||||||
void write_value(size_t pos, const char *x) override;
|
void write_value(size_t pos, const char *x) override;
|
||||||
void write_value(size_t pos, const char *x, size_t size) override;
|
void write_value(size_t pos, const char *x, size_t size) override;
|
||||||
void write_value(size_t pos, const std::string &x) override;
|
void write_value(size_t pos, const std::string &x) override;
|
||||||
void write_value(size_t pos, const std::string &x, size_t size) override;
|
void write_value(size_t pos, const std::string &x, size_t size) override;
|
||||||
void write_value(size_t pos, const utils::blob &x) override;
|
void write_value(size_t pos, const utils::blob_type_t &x) override;
|
||||||
void write_value(size_t pos, const utils::value &x, size_t size) override;
|
void write_value(size_t pos, const utils::value &x, size_t size) override;
|
||||||
|
|
||||||
[[nodiscard]] const bind_data& params() const;
|
[[nodiscard]] const bind_data& params() const;
|
||||||
|
|||||||
@@ -9,8 +9,7 @@ namespace matador::backends::postgres {
|
|||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
class empty_binder final : public utils::attribute_reader
|
class empty_binder final : public utils::attribute_reader {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
void read_value(const char *, size_t, int8_t &) override {}
|
void read_value(const char *, size_t, int8_t &) override {}
|
||||||
void read_value(const char *, size_t, int16_t &) override {}
|
void read_value(const char *, size_t, int16_t &) override {}
|
||||||
@@ -23,19 +22,19 @@ public:
|
|||||||
void read_value(const char *, size_t, bool &) override {}
|
void read_value(const char *, size_t, bool &) override {}
|
||||||
void read_value(const char *, size_t, float &) override {}
|
void read_value(const char *, size_t, float &) override {}
|
||||||
void read_value(const char *, size_t, double &) override {}
|
void read_value(const char *, size_t, double &) override {}
|
||||||
void read_value(const char *, size_t, time &) override {}
|
void read_value(const char *, size_t, utils::date_type_t &) override {}
|
||||||
void read_value(const char *, size_t, date &) override {}
|
void read_value(const char *, size_t, utils::time_type_t &) override {}
|
||||||
|
void read_value(const char *, size_t, utils::timestamp_type_t &) override {}
|
||||||
void read_value(const char *, size_t, char *, size_t) override {}
|
void read_value(const char *, size_t, char *, size_t) override {}
|
||||||
void read_value(const char *, size_t, std::string &) override {}
|
void read_value(const char *, size_t, std::string &) override {}
|
||||||
void read_value(const char *, size_t, std::string &, size_t) override {}
|
void read_value(const char *, size_t, std::string &, size_t) override {}
|
||||||
void read_value(const char *, size_t, utils::blob &) override {}
|
void read_value(const char *, size_t, utils::blob_type_t &) override {}
|
||||||
void read_value(const char *, size_t, utils::value &, size_t) override {}
|
void read_value(const char *, size_t, utils::value &, size_t) override {}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class postgres_result_reader final : public sql::query_result_reader
|
class postgres_result_reader final : public sql::query_result_reader {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
explicit postgres_result_reader(PGresult *result);
|
explicit postgres_result_reader(PGresult *result);
|
||||||
~postgres_result_reader() override;
|
~postgres_result_reader() override;
|
||||||
@@ -57,12 +56,13 @@ public:
|
|||||||
void read_value(const char *id, size_t index, bool &value) override;
|
void read_value(const char *id, size_t index, bool &value) override;
|
||||||
void read_value(const char *id, size_t index, float &value) override;
|
void read_value(const char *id, size_t index, float &value) override;
|
||||||
void read_value(const char *id, size_t index, double &value) override;
|
void read_value(const char *id, size_t index, double &value) override;
|
||||||
void read_value(const char *id, size_t index, matador::time &value) override;
|
void read_value(const char *id, size_t index, utils::date_type_t &) override;
|
||||||
void read_value(const char *id, size_t index, matador::date &value) override;
|
void read_value(const char *id, size_t index, utils::time_type_t &) override;
|
||||||
|
void read_value(const char *id, size_t index, utils::timestamp_type_t &) override;
|
||||||
void read_value(const char *id, size_t index, char *value, size_t size) override;
|
void read_value(const char *id, size_t index, char *value, size_t size) override;
|
||||||
void read_value(const char *id, size_t index, std::string &value) override;
|
void read_value(const char *id, size_t index, std::string &value) override;
|
||||||
void read_value(const char *id, size_t index, std::string &value, size_t size) override;
|
void read_value(const char *id, size_t index, std::string &value, size_t size) override;
|
||||||
void read_value(const char *id, size_t index, utils::blob &value) override;
|
void read_value(const char *id, size_t index, utils::blob_type_t &value) override;
|
||||||
void read_value(const char *id, size_t index, utils::value &val, size_t size) override;
|
void read_value(const char *id, size_t index, utils::value &val, size_t size) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ namespace matador::backends::postgres {
|
|||||||
class postgres_statement final : public sql::statement_impl
|
class postgres_statement final : public sql::statement_impl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
postgres_statement(PGconn *db, std::string name, const sql::query_context &query);
|
postgres_statement(PGconn *db, PGresult *res, std::string name, const sql::query_context &query);
|
||||||
|
~postgres_statement() override;
|
||||||
|
|
||||||
utils::result<size_t, utils::error> execute(const sql::parameter_binder& bindings) override;
|
utils::result<sql::execute_result, utils::error> execute(const sql::parameter_binder& bindings) override;
|
||||||
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetch(const sql::parameter_binder& bindings) override;
|
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetch(const sql::parameter_binder& bindings) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -21,6 +22,7 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
PGconn *db_{nullptr};
|
PGconn *db_{nullptr};
|
||||||
|
PGresult *res_ = nullptr;
|
||||||
|
|
||||||
std::string name_;
|
std::string name_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,17 +7,18 @@
|
|||||||
|
|
||||||
#include "matador/sql/error_code.hpp"
|
#include "matador/sql/error_code.hpp"
|
||||||
#include "matador/sql/record.hpp"
|
#include "matador/sql/record.hpp"
|
||||||
|
|
||||||
#include "matador/sql/internal/query_result_impl.hpp"
|
#include "matador/sql/internal/query_result_impl.hpp"
|
||||||
|
|
||||||
|
#include "matador/utils/string.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
namespace matador::backends::postgres {
|
namespace matador::backends::postgres {
|
||||||
postgres_connection::string_to_int_map postgres_connection::statement_name_map_{};
|
postgres_connection::hash_to_string_map postgres_connection::statement_name_map_{};
|
||||||
|
|
||||||
postgres_connection::postgres_connection(const sql::connection_info &info)
|
postgres_connection::postgres_connection(const sql::connection_info &info)
|
||||||
: connection_impl(info) {
|
: connection_impl(info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
utils::result<void, utils::error> postgres_connection::open() {
|
utils::result<void, utils::error> postgres_connection::open() {
|
||||||
@@ -34,7 +35,7 @@ utils::result<void, utils::error> postgres_connection::open() {
|
|||||||
const std::string msg = PQerrorMessage(conn_);
|
const std::string msg = PQerrorMessage(conn_);
|
||||||
PQfinish(conn_);
|
PQfinish(conn_);
|
||||||
conn_ = nullptr;
|
conn_ = nullptr;
|
||||||
return utils::failure(make_error(sql::error_code::OPEN_ERROR, nullptr, conn_, "Failed to connect"));
|
return utils::failure(make_error(sql::error_code::OpenError, nullptr, conn_, "Failed to connect"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils::ok<void>();
|
return utils::ok<void>();
|
||||||
@@ -70,7 +71,7 @@ utils::result<utils::version, utils::error> postgres_connection::server_version(
|
|||||||
const auto server_version = PQserverVersion(conn_);
|
const auto server_version = PQserverVersion(conn_);
|
||||||
|
|
||||||
if (server_version == 0) {
|
if (server_version == 0) {
|
||||||
return utils::failure(make_error(sql::error_code::FAILURE, nullptr, conn_, "Failed to get server version"));
|
return utils::failure(make_error(sql::error_code::Failure, nullptr, conn_, "Failed to get server version"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils::ok(utils::version{
|
return utils::ok(utils::version{
|
||||||
@@ -82,18 +83,22 @@ utils::result<utils::version, utils::error> postgres_connection::server_version(
|
|||||||
|
|
||||||
utils::basic_type oid2type(Oid oid);
|
utils::basic_type oid2type(Oid oid);
|
||||||
|
|
||||||
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> postgres_connection::fetch(const sql::query_context &context) {
|
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> postgres_connection::fetch(const sql::query_context &ctx) {
|
||||||
PGresult *res = PQexec(conn_, context.sql.c_str());
|
PGresult *res = PQexec(conn_, ctx.sql.c_str());
|
||||||
|
|
||||||
if (is_result_error(res)) {
|
if (is_result_error(res)) {
|
||||||
return utils::failure(make_error(sql::error_code::FETCH_FAILED, res, conn_, "Failed to fetch", context.sql));
|
const auto err = make_error(sql::error_code::FetchFailed, res, conn_, "Failed to fetch", ctx.sql);
|
||||||
|
PQclear(res);
|
||||||
|
return utils::failure(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<object::attribute> prototype = context.prototype;
|
std::vector<object::attribute> prototype = ctx.prototype;
|
||||||
|
|
||||||
const int num_col = PQnfields(res);
|
const int num_col = PQnfields(res);
|
||||||
if (prototype.size() != static_cast<size_t>(num_col)) {
|
if (prototype.size() != static_cast<size_t>(num_col)) {
|
||||||
return utils::failure(make_error(sql::error_code::FETCH_FAILED, res, conn_, "Number of received columns doesn't match expected columns.", context.sql));
|
const auto err = make_error(sql::error_code::FetchFailed, res, conn_, "Number of received columns doesn't match expected columns.", ctx.sql);
|
||||||
|
PQclear(res);
|
||||||
|
return utils::failure(err);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < num_col; ++i) {
|
for (int i = 0; i < num_col; ++i) {
|
||||||
if (!prototype.at(i).is_null()) {
|
if (!prototype.at(i).is_null()) {
|
||||||
@@ -105,111 +110,139 @@ utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> postgres_co
|
|||||||
prototype.at(i).change_type(type);
|
prototype.at(i).change_type(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils::ok(std::make_unique<sql::query_result_impl>(std::make_unique<postgres_result_reader>(res), prototype));
|
return utils::ok(std::make_unique<sql::query_result_impl>(std::make_unique<postgres_result_reader>(res),
|
||||||
|
std::move(prototype),
|
||||||
|
ctx.resolver,
|
||||||
|
ctx.result_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string postgres_connection::generate_statement_name(const sql::query_context &query) {
|
std::string postgres_connection::generate_statement_name(const sql::query_context &ctx) {
|
||||||
std::stringstream name;
|
auto it = statement_name_map_.find(ctx.sql_hash);
|
||||||
name << query.table_name << "_" << query.command_name;
|
|
||||||
auto result = postgres_connection::statement_name_map_.find(name.str());
|
|
||||||
|
|
||||||
if (result == postgres_connection::statement_name_map_.end()) {
|
if (it == statement_name_map_.end()) {
|
||||||
result = postgres_connection::statement_name_map_.insert(std::make_pair(name.str(), 0)).first;
|
it = statement_name_map_.insert(std::make_pair(ctx.sql_hash, utils::to_hex_string(ctx.sql_hash))).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
name << "_" << ++result->second;
|
return it->second;
|
||||||
|
|
||||||
return name.str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
utils::result<std::unique_ptr<sql::statement_impl>, utils::error> postgres_connection::prepare(const sql::query_context &context) {
|
utils::result<sql::execute_result, utils::error> postgres_connection::execute(const std::string& stmt) const {
|
||||||
auto statement_name = postgres_connection::generate_statement_name(context);
|
|
||||||
|
|
||||||
const PGresult *result = PQprepare(conn_, statement_name.c_str(), context.sql.c_str(),
|
|
||||||
static_cast<int>(context.bind_vars.size()), nullptr);
|
|
||||||
|
|
||||||
if (is_result_error(result)) {
|
|
||||||
return utils::failure(make_error(sql::error_code::PREPARE_FAILED, result, conn_, "Failed to prepare", context.sql));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<sql::statement_impl> s(std::make_unique<postgres_statement>(conn_, statement_name, context));
|
|
||||||
return utils::ok(std::move(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
utils::result<size_t, utils::error> postgres_connection::execute(const std::string &stmt) {
|
|
||||||
PGresult *res = PQexec(conn_, stmt.c_str());
|
PGresult *res = PQexec(conn_, stmt.c_str());
|
||||||
|
|
||||||
if (const auto status = PQresultStatus(res); status != PGRES_COMMAND_OK &&
|
if (const auto status = PQresultStatus(res); status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) {
|
||||||
status != PGRES_TUPLES_OK) {
|
return utils::failure(make_error(sql::error_code::Failure, res, conn_, "Failed to execute", stmt));
|
||||||
return utils::failure(make_error(sql::error_code::FAILURE, res, conn_, "Failed to execute", stmt));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto affected_rows = utils::to<size_t>(PQcmdTuples(res));
|
const size_t affected_rows = utils::to<size_t>(PQcmdTuples(res));
|
||||||
|
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
||||||
return utils::ok(static_cast<size_t>(affected_rows));
|
return utils::ok(sql::execute_result{affected_rows});
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::result<std::unique_ptr<sql::statement_impl>, utils::error> postgres_connection::prepare(const sql::query_context &context) {
|
||||||
|
auto statement_name = generate_statement_name(context);
|
||||||
|
|
||||||
|
PGresult *result = PQprepare(conn_, statement_name.c_str(), context.sql.c_str(), static_cast<int>(context.bind_vars.size()), nullptr);
|
||||||
|
|
||||||
|
if (is_result_error(result)) {
|
||||||
|
return utils::failure(make_error(sql::error_code::PrepareFailed, result, conn_, "Failed to prepare", context.sql));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<sql::statement_impl> s(std::make_unique<postgres_statement>(conn_, result, statement_name, context));
|
||||||
|
return utils::ok(std::move(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::result<sql::execute_result, utils::error> postgres_connection::execute(const sql::query_context &context) {
|
||||||
|
return execute(context.sql);
|
||||||
|
PGresult *res = PQexec(conn_, context.sql.c_str());
|
||||||
|
|
||||||
|
if (const auto status = PQresultStatus(res); status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) {
|
||||||
|
return utils::failure(make_error(sql::error_code::Failure, res, conn_, "Failed to execute", context.sql));
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t affected_rows = utils::to<size_t>(PQcmdTuples(res));
|
||||||
|
|
||||||
|
PQclear(res);
|
||||||
|
|
||||||
|
return utils::ok(sql::execute_result{affected_rows});
|
||||||
}
|
}
|
||||||
|
|
||||||
utils::basic_type oid2type(const Oid oid) {
|
utils::basic_type oid2type(const Oid oid) {
|
||||||
switch (oid) {
|
switch (oid) {
|
||||||
case 16:
|
case 16:
|
||||||
return utils::basic_type::type_bool;
|
return utils::basic_type::Boolean;
|
||||||
case 17:
|
case 17:
|
||||||
return utils::basic_type::type_blob;
|
return utils::basic_type::Blob;
|
||||||
case 18:
|
case 18:
|
||||||
return utils::basic_type::type_int8;
|
return utils::basic_type::Int8;
|
||||||
case 21:
|
case 21:
|
||||||
return utils::basic_type::type_int16;
|
return utils::basic_type::Int16;
|
||||||
case 23:
|
case 23:
|
||||||
return utils::basic_type::type_int32;
|
return utils::basic_type::Int32;
|
||||||
case 20:
|
case 20:
|
||||||
return utils::basic_type::type_int64;
|
return utils::basic_type::Int64;
|
||||||
case 25:
|
case 25:
|
||||||
return utils::basic_type::type_text;
|
return utils::basic_type::Text;
|
||||||
case 1043:
|
case 1043:
|
||||||
return utils::basic_type::type_varchar;
|
return utils::basic_type::Varchar;
|
||||||
case 700:
|
case 700:
|
||||||
return utils::basic_type::type_float;
|
return utils::basic_type::Float;
|
||||||
case 701:
|
case 701:
|
||||||
return utils::basic_type::type_double;
|
return utils::basic_type::Double;
|
||||||
case 1082:
|
case 1082:
|
||||||
return utils::basic_type::type_date;
|
return utils::basic_type::Date;
|
||||||
|
case 1083:
|
||||||
|
return utils::basic_type::Time;
|
||||||
case 1114:
|
case 1114:
|
||||||
return utils::basic_type::type_time;
|
return utils::basic_type::DateTime;
|
||||||
default:
|
default:
|
||||||
return utils::basic_type::type_null;
|
return utils::basic_type::Null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
utils::basic_type string2type(const char *type) {
|
utils::basic_type string2type(const char *type) {
|
||||||
if (strcmp(type, "int2") == 0) {
|
if (strcmp(type, "int2") == 0) {
|
||||||
return utils::basic_type::type_int16;
|
return utils::basic_type::Int16;
|
||||||
} else if (strcmp(type, "int4") == 0) {
|
|
||||||
return utils::basic_type::type_int32;
|
|
||||||
} else if (strcmp(type, "int8") == 0) {
|
|
||||||
return utils::basic_type::type_int64;
|
|
||||||
} else if (strcmp(type, "bool") == 0) {
|
|
||||||
return utils::basic_type::type_bool;
|
|
||||||
} else if (strcmp(type, "date") == 0) {
|
|
||||||
return utils::basic_type::type_date;
|
|
||||||
} else if (strcmp(type, "timestamp") == 0) {
|
|
||||||
return utils::basic_type::type_time;
|
|
||||||
} else if (strcmp(type, "float4") == 0) {
|
|
||||||
return utils::basic_type::type_float;
|
|
||||||
} else if (strcmp(type, "float8") == 0) {
|
|
||||||
return utils::basic_type::type_double;
|
|
||||||
} else if (strncmp(type, "varchar", 7) == 0) {
|
|
||||||
return utils::basic_type::type_varchar;
|
|
||||||
} else if (strcmp(type, "character varying") == 0) {
|
|
||||||
return utils::basic_type::type_varchar;
|
|
||||||
} else if (strcmp(type, "text") == 0) {
|
|
||||||
return utils::basic_type::type_text;
|
|
||||||
} else if (strcmp(type, "bytea") == 0) {
|
|
||||||
return utils::basic_type::type_blob;
|
|
||||||
} else {
|
|
||||||
return utils::basic_type::type_null;
|
|
||||||
}
|
}
|
||||||
|
if (strcmp(type, "int4") == 0) {
|
||||||
|
return utils::basic_type::Int32;
|
||||||
|
}
|
||||||
|
if (strcmp(type, "int8") == 0) {
|
||||||
|
return utils::basic_type::Int64;
|
||||||
|
}
|
||||||
|
if (strcmp(type, "bool") == 0) {
|
||||||
|
return utils::basic_type::Boolean;
|
||||||
|
}
|
||||||
|
if (strcmp(type, "date") == 0) {
|
||||||
|
return utils::basic_type::Date;
|
||||||
|
}
|
||||||
|
if (strcmp(type, "time") == 0) {
|
||||||
|
return utils::basic_type::Time;
|
||||||
|
}
|
||||||
|
if (strcmp(type, "timestamp") == 0) {
|
||||||
|
return utils::basic_type::DateTime;
|
||||||
|
}
|
||||||
|
if (strcmp(type, "float4") == 0) {
|
||||||
|
return utils::basic_type::Float;
|
||||||
|
}
|
||||||
|
if (strcmp(type, "float8") == 0) {
|
||||||
|
return utils::basic_type::Double;
|
||||||
|
}
|
||||||
|
if (strncmp(type, "varchar", 7) == 0) {
|
||||||
|
return utils::basic_type::Varchar;
|
||||||
|
}
|
||||||
|
if (strcmp(type, "character varying") == 0) {
|
||||||
|
return utils::basic_type::Varchar;
|
||||||
|
}
|
||||||
|
if (strcmp(type, "text") == 0) {
|
||||||
|
return utils::basic_type::Text;
|
||||||
|
}
|
||||||
|
if (strcmp(type, "bytea") == 0) {
|
||||||
|
return utils::basic_type::Blob;
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils::basic_type::Null;
|
||||||
}
|
}
|
||||||
|
|
||||||
utils::result<std::vector<object::attribute>, utils::error> postgres_connection::describe(const std::string &table) {
|
utils::result<std::vector<object::attribute>, utils::error> postgres_connection::describe(const std::string &table) {
|
||||||
@@ -220,7 +253,7 @@ utils::result<std::vector<object::attribute>, utils::error> postgres_connection:
|
|||||||
PGresult *res = PQexec(conn_, stmt.c_str());
|
PGresult *res = PQexec(conn_, stmt.c_str());
|
||||||
|
|
||||||
if (is_result_error(res)) {
|
if (is_result_error(res)) {
|
||||||
return utils::failure(make_error(sql::error_code::DESCRIBE_FAILED, res, conn_, "Failed to describe", stmt));
|
return utils::failure(make_error(sql::error_code::DescribeFailed, res, conn_, "Failed to describe", stmt));
|
||||||
}
|
}
|
||||||
|
|
||||||
postgres_result_reader reader(res);
|
postgres_result_reader reader(res);
|
||||||
@@ -234,49 +267,66 @@ utils::result<std::vector<object::attribute>, utils::error> postgres_connection:
|
|||||||
}
|
}
|
||||||
char *end = nullptr;
|
char *end = nullptr;
|
||||||
// Todo: Handle error
|
// Todo: Handle error
|
||||||
auto index = strtoul(reader.column(0), &end, 10) - 1;
|
// auto index = strtoul(reader.column(0), &end, 10) - 1;
|
||||||
std::string name = reader.column(1);
|
std::string name = reader.column(1);
|
||||||
|
|
||||||
// Todo: extract size
|
// Todo: extract size
|
||||||
auto type = (string2type(reader.column(2)));
|
auto type = (string2type(reader.column(2)));
|
||||||
end = nullptr;
|
end = nullptr;
|
||||||
object::null_option_type null_opt{object::null_option_type::NULLABLE};
|
object::null_option_type null_opt{object::null_option_type::Nullable};
|
||||||
if (strtoul(reader.column(4), &end, 10) == 0) {
|
if (strtoul(reader.column(4), &end, 10) == 0) {
|
||||||
null_opt = object::null_option_type::NOT_NULL;
|
null_opt = object::null_option_type::NotNull;
|
||||||
}
|
}
|
||||||
// f.default_value(res->column(4));
|
// f.default_value(res->column(4));
|
||||||
prototype.emplace_back(name, type, utils::null_attributes, null_opt, index);
|
prototype.emplace_back(name, type, NullAttributes, null_opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils::ok(prototype);
|
return utils::ok(prototype);
|
||||||
}
|
}
|
||||||
|
|
||||||
utils::result<bool, utils::error> postgres_connection::exists(const std::string &schema_name, const std::string &table_name) {
|
utils::result<bool, utils::error> postgres_connection::exists(const std::string &schema_name,
|
||||||
const std::string stmt(
|
const std::string &table_name) {
|
||||||
"SELECT 1 FROM information_schema.tables WHERE table_schema = '" + schema_name + "' AND table_name = '" + table_name
|
std::string stmt("SELECT 1 FROM information_schema.tables WHERE table_name = '" + table_name + "'");
|
||||||
+ "'");
|
if (!schema_name.empty()) {
|
||||||
|
stmt += " AND table_schema = '" + schema_name + "'";
|
||||||
|
}
|
||||||
|
|
||||||
PGresult *res = PQexec(conn_, stmt.c_str());
|
PGresult *res = PQexec(conn_, stmt.c_str());
|
||||||
|
|
||||||
if (is_result_error(res)) {
|
if (is_result_error(res)) {
|
||||||
return utils::failure(make_error(sql::error_code::TABLE_EXISTS_FAILED, res, conn_, "Failed check if table exists", stmt));
|
return utils::failure(make_error(sql::error_code::TableExistsFailed, res, conn_, "Failed check if table exists", stmt));
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto result = utils::to<size_t>(PQcmdTuples(res));
|
const auto result = utils::to<size_t>(PQcmdTuples(res));
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return utils::failure(make_error(sql::error_code::FAILURE, res, conn_, "Failed to convert result value", stmt));
|
PQclear(res);
|
||||||
|
return utils::failure(make_error(sql::error_code::Failure, res, conn_, "Failed to convert result value", stmt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PQclear(res);
|
||||||
return utils::ok(*result == 1);
|
return utils::ok(*result == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string postgres_connection::to_escaped_string(const utils::blob& value) const
|
utils::result<bool, utils::error> postgres_connection::sequence_exists(const std::string& schema_name, const std::string& sequence_name) {
|
||||||
{
|
const std::string sql{"SELECT to_regclass('" + schema_name + "." + sequence_name + "')"};
|
||||||
|
PGresult* res = PQexec(conn_, sql.c_str());
|
||||||
|
|
||||||
|
if (PQresultStatus(res) != PGRES_TUPLES_OK) {
|
||||||
|
return utils::failure(make_error(sql::error_code::SequenceExistsFailed, res, conn_, "Failed check if sequence exists", sql));
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool exists = PQgetisnull(res, 0, 0) ? false : true;
|
||||||
|
PQclear(res);
|
||||||
|
|
||||||
|
return utils::ok(exists);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string postgres_connection::to_escaped_string(const utils::blob_type_t &value) const {
|
||||||
size_t escapedDataLength;
|
size_t escapedDataLength;
|
||||||
unsigned char *escapedData = PQescapeByteaConn(conn_, value.data(), value.size(), &escapedDataLength);
|
unsigned char *escapedData = PQescapeByteaConn(conn_, value.data(), value.size(), &escapedDataLength);
|
||||||
|
|
||||||
return {reinterpret_cast<char*>(escapedData), escapedDataLength-1};
|
return {reinterpret_cast<char *>(escapedData), escapedDataLength - 1};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|||||||
@@ -4,8 +4,7 @@
|
|||||||
|
|
||||||
#include "matador/utils/basic_types.hpp"
|
#include "matador/utils/basic_types.hpp"
|
||||||
|
|
||||||
[[maybe_unused]] const matador::sql::dialect *get_dialect()
|
[[maybe_unused]] const matador::sql::dialect *get_dialect() {
|
||||||
{
|
|
||||||
using namespace matador::sql;
|
using namespace matador::sql;
|
||||||
const static dialect d = dialect_builder::builder()
|
const static dialect d = dialect_builder::builder()
|
||||||
.create()
|
.create()
|
||||||
@@ -13,15 +12,17 @@
|
|||||||
return "$" + std::to_string(index);
|
return "$" + std::to_string(index);
|
||||||
})
|
})
|
||||||
.with_token_replace_map({
|
.with_token_replace_map({
|
||||||
{dialect_token::BeginBinaryData, "'\\x"}
|
{dialect_token::BeginBinaryData, "'\\x"},
|
||||||
|
{dialect_token::Identity, "GENERATED BY DEFAULT AS IDENTITY"}
|
||||||
})
|
})
|
||||||
.with_data_type_replace_map({
|
.with_data_type_replace_map({
|
||||||
{matador::utils::basic_type::type_int8, "SMALLINT"},
|
{matador::utils::basic_type::Int8, "SMALLINT"},
|
||||||
{matador::utils::basic_type::type_uint8, "SMALLINT"},
|
{matador::utils::basic_type::UInt8, "SMALLINT"},
|
||||||
{matador::utils::basic_type::type_float, "REAL"},
|
{matador::utils::basic_type::Float, "REAL"},
|
||||||
{matador::utils::basic_type::type_double, "DOUBLE PRECISION"},
|
{matador::utils::basic_type::Double, "DOUBLE PRECISION"},
|
||||||
{matador::utils::basic_type::type_time, "TIMESTAMP"},
|
{matador::utils::basic_type::Time, "TIME(6)"},
|
||||||
{matador::utils::basic_type::type_blob, "BYTEA"}
|
{matador::utils::basic_type::DateTime, "TIMESTAMPTZ(6)"},
|
||||||
|
{matador::utils::basic_type::Blob, "BYTEA"}
|
||||||
})
|
})
|
||||||
.with_bool_strings("TRUE", "FALSE")
|
.with_bool_strings("TRUE", "FALSE")
|
||||||
.with_default_schema_name("public")
|
.with_default_schema_name("public")
|
||||||
|
|||||||
@@ -6,7 +6,10 @@
|
|||||||
|
|
||||||
namespace matador::backends::postgres {
|
namespace matador::backends::postgres {
|
||||||
|
|
||||||
utils::error make_error(const sql::error_code ec, const PGresult *res, const PGconn *db, const std::string &msg,
|
utils::error make_error(const sql::error_code ec,
|
||||||
|
const PGresult *res,
|
||||||
|
const PGconn *db,
|
||||||
|
const std::string &msg,
|
||||||
const std::string &sql) {
|
const std::string &sql) {
|
||||||
utils::error err(ec, msg);
|
utils::error err(ec, msg);
|
||||||
err.add_error_info("dbms", "postgres");
|
err.add_error_info("dbms", "postgres");
|
||||||
@@ -30,22 +33,19 @@ bool is_result_error(const PGresult *res) {
|
|||||||
return status != PGRES_TUPLES_OK && status != PGRES_COMMAND_OK;
|
return status != PGRES_TUPLES_OK && status != PGRES_COMMAND_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void throw_postgres_error(const char *what, const std::string &source)
|
void throw_postgres_error(const char *what, const std::string &source) {
|
||||||
{
|
|
||||||
std::stringstream msg;
|
std::stringstream msg;
|
||||||
msg << "postgres error (" << source << "): " << what;
|
msg << "postgres error (" << source << "): " << what;
|
||||||
throw std::logic_error(msg.str());
|
throw std::logic_error(msg.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void throw_postgres_error(PGconn *db, const std::string &source)
|
void throw_postgres_error(const PGconn *db, const std::string &source) {
|
||||||
{
|
|
||||||
if (PQstatus(db) == CONNECTION_BAD) {
|
if (PQstatus(db) == CONNECTION_BAD) {
|
||||||
throw_postgres_error(PQerrorMessage(db), source);
|
throw_postgres_error(PQerrorMessage(db), source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void throw_postgres_error(PGresult *res, PGconn *db, const std::string &source, const std::string &sql)
|
void throw_postgres_error(const PGresult *res, const PGconn *db, const std::string &source, const std::string &sql) {
|
||||||
{
|
|
||||||
if (res == nullptr) {
|
if (res == nullptr) {
|
||||||
std::stringstream msg;
|
std::stringstream msg;
|
||||||
msg << "postgres error (" << source << ", " << PQerrorMessage(db) << ": " << sql;
|
msg << "postgres error (" << source << ", " << PQerrorMessage(db) << ": " << sql;
|
||||||
|
|||||||
@@ -47,15 +47,15 @@ void bind_value(postgres_parameter_binder::bind_data &data, const size_t index,
|
|||||||
|
|
||||||
postgres_parameter_binder::bind_data::bind_data(const size_t size)
|
postgres_parameter_binder::bind_data::bind_data(const size_t size)
|
||||||
: strings(size)
|
: strings(size)
|
||||||
, bytes(size)
|
, bytes(size)
|
||||||
, values(size)
|
, values(size)
|
||||||
, lengths(size)
|
, lengths(size)
|
||||||
, formats(size)
|
, formats(size) {
|
||||||
{}
|
}
|
||||||
|
|
||||||
postgres_parameter_binder::postgres_parameter_binder(const size_t size)
|
postgres_parameter_binder::postgres_parameter_binder(const size_t size)
|
||||||
: bind_data_(size)
|
: bind_data_(size) {
|
||||||
{}
|
}
|
||||||
|
|
||||||
void postgres_parameter_binder::write_value(const size_t pos, const int8_t &x) {
|
void postgres_parameter_binder::write_value(const size_t pos, const int8_t &x) {
|
||||||
detail::bind_value(bind_data_, pos, x);
|
detail::bind_value(bind_data_, pos, x);
|
||||||
@@ -123,31 +123,42 @@ void postgres_parameter_binder::write_value(const size_t pos, const std::string
|
|||||||
write_value(pos, x);
|
write_value(pos, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
void postgres_parameter_binder::write_value(const size_t pos, const time &/*x*/) {
|
void postgres_parameter_binder::write_value(const size_t pos, const utils::date_type_t &x) {
|
||||||
// bind_data_.strings[pos] = utils::to_string(x, "%Y-%m-%d %T.%f");
|
char buf[11]; // "YYYY-MM-DD" + '\0'
|
||||||
|
|
||||||
|
std::snprintf(buf, sizeof(buf), "%04d-%02u-%02u", x.year, static_cast<unsigned>(x.month), static_cast<unsigned>(x.day));
|
||||||
|
bind_data_.strings[pos] = std::string{buf};
|
||||||
bind_data_.values[pos] = bind_data_.strings[pos].data();
|
bind_data_.values[pos] = bind_data_.strings[pos].data();
|
||||||
bind_data_.lengths[pos] = static_cast<int>(bind_data_.strings[pos].size());
|
bind_data_.lengths[pos] = static_cast<int>(bind_data_.strings[pos].size());
|
||||||
bind_data_.formats[pos] = 0;
|
bind_data_.formats[pos] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void postgres_parameter_binder::write_value(const size_t pos, const date &/*x*/) {
|
void postgres_parameter_binder::write_value(const size_t pos, const utils::time_type_t &x) {
|
||||||
// bind_data_.strings[pos] = utils::to_string(x, utils::date_format::ISO8601);
|
char buf[16]; // "HH:MM:SS.ffffff" + '\0'
|
||||||
|
|
||||||
|
std::snprintf(buf, sizeof(buf), "%02u:%02u:%02u.%06u",
|
||||||
|
static_cast<unsigned>(x.hour), static_cast<unsigned>(x.minute), static_cast<unsigned>(x.second), x.microsecond);
|
||||||
|
|
||||||
|
bind_data_.strings[pos] = std::string{buf};
|
||||||
bind_data_.values[pos] = bind_data_.strings[pos].data();
|
bind_data_.values[pos] = bind_data_.strings[pos].data();
|
||||||
bind_data_.lengths[pos] = static_cast<int>(bind_data_.strings[pos].size());
|
bind_data_.lengths[pos] = static_cast<int>(bind_data_.strings[pos].size());
|
||||||
bind_data_.formats[pos] = 0;
|
bind_data_.formats[pos] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void postgres_parameter_binder::write_value(const size_t pos, const utils::blob &x) {
|
void postgres_parameter_binder::write_value(size_t pos, const utils::timestamp_type_t &x) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void postgres_parameter_binder::write_value(const size_t pos, const utils::blob_type_t &x) {
|
||||||
bind_data_.bytes[pos] = x;
|
bind_data_.bytes[pos] = x;
|
||||||
bind_data_.values[pos] = reinterpret_cast<char*>(bind_data_.bytes[pos].data());
|
bind_data_.values[pos] = reinterpret_cast<char *>(bind_data_.bytes[pos].data());
|
||||||
bind_data_.lengths[pos] = static_cast<int>(bind_data_.bytes[pos].size());
|
bind_data_.lengths[pos] = static_cast<int>(bind_data_.bytes[pos].size());
|
||||||
bind_data_.formats[pos] = 1;
|
bind_data_.formats[pos] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void postgres_parameter_binder::write_value(const size_t /*pos*/, const utils::value &/*x*/, size_t /*size*/) {}
|
void postgres_parameter_binder::write_value(const size_t /*pos*/, const utils::value &/*x*/, size_t /*size*/) {
|
||||||
|
}
|
||||||
|
|
||||||
const postgres_parameter_binder::bind_data &postgres_parameter_binder::params() const {
|
const postgres_parameter_binder::bind_data &postgres_parameter_binder::params() const {
|
||||||
return bind_data_;
|
return bind_data_;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,29 +2,26 @@
|
|||||||
|
|
||||||
#include "matador/utils/convert.hpp"
|
#include "matador/utils/convert.hpp"
|
||||||
#include "matador/utils/value.hpp"
|
#include "matador/utils/value.hpp"
|
||||||
|
#include "matador/utils/string.hpp"
|
||||||
|
|
||||||
namespace matador::backends::postgres {
|
namespace matador::backends::postgres {
|
||||||
|
|
||||||
postgres_result_reader::postgres_result_reader(PGresult *result)
|
postgres_result_reader::postgres_result_reader(PGresult *result)
|
||||||
: result_(result)
|
: result_(result)
|
||||||
, row_count_(PQntuples(result_))
|
, row_count_(PQntuples(result_))
|
||||||
, column_count_(PQnfields(result_))
|
, column_count_(PQnfields(result_)) {
|
||||||
{}
|
}
|
||||||
|
|
||||||
postgres_result_reader::~postgres_result_reader()
|
postgres_result_reader::~postgres_result_reader() {
|
||||||
{
|
|
||||||
if (result_) {
|
if (result_) {
|
||||||
PQclear(result_);
|
PQclear(result_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t postgres_result_reader::column_count() const
|
size_t postgres_result_reader::column_count() const {
|
||||||
{
|
|
||||||
return column_count_;
|
return column_count_;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *postgres_result_reader::column( const size_t index) const
|
const char *postgres_result_reader::column(const size_t index) const {
|
||||||
{
|
|
||||||
return PQgetvalue(result_, static_cast<int>(row_index_), static_cast<int>(index));
|
return PQgetvalue(result_, static_cast<int>(row_index_), static_cast<int>(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,16 +103,28 @@ void postgres_result_reader::read_value(const char * /*id*/, const size_t index,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void postgres_result_reader::read_value(const char * /*id*/, const size_t /*index*/, time &/*value*/) {
|
void postgres_result_reader::read_value(const char * /*id*/, const size_t index, utils::date_type_t &value) {
|
||||||
// if (const auto val = column(index); strlen(val) > 0) {
|
if (const auto val = column(index); strlen(val) > 0) {
|
||||||
// value = time::parse(val, "%Y-%m-%d %T.%f");
|
if (const auto res = utils::to<utils::date_type_t>(std::string(val)); res.is_ok()) {
|
||||||
// }
|
value = res.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void postgres_result_reader::read_value(const char * /*id*/, const size_t /*index*/, date &/*value*/) {
|
void postgres_result_reader::read_value(const char * /*id*/, const size_t index, utils::time_type_t &value) {
|
||||||
// if (const auto val = column(index); strlen(val) > 0) {
|
if (const auto val = column(index); strlen(val) > 0) {
|
||||||
// value.set(val, matador::utils::date_format::ISO8601);
|
if (const auto res = utils::to<utils::time_type_t>(std::string(val)); res.is_ok()) {
|
||||||
// }
|
value = res.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void postgres_result_reader::read_value(const char * /*id*/, const size_t index, utils::timestamp_type_t &value) {
|
||||||
|
if (const auto val = column(index); strlen(val) > 0) {
|
||||||
|
if (const auto res = utils::to<utils::timestamp_type_t>(std::string(val)); res.is_ok()) {
|
||||||
|
value = res.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void postgres_result_reader::read_value(const char * /*id*/, const size_t index, char *value, size_t size) {
|
void postgres_result_reader::read_value(const char * /*id*/, const size_t index, char *value, size_t size) {
|
||||||
@@ -126,7 +135,7 @@ void postgres_result_reader::read_value(const char * /*id*/, const size_t index,
|
|||||||
#else
|
#else
|
||||||
strncpy(value, val, size);
|
strncpy(value, val, size);
|
||||||
#endif
|
#endif
|
||||||
value[size-1] = '\n';
|
value[size - 1] = '\n';
|
||||||
} else {
|
} else {
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
strcpy_s(value, size, val);
|
strcpy_s(value, size, val);
|
||||||
@@ -144,69 +153,71 @@ void postgres_result_reader::read_value(const char * /*id*/, const size_t index,
|
|||||||
value.assign(column(index));
|
value.assign(column(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
void postgres_result_reader::read_value( const char* /*id*/, const size_t index, utils::blob& value )
|
void postgres_result_reader::read_value(const char * /*id*/, const size_t index, utils::blob_type_t &value) {
|
||||||
{
|
const auto *data = reinterpret_cast<const unsigned char *>(column(index));
|
||||||
const auto *data = reinterpret_cast<const unsigned char*>(column(index));
|
|
||||||
// auto length = PQgetlength(result_, row_index_, static_cast<int>(index));
|
|
||||||
|
|
||||||
size_t length;
|
size_t length;
|
||||||
unsigned char* unescaped = PQunescapeBytea(data, &length);
|
unsigned char *unescaped = PQunescapeBytea(data, &length);
|
||||||
|
|
||||||
value.assign(unescaped, unescaped+length);
|
value.assign(unescaped, unescaped + length);
|
||||||
|
|
||||||
|
PQfreemem(unescaped);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type>
|
template<typename Type>
|
||||||
void set_value(const char* str, utils::value& value) {
|
void set_value(const char *str, utils::value &value) {
|
||||||
if (const auto res = utils::to<Type>(str); res.is_ok()) {
|
if (const auto res = utils::to<Type>(str); res.is_ok()) {
|
||||||
value = res.value();
|
value = res.value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template<>
|
||||||
void set_value<utils::blob>(const char* str, utils::value& value) {
|
void set_value<utils::blob_type_t>(const char *str, utils::value &value) {
|
||||||
size_t length;
|
size_t length;
|
||||||
unsigned char* unescaped = PQunescapeBytea(reinterpret_cast<const unsigned char*>(str), &length);
|
unsigned char *unescaped = PQunescapeBytea(reinterpret_cast<const unsigned char *>(str), &length);
|
||||||
|
|
||||||
value = utils::blob(unescaped, unescaped+length);
|
value = utils::blob_type_t(unescaped, unescaped + length);
|
||||||
|
|
||||||
|
PQfreemem(unescaped);
|
||||||
}
|
}
|
||||||
|
|
||||||
void postgres_result_reader::read_value(const char * /*id*/, const size_t index, utils::value &val, size_t) {
|
void postgres_result_reader::read_value(const char * /*id*/, const size_t index, utils::value &val, size_t) {
|
||||||
switch (val.type()) {
|
switch (val.type()) {
|
||||||
case utils::basic_type::type_int8:
|
case utils::basic_type::Int8:
|
||||||
set_value<int8_t>(column(index), val);
|
set_value<int8_t>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case utils::basic_type::type_int16:
|
case utils::basic_type::Int16:
|
||||||
set_value<int16_t>(column(index), val);
|
set_value<int16_t>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case utils::basic_type::type_int32:
|
case utils::basic_type::Int32:
|
||||||
set_value<int32_t>(column(index), val);
|
set_value<int32_t>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case utils::basic_type::type_int64:
|
case utils::basic_type::Int64:
|
||||||
set_value<int64_t>(column(index), val);
|
set_value<int64_t>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case utils::basic_type::type_uint8:
|
case utils::basic_type::UInt8:
|
||||||
set_value<uint8_t>(column(index), val);
|
set_value<uint8_t>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case utils::basic_type::type_uint16:
|
case utils::basic_type::UInt16:
|
||||||
set_value<uint16_t>(column(index), val);
|
set_value<uint16_t>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case utils::basic_type::type_uint32:
|
case utils::basic_type::UInt32:
|
||||||
set_value<uint32_t>(column(index), val);
|
set_value<uint32_t>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case utils::basic_type::type_uint64:
|
case utils::basic_type::UInt64:
|
||||||
set_value<uint64_t>(column(index), val);
|
set_value<uint64_t>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case utils::basic_type::type_float:
|
case utils::basic_type::Float:
|
||||||
set_value<float>(column(index), val);
|
set_value<float>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case utils::basic_type::type_double:
|
case utils::basic_type::Double:
|
||||||
set_value<double>(column(index), val);
|
set_value<double>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case utils::basic_type::type_bool:
|
case utils::basic_type::Boolean:
|
||||||
set_value<bool>(column(index), val);
|
set_value<bool>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case utils::basic_type::type_text:
|
case utils::basic_type::Text:
|
||||||
case utils::basic_type::type_varchar: {
|
case utils::basic_type::Varchar: {
|
||||||
if (const auto *column_value = column(index); column_value == nullptr) {
|
if (const auto *column_value = column(index); column_value == nullptr) {
|
||||||
val = std::string{};
|
val = std::string{};
|
||||||
} else {
|
} else {
|
||||||
@@ -214,24 +225,30 @@ void postgres_result_reader::read_value(const char * /*id*/, const size_t index,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case utils::basic_type::type_time:
|
case utils::basic_type::Time:
|
||||||
case utils::basic_type::type_date: {
|
set_value<utils::time_type_t>(column(index), val);
|
||||||
val = std::string{column(index)};
|
break;
|
||||||
|
case utils::basic_type::Date:
|
||||||
|
set_value<utils::date_type_t>(column(index), val);
|
||||||
|
break;
|
||||||
|
case utils::basic_type::DateTime: {
|
||||||
|
set_value<utils::timestamp_type_t>(column(index), val);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case utils::basic_type::type_null: {
|
case utils::basic_type::Null: {
|
||||||
val = nullptr_t{};
|
val = nullptr_t{};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case utils::basic_type::type_blob: {
|
case utils::basic_type::Blob: {
|
||||||
set_value<utils::blob>(column(index), val);
|
set_value<utils::blob_type_t>(column(index), val);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case utils::basic_type::Unknown:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
utils::attribute_reader &postgres_result_reader::result_binder() {
|
utils::attribute_reader &postgres_result_reader::result_binder() {
|
||||||
return empty_binder_;
|
return empty_binder_;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace matador::backends::postgres
|
} // namespace matador::backends::postgres
|
||||||
|
|||||||
@@ -1,21 +1,33 @@
|
|||||||
#include "postgres_statement.hpp"
|
#include "postgres_statement.hpp"
|
||||||
|
|
||||||
|
#include "matador/sql/execute_result.hpp"
|
||||||
#include "postgres_error.hpp"
|
#include "postgres_error.hpp"
|
||||||
#include "postgres_parameter_binder.h"
|
#include "postgres_parameter_binder.h"
|
||||||
#include "postgres_result_reader.hpp"
|
#include "postgres_result_reader.hpp"
|
||||||
|
|
||||||
namespace matador::backends::postgres {
|
namespace matador::backends::postgres {
|
||||||
|
|
||||||
postgres_statement::postgres_statement(PGconn *db, std::string name, const sql::query_context &query)
|
postgres_statement::postgres_statement(PGconn *db, PGresult *res, std::string name, const sql::query_context &query)
|
||||||
: statement_impl(query, 0)
|
: statement_impl(query, 0)
|
||||||
, db_(db)
|
, db_(db)
|
||||||
|
, res_(res)
|
||||||
, name_(std::move(name))
|
, name_(std::move(name))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
utils::result<size_t, utils::error> postgres_statement::execute(const sql::parameter_binder& bindings) {
|
postgres_statement::~postgres_statement() {
|
||||||
|
PQclear(res_);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::result<sql::execute_result, utils::error> postgres_statement::execute(const sql::parameter_binder& bindings) {
|
||||||
const auto* postgres_bindings = dynamic_cast<const postgres_parameter_binder*>(&bindings);
|
const auto* postgres_bindings = dynamic_cast<const postgres_parameter_binder*>(&bindings);
|
||||||
if (!postgres_bindings) {
|
if (!postgres_bindings) {
|
||||||
return utils::failure(utils::error(sql::error_code::EXECUTE_FAILED, "Failed to cast bindings to postgres bindings"));
|
return utils::failure(utils::error(sql::error_code::ExecuteFailed, "Failed to cast bindings to postgres bindings"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (query_.command == sql::sql_command::Insert) {
|
||||||
|
// handle insert command with the primary key generator strategy
|
||||||
|
}
|
||||||
|
|
||||||
PGresult *res = PQexecPrepared(db_,
|
PGresult *res = PQexecPrepared(db_,
|
||||||
name_.c_str(),
|
name_.c_str(),
|
||||||
static_cast<int>(postgres_bindings->params().values.size()),
|
static_cast<int>(postgres_bindings->params().values.size()),
|
||||||
@@ -25,21 +37,23 @@ utils::result<size_t, utils::error> postgres_statement::execute(const sql::param
|
|||||||
0);
|
0);
|
||||||
|
|
||||||
if (is_result_error(res)) {
|
if (is_result_error(res)) {
|
||||||
return utils::failure(make_error(sql::error_code::EXECUTE_FAILED, res, db_, "Failed to execute statement", query_.sql));
|
return utils::failure(make_error(sql::error_code::ExecuteFailed, res, db_, "Failed to execute statement", query_.sql));
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto *tuples = PQcmdTuples(res);
|
size_t value{0};
|
||||||
if (strlen(tuples) == 0) {
|
if (const auto *tuples = PQcmdTuples(res); strlen(tuples) != 0) {
|
||||||
return utils::ok(static_cast<size_t>(0));
|
value = std::stoul(tuples);
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils::ok(static_cast<size_t>(std::stoul(tuples)));
|
PQclear(res);
|
||||||
|
|
||||||
|
return utils::ok(sql::execute_result{value});
|
||||||
}
|
}
|
||||||
|
|
||||||
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> postgres_statement::fetch(const sql::parameter_binder& bindings) {
|
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> postgres_statement::fetch(const sql::parameter_binder& bindings) {
|
||||||
const auto* postgres_bindings = dynamic_cast<const postgres_parameter_binder*>(&bindings);
|
const auto* postgres_bindings = dynamic_cast<const postgres_parameter_binder*>(&bindings);
|
||||||
if (!postgres_bindings) {
|
if (!postgres_bindings) {
|
||||||
return utils::failure(utils::error(sql::error_code::EXECUTE_FAILED, "Failed to cast bindings to postgres bindings"));
|
return utils::failure(utils::error(sql::error_code::ExecuteFailed, "Failed to cast bindings to postgres bindings"));
|
||||||
}
|
}
|
||||||
PGresult *res = PQexecPrepared(db_,
|
PGresult *res = PQexecPrepared(db_,
|
||||||
name_.c_str(),
|
name_.c_str(),
|
||||||
@@ -50,10 +64,13 @@ utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> postgres_st
|
|||||||
0);
|
0);
|
||||||
|
|
||||||
if (is_result_error(res)) {
|
if (is_result_error(res)) {
|
||||||
return utils::failure(make_error(sql::error_code::FETCH_FAILED, res, db_, "Failed to fetch statement", query_.sql));
|
return utils::failure(make_error(sql::error_code::FetchFailed, res, db_, "Failed to fetch statement", query_.sql));
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils::ok(std::make_unique<sql::query_result_impl>(std::make_unique<postgres_result_reader>(res), query_.prototype));
|
return utils::ok(std::make_unique<sql::query_result_impl>(std::make_unique<postgres_result_reader>(res),
|
||||||
|
query_.prototype,
|
||||||
|
query_.resolver,
|
||||||
|
query_.result_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<utils::attribute_writer> postgres_statement::create_binder() const {
|
std::unique_ptr<utils::attribute_writer> postgres_statement::create_binder() const {
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
CPMAddPackage("gh:catchorg/Catch2@3.7.1")
|
CPMAddPackage("gh:catchorg/Catch2@3.14.0")
|
||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)
|
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)
|
||||||
|
|
||||||
set(POSTGRES_CONNECTION_STRING "postgres://test:test123!@127.0.0.1:15442/matador")
|
#set(POSTGRES_CONNECTION_STRING "postgres://test:test123!@127.0.0.1:15442/matador")
|
||||||
#set(POSTGRES_CONNECTION_STRING "postgres://test:test123!@127.0.0.1:5432/matador")
|
set(POSTGRES_CONNECTION_STRING "postgres://test:test123!@127.0.0.1:5432/matador")
|
||||||
|
|
||||||
configure_file(Connection.hpp.in ${PROJECT_BINARY_DIR}/backends/postgres/test/connection.hpp @ONLY IMMEDIATE)
|
configure_file(Connection.hpp.in ${PROJECT_BINARY_DIR}/backends/postgres/test/connection.hpp @ONLY IMMEDIATE)
|
||||||
|
|
||||||
message(STATUS "postgresql connection string: ${POSTGRES_CONNECTION_STRING}")
|
message(STATUS "postgresql connection string: ${POSTGRES_CONNECTION_STRING}")
|
||||||
|
|
||||||
set(TEST_SOURCES
|
set(TEST_SOURCES
|
||||||
../../../test/models/coordinate.hpp
|
|
||||||
../../../test/models/location.hpp
|
|
||||||
../../../test/models/types.hpp
|
|
||||||
../../../test/backends/ColorEnumTraits.cpp
|
../../../test/backends/ColorEnumTraits.cpp
|
||||||
../../../test/backends/ColorEnumTraits.hpp
|
../../../test/backends/ColorEnumTraits.hpp
|
||||||
../../../test/backends/ConnectionTest.cpp
|
../../../test/backends/ConnectionTest.cpp
|
||||||
@@ -25,12 +22,32 @@ set(TEST_SOURCES
|
|||||||
../../../test/backends/SchemaFixture.cpp
|
../../../test/backends/SchemaFixture.cpp
|
||||||
../../../test/backends/SchemaFixture.hpp
|
../../../test/backends/SchemaFixture.hpp
|
||||||
../../../test/backends/SchemaTest.cpp
|
../../../test/backends/SchemaTest.cpp
|
||||||
|
../../../test/backends/SequenceFixture.cpp
|
||||||
|
../../../test/backends/SequenceFixture.hpp
|
||||||
|
../../../test/backends/SequenceTest.cpp
|
||||||
|
../../../test/backends/SessionDeleteHasMany.cpp
|
||||||
|
../../../test/backends/SessionDeleteHasManyToMany.cpp
|
||||||
../../../test/backends/SessionFixture.cpp
|
../../../test/backends/SessionFixture.cpp
|
||||||
../../../test/backends/SessionFixture.hpp
|
../../../test/backends/SessionFixture.hpp
|
||||||
|
../../../test/backends/SessionInsertBelongsTo.cpp
|
||||||
|
../../../test/backends/SessionInsertHasMany.cpp
|
||||||
|
../../../test/backends/SessionInsertHasManyToManyTest.cpp
|
||||||
|
../../../test/backends/SessionInsertHasOne.cpp
|
||||||
../../../test/backends/SessionTest.cpp
|
../../../test/backends/SessionTest.cpp
|
||||||
../../../test/backends/StatementCacheTest.cpp
|
../../../test/backends/StatementCacheTest.cpp
|
||||||
../../../test/backends/StatementTest.cpp
|
../../../test/backends/StatementTest.cpp
|
||||||
|
../../../test/backends/TableSequenceFixture.cpp
|
||||||
|
../../../test/backends/TableSequenceFixture.hpp
|
||||||
|
../../../test/backends/TableSequenceTest.cpp
|
||||||
../../../test/backends/TypeTraitsTest.cpp
|
../../../test/backends/TypeTraitsTest.cpp
|
||||||
|
../../../test/models/author.hpp
|
||||||
|
../../../test/models/coordinate.hpp
|
||||||
|
../../../test/models/location.hpp
|
||||||
|
../../../test/models/model_metas.hpp
|
||||||
|
../../../test/models/types.hpp
|
||||||
|
../../../test/models/user.hpp
|
||||||
|
../../../test/utils/RecordPrinter.cpp
|
||||||
|
../../../test/utils/RecordPrinter.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(LIBRARY_TEST_TARGET PostgresTests)
|
set(LIBRARY_TEST_TARGET PostgresTests)
|
||||||
|
|||||||
+2
-1
@@ -1,5 +1,6 @@
|
|||||||
add_executable(demo main.cpp
|
add_executable(demo main.cpp
|
||||||
object.cpp)
|
../include/matador/query/query_column.hpp)
|
||||||
|
|
||||||
target_link_libraries(demo PRIVATE
|
target_link_libraries(demo PRIVATE
|
||||||
matador-core
|
matador-core
|
||||||
matador-orm
|
matador-orm
|
||||||
|
|||||||
+6
-5
@@ -20,14 +20,15 @@ struct author {
|
|||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process( Operator& op ) {
|
||||||
namespace field = matador::access;
|
using namespace matador;
|
||||||
|
namespace field = access;
|
||||||
field::primary_key( op, "id", id );
|
field::primary_key( op, "id", id );
|
||||||
field::attribute( op, "first_name", first_name, 63 );
|
field::attribute( op, "first_name", first_name, VarChar63 );
|
||||||
field::attribute( op, "last_name", last_name, 63 );
|
field::attribute( op, "last_name", last_name, VarChar63 );
|
||||||
field::attribute( op, "date_of_birth", date_of_birth, 31 );
|
field::attribute( op, "date_of_birth", date_of_birth, VarChar63 );
|
||||||
field::attribute( op, "year_of_birth", year_of_birth );
|
field::attribute( op, "year_of_birth", year_of_birth );
|
||||||
field::attribute( op, "distinguished", distinguished );
|
field::attribute( op, "distinguished", distinguished );
|
||||||
field::has_many( op, "books", books, "author_id", matador::utils::default_foreign_attributes );
|
field::has_many( op, "books", books, "author_id", utils::CascadeNoneFetchLazy );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-3
@@ -15,10 +15,11 @@ struct book {
|
|||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process( Operator& op ) {
|
||||||
namespace field = matador::access;
|
using namespace matador;
|
||||||
|
namespace field = access;
|
||||||
field::primary_key( op, "id", id );
|
field::primary_key( op, "id", id );
|
||||||
field::attribute( op, "title", title, 511 );
|
field::attribute( op, "title", title, VarChar511 );
|
||||||
field::belongs_to( op, "author_id", book_author, matador::utils::default_foreign_attributes );
|
field::belongs_to( op, "author_id", book_author, utils::CascadeNoneFetchLazy );
|
||||||
field::attribute( op, "published_in", published_in );
|
field::attribute( op, "published_in", published_in );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+126
-111
@@ -1,9 +1,11 @@
|
|||||||
#include "matador/query/column.hpp"
|
|
||||||
#include "matador/sql/connection.hpp"
|
#include "matador/sql/connection.hpp"
|
||||||
#include "matador/sql/query_macro.hpp"
|
#include "matador/sql/connection_pool.hpp"
|
||||||
|
|
||||||
#include "matador/query/criteria.hpp"
|
#include "matador/query/criteria.hpp"
|
||||||
#include "matador/query/query.hpp"
|
#include "matador/query/query.hpp"
|
||||||
|
#include "matador/query/table_column.hpp"
|
||||||
|
#include "matador/query/meta_table_macro.hpp"
|
||||||
|
#include "matador/query/schema.hpp"
|
||||||
|
|
||||||
#include "matador/object/object_ptr.hpp"
|
#include "matador/object/object_ptr.hpp"
|
||||||
#include "matador/object/repository.hpp"
|
#include "matador/object/repository.hpp"
|
||||||
@@ -11,12 +13,8 @@
|
|||||||
#include "matador/utils/access.hpp"
|
#include "matador/utils/access.hpp"
|
||||||
#include "matador/utils/default_type_traits.hpp"
|
#include "matador/utils/default_type_traits.hpp"
|
||||||
#include "matador/utils/enum_mapper.hpp"
|
#include "matador/utils/enum_mapper.hpp"
|
||||||
#include "matador/utils/types.hpp"
|
|
||||||
|
|
||||||
#include "matador/sql/query_macro.hpp"
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
struct author {
|
struct author {
|
||||||
unsigned int id{};
|
unsigned int id{};
|
||||||
@@ -27,14 +25,14 @@ struct author {
|
|||||||
bool distinguished{false};
|
bool distinguished{false};
|
||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process(Operator &op) {
|
||||||
namespace field = matador::access;
|
namespace field = matador::access;
|
||||||
field::primary_key( op, "id", id );
|
field::primary_key(op, "id", id);
|
||||||
field::attribute( op, "first_name", first_name, 63 );
|
field::attribute(op, "first_name", first_name, 63);
|
||||||
field::attribute( op, "last_name", last_name, 63 );
|
field::attribute(op, "last_name", last_name, 63);
|
||||||
field::attribute( op, "date_of_birth", date_of_birth, 31 );
|
field::attribute(op, "date_of_birth", date_of_birth, 31);
|
||||||
field::attribute( op, "year_of_birth", year_of_birth );
|
field::attribute(op, "year_of_birth", year_of_birth);
|
||||||
field::attribute( op, "distinguished", distinguished );
|
field::attribute(op, "distinguished", distinguished);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -45,12 +43,12 @@ struct book {
|
|||||||
unsigned short published_in{};
|
unsigned short published_in{};
|
||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process(Operator &op) {
|
||||||
namespace field = matador::access;
|
namespace field = matador::access;
|
||||||
field::primary_key( op, "id", id );
|
field::primary_key(op, "id", id);
|
||||||
field::attribute( op, "title", title, 511 );
|
field::attribute(op, "title", title, 511);
|
||||||
field::has_one( op, "author_id", book_author, matador::utils::default_foreign_attributes );
|
field::belongs_to(op, "author_id", book_author, matador::utils::CascadeNoneFetchLazy);
|
||||||
field::attribute( op, "published_in", published_in );
|
field::attribute(op, "published_in", published_in);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -58,9 +56,9 @@ struct payload {
|
|||||||
unsigned int id{};
|
unsigned int id{};
|
||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process(Operator &op) {
|
||||||
namespace field = matador::access;
|
namespace field = matador::access;
|
||||||
field::primary_key( op, "id", id );
|
field::primary_key(op, "id", id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -86,14 +84,14 @@ struct job {
|
|||||||
job_mode mode;
|
job_mode mode;
|
||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process(Operator &op) {
|
||||||
namespace field = matador::access;
|
namespace field = matador::access;
|
||||||
field::primary_key( op, "id", id );
|
field::primary_key(op, "id", id);
|
||||||
field::belongs_to( op, "payload", data, matador::utils::default_foreign_attributes );
|
field::belongs_to(op, "payload", data, matador::utils::CascadeNoneFetchLazy);
|
||||||
field::attribute( op, "type", type, 511 );
|
field::attribute(op, "type", type, 511);
|
||||||
field::attribute( op, "description", description, 511 );
|
field::attribute(op, "description", description, 511);
|
||||||
field::attribute( op, "state", state );
|
field::attribute(op, "state", state);
|
||||||
field::attribute( op, "mode", mode );
|
field::attribute(op, "mode", mode);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -103,12 +101,12 @@ static const matador::utils::enum_mapper<job::job_state> job_state_enum({
|
|||||||
{job::job_state::Succeeded, "Succeeded"},
|
{job::job_state::Succeeded, "Succeeded"},
|
||||||
{job::job_state::Failed, "Failed"},
|
{job::job_state::Failed, "Failed"},
|
||||||
{job::job_state::Canceled, "Canceled"}
|
{job::job_state::Canceled, "Canceled"}
|
||||||
});
|
});
|
||||||
|
|
||||||
static const matador::utils::enum_mapper<job::job_mode> job_mode_enum({
|
static const matador::utils::enum_mapper<job::job_mode> job_mode_enum({
|
||||||
{job::job_mode::Foreground, "Foreground"},
|
{job::job_mode::Foreground, "Foreground"},
|
||||||
{job::job_mode::Background, "Background"}
|
{job::job_mode::Background, "Background"}
|
||||||
});
|
});
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct matador::utils::data_type_traits<job::job_state, void> {
|
struct matador::utils::data_type_traits<job::job_state, void> {
|
||||||
@@ -129,7 +127,7 @@ struct matador::utils::data_type_traits<job::job_state, void> {
|
|||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct matador::utils::data_type_traits<job::job_mode, void> {
|
struct matador::utils::data_type_traits<job::job_mode, void> {
|
||||||
static basic_type type( const std::size_t size) { return data_type_traits<std::string>::type(size); }
|
static basic_type type(const std::size_t size) { return data_type_traits<std::string>::type(size); }
|
||||||
|
|
||||||
static void read_value(attribute_reader &reader, const char *id, const size_t index, job::job_mode &value) {
|
static void read_value(attribute_reader &reader, const char *id, const size_t index, job::job_mode &value) {
|
||||||
std::string enum_string;
|
std::string enum_string;
|
||||||
@@ -144,73 +142,78 @@ struct matador::utils::data_type_traits<job::job_mode, void> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
QUERY_HELPER( authors, AUTHOR, id, first_name, last_name, date_of_birth, year_of_birth, distinguished )
|
META_TABLE(authors, AUTHOR, id, first_name, last_name, date_of_birth, year_of_birth, distinguished)
|
||||||
|
|
||||||
QUERY_HELPER( books, BOOK, id, author_id, title, published_in )
|
META_TABLE(books, BOOK, id, author_id, title, published_in)
|
||||||
|
|
||||||
QUERY_HELPER( job, JOB, id, payload, type, description, state, mode )
|
META_TABLE(job, JOB, id, payload, type, description, state, mode)
|
||||||
|
|
||||||
QUERY_HELPER( payload, PAYLOAD, id )
|
META_TABLE(payload, PAYLOAD, id)
|
||||||
|
|
||||||
QUERY_HELPER( temporary_table, TEMPORARY_TABLE, id );
|
META_TABLE(temporary_table, TEMPORARY_TABLE, id);
|
||||||
|
|
||||||
QUERY_HELPER(customer, CUSTOMER, id, name, email, address)
|
META_TABLE(customer, CUSTOMER, id, name, email, address)
|
||||||
QUERY_HELPER(product, PRODUCT, id, title, description, price, category)
|
|
||||||
QUERY_HELPER(category, CATEGORY, id, title, description)
|
META_TABLE(product, PRODUCT, id, title, description, price, category)
|
||||||
QUERY_HELPER(cart, CART, id, items, owner)
|
|
||||||
|
META_TABLE(category, CATEGORY, id, title, description)
|
||||||
|
|
||||||
|
META_TABLE(cart, CART, id, items, owner)
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
using namespace matador::sql;
|
using namespace matador::sql;
|
||||||
using namespace matador::object;
|
using namespace matador::object;
|
||||||
using namespace matador::utils;
|
using namespace matador::utils;
|
||||||
|
using namespace matador::query;
|
||||||
using namespace matador::query::meta;
|
using namespace matador::query::meta;
|
||||||
|
|
||||||
const std::string env_var{"MATADOR_BACKENDS_PATH"};
|
const std::string env_var{"MATADOR_BACKENDS_PATH"};
|
||||||
|
|
||||||
std::string dns{"sqlite://demo.db"};
|
connection_pool pool("postgres://test:test123!@127.0.0.1:5432/matador", 4);
|
||||||
repository s( "main" );
|
|
||||||
auto result = s.attach<author>( "authors" ).and_then( [&s] {
|
|
||||||
return s.attach<book>( "books" );
|
|
||||||
} );
|
|
||||||
// s.attach<book>( "books" );
|
|
||||||
|
|
||||||
connection c( dns );
|
schema s("");
|
||||||
result = c.open();
|
auto result = s.attach<author>("authors").and_then([&s] {
|
||||||
// s.create( c );
|
return s.attach<book>("books");
|
||||||
//
|
});
|
||||||
// auto create_authors_sql = c.query( s )
|
|
||||||
// .create()
|
const auto c = pool.acquire();
|
||||||
// .table<author>( qh::authors )
|
result = s.create(*c);
|
||||||
// .execute();
|
if (!result) {
|
||||||
//
|
std::cout << "error: " << result.err() << std::endl;
|
||||||
// c.query( s )
|
return 0;
|
||||||
// .create()
|
}
|
||||||
// .table<book>( qh::books )
|
|
||||||
// .execute();
|
author mc;
|
||||||
//
|
mc.id = 1;
|
||||||
// std::cout << "SQL: " << create_authors_sql << "\n";
|
mc.first_name = "Michael";
|
||||||
//
|
mc.last_name = "Crichton";
|
||||||
// author mc;
|
mc.date_of_birth = "19.8.1954";
|
||||||
// mc.id = 1;
|
mc.year_of_birth = 1954;
|
||||||
// mc.first_name = "Michael";
|
mc.distinguished = true;
|
||||||
// mc.last_name = "Crichton";
|
auto insert_authors_sql = insert()
|
||||||
// mc.date_of_birth = "19.8.1954";
|
.into(AUTHOR)
|
||||||
// mc.year_of_birth = 1954;
|
.values(mc)
|
||||||
// mc.distinguished = true;
|
.execute(*c);
|
||||||
// auto insert_authors_sql = c.query( s )
|
|
||||||
// .insert()
|
if (!insert_authors_sql) {
|
||||||
// .into( qh::authors )
|
std::cout << "error: " << insert_authors_sql.err() << std::endl;
|
||||||
// .values( mc )
|
std::ignore = s.drop(*c);
|
||||||
// .execute();
|
return 0;
|
||||||
//
|
}
|
||||||
// std::cout << "SQL: " << insert_authors_sql << "\n";
|
|
||||||
//
|
auto authors_result = select(AUTHOR)
|
||||||
// auto result = c.query( s )
|
.from(AUTHOR)
|
||||||
// .select( qh::authors.columns )
|
.fetch_all(*c);
|
||||||
// .from( qh::authors )
|
|
||||||
// .fetch_all();
|
if (!authors_result) {
|
||||||
//
|
std::cout << "error: " << authors_result.err() << std::endl;
|
||||||
// for (const auto& row: result) { std::cout << "Author " << row.at( qh::authors.first_name ) << "\n"; }
|
std::ignore = s.drop(*c);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &row: *authors_result) {
|
||||||
|
std::cout << "Author " << row.at(AUTHOR.first_name.canonical_name()) << "\n";
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// auto update_authors_sql = c.query( s )
|
// auto update_authors_sql = c.query( s )
|
||||||
// .update( qh::authors )
|
// .update( qh::authors )
|
||||||
@@ -240,20 +243,35 @@ int main() {
|
|||||||
// .values( {3, "Misery", mc.id, 1984} )
|
// .values( {3, "Misery", mc.id, 1984} )
|
||||||
// .execute();
|
// .execute();
|
||||||
//
|
//
|
||||||
auto select_books_sql = matador::query::query::select( BOOK, {AUTHOR.last_name} )
|
// auto select_books_sql = select( BOOK, {AUTHOR.last_name} )
|
||||||
.from( BOOK )
|
auto select_books_sql = select({BOOK.id, BOOK.title, BOOK.author_id, BOOK.published_in, AUTHOR.last_name})
|
||||||
.join_left( AUTHOR )
|
.from(BOOK)
|
||||||
.on( BOOK.author_id == AUTHOR.id )
|
.join_left(AUTHOR)
|
||||||
.where( BOOK.published_in < 2008 && AUTHOR.last_name == "King" )
|
.on(BOOK.author_id == AUTHOR.id)
|
||||||
.group_by( BOOK.published_in )
|
.where(BOOK.published_in < 2008 && AUTHOR.last_name == "King")
|
||||||
.order_by( BOOK.title ).asc()
|
.group_by({BOOK.id, AUTHOR.last_name})
|
||||||
.limit( 5 )
|
.order_by(BOOK.title).asc()
|
||||||
.offset( 2 )
|
.limit(5)
|
||||||
.fetch_all(c);
|
.offset(2)
|
||||||
|
.fetch_all(*c);
|
||||||
|
|
||||||
for (const auto& r: *select_books_sql) {
|
if (!select_books_sql) {
|
||||||
std::cout << "R: " << r.at( BOOK.title ) << ", " << r.at( AUTHOR.last_name ) << "\n";
|
std::cout << "error: " << select_books_sql.err() << std::endl;
|
||||||
|
std::ignore = s.drop(*c);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto &r: *select_books_sql) {
|
||||||
|
std::cout << "R: " << r.at(BOOK.title.canonical_name()) << ", " << r.at(AUTHOR.last_name.canonical_name()) << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
result = s.drop(*c);
|
||||||
|
if (!result) {
|
||||||
|
std::cout << "error: " << result.err() << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// // SELECT book.title, book.id, book.author_id, book.published_in, author.name
|
// // SELECT book.title, book.id, book.author_id, book.published_in, author.name
|
||||||
// // FROM book
|
// // FROM book
|
||||||
// // INNER JOIN author ON book.author_id = author.id
|
// // INNER JOIN author ON book.author_id = author.id
|
||||||
@@ -270,24 +288,21 @@ int main() {
|
|||||||
//
|
//
|
||||||
// std::cout << "SQL: " << drop_authors_sql << "\n";
|
// std::cout << "SQL: " << drop_authors_sql << "\n";
|
||||||
//
|
//
|
||||||
// auto res = c.query( s )
|
auto res = select({PAYLOAD.id})
|
||||||
// .select( {qh::payload.id} )
|
.from(PAYLOAD)
|
||||||
// .from( qh::payload )
|
.join_left(JOB)
|
||||||
// .join_left( qh::job )
|
.on(JOB.payload == PAYLOAD.id)
|
||||||
// .on( qh::job.payload == qh::payload.id )
|
.where(
|
||||||
// .where(
|
in(PAYLOAD.id, select({JOB.state})
|
||||||
// in( qh::payload.id, c.query( s )
|
.from(JOB)
|
||||||
// .select( {qh::job.state} )
|
.where(JOB.state == job::job_state::Running)
|
||||||
// .from( qh::job )
|
) &&
|
||||||
// .where( qh::job.state == job::job_state::Running )
|
in(PAYLOAD.id, select({TEMPORARY_TABLE.id})
|
||||||
// ) &&
|
.from(TEMPORARY_TABLE)
|
||||||
// in( qh::payload.id, c.query( s )
|
)
|
||||||
// .select( {qh::temporary_table.id} )
|
).compile(c->dialect());
|
||||||
// .from( qh::temporary_table ) )
|
|
||||||
// )
|
|
||||||
// .build();
|
|
||||||
// // .fetch_value<unsigned long>();
|
// // .fetch_value<unsigned long>();
|
||||||
// std::cout << "SQL: " << res.sql << "\n";
|
std::cout << "SQL: " << res.sql << "\n";
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
+11
-11
@@ -29,7 +29,7 @@ public:
|
|||||||
attribute() = default;
|
attribute() = default;
|
||||||
attribute(std::string name,
|
attribute(std::string name,
|
||||||
utils::basic_type type,
|
utils::basic_type type,
|
||||||
const utils::field_attributes& opts = utils::null_attributes,
|
const utils::field_attributes& opts = matador::NullAttributes,
|
||||||
null_option_type null_opt = null_option_type::NotNull)
|
null_option_type null_opt = null_option_type::NotNull)
|
||||||
: name_(std::move(name)), type_(type), options_(opts), null_option_type_(null_opt) {}
|
: name_(std::move(name)), type_(type), options_(opts), null_option_type_(null_opt) {}
|
||||||
|
|
||||||
@@ -41,22 +41,22 @@ public:
|
|||||||
[[nodiscard]] bool is_nullable() const { return null_option_type_ == null_option_type::Nullable; }
|
[[nodiscard]] bool is_nullable() const { return null_option_type_ == null_option_type::Nullable; }
|
||||||
[[nodiscard]] utils::basic_type type() const { return type_; }
|
[[nodiscard]] utils::basic_type type() const { return type_; }
|
||||||
|
|
||||||
[[nodiscard]] bool is_integer() const { return type_ >= utils::basic_type::type_int8 && type_ <= utils::basic_type::type_uint64; }
|
[[nodiscard]] bool is_integer() const { return type_ >= utils::basic_type::Int8 && type_ <= utils::basic_type::UInt64; }
|
||||||
[[nodiscard]] bool is_floating_point() const { return type_ == utils::basic_type::type_float || type_ == utils::basic_type::type_double; }
|
[[nodiscard]] bool is_floating_point() const { return type_ == utils::basic_type::Float || type_ == utils::basic_type::Double; }
|
||||||
[[nodiscard]] bool is_bool() const { return type_ == utils::basic_type::type_bool; }
|
[[nodiscard]] bool is_bool() const { return type_ == utils::basic_type::Boolean; }
|
||||||
[[nodiscard]] bool is_string() const { return type_ == utils::basic_type::type_text; }
|
[[nodiscard]] bool is_string() const { return type_ == utils::basic_type::Text; }
|
||||||
[[nodiscard]] bool is_varchar() const { return type_ == utils::basic_type::type_varchar; }
|
[[nodiscard]] bool is_varchar() const { return type_ == utils::basic_type::Varchar; }
|
||||||
[[nodiscard]] bool is_date() const { return type_ == utils::basic_type::type_date; }
|
[[nodiscard]] bool is_date() const { return type_ == utils::basic_type::Date; }
|
||||||
[[nodiscard]] bool is_time() const { return type_ == utils::basic_type::type_time; }
|
[[nodiscard]] bool is_time() const { return type_ == utils::basic_type::Time; }
|
||||||
[[nodiscard]] bool is_blob() const { return type_ == utils::basic_type::type_blob; }
|
[[nodiscard]] bool is_blob() const { return type_ == utils::basic_type::Blob; }
|
||||||
[[nodiscard]] bool is_null() const { return type_ == utils::basic_type::type_null; }
|
[[nodiscard]] bool is_null() const { return type_ == utils::basic_type::Null; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class object;
|
friend class object;
|
||||||
|
|
||||||
std::string name_;
|
std::string name_;
|
||||||
std::string alias_;
|
std::string alias_;
|
||||||
utils::basic_type type_{utils::basic_type::type_null};
|
utils::basic_type type_{utils::basic_type::Null};
|
||||||
utils::field_attributes options_;
|
utils::field_attributes options_;
|
||||||
null_option_type null_option_type_{null_option_type::NotNull};
|
null_option_type null_option_type_{null_option_type::NotNull};
|
||||||
|
|
||||||
|
|||||||
+10
-10
@@ -13,8 +13,7 @@
|
|||||||
namespace demo {
|
namespace demo {
|
||||||
|
|
||||||
struct recipe;
|
struct recipe;
|
||||||
struct ingredient
|
struct ingredient {
|
||||||
{
|
|
||||||
unsigned int id{};
|
unsigned int id{};
|
||||||
std::string name;
|
std::string name;
|
||||||
matador::object::collection<matador::object::object_ptr<demo::recipe>> recipes{};
|
matador::object::collection<matador::object::object_ptr<demo::recipe>> recipes{};
|
||||||
@@ -25,15 +24,15 @@ struct ingredient
|
|||||||
|
|
||||||
template<class Operator>
|
template<class Operator>
|
||||||
void process(Operator &op) {
|
void process(Operator &op) {
|
||||||
namespace field = matador::access;
|
using namespace matador;
|
||||||
|
namespace field = access;
|
||||||
field::primary_key(op, "id", id);
|
field::primary_key(op, "id", id);
|
||||||
field::attribute(op, "name", name, 255);
|
field::attribute(op, "name", name, VarChar255);
|
||||||
field::has_many_to_many(op, "recipe_ingredients", recipes, "ingredient_id", "recipe_id", matador::utils::fetch_type::EAGER);
|
field::has_many_to_many(op, "recipe_ingredients", recipes, "ingredient_id", "recipe_id", utils::CascadeAllFetchEager);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct recipe
|
struct recipe {
|
||||||
{
|
|
||||||
unsigned int id{};
|
unsigned int id{};
|
||||||
std::string name;
|
std::string name;
|
||||||
matador::object::collection<matador::object::object_ptr<demo::ingredient>> ingredients{};
|
matador::object::collection<matador::object::object_ptr<demo::ingredient>> ingredients{};
|
||||||
@@ -44,10 +43,11 @@ struct recipe
|
|||||||
|
|
||||||
template<class Operator>
|
template<class Operator>
|
||||||
void process(Operator &op) {
|
void process(Operator &op) {
|
||||||
namespace field = matador::access;
|
using namespace matador;
|
||||||
|
namespace field = access;
|
||||||
field::primary_key(op, "id", id);
|
field::primary_key(op, "id", id);
|
||||||
field::attribute(op, "name", name, 255);
|
field::attribute(op, "name", name, VarChar255);
|
||||||
field::has_many_to_many(op, "recipe_ingredients", ingredients, matador::utils::fetch_type::LAZY);
|
field::has_many_to_many(op, "recipe_ingredients", ingredients, utils::CascadeAllFetchLazy);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+22
-10
@@ -1,4 +1,7 @@
|
|||||||
#include "matador/object/repository.hpp"
|
#include "matador/object/repository.hpp"
|
||||||
|
#include "matador/object/collection.hpp"
|
||||||
|
|
||||||
|
#include "matador/sql/resolver_service.hpp"
|
||||||
|
|
||||||
#include "matador/logger/log_manager.hpp"
|
#include "matador/logger/log_manager.hpp"
|
||||||
|
|
||||||
@@ -65,7 +68,7 @@ struct names {
|
|||||||
void process(Operator &op) {
|
void process(Operator &op) {
|
||||||
namespace field = matador::access;
|
namespace field = matador::access;
|
||||||
field::primary_key( op, "id", id );
|
field::primary_key( op, "id", id );
|
||||||
field::has_many(op, "name_list", names_list, "names_id", matador::utils::fetch_type::EAGER);
|
field::has_many(op, "name_list", names_list, "names_id", matador::utils::fetch_type::Eager);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -78,11 +81,12 @@ struct profile {
|
|||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process(Operator &op) {
|
void process(Operator &op) {
|
||||||
namespace field = matador::access;
|
using namespace matador;
|
||||||
|
namespace field = access;
|
||||||
field::primary_key( op, "id", id );
|
field::primary_key( op, "id", id );
|
||||||
field::attribute( op, "first_name", first_name, 255 );
|
field::attribute( op, "first_name", first_name, VarChar255 );
|
||||||
field::attribute( op, "last_name", last_name, 255 );
|
field::attribute( op, "last_name", last_name, VarChar255 );
|
||||||
field::belongs_to( op, "user_id", user, matador::utils::default_foreign_attributes );
|
field::belongs_to( op, "user_id", user, utils::CascadeNoneFetchLazy );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
struct user {
|
struct user {
|
||||||
@@ -92,10 +96,11 @@ struct user {
|
|||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process(Operator &op) {
|
void process(Operator &op) {
|
||||||
namespace field = matador::access;
|
using namespace matador;
|
||||||
|
namespace field = access;
|
||||||
field::primary_key( op, "id", id );
|
field::primary_key( op, "id", id );
|
||||||
field::attribute( op, "username", username, 255 );
|
field::attribute( op, "username", username, VarChar255 );
|
||||||
field::has_one(op, "profile_id", profile, matador::utils::default_foreign_attributes );
|
field::has_one(op, "profiles", profile, "profile_id", utils::CascadeNoneFetchLazy );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -105,9 +110,10 @@ struct person {
|
|||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process(Operator &op) {
|
void process(Operator &op) {
|
||||||
|
using namespace matador;
|
||||||
namespace field = matador::access;
|
namespace field = matador::access;
|
||||||
field::primary_key( op, "id", id );
|
field::primary_key( op, "id", id );
|
||||||
field::attribute( op, "name", name, 255 );
|
field::attribute( op, "name", name, VarChar255 );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -119,7 +125,7 @@ struct person_repo {
|
|||||||
void process(Operator &op) {
|
void process(Operator &op) {
|
||||||
namespace field = matador::access;
|
namespace field = matador::access;
|
||||||
field::primary_key( op, "id", id );
|
field::primary_key( op, "id", id );
|
||||||
field::has_many( op, "person_list", person_list, "person_id", matador::utils::default_foreign_attributes );
|
field::has_many( op, "person_list", person_list, "person_id", matador::utils::CascadeNoneFetchLazy );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -131,6 +137,12 @@ int main() {
|
|||||||
// logger::default_min_log_level(logger::log_level::LVL_DEBUG);
|
// logger::default_min_log_level(logger::log_level::LVL_DEBUG);
|
||||||
// logger::add_log_sink(logger::create_stdout_sink());
|
// logger::add_log_sink(logger::create_stdout_sink());
|
||||||
|
|
||||||
|
sql::resolver_service rs;
|
||||||
|
|
||||||
|
std::weak_ptr cr = rs.joined_collection_resolver<object::object_ptr<names>>( typeid(person), "names" );
|
||||||
|
utils::identifier id{1};
|
||||||
|
|
||||||
|
object::collection_proxy cp(cr, id);
|
||||||
{
|
{
|
||||||
// has_many with builtin-type
|
// has_many with builtin-type
|
||||||
object::repository repo;
|
object::repository repo;
|
||||||
|
|||||||
+299
-54
@@ -21,24 +21,16 @@
|
|||||||
|
|
||||||
#include "matador/sql/connection.hpp"
|
#include "matador/sql/connection.hpp"
|
||||||
|
|
||||||
#include "matador/orm/session.hpp"
|
#include "matador/query/schema.hpp"
|
||||||
|
|
||||||
template <> struct matador::utils::data_type_traits<work::core::timestamp, void> {
|
#include "matador/query/session.hpp"
|
||||||
static basic_type type(std::size_t /*size*/) { return basic_type::type_uint64; }
|
|
||||||
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*/) {
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <> struct matador::utils::data_type_traits<work::core::UserInfo, void> {
|
template <> struct matador::utils::data_type_traits<work::core::UserInfo, void> {
|
||||||
static basic_type type(std::size_t /*size*/) { return basic_type::type_uint64; }
|
static basic_type type(std::size_t /*size*/) { return basic_type::UInt64; }
|
||||||
static void read_value(attribute_reader &/*reader*/, const char * /*id*/, size_t /*index*/, nullptr_t &/*value*/) {
|
static void read_value(attribute_reader &/*reader*/, const char * /*id*/, size_t /*index*/, work::core::UserInfo &/*value*/) {
|
||||||
|
|
||||||
}
|
}
|
||||||
static void bind_value(attribute_writer &/*binder*/, size_t /*index*/, nullptr_t &/*value*/) {
|
static void bind_value(attribute_writer &/*binder*/, size_t /*index*/, work::core::UserInfo &/*value*/) {
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -56,7 +48,7 @@ using namespace work::models;
|
|||||||
//
|
//
|
||||||
// If all checks succeed, the requested is fetched from
|
// If all checks succeed, the requested is fetched from
|
||||||
// the database.
|
// the database.
|
||||||
// schema.attach<jobs::Payload>("payloads", make_polymorph("type"));
|
// schema.attach_as_base<jobs::Payload>("payloads", make_polymorph("type"));
|
||||||
// schema.attach<jobs::Payload, jobs::IdPayload>("id_list_payloads", make_polymorph_type("IdPayload"));
|
// schema.attach<jobs::Payload, jobs::IdPayload>("id_list_payloads", make_polymorph_type("IdPayload"));
|
||||||
// schema.attach<jobs::Payload, jobs::IdListPayload>("id_payloads", make_polymorph_type("IdListPayload"));
|
// schema.attach<jobs::Payload, jobs::IdListPayload>("id_payloads", make_polymorph_type("IdListPayload"));
|
||||||
// object::object_ptr<jobs::Payload> payload;
|
// object::object_ptr<jobs::Payload> payload;
|
||||||
@@ -70,60 +62,313 @@ using namespace work::models;
|
|||||||
// payload.is_polymorphic_type<jobs::IdPayload>();
|
// payload.is_polymorphic_type<jobs::IdPayload>();
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// logger::default_min_log_level(logger::log_level::LVL_DEBUG);
|
logger::default_min_log_level(logger::log_level::Debug);
|
||||||
// logger::add_log_sink(logger::create_stdout_sink());
|
logger::add_log_sink(logger::create_stdout_sink());
|
||||||
|
|
||||||
// sql::connection_pool<sql::connection> pool("postgres://news:news@127.0.0.1:15432/matador", 4);
|
// sql::connection_pool<sql::connection> pool("postgres://news:news@127.0.0.1:15432/matador", 4);
|
||||||
sql::connection_pool pool("postgres://test:test123!@127.0.0.1:5432/matador", 4);
|
sql::connection_pool pool("postgres://test:test123!@127.0.0.1:15442/matador", 4);
|
||||||
|
|
||||||
object::repository repo("Administration");
|
|
||||||
|
|
||||||
auto result = repo.attach<admin::CollectionCenter>("collection_centers");
|
|
||||||
// repo.create(pool);
|
|
||||||
// repo.drop(pool);
|
|
||||||
|
|
||||||
utils::message_bus bus;
|
utils::message_bus bus;
|
||||||
orm::session ses({bus, pool});
|
// query::schema ses({bus, pool});
|
||||||
|
query::schema admin_schema("Administration");
|
||||||
|
|
||||||
result = ses.attach<admin::CollectionCenter>("collection_centers")
|
auto result = admin_schema.attach<admin::CollectionCenter>("collection_centers")
|
||||||
.and_then([&ses] { return ses.attach<admin::UserDirectory>("user_directories"); })
|
.and_then([&admin_schema] { return admin_schema.attach<admin::UserDirectory>("user_directories"); })
|
||||||
.and_then([&ses] { return ses.attach<admin::LdapGroupSchemaSettings>("ldap_group_schema_settings"); })
|
.and_then([&admin_schema] { return admin_schema.attach<admin::LdapGroupSchemaSettings>("ldap_group_schema_settings"); })
|
||||||
.and_then([&ses] { return ses.attach<admin::LdapImportSettings>("ldap_import_settings"); })
|
.and_then([&admin_schema] { return admin_schema.attach<admin::LdapImportSettings>("ldap_import_settings"); })
|
||||||
.and_then([&ses] { return ses.attach<admin::LdapUserSchemaSettings>("ldap_user_schema_settings"); })
|
.and_then([&admin_schema] { return admin_schema.attach<admin::LdapUserSchemaSettings>("ldap_user_schema_settings"); })
|
||||||
.and_then([&ses] { return ses.attach<admin::InternalUserDirectory, admin::UserDirectory>("internal_user_directories"); })
|
.and_then([&admin_schema] { return admin_schema.attach<admin::InternalUserDirectory, admin::UserDirectory>("internal_user_directories"); })
|
||||||
.and_then([&ses] { return ses.attach<admin::LdapUserDirectory, admin::UserDirectory>("ldap_user_directories"); } )
|
.and_then([&admin_schema] { return admin_schema.attach<admin::LdapUserDirectory, admin::UserDirectory>("ldap_user_directories"); } )
|
||||||
.and_then([&ses] { return ses.attach<admin::LoginHistory>("login_histories"); })
|
.and_then([&admin_schema] { return admin_schema.attach<admin::LoginHistory>("login_histories"); })
|
||||||
.and_then([&ses] { return ses.attach<admin::Scenario>("scenarios"); })
|
.and_then([&admin_schema] { return admin_schema.attach<admin::Scenario>("scenarios"); })
|
||||||
.and_then([&ses] { return ses.attach<admin::User>("users"); })
|
.and_then([&admin_schema] { return admin_schema.attach<admin::User>("users"); })
|
||||||
.and_then([&ses] { return ses.attach<admin::UserSession>("user_sessions"); })
|
.and_then([&admin_schema] { return admin_schema.attach<admin::UserSession>("user_sessions"); })
|
||||||
.and_then([&ses] { return ses.attach<jobs::Job>("jobs"); })
|
.and_then([&admin_schema] { return admin_schema.attach<jobs::Job>("jobs"); })
|
||||||
.and_then([&ses] { return ses.attach<jobs::Payload>("payloads"); })
|
.and_then([&admin_schema] { return admin_schema.attach<jobs::Payload>("payloads"); })
|
||||||
.and_then([&ses] { return ses.attach<jobs::IdPayload, jobs::Payload>("id_list_payloads"); })
|
.and_then([&admin_schema] { return admin_schema.attach<jobs::IdPayload, jobs::Payload>("id_list_payloads"); })
|
||||||
.and_then([&ses] { return ses.attach<jobs::IdListPayload, jobs::Payload>("id_payloads"); })
|
.and_then([&admin_schema] { return admin_schema.attach<jobs::IdListPayload, jobs::Payload>("id_payloads"); })
|
||||||
.and_then([&ses] { return ses.attach<jobs::Task>("tasks"); })
|
.and_then([&admin_schema] { return admin_schema.attach<jobs::Task>("tasks"); })
|
||||||
|
.and_then([&admin_schema, &pool] { return admin_schema.create( *pool.acquire() ); })
|
||||||
;
|
;
|
||||||
ses.dump_schema(std::cout);
|
admin_schema.dump(std::cout);
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
std::cout << "error: " << result.err().message() << std::endl;
|
std::cout << "error: " << result.err().message() << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = ses.create_schema();
|
const auto conn = pool.acquire();
|
||||||
if (!result) {
|
// result = admin_schema.create(*conn);
|
||||||
std::cout << "error: " << result.err() << std::endl;
|
// if (!result) {
|
||||||
return 0;
|
// std::cout << "error: " << result.err() << std::endl;
|
||||||
}
|
// return 0;
|
||||||
|
// }
|
||||||
// const std::string dns{"sqlite://demo.db"};
|
// result = admin_schema.drop(*conn);
|
||||||
// sql::connection c(dns);
|
// if (!result) {
|
||||||
//
|
// std::cout << "error: " << result.err() << std::endl;
|
||||||
// result = c.open();
|
|
||||||
//
|
|
||||||
// // orm::session s()
|
|
||||||
// if (!result.is_ok()) {
|
|
||||||
// return 0;
|
// return 0;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
/*
|
||||||
|
const auto statement = QString( "SELECT %5.%6, %1.%2 FROM %3 %1, %4 %5 WHERE %1.%2=%5.%6 AND %7" )
|
||||||
|
.arg( payloadTableAliasName,
|
||||||
|
payloadSqlMetaInfo.columnName( Payload::Attributes::idAttributeId() ),
|
||||||
|
Payload::staticSqlMetaInfo().tableName(),
|
||||||
|
Task::staticSqlMetaInfo().tableName(),
|
||||||
|
taskTableAliasName,
|
||||||
|
taskSqlMetaInfo.columnName( Task::Attributes::payloadAttributeId() ),
|
||||||
|
filter->idSelectStatement( taskTableAliasName ) );
|
||||||
|
*/
|
||||||
|
|
||||||
|
using namespace matador::query::meta;
|
||||||
|
using namespace matador::utils;
|
||||||
|
|
||||||
|
const auto payloads = PAYLOAD.as( "payloads" );
|
||||||
|
const auto tasks = TASK.as( "tasks" );
|
||||||
|
|
||||||
|
const auto stmt1 = query::select( { tasks.payload, payloads.id } )
|
||||||
|
.from( tasks, payloads )
|
||||||
|
.where ( payloads.id == tasks.payload )
|
||||||
|
.str( conn->dialect() );
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
const auto temporaryTable = status.addChildExc( fillTemporaryTable( idsInsidePayload ) );
|
||||||
|
const auto lookUpTableName = temporaryTable->tableName();
|
||||||
|
|
||||||
|
const auto& jobSqlMetaInfo = Job::staticSqlMetaInfo();
|
||||||
|
const auto& payloadSqlMetaInfo = Payload::staticSqlMetaInfo();
|
||||||
|
const auto& idPayloadSqlMetaInfo = IdPayload::staticSqlMetaInfo();
|
||||||
|
|
||||||
|
const auto statement = QString( "SELECT iPT.%1 FROM %2 iPT INNER JOIN %3 pT ON iPT.%4 = pT.%5 WHERE pT.%5 IN (SELECT %6 FROM %7 WHERE %8=?) AND iPT.%1 IN (SELECT %9 FROM %10)" )
|
||||||
|
.arg( idPayloadSqlMetaInfo.columnName( IdPayload::Attributes::payloadIdAttributeId() ) ) // %1
|
||||||
|
.arg( idPayloadSqlMetaInfo.tableName() ) // %2
|
||||||
|
.arg( payloadSqlMetaInfo.tableName() ) // %3
|
||||||
|
.arg( idPayloadSqlMetaInfo.columnName( IdPayload::Attributes::idAttributeId() ) ) // %4
|
||||||
|
.arg( payloadSqlMetaInfo.columnName( Payload::Attributes::idAttributeId() ) ) // %5
|
||||||
|
.arg( jobSqlMetaInfo.columnName( Job::Attributes::payloadAttributeId() ) ) // %6
|
||||||
|
.arg( jobSqlMetaInfo.tableName() ) // %7
|
||||||
|
.arg( jobSqlMetaInfo.columnName( Job::Attributes::stateSqlAttributeId() ) ) // %8
|
||||||
|
.arg( lookUpColName() ) // %9
|
||||||
|
.arg( lookUpTableName ); // %10
|
||||||
|
*/
|
||||||
|
|
||||||
|
query::table_column temp_id_col("ID");
|
||||||
|
query::table temporary("TempTable", { temp_id_col } );
|
||||||
|
|
||||||
|
const auto iPT = ID_PAYLOAD.as("iPT");
|
||||||
|
const auto pT = PAYLOAD.as("pT");
|
||||||
|
|
||||||
|
const auto stmt2 = query::select({ iPT.payload_id })
|
||||||
|
.from( iPT )
|
||||||
|
.join_left( pT ).on( iPT.id == pT.id )
|
||||||
|
.where(
|
||||||
|
in( pT.id, query::select({ JOB.payload }).from( JOB ).where( JOB.state == _) ) &&
|
||||||
|
in( iPT.payload_id, query::select({ temp_id_col }).from( temporary ) )
|
||||||
|
)
|
||||||
|
.str( conn->dialect() );
|
||||||
|
|
||||||
|
// const QString statement = QString( "SELECT %5 FROM %1 "
|
||||||
|
// "LEFT JOIN (SELECT %2, MAX(%3) AS lastSuccessfulLogin FROM %1 WHERE %4 = ? GROUP BY %2) ll "
|
||||||
|
// "ON %1.%2 = ll.%2 "
|
||||||
|
// "WHERE (lastSuccessfulLogin IS NULL OR %3 <= lastSuccessfulLogin) AND %3 < ?" )
|
||||||
|
// .arg( LoginHistory::staticSqlMetaInfo().tableName() )
|
||||||
|
// .arg( LoginHistory::staticSqlMetaInfo().columnName( LoginHistory::Attributes::userAttributeId() ) )
|
||||||
|
// .arg( LoginHistory::staticSqlMetaInfo().columnName( LoginHistory::Attributes::timestampAttributeId() ) )
|
||||||
|
// .arg( LoginHistory::staticSqlMetaInfo().columnName( LoginHistory::Attributes::failReasonSqlAttributeId() ) )
|
||||||
|
// .arg( LoginHistory::staticSqlMetaInfo().columnName( LoginHistory::Attributes::idAttributeId() ) );
|
||||||
|
|
||||||
|
const auto q = query::select({LOGIN_HISTORY.client, query::maximum(LOGIN_HISTORY.login_time).as( "lastSuccessfulLogin" ) } )
|
||||||
|
.from( LOGIN_HISTORY )
|
||||||
|
.where( LOGIN_HISTORY.fail_reason == _ )
|
||||||
|
.group_by( LOGIN_HISTORY.client );
|
||||||
|
// .as_table("ll");
|
||||||
|
|
||||||
|
const auto stmt3 = query::select({ LOGIN_HISTORY.client })
|
||||||
|
.from( LOGIN_HISTORY )
|
||||||
|
.join_left(q/*, "ll"*/ )
|
||||||
|
.on( LOGIN_HISTORY.client == "ll.client" )
|
||||||
|
.where( query::is_null("lastSuccessfulLogin") && LOGIN_HISTORY.login_time < "ll.lastSuccessfulLogin" )
|
||||||
|
.str( conn->dialect() );
|
||||||
|
|
||||||
|
// const QString subQuery = QString( "SELECT MAX(%1) AS lastSuccessfulLogin, %3 FROM %2 "
|
||||||
|
// "WHERE(%4 = ? OR %4 = ? OR %4 = ?) AND %3 = ? GROUP BY %3 " );
|
||||||
|
//
|
||||||
|
// const QString statement = QString( "SELECT MAX(t1.%1) AS LAST_FAILED_LOGIN FROM %2 t1 LEFT JOIN"
|
||||||
|
// "(%0) t2 "
|
||||||
|
// "ON t1.%3 = t2.%3 "
|
||||||
|
// "WHERE(t2.lastSuccessfulLogin IS NULL OR t2.lastSuccessfulLogin < t1.%1) "
|
||||||
|
// "AND (t1.%4 = ? OR t1.%4 = ?) "
|
||||||
|
// "AND t1.%3 = ?" )
|
||||||
|
// .arg( subQuery )
|
||||||
|
// .arg( LoginHistory::staticSqlMetaInfo().columnName( LoginHistory::Attributes::timestampAttributeId() ) )
|
||||||
|
// .arg( LoginHistory::staticSqlMetaInfo().tableName() )
|
||||||
|
// .arg( columnFilterName )
|
||||||
|
// .arg( LoginHistory::staticSqlMetaInfo().columnName( LoginHistory::Attributes::failReasonSqlAttributeId() ) );
|
||||||
|
//
|
||||||
|
// QSqlQuery query( sqlDatabase() );
|
||||||
|
// if ( query.prepare( statement ) ) {
|
||||||
|
// query.addBindValue( LoginHistory::FailReason::NoFailReason );
|
||||||
|
// query.addBindValue( LoginHistory::FailReason::NoScenarioForUser );
|
||||||
|
// query.addBindValue( LoginHistory::FailReason::UserLockedByAdmin );
|
||||||
|
// query.addBindValue( columnFilterValue );
|
||||||
|
// query.addBindValue( LoginHistory::FailReason::WrongPassword );
|
||||||
|
// query.addBindValue( LoginHistory::FailReason::UnknownUserName );
|
||||||
|
// query.addBindValue( columnFilterValue );
|
||||||
|
|
||||||
|
|
||||||
|
// const auto temporaryTable = status.addChildExc( fillTemporaryTable( idsInsidePayload ) );
|
||||||
|
//
|
||||||
|
// const auto& jobSqlMetaInfo = Job::staticSqlMetaInfo();
|
||||||
|
// const auto& payloadSqlMetaInfo = Payload::staticSqlMetaInfo();
|
||||||
|
// const auto& idPayloadSqlMetaInfo = IdPayload::staticSqlMetaInfo();
|
||||||
|
//
|
||||||
|
// auto filter = std::make_unique<SqlTools::GenericFilter>( new SqlTools::AttributeDefaultFilter( jobSqlMetaInfo,
|
||||||
|
// Job::Attributes::idAttributeId(),
|
||||||
|
// Job::Attributes::idAttributeId(),
|
||||||
|
// Job::Attributes::typeAttributeId(),
|
||||||
|
// SqlTools::AttributeDefaultFilter::Operation::Equal,
|
||||||
|
// jobName ),
|
||||||
|
// new SqlTools::InFilter( payloadSqlMetaInfo.tableName(),
|
||||||
|
// jobSqlMetaInfo.columnName( Job::Attributes::payloadAttributeId() ),
|
||||||
|
// payloadSqlMetaInfo.columnName( Payload::Attributes::idAttributeId() ),
|
||||||
|
// new SqlTools::InFilter( idPayloadSqlMetaInfo.tableName(),
|
||||||
|
// payloadSqlMetaInfo.columnName( Payload::Attributes::idAttributeId() ),
|
||||||
|
// idPayloadSqlMetaInfo.columnName( IdPayload::Attributes::idAttributeId() ),
|
||||||
|
// new SqlTools::TemporaryInFilter( temporaryTable,
|
||||||
|
// idPayloadSqlMetaInfo.columnName( IdPayload::Attributes::payloadIdAttributeId() ),
|
||||||
|
// lookUpColName() ) ) ),
|
||||||
|
// SqlTools::GenericFilter::Operation::And );
|
||||||
|
//
|
||||||
|
// if ( !jobStates.empty() ) {
|
||||||
|
// auto it = jobStates.begin();
|
||||||
|
// std::unique_ptr<SqlTools::GenericFilter> criteria = std::make_unique<SqlTools::AttributeDefaultFilter>( jobSqlMetaInfo,
|
||||||
|
// Job::Attributes::idAttributeId(),
|
||||||
|
// Job::Attributes::idAttributeId(),
|
||||||
|
// Job::Attributes::stateSqlAttributeId(),
|
||||||
|
// SqlTools::AttributeDefaultFilter::Operation::Equal,
|
||||||
|
// *it++ );
|
||||||
|
// for ( ; it != jobStates.end(); ++it ) {
|
||||||
|
// criteria = std::make_unique<SqlTools::GenericFilter>( new SqlTools::AttributeDefaultFilter( jobSqlMetaInfo,
|
||||||
|
// Job::Attributes::idAttributeId(),
|
||||||
|
// Job::Attributes::idAttributeId(),
|
||||||
|
// Job::Attributes::stateSqlAttributeId(),
|
||||||
|
// SqlTools::AttributeDefaultFilter::Operation::Equal,
|
||||||
|
// *it ),
|
||||||
|
// criteria.release(),
|
||||||
|
// SqlTools::GenericFilter::Operation::Or );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// filter = std::make_unique<SqlTools::GenericFilter>( criteria.release(), filter.release(), SqlTools::GenericFilter::Operation::And );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// const auto ids = status.addChildExc( this->ids( SqlManager::jobFilter, filter.get() ) );
|
||||||
|
// SELECT
|
||||||
|
// ID
|
||||||
|
// FROM
|
||||||
|
// NEWS_JOBS
|
||||||
|
// WHERE
|
||||||
|
// NEWS_JOBS.ID > ?
|
||||||
|
// AND (NEWS_JOBS.TYPE = ?
|
||||||
|
// AND ( NEWS_JOBS.PAYLOAD IN (
|
||||||
|
// SELECT
|
||||||
|
// ID
|
||||||
|
// FROM
|
||||||
|
// NEWS_PAYLOADS
|
||||||
|
// WHERE
|
||||||
|
// NEWS_PAYLOADS.ID IN (
|
||||||
|
// SELECT
|
||||||
|
// ID
|
||||||
|
// FROM
|
||||||
|
// NEWS_ID_PAYLOADS
|
||||||
|
// WHERE
|
||||||
|
// NEWS_ID_PAYLOADS.PAYLOAD_ID IN (SELECT ID FROM NEWS_TMP_3499274F12B644179DBD25BB60C48529)
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
|
||||||
|
const auto stmt4 = query::select({JOB.id})
|
||||||
|
.from(JOB)
|
||||||
|
.where( JOB.id > _ && JOB.name == _ && in( JOB.payload, query::select({PAYLOAD.id}).from(PAYLOAD).where(
|
||||||
|
in( PAYLOAD.id, query::select({ID_PAYLOAD.id}).from(ID_PAYLOAD).where(
|
||||||
|
in( ID_PAYLOAD.id, query::select({temp_id_col}).from(temporary))
|
||||||
|
) ) ) ) )
|
||||||
|
.str( conn->dialect() );
|
||||||
|
|
||||||
|
// SELECT DISTINCT nj.ID
|
||||||
|
// FROM NEWS_JOBS nj
|
||||||
|
// JOIN NEWS_PAYLOADS np
|
||||||
|
// ON nj.PAYLOAD = np.ID
|
||||||
|
// JOIN NEWS_ID_PAYLOADS nip
|
||||||
|
// ON np.ID = nip.ID
|
||||||
|
// JOIN NEWS_TMP_3499274F12B644179DBD25BB60C48529 tmp
|
||||||
|
// ON nip.PAYLOAD_ID = tmp.ID
|
||||||
|
// WHERE nj.ID > ?
|
||||||
|
// AND nj.TYPE = ?;
|
||||||
|
|
||||||
|
const auto stmt5 = query::select({JOB.id})
|
||||||
|
.from(JOB)
|
||||||
|
.join_left(PAYLOAD).on(JOB.payload == PAYLOAD.id)
|
||||||
|
.join_left(ID_PAYLOAD).on(PAYLOAD.id == ID_PAYLOAD.id)
|
||||||
|
.join_left(temporary).on(ID_PAYLOAD.id == temp_id_col)
|
||||||
|
.where(JOB.id > _ && JOB.name == _)
|
||||||
|
.str(conn->dialect());
|
||||||
|
|
||||||
|
std::cout << stmt1 << std::endl;
|
||||||
|
std::cout << stmt2 << std::endl;
|
||||||
|
std::cout << stmt3 << std::endl;
|
||||||
|
std::cout << stmt4 << std::endl;
|
||||||
|
std::cout << stmt5 << std::endl;
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
SELECT
|
||||||
|
"tasks"."payload", "payloads"."id"
|
||||||
|
FROM
|
||||||
|
"public"."tasks", "public"."payloads"
|
||||||
|
WHERE
|
||||||
|
"payloads"."id" = "tasks"."payload"
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
"iPT"."payload_id" FROM "public"."id_payloads" "iPT"
|
||||||
|
LEFT JOIN
|
||||||
|
"public"."payloads" "pT"
|
||||||
|
ON
|
||||||
|
"iPT"."id" = "pT"."id"
|
||||||
|
WHERE ("pT"."id" IN (
|
||||||
|
SELECT
|
||||||
|
"jobs"."payload"
|
||||||
|
FROM
|
||||||
|
"public"."jobs"
|
||||||
|
WHERE
|
||||||
|
"jobs"."state" = $1
|
||||||
|
) AND "iPT"."payload_id" IN (
|
||||||
|
SELECT
|
||||||
|
"ID"
|
||||||
|
FROM "public"."TempTable"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
"login_histories"."client"
|
||||||
|
FROM
|
||||||
|
"public"."login_histories"
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT
|
||||||
|
"login_histories"."client", MAX(login_time) AS lastSuccessfulLogin
|
||||||
|
FROM
|
||||||
|
"public"."login_histories"
|
||||||
|
WHERE
|
||||||
|
"login_histories"."fail_reason" = $1
|
||||||
|
GROUP BY
|
||||||
|
"login_histories"."client"
|
||||||
|
)
|
||||||
|
ON
|
||||||
|
"login_histories"."client" = 'll.client'
|
||||||
|
WHERE
|
||||||
|
("lastSuccessfulLogin" IS NULL AND "login_histories"."login_time" < 'll.lastSuccessfulLogin')
|
||||||
|
*/
|
||||||
@@ -11,6 +11,8 @@
|
|||||||
#include "matador/utils/fetch_type.hpp"
|
#include "matador/utils/fetch_type.hpp"
|
||||||
#include "matador/utils/types.hpp"
|
#include "matador/utils/types.hpp"
|
||||||
|
|
||||||
|
#include "matador/query/meta_table_macro.hpp"
|
||||||
|
|
||||||
namespace work::models::admin {
|
namespace work::models::admin {
|
||||||
struct User;
|
struct User;
|
||||||
|
|
||||||
@@ -28,21 +30,24 @@ static const matador::utils::enum_mapper<CollectionCenterType> CollectionCenterT
|
|||||||
|
|
||||||
struct CollectionCenter : core::Model {
|
struct CollectionCenter : core::Model {
|
||||||
std::string name;
|
std::string name;
|
||||||
matador::utils::blob symbol;
|
matador::utils::blob_type_t symbol;
|
||||||
CollectionCenterType type{CollectionCenterType::NoType};
|
CollectionCenterType type{CollectionCenterType::NoType};
|
||||||
matador::object::collection<matador::object::object_ptr<User>> users;
|
matador::object::collection<matador::object::object_ptr<User>> users;
|
||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process( Operator& op ) {
|
||||||
|
using namespace matador;
|
||||||
namespace field = matador::access;
|
namespace field = matador::access;
|
||||||
field::process( op, *matador::base_class<Model>( this ) );
|
field::process( op, *matador::base_class<Model>( this ) );
|
||||||
field::attribute( op, "name", name, 511 );
|
field::attribute( op, "name", name, UniqueVarChar511 );
|
||||||
field::attribute( op, "symbol", symbol );
|
field::attribute( op, "symbol", symbol );
|
||||||
field::attribute( op, "type", type );
|
field::attribute( op, "type", type );
|
||||||
field::has_many( op, "collection_center_users", users, "users_id", matador::utils::fetch_type::LAZY );
|
field::has_many( op, "collection_center_users", users, "users_id", utils::CascadeAllFetchLazy );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
META_TABLE(collection_center, COLLECTION_CENTER, id, version, name, symbol, type)
|
||||||
|
|
||||||
#endif //COLLECTION_CENTER_HPP
|
#endif //COLLECTION_CENTER_HPP
|
||||||
|
|||||||
@@ -15,4 +15,4 @@ struct InternalUserDirectory : UserDirectory {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //INTERNALUSERDIRECTORY_HPP
|
#endif //INTERNAL_USER_DIRECTORY_HPP
|
||||||
|
|||||||
@@ -4,22 +4,24 @@
|
|||||||
#include "../core/Model.hpp"
|
#include "../core/Model.hpp"
|
||||||
|
|
||||||
#include "matador/utils/base_class.hpp"
|
#include "matador/utils/base_class.hpp"
|
||||||
|
#include "matador/utils/foreign_attributes.hpp"
|
||||||
|
|
||||||
namespace work::models::admin {
|
namespace work::models::admin {
|
||||||
struct LdapUserDirectory;
|
struct LdapUserDirectory;
|
||||||
|
|
||||||
struct LdapGroupSchemaSettings : core::Model {
|
struct LdapGroupSchemaSettings : core::Model {
|
||||||
std::string group_object_filter;
|
std::string group_object_filter{};
|
||||||
std::string user_member_attribute;
|
std::string user_member_attribute{};
|
||||||
matador::object::object_ptr<LdapUserDirectory> ldap_user_directory;
|
matador::object::object_ptr<LdapUserDirectory> ldap_user_directory{};
|
||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process( Operator& op ) {
|
||||||
namespace field = matador::access;
|
using namespace matador;
|
||||||
|
namespace field = access;
|
||||||
field::process( op, *matador::base_class<Model>( this ) );
|
field::process( op, *matador::base_class<Model>( this ) );
|
||||||
field::has_one(op, "ldap_user_directory", ldap_user_directory, matador::utils::default_foreign_attributes);
|
field::has_one(op, "ldap_user_directory", ldap_user_directory, utils::CascadeAllFetchLazy);
|
||||||
field::attribute( op, "group_object_filter", group_object_filter, 511 );
|
field::attribute( op, "group_object_filter", group_object_filter, VarChar511 );
|
||||||
field::attribute( op, "user_member_attribute", user_member_attribute, 511 );
|
field::attribute( op, "user_member_attribute", user_member_attribute, VarChar511 );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "../core/Model.hpp"
|
#include "../core/Model.hpp"
|
||||||
|
|
||||||
#include "matador/utils/base_class.hpp"
|
#include "matador/utils/base_class.hpp"
|
||||||
|
#include "matador/utils/foreign_attributes.hpp"
|
||||||
|
|
||||||
namespace work::models::admin {
|
namespace work::models::admin {
|
||||||
struct LdapUserDirectory;
|
struct LdapUserDirectory;
|
||||||
@@ -16,10 +17,11 @@ struct LdapImportSettings : core::Model {
|
|||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process( Operator& op ) {
|
||||||
namespace field = matador::access;
|
using namespace matador;
|
||||||
|
namespace field = access;
|
||||||
field::process( op, *matador::base_class<Model>( this ) );
|
field::process( op, *matador::base_class<Model>( this ) );
|
||||||
field::has_one(op, "ldap_user_directory", ldap_user_directory, matador::utils::default_foreign_attributes);
|
field::has_one(op, "ldap_user_directory", ldap_user_directory, utils::CascadeAllFetchLazy);
|
||||||
field::attribute( op, "default_role", default_role, 511 );
|
field::attribute( op, "default_role", default_role, VarChar511 );
|
||||||
field::attribute( op, "sync_interval", sync_interval );
|
field::attribute( op, "sync_interval", sync_interval );
|
||||||
field::attribute( op, "network_timeout", network_timeout );
|
field::attribute( op, "network_timeout", network_timeout );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "matador/object/object_ptr.hpp"
|
#include "matador/object/object_ptr.hpp"
|
||||||
|
|
||||||
#include "matador/utils/base_class.hpp"
|
#include "matador/utils/base_class.hpp"
|
||||||
|
#include "matador/utils/foreign_attributes.hpp"
|
||||||
|
|
||||||
namespace work::models::admin {
|
namespace work::models::admin {
|
||||||
struct LdapUserDirectory : UserDirectory {
|
struct LdapUserDirectory : UserDirectory {
|
||||||
@@ -24,16 +25,17 @@ struct LdapUserDirectory : UserDirectory {
|
|||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process( Operator& op ) {
|
||||||
namespace field = matador::access;
|
using namespace matador;
|
||||||
|
namespace field = access;
|
||||||
field::process( op, *matador::base_class<UserDirectory>( this ) );
|
field::process( op, *matador::base_class<UserDirectory>( this ) );
|
||||||
field::attribute( op, "schema_base_dn", schema_base_dn, 511 );
|
field::attribute( op, "schema_base_dn", schema_base_dn, VarChar511 );
|
||||||
field::attribute( op, "additional_user_base_dn", additional_user_base_dn, 511 );
|
field::attribute( op, "additional_user_base_dn", additional_user_base_dn, VarChar511 );
|
||||||
field::attribute( op, "additional_group_base_dn", additional_group_base_dn, 511 );
|
field::attribute( op, "additional_group_base_dn", additional_group_base_dn, VarChar511 );
|
||||||
field::belongs_to( op, "user_schema_settings", user_schema_settings, matador::utils::default_foreign_attributes );
|
field::belongs_to( op, "user_schema_settings", user_schema_settings, utils::CascadeAllFetchLazy );
|
||||||
field::belongs_to( op, "group_schema_settings", group_schema_settings, matador::utils::default_foreign_attributes );
|
field::belongs_to( op, "group_schema_settings", group_schema_settings, utils::CascadeAllFetchLazy );
|
||||||
field::belongs_to( op, "import_settings", import_settings, matador::utils::default_foreign_attributes );
|
field::belongs_to( op, "import_settings", import_settings, utils::CascadeAllFetchLazy );
|
||||||
field::has_many( op, "ldap_users", users, "users_id", matador::utils::default_foreign_attributes );
|
field::has_many( op, "ldap_users", users, "users_id", utils::CascadeAllFetchEager );
|
||||||
field::has_many( op, "ldap_groups", groups, "groups_id", matador::utils::default_foreign_attributes );
|
field::has_many( op, "ldap_groups", groups, "groups_id", utils::CascadeAllFetchEager );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,27 +4,28 @@
|
|||||||
#include "../core/Model.hpp"
|
#include "../core/Model.hpp"
|
||||||
|
|
||||||
#include "matador/utils/base_class.hpp"
|
#include "matador/utils/base_class.hpp"
|
||||||
|
#include "matador/utils/foreign_attributes.hpp"
|
||||||
|
|
||||||
namespace work::models::admin {
|
namespace work::models::admin {
|
||||||
struct LdapUserDirectory;
|
struct LdapUserDirectory;
|
||||||
|
|
||||||
struct LdapUserSchemaSettings : core::Model {
|
struct LdapUserSchemaSettings : core::Model {
|
||||||
std::string user_object_filter;
|
std::string user_object_filter{};
|
||||||
std::string user_unique_id_attribute;
|
std::string user_unique_id_attribute{};
|
||||||
std::string user_member_of_attribute;
|
std::string user_member_of_attribute{};
|
||||||
std::string user_name_attribute;
|
std::string user_name_attribute{};
|
||||||
matador::object::object_ptr<LdapUserDirectory> ldap_user_directory;
|
matador::object::object_ptr<LdapUserDirectory> ldap_user_directory{};
|
||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process( Operator& op ) {
|
||||||
namespace field = matador::access;
|
using namespace matador;
|
||||||
|
namespace field = access;
|
||||||
field::process(op, *matador::base_class<Model>( this ));
|
field::process(op, *matador::base_class<Model>( this ));
|
||||||
field::has_one(op, "ldap_user_directory", ldap_user_directory, matador::utils::default_foreign_attributes);
|
field::has_one(op, "ldap_user_directory", ldap_user_directory, utils::CascadeAllFetchLazy);
|
||||||
field::attribute(op, "user_object_filter", user_object_filter, 511);
|
field::attribute(op, "user_object_filter", user_object_filter, VarChar511);
|
||||||
field::attribute(op, "user_unique_id_attribute", user_unique_id_attribute, 511);
|
field::attribute(op, "user_unique_id_attribute", user_unique_id_attribute, VarChar511);
|
||||||
field::attribute(op, "user_member_of_attribute", user_member_of_attribute, 511);
|
field::attribute(op, "user_member_of_attribute", user_member_of_attribute, VarChar511);
|
||||||
field::attribute(op, "user_name_attribute", user_name_attribute, 511);
|
field::attribute(op, "user_name_attribute", user_name_attribute, VarChar511);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,11 @@
|
|||||||
|
|
||||||
#include "matador/object/object_ptr.hpp"
|
#include "matador/object/object_ptr.hpp"
|
||||||
|
|
||||||
|
#include "matador/query/meta_table_macro.hpp"
|
||||||
|
|
||||||
#include "matador/utils/base_class.hpp"
|
#include "matador/utils/base_class.hpp"
|
||||||
#include "matador/utils/enum_mapper.hpp"
|
#include "matador/utils/enum_mapper.hpp"
|
||||||
|
#include "matador/utils/foreign_attributes.hpp"
|
||||||
|
|
||||||
namespace work::models::admin {
|
namespace work::models::admin {
|
||||||
|
|
||||||
@@ -39,25 +42,30 @@ static const matador::utils::enum_mapper<FailReason> FailReasonEnum({
|
|||||||
});
|
});
|
||||||
|
|
||||||
struct LoginHistory : core::Model {
|
struct LoginHistory : core::Model {
|
||||||
matador::object::object_ptr<User> user;
|
matador::object::object_ptr<User> client;
|
||||||
matador::object::object_ptr<Scenario> scenario;
|
matador::object::object_ptr<Scenario> scenario;
|
||||||
matador::object::object_ptr<CollectionCenter> collection_center;
|
matador::object::object_ptr<CollectionCenter> collection_center;
|
||||||
std::string login_name;
|
std::string login_name;
|
||||||
FailReason fail_reason{FailReason::NoFailReason};
|
FailReason fail_reason{FailReason::NoFailReason};
|
||||||
core::timestamp login_time;
|
matador::utils::timestamp_type_t login_time;
|
||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process( Operator& op ) {
|
||||||
namespace field = matador::access;
|
using namespace matador;
|
||||||
|
namespace field = access;
|
||||||
|
field::process_base<Model>( op, *this );
|
||||||
field::process( op, *matador::base_class<Model>( this ) );
|
field::process( op, *matador::base_class<Model>( this ) );
|
||||||
field::belongs_to( op, "user", user, matador::utils::default_foreign_attributes );
|
field::belongs_to( op, "client", client, utils::CascadeAllFetchLazy );
|
||||||
field::belongs_to( op, "scenario", scenario, matador::utils::default_foreign_attributes );
|
field::belongs_to( op, "scenario", scenario, utils::CascadeAllFetchLazy );
|
||||||
field::belongs_to( op, "collection_center", collection_center, matador::utils::default_foreign_attributes );
|
field::belongs_to( op, "collection_center", collection_center, utils::CascadeAllFetchLazy );
|
||||||
field::attribute( op, "login_name", login_name, 511 );
|
field::attribute( op, "login_name", login_name, VarChar511 );
|
||||||
field::attribute( op, "fail_reason", fail_reason );
|
field::attribute( op, "fail_reason", fail_reason );
|
||||||
field::attribute( op, "login_time", login_time );
|
field::attribute( op, "login_time", login_time );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
META_TABLE( login_histories, LOGIN_HISTORY, id, version, client, scenario, collection_center, login_name, fail_reason, login_time )
|
||||||
|
|
||||||
#endif //LOGIN_HISTORY_HPP
|
#endif //LOGIN_HISTORY_HPP
|
||||||
|
|||||||
@@ -40,20 +40,21 @@ struct Scenario : core::Model {
|
|||||||
std::string name;
|
std::string name;
|
||||||
ScenarioMode mode{ScenarioMode::InvalidMode};
|
ScenarioMode mode{ScenarioMode::InvalidMode};
|
||||||
std::string description;
|
std::string description;
|
||||||
matador::utils::blob symbol;
|
matador::utils::blob_type_t symbol;
|
||||||
ScenarioState state{ScenarioState::InvalidState};
|
ScenarioState state{ScenarioState::InvalidState};
|
||||||
matador::object::collection<matador::object::object_ptr<CollectionCenter>> collection_center;
|
matador::object::collection<matador::object::object_ptr<CollectionCenter>> collection_center;
|
||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process( Operator& op ) {
|
||||||
namespace field = matador::access;
|
using namespace matador;
|
||||||
|
namespace field = access;
|
||||||
field::process( op, *matador::base_class<Model>( this ) );
|
field::process( op, *matador::base_class<Model>( this ) );
|
||||||
field::attribute( op, "name", name, 511 );
|
field::attribute( op, "name", name, UniqueVarChar511 );
|
||||||
field::attribute( op, "mode", mode );
|
field::attribute( op, "mode", mode );
|
||||||
field::attribute( op, "description", description, 511 );
|
field::attribute( op, "description", description, VarChar511 );
|
||||||
field::attribute( op, "symbol", symbol );
|
field::attribute( op, "symbol", symbol );
|
||||||
field::attribute( op, "state", state );
|
field::attribute( op, "state", state );
|
||||||
field::has_many( op, "collection_center", collection_center, "scenario_id", matador::utils::fetch_type::LAZY );
|
field::has_many( op, "collection_center", collection_center, "scenario_id", utils::CascadeAllFetchLazy );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-10
@@ -4,11 +4,13 @@
|
|||||||
#include "LockType.hpp"
|
#include "LockType.hpp"
|
||||||
|
|
||||||
#include "../core/Model.hpp"
|
#include "../core/Model.hpp"
|
||||||
#include "../core/Types.hpp"
|
|
||||||
|
|
||||||
#include "matador/object/object_ptr.hpp"
|
#include "matador/object/object_ptr.hpp"
|
||||||
|
|
||||||
|
#include "matador/query/meta_table_macro.hpp"
|
||||||
|
|
||||||
#include "matador/utils/base_class.hpp"
|
#include "matador/utils/base_class.hpp"
|
||||||
|
#include "matador/utils/foreign_attributes.hpp"
|
||||||
#include "matador/utils/types.hpp"
|
#include "matador/utils/types.hpp"
|
||||||
|
|
||||||
namespace work::models::admin {
|
namespace work::models::admin {
|
||||||
@@ -16,30 +18,34 @@ struct UserDirectory;
|
|||||||
|
|
||||||
struct User : core::Model {
|
struct User : core::Model {
|
||||||
std::string name;
|
std::string name;
|
||||||
matador::utils::blob symbol;
|
matador::utils::blob_type_t symbol;
|
||||||
std::string salt;
|
std::string salt;
|
||||||
std::string password;
|
std::string password;
|
||||||
LockType lock_type{LockType::NoLock};
|
LockType lock_type{LockType::NoLock};
|
||||||
core::timestamp locked_at;
|
matador::utils::timestamp_type_t locked_at;
|
||||||
std::string lock_reason;
|
std::string lock_reason;
|
||||||
std::string role;
|
std::string role;
|
||||||
matador::object::object_ptr<UserDirectory> user_directory;
|
matador::object::object_ptr<UserDirectory> user_directory;
|
||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process( Operator& op ) {
|
||||||
namespace field = matador::access;
|
using namespace matador;
|
||||||
|
namespace field = access;
|
||||||
field::process( op, *matador::base_class<Model>( this ) );
|
field::process( op, *matador::base_class<Model>( this ) );
|
||||||
field::attribute( op, "name", name, 511 );
|
field::attribute( op, "name", name, UniqueVarChar511 );
|
||||||
field::attribute( op, "symbol", symbol );
|
field::attribute( op, "symbol", symbol );
|
||||||
field::attribute( op, "salt", salt, 511 );
|
field::attribute( op, "salt", salt, VarChar511 );
|
||||||
field::attribute( op, "password", password, 511 );
|
field::attribute( op, "password", password, VarChar511 );
|
||||||
field::attribute( op, "lock_type", lock_type );
|
field::attribute( op, "lock_type", lock_type );
|
||||||
field::attribute( op, "locked_at", locked_at );
|
field::attribute( op, "locked_at", locked_at );
|
||||||
field::attribute( op, "lock_reason", lock_reason, 511 );
|
field::attribute( op, "lock_reason", lock_reason, VarChar511 );
|
||||||
field::attribute( op, "role", role, 63 );
|
field::attribute( op, "role", role, VarChar63 );
|
||||||
field::belongs_to( op, "user_directory", user_directory, matador::utils::default_foreign_attributes );
|
field::belongs_to( op, "user_directory", user_directory, utils::CascadeAllFetchLazy );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
META_TABLE(users, USER, id, version, name, symbol, salt, password, lock_type, locked_at, lock_reason, role, user_directory)
|
||||||
|
|
||||||
#endif //USER_HPP
|
#endif //USER_HPP
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ struct UserDirectory : core::Model {
|
|||||||
void process( Operator& op ) {
|
void process( Operator& op ) {
|
||||||
namespace field = matador::access;
|
namespace field = matador::access;
|
||||||
field::process( op, *matador::base_class<Model>( this ) );
|
field::process( op, *matador::base_class<Model>( this ) );
|
||||||
field::attribute( op, "name", name, 511 );
|
field::attribute( op, "name", name, matador::VarChar511 );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,26 +6,27 @@
|
|||||||
#include "User.hpp"
|
#include "User.hpp"
|
||||||
|
|
||||||
#include "../core/Model.hpp"
|
#include "../core/Model.hpp"
|
||||||
#include "../core/Types.hpp"
|
|
||||||
|
|
||||||
#include "matador/object/object_ptr.hpp"
|
#include "matador/object/object_ptr.hpp"
|
||||||
|
|
||||||
#include "matador/utils/base_class.hpp"
|
#include "matador/utils/base_class.hpp"
|
||||||
|
#include "matador/utils/foreign_attributes.hpp"
|
||||||
|
|
||||||
namespace work::models::admin {
|
namespace work::models::admin {
|
||||||
struct UserSession : core::Model {
|
struct UserSession : core::Model {
|
||||||
matador::object::object_ptr<User> user;
|
matador::object::object_ptr<User> client;
|
||||||
matador::object::object_ptr<Scenario> scenario;
|
matador::object::object_ptr<Scenario> scenario;
|
||||||
matador::object::object_ptr<CollectionCenter> collection_center;
|
matador::object::object_ptr<CollectionCenter> collection_center;
|
||||||
core::timestamp offline_since;
|
matador::utils::timestamp_type_t offline_since;
|
||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process( Operator& op ) {
|
||||||
namespace field = matador::access;
|
using namespace matador;
|
||||||
|
namespace field = access;
|
||||||
field::process( op, *matador::base_class<Model>( this ) );
|
field::process( op, *matador::base_class<Model>( this ) );
|
||||||
field::belongs_to( op, "user", user, matador::utils::default_foreign_attributes );
|
field::belongs_to( op, "client", client, utils::CascadeAllFetchLazy );
|
||||||
field::belongs_to( op, "scenario", scenario, matador::utils::default_foreign_attributes );
|
field::belongs_to( op, "scenario", scenario, utils::CascadeAllFetchLazy );
|
||||||
field::belongs_to( op, "collection_center", collection_center, matador::utils::default_foreign_attributes );
|
field::belongs_to( op, "collection_center", collection_center, utils::CascadeAllFetchLazy );
|
||||||
field::attribute( op, "offline_since", offline_since );
|
field::attribute( op, "offline_since", offline_since );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
|
|
||||||
namespace work::core {
|
namespace work::core {
|
||||||
struct Model {
|
struct Model {
|
||||||
uint64_t id;
|
int64_t id{};
|
||||||
uint64_t version;
|
uint64_t version{};
|
||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process( Operator& op ) {
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
#ifndef TYPES_HPP
|
|
||||||
#define TYPES_HPP
|
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
|
|
||||||
namespace work::core {
|
|
||||||
using timestamp = std::chrono::system_clock::time_point;
|
|
||||||
}
|
|
||||||
#endif //TYPES_HPP
|
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
#define USERINFO_HPP
|
#define USERINFO_HPP
|
||||||
|
|
||||||
#include "matador/utils/access.hpp"
|
#include "matador/utils/access.hpp"
|
||||||
|
#include "matador/utils/field_attributes.hpp"
|
||||||
|
|
||||||
namespace work::core {
|
namespace work::core {
|
||||||
struct UserInfo {
|
struct UserInfo {
|
||||||
@@ -12,9 +13,10 @@ struct UserInfo {
|
|||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process( Operator& op ) {
|
||||||
namespace field = matador::access;
|
namespace field = matador::access;
|
||||||
|
using namespace matador;
|
||||||
field::attribute( op, "user_session_id", user_session_id );
|
field::attribute( op, "user_session_id", user_session_id );
|
||||||
field::attribute( op, "user_role", user_role, 255 );
|
field::attribute( op, "user_role", user_role, VarChar255 );
|
||||||
field::attribute( op, "database_name", database_name, 255 );
|
field::attribute( op, "database_name", database_name, VarChar255 );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
#include "matador/object/collection.hpp"
|
#include "matador/object/collection.hpp"
|
||||||
|
|
||||||
|
#include "matador/query/meta_table_macro.hpp"
|
||||||
|
|
||||||
#include "matador/utils/foreign_attributes.hpp"
|
#include "matador/utils/foreign_attributes.hpp"
|
||||||
|
|
||||||
namespace work::models::jobs {
|
namespace work::models::jobs {
|
||||||
@@ -14,9 +16,11 @@ struct IdListPayload : Payload {
|
|||||||
void process( Operator& op ) {
|
void process( Operator& op ) {
|
||||||
namespace field = matador::access;
|
namespace field = matador::access;
|
||||||
field::process( op, *matador::base_class<Payload>( this ) );
|
field::process( op, *matador::base_class<Payload>( this ) );
|
||||||
field::has_many( op, "payload_ids", payload_ids, "payload_id", matador::utils::default_foreign_attributes );
|
field::has_many( op, "payload_ids", payload_ids, "payload_id", matador::utils::CascadeNoneFetchLazy );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
META_TABLE(id_list_payloads, ID_LIST_PAYLOAD, id, version, type, job)
|
||||||
|
|
||||||
#endif //ID_LIST_PAYLOAD_HPP
|
#endif //ID_LIST_PAYLOAD_HPP
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include "Payload.hpp"
|
#include "Payload.hpp"
|
||||||
|
|
||||||
|
#include "matador/query/meta_table_macro.hpp"
|
||||||
|
|
||||||
namespace work::models::jobs {
|
namespace work::models::jobs {
|
||||||
struct IdPayload : Payload {
|
struct IdPayload : Payload {
|
||||||
uint64_t payload_id{};
|
uint64_t payload_id{};
|
||||||
@@ -15,4 +17,6 @@ struct IdPayload : Payload {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
META_TABLE(id_payloads, ID_PAYLOAD, id, version, type, job, payload_id)
|
||||||
|
|
||||||
#endif //ID_PAYLOAD_HPP
|
#endif //ID_PAYLOAD_HPP
|
||||||
|
|||||||
+11
-6
@@ -7,12 +7,14 @@
|
|||||||
#include "Task.hpp"
|
#include "Task.hpp"
|
||||||
|
|
||||||
#include "../core/Model.hpp"
|
#include "../core/Model.hpp"
|
||||||
#include "../core/Types.hpp"
|
|
||||||
#include "../core/UserInfo.hpp"
|
#include "../core/UserInfo.hpp"
|
||||||
|
|
||||||
#include "matador/object/object_ptr.hpp"
|
#include "matador/object/object_ptr.hpp"
|
||||||
|
|
||||||
|
#include "matador/query/meta_table_macro.hpp"
|
||||||
|
|
||||||
#include "matador/utils/base_class.hpp"
|
#include "matador/utils/base_class.hpp"
|
||||||
|
#include "matador/utils/foreign_attributes.hpp"
|
||||||
|
|
||||||
namespace work::models::jobs {
|
namespace work::models::jobs {
|
||||||
|
|
||||||
@@ -21,26 +23,29 @@ struct Job : core::Model {
|
|||||||
std::string description;
|
std::string description;
|
||||||
JobState state;
|
JobState state;
|
||||||
JobMode mode;
|
JobMode mode;
|
||||||
core::timestamp created_at;
|
matador::utils::timestamp_type_t created_at;
|
||||||
matador::object::object_ptr<Payload> payload;
|
matador::object::object_ptr<Payload> payload;
|
||||||
matador::object::object_ptr<Task> task;
|
matador::object::object_ptr<Task> task;
|
||||||
core::UserInfo user_info;
|
core::UserInfo user_info;
|
||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process( Operator& op ) {
|
||||||
|
using namespace matador;
|
||||||
namespace field = matador::access;
|
namespace field = matador::access;
|
||||||
field::process( op, *matador::base_class<Model>( this ) );
|
field::process( op, *matador::base_class<Model>( this ) );
|
||||||
field::attribute( op, "name", name, 511 );
|
field::attribute( op, "name", name, UniqueVarChar511 );
|
||||||
field::attribute( op, "description", description, 511 );
|
field::attribute( op, "description", description, VarChar1023 );
|
||||||
field::attribute( op, "state", state );
|
field::attribute( op, "state", state );
|
||||||
field::attribute( op, "mode", mode );
|
field::attribute( op, "mode", mode );
|
||||||
field::attribute( op, "created_at", created_at );
|
field::attribute( op, "created_at", created_at );
|
||||||
field::has_one(op, "payload", payload, matador::utils::default_foreign_attributes );
|
field::has_one(op, "payload", payload, utils::CascadeAllFetchLazy );
|
||||||
field::belongs_to( op, "task", task, matador::utils::default_foreign_attributes );
|
field::belongs_to( op, "task", task, utils::CascadeAllFetchLazy );
|
||||||
field::attribute( op, "user_info", user_info );
|
field::attribute( op, "user_info", user_info );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
META_TABLE(jobs, JOB, id, version, name, description, state, mode, created_at, payload, task, user_info)
|
||||||
|
|
||||||
#endif //JOB_HPP
|
#endif //JOB_HPP
|
||||||
|
|||||||
@@ -3,22 +3,28 @@
|
|||||||
|
|
||||||
#include "../core/Model.hpp"
|
#include "../core/Model.hpp"
|
||||||
|
|
||||||
|
#include "matador/query/meta_table_macro.hpp"
|
||||||
|
|
||||||
#include "matador/utils/base_class.hpp"
|
#include "matador/utils/base_class.hpp"
|
||||||
|
#include "matador/utils/foreign_attributes.hpp"
|
||||||
|
|
||||||
namespace work::models::jobs {
|
namespace work::models::jobs {
|
||||||
struct Job;
|
struct Job;
|
||||||
struct Payload : core::Model {
|
struct Payload : core::Model {
|
||||||
std::string type;
|
std::string type{};
|
||||||
matador::object::object_ptr<Job> job;
|
matador::object::object_ptr<Job> job{};
|
||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process( Operator& op ) {
|
||||||
|
using namespace matador;
|
||||||
namespace field = matador::access;
|
namespace field = matador::access;
|
||||||
field::process( op, *matador::base_class<Model>( this ) );
|
field::process( op, *matador::base_class<Model>( this ) );
|
||||||
field::attribute( op, "type", type, 255 );
|
field::attribute( op, "type", type, VarChar255 );
|
||||||
field::belongs_to( op, "job", job, matador::utils::default_foreign_attributes );
|
field::belongs_to( op, "job", job, utils::CascadeAllFetchLazy );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
META_TABLE(payloads, PAYLOAD, id, version, type, job)
|
||||||
|
|
||||||
#endif //PAYLOAD_HPP
|
#endif //PAYLOAD_HPP
|
||||||
|
|||||||
+12
-7
@@ -4,11 +4,13 @@
|
|||||||
#include "TaskState.hpp"
|
#include "TaskState.hpp"
|
||||||
|
|
||||||
#include "../core/Model.hpp"
|
#include "../core/Model.hpp"
|
||||||
#include "../core/Types.hpp"
|
|
||||||
|
|
||||||
#include "matador/object/object_ptr.hpp"
|
#include "matador/object/object_ptr.hpp"
|
||||||
|
|
||||||
|
#include "matador/query/meta_table_macro.hpp"
|
||||||
|
|
||||||
#include "matador/utils/base_class.hpp"
|
#include "matador/utils/base_class.hpp"
|
||||||
|
#include "matador/utils/foreign_attributes.hpp"
|
||||||
|
|
||||||
namespace work::models::jobs {
|
namespace work::models::jobs {
|
||||||
struct Task : core::Model {
|
struct Task : core::Model {
|
||||||
@@ -18,19 +20,20 @@ struct Task : core::Model {
|
|||||||
TaskState state;
|
TaskState state;
|
||||||
matador::object::object_ptr<Payload> payload;
|
matador::object::object_ptr<Payload> payload;
|
||||||
JobMode job_mode;
|
JobMode job_mode;
|
||||||
core::timestamp start_delay;
|
matador::utils::timestamp_type_t start_delay;
|
||||||
core::timestamp interval;
|
matador::utils::timestamp_type_t interval;
|
||||||
uint64_t user_session_id;
|
uint64_t user_session_id;
|
||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process( Operator& op ) {
|
||||||
|
using namespace matador;
|
||||||
namespace field = matador::access;
|
namespace field = matador::access;
|
||||||
field::process( op, *matador::base_class<Model>( this ) );
|
field::process( op, *matador::base_class<Model>( this ) );
|
||||||
field::attribute( op, "name", name, 511 );
|
field::attribute( op, "name", name, UniqueVarChar511 );
|
||||||
field::attribute( op, "description", description, 511 );
|
field::attribute( op, "description", description, VarChar1023 );
|
||||||
field::attribute( op, "job_name", job_name, 511 );
|
field::attribute( op, "job_name", job_name, VarChar511 );
|
||||||
field::attribute( op, "state", state );
|
field::attribute( op, "state", state );
|
||||||
field::belongs_to( op, "payload", payload, matador::utils::default_foreign_attributes );
|
field::belongs_to( op, "payload", payload, utils::CascadeAllFetchLazy );
|
||||||
field::attribute( op, "job_mode", job_mode );
|
field::attribute( op, "job_mode", job_mode );
|
||||||
field::attribute( op, "start_delay", start_delay );
|
field::attribute( op, "start_delay", start_delay );
|
||||||
field::attribute( op, "interval", interval );
|
field::attribute( op, "interval", interval );
|
||||||
@@ -39,4 +42,6 @@ struct Task : core::Model {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
META_TABLE(tasks, TASK, id, version, name, description, job_name, state, payload, job_mode, start_delay, interval, user_session_id)
|
||||||
|
|
||||||
#endif //TASK_HPP
|
#endif //TASK_HPP
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ public:
|
|||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void get_time_stamp(char* timestamp_buffer) const;
|
static void get_time_stamp(char* timestamp_buffer);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::map<log_level, std::string> level_strings;
|
static std::map<log_level, std::string> level_strings;
|
||||||
|
|||||||
@@ -8,15 +8,14 @@ namespace matador::logger {
|
|||||||
/**
|
/**
|
||||||
* Represents all available log levels
|
* Represents all available log levels
|
||||||
*/
|
*/
|
||||||
enum class log_level
|
enum class log_level {
|
||||||
{
|
Fatal, /**< If a serious error occurred, use FATAL level */
|
||||||
LVL_FATAL, /**< If a serious error occurred, use FATAL level */
|
Error, /**< On error use ERROR level */
|
||||||
LVL_ERROR, /**< On error use ERROR level */
|
Warn, /**< Warnings should use WARN level */
|
||||||
LVL_WARN, /**< Warnings should use WARN level */
|
Info, /**< Information should go with INFO level */
|
||||||
LVL_INFO, /**< Information should go with INFO level */
|
Debug, /**< Debug output should use DEBUG level */
|
||||||
LVL_DEBUG, /**< Debug output should use DEBUG level */
|
Trace, /**< Trace information should use TRACE level */
|
||||||
LVL_TRACE, /**< Trace information should use TRACE level */
|
All /**< This level represents all log levels and should be used for logging */
|
||||||
LVL_ALL /**< This level represents all log levels and should be used for logging */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,10 +30,9 @@ std::ostream& operator<<(std::ostream &os, log_level lvl);
|
|||||||
|
|
||||||
/// @cond MATADOR_DEV
|
/// @cond MATADOR_DEV
|
||||||
|
|
||||||
struct log_level_range
|
struct log_level_range {
|
||||||
{
|
log_level min_level = log_level::Fatal;
|
||||||
log_level min_level = log_level::LVL_INFO;
|
log_level max_level = log_level::Info;
|
||||||
log_level max_level = log_level::LVL_FATAL;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @endcond
|
/// @endcond
|
||||||
|
|||||||
@@ -123,10 +123,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// @cond MATADOR_DEV
|
/// @cond MATADOR_DEV
|
||||||
log_manager()
|
log_manager();
|
||||||
{
|
|
||||||
default_log_domain_ = log_domain_map_.insert(std::make_pair("default", std::make_shared<log_domain>("default", default_log_level_range_))).first->second;
|
|
||||||
}
|
|
||||||
/// @endcond
|
/// @endcond
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -140,6 +137,8 @@ private:
|
|||||||
std::map<std::string, std::shared_ptr<log_domain>> log_domain_map_;
|
std::map<std::string, std::shared_ptr<log_domain>> log_domain_map_;
|
||||||
|
|
||||||
static log_level_range default_log_level_range_;
|
static log_level_range default_log_level_range_;
|
||||||
|
|
||||||
|
std::mutex mutex_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -285,15 +284,10 @@ void log_default(log_level lvl, const std::string &source, const char *message);
|
|||||||
* @param args The arguments for the message
|
* @param args The arguments for the message
|
||||||
*/
|
*/
|
||||||
template<typename... ARGS>
|
template<typename... ARGS>
|
||||||
void log(const log_level lvl, const std::string &source, const char *what, ARGS const &... args)
|
void log(const log_level lvl, const std::string &source, const char *what, ARGS const &... args) {
|
||||||
{
|
char message_buffer[logger::buffer_size];
|
||||||
char message_buffer[16384];
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
snprintf(message_buffer, logger::buffer_size, what, args...);
|
||||||
sprintf_s(message_buffer, 912, what, args...);
|
|
||||||
#else
|
|
||||||
sprintf(message_buffer, what, args...);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
log_default(lvl, source, message_buffer);
|
log_default(lvl, source, message_buffer);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
namespace matador::logger {
|
namespace matador::logger {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief logger to write log messages to log domains
|
* @brief logger to write log messages to log domains
|
||||||
*
|
*
|
||||||
@@ -31,9 +30,9 @@ namespace matador::logger {
|
|||||||
* All log messages are written through the internal
|
* All log messages are written through the internal
|
||||||
* log_domain object to the sinks.
|
* log_domain object to the sinks.
|
||||||
*/
|
*/
|
||||||
class logger final
|
class logger final {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
static constexpr size_t buffer_size = 16384;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a logger with a given source name connected
|
* Create a logger with a given source name connected
|
||||||
@@ -69,7 +68,7 @@ public:
|
|||||||
* @param args The arguments to be replaced in the message
|
* @param args The arguments to be replaced in the message
|
||||||
*/
|
*/
|
||||||
template<typename ... ARGS>
|
template<typename ... ARGS>
|
||||||
void fatal(const char *what, ARGS const &... args) const { log(log_level::LVL_FATAL, what, args...); }
|
void fatal(const char *what, ARGS const &... args) const { log(log_level::Fatal, what, args...); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a log message string with log level LVL_FATAL
|
* Writes a log message string with log level LVL_FATAL
|
||||||
@@ -91,7 +90,7 @@ public:
|
|||||||
* @param args The arguments to be replaced in the message
|
* @param args The arguments to be replaced in the message
|
||||||
*/
|
*/
|
||||||
template<typename ... ARGS>
|
template<typename ... ARGS>
|
||||||
void error(const char *what, ARGS const &... args) const { log(log_level::LVL_ERROR, what, args...); }
|
void error(const char *what, ARGS const &... args) const { log(log_level::Error, what, args...); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a log message string with log level LVL_FATAL
|
* Writes a log message string with log level LVL_FATAL
|
||||||
@@ -113,7 +112,7 @@ public:
|
|||||||
* @param args The arguments to be replaced in the message
|
* @param args The arguments to be replaced in the message
|
||||||
*/
|
*/
|
||||||
template<typename ... ARGS>
|
template<typename ... ARGS>
|
||||||
void warn(const char *what, ARGS const &... args) const { log(log_level::LVL_WARN, what, args...); }
|
void warn(const char *what, ARGS const &... args) const { log(log_level::Warn, what, args...); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a log message string with log level LVL_FATAL
|
* Writes a log message string with log level LVL_FATAL
|
||||||
@@ -135,7 +134,7 @@ public:
|
|||||||
* @param args The arguments to be replaced in the message
|
* @param args The arguments to be replaced in the message
|
||||||
*/
|
*/
|
||||||
template<typename ... ARGS>
|
template<typename ... ARGS>
|
||||||
void info(const char *what, ARGS const &... args) const { log(log_level::LVL_INFO, what, args...); }
|
void info(const char *what, ARGS const &... args) const { log(log_level::Info, what, args...); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a log message string with log level LVL_FATAL
|
* Writes a log message string with log level LVL_FATAL
|
||||||
@@ -157,7 +156,7 @@ public:
|
|||||||
* @param args The arguments to be replaced in the message
|
* @param args The arguments to be replaced in the message
|
||||||
*/
|
*/
|
||||||
template<typename ... ARGS>
|
template<typename ... ARGS>
|
||||||
void debug(const char *what, ARGS const &... args) const { log(log_level::LVL_DEBUG, what, args...); }
|
void debug(const char *what, ARGS const &... args) const { log(log_level::Debug, what, args...); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a log message string with log level LVL_FATAL
|
* Writes a log message string with log level LVL_FATAL
|
||||||
@@ -179,7 +178,7 @@ public:
|
|||||||
* @param args The arguments to be replaced in the message
|
* @param args The arguments to be replaced in the message
|
||||||
*/
|
*/
|
||||||
template<typename ... ARGS>
|
template<typename ... ARGS>
|
||||||
void trace(const char *what, ARGS const &... args) const { log(log_level::LVL_TRACE, what, args...); }
|
void trace(const char *what, ARGS const &... args) const { log(log_level::Trace, what, args...); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a log message represented by a char pointer
|
* Writes a log message represented by a char pointer
|
||||||
@@ -222,14 +221,10 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename... ARGS>
|
template<typename... ARGS>
|
||||||
void logger::log(log_level lvl, const char *what, ARGS const &... args) const {
|
void logger::log(const log_level lvl, const char *what, ARGS const &... args) const {
|
||||||
char message_buffer[16384];
|
char message_buffer[buffer_size];
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
snprintf(message_buffer, buffer_size, what, args...);
|
||||||
sprintf_s(message_buffer, 16384, what, args...);
|
|
||||||
#else
|
|
||||||
sprintf(message_buffer, what, args...);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
logger_domain_->log(lvl, source_, message_buffer);
|
logger_domain_->log(lvl, source_, message_buffer);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
#ifndef MATADOR_NET_OS_HPP
|
#ifndef MATADOR_NET_OS_HPP
|
||||||
#define MATADOR_NET_OS_HPP
|
#define MATADOR_NET_OS_HPP
|
||||||
|
|
||||||
#include "matador/net/export.hpp"
|
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef MATADOR_ABSTRACT_COLLECTION_RESOLVER_HPP
|
||||||
|
#define MATADOR_ABSTRACT_COLLECTION_RESOLVER_HPP
|
||||||
|
|
||||||
|
#include "matador/object/abstract_type_resolver.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <typeindex>
|
||||||
|
|
||||||
|
namespace matador::object {
|
||||||
|
class abstract_joined_resolver : public abstract_type_resolver {
|
||||||
|
public:
|
||||||
|
[[nodiscard]] const std::type_index& root_type() const;
|
||||||
|
[[nodiscard]] const std::string& collection_name() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit abstract_joined_resolver(const std::type_index& root_type, const std::type_index& type, std::string collection_name);
|
||||||
|
|
||||||
|
public:
|
||||||
|
const std::type_index root_type_;
|
||||||
|
const std::string collection_name_;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif // MATADOR_ABSTRACT_COLLECTION_RESOLVER_HPP
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef MATADOR_ABSTRACT_TYPE_RESOLVER_HPP
|
||||||
|
#define MATADOR_ABSTRACT_TYPE_RESOLVER_HPP
|
||||||
|
|
||||||
|
#include <typeindex>
|
||||||
|
|
||||||
|
namespace matador::object {
|
||||||
|
class abstract_type_resolver {
|
||||||
|
public:
|
||||||
|
virtual ~abstract_type_resolver() = default;
|
||||||
|
|
||||||
|
[[nodiscard]] const std::type_index& type() const { return type_; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit abstract_type_resolver(const std::type_index& ti) : type_(ti) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
const std::type_index type_;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif //MATADOR_ABSTRACT_TYPE_RESOLVER_HPP
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#ifndef MATADOR_ABSTRACT_TYPE_RESOLVER_FACTORY_HPP
|
||||||
|
#define MATADOR_ABSTRACT_TYPE_RESOLVER_FACTORY_HPP
|
||||||
|
|
||||||
|
#include "matador/object/abstract_type_resolver.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace matador::object {
|
||||||
|
class abstract_type_resolver_factory {
|
||||||
|
public:
|
||||||
|
virtual ~abstract_type_resolver_factory() = default;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual std::shared_ptr<abstract_type_resolver> acquire_object_resolver(const std::type_index &type) const = 0;
|
||||||
|
virtual void register_object_resolver(std::shared_ptr<abstract_type_resolver> &&resolver) = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif //MATADOR_ABSTRACT_TYPE_RESOLVER_FACTORY_HPP
|
||||||
@@ -6,20 +6,15 @@
|
|||||||
#include "matador/utils/field_attributes.hpp"
|
#include "matador/utils/field_attributes.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
namespace matador::object {
|
namespace matador::object {
|
||||||
|
|
||||||
enum class null_option_type : uint8_t {
|
enum class null_option_type : uint8_t {
|
||||||
NULLABLE, NOT_NULL
|
Nullable, NotNull
|
||||||
};
|
};
|
||||||
|
|
||||||
struct attribute_options {
|
|
||||||
utils::field_attributes attributes;
|
|
||||||
null_option_type null_option{null_option_type::NOT_NULL};
|
|
||||||
int index{-1};
|
|
||||||
};
|
|
||||||
class object;
|
class object;
|
||||||
class attribute_generator;
|
|
||||||
|
|
||||||
class attribute {
|
class attribute {
|
||||||
public:
|
public:
|
||||||
@@ -33,23 +28,21 @@ public:
|
|||||||
attribute() = default;
|
attribute() = default;
|
||||||
attribute(std::string name,
|
attribute(std::string name,
|
||||||
utils::basic_type type,
|
utils::basic_type type,
|
||||||
const utils::field_attributes&,
|
const utils::field_attributes &attr = NullAttributes,
|
||||||
null_option_type null_opt);
|
null_option_type null_opt = null_option_type::NotNull);
|
||||||
|
|
||||||
[[nodiscard]] const std::string& name() const;
|
[[nodiscard]] const std::string& name() const;
|
||||||
void name(const std::string& n);
|
void name(const std::string& n);
|
||||||
[[nodiscard]] std::string full_name() const;
|
[[nodiscard]] std::string full_name() const;
|
||||||
[[nodiscard]] int index() const;
|
[[nodiscard]] size_t index() const;
|
||||||
[[nodiscard]] const utils::field_attributes& attributes() const;
|
[[nodiscard]] const utils::field_attributes& attributes() const;
|
||||||
[[nodiscard]] utils::field_attributes& attributes();
|
[[nodiscard]] utils::field_attributes& attributes();
|
||||||
[[nodiscard]] bool is_nullable() const;
|
[[nodiscard]] bool is_nullable() const;
|
||||||
[[nodiscard]] utils::basic_type type() const;
|
[[nodiscard]] utils::basic_type type() const;
|
||||||
[[nodiscard]] object* owner() const;
|
[[nodiscard]] std::shared_ptr<object> owner() const;
|
||||||
// [[nodiscard]] const std::string& table_name() const;
|
void change_type(utils::basic_type type, const utils::field_attributes &attr = NullAttributes);
|
||||||
// void table_name(const std::string& name);
|
|
||||||
void change_type(utils::basic_type type, const utils::field_attributes &attr = utils::null_attributes);
|
|
||||||
template < typename Type >
|
template < typename Type >
|
||||||
void change_type(const utils::field_attributes &attr = utils::null_attributes) {
|
void change_type(const utils::field_attributes &attr = NullAttributes) {
|
||||||
type_ = utils::data_type_traits<Type>::type(attr.size());
|
type_ = utils::data_type_traits<Type>::type(attr.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,6 +53,7 @@ public:
|
|||||||
[[nodiscard]] bool is_varchar() const;
|
[[nodiscard]] bool is_varchar() const;
|
||||||
[[nodiscard]] bool is_date() const;
|
[[nodiscard]] bool is_date() const;
|
||||||
[[nodiscard]] bool is_time() const;
|
[[nodiscard]] bool is_time() const;
|
||||||
|
[[nodiscard]] bool is_timestamp() const;
|
||||||
[[nodiscard]] bool is_blob() const;
|
[[nodiscard]] bool is_blob() const;
|
||||||
[[nodiscard]] bool is_null() const;
|
[[nodiscard]] bool is_null() const;
|
||||||
|
|
||||||
@@ -68,82 +62,20 @@ public:
|
|||||||
return type() == utils::data_type_traits<Type>::type(attributes().size());
|
return type() == utils::data_type_traits<Type>::type(attributes().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
friend std::ostream& operator<<(std::ostream& os, const attribute& attr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class object;
|
friend class object;
|
||||||
friend class attribute_generator;
|
friend class object_generator;
|
||||||
|
|
||||||
std::string name_;
|
std::string name_;
|
||||||
object *owner_{nullptr};
|
size_t index_{0};
|
||||||
attribute_options options_;
|
std::weak_ptr<object> owner_;
|
||||||
utils::basic_type type_{utils::basic_type::type_null};
|
utils::basic_type type_{utils::basic_type::Null};
|
||||||
|
utils::field_attributes options_{};
|
||||||
|
null_option_type null_option_{null_option_type::NotNull};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User defined literal to have a shortcut creating a column object
|
|
||||||
* @param name Name of the column
|
|
||||||
* @param type
|
|
||||||
* @param attr Length of the column name
|
|
||||||
* @param null_opt
|
|
||||||
* @return A column object with a given name
|
|
||||||
*/
|
|
||||||
// attribute make_column(const std::string &name, utils::basic_type type, utils::field_attributes attr = utils::null_attributes, null_option_type null_opt = null_option_type::NOT_NULL);
|
|
||||||
//
|
|
||||||
// template < typename Type >
|
|
||||||
// attribute make_column(const std::string &name, utils::field_attributes attr = utils::null_attributes, null_option_type null_opt = null_option_type::NOT_NULL)
|
|
||||||
// {
|
|
||||||
// return make_column(name, utils::data_type_traits<Type>::type(0), attr, null_opt);
|
|
||||||
// }
|
|
||||||
// template <>
|
|
||||||
// attribute make_column<std::string>(const std::string &name, utils::field_attributes attr, null_option_type null_opt);
|
|
||||||
//
|
|
||||||
// template < typename Type >
|
|
||||||
// attribute make_pk_column(const std::string &name, size_t size = 0)
|
|
||||||
// {
|
|
||||||
// return make_column<Type>(name, { size, utils::constraints::PrimaryKey });
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// template <>
|
|
||||||
// attribute make_pk_column<std::string>(const std::string &name, size_t size);
|
|
||||||
//
|
|
||||||
// template < typename Type >
|
|
||||||
// attribute make_fk_column(const std::string &name, size_t size, const std::shared_ptr<attribute> &ref_column) {
|
|
||||||
// return {name, utils::data_type_traits<Type>::type(size), ref_column, { size, utils::constraints::ForeignKey }};
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// template < typename Type >
|
|
||||||
// [[maybe_unused]] attribute make_fk_column(const std::string &name, const std::shared_ptr<attribute> &ref_column)
|
|
||||||
// {
|
|
||||||
// return {name, utils::data_type_traits<Type>::type(0), 0, ref_column, { 0, utils::constraints::ForeignKey }, null_option_type::NOT_NULL};
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// template <>
|
|
||||||
// [[maybe_unused]] attribute make_fk_column<std::string>(const std::string &name, size_t size, const std::shared_ptr<attribute> &ref_column);
|
|
||||||
//
|
|
||||||
// template < typename Type >
|
|
||||||
// [[maybe_unused]] attribute make_fk_column(const std::string &name, size_t size, const std::string &ref_table_name, const std::string &ref_column_name) {
|
|
||||||
// return {
|
|
||||||
// name, utils::data_type_traits<Type>::type(size), 0,
|
|
||||||
// std::make_shared<attribute>(ref_column_name, ref_table_name, utils::data_type_traits<Type>::type(size), utils::constraints::ForeignKey),
|
|
||||||
// { 0, utils::constraints::ForeignKey }, null_option_type::NOT_NULL
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// template < typename Type >
|
|
||||||
// [[maybe_unused]] attribute make_fk_column(const std::string &name, const std::string &ref_table_name, const std::string &ref_column_name) {
|
|
||||||
// return {
|
|
||||||
// name, utils::data_type_traits<Type>::type(0), 0,
|
|
||||||
// std::make_shared<attribute>(ref_column_name, utils::data_type_traits<Type>::type(0), ref_table_name, attribute_options{utils::constraints::ForeignKey}),
|
|
||||||
// { 0, utils::constraints::ForeignKey }, null_option_type::NOT_NULL
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// template <>
|
|
||||||
// [[maybe_unused]] attribute make_fk_column<std::string>(const std::string &name, const std::string &ref_table_name, const std::string &ref_column_name);
|
|
||||||
//
|
|
||||||
// template <>
|
|
||||||
// [[maybe_unused]] attribute make_fk_column<std::string>(const std::string &name, size_t size, const std::string &ref_table_name, const std::string &ref_column_name);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //QUERY_COLUMN_DEFINITION_HPP
|
#endif //QUERY_COLUMN_DEFINITION_HPP
|
||||||
|
|||||||
@@ -1,160 +0,0 @@
|
|||||||
#ifndef QUERY_COLUMN_DEFINITION_GENERATOR_HPP
|
|
||||||
#define QUERY_COLUMN_DEFINITION_GENERATOR_HPP
|
|
||||||
|
|
||||||
#include "matador/object/attribute.hpp"
|
|
||||||
|
|
||||||
#include "matador/utils/access.hpp"
|
|
||||||
#include "matador/utils/data_type_traits.hpp"
|
|
||||||
#include "matador/utils/error.hpp"
|
|
||||||
#include "matador/utils/field_attributes.hpp"
|
|
||||||
#include "matador/utils/identifier.hpp"
|
|
||||||
#include "matador/utils/primary_key_attribute.hpp"
|
|
||||||
#include "matador/utils/result.hpp"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <typeindex>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace matador::object {
|
|
||||||
|
|
||||||
class repository;
|
|
||||||
|
|
||||||
class fk_attribute_generator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
fk_attribute_generator() = default;
|
|
||||||
|
|
||||||
template<class Type>
|
|
||||||
attribute generate(const char *id, Type &x, const std::shared_ptr<attribute> &ref_column) {
|
|
||||||
access::process(*this, x);
|
|
||||||
return attribute{id, type_, 0, ref_column, {utils::constraints::ForeignKey }, null_option_type::NOT_NULL};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename ValueType>
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
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) {}
|
|
||||||
static void on_attribute(const char * /*id*/, char * /*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
|
||||||
template<class Pointer>
|
|
||||||
static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
|
|
||||||
template<class Pointer>
|
|
||||||
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
|
|
||||||
template<class ContainerType>
|
|
||||||
static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {}
|
|
||||||
template<class ContainerType>
|
|
||||||
static void on_has_many_to_many(const char * /*id*/, ContainerType & /*cont*/, 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 & /*cont*/, const utils::foreign_attributes &/*attr*/) {}
|
|
||||||
|
|
||||||
private:
|
|
||||||
utils::basic_type type_{};
|
|
||||||
};
|
|
||||||
|
|
||||||
class attribute_generator final {
|
|
||||||
private:
|
|
||||||
attribute_generator(std::vector<attribute> &columns, const repository &repo, object &obj);
|
|
||||||
|
|
||||||
public:
|
|
||||||
~attribute_generator() = default;
|
|
||||||
|
|
||||||
template < class Type >
|
|
||||||
static std::vector<attribute> generate(const repository &repo, object &obj) {
|
|
||||||
std::vector<attribute> columns;
|
|
||||||
attribute_generator gen(columns, repo, obj);
|
|
||||||
Type t;
|
|
||||||
access::process(gen, t);
|
|
||||||
return columns;
|
|
||||||
}
|
|
||||||
|
|
||||||
template < class Type >
|
|
||||||
static std::vector<attribute> generate(const Type& t, const repository &repo, object &obj) {
|
|
||||||
std::vector<attribute> columns;
|
|
||||||
attribute_generator gen(columns, repo, obj);
|
|
||||||
access::process(gen, t);
|
|
||||||
return columns;
|
|
||||||
}
|
|
||||||
|
|
||||||
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>
|
|
||||||
void on_attribute(const char *id, Type &x, const utils::field_attributes &attr = utils::null_attributes);
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
void on_attribute(const char *id, std::optional<Type> &x, const utils::field_attributes &attr = utils::null_attributes);
|
|
||||||
|
|
||||||
template<class Pointer>
|
|
||||||
void on_belongs_to(const char *id, Pointer &x, const utils::foreign_attributes &/*attr*/) {
|
|
||||||
on_foreign_key(id, x);
|
|
||||||
}
|
|
||||||
template<class Pointer>
|
|
||||||
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
|
|
||||||
|
|
||||||
template <class Pointer>
|
|
||||||
void on_foreign_key(const char *id, Pointer &x) {
|
|
||||||
attribute* ref_column;
|
|
||||||
std::type_index ti = typeid(typename Pointer::value_type);
|
|
||||||
if (auto result = determine_foreign_ref(std::type_index(ti))) {
|
|
||||||
ref_column = *result;
|
|
||||||
} else {
|
|
||||||
ref_column = nullptr;
|
|
||||||
insert_missing_reference_column(ti, ref_column);
|
|
||||||
}
|
|
||||||
if (x.empty()) {
|
|
||||||
typename Pointer::value_type temp_val;
|
|
||||||
columns_.push_back(fk_column_generator_.generate(id, temp_val, ref_column));
|
|
||||||
} else {
|
|
||||||
columns_.push_back(fk_column_generator_.generate(id, *x, ref_column));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
template<class ContainerType>
|
|
||||||
static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {}
|
|
||||||
template<class ContainerType>
|
|
||||||
static void on_has_many_to_many(const char * /*id*/, ContainerType & /*cont*/, 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 & /*cont*/, const utils::foreign_attributes &/*attr*/) {}
|
|
||||||
|
|
||||||
private:
|
|
||||||
[[nodiscard]] utils::result<attribute*, utils::error> determine_foreign_ref(const std::type_index &ti) const;
|
|
||||||
void insert_missing_reference_column(const std::type_index &ti, attribute* ref_column) const;
|
|
||||||
|
|
||||||
template<typename ValueType>
|
|
||||||
attribute &emplace_attribute(const char *id, const utils::field_attributes& attr, null_option_type null_option) {
|
|
||||||
auto &ref = columns_.emplace_back(id, utils::data_type_traits<ValueType>::type(attr.size()), attr, null_option);
|
|
||||||
ref.owner_ = &obj_;
|
|
||||||
return ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
void prepare_primary_key(attribute &ref, utils::identifier &&pk) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
size_t index_ = 0;
|
|
||||||
std::vector<attribute> &columns_;
|
|
||||||
const repository &repo_;
|
|
||||||
object &obj_;
|
|
||||||
|
|
||||||
fk_attribute_generator fk_column_generator_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename ValueType>
|
|
||||||
void attribute_generator::on_primary_key(const char *id, ValueType &x, const utils::primary_key_attribute& attr) {
|
|
||||||
auto &ref = emplace_attribute<ValueType>(id, { attr.size(), utils::constraints::PrimaryKey }, null_option_type::NOT_NULL);
|
|
||||||
prepare_primary_key(ref, utils::identifier(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
void attribute_generator::on_attribute(const char *id, Type &/*x*/, const utils::field_attributes &attr) {
|
|
||||||
std::ignore = emplace_attribute<Type>(id, attr, null_option_type::NOT_NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
void attribute_generator::on_attribute(const char *id, std::optional<Type> & /*x*/, const utils::field_attributes &attr) {
|
|
||||||
std::ignore = emplace_attribute<Type>(id, attr, null_option_type::NULLABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif //QUERY_COLUMN_DEFINITION_GENERATOR_HPP
|
|
||||||
@@ -2,10 +2,12 @@
|
|||||||
#define BASIC_PROTOTYPE_INFO_HPP
|
#define BASIC_PROTOTYPE_INFO_HPP
|
||||||
|
|
||||||
#include "matador/object/attribute.hpp"
|
#include "matador/object/attribute.hpp"
|
||||||
|
#include "matador/object/restriction.hpp"
|
||||||
#include "matador/object/relation_endpoint.hpp"
|
#include "matador/object/relation_endpoint.hpp"
|
||||||
|
|
||||||
#include "matador/utils/identifier.hpp"
|
#include "matador/utils/identifier.hpp"
|
||||||
|
|
||||||
|
#include <list>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <typeindex>
|
#include <typeindex>
|
||||||
|
|
||||||
@@ -24,12 +26,18 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] std::type_index type_index() const;
|
[[nodiscard]] std::type_index type_index() const;
|
||||||
[[nodiscard]] std::string name() const;
|
[[nodiscard]] std::string name() const;
|
||||||
|
[[nodiscard]] std::shared_ptr<class object> object() const;
|
||||||
[[nodiscard]] const std::vector<attribute>& attributes() const;
|
[[nodiscard]] const std::vector<attribute>& attributes() const;
|
||||||
// [[nodiscard]] std::shared_ptr<attribute> reference_column() const;
|
[[nodiscard]] const std::list<restriction>& constraints() const;
|
||||||
|
|
||||||
[[nodiscard]] bool has_primary_key() const;
|
[[nodiscard]] bool has_primary_key() const;
|
||||||
[[nodiscard]] const utils::identifier& primary_key() const;
|
[[nodiscard]] const utils::identifier& primary_key() const;
|
||||||
[[nodiscard]] attribute* primary_key_attribute() const;
|
[[nodiscard]] const attribute* primary_key_attribute() const;
|
||||||
|
|
||||||
|
void update_name(const std::string& name) const;
|
||||||
|
|
||||||
|
virtual void on_attach() const = 0;
|
||||||
|
virtual void on_detach() const = 0;
|
||||||
|
|
||||||
endpoint_iterator register_relation_endpoint(const std::type_index &type, const std::shared_ptr<relation_endpoint> &endpoint);
|
endpoint_iterator register_relation_endpoint(const std::type_index &type, const std::shared_ptr<relation_endpoint> &endpoint);
|
||||||
void unregister_relation_endpoint(const std::type_index &type);
|
void unregister_relation_endpoint(const std::type_index &type);
|
||||||
@@ -50,13 +58,11 @@ public:
|
|||||||
[[nodiscard]] bool endpoints_empty() const;
|
[[nodiscard]] bool endpoints_empty() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// basic_object_info(std::shared_ptr<repository_node> node, const std::vector<attribute> &attributes, utils::identifier &&pk, const std::shared_ptr<attribute> &pk_as_fk_column);
|
basic_object_info(const repository_node& node, const std::shared_ptr<class object> &obj);
|
||||||
// basic_object_info(std::shared_ptr<repository_node> node, const std::vector<attribute> &attributes);
|
|
||||||
basic_object_info(std::shared_ptr<repository_node> node, std::unique_ptr<object> &&obj);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::unique_ptr<object> object_;
|
std::shared_ptr<class object> object_;
|
||||||
std::shared_ptr<repository_node> node_; /**< prototype node of the represented object type */
|
const repository_node& node_; /**< prototype node of the represented object type */
|
||||||
t_endpoint_map relation_endpoints_;
|
t_endpoint_map relation_endpoints_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,156 @@
|
|||||||
|
#ifndef MATADOR_BASIC_REPOSITORY_HPP
|
||||||
|
#define MATADOR_BASIC_REPOSITORY_HPP
|
||||||
|
|
||||||
|
#include "matador/object/error_code.hpp"
|
||||||
|
#include "matador/object/object_info.hpp"
|
||||||
|
#include "matador/object/repository_node_iterator.hpp"
|
||||||
|
|
||||||
|
#include "matador/logger/logger.hpp"
|
||||||
|
|
||||||
|
#include "matador/utils/error.hpp"
|
||||||
|
#include "matador/utils/result.hpp"
|
||||||
|
|
||||||
|
#include <typeindex>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace matador::object {
|
||||||
|
utils::error make_error(error_code ec, const std::string &msg);
|
||||||
|
|
||||||
|
class repository_node;
|
||||||
|
class const_repository_node_iterator;
|
||||||
|
|
||||||
|
class basic_repository {
|
||||||
|
public:
|
||||||
|
typedef const_repository_node_iterator const_iterator; /**< Shortcut for the list const iterator. */
|
||||||
|
|
||||||
|
explicit basic_repository(std::string name = "");
|
||||||
|
~basic_repository();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param node Node to attach
|
||||||
|
* @param parent Name of parent node
|
||||||
|
* @return Attached node
|
||||||
|
*/
|
||||||
|
[[nodiscard]] utils::result<repository_node*, utils::error> attach_node(repository_node *node, const std::string &parent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detaches a given node from the schema. If the
|
||||||
|
* node is a parent of other nodes, these nodes are
|
||||||
|
* detached as well.
|
||||||
|
*
|
||||||
|
* @param node Node to detach from schema
|
||||||
|
* @return Result object indicating success or failure
|
||||||
|
*/
|
||||||
|
[[nodiscard]] utils::result<void, utils::error> detach(repository_node *node);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the first schema node.
|
||||||
|
*
|
||||||
|
* @return The first schema node iterator.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] const_iterator begin() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the last schema node.
|
||||||
|
*
|
||||||
|
* @return The last schema node iterator.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] const_iterator end() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the schema contains
|
||||||
|
* no schema nodes.
|
||||||
|
*
|
||||||
|
* @return True if the schema is empty
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool empty() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current number of the schema node.
|
||||||
|
*
|
||||||
|
* @return Number of schema nodes
|
||||||
|
*/
|
||||||
|
[[nodiscard]] size_t size() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the schema.
|
||||||
|
*
|
||||||
|
* @return The name of the schema
|
||||||
|
*/
|
||||||
|
[[nodiscard]] std::string name() const;
|
||||||
|
|
||||||
|
[[nodiscard]] bool contains(const std::string &name) const;
|
||||||
|
[[nodiscard]] bool contains(const std::type_index &index) const;
|
||||||
|
template < typename Type >
|
||||||
|
[[nodiscard]] bool contains() const {
|
||||||
|
return contains(std::type_index(typeid(Type)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[[nodiscard]] utils::result<basic_object_info_ref, utils::error> basic_info(const std::type_index& ti) const;
|
||||||
|
[[nodiscard]] utils::result<basic_object_info_ref, utils::error> basic_info(const std::string &name) const;
|
||||||
|
template<typename Type>
|
||||||
|
[[nodiscard]] utils::result<basic_object_info_ref, utils::error> basic_info() const {
|
||||||
|
return basic_info(std::type_index(typeid(Type)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] utils::result<const attribute*, utils::error> primary_key_attribute(const std::type_index &ti) const;
|
||||||
|
|
||||||
|
void dump(std::ostream &os) const;
|
||||||
|
static void dump(std::ostream &os, const repository_node& node);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
using t_node_map = std::unordered_map<std::string, repository_node*>;
|
||||||
|
using t_type_index_node_map = std::unordered_map<std::type_index, repository_node*>;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
[[nodiscard]] const_iterator find_node(const std::string &name) const;
|
||||||
|
[[nodiscard]] const_iterator find_node(const std::type_index &type_index) const;
|
||||||
|
template<typename Type>
|
||||||
|
[[nodiscard]] const_iterator find_node() const {
|
||||||
|
return find_node(std::type_index(typeid(Type)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool has_node(const std::string &name) const;
|
||||||
|
[[nodiscard]] bool has_node(const std::type_index &index) const;
|
||||||
|
[[nodiscard]] bool has_node(const repository_node* node) const;
|
||||||
|
|
||||||
|
static void insert_node(repository_node *parent, repository_node *child);
|
||||||
|
void remove_node(repository_node *node);
|
||||||
|
|
||||||
|
[[nodiscard]] bool expecting_relation_node(const std::string &name) const;
|
||||||
|
void expect_relation_node(const std::string &name, const std::type_index &ti);
|
||||||
|
void remove_expected_relation_node(const std::string &name);
|
||||||
|
|
||||||
|
[[nodiscard]] std::shared_ptr<object> provide_object_in_advance(const std::type_index &ti, const std::shared_ptr<object>& obj);
|
||||||
|
[[nodiscard]] bool has_object_for_type(const std::type_index &ti) const;
|
||||||
|
[[nodiscard]] std::shared_ptr<object> object_for_type(const std::type_index &ti) const;
|
||||||
|
void remove_object_for_type(const std::type_index &ti);
|
||||||
|
|
||||||
|
[[nodiscard]] bool is_node_announced(const std::type_index &ti) const;
|
||||||
|
void push_announce_node(const std::type_index &ti, std::unique_ptr<repository_node> &&node);
|
||||||
|
[[nodiscard]] repository_node* announce_node(const std::type_index &ti) const;
|
||||||
|
[[nodiscard]] std::unique_ptr<repository_node> pop_announce_node(const std::type_index &ti);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
friend class object_generator;
|
||||||
|
template < typename NodeType, template<typename> typename ...Observers >
|
||||||
|
friend class foreign_node_completer;
|
||||||
|
template < typename NodeType, template<typename> typename ...Observers >
|
||||||
|
friend class relation_completer;
|
||||||
|
|
||||||
|
std::string name_;
|
||||||
|
repository_node* root_{nullptr};
|
||||||
|
|
||||||
|
t_node_map nodes_by_name_;
|
||||||
|
t_type_index_node_map nodes_by_type_;
|
||||||
|
logger::logger log_;
|
||||||
|
|
||||||
|
std::unordered_map<std::type_index, std::unique_ptr<repository_node>> announced_node_;
|
||||||
|
std::unordered_map<std::type_index, attribute*> missing_references_{};
|
||||||
|
std::unordered_map<std::string, std::type_index> expected_relation_nodes_;
|
||||||
|
std::unordered_map<std::type_index, std::shared_ptr<object>> object_by_type_{};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif //MATADOR_BASIC_REPOSITORY_HPP
|
||||||
@@ -1,18 +1,59 @@
|
|||||||
#ifndef COLLECTION_HPP
|
#ifndef COLLECTION_HPP
|
||||||
#define COLLECTION_HPP
|
#define COLLECTION_HPP
|
||||||
|
|
||||||
#include <vector>
|
#include "matador/object/collection_proxy.hpp"
|
||||||
|
|
||||||
namespace matador::object {
|
namespace matador::object {
|
||||||
|
|
||||||
template < class Type >
|
template < class Type >
|
||||||
class collection {
|
class collection {
|
||||||
public:
|
public:
|
||||||
using value_type = Type;
|
using value_type = typename collection_proxy<Type>::value_type;
|
||||||
|
using iterator = typename collection_proxy<Type>::iterator;
|
||||||
|
using const_iterator = typename collection_proxy<Type>::const_iterator;
|
||||||
|
|
||||||
|
collection()
|
||||||
|
: proxy_(std::make_shared<collection_proxy<Type>>()) {}
|
||||||
|
explicit collection(std::shared_ptr<collection_proxy<Type>> proxy)
|
||||||
|
: proxy_(std::move(proxy)) {}
|
||||||
|
explicit collection(std::vector<Type> items)
|
||||||
|
: proxy_(std::make_shared<collection_proxy<Type>>(std::move(items))) {}
|
||||||
|
collection(const collection& other) = default;
|
||||||
|
|
||||||
|
void push_back(const value_type& value) {
|
||||||
|
proxy_->push_back(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator begin() {
|
||||||
|
return proxy_->begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator end() {
|
||||||
|
return proxy_->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator begin() const {
|
||||||
|
return proxy_->begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator end() const {
|
||||||
|
return proxy_->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] size_t size() const {
|
||||||
|
return proxy_->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool empty() const {
|
||||||
|
return proxy_->empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset(std::shared_ptr<collection_proxy<Type>> proxy) {
|
||||||
|
proxy_ = std::move(proxy);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Type> data_;
|
std::shared_ptr<abstract_collection_proxy<Type>> proxy_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,188 @@
|
|||||||
|
#ifndef MATADOR_COLLECTION_PROXY_HPP
|
||||||
|
#define MATADOR_COLLECTION_PROXY_HPP
|
||||||
|
|
||||||
|
#include "matador/object/collection_resolver.hpp"
|
||||||
|
#include "matador/object/many_to_many_relation.hpp"
|
||||||
|
|
||||||
|
#include "matador/utils/identifier.hpp"
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <mutex>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace matador::object {
|
||||||
|
|
||||||
|
// has many primitive
|
||||||
|
// relation<OwnerType, PrimitiveType>
|
||||||
|
// has many ptr
|
||||||
|
// relation<OwnerType, ObjectType>
|
||||||
|
// has many to many
|
||||||
|
// relation<OwnerType, ForeignType>
|
||||||
|
|
||||||
|
template < class RelationType >
|
||||||
|
struct relation_iterator_traits {
|
||||||
|
static RelationType& value(RelationType& item) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template < typename Type, typename OwnerType >
|
||||||
|
struct relation_iterator_traits<relation<OwnerType, Type>> {
|
||||||
|
static Type& value(relation<OwnerType, Type>& re) {
|
||||||
|
return re.relation().value();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Type, typename RelationType = Type>
|
||||||
|
class collection_proxy_iterator {
|
||||||
|
public:
|
||||||
|
using value_type = Type;
|
||||||
|
using reference = Type&;
|
||||||
|
using pointer = Type*;
|
||||||
|
using relation_type = RelationType;
|
||||||
|
using iterator_category = std::forward_iterator_tag;
|
||||||
|
|
||||||
|
collection_proxy_iterator() = default;
|
||||||
|
collection_proxy_iterator(typename std::vector<RelationType>::iterator it)
|
||||||
|
: it_(it) {}
|
||||||
|
|
||||||
|
reference operator*() {
|
||||||
|
return relation_iterator_traits<relation_type>::value(*it_);
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer operator->() {
|
||||||
|
return &relation_iterator_traits<relation_type>::value(*it_);
|
||||||
|
}
|
||||||
|
|
||||||
|
collection_proxy_iterator& operator++() {
|
||||||
|
++it_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
bool operator==(const collection_proxy_iterator& other) const {
|
||||||
|
return it_ == other.it_;
|
||||||
|
}
|
||||||
|
bool operator!=(const collection_proxy_iterator& other) const {
|
||||||
|
return !operator==(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
// relation_type& relation() {
|
||||||
|
|
||||||
|
// return *it_;
|
||||||
|
// }
|
||||||
|
private:
|
||||||
|
typename std::vector<RelationType>::iterator it_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Type, typename RelationType = Type>
|
||||||
|
class abstract_collection_proxy {
|
||||||
|
public:
|
||||||
|
using value_type = Type;
|
||||||
|
using relation_type = RelationType;
|
||||||
|
// using iterator = typename std::vector<value_type>::iterator;
|
||||||
|
// using const_iterator = typename std::vector<value_type>::const_iterator;
|
||||||
|
using iterator = collection_proxy_iterator<value_type, relation_type>;
|
||||||
|
using const_iterator = collection_proxy_iterator<value_type, relation_type>;
|
||||||
|
|
||||||
|
virtual ~abstract_collection_proxy() = default;
|
||||||
|
|
||||||
|
virtual void push_back(const value_type& value) = 0;
|
||||||
|
|
||||||
|
virtual iterator begin() = 0;
|
||||||
|
virtual iterator end() = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual size_t size() = 0;
|
||||||
|
[[nodiscard]] virtual bool empty() = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual const utils::identifier& owner_id() const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector<relation_type> items_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
class collection_proxy : public abstract_collection_proxy<Type> {
|
||||||
|
public:
|
||||||
|
using value_type = Type;
|
||||||
|
using iterator = typename abstract_collection_proxy<Type>::iterator;
|
||||||
|
using const_iterator = typename abstract_collection_proxy<Type>::const_iterator;
|
||||||
|
|
||||||
|
collection_proxy() = default;
|
||||||
|
|
||||||
|
// Lazy
|
||||||
|
collection_proxy(std::weak_ptr<collection_resolver<Type>> resolver, utils::identifier owner_id)
|
||||||
|
: owner_id_(std::move(owner_id)), resolver_(std::move(resolver)) {}
|
||||||
|
|
||||||
|
// Eager
|
||||||
|
collection_proxy(std::weak_ptr<collection_resolver<Type>> resolver, std::vector<Type> items)
|
||||||
|
: loaded_{true}, items_(std::move(items)), resolver_(std::move(resolver)) {}
|
||||||
|
|
||||||
|
// Transient
|
||||||
|
explicit collection_proxy(std::vector<Type> items)
|
||||||
|
: items_(std::move(items)) {}
|
||||||
|
|
||||||
|
[[nodiscard]] const utils::identifier& owner_id() const override {
|
||||||
|
return owner_id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator begin() override {
|
||||||
|
resolve();
|
||||||
|
return items_.begin();
|
||||||
|
}
|
||||||
|
iterator end() override {
|
||||||
|
resolve();
|
||||||
|
return items_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_back(const value_type& value) override {
|
||||||
|
resolve();
|
||||||
|
items_.push_back(value);
|
||||||
|
}
|
||||||
|
[[nodiscard]] size_t size() override {
|
||||||
|
resolve();
|
||||||
|
return items_.size();
|
||||||
|
}
|
||||||
|
[[nodiscard]] bool empty() override {
|
||||||
|
resolve();
|
||||||
|
return items_.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void resolve() {
|
||||||
|
if (loaded_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
auto resolver = resolver_.lock();
|
||||||
|
if (!resolver) {
|
||||||
|
return;
|
||||||
|
// Todo: Add states (Detached, Attached, Transient) - if attached an no resolver is available throw runtime exception
|
||||||
|
// throw std::runtime_error("Detached proxy (session expired)");
|
||||||
|
}
|
||||||
|
|
||||||
|
items_ = resolver->resolve(owner_id_);
|
||||||
|
loaded_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const utils::identifier owner_id_;
|
||||||
|
std::atomic_bool loaded_{false};
|
||||||
|
std::vector<Type> items_;
|
||||||
|
std::weak_ptr<collection_resolver<Type>> resolver_{};
|
||||||
|
mutable std::mutex mutex_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Type, class OwnerType>
|
||||||
|
class collection_many_to_many_proxy {
|
||||||
|
public:
|
||||||
|
using value_type = Type;
|
||||||
|
using owner_type = OwnerType;
|
||||||
|
using relation_type = many_to_many_relation<value_type, owner_type>;
|
||||||
|
using iterator = typename std::vector<relation_type>::iterator;
|
||||||
|
using const_iterator = typename std::vector<relation_type>::const_iterator;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<relation_type> relations_;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif //MATADOR_COLLECTION_PROXY_HPP
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef MATADOR_COLLECTION_RESOLVER_HPP
|
||||||
|
#define MATADOR_COLLECTION_RESOLVER_HPP
|
||||||
|
|
||||||
|
#include "matador/object/abstract_joined_resolver.hpp"
|
||||||
|
|
||||||
|
#include <typeindex>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace matador::utils {
|
||||||
|
class identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace matador::object {
|
||||||
|
template<typename Type>
|
||||||
|
class collection_resolver : public abstract_joined_resolver {
|
||||||
|
public:
|
||||||
|
collection_resolver(const std::type_index& root_type, std::string collection_name)
|
||||||
|
: abstract_joined_resolver(root_type, typeid(Type), std::move(collection_name)) {}
|
||||||
|
|
||||||
|
virtual std::vector<Type> resolve(const utils::identifier& id) = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif //MATADOR_COLLECTION_RESOLVER_HPP
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef MATADOR_COLLECTION_UTILS_HPP
|
||||||
|
#define MATADOR_COLLECTION_UTILS_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <typeindex>
|
||||||
|
|
||||||
|
namespace matador::object {
|
||||||
|
struct collection_composite_key {
|
||||||
|
std::type_index root_type;
|
||||||
|
std::type_index type;
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
bool operator==(const collection_composite_key& other) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct collection_composite_key_hash {
|
||||||
|
std::size_t operator()(const collection_composite_key& k) const noexcept;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif //MATADOR_COLLECTION_UTILS_HPP
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
#ifndef MATADOR_CONSTRAINT_HPP
|
|
||||||
#define MATADOR_CONSTRAINT_HPP
|
|
||||||
|
|
||||||
#include "matador/utils/constraints.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace matador::object {
|
|
||||||
|
|
||||||
class attribute;
|
|
||||||
class constraint_builder;
|
|
||||||
class constraint_generator;
|
|
||||||
class object;
|
|
||||||
|
|
||||||
class constraint {
|
|
||||||
public:
|
|
||||||
constraint() = default;
|
|
||||||
explicit constraint(std::string name);
|
|
||||||
|
|
||||||
[[nodiscard]] const std::string& name() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class constraint_builder;
|
|
||||||
friend class constraints_generator;
|
|
||||||
friend class object;
|
|
||||||
|
|
||||||
std::string name_;
|
|
||||||
attribute* attr_{nullptr};
|
|
||||||
object *owner_{nullptr};
|
|
||||||
utils::constraints options_{utils::constraints::None};
|
|
||||||
std::string ref_table_name_{};
|
|
||||||
std::string ref_column_name_{};
|
|
||||||
};
|
|
||||||
|
|
||||||
class constraint_builder {
|
|
||||||
public:
|
|
||||||
constraint_builder& constraint(std::string name);
|
|
||||||
constraint_builder& primary_key(std::string name);
|
|
||||||
constraint_builder& foreign_key(std::string name);
|
|
||||||
constraint_builder& references(std::string table, std::string column);
|
|
||||||
|
|
||||||
operator class constraint() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string constraint_name;
|
|
||||||
utils::constraints options_{utils::constraints::None};
|
|
||||||
std::string column_name;
|
|
||||||
std::string ref_table_name;
|
|
||||||
std::string ref_column_name;
|
|
||||||
};
|
|
||||||
|
|
||||||
constraint_builder constraint(std::string name);
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif //MATADOR_CONSTRAINT_HPP
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
#ifndef MATADOR_CONSTRAINTS_GENERATOR_HPP
|
|
||||||
#define MATADOR_CONSTRAINTS_GENERATOR_HPP
|
|
||||||
|
|
||||||
#include "matador/object/constraint.hpp"
|
|
||||||
|
|
||||||
#include "matador/utils/access.hpp"
|
|
||||||
#include "matador/utils/field_attributes.hpp"
|
|
||||||
#include "matador/utils/primary_key_attribute.hpp"
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace matador::object {
|
|
||||||
class object;
|
|
||||||
class basic_object_info;
|
|
||||||
class repository;
|
|
||||||
|
|
||||||
class constraints_generator final {
|
|
||||||
private:
|
|
||||||
constraints_generator(std::vector<class constraint> &constraints, const repository &repo, object &obj);
|
|
||||||
|
|
||||||
public:
|
|
||||||
constraints_generator() = delete;
|
|
||||||
|
|
||||||
template < typename Type >
|
|
||||||
static std::vector<class constraint> generate(const repository &repo, object &obj) {
|
|
||||||
std::vector<class constraint> constraints;
|
|
||||||
constraints_generator gen(constraints, repo, obj);
|
|
||||||
Type t;
|
|
||||||
access::process(gen, t);
|
|
||||||
return constraints;
|
|
||||||
}
|
|
||||||
|
|
||||||
template < class Type >
|
|
||||||
void on_primary_key(const char *id, Type &/*x*/, const utils::primary_key_attribute& attr = utils::default_pk_attributes) {
|
|
||||||
create_pk_constraint(id);
|
|
||||||
}
|
|
||||||
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
|
|
||||||
template<typename Type>
|
|
||||||
void on_attribute(const char *id, Type &x, const utils::field_attributes &attr = utils::null_attributes) {
|
|
||||||
if (utils::is_constraint_set(attr.options() ,utils::constraints::Unique)) {
|
|
||||||
create_unique_constraint(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Pointer>
|
|
||||||
void on_belongs_to(const char *id, Pointer &x, const utils::foreign_attributes &/*attr*/) {
|
|
||||||
const auto result = repo_.info<typename Pointer::value_type>();
|
|
||||||
if (!result) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
create_fk_constraint(id, *result);
|
|
||||||
}
|
|
||||||
template<class Pointer>
|
|
||||||
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
|
|
||||||
template<class ContainerType>
|
|
||||||
static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {}
|
|
||||||
template<class ContainerType>
|
|
||||||
static void on_has_many_to_many(const char * /*id*/, ContainerType & /*cont*/, 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 & /*cont*/, const utils::foreign_attributes &/*attr*/) {}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void create_pk_constraint(const std::string& name) const;
|
|
||||||
void create_fk_constraint(const std::string& name, const basic_object_info& info) const;
|
|
||||||
void create_unique_constraint(const std::string& name) const;
|
|
||||||
|
|
||||||
[[nodiscard]] std::vector<attribute>::iterator find_attribute_by_name(const std::string &name) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<class constraint> &constraints_;
|
|
||||||
const repository &repo_;
|
|
||||||
object &obj_;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //MATADOR_CONSTRAINTS_GENERATOR_HPP
|
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
#ifndef FOREIGN_NODE_COMPLETER_HPP
|
#ifndef FOREIGN_NODE_COMPLETER_HPP
|
||||||
#define FOREIGN_NODE_COMPLETER_HPP
|
#define FOREIGN_NODE_COMPLETER_HPP
|
||||||
|
|
||||||
#include "matador/object/internal/shadow_repository.hpp"
|
#include "matador/object/basic_repository.hpp"
|
||||||
|
#include "matador/object/internal/observer_list_copy_creator.hpp"
|
||||||
#include "matador/object/repository_node.hpp"
|
#include "matador/object/repository_node.hpp"
|
||||||
#include "matador/object/join_columns_collector.hpp"
|
#include "matador/object/join_columns_collector.hpp"
|
||||||
#include "matador/object/object_ptr.hpp"
|
#include "matador/object/object_ptr.hpp"
|
||||||
@@ -11,104 +12,153 @@
|
|||||||
#include "matador/logger/log_manager.hpp"
|
#include "matador/logger/log_manager.hpp"
|
||||||
|
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace matador::object {
|
namespace matador::object {
|
||||||
|
template<typename NodeType, template<typename> typename... Observers>
|
||||||
|
class completer {
|
||||||
|
public:
|
||||||
|
template<typename Type>
|
||||||
|
void foo(Observers<NodeType>&&... observers) {
|
||||||
|
(std::unique_ptr<Observers<Type>>(new Observers(std::forward<Observers>(observers))), ...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes the given node and ensures
|
* Processes the given node and ensures
|
||||||
* that all foreign nodes needed by the given node
|
* that all foreign nodes needed by the given node
|
||||||
* relations are attached in schema.
|
* relations are attached in schema.
|
||||||
*/
|
*/
|
||||||
|
template<typename NodeType, template<typename> typename ...Observers>
|
||||||
class foreign_node_completer final {
|
class foreign_node_completer final {
|
||||||
private:
|
|
||||||
using node_ptr = std::shared_ptr<repository_node>;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template<class Type>
|
static void complete(repository_node *node, const std::vector<std::unique_ptr<observer<NodeType>>> &observers) {
|
||||||
static void complete(const std::shared_ptr<repository_node> &node) {
|
foreign_node_completer completer(node->repo_, observers);
|
||||||
internal::shadow_repository shadow(node->repo_);
|
|
||||||
foreign_node_completer completer(shadow);
|
|
||||||
|
|
||||||
completer.complete_node<Type>(node);
|
completer.complete_node(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename BaseType>
|
||||||
|
static void on_base(const BaseType&) {}
|
||||||
template<class PrimaryKeyType>
|
template<class PrimaryKeyType>
|
||||||
static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {}
|
static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, const utils::primary_key_attribute & /*attr*/) {}
|
||||||
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
|
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
|
||||||
template<typename AttributeType>
|
template<typename AttributeType>
|
||||||
static void on_attribute(const char * /*id*/, AttributeType &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
static void on_attribute(const char * /*id*/, AttributeType &/*val*/, const utils::field_attributes &/*attr*/) {}
|
||||||
template<typename AttributeType>
|
template<typename AttributeType>
|
||||||
static void on_attribute(const char * /*id*/, std::optional<AttributeType> &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
static void on_attribute(const char * /*id*/, std::optional<AttributeType> &/*val*/, const utils::field_attributes &/*attr*/) {}
|
||||||
|
|
||||||
template<class ForeignPointerType>
|
template<class ForeignPointerType>
|
||||||
void on_belongs_to(const char *id, ForeignPointerType &/*obj*/, const utils::foreign_attributes &/*attr*/);
|
void on_belongs_to(const char *id, ForeignPointerType &/*obj*/, const utils::foreign_attributes &/*attr*/);
|
||||||
template<class ForeignPointerType>
|
template<class ForeignPointerType>
|
||||||
void on_has_one(const char * /*id*/, ForeignPointerType &/*obj*/, const utils::foreign_attributes &/*attr*/);
|
void on_has_one(const char * /*id*/, ForeignPointerType &/*obj*/, const char *join_column, const utils::foreign_attributes &/*attr*/);
|
||||||
|
template<class CollectionType>
|
||||||
|
void on_has_many(const char *id, CollectionType &,
|
||||||
|
const char *join_column,
|
||||||
|
const utils::foreign_attributes &attr,
|
||||||
|
std::enable_if_t<is_object_ptr<typename CollectionType::value_type>::value> * = nullptr);
|
||||||
|
|
||||||
template<class CollectionType>
|
template<class CollectionType>
|
||||||
void on_has_many(const char *id, CollectionType &, const char *join_column, const utils::foreign_attributes &attr, std::enable_if_t<is_object_ptr<typename CollectionType::value_type>::value> * = nullptr);
|
void on_has_many(const char * /*id*/,
|
||||||
template<class CollectionType>
|
CollectionType &,
|
||||||
void on_has_many(const char * /*id*/, CollectionType &, const char * /*join_column*/, const utils::foreign_attributes & /*attr*/, std::enable_if_t<!is_object_ptr<typename CollectionType::value_type>::value> * = nullptr) {}
|
const char * /*join_column*/,
|
||||||
|
const utils::foreign_attributes & /*attr*/,
|
||||||
|
std::enable_if_t<!is_object_ptr<typename CollectionType::value_type>::value> * = nullptr) {
|
||||||
|
}
|
||||||
|
|
||||||
template<class CollectionType>
|
template<class CollectionType>
|
||||||
void on_has_many_to_many(const char *id, CollectionType &collection, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &attr);
|
static void on_has_many_to_many(const char * /*id*/,
|
||||||
|
CollectionType &/*collection*/,
|
||||||
|
const char * /*join_column*/,
|
||||||
|
const char * /*inverse_join_column*/,
|
||||||
|
const utils::foreign_attributes &/*attr*/) {}
|
||||||
template<class CollectionType>
|
template<class CollectionType>
|
||||||
void on_has_many_to_many(const char *id, CollectionType &collection, const utils::foreign_attributes &attr);
|
static void on_has_many_to_many(const char * /*id*/, CollectionType &/*collection*/, const utils::foreign_attributes &/*attr*/) {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit foreign_node_completer(internal::shadow_repository &shadow);
|
explicit foreign_node_completer(basic_repository &repo, const std::vector<std::unique_ptr<observer<NodeType>>> &observers)
|
||||||
|
: repo_(repo)
|
||||||
|
, log_(logger::create_logger("node_completer"))
|
||||||
|
, observers_(observers) {}
|
||||||
|
|
||||||
template<typename Type>
|
void complete_node(repository_node *node) {
|
||||||
void complete_node(const std::shared_ptr<repository_node> &node) {
|
|
||||||
nodes_.push(node);
|
nodes_.push(node);
|
||||||
|
|
||||||
Type obj;
|
NodeType obj;
|
||||||
access::process(*this, obj);
|
access::process(*this, obj);
|
||||||
nodes_.pop();
|
nodes_.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
void attach_node(const std::string &name = "") {
|
void attach_node() {
|
||||||
if (repo_.contains(typeid(Type))) {
|
if (repo_.contains(typeid(Type))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto node = repository_node::make_node<Type>(repo_.repo(), name);
|
|
||||||
if (auto result = repo_.attach_node(node)) {
|
auto observers = internal::observer_list_copy_creator<NodeType, Type, Observers...>::copy_create(observers_);
|
||||||
complete<Type>(result.value());
|
|
||||||
|
if (repo_.is_node_announced(typeid(Type))) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
auto node = repository_node::make_node<Type>(repo_, "", []{ return std::make_unique<Type>(); }, std::move(observers));
|
||||||
|
repo_.push_announce_node(typeid(Type), std::move(node));
|
||||||
|
// if (auto result = repo_.attach_node(node)) {
|
||||||
|
// foreign_node_completer<Type>::complete(result.value(), {});
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::stack<node_ptr> nodes_;
|
using endpoint_ptr = std::shared_ptr<relation_endpoint>;
|
||||||
internal::shadow_repository &repo_;
|
static void register_relation_endpoints(const endpoint_ptr &endpoint,
|
||||||
|
const endpoint_ptr &other_endpoint);
|
||||||
|
static void link_relation_endpoints(const endpoint_ptr &endpoint,
|
||||||
|
const endpoint_ptr &other_endpoint);
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename Type, template<typename> typename ...OtherObservers>
|
||||||
|
friend class foreign_node_completer;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::stack<repository_node*> nodes_;
|
||||||
|
basic_repository &repo_;
|
||||||
logger::logger log_;
|
logger::logger log_;
|
||||||
join_columns_collector join_columns_collector_{};
|
join_columns_collector join_columns_collector_{};
|
||||||
|
const std::vector<std::unique_ptr<observer<NodeType>>>& observers_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename NodeType, template<typename> typename ...Observers>
|
||||||
template<class ForeignPointerType>
|
template<class ForeignPointerType>
|
||||||
void foreign_node_completer::on_belongs_to( const char* /*id*/, ForeignPointerType&, const utils::foreign_attributes& ) {
|
void foreign_node_completer<NodeType, Observers...>::on_belongs_to(const char * /*id*/, ForeignPointerType &, const utils::foreign_attributes &) {
|
||||||
attach_node<typename ForeignPointerType::value_type>();
|
attach_node<typename ForeignPointerType::value_type>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename NodeType, template<typename> typename ...Observers>
|
||||||
template<class ForeignPointerType>
|
template<class ForeignPointerType>
|
||||||
void foreign_node_completer::on_has_one( const char*, ForeignPointerType&, const utils::foreign_attributes& ) {
|
void foreign_node_completer<NodeType, Observers...>::on_has_one(const char * /*id*/, ForeignPointerType &, const char * /*join_column*/, const utils::foreign_attributes &) {
|
||||||
attach_node<typename ForeignPointerType::value_type>();
|
attach_node<typename ForeignPointerType::value_type>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename NodeType, template<typename> typename ...Observers>
|
||||||
template<class CollectionType>
|
template<class CollectionType>
|
||||||
void foreign_node_completer::on_has_many( const char* /*id*/, CollectionType&, const char* /*join_column*/, const utils::foreign_attributes& /*attr*/, std::enable_if_t<is_object_ptr<typename CollectionType::value_type>::value>* ) {
|
void foreign_node_completer<NodeType, Observers...>::on_has_many(const char * /*id*/,
|
||||||
|
CollectionType &, const char * /*join_column*/,
|
||||||
|
const utils::foreign_attributes & /*attr*/,
|
||||||
|
std::enable_if_t<is_object_ptr<typename CollectionType::value_type>::value> *) {
|
||||||
attach_node<typename CollectionType::value_type::value_type>();
|
attach_node<typename CollectionType::value_type::value_type>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class CollectionType>
|
template<typename NodeType, template<typename> typename ...Observers>
|
||||||
void foreign_node_completer::on_has_many_to_many( const char* /*id*/, CollectionType& /*collection*/, const char* /*join_column*/, const char* /*inverse_join_column*/, const utils::foreign_attributes& /*attr*/ ) {
|
void foreign_node_completer<NodeType, Observers...>::register_relation_endpoints(const endpoint_ptr &endpoint,
|
||||||
attach_node<typename CollectionType::value_type::value_type>(/*id*/);
|
const endpoint_ptr &other_endpoint) {
|
||||||
|
endpoint->node().info_->register_relation_endpoint(other_endpoint->node().type_index(), endpoint);
|
||||||
|
other_endpoint->node().info_->register_relation_endpoint(endpoint->node().type_index(), other_endpoint);
|
||||||
|
link_relation_endpoints(endpoint, other_endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class CollectionType>
|
template<typename NodeType, template<typename> typename ...Observers>
|
||||||
void foreign_node_completer::on_has_many_to_many( const char* /*id*/, CollectionType& /*collection*/, const utils::foreign_attributes& /*attr*/ ) {
|
void foreign_node_completer<NodeType, Observers...>::link_relation_endpoints(const endpoint_ptr &endpoint, const endpoint_ptr &other_endpoint) {
|
||||||
attach_node<typename CollectionType::value_type::value_type>(/*id*/);
|
endpoint->link_foreign_endpoint(other_endpoint);
|
||||||
|
other_endpoint->link_foreign_endpoint(endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif //FOREIGN_NODE_COMPLETER_HPP
|
#endif //FOREIGN_NODE_COMPLETER_HPP
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
#ifndef MATADOR_OBSERVER_LIST_COPY_CREATOR_HPP
|
||||||
|
#define MATADOR_OBSERVER_LIST_COPY_CREATOR_HPP
|
||||||
|
|
||||||
|
#include "matador/object/observer.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace matador::object::internal {
|
||||||
|
template <typename SourceType, typename DestType, template <typename> class... ObserverType>
|
||||||
|
class observer_list_copy_creator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using source_observer_vector = std::vector<std::unique_ptr<observer<SourceType>>>;
|
||||||
|
using observer_vector = std::vector<std::unique_ptr<observer<DestType>>>;
|
||||||
|
using iterator = typename observer_vector::iterator;
|
||||||
|
|
||||||
|
static observer_vector copy_create(const source_observer_vector &source_observers) {
|
||||||
|
observer_list_copy_creator creator(source_observers);
|
||||||
|
|
||||||
|
return std::move(creator.observers_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit observer_list_copy_creator(const source_observer_vector &source_observers)
|
||||||
|
: source_observers_(source_observers) {
|
||||||
|
if constexpr (sizeof...(ObserverType) != 0) {
|
||||||
|
copy_observer<ObserverType...>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <template <typename> class FirstObserverType>
|
||||||
|
void copy_observer() {
|
||||||
|
try_copy_observer<FirstObserverType>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <template <typename> class FirstObserverType, template <typename> class NextObserverType, template <typename> class... RestObserverType>
|
||||||
|
void copy_observer() {
|
||||||
|
try_copy_observer<FirstObserverType>();
|
||||||
|
copy_observer<NextObserverType, RestObserverType...>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <template <typename> class CurrentObserverType>
|
||||||
|
void try_copy_observer() {
|
||||||
|
for ( const auto &obs : source_observers_ ) {;
|
||||||
|
if (const auto *casted_observer = dynamic_cast<const CurrentObserverType<SourceType>*>(obs.get()); casted_observer != nullptr) {
|
||||||
|
observers_.emplace_back(std::make_unique<CurrentObserverType<DestType>>(*casted_observer));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
const source_observer_vector &source_observers_;
|
||||||
|
observer_vector observers_;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif //MATADOR_OBSERVER_LIST_COPY_CREATOR_HPP
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
#ifndef MATADOR_OBSERVER_LIST_CREATOR_HPP
|
||||||
|
#define MATADOR_OBSERVER_LIST_CREATOR_HPP
|
||||||
|
|
||||||
|
#include "matador/object/observer.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace matador::object::internal {
|
||||||
|
template <typename Type, template <typename> class... ObserverType>
|
||||||
|
class observer_list_creator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using observer_vector = std::vector<std::unique_ptr<observer<Type>>>;
|
||||||
|
|
||||||
|
static void create_missing(observer_vector &observers) {
|
||||||
|
observer_list_creator creator(observers);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit observer_list_creator(observer_vector &observers)
|
||||||
|
: observers_(observers) {
|
||||||
|
if constexpr (sizeof...(ObserverType) != 0) {
|
||||||
|
build_observer<ObserverType...>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <template <typename> class FirstObserverType>
|
||||||
|
void build_observer() {
|
||||||
|
try_copy_on_missing<FirstObserverType>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <template <typename> class FirstObserverType, template <typename> class NextObserverType, template <typename> class... RestObserverType>
|
||||||
|
void build_observer() {
|
||||||
|
try_copy_on_missing<FirstObserverType>();
|
||||||
|
build_observer<NextObserverType, RestObserverType...>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <template <typename> class CurrentObserverType>
|
||||||
|
void try_copy_on_missing() {
|
||||||
|
bool is_missing{true};
|
||||||
|
for ( const auto &obs : observers_ ) {;
|
||||||
|
if (dynamic_cast<const CurrentObserverType<Type>*>(obs.get())) {
|
||||||
|
is_missing = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_missing) {
|
||||||
|
append<CurrentObserverType<Type>>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class CurrentObserverType>
|
||||||
|
void append(std::enable_if_t<std::is_default_constructible_v<CurrentObserverType> || std::is_trivially_default_constructible_v<CurrentObserverType>>* = nullptr) {
|
||||||
|
observers_.emplace_back(std::make_unique<CurrentObserverType>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class CurrentObserverType>
|
||||||
|
void append(std::enable_if_t<!std::is_default_constructible_v<CurrentObserverType> && !std::is_trivially_default_constructible_v<CurrentObserverType>>* = nullptr) {
|
||||||
|
static_assert("no default constructor");
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
observer_vector &observers_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif //MATADOR_OBSERVER_LIST_CREATOR_HPP
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
#ifndef SHADOW_SCHEMA_HPP
|
|
||||||
#define SHADOW_SCHEMA_HPP
|
|
||||||
|
|
||||||
#include "matador/utils/result.hpp"
|
|
||||||
#include "matador/utils/error.hpp"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <typeindex>
|
|
||||||
|
|
||||||
namespace matador::object {
|
|
||||||
class repository;
|
|
||||||
class repository_node;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace matador::object::internal {
|
|
||||||
class shadow_repository {
|
|
||||||
private:
|
|
||||||
using node_ptr = std::shared_ptr<repository_node>;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit shadow_repository(repository& s);
|
|
||||||
|
|
||||||
[[nodiscard]] repository& repo() const;
|
|
||||||
[[nodiscard]] bool contains(const std::type_index& ti) const;
|
|
||||||
[[nodiscard]] utils::result<node_ptr, utils::error> find_node(const std::type_index &type_index) const;
|
|
||||||
[[nodiscard]] utils::result<node_ptr, utils::error> find_node(const std::string &name) const;
|
|
||||||
[[nodiscard]] utils::result<node_ptr, utils::error> attach_node(const std::shared_ptr<repository_node> &node) const;
|
|
||||||
[[nodiscard]] utils::result<void, utils::error> detach_node(const std::shared_ptr<repository_node> &node) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
repository& repo_;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
#endif //SHADOW_SCHEMA_HPP
|
|
||||||
@@ -24,15 +24,17 @@ public:
|
|||||||
|
|
||||||
return join_columns_;
|
return join_columns_;
|
||||||
}
|
}
|
||||||
|
template<typename BaseType>
|
||||||
|
static void on_base(const BaseType&) {}
|
||||||
template < class V >
|
template < class V >
|
||||||
static void on_primary_key(const char * /*id*/, V &, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {}
|
static void on_primary_key(const char * /*id*/, V &, const utils::primary_key_attribute& /*attr*/) {}
|
||||||
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
|
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
static void on_attribute(const char * /*id*/, Type &, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
static void on_attribute(const char * /*id*/, Type &, const utils::field_attributes &/*attr*/) {}
|
||||||
template<class Pointer>
|
template<class Pointer>
|
||||||
static void on_belongs_to(const char * /*id*/, Pointer &/*obj*/, const utils::foreign_attributes &/*attr*/) {}
|
static void on_belongs_to(const char * /*id*/, Pointer &/*obj*/, const utils::foreign_attributes &/*attr*/) {}
|
||||||
template<class Pointer>
|
template<class Pointer>
|
||||||
static void on_has_one(const char * /*id*/, Pointer &/*obj*/, const utils::foreign_attributes &/*attr*/) {}
|
static void on_has_one(const char * /*id*/, Pointer &/*obj*/, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {}
|
||||||
template<class ContainerType>
|
template<class ContainerType>
|
||||||
static void on_has_many(ContainerType &, const char */*join_column*/, const utils::foreign_attributes &/*attr*/) {}
|
static void on_has_many(ContainerType &, const char */*join_column*/, const utils::foreign_attributes &/*attr*/) {}
|
||||||
template<class ContainerType>
|
template<class ContainerType>
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#ifndef MATADOR_CONTAINER_RESOLVER_FACTORY_HPP
|
||||||
|
#define MATADOR_CONTAINER_RESOLVER_FACTORY_HPP
|
||||||
|
|
||||||
|
#include "matador/object/collection_resolver.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace matador::object {
|
||||||
|
class abstract_collection_resolver_factory {
|
||||||
|
public:
|
||||||
|
virtual ~abstract_collection_resolver_factory() = default;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual std::shared_ptr<abstract_joined_resolver> acquire_collection_resolver(const std::type_index &root_type, const std::type_index &element_type, const std::string &collection_name) const = 0;
|
||||||
|
virtual void register_collection_resolver(std::shared_ptr<abstract_joined_resolver> &&resolver) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class joined_collection_resolver_factory : public abstract_collection_resolver_factory {
|
||||||
|
public:
|
||||||
|
template<class Type>
|
||||||
|
[[nodiscard]] std::shared_ptr<collection_resolver<Type>> resolver(const std::type_index &root_type, const std::string &collection_name) const {
|
||||||
|
const auto res = acquire_collection_resolver(root_type, typeid(Type), collection_name);
|
||||||
|
if (!res) {
|
||||||
|
return std::dynamic_pointer_cast<collection_resolver<Type>>(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::dynamic_pointer_cast<collection_resolver<Type>>(res);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class abstract_joined_object_resolver_factory {
|
||||||
|
public:
|
||||||
|
virtual ~abstract_joined_object_resolver_factory() = default;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual std::shared_ptr<abstract_type_resolver> acquire_joined_object_resolver(const std::type_index &root_type, const std::type_index &element_type, const std::string &collection_name) const = 0;
|
||||||
|
virtual void register_joined_object_resolver(std::shared_ptr<abstract_type_resolver> &&resolver, const std::type_index& root_type, const std::string& join_column) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class joined_object_resolver_factory : public abstract_joined_object_resolver_factory {
|
||||||
|
public:
|
||||||
|
template<class Type>
|
||||||
|
[[nodiscard]] std::shared_ptr<object_resolver<Type>> resolver(const std::type_index &root_type, const std::string &collection_name) const {
|
||||||
|
const auto res = acquire_joined_object_resolver(root_type, typeid(Type), collection_name);
|
||||||
|
if (!res) {
|
||||||
|
return std::dynamic_pointer_cast<object_resolver<Type>>(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::dynamic_pointer_cast<object_resolver<Type>>(res);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif //MATADOR_CONTAINER_RESOLVER_FACTORY_HPP
|
||||||
@@ -8,6 +8,48 @@
|
|||||||
|
|
||||||
namespace matador::object {
|
namespace matador::object {
|
||||||
|
|
||||||
|
template < class LocalType, class ForeignType >
|
||||||
|
class relation {
|
||||||
|
public:
|
||||||
|
relation() = default;
|
||||||
|
relation(std::string local_name, std::string remote_name)
|
||||||
|
: local_name_(std::move(local_name))
|
||||||
|
, remote_name_(std::move(remote_name)) {}
|
||||||
|
relation(std::string local_name, std::string remote_name, const object_ptr<LocalType>& local, const ForeignType& remote)
|
||||||
|
: local_name_(std::move(local_name))
|
||||||
|
, remote_name_(std::move(remote_name))
|
||||||
|
, local_(local)
|
||||||
|
, remote_(remote)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<class Operator>
|
||||||
|
void process(Operator &op) {
|
||||||
|
namespace field = matador::access;
|
||||||
|
field::belongs_to(op, local_name_.c_str(), local_, utils::CascadeNoneFetchLazy);
|
||||||
|
foreign_field(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
object_ptr<LocalType> local() const { return local_; }
|
||||||
|
const ForeignType& remote() const { return remote_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename Operator, class RemoteType = ForeignType>
|
||||||
|
void foreign_field(Operator &op, std::enable_if_t<!is_object_ptr<RemoteType>::value>* /*unused*/) {
|
||||||
|
namespace field = matador::access;
|
||||||
|
field::attribute(op, remote_name_.c_str(), remote_);
|
||||||
|
}
|
||||||
|
template<typename Operator, class RemoteType = ForeignType>
|
||||||
|
void foreign_field(Operator &op, std::enable_if_t<is_object_ptr<RemoteType>::value>* /*unused*/) {
|
||||||
|
namespace field = matador::access;
|
||||||
|
field::belongs_to(op, remote_name_.c_str(), remote_, utils::CascadeNoneFetchLazy);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::string local_name_;
|
||||||
|
std::string remote_name_;
|
||||||
|
object_ptr<LocalType> local_;
|
||||||
|
ForeignType remote_;
|
||||||
|
};
|
||||||
|
|
||||||
template < class LocalType, class ForeignType >
|
template < class LocalType, class ForeignType >
|
||||||
class many_to_many_relation {
|
class many_to_many_relation {
|
||||||
public:
|
public:
|
||||||
@@ -15,12 +57,18 @@ public:
|
|||||||
many_to_many_relation(std::string local_name, std::string remote_name)
|
many_to_many_relation(std::string local_name, std::string remote_name)
|
||||||
: local_name_(std::move(local_name))
|
: local_name_(std::move(local_name))
|
||||||
, remote_name_(std::move(remote_name)) {}
|
, remote_name_(std::move(remote_name)) {}
|
||||||
|
many_to_many_relation(std::string local_name, std::string remote_name, const object_ptr<LocalType>& local, const object_ptr<ForeignType>& remote)
|
||||||
|
: local_name_(std::move(local_name))
|
||||||
|
, remote_name_(std::move(remote_name))
|
||||||
|
, local_(local)
|
||||||
|
, remote_(remote)
|
||||||
|
{}
|
||||||
|
|
||||||
template<class Operator>
|
template<class Operator>
|
||||||
void process(Operator &op) {
|
void process(Operator &op) {
|
||||||
namespace field = matador::access;
|
namespace field = matador::access;
|
||||||
field::belongs_to(op, local_name_.c_str(), local_, utils::default_foreign_attributes);
|
field::belongs_to(op, local_name_.c_str(), local_, utils::CascadeNoneFetchLazy);
|
||||||
field::belongs_to(op, remote_name_.c_str(), remote_, utils::default_foreign_attributes);
|
field::belongs_to(op, remote_name_.c_str(), remote_, utils::CascadeNoneFetchLazy);
|
||||||
}
|
}
|
||||||
|
|
||||||
object_ptr<LocalType> local() const { return local_; }
|
object_ptr<LocalType> local() const { return local_; }
|
||||||
@@ -40,11 +88,16 @@ public:
|
|||||||
many_to_relation(std::string local_name, std::string remote_name)
|
many_to_relation(std::string local_name, std::string remote_name)
|
||||||
: local_name_(std::move(local_name))
|
: local_name_(std::move(local_name))
|
||||||
, type_name_(std::move(remote_name)) {}
|
, type_name_(std::move(remote_name)) {}
|
||||||
|
many_to_relation(std::string local_name, std::string remote_name, const object_ptr<LocalType>& local, const Type& value)
|
||||||
|
: local_name_(std::move(local_name))
|
||||||
|
, type_name_(std::move(remote_name))
|
||||||
|
, local_(local)
|
||||||
|
, value_(value){}
|
||||||
|
|
||||||
template<class Operator>
|
template<class Operator>
|
||||||
void process(Operator &op) {
|
void process(Operator &op) {
|
||||||
namespace field = matador::access;
|
namespace field = matador::access;
|
||||||
field::belongs_to(op, local_name_.c_str(), local_, utils::default_foreign_attributes);
|
field::belongs_to(op, local_name_.c_str(), local_, utils::CascadeNoneFetchLazy);
|
||||||
field::attribute(op, type_name_.c_str(), value_);
|
field::attribute(op, type_name_.c_str(), value_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,40 +1,31 @@
|
|||||||
#ifndef MATADOR_OBJECT_GENERATOR_HPP
|
#ifndef MATADOR_OBJECT_HPP
|
||||||
#define MATADOR_OBJECT_GENERATOR_HPP
|
#define MATADOR_OBJECT_HPP
|
||||||
|
|
||||||
#include "matador/object/attribute.hpp"
|
#include "matador/object/attribute.hpp"
|
||||||
#include "matador/object/attribute_generator.hpp"
|
#include "matador/object/restriction.hpp"
|
||||||
#include "matador/object/constraint.hpp"
|
|
||||||
#include "matador/object/constraints_generator.hpp"
|
|
||||||
|
|
||||||
#include "matador/utils/identifier.hpp"
|
#include "matador/utils/identifier.hpp"
|
||||||
|
|
||||||
namespace matador::object {
|
#include <list>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
class repository;
|
namespace matador::object {
|
||||||
|
|
||||||
class object {
|
class object {
|
||||||
public:
|
public:
|
||||||
explicit object(std::string name, std::string alias = "");
|
explicit object(std::string name);
|
||||||
|
|
||||||
template<typename Type>
|
static const attribute& create_attribute(std::string name, const std::shared_ptr<object>& obj);
|
||||||
static std::unique_ptr<object> generate(const repository& repo, std::string name, std::string alias = "") {
|
|
||||||
auto obj = std::make_unique<object>(std::move(name), std::move(alias));
|
|
||||||
obj->attributes_ = std::move(attribute_generator::generate<Type>(repo, *obj));
|
|
||||||
obj->constraints_ = std::move(constraints_generator::generate<Type>(repo, *obj));
|
|
||||||
return std::move(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const attribute& create_attribute(std::string name, object& obj);
|
[[nodiscard]] const attribute* primary_key_attribute() const;
|
||||||
|
|
||||||
void add_attribute(attribute attr);
|
|
||||||
void add_constraint(class constraint c);
|
|
||||||
|
|
||||||
[[nodiscard]] attribute* primary_key_attribute() const;
|
|
||||||
[[nodiscard]] const utils::identifier& primary_key() const;
|
[[nodiscard]] const utils::identifier& primary_key() const;
|
||||||
[[nodiscard]] bool has_primary_key() const;
|
[[nodiscard]] bool has_primary_key() const;
|
||||||
|
|
||||||
|
[[nodiscard]] bool is_relation_object() const;
|
||||||
|
[[nodiscard]] const attribute* join_attribute() const;
|
||||||
|
[[nodiscard]] const attribute* inverse_join_attribute() const;
|
||||||
|
|
||||||
[[nodiscard]] const std::string& name() const;
|
[[nodiscard]] const std::string& name() const;
|
||||||
[[nodiscard]] const std::string& alias() const;
|
|
||||||
|
|
||||||
void update_name(const std::string& name);
|
void update_name(const std::string& name);
|
||||||
|
|
||||||
@@ -44,19 +35,22 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] bool has_constraints() const;
|
[[nodiscard]] bool has_constraints() const;
|
||||||
[[nodiscard]] size_t constraint_count() const;
|
[[nodiscard]] size_t constraint_count() const;
|
||||||
[[nodiscard]] const std::vector<class constraint>& constraints() const;
|
[[nodiscard]] const std::list<restriction>& constraints() const;
|
||||||
|
|
||||||
|
friend std::ostream& operator<<(std::ostream& os, const object& obj);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class constraints_generator;
|
|
||||||
friend class attribute_generator;
|
friend class attribute_generator;
|
||||||
|
friend class object_generator;
|
||||||
|
|
||||||
std::string name_;
|
std::string name_;
|
||||||
std::string alias_;
|
int pk_column_index_{-1};
|
||||||
|
int join_column_index_{-1};
|
||||||
|
int inverse_join_column_index_{-1};
|
||||||
|
|
||||||
attribute* pk_attribute_{nullptr};
|
|
||||||
utils::identifier pk_identifier_;
|
utils::identifier pk_identifier_;
|
||||||
std::vector<attribute> attributes_;
|
std::vector<attribute> attributes_;
|
||||||
std::vector<class constraint> constraints_;
|
std::list<restriction> constraints_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif //MATADOR_OBJECT_GENERATOR_HPP
|
#endif //MATADOR_OBJECT_HPP
|
||||||
@@ -0,0 +1,429 @@
|
|||||||
|
#ifndef MATADOR_OBJECT_CACHE_HPP
|
||||||
|
#define MATADOR_OBJECT_CACHE_HPP
|
||||||
|
|
||||||
|
#include "matador/object/object_proxy.hpp"
|
||||||
|
#include "matador/object/object_resolver.hpp"
|
||||||
|
|
||||||
|
#include "matador/utils/identifier.hpp"
|
||||||
|
#include "matador/utils/message_bus.hpp"
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <memory>
|
||||||
|
#include <shared_mutex>
|
||||||
|
#include <typeindex>
|
||||||
|
#include <utility>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace matador::object {
|
||||||
|
struct cache_entry_base {
|
||||||
|
virtual ~cache_entry_base() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gibt an, ob der Eintrag vollständig "tot" ist (weder Proxy noch Entity leben).
|
||||||
|
*
|
||||||
|
* Wird von @ref object_cache::sweep() verwendet, um Einträge ohne T-Kenntnis zu bereinigen.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual bool is_dead() const noexcept = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
struct cache_entry : cache_entry_base {
|
||||||
|
std::weak_ptr<object_proxy<Type> > proxy;
|
||||||
|
std::weak_ptr<Type> entity;
|
||||||
|
|
||||||
|
[[nodiscard]] bool is_dead() const noexcept override {
|
||||||
|
return proxy.expired() && entity.expired();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct object_cache_event {
|
||||||
|
std::type_index type{typeid(void)};
|
||||||
|
utils::identifier id{};
|
||||||
|
std::chrono::steady_clock::time_point timestamp{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct object_cache_accessed_event : object_cache_event {};
|
||||||
|
struct object_cache_proxy_added_event : object_cache_event {};
|
||||||
|
struct object_cache_entity_attached_event : object_cache_event {};
|
||||||
|
struct object_cache_imported_event : object_cache_event {};
|
||||||
|
struct object_cache_erased_event : object_cache_event {};
|
||||||
|
|
||||||
|
struct object_cache_sweep_event {
|
||||||
|
std::size_t removed{};
|
||||||
|
std::chrono::steady_clock::time_point timestamp{};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Thread-sicherer Cache für Objekt-Proxies und (optional) geladene Entities.
|
||||||
|
*
|
||||||
|
* Der Cache verwaltet Einträge pro Kombination aus Objekt-Typ @p T und Primärschlüssel/Identifier.
|
||||||
|
* Für jede (T, id)-Kombination können sowohl
|
||||||
|
* - ein Proxy (@c object_proxy<T>) als auch
|
||||||
|
* - die dazugehörige Entity (@c T)
|
||||||
|
* zwischengespeichert werden.
|
||||||
|
*
|
||||||
|
* Der Cache hält dabei nur @c std::weak_ptr auf Proxy und Entity, d.h. er verlängert deren Lebensdauer nicht.
|
||||||
|
*
|
||||||
|
* @note Thread-Safety: Alle öffentlichen Methoden sind threadsafe (intern synchronisiert).
|
||||||
|
* @note Semantik: Ein Eintrag kann aus dem Cache opportunistisch entfernt werden, sobald Proxy und Entity abgelaufen sind.
|
||||||
|
*/
|
||||||
|
class object_cache {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Erzeugt einen leeren Cache.
|
||||||
|
*/
|
||||||
|
explicit object_cache(utils::message_bus &bus)
|
||||||
|
: bus_(bus) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Liefert einen Proxy für (T, id) und erstellt ihn bei Bedarf.
|
||||||
|
*
|
||||||
|
* Falls bereits ein lebender Proxy im Cache existiert, wird er wiederverwendet.
|
||||||
|
* Andernfalls wird ein neuer Proxy erzeugt, im Cache abgelegt und zurückgegeben.
|
||||||
|
* Falls für (T, id) bereits eine Entity vorhanden ist, wird sie an den Proxy gebunden.
|
||||||
|
*
|
||||||
|
* @tparam Type Entity-Typ.
|
||||||
|
* @tparam ResolverPointerType Zeiger-Typ auf einen Resolver, typischerweise
|
||||||
|
* @c std::shared_ptr<object_resolver<T>> oder @c std::weak_ptr<object_resolver<T>>.
|
||||||
|
* @param id Identifier/Primärschlüssel der Entity.
|
||||||
|
* @param resolver_ptr Resolver (shared/weak), der zur Lazy-Auflösung durch den Proxy genutzt wird.
|
||||||
|
* @return Shared-Pointer auf den (ggf. neu erstellten) Proxy.
|
||||||
|
*
|
||||||
|
* @note Diese Methode ist threadsafe.
|
||||||
|
*/
|
||||||
|
template<typename Type, typename ResolverPointerType>
|
||||||
|
std::shared_ptr<object_proxy<Type>> acquire_proxy(utils::identifier id, ResolverPointerType &&resolver_ptr) {
|
||||||
|
const auto k = make_key<Type>(id);
|
||||||
|
|
||||||
|
std::unique_lock lock(mutex_);
|
||||||
|
|
||||||
|
auto it = map_.find(k);
|
||||||
|
if (it != map_.end()) {
|
||||||
|
// found entry, return std::shared_ptr of proxy
|
||||||
|
auto *entry = entry_cast_<Type>(it->second.get());
|
||||||
|
if (auto proxy_ptr = entry->proxy.lock()) {
|
||||||
|
bus_.publish<object_cache_accessed_event>({k.type, id, std::chrono::steady_clock::now()});
|
||||||
|
return proxy_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the proxy is dead, but the entity is alive, create a new proxy and attach entity
|
||||||
|
auto weak_resolver = to_weak<Type>(std::forward<ResolverPointerType>(resolver_ptr));
|
||||||
|
auto proxy_ptr = std::make_shared<object_proxy<Type>>(weak_resolver, id);
|
||||||
|
|
||||||
|
if (auto obj = entry->entity.lock()) {
|
||||||
|
proxy_ptr->attach(std::move(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->proxy = proxy_ptr;
|
||||||
|
|
||||||
|
bus_.publish<object_cache_proxy_added_event>({k.type, id, std::chrono::steady_clock::now()});
|
||||||
|
|
||||||
|
// return the shared_ptr of the proxy
|
||||||
|
return proxy_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// entry couldn't be found, create a new entry
|
||||||
|
auto entry_ptr = std::make_unique<cache_entry<Type>>();
|
||||||
|
auto *entry = entry_ptr.get();
|
||||||
|
|
||||||
|
// create a weak resolver and shared proxy
|
||||||
|
auto weak_resolver = to_weak<Type>(std::forward<ResolverPointerType>(resolver_ptr));
|
||||||
|
auto proxy_ptr = std::make_shared<object_proxy<Type>>(weak_resolver, id);
|
||||||
|
|
||||||
|
// lock entity and attach to proxy
|
||||||
|
if (auto obj = entry->entity.lock()) {
|
||||||
|
proxy_ptr->attach(std::move(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the new proxy into cache entry
|
||||||
|
entry->proxy = proxy_ptr;
|
||||||
|
map_.emplace(k, std::move(entry_ptr));
|
||||||
|
|
||||||
|
bus_.publish<object_cache_proxy_added_event>({k.type, id, std::chrono::steady_clock::now()});
|
||||||
|
|
||||||
|
// return the shared_ptr of the proxy
|
||||||
|
return proxy_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Type, typename ResolverPointerType>
|
||||||
|
bool import(const utils::identifier &id, const std::shared_ptr<object_proxy<Type>> &proxy, ResolverPointerType &&resolver_ptr) {
|
||||||
|
if (!proxy) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto obj = proxy->object();
|
||||||
|
auto weak_resolver = to_weak<Type>(std::forward<ResolverPointerType>(resolver_ptr));
|
||||||
|
const auto k = make_key<Type>(id);
|
||||||
|
|
||||||
|
std::unique_lock lock(mutex_);
|
||||||
|
|
||||||
|
auto it = map_.find(k);
|
||||||
|
if (it != map_.end()) {
|
||||||
|
auto *entry = entry_cast_<Type>(it->second.get());
|
||||||
|
|
||||||
|
if (auto existing_proxy = entry->proxy.lock()) {
|
||||||
|
if (existing_proxy != proxy) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy->primary_key(id);
|
||||||
|
proxy->resolver(std::move(weak_resolver));
|
||||||
|
|
||||||
|
if (obj) {
|
||||||
|
entry->entity = obj;
|
||||||
|
proxy->attach(std::move(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->proxy = proxy;
|
||||||
|
bus_.publish<object_cache_imported_event>({k.type, id, std::chrono::steady_clock::now()});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto entry_ptr = std::make_unique<cache_entry<Type>>();
|
||||||
|
auto *entry = entry_ptr.get();
|
||||||
|
|
||||||
|
proxy->primary_key(id);
|
||||||
|
proxy->resolver(std::move(weak_resolver));
|
||||||
|
|
||||||
|
if (obj) {
|
||||||
|
entry->entity = obj;
|
||||||
|
proxy->attach(std::move(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->proxy = proxy;
|
||||||
|
map_.emplace(k, std::move(entry_ptr));
|
||||||
|
|
||||||
|
bus_.publish<object_cache_imported_event>({k.type, id, std::chrono::steady_clock::now()});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Verknüpft eine geladene Entity mit einem Cache-Eintrag (Type, id).
|
||||||
|
*
|
||||||
|
* Speichert die Entity als @c weak_ptr im Cache. Falls bereits ein Proxy existiert,
|
||||||
|
* wird die Entity sofort an den Proxy gebunden.
|
||||||
|
*
|
||||||
|
* @tparam Type Entity-Typ.
|
||||||
|
* @param id Identifier/Primärschlüssel der Entity.
|
||||||
|
* @param obj Geladene Entity als @c shared_ptr.
|
||||||
|
*
|
||||||
|
* @note Diese Methode ist threadsafe.
|
||||||
|
*/
|
||||||
|
template<typename Type>
|
||||||
|
void attach_entity(const utils::identifier &id, std::shared_ptr<Type> obj) {
|
||||||
|
const auto k = make_key<Type>(id);
|
||||||
|
|
||||||
|
std::unique_lock lock(mutex_);
|
||||||
|
|
||||||
|
auto it = map_.find(k);
|
||||||
|
if (it == map_.end()) {
|
||||||
|
auto entry_ptr = std::make_unique<cache_entry<Type>>();
|
||||||
|
auto *entry = entry_ptr.get();
|
||||||
|
entry->entity = obj;
|
||||||
|
map_.emplace(k, std::move(entry_ptr));
|
||||||
|
bus_.publish<object_cache_entity_attached_event>({k.type, id, std::chrono::steady_clock::now()});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *entry = entry_cast_<Type>(it->second.get());
|
||||||
|
entry->entity = obj;
|
||||||
|
|
||||||
|
if (auto proxy = entry->proxy.lock()) {
|
||||||
|
proxy->attach(std::move(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
bus_.publish<object_cache_entity_attached_event>({k.type, id, std::chrono::steady_clock::now()});
|
||||||
|
|
||||||
|
prune_if_dead(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Liefert die aktuell geladene Entity für (Type, id), falls vorhanden.
|
||||||
|
*
|
||||||
|
* @tparam Type Entity-Typ.
|
||||||
|
* @param id Identifier/Primärschlüssel der Entity.
|
||||||
|
* @return @c shared_ptr auf die Entity oder ein leerer Pointer, falls nicht geladen/abgelaufen.
|
||||||
|
*
|
||||||
|
* @note Diese Methode ist threadsafe.
|
||||||
|
*/
|
||||||
|
template<typename Type>
|
||||||
|
std::shared_ptr<Type> get_entity(const utils::identifier &id) {
|
||||||
|
const auto k = make_key<Type>(id);
|
||||||
|
|
||||||
|
std::unique_lock lock(mutex_);
|
||||||
|
auto it = map_.find(k);
|
||||||
|
if (it == map_.end()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *entry = entry_cast_<Type>(it->second.get());
|
||||||
|
auto entity_ptr = entry->entity.lock();
|
||||||
|
if (entity_ptr) {
|
||||||
|
bus_.publish<object_cache_accessed_event>({k.type, id, std::chrono::steady_clock::now()});
|
||||||
|
}
|
||||||
|
prune_if_dead(it);
|
||||||
|
return entity_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prüft, ob für (Type, id) aktuell eine lebende Entity verfügbar ist.
|
||||||
|
*
|
||||||
|
* @tparam Type Entity-Typ.
|
||||||
|
* @param id Identifier/Primärschlüssel der Entity.
|
||||||
|
* @return @c true, wenn die Entity-Referenz nicht abgelaufen ist; sonst @c false.
|
||||||
|
*
|
||||||
|
* @note Diese Methode ist threadsafe.
|
||||||
|
*/
|
||||||
|
template<typename Type>
|
||||||
|
bool is_loaded(const utils::identifier &id) {
|
||||||
|
const auto k = make_key<Type>(id);
|
||||||
|
|
||||||
|
std::unique_lock lock(mutex_);
|
||||||
|
auto it = map_.find(k);
|
||||||
|
if (it == map_.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *entry = entry_cast_<Type>(it->second.get());
|
||||||
|
const bool loaded = !entry->entity.expired();
|
||||||
|
if (loaded) {
|
||||||
|
bus_.publish<object_cache_accessed_event>({k.type, id, std::chrono::steady_clock::now()});
|
||||||
|
}
|
||||||
|
prune_if_dead(it);
|
||||||
|
return loaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void erase(utils::identifier id) {
|
||||||
|
const auto k = make_key<T>(id);
|
||||||
|
|
||||||
|
std::unique_lock lock(mutex_);
|
||||||
|
auto it = map_.find(k);
|
||||||
|
if (it == map_.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *e = entry_cast_<T>(it->second.get());
|
||||||
|
if (auto p = e->proxy.lock()) {
|
||||||
|
p->invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
map_.erase(it);
|
||||||
|
bus_.publish<object_cache_erased_event>({k.type, id, std::chrono::steady_clock::now()});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Führt einen Cleanup-Lauf aus und entfernt Einträge, deren Proxy und Entity abgelaufen sind.
|
||||||
|
*
|
||||||
|
* @return Anzahl der entfernten Einträge.
|
||||||
|
*
|
||||||
|
* @note Diese Methode ist threadsafe.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] std::size_t sweep() {
|
||||||
|
std::unique_lock lock(mutex_);
|
||||||
|
std::size_t removed = 0;
|
||||||
|
|
||||||
|
for (auto it = map_.begin(); it != map_.end(); ) {
|
||||||
|
if (it->second->is_dead()) {
|
||||||
|
it = map_.erase(it);
|
||||||
|
++removed;
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removed > 0) {
|
||||||
|
bus_.publish<object_cache_sweep_event>({removed, std::chrono::steady_clock::now()});
|
||||||
|
}
|
||||||
|
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct key {
|
||||||
|
std::type_index type;
|
||||||
|
utils::identifier id{};
|
||||||
|
bool operator==(key const &other) const {
|
||||||
|
return type == other.type && id == other.id;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct key_hash {
|
||||||
|
size_t operator()(key const &k) const noexcept {
|
||||||
|
// (3) robustere Hash-Kombination als XOR
|
||||||
|
size_t seed = std::hash<std::type_index>()(k.type);
|
||||||
|
const size_t h2 = std::hash<utils::identifier>()(k.id);
|
||||||
|
seed ^= h2 + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static key make_key(const utils::identifier &id) {
|
||||||
|
return key{std::type_index(typeid(T)), id};
|
||||||
|
}
|
||||||
|
|
||||||
|
// (4) Debug-Absicherung für type-erased Casts
|
||||||
|
template<typename T>
|
||||||
|
static cache_entry<T> *entry_cast_(cache_entry_base *base) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
auto *p = dynamic_cast<cache_entry<T> *>(base);
|
||||||
|
assert(p && "object_cache: Type mismatch in cache entry (key/type invariant violated)");
|
||||||
|
return p;
|
||||||
|
#else
|
||||||
|
return static_cast<cache_entry<T> *>(base);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename U>
|
||||||
|
using enable_if_resolver_shared_ptr_t = std::enable_if_t<std::is_base_of_v<object_resolver<T>, U>, int>;
|
||||||
|
|
||||||
|
template<typename T, typename U>
|
||||||
|
using enable_if_resolver_weak_ptr_t = std::enable_if_t<std::is_base_of_v<object_resolver<T>, U>, int>;
|
||||||
|
|
||||||
|
// shared_ptr<Derived> -> weak_ptr<Base>
|
||||||
|
template<typename T, typename U, enable_if_resolver_shared_ptr_t<T, U> = 0>
|
||||||
|
static std::weak_ptr<object_resolver<T>> to_weak(const std::shared_ptr<U> &s) {
|
||||||
|
return std::weak_ptr<object_resolver<T>>(std::static_pointer_cast<object_resolver<T>>(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
// weak_ptr<Derived> -> weak_ptr<Base>
|
||||||
|
template<typename T, typename U, enable_if_resolver_weak_ptr_t<T, U> = 0>
|
||||||
|
static std::weak_ptr<object_resolver<T>> to_weak(const std::weak_ptr<U> &w) {
|
||||||
|
return std::weak_ptr<object_resolver<T>>(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (2) Opportunistischer Cleanup: entferne Entry, wenn beide weak_ptr abgelaufen sind.
|
||||||
|
template<typename IteratorType>
|
||||||
|
bool prune_if_dead(IteratorType &it) {
|
||||||
|
if (it == map_.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (it->second && it->second->is_dead()) {
|
||||||
|
map_.erase(it);
|
||||||
|
it = map_.end();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
void prune_if_dead_typed(typename std::unordered_map<key, std::unique_ptr<cache_entry_base>, key_hash>::iterator &it) {
|
||||||
|
(void)Type{}; // T bleibt im Interface, damit bestehende Call-Sites unverändert bleiben können.
|
||||||
|
prune_if_dead(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable std::shared_mutex mutex_{};
|
||||||
|
utils::message_bus &bus_;
|
||||||
|
std::unordered_map<key, std::unique_ptr<cache_entry_base>, key_hash> map_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- Inline Anpassungen: typed prune nach Zugriff (damit wir T haben) ---
|
||||||
|
|
||||||
|
// ... existing code ...
|
||||||
|
// (Die typed prune wird oben benutzt; wir rufen sie direkt im Codepfad anstelle von prune_if_dead_)
|
||||||
|
|
||||||
|
} // namespace matador::object
|
||||||
|
#endif //MATADOR_OBJECT_CACHE_HPP
|
||||||
@@ -0,0 +1,198 @@
|
|||||||
|
#ifndef MATADOR_OBJECT_GENERATOR_HPP
|
||||||
|
#define MATADOR_OBJECT_GENERATOR_HPP
|
||||||
|
|
||||||
|
#include "matador/object/basic_repository.hpp"
|
||||||
|
#include "matador/object/object.hpp"
|
||||||
|
|
||||||
|
#include "matador/utils/access.hpp"
|
||||||
|
#include "matador/utils/primary_key_attribute.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace matador::object {
|
||||||
|
class pk_type_determinator {
|
||||||
|
private:
|
||||||
|
pk_type_determinator() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<class Type>
|
||||||
|
static utils::basic_type determine() {
|
||||||
|
pk_type_determinator determinator;
|
||||||
|
Type t;
|
||||||
|
|
||||||
|
access::process(determinator, t);
|
||||||
|
return determinator.type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ValueType>
|
||||||
|
void on_primary_key(const char *, ValueType &/*pk*/, const utils::primary_key_attribute& attr) {
|
||||||
|
type_ = utils::data_type_traits<ValueType>::type(attr.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*/) {}
|
||||||
|
static void on_attribute(const char * /*id*/, char * /*x*/, const utils::field_attributes &/*attr*/) {}
|
||||||
|
template<class Pointer>
|
||||||
|
static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
|
||||||
|
template<class Pointer>
|
||||||
|
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {}
|
||||||
|
template<class ContainerType>
|
||||||
|
static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {}
|
||||||
|
template<class ContainerType>
|
||||||
|
static void on_has_many_to_many(const char * /*id*/, ContainerType & /*cont*/, 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 & /*cont*/, const utils::foreign_attributes &/*attr*/) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
utils::basic_type type_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
class object_generator {
|
||||||
|
private:
|
||||||
|
explicit object_generator(basic_repository& repo, const std::shared_ptr<object> &object);
|
||||||
|
|
||||||
|
public:
|
||||||
|
template < class Type >
|
||||||
|
static std::shared_ptr<object> generate(basic_repository &repo, const std::string &name) {
|
||||||
|
return generate(std::make_unique<Type>(), repo, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < class Type >
|
||||||
|
static std::shared_ptr<object> generate(std::unique_ptr<Type>&& t,
|
||||||
|
basic_repository &repo,
|
||||||
|
const std::string &name,
|
||||||
|
const std::string &join_column = "",
|
||||||
|
const std::string &inverse_join_column = "") {
|
||||||
|
const std::type_index ti(typeid(Type));
|
||||||
|
if (repo.has_object_for_type(ti)) {
|
||||||
|
auto obj = repo.object_for_type(ti);
|
||||||
|
repo.remove_object_for_type(ti);
|
||||||
|
obj->update_name(name);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto obj = std::make_shared<object>(name);
|
||||||
|
std::ignore = repo.provide_object_in_advance(ti, obj);
|
||||||
|
object_generator gen(repo, obj);
|
||||||
|
access::process(gen, *t);
|
||||||
|
if (!join_column.empty() && !inverse_join_column.empty()) {
|
||||||
|
gen.prepare_relation_table(join_column, inverse_join_column);
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BaseType>
|
||||||
|
static void on_base(const BaseType&) {}
|
||||||
|
template < class Type >
|
||||||
|
void on_primary_key(const char *, Type &x, const utils::primary_key_attribute& attr);
|
||||||
|
void on_revision(const char *id, uint64_t &rev);
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
void on_attribute(const char *id, Type &x, const utils::field_attributes &attr);
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
void on_attribute(const char *id, std::optional<Type> &x, const utils::field_attributes &attr);
|
||||||
|
|
||||||
|
template<class Pointer>
|
||||||
|
void on_belongs_to(const char *id, Pointer &x, const utils::foreign_attributes &/*attr*/) {
|
||||||
|
on_foreign_key(id, x);
|
||||||
|
create_fk_constraint<typename Pointer::value_type>(id);
|
||||||
|
}
|
||||||
|
template<class Pointer>
|
||||||
|
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {}
|
||||||
|
|
||||||
|
template <class Pointer>
|
||||||
|
void on_foreign_key(const char *id, Pointer &/*x*/) {
|
||||||
|
const auto type = pk_type_determinator::determine<typename Pointer::value_type>();
|
||||||
|
auto &ref = object_->attributes_.emplace_back(id, type, utils::constraints::ForeignKey, null_option_type::NotNull);
|
||||||
|
ref.index_ = object_->attributes_.size() - 1;
|
||||||
|
ref.owner_ = object_;
|
||||||
|
}
|
||||||
|
template<class ContainerType>
|
||||||
|
static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {}
|
||||||
|
template<class ContainerType>
|
||||||
|
static void on_has_many_to_many(const char * /*id*/, ContainerType & /*cont*/, 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 & /*cont*/, const utils::foreign_attributes &/*attr*/) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename ValueType>
|
||||||
|
attribute &emplace_attribute(const char *id, const utils::field_attributes& attr, null_option_type null_option) {
|
||||||
|
auto &ref = object_->attributes_.emplace_back(id, utils::data_type_traits<ValueType>::type(attr.size()), attr, null_option);
|
||||||
|
ref.index_ = object_->attributes_.size() - 1;
|
||||||
|
ref.owner_ = object_;
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
void create_pk_constraint(const std::string& name) const;
|
||||||
|
template<typename Type>
|
||||||
|
void create_fk_constraint(const std::string& name) const;
|
||||||
|
void create_unique_constraint(const std::string& name) const;
|
||||||
|
|
||||||
|
[[nodiscard]] std::vector<attribute>::iterator find_attribute_by_name(const std::string &name) const;
|
||||||
|
|
||||||
|
void prepare_primary_key(const attribute &ref, utils::identifier &&pk) const;
|
||||||
|
void prepare_relation_table(const std::string &join_column, const std::string &inverse_join_column) const;
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
[[nodiscard]] std::shared_ptr<object> fk_object() const;
|
||||||
|
|
||||||
|
static std::shared_ptr<object> acquire_object(basic_repository &repo, const std::type_index &ti, const std::string& name);
|
||||||
|
private:
|
||||||
|
basic_repository &repo_;
|
||||||
|
std::shared_ptr<object> object_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename ValueType>
|
||||||
|
void object_generator::on_primary_key(const char *id, ValueType &x, const utils::primary_key_attribute& attr) {
|
||||||
|
auto cs = utils::constraints::PrimaryKey;
|
||||||
|
if (attr.generator() == utils::generator_type::Identity) {
|
||||||
|
cs |= utils::constraints::Identity;
|
||||||
|
}
|
||||||
|
auto &ref = emplace_attribute<ValueType>(id, { attr.size(), cs }, null_option_type::NotNull);
|
||||||
|
prepare_primary_key(ref, utils::identifier(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
void object_generator::on_attribute(const char *id, Type &/*x*/, const utils::field_attributes &attr) {
|
||||||
|
std::ignore = emplace_attribute<Type>(id, attr, null_option_type::NotNull);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
void object_generator::on_attribute(const char *id, std::optional<Type> & /*x*/, const utils::field_attributes &attr) {
|
||||||
|
std::ignore = emplace_attribute<Type>(id, attr, null_option_type::Nullable);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
void object_generator::create_fk_constraint(const std::string& name) const {
|
||||||
|
const auto pk_attr = find_attribute_by_name(name);
|
||||||
|
if (pk_attr == std::end(object_->attributes_)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto obj = fk_object<Type>();
|
||||||
|
restriction pk_constraint(pk_attr->index());
|
||||||
|
pk_constraint.options_ |= utils::constraints::ForeignKey;
|
||||||
|
pk_constraint.owner_ = object_;
|
||||||
|
pk_constraint.reference_ = obj;
|
||||||
|
object_->constraints_.emplace_back(std::move(pk_constraint));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
std::shared_ptr<object> object_generator::fk_object() const {
|
||||||
|
const auto ti = std::type_index(typeid(Type));
|
||||||
|
if (const auto result = repo_.basic_info(ti)) {
|
||||||
|
return result->get().object();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (repo_.has_object_for_type(ti)) {
|
||||||
|
return repo_.object_for_type(ti);
|
||||||
|
}
|
||||||
|
const auto obj = repo_.provide_object_in_advance(ti, std::make_shared<object>(""));
|
||||||
|
object_generator gen(repo_, obj);
|
||||||
|
Type t;
|
||||||
|
access::process(gen, t);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif //MATADOR_OBJECT_GENERATOR_HPP
|
||||||
@@ -2,6 +2,9 @@
|
|||||||
#define OBJECT_INFO_HPP
|
#define OBJECT_INFO_HPP
|
||||||
|
|
||||||
#include "matador/object/basic_object_info.hpp"
|
#include "matador/object/basic_object_info.hpp"
|
||||||
|
#include "matador/object/observer.hpp"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace matador::object {
|
namespace matador::object {
|
||||||
class repository_node;
|
class repository_node;
|
||||||
@@ -11,23 +14,45 @@ class object_info final : public basic_object_info {
|
|||||||
public:
|
public:
|
||||||
using create_func = std::function<std::unique_ptr<Type>()>;
|
using create_func = std::function<std::unique_ptr<Type>()>;
|
||||||
|
|
||||||
object_info(const std::shared_ptr<repository_node>& node,
|
object_info(const repository_node& node,
|
||||||
std::unique_ptr<object> &&obj,
|
const std::shared_ptr<class object> &obj,
|
||||||
|
std::vector<std::unique_ptr<observer<Type>>>&& observers,
|
||||||
create_func&& creator)
|
create_func&& creator)
|
||||||
: basic_object_info(node, std::move(obj))
|
: basic_object_info(node, obj)
|
||||||
, creator_(std::move(creator)){
|
, creator_(std::move(creator))
|
||||||
}
|
, observers_(std::move(observers)){}
|
||||||
|
|
||||||
explicit object_info(const std::shared_ptr<repository_node>& node)
|
explicit object_info(const repository_node& node)
|
||||||
: basic_object_info(node, {}) {
|
: basic_object_info(node, {}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const Type &prototype() const { return prototype_; }
|
const Type &prototype() const { return prototype_; }
|
||||||
std::unique_ptr<Type> create() const { return creator_(); }
|
std::unique_ptr<Type> create() const { return creator_(); }
|
||||||
|
|
||||||
|
void on_attach() const override {
|
||||||
|
for (auto &observer : observers_) {
|
||||||
|
observer->on_attach(node_, prototype_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_detach() const override {
|
||||||
|
for (auto &observer : observers_) {
|
||||||
|
observer->on_detach(node_, prototype_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_observer(std::unique_ptr<observer<Type>>&& observer) {
|
||||||
|
observers_.push_back(std::move(observer));
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<std::unique_ptr<observer<Type>>>& observers() const {
|
||||||
|
return observers_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Type prototype_;
|
Type prototype_;
|
||||||
create_func creator_{[]{ return std::make_unique<Type>(); }};
|
create_func creator_{[]{ return std::make_unique<Type>(); }};
|
||||||
|
std::vector<std::unique_ptr<observer<Type>>> observers_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
|
|||||||
@@ -3,92 +3,188 @@
|
|||||||
|
|
||||||
#include "matador/object/primary_key_resolver.hpp"
|
#include "matador/object/primary_key_resolver.hpp"
|
||||||
|
|
||||||
|
#include "matador/object/object_resolver.hpp"
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
namespace matador::object {
|
namespace matador::object {
|
||||||
|
enum class object_state : uint8_t {
|
||||||
class basic_object_proxy {
|
Transient,
|
||||||
public:
|
Persistent,
|
||||||
virtual ~basic_object_proxy() = default;
|
Detached,
|
||||||
|
Removed
|
||||||
[[nodiscard]] virtual void *get() const = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template < typename Type >
|
|
||||||
class object_proxy;
|
|
||||||
|
|
||||||
template < typename Type >
|
|
||||||
class object_resolver {
|
|
||||||
public:
|
|
||||||
virtual ~object_resolver() = default;
|
|
||||||
|
|
||||||
virtual Type* resolve(const object_proxy<Type> &proxy) const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
template < typename Type >
|
|
||||||
class static_object_resolver final : public object_resolver<Type> {
|
|
||||||
public:
|
|
||||||
static_object_resolver() = default;
|
|
||||||
explicit static_object_resolver(Type* obj)
|
|
||||||
: obj_(obj) {}
|
|
||||||
explicit static_object_resolver(std::unique_ptr<Type> obj)
|
|
||||||
: obj_(std::move(obj)) {}
|
|
||||||
|
|
||||||
Type* resolve(const object_proxy<Type> &/*proxy*/) const override {
|
|
||||||
return obj_.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::unique_ptr<Type> obj_{};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template<class Type>
|
template<class Type>
|
||||||
class object_proxy final : public basic_object_proxy {
|
class object_proxy final {
|
||||||
public:
|
public:
|
||||||
object_proxy() = default;
|
object_proxy() = default;
|
||||||
explicit object_proxy(Type* obj)
|
|
||||||
: resolver_(std::make_unique<static_object_resolver<Type>>(obj))
|
|
||||||
, pk_(primary_key_resolver::resolve_object(*obj).pk) {}
|
|
||||||
|
|
||||||
[[nodiscard]] void *get() const override { return static_cast<void*>(pointer()); }
|
// Lazy
|
||||||
|
object_proxy(std::weak_ptr<object_resolver<Type>> resolver, utils::identifier id)
|
||||||
Type* operator->() const { return pointer(); }
|
: resolver_(std::move(resolver))
|
||||||
Type& operator*() { return *pointer(); }
|
, pk_(std::move(id))
|
||||||
const Type& operator*() const { return *pointer(); }
|
, state_(object_state::Persistent) {
|
||||||
|
|
||||||
Type* pointer() const { return resolve(); }
|
|
||||||
|
|
||||||
Type& ref() { return *pointer(); }
|
|
||||||
const Type& ref() const { return *pointer(); }
|
|
||||||
|
|
||||||
void reset(Type* obj) {
|
|
||||||
pk_ = primary_key_resolver::resolve_object(*obj).pk;
|
|
||||||
resolver_ = std::make_unique<static_object_resolver<Type>>(obj);
|
|
||||||
}
|
}
|
||||||
void reset(std::unique_ptr<Type> obj) {
|
|
||||||
pk_ = primary_key_resolver::resolve_object(*obj).pk;
|
// Eager
|
||||||
resolver_ = std::make_unique<static_object_resolver<Type>>(std::move(obj));
|
object_proxy(std::weak_ptr<object_resolver<Type>> resolver, std::shared_ptr<Type> obj)
|
||||||
|
: obj_(std::move(obj))
|
||||||
|
, resolver_(std::move(resolver))
|
||||||
|
, pk_(obj_ ? primary_key_resolver::resolve_object(*obj_).pk : utils::identifier{})
|
||||||
|
, state_(obj_ ? object_state::Persistent : object_state::Detached) {
|
||||||
}
|
}
|
||||||
void reset(std::unique_ptr<object_resolver<Type>> &&resolver) {
|
|
||||||
|
// Transient
|
||||||
|
explicit object_proxy(std::shared_ptr<Type> obj)
|
||||||
|
: obj_(std::move(obj))
|
||||||
|
, pk_(obj_ ? primary_key_resolver::resolve_object(*obj_).pk : utils::identifier{}) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void attach(std::shared_ptr<Type> obj) {
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
|
||||||
|
obj_ = std::move(obj);
|
||||||
|
if (!obj_) {
|
||||||
|
pk_.clear();
|
||||||
|
state_ = object_state::Detached;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pk_ = primary_key_resolver::resolve_object(*obj_).pk;
|
||||||
|
state_ = object_state::Persistent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resolver(std::weak_ptr<object_resolver<Type>> resolver) {
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
resolver_ = std::move(resolver);
|
resolver_ = std::move(resolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool empty() const { return resolver_ == nullptr; }
|
[[nodiscard]] std::shared_ptr<Type> object() const {
|
||||||
[[nodiscard]] bool valid() const { return !empty(); }
|
return resolve_object();
|
||||||
[[nodiscard]] bool has_primary_key() const { return !pk_.is_null(); }
|
|
||||||
[[nodiscard]] const utils::identifier& primary_key() const { return pk_; }
|
|
||||||
void primary_key(const utils::identifier &pk) { pk_ = pk; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Type* resolve() const {
|
|
||||||
return resolver_->resolve(*this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
void invalidate() {
|
||||||
std::unique_ptr<object_resolver<Type>> resolver_{std::make_unique<static_object_resolver<Type>>()};
|
std::lock_guard lock(mutex_);
|
||||||
utils::identifier pk_{};
|
obj_.reset();
|
||||||
};
|
resolver_.reset();
|
||||||
|
state_ = object_state::Detached;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] void *raw_pointer() const { return static_cast<void *>(pointer()); }
|
||||||
|
|
||||||
|
Type *operator->() {
|
||||||
|
auto *ptr = pointer();
|
||||||
|
if (!ptr) {
|
||||||
|
throw std::runtime_error("Cannot dereference empty object proxy");
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type *operator->() const {
|
||||||
|
auto *ptr = pointer();
|
||||||
|
if (!ptr) {
|
||||||
|
throw std::runtime_error("Cannot dereference empty object proxy");
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type &operator*() {
|
||||||
|
auto *ptr = pointer();
|
||||||
|
if (!ptr) {
|
||||||
|
throw std::runtime_error("Cannot dereference empty object proxy");
|
||||||
|
}
|
||||||
|
return *ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type &operator*() const {
|
||||||
|
auto *ptr = pointer();
|
||||||
|
if (!ptr) {
|
||||||
|
throw std::runtime_error("Cannot dereference empty object proxy");
|
||||||
|
}
|
||||||
|
return *ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type *pointer() const {
|
||||||
|
return resolve_object().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool empty() const {
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
return !obj_ && resolver_.expired();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool valid() const { return !empty(); }
|
||||||
|
|
||||||
|
[[nodiscard]] bool has_primary_key() const {
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
return !pk_.is_null();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] utils::identifier primary_key() const {
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
return pk_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void primary_key(const utils::identifier &pk) {
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
pk_ = pk;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_persistent() const { return is_state(object_state::Persistent); }
|
||||||
|
bool is_transient() const { return is_state(object_state::Transient); }
|
||||||
|
bool is_detached() const { return is_state(object_state::Detached); }
|
||||||
|
bool is_removed() const { return is_state(object_state::Removed); }
|
||||||
|
|
||||||
|
bool is_state(const object_state state) const {
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
return state_ == state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void change_state(const object_state state) {
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
state_ = state;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::shared_ptr<Type> resolve_object() const {
|
||||||
|
std::shared_ptr<Type> current;
|
||||||
|
std::shared_ptr<object_resolver<Type>> resolver;
|
||||||
|
utils::identifier pk;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
if (obj_) {
|
||||||
|
return obj_;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolver = resolver_.lock();
|
||||||
|
if (!resolver) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
pk = pk_;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = resolver->resolve(pk);
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
if (!obj_) {
|
||||||
|
obj_ = std::move(current);
|
||||||
|
}
|
||||||
|
return obj_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
mutable std::shared_ptr<Type> obj_{};
|
||||||
|
mutable std::weak_ptr<object_resolver<Type>> resolver_{};
|
||||||
|
utils::identifier pk_{};
|
||||||
|
object_state state_{object_state::Transient};
|
||||||
|
mutable std::mutex mutex_{};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
#endif //OBJECT_PROXY_HPP
|
#endif //OBJECT_PROXY_HPP
|
||||||
|
|||||||
@@ -8,48 +8,175 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace matador::object {
|
namespace matador::object {
|
||||||
|
struct null_object_ptr_t {
|
||||||
|
constexpr null_object_ptr_t() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr null_object_ptr_t nullobj{};
|
||||||
|
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
class object_ptr {
|
class object_ptr {
|
||||||
public:
|
public:
|
||||||
object_ptr()
|
object_ptr()
|
||||||
: ptr_(std::make_shared<object_proxy<Type>>()) {}
|
: proxy_(std::make_shared<object_proxy<Type>>()) {}
|
||||||
explicit object_ptr(Type *obj)
|
|
||||||
: ptr_(std::make_shared<object_proxy<Type>>(obj)) {}
|
|
||||||
object_ptr(const object_ptr &other) : ptr_(other.ptr_) {}
|
|
||||||
object_ptr(object_ptr &&other) noexcept : ptr_(std::move(other.ptr_)) {}
|
|
||||||
object_ptr &operator=(const object_ptr &other) = default;
|
|
||||||
object_ptr &operator=(object_ptr &&other) = default;
|
|
||||||
|
|
||||||
using value_type = Type;
|
object_ptr(null_object_ptr_t) {}
|
||||||
Type* operator->() const { return ptr_->pointer(); }
|
|
||||||
Type& operator*() { return ptr_->ref(); }
|
|
||||||
const Type& operator*() const { return ptr_->ref(); }
|
|
||||||
|
|
||||||
[[nodiscard]] bool empty() const { return ptr_->pointer() == nullptr; }
|
explicit object_ptr(std::shared_ptr<Type> obj)
|
||||||
void reset(Type *obj) {
|
: proxy_(std::make_shared<object_proxy<Type>>(std::move(obj))) {}
|
||||||
ptr_->reset(obj);
|
|
||||||
|
explicit object_ptr(std::shared_ptr<object_proxy<Type>> obj)
|
||||||
|
: proxy_(std::move(obj)) {}
|
||||||
|
|
||||||
|
object_ptr(const object_ptr &other) = default;
|
||||||
|
object_ptr(object_ptr &&other) noexcept = default;
|
||||||
|
object_ptr& operator=(const object_ptr &other) = default;
|
||||||
|
object_ptr& operator=(object_ptr &&other) noexcept = default;
|
||||||
|
|
||||||
|
object_ptr& operator=(null_object_ptr_t) {
|
||||||
|
proxy_.reset();
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type* get() const { return static_cast<Type*>(ptr_->pointer()); }
|
bool operator==(const object_ptr &other) const {
|
||||||
|
if (proxy_ == other.proxy_) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
operator bool() { return valid(); }
|
if (!proxy_ || !other.proxy_) {
|
||||||
bool valid() { return ptr_ != nullptr; }
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_primary_key() && other.has_primary_key()) {
|
||||||
|
return primary_key() == other.primary_key();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(null_object_ptr_t) const {
|
||||||
|
return empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const object_ptr &other) const { return !operator==(other); }
|
||||||
|
bool operator!=(null_object_ptr_t) const { return !empty(); }
|
||||||
|
|
||||||
|
using value_type = Type;
|
||||||
|
|
||||||
|
Type *operator->() const {
|
||||||
|
return checked_get();
|
||||||
|
}
|
||||||
|
|
||||||
|
Type &operator*() {
|
||||||
|
return *checked_get();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type &operator*() const {
|
||||||
|
return *checked_get();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool empty() const {
|
||||||
|
return proxy_ == nullptr || proxy_->empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
Type *get() const {
|
||||||
|
return proxy_ ? proxy_->pointer() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::shared_ptr<Type> object() const {
|
||||||
|
return proxy_ ? proxy_->object() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
proxy_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset(std::shared_ptr<object_proxy<Type>> proxy) {
|
||||||
|
proxy_ = std::move(proxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::shared_ptr<object_proxy<Type>> proxy() const {
|
||||||
|
return proxy_;
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit operator bool() const {
|
||||||
|
return valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool valid() const {
|
||||||
|
return proxy_ != nullptr && !proxy_->empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool has_primary_key() const {
|
||||||
|
return proxy_ != nullptr && proxy_->has_primary_key();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] utils::identifier primary_key() const {
|
||||||
|
return proxy_ ? proxy_->primary_key() : utils::identifier{};
|
||||||
|
}
|
||||||
|
|
||||||
|
void primary_key(const utils::identifier &pk) {
|
||||||
|
ensure_proxy();
|
||||||
|
proxy_->primary_key(pk);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool is_persistent() const {
|
||||||
|
return proxy_ != nullptr && proxy_->is_persistent();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool is_transient() const {
|
||||||
|
return proxy_ != nullptr && proxy_->is_transient();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool is_detached() const {
|
||||||
|
return proxy_ != nullptr && proxy_->is_detached();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool is_removed() const {
|
||||||
|
return proxy_ != nullptr && proxy_->is_removed();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool is_state(const object_state state) const {
|
||||||
|
return proxy_ != nullptr && proxy_->is_state(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void change_state(object_state s) const {
|
||||||
|
if (proxy_) {
|
||||||
|
proxy_->change_state(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool has_primary_key() const { return ptr_->has_primary_key(); }
|
|
||||||
[[nodiscard]] const utils::identifier& primary_key() const { return ptr_->primary_key(); }
|
|
||||||
void primary_key(const utils::identifier &pk) { ptr_->primary_key(pk); }
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<object_proxy<Type>> ptr_{};
|
Type *checked_get() const {
|
||||||
|
auto *ptr = get();
|
||||||
|
if (!ptr) {
|
||||||
|
throw std::runtime_error("Cannot dereference empty object_ptr");
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ensure_proxy() {
|
||||||
|
if (!proxy_) {
|
||||||
|
proxy_ = std::make_shared<object_proxy<Type>>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<object_proxy<Type>> proxy_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename>
|
template<typename>
|
||||||
struct is_object_ptr : std::false_type
|
struct is_object_ptr : std::false_type {
|
||||||
{};
|
};
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
struct is_object_ptr<object_ptr<Type>> : std::true_type
|
struct is_object_ptr<object_ptr<Type> > : std::true_type {
|
||||||
{};
|
};
|
||||||
|
|
||||||
|
template<class Type, typename... Args>
|
||||||
|
object_ptr<Type> make_object(Args &&... args) {
|
||||||
|
return object_ptr<Type>(std::make_shared<Type>(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //OBJECT_PTR_HPP
|
#endif //OBJECT_PTR_HPP
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#ifndef MATADOR_OBJECT_LOADER_HPP
|
||||||
|
#define MATADOR_OBJECT_LOADER_HPP
|
||||||
|
|
||||||
|
#include "matador/object/abstract_type_resolver.hpp"
|
||||||
|
#include "matador/object/abstract_joined_resolver.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace matador::utils {
|
||||||
|
class identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace matador::object {
|
||||||
|
template<typename Type>
|
||||||
|
class object_resolver : public abstract_type_resolver {
|
||||||
|
public:
|
||||||
|
object_resolver() : abstract_type_resolver(typeid(Type)) {}
|
||||||
|
|
||||||
|
virtual std::shared_ptr<Type> resolve(const utils::identifier& id) = 0;
|
||||||
|
};
|
||||||
|
template<typename Type>
|
||||||
|
class joined_object_resolver : public abstract_joined_resolver, public object_resolver<Type> {
|
||||||
|
public:
|
||||||
|
joined_object_resolver(const std::type_index& root_type, const std::string& join_column)
|
||||||
|
: abstract_joined_resolver(root_type, typeid(Type), join_column) {}
|
||||||
|
|
||||||
|
std::shared_ptr<Type> resolve(const utils::identifier& id) override = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif //MATADOR_OBJECT_LOADER_HPP
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef MATADOR_OBJECT_RESOLVER_FACTORY_HPP
|
||||||
|
#define MATADOR_OBJECT_RESOLVER_FACTORY_HPP
|
||||||
|
|
||||||
|
#include "matador/object/abstract_type_resolver_factory.hpp"
|
||||||
|
#include "matador/object/object_resolver.hpp"
|
||||||
|
|
||||||
|
namespace matador::object {
|
||||||
|
class object_resolver_factory : public abstract_type_resolver_factory {
|
||||||
|
public:
|
||||||
|
template<class Type>
|
||||||
|
[[nodiscard]] std::shared_ptr<object_resolver<Type>> resolver() const {
|
||||||
|
const auto res = acquire_object_resolver(std::type_index(typeid(Type)));
|
||||||
|
if (!res) {
|
||||||
|
return std::dynamic_pointer_cast<object_resolver<Type>>(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::dynamic_pointer_cast<object_resolver<Type>>(res);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif //MATADOR_OBJECT_RESOLVER_FACTORY_HPP
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
#ifndef MATADOR_OBSERVER_HPP
|
||||||
|
#define MATADOR_OBSERVER_HPP
|
||||||
|
|
||||||
|
#include <typeindex>
|
||||||
|
|
||||||
|
namespace matador::object {
|
||||||
|
class repository_node;
|
||||||
|
|
||||||
|
class abstract_observer {
|
||||||
|
public:
|
||||||
|
virtual ~abstract_observer() = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Constructs a basic_object_store_observer for the
|
||||||
|
* give std::type_index.
|
||||||
|
*
|
||||||
|
* @param ti type index of the observer
|
||||||
|
*/
|
||||||
|
explicit abstract_observer(const std::type_index &ti);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Return the type index of the observer.
|
||||||
|
*
|
||||||
|
* @return The type index of the observer.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] const std::type_index& index() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::type_index type_index_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class observer
|
||||||
|
* @tparam Type Type of the observer
|
||||||
|
* @brief Base class for typed observer classes
|
||||||
|
*
|
||||||
|
* When interested in observe
|
||||||
|
* - attach (prototype_node)
|
||||||
|
* - detach (prototype_node)
|
||||||
|
* - insert (an object)
|
||||||
|
* - update (an object)
|
||||||
|
* - delete (an object)
|
||||||
|
* actions an observer class instance must be
|
||||||
|
* registered within the repository.
|
||||||
|
* Use this class as a base class for all observer classes.
|
||||||
|
*/
|
||||||
|
template < class Type >
|
||||||
|
class observer : public abstract_observer {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Default constructor
|
||||||
|
*/
|
||||||
|
observer() : abstract_observer(std::type_index(typeid(Type))) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Called on repository_node attachment
|
||||||
|
*
|
||||||
|
* When a prototype node is attached to the repository,
|
||||||
|
* this is called after the attaching succeeded.
|
||||||
|
*
|
||||||
|
* @param node The attached repository_node
|
||||||
|
* @param prototype The prototype object of the attached node
|
||||||
|
*/
|
||||||
|
virtual void on_attach(const repository_node &node, const Type &prototype) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Called on repository_node detached
|
||||||
|
*
|
||||||
|
* When a prototype node is detached from the repository,
|
||||||
|
* this is called before the detaching succeeded.
|
||||||
|
*
|
||||||
|
* @param node The to be detached repository_node
|
||||||
|
* @param prototype The prototype object of the detached node
|
||||||
|
*/
|
||||||
|
virtual void on_detach(const repository_node &node, const Type &prototype) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Called on object insertion.
|
||||||
|
*
|
||||||
|
* Called when an object is inserted
|
||||||
|
* into the repository.
|
||||||
|
*
|
||||||
|
* @param obj The proxy of the inserted object.
|
||||||
|
*/
|
||||||
|
virtual void on_insert(const Type &obj) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Called on object update.
|
||||||
|
*
|
||||||
|
* Called when an object is updated
|
||||||
|
* in the repository.
|
||||||
|
*
|
||||||
|
* @param obj The proxy of the updated object.
|
||||||
|
*/
|
||||||
|
virtual void on_update(const Type &obj) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Called on object deletion.
|
||||||
|
*
|
||||||
|
* Called when an object is deleted
|
||||||
|
* from the repository.
|
||||||
|
*
|
||||||
|
* @param obj The proxy of the deleted object.
|
||||||
|
*/
|
||||||
|
virtual void on_delete(const Type &obj) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
template < class Type >
|
||||||
|
class null_observer : public observer<Type> {
|
||||||
|
public:
|
||||||
|
template < class OtherType >
|
||||||
|
explicit null_observer(const null_observer<OtherType> *) {}
|
||||||
|
void on_attach(const repository_node &, const Type &) const override {}
|
||||||
|
void on_detach(const repository_node &, const Type &) const override {}
|
||||||
|
void on_insert(Type &) override {}
|
||||||
|
void on_update(Type &) override {}
|
||||||
|
void on_delete(Type &) override {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif //MATADOR_OBSERVER_HPP
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
#ifndef MATADOR_PK_FIELD_LOCATOR_HPP
|
||||||
|
#define MATADOR_PK_FIELD_LOCATOR_HPP
|
||||||
|
|
||||||
|
#include "matador/utils/primary_key_attribute.hpp"
|
||||||
|
#include "matador/utils/field_attributes.hpp"
|
||||||
|
#include "matador/utils/foreign_attributes.hpp"
|
||||||
|
|
||||||
|
#include <variant>
|
||||||
|
#include <array>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace matador::object::detail {
|
||||||
|
using uuid16 = std::array<std::uint8_t, 16>;
|
||||||
|
using pk_value = std::variant<std::int64_t, std::string, uuid16>;
|
||||||
|
|
||||||
|
enum class pk_kind { integer, string, uuid };
|
||||||
|
|
||||||
|
struct pk_field_descriptor {
|
||||||
|
std::size_t offset{};
|
||||||
|
pk_kind kind{pk_kind::integer};
|
||||||
|
|
||||||
|
bool (*is_known_at)(const void* obj, std::size_t offset) = nullptr;
|
||||||
|
pk_value (*get_at)(const void* obj, std::size_t offset) = nullptr;
|
||||||
|
void (*set_at)(void* obj, std::size_t offset, const pk_value& v) = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
template < typename Type >
|
||||||
|
struct pk_field_locator {
|
||||||
|
Type *base{nullptr};
|
||||||
|
pk_field_descriptor desc{};
|
||||||
|
bool found{false};
|
||||||
|
|
||||||
|
explicit pk_field_locator (Type &obj)
|
||||||
|
: base(&obj) {}
|
||||||
|
|
||||||
|
template<typename BaseType>
|
||||||
|
static void on_base(const BaseType&) {}
|
||||||
|
template <typename PrimaryKeyType>
|
||||||
|
void on_primary_key(const char *, PrimaryKeyType &pk, const utils::primary_key_attribute & /*attr*/) {
|
||||||
|
// Offset bestimmen
|
||||||
|
const auto* obj_bytes = reinterpret_cast<std::uint8_t*>(base);
|
||||||
|
const auto* pk_bytes = reinterpret_cast<std::uint8_t*>(&pk);
|
||||||
|
desc.offset = static_cast<std::size_t>(pk_bytes - obj_bytes);
|
||||||
|
if constexpr (std::is_integral_v<PrimaryKeyType> || std::is_enum_v<PrimaryKeyType>) {
|
||||||
|
desc.kind = pk_kind::integer;
|
||||||
|
|
||||||
|
desc.is_known_at = [](void *obj, const std::size_t off) -> bool {
|
||||||
|
auto *p = reinterpret_cast<PrimaryKeyType *>(static_cast<std::uint8_t *>(obj) + off);
|
||||||
|
return *p != PrimaryKeyType{};
|
||||||
|
};
|
||||||
|
|
||||||
|
desc.get_at = [](void *obj, const std::size_t off) -> pk_value {
|
||||||
|
auto *p = reinterpret_cast<PrimaryKeyType *>(static_cast<std::uint8_t *>(obj) + off);
|
||||||
|
return static_cast<std::int64_t>(*p);
|
||||||
|
};
|
||||||
|
|
||||||
|
desc.set_at = [](void *obj, const std::size_t off, const pk_value &v) {
|
||||||
|
auto *p = reinterpret_cast<PrimaryKeyType *>(static_cast<std::uint8_t *>(obj) + off);
|
||||||
|
if (auto *i = std::get_if<std::int64_t>(&v)) {
|
||||||
|
*p = static_cast<PrimaryKeyType>(*i);
|
||||||
|
} else {
|
||||||
|
throw std::logic_error("PK type mismatch: expected integer");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else if constexpr (std::is_same_v<PrimaryKeyType, std::string>) {
|
||||||
|
desc.kind = pk_kind::string;
|
||||||
|
|
||||||
|
desc.is_known_at = [](void *obj, const std::size_t off) -> bool {
|
||||||
|
const auto *p = reinterpret_cast<std::string *>(static_cast<std::uint8_t *>(obj) + off);
|
||||||
|
return !p->empty();
|
||||||
|
};
|
||||||
|
|
||||||
|
desc.get_at = [](void *obj, const std::size_t off) -> pk_value {
|
||||||
|
auto *p = reinterpret_cast<std::string *>(static_cast<std::uint8_t *>(obj) + off);
|
||||||
|
return *p;
|
||||||
|
};
|
||||||
|
|
||||||
|
desc.set_at = [](void *obj, const std::size_t off, const pk_value &v) {
|
||||||
|
auto *p = reinterpret_cast<std::string *>(static_cast<std::uint8_t *>(obj) + off);
|
||||||
|
if (auto *s = std::get_if<std::string>(&v)) {
|
||||||
|
*p = *s;
|
||||||
|
} else {
|
||||||
|
throw std::logic_error("PK type mismatch: expected string");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else if constexpr (std::is_same_v<PrimaryKeyType, uuid16>) {
|
||||||
|
desc.kind = pk_kind::uuid;
|
||||||
|
|
||||||
|
desc.is_known_at = [](void *obj, const std::size_t off) -> bool {
|
||||||
|
const auto *p = reinterpret_cast<uuid16 *>(static_cast<std::uint8_t *>(obj) + off);
|
||||||
|
// “unknown” = all zeros
|
||||||
|
for (const auto b: *p) {
|
||||||
|
if (b != 0) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
desc.get_at = [](void *obj, const std::size_t off) -> pk_value {
|
||||||
|
auto *p = reinterpret_cast<uuid16 *>(static_cast<std::uint8_t *>(obj) + off);
|
||||||
|
return *p;
|
||||||
|
};
|
||||||
|
|
||||||
|
desc.set_at = [](void *obj, const std::size_t off, const pk_value &v) {
|
||||||
|
auto *p = reinterpret_cast<uuid16 *>(static_cast<std::uint8_t *>(obj) + off);
|
||||||
|
if (auto *u = std::get_if<uuid16>(&v)) {
|
||||||
|
*p = *u;
|
||||||
|
} else {
|
||||||
|
throw std::logic_error("PK type mismatch: expected uuid16");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
throw std::logic_error("Unsupported primary key field type");
|
||||||
|
}
|
||||||
|
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
static void on_revision(const char *, std::uint64_t &) {}
|
||||||
|
template <typename V>
|
||||||
|
static void on_attribute(const char *, V &, const utils::field_attributes &/*attr*/) {}
|
||||||
|
template <typename Pointer>
|
||||||
|
static void on_belongs_to(const char *, Pointer &, const utils::foreign_attributes &) {}
|
||||||
|
template <typename Pointer>
|
||||||
|
static void on_has_one(const char *, Pointer &, const char * /*join_column*/, const utils::foreign_attributes &) {}
|
||||||
|
template <typename Container>
|
||||||
|
static void on_has_many(const char *, Container &, const char *, const utils::foreign_attributes &) {}
|
||||||
|
template <typename Container>
|
||||||
|
static void on_has_many_to_many(const char *, Container &, const char *, const char *,const utils::foreign_attributes &) {}
|
||||||
|
template <typename Container>
|
||||||
|
static void on_has_many_to_many(const char *, Container &, const utils::foreign_attributes &) {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif //MATADOR_PK_FIELD_LOCATOR_HPP
|
||||||
@@ -43,8 +43,10 @@ public:
|
|||||||
return resolver.resolve(obj);
|
return resolver.resolve(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename BaseType>
|
||||||
|
static void on_base(const BaseType&) {}
|
||||||
template < class Type >
|
template < class Type >
|
||||||
void on_primary_key(const char *id, Type &pk, const utils::primary_key_attribute& attr = utils::default_pk_attributes) {
|
void on_primary_key(const char *id, Type &pk, const utils::primary_key_attribute& attr) {
|
||||||
primary_key_info_.pk_column_name = id;
|
primary_key_info_.pk_column_name = id;
|
||||||
primary_key_info_.type = utils::data_type_traits<Type>::type(attr.size());
|
primary_key_info_.type = utils::data_type_traits<Type>::type(attr.size());
|
||||||
primary_key_info_.pk = pk;
|
primary_key_info_.pk = pk;
|
||||||
@@ -52,11 +54,11 @@ public:
|
|||||||
|
|
||||||
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
|
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
static void on_attribute(const char * /*id*/, Type &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
static void on_attribute(const char * /*id*/, Type &/*val*/, const utils::field_attributes &/*attr*/) {}
|
||||||
template<class Pointer>
|
template<class Pointer>
|
||||||
static void on_belongs_to(const char * /*id*/, Pointer &/*val*/, const utils::foreign_attributes &/*attr*/) {}
|
static void on_belongs_to(const char * /*id*/, Pointer &/*val*/, const utils::foreign_attributes &/*attr*/) {}
|
||||||
template<class Pointer>
|
template<class Pointer>
|
||||||
static void on_has_one(const char * /*id*/, Pointer &/*val*/, const utils::foreign_attributes &/*attr*/) {}
|
static void on_has_one(const char * /*id*/, Pointer &/*val*/, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {}
|
||||||
template<class ContainerType>
|
template<class ContainerType>
|
||||||
static void on_has_many(const char * /*id*/, ContainerType &/*col*/, const char *, const utils::foreign_attributes &/*attr*/) {}
|
static void on_has_many(const char * /*id*/, ContainerType &/*col*/, const char *, const utils::foreign_attributes &/*attr*/) {}
|
||||||
template<class ContainerType>
|
template<class ContainerType>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#ifndef RELATION_COMPLETER_HPP
|
#ifndef RELATION_COMPLETER_HPP
|
||||||
#define RELATION_COMPLETER_HPP
|
#define RELATION_COMPLETER_HPP
|
||||||
|
|
||||||
#include "matador/object/internal/shadow_repository.hpp"
|
#include "matador/object/basic_repository.hpp"
|
||||||
|
#include "matador/object/foreign_node_completer.hpp"
|
||||||
#include "matador/object/many_to_many_relation.hpp"
|
#include "matador/object/many_to_many_relation.hpp"
|
||||||
#include "matador/object/join_columns_collector.hpp"
|
#include "matador/object/join_columns_collector.hpp"
|
||||||
#include "matador/object/object_ptr.hpp"
|
|
||||||
#include "matador/object/repository_node.hpp"
|
#include "matador/object/repository_node.hpp"
|
||||||
|
|
||||||
#include "matador/logger/log_manager.hpp"
|
#include "matador/logger/log_manager.hpp"
|
||||||
@@ -28,20 +28,22 @@ public:
|
|||||||
return finder.found_;
|
return finder.found_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename BaseType>
|
||||||
|
static void on_base(const BaseType&) {}
|
||||||
template<class PrimaryKeyType>
|
template<class PrimaryKeyType>
|
||||||
static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {}
|
static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, const utils::primary_key_attribute& /*attr*/) {}
|
||||||
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
|
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
|
||||||
template<typename AttributeType>
|
template<typename AttributeType>
|
||||||
static void on_attribute(const char * /*id*/, AttributeType &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
static void on_attribute(const char * /*id*/, AttributeType &/*val*/, const utils::field_attributes &/*attr*/) {}
|
||||||
template<typename AttributeType>
|
template<typename AttributeType>
|
||||||
static void on_attribute(const char * /*id*/, std::optional<AttributeType> &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
static void on_attribute(const char * /*id*/, std::optional<AttributeType> &/*val*/, const utils::field_attributes &/*attr*/) {}
|
||||||
|
|
||||||
template<class ForeignPointerType>
|
template<class ForeignPointerType>
|
||||||
void on_belongs_to(const char *id, ForeignPointerType &/*obj*/, const utils::foreign_attributes &/*attr*/) {
|
void on_belongs_to(const char *id, ForeignPointerType &/*obj*/, const utils::foreign_attributes &/*attr*/) {
|
||||||
found_ = requested_join_column_ == id;
|
found_ = requested_join_column_ == id;
|
||||||
}
|
}
|
||||||
template<class ForeignPointerType>
|
template<class ForeignPointerType>
|
||||||
static void on_has_one(const char * /*id*/, ForeignPointerType &/*obj*/, const utils::foreign_attributes &/*attr*/) {}
|
static void on_has_one(const char * /*id*/, ForeignPointerType &/*obj*/, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {}
|
||||||
|
|
||||||
template<class CollectionType>
|
template<class CollectionType>
|
||||||
static void on_has_many(const char * /*id*/, CollectionType &, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {}
|
static void on_has_many(const char * /*id*/, CollectionType &, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {}
|
||||||
@@ -91,33 +93,31 @@ private:
|
|||||||
* no has_many or belongs_to
|
* no has_many or belongs_to
|
||||||
* invalid relation -> error
|
* invalid relation -> error
|
||||||
*/
|
*/
|
||||||
template<typename Type>
|
template<typename Type, template<typename> typename... Observers>
|
||||||
class relation_completer final {
|
class relation_completer final {
|
||||||
private:
|
|
||||||
using node_ptr = std::shared_ptr<repository_node>;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using endpoint_ptr = std::shared_ptr<relation_endpoint>;
|
using endpoint_ptr = std::shared_ptr<relation_endpoint>;
|
||||||
|
|
||||||
static void complete(const std::shared_ptr<repository_node> &node) {
|
static void complete(repository_node *node, const std::vector<std::unique_ptr<observer<Type>>> &observers) {
|
||||||
internal::shadow_repository shadow(node->repo_);
|
relation_completer completer(node->repo_, observers);
|
||||||
relation_completer completer(shadow);
|
|
||||||
|
|
||||||
completer.complete_node_relations(node);
|
completer.complete_node_relations(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename BaseType>
|
||||||
|
static void on_base(const BaseType&) {}
|
||||||
template<class PrimaryKeyType>
|
template<class PrimaryKeyType>
|
||||||
static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {}
|
static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, const utils::primary_key_attribute& /*attr*/) {}
|
||||||
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
|
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
|
||||||
template<typename AttributeType>
|
template<typename AttributeType>
|
||||||
static void on_attribute(const char * /*id*/, AttributeType &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
static void on_attribute(const char * /*id*/, AttributeType &/*val*/, const utils::field_attributes &/*attr*/) {}
|
||||||
template<typename AttributeType>
|
template<typename AttributeType>
|
||||||
static void on_attribute(const char * /*id*/, std::optional<AttributeType> &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
static void on_attribute(const char * /*id*/, std::optional<AttributeType> &/*val*/, const utils::field_attributes &/*attr*/) {}
|
||||||
|
|
||||||
template<class ForeignPointerType>
|
template<class ForeignPointerType>
|
||||||
void on_belongs_to(const char *id, ForeignPointerType &obj, const utils::foreign_attributes &attr);
|
void on_belongs_to(const char *id, ForeignPointerType &obj, const utils::foreign_attributes &attr);
|
||||||
template<class ForeignPointerType>
|
template<class ForeignPointerType>
|
||||||
void on_has_one(const char * /*id*/, ForeignPointerType &/*obj*/, const utils::foreign_attributes &/*attr*/);
|
void on_has_one(const char * /*id*/, ForeignPointerType &/*obj*/, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/);
|
||||||
|
|
||||||
template<class CollectionType>
|
template<class CollectionType>
|
||||||
void on_has_many(const char *id, CollectionType &, const char *join_column, const utils::foreign_attributes &attr, std::enable_if_t<is_object_ptr<typename CollectionType::value_type>::value> * = nullptr);
|
void on_has_many(const char *id, CollectionType &, const char *join_column, const utils::foreign_attributes &attr, std::enable_if_t<is_object_ptr<typename CollectionType::value_type>::value> * = nullptr);
|
||||||
@@ -130,12 +130,12 @@ public:
|
|||||||
void on_has_many_to_many(const char *id, CollectionType &collection, const utils::foreign_attributes &attr);
|
void on_has_many_to_many(const char *id, CollectionType &collection, const utils::foreign_attributes &attr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit relation_completer(internal::shadow_repository &shadow)
|
explicit relation_completer(basic_repository &repo, const std::vector<std::unique_ptr<observer<Type>>>& observers)
|
||||||
: schema_(shadow)
|
: repo_(repo)
|
||||||
, log_(logger::create_logger("relation_completer")) {
|
, log_(logger::create_logger("relation_completer"))
|
||||||
}
|
, observers_(observers) {}
|
||||||
|
|
||||||
void complete_node_relations(const std::shared_ptr<repository_node> &node) {
|
void complete_node_relations(repository_node* node) {
|
||||||
nodes_.push(node);
|
nodes_.push(node);
|
||||||
|
|
||||||
Type obj;
|
Type obj;
|
||||||
@@ -143,21 +143,27 @@ private:
|
|||||||
nodes_.pop();
|
nodes_.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename NodeType>
|
||||||
|
void attach_relation_node(const std::string &name, const std::string &join_column, const std::string &inverse_join_column);
|
||||||
|
|
||||||
static void register_relation_endpoints(const endpoint_ptr &endpoint,
|
static void register_relation_endpoints(const endpoint_ptr &endpoint,
|
||||||
const endpoint_ptr &other_endpoint);
|
const endpoint_ptr &other_endpoint);
|
||||||
static void link_relation_endpoints(const endpoint_ptr &endpoint,
|
static void link_relation_endpoints(const endpoint_ptr &endpoint,
|
||||||
const endpoint_ptr &other_endpoint);
|
const endpoint_ptr &other_endpoint);
|
||||||
|
|
||||||
|
[[nodiscard]] repository_node* find_node(const std::type_index &ti) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::stack<node_ptr> nodes_;
|
std::stack<repository_node*> nodes_;
|
||||||
internal::shadow_repository &schema_;
|
basic_repository &repo_;
|
||||||
logger::logger log_;
|
logger::logger log_;
|
||||||
join_columns_collector join_columns_collector_{};
|
join_columns_collector join_columns_collector_{};
|
||||||
|
const std::vector<std::unique_ptr<observer<Type>>>& observers_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type, template<typename> typename... Observers>
|
||||||
template<class CollectionType>
|
template<class CollectionType>
|
||||||
void relation_completer<Type>::on_has_many(const char *id, CollectionType &,
|
void relation_completer<Type, Observers...>::on_has_many(const char *id, CollectionType &,
|
||||||
const char *join_column,
|
const char *join_column,
|
||||||
const utils::foreign_attributes &,
|
const utils::foreign_attributes &,
|
||||||
std::enable_if_t<is_object_ptr<typename CollectionType::value_type>::value> * /*unused*/) {
|
std::enable_if_t<is_object_ptr<typename CollectionType::value_type>::value> * /*unused*/) {
|
||||||
@@ -166,131 +172,98 @@ void relation_completer<Type>::on_has_many(const char *id, CollectionType &,
|
|||||||
using relation_value_type = many_to_many_relation<Type, value_type>;
|
using relation_value_type = many_to_many_relation<Type, value_type>;
|
||||||
|
|
||||||
// Check if the object_ptr type is already inserted in the schema (by id)
|
// Check if the object_ptr type is already inserted in the schema (by id)
|
||||||
auto result = schema_.find_node(typeid(value_type));
|
const auto foreign_node = find_node(typeid(value_type));
|
||||||
if (!result) {
|
if (!foreign_node) {
|
||||||
// Todo: throw internal error or attach node
|
// Todo: throw internal error or attach node
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto foreign_node = result.value();
|
|
||||||
// has foreign node corresponding join column (join_column)
|
// has foreign node corresponding join column (join_column)
|
||||||
|
|
||||||
if (const auto it = foreign_node->info_->find_relation_endpoint(typeid(Type)); it != foreign_node->info().endpoint_end()) {
|
if (const auto it = foreign_node->info_->find_relation_endpoint(typeid(Type)); it != foreign_node->info().endpoint_end()) {
|
||||||
// corresponding belongs_to is available and was called (has_many <-> belongs_to)
|
// corresponding belongs_to is available and was called (has_many <-> belongs_to)
|
||||||
// complete the relation
|
// complete the relation
|
||||||
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HAS_MANY, foreign_node);
|
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasMany, *foreign_node);
|
||||||
nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
|
nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
|
||||||
link_relation_endpoints(local_endpoint, it->second);
|
link_relation_endpoints(local_endpoint, it->second);
|
||||||
} else if (join_column_finder::has_join_column<value_type>(join_column)) {
|
} else if (join_column_finder::has_join_column<value_type>(join_column)) {
|
||||||
// corresponding belongs_to is available but was not called (has_many <-> belongs_to)
|
// corresponding belongs_to is available but was not called (has_many <-> belongs_to)
|
||||||
// prepare the relation
|
// prepare the relation
|
||||||
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HAS_MANY, foreign_node);
|
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasMany, *foreign_node);
|
||||||
nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
|
nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
|
||||||
} else {
|
} else {
|
||||||
// A relation table is necessary
|
// A relation table is necessary.
|
||||||
// Endpoint was not found.
|
// Endpoint was not found.
|
||||||
// Always attach a many-to-many relation type. If later a
|
// Always attach a many-to-many relation type. If later a
|
||||||
// belongs-to relation handles this relation, the many-to-many
|
// belongs-to relation handles this relation, the many-to-many
|
||||||
// relation is maybe detached.
|
// relation is maybe detached.
|
||||||
log_.debug("node '%s' has has many foreign keys '%s' mapped by '%s'", nodes_.top()->name().c_str(), id, join_column);
|
log_.debug("node '%s' has has many foreign keys '%s' mapped by '%s'", nodes_.top()->name().c_str(), id, join_column);
|
||||||
result = repository_node::make_relation_node<relation_value_type>(
|
auto node = repository_node::make_node<relation_value_type>(repo_, id, [join_column] {
|
||||||
schema_.repo(), id, [join_column] {
|
|
||||||
return std::make_unique<relation_value_type>("id", join_column);
|
return std::make_unique<relation_value_type>("id", join_column);
|
||||||
});
|
}, {});
|
||||||
|
const auto result = repo_.attach_node(node.release(), "");
|
||||||
if (!result) {
|
if (!result) {
|
||||||
// Todo: throw internal error
|
// Todo: throw internal error
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
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>("id", relation_type::BELONGS_TO, nodes_.top());
|
auto *attached_node = result.value();
|
||||||
|
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasMany, *attached_node);
|
||||||
|
const auto foreign_endpoint = std::make_shared<relation_endpoint>("id", relation_type::BelongsTo, *nodes_.top());
|
||||||
nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
|
nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
|
||||||
result.value()->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint);
|
attached_node->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint);
|
||||||
link_relation_endpoints(local_endpoint, foreign_endpoint);
|
link_relation_endpoints(local_endpoint, foreign_endpoint);
|
||||||
|
|
||||||
const auto foreign_value_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BELONGS_TO, foreign_node);
|
const auto foreign_value_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BelongsTo, *foreign_node);
|
||||||
result.value()->info_->register_relation_endpoint(typeid(value_type), foreign_value_endpoint);
|
attached_node->info_->register_relation_endpoint(typeid(value_type), foreign_value_endpoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type, template<typename> typename... Observers>
|
||||||
template<class CollectionType>
|
template<class CollectionType>
|
||||||
void relation_completer<Type>::on_has_many(const char *id, CollectionType &, const char *join_column,
|
void relation_completer<Type, Observers...>::on_has_many(const char *id, CollectionType &, const char *join_column,
|
||||||
const utils::foreign_attributes &,
|
const utils::foreign_attributes &,
|
||||||
std::enable_if_t<!is_object_ptr<typename CollectionType::value_type>::value>
|
std::enable_if_t<!is_object_ptr<typename CollectionType::value_type>::value>* /*unused*/) {
|
||||||
* /*unused*/) {
|
|
||||||
using value_type = typename CollectionType::value_type;
|
using value_type = typename CollectionType::value_type;
|
||||||
using relation_value_type = many_to_relation<Type, value_type>;
|
using relation_value_type = many_to_relation<Type, value_type>;
|
||||||
|
|
||||||
const auto result = repository_node::make_relation_node<relation_value_type>(
|
auto observers = internal::observer_list_copy_creator<Type, relation_value_type, Observers...>::copy_create(observers_);
|
||||||
schema_.repo(), id, [join_column] {
|
|
||||||
return std::make_unique<relation_value_type>(join_column, "value");
|
|
||||||
});
|
|
||||||
|
|
||||||
|
auto node = repository_node::make_node<relation_value_type>(repo_, id, [join_column] {
|
||||||
|
return std::make_unique<relation_value_type>(join_column, "value");
|
||||||
|
}, std::move(observers));
|
||||||
|
const auto result = repo_.attach_node(node.release(), "");
|
||||||
if (!result) {
|
if (!result) {
|
||||||
// Todo: throw internal exception
|
// Todo: throw internal exception
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HAS_MANY, result.value());
|
auto *attached_node = result.value();
|
||||||
const auto foreign_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BELONGS_TO, nodes_.top());
|
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasMany, *attached_node);
|
||||||
|
const auto foreign_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BelongsTo, *nodes_.top());
|
||||||
|
|
||||||
nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
|
nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
|
||||||
result.value()->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint);
|
attached_node->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint);
|
||||||
link_relation_endpoints(local_endpoint, foreign_endpoint);
|
link_relation_endpoints(local_endpoint, foreign_endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type, template<typename> typename... Observers>
|
||||||
template<class CollectionType>
|
template<class CollectionType>
|
||||||
void relation_completer<Type>::on_has_many_to_many(const char *id,
|
void relation_completer<Type, Observers...>::on_has_many_to_many(const char *id,
|
||||||
CollectionType &/*collection*/,
|
CollectionType &/*collection*/,
|
||||||
const char *join_column,
|
const char *join_column,
|
||||||
const char *inverse_join_column,
|
const char *inverse_join_column,
|
||||||
const utils::foreign_attributes &/*attr*/) {
|
const utils::foreign_attributes &/*attr*/) {
|
||||||
using relation_value_type = many_to_many_relation<typename CollectionType::value_type::value_type, Type>;
|
if (!repo_.expecting_relation_node(id)) {
|
||||||
using value_type = typename CollectionType::value_type::value_type;
|
repo_.expect_relation_node(id, typeid(typename CollectionType::value_type::value_type));
|
||||||
|
} else {
|
||||||
// Check if the object_ptr type is already inserted in the schema (by id)
|
attach_relation_node<typename CollectionType::value_type::value_type>(id, join_column, inverse_join_column);
|
||||||
auto result = schema_.find_node(typeid(value_type));
|
repo_.remove_expected_relation_node(id);
|
||||||
if (!result) {
|
|
||||||
// Todo: throw internal error or attach node
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto foreign_node = result.value();
|
|
||||||
result = schema_.find_node(id);
|
|
||||||
if (!result) {
|
|
||||||
// Relation not found.
|
|
||||||
auto creator = [join_column, inverse_join_column] {
|
|
||||||
return std::make_unique<relation_value_type>(join_column, inverse_join_column);
|
|
||||||
};
|
|
||||||
|
|
||||||
result = repository_node::make_relation_node<relation_value_type>(schema_.repo(), id, std::move(creator));
|
|
||||||
if (!result) {
|
|
||||||
// Todo: throw internal error
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& node = result.value();
|
|
||||||
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HAS_MANY, node);
|
|
||||||
const auto join_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BELONGS_TO, nodes_.top());
|
|
||||||
const auto inverse_join_endpoint = std::make_shared<relation_endpoint>(inverse_join_column, relation_type::BELONGS_TO, foreign_node);
|
|
||||||
const auto foreign_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HAS_MANY, node);
|
|
||||||
// register relation endpoint in local node
|
|
||||||
nodes_.top()->info_->register_relation_endpoint(typeid(typename CollectionType::value_type::value_type), local_endpoint);
|
|
||||||
// register relation endpoint in foreign node
|
|
||||||
foreign_node->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint);
|
|
||||||
// register endpoints in relation node
|
|
||||||
node->info_->register_relation_endpoint(nodes_.top()->type_index(), join_endpoint);
|
|
||||||
node->info_->register_relation_endpoint(typeid(typename CollectionType::value_type::value_type), inverse_join_endpoint);
|
|
||||||
|
|
||||||
// link endpoints
|
|
||||||
link_relation_endpoints(local_endpoint, join_endpoint);
|
|
||||||
link_relation_endpoints(foreign_endpoint, inverse_join_endpoint);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type, template<typename> typename... Observers>
|
||||||
template<class CollectionType>
|
template<class CollectionType>
|
||||||
void relation_completer<Type>::on_has_many_to_many(const char *id,
|
void relation_completer<Type, Observers...>::on_has_many_to_many(const char *id,
|
||||||
CollectionType &collection,
|
CollectionType &collection,
|
||||||
const utils::foreign_attributes &attr) {
|
const utils::foreign_attributes &attr) {
|
||||||
const auto join_columns = join_columns_collector_.collect<typename CollectionType::value_type::value_type>();
|
const auto join_columns = join_columns_collector_.collect<typename CollectionType::value_type::value_type>();
|
||||||
@@ -302,55 +275,53 @@ void relation_completer<Type>::on_has_many_to_many(const char *id,
|
|||||||
attr);
|
attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type, template<typename> typename... Observers>
|
||||||
template<class ForeignPointerType>
|
template<class ForeignPointerType>
|
||||||
void relation_completer<Type>::on_has_one(const char *id,
|
void relation_completer<Type, Observers...>::on_has_one(const char *id,
|
||||||
ForeignPointerType &/*obj*/,
|
ForeignPointerType &/*obj*/,
|
||||||
|
const char * /*join_column*/,
|
||||||
const utils::foreign_attributes &/*attr*/) {
|
const utils::foreign_attributes &/*attr*/) {
|
||||||
using value_type = typename ForeignPointerType::value_type;
|
using value_type = typename ForeignPointerType::value_type;
|
||||||
const auto ti = std::type_index(typeid(value_type));
|
const auto foreign_node = find_node(typeid(value_type));
|
||||||
const auto result = schema_.find_node(ti);
|
if (!foreign_node) {
|
||||||
if (!result) {
|
// Todo: throw internal error or attach node
|
||||||
// Node was not found
|
|
||||||
// Todo: Throw internal error
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto local_it = nodes_.top()->info().find_relation_endpoint(typeid(value_type));
|
auto local_it = nodes_.top()->info().find_relation_endpoint(typeid(value_type));
|
||||||
if (local_it == nodes_.top()->info().endpoint_end()) {
|
if (local_it == nodes_.top()->info().endpoint_end()) {
|
||||||
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HAS_ONE, result.value());
|
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasOne, *foreign_node);
|
||||||
local_it = nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
|
local_it = nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
|
||||||
}
|
}
|
||||||
if (const auto foreign_it = result.value()->info().find_relation_endpoint(typeid(Type)); foreign_it != result.value()->info().endpoint_end()) {
|
if (const auto foreign_it = foreign_node->info().find_relation_endpoint(typeid(Type)); foreign_it != foreign_node->info().endpoint_end()) {
|
||||||
link_relation_endpoints(local_it->second, foreign_it->second);
|
link_relation_endpoints(local_it->second, foreign_it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type, template<typename> typename... Observers>
|
||||||
template<class ForeignPointerType>
|
template<class ForeignPointerType>
|
||||||
void relation_completer<Type>::on_belongs_to(const char *id,
|
void relation_completer<Type, Observers...>::on_belongs_to(const char *id,
|
||||||
ForeignPointerType & /*obj*/,
|
ForeignPointerType & /*obj*/,
|
||||||
const utils::foreign_attributes & /*attr*/) {
|
const utils::foreign_attributes & /*attr*/) {
|
||||||
using value_type = typename ForeignPointerType::value_type;
|
using value_type = typename ForeignPointerType::value_type;
|
||||||
const auto ti = std::type_index(typeid(value_type));
|
const auto ti = std::type_index(typeid(value_type));
|
||||||
auto result = schema_.find_node(ti);
|
const auto foreign_node = find_node(typeid(value_type));
|
||||||
if (!result) {
|
if (!foreign_node) {
|
||||||
// Type was not found
|
// Todo: throw internal error or attach node
|
||||||
// Todo: Throw internal error
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type was found
|
// Type was found
|
||||||
const auto &foreign_node = result.value();
|
|
||||||
// Check foreign node and relation endpoint
|
// Check foreign node and relation endpoint
|
||||||
if (const auto it = foreign_node->info_->find_relation_endpoint(nodes_.top()->type_index()); it != foreign_node->info().endpoint_end()) {
|
if (const auto it = foreign_node->info_->find_relation_endpoint(nodes_.top()->type_index()); it != foreign_node->info().endpoint_end()) {
|
||||||
// Found corresponding relation endpoint in the foreign node
|
// Found corresponding relation endpoint in the foreign node
|
||||||
if (it->second->is_has_one()) {
|
if (it->second->is_has_one()) {
|
||||||
const auto endpoint = std::make_shared<relation_endpoint>(id, relation_type::BELONGS_TO, foreign_node);
|
const auto endpoint = std::make_shared<relation_endpoint>(id, relation_type::BelongsTo, *foreign_node);
|
||||||
nodes_.top()->info_->register_relation_endpoint(ti, endpoint);
|
nodes_.top()->info_->register_relation_endpoint(ti, endpoint);
|
||||||
link_relation_endpoints(endpoint, it->second);
|
link_relation_endpoints(endpoint, it->second);
|
||||||
} else if (it->second->is_has_many()) {
|
} else if (it->second->is_has_many()) {
|
||||||
const auto endpoint = std::make_shared<relation_endpoint>(id, relation_type::BELONGS_TO, foreign_node);
|
const auto endpoint = std::make_shared<relation_endpoint>(id, relation_type::BelongsTo, *foreign_node);
|
||||||
nodes_.top()->info_->register_relation_endpoint(ti, endpoint);
|
nodes_.top()->info_->register_relation_endpoint(ti, endpoint);
|
||||||
link_relation_endpoints(endpoint, it->second);
|
link_relation_endpoints(endpoint, it->second);
|
||||||
} else if (it->second->foreign_endpoint()->node().type_index() == typeid(many_to_many_relation<Type, value_type>)) {
|
} else if (it->second->foreign_endpoint()->node().type_index() == typeid(many_to_many_relation<Type, value_type>)) {
|
||||||
@@ -359,32 +330,97 @@ void relation_completer<Type>::on_belongs_to(const char *id,
|
|||||||
// "belongs_to"-relation the "many_to_many_relation" can be removed
|
// "belongs_to"-relation the "many_to_many_relation" can be removed
|
||||||
// (detach), and the endpoints must be adjusted
|
// (detach), and the endpoints must be adjusted
|
||||||
const auto foreign_endpoint = it->second->foreign_endpoint();
|
const auto foreign_endpoint = it->second->foreign_endpoint();
|
||||||
const auto detach_result = schema_.detach_node(foreign_endpoint->node_);
|
const auto detach_result = repo_.detach(foreign_endpoint->node_);
|
||||||
foreign_endpoint->node_ = foreign_node;
|
foreign_endpoint->node_ = foreign_node;
|
||||||
// foreign_endpoint->node_ = nodes_.top();
|
|
||||||
nodes_.top()->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint);
|
nodes_.top()->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint);
|
||||||
} else {
|
} else {
|
||||||
// check type
|
// check type
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Relation node was not found, create only endpoint.
|
// Relation node was not found, create only endpoint.
|
||||||
const auto endpoint = std::make_shared<relation_endpoint>(id, relation_type::BELONGS_TO, foreign_node);
|
const auto endpoint = std::make_shared<relation_endpoint>(id, relation_type::BelongsTo, *foreign_node);
|
||||||
nodes_.top()->info_->register_relation_endpoint(ti, endpoint);
|
nodes_.top()->info_->register_relation_endpoint(ti, endpoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type, template<typename> typename... Observers>
|
||||||
void relation_completer<Type>::register_relation_endpoints(const endpoint_ptr &endpoint,
|
template<typename NodeType>
|
||||||
|
void relation_completer<Type, Observers...>::attach_relation_node(const std::string &name, const std::string &join_column, const std::string &inverse_join_column) {
|
||||||
|
using relation_value_type = many_to_many_relation<Type, NodeType>;
|
||||||
|
using value_type = NodeType;
|
||||||
|
|
||||||
|
// Check if the object_ptr type is already inserted in the schema (by id)
|
||||||
|
const auto foreign_node = find_node(typeid(value_type));
|
||||||
|
if (!foreign_node) {
|
||||||
|
// Todo: throw internal error or attach node
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const auto it = repo_.find_node(name); it != repo_.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Relation does not exist. Create it.
|
||||||
|
auto creator = [join_column, inverse_join_column] {
|
||||||
|
return std::make_unique<relation_value_type>(join_column, inverse_join_column);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto observers = internal::observer_list_copy_creator<Type, relation_value_type, Observers...>::copy_create(observers_);
|
||||||
|
|
||||||
|
auto node = repository_node::make_relation_node<relation_value_type>(repo_,
|
||||||
|
name,
|
||||||
|
join_column,
|
||||||
|
inverse_join_column,
|
||||||
|
std::move(creator),
|
||||||
|
std::move(observers));
|
||||||
|
auto result = repo_.attach_node(node.release(), "");
|
||||||
|
if (!result) {
|
||||||
|
// Todo: throw internal error
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *attached_node = result.value();
|
||||||
|
foreign_node_completer<relation_value_type>::complete(result.value(), {});
|
||||||
|
|
||||||
|
const auto local_endpoint = std::make_shared<relation_endpoint>(name, relation_type::HasMany, *attached_node);
|
||||||
|
const auto join_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BelongsTo, *nodes_.top());
|
||||||
|
const auto inverse_join_endpoint = std::make_shared<relation_endpoint>(inverse_join_column, relation_type::BelongsTo, *foreign_node);
|
||||||
|
const auto foreign_endpoint = std::make_shared<relation_endpoint>(name, relation_type::HasMany, *attached_node);
|
||||||
|
// register relation endpoint in local node
|
||||||
|
nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
|
||||||
|
// register relation endpoint in foreign node
|
||||||
|
foreign_node->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint);
|
||||||
|
// register endpoints in relation node
|
||||||
|
attached_node->info_->register_relation_endpoint(nodes_.top()->type_index(), join_endpoint);
|
||||||
|
attached_node->info_->register_relation_endpoint(typeid(value_type), inverse_join_endpoint);
|
||||||
|
// link endpoints
|
||||||
|
link_relation_endpoints(local_endpoint, join_endpoint);
|
||||||
|
link_relation_endpoints(foreign_endpoint, inverse_join_endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Type, template<typename> typename... Observers>
|
||||||
|
void relation_completer<Type, Observers...>::register_relation_endpoints(const endpoint_ptr &endpoint,
|
||||||
const endpoint_ptr &other_endpoint) {
|
const endpoint_ptr &other_endpoint) {
|
||||||
endpoint->node_->info_->register_relation_endpoint(other_endpoint->node_->type_index(), endpoint);
|
endpoint->node().info_->register_relation_endpoint(other_endpoint->node().type_index(), endpoint);
|
||||||
other_endpoint->node_->info_->register_relation_endpoint(endpoint->node_->type_index(), other_endpoint);
|
other_endpoint->node().info_->register_relation_endpoint(endpoint->node().type_index(), other_endpoint);
|
||||||
link_relation_endpoints(endpoint, other_endpoint);
|
link_relation_endpoints(endpoint, other_endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type, template<typename> typename... Observers>
|
||||||
void relation_completer<Type>::link_relation_endpoints(const endpoint_ptr &endpoint, const endpoint_ptr &other_endpoint) {
|
void relation_completer<Type, Observers...>::link_relation_endpoints(const endpoint_ptr &endpoint, const endpoint_ptr &other_endpoint) {
|
||||||
endpoint->link_foreign_endpoint(other_endpoint);
|
endpoint->link_foreign_endpoint(other_endpoint);
|
||||||
other_endpoint->link_foreign_endpoint(endpoint);
|
other_endpoint->link_foreign_endpoint(endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Type, template <typename> class ... Observers>
|
||||||
|
repository_node* relation_completer<Type, Observers...>::find_node(const std::type_index &ti) const {
|
||||||
|
if (const auto it = repo_.find_node(ti); it != repo_.end()) {
|
||||||
|
return it.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!repo_.is_node_announced(ti)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return repo_.announce_node(ti);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif //RELATION_COMPLETER_HPP
|
#endif //RELATION_COMPLETER_HPP
|
||||||
|
|||||||
@@ -11,28 +11,26 @@ namespace matador::object {
|
|||||||
class repository_node;
|
class repository_node;
|
||||||
|
|
||||||
enum class relation_type : uint8_t {
|
enum class relation_type : uint8_t {
|
||||||
BELONGS_TO,
|
BelongsTo,
|
||||||
HAS_ONE,
|
HasOne,
|
||||||
HAS_MANY
|
HasMany
|
||||||
};
|
};
|
||||||
|
|
||||||
static const utils::enum_mapper<relation_type> relation_type_enum({
|
static const utils::enum_mapper<relation_type> relation_type_enum({
|
||||||
{ relation_type::BELONGS_TO, "belongs_to" },
|
{ relation_type::BelongsTo, "belongs_to" },
|
||||||
{ relation_type::HAS_ONE, "has_one" },
|
{ relation_type::HasOne, "has_one" },
|
||||||
{ relation_type::HAS_MANY, "has_many" },
|
{ relation_type::HasMany, "has_many" },
|
||||||
});
|
});
|
||||||
|
|
||||||
class relation_endpoint {
|
class relation_endpoint {
|
||||||
public:
|
public:
|
||||||
relation_endpoint(std::string field_name, relation_type type, const std::shared_ptr<repository_node>& node);
|
relation_endpoint(std::string field_name, relation_type type, repository_node& node);
|
||||||
|
|
||||||
[[nodiscard]] std::string field_name() const;
|
[[nodiscard]] std::string field_name() const;
|
||||||
[[nodiscard]] relation_type type() const;
|
[[nodiscard]] relation_type type() const;
|
||||||
[[nodiscard]] std::string type_name() const;
|
[[nodiscard]] std::string type_name() const;
|
||||||
[[nodiscard]] const repository_node& node() const;
|
[[nodiscard]] const repository_node& node() const;
|
||||||
|
|
||||||
[[nodiscard]] std::shared_ptr<repository_node> node_ptr() const;
|
|
||||||
|
|
||||||
[[nodiscard]] bool is_has_one() const;
|
[[nodiscard]] bool is_has_one() const;
|
||||||
[[nodiscard]] bool is_has_many() const;
|
[[nodiscard]] bool is_has_many() const;
|
||||||
[[nodiscard]] bool is_belongs_to() const;
|
[[nodiscard]] bool is_belongs_to() const;
|
||||||
@@ -41,13 +39,15 @@ public:
|
|||||||
void link_foreign_endpoint(const std::shared_ptr<relation_endpoint>& endpoint);
|
void link_foreign_endpoint(const std::shared_ptr<relation_endpoint>& endpoint);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename Type>
|
template<typename Type, template<typename> typename... Observers>
|
||||||
friend class relation_completer;
|
friend class relation_completer;
|
||||||
|
template<typename Type, template<typename> typename ...Observers>
|
||||||
|
friend class foreign_node_completer;
|
||||||
|
|
||||||
std::string field_name_;
|
std::string field_name_;
|
||||||
relation_type type_;
|
relation_type type_;
|
||||||
std::shared_ptr<repository_node> node_;
|
repository_node *node_{nullptr};
|
||||||
std::shared_ptr<relation_endpoint> foreign_endpoint_;
|
std::weak_ptr<relation_endpoint> foreign_endpoint_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,194 +1,93 @@
|
|||||||
#ifndef SCHEMA_HPP
|
#ifndef REPOSITORY_HPP
|
||||||
#define SCHEMA_HPP
|
#define REPOSITORY_HPP
|
||||||
|
|
||||||
#include "matador/logger/log_manager.hpp"
|
#include "matador/object/basic_repository.hpp"
|
||||||
|
|
||||||
#include "matador/object/error_code.hpp"
|
|
||||||
#include "matador/object/foreign_node_completer.hpp"
|
#include "matador/object/foreign_node_completer.hpp"
|
||||||
#include "matador/object/object_info.hpp"
|
#include "matador/object/observer.hpp"
|
||||||
#include "matador/object/relation_completer.hpp"
|
#include "matador/object/relation_completer.hpp"
|
||||||
#include "matador/object/repository_node.hpp"
|
|
||||||
#include "matador/object/repository_node_iterator.hpp"
|
|
||||||
|
|
||||||
#include "matador/utils/result.hpp"
|
#include "matador/utils/result.hpp"
|
||||||
#include "matador/utils/error.hpp"
|
#include "matador/utils/error.hpp"
|
||||||
|
|
||||||
#include "matador/logger/logger.hpp"
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
namespace matador::object {
|
namespace matador::object {
|
||||||
namespace internal {
|
class repository : public basic_repository {
|
||||||
class shadow_repository;
|
|
||||||
}
|
|
||||||
|
|
||||||
utils::error make_error(error_code ec, const std::string &msg);
|
|
||||||
|
|
||||||
class repository {
|
|
||||||
public:
|
public:
|
||||||
typedef const_repository_node_iterator const_iterator; /**< Shortcut for the list const iterator. */
|
using basic_repository::basic_repository;
|
||||||
|
|
||||||
using node_ptr = std::shared_ptr<repository_node>;
|
template<typename Type, template<typename> typename... Observers>
|
||||||
|
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, Observers<Type>&&... observers) {
|
||||||
|
return attach_type<Type, Observers...>(name, std::string{}, std::forward<Observers<Type>>(observers)...);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
template<typename Type, typename SuperType, template<typename> typename... Observers>
|
||||||
* Creates an empty schema
|
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, Observers<Type>&&... observers) {
|
||||||
*/
|
const auto ti = std::type_index(typeid(SuperType));
|
||||||
explicit repository(std::string name = "");
|
const auto it = find_node(ti);
|
||||||
|
if (it == end()) {
|
||||||
|
return utils::failure(make_error(error_code::NodeNotFound, "Parent node '" + std::string(ti.name()) + "' not found"));
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Type>
|
return attach_type<Type, Observers...>(name, it->name(), std::forward<Observers<Type>>(observers)...);
|
||||||
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, const std::string &parent = "") {
|
}
|
||||||
|
|
||||||
|
template<typename Type, template<typename> typename... Observers>
|
||||||
|
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, const std::string &parent, Observers<Type>&&... observers) {
|
||||||
|
return attach_type<Type, Observers...>(name, parent, std::forward<Observers<Type>>(observers)...);
|
||||||
|
}
|
||||||
|
template<typename Type, template<typename> typename... Observers>
|
||||||
|
[[nodiscard]] utils::result<void, utils::error> attach_type(const std::string &name, const std::string &parent, Observers<Type>&&... observers) {
|
||||||
if (const auto it = nodes_by_type_.find(typeid(Type)); it == nodes_by_type_.end() ) {
|
if (const auto it = nodes_by_type_.find(typeid(Type)); it == nodes_by_type_.end() ) {
|
||||||
|
std::vector<std::unique_ptr<observer<Type>>> obs;
|
||||||
|
obs.reserve(sizeof...(Observers));
|
||||||
|
(obs.push_back(std::unique_ptr<observer<Type>>(new Observers<Type>(std::forward<Observers<Type>>(observers)))), ...);
|
||||||
// if the type was not found
|
// if the type was not found
|
||||||
auto node = repository_node::make_node<Type>(*this, name);
|
std::unique_ptr<repository_node> node;
|
||||||
if (auto result = attach_node(node, parent); !result) {
|
if (is_node_announced(typeid(Type))) {
|
||||||
|
node = pop_announce_node(typeid(Type));
|
||||||
|
node->update_name(name);
|
||||||
|
} else {
|
||||||
|
node = repository_node::make_node<Type>(*this, name, []{ return std::make_unique<Type>(); }, std::move(obs));
|
||||||
|
}
|
||||||
|
auto result = attach_node(node.release(), parent);
|
||||||
|
if (!result) {
|
||||||
return utils::failure(result.err());
|
return utils::failure(result.err());
|
||||||
}
|
}
|
||||||
foreign_node_completer::complete<Type>(node);
|
|
||||||
relation_completer<Type>::complete(node);
|
repository_node* attached_node = result.value();
|
||||||
|
const auto info = attached_node->template info<Type>();
|
||||||
|
foreign_node_completer<Type, Observers...>::complete(attached_node, info.get().observers());
|
||||||
|
relation_completer<Type, Observers...>::complete(attached_node, info.get().observers());
|
||||||
} else if (!has_node(name)) {
|
} else if (!has_node(name)) {
|
||||||
it->second->update_name(name);
|
it->second->update_name(name);
|
||||||
nodes_by_name_[name] = it->second;
|
nodes_by_name_[name] = it->second;
|
||||||
if (const auto i = nodes_by_name_.find(""); i != nodes_by_name_.end()) {
|
if (const auto i = nodes_by_name_.find(""); i != nodes_by_name_.end()) {
|
||||||
nodes_by_name_.erase(i);
|
nodes_by_name_.erase(i);
|
||||||
}
|
}
|
||||||
relation_completer<Type>::complete(it->second);
|
const auto info = it->second->info<Type>();
|
||||||
|
relation_completer<Type, Observers...>::complete(it->second, info.get().observers());
|
||||||
log_.info("attach: update node name to '%s' (type: %s)", it->second->name().c_str(), it->second->type_index().name());
|
log_.info("attach: update node name to '%s' (type: %s)", it->second->name().c_str(), it->second->type_index().name());
|
||||||
} else {
|
} else {
|
||||||
// remove_node( )
|
|
||||||
return utils::failure(make_error(error_code::NodeAlreadyExists, "Node '" + name + "' already exists"));
|
return utils::failure(make_error(error_code::NodeAlreadyExists, "Node '" + name + "' already exists"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils::ok<void>();
|
return utils::ok<void>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Type, typename SuperType>
|
|
||||||
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name) {
|
|
||||||
const auto ti = std::type_index(typeid(SuperType));
|
|
||||||
auto result = find_node(ti);
|
|
||||||
if (!result) {
|
|
||||||
return utils::failure(make_error(error_code::NodeNotFound, "Parent node '" + std::string(ti.name()) + "' not found"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return attach<Type>(name, (*result)->name());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Detaches a given node from the schema. If the
|
|
||||||
* node is a parent of other nodes, these nodes are
|
|
||||||
* detached as well.
|
|
||||||
*
|
|
||||||
* @param node Node to detach from schema
|
|
||||||
* @return Result object indicating success or failure
|
|
||||||
*/
|
|
||||||
[[nodiscard]] utils::result<void, utils::error> detach(const node_ptr &node);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the first schema node.
|
|
||||||
*
|
|
||||||
* @return The first schema node iterator.
|
|
||||||
*/
|
|
||||||
[[nodiscard]] const_iterator begin() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the last schema node.
|
|
||||||
*
|
|
||||||
* @return The last schema node iterator.
|
|
||||||
*/
|
|
||||||
[[nodiscard]] const_iterator end() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the schema contains
|
|
||||||
* no schema nodes.
|
|
||||||
*
|
|
||||||
* @return True if the schema is empty
|
|
||||||
*/
|
|
||||||
[[nodiscard]] bool empty() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current number of the schema node.
|
|
||||||
*
|
|
||||||
* @return Number of schema nodes
|
|
||||||
*/
|
|
||||||
[[nodiscard]] size_t size() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the name of the schema.
|
|
||||||
*
|
|
||||||
* @return The name of the schema
|
|
||||||
*/
|
|
||||||
[[nodiscard]] std::string name() const;
|
|
||||||
|
|
||||||
[[nodiscard]] bool contains(const std::string &name) const;
|
|
||||||
[[nodiscard]] bool contains(const std::type_index &index) const;
|
|
||||||
template < typename Type >
|
|
||||||
[[nodiscard]] bool contains() const {
|
|
||||||
return contains(std::type_index(typeid(Type)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
[[nodiscard]] utils::result<object_info_ref<Type>, utils::error> info() const {
|
[[nodiscard]] utils::result<object_info_ref<Type>, utils::error> info() const {
|
||||||
auto result = find_node(std::type_index(typeid(Type)));
|
const auto it = find_node(std::type_index(typeid(Type)));
|
||||||
if (!result) {
|
if (it == end()) {
|
||||||
return utils::failure(result.err());
|
return utils::failure(make_error(error_code::NodeNotFound, "Parent node '" + std::string(typeid(Type).name()) + "' not found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils::ok(result.value()->info<Type>());
|
return utils::ok(it->info<Type>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] utils::result<basic_object_info_ref, utils::error> basic_info(const std::string &name) const;
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
[[nodiscard]] utils::result<basic_object_info_ref, utils::error> basic_info() const {
|
|
||||||
auto result = find_node(std::type_index(typeid(Type)));
|
|
||||||
if (!result) {
|
|
||||||
return utils::failure(result.err());
|
|
||||||
}
|
|
||||||
|
|
||||||
return utils::ok(basic_object_info_ref{result.value()->info()});
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] utils::result<attribute*, utils::error> primary_key_attribute(const std::type_index &type_index) const;
|
|
||||||
|
|
||||||
void dump(std::ostream &os) const;
|
|
||||||
static void dump(std::ostream &os, const node_ptr& node);
|
|
||||||
|
|
||||||
private:
|
|
||||||
using t_node_map = std::unordered_map<std::string, node_ptr>;
|
|
||||||
using t_type_index_node_map = std::unordered_map<std::type_index, node_ptr>;
|
|
||||||
|
|
||||||
[[nodiscard]] utils::result<node_ptr, utils::error> attach_node(const node_ptr &node, const std::string &parent);
|
|
||||||
[[nodiscard]] utils::result<node_ptr, utils::error> find_node(const std::string &name) const;
|
|
||||||
[[nodiscard]] utils::result<node_ptr, utils::error> find_node(const std::type_index &type_index) const;
|
|
||||||
template<typename Type>
|
|
||||||
[[nodiscard]] utils::result<node_ptr, utils::error> find_node() const {
|
|
||||||
return find_node(std::type_index(typeid(Type)));
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool has_node(const std::string &name) const;
|
|
||||||
[[nodiscard]] bool has_node(const std::type_index &index) const;
|
|
||||||
[[nodiscard]] bool has_node(const node_ptr& node) const;
|
|
||||||
|
|
||||||
static void insert_node(const node_ptr &parent, const node_ptr &child);
|
|
||||||
void remove_node(const node_ptr &node);
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class internal::shadow_repository;
|
|
||||||
friend class repository_node;
|
|
||||||
friend class attribute_generator;
|
|
||||||
|
|
||||||
std::string name_;
|
|
||||||
std::shared_ptr<repository_node> root_;
|
|
||||||
|
|
||||||
t_node_map nodes_by_name_;
|
|
||||||
t_type_index_node_map nodes_by_type_;
|
|
||||||
logger::logger log_;
|
|
||||||
|
|
||||||
std::unordered_map<std::type_index, attribute*> missing_references_;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //SCHEMA_HPP
|
#endif //REPOSITORY_HPP
|
||||||
|
|||||||
@@ -1,62 +1,37 @@
|
|||||||
#ifndef SCHEMA_NODE_HPP
|
#ifndef REPOSITORY_NODE_HPP
|
||||||
#define SCHEMA_NODE_HPP
|
#define REPOSITORY_NODE_HPP
|
||||||
|
|
||||||
#include "matador/object/attribute_generator.hpp"
|
#include "matador/object/object_generator.hpp"
|
||||||
#include "matador/object/object.hpp"
|
|
||||||
#include "matador/object/object_info.hpp"
|
#include "matador/object/object_info.hpp"
|
||||||
#include "matador/object/primary_key_resolver.hpp"
|
#include "matador/object/internal/observer_list_creator.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace matador::object {
|
namespace matador::object {
|
||||||
|
|
||||||
class basic_object_info;
|
class basic_object_info;
|
||||||
class repository;
|
class basic_repository;
|
||||||
|
|
||||||
class repository_node final {
|
class repository_node final {
|
||||||
public:
|
public:
|
||||||
using node_ptr = std::shared_ptr<repository_node>;
|
using node_ptr = repository_node*;
|
||||||
|
template< typename Type>
|
||||||
|
using creator_func = std::function<std::unique_ptr<Type>()>;
|
||||||
|
|
||||||
template < typename Type >
|
template < typename Type, template<typename> typename... Observers >
|
||||||
static std::shared_ptr<repository_node> make_node(repository& repo, const std::string& name) {
|
static std::unique_ptr<repository_node> make_node(basic_repository& repo,
|
||||||
auto node = std::shared_ptr<repository_node>(new repository_node(repo, name, typeid(Type)));
|
const std::string& name,
|
||||||
|
creator_func<Type> creator,
|
||||||
primary_key_resolver resolver;
|
std::vector<std::unique_ptr<observer<Type>>>&& observers);
|
||||||
auto pk_info = resolver.resolve<Type>();
|
template < typename Type, template<typename> typename... Observers >
|
||||||
auto obj = object::generate<Type>(repo, name);
|
static std::unique_ptr<repository_node> make_relation_node(basic_repository& repo,
|
||||||
auto ref_column = determine_reference_column(typeid(Type), name, pk_info, repo);
|
const std::string& name,
|
||||||
const auto attributes = attribute_generator::generate<Type>(repo, *obj);
|
const std::string& join_column,
|
||||||
auto info = std::make_unique<object_info<Type>>(
|
const std::string& inverse_join_column,
|
||||||
node,
|
creator_func<Type> creator,
|
||||||
std::move(obj),
|
std::vector<std::unique_ptr<observer<Type>>>&& observers);
|
||||||
[]{ return std::make_unique<Type>(); }
|
|
||||||
);
|
|
||||||
node->info_ = std::move(info);
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
template < typename Type, typename CreatorFunc >
|
|
||||||
static utils::result<node_ptr, utils::error> make_relation_node(repository& repo, const std::string& name, CreatorFunc &&creator) {
|
|
||||||
const auto result = make_and_attach_node(repo, name, typeid(Type));
|
|
||||||
if (!result) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto obj = creator();
|
|
||||||
object o(name);
|
|
||||||
auto info = std::make_unique<object_info<Type>>(
|
|
||||||
result.value(),
|
|
||||||
attribute_generator::generate(*obj, repo, o),
|
|
||||||
std::forward<CreatorFunc>(creator)
|
|
||||||
);
|
|
||||||
result.value()->info_ = std::move(info);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::shared_ptr<repository_node> make_null_node(repository& repo);
|
|
||||||
|
|
||||||
|
explicit repository_node(basic_repository& repo);
|
||||||
repository_node(const repository_node& other) = delete;
|
repository_node(const repository_node& other) = delete;
|
||||||
repository_node(repository_node&& other) = default;
|
repository_node(repository_node&& other) = default;
|
||||||
repository_node& operator=(const repository_node& other) = delete;
|
repository_node& operator=(const repository_node& other) = delete;
|
||||||
@@ -78,43 +53,83 @@ public:
|
|||||||
return std::ref(static_cast<const object_info<Type>&>(*info_));
|
return std::ref(static_cast<const object_info<Type>&>(*info_));
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] const repository& schema() const;
|
[[nodiscard]] const basic_repository& schema() const;
|
||||||
|
|
||||||
[[nodiscard]] bool has_children() const;
|
[[nodiscard]] bool has_children() const;
|
||||||
|
|
||||||
|
void on_attach() const;
|
||||||
|
void on_detach() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit repository_node(repository& repo);
|
repository_node(basic_repository& repo, const std::type_index& ti);
|
||||||
repository_node(repository& repo, const std::type_index& ti);
|
repository_node(basic_repository& repo, std::string name, const std::type_index& ti);
|
||||||
repository_node(repository& repo, std::string name, const std::type_index& ti);
|
|
||||||
|
|
||||||
void unlink();
|
void unlink();
|
||||||
|
|
||||||
static utils::result<node_ptr, utils::error> make_and_attach_node(repository& repo, const std::string& name, const std::type_index& ti);
|
|
||||||
static attribute* determine_reference_column(const std::type_index& ti,
|
|
||||||
const std::string& table_name,
|
|
||||||
const primary_key_info& pk_info,
|
|
||||||
repository& repo);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class repository;
|
friend class basic_repository;
|
||||||
template<typename Type>
|
template<typename Type, template<typename> typename... Observers>
|
||||||
friend class relation_completer;
|
friend class relation_completer;
|
||||||
|
template < typename NodeType, template<typename> typename ...Observers >
|
||||||
friend class foreign_node_completer;
|
friend class foreign_node_completer;
|
||||||
friend class const_repository_node_iterator;
|
friend class const_repository_node_iterator;
|
||||||
|
|
||||||
repository &repo_;
|
basic_repository &repo_;
|
||||||
std::type_index type_index_;
|
std::type_index type_index_;
|
||||||
std::unique_ptr<basic_object_info> info_;
|
std::unique_ptr<basic_object_info> info_;
|
||||||
|
|
||||||
std::shared_ptr<repository_node> parent_;
|
repository_node* parent_{nullptr};
|
||||||
std::shared_ptr<repository_node> previous_sibling_;
|
repository_node* previous_sibling_{nullptr};
|
||||||
std::shared_ptr<repository_node> next_sibling_;
|
repository_node* next_sibling_{nullptr};
|
||||||
std::shared_ptr<repository_node> first_child_;
|
std::unique_ptr<repository_node> first_child_;
|
||||||
std::shared_ptr<repository_node> last_child_;
|
std::unique_ptr<repository_node> last_child_;
|
||||||
|
|
||||||
std::string name_;
|
std::string name_;
|
||||||
size_t depth_{0};
|
size_t depth_{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename Type, template <typename> class ... Observers>
|
||||||
|
std::unique_ptr<repository_node> repository_node::make_node(basic_repository &repo,
|
||||||
|
const std::string &name,
|
||||||
|
creator_func<Type> creator,
|
||||||
|
std::vector<std::unique_ptr<observer<Type>>> &&observers) {
|
||||||
|
const std::type_index ti(typeid(Type));
|
||||||
|
auto node = std::unique_ptr<repository_node>(new repository_node(repo, name, ti));
|
||||||
|
|
||||||
|
internal::observer_list_creator<Type, Observers...>::create_missing(observers);
|
||||||
|
|
||||||
|
auto obj = object_generator::generate<Type>(creator(), repo, name);
|
||||||
|
node->info_.reset(std::make_unique<object_info<Type>>(
|
||||||
|
*node,
|
||||||
|
obj,
|
||||||
|
std::move(observers),
|
||||||
|
std::forward<creator_func<Type>>(creator)
|
||||||
|
).release());
|
||||||
|
|
||||||
|
return node;
|
||||||
}
|
}
|
||||||
#endif //SCHEMA_NODE_HPP
|
|
||||||
|
template<typename Type, template <typename> class ... Observers>
|
||||||
|
std::unique_ptr<repository_node> repository_node::make_relation_node(basic_repository &repo,
|
||||||
|
const std::string &name,
|
||||||
|
const std::string &join_column,
|
||||||
|
const std::string &inverse_join_column,
|
||||||
|
creator_func<Type> creator,
|
||||||
|
std::vector<std::unique_ptr<observer<Type>>> &&observers) {
|
||||||
|
const std::type_index ti(typeid(Type));
|
||||||
|
auto node = std::unique_ptr<repository_node>(new repository_node(repo, name, ti));
|
||||||
|
|
||||||
|
internal::observer_list_creator<Type, Observers...>::create_missing(observers);
|
||||||
|
|
||||||
|
auto obj = object_generator::generate<Type>(creator(), repo, name, join_column, inverse_join_column);
|
||||||
|
node->info_.reset(std::make_unique<object_info<Type>>(
|
||||||
|
*node,
|
||||||
|
obj,
|
||||||
|
std::move(observers),
|
||||||
|
std::forward<creator_func<Type>>(creator)
|
||||||
|
).release());
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif //REPOSITORY_NODE_HPP
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
#ifndef SCHEMA_NODE_ITERATOR_HPP
|
#ifndef REPOSITORY_NODE_ITERATOR_HPP
|
||||||
#define SCHEMA_NODE_ITERATOR_HPP
|
#define REPOSITORY_NODE_ITERATOR_HPP
|
||||||
|
|
||||||
#include "matador/object/repository_node.hpp"
|
|
||||||
|
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
|
||||||
namespace matador::object {
|
namespace matador::object {
|
||||||
|
|
||||||
|
class repository_node;
|
||||||
|
|
||||||
class const_repository_node_iterator {
|
class const_repository_node_iterator {
|
||||||
public:
|
public:
|
||||||
using iterator_category = std::bidirectional_iterator_tag;
|
using iterator_category = std::bidirectional_iterator_tag;
|
||||||
using difference_type = std::ptrdiff_t;
|
using difference_type = std::ptrdiff_t;
|
||||||
using value_type = std::shared_ptr<repository_node>;
|
using value_type = repository_node;
|
||||||
using pointer = repository_node*;
|
using pointer = repository_node*;
|
||||||
using reference = value_type;
|
using reference = value_type&;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an empty iterator
|
* Creates an empty iterator
|
||||||
@@ -28,7 +28,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @param node The schema node of the object
|
* @param node The schema node of the object
|
||||||
*/
|
*/
|
||||||
explicit const_repository_node_iterator(const value_type& node);
|
explicit const_repository_node_iterator(value_type* node);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy from a given const_object_view_iterator.
|
* Copy from a given const_object_view_iterator.
|
||||||
@@ -123,8 +123,8 @@ private:
|
|||||||
void decrement();
|
void decrement();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
value_type node_{};
|
pointer node_{nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif //SCHEMA_NODE_ITERATOR_HPP
|
#endif //REPOSITORY_NODE_ITERATOR_HPP
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
#ifndef MATADOR_RESTRICTION_HPP
|
||||||
|
#define MATADOR_RESTRICTION_HPP
|
||||||
|
|
||||||
|
#include "matador/utils/constraints.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <ostream>
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
namespace matador::object {
|
||||||
|
|
||||||
|
class attribute;
|
||||||
|
class constraint_builder;
|
||||||
|
class constraint_generator;
|
||||||
|
class object;
|
||||||
|
|
||||||
|
class restriction {
|
||||||
|
public:
|
||||||
|
explicit restriction(size_t attr_index);
|
||||||
|
|
||||||
|
[[nodiscard]] size_t attribute_index() const;
|
||||||
|
[[nodiscard]] std::string column_name() const;
|
||||||
|
[[nodiscard]] utils::constraints options() const;
|
||||||
|
[[nodiscard]] std::shared_ptr<object> owner() const;
|
||||||
|
[[nodiscard]] bool is_primary_key_constraint() const;
|
||||||
|
[[nodiscard]] bool is_foreign_key_constraint() const;
|
||||||
|
[[nodiscard]] bool is_unique_constraint() const;
|
||||||
|
[[nodiscard]] std::string ref_table_name() const;
|
||||||
|
[[nodiscard]] std::string ref_column_name() const;
|
||||||
|
friend std::ostream& operator<<(std::ostream& os, const restriction& c);
|
||||||
|
|
||||||
|
[[nodiscard]] std::string type_string() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class constraint_builder;
|
||||||
|
friend class object_generator;
|
||||||
|
friend class object;
|
||||||
|
|
||||||
|
const size_t index_;
|
||||||
|
std::weak_ptr<object> owner_;
|
||||||
|
std::weak_ptr<object> reference_;
|
||||||
|
utils::constraints options_{utils::constraints::None};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif //MATADOR_RESTRICTION_HPP
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
#ifndef ERROR_CODE_HPP
|
|
||||||
#define ERROR_CODE_HPP
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <system_error>
|
|
||||||
|
|
||||||
namespace matador::orm {
|
|
||||||
|
|
||||||
enum class error_code : uint8_t {
|
|
||||||
Ok = 0,
|
|
||||||
NoConnectionAvailable,
|
|
||||||
UnknownType,
|
|
||||||
NoPrimaryKey,
|
|
||||||
FailedToBuildQuery,
|
|
||||||
FailedToFindObject,
|
|
||||||
Failed
|
|
||||||
};
|
|
||||||
|
|
||||||
class orm_category_impl final : public std::error_category
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
[[nodiscard]] const char* name() const noexcept override;
|
|
||||||
[[nodiscard]] std::string message(int ev) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::error_category& orm_category();
|
|
||||||
std::error_code make_error_code(error_code e);
|
|
||||||
std::error_condition make_error_condition(error_code e);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct std::is_error_code_enum<matador::orm::error_code> : true_type {};
|
|
||||||
|
|
||||||
#endif //ERROR_CODE_HPP
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
#ifndef QUERY_BUILDER_EXCEPTION_HPP
|
|
||||||
#define QUERY_BUILDER_EXCEPTION_HPP
|
|
||||||
|
|
||||||
#include "matador/utils/error.hpp"
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace matador::orm {
|
|
||||||
|
|
||||||
enum class query_build_error : std::uint8_t {
|
|
||||||
Ok = 0,
|
|
||||||
UnknownType,
|
|
||||||
MissingPrimaryKey,
|
|
||||||
UnexpectedError,
|
|
||||||
QueryError
|
|
||||||
};
|
|
||||||
|
|
||||||
class query_builder_exception final : public std::exception {
|
|
||||||
public:
|
|
||||||
explicit query_builder_exception(const query_build_error error, utils::error &&err = {});
|
|
||||||
|
|
||||||
[[nodiscard]] query_build_error error_type() const;
|
|
||||||
[[nodiscard]] const utils::error &error() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
const query_build_error error_type_;
|
|
||||||
utils::error error_;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //QUERY_BUILDER_EXCEPTION_HPP
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
#ifndef MATADOR_SCHEMA_HPP
|
|
||||||
#define MATADOR_SCHEMA_HPP
|
|
||||||
|
|
||||||
#include "matador/object/repository.hpp"
|
|
||||||
|
|
||||||
namespace matador::sql {
|
|
||||||
class connection_pool;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace matador::orm {
|
|
||||||
|
|
||||||
class schema;
|
|
||||||
|
|
||||||
using schema_ref = std::reference_wrapper<schema>;
|
|
||||||
|
|
||||||
class schema_repository final {
|
|
||||||
public:
|
|
||||||
utils::result<void, utils::error> add(const std::string &name, const schema &schema);
|
|
||||||
utils::result<void, utils::error> remove(const std::string &name);
|
|
||||||
|
|
||||||
[[nodiscard]] utils::result<schema_ref, utils::error> get(const std::string &name);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::unordered_map<std::string, schema> schema_map_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class schema final {
|
|
||||||
public:
|
|
||||||
explicit schema(sql::connection_pool &pool);
|
|
||||||
schema(sql::connection_pool &pool, const std::string &name);
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, const std::string &parent = "") {
|
|
||||||
return repo_.attach<Type>(name, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Type, typename SuperType>
|
|
||||||
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name) {
|
|
||||||
return repo_.attach<Type, SuperType>(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] utils::result<void, utils::error> create() const;
|
|
||||||
[[nodiscard]] utils::result<void, utils::error> drop() const;
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
[[nodiscard]] utils::result<void, utils::error> drop_table();
|
|
||||||
[[nodiscard]] utils::result<void, utils::error> drop_table(const std::string &table_name) const;
|
|
||||||
|
|
||||||
[[nodiscard]] utils::result<std::vector<object::attribute>, utils::error> describe_table(const std::string &table_name) const;
|
|
||||||
[[nodiscard]] utils::result<bool, utils::error> table_exists(const std::string &table_name) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
object::repository repo_;
|
|
||||||
sql::connection_pool &pool_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
utils::result<void, utils::error> schema::drop_table() {
|
|
||||||
auto info = repo_.info<Type>();
|
|
||||||
if (info) {
|
|
||||||
return drop_table(info->get().name());
|
|
||||||
}
|
|
||||||
|
|
||||||
return utils::failure(info.err());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif //MATADOR_SCHEMA_HPP
|
|
||||||
@@ -1,354 +0,0 @@
|
|||||||
#ifndef QUERY_SESSION_HPP
|
|
||||||
#define QUERY_SESSION_HPP
|
|
||||||
|
|
||||||
#include "matador/orm/error_code.hpp"
|
|
||||||
#include "matador/orm/session_query_builder.hpp"
|
|
||||||
|
|
||||||
#include "matador/query/criteria.hpp"
|
|
||||||
#include "matador/query/query.hpp"
|
|
||||||
#include "matador/query/generator.hpp"
|
|
||||||
|
|
||||||
#include "matador/sql/connection.hpp"
|
|
||||||
#include "matador/sql/connection_pool.hpp"
|
|
||||||
#include "matador/sql/executor.hpp"
|
|
||||||
#include "matador/sql/statement.hpp"
|
|
||||||
#include "matador/sql/statement_cache.hpp"
|
|
||||||
|
|
||||||
#include "matador/object/object_ptr.hpp"
|
|
||||||
#include "matador/object/repository.hpp"
|
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
namespace matador::orm {
|
|
||||||
|
|
||||||
utils::error make_error(error_code ec, const std::string &msg);
|
|
||||||
|
|
||||||
struct session_context {
|
|
||||||
utils::message_bus &bus;
|
|
||||||
sql::connection_pool &pool;
|
|
||||||
size_t cache_size{500};
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
class lazy_object_resolver final : public object::object_resolver<Type> {
|
|
||||||
public:
|
|
||||||
explicit lazy_object_resolver(sql::statement &&stmt) : stmt_(std::move(stmt)) {}
|
|
||||||
|
|
||||||
Type* resolve(const object::object_proxy<Type>& proxy) const override {
|
|
||||||
return proxy.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
sql::statement stmt_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class prototype_builder final {
|
|
||||||
public:
|
|
||||||
explicit prototype_builder(const std::unordered_map<std::string, sql::statement> &statements_per_column)
|
|
||||||
: statements_per_column_(statements_per_column) {}
|
|
||||||
|
|
||||||
|
|
||||||
template < typename Type >
|
|
||||||
Type build() const {
|
|
||||||
Type obj;
|
|
||||||
access::process(*this, obj);
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
template < class V >
|
|
||||||
static void on_primary_key(const char * /*id*/, V &/*pk*/, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {}
|
|
||||||
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
|
|
||||||
template<typename Type>
|
|
||||||
static void on_attribute(const char * /*id*/, Type &/*obj*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
|
||||||
template<class Pointer>
|
|
||||||
void on_belongs_to(const char *id, Pointer &/*obj*/, const utils::foreign_attributes &/*attr*/) {
|
|
||||||
const auto it = statements_per_column_.find(id);
|
|
||||||
if (it == statements_per_column_.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
template<class Pointer>
|
|
||||||
void on_has_one(const char * /*id*/, Pointer &/*obj*/, const utils::foreign_attributes &/*attr*/) {
|
|
||||||
|
|
||||||
}
|
|
||||||
template<class ContainerType>
|
|
||||||
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 &/*cont*/, 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 &/*cont*/, const utils::foreign_attributes &attr) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const std::unordered_map<std::string, sql::statement> &statements_per_column_;
|
|
||||||
};
|
|
||||||
class session final : public sql::executor {
|
|
||||||
public:
|
|
||||||
explicit session(session_context &&ctx);
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &table_name) const;
|
|
||||||
template<typename Type, typename SuperType>
|
|
||||||
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &table_name) const;
|
|
||||||
|
|
||||||
utils::result<void, utils::error> create_schema() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert the given object into the session.
|
|
||||||
*
|
|
||||||
* @tparam Type Type of object to insert
|
|
||||||
* @param obj Object to insert
|
|
||||||
* @return Inserted object
|
|
||||||
*/
|
|
||||||
template<typename Type>
|
|
||||||
utils::result<object::object_ptr<Type>, utils::error> insert(Type *obj);
|
|
||||||
template< class Type, typename... Args >
|
|
||||||
utils::result<object::object_ptr<Type>, utils::error> insert(Args&&... args);
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
utils::result<object::object_ptr<Type>, utils::error> update(const object::object_ptr<Type> &obj);
|
|
||||||
template<typename Type>
|
|
||||||
utils::result<void, utils::error> remove(const object::object_ptr<Type> &obj);
|
|
||||||
|
|
||||||
template<typename Type, typename PrimaryKeyType>
|
|
||||||
utils::result<object::object_ptr<Type>, utils::error> find(const PrimaryKeyType &pk);
|
|
||||||
template<typename Type>
|
|
||||||
utils::result<sql::query_result<Type>, utils::error> find(query::criteria_ptr clause = {});
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
utils::result<void, utils::error> drop_table();
|
|
||||||
utils::result<void, utils::error> drop_table(const std::string &table_name) const;
|
|
||||||
|
|
||||||
[[nodiscard]] utils::result<sql::query_result<sql::record>, utils::error> fetch_all(const sql::query_context &q) const;
|
|
||||||
[[nodiscard]] utils::result<size_t, utils::error> execute(const std::string &sql) const;
|
|
||||||
|
|
||||||
[[nodiscard]] std::vector<object::attribute> describe_table(const std::string &table_name) const;
|
|
||||||
[[nodiscard]] bool table_exists(const std::string &table_name) const;
|
|
||||||
|
|
||||||
void dump_schema(std::ostream &os) const;
|
|
||||||
|
|
||||||
[[nodiscard]] utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetch(const sql::query_context &ctx) const override;
|
|
||||||
[[nodiscard]] utils::result<size_t, utils::error> execute(const sql::query_context &ctx) const override;
|
|
||||||
[[nodiscard]] utils::result<sql::statement, utils::error> prepare(const sql::query_context &ctx) override;
|
|
||||||
[[nodiscard]] std::string str( const sql::query_context& ctx ) const override;
|
|
||||||
[[nodiscard]] const sql::dialect& dialect() const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class query_select;
|
|
||||||
|
|
||||||
static query::fetchable_query build_select_query(entity_query_data &&data);
|
|
||||||
|
|
||||||
private:
|
|
||||||
mutable sql::statement_cache cache_;
|
|
||||||
const sql::dialect &dialect_;
|
|
||||||
|
|
||||||
std::unique_ptr<object::repository> schema_;
|
|
||||||
mutable std::unordered_map<std::string, std::vector<object::attribute>> prototypes_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
[[nodiscard]] utils::result<void, utils::error> session::attach(const std::string &table_name) const {
|
|
||||||
return schema_->attach<Type>(table_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Type, typename SuperType>
|
|
||||||
utils::result<void, utils::error> session::attach( const std::string& table_name ) const {
|
|
||||||
return schema_->attach<Type, SuperType>(table_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
utils::result<object::object_ptr<Type>, utils::error> session::insert(Type *obj) {
|
|
||||||
auto info = schema_->info<Type>();
|
|
||||||
if (!info) {
|
|
||||||
return utils::failure(info.err());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto res = query::query::insert()
|
|
||||||
.into(info->get().name(), query::generator::columns<Type>(*schema_))
|
|
||||||
.values(query::generator::placeholders<Type>())
|
|
||||||
.prepare(*this);
|
|
||||||
if (!res) {
|
|
||||||
return utils::failure(res.err());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const auto insert_result = res->bind(*obj).execute(); !insert_result.is_ok()) {
|
|
||||||
return utils::failure(insert_result.err());
|
|
||||||
}
|
|
||||||
return utils::ok(object::object_ptr{obj});
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Type, typename ... Args>
|
|
||||||
utils::result<object::object_ptr<Type>, utils::error> session::insert( Args&&... args ) {
|
|
||||||
return insert(new Type(std::forward<Args>(args)...));
|
|
||||||
}
|
|
||||||
|
|
||||||
class pk_object_binder final {
|
|
||||||
public:
|
|
||||||
explicit pk_object_binder(sql::statement &stmt, size_t position)
|
|
||||||
: stmt_(stmt)
|
|
||||||
, binding_position_(position){}
|
|
||||||
|
|
||||||
template < class Type >
|
|
||||||
sql::statement& bind(Type &obj) {
|
|
||||||
access::process(*this, obj);
|
|
||||||
return stmt_;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Type>
|
|
||||||
void on_primary_key(const char * /*id*/, Type &x, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {
|
|
||||||
stmt_.bind(binding_position_, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {}
|
|
||||||
template < class Pointer >
|
|
||||||
static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
|
|
||||||
template < class Pointer >
|
|
||||||
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {}
|
|
||||||
|
|
||||||
template<class ContainerType>
|
|
||||||
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>
|
|
||||||
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:
|
|
||||||
sql::statement &stmt_;
|
|
||||||
size_t binding_position_{0};
|
|
||||||
sql::object_pk_binder pk_binder_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
utils::result<object::object_ptr<Type>, utils::error> session::update( const object::object_ptr<Type>& obj ) {
|
|
||||||
auto info = schema_->info<Type>();
|
|
||||||
if (!info) {
|
|
||||||
return utils::failure(info.err());
|
|
||||||
}
|
|
||||||
using namespace matador::utils;
|
|
||||||
using namespace matador::query;
|
|
||||||
|
|
||||||
const auto col = column(info.value().get().reference_column()->name());
|
|
||||||
auto res = matador::query::query::update(info->get().name())
|
|
||||||
.set(generator::column_value_pairs<Type>())
|
|
||||||
.where(col == _)
|
|
||||||
.prepare(*this);
|
|
||||||
if (!res) {
|
|
||||||
return utils::failure(res.err());
|
|
||||||
}
|
|
||||||
|
|
||||||
res->bind(*obj);
|
|
||||||
pk_object_binder binder(res.value(), res->bind_pos());
|
|
||||||
if (const auto update_result = binder.bind(*obj).execute(); !update_result.is_ok()) {
|
|
||||||
return utils::failure(update_result.err());
|
|
||||||
}
|
|
||||||
return utils::ok(object::object_ptr{obj});
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
utils::result<void, utils::error> session::remove( const object::object_ptr<Type>& obj ) {
|
|
||||||
auto info = schema_->info<Type>();
|
|
||||||
if (!info) {
|
|
||||||
return utils::failure(info.err());
|
|
||||||
}
|
|
||||||
using namespace matador::utils;
|
|
||||||
using namespace matador::query;
|
|
||||||
|
|
||||||
const auto col = column(info.value().get().reference_column()->name());
|
|
||||||
auto res = matador::query::query::remove()
|
|
||||||
.from( info->get().name() )
|
|
||||||
.where(col == _)
|
|
||||||
.prepare(*this);
|
|
||||||
if (!res) {
|
|
||||||
return utils::failure(res.err());
|
|
||||||
}
|
|
||||||
|
|
||||||
pk_object_binder binder(res.value(), res->bind_pos());
|
|
||||||
if (const auto update_result = binder.bind(*obj).execute(); !update_result.is_ok()) {
|
|
||||||
return utils::failure(update_result.err());
|
|
||||||
}
|
|
||||||
return utils::ok<void>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Type, typename PrimaryKeyType>
|
|
||||||
utils::result<object::object_ptr<Type>, utils::error> session::find(const PrimaryKeyType& pk) {
|
|
||||||
auto info = schema_->info<Type>();
|
|
||||||
if (!info) {
|
|
||||||
return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type."));
|
|
||||||
}
|
|
||||||
if (!info.value().get().has_primary_key()) {
|
|
||||||
return utils::failure(make_error(error_code::NoPrimaryKey, "Type hasn't primary key."));
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& type_info = info.value().get();
|
|
||||||
|
|
||||||
session_query_builder eqb(*schema_, *this);
|
|
||||||
const query::column col(query::table{type_info.reference_column()->table_name()}, type_info.reference_column()->name());
|
|
||||||
using namespace matador::query;
|
|
||||||
auto data = eqb.build<Type>(col == utils::_);
|
|
||||||
if (!data.is_ok()) {
|
|
||||||
return utils::failure(make_error(error_code::FailedToBuildQuery, "Failed to build query for type " + type_info.name() + "."));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto res = build_select_query(data.release()).prepare(*this);
|
|
||||||
|
|
||||||
if (!res) {
|
|
||||||
return utils::failure(res.err());
|
|
||||||
}
|
|
||||||
auto stmt_result = res->bind(0, const_cast<PrimaryKeyType&>(pk)).template fetch_one<Type>();
|
|
||||||
if (stmt_result && !stmt_result.value()) {
|
|
||||||
return utils::failure(make_error(error_code::FailedToFindObject, "Failed to find object of type " + type_info.name() + " with primary key " + std::to_string(pk) + "."));
|
|
||||||
}
|
|
||||||
return utils::ok(object::object_ptr<Type>{ stmt_result->release() });
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
utils::result<sql::query_result<Type>, utils::error> session::find(query::criteria_ptr clause) {
|
|
||||||
auto info = schema_->info<Type>();
|
|
||||||
if (!info) {
|
|
||||||
return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type."));
|
|
||||||
}
|
|
||||||
|
|
||||||
session_query_builder eqb(*schema_, *this);
|
|
||||||
auto data = eqb.build<Type>(std::move(clause));
|
|
||||||
if (!data.is_ok()) {
|
|
||||||
return utils::failure(make_error(error_code::FailedToBuildQuery, "Failed to build query for type " + info->get().name() + "."));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto result = build_select_query(data.release()).prepare(*this);
|
|
||||||
if (!result.is_ok()) {
|
|
||||||
return utils::failure(result.err());
|
|
||||||
}
|
|
||||||
|
|
||||||
return result->template fetch<Type>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
utils::result<void, utils::error> session::drop_table() {
|
|
||||||
auto info = schema_->info<Type>();
|
|
||||||
if (info) {
|
|
||||||
return drop_table(info->get().name());
|
|
||||||
}
|
|
||||||
|
|
||||||
return utils::failure(info.err());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif //QUERY_SESSION_HPP
|
|
||||||
@@ -1,292 +0,0 @@
|
|||||||
#ifndef QUERY_ENTITY_QUERY_BUILDER_HPP
|
|
||||||
#define QUERY_ENTITY_QUERY_BUILDER_HPP
|
|
||||||
|
|
||||||
#include "matador/orm/query_builder_exception.hpp"
|
|
||||||
|
|
||||||
#include "matador/query/criteria.hpp"
|
|
||||||
#include "matador/query/query.hpp"
|
|
||||||
|
|
||||||
#include "matador/sql/executor.hpp"
|
|
||||||
#include "matador/sql/statement.hpp"
|
|
||||||
|
|
||||||
#include "matador/object/join_columns_collector.hpp"
|
|
||||||
#include "matador/object/repository.hpp"
|
|
||||||
#include "matador/query/criteria/criteria_visitor.hpp"
|
|
||||||
|
|
||||||
#include "matador/utils/primary_key_attribute.hpp"
|
|
||||||
#include "matador/utils/result.hpp"
|
|
||||||
#include "matador/utils/value.hpp"
|
|
||||||
|
|
||||||
#include <stack>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
namespace matador::orm {
|
|
||||||
|
|
||||||
struct entity_query_data {
|
|
||||||
std::shared_ptr<query::table> root_table;
|
|
||||||
std::string pk_column_name{};
|
|
||||||
std::vector<query::column> columns{};
|
|
||||||
std::unordered_map<std::string, sql::statement> lazy_loading_statements{};
|
|
||||||
std::vector<query::join_data> joins{};
|
|
||||||
query::criteria_ptr where_clause{};
|
|
||||||
};
|
|
||||||
|
|
||||||
class criteria_transformer final : public query::criteria_visitor {
|
|
||||||
public:
|
|
||||||
criteria_transformer(const object::repository &repo, const std::unordered_map<std::string, std::shared_ptr<query::table>>& tables_by_name);
|
|
||||||
void visit( const query::between_criteria& node ) override;
|
|
||||||
void visit( const query::binary_criteria& node ) override;
|
|
||||||
void visit( const query::binary_column_criteria& node ) override;
|
|
||||||
void visit( const query::collection_criteria& node ) override;
|
|
||||||
void visit( const query::collection_query_criteria& node ) override;
|
|
||||||
void visit( const query::like_criteria& node ) override;
|
|
||||||
void visit( const query::logical_criteria& node ) override;
|
|
||||||
void visit( const query::not_criteria& node ) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void update_criteria_column(const query::abstract_column_criteria& node) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
const object::repository &repo_;
|
|
||||||
const std::unordered_map<std::string, std::shared_ptr<query::table>>& tables_by_name_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class session_query_builder final {
|
|
||||||
public:
|
|
||||||
session_query_builder(const object::repository &scm, sql::executor &exec)
|
|
||||||
: schema_(scm)
|
|
||||||
, executor_(exec){}
|
|
||||||
|
|
||||||
template<class EntityType>
|
|
||||||
utils::result<entity_query_data, query_build_error> build(query::criteria_ptr clause = {}) {
|
|
||||||
const auto info = schema_.info<EntityType>();
|
|
||||||
if (!info) {
|
|
||||||
return utils::failure(query_build_error::UnknownType);
|
|
||||||
}
|
|
||||||
table_info_stack_.push({info.value(), std::make_shared<query::table>(info.value().get().name(), build_alias('t', ++table_index))});
|
|
||||||
entity_query_data_ = { table_info_stack_.top().table };
|
|
||||||
processed_tables_.insert({info->get().name(), entity_query_data_.root_table});
|
|
||||||
try {
|
|
||||||
access::process(*this, info->get().prototype());
|
|
||||||
|
|
||||||
if (clause) {
|
|
||||||
criteria_transformer transformer{schema_, processed_tables_};
|
|
||||||
clause->accept(transformer);
|
|
||||||
entity_query_data_.where_clause = std::move(clause);
|
|
||||||
}
|
|
||||||
return {utils::ok(std::move(entity_query_data_))};
|
|
||||||
} catch (const query_builder_exception &ex) {
|
|
||||||
return {utils::failure(ex.error_type())};
|
|
||||||
} catch (...) {
|
|
||||||
return {utils::failure(query_build_error::UnexpectedError)};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template < class V >
|
|
||||||
void on_primary_key(const char *id, V &, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {
|
|
||||||
push(id);
|
|
||||||
if (!is_root_entity()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
entity_query_data_.pk_column_name = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_revision(const char *id, uint64_t &/*rev*/);
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
void on_attribute(const char *id, Type &, const utils::field_attributes &/*attr*/ = utils::null_attributes)
|
|
||||||
{
|
|
||||||
push(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Pointer>
|
|
||||||
void on_belongs_to(const char *id, Pointer &obj, const utils::foreign_attributes &attr)
|
|
||||||
{
|
|
||||||
on_foreign_object(id, obj, attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Pointer>
|
|
||||||
void on_has_one(const char *id, Pointer &obj, const utils::foreign_attributes &attr)
|
|
||||||
{
|
|
||||||
on_foreign_object(id, obj, attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ContainerType>
|
|
||||||
void on_has_many(const char * /*id*/, ContainerType &, const char *join_column, const utils::foreign_attributes &attr) {
|
|
||||||
if (attr.fetch() == utils::fetch_type::EAGER) {
|
|
||||||
const auto info = schema_.info<typename ContainerType::value_type::value_type>();
|
|
||||||
if (!info) {
|
|
||||||
throw query_builder_exception{query_build_error::UnknownType};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto next = processed_tables_.find(info->get().name());
|
|
||||||
if (next != processed_tables_.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
table_info_stack_.push({info.value(), std::make_shared<query::table>(info->get().name(), build_alias('t', ++table_index))});
|
|
||||||
next = processed_tables_.insert({info->get().name(), table_info_stack_.top().table}).first;
|
|
||||||
typename ContainerType::value_type::value_type obj;
|
|
||||||
access::process(*this , obj);
|
|
||||||
table_info_stack_.pop();
|
|
||||||
|
|
||||||
if (!info->get().has_primary_key()) {
|
|
||||||
throw query_builder_exception{query_build_error::MissingPrimaryKey};
|
|
||||||
}
|
|
||||||
|
|
||||||
append_join(
|
|
||||||
query::column{table_info_stack_.top().table, table_info_stack_.top().info.get().reference_column()->name()},
|
|
||||||
query::column{next->second, join_column}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ContainerType>
|
|
||||||
void on_has_many_to_many(const char *id, ContainerType &/*cont*/, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &attr) {
|
|
||||||
if (attr.fetch() != utils::fetch_type::EAGER) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const auto info = schema_.info<typename ContainerType::value_type::value_type>();
|
|
||||||
if (!info) {
|
|
||||||
throw query_builder_exception{query_build_error::UnknownType};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto next = processed_tables_.find(info->get().name());
|
|
||||||
if (next != processed_tables_.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto relation = processed_tables_.find(id);
|
|
||||||
if (relation == processed_tables_.end()) {
|
|
||||||
relation = processed_tables_.insert({id, std::make_shared<query::table>(id, build_alias('t', ++table_index))}).first;
|
|
||||||
}
|
|
||||||
|
|
||||||
table_info_stack_.push({info.value(), std::make_shared<query::table>(info->get().name(), build_alias('t', ++table_index))});
|
|
||||||
next = processed_tables_.insert({info->get().name(), table_info_stack_.top().table}).first;
|
|
||||||
typename ContainerType::value_type::value_type obj;
|
|
||||||
access::process(*this , obj);
|
|
||||||
table_info_stack_.pop();
|
|
||||||
|
|
||||||
if (!info->get().has_primary_key()) {
|
|
||||||
throw query_builder_exception{query_build_error::MissingPrimaryKey};
|
|
||||||
}
|
|
||||||
|
|
||||||
append_join(
|
|
||||||
query::column{table_info_stack_.top().table, table_info_stack_.top().info.get().reference_column()->name()},
|
|
||||||
query::column{relation->second, join_column}
|
|
||||||
);
|
|
||||||
append_join(
|
|
||||||
query::column{relation->second, inverse_join_column},
|
|
||||||
query::column{next->second, info->get().reference_column()->name()}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ContainerType>
|
|
||||||
void on_has_many_to_many(const char *id, ContainerType &/*cont*/, const utils::foreign_attributes &attr) {
|
|
||||||
if (attr.fetch() != utils::fetch_type::EAGER) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const auto info = schema_.info<typename ContainerType::value_type::value_type>();
|
|
||||||
if (!info) {
|
|
||||||
throw query_builder_exception{query_build_error::UnknownType};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto next = processed_tables_.find(info->get().name());
|
|
||||||
if (next != processed_tables_.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto relation = processed_tables_.find(id);
|
|
||||||
if (relation == processed_tables_.end()) {
|
|
||||||
relation = processed_tables_.insert({id, std::make_shared<query::table>(id, build_alias('t', ++table_index))}).first;
|
|
||||||
}
|
|
||||||
table_info_stack_.push({info.value(), std::make_shared<query::table>(info->get().name(), build_alias('t', ++table_index))});
|
|
||||||
next = processed_tables_.insert({info->get().name(), table_info_stack_.top().table}).first;
|
|
||||||
typename ContainerType::value_type::value_type obj;
|
|
||||||
access::process(*this , obj);
|
|
||||||
table_info_stack_.pop();
|
|
||||||
|
|
||||||
if (!info->get().has_primary_key()) {
|
|
||||||
throw query_builder_exception{query_build_error::MissingPrimaryKey};
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto join_columns = join_columns_collector_.collect<typename ContainerType::value_type::value_type>();
|
|
||||||
|
|
||||||
append_join(
|
|
||||||
query::column{table_info_stack_.top().table, table_info_stack_.top().info.get().reference_column()->name()},
|
|
||||||
query::column{relation->second, join_columns.inverse_join_column}
|
|
||||||
);
|
|
||||||
append_join(
|
|
||||||
query::column{relation->second, join_columns.join_column},
|
|
||||||
query::column{next->second, info->get().reference_column()->name()}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
template<class Pointer>
|
|
||||||
void on_foreign_object(const char *id, Pointer &, const utils::foreign_attributes &attr);
|
|
||||||
void push(const std::string &column_name);
|
|
||||||
static std::string build_alias(char prefix, unsigned int count);
|
|
||||||
[[nodiscard]] bool is_root_entity() const;
|
|
||||||
void append_join(const query::column &left, const query::column &right);
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct table_info {
|
|
||||||
std::reference_wrapper<const object::basic_object_info> info;
|
|
||||||
std::shared_ptr<query::table> table;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::stack<table_info> table_info_stack_{};
|
|
||||||
std::unordered_map<std::string, std::shared_ptr<query::table>> processed_tables_{};
|
|
||||||
const object::repository &schema_;
|
|
||||||
entity_query_data entity_query_data_{};
|
|
||||||
unsigned int column_index{0};
|
|
||||||
unsigned int table_index{0};
|
|
||||||
object::join_columns_collector join_columns_collector_{};
|
|
||||||
sql::executor &executor_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class Pointer>
|
|
||||||
void session_query_builder::on_foreign_object(const char *id, Pointer &, const utils::foreign_attributes &attr) {
|
|
||||||
const auto info = schema_.info<typename Pointer::value_type>();
|
|
||||||
if (!info) {
|
|
||||||
throw query_builder_exception{query_build_error::UnknownType};
|
|
||||||
}
|
|
||||||
if (!info->get().has_primary_key()) {
|
|
||||||
throw query_builder_exception{query_build_error::MissingPrimaryKey};
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto foreign_table = std::make_shared<query::table>(info->get().name(), build_alias('t', ++table_index));
|
|
||||||
if (attr.fetch() == utils::fetch_type::EAGER) {
|
|
||||||
|
|
||||||
auto next = processed_tables_.find(info->get().name());
|
|
||||||
if (next != processed_tables_.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
table_info_stack_.push({info.value(), foreign_table});
|
|
||||||
next = processed_tables_.insert({info->get().name(), table_info_stack_.top().table}).first;
|
|
||||||
typename Pointer::value_type obj;
|
|
||||||
access::process(*this, obj);
|
|
||||||
table_info_stack_.pop();
|
|
||||||
|
|
||||||
append_join(
|
|
||||||
query::column{table_info_stack_.top().table, id},
|
|
||||||
query::column{next->second, info->get().reference_column()->name()}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
push(id);
|
|
||||||
using namespace matador::utils;
|
|
||||||
using namespace matador::query;
|
|
||||||
// create select query
|
|
||||||
auto result = matador::query::query::select(generator::columns<typename Pointer::value_type>(schema_, generator::column_generator_options::ForceLazy))
|
|
||||||
.from(*foreign_table)
|
|
||||||
.where(column(foreign_table, info->get().reference_column()->name(), "") == _)
|
|
||||||
.prepare(executor_);
|
|
||||||
if (!result) {
|
|
||||||
throw query_builder_exception(query_build_error::QueryError, result.release_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
entity_query_data_.lazy_loading_statements.emplace(id, std::move(result.release()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif //QUERY_ENTITY_QUERY_BUILDER_HPP
|
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#ifndef MATADOR_ABSTRACT_PK_GENERATOR_HPP
|
||||||
|
#define MATADOR_ABSTRACT_PK_GENERATOR_HPP
|
||||||
|
|
||||||
|
#include "matador/utils/error.hpp"
|
||||||
|
#include "matador/utils/result.hpp"
|
||||||
|
#include "matador/utils/primary_key_generator_type.hpp"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace matador::sql {
|
||||||
|
class executor;
|
||||||
|
}
|
||||||
|
namespace matador::query {
|
||||||
|
class abstract_pk_generator {
|
||||||
|
public:
|
||||||
|
virtual ~abstract_pk_generator() = default;
|
||||||
|
virtual utils::result<int64_t, utils::error> next_id(const sql::executor& exec) = 0;
|
||||||
|
virtual utils::result<int64_t, utils::error> current_id(const sql::executor& exec) = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] utils::generator_type type() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit abstract_pk_generator(utils::generator_type type);
|
||||||
|
|
||||||
|
private:
|
||||||
|
utils::generator_type generator_type_{};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif //MATADOR_ABSTRACT_PK_GENERATOR_HPP
|
||||||
@@ -3,17 +3,13 @@
|
|||||||
|
|
||||||
#include "matador/utils/attribute_writer.hpp"
|
#include "matador/utils/attribute_writer.hpp"
|
||||||
|
|
||||||
#include <optional>
|
#include "matador/sql/interface/connection_impl.hpp"
|
||||||
|
|
||||||
namespace matador::sql {
|
#include <optional>
|
||||||
class dialect;
|
|
||||||
class connection_impl;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace matador::query {
|
namespace matador::query {
|
||||||
|
|
||||||
class attribute_string_writer final : public utils::attribute_writer
|
class attribute_string_writer final : public utils::attribute_writer {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
attribute_string_writer(const sql::dialect &d, std::optional<std::reference_wrapper<const sql::connection_impl>> conn);
|
attribute_string_writer(const sql::dialect &d, std::optional<std::reference_wrapper<const sql::connection_impl>> conn);
|
||||||
|
|
||||||
@@ -38,13 +34,14 @@ public:
|
|||||||
void write_value(size_t pos, const bool& x) override;
|
void write_value(size_t pos, const bool& x) override;
|
||||||
void write_value(size_t pos, const float& x) override;
|
void write_value(size_t pos, const float& x) override;
|
||||||
void write_value(size_t pos, const double& x) override;
|
void write_value(size_t pos, const double& x) override;
|
||||||
void write_value(size_t pos, const time& x) override;
|
void write_value(size_t pos, const utils::date_type_t& x) override;
|
||||||
void write_value(size_t pos, const date& x) override;
|
void write_value(size_t pos, const utils::time_type_t& x) override;
|
||||||
|
void write_value(size_t pos, const utils::timestamp_type_t& x) override;
|
||||||
void write_value(size_t pos, const char* x) override;
|
void write_value(size_t pos, const char* x) override;
|
||||||
void write_value(size_t pos, const char* x, size_t size) override;
|
void write_value(size_t pos, const char* x, size_t size) override;
|
||||||
void write_value(size_t pos, const std::string& x) override;
|
void write_value(size_t pos, const std::string& x) override;
|
||||||
void write_value(size_t pos, const std::string& x, size_t size) override;
|
void write_value(size_t pos, const std::string& x, size_t size) override;
|
||||||
void write_value(size_t pos, const utils::blob& x) override;
|
void write_value(size_t pos, const utils::blob_type_t& x) override;
|
||||||
void write_value(size_t pos, const utils::value& x, size_t size) override;
|
void write_value(size_t pos, const utils::value& x, size_t size) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -0,0 +1,120 @@
|
|||||||
|
#ifndef MATADOR_BASIC_SCHEMA_HPP
|
||||||
|
#define MATADOR_BASIC_SCHEMA_HPP
|
||||||
|
|
||||||
|
#include "matador/object/repository.hpp"
|
||||||
|
|
||||||
|
#include "matador/query/abstract_pk_generator.hpp"
|
||||||
|
#include "matador/query/table.hpp"
|
||||||
|
|
||||||
|
#include "matador/sql/internal/joined_collection_resolver_producer.hpp"
|
||||||
|
#include "matador/sql/internal/object_resolver_producer.hpp"
|
||||||
|
#include "matador/sql/producer_object_resolver_factory.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <typeindex>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace matador::sql {
|
||||||
|
class connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace matador::query {
|
||||||
|
class schema_node final {
|
||||||
|
public:
|
||||||
|
schema_node(class table tab, std::unique_ptr<abstract_pk_generator> &&pk_generator, const object::repository_node& node);
|
||||||
|
|
||||||
|
[[nodiscard]] const std::string& name() const;
|
||||||
|
[[nodiscard]] const class table& table() const;
|
||||||
|
[[nodiscard]] abstract_pk_generator& pk_generator() const;
|
||||||
|
[[nodiscard]] const object::repository_node& node() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class table table_;
|
||||||
|
std::unique_ptr<abstract_pk_generator> pk_generator_;
|
||||||
|
const object::repository_node& node_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class primary_key_generator_finder final {
|
||||||
|
public:
|
||||||
|
template< typename Type >
|
||||||
|
utils::generator_type find(const object::object_info<Type>& info) {
|
||||||
|
generator_type_ = utils::generator_type::Manual;
|
||||||
|
|
||||||
|
access::process(*this, info.prototype());
|
||||||
|
|
||||||
|
return generator_type_;
|
||||||
|
}
|
||||||
|
template<typename BaseType>
|
||||||
|
static void on_base(const BaseType&) {}
|
||||||
|
template<class V>
|
||||||
|
void on_primary_key(const char * /*id*/, V &/*pk*/, const utils::primary_key_attribute &attr) {
|
||||||
|
generator_type_ = attr.generator();
|
||||||
|
}
|
||||||
|
static void on_revision(const char * /*id*/, uint64_t & /*rev*/) {}
|
||||||
|
template<typename T>
|
||||||
|
static void on_attribute(const char * /*id*/, T &, const utils::field_attributes &/*attr*/) {}
|
||||||
|
template<class P>
|
||||||
|
static void on_belongs_to(const char * /*id*/, P &, const utils::foreign_attributes & ) {}
|
||||||
|
template<class P>
|
||||||
|
static void on_has_one(const char * /*id*/, P &, const char * /*join_column*/, const utils::foreign_attributes & ) {}
|
||||||
|
template<class C>
|
||||||
|
static void on_has_many(const char * /*id*/, C &, const char * /*join_column*/, const utils::foreign_attributes & ) {}
|
||||||
|
template<class C>
|
||||||
|
static void on_has_many_to_many(const char * /*id*/, C &, const char * /*join_column*/, const char * /*inverse_join_column*/, const utils::foreign_attributes & ) {}
|
||||||
|
template<class C>
|
||||||
|
static void on_has_many_to_many(const char * /*id*/, C &, const utils::foreign_attributes & ) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
utils::generator_type generator_type_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
class basic_schema {
|
||||||
|
public:
|
||||||
|
using schema_node_map = std::unordered_map<std::type_index, schema_node>;
|
||||||
|
using iterator = std::unordered_map<std::type_index, schema_node>::iterator;
|
||||||
|
using const_iterator = std::unordered_map<std::type_index, schema_node>::const_iterator;
|
||||||
|
|
||||||
|
basic_schema();
|
||||||
|
explicit basic_schema(const std::string &name);
|
||||||
|
|
||||||
|
[[nodiscard]] std::string name() const;
|
||||||
|
|
||||||
|
[[nodiscard]] const object::repository &repo() const;
|
||||||
|
object::repository &repo();
|
||||||
|
|
||||||
|
[[nodiscard]] utils::result<void, utils::error> create(const sql::connection &conn) const;
|
||||||
|
[[nodiscard]] utils::result<void, utils::error> drop(const sql::connection &conn) const;
|
||||||
|
|
||||||
|
iterator begin();
|
||||||
|
iterator end();
|
||||||
|
[[nodiscard]] const_iterator begin() const;
|
||||||
|
[[nodiscard]] const_iterator end() const;
|
||||||
|
|
||||||
|
[[nodiscard]] size_t size() const;
|
||||||
|
[[nodiscard]] bool empty() const;
|
||||||
|
|
||||||
|
iterator find(const std::type_index& ti);
|
||||||
|
iterator find(const std::string& name);
|
||||||
|
|
||||||
|
[[nodiscard]] const_iterator find(const std::type_index& ti) const;
|
||||||
|
[[nodiscard]] const_iterator find(const std::string& name) const;
|
||||||
|
|
||||||
|
[[nodiscard]] bool contains(const std::type_index &index) const;
|
||||||
|
|
||||||
|
[[nodiscard]] const std::unordered_map<std::type_index, std::unique_ptr<sql::object_resolver_producer>>& resolver_producers() const;
|
||||||
|
[[nodiscard]] const std::unordered_map<object::collection_composite_key, std::unique_ptr<sql::joined_collection_resolver_producer>, object::collection_composite_key_hash>& collection_resolver_producers() const;
|
||||||
|
[[nodiscard]] const std::unordered_map<object::collection_composite_key, std::unique_ptr<sql::joined_object_resolver_producer>, object::collection_composite_key_hash>& joined_object_resolver_producers() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template<typename Type>
|
||||||
|
friend class schema_observer;
|
||||||
|
friend class producer_creator;
|
||||||
|
|
||||||
|
object::repository repo_;
|
||||||
|
std::unordered_map<std::type_index, schema_node> schema_nodes_;
|
||||||
|
std::unordered_map<std::type_index, std::unique_ptr<sql::object_resolver_producer>> resolver_producers_;
|
||||||
|
std::unordered_map<object::collection_composite_key, std::unique_ptr<sql::joined_collection_resolver_producer>, object::collection_composite_key_hash> collection_resolver_producers_;
|
||||||
|
std::unordered_map<object::collection_composite_key, std::unique_ptr<sql::joined_object_resolver_producer>, object::collection_composite_key_hash> joined_object_resolver_producers_;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif //MATADOR_BASIC_SCHEMA_HPP
|
||||||
@@ -1,37 +1,25 @@
|
|||||||
#ifndef MATADOR_BUILDER_HPP
|
#ifndef MATADOR_BUILDER_HPP
|
||||||
#define MATADOR_BUILDER_HPP
|
#define MATADOR_BUILDER_HPP
|
||||||
|
|
||||||
#include "matador/query/column.hpp"
|
#include "matador/query/table_column.hpp"
|
||||||
|
#include "matador/query/table_constraint.hpp"
|
||||||
#include "matador/query/table.hpp"
|
#include "matador/query/table.hpp"
|
||||||
|
|
||||||
#include "matador/utils/basic_types.hpp"
|
#include "matador/utils/basic_types.hpp"
|
||||||
#include "matador/utils/constraints.hpp"
|
#include "matador/utils/constraints.hpp"
|
||||||
#include "matador/utils/data_type_traits.hpp"
|
#include "matador/utils/data_type_traits.hpp"
|
||||||
|
#include "matador/utils/types.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace matador::object {
|
namespace matador::object {
|
||||||
|
|
||||||
class entity {
|
|
||||||
public:
|
|
||||||
explicit entity(std::string name)
|
|
||||||
: name_(std::move(name)) {}
|
|
||||||
|
|
||||||
[[nodiscard]] const std::string& name() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string name_;
|
|
||||||
std::string alias_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class data_type {
|
class data_type {
|
||||||
public:
|
public:
|
||||||
template<typename Type>
|
explicit data_type(const utils::basic_type type, const size_t size = 0)
|
||||||
data_type() : type_(utils::data_type_traits<Type>()) {}
|
: type_(type), size_(size) {
|
||||||
template<typename Type>
|
}
|
||||||
explicit data_type(const size_t size) : type_(utils::data_type_traits<Type>()), size_(size) {}
|
|
||||||
|
|
||||||
[[nodiscard]] const utils::basic_type& type() const { return type_; }
|
[[nodiscard]] const utils::basic_type &type() const { return type_; }
|
||||||
[[nodiscard]] size_t size() const { return size_; }
|
[[nodiscard]] size_t size() const { return size_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -39,85 +27,95 @@ private:
|
|||||||
size_t size_{0};
|
size_t size_{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
// using BigInt = data_type<int64_t>();
|
template<typename Type>
|
||||||
// using Real = data_type<float>;
|
class typed_data_type final : public data_type {
|
||||||
// using double_ = data_type<double>;
|
|
||||||
// using string = data_type<std::string>;
|
|
||||||
|
|
||||||
class constraint {
|
|
||||||
public:
|
public:
|
||||||
explicit constraint(std::string name)
|
typed_data_type()
|
||||||
: name_(std::move(name)) {}
|
: data_type(utils::data_type_traits<Type>::type()) {
|
||||||
|
}
|
||||||
[[nodiscard]] const std::string& name() const;
|
|
||||||
[[nodiscard]] const std::string& column_name() const;
|
|
||||||
[[nodiscard]] const utils::constraints& type() const;
|
|
||||||
[[nodiscard]] bool is_primary_key_constraint() const;
|
|
||||||
[[nodiscard]] bool is_foreign_key_constraint() const;
|
|
||||||
[[nodiscard]] bool is_unique_constraint() const;
|
|
||||||
[[nodiscard]] const std::string& referenced_table() const;
|
|
||||||
[[nodiscard]] const std::string& referenced_column() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string name_;
|
|
||||||
std::string column_name_;
|
|
||||||
utils::constraints type_{};
|
|
||||||
std::string referenced_table_;
|
|
||||||
std::string referenced_column_;
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
namespace matador::query {
|
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
class sized_typed_data_type final : public data_type {
|
||||||
|
public:
|
||||||
|
explicit sized_typed_data_type(size_t size)
|
||||||
|
: data_type(utils::data_type_traits<Type>::type(size), size) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using TinyInt = typed_data_type<int8_t>;
|
||||||
|
using SmallInt = typed_data_type<int16_t>;
|
||||||
|
using Integer = typed_data_type<int32_t>;
|
||||||
|
using BigInt = typed_data_type<int64_t>;
|
||||||
|
using TinyIntUnsigned = typed_data_type<uint8_t>;
|
||||||
|
using SmallIntUnsigned = typed_data_type<uint16_t>;
|
||||||
|
using IntegerUnsigned = typed_data_type<uint32_t>;
|
||||||
|
using BigIntUnsigned = typed_data_type<uint64_t>;
|
||||||
|
|
||||||
|
using Real = typed_data_type<float>;
|
||||||
|
using Double = typed_data_type<double>;
|
||||||
|
|
||||||
|
using Text = typed_data_type<std::string>;
|
||||||
|
using Boolean = typed_data_type<bool>;
|
||||||
|
using Varchar = sized_typed_data_type<std::string>;
|
||||||
|
using Blob = sized_typed_data_type<std::vector<std::byte> >;
|
||||||
|
|
||||||
|
using Time = typed_data_type<utils::time_type_t>;
|
||||||
|
using Date = typed_data_type<utils::date_type_t>;
|
||||||
|
using Timestamp = typed_data_type<utils::timestamp_type_t>;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace matador::query {
|
||||||
class column_builder {
|
class column_builder {
|
||||||
public:
|
public:
|
||||||
explicit column_builder(std::string column_name, utils::basic_type type, size_t size = 0);
|
explicit column_builder(std::string column_name, utils::basic_type type, size_t size = 0);
|
||||||
|
|
||||||
// ReSharper disable once CppNonExplicitConversionOperator
|
// ReSharper disable once CppNonExplicitConversionOperator
|
||||||
operator query::column() const; // NOLINT(*-explicit-constructor)
|
operator table_column() const; // NOLINT(*-explicit-constructor)
|
||||||
|
|
||||||
column_builder& not_null();
|
column_builder ¬_null();
|
||||||
|
column_builder &primary_key();
|
||||||
|
column_builder &unique();
|
||||||
|
column_builder &identity();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string column_name_;
|
std::string column_name_;
|
||||||
utils::basic_type type_{};
|
utils::basic_type type_{};
|
||||||
utils::constraints constraints_{};
|
utils::constraints constraints_{utils::constraints::NotNull};
|
||||||
|
size_t size_{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
class table_builder {
|
class table_builder {
|
||||||
public:
|
public:
|
||||||
explicit table_builder(std::string name);
|
explicit table_builder(std::string name);
|
||||||
|
|
||||||
table_builder& as(std::string table_alias);
|
|
||||||
|
|
||||||
// ReSharper disable once CppNonExplicitConversionOperator
|
// ReSharper disable once CppNonExplicitConversionOperator
|
||||||
operator query::table() const; // NOLINT(*-explicit-constructor)
|
operator table() const; // NOLINT(*-explicit-constructor)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string table_name;
|
std::string table_name;
|
||||||
std::string alias;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class constraint_builder {
|
class constraint_builder {
|
||||||
public:
|
public:
|
||||||
constraint_builder& constraint(std::string name);
|
constraint_builder &constraint(std::string name);
|
||||||
constraint_builder& primary_key(std::string name);
|
constraint_builder &primary_key(std::string name);
|
||||||
constraint_builder& foreign_key(std::string name);
|
constraint_builder &foreign_key(std::string name);
|
||||||
constraint_builder& references(std::string table, std::string column);
|
constraint_builder &references(std::string table, std::string column);
|
||||||
|
|
||||||
// ReSharper disable once CppNonExplicitConversionOperator
|
// ReSharper disable once CppNonExplicitConversionOperator
|
||||||
operator object::constraint() const; // NOLINT(*-explicit-constructor)
|
operator table_constraint() const; // NOLINT(*-explicit-constructor)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string constraint_name;
|
std::string constraint_name_;
|
||||||
std::string pk_column_name;
|
std::string column_name_;
|
||||||
std::string fk_column_name;
|
std::string ref_table_name_;
|
||||||
std::string table_name;
|
std::string ref_column_name_;
|
||||||
std::string column_name;
|
utils::constraints type_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
constraint_builder constraint(std::string name);
|
constraint_builder constraint(std::string name);
|
||||||
table_builder table(std::string name);
|
// table_builder table(std::string name);
|
||||||
column_builder column(std::string name, utils::basic_type type, size_t size = 0);
|
column_builder column(std::string name, utils::basic_type type, size_t size = 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif //MATADOR_BUILDER_HPP
|
#endif //MATADOR_BUILDER_HPP
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
#ifndef QUERY_COLUMN_HPP
|
|
||||||
#define QUERY_COLUMN_HPP
|
|
||||||
|
|
||||||
#include "matador/sql/sql_functions.hpp"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace matador::query {
|
|
||||||
|
|
||||||
class table;
|
|
||||||
|
|
||||||
class column {
|
|
||||||
public:
|
|
||||||
column(const char *name, const std::string& as = ""); // NOLINT(*-explicit-constructor)
|
|
||||||
column(std::string name, std::string as = "");
|
|
||||||
column(sql::sql_function_t func, std::string name); // NOLINT(*-explicit-constructor)
|
|
||||||
column(const class table &tab, std::string name, std::string as = "");
|
|
||||||
column(const std::shared_ptr<table> &t, std::string name, std::string as = "");
|
|
||||||
|
|
||||||
[[nodiscard]] bool equals(const column &x) const;
|
|
||||||
|
|
||||||
column& as(std::string a);
|
|
||||||
|
|
||||||
[[nodiscard]] const std::string& column_name() const;
|
|
||||||
[[nodiscard]] std::string full_name() const;
|
|
||||||
[[nodiscard]] const std::string& alias_name() const;
|
|
||||||
[[nodiscard]] bool is_function() const;
|
|
||||||
[[nodiscard]] sql::sql_function_t function() const;
|
|
||||||
[[nodiscard]] bool has_alias() const;
|
|
||||||
[[nodiscard]] std::string alias() const;
|
|
||||||
|
|
||||||
[[nodiscard]] std::shared_ptr<class table> table() const;
|
|
||||||
void table(const std::shared_ptr<query::table>& t);
|
|
||||||
|
|
||||||
operator const std::string&() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::shared_ptr<query::table> table_;
|
|
||||||
std::string name;
|
|
||||||
std::string alias_;
|
|
||||||
|
|
||||||
sql::sql_function_t function_{sql::sql_function_t::None};
|
|
||||||
};
|
|
||||||
|
|
||||||
column operator ""_col(const char *name, size_t len);
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif //QUERY_COLUMN_HPP
|
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "matador/query/criteria/between_criteria.hpp"
|
#include "matador/query/criteria/between_criteria.hpp"
|
||||||
#include "matador/query/criteria/binary_criteria.hpp"
|
#include "matador/query/criteria/binary_criteria.hpp"
|
||||||
|
#include "matador/query/criteria/check_null_criteria.hpp"
|
||||||
#include "matador/query/criteria/collection_criteria.hpp"
|
#include "matador/query/criteria/collection_criteria.hpp"
|
||||||
#include "matador/query/criteria/like_criteria.hpp"
|
#include "matador/query/criteria/like_criteria.hpp"
|
||||||
#include "matador/query/criteria/logical_criteria.hpp"
|
#include "matador/query/criteria/logical_criteria.hpp"
|
||||||
|
|||||||
@@ -3,19 +3,19 @@
|
|||||||
|
|
||||||
#include "matador/query/criteria/abstract_criteria.hpp"
|
#include "matador/query/criteria/abstract_criteria.hpp"
|
||||||
|
|
||||||
#include "matador/query/column.hpp"
|
#include "matador/query/table_column.hpp"
|
||||||
|
|
||||||
namespace matador::query {
|
namespace matador::query {
|
||||||
|
|
||||||
class abstract_column_criteria : public abstract_criteria {
|
class abstract_column_criteria : public abstract_criteria {
|
||||||
public:
|
public:
|
||||||
abstract_column_criteria() = delete;
|
abstract_column_criteria() = delete;
|
||||||
explicit abstract_column_criteria(column col);
|
explicit abstract_column_criteria(const table_column& col);
|
||||||
|
|
||||||
[[nodiscard]] const column& col() const;
|
[[nodiscard]] const table_column& col() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
column column_;
|
table_column column_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,15 +4,13 @@
|
|||||||
#include "matador/query/criteria/abstract_column_criteria.hpp"
|
#include "matador/query/criteria/abstract_column_criteria.hpp"
|
||||||
#include "matador/query/criteria/criteria_utils.hpp"
|
#include "matador/query/criteria/criteria_utils.hpp"
|
||||||
|
|
||||||
#include "matador/utils/value.hpp"
|
|
||||||
|
|
||||||
namespace matador::query {
|
namespace matador::query {
|
||||||
|
|
||||||
class between_criteria final : public abstract_column_criteria {
|
class between_criteria final : public abstract_column_criteria {
|
||||||
public:
|
public:
|
||||||
between_criteria() = delete;
|
between_criteria() = delete;
|
||||||
between_criteria(column col, int64_t min, int64_t max);
|
between_criteria(const table_column& col, int64_t min, int64_t max);
|
||||||
between_criteria(column col, utils::placeholder min, utils::placeholder max);
|
between_criteria(const table_column& col, utils::placeholder min, utils::placeholder max);
|
||||||
|
|
||||||
void accept(criteria_visitor& visitor) const override;
|
void accept(criteria_visitor& visitor) const override;
|
||||||
|
|
||||||
|
|||||||
@@ -3,23 +3,23 @@
|
|||||||
|
|
||||||
#include "matador/query/criteria/abstract_column_criteria.hpp"
|
#include "matador/query/criteria/abstract_column_criteria.hpp"
|
||||||
#include "matador/query/criteria/criteria_utils.hpp"
|
#include "matador/query/criteria/criteria_utils.hpp"
|
||||||
|
#include "matador/query/table_column.hpp"
|
||||||
#include "matador/query/column.hpp"
|
#include "matador/query/intermediates/fetchable_query.hpp"
|
||||||
|
|
||||||
namespace matador::query {
|
namespace matador::query {
|
||||||
enum class binary_operator {
|
enum class binary_operator {
|
||||||
EQUALS,
|
Equals,
|
||||||
NOT_EQUALS,
|
NotEquals,
|
||||||
GREATER_THAN,
|
GreaterThan,
|
||||||
GREATER_THAN_OR_EQUAL,
|
GreaterThanOrEqual,
|
||||||
LESS_THAN,
|
LessThan,
|
||||||
LESS_THAN_OR_EQUAL,
|
LessThanOrEqual,
|
||||||
};
|
};
|
||||||
|
|
||||||
class binary_criteria final : public abstract_column_criteria {
|
class binary_criteria final : public abstract_column_criteria {
|
||||||
public:
|
public:
|
||||||
binary_criteria() = delete;
|
binary_criteria() = delete;
|
||||||
binary_criteria(column col, binary_operator operand, criteria_value value);
|
binary_criteria(const table_column& col, binary_operator operand, criteria_value value);
|
||||||
|
|
||||||
void accept( criteria_visitor& visitor ) const override;
|
void accept( criteria_visitor& visitor ) const override;
|
||||||
|
|
||||||
@@ -34,18 +34,18 @@ private:
|
|||||||
class binary_column_criteria final : public abstract_criteria {
|
class binary_column_criteria final : public abstract_criteria {
|
||||||
public:
|
public:
|
||||||
binary_column_criteria() = delete;
|
binary_column_criteria() = delete;
|
||||||
binary_column_criteria(column left_column, binary_operator operand, column right_column);
|
binary_column_criteria(table_column left_column, binary_operator operand, table_column right_column);
|
||||||
|
|
||||||
void accept(criteria_visitor& visitor) const override;
|
void accept(criteria_visitor& visitor) const override;
|
||||||
|
|
||||||
[[nodiscard]] const column& left_column() const;
|
[[nodiscard]] const table_column& left_column() const;
|
||||||
[[nodiscard]] binary_operator operand() const;
|
[[nodiscard]] binary_operator operand() const;
|
||||||
[[nodiscard]] const column& right_column() const;
|
[[nodiscard]] const table_column& right_column() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
column left_column_;
|
table_column left_column_;
|
||||||
binary_operator operator_{};
|
binary_operator operator_{};
|
||||||
column right_column_;
|
table_column right_column_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif //CRITERIA_BINARY_CRITERIA_NODE_HPP
|
#endif //CRITERIA_BINARY_CRITERIA_NODE_HPP
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef MATADOR_IS_NULL_CRITERIA_HPP
|
||||||
|
#define MATADOR_IS_NULL_CRITERIA_HPP
|
||||||
|
|
||||||
|
#include "matador/query/criteria/abstract_column_criteria.hpp"
|
||||||
|
|
||||||
|
namespace matador::query {
|
||||||
|
enum class check_null_operator {
|
||||||
|
IsNull,
|
||||||
|
IsNotNull,
|
||||||
|
};
|
||||||
|
|
||||||
|
class check_null_criteria final : public abstract_column_criteria {
|
||||||
|
public:
|
||||||
|
check_null_criteria() = delete;
|
||||||
|
check_null_criteria(const table_column& col, check_null_operator op);
|
||||||
|
|
||||||
|
void accept(criteria_visitor& visitor) const override;
|
||||||
|
|
||||||
|
[[nodiscard]] check_null_operator operand() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
check_null_operator operator_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif // MATADOR_IS_NULL_CRITERIA_HPP
|
||||||
@@ -3,11 +3,14 @@
|
|||||||
|
|
||||||
#include "matador/query/criteria/abstract_column_criteria.hpp"
|
#include "matador/query/criteria/abstract_column_criteria.hpp"
|
||||||
#include "matador/query/criteria/criteria_utils.hpp"
|
#include "matador/query/criteria/criteria_utils.hpp"
|
||||||
|
#include "matador/query/intermediates/fetchable_query.hpp"
|
||||||
|
#include "matador/query/table.hpp"
|
||||||
|
|
||||||
#include "matador/query/column.hpp"
|
|
||||||
#include "matador/sql/query_context.hpp"
|
#include "matador/sql/query_context.hpp"
|
||||||
|
|
||||||
namespace matador::query {
|
namespace matador::query {
|
||||||
|
class table_column;
|
||||||
|
|
||||||
enum class collection_operator {
|
enum class collection_operator {
|
||||||
In,
|
In,
|
||||||
Out
|
Out
|
||||||
@@ -36,8 +39,8 @@ public:
|
|||||||
* @param operand_ Operator to use
|
* @param operand_ Operator to use
|
||||||
* @param values List of values
|
* @param values List of values
|
||||||
*/
|
*/
|
||||||
collection_criteria(column col, collection_operator operand_, std::vector<criteria_value> values);
|
collection_criteria(const table_column& col, collection_operator operand_, std::vector<criteria_value> values);
|
||||||
collection_criteria(column col, collection_operator operand_, std::initializer_list<criteria_value> values);
|
collection_criteria(const table_column& col, collection_operator operand_, std::initializer_list<criteria_value> values);
|
||||||
|
|
||||||
void accept(criteria_visitor& visitor) const override;
|
void accept(criteria_visitor& visitor) const override;
|
||||||
|
|
||||||
@@ -52,16 +55,16 @@ private:
|
|||||||
class collection_query_criteria final : public abstract_column_criteria {
|
class collection_query_criteria final : public abstract_column_criteria {
|
||||||
public:
|
public:
|
||||||
collection_query_criteria() = delete;
|
collection_query_criteria() = delete;
|
||||||
collection_query_criteria(column col, collection_operator operand_, sql::query_context ctx);
|
collection_query_criteria(const table_column& col, collection_operator operand_, fetchable_query ctx);
|
||||||
|
|
||||||
void accept(criteria_visitor& visitor) const override;
|
void accept(criteria_visitor& visitor) const override;
|
||||||
|
|
||||||
[[nodiscard]] collection_operator operand() const;
|
[[nodiscard]] collection_operator operand() const;
|
||||||
[[nodiscard]] const sql::query_context& context() const;
|
[[nodiscard]] const fetchable_query& query() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
collection_operator operand_;
|
collection_operator operand_;
|
||||||
sql::query_context query_context_;
|
fetchable_query query_context_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif //CRITERIA_COLLECTION_CRITERIA_NODE_HPP
|
#endif //CRITERIA_COLLECTION_CRITERIA_NODE_HPP
|
||||||
@@ -3,60 +3,68 @@
|
|||||||
|
|
||||||
#include "matador/query/criteria/binary_criteria.hpp"
|
#include "matador/query/criteria/binary_criteria.hpp"
|
||||||
#include "matador/query/criteria/collection_criteria.hpp"
|
#include "matador/query/criteria/collection_criteria.hpp"
|
||||||
|
#include "matador/query/intermediates/fetchable_query.hpp"
|
||||||
#include "matador/query/column.hpp"
|
|
||||||
|
|
||||||
#include "matador/utils/placeholder.hpp"
|
#include "matador/utils/placeholder.hpp"
|
||||||
#include "matador/utils/value.hpp"
|
#include "matador/utils/value.hpp"
|
||||||
|
|
||||||
|
namespace matador::utils {
|
||||||
|
class identifier;
|
||||||
|
}
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
struct query_context;
|
struct query_context;
|
||||||
}
|
}
|
||||||
namespace matador::query {
|
namespace matador::query {
|
||||||
|
class table_column;
|
||||||
|
|
||||||
template<class Type>
|
template<class Type>
|
||||||
criteria_ptr operator==(const column &col, Type val) {
|
std::enable_if_t<!std::is_base_of_v<fetchable_query, std::decay_t<Type>>, criteria_ptr>
|
||||||
return std::make_unique<binary_criteria>(col, binary_operator::EQUALS, utils::value(val));
|
operator==(const table_column &col, Type val) {
|
||||||
|
return std::make_unique<binary_criteria>(col, binary_operator::Equals, utils::value(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Type>
|
template<class Type>
|
||||||
criteria_ptr operator!=(const column &col, Type val) {
|
std::enable_if_t<!std::is_base_of_v<fetchable_query, std::decay_t<Type>>, criteria_ptr>
|
||||||
return std::make_unique<binary_criteria>(col, binary_operator::NOT_EQUALS, utils::value(val));
|
operator!=(const table_column &col, Type val) {
|
||||||
|
return std::make_unique<binary_criteria>(col, binary_operator::NotEquals, utils::value(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Type>
|
template<class Type>
|
||||||
criteria_ptr operator>(const column &col, Type val) {
|
criteria_ptr operator>(const table_column &col, Type val) {
|
||||||
return std::make_unique<binary_criteria>(col, binary_operator::GREATER_THAN, utils::value(val));
|
return std::make_unique<binary_criteria>(col, binary_operator::GreaterThan, utils::value(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Type>
|
template<class Type>
|
||||||
criteria_ptr operator>=(const column &col, Type val) {
|
criteria_ptr operator>=(const table_column &col, Type val) {
|
||||||
return std::make_unique<binary_criteria>(col, binary_operator::GREATER_THAN_OR_EQUAL, utils::value(val));
|
return std::make_unique<binary_criteria>(col, binary_operator::GreaterThanOrEqual, utils::value(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Type>
|
template<class Type>
|
||||||
criteria_ptr operator<(const column &col, Type val) {
|
criteria_ptr operator<(const table_column &col, Type val) {
|
||||||
return std::make_unique<binary_criteria>(col, binary_operator::LESS_THAN, utils::value(val));
|
return std::make_unique<binary_criteria>(col, binary_operator::LessThan, utils::value(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Type>
|
template<class Type>
|
||||||
criteria_ptr operator<=(const column &col, Type val) {
|
criteria_ptr operator<=(const table_column &col, Type val) {
|
||||||
return std::make_unique<binary_criteria>(col, binary_operator::LESS_THAN_OR_EQUAL, utils::value(val));
|
return std::make_unique<binary_criteria>(col, binary_operator::LessThanOrEqual, utils::value(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
criteria_ptr operator==(const column &col_left, const column &col_right);
|
criteria_ptr operator==(const table_column &col_left, const table_column &col_right);
|
||||||
criteria_ptr operator!=(const column &col_left, const column &col_right);
|
criteria_ptr operator!=(const table_column &col_left, const table_column &col_right);
|
||||||
criteria_ptr operator>(const column &col_left, const column &col_right);
|
criteria_ptr operator>(const table_column &col_left, const table_column &col_right);
|
||||||
criteria_ptr operator>=(const column &col_left, const column &col_right);
|
criteria_ptr operator>=(const table_column &col_left, const table_column &col_right);
|
||||||
criteria_ptr operator<(const column &col_left, const column &col_right);
|
criteria_ptr operator<(const table_column &col_left, const table_column &col_right);
|
||||||
criteria_ptr operator<=(const column &col_left, const column &col_right);
|
criteria_ptr operator<=(const table_column &col_left, const table_column &col_right);
|
||||||
|
|
||||||
criteria_ptr operator==(const column &col, utils::placeholder p);
|
criteria_ptr operator==(const table_column &col, utils::placeholder p);
|
||||||
criteria_ptr operator!=(const column &col, utils::placeholder p);
|
criteria_ptr operator!=(const table_column &col, utils::placeholder p);
|
||||||
criteria_ptr operator>(const column &col, utils::placeholder p);
|
criteria_ptr operator>(const table_column &col, utils::placeholder p);
|
||||||
criteria_ptr operator>=(const column &col, utils::placeholder p);
|
criteria_ptr operator>=(const table_column &col, utils::placeholder p);
|
||||||
criteria_ptr operator<(const column &col, utils::placeholder p);
|
criteria_ptr operator<(const table_column &col, utils::placeholder p);
|
||||||
criteria_ptr operator<=(const column &col, utils::placeholder p);
|
criteria_ptr operator<=(const table_column &col, utils::placeholder p);
|
||||||
|
|
||||||
|
criteria_ptr operator==(const table_column &col, const utils::identifier &id);
|
||||||
|
criteria_ptr operator!=(const table_column &col, const utils::identifier &id);
|
||||||
|
|
||||||
criteria_ptr operator&&(criteria_ptr left, criteria_ptr right);
|
criteria_ptr operator&&(criteria_ptr left, criteria_ptr right);
|
||||||
|
|
||||||
@@ -65,7 +73,7 @@ criteria_ptr operator||(criteria_ptr left, criteria_ptr right);
|
|||||||
criteria_ptr operator!(criteria_ptr clause);
|
criteria_ptr operator!(criteria_ptr clause);
|
||||||
|
|
||||||
template < class Type >
|
template < class Type >
|
||||||
criteria_ptr in(const column &col, std::initializer_list<Type> args) {
|
criteria_ptr in(const table_column &col, std::initializer_list<Type> args) {
|
||||||
std::vector<criteria_value> values;
|
std::vector<criteria_value> values;
|
||||||
for ( auto &&arg : args ) {
|
for ( auto &&arg : args ) {
|
||||||
values.emplace_back(utils::value{std::move(arg)});
|
values.emplace_back(utils::value{std::move(arg)});
|
||||||
@@ -74,12 +82,12 @@ criteria_ptr in(const column &col, std::initializer_list<Type> args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
criteria_ptr in(const column &col, std::initializer_list<utils::placeholder> args);
|
criteria_ptr in(const table_column &col, std::initializer_list<utils::placeholder> args);
|
||||||
|
|
||||||
criteria_ptr in(const column &col, sql::query_context &&ctx);
|
criteria_ptr in(const table_column &col, fetchable_query &&q);
|
||||||
|
|
||||||
template < class Type >
|
template < class Type >
|
||||||
criteria_ptr out(const column &col, std::initializer_list<Type> args) {
|
criteria_ptr out(const table_column &col, std::initializer_list<Type> args) {
|
||||||
std::vector<criteria_value> values;
|
std::vector<criteria_value> values;
|
||||||
for ( auto &&arg : args ) {
|
for ( auto &&arg : args ) {
|
||||||
values.emplace_back(utils::value{std::move(arg)});
|
values.emplace_back(utils::value{std::move(arg)});
|
||||||
@@ -88,14 +96,16 @@ criteria_ptr out(const column &col, std::initializer_list<Type> args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
criteria_ptr out(const column &col, std::initializer_list<utils::placeholder> args);
|
criteria_ptr out(const table_column &col, std::initializer_list<utils::placeholder> args);
|
||||||
|
criteria_ptr out(const table_column &col, fetchable_query &&q);
|
||||||
|
|
||||||
criteria_ptr out(const column &col, sql::query_context &&ctx);
|
criteria_ptr between(const table_column &col, int64_t min, int64_t max);
|
||||||
|
criteria_ptr between(const table_column &col, utils::placeholder min, utils::placeholder max);
|
||||||
|
|
||||||
criteria_ptr between(const column &col, int64_t min, int64_t max);
|
criteria_ptr like(const table_column &col, const std::string &pattern);
|
||||||
criteria_ptr between(const column &col, utils::placeholder min, utils::placeholder max);
|
|
||||||
|
|
||||||
criteria_ptr like(const column &col, const std::string &pattern);
|
criteria_ptr is_null(const table_column &col);
|
||||||
|
criteria_ptr is_not_null(const table_column &col);
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif //CRITERIA_CRITERIA_OPERATORS_HPP
|
#endif //CRITERIA_CRITERIA_OPERATORS_HPP
|
||||||
@@ -5,6 +5,7 @@ namespace matador::query {
|
|||||||
class between_criteria;
|
class between_criteria;
|
||||||
class binary_criteria;
|
class binary_criteria;
|
||||||
class binary_column_criteria;
|
class binary_column_criteria;
|
||||||
|
class check_null_criteria;
|
||||||
class like_criteria;
|
class like_criteria;
|
||||||
class logical_criteria;
|
class logical_criteria;
|
||||||
class not_criteria;
|
class not_criteria;
|
||||||
@@ -18,6 +19,7 @@ public:
|
|||||||
virtual void visit(const between_criteria &node) = 0;
|
virtual void visit(const between_criteria &node) = 0;
|
||||||
virtual void visit(const binary_criteria &node) = 0;
|
virtual void visit(const binary_criteria &node) = 0;
|
||||||
virtual void visit(const binary_column_criteria &node) = 0;
|
virtual void visit(const binary_column_criteria &node) = 0;
|
||||||
|
virtual void visit(const check_null_criteria &node) = 0;
|
||||||
virtual void visit(const collection_criteria &node) = 0;
|
virtual void visit(const collection_criteria &node) = 0;
|
||||||
virtual void visit(const collection_query_criteria &node) = 0;
|
virtual void visit(const collection_query_criteria &node) = 0;
|
||||||
virtual void visit(const like_criteria &node) = 0;
|
virtual void visit(const like_criteria &node) = 0;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user