diff --git a/include/matador/orm/session_insert_builder.hpp b/include/matador/orm/session_insert_builder.hpp index 4811956..a61ddf0 100644 --- a/include/matador/orm/session_insert_builder.hpp +++ b/include/matador/orm/session_insert_builder.hpp @@ -1,9 +1,108 @@ #ifndef SESSION_INSERT_BUILDER_HPP #define SESSION_INSERT_BUILDER_HPP +#include "matador/query/condition.hpp" +#include "matador/query/query_intermediates.hpp" + +#include "matador/object/schema.hpp" + namespace matador::orm { +struct entity_insert_data { + sql::table table; + std::vector columns; + std::vector values; +}; + +enum class insert_build_error : std::uint8_t { + Ok = 0, + UnknownType, + MissingPrimaryKey, + UnexpectedError +}; + +class insert_builder_exception final : public std::exception +{ +public: + explicit insert_builder_exception(const insert_build_error error) : error_(error) {} + + [[nodiscard]] insert_build_error error() const { return error_; } + +private: + const insert_build_error error_; +}; + class session_insert_builder final { +public: + explicit session_insert_builder(const object::schema &scm) + : schema_(scm) {} + + template + utils::result, insert_build_error> build(const EntityType &obj) { + auto info = schema_.info(); + if (!info) { + return utils::failure(insert_build_error::UnknownType); + } + table_info_stack_.push({info.value()}); + entity_insert_data_ = {{sql::table{info.value().get().name()}}}; + // processed_tables_.insert({info->get().name(), entity_insert_data_.root_table}); + try { + access::process(*this, obj); + + return {utils::ok(std::move(entity_insert_data_))}; + } catch (const insert_builder_exception &ex) { + return {utils::failure(ex.error())}; + } catch (...) { + return {utils::failure(insert_build_error::UnexpectedError)}; + } + } + + template < class V > + void on_primary_key(const char *id, V &x, std::enable_if_t && !std::is_same_v>* = nullptr) + { + push(id, x); + } + + void on_primary_key(const char *id, std::string &, size_t); + void on_revision(const char *id, unsigned long long &/*rev*/); + + template + void on_attribute(const char *id, Type &, const utils::field_attributes &/*attr*/ = utils::null_attributes) { + } + + template + void on_belongs_to(const char *id, Pointer &obj, const utils::foreign_attributes &attr) { + } + + template + void on_has_one(const char *id, Pointer &obj, const utils::foreign_attributes &attr) { + } + + template + void on_has_many(const char * /*id*/, ContainerType &, const char *join_column, const utils::foreign_attributes &attr) { + } + + template + void on_has_many_to_many(const char *id, ContainerType &/*cont*/, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &attr) { + } + + template + void on_has_many_to_many(const char *id, ContainerType &/*cont*/, const utils::foreign_attributes &attr) { + } + +private: + [[nodiscard]] bool is_root_entity() const; + void push(const std::string &column_name, const utils::database_type &value); + +private: + struct table_info { + std::reference_wrapper info; + }; + + std::stack table_info_stack_; + std::unordered_map> processed_tables_; + const object::schema &schema_; + std::vector entity_insert_data_; }; } diff --git a/include/matador/utils/uuid.hpp b/include/matador/utils/uuid.hpp index e69de29..a11d411 100644 --- a/include/matador/utils/uuid.hpp +++ b/include/matador/utils/uuid.hpp @@ -0,0 +1,50 @@ +#ifndef MATADOR_UUID_HPP +#define MATADOR_UUID_HPP + +#include +#include + +namespace matador::utils { + +class uuid { +public: + using uuid_array = std::array; + + // Default constructor initializes to zero + uuid() = default; + + // Static UUID v4 generator + static uuid generate(); + + // Returns UUID as a string + [[nodiscard]] std::string str() const; + + // Access to internal data + [[nodiscard]] const uuid_array& data() const; + + // Reset UUID to zero + void clear() { _data.fill(0); } + + // Comparisons + friend bool operator==(const uuid& lhs, const uuid& rhs); + friend bool operator!=(const uuid& lhs, const uuid& rhs); + friend bool operator<(const uuid& lhs, const uuid& rhs); + +private: + uuid_array _data{0, 0, 0, 0}; +}; +} + +// Hash specialization to allow use in unordered containers +template <> +struct std::hash { + std::size_t operator()(const matador::utils::uuid& u) const noexcept { + std::size_t h = 0; + for (uint32_t val : u.data()) { + h ^= std::hash{}(val) + 0x9e3779b9 + (h << 6) + (h >> 2); + } + return h; + } +}; + +#endif //MATADOR_UUID_HPP diff --git a/source/core/CMakeLists.txt b/source/core/CMakeLists.txt index 5610b61..ef4a506 100644 --- a/source/core/CMakeLists.txt +++ b/source/core/CMakeLists.txt @@ -8,6 +8,7 @@ add_library(matador-core STATIC ../../include/matador/object/object_info.hpp ../../include/matador/object/object_proxy.hpp ../../include/matador/object/object_ptr.hpp + ../../include/matador/object/primary_key_resolver.hpp ../../include/matador/object/schema.hpp ../../include/matador/object/schema_node.hpp ../../include/matador/object/schema_node_iterator.hpp @@ -39,6 +40,7 @@ add_library(matador-core STATIC ../../include/matador/utils/singleton.hpp ../../include/matador/utils/string.hpp ../../include/matador/utils/types.hpp + ../../include/matador/utils/uuid.hpp ../../include/matador/utils/value.hpp ../../include/matador/utils/version.hpp object/attribute_definition_generator.cpp @@ -46,6 +48,7 @@ add_library(matador-core STATIC object/basic_object_info.cpp object/error_code.cpp object/object_definition.cpp + object/primary_key_resolver.cpp object/schema.cpp object/schema_node.cpp object/schema_node_iterator.cpp @@ -59,10 +62,9 @@ add_library(matador-core STATIC utils/os.cpp utils/string.cpp utils/types.cpp + utils/uuid.cpp utils/value.cpp utils/version.cpp - ../../include/matador/object/primary_key_resolver.hpp - object/primary_key_resolver.cpp ) target_link_libraries(matador-core ${CMAKE_DL_LIBS}) diff --git a/source/core/utils/uuid.cpp b/source/core/utils/uuid.cpp index e69de29..c1f0f39 100644 --- a/source/core/utils/uuid.cpp +++ b/source/core/utils/uuid.cpp @@ -0,0 +1,75 @@ +#include "matador/utils/uuid.hpp" + +#include + +namespace matador::utils { + +uuid uuid::generate() { + std::random_device rd; + std::mt19937_64 gen(rd()); + std::uniform_int_distribution dist; + + uint64_t high = dist(gen); + uint64_t low = dist(gen); + + // Set version to 4 (UUID v4) + high &= 0xFFFFFFFFFFFF0FFFULL; + high |= 0x0000000000004000ULL; + + // Set variant to 10xx (RFC 4122) + low &= 0x3FFFFFFFFFFFFFFFULL; + low |= 0x8000000000000000ULL; + + uuid result; + result._data[0] = static_cast(high >> 32); + result._data[1] = static_cast(high & 0xFFFFFFFF); + result._data[2] = static_cast(low >> 32); + result._data[3] = static_cast(low & 0xFFFFFFFF); + + return result; +} + +std::string uuid::str() const { + const char* hex = "0123456789abcdef"; + char out[36]; // UUID string format is 36 characters + int pos = 0; + + auto write_hex = [&](uint32_t value, int digits) { + for (int i = digits - 1; i >= 0; --i) { + out[pos + i] = hex[value & 0xF]; + value >>= 4; + } + pos += digits; + }; + + write_hex(_data[0] >> 16, 8); + out[pos++] = '-'; + write_hex(_data[0] & 0xFFFF, 4); + out[pos++] = '-'; + write_hex(_data[1] >> 16, 4); + out[pos++] = '-'; + write_hex(_data[1] & 0xFFFF, 4); + out[pos++] = '-'; + write_hex(_data[2] >> 16, 4); + write_hex(_data[2] & 0xFFFF, 4); + write_hex(_data[3], 4); + + return {out, 36}; +} + +const uuid::uuid_array& uuid::data() const { + return _data; +} + +bool operator==( const uuid& lhs, const uuid& rhs ) { + return lhs._data == rhs._data; +} + +bool operator!=( const uuid& lhs, const uuid& rhs ) { + return !(lhs == rhs); +} + +bool operator<( const uuid& lhs, const uuid& rhs ) { + return lhs._data < rhs._data; +} +} diff --git a/source/orm/orm/session_insert_builder.cpp b/source/orm/orm/session_insert_builder.cpp index e69de29..ace9c88 100644 --- a/source/orm/orm/session_insert_builder.cpp +++ b/source/orm/orm/session_insert_builder.cpp @@ -0,0 +1,16 @@ +#include "matador/orm/session_insert_builder.hpp" + +namespace matador::orm { +void session_insert_builder::on_primary_key(const char* id, std::string& value, size_t) { + push(id, value); +} + +void session_insert_builder::on_revision(const char* id, unsigned long long& x) { + push(id, x); +} + +void session_insert_builder::push(const std::string& column_name, const utils::database_type& value) { + entity_insert_data_.back().columns.emplace_back(column_name); + entity_insert_data_.back().values.emplace_back(value); +} +} \ No newline at end of file diff --git a/source/orm/query/intermediates/query_insert_intermediate.cpp b/source/orm/query/intermediates/query_insert_intermediate.cpp index f182066..39ee71d 100644 --- a/source/orm/query/intermediates/query_insert_intermediate.cpp +++ b/source/orm/query/intermediates/query_insert_intermediate.cpp @@ -11,7 +11,7 @@ query_insert_intermediate::query_insert_intermediate() context_->parts.push_back(std::make_unique()); } -query_into_intermediate query_insert_intermediate::into(const sql::table &table, std::initializer_list columns) +query_into_intermediate query_insert_intermediate::into(const sql::table &table, const std::initializer_list columns) { return into(table, std::move(std::vector{columns})); } diff --git a/source/orm/query/query_compiler.cpp b/source/orm/query/query_compiler.cpp index c2bf3c4..19efa79 100644 --- a/source/orm/query/query_compiler.cpp +++ b/source/orm/query/query_compiler.cpp @@ -226,7 +226,7 @@ void query_compiler::visit(internal::query_delete_part &/*delete_part*/) void query_compiler::visit(internal::query_delete_from_part &delete_from_part) { query_.table = delete_from_part.table(); - query_.sql += " " + query_compiler::build_table_name(delete_from_part.token(), *dialect_, query_.table); + query_.sql += " " + build_table_name(delete_from_part.token(), *dialect_, query_.table); } void query_compiler::visit(internal::query_create_part &/*create_part*/)