#pragma once #include // std::string #include // std::remove_reference, std::is_same, std::decay #include // std::vector #include // std::tuple_size, std::tuple_element #include // std::forward, std::move #include "functional/cxx_universal.h" #include "functional/cxx_type_traits_polyfill.h" #include "functional/cxx_functional_polyfill.h" #include "functional/static_magic.h" #include "functional/mpl.h" #include "functional/index_sequence_util.h" #include "tuple_helper/tuple_filter.h" #include "tuple_helper/tuple_traits.h" #include "tuple_helper/tuple_iteration.h" #include "member_traits/member_traits.h" #include "typed_comparator.h" #include "type_traits.h" #include "constraints.h" #include "table_info.h" #include "column.h" namespace sqlite_orm { namespace internal { struct basic_table { /** * Table name. */ std::string name; }; /** * Table definition. */ template struct table_t : basic_table { using object_type = O; using elements_type = std::tuple; static constexpr bool is_without_rowid_v = WithoutRowId; using is_without_rowid = polyfill::bool_constant; elements_type elements; #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED table_t(std::string name_, elements_type elements_) : basic_table{std::move(name_)}, elements{std::move(elements_)} {} #endif table_t without_rowid() const { return {this->name, this->elements}; } /** * Returns foreign keys count in table definition */ constexpr int foreign_keys_count() const { #if SQLITE_VERSION_NUMBER >= 3006019 using fk_index_sequence = filter_tuple_sequence_t; return int(fk_index_sequence::size()); #else return 0; #endif } /** * Function used to get field value from object by mapped member pointer/setter/getter. * * For a setter the corresponding getter has to be searched, * so the method returns a pointer to the field as returned by the found getter. * Otherwise the method invokes the member pointer and returns its result. */ template = true> decltype(auto) object_field_value(const object_type& object, M memberPointer) const { return polyfill::invoke(memberPointer, object); } template = true> const member_field_type_t* object_field_value(const object_type& object, M memberPointer) const { using field_type = member_field_type_t; const field_type* res = nullptr; iterate_tuple(this->elements, col_index_sequence_with_field_type{}, call_as_template_base([&res, &memberPointer, &object](const auto& column) { if(compare_any(column.setter, memberPointer)) { res = &polyfill::invoke(column.member_pointer, object); } })); return res; } const basic_generated_always::storage_type* find_column_generated_storage_type(const std::string& name) const { const basic_generated_always::storage_type* result = nullptr; #if SQLITE_VERSION_NUMBER >= 3031000 iterate_tuple(this->elements, col_index_sequence_with{}, [&result, &name](auto& column) { if(column.name != name) { return; } using generated_op_index_sequence = filter_tuple_sequence_t, is_generated_always>; constexpr size_t opIndex = first_index_sequence_value(generated_op_index_sequence{}); result = &get(column.constraints).storage; }); #else (void)name; #endif return result; } template bool exists_in_composite_primary_key(const column_field& column) const { bool res = false; this->for_each_primary_key([&column, &res](auto& primaryKey) { using colrefs_tuple = decltype(primaryKey.columns); using same_type_index_sequence = filter_tuple_sequence_t>::template fn, member_field_type_t>; iterate_tuple(primaryKey.columns, same_type_index_sequence{}, [&res, &column](auto& memberPointer) { if(compare_any(memberPointer, column.member_pointer) || compare_any(memberPointer, column.setter)) { res = true; } }); }); return res; } /** * Call passed lambda with all defined primary keys. */ template void for_each_primary_key(L&& lambda) const { using pk_index_sequence = filter_tuple_sequence_t; iterate_tuple(this->elements, pk_index_sequence{}, lambda); } std::vector composite_key_columns_names() const { std::vector res; this->for_each_primary_key([this, &res](auto& primaryKey) { res = this->composite_key_columns_names(primaryKey); }); return res; } std::vector primary_key_column_names() const { using pkcol_index_sequence = col_index_sequence_with; if(pkcol_index_sequence::size() > 0) { return create_from_tuple>(this->elements, pkcol_index_sequence{}, &column_identifier::name); } else { return this->composite_key_columns_names(); } } template void for_each_primary_key_column(L&& lambda) const { iterate_tuple(this->elements, col_index_sequence_with{}, call_as_template_base([&lambda](const auto& column) { lambda(column.member_pointer); })); this->for_each_primary_key([&lambda](auto& primaryKey) { iterate_tuple(primaryKey.columns, lambda); }); } template std::vector composite_key_columns_names(const primary_key_t& primaryKey) const { return create_from_tuple>(primaryKey.columns, [this, empty = std::string{}](auto& memberPointer) { if(const std::string* columnName = this->find_column_name(memberPointer)) { return *columnName; } else { return empty; } }); } /** * Searches column name by class member pointer passed as the first argument. * @return column name or empty string if nothing found. */ template = true> const std::string* find_column_name(M m) const { const std::string* res = nullptr; using field_type = member_field_type_t; iterate_tuple(this->elements, col_index_sequence_with_field_type{}, [&res, m](auto& c) { if(compare_any(c.member_pointer, m) || compare_any(c.setter, m)) { res = &c.name; } }); return res; } /** * Counts and returns amount of columns without GENERATED ALWAYS constraints. Skips table constraints. */ constexpr int non_generated_columns_count() const { #if SQLITE_VERSION_NUMBER >= 3031000 using non_generated_col_index_sequence = col_index_sequence_excluding; return int(non_generated_col_index_sequence::size()); #else return this->count_columns_amount(); #endif } /** * Counts and returns amount of columns. Skips constraints. */ constexpr int count_columns_amount() const { using col_index_sequence = filter_tuple_sequence_t; return int(col_index_sequence::size()); } /** * Call passed lambda with all defined foreign keys. * @param lambda Lambda called for each column. Function signature: `void(auto& column)` */ template void for_each_foreign_key(L&& lambda) const { using fk_index_sequence = filter_tuple_sequence_t; iterate_tuple(this->elements, fk_index_sequence{}, lambda); } template void for_each_foreign_key_to(L&& lambda) const { using fk_index_sequence = filter_tuple_sequence_t; using filtered_index_sequence = filter_tuple_sequence_t::template fn, target_type_t, fk_index_sequence>; iterate_tuple(this->elements, filtered_index_sequence{}, lambda); } /** * Call passed lambda with all defined columns. * @param lambda Lambda called for each column. Function signature: `void(auto& column)` */ template void for_each_column(L&& lambda) const { using col_index_sequence = filter_tuple_sequence_t; iterate_tuple(this->elements, col_index_sequence{}, lambda); } /** * Call passed lambda with columns not having the specified constraint trait `OpTrait`. * @param lambda Lambda called for each column. */ template class OpTraitFn, class L> void for_each_column_excluding(L&& lambda) const { iterate_tuple(this->elements, col_index_sequence_excluding{}, lambda); } /** * Call passed lambda with columns not having the specified constraint trait `OpTrait`. * @param lambda Lambda called for each column. */ template = true> void for_each_column_excluding(L&& lambda) const { this->for_each_column_excluding(lambda); } std::vector get_table_info() const; }; template struct is_table : std::false_type {}; template struct is_table> : std::true_type {}; } /** * Factory function for a table definition. * * The mapped object type is determined implicitly from the first column definition. */ template>::object_type> internal::table_t make_table(std::string name, Cs... args) { SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( return {std::move(name), std::make_tuple(std::forward(args)...)}); } /** * Factory function for a table definition. * * The mapped object type is explicitly specified. */ template internal::table_t make_table(std::string name, Cs... args) { SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( return {std::move(name), std::make_tuple(std::forward(args)...)}); } }