Compare commits

..
Author SHA1 Message Date
sascha 24677d61df Merge remote-tracking branch 'origin/feature/matador-ng' into feature/matador-ng 2026-07-31 17:52:25 +02:00
sascha 5da70ba3a5 refactored object_proxy and object_ptr and fixed their bugs 2026-07-30 12:34:02 +02:00
sascha c880728093 refactored result that an overload for void doesn't need to exist 2026-07-30 12:33:24 +02:00
sascha 78b30f9742 removed double line 2026-07-30 12:32:19 +02:00
sascha b19d0fd3ca improved version::str() and version::from_string() 2026-07-28 09:53:25 +02:00
sascha 730ab05213 small result fixes 2026-07-28 09:52:49 +02:00
sascha 6ecda781f5 collection_proxy progress 2026-07-20 07:02:16 +02:00
sascha d4865e4d10 collection proxy progress 2026-07-07 08:23:43 +02:00
sascha 06f6166f05 Enhanced some test descriptions 2026-07-06 16:06:09 +02:00
sascha 89b795c488 fixed compilation 2026-07-06 06:53:11 +02:00
sascha 1b98eb4019 collection_proxy progress added test frame 2026-06-26 15:52:53 +02:00
sascha 47fd6d68e4 Merge remote-tracking branch 'origin/feature/matador-ng' into feature/matador-ng 2026-06-15 08:43:20 +02:00
sascha 34a5cfcc88 started refactoring collection proxy 2026-06-15 08:42:58 +02:00
sascha 705d361aaa fixed restriction and constraint class to use size_t 2026-06-03 16:36:51 +02:00
sascha 87bd2f8b89 Revert "fixed compile"
This reverts commit 8914c06833.
2026-06-03 11:19:24 +02:00
sascha 8914c06833 fixed compile 2026-06-03 11:06:47 +02:00
sascha 34a9a8aa4a fixed table constructor with join and inverse join columns 2026-06-02 16:43:31 +02:00
sascha 12f8590634 delete many to many progress 2026-06-01 16:44:07 +02:00
sascha cea7b97f2b added join_column_index and inverse_join_column_index to object and table classes 2026-06-01 06:57:38 +02:00
sascha bd06034ebf renamed binary_operator to be pascal case 2026-05-29 15:09:11 +02:00
sascha 68d67b17b7 delete has many to many progress 2026-05-28 15:45:46 +02:00
sascha 73bd6f641c delete has many to many progress 2026-05-27 16:10:26 +02:00
sascha 98d58d8e60 small fixes 2026-05-27 16:10:03 +02:00
sascha b22a830d18 added SessionDeleteHasMany and SessionDeleteHasManyToMany tests 2026-05-26 15:50:32 +02:00
sascha 85e6ee4b93 fixed delete_query_builder.hpp 2026-05-26 15:50:03 +02:00
sascha 2e1b583741 moved recipe and ingredient pk generators into recipe.hpp 2026-05-26 15:49:49 +02:00
sascha 6701031007 removed unused include 2026-05-26 15:49:13 +02:00
sascha 57f57956de added delete_query_builder (progress) 2026-05-26 07:01:53 +02:00
sascha 141d798a41 small fixes and renames 2026-05-23 20:48:21 +02:00
sascha cc0bcbeb61 fixed some includes 2026-05-23 20:23:29 +02:00
sascha 5ec7c13420 integrated object cache into session and added message bus to object_cache and update tests 2026-05-22 15:26:16 +02:00
sascha ddf19bbf07 updated return type 2026-05-21 12:39:25 +02:00
sascha 194e139e8b changed passed error in or_else to release_error 2026-05-21 12:39:10 +02:00
sascha 6629a71f6e use existing result error in query_builder_exception constructor 2026-05-21 12:38:46 +02:00
sascha 72019bc1e7 fixed insert_step_processor 2026-05-21 12:04:10 +02:00
sascha 7216f07c9f refactored insert_query_builder into insert_step_processor and added insert_context 2026-05-20 16:22:15 +02:00
sascha aa8da1f76f insert_query_builder optimizations 2026-05-19 15:50:39 +02:00
sascha 627af1d1a8 removed unused code 2026-05-18 22:04:09 +02:00
sascha 0f3028c5c7 use specific type for vector to match expected sizes 2026-05-18 19:25:20 +02:00
sascha 25405de2e0 renamed record_printer to RecordPrinter 2026-05-18 19:25:04 +02:00
sascha e58b7b9b0d moved prepare_* methods from dialect to query_utils 2026-05-18 15:05:00 +02:00
sascha 052ff657c1 updated todo.md 2026-05-18 14:07:20 +02:00
sascha 08a28b1627 completed session tests for lazy and eager has_many_to_many tests 2026-05-18 14:07:08 +02:00
sascha 60f03246dc rename record_printer to RecordPrinter 2026-05-18 13:48:34 +02:00
sascha caacdfa34a added has_one eager functionality and tests 2026-05-18 12:28:21 +02:00
sascha 8c8423bf64 fixed has one definitions 2026-05-18 09:03:41 +02:00
sascha 820b5432b2 renamed collection resolver producer related classes 2026-05-18 09:03:24 +02:00
sascha bf99642af4 resolve has one progress 2026-05-18 06:58:26 +02:00
sascha 9f54716df2 resolve has one progress 2026-05-17 21:46:43 +02:00
sascha 57703dfb67 has one progress 2026-05-15 15:22:59 +02:00
sascha 22f6f71412 insert has one progress 2026-05-15 07:24:48 +02:00
sascha 1cdd83cb31 added belongs to and has one tests 2026-05-13 16:09:35 +02:00
sascha e3618c60e3 added more has many to many test cases with different pk generators 2026-05-12 16:04:11 +02:00
sascha ceb7795d9c has many primitive collection resolver with table and sequence 2026-05-11 21:17:27 +02:00
sascha 68eb2b6a6e has many primitive collection resolver 2026-05-11 20:54:48 +02:00
sascha a714cd2a53 has many primitive relation progress 2026-05-08 15:53:52 +02:00
sascha 1e08996087 renamed a member variable 2026-05-07 16:18:08 +02:00
sascha 5e6ba3666e added benchmark test suite 2026-05-07 14:29:35 +02:00
sascha 3d4a61749b renamed template parameters 2026-05-07 14:28:22 +02:00
sascha 3658664eb9 added checks to SessionInsertHasMany Test 2026-05-07 10:21:29 +02:00
sascha 8753042b3c added is_state method to object_proxy and object_ptr to check state 2026-05-07 10:06:38 +02:00
sascha 85d297995d insert query builder insert step improvements 2026-05-07 09:27:21 +02:00
sascha e6adffc264 insert query builder insert step refactoring progress 2026-05-06 22:51:16 +02:00
sascha 95cd363097 Merge remote-tracking branch 'origin/feature/matador-ng' into feature/matador-ng 2026-05-06 16:18:39 +02:00
sascha 9c37e989ba insert query builder improvements progress 2026-05-06 16:18:27 +02:00
sascha e7523e2bba updated catch2 2026-05-02 18:59:56 +02:00
sascha 37855dc6fb fixed sequence table 2026-04-30 15:49:54 +02:00
sascha 433b0e40e1 sequence table progress 2026-04-29 16:08:53 +02:00
171 changed files with 4451 additions and 1803 deletions
@@ -33,7 +33,7 @@ public:
utils::result<sql::execute_result, utils::error> execute(const sql::query_context &context) 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;
@@ -43,16 +43,16 @@ public:
[[nodiscard]] std::string to_escaped_string( const utils::blob_type_t& value ) const 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) ;
utils::result<sql::execute_result, utils::error> execute(const std::string &stmt) const; [[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_;
}; };
} }
+15 -18
View File
@@ -7,14 +7,15 @@
#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) {
@@ -82,20 +83,20 @@ 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)) {
const auto err = make_error(sql::error_code::FetchFailed, 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); PQclear(res);
return utils::failure(err); 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)) {
const auto err = make_error(sql::error_code::FetchFailed, 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); PQclear(res);
return utils::failure(err); return utils::failure(err);
} }
@@ -111,22 +112,18 @@ utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> postgres_co
return utils::ok(std::make_unique<sql::query_result_impl>(std::make_unique<postgres_result_reader>(res), return utils::ok(std::make_unique<sql::query_result_impl>(std::make_unique<postgres_result_reader>(res),
std::move(prototype), std::move(prototype),
context.resolver, ctx.resolver,
context.result_type)); 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 = statement_name_map_.find(name.str());
if (result == statement_name_map_.end()) { if (it == statement_name_map_.end()) {
result = 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<sql::execute_result, utils::error> postgres_connection::execute(const std::string& stmt) const { utils::result<sql::execute_result, utils::error> postgres_connection::execute(const std::string& stmt) const {
+7 -7
View File
@@ -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;
+20 -14
View File
@@ -1,4 +1,4 @@
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)
@@ -10,9 +10,6 @@ configure_file(Connection.hpp.in ${PROJECT_BINARY_DIR}/backends/postgres/test/co
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,23 +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/TypeTraitsTest.cpp
../../../test/utils/record_printer.hpp
../../../test/utils/record_printer.cpp
../../../test/models/model_metas.hpp
../../../test/backends/SequenceFixture.hpp
../../../test/backends/SequenceFixture.cpp
../../../test/backends/SequenceTest.cpp
../../../test/backends/TableSequenceFixture.hpp
../../../test/backends/TableSequenceFixture.cpp ../../../test/backends/TableSequenceFixture.cpp
../../../test/backends/TableSequenceFixture.hpp
../../../test/backends/TableSequenceTest.cpp ../../../test/backends/TableSequenceTest.cpp
../../../test/backends/SessionInsertHasMany.cpp ../../../test/backends/TypeTraitsTest.cpp
../../../test/backends/SessionInsertHasManyToManyTest.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 -2
View File
@@ -100,7 +100,7 @@ struct user {
namespace field = access; namespace field = access;
field::primary_key( op, "id", id ); field::primary_key( op, "id", id );
field::attribute( op, "username", username, VarChar255 ); field::attribute( op, "username", username, VarChar255 );
field::has_one(op, "profile_id", profile, utils::CascadeNoneFetchLazy ); field::has_one(op, "profiles", profile, "profile_id", utils::CascadeNoneFetchLazy );
} }
}; };
@@ -139,7 +139,7 @@ int main() {
sql::resolver_service rs; sql::resolver_service rs;
std::weak_ptr cr = rs.collection_resolver<object::object_ptr<names>>( typeid(person), "names" ); std::weak_ptr cr = rs.joined_collection_resolver<object::object_ptr<names>>( typeid(person), "names" );
utils::identifier id{1}; utils::identifier id{1};
object::collection_proxy cp(cr, id); object::collection_proxy cp(cr, id);
@@ -1,24 +1,22 @@
#ifndef MATADOR_ABSTRACT_COLLECTION_RESOLVER_HPP #ifndef MATADOR_ABSTRACT_COLLECTION_RESOLVER_HPP
#define MATADOR_ABSTRACT_COLLECTION_RESOLVER_HPP #define MATADOR_ABSTRACT_COLLECTION_RESOLVER_HPP
#include "matador/object/abstract_type_resolver.hpp"
#include <string> #include <string>
#include <typeindex> #include <typeindex>
namespace matador::object { namespace matador::object {
class abstract_collection_resolver { class abstract_joined_resolver : public abstract_type_resolver {
public: public:
virtual ~abstract_collection_resolver() = default;
[[nodiscard]] const std::type_index& root_type() const; [[nodiscard]] const std::type_index& root_type() const;
[[nodiscard]] const std::type_index& type() const;
[[nodiscard]] const std::string& collection_name() const; [[nodiscard]] const std::string& collection_name() const;
protected: protected:
explicit abstract_collection_resolver(const std::type_index& root_type, const std::type_index& type, std::string collection_name); explicit abstract_joined_resolver(const std::type_index& root_type, const std::type_index& type, std::string collection_name);
public: public:
const std::type_index root_type_; const std::type_index root_type_;
const std::type_index type_;
const std::string collection_name_; const std::string collection_name_;
}; };
} }
+2
View File
@@ -34,6 +34,7 @@ public:
[[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]] 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;
@@ -68,6 +69,7 @@ private:
friend class object_generator; friend class object_generator;
std::string name_; std::string name_;
size_t index_{0};
std::weak_ptr<object> owner_; std::weak_ptr<object> owner_;
utils::basic_type type_{utils::basic_type::Null}; utils::basic_type type_{utils::basic_type::Null};
utils::field_attributes options_{}; utils::field_attributes options_{};
+3 -3
View File
@@ -27,12 +27,12 @@ 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]] std::shared_ptr<class object> object() const;
[[nodiscard]] const std::list<attribute>& attributes() const; [[nodiscard]] const std::vector<attribute>& attributes() const;
[[nodiscard]] const std::list<class restriction>& constraints() 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; void update_name(const std::string& name) const;
+1 -1
View File
@@ -95,7 +95,7 @@ public:
return basic_info(std::type_index(typeid(Type))); return basic_info(std::type_index(typeid(Type)));
} }
[[nodiscard]] utils::result<attribute*, utils::error> primary_key_attribute(const std::type_index &ti) const; [[nodiscard]] utils::result<const attribute*, utils::error> primary_key_attribute(const std::type_index &ti) const;
void dump(std::ostream &os) const; void dump(std::ostream &os) const;
static void dump(std::ostream &os, const repository_node& node); static void dump(std::ostream &os, const repository_node& node);
+8 -8
View File
@@ -21,31 +21,31 @@ public:
collection(const collection& other) = default; collection(const collection& other) = default;
void push_back(const value_type& value) { void push_back(const value_type& value) {
proxy_->items().push_back(value); proxy_->push_back(value);
} }
iterator begin() { iterator begin() {
return proxy_->items().begin(); return proxy_->begin();
} }
iterator end() { iterator end() {
return proxy_->items().end(); return proxy_->end();
} }
const_iterator begin() const { const_iterator begin() const {
return proxy_->items().begin(); return proxy_->begin();
} }
const_iterator end() const { const_iterator end() const {
return proxy_->items().end(); return proxy_->end();
} }
[[nodiscard]] size_t size() const { [[nodiscard]] size_t size() const {
return proxy_->items().size(); return proxy_->size();
} }
[[nodiscard]] bool empty() const { [[nodiscard]] bool empty() const {
return proxy_->items().empty(); return proxy_->empty();
} }
void reset(std::shared_ptr<collection_proxy<Type>> proxy) { void reset(std::shared_ptr<collection_proxy<Type>> proxy) {
@@ -53,7 +53,7 @@ public:
} }
private: private:
std::shared_ptr<collection_proxy<Type>> proxy_; std::shared_ptr<abstract_collection_proxy<Type>> proxy_;
}; };
} }
+124 -10
View File
@@ -1,8 +1,8 @@
#ifndef MATADOR_COLLECTION_PROXY_HPP #ifndef MATADOR_COLLECTION_PROXY_HPP
#define MATADOR_COLLECTION_PROXY_HPP #define MATADOR_COLLECTION_PROXY_HPP
#include "matador/object/collection_resolver.hpp" #include "matador/object/collection_resolver.hpp"
#include "matador/object/many_to_many_relation.hpp"
#include "matador/utils/identifier.hpp" #include "matador/utils/identifier.hpp"
@@ -12,13 +12,99 @@
namespace matador::object { namespace matador::object {
// has many primitive
// relation<OwnerType, PrimitiveType>
// has many ptr
// relation<OwnerType, ObjectType>
// has many to many
// relation<OwnerType, ForeignType>
template<typename Type> template < class RelationType >
class collection_proxy final { 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: public:
using value_type = Type; using value_type = Type;
using iterator = typename std::vector<value_type>::iterator; using reference = Type&;
using const_iterator = typename std::vector<value_type>::const_iterator; 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; collection_proxy() = default;
@@ -34,17 +120,32 @@ public:
explicit collection_proxy(std::vector<Type> items) explicit collection_proxy(std::vector<Type> items)
: items_(std::move(items)) {} : items_(std::move(items)) {}
[[nodiscard]] const utils::identifier& owner_id() const { [[nodiscard]] const utils::identifier& owner_id() const override {
return owner_id_; return owner_id_;
} }
const std::vector<Type>& items() const {
iterator begin() override {
resolve(); resolve();
return items_; return items_.begin();
} }
std::vector<Type>& items() { iterator end() override {
resolve(); resolve();
return items_; 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: private:
void resolve() { void resolve() {
if (loaded_) { if (loaded_) {
@@ -70,5 +171,18 @@ private:
std::weak_ptr<collection_resolver<Type>> resolver_{}; std::weak_ptr<collection_resolver<Type>> resolver_{};
mutable std::mutex mutex_{}; 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 #endif //MATADOR_COLLECTION_PROXY_HPP
@@ -1,7 +1,7 @@
#ifndef MATADOR_COLLECTION_RESOLVER_HPP #ifndef MATADOR_COLLECTION_RESOLVER_HPP
#define MATADOR_COLLECTION_RESOLVER_HPP #define MATADOR_COLLECTION_RESOLVER_HPP
#include "matador/object/abstract_collection_resolver.hpp" #include "matador/object/abstract_joined_resolver.hpp"
#include <typeindex> #include <typeindex>
#include <vector> #include <vector>
@@ -12,10 +12,10 @@ class identifier;
namespace matador::object { namespace matador::object {
template<typename Type> template<typename Type>
class collection_resolver : public abstract_collection_resolver { class collection_resolver : public abstract_joined_resolver {
public: public:
collection_resolver(const std::type_index& root_type, std::string collection_name) collection_resolver(const std::type_index& root_type, std::string collection_name)
: abstract_collection_resolver(root_type, typeid(Type), std::move(collection_name)) {} : abstract_joined_resolver(root_type, typeid(Type), std::move(collection_name)) {}
virtual std::vector<Type> resolve(const utils::identifier& id) = 0; virtual std::vector<Type> resolve(const utils::identifier& id) = 0;
}; };
@@ -1,28 +0,0 @@
#ifndef MATADOR_CONTAINER_RESOLVER_FACTORY_HPP
#define MATADOR_CONTAINER_RESOLVER_FACTORY_HPP
#include "matador/object/collection_resolver.hpp"
namespace matador::object {
class abstract_collection_resolver_factory {
public:
virtual ~abstract_collection_resolver_factory() = default;
[[nodiscard]] virtual std::shared_ptr<abstract_collection_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_collection_resolver> &&resolver) = 0;
};
class 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);
}
};
}
#endif //MATADOR_CONTAINER_RESOLVER_FACTORY_HPP
@@ -50,7 +50,7 @@ public:
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 &, void on_has_many(const char *id, CollectionType &,
const char *join_column, const char *join_column,
@@ -134,7 +134,7 @@ void foreign_node_completer<NodeType, Observers...>::on_belongs_to(const char *
template<typename NodeType, template<typename> typename ...Observers> template<typename NodeType, template<typename> typename ...Observers>
template<class ForeignPointerType> template<class ForeignPointerType>
void foreign_node_completer<NodeType, Observers...>::on_has_one(const char * /*id*/, 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>();
} }
@@ -34,7 +34,7 @@ public:
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:
@@ -46,6 +88,11 @@ 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) {
+11 -4
View File
@@ -17,17 +17,21 @@ public:
static const attribute& create_attribute(std::string name, const std::shared_ptr<object>& obj); static const attribute& create_attribute(std::string name, const std::shared_ptr<object>& obj);
[[nodiscard]] attribute* primary_key_attribute() const; [[nodiscard]] const 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;
void update_name(const std::string& name); void update_name(const std::string& name);
[[nodiscard]] bool has_attributes() const; [[nodiscard]] bool has_attributes() const;
[[nodiscard]] size_t attribute_count() const; [[nodiscard]] size_t attribute_count() const;
[[nodiscard]] const std::list<attribute>& attributes() const; [[nodiscard]] const std::vector<attribute>& attributes() const;
[[nodiscard]] bool has_constraints() const; [[nodiscard]] bool has_constraints() const;
[[nodiscard]] size_t constraint_count() const; [[nodiscard]] size_t constraint_count() const;
@@ -40,9 +44,12 @@ private:
friend class object_generator; friend class object_generator;
std::string name_; std::string name_;
attribute* pk_attribute_{nullptr}; int pk_column_index_{-1};
int join_column_index_{-1};
int inverse_join_column_index_{-1};
utils::identifier pk_identifier_; utils::identifier pk_identifier_;
std::list<attribute> attributes_; std::vector<attribute> attributes_;
std::list<restriction> constraints_; std::list<restriction> constraints_;
}; };
} }
+113 -23
View File
@@ -5,6 +5,7 @@
#include "matador/object/object_resolver.hpp" #include "matador/object/object_resolver.hpp"
#include "matador/utils/identifier.hpp" #include "matador/utils/identifier.hpp"
#include "matador/utils/message_bus.hpp"
#include <unordered_map> #include <unordered_map>
#include <memory> #include <memory>
@@ -25,16 +26,33 @@ struct cache_entry_base {
[[nodiscard]] virtual bool is_dead() const noexcept = 0; [[nodiscard]] virtual bool is_dead() const noexcept = 0;
}; };
template<typename T> template<typename Type>
struct cache_entry : cache_entry_base { struct cache_entry : cache_entry_base {
std::weak_ptr<object_proxy<T> > proxy; std::weak_ptr<object_proxy<Type> > proxy;
std::weak_ptr<T> entity; std::weak_ptr<Type> entity;
[[nodiscard]] bool is_dead() const noexcept override { [[nodiscard]] bool is_dead() const noexcept override {
return proxy.expired() && entity.expired(); 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. * @brief Thread-sicherer Cache für Objekt-Proxies und (optional) geladene Entities.
* *
@@ -54,7 +72,8 @@ public:
/** /**
* @brief Erzeugt einen leeren Cache. * @brief Erzeugt einen leeren Cache.
*/ */
object_cache() = default; explicit object_cache(utils::message_bus &bus)
: bus_(bus) {}
/** /**
* @brief Liefert einen Proxy für (T, id) und erstellt ihn bei Bedarf. * @brief Liefert einen Proxy für (T, id) und erstellt ihn bei Bedarf.
@@ -63,8 +82,8 @@ public:
* Andernfalls wird ein neuer Proxy erzeugt, im Cache abgelegt und zurückgegeben. * 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. * Falls für (T, id) bereits eine Entity vorhanden ist, wird sie an den Proxy gebunden.
* *
* @tparam T Entity-Typ. * @tparam Type Entity-Typ.
* @tparam ResolverPtr Zeiger-Typ auf einen Resolver, typischerweise * @tparam ResolverPointerType Zeiger-Typ auf einen Resolver, typischerweise
* @c std::shared_ptr<object_resolver<T>> oder @c std::weak_ptr<object_resolver<T>>. * @c std::shared_ptr<object_resolver<T>> oder @c std::weak_ptr<object_resolver<T>>.
* @param id Identifier/Primärschlüssel der Entity. * @param id Identifier/Primärschlüssel der Entity.
* @param resolver_ptr Resolver (shared/weak), der zur Lazy-Auflösung durch den Proxy genutzt wird. * @param resolver_ptr Resolver (shared/weak), der zur Lazy-Auflösung durch den Proxy genutzt wird.
@@ -72,23 +91,24 @@ public:
* *
* @note Diese Methode ist threadsafe. * @note Diese Methode ist threadsafe.
*/ */
template<typename T, typename ResolverPtr> template<typename Type, typename ResolverPointerType>
std::shared_ptr<object_proxy<T>> acquire_proxy(utils::identifier id, ResolverPtr &&resolver_ptr) { std::shared_ptr<object_proxy<Type>> acquire_proxy(utils::identifier id, ResolverPointerType &&resolver_ptr) {
const auto k = make_key<T>(id); const auto k = make_key<Type>(id);
std::unique_lock lock(mutex_); std::unique_lock lock(mutex_);
auto it = map_.find(k); auto it = map_.find(k);
if (it != map_.end()) { if (it != map_.end()) {
// found entry, return std::shared_ptr of proxy // found entry, return std::shared_ptr of proxy
auto *entry = entry_cast_<T>(it->second.get()); auto *entry = entry_cast_<Type>(it->second.get());
if (auto proxy_ptr = entry->proxy.lock()) { if (auto proxy_ptr = entry->proxy.lock()) {
bus_.publish<object_cache_accessed_event>({k.type, id, std::chrono::steady_clock::now()});
return proxy_ptr; return proxy_ptr;
} }
// if the proxy is dead, but the entity is alive, create a new proxy and attach entity // if the proxy is dead, but the entity is alive, create a new proxy and attach entity
auto weak_resolver = to_weak<T>(std::forward<ResolverPtr>(resolver_ptr)); auto weak_resolver = to_weak<Type>(std::forward<ResolverPointerType>(resolver_ptr));
auto proxy_ptr = std::make_shared<object_proxy<T>>(weak_resolver, id); auto proxy_ptr = std::make_shared<object_proxy<Type>>(weak_resolver, id);
if (auto obj = entry->entity.lock()) { if (auto obj = entry->entity.lock()) {
proxy_ptr->attach(std::move(obj)); proxy_ptr->attach(std::move(obj));
@@ -96,17 +116,19 @@ public:
entry->proxy = proxy_ptr; 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 the shared_ptr of the proxy
return proxy_ptr; return proxy_ptr;
} }
// entry couldn't be found, create a new entry // entry couldn't be found, create a new entry
auto entry_ptr = std::make_unique<cache_entry<T>>(); auto entry_ptr = std::make_unique<cache_entry<Type>>();
auto *entry = entry_ptr.get(); auto *entry = entry_ptr.get();
// create a weak resolver and shared proxy // create a weak resolver and shared proxy
auto weak_resolver = to_weak<T>(std::forward<ResolverPtr>(resolver_ptr)); auto weak_resolver = to_weak<Type>(std::forward<ResolverPointerType>(resolver_ptr));
auto proxy_ptr = std::make_shared<object_proxy<T>>(weak_resolver, id); auto proxy_ptr = std::make_shared<object_proxy<Type>>(weak_resolver, id);
// lock entity and attach to proxy // lock entity and attach to proxy
if (auto obj = entry->entity.lock()) { if (auto obj = entry->entity.lock()) {
@@ -117,10 +139,65 @@ public:
entry->proxy = proxy_ptr; entry->proxy = proxy_ptr;
map_.emplace(k, std::move(entry_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 the shared_ptr of the proxy
return proxy_ptr; 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). * @brief Verknüpft eine geladene Entity mit einem Cache-Eintrag (Type, id).
* *
@@ -145,6 +222,7 @@ public:
auto *entry = entry_ptr.get(); auto *entry = entry_ptr.get();
entry->entity = obj; entry->entity = obj;
map_.emplace(k, std::move(entry_ptr)); map_.emplace(k, std::move(entry_ptr));
bus_.publish<object_cache_entity_attached_event>({k.type, id, std::chrono::steady_clock::now()});
return; return;
} }
@@ -155,6 +233,8 @@ public:
proxy->attach(std::move(obj)); proxy->attach(std::move(obj));
} }
bus_.publish<object_cache_entity_attached_event>({k.type, id, std::chrono::steady_clock::now()});
prune_if_dead(it); prune_if_dead(it);
} }
@@ -179,6 +259,9 @@ public:
auto *entry = entry_cast_<Type>(it->second.get()); auto *entry = entry_cast_<Type>(it->second.get());
auto entity_ptr = entry->entity.lock(); 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); prune_if_dead(it);
return entity_ptr; return entity_ptr;
} }
@@ -204,6 +287,9 @@ public:
auto *entry = entry_cast_<Type>(it->second.get()); auto *entry = entry_cast_<Type>(it->second.get());
const bool loaded = !entry->entity.expired(); 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); prune_if_dead(it);
return loaded; return loaded;
} }
@@ -224,6 +310,7 @@ public:
} }
map_.erase(it); map_.erase(it);
bus_.publish<object_cache_erased_event>({k.type, id, std::chrono::steady_clock::now()});
} }
/** /**
@@ -246,6 +333,10 @@ public:
} }
} }
if (removed > 0) {
bus_.publish<object_cache_sweep_event>({removed, std::chrono::steady_clock::now()});
}
return removed; return removed;
} }
@@ -286,12 +377,10 @@ private:
} }
template<typename T, typename U> template<typename T, typename U>
using enable_if_resolver_shared_ptr_t = using enable_if_resolver_shared_ptr_t = std::enable_if_t<std::is_base_of_v<object_resolver<T>, U>, int>;
std::enable_if_t<std::is_base_of_v<object_resolver<T>, U>, int>;
template<typename T, typename U> template<typename T, typename U>
using enable_if_resolver_weak_ptr_t = using enable_if_resolver_weak_ptr_t = std::enable_if_t<std::is_base_of_v<object_resolver<T>, U>, int>;
std::enable_if_t<std::is_base_of_v<object_resolver<T>, U>, int>;
// shared_ptr<Derived> -> weak_ptr<Base> // shared_ptr<Derived> -> weak_ptr<Base>
template<typename T, typename U, enable_if_resolver_shared_ptr_t<T, U> = 0> template<typename T, typename U, enable_if_resolver_shared_ptr_t<T, U> = 0>
@@ -306,8 +395,8 @@ private:
} }
// (2) Opportunistischer Cleanup: entferne Entry, wenn beide weak_ptr abgelaufen sind. // (2) Opportunistischer Cleanup: entferne Entry, wenn beide weak_ptr abgelaufen sind.
template<typename It> template<typename IteratorType>
bool prune_if_dead(It &it) { bool prune_if_dead(IteratorType &it) {
if (it == map_.end()) { if (it == map_.end()) {
return false; return false;
} }
@@ -319,14 +408,15 @@ private:
return false; return false;
} }
template<typename T> template<typename Type>
void prune_if_dead_typed(typename std::unordered_map<key, std::unique_ptr<cache_entry_base>, key_hash>::iterator &it) { void prune_if_dead_typed(typename std::unordered_map<key, std::unique_ptr<cache_entry_base>, key_hash>::iterator &it) {
(void)T{}; // T bleibt im Interface, damit bestehende Call-Sites unverändert bleiben können. (void)Type{}; // T bleibt im Interface, damit bestehende Call-Sites unverändert bleiben können.
prune_if_dead(it); prune_if_dead(it);
} }
private: private:
mutable std::shared_mutex mutex_{}; mutable std::shared_mutex mutex_{};
utils::message_bus &bus_;
std::unordered_map<key, std::unique_ptr<cache_entry_base>, key_hash> map_; std::unordered_map<key, std::unique_ptr<cache_entry_base>, key_hash> map_;
}; };
+17 -7
View File
@@ -35,7 +35,7 @@ public:
template<class Pointer> template<class Pointer>
static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
template<class Pointer> template<class Pointer>
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_has_one(const char * /*id*/, Pointer &/*x*/, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {} static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType> template<class ContainerType>
@@ -58,7 +58,11 @@ public:
} }
template < class Type > template < class Type >
static std::shared_ptr<object> generate(std::unique_ptr<Type>&& t, basic_repository &repo, const std::string &name) { 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)); const std::type_index ti(typeid(Type));
if (repo.has_object_for_type(ti)) { if (repo.has_object_for_type(ti)) {
auto obj = repo.object_for_type(ti); auto obj = repo.object_for_type(ti);
@@ -71,6 +75,9 @@ public:
std::ignore = repo.provide_object_in_advance(ti, obj); std::ignore = repo.provide_object_in_advance(ti, obj);
object_generator gen(repo, obj); object_generator gen(repo, obj);
access::process(gen, *t); access::process(gen, *t);
if (!join_column.empty() && !inverse_join_column.empty()) {
gen.prepare_relation_table(join_column, inverse_join_column);
}
return obj; return obj;
} }
@@ -92,12 +99,13 @@ public:
create_fk_constraint<typename Pointer::value_type>(id); create_fk_constraint<typename Pointer::value_type>(id);
} }
template<class Pointer> template<class Pointer>
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_has_one(const char * /*id*/, Pointer &/*x*/, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {}
template <class Pointer> template <class Pointer>
void on_foreign_key(const char *id, Pointer &/*x*/) { void on_foreign_key(const char *id, Pointer &/*x*/) {
const auto type = pk_type_determinator::determine<typename Pointer::value_type>(); 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); auto &ref = object_->attributes_.emplace_back(id, type, utils::constraints::ForeignKey, null_option_type::NotNull);
ref.index_ = object_->attributes_.size() - 1;
ref.owner_ = object_; ref.owner_ = object_;
} }
template<class ContainerType> template<class ContainerType>
@@ -111,6 +119,7 @@ private:
template<typename ValueType> template<typename ValueType>
attribute &emplace_attribute(const char *id, const utils::field_attributes& attr, null_option_type null_option) { 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); 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_; ref.owner_ = object_;
return ref; return ref;
} }
@@ -120,9 +129,10 @@ private:
void create_fk_constraint(const std::string& name) const; void create_fk_constraint(const std::string& name) const;
void create_unique_constraint(const std::string& name) const; void create_unique_constraint(const std::string& name) const;
[[nodiscard]] std::list<attribute>::iterator find_attribute_by_name(const std::string &name) const; [[nodiscard]] std::vector<attribute>::iterator find_attribute_by_name(const std::string &name) const;
void prepare_primary_key(attribute &ref, utils::identifier &&pk) 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> template<typename Type>
[[nodiscard]] std::shared_ptr<object> fk_object() const; [[nodiscard]] std::shared_ptr<object> fk_object() const;
@@ -135,7 +145,7 @@ private:
template<typename ValueType> template<typename ValueType>
void object_generator::on_primary_key(const char *id, ValueType &x, const utils::primary_key_attribute& attr) { void object_generator::on_primary_key(const char *id, ValueType &x, const utils::primary_key_attribute& attr) {
utils::constraints cs = utils::constraints::PrimaryKey; auto cs = utils::constraints::PrimaryKey;
if (attr.generator() == utils::generator_type::Identity) { if (attr.generator() == utils::generator_type::Identity) {
cs |= utils::constraints::Identity; cs |= utils::constraints::Identity;
} }
@@ -160,7 +170,7 @@ void object_generator::create_fk_constraint(const std::string& name) const {
return; return;
} }
const auto obj = fk_object<Type>(); const auto obj = fk_object<Type>();
restriction pk_constraint(*pk_attr); restriction pk_constraint(pk_attr->index());
pk_constraint.options_ |= utils::constraints::ForeignKey; pk_constraint.options_ |= utils::constraints::ForeignKey;
pk_constraint.owner_ = object_; pk_constraint.owner_ = object_;
pk_constraint.reference_ = obj; pk_constraint.reference_ = obj;
+115 -37
View File
@@ -26,86 +26,164 @@ public:
// Lazy // Lazy
object_proxy(std::weak_ptr<object_resolver<Type>> resolver, utils::identifier id) object_proxy(std::weak_ptr<object_resolver<Type>> resolver, utils::identifier id)
: resolver_(resolver) : resolver_(std::move(resolver))
, pk_(std::move(id)) { , pk_(std::move(id))
, state_(object_state::Persistent) {
} }
// Eager // Eager
object_proxy(std::weak_ptr<object_resolver<Type>> resolver, std::shared_ptr<Type> obj) object_proxy(std::weak_ptr<object_resolver<Type>> resolver, std::shared_ptr<Type> obj)
: obj_(obj) : obj_(std::move(obj))
, resolver_(resolver) , resolver_(std::move(resolver))
, pk_(primary_key_resolver::resolve_object(*obj).pk) , pk_(obj_ ? primary_key_resolver::resolve_object(*obj_).pk : utils::identifier{})
, state_(object_state::Persistent){ , state_(obj_ ? object_state::Persistent : object_state::Detached) {
} }
// Transient // Transient
explicit object_proxy(std::shared_ptr<Type> obj) explicit object_proxy(std::shared_ptr<Type> obj)
: obj_(obj) : obj_(std::move(obj))
, pk_(primary_key_resolver::resolve_object(*obj).pk) { , pk_(obj_ ? primary_key_resolver::resolve_object(*obj_).pk : utils::identifier{}) {
} }
void attach(std::shared_ptr<Type> obj) { void attach(std::shared_ptr<Type> obj) {
std::lock_guard lock(mutex_); std::lock_guard lock(mutex_);
obj_ = std::move(obj); obj_ = std::move(obj);
if (obj_) { if (!obj_) {
pk_ = primary_key_resolver::resolve_object(*obj_).pk; pk_.clear();
state_.store(object_state::Persistent, std::memory_order_release); 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);
}
[[nodiscard]] std::shared_ptr<Type> object() const {
return resolve_object();
} }
void invalidate() { void invalidate() {
std::lock_guard lock(mutex_); std::lock_guard lock(mutex_);
obj_.reset(); obj_.reset();
resolver_.reset(); resolver_.reset();
state_.store(object_state::Detached, std::memory_order_release); state_ = object_state::Detached;
} }
[[nodiscard]] void *raw_pointer() const { return static_cast<void *>(pointer()); } [[nodiscard]] void *raw_pointer() const { return static_cast<void *>(pointer()); }
Type *operator->() { return pointer(); } Type *operator->() {
Type &operator*() { return *pointer(); } auto *ptr = pointer();
const Type &operator*() const { return *pointer(); } if (!ptr) {
throw std::runtime_error("Cannot dereference empty object proxy");
}
return ptr;
}
Type *pointer() const { return resolve(); } 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 empty() const { return !obj_ && resolver_.expired(); }
[[nodiscard]] bool valid() const { return !empty(); } [[nodiscard]] bool valid() const { return !empty(); }
[[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; }
bool is_persistent() const { return state_ == object_state::Persistent; } [[nodiscard]] bool has_primary_key() const {
bool is_transient() const { return state_ == object_state::Transient; } std::lock_guard lock(mutex_);
bool is_detached() const { return state_ == object_state::Detached; } return !pk_.is_null();
bool is_removed() const { return state_ == object_state::Removed; } }
[[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) { void change_state(const object_state state) {
state_.store(state, std::memory_order_release); std::lock_guard lock(mutex_);
state_ = state;
} }
private: private:
Type* resolve() const { 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_) { if (obj_) {
return obj_.get(); return obj_;
} }
std::lock_guard lock(mutex_); resolver = resolver_.lock();
auto resolver = resolver_.lock();
if (!resolver) { if (!resolver) {
return nullptr; return nullptr;
// Todo: Add states (Detached, Attached, Transient) - if attached an no resolver is available throw runtime exception
// throw std::runtime_error("Detached proxy (session expired)");
} }
const_cast<std::shared_ptr<Type>&>(obj_) = resolver->resolve(pk_); pk = pk_;
return obj_.get();
} }
current = resolver->resolve(pk);
{
std::lock_guard lock(mutex_);
if (!obj_) {
obj_ = std::move(current);
}
return obj_;
}
}
private: private:
std::shared_ptr<Type> obj_{}; mutable std::shared_ptr<Type> obj_{};
std::weak_ptr<object_resolver<Type>> resolver_{}; mutable std::weak_ptr<object_resolver<Type>> resolver_{};
utils::identifier pk_{}; utils::identifier pk_{};
std::atomic<object_state> state_{object_state::Transient}; object_state state_{object_state::Transient};
mutable std::mutex mutex_{}; mutable std::mutex mutex_{};
}; };
} }
+105 -17
View File
@@ -19,60 +19,148 @@ class object_ptr {
public: public:
object_ptr() object_ptr()
: proxy_(std::make_shared<object_proxy<Type>>()) {} : proxy_(std::make_shared<object_proxy<Type>>()) {}
object_ptr(null_object_ptr_t) {} object_ptr(null_object_ptr_t) {}
explicit object_ptr(std::shared_ptr<Type> obj) explicit object_ptr(std::shared_ptr<Type> obj)
: proxy_(std::make_shared<object_proxy<Type>>(obj)) {} : proxy_(std::make_shared<object_proxy<Type>>(std::move(obj))) {}
explicit object_ptr(std::shared_ptr<object_proxy<Type>> obj) explicit object_ptr(std::shared_ptr<object_proxy<Type>> obj)
: proxy_(std::move(obj)) {} : proxy_(std::move(obj)) {}
object_ptr(const object_ptr &other) = default; object_ptr(const object_ptr &other) = default;
object_ptr(object_ptr &&other) noexcept = default; object_ptr(object_ptr &&other) noexcept = default;
object_ptr& operator=(const object_ptr &other) = default; object_ptr& operator=(const object_ptr &other) = default;
object_ptr& operator=(object_ptr &&other) = default; object_ptr& operator=(object_ptr &&other) noexcept = default;
object_ptr& operator=(null_object_ptr_t) { object_ptr& operator=(null_object_ptr_t) {
proxy_.reset(); proxy_.reset();
return *this; return *this;
} }
bool operator==(const object_ptr &other) const { bool operator==(const object_ptr &other) const {
return get() == other.get(); if (proxy_ == other.proxy_) {
return true;
} }
if (!proxy_ || !other.proxy_) {
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 { bool operator==(null_object_ptr_t) const {
return empty(); return empty();
} }
bool operator!=(const object_ptr &other) const { return !operator==(other); } bool operator!=(const object_ptr &other) const { return !operator==(other); }
bool operator!=(null_object_ptr_t) const { return !empty(); } bool operator!=(null_object_ptr_t) const { return !empty(); }
using value_type = Type; using value_type = Type;
Type *operator->() const { return get(); } Type *operator->() const {
Type &operator*() { return *get(); } return checked_get();
const Type &operator*() const { return *get(); } }
[[nodiscard]] bool empty() const { return get() == nullptr; } Type &operator*() {
return *checked_get();
}
const Type &operator*() const {
return *checked_get();
}
[[nodiscard]] bool empty() const {
return proxy_ == nullptr || proxy_->empty();
}
Type *get() const { Type *get() const {
return proxy_ ? proxy_->pointer() : nullptr; return proxy_ ? proxy_->pointer() : nullptr;
} }
void reset() { proxy_.reset(); } [[nodiscard]] std::shared_ptr<Type> object() const {
return proxy_ ? proxy_->object() : nullptr;
}
operator bool() const { return valid(); } void reset() {
[[nodiscard]] bool valid() const { return proxy_ != nullptr && !proxy_->empty(); } proxy_.reset();
}
[[nodiscard]] bool has_primary_key() const { return proxy_->has_primary_key(); } void reset(std::shared_ptr<object_proxy<Type>> proxy) {
[[nodiscard]] const utils::identifier &primary_key() const { return proxy_->primary_key(); } proxy_ = std::move(proxy);
void primary_key(const utils::identifier &pk) { proxy_->primary_key(pk); } }
[[nodiscard]] bool is_persistent() const { return proxy_->is_persistent(); } [[nodiscard]] std::shared_ptr<object_proxy<Type>> proxy() const {
[[nodiscard]] bool is_transient() const { return proxy_->is_transient(); } return proxy_;
[[nodiscard]] bool is_detached() const { return proxy_->is_detached(); } }
[[nodiscard]] bool is_removed() const { return proxy_->is_removed(); }
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 { void change_state(object_state s) const {
if (proxy_) { if (proxy_) {
proxy_->change_state(s); proxy_->change_state(s);
} }
} }
private:
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: private:
std::shared_ptr<object_proxy<Type>> proxy_{}; std::shared_ptr<object_proxy<Type>> proxy_{};
}; };
@@ -2,6 +2,7 @@
#define MATADOR_OBJECT_LOADER_HPP #define MATADOR_OBJECT_LOADER_HPP
#include "matador/object/abstract_type_resolver.hpp" #include "matador/object/abstract_type_resolver.hpp"
#include "matador/object/abstract_joined_resolver.hpp"
#include <memory> #include <memory>
@@ -17,5 +18,13 @@ public:
virtual std::shared_ptr<Type> resolve(const utils::identifier& id) = 0; 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 #endif //MATADOR_OBJECT_LOADER_HPP
+2 -2
View File
@@ -113,8 +113,8 @@ class null_observer : public observer<Type> {
public: public:
template < class OtherType > template < class OtherType >
explicit null_observer(const null_observer<OtherType> *) {} explicit null_observer(const null_observer<OtherType> *) {}
void on_attach(repository_node &, Type &) override {} void on_attach(const repository_node &, const Type &) const override {}
void on_detach(repository_node &, Type &) override {} void on_detach(const repository_node &, const Type &) const override {}
void on_insert(Type &) override {} void on_insert(Type &) override {}
void on_update(Type &) override {} void on_update(Type &) override {}
void on_delete(Type &) override {} void on_delete(Type &) override {}
+5 -3
View File
@@ -88,9 +88,11 @@ struct pk_field_locator {
desc.kind = pk_kind::uuid; desc.kind = pk_kind::uuid;
desc.is_known_at = [](void *obj, const std::size_t off) -> bool { desc.is_known_at = [](void *obj, const std::size_t off) -> bool {
auto *p = reinterpret_cast<uuid16 *>(static_cast<std::uint8_t *>(obj) + off); const auto *p = reinterpret_cast<uuid16 *>(static_cast<std::uint8_t *>(obj) + off);
// “unknown” = all zeros // “unknown” = all zeros
for (auto b: *p) { if (b != 0) return true; } for (const auto b: *p) {
if (b != 0) return true;
}
return false; return false;
}; };
@@ -119,7 +121,7 @@ struct pk_field_locator {
template <typename Pointer> template <typename Pointer>
static void on_belongs_to(const char *, Pointer &, const utils::foreign_attributes &) {} static void on_belongs_to(const char *, Pointer &, const utils::foreign_attributes &) {}
template <typename Pointer> template <typename Pointer>
static void on_has_one(const char *, Pointer &, const utils::foreign_attributes &) {} static void on_has_one(const char *, Pointer &, const char * /*join_column*/, const utils::foreign_attributes &) {}
template <typename Container> template <typename Container>
static void on_has_many(const char *, Container &, const char *, const utils::foreign_attributes &) {} static void on_has_many(const char *, Container &, const char *, const utils::foreign_attributes &) {}
template <typename Container> template <typename Container>
@@ -58,7 +58,7 @@ public:
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>
+15 -8
View File
@@ -43,7 +43,7 @@ public:
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*/) {}
@@ -117,7 +117,7 @@ public:
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);
@@ -172,7 +172,7 @@ void relation_completer<Type, Observers...>::on_has_many(const char *id, Collect
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 foreign_node = find_node(typeid(value_type)); const auto foreign_node = find_node(typeid(value_type));
if (!foreign_node) { if (!foreign_node) {
// Todo: throw internal error or attach node // Todo: throw internal error or attach node
return; return;
@@ -191,7 +191,7 @@ void relation_completer<Type, Observers...>::on_has_many(const char *id, Collect
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasMany, *foreign_node); const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasMany, *foreign_node);
nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint); 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
@@ -222,14 +222,15 @@ template<typename Type, template<typename> typename... Observers>
template<class CollectionType> template<class CollectionType>
void relation_completer<Type, Observers...>::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>;
auto observers = internal::observer_list_copy_creator<Type, relation_value_type, Observers...>::copy_create(observers_);
auto node = repository_node::make_node<relation_value_type>(repo_, id, [join_column] { auto node = repository_node::make_node<relation_value_type>(repo_, id, [join_column] {
return std::make_unique<relation_value_type>(join_column, "value"); return std::make_unique<relation_value_type>(join_column, "value");
}, {}); }, std::move(observers));
const auto result = repo_.attach_node(node.release(), ""); const auto result = repo_.attach_node(node.release(), "");
if (!result) { if (!result) {
// Todo: throw internal exception // Todo: throw internal exception
@@ -278,6 +279,7 @@ template<typename Type, template<typename> typename... Observers>
template<class ForeignPointerType> template<class ForeignPointerType>
void relation_completer<Type, Observers...>::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 foreign_node = find_node(typeid(value_type)); const auto foreign_node = find_node(typeid(value_type));
@@ -364,7 +366,12 @@ void relation_completer<Type, Observers...>::attach_relation_node(const std::str
auto observers = internal::observer_list_copy_creator<Type, relation_value_type, Observers...>::copy_create(observers_); auto observers = internal::observer_list_copy_creator<Type, relation_value_type, Observers...>::copy_create(observers_);
auto node = repository_node::make_node<relation_value_type>(repo_, name, std::move(creator), std::move(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(), ""); auto result = repo_.attach_node(node.release(), "");
if (!result) { if (!result) {
// Todo: throw internal error // Todo: throw internal error
@@ -23,6 +23,13 @@ public:
const std::string& name, const std::string& name,
creator_func<Type> creator, creator_func<Type> creator,
std::vector<std::unique_ptr<observer<Type>>>&& observers); std::vector<std::unique_ptr<observer<Type>>>&& observers);
template < typename Type, template<typename> typename... Observers >
static std::unique_ptr<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);
explicit repository_node(basic_repository& repo); explicit repository_node(basic_repository& repo);
repository_node(const repository_node& other) = delete; repository_node(const repository_node& other) = delete;
@@ -101,5 +108,28 @@ std::unique_ptr<repository_node> repository_node::make_node(basic_repository &re
return node; return node;
} }
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 #endif //REPOSITORY_NODE_HPP
+4 -4
View File
@@ -17,17 +17,17 @@ class object;
class restriction { class restriction {
public: public:
explicit restriction(const class attribute& attr); explicit restriction(size_t attr_index);
[[nodiscard]] const class attribute& attribute() const; [[nodiscard]] size_t attribute_index() const;
[[nodiscard]] std::string column_name() const; [[nodiscard]] std::string column_name() const;
[[nodiscard]] utils::constraints options() const;
[[nodiscard]] std::shared_ptr<object> owner() const; [[nodiscard]] std::shared_ptr<object> owner() const;
[[nodiscard]] bool is_primary_key_constraint() const; [[nodiscard]] bool is_primary_key_constraint() const;
[[nodiscard]] bool is_foreign_key_constraint() const; [[nodiscard]] bool is_foreign_key_constraint() const;
[[nodiscard]] bool is_unique_constraint() const; [[nodiscard]] bool is_unique_constraint() const;
[[nodiscard]] std::string ref_table_name() const; [[nodiscard]] std::string ref_table_name() const;
[[nodiscard]] std::string ref_column_name() const; [[nodiscard]] std::string ref_column_name() const;
friend std::ostream& operator<<(std::ostream& os, const restriction& c); friend std::ostream& operator<<(std::ostream& os, const restriction& c);
[[nodiscard]] std::string type_string() const; [[nodiscard]] std::string type_string() const;
@@ -37,7 +37,7 @@ private:
friend class object_generator; friend class object_generator;
friend class object; friend class object;
const class attribute& attr_; const size_t index_;
std::weak_ptr<object> owner_; std::weak_ptr<object> owner_;
std::weak_ptr<object> reference_; std::weak_ptr<object> reference_;
utils::constraints options_{utils::constraints::None}; utils::constraints options_{utils::constraints::None};
@@ -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);
+12 -5
View File
@@ -6,9 +6,9 @@
#include "matador/query/abstract_pk_generator.hpp" #include "matador/query/abstract_pk_generator.hpp"
#include "matador/query/table.hpp" #include "matador/query/table.hpp"
#include "matador/sql/internal/collection_resolver_producer.hpp" #include "matador/sql/internal/joined_collection_resolver_producer.hpp"
#include "matador/sql/internal/object_resolver_producer.hpp" #include "matador/sql/internal/object_resolver_producer.hpp"
#include "matador/sql/producer_resolver_factory.hpp" #include "matador/sql/producer_object_resolver_factory.hpp"
#include <memory> #include <memory>
#include <typeindex> #include <typeindex>
@@ -56,7 +56,7 @@ public:
template<class P> template<class P>
static void on_belongs_to(const char * /*id*/, P &, const utils::foreign_attributes & ) {} static void on_belongs_to(const char * /*id*/, P &, const utils::foreign_attributes & ) {}
template<class P> template<class P>
static void on_has_one(const char * /*id*/, P &, const utils::foreign_attributes & ) {} static void on_has_one(const char * /*id*/, P &, const char * /*join_column*/, const utils::foreign_attributes & ) {}
template<class C> template<class C>
static void on_has_many(const char * /*id*/, C &, const char * /*join_column*/, const utils::foreign_attributes & ) {} static void on_has_many(const char * /*id*/, C &, const char * /*join_column*/, const utils::foreign_attributes & ) {}
template<class C> template<class C>
@@ -77,6 +77,11 @@ public:
basic_schema(); basic_schema();
explicit basic_schema(const std::string &name); 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> create(const sql::connection &conn) const;
[[nodiscard]] utils::result<void, utils::error> drop(const sql::connection &conn) const; [[nodiscard]] utils::result<void, utils::error> drop(const sql::connection &conn) const;
@@ -97,7 +102,8 @@ public:
[[nodiscard]] bool contains(const std::type_index &index) 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<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::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_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: protected:
template<typename Type> template<typename Type>
@@ -107,7 +113,8 @@ protected:
object::repository repo_; object::repository repo_;
std::unordered_map<std::type_index, schema_node> schema_nodes_; 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<std::type_index, std::unique_ptr<sql::object_resolver_producer>> resolver_producers_;
std::unordered_map<object::collection_composite_key, std::unique_ptr<sql::collection_resolver_producer>, object::collection_composite_key_hash> collection_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 #endif //MATADOR_BASIC_SCHEMA_HPP
+11 -6
View File
@@ -8,15 +8,16 @@
#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 data_type { class data_type {
public: public:
explicit data_type(const utils::basic_type type, const size_t size = 0) explicit data_type(const utils::basic_type type, const size_t size = 0)
: type_(type), size_(size) {} : type_(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_; }
@@ -30,14 +31,16 @@ template<typename Type>
class typed_data_type final : public data_type { class typed_data_type final : public data_type {
public: public:
typed_data_type() typed_data_type()
: data_type(utils::data_type_traits<Type>::type()) {} : data_type(utils::data_type_traits<Type>::type()) {
}
}; };
template<typename Type> template<typename Type>
class sized_typed_data_type final : public data_type { class sized_typed_data_type final : public data_type {
public: public:
explicit sized_typed_data_type(size_t size) explicit sized_typed_data_type(size_t size)
: data_type(utils::data_type_traits<Type>::type(size), size) {} : data_type(utils::data_type_traits<Type>::type(size), size) {
}
}; };
using TinyInt = typed_data_type<int8_t>; using TinyInt = typed_data_type<int8_t>;
@@ -57,9 +60,12 @@ using Boolean = typed_data_type<bool>;
using Varchar = sized_typed_data_type<std::string>; using Varchar = sized_typed_data_type<std::string>;
using Blob = sized_typed_data_type<std::vector<std::byte> >; 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 {
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);
@@ -111,6 +117,5 @@ private:
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
@@ -8,12 +8,12 @@
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 {
@@ -20,33 +20,33 @@ class table_column;
template<class Type> template<class Type>
std::enable_if_t<!std::is_base_of_v<fetchable_query, std::decay_t<Type>>, criteria_ptr> std::enable_if_t<!std::is_base_of_v<fetchable_query, std::decay_t<Type>>, criteria_ptr>
operator==(const table_column &col, Type val) { operator==(const table_column &col, Type val) {
return std::make_unique<binary_criteria>(col, binary_operator::EQUALS, utils::value(val)); return std::make_unique<binary_criteria>(col, binary_operator::Equals, utils::value(val));
} }
template<class Type> template<class Type>
std::enable_if_t<!std::is_base_of_v<fetchable_query, std::decay_t<Type>>, criteria_ptr> std::enable_if_t<!std::is_base_of_v<fetchable_query, std::decay_t<Type>>, criteria_ptr>
operator!=(const table_column &col, Type val) { operator!=(const table_column &col, Type val) {
return std::make_unique<binary_criteria>(col, binary_operator::NOT_EQUALS, utils::value(val)); return std::make_unique<binary_criteria>(col, binary_operator::NotEquals, utils::value(val));
} }
template<class Type> template<class Type>
criteria_ptr operator>(const table_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 table_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 table_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 table_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 table_column &col_left, const table_column &col_right); criteria_ptr operator==(const table_column &col_left, const table_column &col_right);
@@ -0,0 +1,272 @@
#ifndef MATADOR_DELETE_QUERY_BUILDER_HPP
#define MATADOR_DELETE_QUERY_BUILDER_HPP
#include "matador/object/collection.hpp"
#include "matador/object/object_cache.hpp"
#include "matador/object/object_ptr.hpp"
#include "matador/query/basic_schema.hpp"
#include "matador/query/error_code.hpp"
#include "matador/query/delete_step.hpp"
#include "matador/query/query_contexts.hpp"
#include "matador/query/query_builder_exception.hpp"
#include "matador/query/query_builder_utils.hpp"
#include "matador/sql/statement.hpp"
#include "matador/utils/error.hpp"
#include "matador/utils/identifier.hpp"
#include "matador/utils/primary_key_accessor.hpp"
#include "matador/utils/result.hpp"
namespace matador::query {
template<typename ObjectType>
class delete_step_processor {
public:
explicit delete_step_processor(query_builder_context &ctx)
: ctx_(ctx) {}
utils::result<void, utils::error> build(object::object_ptr<ObjectType> ptr, const bool as_relation_step = false) {
if (!ptr) {
return utils::failure(utils::error{error_code::InvalidObject, "Object is null"});
}
ptr_ = ptr;
const auto key = make_entity_visit_key<ObjectType>(*ptr_);
if (ctx_.visited_.find(key) != ctx_.visited_.end()) {
return utils::ok<void>();
}
ctx_.visited_.insert(key);
const auto it = ctx_.schema_.find(typeid(ObjectType));
if (it == ctx_.schema_.end()) {
return utils::failure(utils::error{error_code::UnknownType, "Unknown type"});
}
if (const auto &info = it->second.node().info(); !info.has_primary_key()) {
return utils::failure(utils::error{error_code::MissingPrimaryKey, "Type " + info.name() + " has no primary key"});
}
try {
access::process(*this, *ptr_);
} catch (const query_builder_exception &ex) {
return utils::failure(ex.error());
}
const auto cit = ctx_.contexts_by_type_.find(it->second.node().info().type_index());
if (cit == ctx_.contexts_by_type_.end()) {
return utils::failure(utils::error{error_code::UnknownType, "Unknown type"});
}
if (as_relation_step) {
ctx_.relation_steps_.push_back(std::make_unique<delete_step_object<ObjectType>>(cit->second.delete_one, ptr_));
} else {
ctx_.steps_.push_back(std::make_unique<delete_step_object<ObjectType>>(cit->second.delete_one, ptr_));
}
ptr_.reset();
return utils::ok<void>();
}
template<class PrimaryKeyType>
static void on_primary_key(const char * /*id*/, PrimaryKeyType &, const utils::primary_key_attribute & /*attr*/) {}
static void on_revision(const char * /*id*/, uint64_t & /*rev*/) {}
template<typename Type>
static void on_attribute(const char * /*id*/, Type &, const utils::field_attributes & /*attr*/) {}
template<class Pointer>
void on_belongs_to(const char * /*id*/, Pointer &obj, const utils::foreign_attributes &attr) {
on_foreign_object(obj, attr);
}
template<class Pointer>
void on_has_one(const char * /*id*/, Pointer &obj, const char * /*join_column*/, const utils::foreign_attributes &attr) {
on_foreign_object(obj, attr);
}
template<class CollectionType>
void on_has_many(const char * /*id*/,
object::collection<object::object_ptr<CollectionType>> &objects,
const char *join_column,
const utils::foreign_attributes &attr) {
if (join_column == nullptr) {
return;
}
if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Remove)) {
return;
}
delete_step_processor<CollectionType> processor{ctx_};
for (auto &obj : objects) {
if (!obj) {
continue;
}
auto result = processor.build(obj, true);
if (!result) {
throw query_builder_exception(result.release_error());
}
}
}
template<class CollectionType>
static void on_has_many(const char * /*id*/,
object::collection<CollectionType> & /*objects*/,
const char * /*join_column*/,
const utils::foreign_attributes & /*attr*/) {
// Value-Collections bzw. Relationstabellen werden hier nicht direkt gelöscht.
// Dafür wird das Delete-Statement der jeweiligen Entity verwendet.
}
template<class ForeignType>
void on_has_many_to_many(const char *id,
object::collection<object::object_ptr<ForeignType>> &objects,
const char *join_column,
const char *inverse_join_column,
const utils::foreign_attributes &attr) {
if (id == nullptr || join_column == nullptr || inverse_join_column == nullptr) {
return;
}
using relation_value_type = object::many_to_many_relation<ObjectType, ForeignType>;
const std::type_index foreign_type{typeid(ForeignType)};
const std::type_index local_type{typeid(ObjectType)};
on_many_to_many_objects<relation_value_type>(
id,
objects,
attr,
[foreign_type, local_type](const char* relation_name) -> processing_many_to_many_key {
return {std::string{relation_name}, local_type, foreign_type};
});
}
template<class ForeignType>
void on_has_many_to_many(const char *id,
object::collection<object::object_ptr<ForeignType>> &objects,
const utils::foreign_attributes &attr) {
if (id == nullptr) {
return;
}
object::join_columns_collector collector;
if (auto join_columns = collector.collect<ForeignType>(); join_columns.join_column.empty() || join_columns.inverse_join_column.empty()) {
return;
}
using relation_value_type = object::many_to_many_relation<ForeignType, ObjectType>;
const std::type_index foreign_type{typeid(ForeignType)};
const std::type_index local_type{typeid(ObjectType)};
on_many_to_many_objects<relation_value_type>(
id,
objects,
attr,
[foreign_type, local_type](const char* relation_name) -> processing_many_to_many_key {
return {std::string{relation_name}, foreign_type, local_type};
});
}
private:
template<class PointerType>
void on_foreign_object(object::object_ptr<PointerType> &obj, const utils::foreign_attributes &attr) {
if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Remove) || !obj) {
return;
}
delete_step_processor<PointerType> processor{ctx_};
auto result = processor.build(obj);
if (!result) {
throw query_builder_exception(result.release_error());
}
}
template<class LocalType, class ForeignType, class RelationKeyFactory>
void on_many_to_many_objects(const char *id,
object::collection<object::object_ptr<ForeignType>> &objects,
const utils::foreign_attributes &attr,
RelationKeyFactory make_relation_key) {
if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Remove)) {
return;
}
const auto key = make_relation_key(id);
if (ctx_.processing_many_to_many_relations_.find(key) != ctx_.processing_many_to_many_relations_.end()) {
return;
}
const auto it = ctx_.schema_.find(std::string{id});
if (it == ctx_.schema_.end()) {
throw query_builder_exception(error_code::UnknownType, "Unknown type for relation " + std::string{id});
}
if (std::type_index(typeid(LocalType)) != it->second.node().info().type_index()) {
throw query_builder_exception(error_code::InvalidRelationType, "Invalid relation type for " + std::string{id});
}
if (const auto cit = ctx_.contexts_by_type_.find(it->second.node().info().type_index()); cit == ctx_.contexts_by_type_.end()) {
throw query_builder_exception(error_code::UnknownType, "No query contexts for type " + it->second.node().name());
}
std::ignore = ctx_.processing_many_to_many_relations_.insert(key);
std::vector<std::unique_ptr<execute_step>> delete_relation_steps;
delete_step_processor<ForeignType> processor{ctx_};
for (auto &obj : objects) {
if (!obj) {
continue;
}
if (obj.is_persistent()) {
auto result = processor.build(obj, true);
if (!result) {
throw query_builder_exception(result.release_error());
}
}
}
}
private:
query_builder_context &ctx_;
object::object_ptr<ObjectType> ptr_;
};
template<class ObjectType>
class delete_query_builder {
public:
explicit delete_query_builder(const basic_schema &schema,
const std::unordered_map<std::type_index, query_contexts> &contexts_by_type)
: schema_(schema)
, contexts_by_type_(contexts_by_type) {}
utils::result<std::vector<std::unique_ptr<execute_step>>, utils::error> build(const object::object_ptr<ObjectType> &ptr) {
if (const auto it = schema_.find(typeid(ObjectType)); it == schema_.end()) {
return utils::failure(utils::error{error_code::UnknownType, "Unknown type for delete query"});
}
query_builder_context ctx{schema_, contexts_by_type_};
delete_step_processor<ObjectType> processor{ctx};
const auto result = processor.build(ptr);
if (!result) {
return utils::failure(result.err());
}
// relation inserts must run after all entity inserts were collected
for (auto &s : ctx.steps_) {
ctx.relation_steps_.push_back(std::move(s));
}
ctx.steps_.clear();
return utils::ok(std::move(ctx.relation_steps_));
}
private:
const basic_schema &schema_;
const std::unordered_map<std::type_index, query_contexts> &contexts_by_type_;
};
} // namespace matador::query
#endif //MATADOR_DELETE_QUERY_BUILDER_HPP
+84
View File
@@ -0,0 +1,84 @@
#ifndef MATADOR_DELETE_STEP_HPP
#define MATADOR_DELETE_STEP_HPP
#include "matador/query/error_code.hpp"
#include "matador/query/execute_step.hpp"
#include "matador/sql/internal/identifier_statement_binder.hpp"
#include "matador/sql/statement.hpp"
#include "matador/object/object_ptr.hpp"
namespace matador::query {
template<typename ObjectType>
class delete_step_object final : public execute_step {
public:
delete_step_object(sql::query_context ctx, const object::object_ptr<ObjectType> &ptr)
: execute_step(std::move(ctx))
, ptr_(ptr) {}
utils::result<void, utils::error> prepare(sql::executor &/*conn*/) override {
id_ = ptr_.primary_key();
return utils::ok<void>();
}
utils::result<void, utils::error> execute(sql::statement &stmt) override {
if (!ptr_) {
return utils::failure(utils::error{error_code::InvalidObject, "Object is null"});
}
sql::identifier_statement_binder binder(stmt, 0);
binder.bind(id_);
if (const auto result = stmt.execute(); !result.is_ok()) {
return utils::failure(result.err());
}
return utils::ok<void>();
}
utils::result<void, utils::error> finalize(object::object_cache &cache, const resolver_service_ptr& /*resolver_service*/) override {
if (!ptr_) {
return utils::failure(utils::error{error_code::InvalidObject, "Object is null"});
}
cache.erase<ObjectType>(id_);
ptr_.change_state(object::object_state::Transient);
return utils::ok<void>();
}
private:
object::object_ptr<ObjectType> ptr_;
};
template <typename ObjectType>
class delete_step_relation : public execute_step {
public:
delete_step_relation(sql::query_context ctx, const object::object_ptr<ObjectType>& ptr)
: execute_step(std::move(ctx))
, ptr_(ptr) {}
utils::result<void, utils::error> prepare(sql::executor &) override {
return utils::ok<void>();
}
utils::result<void, utils::error> execute(sql::statement &stmt) override {
stmt.bind(*ptr_);
if (const auto exec_result = stmt.execute(); !exec_result.is_ok()) {
return utils::failure(exec_result.err());
}
return utils::ok<void>();
}
utils::result<void, utils::error> finalize(object::object_cache& /*cache*/, const resolver_service_ptr& /*resolver_service*/) override {
return utils::ok<void>();
}
private:
object::object_ptr<ObjectType> ptr_;
};
}
#endif //MATADOR_DELETE_STEP_HPP
@@ -89,16 +89,16 @@ struct dependency_collector {
} }
template<class Pointer> template<class Pointer>
static void on_has_one(const char*, Pointer&, const auto&) {} static void on_has_one(const char*, Pointer&, const char * /*join_column*/, const utils::foreign_attributes&) {}
template<class Container> template<class Container>
static void on_has_many(const char*, Container&, const char*, const auto&) {} static void on_has_many(const char*, Container&, const char*, const utils::foreign_attributes&) {}
template<class Container> template<class Container>
static void on_has_many_to_many(const char*, Container&, const char*, const char*, const auto&) {} static void on_has_many_to_many(const char*, Container&, const char*, const char*, const utils::foreign_attributes&) {}
template<class Container> template<class Container>
static void on_has_many_to_many(const char*, Container&, const auto&) {} static void on_has_many_to_many(const char*, Container&, const utils::foreign_attributes&) {}
}; };
struct flush_node { struct flush_node {
+37
View File
@@ -0,0 +1,37 @@
#ifndef MATADOR_EXECUTE_STEP_HPP
#define MATADOR_EXECUTE_STEP_HPP
#include "matador/utils/identifier.hpp"
#include "matador/utils/primary_key_accessor.hpp"
#include "matador/utils/error.hpp"
#include "matador/utils/result.hpp"
#include "matador/object/object_cache.hpp"
#include "matador/sql/query_context.hpp"
#include "matador/sql/executor.hpp"
#include "matador/query/abstract_pk_generator.hpp"
namespace matador::query {
using resolver_service_ptr = std::shared_ptr<sql::resolver_service>;
class execute_step {
public:
explicit execute_step(sql::query_context ctx)
: ctx_(std::move(ctx)) {}
virtual ~execute_step() = default;
virtual utils::result<void, utils::error> prepare(sql::executor &conn) = 0;
virtual utils::result<void, utils::error> execute(sql::statement &stmt) = 0;
virtual utils::result<void, utils::error> finalize(object::object_cache& cache, const resolver_service_ptr& resolver_service) = 0;
[[nodiscard]] const sql::query_context& ctx() const { return ctx_; }
protected:
utils::identifier id_;
utils::primary_key_accessor pk_accessor_;
sql::query_context ctx_;
};
}
#endif //MATADOR_EXECUTE_STEP_HPP
@@ -19,7 +19,7 @@ public:
void visit(const value_expression& node) override; void visit(const value_expression& node) override;
void visit(const placeholder_expression& node) override; void visit(const placeholder_expression& node) override;
const std::string& result() const; [[nodiscard]] const std::string& result() const;
private: private:
const sql::dialect &dialect_; const sql::dialect &dialect_;
+3 -5
View File
@@ -12,14 +12,12 @@ class foreign_attributes;
namespace matador::query::detail { namespace matador::query::detail {
class fk_value_extractor class fk_value_extractor {
{
public: public:
fk_value_extractor() = default; fk_value_extractor() = default;
template<class Type> template<class Type>
utils::database_type extract(Type &x) utils::database_type extract(Type &x) {
{
access::process(*this, x); access::process(*this, x);
return value_; return value_;
} }
@@ -37,7 +35,7 @@ public:
template<class Pointer> template<class Pointer>
static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
template<class Pointer> template<class Pointer>
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_has_one(const char * /*id*/, Pointer &/*x*/, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many_to_many(const char *, ContainerType &, const char * /*join_column*/, const char * /*inverse_join_column*/, const utils::foreign_attributes &/*attr*/) {} static void on_has_many_to_many(const char *, ContainerType &, const char * /*join_column*/, const char * /*inverse_join_column*/, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType> template<class ContainerType>
+3 -3
View File
@@ -81,7 +81,7 @@ public:
on_foreign_key(id, x, attr); on_foreign_key(id, x, attr);
} }
template<class Pointer> template<class Pointer>
void on_has_one(const char *id, Pointer &x, const utils::foreign_attributes &attr) { void on_has_one(const char *id, Pointer &x, const char * /*join_column*/, const utils::foreign_attributes &attr) {
on_foreign_key(id, x, attr); on_foreign_key(id, x, attr);
} }
@@ -189,7 +189,7 @@ public:
result_.emplace_back(utils::_); result_.emplace_back(utils::_);
} }
template<class Type, template < class ... > class Pointer> template<class Type, template < class ... > class Pointer>
void on_has_one(const char * /*id*/, Pointer<Type> &/*x*/, const utils::foreign_attributes &/*attr*/) { void on_has_one(const char * /*id*/, Pointer<Type> &/*x*/, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {
result_.emplace_back(utils::_); result_.emplace_back(utils::_);
} }
template<class ContainerType> template<class ContainerType>
@@ -249,7 +249,7 @@ public:
push_back(id, fk_value_extractor_.extract(*x)); push_back(id, fk_value_extractor_.extract(*x));
} }
template<class Type, template < class ... > class Pointer> template<class Type, template < class ... > class Pointer>
void on_has_one(const char *id, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/) { void on_has_one(const char *id, Pointer<Type> &x, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {
push_back(id, fk_value_extractor_.extract(*x)); push_back(id, fk_value_extractor_.extract(*x));
} }
template<class ContainerType> template<class ContainerType>
+227 -213
View File
@@ -2,12 +2,15 @@
#define MATADOR_INSERT_QUERY_BUILDER_HPP #define MATADOR_INSERT_QUERY_BUILDER_HPP
#include "matador/object/collection.hpp" #include "matador/object/collection.hpp"
#include "matador/object/object_ptr.hpp"
#include "matador/query/basic_schema.hpp" #include "matador/query/basic_schema.hpp"
#include "matador/query/intermediates/executable_query.hpp" #include "matador/query/intermediates/executable_query.hpp"
#include "matador/query/insert_step.hpp"
#include "matador/query/query.hpp" #include "matador/query/query.hpp"
#include "matador/query/query_contexts.hpp" #include "matador/query/query_contexts.hpp"
#include "matador/query/query_builder_exception.hpp" #include "matador/query/query_builder_exception.hpp"
#include "matador/query/query_builder_utils.hpp"
#include "matador/sql/statement.hpp" #include "matador/sql/statement.hpp"
@@ -40,7 +43,7 @@ public:
obj = ptr_; obj = ptr_;
} }
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 CollectionType> template<class CollectionType>
static void on_has_many(const char * /*id*/, CollectionType &/*con*/, const char *, const utils::foreign_attributes &/*attr*/, std::enable_if_t<!object::is_object_ptr<typename CollectionType::value_type>::value> * = nullptr) {} static void on_has_many(const char * /*id*/, CollectionType &/*con*/, const char *, const utils::foreign_attributes &/*attr*/, std::enable_if_t<!object::is_object_ptr<typename CollectionType::value_type>::value> * = nullptr) {}
template<class Collection> template<class Collection>
@@ -53,52 +56,57 @@ private:
std::string join_column_; std::string join_column_;
}; };
struct insert_step { template < typename ObjectType >
sql::query_context ctx; class insert_step_processor {
utils::result<void, utils::error> acquire_and_bind(sql::statement &stmt) const;
// Session uses these to handle manual/sequence/table pre-insert PKs
utils::generator_type pk_generator{utils::generator_type::Manual};
utils::primary_key_accessor pk_accessor;
// Identity post-insert
std::function<void(const sql::record &)> apply_returning{};
std::function<void(const utils::identifier &)> apply_primary_key{};
std::function<void(sql::statement &)> bind_object{};
std::function<void()> make_object_persistent{};
};
template<class ObjectType>
class insert_query_builder {
public: public:
explicit insert_query_builder(const basic_schema &schema, const std::unordered_map<std::type_index, query_contexts> &contexts_by_type) explicit insert_step_processor(query_builder_context &ctx)
: schema_(schema) : ctx_{ctx}
, contexts_by_type_{contexts_by_type}
{} {}
utils::result<std::vector<insert_step>, utils::error> build(const object::object_ptr<ObjectType> &ptr) { utils::result<void, utils::error> build(object::object_ptr<ObjectType> ptr, const bool as_relation_step = false) {
if (const auto it = schema_.find(typeid(ObjectType)); it == schema_.end()) { if (!ptr) {
return utils::failure(utils::error{error_code::UnknownType, "Unknown type for insert query"}); return utils::failure(utils::error{error_code::InvalidObject, "Object is null"});
} }
steps_.clear();
visited_.clear();
ptr_ = ptr; ptr_ = ptr;
const auto result = build_for(ptr, steps_);
const auto key = make_entity_visit_key<ObjectType>(*ptr_);
if (ctx_.visited_.find(key) != ctx_.visited_.end()) {
return utils::ok<void>();
}
ctx_.visited_.insert(key);
const auto it = ctx_.schema_.find(typeid(ObjectType));
if (it == ctx_.schema_.end()) {
return utils::failure(utils::error{error_code::UnknownType, "Unknown type"});
}
// 1) Traverse relations first => dependencies will be inserted before this object
try {
access::process(*this, *ptr_);
} catch (const query_builder_exception &ex) {
return utils::failure(ex.error());
}
// 2) Build INSERT for this object
const auto &info = it->second.node().info();
if (!info.has_primary_key() || it->second.pk_generator().type() == utils::generator_type::None) {
return utils::failure(utils::error{error_code::MissingPrimaryKey, "Type " + info.name() + " has no primary key"});
}
const auto cit = ctx_.contexts_by_type_.find(it->second.node().info().type_index());
if (cit == ctx_.contexts_by_type_.end()) {
return utils::failure(utils::error{error_code::UnknownType, "Unknown type"});
}
auto step = create_insert_step(cit->second.insert, it->second);
if (as_relation_step) {
ctx_.relation_steps_.push_back(std::move(step));
} else {
ctx_.steps_.push_back(std::move(step));
}
ptr_.reset(); ptr_.reset();
if (!result) {
return utils::failure(result.err());
}
// relation inserts must run after all entity inserts were collected return utils::ok<void>();
for (auto &s : relation_steps_) {
steps_.push_back(std::move(s));
}
relation_steps_.clear();
return utils::ok(steps_);
} }
template < class PrimaryKeyType > template < class PrimaryKeyType >
@@ -113,240 +121,246 @@ public:
} }
template<class Pointer> template<class Pointer>
void on_has_one(const char * /*id*/, Pointer &obj, const utils::foreign_attributes &attr) { void on_has_one(const char * /*id*/, Pointer &obj, const char * /*join_column*/, const utils::foreign_attributes &attr) {
on_foreign_object(obj, attr); on_foreign_object(obj, attr);
} }
template<class CollectionType> template<class CollectionType>
void on_has_many(const char * /*id*/, object::collection<object::object_ptr<CollectionType>> &objects, const char *join_column, const utils::foreign_attributes &attr) { void on_has_many(const char * /*id*/,
object::collection<object::object_ptr<CollectionType>> &objects,
const char *join_column,
const utils::foreign_attributes &attr) {
if (join_column == nullptr) {
return;
}
if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Insert)) { if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Insert)) {
return; return;
} }
has_many_linker<ObjectType> linker(ptr_, join_column); has_many_linker<ObjectType> linker(ptr_, join_column);
for (auto &obj : objects) { insert_step_processor<CollectionType> processor{ctx_};
if (obj.is_transient()) {
build_for(obj, relation_steps_);
}
access::process(linker, *obj);
}
}
template<class CollectionType>
static void on_has_many(const char * /*id*/, object::collection<CollectionType> &/*con*/, const char *, const utils::foreign_attributes &/*attr*/) {}
template<class ForeignType>
void on_has_many_to_many(const char *id, object::collection<object::object_ptr<ForeignType>> &objects, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &attr) {
if (id == nullptr || join_column == nullptr || inverse_join_column == nullptr) {
return;
}
if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Insert)) {
return;
}
if (processing_many_to_many_relations_.find(id) != processing_many_to_many_relations_.end()) {
return;
}
const auto it = schema_.find(std::string{id});
if (it == schema_.end()) {
throw query_builder_exception(error_code::UnknownType, "Unknown type");
}
using relation_value_type = object::many_to_many_relation<ObjectType, ForeignType>;
if (std::type_index(typeid(relation_value_type)) != it->second.node().info().type_index()) {
throw query_builder_exception(error_code::InvalidRelationType, "Invalid relation type");
}
const auto cit = contexts_by_type_.find(it->second.node().info().type_index());
if (cit == contexts_by_type_.end()) {
throw query_builder_exception(error_code::UnknownType, "Unknown type");
}
std::ignore = processing_many_to_many_relations_.insert(id);
std::vector<insert_step> rel_steps;
for (auto &obj : objects) { for (auto &obj : objects) {
if (!obj) { if (!obj) {
continue; continue;
} }
// Ensure target exists as dependency (deps first)
if (obj.is_transient()) { if (obj.is_transient()) {
build_for(obj, relation_steps_); auto result = processor.build(obj, true);
if (!result) {
throw query_builder_exception(result.release_error());
}
} }
auto rel = object::make_object<relation_value_type>(join_column, inverse_join_column, ptr_, obj); access::process(linker, *obj);
access::process(*this, *rel);
insert_step step{};
step.pk_generator = utils::generator_type::None;
step.ctx = cit->second.insert;
step.bind_object = [rel](sql::statement &stmt) { stmt.bind(*rel); };
step.make_object_persistent = [] {};
rel_steps.push_back(std::move(step));
} }
relation_steps_.insert(relation_steps_.end(), rel_steps.begin(), rel_steps.end());
processing_many_to_many_relations_.erase(id);
} }
template<class ForeignType> template<class CollectionType>
void on_has_many_to_many(const char *id, object::collection<object::object_ptr<ForeignType>> &objects, const utils::foreign_attributes &attr) { void on_has_many(const char *id,
object::collection<CollectionType> &objects,
const char *join_column,
const utils::foreign_attributes &attr) {
if (id == nullptr || join_column == nullptr) {
return;
}
if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Insert)) { if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Insert)) {
return; return;
} }
if (processing_many_to_many_relations_.find(id) != processing_many_to_many_relations_.end()) { const auto it = ctx_.schema_.find(std::string{id});
if (it == ctx_.schema_.end()) {
throw query_builder_exception(error_code::UnknownType, "Unknown type " + std::string{id});
}
using relation_value_type = object::many_to_relation<ObjectType, CollectionType>;
if (std::type_index(typeid(relation_value_type)) != it->second.node().info().type_index()) {
throw query_builder_exception(error_code::InvalidRelationType, "Invalid relation type");
}
const auto cit = ctx_.contexts_by_type_.find(it->second.node().info().type_index());
if (cit == ctx_.contexts_by_type_.end()) {
throw query_builder_exception(error_code::UnknownType, "Unknown type" + std::string{id});
}
for (auto &obj : objects) {
auto rel = object::make_object<relation_value_type>(join_column, "value", ptr_, obj);
ctx_.relation_steps_.push_back(std::make_unique<insert_step_relation<relation_value_type>>(cit->second.insert, rel));
}
}
template<class ForeignType>
void on_has_many_to_many(const char *id,
object::collection<object::object_ptr<ForeignType>> &objects,
const char *join_column,
const char *inverse_join_column,
const utils::foreign_attributes &attr) {
if (id == nullptr || join_column == nullptr || inverse_join_column == nullptr) {
return;
}
using relation_value_type = object::many_to_many_relation<ObjectType, ForeignType>;
const std::type_index foreign_type{typeid(ForeignType)};
const std::type_index local_type{typeid(ObjectType)};
insert_many_to_many_relations<relation_value_type>(
id,
objects,
attr,
[foreign_type, local_type](const char* relation_name) -> processing_many_to_many_key {
return {std::string{relation_name}, local_type, foreign_type};
},
[this, join_column, inverse_join_column](const auto &obj) {
return object::make_object<relation_value_type>(join_column, inverse_join_column, ptr_, obj);
});
}
template<class ForeignType>
void on_has_many_to_many(const char *id, object::collection<object::object_ptr<ForeignType>> &objects, const utils::foreign_attributes &attr) {
if (id == nullptr) {
return; return;
} }
object::join_columns_collector collector; object::join_columns_collector collector;
auto join_columns = collector.collect<ForeignType>(); auto join_columns = collector.collect<ForeignType>();
if (join_columns.join_column.empty() || join_columns.inverse_join_column.empty()) {
const auto it = schema_.find(std::string{id}); return;
if (it == schema_.end()) {
throw query_builder_exception(error_code::UnknownType, "Unknown type");
} }
using relation_value_type = object::many_to_many_relation<ForeignType, ObjectType>; using relation_value_type = object::many_to_many_relation<ForeignType, ObjectType>;
const std::type_index foreign_type{typeid(ForeignType)};
if (std::type_index(typeid(relation_value_type)) != it->second.node().info().type_index()) { const std::type_index local_type{typeid(ObjectType)};
throw query_builder_exception(error_code::InvalidRelationType, "Invalid relation type"); insert_many_to_many_relations<relation_value_type>(
id,
objects,
attr,
[foreign_type, local_type](const char* relation_name) -> processing_many_to_many_key {
return {std::string{relation_name}, foreign_type, local_type};
},
[this, join_columns = std::move(join_columns)](const auto &obj) {
return object::make_object<relation_value_type>(join_columns.inverse_join_column, join_columns.join_column, obj, ptr_);
});
} }
const auto cit = contexts_by_type_.find(it->second.node().info().type_index()); private:
if (cit == contexts_by_type_.end()) { template<class PointerType>
throw query_builder_exception(error_code::UnknownType, "Unknown type"); void on_foreign_object(object::object_ptr<PointerType> &obj, const utils::foreign_attributes &attr) {
if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Insert) || !obj || !obj.is_transient()) {
return;
} }
std::ignore = processing_many_to_many_relations_.insert(id); insert_step_processor<PointerType> processor{ctx_};
std::vector<insert_step> rel_steps;
auto result = processor.build(obj);
if (!result) {
throw query_builder_exception(result.release_error());
}
}
template<class LocalType, class ForeignType, class RelationKeyFactory, class RelationFactory>
void insert_many_to_many_relations(const char *id,
object::collection<object::object_ptr<ForeignType>> &objects,
const utils::foreign_attributes &attr,
RelationKeyFactory make_relation_key,
RelationFactory make_relation) {
if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Insert)) {
return;
}
const auto key = make_relation_key(id);
if (ctx_.processing_many_to_many_relations_.find(key) != ctx_.processing_many_to_many_relations_.end()) {
return;
}
const auto it = ctx_.schema_.find(std::string{id});
if (it == ctx_.schema_.end()) {
throw query_builder_exception(error_code::UnknownType, "Unknown type for relation " + std::string{id});
}
if (std::type_index(typeid(LocalType)) != it->second.node().info().type_index()) {
throw query_builder_exception(error_code::InvalidRelationType, "Invalid relation type for " + std::string{id});
}
const auto cit = ctx_.contexts_by_type_.find(it->second.node().info().type_index());
if (cit == ctx_.contexts_by_type_.end()) {
throw query_builder_exception(error_code::UnknownType, "No query contexts for type " + it->second.node().name());
}
std::ignore = ctx_.processing_many_to_many_relations_.insert(key);
std::vector<std::unique_ptr<execute_step>> insert_relation_steps;
insert_step_processor<ForeignType> processor(ctx_);
for (auto &obj : objects) { for (auto &obj : objects) {
if (!obj) { if (!obj) {
continue; continue;
} }
// Ensure target exists as dependency (deps first)
if (obj.is_transient()) { if (obj.is_transient()) {
build_for(obj, relation_steps_); auto result = processor.build(obj, true);
if (!result) {
throw query_builder_exception(result.release_error());
};
} }
auto rel = object::make_object<relation_value_type>(join_columns.inverse_join_column, join_columns.join_column, obj, ptr_); auto rel = make_relation(obj);
access::process(*this, *rel); // access::process(*this, *rel);
insert_step step{}; insert_relation_steps.push_back(std::make_unique<insert_step_relation<LocalType>>(cit->second.insert, rel));
step.pk_generator = utils::generator_type::None;
step.ctx = cit->second.insert;
step.bind_object = [rel](sql::statement &stmt) { stmt.bind(*rel); };
step.make_object_persistent = [] {};
rel_steps.push_back(std::move(step));
} }
relation_steps_.insert(relation_steps_.end(), rel_steps.begin(), rel_steps.end()); ctx_.relation_steps_.insert(
processing_many_to_many_relations_.erase(id); ctx_.relation_steps_.end(),
std::make_move_iterator(insert_relation_steps.begin()),
std::make_move_iterator(insert_relation_steps.end()));
ctx_.processing_many_to_many_relations_.erase(key);
}
std::unique_ptr<execute_step> create_insert_step(const sql::query_context& query_ctx, const schema_node& node) {
if (node.pk_generator().type() == utils::generator_type::Manual) {
return std::make_unique<insert_step_pk_manual<ObjectType>>(query_ctx, ptr_);
}
if (node.pk_generator().type() == utils::generator_type::Identity) {
return std::make_unique<insert_step_pk_identity<ObjectType>>(query_ctx, ptr_, node.node().info().primary_key_attribute()->name());
}
return std::make_unique<insert_step_pk_generated<ObjectType>>(query_ctx, ptr_, node.pk_generator());
} }
private: private:
template<class EntityType> query_builder_context& ctx_;
static std::pair<std::type_index, const void *> make_visit_key(const object::object_ptr<EntityType> &ptr) { object::object_ptr<ObjectType> ptr_;
return {std::type_index(typeid(EntityType)), static_cast<const void *>(&(*ptr))};
}
struct visit_key_hash {
size_t operator()(const std::pair<std::type_index, const void *> &p) const noexcept {
// combine hashes (simple + sufficient here)
const size_t h1 = p.first.hash_code();
const size_t h2 = std::hash<const void *>{}(p.second);
return h1 ^ (h2 + 0x9e3779b97f4a7c15ULL + (h1 << 6) + (h1 >> 2));
}
}; };
template<class EntityType> template<class ObjectType>
utils::result<void, utils::error> build_for(const object::object_ptr<EntityType> &ptr, std::vector<insert_step> &steps) { class insert_query_builder {
if (!ptr) { public:
return utils::failure(utils::error{error_code::InvalidObject, "Object is null"}); explicit insert_query_builder(const basic_schema &schema, const std::unordered_map<std::type_index, query_contexts> &contexts_by_type)
: schema_(schema)
, contexts_by_type_(contexts_by_type)
{}
utils::result<std::vector<std::unique_ptr<execute_step>>, utils::error> build(const object::object_ptr<ObjectType> &ptr) {
if (const auto it = schema_.find(typeid(ObjectType)); it == schema_.end()) {
return utils::failure(utils::error{error_code::UnknownType, "Unknown type for insert query"});
} }
const auto key = make_visit_key<EntityType>(ptr); query_builder_context ctx{schema_, contexts_by_type_};
if (visited_.find(key) != visited_.end()) { insert_step_processor<ObjectType> processor{ctx};
return utils::ok<void>();
}
visited_.insert(key);
const auto it = schema_.find(typeid(EntityType)); const auto result = processor.build(ptr);
if (it == schema_.end()) { if (!result) {
return utils::failure(utils::error{error_code::UnknownType, "Unknown type"}); return utils::failure(result.err());
} }
// 1) Traverse relations first => dependencies will be inserted before this object // relation inserts must run after all entity inserts were collected
try { for (auto &s : ctx.relation_steps_) {
access::process(*this, *ptr); ctx.steps_.push_back(std::move(s));
} catch (const query_builder_exception &ex) { }
return utils::failure(ex.error()); ctx.relation_steps_.clear();
return utils::ok(std::move(ctx.steps_));
} }
// 2) Build INSERT for this object
const auto &info = it->second.node().info();
insert_step step{};
if (info.has_primary_key()) {
step.pk_generator = it->second.pk_generator().type();
}
const auto cit = contexts_by_type_.find(it->second.node().info().type_index());
if (cit == contexts_by_type_.end()) {
return utils::failure(utils::error{error_code::UnknownType, "Unknown type"});
}
step.ctx = cit->second.insert;
step.bind_object = [ptr](sql::statement &stmt) {
stmt.bind(*ptr);
};
if (info.has_primary_key() && step.pk_generator == utils::generator_type::Identity) {
const auto pk_name = info.primary_key_attribute()->name();
const table_column pk_col(&it->second.table(), pk_name);
step.apply_returning = [ptr, &step, pk_name = pk_name](const sql::record &rec) {
const auto& f = rec.at(pk_name);
utils::identifier id;
id.assign(f.value());
step.pk_accessor.set(*ptr, id);
};
} else if (info.has_primary_key() && (step.pk_generator == utils::generator_type::Sequence || step.pk_generator == utils::generator_type::Table)) {
step.apply_primary_key = [ptr, &step](const utils::identifier &id) {
step.pk_accessor.set(*ptr, id);
};
}
step.make_object_persistent = [ptr] { ptr.change_state(object::object_state::Persistent); };
steps.push_back(std::move(step));
return utils::ok<void>();
}
template<class Pointer>
void on_foreign_object(Pointer &obj, const utils::foreign_attributes & /*attr*/) {
if (!obj) {
return;
}
// Dependency only matters if the referenced object must be inserted
if (obj.is_persistent()) {
return;
}
using dep_t = std::remove_reference_t<decltype(*obj)>;
build_for<dep_t>(obj, steps_);
}
private: private:
const basic_schema &schema_; const basic_schema &schema_;
const std::unordered_map<std::type_index, query_contexts> &contexts_by_type_; const std::unordered_map<std::type_index, query_contexts> &contexts_by_type_;
object::object_ptr<ObjectType> ptr_;
std::vector<insert_step> steps_;
std::vector<insert_step> relation_steps_;
std::unordered_set<std::pair<std::type_index, const void *>, visit_key_hash> visited_;
std::unordered_set<std::string> processing_many_to_many_relations_;
}; };
} }
#endif //MATADOR_INSERT_QUERY_BUILDER_HPP #endif //MATADOR_INSERT_QUERY_BUILDER_HPP
+180
View File
@@ -0,0 +1,180 @@
#ifndef MATADOR_INSERT_STEP_HPP
#define MATADOR_INSERT_STEP_HPP
#include "matador/query/abstract_pk_generator.hpp"
#include "matador/query/execute_step.hpp"
#include "matador/query/error_code.hpp"
#include "matador/object/object_cache.hpp"
#include "matador/object/object_ptr.hpp"
#include "matador/sql/execute_result.hpp"
#include "matador/sql/resolver_service.hpp"
#include "matador/sql/statement.hpp"
namespace matador::query {
template<typename ObjectType>
utils::result<void, utils::error> finalize_inserted_object(object::object_ptr<ObjectType> &ptr,
const utils::identifier& pk,
object::object_cache &cache,
const std::shared_ptr<sql::resolver_service> &resolver_service) {
if (!ptr) {
return utils::failure(utils::error(error_code::InvalidObject, "Inserted object is null."));
}
if (!resolver_service) {
return utils::failure(utils::error(error_code::UnknownType, "Missing resolver service."));
}
auto resolver = resolver_service->template object_resolver<ObjectType>();
if (!resolver) {
return utils::failure(utils::error(error_code::UnknownType, "Missing object resolver for inserted type."));
}
if (!cache.import<ObjectType>(pk, ptr.proxy(), resolver)) {
return utils::failure(utils::error(error_code::FailedToFindObject, "Object cache already contains another live proxy for inserted object."));
}
ptr.change_state(object::object_state::Persistent);
return utils::ok<void>();
}
template <typename ObjectType>
class insert_step_pk_generated : public execute_step {
public:
insert_step_pk_generated(sql::query_context ctx, const object::object_ptr<ObjectType>& ptr, abstract_pk_generator& pk_generator)
: execute_step(std::move(ctx))
, ptr_(ptr)
, pk_generator_(pk_generator){}
utils::result<void, utils::error> prepare(sql::executor& conn) override {
auto result = pk_generator_.next_id(conn);
if (!result.is_ok()) {
return utils::failure(result.err());
}
id_ = *result;
pk_accessor_.set(*ptr_, id_);
return utils::ok<void>();
}
utils::result<void, utils::error> execute(sql::statement& stmt) override {
stmt.bind(*ptr_);
if (const auto exec_result = stmt.execute(); !exec_result.is_ok()) {
return utils::failure(exec_result.err());
}
ptr_.change_state(object::object_state::Persistent);
return utils::ok<void>();
}
utils::result<void, utils::error> finalize(object::object_cache& cache, const resolver_service_ptr& resolver_service) override {
return finalize_inserted_object(ptr_, id_, cache, resolver_service);
}
private:
object::object_ptr<ObjectType> ptr_;
abstract_pk_generator& pk_generator_;
};
template <typename ObjectType>
class insert_step_pk_identity : public execute_step {
public:
insert_step_pk_identity(sql::query_context ctx, const object::object_ptr<ObjectType>& ptr, std::string pk_column_name)
: execute_step(std::move(ctx))
, ptr_(ptr)
, pk_column_name_(std::move(pk_column_name)){}
utils::result<void, utils::error> prepare(sql::executor&) override {
return utils::ok<void>();
}
utils::result<void, utils::error> execute(sql::statement& stmt) override {
stmt.bind(*ptr_);
auto result = stmt.fetch_one();
if (!result.is_ok()) {
return utils::failure(result.err());
}
if (!result.value().has_value()) {
return utils::failure(utils::error(error_code::FailedToFindObject, "Failed to insert object and retrieve identity."));
}
auto rec = result->value();
const auto& f = rec.at(pk_column_name_);
if (auto res = id_.assign(f.value()); !res.is_ok()) {
return utils::failure(res.err());
}
pk_accessor_.set(*ptr_, id_);
ptr_.change_state(object::object_state::Persistent);
return utils::ok<void>();
}
utils::result<void, utils::error> finalize(object::object_cache& cache, const resolver_service_ptr& resolver_service) override {
return finalize_inserted_object(ptr_, id_, cache, resolver_service);
}
private:
object::object_ptr<ObjectType> ptr_;
std::string pk_column_name_;
};
template <typename ObjectType>
class insert_step_pk_manual : public execute_step {
public:
insert_step_pk_manual(sql::query_context ctx, const object::object_ptr<ObjectType>& ptr)
: execute_step(std::move(ctx))
, ptr_(ptr) {}
utils::result<void, utils::error> prepare(sql::executor &) override {
return utils::ok<void>();
}
utils::result<void, utils::error> execute(sql::statement &stmt) override {
stmt.bind(*ptr_);
if (const auto exec_result = stmt.execute(); !exec_result.is_ok()) {
return utils::failure(exec_result.err());
}
id_ = object::primary_key_resolver::resolve_object(*ptr_).pk;
ptr_.change_state(object::object_state::Persistent);
return utils::ok<void>();
}
utils::result<void, utils::error> finalize(object::object_cache& cache, const resolver_service_ptr& resolver_service) override {
return finalize_inserted_object(ptr_, id_, cache, resolver_service);
}
private:
object::object_ptr<ObjectType> ptr_;
};
template <typename ObjectType>
class insert_step_relation : public execute_step {
public:
insert_step_relation(sql::query_context ctx, const object::object_ptr<ObjectType>& ptr)
: execute_step(std::move(ctx))
, ptr_(ptr) {}
utils::result<void, utils::error> prepare(sql::executor &) override {
return utils::ok<void>();
}
utils::result<void, utils::error> execute(sql::statement &stmt) override {
stmt.bind(*ptr_);
if (const auto exec_result = stmt.execute(); !exec_result.is_ok()) {
return utils::failure(exec_result.err());
}
return utils::ok<void>();
}
utils::result<void, utils::error> finalize(object::object_cache& /*cache*/, const resolver_service_ptr& /*resolver_service*/) override {
return utils::ok<void>();
}
private:
object::object_ptr<ObjectType> ptr_;
};
}
#endif //MATADOR_INSERT_STEP_HPP
@@ -23,7 +23,7 @@ public:
[[nodiscard]] utils::result<sql::execute_result, utils::error> execute(const sql::executor &exec) const; [[nodiscard]] utils::result<sql::execute_result, utils::error> execute(const sql::executor &exec) const;
[[nodiscard]] utils::result<sql::statement, utils::error> prepare(sql::executor &exec) const; [[nodiscard]] utils::result<sql::statement, utils::error> prepare(sql::executor &exec) const;
[[nodiscard]] sql::query_context compile(const sql::dialect &d) const; [[nodiscard]] sql::query_context compile(const sql::dialect &d) const;
[[nodiscard]] std::string str(const sql::executor &exec) const; [[nodiscard]] std::string str(const sql::dialect &d) const;
}; };
} }
@@ -75,7 +75,6 @@ public:
[[nodiscard]] utils::result<sql::statement, utils::error> prepare(sql::executor &exec) const; [[nodiscard]] utils::result<sql::statement, utils::error> prepare(sql::executor &exec) const;
[[nodiscard]] std::string str(const sql::executor &exec) const;
[[nodiscard]] std::string str(const sql::dialect &d) const; [[nodiscard]] std::string str(const sql::dialect &d) const;
[[nodiscard]] sql::query_context compile(const sql::dialect &d) const; [[nodiscard]] sql::query_context compile(const sql::dialect &d) const;
@@ -11,6 +11,5 @@ public:
[[nodiscard]] query_alter_table_intermediate table(const table &tab) const; [[nodiscard]] query_alter_table_intermediate table(const table &tab) const;
}; };
} }
#endif //MATADOR_QUERY_ALTER_INTERMEDIATE_HPP #endif //MATADOR_QUERY_ALTER_INTERMEDIATE_HPP
@@ -30,7 +30,7 @@ public:
using query_intermediate::query_intermediate; using query_intermediate::query_intermediate;
query_create_table_columns_intermediate columns(std::initializer_list<object::attribute> attributes); query_create_table_columns_intermediate columns(std::initializer_list<object::attribute> attributes);
query_create_table_columns_intermediate columns(const std::list<object::attribute> &attributes); query_create_table_columns_intermediate columns(const std::vector<object::attribute> &attributes);
query_create_table_columns_intermediate columns(std::initializer_list<table_column> columns); query_create_table_columns_intermediate columns(std::initializer_list<table_column> columns);
query_create_table_columns_intermediate columns(const std::list<table_column> &columns); query_create_table_columns_intermediate columns(const std::list<table_column> &columns);
query_create_table_columns_intermediate columns(const std::vector<table_column> &columns); query_create_table_columns_intermediate columns(const std::vector<table_column> &columns);
@@ -1,8 +1,6 @@
#ifndef QUERY_INTERMEDIATE_HPP #ifndef QUERY_INTERMEDIATE_HPP
#define QUERY_INTERMEDIATE_HPP #define QUERY_INTERMEDIATE_HPP
// #include "matador/query/query_data.hpp"
#include <memory> #include <memory>
namespace matador::query { namespace matador::query {
@@ -12,10 +12,6 @@ namespace matador::query::internal {
class column_value_pair { class column_value_pair {
public: public:
column_value_pair() = default; column_value_pair() = default;
// column_value_pair(table_column col, utils::database_type value);
// column_value_pair(const std::string& name, utils::database_type value);
// column_value_pair(const char *name, utils::database_type value);
// column_value_pair(const char *name, utils::placeholder p);
column_value_pair(column_value_pair&& x) = default; column_value_pair(column_value_pair&& x) = default;
column_value_pair& operator=(column_value_pair&& x) = default; column_value_pair& operator=(column_value_pair&& x) = default;
column_value_pair(table_column col, column_expression_ptr expression); column_value_pair(table_column col, column_expression_ptr expression);
@@ -24,12 +20,10 @@ public:
friend bool operator!=(const column_value_pair &lhs, const column_value_pair &rhs); friend bool operator!=(const column_value_pair &lhs, const column_value_pair &rhs);
[[nodiscard]] const table_column& col() const; [[nodiscard]] const table_column& col() const;
// [[nodiscard]] const std::variant<utils::placeholder, utils::database_type>& value() const;
[[nodiscard]] const abstract_column_expression& expression() const; [[nodiscard]] const abstract_column_expression& expression() const;
private: private:
table_column column_; table_column column_;
// std::variant<utils::placeholder, utils::database_type> value_;
column_expression_ptr expression_; column_expression_ptr expression_;
}; };
@@ -15,8 +15,6 @@
#include <list> #include <list>
#include <memory> #include <memory>
#include "matador/object/restriction.hpp"
namespace matador::query::internal { namespace matador::query::internal {
class query_alter_part final : public query_part { class query_alter_part final : public query_part {
@@ -44,7 +44,7 @@ public:
result_.emplace_back(id, fk_value_extractor_.extract(*x)); result_.emplace_back(id, fk_value_extractor_.extract(*x));
} }
template<class Type, template < class ... > class Pointer> template<class Type, template < class ... > class Pointer>
void on_has_one(const char *id, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/) { void on_has_one(const char *id, Pointer<Type> &x, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {
result_.emplace_back(id, fk_value_extractor_.extract(*x)); result_.emplace_back(id, fk_value_extractor_.extract(*x));
} }
template<class ContainerType> template<class ContainerType>
+1 -1
View File
@@ -18,7 +18,7 @@ TABLE_NAME##_table()\
: TABLE_NAME##_table(#TABLE_NAME) \ : TABLE_NAME##_table(#TABLE_NAME) \
{} \ {} \
TABLE_NAME##_table(const std::string& alias) \ TABLE_NAME##_table(const std::string& alias) \
: typed_table(#TABLE_NAME, alias, {MAP(FIELD_STRING, __VA_ARGS__)}) \ : typed_table(#TABLE_NAME, alias, {MAP(FIELD_STRING, __VA_ARGS__)}, {}, {}) \
MAP(INIT_FIELD, __VA_ARGS__) \ MAP(INIT_FIELD, __VA_ARGS__) \
{} \ {} \
MAP(FIELD, __VA_ARGS__) \ MAP(FIELD, __VA_ARGS__) \
+1 -2
View File
@@ -5,6 +5,7 @@
#include "matador/query/query_data.hpp" #include "matador/query/query_data.hpp"
#include "matador/sql/query_context.hpp" #include "matador/sql/query_context.hpp"
#include "matador/sql/interface/connection_impl.hpp"
#include "matador/utils/placeholder.hpp" #include "matador/utils/placeholder.hpp"
@@ -12,7 +13,6 @@
#include <optional> #include <optional>
namespace matador::sql { namespace matador::sql {
class connection_impl;
class dialect; class dialect;
} }
@@ -33,7 +33,6 @@ public:
const sql::dialect &d, const sql::dialect &d,
std::optional<std::reference_wrapper<const sql::connection_impl>> conn); std::optional<std::reference_wrapper<const sql::connection_impl>> conn);
protected:
void visit(internal::query_alter_part& part) override; void visit(internal::query_alter_part& part) override;
void visit(internal::query_alter_table_part& part) override; void visit(internal::query_alter_table_part& part) override;
void visit(internal::query_add_key_constraint_part& part) override; void visit(internal::query_add_key_constraint_part& part) override;
@@ -11,7 +11,8 @@ namespace matador::query {
class query_builder_exception final : public std::exception { class query_builder_exception final : public std::exception {
public: public:
explicit query_builder_exception(error_code error, std::string &&msg); explicit query_builder_exception(utils::error &&err);
query_builder_exception(error_code error, std::string &&msg);
[[nodiscard]] const utils::error &error() const; [[nodiscard]] const utils::error &error() const;
@@ -0,0 +1,60 @@
#ifndef MATADOR_QUERY_BUILDER_UTILS_HPP
#define MATADOR_QUERY_BUILDER_UTILS_HPP
#include <functional>
#include <map>
#include <typeindex>
namespace matador::query {
template<class EntityType>
static std::pair<std::type_index, const void *> make_entity_visit_key(const EntityType &ptr) {
return {std::type_index(typeid(EntityType)), static_cast<const void *>(&ptr)};
}
struct entity_visit_key_hash {
size_t operator()(const std::pair<std::type_index, const void *> &p) const noexcept {
const size_t h1 = p.first.hash_code();
const size_t h2 = std::hash<const void *>{}(p.second);
return h1 ^ (h2 + 0x9e3779b97f4a7c15ULL + (h1 << 6) + (h1 >> 2));
}
};
struct processing_many_to_many_key {
std::string id;
std::type_index local_type{typeid(void)};
std::type_index foreign_type{typeid(void)};
bool operator==(processing_many_to_many_key const &other) const {
return local_type == other.local_type && foreign_type == other.foreign_type && id == other.id;
}
};
template<class LocalType, typename ForeignType>
static processing_many_to_many_key make_processing_many_to_many_key(const std::string &id) {
return {id, std::type_index(typeid(LocalType)), std::type_index(typeid(ForeignType))};
}
struct processing_many_to_many_key_hash {
size_t operator()(const processing_many_to_many_key &p) const noexcept {
size_t seed = std::hash<std::type_index>{}(p.local_type);
const size_t foreign_hash = std::hash<std::type_index>{}(p.foreign_type);
seed ^= foreign_hash + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);
const size_t id_hash = std::hash<std::string>{}(p.id);
seed ^= id_hash + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);
return seed;
}
};
struct query_builder_context {
const basic_schema &schema_;
const std::unordered_map<std::type_index, query_contexts> &contexts_by_type_;
std::vector<std::unique_ptr<execute_step>> steps_{};
std::vector<std::unique_ptr<execute_step>> relation_steps_{};
std::unordered_set<std::pair<std::type_index, const void *>, entity_visit_key_hash> visited_{};
std::unordered_set<processing_many_to_many_key, processing_many_to_many_key_hash> processing_many_to_many_relations_{};
};
}
#endif //MATADOR_QUERY_BUILDER_UTILS_HPP
@@ -31,6 +31,46 @@ protected:
std::shared_ptr<object::object_resolver<typename Type::value_type>> resolver_; std::shared_ptr<object::object_resolver<typename Type::value_type>> resolver_;
}; };
template<typename Type>
class query_collection_primitive_resolver : public object::collection_resolver<Type> {
public:
explicit query_collection_primitive_resolver(sql::statement &&stmt,
const std::type_index& root_type,
std::string join_column//,
/*const std::shared_ptr<object::object_resolver<typename Type::value_type>> &resolver*/)
: object::collection_resolver<Type>(root_type, join_column)
, stmt_(std::move(stmt))
// , resolver_(resolver)
{}
std::vector<Type> resolve(const utils::identifier &id) override {
sql::identifier_statement_binder binder(stmt_);
binder.bind(id);
auto result = stmt_.fetch();
if (!result) {
return {};
}
std::vector<Type> out;
for (auto &r : *result) {
// Todo: convert the first value of record into an utils::identifier
// then create a object_proxy<Type>(resolver, identifier)
if (r.size() != 1) {
continue;
}
auto val = r.at<Type>(0);
if (val.has_value()) {
out.push_back(*val);
}
}
return out;
}
protected:
sql::statement stmt_;
std::type_index index{typeid(Type)};
// std::shared_ptr<object::object_resolver<typename Type::value_type>> resolver_;
};
struct value_to_identifier{ struct value_to_identifier{
void operator()(const int8_t &x) { assign(x); } void operator()(const int8_t &x) { assign(x); }
void operator()(const int16_t &x) { assign(x); } void operator()(const int16_t &x) { assign(x); }
@@ -22,6 +22,17 @@ protected:
sql::statement stmt_; sql::statement stmt_;
}; };
template<typename Type>
class query_joined_object_resolver : public object::joined_object_resolver<Type> {
public:
explicit query_joined_object_resolver(sql::statement &&stmt)
: stmt_(std::move(stmt)) {}
std::shared_ptr<Type> resolve(const utils::identifier &id) override;
protected:
sql::statement stmt_;
};
template<typename Type> template<typename Type>
std::shared_ptr<Type> query_object_resolver<Type>::resolve(const utils::identifier &id) { std::shared_ptr<Type> query_object_resolver<Type>::resolve(const utils::identifier &id) {
sql::identifier_statement_binder binder(stmt_); sql::identifier_statement_binder binder(stmt_);
@@ -34,5 +45,16 @@ std::shared_ptr<Type> query_object_resolver<Type>::resolve(const utils::identifi
return *result; return *result;
} }
template<typename Type>
std::shared_ptr<Type> query_joined_object_resolver<Type>::resolve(const utils::identifier &id) {
sql::identifier_statement_binder binder(stmt_);
binder.bind(id);
auto result = stmt_.template fetch_one_raw<Type>();
if (!result) {
return nullptr;
}
return *result;
}
} }
#endif //MATADOR_QUERY_OBJECT_LOADER_HPP #endif //MATADOR_QUERY_OBJECT_LOADER_HPP
+40 -2
View File
@@ -1,8 +1,7 @@
#ifndef MATADOR_QUERY_UTILS_HPP #ifndef MATADOR_QUERY_UTILS_HPP
#define MATADOR_QUERY_UTILS_HPP #define MATADOR_QUERY_UTILS_HPP
#include "table.hpp" #include "matador/utils/value.hpp"
#include "matador/sql/dialect.hpp"
#include <string> #include <string>
@@ -11,11 +10,50 @@ class dialect;
struct query_context; struct query_context;
} }
namespace matador::query { namespace matador::query {
class table;
class table_column; class table_column;
void prepare_column(sql::query_context& ctx, const sql::dialect& d, const table_column& col); void prepare_column(sql::query_context& ctx, const sql::dialect& d, const table_column& col);
void prepare_column(std::string &out, const sql::dialect& d, const table_column &col); void prepare_column(std::string &out, const sql::dialect& d, const table_column &col);
[[nodiscard]] std::string prepare_identifier(const sql::dialect& d, const table_column &col); [[nodiscard]] std::string prepare_identifier(const sql::dialect& d, const table_column &col);
[[nodiscard]] std::string prepare_criteria(const sql::dialect& d, const table_column &col); [[nodiscard]] std::string prepare_criteria(const sql::dialect& d, const table_column &col);
[[nodiscard]] std::string to_query_string(const utils::value &val, const sql::dialect& d);
/**
* Prepare string literal
*
* @param str String literal to be prepared
* @param d The SQL dialect to use preparing the literal
*/
[[nodiscard]] std::string prepare_literal(const std::string &str, const sql::dialect& d);
/**
* Prepare SQL dialect identifier for execution
* and escape quotes and quote the identifier
* string
*
* @param col The identifier string to be prepared
* @param d The SQL dialect to use preparing the identifier string
* @return The prepared string
*/
[[nodiscard]] std::string prepare_identifier_string(const std::string &col, const sql::dialect& d);
/**
* Escape identifier quotes inside identifiers.
*
* @param str Identifier to be escaped
* @param d The SQL dialect to use for escaping
*/
void escape_quotes_in_identifier(std::string &str, const sql::dialect& d);
/**
* Escape quotes in string literals
*
* @param str String literal to be escaped
* @param d The SQL dialect to use for escaping
*/
void escape_quotes_in_literals(std::string &str, const sql::dialect& d);
} }
#endif //MATADOR_QUERY_UTILS_HPP #endif //MATADOR_QUERY_UTILS_HPP
+156 -60
View File
@@ -5,7 +5,7 @@
#include "matador/sql/query_context.hpp" #include "matador/sql/query_context.hpp"
#include "matador/sql/internal/object_resolver_producer.hpp" #include "matador/sql/internal/object_resolver_producer.hpp"
#include "matador/sql/internal/collection_resolver_producer.hpp" #include "matador/sql/internal/joined_collection_resolver_producer.hpp"
#include "matador/query/query_collection_resolver.hpp" #include "matador/query/query_collection_resolver.hpp"
#include "matador/query/query_object_resolver.hpp" #include "matador/query/query_object_resolver.hpp"
@@ -20,11 +20,55 @@ class executor;
namespace matador::query { namespace matador::query {
template<typename Type> template<typename Type>
class query_collection_resolver_producer : public sql::collection_resolver_producer { class query_object_resolver_producer : public sql::object_resolver_producer {
public: public:
query_collection_resolver_producer() = default; query_object_resolver_producer() = default;
query_collection_resolver_producer(const basic_schema& repo, const table& tab, std::string pk_name, const std::type_index& root_type, std::string join_column) query_object_resolver_producer(basic_schema& repo, const table& tab, std::string pk_name)
: collection_resolver_producer(root_type, typeid(Type), std::move(join_column)) : object_resolver_producer(typeid(Type))
, repo_(repo)
, table_(tab)
, pk_name_(std::move(pk_name)) {}
std::shared_ptr<object::abstract_type_resolver> produce(sql::statement&& stmt) override {
return std::make_shared<query_object_resolver<Type>>(std::move(stmt));
}
utils::result<sql::query_context, utils::error> build_query(const sql::dialect& d) override;
private:
basic_schema& repo_;
const table& table_;
std::string pk_name_;
};
template<typename Type>
class query_joined_object_resolver_producer : public sql::joined_object_resolver_producer {
public:
query_joined_object_resolver_producer() = default;
query_joined_object_resolver_producer(basic_schema& repo, const table& tab, std::string pk_name, const std::type_index& root_type, const std::string &join_column)
: joined_object_resolver_producer(root_type, typeid(Type), join_column)
, repo_(repo)
, table_(tab)
, pk_name_(std::move(pk_name)) {}
std::shared_ptr<object::abstract_type_resolver> produce(sql::statement&& stmt) override {
return std::make_shared<query_object_resolver<Type>>(std::move(stmt));
}
utils::result<sql::query_context, utils::error> build_query(const sql::dialect& /*d*/) override;
private:
basic_schema& repo_;
const table& table_;
std::string pk_name_;
};
template<typename Type>
class query_joined_collection_resolver_producer : public sql::joined_collection_resolver_producer {
public:
query_joined_collection_resolver_producer() = default;
query_joined_collection_resolver_producer(const basic_schema& repo, const table& tab, std::string pk_name, const std::type_index& root_type, std::string join_column)
: joined_collection_resolver_producer(root_type, typeid(Type), std::move(join_column))
, repo_(repo) , repo_(repo)
, table_(tab) , table_(tab)
, pk_name_(std::move(pk_name)) , pk_name_(std::move(pk_name))
@@ -32,7 +76,7 @@ public:
utils::result<sql::query_context, utils::error> build_query(const sql::dialect& d) override { utils::result<sql::query_context, utils::error> build_query(const sql::dialect& d) override {
const auto *pk_column = table_[pk_name_]; const auto *pk_column = table_[pk_name_];
const auto *join_column = table_[collection_name()]; const auto *join_column = table_[join_column_name()];
const auto stmt = select({*pk_column}) const auto stmt = select({*pk_column})
.from(table_) .from(table_)
@@ -42,10 +86,10 @@ public:
return utils::ok(stmt); return utils::ok(stmt);
} }
std::shared_ptr<object::abstract_collection_resolver> produce(sql::statement&& stmt, const sql::resolver_service& rs) override { std::shared_ptr<object::abstract_joined_resolver> produce(sql::statement&& stmt, const sql::resolver_service& rs) override {
const auto object_resolver = rs.object_resolver<typename Type::value_type>(); const auto object_resolver = rs.object_resolver<typename Type::value_type>();
return std::make_shared<query_collection_resolver<Type>>(std::move(stmt), root_type(), collection_name(), object_resolver); return std::make_shared<query_collection_resolver<Type>>(std::move(stmt), root_type(), join_column_name(), object_resolver);
} }
private: private:
@@ -54,6 +98,39 @@ private:
std::string pk_name_; std::string pk_name_;
}; };
template<typename Type>
class query_joined_collection_primitive_resolver_producer : public sql::joined_collection_resolver_producer {
public:
query_joined_collection_primitive_resolver_producer() = default;
query_joined_collection_primitive_resolver_producer(const basic_schema& repo, const table& tab, std::string value_name, const std::type_index& root_type, std::string join_column)
: joined_collection_resolver_producer(root_type, typeid(Type), std::move(join_column))
, repo_(repo)
, table_(tab)
, value_name_(std::move(value_name))
{}
utils::result<sql::query_context, utils::error> build_query(const sql::dialect& d) override {
const auto *value_column = table_[value_name_];
const auto *join_column = table_[join_column_name()];
const auto stmt = select({*value_column})
.from(table_)
.where(*join_column == utils::_)
.compile(d);
return utils::ok(stmt);
}
std::shared_ptr<object::abstract_joined_resolver> produce(sql::statement&& stmt, const sql::resolver_service& /*rs*/) override {
return std::make_shared<query_collection_primitive_resolver<Type>>(std::move(stmt), root_type(), join_column_name()/*, object_resolver*/);
}
private:
const basic_schema& repo_;
const table& table_;
std::string value_name_;
};
class producer_creator final { class producer_creator final {
public: public:
producer_creator(basic_schema& schema, const std::type_index& root_type) producer_creator(basic_schema& schema, const std::type_index& root_type)
@@ -71,7 +148,24 @@ public:
template<class Pointer> template<class Pointer>
static void on_belongs_to(const char * /*id*/, Pointer & /*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_belongs_to(const char * /*id*/, Pointer & /*x*/, const utils::foreign_attributes &/*attr*/) {}
template<class Pointer> template<class Pointer>
static void on_has_one(const char * /*id*/, Pointer & /*x*/, const utils::foreign_attributes &/*attr*/) {} void on_has_one(const char * /*id*/, Pointer & /*x*/, const char *join_column, const utils::foreign_attributes &/*attr*/) {
const auto it = schema_.find(typeid(typename Pointer::value_type));
if (it == schema_.end()) {
throw query_builder_exception{error_code::UnknownType, "Unknown type"};
}
if (!it->second.node().info().has_primary_key()) {
throw query_builder_exception{error_code::MissingPrimaryKey, "Missing primary key"};
}
auto producer = std::make_unique<query_joined_object_resolver_producer<typename Pointer::value_type>>(
schema_,
it->second.table(),
it->second.node().info().primary_key_attribute()->name(),
root_type_,
join_column);
const object::collection_composite_key key{root_type_, typeid(Pointer), join_column};
schema_.joined_object_resolver_producers_[key] = std::move(producer);
}
template<class CollectionType> template<class CollectionType>
void on_has_many(const char * /*id*/, CollectionType &/*cont*/, const char *join_column, const utils::foreign_attributes &/*attr*/, std::enable_if_t<object::is_object_ptr<typename CollectionType::value_type>::value> * = nullptr) { void on_has_many(const char * /*id*/, CollectionType &/*cont*/, const char *join_column, const utils::foreign_attributes &/*attr*/, std::enable_if_t<object::is_object_ptr<typename CollectionType::value_type>::value> * = nullptr) {
@@ -83,7 +177,7 @@ public:
throw query_builder_exception{error_code::MissingPrimaryKey, "Missing primary key"}; throw query_builder_exception{error_code::MissingPrimaryKey, "Missing primary key"};
} }
auto producer = std::make_unique<query_collection_resolver_producer<typename CollectionType::value_type>>( auto producer = std::make_unique<query_joined_collection_resolver_producer<typename CollectionType::value_type>>(
schema_, schema_,
it->second.table(), it->second.table(),
it->second.node().info().primary_key_attribute()->name(), it->second.node().info().primary_key_attribute()->name(),
@@ -94,8 +188,19 @@ public:
} }
template<class CollectionType> template<class CollectionType>
void on_has_many(const char * /*id*/, CollectionType &/*cont*/, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/, std::enable_if_t<!object::is_object_ptr<typename CollectionType::value_type>::value> * = nullptr) { void on_has_many(const char *id, CollectionType &/*cont*/, const char *join_column, const utils::foreign_attributes &/*attr*/, std::enable_if_t<!object::is_object_ptr<typename CollectionType::value_type>::value> * = nullptr) {
const auto it = schema_.find(id);
if (it == schema_.end()) {
throw query_builder_exception{error_code::UnknownType, "Unknown type" + std::string{id}};
}
auto producer = std::make_unique<query_joined_collection_primitive_resolver_producer<typename CollectionType::value_type>>(
schema_,
it->second.table(),
"value",
root_type_,
join_column);
const object::collection_composite_key key{root_type_, typeid(typename CollectionType::value_type), join_column};
schema_.collection_resolver_producers_[key] = std::move(producer);
} }
template<class CollectionType> template<class CollectionType>
@@ -105,7 +210,7 @@ public:
throw query_builder_exception{error_code::UnknownType, "Unknown type"}; throw query_builder_exception{error_code::UnknownType, "Unknown type"};
} }
auto producer = std::make_unique<query_collection_resolver_producer<typename CollectionType::value_type>>( auto producer = std::make_unique<query_joined_collection_resolver_producer<typename CollectionType::value_type>>(
schema_, schema_,
it->second.table(), it->second.table(),
inverse_join_column, inverse_join_column,
@@ -125,7 +230,7 @@ public:
object::join_columns_collector collector; object::join_columns_collector collector;
const auto jc = collector.collect<typename CollectionType::value_type::value_type>(); const auto jc = collector.collect<typename CollectionType::value_type::value_type>();
auto producer = std::make_unique<query_collection_resolver_producer<typename CollectionType::value_type>>( auto producer = std::make_unique<query_joined_collection_resolver_producer<typename CollectionType::value_type>>(
schema_, schema_,
it->second.table(), it->second.table(),
jc.join_column, jc.join_column,
@@ -141,42 +246,6 @@ private:
const std::type_index root_type_; const std::type_index root_type_;
}; };
template<typename Type>
class query_object_resolver_producer : public sql::object_resolver_producer {
public:
query_object_resolver_producer() = default;
query_object_resolver_producer(basic_schema& repo, const table& tab, std::string pk_name)
: object_resolver_producer(typeid(Type))
, repo_(repo)
, table_(tab)
, pk_name_(std::move(pk_name)) {}
std::shared_ptr<object::abstract_type_resolver> produce(sql::statement&& stmt) override {
return std::make_shared<query_object_resolver<Type>>(std::move(stmt));
}
utils::result<sql::query_context, utils::error> build_query(const sql::dialect& d) override {
producer_creator pc(repo_, typeid(Type));
Type obj;
access::process(pc, obj);
select_query_builder qb(repo_);
const auto *pk_column = table_[pk_name_];
const auto result = qb.build<Type>(*pk_column == utils::_);
if (!result) {
return utils::failure(result.err());
}
return utils::ok(result->compile(d));
}
private:
basic_schema& repo_;
const table& table_;
std::string pk_name_;
};
class schema; class schema;
using schema_ref = std::reference_wrapper<schema>; using schema_ref = std::reference_wrapper<schema>;
@@ -245,13 +314,11 @@ public:
return basic_schema::contains(std::type_index(typeid(Type))); return basic_schema::contains(std::type_index(typeid(Type)));
} }
[[nodiscard]] const object::repository &repo() const { return repo_; }
object::repository &repo() { return repo_; }
void dump(std::ostream &os) const; void dump(std::ostream &os) const;
private: private:
iterator insert_table(const std::type_index& ti, const object::repository_node &node, utils::generator_type generator_type); iterator insert_table(const std::type_index& ti, const object::repository_node &node, utils::generator_type generator_type);
iterator insert_relation_table(const std::type_index& ti, const object::repository_node &node);
private: private:
template<typename Type> template<typename Type>
@@ -269,18 +336,47 @@ utils::result<void, utils::error> schema::drop_table(const sql::connection &conn
} }
template<typename Type> template<typename Type>
void schema_observer<Type>::on_attach(const object::repository_node &node, const Type &/*prototype*/) const { utils::result<sql::query_context, utils::error> query_object_resolver_producer<Type>::build_query(const sql::dialect &d) {
primary_key_generator_finder finder; producer_creator pc(repo_, typeid(Type));
const auto generator_type = finder.find(node.info<Type>().get()); Type obj;
access::process(pc, obj);
const auto it = schema_.insert_table(typeid(Type), node, generator_type); select_query_builder qb(repo_);
const auto *pk_column = table_[pk_name_];
if (!it->second.node().info().has_primary_key()) { const auto result = qb.build<Type>(*pk_column == utils::_);
return; if (!result) {
return utils::failure(result.err());
} }
return utils::ok(result->compile(d));
}
template<typename Type>
utils::result<sql::query_context, utils::error> query_joined_object_resolver_producer<Type>::build_query(const sql::dialect &d) {
select_query_builder qb(repo_);
const auto *join_column = table_[collection_name()];
const auto result = qb.build<Type>(*join_column == utils::_);
if (!result) {
return utils::failure(result.err());
}
return utils::ok(result->compile(d));
}
template <typename Type>
void schema_observer<Type>::on_attach(const object::repository_node &node, const Type &/*prototype*/) const {
const object::object_info<Type>& info = node.info<Type>().get();
if (info.has_primary_key()) {
primary_key_generator_finder finder;
const auto generator_type = finder.find(info);
const auto it = schema_.insert_table(typeid(Type), node, generator_type);
auto producer = std::make_unique<query_object_resolver_producer<Type>>(schema_, it->second.table(), it->second.node().info().primary_key_attribute()->name()); auto producer = std::make_unique<query_object_resolver_producer<Type>>(schema_, it->second.table(), it->second.node().info().primary_key_attribute()->name());
schema_.resolver_producers_[typeid(Type)] = std::move(producer); schema_.resolver_producers_[typeid(Type)] = std::move(producer);
} else {
const auto it = schema_.insert_relation_table(typeid(Type), node);
// auto producer = std::make_unique<query_object_resolver_producer<Type>>(schema_, it->second.table(), it->second.node().info().primary_key_attribute()->name());
// schema_.resolver_producers_[typeid(Type)] = std::move(producer);
}
} }
template <typename Type> template <typename Type>
+13
View File
@@ -0,0 +1,13 @@
#ifndef MATADOR_SCHEMA_UTILS_HPP
#define MATADOR_SCHEMA_UTILS_HPP
#include "matador/query/query_contexts.hpp"
#include "matador/query/basic_schema.hpp"
namespace matador::sql {
class dialect;
}
namespace matador::query {
query_contexts to_query_contexts(const schema_node &node, const sql::dialect &d);
}
#endif //MATADOR_SCHEMA_UTILS_HPP
+58 -40
View File
@@ -112,13 +112,67 @@ public:
} }
template<class Pointer> template<class Pointer>
void on_belongs_to(const char *id, Pointer &obj, const utils::foreign_attributes &attr) { void on_belongs_to(const char *id, Pointer &/*obj*/, const utils::foreign_attributes &attr) {
on_foreign_object(id, obj, attr); const auto it = schema_.find(typeid(typename Pointer::value_type));
if (it == schema_.end()) {
throw query_builder_exception{error_code::UnknownType, "Unknown type"};
}
if (!it->second.node().info().has_primary_key()) {
throw query_builder_exception{error_code::MissingPrimaryKey, "Missing primary key"};
}
const auto& info = it->second.node().info();
auto foreign_table = it->second.table().as(build_alias('t', ++table_index));
if (attr.fetch() == utils::fetch_type::Eager) {
auto next = processed_tables_.find(info.name());
if (next != processed_tables_.end()) {
return;
}
table_info_stack_.push({info, std::move(foreign_table)});
next = processed_tables_.insert({info.name(), table_info_stack_.top().table}).first;
typename Pointer::value_type obj;
access::process(*this, obj);
table_info_stack_.pop();
append_join(
table_column{&table_info_stack_.top().table, id},
table_column{&next->second, info.primary_key_attribute()->name()}
);
} else {
push(id);
}
} }
template<class Pointer> template<class Pointer>
void on_has_one(const char *id, Pointer &obj, const utils::foreign_attributes &attr) { void on_has_one(const char * /*id*/, Pointer &/*obj*/, const char * join_column, const utils::foreign_attributes &attr) {
on_foreign_object(id, obj, attr); const auto it = schema_.find(typeid(typename Pointer::value_type));
if (it == schema_.end()) {
throw query_builder_exception{error_code::UnknownType, "Unknown type"};
}
if (!it->second.node().info().has_primary_key()) {
throw query_builder_exception{error_code::MissingPrimaryKey, "Missing primary key"};
}
const auto& info = it->second.node().info();
auto foreign_table = it->second.table().as(build_alias('t', ++table_index));
if (attr.fetch() == utils::fetch_type::Eager) {
auto next = processed_tables_.find(info.name());
if (next != processed_tables_.end()) {
return;
}
table_info_stack_.push({info, std::move(foreign_table)});
next = processed_tables_.insert({info.name(), table_info_stack_.top().table}).first;
typename Pointer::value_type obj;
access::process(*this, obj);
table_info_stack_.pop();
append_join(
table_column{&table_info_stack_.top().table, it->second.node().info().primary_key_attribute()->name()},
table_column{&next->second, join_column}
);
}
} }
template<typename T> template<typename T>
@@ -257,8 +311,6 @@ public:
[[nodiscard]] const select_query_data &query_data() const; [[nodiscard]] const select_query_data &query_data() const;
private: private:
template<class Pointer>
void on_foreign_object(const char *id, Pointer &, const utils::foreign_attributes &attr);
void push(const std::string &column_name); void push(const std::string &column_name);
static std::string build_alias(char prefix, unsigned int count); static std::string build_alias(char prefix, unsigned int count);
[[nodiscard]] bool is_root_entity() const; [[nodiscard]] bool is_root_entity() const;
@@ -278,39 +330,5 @@ private:
unsigned int table_index{0}; unsigned int table_index{0};
object::join_columns_collector join_columns_collector_{}; object::join_columns_collector join_columns_collector_{};
}; };
template<class Pointer>
void select_query_builder::on_foreign_object(const char *id, Pointer &, const utils::foreign_attributes &attr) {
const auto it = schema_.find(typeid(typename Pointer::value_type));
if (it == schema_.end()) {
throw query_builder_exception{error_code::UnknownType, "Unknown type"};
}
if (!it->second.node().info().has_primary_key()) {
throw query_builder_exception{error_code::MissingPrimaryKey, "Missing primary key"};
}
const auto& info = it->second.node().info();
auto foreign_table = it->second.table().as(build_alias('t', ++table_index));
if (attr.fetch() == utils::fetch_type::Eager) {
auto next = processed_tables_.find(info.name());
if (next != processed_tables_.end()) {
return;
}
table_info_stack_.push({info, std::move(foreign_table)});
next = processed_tables_.insert({info.name(), table_info_stack_.top().table}).first;
typename Pointer::value_type obj;
access::process(*this, obj);
table_info_stack_.pop();
append_join(
table_column{&table_info_stack_.top().table, id},
table_column{&next->second, info.primary_key_attribute()->name()}
);
} else {
push(id);
}
}
} }
#endif //QUERY_ENTITY_QUERY_BUILDER_HPP #endif //QUERY_ENTITY_QUERY_BUILDER_HPP
+80 -41
View File
@@ -2,6 +2,7 @@
#define QUERY_SESSION_HPP #define QUERY_SESSION_HPP
#include "matador/query/error_code.hpp" #include "matador/query/error_code.hpp"
#include "matador/query/delete_query_builder.hpp"
#include "matador/query/select_query_builder.hpp" #include "matador/query/select_query_builder.hpp"
#include "matador/query/criteria.hpp" #include "matador/query/criteria.hpp"
#include "matador/query/insert_query_builder.hpp" #include "matador/query/insert_query_builder.hpp"
@@ -16,6 +17,7 @@
#include "matador/sql/statement.hpp" #include "matador/sql/statement.hpp"
#include "matador/sql/statement_cache.hpp" #include "matador/sql/statement_cache.hpp"
#include "matador/object/object_cache.hpp"
#include "matador/object/object_ptr.hpp" #include "matador/object/object_ptr.hpp"
#include <unordered_map> #include <unordered_map>
@@ -51,7 +53,6 @@ public:
*/ */
template<typename Type> template<typename Type>
utils::result<object::object_ptr<Type>, utils::error> insert(object::object_ptr<Type> obj); utils::result<object::object_ptr<Type>, utils::error> insert(object::object_ptr<Type> obj);
template<typename Type> template<typename Type>
utils::result<object::object_ptr<Type>, utils::error> update(const object::object_ptr<Type> &obj); utils::result<object::object_ptr<Type>, utils::error> update(const object::object_ptr<Type> &obj);
template<typename Type> template<typename Type>
@@ -69,6 +70,8 @@ private:
mutable sql::statement_cache cache_; mutable sql::statement_cache cache_;
const sql::dialect &dialect_; const sql::dialect &dialect_;
object::object_cache object_cache_;
const basic_schema &schema_; const basic_schema &schema_;
mutable std::unordered_map<std::string, std::vector<object::attribute> > prototypes_; mutable std::unordered_map<std::string, std::vector<object::attribute> > prototypes_;
std::shared_ptr<sql::resolver_service> resolver_service_; std::shared_ptr<sql::resolver_service> resolver_service_;
@@ -81,8 +84,7 @@ utils::result<object::object_ptr<Type>, utils::error> session::insert(object::ob
return utils::ok(obj); return utils::ok(obj);
} }
const auto it = schema_.find(typeid(Type)); if (const auto it = schema_.find(typeid(Type)); it == schema_.end()) {
if (it == schema_.end()) {
return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type.")); return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type."));
} }
@@ -94,45 +96,34 @@ utils::result<object::object_ptr<Type>, utils::error> session::insert(object::ob
} }
// Execute all steps; for Identity steps read RETURNING and write pk back into the object // Execute all steps; for Identity steps read RETURNING and write pk back into the object
for (insert_step &step : *steps) { for (auto &step : *steps) {
if (step.pk_generator == utils::generator_type::Sequence || step.pk_generator == utils::generator_type::Table) {
const auto conn = pool_.acquire(); const auto conn = pool_.acquire();
if (!conn.valid()) { if (!conn.valid()) {
return utils::failure(make_error(error_code::FailedToAcquirePool, "Failed to acquire connection pool for primary key generation.")); return utils::failure(make_error(error_code::FailedToAcquirePool, "Failed to acquire connection pool for primary key generation."));
} }
auto result = it->second.pk_generator().next_id(*conn);
if (!result.is_ok()) { if (const auto result = step->prepare(*conn); !result.is_ok()) {
return utils::failure(result.err()); return utils::failure(result.err());
} }
step.apply_primary_key(utils::identifier{*result}); conn.release();
}
auto stmt = cache_.acquire(step.ctx); auto stmt = cache_.acquire(step->ctx());
if (!stmt.is_ok()) { if (!stmt.is_ok()) {
return utils::failure(stmt.err()); return utils::failure(stmt.err());
} }
if (auto result = step.acquire_and_bind(*stmt); !result.is_ok()) { if (const auto result = step->execute(*stmt); !result.is_ok()) {
return utils::failure(result.err());
}
}
// After successfully executed all inserts, add them to the object cache
for (auto &step : *steps) {
if (const auto result = step->finalize(object_cache_, resolver_service_); !result.is_ok()) {
return utils::failure(result.err()); return utils::failure(result.err());
} }
if (step.pk_generator == utils::generator_type::Identity) {
// insert and read RETURNING
auto record = stmt->fetch_one();
if (!record.is_ok()) {
return utils::failure(record.err());
}
if (!record.value().has_value()) {
return utils::failure(make_error(error_code::FailedToFindObject, "Failed to insert object and retrieve identity."));
}
step.apply_returning(*record.value());
} else if (const auto exec_result = stmt->execute(); !exec_result.is_ok()) {
return utils::failure(exec_result.err());
}
step.make_object_persistent();
} }
obj.change_state(object::object_state::Persistent);
return utils::ok(obj); return utils::ok(obj);
} }
@@ -162,7 +153,7 @@ public:
template<class Pointer> template<class Pointer>
static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
template<class Pointer> template<class Pointer>
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_has_one(const char * /*id*/, Pointer &/*x*/, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many(const char * /*id*/, static void on_has_many(const char * /*id*/,
@@ -216,28 +207,67 @@ utils::result<object::object_ptr<Type>, utils::error> session::update(const obje
template<typename Type> template<typename Type>
utils::result<void, utils::error> session::remove(const object::object_ptr<Type> &obj) { utils::result<void, utils::error> session::remove(const object::object_ptr<Type> &obj) {
const auto it = schema_.find(typeid(Type)); if (!obj.is_persistent()) {
if (it == schema_.end()) { return utils::ok<void>();
}
if (const auto it = schema_.find(typeid(Type)); it == schema_.end()) {
return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type.")); return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type."));
} }
using namespace matador::utils;
using namespace matador::query;
const auto col = table_column(it->second.node().info().primary_key_attribute()->name()); delete_query_builder<Type> dqb(schema_, contexts_by_type_);
const auto cit = contexts_by_type_.find(it->second.node().info().type_index()); auto steps = dqb.build(obj);
if (cit == contexts_by_type_.end()) { if (!steps.is_ok()) {
return failure(make_error(error_code::UnknownType, "Failed to determine requested type.")); return utils::failure(make_error(error_code::FailedToBuildQuery, "Failed to build delete dependency queries."));
} }
auto stmt = cache_.acquire(cit->second.delete_one);
for (auto &step : *steps) {
const auto conn = pool_.acquire();
if (!conn.valid()) {
return utils::failure(make_error(error_code::FailedToAcquirePool, "Failed to acquire connection pool for primary key generation."));
}
if (const auto result = step->prepare(*conn); !result.is_ok()) {
return utils::failure(result.err());
}
conn.release();
auto stmt = cache_.acquire(step->ctx());
if (!stmt.is_ok()) { if (!stmt.is_ok()) {
return failure(stmt.err()); return utils::failure(stmt.err());
} }
pk_object_binder binder(*stmt, stmt->bind_pos()); if (const auto result = step->execute(*stmt); !result.is_ok()) {
if (const auto update_result = binder.bind(*obj).execute(); !update_result.is_ok()) { return utils::failure(result.err());
return utils::failure(update_result.err());
} }
}
// After successfully executed all deletes, add them to the object cache
for (auto &step : *steps) {
if (const auto result = step->finalize(object_cache_, resolver_service_); !result.is_ok()) {
return utils::failure(result.err());
}
}
return utils::ok<void>(); return utils::ok<void>();
// using namespace matador::utils;
// using namespace matador::query;
//
// const auto col = table_column(it->second.node().info().primary_key_attribute()->name());
// const auto cit = contexts_by_type_.find(it->second.node().info().type_index());
// if (cit == contexts_by_type_.end()) {
// return failure(make_error(error_code::UnknownType, "Failed to determine requested type."));
// }
// auto stmt = cache_.acquire(cit->second.delete_one);
// if (!stmt.is_ok()) {
// return failure(stmt.err());
// }
//
// pk_object_binder binder(*stmt, stmt->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> template<typename Type, typename PrimaryKeyType>
@@ -251,6 +281,15 @@ utils::result<object::object_ptr<Type>, utils::error> session::find(const Primar
return utils::failure(make_error(error_code::FailedToFindPrimaryKey, "Type hasn't primary key.")); return utils::failure(make_error(error_code::FailedToFindPrimaryKey, "Type hasn't primary key."));
} }
auto resolver = resolver_service_->template object_resolver<Type>();
if (!resolver) {
return utils::failure(utils::error(error_code::UnknownType, "Missing object resolver for inserted type."));
}
if (object_cache_.is_loaded<Type>(utils::identifier{pk})) {
return utils::ok(object::object_ptr(object_cache_.acquire_proxy<Type>(utils::identifier{pk}, resolver)));
}
select_query_builder eqb(schema_); select_query_builder eqb(schema_);
auto data = eqb.build<Type>(*it->second.table().primary_key_column() == pk); auto data = eqb.build<Type>(*it->second.table().primary_key_column() == pk);
if (!data.is_ok()) { if (!data.is_ok()) {
+6 -5
View File
@@ -17,6 +17,7 @@ public:
table(const char *name); // NOLINT(*-explicit-constructor) table(const char *name); // NOLINT(*-explicit-constructor)
table(const std::string& name); // NOLINT(*-explicit-constructor) table(const std::string& name); // NOLINT(*-explicit-constructor)
table(const std::string& name, const std::vector<table_column>& columns); table(const std::string& name, const std::vector<table_column>& columns);
table(const std::string& name, const std::vector<table_column>& columns, const std::string& join_column, const std::string& inverse_join_column);
table(const table& other); table(const table& other);
table& operator=(const table& other); table& operator=(const table& other);
table(table&& other) noexcept; table(table&& other) noexcept;
@@ -44,11 +45,11 @@ public:
[[nodiscard]] bool has_primary_key() const; [[nodiscard]] bool has_primary_key() const;
[[nodiscard]] const table_column* primary_key_column() const; [[nodiscard]] const table_column* primary_key_column() const;
[[nodiscard]] const std::string& join_column_name() const; [[nodiscard]] const table_column* join_column() const;
[[nodiscard]] const std::string& inverse_join_column_name() const; [[nodiscard]] const table_column* inverse_join_column() const;
protected: protected:
table(std::string name, std::string alias, const std::vector<table_column>& columns); table(std::string name, std::string alias, const std::vector<table_column>& columns, const std::string& join_column, const std::string& inverse_join_column);
private: private:
friend table_column; friend table_column;
@@ -60,8 +61,8 @@ private:
std::vector<table_column> columns_; std::vector<table_column> columns_;
int pk_column_index_{-1}; int pk_column_index_{-1};
std::string join_column_name_; int join_column_index_{-1};
std::string inverse_join_column_name_; int inverse_join_column_index_{-1};
}; };
template<typename Type = table> template<typename Type = table>
+1 -2
View File
@@ -44,8 +44,7 @@ public:
values_.emplace_back(fk_value_extractor_.extract(*x)); values_.emplace_back(fk_value_extractor_.extract(*x));
} }
template<class Type, template < class ... > class Pointer> template<class Type, template < class ... > class Pointer>
void on_has_one(const char * /*id*/, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/) void on_has_one(const char * /*id*/, Pointer<Type> &x, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {
{
values_.emplace_back(fk_value_extractor_.extract(*x)); values_.emplace_back(fk_value_extractor_.extract(*x));
} }
template<class ContainerType> template<class ContainerType>
+2
View File
@@ -36,6 +36,8 @@ public:
[[nodiscard]] std::optional<size_t> id() const; [[nodiscard]] std::optional<size_t> id() const;
[[nodiscard]] bool valid() const; [[nodiscard]] bool valid() const;
void release() const;
private: private:
friend class connection_pool; friend class connection_pool;
+4 -45
View File
@@ -21,15 +21,14 @@ namespace matador::sql {
class connection_impl; class connection_impl;
class dialect final class dialect final {
{
public: public:
/** /**
* Holding enums concerning escaping identifiers * Holding enums concerning escaping identifiers
*/ */
enum class escape_identifier_t : uint8_t { enum class escape_identifier_t : uint8_t {
ESCAPE_BOTH_SAME, /**< The escape quotes are the same */ EscapeBothSame, /**< The escape quotes are the same */
ESCAPE_CLOSING_BRACKET /**< The escape quotes differ; escape the closing one */ EscapeClosingBracket /**< The escape quotes differ; escape the closing one */
}; };
using token_to_string_map = std::unordered_map<dialect_token, std::string>; using token_to_string_map = std::unordered_map<dialect_token, std::string>;
@@ -44,50 +43,10 @@ public:
[[nodiscard]] const std::string& data_type_at(utils::basic_type type) const; [[nodiscard]] const std::string& data_type_at(utils::basic_type type) const;
[[nodiscard]] const std::string& sql_function_at(sql_function_t func) const; [[nodiscard]] const std::string& sql_function_at(sql_function_t func) const;
/**
* Prepare sql dialect identifier for execution
* and escape quotes and quote the identifier
* string
*
* @param col The identifier string to be prepared
* @return The prepared string
*/
[[nodiscard]] std::string prepare_identifier_string(const std::string &col) const;
[[nodiscard]] const std::string& to_string(bool val) const; [[nodiscard]] const std::string& to_string(bool val) const;
[[nodiscard]] std::string to_sql_string(const utils::value &val) const ;
void bool_strings(const std::string &true_string, const std::string &false_string); void bool_strings(const std::string &true_string, const std::string &false_string);
/**
* Prepare string literal
*
* @param str String literal to be prepared
*/
[[nodiscard]] std::string prepare_literal(const std::string &str) const;
/**
* Wrap identifier quotes around a SQL identifier keyword
*
* @param str Identifier to put quotes around
*/
void quote_identifier(std::string &str) const;
/**
* Escape identifier quotes inside identifiers.
*
* @param str Identifier to be escaped
*/
void escape_quotes_in_identifier(std::string &str) const;
/**
* Escape quotes in string literals
*
* @param str String literal to be escaped
*/
void escape_quotes_in_literals(std::string &str) const;
/** /**
* Returns how the identifier quotes should be * Returns how the identifier quotes should be
* escaped. * escaped.
@@ -192,7 +151,7 @@ private:
next_placeholder_func placeholder_func_ = [](size_t) { return "?"; }; next_placeholder_func placeholder_func_ = [](size_t) { return "?"; };
to_escaped_string_func to_escaped_string_func_ = [](const utils::blob_type_t &val) { return utils::to_string(val); }; to_escaped_string_func to_escaped_string_func_ = [](const utils::blob_type_t &val) { return utils::to_string(val); };
escape_identifier_t identifier_escape_type_ = escape_identifier_t::ESCAPE_BOTH_SAME; escape_identifier_t identifier_escape_type_ = escape_identifier_t::EscapeBothSame;
std::string default_schema_name_; std::string default_schema_name_;
+1 -1
View File
@@ -68,7 +68,7 @@ public:
on_foreign_key(id, x, attr); on_foreign_key(id, x, attr);
} }
template<class Pointer> template<class Pointer>
void on_has_one(const char *id, Pointer &x, const utils::foreign_attributes &attr) { void on_has_one(const char *id, Pointer &x, const char * /*join_column*/, const utils::foreign_attributes &attr) {
on_foreign_key(id, x, attr); on_foreign_key(id, x, attr);
} }
@@ -5,6 +5,7 @@
#include "matador/object/attribute.hpp" #include "matador/object/attribute.hpp"
#include "matador/sql/dialect.hpp"
#include "matador/sql/connection_info.hpp" #include "matador/sql/connection_info.hpp"
#include "matador/sql/execute_result.hpp" #include "matador/sql/execute_result.hpp"
@@ -17,13 +18,11 @@ using blob_type_t = std::vector<unsigned char>;
} }
namespace matador::sql { namespace matador::sql {
struct query_context; struct query_context;
class query_result_impl; class query_result_impl;
class statement_impl; class statement_impl;
class connection_impl class connection_impl {
{
public: public:
virtual ~connection_impl() = default; virtual ~connection_impl() = default;
@@ -36,7 +36,7 @@ public:
template < class Pointer > template < class Pointer >
static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
template < class Pointer > template < class Pointer >
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_has_one(const char * /*id*/, Pointer &/*x*/, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {} static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType> template<class ContainerType>
@@ -1,7 +1,7 @@
#ifndef MATADOR_COLLECTION_RESOLVER_PRODUCER_HPP #ifndef MATADOR_COLLECTION_RESOLVER_PRODUCER_HPP
#define MATADOR_COLLECTION_RESOLVER_PRODUCER_HPP #define MATADOR_COLLECTION_RESOLVER_PRODUCER_HPP
#include "matador/object/abstract_collection_resolver.hpp" #include "matador/object/abstract_joined_resolver.hpp"
#include "matador/sql/query_context.hpp" #include "matador/sql/query_context.hpp"
@@ -14,23 +14,23 @@ namespace matador::sql {
class dialect; class dialect;
class statement; class statement;
class resolver_service; class resolver_service;
class collection_resolver_producer { class joined_collection_resolver_producer {
public: public:
virtual ~collection_resolver_producer() = default; virtual ~joined_collection_resolver_producer() = default;
virtual utils::result<query_context, utils::error> build_query(const dialect& d) = 0; virtual utils::result<query_context, utils::error> build_query(const dialect& d) = 0;
virtual std::shared_ptr<object::abstract_collection_resolver> produce(statement&& stmt, const resolver_service& rs) = 0; virtual std::shared_ptr<object::abstract_joined_resolver> produce(statement&& stmt, const resolver_service& rs) = 0;
[[nodiscard]] const std::type_index& root_type() const; [[nodiscard]] const std::type_index& root_type() const;
[[nodiscard]] const std::type_index& type() const; [[nodiscard]] const std::type_index& type() const;
[[nodiscard]] const std::string& collection_name() const; [[nodiscard]] const std::string& join_column_name() const;
protected: protected:
explicit collection_resolver_producer(const std::type_index &root_type, const std::type_index &type, std::string collection_name); explicit joined_collection_resolver_producer(const std::type_index &root_type, const std::type_index &type, std::string join_column_name);
private: private:
std::type_index root_type_; std::type_index root_type_;
std::type_index type_; std::type_index type_;
std::string collection_name_; std::string join_column_name_;
}; };
} }
#endif // MATADOR_COLLECTION_RESOLVER_PRODUCER_HPP #endif // MATADOR_COLLECTION_RESOLVER_PRODUCER_HPP
@@ -27,5 +27,24 @@ protected:
private: private:
std::type_index type_; std::type_index type_;
}; };
class joined_object_resolver_producer {
public:
virtual ~joined_object_resolver_producer() = default;
virtual utils::result<query_context, utils::error> build_query(const dialect& d) = 0;
virtual std::shared_ptr<object::abstract_type_resolver> produce(statement&& stmt) = 0;
[[nodiscard]] const std::type_index& root_type() const;
[[nodiscard]] const std::type_index& type() const;
[[nodiscard]] const std::string& collection_name() const;
protected:
explicit joined_object_resolver_producer(const std::type_index &root_type, const std::type_index &type, std::string collection_name);
private:
std::type_index root_type_;
std::type_index type_;
std::string collection_name_;
};
} }
#endif //MATADOR_RESOLVER_PRODUCER_HPP #endif //MATADOR_RESOLVER_PRODUCER_HPP
@@ -38,7 +38,7 @@ public:
template < class Pointer > template < class Pointer >
static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
template < class Pointer > template < class Pointer >
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_has_one(const char * /*id*/, Pointer &/*x*/, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many(const char * /*id*/, static void on_has_many(const char * /*id*/,
@@ -96,7 +96,7 @@ public:
fk_result_binder_.bind(*x, id, index_++, *binder_); fk_result_binder_.bind(*x, id, index_++, *binder_);
} }
template<class Type, template < class ... > class Pointer> template<class Type, template < class ... > class Pointer>
void on_has_one(const char *id, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/) { void on_has_one(const char *id, Pointer<Type> &x, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {
fk_result_binder_.bind(*x, id, index_++, *binder_); fk_result_binder_.bind(*x, id, index_++, *binder_);
} }
template<class ContainerType> template<class ContainerType>
+1 -1
View File
@@ -32,7 +32,7 @@ public:
++column_index_; ++column_index_;
} }
template<class Pointer> template<class Pointer>
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_has_one(const char * /*id*/, Pointer &/*x*/, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many(const char * /*id*/, ContainerType &, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {} static void on_has_many(const char * /*id*/, ContainerType &, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType> template<class ContainerType>
@@ -63,15 +63,9 @@ public:
void on_attribute(const char *id, utils::value &val, const utils::field_attributes &attr); void on_attribute(const char *id, utils::value &val, const utils::field_attributes &attr);
template<class Pointer> template<class Pointer>
void on_belongs_to(const char * /*id*/, Pointer &x, const utils::foreign_attributes &attr) { void on_belongs_to(const char * /*id*/, Pointer &x, const utils::foreign_attributes &attr);
on_foreign_key(x, attr); template<class PointerType>
} void on_has_one(const char * /*id*/, object::object_ptr<PointerType> &x, const char * /*join_column*/, const utils::foreign_attributes &attr);
template<class Pointer>
void on_has_one(const char * /*id*/, Pointer &x, const utils::foreign_attributes &attr) {
on_foreign_key(x, attr);
}
template<class CollectionType> template<class CollectionType>
void on_has_many(const char * /*id*/, CollectionType &cont, const char *join_column, const utils::foreign_attributes &attr, std::enable_if_t<object::is_object_ptr<typename CollectionType::value_type>::value> * = nullptr); void on_has_many(const char * /*id*/, CollectionType &cont, const char *join_column, const utils::foreign_attributes &attr, std::enable_if_t<object::is_object_ptr<typename CollectionType::value_type>::value> * = nullptr);
template<class CollectionType> template<class CollectionType>
@@ -103,8 +97,22 @@ private:
return resolver.discover(obj); return resolver.discover(obj);
} }
protected:
size_t column_index_ = 0;
std::vector<object::attribute> prototype_;
std::unique_ptr<query_result_reader> reader_;
std::shared_ptr<resolver_service> resolver_;
const std::type_index result_type_;
internal::identifier_reader id_reader_;
detail::pk_reader pk_reader_;
std::stack<std::type_index> type_stack_;
utils::identifier current_pk_{};
utils::identifier last_pk_{};
std::unordered_set<object::collection_composite_key, object::collection_composite_key_hash> initialized_collections_;
};
template <class Pointer> template <class Pointer>
void on_foreign_key(Pointer &x, const utils::foreign_attributes &attr) { void query_result_impl::on_belongs_to(const char*, Pointer& x, const utils::foreign_attributes& attr) {
const auto resolver = resolver_->object_resolver<typename Pointer::value_type>(); const auto resolver = resolver_->object_resolver<typename Pointer::value_type>();
if (attr.fetch() == utils::fetch_type::Lazy) { if (attr.fetch() == utils::fetch_type::Lazy) {
typename Pointer::value_type obj; typename Pointer::value_type obj;
@@ -120,25 +128,26 @@ private:
} }
} }
protected: template <class PointerType>
size_t column_index_ = 0; void query_result_impl::on_has_one(const char*, object::object_ptr<PointerType>& x, const char *join_column, const utils::foreign_attributes& attr) {
std::vector<object::attribute> prototype_; const auto resolver = resolver_->joined_object_resolver<PointerType>(result_type_, join_column);
std::unique_ptr<query_result_reader> reader_; if (attr.fetch() == utils::fetch_type::Lazy) {
std::shared_ptr<resolver_service> resolver_; x.reset(std::make_shared<object::object_proxy<PointerType>>(resolver, current_pk_));
const std::type_index result_type_; } else {
internal::identifier_reader id_reader_; auto obj = std::make_shared<PointerType>();
detail::pk_reader pk_reader_; const auto ti = std::type_index(typeid(*x));
std::stack<std::type_index> type_stack_; type_stack_.push(ti);
utils::identifier current_pk_{}; access::process(*this, *obj);
utils::identifier last_pk_{}; type_stack_.pop();
std::unordered_set<object::collection_composite_key, object::collection_composite_key_hash> initialized_collections_; x.reset(std::make_shared<object::object_proxy<PointerType>>(resolver, obj));
}; }
}
template <class CollectionType> template <class CollectionType>
void query_result_impl::on_has_many(const char *, CollectionType &cont, const char *join_column, const utils::foreign_attributes &attr, std::enable_if_t<object::is_object_ptr<typename CollectionType::value_type>::value> *) { void query_result_impl::on_has_many(const char *, CollectionType &cont, const char *join_column, const utils::foreign_attributes &attr, std::enable_if_t<object::is_object_ptr<typename CollectionType::value_type>::value> *) {
using value_type = typename CollectionType::value_type::value_type; using value_type = typename CollectionType::value_type::value_type;
auto object_resolver = resolver_->object_resolver<value_type>(); auto object_resolver = resolver_->object_resolver<value_type>();
auto resolver = resolver_->collection_resolver<typename CollectionType::value_type>(result_type_, join_column); auto resolver = resolver_->joined_collection_resolver<typename CollectionType::value_type>(result_type_, join_column);
if (attr.fetch() == utils::fetch_type::Lazy) { if (attr.fetch() == utils::fetch_type::Lazy) {
cont.reset(std::make_shared<object::collection_proxy<typename CollectionType::value_type>>(resolver, current_pk_)); cont.reset(std::make_shared<object::collection_proxy<typename CollectionType::value_type>>(resolver, current_pk_));
@@ -163,7 +172,7 @@ template <class CollectionType>
void query_result_impl::on_has_many(const char *id, CollectionType &cont, const char *join_column, const utils::foreign_attributes &attr, std::enable_if_t<!object::is_object_ptr<typename CollectionType::value_type>::value> *) { void query_result_impl::on_has_many(const char *id, CollectionType &cont, const char *join_column, const utils::foreign_attributes &attr, std::enable_if_t<!object::is_object_ptr<typename CollectionType::value_type>::value> *) {
using value_type = typename CollectionType::value_type; using value_type = typename CollectionType::value_type;
auto object_resolver = resolver_->object_resolver<value_type>(); auto object_resolver = resolver_->object_resolver<value_type>();
auto resolver = resolver_->collection_resolver<value_type>(result_type_, join_column); auto resolver = resolver_->joined_collection_resolver<value_type>(result_type_, join_column);
if (attr.fetch() == utils::fetch_type::Lazy) { if (attr.fetch() == utils::fetch_type::Lazy) {
cont.reset(std::make_shared<object::collection_proxy<value_type>>(resolver, current_pk_)); cont.reset(std::make_shared<object::collection_proxy<value_type>>(resolver, current_pk_));
@@ -183,7 +192,7 @@ template <class CollectionType>
void query_result_impl::on_has_many_to_many(const char *id, CollectionType &cont, const char *join_column, const char *, const utils::foreign_attributes &attr) { void query_result_impl::on_has_many_to_many(const char *id, CollectionType &cont, const char *join_column, const char *, const utils::foreign_attributes &attr) {
using value_type = typename CollectionType::value_type::value_type; using value_type = typename CollectionType::value_type::value_type;
auto object_resolver = resolver_->object_resolver<value_type>(); auto object_resolver = resolver_->object_resolver<value_type>();
auto resolver = resolver_->collection_resolver<typename CollectionType::value_type>(result_type_, join_column); auto resolver = resolver_->joined_collection_resolver<typename CollectionType::value_type>(result_type_, join_column);
if (attr.fetch() == utils::fetch_type::Lazy) { if (attr.fetch() == utils::fetch_type::Lazy) {
cont.reset(std::make_shared<object::collection_proxy<typename CollectionType::value_type>>(resolver, current_pk_)); cont.reset(std::make_shared<object::collection_proxy<typename CollectionType::value_type>>(resolver, current_pk_));
} else { } else {
@@ -211,7 +220,7 @@ void query_result_impl::on_has_many_to_many(const char *id, CollectionType &cont
const auto jc = collector.collect<typename CollectionType::value_type::value_type>(); const auto jc = collector.collect<typename CollectionType::value_type::value_type>();
auto object_resolver = resolver_->object_resolver<value_type>(); auto object_resolver = resolver_->object_resolver<value_type>();
auto resolver = resolver_->collection_resolver<typename CollectionType::value_type>(result_type_, jc.inverse_join_column); auto resolver = resolver_->joined_collection_resolver<typename CollectionType::value_type>(result_type_, jc.inverse_join_column);
if (attr.fetch() == utils::fetch_type::Lazy) { if (attr.fetch() == utils::fetch_type::Lazy) {
cont.reset(std::make_shared<object::collection_proxy<typename CollectionType::value_type>>(resolver, current_pk_)); cont.reset(std::make_shared<object::collection_proxy<typename CollectionType::value_type>>(resolver, current_pk_));
} else { } else {
@@ -16,7 +16,8 @@ namespace matador::sql::internal {
class query_result_pk_resolver final { class query_result_pk_resolver final {
public: public:
explicit query_result_pk_resolver(query_result_reader &reader) : reader_(reader) {} explicit query_result_pk_resolver(query_result_reader &reader)
: reader_(reader) {}
template<class Type> template<class Type>
utils::identifier discover(Type &obj) { utils::identifier discover(Type &obj) {
@@ -38,16 +39,22 @@ public:
utils::data_type_traits<ValueType>::read_value(reader_, id, column_index_++, value, attr.size()); utils::data_type_traits<ValueType>::read_value(reader_, id, column_index_++, value, attr.size());
pk_ = value; pk_ = value;
} }
void on_revision(const char * /*id*/, uint64_t &/*rev*/) { ++column_index_; } void on_revision(const char * /*id*/, uint64_t &/*rev*/) {
++column_index_;
}
template < class Type > template < class Type >
void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/) { ++column_index_; } void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/) { ++column_index_; }
void on_attribute(const char *id, const utils::value &x, const utils::field_attributes &attr); void on_attribute(const char *id, const utils::value &x, const utils::field_attributes &attr);
template < class Pointer > template < class Pointer >
void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &attr) { on_foreign_key<typename Pointer::value_type>(attr.fetch() ); } void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &attr) {
on_foreign_key<typename Pointer::value_type>(attr.fetch() );
}
template < class Pointer > template < class Pointer >
void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &attr) { on_foreign_key<typename Pointer::value_type>(attr.fetch() ); } void on_has_one(const char * /*id*/, Pointer &/*x*/, const char * /*join_column*/, const utils::foreign_attributes &attr) {
on_foreign_key<typename Pointer::value_type>(attr.fetch() );
}
template<class ContainerType> template<class ContainerType>
static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {} static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {}
@@ -38,9 +38,10 @@ public:
pk_binder_.bind(*x, index_++, *binder_); pk_binder_.bind(*x, index_++, *binder_);
} }
template<class Type, template < class ... > class Pointer> template<class Type, template < class ... > class Pointer>
void on_has_one(const char * /*id*/, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/) { static void on_has_one(const char * /*id*/,
pk_binder_.bind(*x, index_++, *binder_); Pointer<Type> &/*x*/,
} const char * /*join_column*/,
const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many(const char * /*id*/, static void on_has_many(const char * /*id*/,
ContainerType &/*c*/, ContainerType &/*c*/,
+1 -1
View File
@@ -30,7 +30,7 @@ public:
template < class Pointer > template < class Pointer >
static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
template < class Pointer > template < class Pointer >
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_has_one(const char * /*id*/, Pointer &/*x*/, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many(const char * /*id*/, static void on_has_many(const char * /*id*/,
@@ -0,0 +1,45 @@
#ifndef MATADOR_RESOLVER_FACTORY_HPP
#define MATADOR_RESOLVER_FACTORY_HPP
#include <unordered_map>
#include "matador/object/abstract_joined_resolver.hpp"
#include "matador/object/object_resolver_factory.hpp"
#include "matador/object/joined_collection_resolver_factory.hpp"
#include "matador/object/collection_utils.hpp"
namespace matador::sql {
class executor;
class producer_object_resolver_factory : public object::object_resolver_factory {
public:
[[nodiscard]] std::shared_ptr<object::abstract_type_resolver> acquire_object_resolver(const std::type_index &type) const override;
void register_object_resolver(std::shared_ptr<object::abstract_type_resolver> &&resolver) override;
private:
std::unordered_map<std::type_index, std::shared_ptr<object::abstract_type_resolver>> resolvers_;
};
class producer_joined_collection_resolver_factory : public object::joined_collection_resolver_factory {
public:
[[nodiscard]] std::shared_ptr<object::abstract_joined_resolver> acquire_collection_resolver(const std::type_index& root_type,
const std::type_index& element_type,
const std::string& collection_name) const override;
void register_collection_resolver(std::shared_ptr<object::abstract_joined_resolver>&& resolver) override;
private:
std::unordered_map<object::collection_composite_key, std::shared_ptr<object::abstract_joined_resolver>, object::collection_composite_key_hash> resolvers_;
};
class producer_joined_object_resolver_factory : public object::joined_object_resolver_factory {
public:
[[nodiscard]] std::shared_ptr<object::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 override;
void register_joined_object_resolver(std::shared_ptr<object::abstract_type_resolver>&& resolver, const std::type_index& root_type, const std::string& join_column) override;
private:
std::unordered_map<object::collection_composite_key, std::shared_ptr<object::abstract_type_resolver>, object::collection_composite_key_hash> resolvers_;
};
}
#endif //MATADOR_RESOLVER_FACTORY_HPP
@@ -1,34 +0,0 @@
#ifndef MATADOR_RESOLVER_FACTORY_HPP
#define MATADOR_RESOLVER_FACTORY_HPP
#include <unordered_map>
#include "matador/object/abstract_collection_resolver.hpp"
#include "matador/object/object_resolver_factory.hpp"
#include "matador/object/collection_resolver_factory.hpp"
#include "matador/object/collection_utils.hpp"
namespace matador::sql {
class executor;
class producer_resolver_factory : public object::object_resolver_factory {
public:
[[nodiscard]] std::shared_ptr<object::abstract_type_resolver> acquire_object_resolver(const std::type_index &type) const override;
void register_object_resolver(std::shared_ptr<object::abstract_type_resolver> &&resolver) override;
private:
std::unordered_map<std::type_index, std::shared_ptr<object::abstract_type_resolver>> resolvers_;
};
class producer_collection_resolver_factory : public object::collection_resolver_factory {
public:
[[nodiscard]] std::shared_ptr<object::abstract_collection_resolver> acquire_collection_resolver(const std::type_index& root_type,
const std::type_index& element_type,
const std::string& collection_name) const override;
void register_collection_resolver(std::shared_ptr<object::abstract_collection_resolver>&& resolver) override;
private:
std::unordered_map<object::collection_composite_key, std::shared_ptr<object::abstract_collection_resolver>, object::collection_composite_key_hash> resolvers_;
};
}
#endif //MATADOR_RESOLVER_FACTORY_HPP
-4
View File
@@ -5,8 +5,6 @@
#include "matador/sql/resolver_service.hpp" #include "matador/sql/resolver_service.hpp"
#include "matador/utils/types.hpp"
namespace matador::sql { namespace matador::sql {
enum class sql_command { enum class sql_command {
Unknown, Unknown,
@@ -33,12 +31,10 @@ struct query_context {
std::string sql; std::string sql;
size_t sql_hash{}; size_t sql_hash{};
sql_command command{}; sql_command command{};
std::string command_name{};
std::string schema_name{}; std::string schema_name{};
std::string table_name{}; std::string table_name{};
std::vector<object::attribute> prototype{}; std::vector<object::attribute> prototype{};
std::vector<std::string> bind_vars{}; std::vector<std::string> bind_vars{};
// std::vector<utils::database_type> bind_types{};
// Data for resolving query result // Data for resolving query result
std::shared_ptr<resolver_service> resolver{}; std::shared_ptr<resolver_service> resolver{};
std::type_index result_type = typeid(void); std::type_index result_type = typeid(void);
+13 -6
View File
@@ -1,7 +1,7 @@
#ifndef MATADOR_RESOLVER_SERVICE_HPP #ifndef MATADOR_RESOLVER_SERVICE_HPP
#define MATADOR_RESOLVER_SERVICE_HPP #define MATADOR_RESOLVER_SERVICE_HPP
#include "matador/sql/producer_resolver_factory.hpp" #include "matador/sql/producer_object_resolver_factory.hpp"
namespace matador::sql { namespace matador::sql {
class resolver_service { class resolver_service {
@@ -12,16 +12,23 @@ public:
} }
template<class Type> template<class Type>
std::shared_ptr<object::collection_resolver<Type>> collection_resolver(const std::type_index &root_type, const std::string &collection_name) const { std::shared_ptr<object::collection_resolver<Type>> joined_collection_resolver(const std::type_index &root_type, const std::string &collection_name) const {
return collection_resolver_factory_.resolver<Type>(root_type, collection_name); return joined_collection_resolver_factory_.resolver<Type>(root_type, collection_name);
}
template<class Type>
std::shared_ptr<object::object_resolver<Type>> joined_object_resolver(const std::type_index &root_type, const std::string &join_column) const {
return joined_object_resolver_factory_.resolver<Type>(root_type, join_column);
} }
void register_object_resolver(std::shared_ptr<object::abstract_type_resolver> &&resolver); void register_object_resolver(std::shared_ptr<object::abstract_type_resolver> &&resolver);
void register_collection_resolver(std::shared_ptr<object::abstract_collection_resolver>&& resolver); void register_collection_resolver(std::shared_ptr<object::abstract_joined_resolver>&& resolver);
void register_joined_object_resolver(std::shared_ptr<object::abstract_type_resolver>&& resolver, const std::type_index& root_type, const std::string& join_column);
private: private:
sql::producer_resolver_factory object_resolver_factory_; producer_object_resolver_factory object_resolver_factory_;
sql::producer_collection_resolver_factory collection_resolver_factory_; producer_joined_collection_resolver_factory joined_collection_resolver_factory_;
producer_joined_object_resolver_factory joined_object_resolver_factory_;
}; };
} }
#endif // MATADOR_RESOLVER_SERVICE_HPP #endif // MATADOR_RESOLVER_SERVICE_HPP
+3 -3
View File
@@ -3,11 +3,10 @@
#include "matador/sql/abstract_sql_logger.hpp" #include "matador/sql/abstract_sql_logger.hpp"
#include "matador/sql/error_code.hpp" #include "matador/sql/error_code.hpp"
#include "matador/sql/execute_result.hpp"
#include "matador/sql/query_result.hpp" #include "matador/sql/query_result.hpp"
#include "matador/sql/interface/statement_proxy.hpp" #include "matador/sql/interface/statement_proxy.hpp"
#include "matador/object/basic_repository.hpp"
#include "matador/utils/error.hpp" #include "matador/utils/error.hpp"
#include "matador/utils/result.hpp" #include "matador/utils/result.hpp"
@@ -172,7 +171,8 @@ template<class Type>
utils::result<query_result<Type>, utils::error> statement::fetch() { utils::result<query_result<Type>, utils::error> statement::fetch() {
std::cout << statement_proxy_->sql() << std::endl; std::cout << statement_proxy_->sql() << std::endl;
statement_proxy_->statement_->query_.result_type = typeid(Type); statement_proxy_->statement_->query_.result_type = typeid(Type);
return statement_proxy_->fetch(*bindings_).and_then([this](std::unique_ptr<query_result_impl> &&value) { return statement_proxy_->fetch(*bindings_)
.and_then([this](std::unique_ptr<query_result_impl> &&value) -> utils::result<query_result<Type>, utils::error> {
auto resolver = statement_proxy_->statement_->query_.resolver->object_resolver<Type>(); auto resolver = statement_proxy_->statement_->query_.resolver->object_resolver<Type>();
const auto prototype = value->prototype(); const auto prototype = value->prototype();
return utils::ok(query_result<Type>(std::forward<decltype(value)>(value), resolver, [prototype] { return utils::ok(query_result<Type>(std::forward<decltype(value)>(value), resolver, [prototype] {
+8 -19
View File
@@ -1,5 +1,5 @@
#ifndef OOS_ACCESS_HPP #ifndef MATADOR_ACCESS_HPP
#define OOS_ACCESS_HPP #define MATADOR_ACCESS_HPP
#include "matador/utils/primary_key_attribute.hpp" #include "matador/utils/primary_key_attribute.hpp"
#include "matador/utils/field_attributes.hpp" #include "matador/utils/field_attributes.hpp"
@@ -7,17 +7,7 @@
#include <optional> #include <optional>
namespace matador { namespace matador::access {
enum class cascade_type;
namespace utils {
class field_attributes;
class foreign_attributes;
class primary_key_attribute;
}
namespace access {
template<class Operator, class Type> template<class Operator, class Type>
void process(Operator &op, Type &object) { void process(Operator &op, Type &object) {
object.process(op); object.process(op);
@@ -63,13 +53,13 @@ void attribute(Operator &op, const char *id, std::optional<Type> &value, const u
} }
template<class Operator, class Type> template<class Operator, class Type>
void has_one(Operator &op, const char *id, Type &value, const utils::foreign_attributes &attr = utils::CascadeNoneFetchLazy) { void belongs_to(Operator &op, const char *id, Type &value, const utils::foreign_attributes &attr = utils::CascadeNoneFetchLazy) {
op.on_has_one(id, value, attr); op.on_belongs_to(id, value, attr);
} }
template<class Operator, class Type> template<class Operator, class Type>
void belongs_to(Operator &op, const char *id, Type &value, const utils::foreign_attributes &attr = utils::CascadeNoneFetchLazy) { void has_one(Operator &op, const char *id, Type &value, const char *join_column, const utils::foreign_attributes &attr = utils::CascadeNoneFetchLazy) {
op.on_belongs_to(id, value, attr); op.on_has_one(id, value, join_column, attr);
} }
template<class Operator, class Type, template<class ...> class ContainerType> template<class Operator, class Type, template<class ...> class ContainerType>
@@ -92,6 +82,5 @@ void has_many_to_many(Operator &op, const char *id, ContainerType &c, const util
op.on_has_many_to_many(id, c, attr); op.on_has_many_to_many(id, c, attr);
} }
} }
}
#endif //OOS_ACCESS_HPP #endif //MATADOR_ACCESS_HPP
@@ -38,7 +38,7 @@ public:
template<class P> template<class P>
static void on_belongs_to(const char * /*id*/, P &, const foreign_attributes & ) {} static void on_belongs_to(const char * /*id*/, P &, const foreign_attributes & ) {}
template<class P> template<class P>
static void on_has_one(const char * /*id*/, P &, const foreign_attributes & ) {} static void on_has_one(const char * /*id*/, P &, const char * /*join_column*/, const foreign_attributes & ) {}
template<class C> template<class C>
static void on_has_many(const char * /*id*/, C &, const char * /*join_column*/, const foreign_attributes & ) {} static void on_has_many(const char * /*id*/, C &, const char * /*join_column*/, const foreign_attributes & ) {}
template<class C> template<class C>
@@ -65,7 +65,7 @@ struct pk_unset_checker {
template<class P> template<class P>
static void on_belongs_to(const char * /*id*/, P &, const foreign_attributes & ) {} static void on_belongs_to(const char * /*id*/, P &, const foreign_attributes & ) {}
template<class P> template<class P>
static void on_has_one(const char * /*id*/, P &, const foreign_attributes & ) {} static void on_has_one(const char * /*id*/, P &, const char * /*join_column*/, const foreign_attributes & ) {}
template<class C> template<class C>
static void on_has_many(const char * /*id*/, C &, const char * /*join_column*/, const foreign_attributes & ) {} static void on_has_many(const char * /*id*/, C &, const char * /*join_column*/, const foreign_attributes & ) {}
template<class C> template<class C>
@@ -89,7 +89,7 @@ struct primary_key_getter {
template<class P> template<class P>
static void on_belongs_to(const char * /*id*/, P &, const foreign_attributes & ) {} static void on_belongs_to(const char * /*id*/, P &, const foreign_attributes & ) {}
template<class P> template<class P>
static void on_has_one(const char * /*id*/, P &, const foreign_attributes & ) {} static void on_has_one(const char * /*id*/, P &, const char * /*join_column*/, const foreign_attributes & ) {}
template<class C> template<class C>
static void on_has_many(const char * /*id*/, C &, const char * /*join_column*/, const foreign_attributes & ) {} static void on_has_many(const char * /*id*/, C &, const char * /*join_column*/, const foreign_attributes & ) {}
template<class C> template<class C>
+129 -96
View File
@@ -2,7 +2,6 @@
#define QUERY_RESULT_HPP #define QUERY_RESULT_HPP
#include <variant> #include <variant>
#include <optional>
#include <functional> #include <functional>
#include <type_traits> #include <type_traits>
@@ -21,6 +20,7 @@ template < typename ValueType >
class ok { class ok {
public: public:
using value_type = ValueType; using value_type = ValueType;
constexpr ok() = default;
explicit constexpr ok(const ValueType &value) : value_(value) {} explicit constexpr ok(const ValueType &value) : value_(value) {}
explicit constexpr ok(ValueType &&value) : value_(std::move(value)) {} explicit constexpr ok(ValueType &&value) : value_(std::move(value)) {}
@@ -49,21 +49,49 @@ public:
constexpr ErrorType&& release() { return std::move(error_); } constexpr ErrorType&& release() { return std::move(error_); }
const ErrorType& value() const { return error_; } const ErrorType& value() const { return error_; }
ErrorType value() { return error_; } ErrorType& value() { return error_; }
private: private:
ErrorType error_; ErrorType error_;
}; };
namespace detail {
template <typename ValueType, typename Func, bool IsVoidValue = std::is_void_v<ValueType>>
struct map_result_value_type;
template <typename ValueType, typename Func>
struct map_result_value_type<ValueType, Func, false> {
using type = std::invoke_result_t<Func, ValueType&&>;
};
template <typename ValueType, typename Func>
struct map_result_value_type<ValueType, Func, true> {
using type = std::invoke_result_t<Func>;
};
template <typename ValueType, typename Func, bool IsVoidValue = std::is_void_v<ValueType>>
struct and_then_result_type;
template <typename ValueType, typename Func>
struct and_then_result_type<ValueType, Func, false> {
using type = std::invoke_result_t<Func, ValueType&&>;
};
template <typename ValueType, typename Func>
struct and_then_result_type<ValueType, Func, true> {
using type = std::invoke_result_t<Func>;
};
}
template < typename ValueType, typename ErrorType > template < typename ValueType, typename ErrorType >
class result { class result {
public: public:
using value_type = ValueType; using value_type = ValueType;
using error_type = ErrorType; using error_type = ErrorType;
result() : result_(ValueType{}) {} result() : result_(ok<value_type>{}) {}
result(ok<value_type> value) : result_(std::move(value.release())) {} // NOLINT(*-explicit-constructor) result(ok<value_type> value) : result_(std::move(value)) {} // NOLINT(*-explicit-constructor)
result(failure<error_type> error) : result_(std::move(error.release())) {} // NOLINT(*-explicit-constructor) result(failure<error_type> error) : result_(std::move(error)) {} // NOLINT(*-explicit-constructor)
result(const result &x) = default; result(const result &x) = default;
result& operator=(const result &x) = default; result& operator=(const result &x) = default;
result(result &&x) = default; result(result &&x) = default;
@@ -71,123 +99,128 @@ public:
operator bool() const { return is_ok(); } // NOLINT(*-explicit-constructor) operator bool() const { return is_ok(); } // NOLINT(*-explicit-constructor)
[[nodiscard]] bool is_ok() const { return std::holds_alternative<value_type>(result_); } [[nodiscard]] bool is_ok() const {
[[nodiscard]] bool is_error() const { return std::holds_alternative<error_type>(result_); } return std::holds_alternative<ok<value_type>>(result_);
}
ValueType&& release() { return std::move(std::get<value_type>(result_)); } [[nodiscard]] bool is_error() const {
ErrorType&& release_error() { return std::move(std::get<error_type>(result_)); } return std::holds_alternative<failure<error_type>>(result_);
const ValueType& value() const { return std::get<value_type>(result_); }
ValueType& value() { return std::get<value_type>(result_); }
const ErrorType& err() const { return std::get<error_type>(result_); }
ErrorType err() { return std::get<error_type>(result_); }
constexpr const ValueType* operator->() const { return &value(); }
constexpr ValueType* operator->() { return &std::get<value_type>(result_); }
constexpr const ValueType& operator*() const& noexcept { return value(); }
constexpr ValueType& operator*() & noexcept { return value(); }
template<typename Func,
typename SecondValueType = std::invoke_result_t<Func, ValueType >>
result<SecondValueType, ErrorType> map(Func &&f) {
if (is_ok()) {
return result<SecondValueType, ErrorType>(ok(f(release())));
} }
return result<SecondValueType, ErrorType>(failure(release_error())); template <typename T = ValueType>
std::enable_if_t<!std::is_void_v<T>, T&&> release() {
return std::move(std::get<ok<value_type>>(result_).release());
}
ErrorType&& release_error() {
return std::move(std::get<failure<error_type>>(result_).release());
}
template <typename T = ValueType>
std::enable_if_t<!std::is_void_v<T>, const T&> value() const {
return std::get<ok<value_type>>(result_).value();
}
template <typename T = ValueType>
std::enable_if_t<!std::is_void_v<T>, T&> value() {
return std::get<ok<value_type>>(result_).value();
}
const ErrorType& err() const {
return std::get<failure<error_type>>(result_).value();
}
ErrorType& err() {
return std::get<failure<error_type>>(result_).value();
}
template <typename T = ValueType>
constexpr std::enable_if_t<!std::is_void_v<T>, const T*> operator->() const {
return &value();
}
template <typename T = ValueType>
constexpr std::enable_if_t<!std::is_void_v<T>, T*> operator->() {
return &value();
}
template <typename T = ValueType>
constexpr std::enable_if_t<!std::is_void_v<T>, const T&> operator*() const& noexcept {
return value();
}
template <typename T = ValueType>
constexpr std::enable_if_t<!std::is_void_v<T>, T&> operator*() & noexcept {
return value();
}
template<typename Func,
typename SecondValueType = typename detail::map_result_value_type<ValueType, Func>::type>
result<SecondValueType, ErrorType> map(Func &&f) {
if (is_error()) {
return failure<ErrorType>(release_error());
}
if constexpr (std::is_void_v<ValueType>) {
if constexpr (std::is_void_v<SecondValueType>) {
std::invoke(std::forward<Func>(f));
return ok<void>{};
} else {
return ok<SecondValueType>(std::invoke(std::forward<Func>(f)));
}
} else {
if constexpr (std::is_void_v<SecondValueType>) {
std::invoke(std::forward<Func>(f), release());
return ok<void>{};
} else {
return ok<SecondValueType>(std::invoke(std::forward<Func>(f), release()));
}
}
} }
template<typename Func, template<typename Func,
typename SecondErrorType = typename std::invoke_result_t<Func, ErrorType >::value_type> typename SecondErrorType = typename std::invoke_result_t<Func, ErrorType >::value_type>
result<SecondErrorType, ErrorType> map_error(Func &&f) { result<SecondErrorType, ErrorType> map_error(Func &&f) {
if (!is_ok()) { if (!is_error()) {
return result<SecondErrorType, ErrorType>(ok(release())); return failure<SecondErrorType>{std::invoke(std::forward<Func>(f), release_error())};
} }
return result<SecondErrorType, ErrorType>(error(release_error())); if constexpr (std::is_void_v<ValueType>) {
return ok<void>{};
} else {
return ok<ValueType>(release());
}
} }
template <typename Func, template <typename Func,
typename SecondValueType = typename std::invoke_result_t<Func, ValueType>::value_type> typename ReturnResult = typename detail::and_then_result_type<ValueType, Func>::type>
result<SecondValueType, ErrorType> and_then(Func &&f) { ReturnResult and_then(Func &&f) {
static_assert(is_result<ReturnResult>::value, "and_then() callback must return matador::utils::result");
if (is_ok()) { if (is_ok()) {
return f(release()); if constexpr (std::is_void_v<ValueType>) {
return std::invoke(std::forward<Func>(f));
} else {
return std::invoke(std::forward<Func>(f), release());
}
} }
return result<SecondValueType, ErrorType>(failure(release_error())); return ReturnResult(failure<ErrorType>(release_error()));
} }
template <typename Func, template <typename Func,
typename SecondErrorType = typename std::invoke_result_t<Func, ErrorType >::value_type> typename FailureType = std::invoke_result_t<Func, ErrorType&&>,
typename SecondErrorType = typename FailureType::value_type>
result<ValueType, SecondErrorType> or_else(Func &&f) { result<ValueType, SecondErrorType> or_else(Func &&f) {
if (is_error()) { if (is_error()) {
return f(err()); return result<ValueType, SecondErrorType>(
std::invoke(std::forward<Func>(f), release_error())
);
} }
return result<ValueType, SecondErrorType>(ok(release())); if constexpr (std::is_void_v<ValueType>) {
return ok<void>{};
} else {
return ok<ValueType>(release());
}
} }
private: private:
std::variant<value_type, error_type> result_; std::variant<ok<value_type>, failure<error_type>> result_;
}; };
template < typename ErrorType >
class result<void, ErrorType>
{
public:
using value_type = void;
using error_type = ErrorType;
result() = default;
result(ok<void> /*value*/) {}
result(failure<error_type> error) : result_(std::move(error.release())) {} // NOLINT(*-explicit-constructor)
result(const result &x) = default;
result& operator=(const result &x) = default;
result(result &&x) = default;
result& operator=(result &&x) = default;
operator bool() const { return is_ok(); } // NOLINT(*-explicit-constructor)
[[nodiscard]] bool is_ok() const { return !result_.has_value(); }
[[nodiscard]] bool is_error() const { return result_.has_value(); }
ErrorType&& release_error() { return std::move(*result_); }
const ErrorType& err() const { return result_.value(); }
ErrorType err() { return result_.value(); }
template<typename Func, typename SecondValueType = std::invoke_result_t<Func>>
result<SecondValueType, ErrorType> map(Func &&f) {
if (is_ok()) {
return result<SecondValueType, ErrorType>(ok(f()));
}
return result<SecondValueType, ErrorType>(failure(release_error()));
}
template<typename Func>
result and_then(Func &&f) {
if (is_ok()) {
return f();
}
return result(failure(release_error()));
}
template<typename Func, typename SecondErrorType = typename std::invoke_result_t<Func, ErrorType >::value_type>
result<void, SecondErrorType> or_else(Func &&f) {
if (is_error()) {
return f(err());
}
return result<void, SecondErrorType>(ok<void>());
}
private:
std::optional<error_type> result_;
};
} }
#endif //QUERY_RESULT_HPP #endif //QUERY_RESULT_HPP
+10
View File
@@ -22,6 +22,16 @@ MATADOR_UTILS_API std::string to_string(const blob_type_t &data);
MATADOR_UTILS_API std::string to_string(const date_type_t &data); MATADOR_UTILS_API std::string to_string(const date_type_t &data);
MATADOR_UTILS_API std::string to_string(const time_type_t &data); MATADOR_UTILS_API std::string to_string(const time_type_t &data);
template <typename IntegerType>
std::string to_hex_string(IntegerType data, const size_t width = sizeof(IntegerType)<<1) {
static auto digits = "0123456789ABCDEF";
std::string result(width,'0');
for (size_t i=0, j=(width-1)*4 ; i<width; ++i,j-=4) {
result[i] = digits[(data>>j) & 0x0f];
}
return result;
}
/** /**
* Splits a string by a delimiter and * Splits a string by a delimiter and
* add the string tokens to a vector. The * add the string tokens to a vector. The
+3 -3
View File
@@ -59,8 +59,8 @@ public:
* @param args Passed arguments * @param args Passed arguments
*/ */
template <typename F, typename... Args> template <typename F, typename... Args>
auto schedule(F&& func, Args&&... args) -> result_fut<std::result_of_t<F(cancel_token&, Args...)>> { auto schedule(F&& func, Args&&... args) -> result_fut<std::invoke_result_t<F, cancel_token&, Args...>> {
using return_type = std::result_of_t<F(cancel_token&, Args...)>; using return_type = std::invoke_result_t<F, cancel_token&, Args...>;
const auto token = std::make_shared<cancel_token>(); const auto token = std::make_shared<cancel_token>();
auto task_ptr = std::make_shared<std::packaged_task<return_type()>>( auto task_ptr = std::make_shared<std::packaged_task<return_type()>>(
@@ -73,7 +73,7 @@ public:
if (!running_) { if (!running_) {
return failure(std::string("Thread pool is shut down, cannot schedule new tasks.")); return failure(std::string("Thread pool is shut down, cannot schedule new tasks."));
} }
tasks_.emplace_back([task_ptr, token] { tasks_.emplace_back([task_ptr] {
try { (*task_ptr)(); } try { (*task_ptr)(); }
catch (...) { /* Prevent exception escape */ } catch (...) { /* Prevent exception escape */ }
}, token); }, token);
+1 -1
View File
@@ -56,7 +56,7 @@ public:
if (!res.is_ok()) { if (!res.is_ok()) {
return std::nullopt; return std::nullopt;
} }
return *res; return res.value();
} }
template<class Type> template<class Type>
+2 -2
View File
@@ -3,13 +3,13 @@
#include "matador/utils/result.hpp" #include "matador/utils/result.hpp"
#include "matador/utils/error.hpp" #include "matador/utils/error.hpp"
#include "matador/utils/export.hpp"
#include <string> #include <string>
#include <ostream>
namespace matador::utils { namespace matador::utils {
class version { class MATADOR_UTILS_API version final {
public: public:
version() = default; version() = default;
~version() = default; ~version() = default;
+3 -3
View File
@@ -13,7 +13,7 @@ add_library(matador-core STATIC
../../include/matador/net/reactor.hpp ../../include/matador/net/reactor.hpp
../../include/matador/net/select_fd_sets.hpp ../../include/matador/net/select_fd_sets.hpp
../../include/matador/net/socket_interrupter.hpp ../../include/matador/net/socket_interrupter.hpp
../../include/matador/object/abstract_collection_resolver.hpp ../../include/matador/object/abstract_joined_resolver.hpp
../../include/matador/object/abstract_type_resolver.hpp ../../include/matador/object/abstract_type_resolver.hpp
../../include/matador/object/abstract_type_resolver_factory.hpp ../../include/matador/object/abstract_type_resolver_factory.hpp
../../include/matador/object/attribute.hpp ../../include/matador/object/attribute.hpp
@@ -21,7 +21,7 @@ add_library(matador-core STATIC
../../include/matador/object/basic_repository.hpp ../../include/matador/object/basic_repository.hpp
../../include/matador/object/collection_proxy.hpp ../../include/matador/object/collection_proxy.hpp
../../include/matador/object/collection_resolver.hpp ../../include/matador/object/collection_resolver.hpp
../../include/matador/object/collection_resolver_factory.hpp ../../include/matador/object/joined_collection_resolver_factory.hpp
../../include/matador/object/collection_utils.hpp ../../include/matador/object/collection_utils.hpp
../../include/matador/object/error_code.hpp ../../include/matador/object/error_code.hpp
../../include/matador/object/foreign_node_completer.hpp ../../include/matador/object/foreign_node_completer.hpp
@@ -92,7 +92,7 @@ add_library(matador-core STATIC
logger/log_manager.cpp logger/log_manager.cpp
logger/logger.cpp logger/logger.cpp
logger/rotating_file_sink.cpp logger/rotating_file_sink.cpp
object/abstract_collection_resolver.cpp object/abstract_joined_resolver.cpp
object/attribute.cpp object/attribute.cpp
object/basic_object_info.cpp object/basic_object_info.cpp
object/basic_repository.cpp object/basic_repository.cpp
@@ -1,23 +0,0 @@
#include "matador/object/abstract_collection_resolver.hpp"
namespace matador::object {
const std::type_index& abstract_collection_resolver::root_type() const {
return root_type_;
}
const std::type_index& abstract_collection_resolver::type() const {
return type_;
}
const std::string& abstract_collection_resolver::collection_name() const {
return collection_name_;
}
abstract_collection_resolver::abstract_collection_resolver(const std::type_index& root_type, const std::type_index& type, std::string collection_name)
: root_type_(root_type)
, type_(type)
, collection_name_(std::move(collection_name)) {}
} // namespace matador::object
@@ -0,0 +1,16 @@
#include "matador/object/abstract_joined_resolver.hpp"
namespace matador::object {
const std::type_index& abstract_joined_resolver::root_type() const {
return root_type_;
}
const std::string& abstract_joined_resolver::collection_name() const {
return collection_name_;
}
abstract_joined_resolver::abstract_joined_resolver(const std::type_index& root_type, const std::type_index& type, std::string collection_name)
: abstract_type_resolver(type)
, root_type_(root_type)
, collection_name_(std::move(collection_name)) {}
} // namespace matador::object
+4
View File
@@ -32,6 +32,10 @@ std::string attribute::full_name() const {
return owner ? owner->name() + "." + name_ : name_; return owner ? owner->name() + "." + name_ : name_;
} }
size_t attribute::index() const {
return index_;
}
const utils::field_attributes &attribute::attributes() const { const utils::field_attributes &attribute::attributes() const {
return options_; return options_;
} }
+3 -3
View File
@@ -21,11 +21,11 @@ std::shared_ptr<class object> basic_object_info::object() const {
return object_; return object_;
} }
const std::list<attribute>& basic_object_info::attributes() const { const std::vector<attribute>& basic_object_info::attributes() const {
return object_->attributes(); return object_->attributes();
} }
const std::list<class restriction>& basic_object_info::constraints() const { const std::list<restriction>& basic_object_info::constraints() const {
return object_->constraints(); return object_->constraints();
} }
@@ -37,7 +37,7 @@ const utils::identifier& basic_object_info::primary_key() const {
return object_->primary_key(); return object_->primary_key();
} }
attribute* basic_object_info::primary_key_attribute() const { const attribute* basic_object_info::primary_key_attribute() const {
return object_->primary_key_attribute(); return object_->primary_key_attribute();
} }
+1 -1
View File
@@ -88,7 +88,7 @@ utils::result<basic_object_info_ref, utils::error> basic_repository::basic_info(
return utils::ok(basic_object_info_ref{it->info()}); return utils::ok(basic_object_info_ref{it->info()});
} }
utils::result<attribute*, utils::error> basic_repository::primary_key_attribute(const std::type_index &ti) const { utils::result<const attribute*, utils::error> basic_repository::primary_key_attribute(const std::type_index &ti) const {
const auto it = find_node(ti); const auto it = find_node(ti);
if (it == end()) { if (it == end()) {
return utils::failure(make_error(error_code::NodeNotFound, "Node '" + std::string(ti.name()) + "' not found.")); return utils::failure(make_error(error_code::NodeNotFound, "Node '" + std::string(ti.name()) + "' not found."));
+16 -4
View File
@@ -10,8 +10,8 @@ const attribute& object::create_attribute(std::string name, const std::shared_pt
return obj->attributes_.emplace_back(std::move(attr)); return obj->attributes_.emplace_back(std::move(attr));
} }
attribute* object::primary_key_attribute() const { const attribute* object::primary_key_attribute() const {
return pk_attribute_; return pk_column_index_ != -1 ? &attributes_.at(pk_column_index_) : nullptr;
} }
const utils::identifier& object::primary_key() const { const utils::identifier& object::primary_key() const {
@@ -19,7 +19,19 @@ const utils::identifier& object::primary_key() const {
} }
bool object::has_primary_key() const { bool object::has_primary_key() const {
return pk_attribute_ != nullptr; return pk_column_index_ != -1;
}
bool object::is_relation_object() const {
return join_column_index_ != -1 && inverse_join_column_index_ != -1;
}
const attribute * object::join_attribute() const {
return join_column_index_ != -1 ? &attributes_.at(join_column_index_) : nullptr;
}
const attribute * object::inverse_join_attribute() const {
return inverse_join_column_index_ != -1 ? &attributes_.at(inverse_join_column_index_) : nullptr;
} }
const std::string& object::name() const { const std::string& object::name() const {
@@ -38,7 +50,7 @@ size_t object::attribute_count() const {
return attributes_.size(); return attributes_.size();
} }
const std::list<attribute>& object::attributes() const { const std::vector<attribute>& object::attributes() const {
return attributes_; return attributes_;
} }
+21 -6
View File
@@ -7,7 +7,8 @@
namespace matador::object { namespace matador::object {
object_generator::object_generator(basic_repository &repo, const std::shared_ptr<object> &object) object_generator::object_generator(basic_repository &repo, const std::shared_ptr<object> &object)
: repo_(repo) : repo_(repo)
, object_(object) {} , object_(object) {
}
std::shared_ptr<object> object_generator::acquire_object(basic_repository &repo, const std::type_index &ti, const std::string &name) { std::shared_ptr<object> object_generator::acquire_object(basic_repository &repo, const std::type_index &ti, const std::string &name) {
if (repo.has_object_for_type(ti)) { if (repo.has_object_for_type(ti)) {
@@ -29,7 +30,7 @@ void object_generator::create_pk_constraint(const std::string& name) const {
if (pk_attr == std::end(object_->attributes_)) { if (pk_attr == std::end(object_->attributes_)) {
return; return;
} }
restriction pk_constraint(*pk_attr); restriction pk_constraint(pk_attr->index());
pk_constraint.options_ |= utils::constraints::PrimaryKey; pk_constraint.options_ |= utils::constraints::PrimaryKey;
pk_constraint.owner_ = object_; pk_constraint.owner_ = object_;
object_->constraints_.emplace_back(std::move(pk_constraint)); object_->constraints_.emplace_back(std::move(pk_constraint));
@@ -40,19 +41,33 @@ void object_generator::create_unique_constraint(const std::string& name) const {
if (pk_attr == std::end(object_->attributes_)) { if (pk_attr == std::end(object_->attributes_)) {
return; return;
} }
restriction pk_constraint(*pk_attr); restriction pk_constraint(pk_attr->index());
pk_constraint.options_ |= utils::constraints::Unique; pk_constraint.options_ |= utils::constraints::Unique;
pk_constraint.owner_ = object_; pk_constraint.owner_ = object_;
} }
std::list<attribute>::iterator object_generator::find_attribute_by_name(const std::string& name) const { std::vector<attribute>::iterator object_generator::find_attribute_by_name(const std::string &name) const {
return std::find_if(std::begin(object_->attributes_), std::end(object_->attributes_), [&name](const attribute &elem) { return std::find_if(std::begin(object_->attributes_), std::end(object_->attributes_), [&name](const attribute &elem) {
return elem.name() == name; return elem.name() == name;
}); });
} }
void object_generator::prepare_primary_key(attribute& ref, utils::identifier &&pk) const { void object_generator::prepare_primary_key(const attribute &ref, utils::identifier &&pk) const {
object_->pk_attribute_ = &ref; object_->pk_column_index_ = static_cast<int>(ref.index_);
object_->pk_identifier_ = std::move(pk); object_->pk_identifier_ = std::move(pk);
} }
void object_generator::prepare_relation_table(const std::string &join_column, const std::string &inverse_join_column) const {
auto it = find_attribute_by_name(join_column);
if (it == std::end(object_->attributes_)) {
return;
}
object_->join_column_index_ = static_cast<int>(it->index_);
it = find_attribute_by_name(inverse_join_column);
if (it == std::end(object_->attributes_)) {
return;
}
object_->inverse_join_column_index_ = static_cast<int>(it->index_);
}
} }
+12 -5
View File
@@ -4,16 +4,23 @@
#include "matador/object/object.hpp" #include "matador/object/object.hpp"
namespace matador::object { namespace matador::object {
restriction::restriction(const class attribute& attr) restriction::restriction(const size_t attr_index)
: attr_(attr) {} : index_(attr_index) {}
const class attribute& restriction::attribute() const { size_t restriction::attribute_index() const {
return attr_; return index_;
} }
std::string restriction::column_name() const { std::string restriction::column_name() const {
return attr_.name(); const auto o = owner_.lock();
return o ? o->attributes().at(index_).name() : "";
} }
utils::constraints restriction::options() const {
const auto o = owner_.lock();
return o ? o->attributes().at(index_).attributes().options() : utils::constraints::None;
}
std::shared_ptr<object> restriction::owner() const { std::shared_ptr<object> restriction::owner() const {
return owner_.lock(); return owner_.lock();
} }
+65 -41
View File
@@ -3,98 +3,122 @@
#include <matador/utils/errors.hpp> #include <matador/utils/errors.hpp>
namespace matador::utils { namespace matador::utils {
namespace {
version::version(unsigned int major, unsigned int minor, unsigned int patch) bool parse_uint_component(const std::string &text, std::size_t &pos, unsigned int &value) {
if (pos >= text.size() || text[pos] < '0' || text[pos] > '9') {
return false;
}
unsigned int result{};
while (pos < text.size() && text[pos] >= '0' && text[pos] <= '9') {
const auto digit = static_cast<unsigned int>(text[pos] - '0');
if (result > (std::numeric_limits<unsigned int>::max() - digit) / 10) {
return false;
}
result = result * 10 + digit;
++pos;
}
value = result;
return true;
}
bool parse_dot(const std::string &text, std::size_t &pos) {
if (pos >= text.size() || text[pos] != '.') {
return false;
}
++pos;
return true;
}
} // namespace
version::version(const unsigned int major, const unsigned int minor, const unsigned int patch)
: major_(major) : major_(major)
, minor_(minor) , minor_(minor)
, patch_(patch) , patch_(patch) {
{} }
bool version::operator==(const version &x) const bool version::operator==(const version& x) const {
{
return major_ == x.major_ && return major_ == x.major_ &&
minor_ == x.minor_ && minor_ == x.minor_ &&
patch_ == x.patch_; patch_ == x.patch_;
} }
bool version::operator!=(const version &x) const bool version::operator!=(const version& x) const {
{
return !(*this == x); return !(*this == x);
} }
bool version::operator>(const version &x) const bool version::operator>(const version& x) const {
{
return !(*this <= x); return !(*this <= x);
} }
bool version::operator>=(const version &x) const bool version::operator>=(const version& x) const {
{
return !(*this < x); return !(*this < x);
} }
bool version::operator<(const version &x) const bool version::operator<(const version& x) const {
{
return (major_ < x.major_) || return (major_ < x.major_) ||
(major_ == x.major_ && minor_ < x.minor_) || (major_ == x.major_ && minor_ < x.minor_) ||
(major_ == x.major_ && minor_ == x.minor_ && patch_ < x.patch_); (major_ == x.major_ && minor_ == x.minor_ && patch_ < x.patch_);
} }
bool version::operator<=(const version &x) const bool version::operator<=(const version& x) const {
{
return *this < x || *this == x; return *this < x || *this == x;
} }
std::string version::str() const std::string version::str() const {
{ return std::to_string(major_) + "." +
char buf[32]; std::to_string(minor_) + "." +
sprintf(buf, "%d.%d.%d", major_, minor_, patch_); std::to_string(patch_);
return buf;
} }
std::ostream &operator<<(std::ostream &out, const version &v) std::ostream& operator<<(std::ostream& out, const version& v) {
{
out << v.str(); out << v.str();
return out; return out;
} }
result<version, error> version::from_string(const std::string &version_string) result<version, error> version::from_string(const std::string& version_string) {
{ unsigned int major{};
version result; unsigned int minor{};
if (const auto ret = sscanf(version_string.c_str(), "%u.%u.%u", &result.major_, &result.minor_, &result.patch_); ret != 3) { unsigned int patch{};
if (std::size_t pos{}; !parse_uint_component(version_string, pos, major) ||
!parse_dot(version_string, pos) ||
!parse_uint_component(version_string, pos, minor) ||
!parse_dot(version_string, pos) ||
!parse_uint_component(version_string, pos, patch) ||
pos != version_string.size()) {
return failure(error(utils_error::InvalidVersionString, version_string)); return failure(error(utils_error::InvalidVersionString, version_string));
} }
return ok(result); return ok(version{major, minor, patch});}
}
unsigned int version::major() const unsigned int version::major() const {
{
return major_; return major_;
} }
unsigned int version::minor() const unsigned int version::minor() const {
{
return minor_; return minor_;
} }
unsigned int version::patch() const unsigned int version::patch() const {
{
return patch_; return patch_;
} }
void version::major(unsigned int m) void version::major(unsigned int m) {
{
major_ = m; major_ = m;
} }
void version::minor(unsigned int m) void version::minor(unsigned int m) {
{
minor_ = m; minor_ = m;
} }
void version::patch(unsigned int p) void version::patch(unsigned int p) {
{
patch_ = p; patch_ = p;
} }
} }
+15 -9
View File
@@ -1,5 +1,4 @@
add_library(matador-orm STATIC add_library(matador-orm STATIC
../../include/matador/query/session.hpp
../../include/matador/query/abstract_pk_generator.hpp ../../include/matador/query/abstract_pk_generator.hpp
../../include/matador/query/attribute_string_writer.hpp ../../include/matador/query/attribute_string_writer.hpp
../../include/matador/query/basic_schema.hpp ../../include/matador/query/basic_schema.hpp
@@ -17,7 +16,10 @@ add_library(matador-orm STATIC
../../include/matador/query/criteria/logical_criteria.hpp ../../include/matador/query/criteria/logical_criteria.hpp
../../include/matador/query/criteria_evaluator.hpp ../../include/matador/query/criteria_evaluator.hpp
../../include/matador/query/database.hpp ../../include/matador/query/database.hpp
../../include/matador/query/delete_query_builder.hpp
../../include/matador/query/delete_step.hpp
../../include/matador/query/error_code.hpp ../../include/matador/query/error_code.hpp
../../include/matador/query/execute_step.hpp
../../include/matador/query/expression/abstract_column_expression.hpp ../../include/matador/query/expression/abstract_column_expression.hpp
../../include/matador/query/expression/binary_column_expression.hpp ../../include/matador/query/expression/binary_column_expression.hpp
../../include/matador/query/expression/column_expression.hpp ../../include/matador/query/expression/column_expression.hpp
@@ -29,8 +31,10 @@ add_library(matador-orm STATIC
../../include/matador/query/expression_evaluator.hpp ../../include/matador/query/expression_evaluator.hpp
../../include/matador/query/fk_value_extractor.hpp ../../include/matador/query/fk_value_extractor.hpp
../../include/matador/query/generator.hpp ../../include/matador/query/generator.hpp
../../include/matador/query/identity_pk_generator.hpp
../../include/matador/query/insert_query_builder.hpp ../../include/matador/query/insert_query_builder.hpp
../../include/matador/query/insert_query_builder.hpp ../../include/matador/query/insert_query_builder.hpp
../../include/matador/query/insert_step.hpp
../../include/matador/query/intermediates/executable_query.hpp ../../include/matador/query/intermediates/executable_query.hpp
../../include/matador/query/intermediates/fetchable_query.hpp ../../include/matador/query/intermediates/fetchable_query.hpp
../../include/matador/query/intermediates/query_alter_intermediate.hpp ../../include/matador/query/intermediates/query_alter_intermediate.hpp
@@ -67,9 +71,9 @@ add_library(matador-orm STATIC
../../include/matador/query/key_value_generator.hpp ../../include/matador/query/key_value_generator.hpp
../../include/matador/query/manual_pk_generator.hpp ../../include/matador/query/manual_pk_generator.hpp
../../include/matador/query/meta_table_macro.hpp ../../include/matador/query/meta_table_macro.hpp
../../include/matador/query/meta_table_macro.hpp
../../include/matador/query/query.hpp ../../include/matador/query/query.hpp
../../include/matador/query/query_builder.hpp ../../include/matador/query/query_builder.hpp
../../include/matador/query/query_builder_utils.hpp
../../include/matador/query/query_collection_resolver.hpp ../../include/matador/query/query_collection_resolver.hpp
../../include/matador/query/query_column.hpp ../../include/matador/query/query_column.hpp
../../include/matador/query/query_contexts.hpp ../../include/matador/query/query_contexts.hpp
@@ -79,8 +83,10 @@ add_library(matador-orm STATIC
../../include/matador/query/query_part.hpp ../../include/matador/query/query_part.hpp
../../include/matador/query/query_utils.hpp ../../include/matador/query/query_utils.hpp
../../include/matador/query/schema.hpp ../../include/matador/query/schema.hpp
../../include/matador/query/schema_utils.hpp
../../include/matador/query/select_query_builder.hpp ../../include/matador/query/select_query_builder.hpp
../../include/matador/query/sequence_pk_generator.hpp ../../include/matador/query/sequence_pk_generator.hpp
../../include/matador/query/session.hpp
../../include/matador/query/table.hpp ../../include/matador/query/table.hpp
../../include/matador/query/table_column.hpp ../../include/matador/query/table_column.hpp
../../include/matador/query/table_constraint.hpp ../../include/matador/query/table_constraint.hpp
@@ -102,16 +108,16 @@ add_library(matador-orm STATIC
../../include/matador/sql/interface/query_result_reader.hpp ../../include/matador/sql/interface/query_result_reader.hpp
../../include/matador/sql/interface/statement_impl.hpp ../../include/matador/sql/interface/statement_impl.hpp
../../include/matador/sql/interface/statement_proxy.hpp ../../include/matador/sql/interface/statement_proxy.hpp
../../include/matador/sql/internal/collection_resolver_producer.hpp
../../include/matador/sql/internal/identifier_reader.hpp ../../include/matador/sql/internal/identifier_reader.hpp
../../include/matador/sql/internal/identifier_statement_binder.hpp ../../include/matador/sql/internal/identifier_statement_binder.hpp
../../include/matador/sql/internal/joined_collection_resolver_producer.hpp
../../include/matador/sql/internal/object_resolver_producer.hpp ../../include/matador/sql/internal/object_resolver_producer.hpp
../../include/matador/sql/internal/object_result_binder.hpp ../../include/matador/sql/internal/object_result_binder.hpp
../../include/matador/sql/internal/pk_reader.hpp ../../include/matador/sql/internal/pk_reader.hpp
../../include/matador/sql/internal/query_result_impl.hpp ../../include/matador/sql/internal/query_result_impl.hpp
../../include/matador/sql/internal/query_result_pk_resolver.hpp ../../include/matador/sql/internal/query_result_pk_resolver.hpp
../../include/matador/sql/internal/statement_object_resolver.hpp ../../include/matador/sql/internal/statement_object_resolver.hpp
../../include/matador/sql/producer_resolver_factory.hpp ../../include/matador/sql/producer_object_resolver_factory.hpp
../../include/matador/sql/query_context.hpp ../../include/matador/sql/query_context.hpp
../../include/matador/sql/query_result.hpp ../../include/matador/sql/query_result.hpp
../../include/matador/sql/record.hpp ../../include/matador/sql/record.hpp
@@ -119,7 +125,6 @@ add_library(matador-orm STATIC
../../include/matador/sql/sql_functions.hpp ../../include/matador/sql/sql_functions.hpp
../../include/matador/sql/statement.hpp ../../include/matador/sql/statement.hpp
../../include/matador/sql/statement_cache.hpp ../../include/matador/sql/statement_cache.hpp
query/session.cpp
query/abstract_pk_generator.cpp query/abstract_pk_generator.cpp
query/attribute_string_writer.cpp query/attribute_string_writer.cpp
query/basic_schema.cpp query/basic_schema.cpp
@@ -143,6 +148,7 @@ add_library(matador-orm STATIC
query/expression/value_expression.cpp query/expression/value_expression.cpp
query/expression_evaluator.cpp query/expression_evaluator.cpp
query/generator.cpp query/generator.cpp
query/identity_pk_generator.cpp
query/insert_query_builder.cpp query/insert_query_builder.cpp
query/intermediates/executable_query.cpp query/intermediates/executable_query.cpp
query/intermediates/fetchable_query.cpp query/intermediates/fetchable_query.cpp
@@ -186,8 +192,10 @@ add_library(matador-orm STATIC
query/query_part.cpp query/query_part.cpp
query/query_utils.cpp query/query_utils.cpp
query/schema.cpp query/schema.cpp
query/schema_utils.cpp
query/select_query_builder.cpp query/select_query_builder.cpp
query/sequence_pk_generator.cpp query/sequence_pk_generator.cpp
query/session.cpp
query/table.cpp query/table.cpp
query/table_column.cpp query/table_column.cpp
query/table_constraint.cpp query/table_constraint.cpp
@@ -205,21 +213,19 @@ add_library(matador-orm STATIC
sql/interface/query_result_reader.cpp sql/interface/query_result_reader.cpp
sql/interface/statement_impl.cpp sql/interface/statement_impl.cpp
sql/interface/statement_proxy.cpp sql/interface/statement_proxy.cpp
sql/internal/collection_resolver_producer.cpp
sql/internal/identifier_reader.cpp sql/internal/identifier_reader.cpp
sql/internal/identifier_statement_binder.cpp sql/internal/identifier_statement_binder.cpp
sql/internal/joined_collection_resolver_producer.cpp
sql/internal/object_resolver_producer.cpp sql/internal/object_resolver_producer.cpp
sql/internal/object_result_binder.cpp sql/internal/object_result_binder.cpp
sql/internal/query_result_pk_resolver.cpp sql/internal/query_result_pk_resolver.cpp
sql/object_parameter_binder.cpp sql/object_parameter_binder.cpp
sql/producer_resolver_factory.cpp sql/producer_object_resolver_factory.cpp
sql/query_result.cpp sql/query_result.cpp
sql/record.cpp sql/record.cpp
sql/resolver_service.cpp sql/resolver_service.cpp
sql/statement.cpp sql/statement.cpp
sql/statement_cache.cpp sql/statement_cache.cpp
../../include/matador/query/identity_pk_generator.hpp
query/identity_pk_generator.cpp
) )
target_include_directories(matador-orm target_include_directories(matador-orm

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