diff --git a/connector_api/connection.h b/connector_api/connection.h index 14d22dd0..e3b7a4dc 100644 --- a/connector_api/connection.h +++ b/connector_api/connection.h @@ -51,6 +51,10 @@ namespace sqlpp class connection: public sqlpp::connection // this inheritance helps with ADL for dynamic_select, for instance { public: + using _traits = ::sqlpp::make_traits<::sqlpp::no_value_t, + ::sqlpp::tag::enforce_null_result_treatment // If that is what you really want, leave it out otherwise + >; + using _prepared_statement_t = << handle to a prepared statement of the database >>; using _serializer_context_t = << This context is used to serialize a statement >> using _interpreter_context_t = << This context is used interpret a statement >>; diff --git a/include/sqlpp11/alias.h b/include/sqlpp11/alias.h index eeb9e2b6..99909bb5 100644 --- a/include/sqlpp11/alias.h +++ b/include/sqlpp11/alias.h @@ -35,7 +35,7 @@ namespace sqlpp template struct expression_alias_t { - using _traits = make_traits, tag::named_expression, tag::alias>; + using _traits = make_traits, tag::is_named_expression, tag::is_alias>; using _recursive_traits = make_recursive_traits; static_assert(is_expression_t::value, "invalid argument for an expression alias"); diff --git a/include/sqlpp11/any.h b/include/sqlpp11/any.h index a193b825..708911d9 100644 --- a/include/sqlpp11/any.h +++ b/include/sqlpp11/any.h @@ -35,7 +35,7 @@ namespace sqlpp template struct any_t { - using _traits = make_traits, ::sqlpp::tag::multi_expression>; + using _traits = make_traits, ::sqlpp::tag::is_multi_expression>; using _recursive_traits = make_recursive_traits; static_assert(is_select_t; struct _name_t diff --git a/include/sqlpp11/sort_order.h b/include/sqlpp11/sort_order.h index f7d0f72e..0a5053f2 100644 --- a/include/sqlpp11/sort_order.h +++ b/include/sqlpp11/sort_order.h @@ -41,7 +41,7 @@ namespace sqlpp template struct sort_order_t { - using _traits = make_traits; + using _traits = make_traits; using _recursive_traits = make_recursive_traits; Expression _expression; diff --git a/include/sqlpp11/statement.h b/include/sqlpp11/statement.h index 416f1654..64d17e82 100644 --- a/include/sqlpp11/statement.h +++ b/include/sqlpp11/statement.h @@ -63,6 +63,7 @@ namespace sqlpp using _all_required_tables = detail::make_joined_set_t...>; using _all_provided_tables = detail::make_joined_set_t...>; + using _all_provided_outer_tables = detail::make_joined_set_t...>; using _all_extra_tables = detail::make_joined_set_t...>; using _known_tables = detail::make_joined_set_t<_all_provided_tables, _all_extra_tables>; @@ -97,19 +98,21 @@ namespace sqlpp no_value_t // if a required statement part is missing (e.g. columns in a select), then the statement cannot be used as a value >::type; - using _is_expression = typename std::conditional< - std::is_same<_value_type, no_value_t>::value, - std::false_type, - std::true_type>::type; - - using _traits = make_traits<_value_type>; + using _traits = make_traits<_value_type, tag_if::value>>; struct _recursive_traits { using _required_tables = statement_policies_t::_required_tables; using _provided_tables = detail::type_set<>; + using _provided_outer_tables = detail::type_set<>; using _extra_tables = detail::type_set<>; using _parameters = detail::make_parameter_tuple_t...>; + using _can_be_null = detail::any_t< + can_be_null_t<_result_type_provider>::value, + ::sqlpp::detail::make_intersect_set_t< + required_tables_of<_result_type_provider>, + provided_outer_tables_of + >::size::value>; }; }; } @@ -125,13 +128,16 @@ namespace sqlpp { using _policies_t = typename detail::statement_policies_t; - using _traits = make_traits, ::sqlpp::tag::select, tag::expression_if, tag::named_expression_if>; + using _traits = make_traits, + ::sqlpp::tag::is_select, + tag_if::value>, + tag_if::value>, + tag::requires_braces>; using _recursive_traits = typename _policies_t::_recursive_traits; + using _used_outer_tables = typename _policies_t::_all_provided_outer_tables; using _result_type_provider = typename _policies_t::_result_type_provider; - using _requires_braces = std::true_type; - using _name_t = typename _result_type_provider::_name_t; // Constructors @@ -192,7 +198,7 @@ namespace sqlpp template struct statement_name_t { - using _traits = make_traits; + using _traits = make_traits; using _recursive_traits = make_recursive_traits<>; // Data diff --git a/include/sqlpp11/sum.h b/include/sqlpp11/sum.h index 89045be9..8e3553f3 100644 --- a/include/sqlpp11/sum.h +++ b/include/sqlpp11/sum.h @@ -35,7 +35,7 @@ namespace sqlpp struct sum_t: public value_type_of::template expression_operators>, public alias_operators> { - using _traits = make_traits, ::sqlpp::tag::expression, ::sqlpp::tag::named_expression>; + using _traits = make_traits, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_named_expression>; using _recursive_traits = make_recursive_traits; static_assert(is_noop::value or std::is_same::value, "sum() used with flag other than 'distinct'"); diff --git a/include/sqlpp11/table.h b/include/sqlpp11/table.h index 9dc4183f..52f747f3 100644 --- a/include/sqlpp11/table.h +++ b/include/sqlpp11/table.h @@ -42,14 +42,16 @@ namespace sqlpp template struct table_t: public table_base_t, public ColumnSpec::_name_t::template _member_t>... { - using _traits = make_traits; + using _traits = make_traits; struct _recursive_traits { using _parameters = std::tuple<>; using _required_tables = detail::type_set<>; using _provided_tables = detail::type_set; + using _provided_outer_tables = detail::type_set<>; using _extra_tables = detail::type_set<>; + using _can_be_null = std::false_type; }; static_assert(sizeof...(ColumnSpec), "at least one column required per table"); diff --git a/include/sqlpp11/table_alias.h b/include/sqlpp11/table_alias.h index ff1a3e19..7cc58a9f 100644 --- a/include/sqlpp11/table_alias.h +++ b/include/sqlpp11/table_alias.h @@ -39,14 +39,16 @@ namespace sqlpp struct table_alias_t: public ColumnSpec::_name_t::template _member_t>... { //FIXME: Need to add join functionality - using _traits = make_traits, tag::table, tag::alias, tag::named_expression_if>>; + using _traits = make_traits, tag::is_table, tag::is_alias, tag_if::value>>; struct _recursive_traits { using _parameters = std::tuple<>; using _required_tables = detail::type_set<>; using _provided_tables = detail::type_set; + using _provided_outer_tables = detail::type_set<>; using _extra_tables = detail::type_set<>; + using _can_be_null = std::false_type; }; static_assert(required_tables_of
::size::value == 0, "table aliases must not depend on external tables"); diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index 9fff0b77..e90d5e6c 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -27,7 +27,6 @@ #ifndef SQLPP_TEXT_H #define SQLPP_TEXT_H -#include #include #include #include @@ -41,7 +40,8 @@ namespace sqlpp // text value type struct text { - using _tag = ::sqlpp::tag::text; + using _traits = make_traits; + using _tag = ::sqlpp::tag::is_text; using _cpp_value_type = std::string; struct _parameter_t @@ -95,10 +95,46 @@ namespace sqlpp bool _is_null; }; - template - struct _result_entry_t + template + struct _result_field_t; + + // I am SO waiting for concepts lite! + template + struct field_methods_t { - _result_entry_t(): + static constexpr bool _null_is_trivial = true; + operator _cpp_value_type() const { return static_cast(*this).value(); } + }; + + template + struct field_methods_t< + _result_field_t, + typename std::enable_if::value + and column_spec_can_be_null_t::value + and not null_is_trivial_value_t::value>::type> + { + static constexpr bool _null_is_trivial = false; + }; + + template + struct _result_field_t: public field_methods_t<_result_field_t> + { + using _field_methods_t = field_methods_t<_result_field_t>; + + using _traits = make_traits>; + + struct _recursive_traits + { + using _parameters = std::tuple<>; + using _provided_tables = detail::type_set<>; + using _provided_outer_tables = detail::type_set<>; + using _required_tables = detail::type_set<>; + using _extra_tables = detail::type_set<>; + using _can_be_null = column_spec_can_be_null_t; + }; + + _result_field_t(): _is_valid(false), _value_ptr(nullptr), _len(0) @@ -121,35 +157,29 @@ namespace sqlpp bool is_null() const { - if (connector_assert_result_validity_t::value) - assert(_is_valid); - else if (not _is_valid) + if (not _is_valid) throw exception("accessing is_null in non-existing row"); return _value_ptr == nullptr; } _cpp_value_type value() const { - const bool null_value = _value_ptr == nullptr and not NullIsTrivial and not connector_null_result_is_trivial_value_t::value; - if (connector_assert_result_validity_t::value) - { - assert(_is_valid); - assert(not null_value); - } - else - { - if (not _is_valid) - throw exception("accessing value in non-existing row"); - if (null_value) - throw exception("accessing value of NULL field"); - } - if (_value_ptr) - return std::string(_value_ptr, _value_ptr + _len); - else - return ""; - } + if (not _is_valid) + throw exception("accessing value in non-existing row"); - operator _cpp_value_type() const { return value(); } + if (not _value_ptr) + { + if (enforce_null_result_treatment_t::value and not null_is_trivial_value_t::value) + { + throw exception("accessing value of NULL field"); + } + else + { + return ""; + } + } + return std::string(_value_ptr, _value_ptr + _len); + } template void _bind(Target& target, size_t i) @@ -208,8 +238,8 @@ namespace sqlpp }; }; - template - inline std::ostream& operator<<(std::ostream& os, const text::_result_entry_t& e) + template + inline std::ostream& operator<<(std::ostream& os, const text::_result_field_t& e) { return os << e.value(); } diff --git a/include/sqlpp11/tvin.h b/include/sqlpp11/tvin.h index 82e23b3d..0b80cc44 100644 --- a/include/sqlpp11/tvin.h +++ b/include/sqlpp11/tvin.h @@ -37,16 +37,66 @@ namespace sqlpp { template - struct tvin_t + struct tvin_arg_t { - using _traits = make_traits, tag::expression>; + using _traits = make_traits, tag::is_expression>; using _recursive_traits = make_recursive_traits; using _operand_t = Operand; - tvin_t(Operand operand): + tvin_arg_t(_operand_t operand): _value(operand) {} + tvin_arg_t(const tvin_arg_t&) = default; + tvin_arg_t(tvin_arg_t&&) = default; + tvin_arg_t& operator=(const tvin_arg_t&) = default; + tvin_arg_t& operator=(tvin_arg_t&&) = default; + ~tvin_arg_t() = default; + + _operand_t _value; + }; + + template + struct serializer_t> + { + using T = tvin_arg_t; + + static Context& _(const T& t, Context& context) + { + static_assert(wrong_t::value, "tvin may only be used with operators =, == and !="); + } + }; + + template + struct tvin_t; + + namespace detail + { + template + struct allow_tvin_impl + { + using type = T; + }; + template + struct allow_tvin_impl> + { + using type = tvin_t; + }; + } + template + using allow_tvin_t = typename detail::allow_tvin_impl::type; + + template + struct tvin_t + { + using _traits = make_traits, tag::is_expression>; + using _recursive_traits = make_recursive_traits; + + using _operand_t = Operand; + + tvin_t(tvin_arg_t arg): + _value(arg._value) + {} tvin_t(const tvin_t&) = default; tvin_t(tvin_t&&) = default; tvin_t& operator=(const tvin_t&) = default; @@ -58,71 +108,30 @@ namespace sqlpp return _value._is_trivial(); } - Operand _value; + _operand_t _value; }; + namespace detail + { + template + struct is_tvin_impl + { + using type = std::false_type; + }; + template + struct is_tvin_impl> + { + using type = std::true_type; + }; + } + template + using is_tvin_t = typename detail::is_tvin_impl::type; + template struct serializer_t> { using T = tvin_t; - static void _(const T& t, Context& context) - { - static_assert(wrong_t::value, "tvin() must not be used with anything but =, ==, != and !"); - } - }; - - template - struct maybe_tvin_t - { - using _traits = make_traits, tag::expression>; - using _recursive_traits = make_recursive_traits; - - static constexpr bool _is_trivial() - { - return false; - } - - maybe_tvin_t(Operand operand): - _value(operand) - {} - maybe_tvin_t(const maybe_tvin_t&) = default; - maybe_tvin_t(maybe_tvin_t&&) = default; - maybe_tvin_t& operator=(const maybe_tvin_t&) = default; - maybe_tvin_t& operator=(maybe_tvin_t&&) = default; - ~maybe_tvin_t() = default; - - Operand _value; - }; - - template - struct maybe_tvin_t> - { - using _traits = make_traits, tag::expression>; - using _recursive_traits = make_recursive_traits; - - bool _is_trivial() const - { - return _value._is_trivial(); - }; - - maybe_tvin_t(tvin_t operand): - _value(operand._value) - {} - maybe_tvin_t(const maybe_tvin_t&) = default; - maybe_tvin_t(maybe_tvin_t&&) = default; - maybe_tvin_t& operator=(const maybe_tvin_t&) = default; - maybe_tvin_t& operator=(maybe_tvin_t&&) = default; - ~maybe_tvin_t() = default; - - typename tvin_t::_operand_t _value; - }; - - template - struct serializer_t> - { - using T = maybe_tvin_t; - static Context& _(const T& t, Context& context) { if (t._is_trivial()) @@ -138,7 +147,7 @@ namespace sqlpp }; template - auto tvin(Operand operand) -> tvin_t::type> + auto tvin(Operand operand) -> tvin_arg_t::type> { using _operand_t = typename wrap_operand::type; static_assert(std::is_same<_operand_t, text_operand>::value diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index f74eea08..659d7bab 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -32,129 +32,109 @@ namespace sqlpp { -#define SQLPP_IS_VALUE_TRAIT_GENERATOR(name) \ + namespace detail + { + template + struct can_be_null_impl { using type = std::false_type; }; + template + struct can_be_null_impl::type> { using type = std::true_type; }; + } + template + using can_be_null_t = typename detail::can_be_null_impl::type; + + namespace tag\ + {\ + struct can_be_null{};\ + };\ namespace detail\ {\ template\ - struct is_##name##_impl: std::false_type {};\ + struct column_spec_can_be_null_impl { using type = std::false_type; };\ template\ - struct is_##name##_impl::value>::type>: std::true_type {};\ + struct column_spec_can_be_null_impl::value>::type> { using type = std::true_type; };\ }\ + template\ + using column_spec_can_be_null_t = typename detail::column_spec_can_be_null_impl::type; + +#define SQLPP_VALUE_TRAIT_GENERATOR(name) \ namespace tag\ {\ struct name{};\ };\ - template\ - using is_##name##_t = detail::is_element_of; - -#define SQLPP_IS_COLUMN_TRAIT_GENERATOR(name) \ namespace detail\ {\ template\ struct name##_impl { using type = std::false_type; };\ template\ - struct name##_impl::value>::type> { using type = std::true_type; };\ + struct name##_impl::value>::type> { using type = std::true_type; };\ }\ template\ using name##_t = typename detail::name##_impl::type; -#define SQLPP_TYPE_TRAIT_GENERATOR(name) \ - namespace detail\ - {\ - template\ - struct name##_impl: std::false_type {};\ - template\ - struct name##_impl::value>::type>: std::true_type {};\ - }\ - template\ - struct name##_t: detail::name##_impl {}; - -#define SQLPP_CONNECTOR_TRAIT_GENERATOR(name) \ - namespace detail\ - {\ - template\ - struct connector_##name##_impl: std::false_type {};\ - template\ - struct connector_##name##_impl::value>::type>: std::true_type {};\ - }\ - template\ - struct connector_##name##_t: detail::connector_##name##_impl {}; - - SQLPP_IS_VALUE_TRAIT_GENERATOR(boolean); - SQLPP_IS_VALUE_TRAIT_GENERATOR(integral); - SQLPP_IS_VALUE_TRAIT_GENERATOR(floating_point); + SQLPP_VALUE_TRAIT_GENERATOR(is_boolean); + SQLPP_VALUE_TRAIT_GENERATOR(is_integral); + SQLPP_VALUE_TRAIT_GENERATOR(is_floating_point); template using is_numeric_t = detail::any_t< - detail::is_element_of::value, - detail::is_element_of::value>; - SQLPP_IS_VALUE_TRAIT_GENERATOR(text); - SQLPP_IS_VALUE_TRAIT_GENERATOR(wrapped_value); - SQLPP_IS_VALUE_TRAIT_GENERATOR(expression); - SQLPP_IS_VALUE_TRAIT_GENERATOR(named_expression); - namespace tag - { - template - using named_expression_if = typename std::conditional::type; - } - namespace tag - { - template - using expression_if = typename std::conditional::type; - } - SQLPP_IS_VALUE_TRAIT_GENERATOR(multi_expression); - SQLPP_IS_VALUE_TRAIT_GENERATOR(alias); - SQLPP_IS_VALUE_TRAIT_GENERATOR(select_flag); + detail::is_element_of::value, + detail::is_element_of::value>; + SQLPP_VALUE_TRAIT_GENERATOR(is_text); + SQLPP_VALUE_TRAIT_GENERATOR(is_wrapped_value); + SQLPP_VALUE_TRAIT_GENERATOR(is_expression); + SQLPP_VALUE_TRAIT_GENERATOR(is_named_expression); + SQLPP_VALUE_TRAIT_GENERATOR(is_multi_expression); + SQLPP_VALUE_TRAIT_GENERATOR(is_alias); + SQLPP_VALUE_TRAIT_GENERATOR(is_select_flag); - SQLPP_IS_COLUMN_TRAIT_GENERATOR(must_not_insert); - SQLPP_IS_COLUMN_TRAIT_GENERATOR(must_not_update); - SQLPP_IS_COLUMN_TRAIT_GENERATOR(require_insert); - SQLPP_IS_COLUMN_TRAIT_GENERATOR(can_be_null); - SQLPP_IS_COLUMN_TRAIT_GENERATOR(trivial_value_is_null); + SQLPP_VALUE_TRAIT_GENERATOR(must_not_insert); + SQLPP_VALUE_TRAIT_GENERATOR(must_not_update); + SQLPP_VALUE_TRAIT_GENERATOR(require_insert); + SQLPP_VALUE_TRAIT_GENERATOR(trivial_value_is_null); + SQLPP_VALUE_TRAIT_GENERATOR(null_is_trivial_value); - SQLPP_IS_VALUE_TRAIT_GENERATOR(noop); - SQLPP_IS_VALUE_TRAIT_GENERATOR(missing); - SQLPP_IS_VALUE_TRAIT_GENERATOR(return_value); - SQLPP_IS_VALUE_TRAIT_GENERATOR(table); - SQLPP_IS_VALUE_TRAIT_GENERATOR(join); - SQLPP_IS_VALUE_TRAIT_GENERATOR(pseudo_table); - SQLPP_IS_VALUE_TRAIT_GENERATOR(column); - SQLPP_IS_VALUE_TRAIT_GENERATOR(select); - SQLPP_IS_VALUE_TRAIT_GENERATOR(select_flag_list); - SQLPP_IS_VALUE_TRAIT_GENERATOR(select_column_list); - SQLPP_IS_VALUE_TRAIT_GENERATOR(from); - SQLPP_IS_VALUE_TRAIT_GENERATOR(single_table); - SQLPP_IS_VALUE_TRAIT_GENERATOR(into); - SQLPP_IS_VALUE_TRAIT_GENERATOR(extra_tables); - SQLPP_IS_VALUE_TRAIT_GENERATOR(on); - SQLPP_IS_VALUE_TRAIT_GENERATOR(where); - SQLPP_IS_VALUE_TRAIT_GENERATOR(group_by); - SQLPP_IS_VALUE_TRAIT_GENERATOR(having); - SQLPP_IS_VALUE_TRAIT_GENERATOR(order_by); - SQLPP_IS_VALUE_TRAIT_GENERATOR(limit); - SQLPP_IS_VALUE_TRAIT_GENERATOR(offset); - SQLPP_IS_VALUE_TRAIT_GENERATOR(using_); - SQLPP_IS_VALUE_TRAIT_GENERATOR(column_list); - SQLPP_IS_VALUE_TRAIT_GENERATOR(multi_column); - SQLPP_IS_VALUE_TRAIT_GENERATOR(value_list); - SQLPP_IS_VALUE_TRAIT_GENERATOR(assignment); - SQLPP_IS_VALUE_TRAIT_GENERATOR(update_list); - SQLPP_IS_VALUE_TRAIT_GENERATOR(insert_list); - SQLPP_IS_VALUE_TRAIT_GENERATOR(insert_value); - SQLPP_IS_VALUE_TRAIT_GENERATOR(insert_value_list); - SQLPP_IS_VALUE_TRAIT_GENERATOR(sort_order); - SQLPP_IS_VALUE_TRAIT_GENERATOR(parameter); + SQLPP_VALUE_TRAIT_GENERATOR(is_noop); + SQLPP_VALUE_TRAIT_GENERATOR(is_missing); + SQLPP_VALUE_TRAIT_GENERATOR(is_return_value); + SQLPP_VALUE_TRAIT_GENERATOR(is_table); + SQLPP_VALUE_TRAIT_GENERATOR(is_join); + SQLPP_VALUE_TRAIT_GENERATOR(is_pseudo_table); + SQLPP_VALUE_TRAIT_GENERATOR(is_column); + SQLPP_VALUE_TRAIT_GENERATOR(is_select); + SQLPP_VALUE_TRAIT_GENERATOR(is_select_flag_list); + SQLPP_VALUE_TRAIT_GENERATOR(is_select_column_list); + SQLPP_VALUE_TRAIT_GENERATOR(is_from); + SQLPP_VALUE_TRAIT_GENERATOR(is_single_table); + SQLPP_VALUE_TRAIT_GENERATOR(is_into); + SQLPP_VALUE_TRAIT_GENERATOR(is_extra_tables); + SQLPP_VALUE_TRAIT_GENERATOR(is_on); + SQLPP_VALUE_TRAIT_GENERATOR(is_where); + SQLPP_VALUE_TRAIT_GENERATOR(is_group_by); + SQLPP_VALUE_TRAIT_GENERATOR(is_having); + SQLPP_VALUE_TRAIT_GENERATOR(is_order_by); + SQLPP_VALUE_TRAIT_GENERATOR(is_limit); + SQLPP_VALUE_TRAIT_GENERATOR(is_offset); + SQLPP_VALUE_TRAIT_GENERATOR(is_using_); + SQLPP_VALUE_TRAIT_GENERATOR(is_column_list); + SQLPP_VALUE_TRAIT_GENERATOR(is_multi_column); + SQLPP_VALUE_TRAIT_GENERATOR(is_value_list); + SQLPP_VALUE_TRAIT_GENERATOR(is_assignment); + SQLPP_VALUE_TRAIT_GENERATOR(is_update_list); + SQLPP_VALUE_TRAIT_GENERATOR(is_insert_list); + SQLPP_VALUE_TRAIT_GENERATOR(is_insert_value); + SQLPP_VALUE_TRAIT_GENERATOR(is_insert_value_list); + SQLPP_VALUE_TRAIT_GENERATOR(is_sort_order); + SQLPP_VALUE_TRAIT_GENERATOR(is_parameter); - SQLPP_TYPE_TRAIT_GENERATOR(requires_braces); + SQLPP_VALUE_TRAIT_GENERATOR(requires_braces); - SQLPP_CONNECTOR_TRAIT_GENERATOR(null_result_is_trivial_value); - SQLPP_CONNECTOR_TRAIT_GENERATOR(assert_result_validity); + SQLPP_VALUE_TRAIT_GENERATOR(enforce_null_result_treatment); + + template + using tag_if = typename std::conditional::type; template using is_database = typename std::conditional::value, std::false_type, std::true_type>::type; - template class IsTag> - using copy_type_trait = typename std::conditional::value, std::true_type, std::false_type>::type; - namespace detail { template @@ -175,6 +155,12 @@ namespace sqlpp using type = typename T::_recursive_traits::_provided_tables; }; + template + struct provided_outer_table_of_impl + { + using type = typename T::_recursive_traits::_provided_outer_tables; + }; + template struct extra_table_of_impl { @@ -211,6 +197,9 @@ namespace sqlpp template using provided_tables_of = typename detail::provided_table_of_impl::type; + template + using provided_outer_tables_of = typename detail::provided_outer_table_of_impl::type; + template using extra_tables_of = typename detail::extra_table_of_impl::type; @@ -231,8 +220,10 @@ namespace sqlpp { using _required_tables = detail::make_joined_set_t...>; using _provided_tables = detail::make_joined_set_t...>; + using _provided_outer_tables = detail::make_joined_set_t...>; using _extra_tables = detail::make_joined_set_t...>; using _parameters = detail::make_parameter_tuple_t...>; + using _can_be_null = detail::any_t::value...>; }; } diff --git a/include/sqlpp11/update.h b/include/sqlpp11/update.h index 215200d6..e017865a 100644 --- a/include/sqlpp11/update.h +++ b/include/sqlpp11/update.h @@ -43,7 +43,7 @@ namespace sqlpp struct update_t: public statement_name_t { - using _traits = make_traits; + using _traits = make_traits; struct _name_t {}; template diff --git a/include/sqlpp11/update_list.h b/include/sqlpp11/update_list.h index 903bac66..6b8a255a 100644 --- a/include/sqlpp11/update_list.h +++ b/include/sqlpp11/update_list.h @@ -56,7 +56,7 @@ namespace sqlpp template struct update_list_t { - using _traits = make_traits; + using _traits = make_traits; using _recursive_traits = make_recursive_traits; using _is_dynamic = is_database; @@ -78,9 +78,9 @@ namespace sqlpp { static_assert(_is_dynamic::value, "add must not be called for static from()"); static_assert(is_assignment_t::value, "invalid assignment argument in add()"); - using _assigned_columns = detail::make_type_set_t; - static_assert(not detail::is_element_of::value, "Must not assign value to column twice"); - static_assert(sqlpp::detail::not_t::value, "add() argument must not be updated"); + using _assigned_columns = detail::make_type_set_t; + static_assert(not detail::is_element_of::value, "Must not assign value to column twice"); + static_assert(sqlpp::detail::not_t::value, "add() argument must not be updated"); static_assert(TableCheckRequired::value or Policies::template _no_unknown_tables::value, "assignment uses tables unknown to this statement in add()"); using ok = ::sqlpp::detail::all_t< @@ -130,7 +130,7 @@ namespace sqlpp struct no_update_list_t { - using _traits = make_traits; + using _traits = make_traits; using _recursive_traits = make_recursive_traits<>; // Data @@ -192,9 +192,9 @@ namespace sqlpp { static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in set()"); static_assert(::sqlpp::detail::all_t::value...>::value, "at least one argument is not an assignment in set()"); - static_assert(::sqlpp::detail::none_t::value...>::value, "at least one assignment is prohibited by its column definition in set()"); + static_assert(::sqlpp::detail::none_t::value...>::value, "at least one assignment is prohibited by its column definition in set()"); - using _column_required_tables = typename ::sqlpp::detail::make_joined_set...>::type; + using _column_required_tables = ::sqlpp::detail::make_joined_set_t...>; static_assert(sizeof...(Assignments) ? (_column_required_tables::size::value == 1) : true, "set() contains assignments for columns from more than one table"); return { *static_cast(this), update_list_data_t{assignments...} }; diff --git a/include/sqlpp11/using.h b/include/sqlpp11/using.h index 0214851b..a4897474 100644 --- a/include/sqlpp11/using.h +++ b/include/sqlpp11/using.h @@ -57,7 +57,7 @@ namespace sqlpp template struct using_t { - using _traits = make_traits; + using _traits = make_traits; using _recursive_traits = make_recursive_traits; using _is_dynamic = is_database; @@ -128,7 +128,7 @@ namespace sqlpp // NO USING YET struct no_using_t { - using _traits = make_traits; + using _traits = make_traits; using _recursive_traits = make_recursive_traits<>; // Data diff --git a/include/sqlpp11/verbatim_table.h b/include/sqlpp11/verbatim_table.h index dbacdb9d..2e5fa27c 100644 --- a/include/sqlpp11/verbatim_table.h +++ b/include/sqlpp11/verbatim_table.h @@ -42,13 +42,17 @@ namespace sqlpp { }; }; - using _value_type = no_value_t; - struct _column_type {}; + using _traits = make_traits; }; } struct verbatim_table_t: public sqlpp::table_t { + struct _recursive_traits: public sqlpp::table_t::_recursive_traits + { + using _provided_outer_tables = detail::type_set; + }; + struct _name_t {}; verbatim_table_t(std::string representation): diff --git a/include/sqlpp11/where.h b/include/sqlpp11/where.h index 0a8d704d..20933fee 100644 --- a/include/sqlpp11/where.h +++ b/include/sqlpp11/where.h @@ -58,7 +58,7 @@ namespace sqlpp template struct where_t { - using _traits = make_traits; + using _traits = make_traits; using _recursive_traits = make_recursive_traits; using _is_dynamic = is_database; @@ -141,7 +141,7 @@ namespace sqlpp template<> struct where_t { - using _traits = make_traits; + using _traits = make_traits; using _recursive_traits = make_recursive_traits<>; // Data @@ -184,7 +184,7 @@ namespace sqlpp template struct no_where_t { - using _traits = make_traits; + using _traits = make_traits; using _recursive_traits = make_recursive_traits<>; // Data diff --git a/include/sqlpp11/wrap_operand.h b/include/sqlpp11/wrap_operand.h index 177f9294..0b0f8d23 100644 --- a/include/sqlpp11/wrap_operand.h +++ b/include/sqlpp11/wrap_operand.h @@ -43,7 +43,7 @@ namespace sqlpp struct boolean_operand { - using _traits = make_traits<::sqlpp::detail::boolean, ::sqlpp::tag::expression, ::sqlpp::tag::wrapped_value>; + using _traits = make_traits<::sqlpp::detail::boolean, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_wrapped_value>; using _recursive_traits = make_recursive_traits<>; using _value_t = bool; @@ -81,7 +81,7 @@ namespace sqlpp struct integral_operand { - using _traits = make_traits<::sqlpp::detail::integral, ::sqlpp::tag::expression, ::sqlpp::tag::wrapped_value>; + using _traits = make_traits<::sqlpp::detail::integral, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_wrapped_value>; using _recursive_traits = make_recursive_traits<>; using _value_t = int64_t; @@ -120,7 +120,7 @@ namespace sqlpp struct floating_point_operand { - using _traits = make_traits<::sqlpp::detail::floating_point, ::sqlpp::tag::expression, ::sqlpp::tag::wrapped_value>; + using _traits = make_traits<::sqlpp::detail::floating_point, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_wrapped_value>; using _recursive_traits = make_recursive_traits<>; using _value_t = double; @@ -158,7 +158,7 @@ namespace sqlpp struct text_operand { - using _traits = make_traits<::sqlpp::detail::text, ::sqlpp::tag::expression, ::sqlpp::tag::wrapped_value>; + using _traits = make_traits<::sqlpp::detail::text, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_wrapped_value>; using _recursive_traits = make_recursive_traits<>; using _value_t = std::string; diff --git a/scripts/ddl2cpp b/scripts/ddl2cpp index e65cf233..9fbeabb2 100755 --- a/scripts/ddl2cpp +++ b/scripts/ddl2cpp @@ -155,22 +155,20 @@ for tableCreation in tableCreations: print(' };', file=header) print(' };', file=header) #print(sqlColumnType) - print(' using _value_type = ' + NAMESPACE + '::' + types[sqlColumnType] + ';', file=header) - print(' struct _column_type', file=header) - print(' {', file=header) + traitslist = [NAMESPACE + '::' + types[sqlColumnType]]; requireInsert = True if column.hasAutoValue: - print(' using _must_not_insert = std::true_type;', file=header) - print(' using _must_not_update = std::true_type;', file=header) + traitslist.append(NAMESPACE + '::tag::must_not_insert'); + traitslist.append(NAMESPACE + '::tag::must_not_update'); requireInsert = False if not column.notNull: - print(' using _can_be_null = std::true_type;', file=header) + traitslist.append(NAMESPACE + '::tag::can_be_null'); requireInsert = False if column.hasDefaultValue: requireInsert = False if requireInsert: - print(' using _require_insert = std::true_type;', file=header) - print(' };', file=header) + traitslist.append(NAMESPACE + '::tag::require_insert'); + print(' using _traits = ' + NAMESPACE + '::make_traits<' + ', '.join(traitslist) + '>;', file=header) print(' };', file=header) print(' }', file=header) print('', file=header) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 13942a11..ed2c041d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -15,6 +15,7 @@ build_and_run(SelectTypeTest) build_and_run(FunctionTest) build_and_run(PreparedTest) build_and_run(Minimalistic) +build_and_run(ResultTest) # if you want to use the generator, you can do something like this: #find_package(PythonInterp REQUIRED) diff --git a/tests/InterpretTest.cpp b/tests/InterpretTest.cpp index 528bf21f..02f00dd5 100644 --- a/tests/InterpretTest.cpp +++ b/tests/InterpretTest.cpp @@ -36,7 +36,6 @@ MockDb db = {}; MockDb::_serializer_context_t printer; -SQLPP_ALIAS_PROVIDER(kaesekuchen); int main() { @@ -125,6 +124,10 @@ int main() // join serialize(t.inner_join(t.as(t.alpha)).on(t.beta == t.as(t.alpha).beta), printer).str(); + { + auto inner = t.inner_join(t.as(t.alpha)).on(t.beta == t.as(t.alpha).beta); + serialize(select(t.alpha).from(inner), printer).str(); + } // multi_column serialize(multi_column(t.alpha, (t.beta + "cake").as(t.gamma)).as(t.alpha), printer).str(); diff --git a/tests/MockDb.h b/tests/MockDb.h index 9c4dafd9..8642208e 100644 --- a/tests/MockDb.h +++ b/tests/MockDb.h @@ -30,8 +30,13 @@ #include #include -struct MockDb: public sqlpp::connection +template +struct MockDbT: public sqlpp::connection { + using _traits = ::sqlpp::make_traits<::sqlpp::no_value_t, + ::sqlpp::tag_if<::sqlpp::tag::enforce_null_result_treatment, enforceNullResultTreatment> + >; + struct _serializer_context_t { std::ostringstream _os; @@ -156,5 +161,8 @@ struct MockDb: public sqlpp::connection }; +using MockDb = MockDbT; +using EnforceDb = MockDbT; + #endif diff --git a/tests/Sample.h b/tests/Sample.h index 33eb36e0..4ba3774d 100644 --- a/tests/Sample.h +++ b/tests/Sample.h @@ -21,11 +21,7 @@ namespace test const T& operator()() const { return delta; } }; }; - using _value_type = sqlpp::varchar; - struct _column_type - { - using _can_be_null = std::true_type; - }; + using _traits = sqlpp::make_traits; }; struct Epsilon { @@ -40,11 +36,7 @@ namespace test const T& operator()() const { return epsilon; } }; }; - using _value_type = sqlpp::bigint; - struct _column_type - { - using _can_be_null = std::true_type; - }; + using _traits = sqlpp::make_traits; }; struct Omega { @@ -59,11 +51,7 @@ namespace test const T& operator()() const { return omega; } }; }; - using _value_type = sqlpp::floating_point; - struct _column_type - { - using _can_be_null = std::true_type; - }; + using _traits = sqlpp::make_traits; }; } @@ -100,13 +88,7 @@ namespace test const T& operator()() const { return alpha; } }; }; - using _value_type = sqlpp::bigint; - struct _column_type - { - using _must_not_insert = std::true_type; - using _must_not_update = std::true_type; - using _can_be_null = std::true_type; - }; + using _traits = sqlpp::make_traits; }; struct Beta { @@ -121,11 +103,7 @@ namespace test const T& operator()() const { return beta; } }; }; - using _value_type = sqlpp::varchar; - struct _column_type - { - using _can_be_null = std::true_type; - }; + using _traits = sqlpp::make_traits; }; struct Gamma { @@ -140,11 +118,7 @@ namespace test const T& operator()() const { return gamma; } }; }; - using _value_type = sqlpp::boolean; - struct _column_type - { - using _require_insert = std::true_type; - }; + using _traits = sqlpp::make_traits; }; struct Delta { @@ -159,11 +133,7 @@ namespace test const T& operator()() const { return delta; } }; }; - using _value_type = sqlpp::integer; - struct _column_type - { - using _can_be_null = std::true_type; - }; + using _traits = sqlpp::make_traits; }; } diff --git a/tests/SelectTest.cpp b/tests/SelectTest.cpp index 9a94694b..7bdf43a5 100644 --- a/tests/SelectTest.cpp +++ b/tests/SelectTest.cpp @@ -36,14 +36,6 @@ MockDb db = {}; MockDb::_serializer_context_t printer; -namespace alias -{ - SQLPP_ALIAS_PROVIDER(a); - SQLPP_ALIAS_PROVIDER(b); - SQLPP_ALIAS_PROVIDER(left); - SQLPP_ALIAS_PROVIDER(right); -} - int main() { test::TabFoo f;