diff --git a/CMakeLists.txt b/CMakeLists.txt index 5af682b1..a3d8eeaf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2013, Roland Bock +# Copyright (c) 2013-2014, Roland Bock # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, diff --git a/LICENSE b/LICENSE index c53feede..32872e75 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2013, Roland Bock +Copyright (c) 2013-2014, Roland Bock All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/connector_api/bind_result.h b/connector_api/bind_result.h index 8999c357..d1405e7d 100644 --- a/connector_api/bind_result.h +++ b/connector_api/bind_result.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, diff --git a/connector_api/char_result.h b/connector_api/char_result.h index 355ba959..02ab2014 100644 --- a/connector_api/char_result.h +++ b/connector_api/char_result.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, diff --git a/connector_api/connection.h b/connector_api/connection.h index d6e98663..b6946324 100644 --- a/connector_api/connection.h +++ b/connector_api/connection.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, diff --git a/connector_api/interpreter.h b/connector_api/interpreter.h index 9a83c008..90295276 100644 --- a/connector_api/interpreter.h +++ b/connector_api/interpreter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, diff --git a/connector_api/prepared_statement.h b/connector_api/prepared_statement.h index 4a99ee03..5a3dc94a 100644 --- a/connector_api/prepared_statement.h +++ b/connector_api/prepared_statement.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, diff --git a/include/sqlpp11/alias.h b/include/sqlpp11/alias.h index 179b6c50..39f3bb52 100644 --- a/include/sqlpp11/alias.h +++ b/include/sqlpp11/alias.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -33,6 +33,9 @@ namespace sqlpp template struct expression_alias_t { + static_assert(is_expression_t::value, "invalid argument for an expression alias"); + static_assert(not is_alias_t::value, "cannot create an alias of an alias"); + struct _value_type: Expression::_value_type { using _is_expression = std::false_type; @@ -41,6 +44,7 @@ namespace sqlpp }; using _name_t = typename AliasProvider::_name_t; + using _table_set = typename Expression::_table_set; Expression _expression; }; @@ -48,14 +52,14 @@ namespace sqlpp namespace vendor { template - struct interpreter_t> + struct serializer_t> { using T = expression_alias_t; static Context& _(const T& t, Context& context) { context << '('; - interpret(t._expression, context); + serialize(t._expression, context); context << ") AS "; context << T::_name_t::_get_name(); return context; diff --git a/include/sqlpp11/alias_provider.h b/include/sqlpp11/alias_provider.h index d63ce097..6949933b 100644 --- a/include/sqlpp11/alias_provider.h +++ b/include/sqlpp11/alias_provider.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -27,6 +27,8 @@ #ifndef SQLPP_ALIAS_PROVIDER_H #define SQLPP_ALIAS_PROVIDER_H +#include + #define SQLPP_ALIAS_PROVIDER(name) \ struct name##_t\ {\ @@ -46,6 +48,18 @@ namespace sqlpp { + template + struct is_alias_provider_t + { + static constexpr bool value = false; + }; + + template + struct is_alias_provider_t>::value, void>::type> + { + static constexpr bool value = true; + }; + namespace alias { SQLPP_ALIAS_PROVIDER(a); diff --git a/include/sqlpp11/all_of.h b/include/sqlpp11/all_of.h new file mode 100644 index 00000000..270dea20 --- /dev/null +++ b/include/sqlpp11/all_of.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2013-2014, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLPP_ALL_OF_H +#define SQLPP_ALL_OF_H + +#include +#include +#include + +namespace sqlpp +{ + template + struct all_of_t + { + using _column_tuple_t = typename Table::_column_tuple_t; + + template + detail::copy_tuple_args_t as(const AliasProvider& alias) + { + return ::sqlpp::multi_column(_column_tuple_t{}).as(alias); + } + }; + + template + auto all_of(Table t) -> all_of_t + { + return {}; + } + + namespace vendor + { + template + struct serializer_t> + { + using T = all_of_t
; + + static Context& _(const T& t, const Context&) + { + static_assert(wrong_t::value, "all_of(table) does not seem to be used in select"); + } + }; + } + +} + +#endif + diff --git a/include/sqlpp11/any.h b/include/sqlpp11/any.h index 004a4cfd..1f8a55b5 100644 --- a/include/sqlpp11/any.h +++ b/include/sqlpp11/any.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -27,22 +27,20 @@ #ifndef SQLPP_ANY_H #define SQLPP_ANY_H -#include #include +#include namespace sqlpp { namespace vendor { template - struct any_t: public boolean::template operators> + struct any_t { - static_assert(is_select_t::value, "any() requires a single column select expression as argument"); - struct _value_type: public Select::_value_type::_base_value_type { - using _is_multi_expression = std::true_type; // must not be named + using _is_expression = std::false_type; + using _is_multi_expression = std::true_type; // must not be named or used with +,-,*,/, etc }; struct _name_t @@ -57,6 +55,8 @@ namespace sqlpp }; }; + using _table_set = typename Select::_table_set; + any_t(Select select): _select(select) {} @@ -74,22 +74,24 @@ namespace sqlpp namespace vendor { template - struct interpreter_t> + struct serializer_t> { using T = vendor::any_t::value, "exists() requires a select expression as argument"); @@ -43,6 +43,8 @@ namespace sqlpp using _is_named_expression = std::true_type; }; + using _table_set = typename Select::_table_set; + struct _name_t { static constexpr const char* _get_name() { return "EXISTS"; } @@ -72,14 +74,14 @@ namespace sqlpp namespace vendor { template - struct interpreter_t> + struct serializer_t> { using T = vendor::exists_t
::value or is_table_t
::value, "invalid 'Table' argument"); - static_assert(vendor::is_noop::value or is_insert_list_t::value, "invalid 'InsertList' argument"); - static_assert(vendor::is_noop::value or is_column_list_t::value, "invalid 'ColumnList' argument"); - static_assert(vendor::is_noop::value or is_insert_value_list_t::value, "invalid 'ValueList' argument"); + using _policies_t = typename detail::insert_policies_t; + using _database_t = typename _policies_t::_database_t; + using _table_t = typename _policies_t::_table_t; + using _insert_value_list_t = typename _policies_t::_insert_value_list_t; - using use_default_values_t = insert_t; - template - using set_insert_list_t = insert_t; - template - using set_column_value_list_t = insert_t; + using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; - using _parameter_tuple_t = std::tuple; + using _parameter_tuple_t = std::tuple; using _parameter_list_t = typename make_parameter_list_t::type; - auto default_values() - -> use_default_values_t - { - static_assert(std::is_same::value, "cannot call default_values() after set() or default_values()"); - static_assert(vendor::is_noop::value, "cannot call default_values() after columns()"); - static_assert(Table::_required_insert_columns::size::value == 0, "cannot use default_values, because some columns are configured to require values"); - return { - _table, - {}, - _column_list, - _value_list, - }; - } + static_assert(::sqlpp::detail::is_superset_of::value, "columns do not match the table they are to be inserted into"); - template - auto set(Assignment... assignment) - -> set_insert_list_t> - { - static_assert(std::is_same::value, "cannot call set() after set() or default_values()"); - static_assert(vendor::is_noop::value, "cannot call set() after columns()"); - // FIXME: Need to check if all required columns are set - return { - _table, - vendor::insert_list_t{assignment...}, - _column_list, - _value_list, - }; - } + // Constructors + insert_t() + {} - template - auto dynamic_set(Assignment... assignment) - -> set_insert_list_t> - { - static_assert(std::is_same::value, "cannot call set() after set() or default_values()"); - static_assert(vendor::is_noop::value, "cannot call set() after columns()"); - return { - _table, - vendor::insert_list_t{assignment...}, - _column_list, - _value_list, - }; - } + template + insert_t(Statement s, T t): + _table(detail::arg_selector<_table_t>::_(s._table, t)), + _insert_value_list(detail::arg_selector<_insert_value_list_t>::_(s._insert_value_list, t)) + {} - template - insert_t add_set(Assignment assignment) - { - static_assert(is_dynamic_t::value, "cannot call add_set() in a non-dynamic set"); - - _insert_list.add(assignment); - - return *this; - } - - template - auto columns(Column... columns) - -> set_column_value_list_t, vendor::insert_value_list_t...>> - { - static_assert(vendor::is_noop::value, "cannot call columns() twice"); - static_assert(vendor::is_noop::value, "cannot call columns() after set() or dynamic_set()"); - // FIXME: Need to check if all required columns are set - - return { - _table, - _insert_list, - {std::tuple...>{{columns}...}}, - vendor::insert_value_list_t...>{}, - }; - } - - template - insert_t& add_values(Value... values) - { - static_assert(is_insert_value_list_t::value, "cannot call add_values() before columns()"); - _value_list.add(typename ValueList::_value_tuple_t{values...}); - return *this; - }; + insert_t(const insert_t&) = default; + insert_t(insert_t&&) = default; + insert_t& operator=(const insert_t&) = default; + insert_t& operator=(insert_t&&) = default; + ~insert_t() = default; + // run and prepare static constexpr size_t _get_static_no_of_parameters() { return _parameter_list_t::size::value; @@ -150,72 +126,71 @@ namespace sqlpp return _parameter_list_t::size::value; } - template - std::size_t _run(Db& db) const + template + struct is_table_subset_of_table { - static_assert(not (vendor::is_noop::value and vendor::is_noop::value) , "calling set() or default_values()"); + static constexpr bool value = ::sqlpp::detail::is_subset_of::value; + }; + + void _check_consistency() const + { + // FIXME: Read up on what is allowed/prohibited in INSERT + } + + template + std::size_t _run(Database& db) const + { + _check_consistency(); + static_assert(_get_static_no_of_parameters() == 0, "cannot run insert directly with parameters, use prepare instead"); return db.insert(*this); } - template - auto _prepare(Db& db) const - -> prepared_insert_t + template + auto _prepare(Database& db) const + -> prepared_insert_t { - constexpr bool calledSet = not vendor::is_noop::value; - constexpr bool requireSet = Table::_required_insert_columns::size::value > 0; - static_assert(calledSet or not requireSet, "calling set() required for given table"); + _check_consistency(); return {{}, db.prepare_insert(*this)}; } - Table _table; - InsertList _insert_list; - ColumnList _column_list; - ValueList _value_list; + _insert_value_list_t _insert_value_list; + _table_t _table; }; namespace vendor { - template - struct interpreter_t> + template + struct serializer_t> { - using T = insert_t; + using T = insert_t; static Context& _(const T& t, Context& context) { - if (not vendor::is_noop::value) - { - context << "INSERT INTO "; - interpret(t._table, context); - interpret(t._insert_list, context); - } - else if (not t._value_list.empty()) - { - context << "INSERT INTO "; - interpret(t._table, context); - interpret(t._column_list, context); - interpret(t._value_list, context); - } - else - { - context << "# empty insert"; - } + context << "INSERT INTO "; + serialize(t._table, context); + serialize(t._insert_value_list, context); return context; } }; } + template + using make_insert_t = typename detail::insert_policies_t::_statement_t; + template - insert_t insert_into(Table table) + constexpr auto insert_into(Table table) + -> make_insert_t> { - return {table}; + return { make_insert_t(), vendor::single_table_t{table} }; } template - insert_t dynamic_insert_into(const Database& db, Table table) + constexpr auto dynamic_insert_into(const Database&, Table table) + -> make_insert_t> { - return {table}; + return { make_insert_t(), vendor::single_table_t{table} }; } } diff --git a/include/sqlpp11/integral.h b/include/sqlpp11/integral.h index dcddb299..2e8ea407 100644 --- a/include/sqlpp11/integral.h +++ b/include/sqlpp11/integral.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -28,7 +28,8 @@ #define SQLPP_INTEGRAL_H #include -#include +#include +#include #include #include #include @@ -41,12 +42,14 @@ namespace sqlpp // integral value type struct integral { + using _value_type = integral; using _base_value_type = integral; using _is_numeric = std::true_type; using _is_integral = std::true_type; using _is_value = std::true_type; using _is_expression = std::true_type; using _cpp_value_type = int64_t; + struct _parameter_t { @@ -98,6 +101,7 @@ namespace sqlpp bool _is_null; }; + template struct _result_entry_t { using _value_type = integral; @@ -135,15 +139,28 @@ namespace sqlpp bool is_null() const { - if (not _is_valid) + if (connector_assert_result_validity_t::value) + assert(_is_valid); + else if (not _is_valid) throw exception("accessing is_null in non-existing row"); return _is_null; } _cpp_value_type value() const { - if (not _is_valid) - throw exception("accessing value in non-existing row"); + const bool null_value = _is_null 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"); + } return _value; } @@ -162,89 +179,116 @@ namespace sqlpp }; template - using _operand_t = operand_t; - template - using _constraint = is_numeric_t; + struct _is_valid_operand + { + static constexpr bool value = + is_expression_t::value // expressions are OK + and is_numeric_t::value // the correct value type is required, of course + ; + }; template - struct operators: public basic_operators + struct expression_operators: public basic_expression_operators { template - vendor::plus_t, typename _operand_t::type> operator +(T t) const + vendor::plus_t, vendor::wrap_operand_t> operator +(T t) const { - static_assert(not is_multi_expression_t::value, "multi-expression cannot be used as left hand side operand"); + using rhs = vendor::wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs operand"); + return { *static_cast(this), {t} }; } template - vendor::minus_t, typename _operand_t::type> operator -(T t) const + vendor::minus_t, vendor::wrap_operand_t> operator -(T t) const { - static_assert(not is_multi_expression_t::value, "multi-expression cannot be used as left hand side operand"); + using rhs = vendor::wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs operand"); + return { *static_cast(this), {t} }; } template - vendor::multiplies_t, typename _operand_t::type> operator *(T t) const + vendor::multiplies_t, vendor::wrap_operand_t> operator *(T t) const { - static_assert(not is_multi_expression_t::value, "multi-expression cannot be used as left hand side operand"); + using rhs = vendor::wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs operand"); + return { *static_cast(this), {t} }; } template - vendor::divides_t::type> operator /(T t) const + vendor::divides_t> operator /(T t) const { - static_assert(not is_multi_expression_t::value, "multi-expression cannot be used as left hand side operand"); + using rhs = vendor::wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs operand"); + return { *static_cast(this), {t} }; } template - vendor::modulus_t::type> operator %(T t) const + vendor::modulus_t> operator %(T t) const { - static_assert(not is_multi_expression_t::value, "multi-expression cannot be used as left hand side operand"); + using rhs = vendor::wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs operand"); + return { *static_cast(this), {t} }; } vendor::unary_plus_t operator +() const { - static_assert(not is_multi_expression_t::value, "multi-expression cannot be used as unary operand"); return { *static_cast(this) }; } vendor::unary_minus_t operator -() const { - static_assert(not is_multi_expression_t::value, "multi-expression cannot be used as unary operand"); return { *static_cast(this) }; } + }; + template + struct column_operators + { template - auto operator +=(T t) const -> decltype(std::declval() = std::declval() + t) + auto operator +=(T t) const -> vendor::assignment_t, vendor::wrap_operand_t>> { - return *static_cast(this) = operator +(t); + using rhs = vendor::wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); + + return { *static_cast(this), { *static_cast(this), rhs{t} } }; } template - auto operator -=(T t) const -> decltype(std::declval() = std::declval() - t) + auto operator -=(T t) const -> vendor::assignment_t, vendor::wrap_operand_t>> { - return *static_cast(this) = operator -(t); + using rhs = vendor::wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); + + return { *static_cast(this), { *static_cast(this), rhs{t} } }; } template - auto operator /=(T t) const -> decltype(std::declval() = std::declval() / t) + auto operator /=(T t) const -> vendor::assignment_t>> { - return *static_cast(this) = operator /(t); + using rhs = vendor::wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); + + return { *static_cast(this), { *static_cast(this), rhs{t} } }; } template - auto operator *=(T t) const -> decltype(std::declval() = std::declval() * t) + auto operator *=(T t) const -> vendor::assignment_t, vendor::wrap_operand_t>> { - return *static_cast(this) = operator *(t); + using rhs = vendor::wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); + + return { *static_cast(this), { *static_cast(this), rhs{t} } }; } - - }; }; - inline std::ostream& operator<<(std::ostream& os, const integral::_result_entry_t& e) + template + inline std::ostream& operator<<(std::ostream& os, const integral::_result_entry_t& e) { return os << e.value(); } diff --git a/include/sqlpp11/interpret.h b/include/sqlpp11/interpret.h index 85814a2a..42cc1524 100644 --- a/include/sqlpp11/interpret.h +++ b/include/sqlpp11/interpret.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, diff --git a/include/sqlpp11/join.h b/include/sqlpp11/join.h index b8cffea7..1c959ba3 100644 --- a/include/sqlpp11/join.h +++ b/include/sqlpp11/join.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -82,11 +82,11 @@ namespace sqlpp static_assert(not is_join_t::value, "rhs argument for join must not be a join"); static_assert(vendor::is_noop::value or is_on_t::value, "invalid on expression in join().on()"); - static_assert(Lhs::_table_set::template is_disjunct_from::value, "joined tables must not be identical"); + static_assert(::sqlpp::detail::is_disjunct_from::value, "joined tables must not be identical"); using _is_table = std::true_type; using _is_join = std::true_type; - using _table_set = typename Lhs::_table_set::template join::type; + using _table_set = typename ::sqlpp::detail::make_joined_set::type; template using set_on_t = join_t; @@ -145,18 +145,18 @@ namespace sqlpp namespace vendor { template - struct interpreter_t> + struct serializer_t> { using T = join_t; static Context& _(const T& t, Context& context) { static_assert(not vendor::is_noop::value, "joined tables require on()"); - interpret(t._lhs, context); + serialize(t._lhs, context); context << JoinType::_name; context << " JOIN "; - interpret(t._rhs, context); - interpret(t._on, context); + serialize(t._rhs, context); + serialize(t._on, context); return context; } }; diff --git a/include/sqlpp11/max.h b/include/sqlpp11/max.h index 9e36d2b8..a86c4b22 100644 --- a/include/sqlpp11/max.h +++ b/include/sqlpp11/max.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -27,7 +27,6 @@ #ifndef SQLPP_MAX_H #define SQLPP_MAX_H -#include #include namespace sqlpp @@ -35,7 +34,7 @@ namespace sqlpp namespace vendor { template - struct max_t: public boolean::template operators> + struct max_t: public Expr::_value_type::template expression_operators> { static_assert(is_value_t::value, "max() requires a value expression as argument"); @@ -44,6 +43,8 @@ namespace sqlpp using _is_named_expression = std::true_type; }; + using _table_set = typename Expr::_table_set; + struct _name_t { static constexpr const char* _get_name() { return "MAX"; } @@ -73,14 +74,14 @@ namespace sqlpp namespace vendor { template - struct interpreter_t> + struct serializer_t> { using T = vendor::max_t; static Context& _(const T& t, Context& context) { context << "MAX("; - interpret(t._expr, context); + serialize(t._expr, context); context << ")"; return context; } @@ -88,8 +89,9 @@ namespace sqlpp } template - auto max(T t) -> typename vendor::max_t::type> + auto max(T t) -> typename vendor::max_t> { + static_assert(is_value_t>::value, "max() requires a value expression as argument"); return { t }; } diff --git a/include/sqlpp11/min.h b/include/sqlpp11/min.h index 9e35549c..c7d9f9e0 100644 --- a/include/sqlpp11/min.h +++ b/include/sqlpp11/min.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -27,7 +27,6 @@ #ifndef SQLPP_MIN_H #define SQLPP_MIN_H -#include #include namespace sqlpp @@ -35,7 +34,7 @@ namespace sqlpp namespace vendor { template - struct min_t: public boolean::template operators> + struct min_t: public Expr::_value_type::template expression_operators> { static_assert(is_value_t::value, "min() requires a value expression as argument"); @@ -44,6 +43,8 @@ namespace sqlpp using _is_named_expression = std::true_type; }; + using _table_set = typename Expr::_table_set; + struct _name_t { static constexpr const char* _get_name() { return "MIN"; } @@ -73,14 +74,14 @@ namespace sqlpp namespace vendor { template - struct interpreter_t> + struct serializer_t> { using T = vendor::min_t; static Context& _(const T& t, Context& context) { context << "MIN("; - interpret(t._expr, context); + serialize(t._expr, context); context << ")"; return context; } @@ -88,8 +89,9 @@ namespace sqlpp } template - auto min(T t) -> typename vendor::min_t::type> + auto min(T t) -> typename vendor::min_t> { + static_assert(is_value_t>::value, "min() requires a value expression as argument"); return { t }; } diff --git a/include/sqlpp11/multi_column.h b/include/sqlpp11/multi_column.h index 8cf50469..821cd1c2 100644 --- a/include/sqlpp11/multi_column.h +++ b/include/sqlpp11/multi_column.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -28,23 +28,75 @@ #define SQLPP_MULTI_COLUMN_H #include -#include #include +#include + +#include namespace sqlpp { - template + template + struct multi_column_alias_t; + + template struct multi_column_t { - static_assert(vendor::wrong_t::value, "invalid argument for multicolumn_t"); + static_assert(detail::all_t::value, "multi_column parameters need to be named expressions"); + + using _table_set = sqlpp::detail::make_joined_set_t; + + multi_column_t(std::tuple columns): + _columns(columns) + {} + + multi_column_t(Columns... columns): + _columns(columns...) + {} + + multi_column_t(const multi_column_t&) = default; + multi_column_t(multi_column_t&&) = default; + multi_column_t& operator=(const multi_column_t&) = default; + multi_column_t& operator=(multi_column_t&&) = default; + ~multi_column_t() = default; + + template + multi_column_alias_t as(const AliasProvider&) + { + return { *this }; + } + + + using _value_type = no_value_t; + using _is_multi_column = std::true_type; + + std::tuple _columns; }; - template - struct multi_column_t> + template + struct multi_column_alias_t { - static_assert(detail::and_t::value, "multi_column parameters need to be named expressions"); + static_assert(detail::all_t::value, "multi_column parameters need to be named expressions"); using _name_t = typename AliasProvider::_name_t; + using _table_set = sqlpp::detail::make_joined_set_t; + + multi_column_alias_t(multi_column_t multi_column): + _columns(multi_column._columns) + {} + + multi_column_alias_t(std::tuple columns): + _columns(columns) + {} + + multi_column_alias_t(Columns... columns): + _columns(columns...) + {} + + multi_column_alias_t(const multi_column_alias_t&) = default; + multi_column_alias_t(multi_column_alias_t&&) = default; + multi_column_alias_t& operator=(const multi_column_alias_t&) = default; + multi_column_alias_t& operator=(multi_column_alias_t&&) = default; + ~multi_column_alias_t() = default; struct _value_type: public no_value_t { @@ -52,15 +104,26 @@ namespace sqlpp }; using _is_multi_column = std::true_type; - std::tuple _columns; + std::tuple _columns; }; namespace vendor { - template - struct interpreter_t> + template + struct serializer_t> { - using T = multi_column_t; + using T = multi_column_t; + + static void _(const T& t, Context& context) + { + static_assert(wrong_t::value, "multi_column must be used with an alias"); + } + }; + + template + struct serializer_t> + { + using T = multi_column_alias_t; static Context& _(const T& t, Context& context) { @@ -72,17 +135,20 @@ namespace sqlpp namespace detail { - template + template using make_multi_column_t = - multi_column_t()...))>; + detail::copy_tuple_args_t::_(std::declval())...))>; } - template - detail::make_multi_column_t multi_column(const AliasProvider& aliasProvider, NamedExpr... namedExpr) + template + auto multi_column(Columns... columns) + -> detail::make_multi_column_t { - return { detail::make_expression_tuple(namedExpr...)}; + return detail::make_multi_column_t(std::tuple_cat(detail::as_tuple::_(columns)...)); } + } #endif diff --git a/include/sqlpp11/no_value.h b/include/sqlpp11/no_value.h index 2f330147..2079c5d7 100644 --- a/include/sqlpp11/no_value.h +++ b/include/sqlpp11/no_value.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -36,8 +36,21 @@ namespace sqlpp template using _constraint = std::false_type; + using _base_value_type = no_value_t; + + template + struct _is_valid_operand + { + static constexpr bool value = false; + }; + template - struct operators + struct expression_operators + { + }; + + template + struct column_operators { }; }; diff --git a/include/sqlpp11/null.h b/include/sqlpp11/null.h index c07a3001..d8bcd0bd 100644 --- a/include/sqlpp11/null.h +++ b/include/sqlpp11/null.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -35,14 +35,13 @@ namespace sqlpp { static constexpr bool _is_expression = true; using _value_type = no_value_t; - - static constexpr bool _is_trivial() { return false; } + using _table_set = ::sqlpp::detail::type_set<>; }; namespace vendor { template - struct interpreter_t + struct serializer_t { using Operand = null_t; diff --git a/include/sqlpp11/on.h b/include/sqlpp11/on.h index 68c1297d..da874957 100644 --- a/include/sqlpp11/on.h +++ b/include/sqlpp11/on.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -41,7 +41,7 @@ namespace sqlpp using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; static_assert(_is_dynamic::value or sizeof...(Expr), "at least one expression argument required in on()"); - static_assert(detail::and_t::value, "at least one argument is not an expression in on()"); + static_assert(detail::all_t::value, "at least one argument is not an expression in on()"); template void add(E expr) @@ -57,7 +57,7 @@ namespace sqlpp namespace vendor { template - struct interpreter_t> + struct serializer_t> { using T = on_t; diff --git a/include/sqlpp11/parameter.h b/include/sqlpp11/parameter.h index 3f33b808..de550e15 100644 --- a/include/sqlpp11/parameter.h +++ b/include/sqlpp11/parameter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -28,16 +28,22 @@ #define SQLPP_PARAMETER_H #include +#include +#include namespace sqlpp { template - struct parameter_t: public ValueType::template operators> + struct parameter_t: public ValueType::template expression_operators> { - using _value_type = ValueType; + struct _value_type: public ValueType + { + using _is_expression = std::true_type; + using _is_alias = std::false_type; + }; using _is_parameter = std::true_type; - using _is_expression_t = std::true_type; using _instance_t = typename NameType::_name_t::template _member_t; + using _table_set = sqlpp::detail::type_set<>; parameter_t() {} @@ -52,7 +58,7 @@ namespace sqlpp namespace vendor { template - struct interpreter_t> + struct serializer_t> { using T = parameter_t; @@ -68,6 +74,7 @@ namespace sqlpp auto parameter(const NamedExpr&) -> parameter_t { + static_assert(is_named_expression_t::value, "not a named expression"); return {}; } @@ -75,6 +82,8 @@ namespace sqlpp auto parameter(const ValueType&, const AliasProvider&) -> parameter_t { + static_assert(is_value_t::value, "first argument is not a value type"); + static_assert(is_alias_provider_t::value, "second argument is not an alias provider"); return {}; } diff --git a/include/sqlpp11/parameter_list.h b/include/sqlpp11/parameter_list.h index 9657e647..fcb0cc56 100644 --- a/include/sqlpp11/parameter_list.h +++ b/include/sqlpp11/parameter_list.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, diff --git a/include/sqlpp11/prepared_insert.h b/include/sqlpp11/prepared_insert.h index ae68596f..63a995df 100644 --- a/include/sqlpp11/prepared_insert.h +++ b/include/sqlpp11/prepared_insert.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, diff --git a/include/sqlpp11/prepared_remove.h b/include/sqlpp11/prepared_remove.h index b37fe8ca..21e72986 100644 --- a/include/sqlpp11/prepared_remove.h +++ b/include/sqlpp11/prepared_remove.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, diff --git a/include/sqlpp11/prepared_select.h b/include/sqlpp11/prepared_select.h index 7c7947e9..0cdb56b4 100644 --- a/include/sqlpp11/prepared_select.h +++ b/include/sqlpp11/prepared_select.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -32,15 +32,15 @@ namespace sqlpp { - template + template struct prepared_select_t { - using _result_row_t = typename Select::_result_row_t; + using _result_row_t = typename Select::template _result_row_t; using _parameter_list_t = typename Select::_parameter_list_t; using _dynamic_names_t = typename Select::_dynamic_names_t; - using _prepared_statement_t = typename Db::_prepared_statement_t; + using _prepared_statement_t = typename Database::_prepared_statement_t; - auto _run(Db& db) const + auto _run(Database& db) const -> result_t { return {db.run_prepared_select(*this), _dynamic_names}; diff --git a/include/sqlpp11/prepared_update.h b/include/sqlpp11/prepared_update.h index f4c1a5e6..a6206e9e 100644 --- a/include/sqlpp11/prepared_update.h +++ b/include/sqlpp11/prepared_update.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, diff --git a/include/sqlpp11/remove.h b/include/sqlpp11/remove.h index 270ef9d9..ed12718f 100644 --- a/include/sqlpp11/remove.h +++ b/include/sqlpp11/remove.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -31,108 +31,97 @@ #include #include #include +#include +#include #include #include +#include +#include namespace sqlpp { - template< - typename Database, - typename Table, - typename Using = vendor::noop, - typename Where = vendor::noop - > - struct remove_t; + template + struct remove_t; - template< - typename Database, - typename Table, - typename Using, - typename Where - > - struct remove_t + namespace detail + { + template + struct remove_policies_t + { + using _database_t = Db; + using _table_t = Table; + using _using_t = Using; + using _extra_tables_t = ExtraTables; + using _where_t = Where; + + using _statement_t = remove_t; + + struct _methods_t: + public _using_t::template _methods_t, + public _extra_tables_t::template _methods_t, + public _where_t::template _methods_t + {}; + + template + struct _policies_update_t + { + using type = remove_t...>; + }; + + template + using _new_statement_t = typename _policies_update_t::type; + + using _known_tables = detail::make_joined_set_t; + + template + using _no_unknown_tables = detail::is_subset_of; + }; + } + + // REMOVE + template + struct remove_t: + public detail::remove_policies_t::_methods_t { - static_assert(vendor::is_noop
::value or is_table_t
::value, "invalid 'Table' argument"); - static_assert(vendor::is_noop::value or is_using_t::value, "invalid 'Using' argument"); - static_assert(vendor::is_noop::value or is_where_t::value, "invalid 'Where' argument"); + using _policies_t = typename detail::remove_policies_t; + using _database_t = typename _policies_t::_database_t; + using _table_t = typename _policies_t::_table_t; + using _using_t = typename _policies_t::_using_t; + using _extra_tables_t = typename _policies_t::_extra_tables_t; + using _where_t = typename _policies_t::_where_t; - template - using set_using_t = remove_t; - template - using set_where_t = remove_t; + using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; - using _parameter_tuple_t = std::tuple; + using _parameter_tuple_t = std::tuple; using _parameter_list_t = typename make_parameter_list_t::type; - template - auto using_(Tab... tab) - -> set_using_t> - { - static_assert(vendor::is_noop::value, "cannot call using() twice"); - static_assert(vendor::is_noop::value, "cannot call using() after where()"); - return { - _table, - {std::tuple{tab...}}, - _where - }; - } + // Constructors + remove_t() + {} - template - auto dynamic_using_(Tab... tab) - -> set_using_t> - { - static_assert(vendor::is_noop::value, "cannot call using() twice"); - static_assert(vendor::is_noop::value, "cannot call using() after where()"); - return { - _table, - {std::tuple{tab...}}, - _where - }; - } + template + remove_t(Statement s, T t): + _table(detail::arg_selector<_table_t>::_(s._table, t)), + _using(detail::arg_selector<_using_t>::_(s._using, t)), + _where(detail::arg_selector<_where_t>::_(s._where, t)) + {} - template - remove_t& add_using_(Tab table) - { - static_assert(is_dynamic_t::value, "cannot call add_using() in a non-dynamic using"); - _using.add(table); - - return *this; - } - - template - auto where(Expr... expr) - -> set_where_t> - { - static_assert(vendor::is_noop::value, "cannot call where() twice"); - return { - _table, - _using, - {std::tuple{expr...}}, - }; - } - - template - auto dynamic_where(Expr... expr) - -> set_where_t> - { - static_assert(vendor::is_noop::value, "cannot call where() twice"); - return { - _table, - _using, - {std::tuple{expr...}}, - }; - } - - template - remove_t& add_where(Expr expr) - { - static_assert(is_dynamic_t::value, "cannot call add_where() in a non-dynamic where"); - - _where.add(expr); - - return *this; - } + remove_t(const remove_t&) = default; + remove_t(remove_t&&) = default; + remove_t& operator=(const remove_t&) = default; + remove_t& operator=(remove_t&&) = default; + ~remove_t() = default; + // run and prepare static constexpr size_t _get_static_no_of_parameters() { return _parameter_list_t::size::value; @@ -143,54 +132,76 @@ namespace sqlpp return _parameter_list_t::size::value; } - template - std::size_t _run(Db& db) const + template + struct is_table_subset_of_table { + static constexpr bool value = ::sqlpp::detail::is_subset_of::value; + }; + + void _check_consistency() const + { + static_assert(is_where_t<_where_t>::value, "cannot run update without having a where condition, use .where(true) to update all rows"); + + // FIXME: Read more details about what is allowed and what not in SQL DELETE + static_assert(is_table_subset_of_table<_where_t>::value, "where requires additional tables"); + } + + template + std::size_t _run(Database& db) const + { + _check_consistency(); + static_assert(_get_static_no_of_parameters() == 0, "cannot run remove directly with parameters, use prepare instead"); - static_assert(is_where_t::value, "cannot run update without having a where condition, use .where(true) to remove all rows"); return db.remove(*this); } - template - auto _prepare(Db& db) const - -> prepared_remove_t + template + auto _prepare(Database& db) const + -> prepared_remove_t { + _check_consistency(); + return {{}, db.prepare_remove(*this)}; } - Table _table; - Using _using; - Where _where; + _table_t _table; + _using_t _using; + _where_t _where; }; namespace vendor { - template - struct interpreter_t> + template + struct serializer_t> { - using T = remove_t; + using T = remove_t; static Context& _(const T& t, Context& context) { context << "DELETE FROM "; - interpret(t._table, context); - interpret(t._using, context); - interpret(t._where, context); + serialize(t._table, context); + serialize(t._using, context); + serialize(t._where, context); return context; } }; } + template + using make_remove_t = typename detail::remove_policies_t::_statement_t; + template - constexpr remove_t remove_from(Table table) + constexpr auto remove_from(Table table) + -> make_remove_t> { - return {table}; + return { make_remove_t(), vendor::single_table_t{table} }; } - template - constexpr remove_t dynamic_remove_from(const Db&, Table table) + template + constexpr auto dynamic_remove_from(const Database&, Table table) + -> make_remove_t> { - return {table}; + return { make_remove_t(), vendor::single_table_t{table} }; } } diff --git a/include/sqlpp11/result.h b/include/sqlpp11/result.h index 937f3cf8..314ffc26 100644 --- a/include/sqlpp11/result.h +++ b/include/sqlpp11/result.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, diff --git a/include/sqlpp11/result_row.h b/include/sqlpp11/result_row.h index 1a8df8c3..81015528 100644 --- a/include/sqlpp11/result_row.h +++ b/include/sqlpp11/result_row.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -41,13 +41,13 @@ namespace sqlpp template struct result_row_impl; - template - struct result_row_impl: - public NamedExpr::_name_t::template _member_t, - public result_row_impl + template + struct result_row_impl: + public NamedExpr::_name_t::template _member_t>, + public result_row_impl { - using _field = typename NamedExpr::_name_t::template _member_t; - using _rest = result_row_impl; + using _field = typename NamedExpr::_name_t::template _member_t>; + using _rest = result_row_impl; static constexpr size_t _last_index = _rest::_last_index; result_row_impl() = default; @@ -84,13 +84,13 @@ namespace sqlpp } }; - template - struct result_row_impl>, Rest...>: - public AliasProvider::_name_t::template _member_t>, // level prevents identical closures to be present twice in the inheritance tree - public result_row_impl + template + struct result_row_impl>, Rest...>: + public AliasProvider::_name_t::template _member_t>, // level prevents identical closures to be present twice in the inheritance tree + public result_row_impl { - using _multi_field = typename AliasProvider::_name_t::template _member_t>; - using _rest = result_row_impl; + using _multi_field = typename AliasProvider::_name_t::template _member_t>; + using _rest = result_row_impl; static constexpr size_t _last_index = _rest::_last_index; result_row_impl() = default; @@ -126,8 +126,8 @@ namespace sqlpp } }; - template - struct result_row_impl + template + struct result_row_impl { static constexpr size_t _last_index = index; result_row_impl() = default; @@ -155,10 +155,10 @@ namespace sqlpp }; } - template - struct result_row_t: public detail::result_row_impl<0, 0, NamedExpr...> + template + struct result_row_t: public detail::result_row_impl<0, 0, Db, NamedExpr...> { - using _impl = detail::result_row_impl<0, 0, NamedExpr...>; + using _impl = detail::result_row_impl<0, 0, Db, NamedExpr...>; bool _is_valid; static constexpr size_t _last_static_index = _impl::_last_index; @@ -221,11 +221,11 @@ namespace sqlpp } }; - template - struct dynamic_result_row_t: public detail::result_row_impl<0, 0, NamedExpr...> + template + struct dynamic_result_row_t: public detail::result_row_impl<0, 0, Db, NamedExpr...> { - using _impl = detail::result_row_impl<0, 0, NamedExpr...>; - using _field_type = detail::text::_result_entry_t; + using _impl = detail::result_row_impl<0, 0, Db, NamedExpr...>; + using _field_type = detail::text::_result_entry_t; static constexpr size_t _last_static_index = _impl::_last_index; bool _is_valid; diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index cd68ec59..fd1b3a59 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -28,7 +28,6 @@ #define SQLPP_SELECT_H #include -#include #include #include @@ -36,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -43,559 +43,194 @@ #include #include #include -#include +#include #include +#include -#include -#include - -#include +#include namespace sqlpp { - template< - typename Database, - typename FlagList, - typename ColumnList, - typename From, - typename Where, - typename GroupBy, - typename Having, - typename OrderBy, - typename Limit, - typename Offset - > - struct select_t - : public ColumnList::_value_type::template operators> - { - using _Database = Database; - using _From = From; + template + struct select_t; - static_assert(is_select_flag_list_t::value, "invalid list of select flags"); - static_assert(is_select_column_list_t::value, "invalid list of select expressions"); - static_assert(vendor::is_noop::value or is_from_t::value, "invalid 'from' argument"); - static_assert(vendor::is_noop::value or is_where_t::value, "invalid 'where' argument"); - static_assert(vendor::is_noop::value or is_group_by_t::value, "invalid 'group by' arguments"); - static_assert(vendor::is_noop::value or is_having_t::value, "invalid 'having' arguments"); - static_assert(vendor::is_noop::value or is_order_by_t::value, "invalid 'order by' arguments"); - static_assert(vendor::is_noop::value or is_limit_t::value, "invalid 'limit' arguments"); - static_assert(vendor::is_noop::value or is_offset_t::value, "invalid 'offset' arguments"); + namespace detail + { + template + struct select_policies_t + { + using _database_t = Db; + using _flag_list_t = FlagList; + using _column_list_t = ColumnList; + using _from_t = From; + using _extra_tables_t = ExtraTables; + using _where_t = Where; + using _group_by_t = GroupBy; + using _having_t = Having; + using _order_by_t = OrderBy; + using _limit_t = Limit; + using _offset_t = Offset; + + using _statement_t = select_t; + + struct _methods_t: + public _flag_list_t::template _methods_t, + public _column_list_t::template _methods_t, + public _from_t::template _methods_t, + public _extra_tables_t::template _methods_t, + public _where_t::template _methods_t, + public _group_by_t::template _methods_t, + public _having_t::template _methods_t, + public _order_by_t::template _methods_t, + public _limit_t::template _methods_t, + public _offset_t::template _methods_t + {}; + + template + struct _policies_update_t + { + static_assert(detail::is_element_of>::value, "policies update for non-policy class detected"); + using type = select_t...>; + }; + + template + using _new_statement_t = typename _policies_update_t::type; + + static_assert(is_noop_t::value or sqlpp::is_select_column_list_t::value, "column list of select is neither naught nor a valid column list"); + static_assert(is_noop_t::value or sqlpp::is_from_t::value, "from() part of select is neither naught nor a valid from()"); + + using _known_tables = detail::make_joined_set_t; + + template + using _no_unknown_tables = detail::is_subset_of; + + using _required_tables = + detail::make_joined_set_t< + typename _flag_list_t::_table_set, + typename _column_list_t::_table_set, + typename _where_t::_table_set, + typename _group_by_t::_table_set, + typename _having_t::_table_set, + typename _order_by_t::_table_set, + typename _limit_t::_table_set, + typename _offset_t::_table_set + >; + + // The tables not covered by the from. + using _table_set = detail::make_difference_set_t< + _required_tables, + typename _from_t::_table_set // Hint: extra_tables_t is not used here because it is just a helper for dynamic .add_*() methods and should not change the structural integrity + >; + + // A select can be used as a pseudo table if + // - at least one column is selected + // - the select is complete (leaks no tables) + using _can_be_used_as_table = typename std::conditional< + is_select_column_list_t<_column_list_t>::value and _table_set::size::value == 0, + std::true_type, + std::false_type + >::type; + + using _value_type = typename std::conditional< + is_select_column_list_t<_column_list_t>::value and is_subset_of::value, + typename ColumnList::_value_type, + no_value_t // If something is selected that requires a table, then we require a from for this to be a value + >::type; + }; + } + + // SELECT + template + struct select_t: + public detail::select_policies_t::_value_type::template expression_operators>, + public detail::select_policies_t::_methods_t + { + using _policies_t = typename detail::select_policies_t; + using _database_t = typename _policies_t::_database_t; + using _flag_list_t = typename _policies_t::_flag_list_t; + using _column_list_t = typename _policies_t::_column_list_t; + using _from_t = typename _policies_t::_from_t; + using _extra_tables_t = typename _policies_t::_extra_tables_t; + using _where_t = typename _policies_t::_where_t; + using _group_by_t = typename _policies_t::_group_by_t; + using _having_t = typename _policies_t::_having_t; + using _order_by_t = typename _policies_t::_order_by_t; + using _limit_t = typename _policies_t::_limit_t; + using _offset_t = typename _policies_t::_offset_t; + + using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; + + using _parameter_tuple_t = std::tuple; + using _parameter_list_t = typename make_parameter_list_t::type; + using _table_set = typename _policies_t::_table_set; + + template + using _result_row_t = typename _column_list_t::template _result_row_t; + using _dynamic_names_t = typename _column_list_t::_dynamic_names_t; using _is_select = std::true_type; using _requires_braces = std::true_type; - template - using set_flag_list_t = select_t; - template - using set_column_list_t = select_t; - template - using set_from_t = select_t; - template - using set_where_t = select_t; - template - using set_group_by_t = select_t; - template - using set_having_t = select_t; - template - using set_order_by_t = select_t; - template - using set_limit_t = select_t; - template - using set_offset_t = select_t; + using _value_type = typename detail::select_policies_t::_value_type; + using _name_t = typename _column_list_t::_name_t; - using _result_row_t = typename ColumnList::_result_row_t; - using _dynamic_names_t = typename ColumnList::_dynamic_names_t; - using _parameter_tuple_t = std::tuple; - using _parameter_list_t = typename make_parameter_list_t::type; + // Constructors + select_t() + {} - // Indicators - using _value_type = typename std::conditional< - vendor::is_noop::value, - no_value_t, // If there is no from, the select is not complete (this logic is a bit simple, but better than nothing) - typename ColumnList::_value_type>::type; + template + select_t(Statement s, T t): + _flag_list(detail::arg_selector<_flag_list_t>::_(s._flag_list, t)), + _column_list(detail::arg_selector<_column_list_t>::_(s._column_list, t)), + _from(detail::arg_selector<_from_t>::_(s._from, t)), + _where(detail::arg_selector<_where_t>::_(s._where, t)), + _group_by(detail::arg_selector<_group_by_t>::_(s._group_by, t)), + _having(detail::arg_selector<_having_t>::_(s._having, t)), + _order_by(detail::arg_selector<_order_by_t>::_(s._order_by, t)), + _limit(detail::arg_selector<_limit_t>::_(s._limit, t)), + _offset(detail::arg_selector<_offset_t>::_(s._offset, t)) + {} - using _name_t = typename ColumnList::_name_t; - - // The standard constructors, assigment operators and destructor - constexpr select_t(FlagList flag_list, ColumnList column_list, From from, - Where where, GroupBy group_by, Having having, - OrderBy order_by, Limit limit, Offset offset): - _flags(flag_list), - _columns(column_list), - _from(from), - _where(where), - _group_by(group_by), - _having(having), - _order_by(order_by), - _limit(limit), - _offset(offset) - { - } - - select_t(const select_t& rhs) = default; - select_t(select_t&& rhs) = default; - select_t& operator=(const select_t& rhs) = default; - select_t& operator=(select_t&& rhs) = default; + select_t(const select_t& r) = default; + select_t(select_t&& r) = default; + select_t& operator=(const select_t& r) = default; + select_t& operator=(select_t&& r) = default; ~select_t() = default; - // select functions - template - auto flags(Flag... flag) - -> set_flag_list_t>> - { - static_assert(not FlagList::size::value, "cannot call dynamic_flags() after specifying them the first time"); - static_assert(not ColumnList::size::value, "cannot call columns() after specifying them the first time"); - return { - {std::tuple{flag...}}, - _columns, - _from, - _where, - _group_by, - _having, - _order_by, - _limit, - _offset - }; - } - - template - auto dynamic_flags(Flag... flag) - -> set_flag_list_t>> - { - static_assert(not std::is_same::value, "cannot call dynamic_flags() in a non-dynamic select"); - static_assert(not FlagList::size::value, "cannot call dynamic_flags() after specifying them the first time"); - static_assert(not ColumnList::size::value, "cannot call columns() after specifying them the first time"); - return { - {std::tuple{flag...}}, - _columns, - _from, - _where, - _group_by, - _having, - _order_by, - _limit, - _offset - }; - } - - template - select_t& add_flag(Flag flag) - { - static_assert(is_dynamic_t::value, "cannot call add_flag() in a non-dynamic column list"); - - _flags.add(flag); - - return *this; - } - - template - auto columns(Column... column) - -> set_column_list_t>> - { - static_assert(not ColumnList::size::value, "cannot call columns() after specifying them the first time"); - return { - _flags, - {std::tuple{column...}}, - _from, - _where, - _group_by, - _having, - _order_by, - _limit, - _offset - }; - } - - template - auto dynamic_columns(Column... column) - -> set_column_list_t>> - { - static_assert(not std::is_same::value, "cannot call dynamic_columns() in a non-dynamic select"); - static_assert(not ColumnList::size::value, "cannot call dynamic_columns() after specifying them the first time"); - return { - _flags, - {std::tuple{column...}}, - _from, - _where, - _group_by, - _having, - _order_by, - _limit, - _offset - }; - } - - template - select_t& add_column(NamedExpr namedExpr) - { - static_assert(is_dynamic_t::value, "cannot call add_column() in a non-dynamic column list"); - - _columns.add(namedExpr); - - return *this; - } - - template - auto from(Table... table) - -> set_from_t> - { - static_assert(not vendor::is_noop::value, "cannot call from() without having selected anything"); - static_assert(vendor::is_noop::value, "cannot call from() twice for a single select"); - return { - _flags, - _columns, - {std::tuple{table...}}, - _where, - _group_by, - _having, - _order_by, - _limit, - _offset - }; - } - - template - auto dynamic_from(Table... table) - -> set_from_t> - { - static_assert(not std::is_same::value, "cannot call dynamic_from() in a non-dynamic select"); - static_assert(not vendor::is_noop::value, "cannot call from() without having selected anything"); - static_assert(vendor::is_noop::value, "cannot call from() twice for a single select"); - return { - _flags, - _columns, - {std::tuple{table...}}, - _where, - _group_by, - _having, - _order_by, - _limit, - _offset - }; - } - - template - select_t& add_from(Table table) - { - static_assert(not vendor::is_noop::value, "cannot call add_from() without having selected anything"); - static_assert(is_dynamic_t::value, "cannot call add_from() in a non-dynamic from"); - - _from.add(table); - - return *this; - } - - template - auto where(Expr... expr) - -> set_where_t> - { - static_assert(not vendor::is_noop::value, "cannot call where() without a from()"); - static_assert(vendor::is_noop::value, "cannot call where() or dynamic_where() twice for a single select"); - return { - _flags, - _columns, - _from, - {std::tuple{expr...}}, - _group_by, - _having, - _order_by, - _limit, - _offset, - }; - } - - template - auto dynamic_where(Expr... expr) - -> set_where_t> - { - static_assert(not vendor::is_noop::value, "cannot call dynamic_where() without a from()"); - static_assert(vendor::is_noop::value, "cannot call where() or dynamic_where() twice for a single select"); - return { - _flags, - _columns, - _from, - {std::tuple{expr...}}, - _group_by, - _having, - _order_by, - _limit, - _offset, - }; - } - - template - select_t& add_where(Expr expr) - { - static_assert(is_dynamic_t::value, "cannot call add_where() with a non-dynamic where"); - - _where.add(expr); - - return *this; - } - - template - auto group_by(Col... column) - -> set_group_by_t> - { - static_assert(not vendor::is_noop::value, "cannot call group_by() without a from()"); - static_assert(vendor::is_noop::value, "cannot call group_by() twice for a single select"); - return { - _flags, - _columns, - _from, - _where, - {std::tuple{column...}}, - _having, - _order_by, - _limit, - _offset, - }; - } - - template - auto dynamic_group_by(Col... column) - -> set_group_by_t> - { - static_assert(not vendor::is_noop::value, "cannot call group_by() without a from()"); - static_assert(vendor::is_noop::value, "cannot call group_by() twice for a single select"); - return { - _flags, - _columns, - _from, - _where, - {std::tuple{column...}}, - _having, - _order_by, - _limit, - _offset, - }; - } - - template - select_t& add_group_by(Expr expr) - { - static_assert(is_dynamic_t::value, "cannot call add_group_by() in a non-dynamic group_by"); - - _group_by.add(expr); - - return *this; - } - - template - auto having(Expr... expr) - -> set_having_t> - { - static_assert(not vendor::is_noop::value, "cannot call having() without a group_by"); - static_assert(vendor::is_noop::value, "cannot call having() twice for a single select"); - return { - _flags, - _columns, - _from, - _where, - _group_by, - {std::tuple{expr...}}, - _order_by, - _limit, - _offset, - }; - } - - template - auto dynamic_having(Expr... expr) - -> set_having_t> - { - static_assert(not vendor::is_noop::value, "cannot call having() without a group_by"); - static_assert(vendor::is_noop::value, "cannot call having() twice for a single select"); - return { - _flags, - _columns, - _from, - _where, - _group_by, - {std::tuple{expr...}}, - _order_by, - _limit, - _offset, - }; - } - - template - select_t& add_having(Expr expr) - { - static_assert(is_dynamic_t::value, "cannot call add_having() in a non-dynamic having"); - - _having.add(expr); - - return *this; - } - - template - auto order_by(OrderExpr... expr) - -> set_order_by_t> - { - static_assert(not vendor::is_noop::value, "cannot call order_by() without a from()"); - static_assert(vendor::is_noop::value, "cannot call order_by() twice for a single select"); - return { - _flags, - _columns, - _from, - _where, - _group_by, - _having, - {std::tuple{expr...}}, - _limit, - _offset, - }; - } - - template - auto dynamic_order_by(OrderExpr... expr) - -> set_order_by_t> - { - static_assert(not vendor::is_noop::value, "cannot call order_by() without a from()"); - static_assert(vendor::is_noop::value, "cannot call order_by() twice for a single select"); - return { - _flags, - _columns, - _from, - _where, - _group_by, - _having, - {std::tuple{expr...}}, - _limit, - _offset, - }; - } - - template - select_t& add_order_by(Expr expr) - { - static_assert(is_dynamic_t::value, "cannot call add_order_by() in a non-dynamic order_by"); - - _order_by.add(expr); - - return *this; - } - - template - auto limit(Expr limit) - -> set_limit_t::type>> - { - static_assert(not vendor::is_noop::value, "cannot call limit() without a from()"); - static_assert(vendor::is_noop::value, "cannot call limit() twice for a single select"); - return { - _flags, - _columns, - _from, - _where, - _group_by, - _having, - _order_by, - {limit}, - _offset, - }; - } - - auto dynamic_limit(std::size_t limit = 0) - ->set_limit_t - { - static_assert(not vendor::is_noop::value, "cannot call limit() without a from()"); - static_assert(vendor::is_noop::value, "cannot call limit() twice for a single select"); - return { - _flags, - _columns, - _from, - _where, - _group_by, - _having, - _order_by, - {limit}, - _offset, - }; - } - - select_t& set_limit(std::size_t limit) - { - static_assert(is_dynamic_t::value, "cannot call set_limit() in a non-dynamic limit"); - - _limit.set(limit); - - return *this; - } - - template - auto offset(Expr offset) - -> set_offset_t::type>> - { - static_assert(not vendor::is_noop::value, "cannot call offset() without a limit"); - static_assert(vendor::is_noop::value, "cannot call offset() twice for a single select"); - return { - _flags, - _columns, - _from, - _where, - _group_by, - _having, - _order_by, - _limit, - {offset}, - }; - } - - auto dynamic_offset(std::size_t offset = 0) - -> set_offset_t - { - static_assert(not vendor::is_noop::value, "cannot call offset() without a limit"); - static_assert(vendor::is_noop::value, "cannot call offset() twice for a single select"); - return { - _flags, - _columns, - _from, - _where, - _group_by, - _having, - _order_by, - _limit, - {offset}, - }; - } - - select_t& set_offset(std::size_t offset) - { - static_assert(is_dynamic_t::value, "cannot call set_offset() in a non-dynamic limit"); - - _offset.set(offset); - - return *this; - } - + // PseudoTable template struct _pseudo_table_t { - using table = typename ColumnList::template _pseudo_table_t; + using table = typename _column_list_t::template _pseudo_table_t; using alias = typename table::template _alias_t; }; template typename _pseudo_table_t::alias as(const AliasProvider& aliasProvider) const { + static_assert(_policies_t::_can_be_used_as_table::value, "select cannot be used as table, incomplete from()"); return typename _pseudo_table_t::table( *this).as(aliasProvider); } - const typename ColumnList::_dynamic_names_t& get_dynamic_names() const + const _dynamic_names_t& get_dynamic_names() const { - return _columns._dynamic_columns._dynamic_expression_names; + return _column_list._dynamic_columns._dynamic_expression_names; } static constexpr size_t _get_static_no_of_parameters() @@ -610,146 +245,114 @@ namespace sqlpp size_t get_no_of_result_columns() const { - return _result_row_t::static_size() + get_dynamic_names().size(); + return _column_list_t::static_size() + get_dynamic_names().size(); + } + + template + struct is_table_subset_of_from + { + static constexpr bool value = ::sqlpp::detail::is_subset_of::value; + }; + + void _check_consistency() const + { + static_assert(is_select_column_list_t<_column_list_t>::value, "no columns selected"); + + static_assert(is_table_subset_of_from<_flag_list_t>::value, "flags require additional tables in from()"); + static_assert(is_table_subset_of_from<_column_list_t>::value, "selected columns require additional tables in from()"); + static_assert(is_table_subset_of_from<_where_t>::value, "where() expression requires additional tables in from()"); + static_assert(is_table_subset_of_from<_group_by_t>::value, "group_by() expression requires additional tables in from()"); + static_assert(is_table_subset_of_from<_having_t>::value, "having() expression requires additional tables in from()"); + static_assert(is_table_subset_of_from<_order_by_t>::value, "order_by() expression requires additional tables in from()"); + static_assert(is_table_subset_of_from<_limit_t>::value, "limit() expression requires additional tables in from()"); + static_assert(is_table_subset_of_from<_offset_t>::value, "offset() expression requires additional tables in from()"); + static_assert(not _table_set::size::value, "one sub expression contains tables which are not in the from()"); } // Execute - template - auto _run(Db& db) const - -> result_t + template + auto _run(Database& db) const + -> result_t> { - static_assert(not vendor::is_noop::value, "cannot run select without having selected anything"); - static_assert(is_from_t::value, "cannot run select without a from()"); - static_assert(is_where_t::value, "cannot run select without having a where condition, use .where(true) to select all rows"); + _check_consistency(); static_assert(_get_static_no_of_parameters() == 0, "cannot run select directly with parameters, use prepare instead"); - // FIXME: Check for missing aliases (if references are used) - // FIXME: Check for missing tables, well, actually, check for missing tables at the where(), order_by(), etc. return {db.select(*this), get_dynamic_names()}; } // Prepare - template - auto _prepare(Db& db) const - -> prepared_select_t + template + auto _prepare(Database& db) const + -> prepared_select_t { - static_assert(not vendor::is_noop::value, "cannot run select without having selected anything"); - static_assert(is_from_t::value, "cannot run select without a from()"); - // FIXME: Check for missing aliases (if references are used) - // FIXME: Check for missing tables, well, actually, check for missing tables at the where(), order_by(), etc. + _check_consistency(); return {{}, get_dynamic_names(), db.prepare_select(*this)}; } - FlagList _flags; - ColumnList _columns; - From _from; - Where _where; - GroupBy _group_by; - Having _having; - OrderBy _order_by; - Limit _limit; - Offset _offset; + _flag_list_t _flag_list; + _column_list_t _column_list; + _from_t _from; + _where_t _where; + _group_by_t _group_by; + _having_t _having; + _order_by_t _order_by; + _limit_t _limit; + _offset_t _offset; }; namespace vendor { - template - struct interpreter_t> + template + struct serializer_t> { - using T = select_t; + using T = select_t; static Context& _(const T& t, Context& context) { context << "SELECT "; - interpret(t._flags, context); - interpret(t._columns, context); - interpret(t._from, context); - interpret(t._where, context); - interpret(t._group_by, context); - interpret(t._having, context); - interpret(t._order_by, context); - interpret(t._limit, context); - interpret(t._offset, context); + serialize(t._flag_list, context); + serialize(t._column_list, context); + serialize(t._from, context); + serialize(t._where, context); + serialize(t._group_by, context); + serialize(t._having, context); + serialize(t._order_by, context); + serialize(t._limit, context); + serialize(t._offset, context); return context; } }; } + template + using make_select_t = typename detail::select_policies_t::_statement_t; - // construct select flag list - namespace detail + make_select_t select() // FIXME: These should be constexpr { - template - using make_select_flag_list_t = - vendor::select_flag_list_t()...))>; + return { }; } - // construct select expression list - namespace detail - { - template - using make_select_column_list_t = - vendor::select_column_list_t()...))>; - } - - auto select() - -> select_t>, vendor::select_column_list_t>> + template + auto select(Columns... columns) + -> make_select_t> { - return { {}, vendor::select_column_list_t>{}, {}, {}, {}, {}, {}, {}, {} }; + return { make_select_t(), detail::make_select_column_list_t{std::tuple_cat(detail::as_tuple::_(columns)...)} }; } - template - auto select(NamedExpr... namedExpr) - -> select_t, detail::make_select_column_list_t> + template + make_select_t dynamic_select(const Database&) { - return { - { detail::make_flag_tuple(namedExpr...) }, - { detail::make_expression_tuple(namedExpr...) }, - {}, {}, {}, {}, {}, {}, {} - }; + return { make_select_t() }; } - template - auto dynamic_select(const Db& db, NamedExpr... namedExpr) - -> select_t, detail::make_select_column_list_t> + template + auto dynamic_select(const Database&, Columns... columns) + -> make_select_t> { - return { - { detail::make_flag_tuple(namedExpr...) }, - { detail::make_expression_tuple(namedExpr...) }, - {}, {}, {}, {}, {}, {}, {} - }; + return { make_select_t(), detail::make_select_column_list_t(std::tuple_cat(detail::as_tuple::_(columns)...)) }; } } diff --git a/include/sqlpp11/select_flags.h b/include/sqlpp11/select_flags.h index 3bcce768..e8ee53d5 100644 --- a/include/sqlpp11/select_flags.h +++ b/include/sqlpp11/select_flags.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -27,7 +27,6 @@ #ifndef SQLPP_SELECT_FLAGS_H #define SQLPP_SELECT_FLAGS_H -#include #include #include #include @@ -42,13 +41,14 @@ namespace sqlpp { using _is_select_flag = std::true_type; }; + using _table_set = detail::type_set<>; }; static constexpr all_t all = {}; namespace vendor { template - struct interpreter_t + struct serializer_t { static Context& _(const all_t&, Context& context) { @@ -64,13 +64,14 @@ namespace sqlpp { using _is_select_flag = std::true_type; }; + using _table_set = detail::type_set<>; }; static constexpr distinct_t distinct = {}; namespace vendor { template - struct interpreter_t + struct serializer_t { static Context& _(const distinct_t&, Context& context) { @@ -86,13 +87,14 @@ namespace sqlpp { using _is_select_flag = std::true_type; }; + using _table_set = detail::type_set<>; }; static constexpr straight_join_t straight_join = {}; namespace vendor { template - struct interpreter_t + struct serializer_t { static Context& _(const straight_join_t&, Context& context) { diff --git a/include/sqlpp11/serialize.h b/include/sqlpp11/serialize.h new file mode 100644 index 00000000..296ae043 --- /dev/null +++ b/include/sqlpp11/serialize.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2013-2014, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLPP_SERIALIZE_H +#define SQLPP_SERIALIZE_H + +#include + +namespace sqlpp +{ + template + auto serialize(const T& t, Context& context) + -> decltype(vendor::serializer_t::_(t, context)) + { + return vendor::serializer_t::_(t, context); + } + + /* + namespace vendor // Required if you want to call serialize(sqlpp::value(7), printer), for instance + { + template + auto serialize(const T& t, Context& context) + -> decltype(vendor::serializer_t::_(t, context)) + { + return vendor::serializer_t::_(t, context); + } + } + */ + +} + +#endif diff --git a/include/sqlpp11/serializer.h b/include/sqlpp11/serializer_context.h similarity index 77% rename from include/sqlpp11/serializer.h rename to include/sqlpp11/serializer_context.h index d8bbaaee..df872b54 100644 --- a/include/sqlpp11/serializer.h +++ b/include/sqlpp11/serializer_context.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -23,16 +23,16 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SQLPP_SERIALIZER_H -#define SQLPP_SERIALIZER_H +#ifndef SQLPP_SERIALIZER_CONTEXT_H +#define SQLPP_SERIALIZER_CONTEXT_H #include namespace sqlpp { - struct serializer_t + struct serializer_context_t { - serializer_t(std::ostream& os): + serializer_context_t(std::ostream& os): _os(os) {} @@ -42,14 +42,21 @@ namespace sqlpp return _os << t; } - void flush() + static std::string escape(std::string arg) { - _os << std::endl; - } - - std::string escape(std::string arg) - { - return arg; + if (arg.find('\'')) + { + std::string retVal; + for (const auto c : arg) + { + if (c == '\'') + retVal.push_back(c); + retVal.push_back(c); + } + return retVal; + } + else + return arg; } std::ostream& _os; diff --git a/include/sqlpp11/some.h b/include/sqlpp11/some.h index c9f26081..cd5e63cc 100644 --- a/include/sqlpp11/some.h +++ b/include/sqlpp11/some.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -27,22 +27,20 @@ #ifndef SQLPP_SOME_H #define SQLPP_SOME_H -#include #include +#include namespace sqlpp { namespace vendor { template - struct some_t: public boolean::template operators> + struct some_t { - static_assert(is_select_t::value, "some() requires a single column select expression as argument"); - struct _value_type: public Select::_value_type::_base_value_type { - using _is_multi_expression = std::true_type; // must not be named + using _is_expression = std::false_type; + using _is_multi_expression = std::true_type; // must not be named or used with +,-,*,/, etc }; struct _name_t @@ -56,6 +54,7 @@ namespace sqlpp const T& operator()() const { return some; } }; }; + using _table_set = typename Select::_table_set; some_t(Select select): _select(select) @@ -74,14 +73,14 @@ namespace sqlpp namespace vendor { template - struct interpreter_t> + struct serializer_t> { using T = vendor::some_t
; // Hint need a type_set here to be similar to a join (which always represents more than one table) - using _all_columns = typename detail::make_set...>::type; - static_assert(_all_columns::size::value, "at least one column required per table"); - using _required_insert_columns = typename detail::make_set_if...>::type; - using _all_of_t = std::tuple...>; + static_assert(sizeof...(ColumnSpec), "at least one column required per table"); + using _required_insert_columns = typename detail::make_type_set_if...>::type; + using _column_tuple_t = std::tuple...>; template using _alias_t = table_alias_t; @@ -93,16 +93,10 @@ namespace sqlpp } }; - template - auto all_of(Table t) -> typename Table::_all_of_t - { - return {}; - } - namespace vendor { template - struct interpreter_t::value and not is_pseudo_table_t::value, void>::type> + struct serializer_t::value and not is_pseudo_table_t::value, void>::type> { using T = X; diff --git a/include/sqlpp11/table_alias.h b/include/sqlpp11/table_alias.h index 269d80b1..273b2d90 100644 --- a/include/sqlpp11/table_alias.h +++ b/include/sqlpp11/table_alias.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -42,7 +42,7 @@ namespace sqlpp { //FIXME: Need to add join functionality using _is_table = std::true_type; - using _table_set = detail::type_set; + using _table_set = detail::type_set; struct _value_type: Table::_value_type { @@ -52,7 +52,7 @@ namespace sqlpp }; using _name_t = typename AliasProvider::_name_t; - using _all_of_t = std::tuple...>; + using _column_tuple_t = std::tuple...>; table_alias_t(Table table): _table(table) @@ -64,14 +64,14 @@ namespace sqlpp namespace vendor { template - struct interpreter_t::value, void>::type> + struct serializer_t::value, void>::type> { using T = X; static Context& _(const T& t, Context& context) { context << "("; - interpret(t._table, context); + serialize(t._table, context); context << ") AS " << T::_name_t::_get_name(); return context; } diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index f7d535ea..8a41fa24 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -27,7 +27,8 @@ #ifndef SQLPP_TEXT_H #define SQLPP_TEXT_H -#include +#include +#include #include #include #include @@ -40,6 +41,7 @@ namespace sqlpp // text value type struct text { + using _value_type = text; using _base_value_type = text; using _is_text = std::true_type; using _is_value = std::true_type; @@ -97,6 +99,7 @@ namespace sqlpp bool _is_null; }; + template struct _result_entry_t { _result_entry_t(): @@ -135,16 +138,29 @@ namespace sqlpp bool is_null() const { - if (not _is_valid) + if (connector_assert_result_validity_t::value) + assert(_is_valid); + else if (not _is_valid) throw exception("accessing is_null in non-existing row"); return _value_ptr == nullptr; } _cpp_value_type value() const { - if (not _is_valid) - throw exception("accessing value in non-existing row"); - if (_value_ptr) + 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 ""; @@ -165,31 +181,52 @@ namespace sqlpp }; template - using _operand_t = operand_t; - template - using _constraint = is_text_t; + struct _is_valid_operand + { + static constexpr bool value = + is_expression_t::value // expressions are OK + and is_text_t::value // the correct value type is required, of course + ; + }; template - struct operators: public basic_operators + struct expression_operators: public basic_expression_operators { template - vendor::concat_t::type> operator+(T t) const + vendor::concat_t> operator+(T t) const { - static_assert(not is_multi_expression_t::value, "multi-expression cannot be used as left hand side operand"); + using rhs = vendor::wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs operand"); + return { *static_cast(this), {t} }; } template - vendor::like_t::type> like(T t) const + vendor::like_t> like(T t) const { - static_assert(not is_multi_expression_t::value, "multi-expression cannot be used as left hand side operand"); + using rhs = vendor::wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid argument for like()"); + return { *static_cast(this), {t} }; } + }; + template + struct column_operators + { + template + auto operator +=(T t) const -> vendor::assignment_t>> + { + using rhs = vendor::wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); + + return { *static_cast(this), { *static_cast(this), rhs{t} } }; + } }; }; - inline std::ostream& operator<<(std::ostream& os, const text::_result_entry_t& e) + template + inline std::ostream& operator<<(std::ostream& os, const text::_result_entry_t& e) { return os << e.value(); } diff --git a/include/sqlpp11/transaction.h b/include/sqlpp11/transaction.h index 63b64c91..a2b1dfbc 100644 --- a/include/sqlpp11/transaction.h +++ b/include/sqlpp11/transaction.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, diff --git a/include/sqlpp11/tvin.h b/include/sqlpp11/tvin.h index a3462d08..be1bf137 100644 --- a/include/sqlpp11/tvin.h +++ b/include/sqlpp11/tvin.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -30,7 +30,8 @@ // TVIN: Trivial value is NULL #include -#include +#include +#include namespace sqlpp { @@ -39,6 +40,7 @@ namespace sqlpp { using _operand_t = Operand; using _value_type = typename _operand_t::_value_type; + using _table_set = typename _operand_t::_table_set; tvin_t(Operand operand): _value(operand) @@ -60,7 +62,7 @@ namespace sqlpp namespace vendor { template - struct interpreter_t> + struct serializer_t> { using T = tvin_t; @@ -72,41 +74,43 @@ namespace sqlpp } template - struct tvin_wrap_t + struct maybe_tvin_t { + using _table_set = typename T::_table_set; static constexpr bool _is_trivial() { return false; } - tvin_wrap_t(T t): + maybe_tvin_t(T t): _value(t) {} - tvin_wrap_t(const tvin_wrap_t&) = default; - tvin_wrap_t(tvin_wrap_t&&) = default; - tvin_wrap_t& operator=(const tvin_wrap_t&) = default; - tvin_wrap_t& operator=(tvin_wrap_t&&) = default; - ~tvin_wrap_t() = default; + 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; T _value; }; template - struct tvin_wrap_t> + struct maybe_tvin_t> { + using _table_set = typename T::_table_set; bool _is_trivial() const { return _value._is_trivial(); }; - tvin_wrap_t(tvin_t t): + maybe_tvin_t(tvin_t t): _value(t._value) {} - tvin_wrap_t(const tvin_wrap_t&) = default; - tvin_wrap_t(tvin_wrap_t&&) = default; - tvin_wrap_t& operator=(const tvin_wrap_t&) = default; - tvin_wrap_t& operator=(tvin_wrap_t&&) = default; - ~tvin_wrap_t() = default; + 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; }; @@ -114,9 +118,9 @@ namespace sqlpp namespace vendor { template - struct interpreter_t> + struct serializer_t> { - using T = tvin_wrap_t; + using T = maybe_tvin_t; static Context& _(const T& t, Context& context) { @@ -126,7 +130,7 @@ namespace sqlpp } else { - interpret(t._value, context); + serialize(t._value, context); } return context; } diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index 83f74895..b4d39bf8 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -92,7 +92,9 @@ namespace sqlpp 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_TYPE_TRAIT_GENERATOR(is_noop); SQLPP_TYPE_TRAIT_GENERATOR(is_table); SQLPP_TYPE_TRAIT_GENERATOR(is_join); SQLPP_TYPE_TRAIT_GENERATOR(is_pseudo_table); @@ -122,20 +124,11 @@ namespace sqlpp SQLPP_TYPE_TRAIT_GENERATOR(requires_braces); SQLPP_TYPE_TRAIT_GENERATOR(is_parameter); - SQLPP_CONNECTOR_TRAIT_GENERATOR(has_empty_list_insert); + SQLPP_CONNECTOR_TRAIT_GENERATOR(null_result_is_trivial_value); + SQLPP_CONNECTOR_TRAIT_GENERATOR(assert_result_validity); template class IsTag> using copy_type_trait = typename std::conditional::value, std::true_type, std::false_type>::type; - - template class IsCorrectType> - struct operand_t - { - using type = typename vendor::wrap_operand::type; - static_assert(not is_alias_t::value, "expression operand must not be an alias"); - static_assert(is_expression_t::value, "expression required"); - static_assert(IsCorrectType::value, "invalid operand type"); - }; - } #endif diff --git a/include/sqlpp11/update.h b/include/sqlpp11/update.h index bdc2860d..5865651a 100644 --- a/include/sqlpp11/update.h +++ b/include/sqlpp11/update.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -30,110 +30,96 @@ #include #include #include +#include #include #include #include +#include +#include namespace sqlpp { - template< - typename Database = void, - typename Table = vendor::noop, - typename Assignments = vendor::noop, - typename Where = vendor::noop - > - struct update_t; + template + struct update_t; - template< - typename Database, - typename Table, - typename Assignments, - typename Where - > - struct update_t + namespace detail + { + template + struct update_policies_t + { + using _database_t = Db; + using _table_t = Table; + using _update_list_t = UpdateList; + using _where_t = Where; + + using _statement_t = update_t; + + struct _methods_t: + public _update_list_t::template _methods_t, + public _where_t::template _methods_t + {}; + + template + struct _policies_update_t + { + using type = update_t...>; + }; + + template + using _new_statement_t = typename _policies_update_t::type; + + using _known_tables = detail::make_joined_set_t; + + template + using _no_unknown_tables = detail::is_subset_of; + + }; + } + + template + struct update_t: + public detail::update_policies_t::_methods_t { - static_assert(vendor::is_noop
::value or is_table_t
::value, "invalid 'Table' argument"); - static_assert(vendor::is_noop::value or is_update_list_t::value, "invalid 'Assignments' arguments"); - static_assert(vendor::is_noop::value or is_where_t::value, "invalid 'Where' argument"); + using _policies_t = typename detail::update_policies_t; + using _database_t = typename _policies_t::_database_t; + using _table_t = typename _policies_t::_table_t; + using _update_list_t = typename _policies_t::_update_list_t; + using _where_t = typename _policies_t::_where_t; - template - using set_assignments_t = update_t; - template - using set_where_t = update_t; + using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; - using _parameter_tuple_t = std::tuple; + using _parameter_tuple_t = std::tuple; using _parameter_list_t = typename make_parameter_list_t::type; - template - auto set(Assignment... assignment) - -> set_assignments_t> - { - static_assert(vendor::is_noop::value, "cannot call set() twice"); - return { - _table, - {std::tuple{assignment...}}, - _where, - }; - } + static_assert(::sqlpp::detail::is_superset_of::value, "updated columns do not match the table"); + static_assert(::sqlpp::detail::is_superset_of::value, "where condition does not match updated table"); - template - auto dynamic_set(Assignment... assignment) - -> set_assignments_t> - { - static_assert(vendor::is_noop::value, "cannot call set() twice"); - return { - _table, - {std::tuple{assignment...}}, - _where, - }; - } + // Constructors + update_t() + {} - template - update_t& add_set(Assignment assignment) - { - static_assert(is_dynamic_t::value, "cannot call add_set() in a non-dynamic set"); + template + update_t(Statement s, T t): + _table(detail::arg_selector<_table_t>::_(s._table, t)), + _update_list(detail::arg_selector<_update_list_t>::_(s._update_list, t)), + _where(detail::arg_selector<_where_t>::_(s._where, t)) + {} - _assignments.add(assignment); - - return *this; - } - - template - auto where(Expr... expr) - -> set_where_t> - { - static_assert(not vendor::is_noop::value, "cannot call where() if set() hasn't been called yet"); - static_assert(vendor::is_noop::value, "cannot call where() twice"); - return { - _table, - _assignments, - {std::tuple{expr...}}, - }; - } - - template - auto dynamic_where(Expr... expr) - -> set_where_t> - { - static_assert(not vendor::is_noop::value, "cannot call where() if set() hasn't been called yet"); - static_assert(vendor::is_noop::value, "cannot call where() twice"); - return { - _table, - _assignments, - {std::tuple{expr...}}, - }; - } - - template - update_t& add_where(Expr expr) - { - static_assert(is_dynamic_t::value, "cannot call add_where() in a non-dynamic where"); - - _where.add(expr); - - return *this; - } + update_t(const update_t&) = default; + update_t(update_t&&) = default; + update_t& operator=(const update_t&) = default; + update_t& operator=(update_t&&) = default; + ~update_t() = default; + // run and prepare static constexpr size_t _get_static_no_of_parameters() { return _parameter_list_t::size::value; @@ -144,62 +130,76 @@ namespace sqlpp return _parameter_list_t::size::value; } - template - std::size_t _run(Db& db) const + template + struct is_table_subset_of_table { - static_assert(not vendor::is_noop::value, "calling set() required before running update"); - static_assert(is_where_t::value, "cannot run update without having a where condition, use .where(true) to update all rows"); + static constexpr bool value = ::sqlpp::detail::is_subset_of::value; + }; + + void _check_consistency() const + { + static_assert(is_where_t<_where_t>::value, "cannot run update without having a where condition, use .where(true) to update all rows"); + + static_assert(is_table_subset_of_table<_update_list_t>::value, "updates require additional tables"); + static_assert(is_table_subset_of_table<_where_t>::value, "where requires additional tables"); + } + + template + std::size_t _run(Database& db) const + { + _check_consistency(); + static_assert(_get_static_no_of_parameters() == 0, "cannot run update directly with parameters, use prepare instead"); return db.update(*this); } - template - auto _prepare(Db& db) const - -> prepared_update_t + template + auto _prepare(Database& db) const + -> prepared_update_t { - static_assert(not vendor::is_noop::value, "calling set() required before running update"); + _check_consistency(); return {{}, db.prepare_update(*this)}; } - Table _table; - Assignments _assignments; - Where _where; + _table_t _table; + _update_list_t _update_list; + _where_t _where; }; namespace vendor { - template - struct interpreter_t> - { - using T = update_t; + template + struct serializer_t> + { + using T = update_t; - static Context& _(const T& t, Context& context) - { - context << "UPDATE "; - interpret(t._table, context); - interpret(t._assignments, context); - interpret(t._where, context); - return context; - } - }; + static Context& _(const T& t, Context& context) + { + context << "UPDATE "; + serialize(t._table, context); + serialize(t._update_list, context); + serialize(t._where, context); + return context; + } + }; } + template + using make_update_t = typename detail::update_policies_t::_statement_t; + template - constexpr update_t update(Table table) + constexpr auto update(Table table) + -> make_update_t> { - return {table}; + return { update_t(), vendor::single_table_t{table} }; } - template - constexpr update_t dynamic_update(const Db&, Table table) + template + constexpr auto dynamic_update(const Database&, Table table) + -> make_update_t> { - return {table}; + return { update_t(), vendor::single_table_t{table} }; } } diff --git a/include/sqlpp11/vendor/assignment.h b/include/sqlpp11/vendor/assignment.h index 5d2cfc67..d8f8ac6b 100644 --- a/include/sqlpp11/vendor/assignment.h +++ b/include/sqlpp11/vendor/assignment.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -30,13 +30,38 @@ #include #include #include -#include +#include +#include #include namespace sqlpp { namespace vendor { + template + struct is_trivial_t + { + static constexpr bool _(const T&) + { + return false; + } + }; + + template + struct is_trivial_t::value, void>::type> + { + static bool _(const T& t) + { + return t._is_trivial(); + } + }; + + template + bool is_trivial(const T& t) + { + return is_trivial_t::_(t); + } + template struct assignment_t { @@ -44,8 +69,9 @@ namespace sqlpp using _column_t = Lhs; using value_type = Rhs; using _parameter_tuple_t = std::tuple<_column_t, Rhs>; + using _table_set = typename ::sqlpp::detail::make_joined_set::type; - static_assert(not std::is_same::value or can_be_null_t<_column_t>::value, "column cannot be null"); + static_assert(can_be_null_t<_column_t>::value ? true : not std::is_same::value, "column must not be null"); assignment_t(_column_t lhs, value_type rhs): _lhs(lhs), @@ -63,15 +89,25 @@ namespace sqlpp }; template - struct interpreter_t> + struct serializer_t> { using T = assignment_t; static Context& _(const T& t, Context& context) { - interpret(simple_column(t._lhs), context); - context << "="; - interpret(t._rhs, context); + if ((trivial_value_is_null_t::value + and is_trivial_t::_(t._rhs)) + or (std::is_same::value)) + { + serialize(simple_column(t._lhs), context); + context << "=NULL"; + } + else + { + serialize(simple_column(t._lhs), context); + context << "="; + serialize(t._rhs, context); + } return context; } }; @@ -83,6 +119,7 @@ namespace sqlpp using _column_t = Lhs; using value_type = tvin_t; using _parameter_tuple_t = std::tuple<_column_t, Rhs>; + using _table_set = typename ::sqlpp::detail::make_joined_set::type; static_assert(can_be_null_t<_column_t>::value, "column cannot be null"); @@ -102,13 +139,13 @@ namespace sqlpp }; template - struct interpreter_t>> + struct serializer_t>> { using T = assignment_t>; static Context& _(const T& t, Context& context) { - interpret(simple_column(t._lhs), context); + serialize(simple_column(t._lhs), context); if (t._rhs._value._is_trivial()) { context << "=NULL"; @@ -116,7 +153,7 @@ namespace sqlpp else { context << "="; - interpret(t._rhs._value, context); + serialize(t._rhs._value, context); } return context; } diff --git a/include/sqlpp11/vendor/char_result_row.h b/include/sqlpp11/vendor/char_result_row.h index abfed8f7..3cf09c12 100644 --- a/include/sqlpp11/vendor/char_result_row.h +++ b/include/sqlpp11/vendor/char_result_row.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, diff --git a/include/sqlpp11/vendor/concat.h b/include/sqlpp11/vendor/concat.h index 232e92d2..c88aae93 100644 --- a/include/sqlpp11/vendor/concat.h +++ b/include/sqlpp11/vendor/concat.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -36,10 +36,11 @@ namespace sqlpp namespace vendor { template - struct concat_t: public First::_value_type::template operators> + struct concat_t: public First::_value_type::template expression_operators> { static_assert(sizeof...(Args) > 0, "concat requires two arguments at least"); - static_assert(sqlpp::detail::and_t::value, "at least one non-text argument detected in concat()"); + static_assert(sqlpp::detail::all_t::value, "at least one non-text argument detected in concat()"); + using _table_set = typename ::sqlpp::detail::make_joined_set::type; struct _value_type: public First::_value_type::_base_value_type { @@ -70,7 +71,7 @@ namespace sqlpp }; template - struct interpreter_t> + struct serializer_t> { using T = concat_t; diff --git a/include/sqlpp11/vendor/expression.h b/include/sqlpp11/vendor/expression.h index 20de7a16..e156a84b 100644 --- a/include/sqlpp11/vendor/expression.h +++ b/include/sqlpp11/vendor/expression.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include namespace sqlpp @@ -40,35 +40,36 @@ namespace sqlpp namespace vendor { template - struct equal_t: public ::sqlpp::detail::boolean::template operators> + struct binary_expression_t: public ::sqlpp::detail::boolean::template expression_operators> { using _value_type = ::sqlpp::detail::boolean; using _parameter_tuple_t = std::tuple; + using _table_set = typename ::sqlpp::detail::make_joined_set::type; - equal_t(Lhs lhs, Rhs rhs): + binary_expression_t(Lhs lhs, Rhs rhs): _lhs(lhs), _rhs(rhs) {} - equal_t(const equal_t&) = default; - equal_t(equal_t&&) = default; - equal_t& operator=(const equal_t&) = default; - equal_t& operator=(equal_t&&) = default; - ~equal_t() = default; + binary_expression_t(const binary_expression_t&) = default; + binary_expression_t(binary_expression_t&&) = default; + binary_expression_t& operator=(const binary_expression_t&) = default; + binary_expression_t& operator=(binary_expression_t&&) = default; + ~binary_expression_t() = default; Lhs _lhs; - tvin_wrap_t _rhs; + maybe_tvin_t _rhs; }; template - struct interpreter_t> + struct serializer_t> { - using T = equal_t; + using T = equal_to_t; static Context& _(const T& t, Context& context) { context << "("; - interpret(t._lhs, context); + serialize(t._lhs, context); if (t._rhs._is_trivial()) { context << " IS NULL"; @@ -76,7 +77,7 @@ namespace sqlpp else { context << "="; - interpret(t._rhs, context); + serialize(t._rhs, context); } context << ")"; return context; @@ -84,35 +85,36 @@ namespace sqlpp }; template - struct not_equal_t: public ::sqlpp::detail::boolean::template operators> + struct binary_expression_t: public ::sqlpp::detail::boolean::template expression_operators> { using _value_type = ::sqlpp::detail::boolean; using _parameter_tuple_t = std::tuple; + using _table_set = typename ::sqlpp::detail::make_joined_set::type; - not_equal_t(Lhs lhs, Rhs rhs): + binary_expression_t(Lhs lhs, Rhs rhs): _lhs(lhs), _rhs(rhs) {} - not_equal_t(const not_equal_t&) = default; - not_equal_t(not_equal_t&&) = default; - not_equal_t& operator=(const not_equal_t&) = default; - not_equal_t& operator=(not_equal_t&&) = default; - ~not_equal_t() = default; + binary_expression_t(const binary_expression_t&) = default; + binary_expression_t(binary_expression_t&&) = default; + binary_expression_t& operator=(const binary_expression_t&) = default; + binary_expression_t& operator=(binary_expression_t&&) = default; + ~binary_expression_t() = default; Lhs _lhs; - tvin_wrap_t _rhs; + maybe_tvin_t _rhs; }; template - struct interpreter_t> + struct serializer_t> { - using T = not_equal_t; + using T = not_equal_to_t; static Context& _(const T& t, Context& context) { context << "("; - interpret(t._lhs, context); + serialize(t._lhs, context); if (t._rhs._is_trivial()) { context << " IS NOT NULL"; @@ -120,54 +122,56 @@ namespace sqlpp else { context << "!="; - interpret(t._rhs, context); + serialize(t._rhs, context); } context << ")"; return context; } }; - template - struct logical_not_t: public ::sqlpp::detail::boolean::template operators> + template + struct unary_expression_t: public ::sqlpp::detail::boolean::template expression_operators> { using _value_type = ::sqlpp::detail::boolean; - using _parameter_tuple_t = std::tuple; + using _parameter_tuple_t = std::tuple; + using _table_set = typename Rhs::_table_set; - logical_not_t(Lhs l): - _lhs(l) + unary_expression_t(Rhs rhs): + _rhs(rhs) {} - logical_not_t(const logical_not_t&) = default; - logical_not_t(logical_not_t&&) = default; - logical_not_t& operator=(const logical_not_t&) = default; - logical_not_t& operator=(logical_not_t&&) = default; - ~logical_not_t() = default; + unary_expression_t(const unary_expression_t&) = default; + unary_expression_t(unary_expression_t&&) = default; + unary_expression_t& operator=(const unary_expression_t&) = default; + unary_expression_t& operator=(unary_expression_t&&) = default; + ~unary_expression_t() = default; - Lhs _lhs; + Rhs _rhs; }; - template - struct interpreter_t> + template + struct serializer_t> { - using T = logical_not_t; + using T = logical_not_t; static Context& _(const T& t, Context& context) { context << "("; context << "NOT "; - interpret(t._lhs, context); + serialize(t._lhs, context); context << ")"; return context; } }; template - struct binary_expression_t: public O::_value_type::template operators> + struct binary_expression_t: public O::_value_type::template expression_operators> { using _lhs_t = Lhs; using _rhs_t = Rhs; using _value_type = typename O::_value_type; using _parameter_tuple_t = std::tuple<_lhs_t, _rhs_t>; + using _table_set = typename ::sqlpp::detail::make_joined_set::type; binary_expression_t(_lhs_t lhs, _rhs_t rhs): _lhs(lhs), @@ -185,26 +189,27 @@ namespace sqlpp }; template - struct interpreter_t> + struct serializer_t> { using T = binary_expression_t; static Context& _(const T& t, Context& context) { context << "("; - interpret(t._lhs, context); + serialize(t._lhs, context); context << O::_name; - interpret(t._rhs, context); + serialize(t._rhs, context); context << ")"; return context; } }; template - struct unary_expression_t: public O::_value_type::template operators> + struct unary_expression_t: public O::_value_type::template expression_operators> { using _value_type = typename O::_value_type; using _parameter_tuple_t = std::tuple; + using _table_set = typename Rhs::_table_set; unary_expression_t(Rhs rhs): _rhs(rhs) @@ -220,7 +225,7 @@ namespace sqlpp }; template - struct interpreter_t> + struct serializer_t> { using T = unary_expression_t; @@ -228,7 +233,7 @@ namespace sqlpp { context << "("; context << O::_name; - interpret(t._rhs, context); + serialize(t._rhs, context); context << ")"; return context; } diff --git a/include/sqlpp11/vendor/expression_fwd.h b/include/sqlpp11/vendor/expression_fwd.h index 0cf2cfab..66b446c5 100644 --- a/include/sqlpp11/vendor/expression_fwd.h +++ b/include/sqlpp11/vendor/expression_fwd.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -31,18 +31,9 @@ namespace sqlpp { namespace vendor { - template - struct equal_t; - - template - struct not_equal_t; - - template - struct logical_not_t; - namespace tag { - struct less_than + struct less { using _value_type = ::sqlpp::detail::boolean; static constexpr const char* _name = "<"; @@ -54,13 +45,23 @@ namespace sqlpp static constexpr const char* _name = "<="; }; + struct equal_to + { + using _value_type = ::sqlpp::detail::boolean; + }; + + struct not_equal_to + { + using _value_type = ::sqlpp::detail::boolean; + }; + struct greater_equal { using _value_type = ::sqlpp::detail::boolean; static constexpr const char* _name = ">="; }; - struct greater_than + struct greater { using _value_type = ::sqlpp::detail::boolean; static constexpr const char* _name = ">"; @@ -78,6 +79,11 @@ namespace sqlpp static constexpr const char* _name = " AND "; }; + struct logical_not + { + using _value_type = ::sqlpp::detail::boolean; + }; + template struct plus { @@ -133,13 +139,19 @@ namespace sqlpp struct unary_expression_t; template - using less_than_t = binary_expression_t; + using less_than_t = binary_expression_t; template using less_equal_t = binary_expression_t; template - using greater_than_t = binary_expression_t; + using equal_to_t = binary_expression_t; + + template + using not_equal_to_t = binary_expression_t; + + template + using greater_than_t = binary_expression_t; template using greater_equal_t = binary_expression_t; @@ -165,6 +177,9 @@ namespace sqlpp template using modulus_t = binary_expression_t; + template + using logical_not_t = unary_expression_t; + template using unary_plus_t = unary_expression_t, Rhs>; diff --git a/include/sqlpp11/vendor/extra_tables.h b/include/sqlpp11/vendor/extra_tables.h new file mode 100644 index 00000000..0b91ad7a --- /dev/null +++ b/include/sqlpp11/vendor/extra_tables.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2013-2014, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLPP_EXTRA_TABLES_H +#define SQLPP_EXTRA_TABLES_H + +#include +#include +#include + +namespace sqlpp +{ + namespace vendor + { + // EXTRA_TABLES + template + struct extra_tables_t + { + using _is_extra_tables = std::true_type; + + static_assert(sizeof...(Tables), "at least one table or join argument required in extra_tables()"); + + static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in extra_tables()"); + + static_assert(::sqlpp::detail::all_t::value, "at least one argument is not a table or join in extra_tables()"); + + using _table_set = ::sqlpp::detail::make_joined_set_t; + + + extra_tables_t() + {} + + extra_tables_t(const extra_tables_t&) = default; + extra_tables_t(extra_tables_t&&) = default; + extra_tables_t& operator=(const extra_tables_t&) = default; + extra_tables_t& operator=(extra_tables_t&&) = default; + ~extra_tables_t() = default; + + template + struct _methods_t + { + }; + }; + + struct no_extra_tables_t + { + using _is_noop = std::true_type; + using _table_set = ::sqlpp::detail::type_set<>; + + template + struct _methods_t + { + template + using _new_statement_t = typename Policies::template _new_statement_t; + + template + auto extra_tables(Args...) + -> _new_statement_t> + { + return { *static_cast(this), extra_tables_t{} }; + } + }; + }; + + // Interpreters + template + struct serializer_t> + { + using T = extra_tables_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; + + template + struct serializer_t + { + using T = no_extra_tables_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; + + } +} + +#endif diff --git a/include/sqlpp11/vendor/field.h b/include/sqlpp11/vendor/field.h index cf816b77..7cd6ec62 100644 --- a/include/sqlpp11/vendor/field.h +++ b/include/sqlpp11/vendor/field.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -33,11 +33,12 @@ namespace sqlpp { namespace vendor { - template + template struct field_t { using _name_t = NameType; using _value_type = ValueType; + static constexpr bool _trivial_value_is_null = TrivialValueIsNull; }; template @@ -50,11 +51,13 @@ namespace sqlpp template struct make_field_t_impl { - using type = field_t; + using type = field_t::value>; }; template - struct make_field_t_impl>> + struct make_field_t_impl> { using type = multi_field_t::type...>>; }; diff --git a/include/sqlpp11/vendor/from.h b/include/sqlpp11/vendor/from.h index 11e8c999..6949cfee 100644 --- a/include/sqlpp11/vendor/from.h +++ b/include/sqlpp11/vendor/from.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -27,63 +27,132 @@ #ifndef SQLPP_FROM_H #define SQLPP_FROM_H -#include #include #include #include #include +#include namespace sqlpp { namespace vendor { - template + // FROM + template struct from_t { using _is_from = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; - // ensure one argument at least - static_assert(_is_dynamic::value or sizeof...(TableOrJoin), "at least one table or join argument required in from()"); - - // check for duplicate arguments - static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in from()"); - - // check for invalid arguments - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not a table or join in from()"); + static_assert(_is_dynamic::value or sizeof...(Tables), "at least one table or join argument required in from()"); // FIXME: Joins contain two tables. This is not being dealt with at the moment when looking at duplicates, for instance + static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in from()"); - template - void add(Table table) + static_assert(::sqlpp::detail::all_t::value, "at least one argument is not a table or join in from()"); + + using _table_set = ::sqlpp::detail::make_joined_set_t; + + + from_t(Tables... tables): + _tables(tables...) + {} + + from_t(const from_t&) = default; + from_t(from_t&&) = default; + from_t& operator=(const from_t&) = default; + from_t& operator=(from_t&&) = default; + ~from_t() = default; + + template + struct _methods_t { - static_assert(is_table_t
::value, "from arguments require to be tables or joins"); - _dynamic_tables.emplace_back(table); - } + template + void add_from(Table table) + { + static_assert(_is_dynamic::value, "add_from must not be called for static from()"); + static_assert(is_table_t
::value, "invalid table argument in add_from()"); - std::tuple _tables; + using ok = ::sqlpp::detail::all_t>; + + _add_from_impl(table, ok()); // dispatch to prevent compile messages after the static_assert + } + + private: + template + void _add_from_impl(Table table, const std::true_type&) + { + return static_cast(this)->_from._dynamic_tables.emplace_back(table); + } + + template + void _add_from_impl(Table table, const std::false_type&); + }; + + std::tuple _tables; vendor::interpretable_list_t _dynamic_tables; }; - template - struct interpreter_t> + struct no_from_t + { + using _is_noop = std::true_type; + using _table_set = ::sqlpp::detail::type_set<>; + + template + struct _methods_t + { + using _database_t = typename Policies::_database_t; + template + using _new_statement_t = typename Policies::template _new_statement_t; + + template + auto from(Args... args) + -> _new_statement_t> + { + return { *static_cast(this), from_t{args...} }; + } + + template + auto dynamic_from(Args... args) + -> _new_statement_t> + { + static_assert(not std::is_same<_database_t, void>::value, "dynamic_from must not be called in a static statement"); + return { *static_cast(this), vendor::from_t<_database_t, Args...>{args...} }; + } + }; + }; + + // Interpreters + template + struct serializer_t> { - using T = from_t; + using T = from_t; static Context& _(const T& t, Context& context) { - if (sizeof...(TableOrJoin) == 0 and t._dynamic_tables.empty()) + if (sizeof...(Tables) == 0 and t._dynamic_tables.empty()) return context; context << " FROM "; interpret_tuple(t._tables, ',', context); - if (sizeof...(TableOrJoin) and not t._dynamic_tables.empty()) + if (sizeof...(Tables) and not t._dynamic_tables.empty()) context << ','; interpret_list(t._dynamic_tables, ',', context); return context; } }; - } + template + struct serializer_t + { + using T = no_from_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; + + } } #endif diff --git a/include/sqlpp11/vendor/group_by.h b/include/sqlpp11/vendor/group_by.h index ca8e2e5e..6d3dfba1 100644 --- a/include/sqlpp11/vendor/group_by.h +++ b/include/sqlpp11/vendor/group_by.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -32,57 +32,136 @@ #include #include #include +#include #include namespace sqlpp { namespace vendor { - template + // GROUP BY + template struct group_by_t { using _is_group_by = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; - using _parameter_tuple_t = std::tuple; + using _parameter_tuple_t = std::tuple; + using _parameter_list_t = typename make_parameter_list_t<_parameter_tuple_t>::type; - // ensure one argument at least - static_assert(_is_dynamic::value or sizeof...(Expr), "at least one expression (e.g. a column) required in group_by()"); + using _table_set = typename ::sqlpp::detail::make_joined_set::type; - // check for duplicate expressions - static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in group_by()"); + static_assert(_is_dynamic::value or sizeof...(Expressions), "at least one expression (e.g. a column) required in group_by()"); - // check for invalid expressions - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not an expression in group_by()"); + static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in group_by()"); - template - void add(E expr) + static_assert(::sqlpp::detail::all_t::value, "at least one argument is not an expression in group_by()"); + + group_by_t(Expressions... expressions): + _expressions(expressions...) + {} + + group_by_t(const group_by_t&) = default; + group_by_t(group_by_t&&) = default; + group_by_t& operator=(const group_by_t&) = default; + group_by_t& operator=(group_by_t&&) = default; + ~group_by_t() = default; + + template + struct _methods_t { - static_assert(is_table_t::value, "from arguments require to be tables or joins"); - _dynamic_expressions.emplace_back(expr); - } + template + void add_group_by_ntc(Expression expression) + { + add_group_by(expression); + } + template + void add_group_by(Expression expression) + { + static_assert(_is_dynamic::value, "add_group_by must not be called for static group_by"); + static_assert(is_expression_t::value, "invalid expression argument in add_group_by()"); + static_assert(TableCheckRequired::value or Policies::template _no_unknown_tables::value, "expression uses tables unknown to this statement in add_group_by()"); + + using ok = ::sqlpp::detail::all_t>; + + _add_group_by_impl(expression, ok()); // dispatch to prevent compile messages after the static_assert + } + + private: + template + void _add_group_by_impl(Expression expression, const std::true_type&) + { + return static_cast(this)->_group_by._dynamic_expressions.emplace_back(expression); + } + + template + void _add_group_by_impl(Expression expression, const std::false_type&); + }; + + const group_by_t& _group_by() const { return *this; } _parameter_tuple_t _expressions; vendor::interpretable_list_t _dynamic_expressions; - }; - template - struct interpreter_t> + struct no_group_by_t + { + using _is_noop = std::true_type; + using _table_set = ::sqlpp::detail::type_set<>; + + template + struct _methods_t + { + using _database_t = typename Policies::_database_t; + template + using _new_statement_t = typename Policies::template _new_statement_t; + + template + auto group_by(Args... args) + -> _new_statement_t> + { + return { *static_cast(this), group_by_t{args...} }; + } + + template + auto dynamic_group_by(Args... args) + -> _new_statement_t> + { + static_assert(not std::is_same<_database_t, void>::value, "dynamic_group_by must not be called in a static statement"); + return { *static_cast(this), vendor::group_by_t<_database_t, Args...>{args...} }; + } + }; + }; + + // Interpreters + template + struct serializer_t> { - using T = group_by_t; + using T = group_by_t; static Context& _(const T& t, Context& context) { - if (sizeof...(Expr) == 0 and t._dynamic_expressions.empty()) + if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty()) return context; context << " GROUP BY "; interpret_tuple(t._expressions, ',', context); - if (sizeof...(Expr) and not t._dynamic_expressions.empty()) + if (sizeof...(Expressions) and not t._dynamic_expressions.empty()) context << ','; interpret_list(t._dynamic_expressions, ',', context); return context; } }; + + template + struct serializer_t + { + using T = no_group_by_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; + } } diff --git a/include/sqlpp11/vendor/having.h b/include/sqlpp11/vendor/having.h index e9a474df..20beeb97 100644 --- a/include/sqlpp11/vendor/having.h +++ b/include/sqlpp11/vendor/having.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -31,52 +31,133 @@ #include #include #include +#include #include namespace sqlpp { namespace vendor { - template + // HAVING + template struct having_t { using _is_having = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; - using _parameter_tuple_t = std::tuple; + using _parameter_tuple_t = std::tuple; - static_assert(_is_dynamic::value or sizeof...(Expr), "at least one expression argument required in having()"); - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not an expression in having()"); + static_assert(_is_dynamic::value or sizeof...(Expressions), "at least one expression argument required in having()"); + static_assert(::sqlpp::detail::all_t::value, "at least one argument is not an expression in having()"); using _parameter_list_t = typename make_parameter_list_t<_parameter_tuple_t>::type; - template - void add(E expr) + using _table_set = typename ::sqlpp::detail::make_joined_set::type; + + having_t(Expressions... expressions): + _expressions(expressions...) + {} + + having_t(const having_t&) = default; + having_t(having_t&&) = default; + having_t& operator=(const having_t&) = default; + having_t& operator=(having_t&&) = default; + ~having_t() = default; + + template + struct _methods_t { - static_assert(is_expression_t::value, "invalid expression argument in add_having()"); - _dynamic_expressions.emplace_back(expr); - } + template + void add_having_ntc(Expression expression) + { + add_having(expression); + } + + template + void add_having(Expression expression) + { + static_assert(_is_dynamic::value, "add_having must not be called for static having"); + static_assert(is_expression_t::value, "invalid expression argument in add_having()"); + static_assert(TableCheckRequired::value or Policies::template _no_unknown_tables::value, "expression uses tables unknown to this statement in add_having()"); + + using ok = ::sqlpp::detail::all_t>; + + _add_having_impl(expression, ok()); // dispatch to prevent compile messages after the static_assert + } + + private: + template + void _add_having_impl(Expression expression, const std::true_type&) + { + return static_cast(this)->_having._dynamic_expressions.emplace_back(expression); + } + + template + void _add_having_impl(Expression expression, const std::false_type&); + }; _parameter_tuple_t _expressions; vendor::interpretable_list_t _dynamic_expressions; }; - template - struct interpreter_t> + struct no_having_t + { + using _is_noop = std::true_type; + using _table_set = ::sqlpp::detail::type_set<>; + + template + struct _methods_t + { + using _database_t = typename Policies::_database_t; + template + using _new_statement_t = typename Policies::template _new_statement_t; + + template + auto having(Args... args) + -> _new_statement_t> + { + return { *static_cast(this), having_t{args...} }; + } + + template + auto dynamic_having(Args... args) + -> _new_statement_t> + { + static_assert(not std::is_same<_database_t, void>::value, "dynamic_having must not be called in a static statement"); + return { *static_cast(this), vendor::having_t<_database_t, Args...>{args...} }; + } + }; + }; + + // Interpreters + template + struct serializer_t> { - using T = having_t; + using T = having_t; static Context& _(const T& t, Context& context) { - if (sizeof...(Expr) == 0 and t._dynamic_expressions.empty()) + if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty()) return context; context << " HAVING "; interpret_tuple(t._expressions, " AND ", context); - if (sizeof...(Expr) and not t._dynamic_expressions.empty()) + if (sizeof...(Expressions) and not t._dynamic_expressions.empty()) context << " AND "; interpret_list(t._dynamic_expressions, " AND ", context); return context; } }; + + template + struct serializer_t + { + using T = no_having_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; + } } diff --git a/include/sqlpp11/vendor/in.h b/include/sqlpp11/vendor/in.h index 993a3288..1979264b 100644 --- a/include/sqlpp11/vendor/in.h +++ b/include/sqlpp11/vendor/in.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -37,7 +37,7 @@ namespace sqlpp namespace vendor { template - struct in_t: public boolean::template operators> + struct in_t: public boolean::template expression_operators> { static constexpr bool _inverted = not NotInverted; static_assert(sizeof...(Args) > 0, "in() requires at least one argument"); @@ -56,6 +56,7 @@ namespace sqlpp T in; }; }; + using _table_set = typename ::sqlpp::detail::make_joined_set::type; in_t(Operand operand, Args... args): _operand(operand), @@ -73,13 +74,13 @@ namespace sqlpp }; template - struct interpreter_t> + struct serializer_t> { using T = vendor::in_t; static Context& _(const T& t, Context& context) { - interpret(t._operand, context); + serialize(t._operand, context); context << (t._inverted ? " NOT IN(" : " IN("); interpret_tuple(t._args, ',', context); context << ')'; diff --git a/include/sqlpp11/vendor/in_fwd.h b/include/sqlpp11/vendor/in_fwd.h index b33aee1c..809c4cc2 100644 --- a/include/sqlpp11/vendor/in_fwd.h +++ b/include/sqlpp11/vendor/in_fwd.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, diff --git a/include/sqlpp11/vendor/insert_list.h b/include/sqlpp11/vendor/insert_list.h deleted file mode 100644 index 2d30390f..00000000 --- a/include/sqlpp11/vendor/insert_list.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2013, Roland Bock - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SQLPP_INSERT_LIST_H -#define SQLPP_INSERT_LIST_H - -#include -#include -#include -#include -#include - -namespace sqlpp -{ - namespace vendor - { - struct insert_default_values_t - { - using _is_insert_list = std::true_type; - using _is_dynamic = std::false_type; - }; - - template - struct interpreter_t - { - using T = insert_default_values_t; - - static Context& _(const T& t, Context& context) - { - context << " DEFAULT VALUES"; - return context; - } - }; - - template - struct insert_list_t - { - using _is_insert_list = std::true_type; - using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; - using _parameter_tuple_t = std::tuple; - template class Target> - using copy_assignments_t = Target; // FIXME: Nice idea to copy variadic template arguments? - template class Target, template class Wrap> - using copy_wrapped_assignments_t = Target...>; - - // check for at least one order expression - static_assert(_is_dynamic::value or sizeof...(Assignments), "at least one select expression required in set()"); - - // check for duplicate assignments - static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in set()"); - - // check for invalid assignments - static_assert(sqlpp::detail::and_t::value, "at least one argument is not an assignment in set()"); - - // check for prohibited assignments - static_assert(not sqlpp::detail::or_t::value, "at least one assignment is prohibited by its column definition in set()"); - - insert_list_t(Assignments... assignment): - _assignments(assignment...), - _columns({assignment._lhs}...), - _values(assignment._rhs...) - {} - - insert_list_t(const insert_list_t&) = default; - insert_list_t(insert_list_t&&) = default; - insert_list_t& operator=(const insert_list_t&) = default; - insert_list_t& operator=(insert_list_t&&) = default; - ~insert_list_t() = default; - - template - void add(Assignment assignment) - { - static_assert(is_assignment_t::value, "set() arguments require to be assigments"); - static_assert(not must_not_insert_t::value, "set() argument must not be used in insert"); - _dynamic_columns.emplace_back(simple_column_t{assignment._lhs}); - _dynamic_values.emplace_back(assignment._rhs); - } - - - std::tuple...> _columns; - std::tuple _values; - std::tuple _assignments; // FIXME: Need to replace _columns and _values by _assignments (connector-container requires assignments) - typename vendor::interpretable_list_t _dynamic_columns; - typename vendor::interpretable_list_t _dynamic_values; - }; - - template - struct interpreter_t> - { - using T = insert_list_t; - - static Context& _(const T& t, Context& context) - { - if (sizeof...(Assignments) + t._dynamic_columns.size() == 0) - { - interpret(insert_default_values_t(), context); - } - else - { - context << " ("; - interpret_tuple(t._columns, ",", context); - if (sizeof...(Assignments) and not t._dynamic_columns.empty()) - context << ','; - interpret_list(t._dynamic_columns, ',', context); - context << ") VALUES("; - interpret_tuple(t._values, ",", context); - if (sizeof...(Assignments) and not t._dynamic_values.empty()) - context << ','; - interpret_list(t._dynamic_values, ',', context); - context << ")"; - } - return context; - } - }; - } -} - -#endif diff --git a/include/sqlpp11/vendor/insert_value.h b/include/sqlpp11/vendor/insert_value.h index 88559474..dfcc97ba 100644 --- a/include/sqlpp11/vendor/insert_value.h +++ b/include/sqlpp11/vendor/insert_value.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -31,7 +31,8 @@ #include #include #include -#include +#include +#include namespace sqlpp { @@ -43,6 +44,7 @@ namespace sqlpp struct type_if { using type = Type; + using _table_set = typename Type::_table_set; }; template @@ -50,6 +52,7 @@ namespace sqlpp { struct type { + using _table_set = sqlpp::detail::type_set<>; }; }; } @@ -99,7 +102,7 @@ namespace sqlpp }; template - struct interpreter_t> + struct serializer_t> { using T = insert_value_t; @@ -110,7 +113,7 @@ namespace sqlpp else if (t._is_default) context << "DEFAULT"; else - interpret(t._value, context); + serialize(t._value, context); return context; } }; diff --git a/include/sqlpp11/vendor/insert_value_list.h b/include/sqlpp11/vendor/insert_value_list.h index 76fc1552..7f450792 100644 --- a/include/sqlpp11/vendor/insert_value_list.h +++ b/include/sqlpp11/vendor/insert_value_list.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -29,62 +29,242 @@ #include #include -#include +#include +#include #include +#include +#include namespace sqlpp { namespace vendor { - template - struct insert_value_list_t + // COLUMN AND VALUE LIST + struct insert_default_values_t + { + using _table_set = ::sqlpp::detail::type_set<>; + using _is_dynamic = std::false_type; + + template + struct _methods_t + {}; + }; + + template + struct insert_list_t { - using _is_insert_value_list = std::true_type; + using _is_insert_list = std::true_type; + using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; + using _parameter_tuple_t = std::tuple; + template class Target> + using copy_assignments_t = Target; // FIXME: Nice idea to copy variadic template arguments? + template class Target, template class Wrap> + using copy_wrapped_assignments_t = Target...>; - static_assert(sizeof...(InsertValues), "at least one insert value required"); + static_assert(_is_dynamic::value or sizeof...(Assignments), "at least one select expression required in set()"); - // check for invalid arguments - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not an insert value"); + static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in set()"); - using _value_tuple_t = std::tuple; + static_assert(sqlpp::detail::all_t::value, "at least one argument is not an assignment in set()"); - void add(_value_tuple_t value_tuple) - { - _insert_values.emplace_back(value_tuple); - } + static_assert(not sqlpp::detail::any_t::value, "at least one assignment is prohibited by its column definition in set()"); + + using _column_table_set = typename ::sqlpp::detail::make_joined_set::type; + using _value_table_set = typename ::sqlpp::detail::make_joined_set::type; + using _table_set = typename ::sqlpp::detail::make_joined_set<_column_table_set, _value_table_set>::type; + static_assert(sizeof...(Assignments) ? (_column_table_set::size::value == 1) : true, "set() contains assignments for tables from several columns"); + static_assert(::sqlpp::detail::is_subset_of<_value_table_set, _column_table_set>::value, "set() contains values from foreign tables"); + + insert_list_t(Assignments... assignment): + _assignments(assignment...), + _columns({assignment._lhs}...), + _values(assignment._rhs...) + {} + + insert_list_t(const insert_list_t&) = default; + insert_list_t(insert_list_t&&) = default; + insert_list_t& operator=(const insert_list_t&) = default; + insert_list_t& operator=(insert_list_t&&) = default; + ~insert_list_t() = default; + + template + struct _methods_t + { + template + void add_set(Assignment assignment) + { + static_assert(_is_dynamic::value, "add_set must not be called for static from()"); + static_assert(is_assignment_t::value, "add_set() arguments require to be assigments"); + static_assert(not must_not_insert_t::value, "add_set() argument must not be used in insert"); + using _column_table_set = typename Assignment::_column_t::_table_set; + using _value_table_set = typename Assignment::value_type::_table_set; + static_assert(::sqlpp::detail::is_subset_of<_value_table_set, typename Policies::_table_set>::value, "add_set() contains a column from a foreign table"); + static_assert(::sqlpp::detail::is_subset_of<_column_table_set, typename Policies::_table_set>::value, "add_set() contains a value from a foreign table"); + + using ok = ::sqlpp::detail::all_t, + ::sqlpp::detail::not_t, + ::sqlpp::detail::is_subset_of<_value_table_set, typename Policies::_table_set>, + ::sqlpp::detail::is_subset_of<_column_table_set, typename Policies::_table_set>>; + + _add_set_impl(assignment, ok()); // dispatch to prevent compile messages after the static_assert + } + + private: + template + void _add_set_impl(Assignment assignment, const std::true_type&) + { + static_cast(this)->_insert_value_list._dynamic_columns.emplace_back(simple_column_t{assignment._lhs}); + static_cast(this)->_insert_value_list._dynamic_values.emplace_back(assignment._rhs); + } + + template + void _add_set_impl(Assignment assignment, const std::false_type&); + }; + + + + std::tuple...> _columns; + std::tuple _values; + std::tuple _assignments; // FIXME: Need to replace _columns and _values by _assignments (connector-container requires assignments) + typename vendor::interpretable_list_t _dynamic_columns; + typename vendor::interpretable_list_t _dynamic_values; + }; + + template + struct column_list_t + { + using _is_column_list = std::true_type; + using _parameter_tuple_t = std::tuple; + + static_assert(sizeof...(Columns), "at least one column required in columns()"); + + static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in columns()"); + + static_assert(::sqlpp::detail::all_t::value, "at least one argument is not a column in columns()"); + + static_assert(not ::sqlpp::detail::any_t::value, "at least one column argument has a must_not_insert flag in its definition"); + + using _value_tuple_t = std::tuple...>; + using _table_set = typename ::sqlpp::detail::make_joined_set::type; + + static_assert(_table_set::size::value == 1, "columns from multiple tables in columns()"); + + column_list_t(Columns... columns): + _columns(simple_column_t{columns}...) + {} + + column_list_t(const column_list_t&) = default; + column_list_t(column_list_t&&) = default; + column_list_t& operator=(const column_list_t&) = default; + column_list_t& operator=(column_list_t&&) = default; + ~column_list_t() = default; + + template + struct _methods_t + { + template + void add_values(Assignments... assignments) + { + static_assert(::sqlpp::detail::all_t::value, "add_values() arguments have to be assignments"); + using _arg_value_tuple = std::tuple...>; + using _args_correct = std::is_same<_arg_value_tuple, _value_tuple_t>; + static_assert(_args_correct::value, "add_values() arguments do not match columns() arguments"); + + using ok = ::sqlpp::detail::all_t, + _args_correct>; + + _add_values_impl(ok(), assignments...); // dispatch to prevent compile messages after the static_assert + } + + private: + template + void _add_values_impl(const std::true_type&, Assignments... assignments) + { + return static_cast(this)->_insert_value_list._insert_values.emplace_back(vendor::insert_value_t{assignments}...); + } + + template + void _add_values_impl(const std::false_type&, Assignments... assignments); + }; bool empty() const { return _insert_values.empty(); } + std::tuple...> _columns; std::vector<_value_tuple_t> _insert_values; + }; - template<> - struct insert_value_list_t - { - using _is_insert_value_list = std::true_type; + struct no_insert_value_list_t + { + using _is_noop = std::true_type; + using _table_set = ::sqlpp::detail::type_set<>; - using _value_tuple_t = std::tuple<>; - - void add(_value_tuple_t value_tuple) + template + struct _methods_t { - } + using _database_t = typename Policies::_database_t; + template + using _new_statement_t = typename Policies::template _new_statement_t; - static constexpr bool empty() - { - return true; - } - }; + auto default_values() + -> _new_statement_t + { + return { *static_cast(this), insert_default_values_t{} }; + } - template - struct interpreter_t> + template + auto columns(Args... args) + -> _new_statement_t> + { + return { *static_cast(this), column_list_t{args...} }; + } + + template + auto set(Args... args) + -> _new_statement_t> + { + return { *static_cast(this), insert_list_t{args...} }; + } + + template + auto dynamic_set(Args... args) + -> _new_statement_t> + { + static_assert(not std::is_same<_database_t, void>::value, "dynamic_set must not be called in a static statement"); + return { *static_cast(this), vendor::insert_list_t<_database_t, Args...>{args...} }; + } + }; + }; + + // Interpreters + template + struct serializer_t { - using T = insert_value_list_t; + using T = insert_default_values_t; static Context& _(const T& t, Context& context) { + context << " DEFAULT VALUES"; + return context; + } + }; + + template + struct serializer_t> + { + using T = column_list_t; + + static Context& _(const T& t, Context& context) + { + context << " ("; + interpret_tuple(t._columns, ",", context); + context << ")"; context << " VALUES "; bool first = true; for (const auto& row : t._insert_values) @@ -97,20 +277,51 @@ namespace sqlpp interpret_tuple(row, ",", context); context << ')'; } + + return context; + } + }; + + template + struct serializer_t> + { + using T = insert_list_t; + + static Context& _(const T& t, Context& context) + { + if (sizeof...(Assignments) + t._dynamic_columns.size() == 0) + { + serialize(insert_default_values_t(), context); + } + else + { + context << " ("; + interpret_tuple(t._columns, ",", context); + if (sizeof...(Assignments) and not t._dynamic_columns.empty()) + context << ','; + interpret_list(t._dynamic_columns, ',', context); + context << ") VALUES("; + interpret_tuple(t._values, ",", context); + if (sizeof...(Assignments) and not t._dynamic_values.empty()) + context << ','; + interpret_list(t._dynamic_values, ',', context); + context << ")"; + } return context; } }; template - struct interpreter_t> + struct serializer_t { - using T = insert_value_list_t; + using T = no_insert_value_list_t; static Context& _(const T& t, Context& context) { return context; } }; + } } diff --git a/include/sqlpp11/vendor/interpret_tuple.h b/include/sqlpp11/vendor/interpret_tuple.h index 36e2b598..9c067627 100644 --- a/include/sqlpp11/vendor/interpret_tuple.h +++ b/include/sqlpp11/vendor/interpret_tuple.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -28,8 +28,8 @@ #define SQLPP_INTERPRET_TUPLE_H #include -#include #include +#include namespace sqlpp { @@ -54,7 +54,7 @@ namespace sqlpp using entry_type = typename std::tuple_element::type; if (requires_braces_t::value) context << "("; - interpret(entry, context); + serialize(entry, context); if (requires_braces_t::value) context << ")"; _impl(t, separator, context, type()); diff --git a/include/sqlpp11/vendor/interpretable.h b/include/sqlpp11/vendor/interpretable.h index e6337da8..a190f04e 100644 --- a/include/sqlpp11/vendor/interpretable.h +++ b/include/sqlpp11/vendor/interpretable.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -28,8 +28,9 @@ #define SQLPP_INTERPRETABLE_H #include -#include +#include #include +#include #include namespace sqlpp @@ -39,7 +40,8 @@ namespace sqlpp template struct interpretable_t { - using _context_t = typename Db::_context_t; + using _serializer_context_t = typename Db::_serializer_context_t; + using _interpreter_context_t = typename Db::_interpreter_context_t; template interpretable_t(T t): @@ -52,12 +54,21 @@ namespace sqlpp interpretable_t& operator=(interpretable_t&&) = default; ~interpretable_t() = default; - sqlpp::serializer_t& interpret(sqlpp::serializer_t& context) const + sqlpp::serializer_context_t& serialize(sqlpp::serializer_context_t& context) const { - return _impl->interpret(context); + return _impl->serialize(context); } - _context_t& interpret(_context_t& context) const + // This method only exists if Db::_serializer_context_t and sqlpp::serializer_context_t are not the same + template + auto serialize(Context& context) const + -> typename std::enable_if::value + and not std::is_same::value, Context&>::type + { + return _impl->db_serialize(context); + } + + _interpreter_context_t& interpret(_interpreter_context_t& context) const { return _impl->interpret(context); } @@ -65,8 +76,9 @@ namespace sqlpp private: struct _impl_base { - virtual sqlpp::serializer_t& interpret(sqlpp::serializer_t& context) const = 0; - virtual _context_t& interpret(_context_t& context) const = 0; + virtual sqlpp::serializer_context_t& serialize(sqlpp::serializer_context_t& context) const = 0; + virtual _serializer_context_t& db_serialize(_serializer_context_t& context) const = 0; + virtual _interpreter_context_t& interpret(_interpreter_context_t& context) const = 0; }; template @@ -77,15 +89,21 @@ namespace sqlpp _t(t) {} - sqlpp::serializer_t& interpret(sqlpp::serializer_t& context) const + sqlpp::serializer_context_t& serialize(sqlpp::serializer_context_t& context) const { - sqlpp::interpret(_t, context); + sqlpp::serialize(_t, context); return context; } - _context_t& interpret(_context_t& context) const + _serializer_context_t& db_serialize(_serializer_context_t& context) const { - sqlpp::interpret(_t, context); + Db::_serialize_interpretable(_t, context); + return context; + } + + _interpreter_context_t& interpret(_interpreter_context_t& context) const + { + Db::_interpret_interpretable(_t, context); return context; } @@ -96,13 +114,13 @@ namespace sqlpp }; template - struct interpreter_t> + struct serializer_t> { using T = interpretable_t; static Context& _(const T& t, Context& context) { - t.interpret(context); + t.serialize(context); return context; } }; diff --git a/include/sqlpp11/vendor/interpretable_list.h b/include/sqlpp11/vendor/interpretable_list.h index 94d2a35b..a6b2d27e 100644 --- a/include/sqlpp11/vendor/interpretable_list.h +++ b/include/sqlpp11/vendor/interpretable_list.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -60,9 +60,6 @@ namespace sqlpp template<> struct interpretable_list_t { - template - void emplace_back(const T&) {} - static constexpr std::size_t size() { return 0; @@ -91,7 +88,7 @@ namespace sqlpp context << separator; first = false; } - interpret(entry, context); + serialize(entry, context); } return context; } diff --git a/include/sqlpp11/vendor/interpreter.h b/include/sqlpp11/vendor/interpreter.h index 547d7ebd..17dd6075 100644 --- a/include/sqlpp11/vendor/interpreter.h +++ b/include/sqlpp11/vendor/interpreter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -24,8 +24,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SQLPP_VENDOR_INTERPRET_H -#define SQLPP_VENDOR_INTERPRET_H +#ifndef SQLPP_VENDOR_INTERPRETER_H +#define SQLPP_VENDOR_INTERPRETER_H #include diff --git a/include/sqlpp11/vendor/is_null.h b/include/sqlpp11/vendor/is_null.h index 7b7dab61..2b963134 100644 --- a/include/sqlpp11/vendor/is_null.h +++ b/include/sqlpp11/vendor/is_null.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -36,9 +36,10 @@ namespace sqlpp namespace vendor { template - struct is_null_t: public boolean::template operators> + struct is_null_t: public boolean::template expression_operators> { static constexpr bool _inverted = not NotInverted; + using _table_set = typename Operand::_table_set; struct _value_type: public boolean { @@ -69,13 +70,13 @@ namespace sqlpp }; template - struct interpreter_t> + struct serializer_t> { using T = ::sqlpp::vendor::is_null_t; static Context& _(const T& t, Context& context) { - interpret(t._operand, context); + serialize(t._operand, context); context << (t._inverted ? " IS NOT NULL" : " IS NULL"); return context; } diff --git a/include/sqlpp11/vendor/is_null_fwd.h b/include/sqlpp11/vendor/is_null_fwd.h index 8ef3e8a4..0c8e62f0 100644 --- a/include/sqlpp11/vendor/is_null_fwd.h +++ b/include/sqlpp11/vendor/is_null_fwd.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, diff --git a/include/sqlpp11/vendor/like.h b/include/sqlpp11/vendor/like.h index 6ad5d9a9..ca756cbb 100644 --- a/include/sqlpp11/vendor/like.h +++ b/include/sqlpp11/vendor/like.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -36,11 +36,12 @@ namespace sqlpp namespace vendor { template - struct like_t: public boolean::template operators> + struct like_t: public boolean::template expression_operators> { static_assert(is_text_t::value, "Operand for like() has to be a text"); static_assert(is_text_t::value, "Pattern for like() has to be a text"); using _parameter_tuple_t = std::tuple; + using _table_set = typename ::sqlpp::detail::make_joined_set::type; struct _value_type: public boolean { @@ -73,15 +74,15 @@ namespace sqlpp }; template - struct interpreter_t> + struct serializer_t> { using T = like_t; static Context& _(const T& t, Context& context) { - interpret(t._operand, context); + serialize(t._operand, context); context << " LIKE("; - interpret(t._pattern, context); + serialize(t._pattern, context); context << ")"; return context; } diff --git a/include/sqlpp11/vendor/limit.h b/include/sqlpp11/vendor/limit.h index fdee2700..2d77760a 100644 --- a/include/sqlpp11/vendor/limit.h +++ b/include/sqlpp11/vendor/limit.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -27,63 +27,153 @@ #ifndef SQLPP_LIMIT_H #define SQLPP_LIMIT_H -#include -#include #include +#include +#include namespace sqlpp { namespace vendor { + // LIMIT template struct limit_t { using _is_limit = std::true_type; static_assert(is_integral_t::value, "limit requires an integral value or integral parameter"); + // FIXME: Is this really always empty? + using _table_set = ::sqlpp::detail::type_set<>; - Limit _limit; + limit_t(Limit value): + _value(value) + {} + + limit_t(const limit_t&) = default; + limit_t(limit_t&&) = default; + limit_t& operator=(const limit_t&) = default; + limit_t& operator=(limit_t&&) = default; + ~limit_t() = default; + + template + struct _methods_t + { + }; + + Limit _value; + }; + + template + struct dynamic_limit_t + { + using _is_limit = std::true_type; + using _is_dynamic = std::true_type; + using _table_set = ::sqlpp::detail::type_set<>; + + dynamic_limit_t(): + _value(noop()) + { + } + + template + dynamic_limit_t(Limit value): + _initialized(true), + _value(typename wrap_operand::type(value)) + { + } + + dynamic_limit_t(const dynamic_limit_t&) = default; + dynamic_limit_t(dynamic_limit_t&&) = default; + dynamic_limit_t& operator=(const dynamic_limit_t&) = default; + dynamic_limit_t& operator=(dynamic_limit_t&&) = default; + ~dynamic_limit_t() = default; + + template + struct _methods_t + { + template + void set_limit(Limit value) + { + // FIXME: Make sure that Limit does not require external tables? Need to read up on SQL + using arg_t = typename wrap_operand::type; + static_cast(this)->_limit._value = arg_t{value}; + static_cast(this)->_limit._initialized = true; + } + }; + + bool _initialized = false; + interpretable_t _value; + }; + + struct no_limit_t + { + using _is_noop = std::true_type; + using _table_set = ::sqlpp::detail::type_set<>; + + template + struct _methods_t + { + using _database_t = typename Policies::_database_t; + template + using _new_statement_t = typename Policies::template _new_statement_t; + + template + auto limit(Arg arg) + -> _new_statement_t::type>> + { + return { *static_cast(this), limit_t::type>{{arg}} }; + } + + auto dynamic_limit() + -> _new_statement_t> + { + static_assert(not std::is_same<_database_t, void>::value, "dynamic_limit must not be called in a static statement"); + return { *static_cast(this), dynamic_limit_t<_database_t>{} }; + } + }; + }; + + // Interpreters + template + struct serializer_t> + { + using T = dynamic_limit_t; + + static Context& _(const T& t, Context& context) + { + if (t._initialized) + { + context << " LIMIT "; + serialize(t._value, context); + } + return context; + } }; template - struct interpreter_t> + struct serializer_t> { using T = limit_t; static Context& _(const T& t, Context& context) { context << " LIMIT "; - interpret(t._limit, context); + serialize(t._value, context); return context; } }; - struct dynamic_limit_t - { - using _is_limit = std::true_type; - using _is_dynamic = std::true_type; - - void set(std::size_t limit) - { - _limit = limit; - } - - std::size_t _limit; - }; - template - struct interpreter_t + struct serializer_t { - using T = dynamic_limit_t; + using T = no_limit_t; static Context& _(const T& t, Context& context) { - if (t._limit > 0) - context << " LIMIT " << t._limit; return context; } }; - } + } } #endif diff --git a/include/sqlpp11/vendor/named_interpretable.h b/include/sqlpp11/vendor/named_interpretable.h index 6d3be564..08e4ed68 100644 --- a/include/sqlpp11/vendor/named_interpretable.h +++ b/include/sqlpp11/vendor/named_interpretable.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -28,7 +28,7 @@ #define SQLPP_NAMED_SERIALIZABLE_H #include -#include +#include #include namespace sqlpp @@ -38,7 +38,8 @@ namespace sqlpp template struct named_interpretable_t { - using _context_t = typename Db::_context_t; + using _serializer_context_t = typename Db::_serializer_context_t; + using _interpreter_context_t = typename Db::_interpreter_context_t; template named_interpretable_t(T t): @@ -51,12 +52,21 @@ namespace sqlpp named_interpretable_t& operator=(named_interpretable_t&&) = default; ~named_interpretable_t() = default; - sqlpp::serializer_t& interpret(sqlpp::serializer_t& context) const + sqlpp::serializer_context_t& serialize(sqlpp::serializer_context_t& context) const { - return _impl->interpret(context); + return _impl->serialize(context); } - _context_t& interpret(_context_t& context) const + // This method only exists if Db::_serializer_context_t and sqlpp::serializer_context_t are not the same + template + auto serialize(Context& context) const + -> typename std::enable_if::value + and not std::is_same::value, Context&>::type + { + return _impl->db_serialize(context); + } + + _interpreter_context_t& interpret(_interpreter_context_t& context) const { return _impl->interpret(context); } @@ -69,8 +79,9 @@ namespace sqlpp private: struct _impl_base { - virtual sqlpp::serializer_t& interpret(sqlpp::serializer_t& context) const = 0; - virtual _context_t& interpret(_context_t& context) const = 0; + virtual sqlpp::serializer_context_t& serialize(sqlpp::serializer_context_t& context) const = 0; + virtual _serializer_context_t& db_serialize(_serializer_context_t& context) const = 0; + virtual _interpreter_context_t& interpret(_interpreter_context_t& context) const = 0; virtual std::string _get_name() const = 0; }; @@ -82,15 +93,21 @@ namespace sqlpp _t(t) {} - sqlpp::serializer_t& interpret(sqlpp::serializer_t& context) const + sqlpp::serializer_context_t& serialize(sqlpp::serializer_context_t& context) const { - sqlpp::interpret(_t, context); + sqlpp::serialize(_t, context); return context; } - _context_t& interpret(_context_t& context) const + _serializer_context_t& db_serialize(_serializer_context_t& context) const { - sqlpp::interpret(_t, context); + Db::_serialize_interpretable(_t, context); + return context; + } + + _interpreter_context_t& interpret(_interpreter_context_t& context) const + { + Db::_interpret_interpretable(_t, context); return context; } @@ -106,13 +123,13 @@ namespace sqlpp }; template - struct interpreter_t> + struct serializer_t> { using T = named_interpretable_t; static Context& _(const T& t, Context& context) { - t.interpret(context); + t.serialize(context); return context; } }; diff --git a/include/sqlpp11/vendor/noop.h b/include/sqlpp11/vendor/noop.h index fc057cef..e0c28ef1 100644 --- a/include/sqlpp11/vendor/noop.h +++ b/include/sqlpp11/vendor/noop.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -35,10 +35,11 @@ namespace sqlpp { struct noop { + using is_noop = std::true_type; }; template - struct interpreter_t + struct serializer_t { using T = noop; diff --git a/include/sqlpp11/vendor/noop_fwd.h b/include/sqlpp11/vendor/noop_fwd.h index 704cdc99..243f77a2 100644 --- a/include/sqlpp11/vendor/noop_fwd.h +++ b/include/sqlpp11/vendor/noop_fwd.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, diff --git a/include/sqlpp11/vendor/offset.h b/include/sqlpp11/vendor/offset.h index a7af759a..c8611ce0 100644 --- a/include/sqlpp11/vendor/offset.h +++ b/include/sqlpp11/vendor/offset.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -28,59 +28,149 @@ #define SQLPP_OFFSET_H #include +#include +#include namespace sqlpp { namespace vendor { + // OFFSET template struct offset_t { using _is_offset = std::true_type; + using _table_set = ::sqlpp::detail::type_set<>; static_assert(is_integral_t::value, "offset requires an integral value or integral parameter"); - Offset _offset; + offset_t(Offset value): + _value(value) + {} + + offset_t(const offset_t&) = default; + offset_t(offset_t&&) = default; + offset_t& operator=(const offset_t&) = default; + offset_t& operator=(offset_t&&) = default; + ~offset_t() = default; + + template + struct _methods_t + { + }; + + Offset _value; }; + template + struct dynamic_offset_t + { + using _is_offset = std::true_type; + using _is_dynamic = std::true_type; + using _table_set = ::sqlpp::detail::type_set<>; + + dynamic_offset_t(): + _value(noop()) + { + } + + template + dynamic_offset_t(Offset value): + _initialized(true), + _value(typename wrap_operand::type(value)) + { + } + + dynamic_offset_t(const dynamic_offset_t&) = default; + dynamic_offset_t(dynamic_offset_t&&) = default; + dynamic_offset_t& operator=(const dynamic_offset_t&) = default; + dynamic_offset_t& operator=(dynamic_offset_t&&) = default; + ~dynamic_offset_t() = default; + + template + struct _methods_t + { + template + void set_offset(Offset value) + { + // FIXME: Make sure that Offset does not require external tables? Need to read up on SQL + using arg_t = typename wrap_operand::type; + static_cast(this)->_offset._value = arg_t{value}; + static_cast(this)->_offset._initialized = true; + } + }; + + bool _initialized = false; + interpretable_t _value; + }; + + struct no_offset_t + { + using _is_noop = std::true_type; + using _table_set = ::sqlpp::detail::type_set<>; + + template + struct _methods_t + { + using _database_t = typename Policies::_database_t; + template + using _new_statement_t = typename Policies::template _new_statement_t; + + template + auto offset(Arg arg) + -> _new_statement_t::type>> + { + return { *static_cast(this), offset_t::type>{{arg}} }; + } + + auto dynamic_offset() + -> _new_statement_t> + { + static_assert(not std::is_same<_database_t, void>::value, "dynamic_offset must not be called in a static statement"); + return { *static_cast(this), dynamic_offset_t<_database_t>{} }; + } + }; + }; + + // Interpreters template - struct interpreter_t> + struct serializer_t> { using T = offset_t; static Context& _(const T& t, Context& context) { context << " OFFSET "; - interpret(t._offset, context); + serialize(t._value, context); return context; } }; - struct dynamic_offset_t - { - using _is_offset = std::true_type; - using _is_dynamic = std::true_type; - - void set(std::size_t offset) + template + struct serializer_t> { - _offset = offset; - } - - std::size_t _offset; - }; - - template - struct interpreter_t - { - using T = dynamic_offset_t; + using T = dynamic_offset_t; static Context& _(const T& t, Context& context) { - if (t._offset > 0) - context << " OFFSET " << t._offset; + if (t._initialized) + { + context << " OFFSET "; + serialize(t._value, context); + } return context; } }; + template + struct serializer_t + { + using T = no_offset_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; } } diff --git a/include/sqlpp11/vendor/order_by.h b/include/sqlpp11/vendor/order_by.h index fd58485f..9eae6c43 100644 --- a/include/sqlpp11/vendor/order_by.h +++ b/include/sqlpp11/vendor/order_by.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -28,59 +28,138 @@ #define SQLPP_ORDER_BY_H #include -#include #include #include #include +#include +#include +#include namespace sqlpp { namespace vendor { - template + template struct order_by_t { using _is_order_by = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; - using _parameter_tuple_t = std::tuple; + using _parameter_tuple_t = std::tuple; + using _parameter_list_t = typename make_parameter_list_t<_parameter_tuple_t>::type; - // check for at least one order expression - static_assert(_is_dynamic::value or sizeof...(Expr), "at least one sort-order expression required in order_by()"); + using _table_set = typename ::sqlpp::detail::make_joined_set::type; - // check for duplicate order expressions - static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in order_by()"); + static_assert(_is_dynamic::value or sizeof...(Expressions), "at least one sort-order expression required in order_by()"); - // check for invalid order expressions - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not a sort order expression in order_by()"); + static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in order_by()"); - template - void add(E expr) + static_assert(::sqlpp::detail::all_t::value, "at least one argument is not a sort order expression in order_by()"); + + order_by_t(Expressions... expressions): + _expressions(expressions...) + {} + + order_by_t(const order_by_t&) = default; + order_by_t(order_by_t&&) = default; + order_by_t& operator=(const order_by_t&) = default; + order_by_t& operator=(order_by_t&&) = default; + ~order_by_t() = default; + + template + struct _methods_t { - static_assert(is_sort_order_t::value, "order_by arguments require to be sort-order expressions"); - _dynamic_expressions.push_back(expr); - } + template + void add_order_by_ntc(Expression expression) + { + add_order_by(expression); + } + + template + void add_order_by(Expression expression) + { + static_assert(_is_dynamic::value, "add_order_by must not be called for static order_by"); + static_assert(is_sort_order_t::value, "invalid expression argument in add_order_by()"); + static_assert(TableCheckRequired::value or Policies::template _no_unknown_tables::value, "expression uses tables unknown to this statement in add_order_by()"); + + using ok = ::sqlpp::detail::all_t>; + + _add_order_by_impl(expression, ok()); // dispatch to prevent compile messages after the static_assert + } + + private: + template + void _add_order_by_impl(Expression expression, const std::true_type&) + { + return static_cast(this)->_order_by._dynamic_expressions.emplace_back(expression); + } + + template + void _add_order_by_impl(Expression expression, const std::false_type&); + }; _parameter_tuple_t _expressions; vendor::interpretable_list_t _dynamic_expressions; }; - template - struct interpreter_t> + struct no_order_by_t + { + using _is_noop = std::true_type; + using _table_set = ::sqlpp::detail::type_set<>; + + template + struct _methods_t + { + using _database_t = typename Policies::_database_t; + template + using _new_statement_t = typename Policies::template _new_statement_t; + + template + auto order_by(Args... args) + -> _new_statement_t> + { + return { *static_cast(this), order_by_t{args...} }; + } + + template + auto dynamic_order_by(Args... args) + -> _new_statement_t> + { + static_assert(not std::is_same<_database_t, void>::value, "dynamic_order_by must not be called in a static statement"); + return { *static_cast(this), vendor::order_by_t<_database_t, Args...>{args...} }; + } + }; + }; + + // Interpreters + template + struct serializer_t> { - using T = order_by_t; + using T = order_by_t; static Context& _(const T& t, Context& context) { - if (sizeof...(Expr) == 0 and t._dynamic_expressions.empty()) + if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty()) return context; context << " ORDER BY "; interpret_tuple(t._expressions, ',', context); - if (sizeof...(Expr) and not t._dynamic_expressions.empty()) + if (sizeof...(Expressions) and not t._dynamic_expressions.empty()) context << ','; interpret_list(t._dynamic_expressions, ',', context); return context; } }; + + template + struct serializer_t + { + using T = no_order_by_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; + } } diff --git a/include/sqlpp11/detail/make_flag_tuple.h b/include/sqlpp11/vendor/policy_update.h similarity index 56% rename from include/sqlpp11/detail/make_flag_tuple.h rename to include/sqlpp11/vendor/policy_update.h index 7c9efad0..a65c332b 100644 --- a/include/sqlpp11/detail/make_flag_tuple.h +++ b/include/sqlpp11/vendor/policy_update.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -24,47 +24,36 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SQLPP_DETAIL_MAKE_FLAG_TUPLE_H -#define SQLPP_DETAIL_MAKE_FLAG_TUPLE_H +#ifndef SQLPP_VENDOR_POLICY_UPDATE_H +#define SQLPP_VENDOR_POLICY_UPDATE_H + +#include namespace sqlpp { - namespace detail + namespace vendor { - // accept select flags - template - auto make_single_flag_tuple(Expr expr) -> typename std::enable_if::value, decltype(std::make_tuple(expr))>::type + template + struct policy_update_impl { - return std::make_tuple(expr); + template + using _policy_t = typename std::conditional::value, Replacement, T>::type; }; - // ignore named expressions - template - auto make_single_flag_tuple(Expr expr) -> typename std::enable_if::value, std::tuple<>>::type + template + using policy_update_t = typename policy_update_impl::template _policy_t; + + template + struct update_policies_impl { - return {}; + using type = typename Original::template _policy_update_t; }; - // ignore tables - template - auto make_single_flag_tuple(Tab tab) -> typename std::enable_if::value, std::tuple<>>::type - { - return {}; - }; - - // ignore tuples of expressions - template - auto make_single_flag_tuple(std::tuple t) -> std::tuple<> - { - return {}; - }; - - template - auto make_flag_tuple(Expr... expr) -> decltype(std::tuple_cat(make_single_flag_tuple(expr)...)) - { - return std::tuple_cat(make_single_flag_tuple(expr)...); - }; + template + using update_policies_t = typename update_policies_impl::type; } + } + #endif diff --git a/include/sqlpp11/vendor/select_column_list.h b/include/sqlpp11/vendor/select_column_list.h index ce421e8f..52a48045 100644 --- a/include/sqlpp11/vendor/select_column_list.h +++ b/include/sqlpp11/vendor/select_column_list.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -29,7 +29,6 @@ #include #include -#include #include #include #include @@ -37,7 +36,9 @@ #include #include #include +#include #include +#include namespace sqlpp { @@ -68,7 +69,7 @@ namespace sqlpp _names_t _dynamic_expression_names; template - void push_back(Expr expr) + void emplace_back(Expr expr) { _dynamic_expression_names.push_back(Expr::_name_t::_get_name()); _dynamic_columns.emplace_back(expr); @@ -89,9 +90,6 @@ namespace sqlpp }; _names_t _dynamic_expression_names; - template - void push_back(const T&) {} - static constexpr bool empty() { return true; @@ -99,7 +97,7 @@ namespace sqlpp }; template - struct interpreter_t> + struct serializer_t> { using T = dynamic_select_column_list; @@ -112,14 +110,14 @@ namespace sqlpp first = false; else context << ','; - interpret(column, context); + serialize(column, context); } return context; } }; template - struct interpreter_t> + struct serializer_t> { using T = dynamic_select_column_list; @@ -130,69 +128,165 @@ namespace sqlpp }; - template + // SELECT COLUMNS + template struct select_column_list_t - { - static_assert(::sqlpp::vendor::wrong_t::value, "invalid template argument for select_column_list"); - }; - - template - struct select_column_list_t> { using _is_select_column_list = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; - using _parameter_tuple_t = std::tuple; + using _parameter_tuple_t = std::tuple; using size = std::tuple_size<_parameter_tuple_t>; - // check for duplicate select expressions - static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected"); + using _table_set = sqlpp::detail::make_joined_set_t; + + static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected"); - // check for invalid select expressions template using is_valid_expression_t = std::integral_constant::value or is_multi_column_t::value>; - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not a named expression"); + static_assert(::sqlpp::detail::all_t::value, "at least one argument is not a named expression"); - // check for duplicate select expression names - static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate name detected"); + static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate name detected"); - // provide type information for sub-selects that are used as expressions struct _column_type {}; - struct _value_type: ::sqlpp::detail::get_first_argument_if_unique::_value_type + struct _value_type: ::sqlpp::detail::get_first_argument_if_unique::_value_type { - using _is_expression = typename std::conditional::type; - using _is_named_expression = typename std::conditional::type; + using _is_expression = typename std::conditional::type; + using _is_named_expression = typename std::conditional::type; using _is_alias = std::false_type; }; - using _name_t = typename ::sqlpp::detail::get_first_argument_if_unique::_name_t; + using _name_t = typename ::sqlpp::detail::get_first_argument_if_unique::_name_t; + template using _result_row_t = typename std::conditional<_is_dynamic::value, - dynamic_result_row_t...>, - result_row_t...>>::type; + dynamic_result_row_t...>, + result_row_t...>>::type; using _dynamic_names_t = typename dynamic_select_column_list::_names_t; template - using _pseudo_table_t = select_pseudo_table_t; + using _pseudo_table_t = select_pseudo_table_t; template - using _dynamic_t = select_column_list_t>; + using _dynamic_t = select_column_list_t>; - template - void add(Expr namedExpr) + select_column_list_t(std::tuple columns): + _columns(columns) + {} + + select_column_list_t(Columns... columns): + _columns(columns...) + {} + + select_column_list_t(const select_column_list_t&) = default; + select_column_list_t(select_column_list_t&&) = default; + select_column_list_t& operator=(const select_column_list_t&) = default; + select_column_list_t& operator=(select_column_list_t&&) = default; + ~select_column_list_t() = default; + + static constexpr size_t static_size() + { + return size::value; + } + + template + struct _methods_t { - static_assert(is_named_expression_t::value, "select() arguments require to be named expressions"); - static_assert(_is_dynamic::value, "cannot add columns to a non-dynamic column list"); - _dynamic_columns.push_back(namedExpr); - } + template + void add_column_ntc(NamedExpression namedExpression) + { + add_column(namedExpression); + } + template + void add_column(NamedExpression namedExpression) + { + static_assert(_is_dynamic::value, "add_column can only be called for dynamic_column"); + static_assert(is_named_expression_t::value, "invalid named expression argument in add_column()"); + static_assert(TableCheckRequired::value or Policies::template _no_unknown_tables::value, "named expression uses tables unknown to this statement in add_column()"); + using column_names = ::sqlpp::detail::make_type_set_t; + static_assert(not ::sqlpp::detail::is_element_of::value, "a column of this name is present in the select already"); + + using ok = ::sqlpp::detail::all_t + >; + + _add_column_impl(namedExpression, ok()); // dispatch to prevent compile messages after the static_assert + } + + private: + template + void _add_column_impl(NamedExpression namedExpression, const std::true_type&) + { + return static_cast(this)->_column_list._dynamic_columns.emplace_back(namedExpression); + } + + template + void _add_column_impl(NamedExpression namedExpression, const std::false_type&); + }; + + + const select_column_list_t& _column_list() const { return *this; } _parameter_tuple_t _columns; dynamic_select_column_list _dynamic_columns; }; + } - template - struct interpreter_t> + namespace detail + { + template + using make_select_column_list_t = + copy_tuple_args_t::_(std::declval())...))>; + } + + namespace vendor + { + struct no_select_column_list_t + { + using _is_noop = std::true_type; + using _table_set = ::sqlpp::detail::type_set<>; + template + using _result_row_t = ::sqlpp::result_row_t; + using _dynamic_names_t = typename dynamic_select_column_list::_names_t; + using _value_type = no_value_t; + struct _name_t {}; + + template + struct _pseudo_table_t + { + static_assert(wrong_t::value, "Cannot use a select as a table when no columns have been selected yet"); + }; + + template + struct _methods_t + { + using _database_t = typename Policies::_database_t; + template + using _new_statement_t = typename Policies::template _new_statement_t; + + template + auto columns(Args... args) + -> _new_statement_t<::sqlpp::detail::make_select_column_list_t> + { + return { *static_cast(this), ::sqlpp::detail::make_select_column_list_t{std::tuple_cat(::sqlpp::detail::as_tuple::_(args)...)} }; + } + + template + auto dynamic_columns(Args... args) + -> _new_statement_t<::sqlpp::detail::make_select_column_list_t<_database_t, Args...>> + { + static_assert(not std::is_same<_database_t, void>::value, "dynamic_columns must not be called in a static statement"); + return { *static_cast(this), ::sqlpp::detail::make_select_column_list_t<_database_t, Args...>{std::tuple_cat(::sqlpp::detail::as_tuple::_(args)...)} }; + } + }; + }; + + // Interpreters + template + struct serializer_t> { - using T = select_column_list_t; + using T = select_column_list_t; static Context& _(const T& t, Context& context) { @@ -202,7 +296,18 @@ namespace sqlpp interpret_tuple(t._columns, ',', context); if (T::size::value and not t._dynamic_columns.empty()) context << ','; - interpret(t._dynamic_columns, context); + serialize(t._dynamic_columns, context); + return context; + } + }; + + template + struct serializer_t + { + using T = no_select_column_list_t; + + static Context& _(const T& t, Context& context) + { return context; } }; diff --git a/include/sqlpp11/vendor/select_flag_list.h b/include/sqlpp11/vendor/select_flag_list.h index a167e4fc..93384318 100644 --- a/include/sqlpp11/vendor/select_flag_list.h +++ b/include/sqlpp11/vendor/select_flag_list.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -27,58 +27,118 @@ #ifndef SQLPP_VENDOR_SELECT_FLAG_LIST_H #define SQLPP_VENDOR_SELECT_FLAG_LIST_H -#include +#include #include #include #include #include -#include +#include namespace sqlpp { namespace vendor { - template + // SELECT FLAGS + template struct select_flag_list_t - { - static_assert(::sqlpp::vendor::wrong_t::value, "invalid argument for select_flag_list"); - }; - - // select_flag_list_t - template - struct select_flag_list_t> { using _is_select_flag_list = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; - using _parameter_tuple_t = std::tuple; + using _parameter_tuple_t = std::tuple; using size = std::tuple_size<_parameter_tuple_t>; + using _table_set = typename ::sqlpp::detail::make_joined_set::type; - // check for duplicate order expressions - static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in select flag list"); + static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in select flag list"); - // check for invalid order expressions - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not a select flag in select flag list"); + static_assert(::sqlpp::detail::all_t::value, "at least one argument is not a select flag in select flag list"); - template - void add(E expr) + select_flag_list_t(Flags... flags): + _flags(flags...) + {} + + select_flag_list_t(const select_flag_list_t&) = default; + select_flag_list_t(select_flag_list_t&&) = default; + select_flag_list_t& operator=(const select_flag_list_t&) = default; + select_flag_list_t& operator=(select_flag_list_t&&) = default; + ~select_flag_list_t() = default; + + template + struct _methods_t { - static_assert(is_select_flag_t::value, "flag arguments require to be select flags"); - _dynamic_flags.emplace_back(expr); - } + template + void add_flag_ntc(Flag flag) + { + add_flag(flag); + } + template + void add_flag(Flag flag) + { + static_assert(_is_dynamic::value, "add_flag must not be called for static select flags"); + static_assert(is_select_flag_t::value, "invalid select flag argument in add_flag()"); + static_assert(TableCheckRequired::value or Policies::template _no_unknown_tables::value, "flag uses tables unknown to this statement in add_flag()"); + + using ok = ::sqlpp::detail::all_t>; + + _add_flag_impl(flag, ok()); // dispatch to prevent compile messages after the static_assert + } + + private: + template + void _add_flag_impl(Flag flag, const std::true_type&) + { + return static_cast(this)->_flag_list._dynamic_flags.emplace_back(flag); + } + + template + void _add_flag_impl(Flag flag, const std::false_type&); + }; + + const select_flag_list_t& _flag_list() const { return *this; } _parameter_tuple_t _flags; vendor::interpretable_list_t _dynamic_flags; }; - template - struct interpreter_t>> + struct no_select_flag_list_t + { + using _is_noop = std::true_type; + using _table_set = ::sqlpp::detail::type_set<>; + + template + struct _methods_t + { + using _database_t = typename Policies::_database_t; + template + using _new_statement_t = typename Policies::template _new_statement_t; + + template + auto flags(Args... args) + -> _new_statement_t> + { + return { *static_cast(this), select_flag_list_t{args...} }; + } + + template + auto dynamic_flags(Args... args) + -> _new_statement_t> + { + static_assert(not std::is_same<_database_t, void>::value, "dynamic_flags must not be called in a static statement"); + return { *static_cast(this), vendor::select_flag_list_t<_database_t, Args...>{args...} }; + } + }; + }; + + + // Interpreters + template + struct serializer_t> { - using T = select_flag_list_t>; + using T = select_flag_list_t; static Context& _(const T& t, Context& context) { interpret_tuple(t._flags, ' ', context); - if (sizeof...(Flag)) + if (sizeof...(Flags)) context << ' '; interpret_list(t._dynamic_flags, ',', context); if (not t._dynamic_flags.empty()) @@ -86,6 +146,17 @@ namespace sqlpp return context; } }; + + template + struct serializer_t + { + using T = no_select_flag_list_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; } } diff --git a/include/sqlpp11/vendor/select_pseudo_table.h b/include/sqlpp11/vendor/select_pseudo_table.h index 4bcf4436..a63c4d63 100644 --- a/include/sqlpp11/vendor/select_pseudo_table.h +++ b/include/sqlpp11/vendor/select_pseudo_table.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -37,7 +37,11 @@ namespace sqlpp { using _name_t = typename Expr::_name_t; using _value_type = typename Expr::_value_type; - struct _column_type {}; + struct _column_type + { + using _must_not_insert = std::true_type; + using _must_not_update = std::true_type; + }; }; template< @@ -68,13 +72,13 @@ namespace sqlpp namespace vendor { template - struct interpreter_t> + struct serializer_t> { using T = select_pseudo_table_t; static Context& _(const T& t, Context& context) { - interpret(t._select, context); + serialize(t._select, context); return context; } }; diff --git a/include/sqlpp11/select_fwd.h b/include/sqlpp11/vendor/serializer.h similarity index 71% rename from include/sqlpp11/select_fwd.h rename to include/sqlpp11/vendor/serializer.h index dc432e57..1a5031f9 100644 --- a/include/sqlpp11/select_fwd.h +++ b/include/sqlpp11/vendor/serializer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -24,34 +24,25 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SQLPP_SELECT_FWD_H -#define SQLPP_SELECT_FWD_H +#ifndef SQLPP_VENDOR_SERIALIZER_H +#define SQLPP_VENDOR_SERIALIZER_H -#include +#include namespace sqlpp { namespace vendor { - struct noop; + template + struct serializer_t + { + static void _(const T& t, Context& context) + { + static_assert(wrong_t::value, "missing serializer specialization"); + } + }; } - // select flags - struct all_t; - struct distinct_t; - struct straight_join_t; - template< - typename Db, - typename Flags = vendor::noop, - typename ExpressionList = vendor::noop, - typename From = vendor::noop, - typename Where = vendor::noop, - typename GroupBy = vendor::noop, - typename Having = vendor::noop, - typename OrderBy = vendor::noop, - typename Limit = vendor::noop, - typename Offset = vendor::noop - > - struct select_t; } + #endif diff --git a/include/sqlpp11/vendor/simple_column.h b/include/sqlpp11/vendor/simple_column.h index ccc6f09a..56d664bc 100644 --- a/include/sqlpp11/vendor/simple_column.h +++ b/include/sqlpp11/vendor/simple_column.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -27,7 +27,7 @@ #ifndef SQLPP_SIMPLE_COLUMN_H #define SQLPP_SIMPLE_COLUMN_H -#include +#include namespace sqlpp { @@ -40,7 +40,7 @@ namespace sqlpp }; template - struct interpreter_t> + struct serializer_t> { using T = simple_column_t; diff --git a/include/sqlpp11/vendor/column_list.h b/include/sqlpp11/vendor/single_table.h similarity index 53% rename from include/sqlpp11/vendor/column_list.h rename to include/sqlpp11/vendor/single_table.h index e8bbdb9a..99cf8eea 100644 --- a/include/sqlpp11/vendor/column_list.h +++ b/include/sqlpp11/vendor/single_table.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -24,53 +24,56 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SQLPP_COLUMN_LIST_H -#define SQLPP_COLUMN_LIST_H +#ifndef SQLPP_VENDOR_SINGLE_TABLE_H +#define SQLPP_VENDOR_SINGLE_TABLE_H #include -#include -#include -#include +#include namespace sqlpp { namespace vendor { - template - struct column_list_t + // A SINGLE TABLE + template + struct single_table_t { - using _is_column_list = std::true_type; - using _parameter_tuple_t = std::tuple; + using _is_single_table = std::true_type; - // check for at least one order column - static_assert(sizeof...(Columns), "at least one column required in columns()"); + static_assert(is_table_t
::value, "argument has to be a table"); - // check for duplicate columns - static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in columns()"); + single_table_t(Table table): + _table(table) + {} - // check for invalid columns - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not a column in columns()"); + single_table_t(const single_table_t&) = default; + single_table_t(single_table_t&&) = default; + single_table_t& operator=(const single_table_t&) = default; + single_table_t& operator=(single_table_t&&) = default; + ~single_table_t() = default; - // check for prohibited columns - static_assert(not ::sqlpp::detail::or_t::value, "at least one column argument has a must_not_insert flag in its definition"); - - std::tuple...> _columns; + using _table_set = typename Table::_table_set; + Table _table; }; - template - struct interpreter_t> + struct no_single_table_t + { + using _table_set = ::sqlpp::detail::type_set<>; + }; + + // Interpreters + template + struct serializer_t> { - using T = column_list_t; + using T = single_table_t; static Context& _(const T& t, Context& context) { - context << " ("; - interpret_tuple(t._columns, ",", context); - context << ")"; - + serialize(t._table, context); return context; } }; + } } diff --git a/include/sqlpp11/vendor/update_list.h b/include/sqlpp11/vendor/update_list.h index a58e92fd..b3446857 100644 --- a/include/sqlpp11/vendor/update_list.h +++ b/include/sqlpp11/vendor/update_list.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -36,6 +36,7 @@ namespace sqlpp { namespace vendor { + // UPDATE ASSIGNMENTS template struct update_list_t { @@ -43,32 +44,103 @@ namespace sqlpp using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; using _parameter_tuple_t = std::tuple; - // check for at least one order expression static_assert(_is_dynamic::value or sizeof...(Assignments), "at least one assignment expression required in set()"); - // check for duplicate assignments static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in set()"); - // check for invalid assignments - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not an assignment in set()"); + static_assert(::sqlpp::detail::all_t::value, "at least one argument is not an assignment in set()"); - // check for prohibited assignments - static_assert(not ::sqlpp::detail::or_t::value, "at least one assignment is prohibited by its column definition in set()"); + static_assert(not ::sqlpp::detail::any_t::value, "at least one assignment is prohibited by its column definition in set()"); - template - void add(Assignment assignment) + using _column_table_set = typename ::sqlpp::detail::make_joined_set::type; + using _value_table_set = typename ::sqlpp::detail::make_joined_set::type; + using _table_set = typename ::sqlpp::detail::make_joined_set<_column_table_set, _value_table_set>::type; + static_assert(sizeof...(Assignments) ? (_column_table_set::size::value == 1) : true, "set() contains assignments for tables from several columns"); + static_assert(::sqlpp::detail::is_subset_of<_value_table_set, _column_table_set>::value, "set() contains values from foreign tables"); + + update_list_t(Assignments... assignments): + _assignments(assignments...) + {} + + update_list_t(const update_list_t&) = default; + update_list_t(update_list_t&&) = default; + update_list_t& operator=(const update_list_t&) = default; + update_list_t& operator=(update_list_t&&) = default; + ~update_list_t() = default; + + template + struct _methods_t { - static_assert(is_assignment_t::value, "set() arguments require to be assigments"); - static_assert(not must_not_update_t::value, "set() argument must not be updated"); - _dynamic_assignments.emplace_back(assignment); - } + template + void add_set_ntc(Assignment assignment) + { + add_set(assignment); + } + + template + void add_set(Assignment assignment) + { + static_assert(_is_dynamic::value, "add_set must not be called for static from()"); + static_assert(is_assignment_t::value, "invalid assignment argument in add_set()"); + static_assert(sqlpp::detail::not_t::value, "add_set() 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_set()"); + + using ok = ::sqlpp::detail::all_t, + sqlpp::detail::not_t>; + + _add_set_impl(assignment, ok()); // dispatch to prevent compile messages after the static_assert + } + + private: + template + void _add_set_impl(Assignment assignment, const std::true_type&) + { + return static_cast(this)->_update_list._dynamic_assignments.emplace_back(assignment); + } + + template + void _add_set_impl(Assignment assignment, const std::false_type&); + }; + _parameter_tuple_t _assignments; typename vendor::interpretable_list_t _dynamic_assignments; }; + struct no_update_list_t + { + using _is_noop = std::true_type; + using _table_set = ::sqlpp::detail::type_set<>; + + template + struct _methods_t + { + using _database_t = typename Policies::_database_t; + template + using _new_statement_t = typename Policies::template _new_statement_t; + + template + auto set(Args... args) + -> _new_statement_t> + { + return { *static_cast(this), update_list_t{args...} }; + } + + template + auto dynamic_set(Args... args) + -> _new_statement_t> + { + static_assert(not std::is_same<_database_t, void>::value, "dynamic_set must not be called in a static statement"); + return { *static_cast(this), vendor::update_list_t<_database_t, Args...>{args...} }; + } + }; + }; + + // Interpreters template - struct interpreter_t> + struct serializer_t> { using T = update_list_t; @@ -82,6 +154,18 @@ namespace sqlpp return context; } }; + + template + struct serializer_t + { + using T = no_update_list_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; + } } diff --git a/include/sqlpp11/vendor/using.h b/include/sqlpp11/vendor/using.h index 7f98b821..eaaea22f 100644 --- a/include/sqlpp11/vendor/using.h +++ b/include/sqlpp11/vendor/using.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -31,55 +31,126 @@ #include #include #include +#include namespace sqlpp { namespace vendor { - template + // USING + template struct using_t { using _is_using = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; - using _parameter_tuple_t = std::tuple; + using _parameter_tuple_t = std::tuple; - static_assert(_is_dynamic::value or sizeof...(Table), "at least one table argument required in using()"); + static_assert(_is_dynamic::value or sizeof...(Tables), "at least one table argument required in using()"); - // check for duplicate arguments - static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in using()"); + static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in using()"); - // check for invalid arguments - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not an table in using()"); + static_assert(::sqlpp::detail::all_t::value, "at least one argument is not an table in using()"); + using _table_set = ::sqlpp::detail::make_joined_set_t; - template - void add(T table) + using_t(Tables... tables): + _tables(tables...) + {} + + using_t(const using_t&) = default; + using_t(using_t&&) = default; + using_t& operator=(const using_t&) = default; + using_t& operator=(using_t&&) = default; + ~using_t() = default; + + template + struct _methods_t { - static_assert(is_table_t::value, "using() arguments require to be tables"); - _dynamic_tables.emplace_back(table); - } + template + void add_using(Table table) + { + static_assert(_is_dynamic::value, "add_using must not be called for static using()"); + static_assert(is_table_t
::value, "invalid table argument in add_using()"); + + using ok = ::sqlpp::detail::all_t>; + + _add_using_impl(table, ok()); // dispatch to prevent compile messages after the static_assert + } + + private: + template + void _add_using_impl(Table table, const std::true_type&) + { + return static_cast(this)->_using._dynamic_tables.emplace_back(table); + } + + template + void _add_using_impl(Table table, const std::false_type&); + }; + _parameter_tuple_t _tables; vendor::interpretable_list_t _dynamic_tables; }; - template - struct interpreter_t> + struct no_using_t + { + using _is_noop = std::true_type; + using _table_set = ::sqlpp::detail::type_set<>; + + template + struct _methods_t + { + using _database_t = typename Policies::_database_t; + template + using _new_statement_t = typename Policies::template _new_statement_t; + + template + auto using_(Args... args) + -> _new_statement_t> + { + return { *static_cast(this), using_t{args...} }; + } + + template + auto dynamic_using(Args... args) + -> _new_statement_t> + { + static_assert(not std::is_same<_database_t, void>::value, "dynamic_using must not be called in a static statement"); + return { *static_cast(this), vendor::using_t<_database_t, Args...>{args...} }; + } + }; + }; + + // Interpreters + template + struct serializer_t> { - using T = using_t; + using T = using_t; static Context& _(const T& t, Context& context) { - if (sizeof...(Table) == 0 and t._dynamic_tables.empty()) + if (sizeof...(Tables) == 0 and t._dynamic_tables.empty()) return context; context << " USING "; interpret_tuple(t._tables, ',', context); - if (sizeof...(Table) and not t._dynamic_tables.empty()) + if (sizeof...(Tables) and not t._dynamic_tables.empty()) context << ','; interpret_list(t._dynamic_tables, ',', context); return context; } }; + + template + struct serializer_t + { + using T = no_using_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; } } diff --git a/include/sqlpp11/vendor/value_type.h b/include/sqlpp11/vendor/value_type.h index 4c709a03..06738c36 100644 --- a/include/sqlpp11/vendor/value_type.h +++ b/include/sqlpp11/vendor/value_type.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, diff --git a/include/sqlpp11/vendor/where.h b/include/sqlpp11/vendor/where.h index 72de65fa..a5663ec2 100644 --- a/include/sqlpp11/vendor/where.h +++ b/include/sqlpp11/vendor/where.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -27,83 +27,176 @@ #ifndef SQLPP_WHERE_H #define SQLPP_WHERE_H -#include -#include -#include #include -#include +#include +#include #include #include -#include +#include namespace sqlpp { namespace vendor { - template + // WHERE + template struct where_t { using _is_where = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; - using _parameter_tuple_t = std::tuple; + using _parameter_tuple_t = std::tuple; - static_assert(_is_dynamic::value or sizeof...(Expr), "at least one expression argument required in where()"); - static_assert(sqlpp::detail::and_t::value, "at least one argument is not an expression in where()"); + static_assert(_is_dynamic::value or sizeof...(Expressions), "at least one expression argument required in where()"); + static_assert(not sqlpp::detail::any_t::value, "at least one argument is an assignment in where()"); + static_assert(sqlpp::detail::all_t::value, "at least one argument is not valid expression in where()"); using _parameter_list_t = typename make_parameter_list_t<_parameter_tuple_t>::type; - template - void add(E expr) + using _table_set = typename ::sqlpp::detail::make_joined_set::type; + + where_t(Expressions... expressions): + _expressions(expressions...) + {} + + where_t(const where_t&) = default; + where_t(where_t&&) = default; + where_t& operator=(const where_t&) = default; + where_t& operator=(where_t&&) = default; + ~where_t() = default; + + template + struct _methods_t { - static_assert(is_expression_t::value, "invalid expression argument in add_where()"); - _dynamic_expressions.emplace_back(expr); - } + template + void add_where_ntc(Expression expression) + { + add_where(expression); + } + + template + void add_where(Expression expression) + { + static_assert(_is_dynamic::value, "add_where can only be called for dynamic_where"); + static_assert(is_expression_t::value, "invalid expression argument in add_where()"); + static_assert(TableCheckRequired::value or Policies::template _no_unknown_tables::value, "expression uses tables unknown to this statement in add_where()"); + + using ok = ::sqlpp::detail::all_t>; + + _add_where_impl(expression, ok()); // dispatch to prevent compile messages after the static_assert + } + + private: + template + void _add_where_impl(Expression expression, const std::true_type&) + { + return static_cast(this)->_where._dynamic_expressions.emplace_back(expression); + } + + template + void _add_where_impl(Expression expression, const std::false_type&); + }; _parameter_tuple_t _expressions; vendor::interpretable_list_t _dynamic_expressions; }; - template - struct interpreter_t> - { - using T = where_t; - - static Context& _(const T& t, Context& context) - { - if (sizeof...(Expr) == 0 and t._dynamic_expressions.empty()) - return context; - context << " WHERE "; - interpret_tuple(t._expressions, " AND ", context); - if (sizeof...(Expr) and not t._dynamic_expressions.empty()) - context << " AND "; - interpret_list(t._dynamic_expressions, " AND ", context); - return context; - } - }; - template<> struct where_t { using _is_where = std::true_type; using _is_dynamic = std::false_type; - using _parameter_tuple_t = std::tuple<>; + using _table_set = ::sqlpp::detail::type_set<>; - std::tuple _condition; + where_t(bool condition): + _condition(condition) + {} + + where_t(const where_t&) = default; + where_t(where_t&&) = default; + where_t& operator=(const where_t&) = default; + where_t& operator=(where_t&&) = default; + ~where_t() = default; + + template + struct _methods_t + { + }; + + bool _condition; + }; + + struct no_where_t + { + using _is_noop = std::true_type; + using _table_set = ::sqlpp::detail::type_set<>; + + template + struct _methods_t + { + using _database_t = typename Policies::_database_t; + template + using _new_statement_t = typename Policies::template _new_statement_t; + + template + auto where(Args... args) + -> _new_statement_t> + { + return { *static_cast(this), where_t{args...} }; + } + + template + auto dynamic_where(Args... args) + -> _new_statement_t> + { + static_assert(not std::is_same<_database_t, void>::value, "dynamic_where must not be called in a static statement"); + return { *static_cast(this), vendor::where_t<_database_t, Args...>{args...} }; + } + }; + }; + + // Interpreters + template + struct serializer_t> + { + using T = where_t; + + static Context& _(const T& t, Context& context) + { + if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty()) + return context; + context << " WHERE "; + interpret_tuple(t._expressions, " AND ", context); + if (sizeof...(Expressions) and not t._dynamic_expressions.empty()) + context << " AND "; + interpret_list(t._dynamic_expressions, " AND ", context); + return context; + } }; template - struct interpreter_t> + struct serializer_t> { using T = where_t; static Context& _(const T& t, Context& context) { - if (not std::get<0>(t._condition)) + if (not t._condition) context << " WHERE NULL"; return context; } }; + template + struct serializer_t + { + using T = no_where_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; + } } diff --git a/include/sqlpp11/vendor/wrap_operand.h b/include/sqlpp11/vendor/wrap_operand.h index 106a6349..96092e57 100644 --- a/include/sqlpp11/vendor/wrap_operand.h +++ b/include/sqlpp11/vendor/wrap_operand.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -28,7 +28,8 @@ #define SQLPP_DETAIL_WRAP_OPERAND_H #include -#include +#include +#include namespace sqlpp { @@ -47,6 +48,21 @@ namespace sqlpp static constexpr bool _is_expression = true; using _value_type = sqlpp::detail::boolean; using _value_t = bool; + using _table_set = ::sqlpp::detail::type_set<>; + + boolean_operand(): + _t{} + {} + + boolean_operand(_value_t t): + _t(t) + {} + + boolean_operand(const boolean_operand&) = default; + boolean_operand(boolean_operand&&) = default; + boolean_operand& operator=(const boolean_operand&) = default; + boolean_operand& operator=(boolean_operand&&) = default; + ~boolean_operand() = default; bool _is_trivial() const { return _t == false; } @@ -54,7 +70,7 @@ namespace sqlpp }; template - struct interpreter_t + struct serializer_t { using Operand = boolean_operand; @@ -65,22 +81,36 @@ namespace sqlpp } }; - template - struct integral_operand + struct integral_operand + { + static constexpr bool _is_expression = true; + using _value_type = ::sqlpp::detail::integral; + using _value_t = int64_t; + using _table_set = ::sqlpp::detail::type_set<>; + + integral_operand(): + _t{} + {} + + integral_operand(_value_t t): + _t(t) + {} + + integral_operand(const integral_operand&) = default; + integral_operand(integral_operand&&) = default; + integral_operand& operator=(const integral_operand&) = default; + integral_operand& operator=(integral_operand&&) = default; + ~integral_operand() = default; + + bool _is_trivial() const { return _t == 0; } + + _value_t _t; + }; + + template + struct serializer_t { - static constexpr bool _is_expression = true; - using _value_type = ::sqlpp::detail::integral; - using _value_t = T; - - bool _is_trivial() const { return _t == 0; } - - _value_t _t; - }; - - template - struct interpreter_t> - { - using Operand = integral_operand; + using Operand = integral_operand; static Context& _(const Operand& t, Context& context) { @@ -90,22 +120,36 @@ namespace sqlpp }; - template - struct floating_point_operand + struct floating_point_operand + { + static constexpr bool _is_expression = true; + using _value_type = ::sqlpp::detail::floating_point; + using _value_t = double; + using _table_set = ::sqlpp::detail::type_set<>; + + floating_point_operand(): + _t{} + {} + + floating_point_operand(_value_t t): + _t(t) + {} + + floating_point_operand(const floating_point_operand&) = default; + floating_point_operand(floating_point_operand&&) = default; + floating_point_operand& operator=(const floating_point_operand&) = default; + floating_point_operand& operator=(floating_point_operand&&) = default; + ~floating_point_operand() = default; + + bool _is_trivial() const { return _t == 0; } + + _value_t _t; + }; + + template + struct serializer_t { - static constexpr bool _is_expression = true; - using _value_type = ::sqlpp::detail::floating_point; - using _value_t = T; - - bool _is_trivial() const { return _t == 0; } - - _value_t _t; - }; - - template - struct interpreter_t> - { - using Operand = floating_point_operand; + using Operand = floating_point_operand; static Context& _(const Operand& t, Context& context) { @@ -119,6 +163,21 @@ namespace sqlpp static constexpr bool _is_expression = true; using _value_type = ::sqlpp::detail::text; using _value_t = std::string; + using _table_set = ::sqlpp::detail::type_set<>; + + text_operand(): + _t{} + {} + + text_operand(_value_t t): + _t(t) + {} + + text_operand(const text_operand&) = default; + text_operand(text_operand&&) = default; + text_operand& operator=(const text_operand&) = default; + text_operand& operator=(text_operand&&) = default; + ~text_operand() = default; bool _is_trivial() const { return _t.empty(); } @@ -126,7 +185,7 @@ namespace sqlpp }; template - struct interpreter_t + struct serializer_t { using Operand = text_operand; @@ -152,13 +211,13 @@ namespace sqlpp template struct wrap_operand::value>::type> { - using type = integral_operand; + using type = integral_operand; }; template struct wrap_operand::value>::type> { - using type = floating_point_operand; + using type = floating_point_operand; }; template @@ -168,6 +227,10 @@ namespace sqlpp }; // FIXME: Need to allow std::ref arguments + + template + using wrap_operand_t = typename wrap_operand::type; + } } diff --git a/include/sqlpp11/vendor/wrong.h b/include/sqlpp11/vendor/wrong.h index a37462ba..65a4d181 100644 --- a/include/sqlpp11/vendor/wrong.h +++ b/include/sqlpp11/vendor/wrong.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -38,15 +38,14 @@ namespace sqlpp // A template that always returns false // To be used with static assert, for instance, to ensure it // fires only when the template is instantiated. - template struct wrong_t - { - using type = std::false_type; - }; + template + struct wrong + { + using type = std::false_type; + }; } - - template - using wrong_t = typename detail::wrong_t::type; + template + using wrong_t = typename detail::wrong::type; } - } #endif diff --git a/include/sqlpp11/verbatim_table.h b/include/sqlpp11/verbatim_table.h index d394720c..2ad79190 100644 --- a/include/sqlpp11/verbatim_table.h +++ b/include/sqlpp11/verbatim_table.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -68,7 +68,7 @@ namespace sqlpp namespace vendor { template - struct interpreter_t + struct serializer_t { using T = verbatim_table_t; diff --git a/scripts/ddl2cpp b/scripts/ddl2cpp index cc1d78b2..13011825 100755 --- a/scripts/ddl2cpp +++ b/scripts/ddl2cpp @@ -1,7 +1,7 @@ #!/usr/bin/env python ## - # Copyright (c) 2013 - 2014, Roland Bock + # Copyright (c) 2013-2014, Roland Bock # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b2a56c15..350602ec 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -11,6 +11,7 @@ build_and_run(InsertTest) build_and_run(RemoveTest) build_and_run(UpdateTest) build_and_run(SelectTest) +build_and_run(SelectTypeTest) build_and_run(FunctionTest) build_and_run(PreparedTest) @@ -19,5 +20,6 @@ find_package(PythonInterp REQUIRED) add_custom_command( OUTPUT ${CMAKE_CURRENT_LIST_DIR}/Sample.h COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/scripts/ddl2cpp ${CMAKE_CURRENT_LIST_DIR}/sample.sql Sample test + DEPENDS ${CMAKE_CURRENT_LIST_DIR}/sample.sql ) diff --git a/tests/FunctionTest.cpp b/tests/FunctionTest.cpp index 632875b0..04aa8f52 100644 --- a/tests/FunctionTest.cpp +++ b/tests/FunctionTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -32,7 +32,7 @@ #include -DbMock db = {}; +MockDb db = {}; SQLPP_ALIAS_PROVIDER(kaesekuchen); int main() @@ -40,6 +40,8 @@ int main() test::TabFoo f; test::TabBar t; + //f.omega + 4 *= ""; + // MEMBER FUNCTIONS // ---------------- @@ -183,11 +185,13 @@ int main() static_assert(not sqlpp::is_text_t::value, "type requirement"); } + // Test any { + using TI = decltype(any(select(t.alpha).from(t))); using TT = decltype(any(select(t.beta).from(t))); - using TF = decltype(any(select(f.omega).from(t))); + using TF = decltype(any(select(f.omega).from(f))); static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_multi_expression_t::value, "type requirement"); static_assert(sqlpp::is_numeric_t::value, "type requirement"); @@ -210,7 +214,7 @@ int main() { using TI = decltype(some(select(t.alpha).from(t))); using TT = decltype(some(select(t.beta).from(t))); - using TF = decltype(some(select(f.omega).from(t))); + using TF = decltype(some(select(f.omega).from(f))); static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_multi_expression_t::value, "type requirement"); static_assert(sqlpp::is_numeric_t::value, "type requirement"); diff --git a/tests/InsertTest.cpp b/tests/InsertTest.cpp index a116d93c..67e2efe7 100644 --- a/tests/InsertTest.cpp +++ b/tests/InsertTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -29,12 +29,13 @@ #include #include -DbMock db; -DbMock::_context_t printer(std::cerr); +MockDb db; +MockDb::_serializer_context_t printer; int main() { test::TabBar t; + test::TabFoo f; auto x = t.alpha = 7; auto y = t.beta = "kaesekuchen"; @@ -57,11 +58,22 @@ int main() static_assert(sqlpp::is_regular::value, "type requirement"); } - interpret(insert_into(t), printer).flush(); - interpret(insert_into(t).set(t.beta = "kirschauflauf"), printer).flush(); + db(insert_into(t).default_values()); + db(insert_into(t).set(t.beta = "kirschauflauf")); + + serialize(insert_into(t).default_values(), printer).str(); + + serialize(insert_into(t), printer).str(); + serialize(insert_into(t).set(t.beta = "kirschauflauf"), printer).str(); + serialize(insert_into(t).columns(t.beta), printer).str(); + auto multi_insert = insert_into(t).columns(t.beta, t.delta); + multi_insert.add_values(t.beta = "cheesecake", t.delta = 1); + multi_insert.add_values(t.beta = sqlpp::default_value, t.delta = sqlpp::default_value); auto i = dynamic_insert_into(db, t).dynamic_set(); - i = i.add_set(t.beta = "kirschauflauf"); - interpret(i, printer).flush(); + i.add_set(t.beta = "kirschauflauf"); + serialize(i, printer).str(); + + db(multi_insert); return 0; } diff --git a/tests/InterpretTest.cpp b/tests/InterpretTest.cpp index 8f523298..2fd5c3a3 100644 --- a/tests/InterpretTest.cpp +++ b/tests/InterpretTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -34,8 +34,8 @@ #include -DbMock db = {}; -DbMock::_context_t printer(std::cerr); +MockDb db = {}; +MockDb::_serializer_context_t printer; SQLPP_ALIAS_PROVIDER(kaesekuchen); int main() @@ -43,99 +43,123 @@ int main() test::TabFoo f; test::TabBar t; - interpret(insert_into(t).columns(t.gamma, t.beta), printer).flush(); - interpret(insert_into(t).columns(t.gamma, t.beta).add_values(t.gamma = true, t.beta = "cheesecake"), printer).flush(); - interpret(insert_into(t).columns(t.gamma, t.beta) - .add_values(t.gamma = true, t.beta = "cheesecake") - .add_values(t.gamma = false, t.beta = sqlpp::tvin("coffee")) - .add_values(t.gamma = false, t.beta = sqlpp::tvin(std::string())) - , printer).flush(); - interpret(insert_into(t).columns(t.gamma, t.beta) - .add_values(t.gamma = sqlpp::default_value, t.beta = sqlpp::null) - , printer).flush(); + serialize(insert_into(t).columns(t.beta, t.gamma), printer).str(); + { + auto i = insert_into(t).columns(t.gamma, t.beta); + i.add_values(t.gamma = true, t.beta = "cheesecake"); + serialize(i, printer).str(); + i.add_values(t.gamma = false, t.beta = sqlpp::tvin("coffee")); + i.add_values(t.gamma = false, t.beta = sqlpp::tvin(std::string())); + serialize(i, printer).str(); + i.add_values(t.gamma = sqlpp::default_value, t.beta = sqlpp::null); + serialize(i, printer).str(); + } - interpret(t.alpha = sqlpp::null, printer).flush(); - interpret(t.alpha = sqlpp::default_value, printer).flush(); - interpret(t.alpha, printer).flush(); - interpret(-t.alpha, printer).flush(); - interpret(+t.alpha, printer).flush(); - interpret(-(t.alpha + 7), printer).flush(); - interpret(t.alpha = 0, printer).flush(); - interpret(t.alpha = sqlpp::tvin(0), printer).flush(); - interpret(t.alpha == 0, printer).flush(); - interpret(t.alpha == sqlpp::tvin(0), printer).flush(); - interpret(t.alpha != 0, printer).flush(); - interpret(t.gamma != sqlpp::tvin(false), printer).flush(); - interpret(t.alpha == 7, printer).flush(); - interpret(t.beta + "kaesekuchen", printer).flush(); + serialize(t.alpha = sqlpp::null, printer).str(); + serialize(t.alpha = sqlpp::default_value, printer).str(); + serialize(t.alpha, printer).str(); + serialize(-t.alpha, printer).str(); + serialize(+t.alpha, printer).str(); + serialize(-(t.alpha + 7), printer).str(); + serialize(t.alpha = 0, printer).str(); + serialize(t.alpha = sqlpp::tvin(0), printer).str(); + serialize(t.alpha == 0, printer).str(); + serialize(t.alpha == sqlpp::tvin(0), printer).str(); + serialize(t.alpha != 0, printer).str(); + serialize(t.gamma != sqlpp::tvin(false), printer).str(); + serialize(t.alpha == 7, printer).str(); + serialize(t.beta + "kaesekuchen", printer).str(); - interpret(select(sqlpp::distinct, t.alpha, t.beta), printer).flush(); - interpret(select(sqlpp::distinct, t.alpha, t.beta).from(t), printer).flush(); - interpret(select(sqlpp::distinct, t.alpha, t.beta).from(t).where(t.alpha == 3), printer).flush(); - interpret(select(sqlpp::distinct, t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma), printer).flush(); - interpret(select(sqlpp::distinct, t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")), printer).flush(); - interpret(select(sqlpp::distinct, t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")).order_by(t.beta.asc()), printer).flush(); - interpret(select(sqlpp::distinct, t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")).order_by(t.beta.asc()).limit(17).offset(3), printer).flush(); + serialize(sqlpp::select(), printer).str(); + serialize(sqlpp::select().flags(sqlpp::distinct), printer).str(); + serialize(select(t.alpha, t.beta).flags(sqlpp::distinct), printer).str(); + serialize(select(t.alpha, t.beta), printer).str(); + serialize(select(t.alpha, t.beta).from(t), printer).str(); + serialize(select(t.alpha, t.beta).from(t).where(t.alpha == 3), printer).str(); + serialize(select(t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma), printer).str(); + serialize(select(t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")), printer).str(); + serialize(select(t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")).order_by(t.beta.asc()), printer).str(); + serialize(select(t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")).order_by(t.beta.asc()).limit(17).offset(3), printer).str(); - interpret(parameter(sqlpp::bigint(), t.alpha), printer).flush(); - interpret(parameter(t.alpha), printer).flush(); - interpret(t.alpha == parameter(t.alpha), printer).flush(); - interpret(t.alpha == parameter(t.alpha) and (t.beta + "gimmick").like(parameter(t.beta)), printer).flush(); + serialize(parameter(sqlpp::bigint(), t.alpha), printer).str(); + serialize(parameter(t.alpha), printer).str(); + serialize(t.alpha == parameter(t.alpha), printer).str(); + serialize(t.alpha == parameter(t.alpha) and (t.beta + "gimmick").like(parameter(t.beta)), printer).str(); - interpret(insert_into(t), printer).flush(); - interpret(insert_into(f).default_values(), printer).flush(); - interpret(insert_into(t).set(t.gamma = true), printer).flush(); - //interpret(insert_into(t).set(t.gamma = sqlpp::tvin(false)), printer).flush(); cannot test this since gamma cannot be null and a static assert is thrown + serialize(insert_into(t), printer).str(); + serialize(insert_into(f).default_values(), printer).str(); + serialize(insert_into(t).set(t.gamma = true), printer).str(); + //serialize(insert_into(t).set(t.gamma = sqlpp::tvin(false)), printer).str(); cannot test this since gamma cannot be null and a static assert is thrown - interpret(update(t), printer).flush(); - interpret(update(t).set(t.gamma = true), printer).flush(); - interpret(update(t).set(t.gamma = true).where(t.beta.in("kaesekuchen", "cheesecake")), printer).flush(); + serialize(update(t), printer).str(); + serialize(update(t).set(t.gamma = true), printer).str(); + serialize(update(t).set(t.gamma = true).where(t.beta.in("kaesekuchen", "cheesecake")), printer).str(); - interpret(remove_from(t), printer).flush(); - interpret(remove_from(t).where(t.alpha == sqlpp::tvin(0)), printer).flush(); - interpret(remove_from(t).using_(t).where(t.alpha == sqlpp::tvin(0)), printer).flush(); + serialize(remove_from(t), printer).str(); + serialize(remove_from(t).using_(t), printer).str(); + serialize(remove_from(t).where(t.alpha == sqlpp::tvin(0)), printer).str(); + serialize(remove_from(t).using_(t).where(t.alpha == sqlpp::tvin(0)), printer).str(); // functions - sqlpp::interpret(sqlpp::value(7), printer).flush(); // FIXME: Why is the namespace specifier required? - interpret(sqlpp::verbatim("irgendwas integrales"), printer).flush(); - interpret(sqlpp::value_list(std::vector({1,2,3,4,5,6,8})), printer).flush(); - interpret(exists(select(t.alpha).from(t)), printer).flush(); - interpret(any(select(t.alpha).from(t)), printer).flush(); - interpret(some(select(t.alpha).from(t)), printer).flush(); - interpret(count(t.alpha), printer).flush(); - interpret(min(t.alpha), printer).flush(); - interpret(max(t.alpha), printer).flush(); - interpret(avg(t.alpha), printer).flush(); - interpret(sum(t.alpha), printer).flush(); - interpret(sqlpp::verbatim_table("whatever"), printer).flush(); + sqlpp::serialize(sqlpp::value(7), printer).str();// FIXME: Maybe the vendor namespace is not a good idea? argument lives in namespace vendor + serialize(sqlpp::verbatim("irgendwas integrales"), printer).str(); + serialize(sqlpp::value_list(std::vector({1,2,3,4,5,6,8})), printer).str(); + serialize(exists(select(t.alpha).from(t)), printer).str(); + serialize(any(select(t.alpha).from(t)), printer).str(); + serialize(some(select(t.alpha).from(t)), printer).str(); + serialize(count(t.alpha), printer).str(); + serialize(min(t.alpha), printer).str(); + serialize(max(t.alpha), printer).str(); + serialize(avg(t.alpha), printer).str(); + serialize(sum(t.alpha), printer).str(); + serialize(sqlpp::verbatim_table("whatever"), printer).str(); // alias - interpret(t.as(t.alpha), printer).flush(); - interpret(t.as(t.alpha).beta, printer).flush(); + serialize(t.as(t.alpha), printer).str(); + serialize(t.as(t.alpha).beta, printer).str(); // select alias - interpret(select(t.alpha).from(t).where(t.beta > "kaesekuchen").as(t.gamma), printer).flush(); + serialize(select(t.alpha).from(t).where(t.beta > "kaesekuchen").as(t.gamma), printer).str(); - interpret(t.alpha.is_null(), printer).flush(); + serialize(t.alpha.is_null(), printer).str(); // join - interpret(t.inner_join(t.as(t.alpha)).on(t.beta == t.as(t.alpha).beta), printer).flush(); + serialize(t.inner_join(t.as(t.alpha)).on(t.beta == t.as(t.alpha).beta), printer).str(); // multi_column - interpret(multi_column(t.alpha, t.alpha, (t.beta + "cake").as(t.gamma)), printer).flush(); + serialize(multi_column(t.alpha, (t.beta + "cake").as(t.gamma)).as(t.alpha), printer).str(); + serialize(multi_column(all_of(t)).as(t), printer).str(); + serialize(all_of(t).as(t), printer).str(); // dynamic select - interpret(dynamic_select(db).dynamic_flags().dynamic_columns(t.alpha).add_column(t.beta).add_column(t.gamma), printer).flush(); - interpret(dynamic_select(db).dynamic_flags().add_flag(sqlpp::distinct).dynamic_columns().add_column(t.gamma).add_column(t.beta), printer).flush(); - interpret(dynamic_select(db).dynamic_flags(sqlpp::distinct).add_flag(sqlpp::all).dynamic_columns(t.alpha).add_column(t.beta), printer).flush(); + { + auto s = dynamic_select(db).dynamic_flags().dynamic_columns().from(t); + s.add_column(t.beta); + s.add_column(t.gamma); + serialize(s, printer).str(); + } + { + auto s = dynamic_select(db).dynamic_flags().dynamic_columns().from(t); + s.add_flag(sqlpp::distinct); + s.add_column(t.beta); + s.add_column(t.gamma); + serialize(s, printer).str(); + } + { + auto s = dynamic_select(db).dynamic_flags(sqlpp::distinct).dynamic_columns(t.alpha).extra_tables(t); // Would fail to run() + s.add_flag(sqlpp::all); + s.add_column(t.beta); + s.add_column(t.gamma); + serialize(s, printer).str(); + } // distinct aggregate - interpret(count(sqlpp::distinct, t.alpha % 7), printer).flush(); - interpret(avg(sqlpp::distinct, t.alpha - 7), printer).flush(); - interpret(sum(sqlpp::distinct, t.alpha + 7), printer).flush(); + serialize(count(sqlpp::distinct, t.alpha % 7), printer).str(); + serialize(avg(sqlpp::distinct, t.alpha - 7), printer).str(); + serialize(sum(sqlpp::distinct, t.alpha + 7), printer).str(); - interpret(select(all_of(t)).from(t).where(true), printer).flush(); - interpret(select(all_of(t)).from(t).where(false), printer).flush(); + serialize(select(all_of(t)).from(t).where(true), printer).str(); + serialize(select(all_of(t)).from(t).where(false), printer).str(); return 0; } diff --git a/tests/MockDb.h b/tests/MockDb.h index 7a9e5d37..fd114baf 100644 --- a/tests/MockDb.h +++ b/tests/MockDb.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -24,17 +24,136 @@ */ #ifndef SQLPP_MOCK_DB_H -#define SQLPP_MOCK_DB_H +#define SQLPP_MOCK_DB_H +#include +#include #include -#include -struct DbMock: public sqlpp::connection +struct MockDb: public sqlpp::connection { - struct _context_t : public sqlpp::serializer_t + struct _serializer_context_t { - _context_t(std::ostream& os): sqlpp::serializer_t(os) {} + std::ostringstream _os; + + std::string str() const + { + return _os.str(); + } + + void reset() + { + _os.clear(); + } + + template + std::ostream& operator<<(T t) + { + return _os << t; + } + + static std::string escape(std::string arg) + { + return sqlpp::serializer_context_t::escape(arg); + } }; + + using _interpreter_context_t = _serializer_context_t; + + template + static _serializer_context_t& _serialize_interpretable(const T& t, _serializer_context_t& context) + { + sqlpp::serialize(t, context); + return context; + } + + template + static _serializer_context_t& _interpret_interpretable(const T& t, _interpreter_context_t& context) + { + sqlpp::serialize(t, context); + return context; + } + + class result_t + { + public: + constexpr bool operator==(const result_t& rhs) const + { + return true; + } + + template + void next(ResultRow& result_row) + { + result_row.invalidate(); + }; + }; + + // Directly executed statements start here + template + auto operator() (const T& t) -> decltype(t._run(*this)) + { + return t._run(*this); + } + + template + size_t insert(const Insert& x) + { + return 0; + } + + template + size_t update(const Update& x) + { + return 0; + } + + template + size_t remove(const Remove& x) + { + return 0; + } + + template + result_t select(const Select& s) + { + return {}; + } + + // Prepared statements start here + using _prepared_statement_t = std::nullptr_t; + + template + auto prepare(const T& t) -> decltype(t._prepare(*this)) + { + return t._prepare(*this); + } + + + template + _prepared_statement_t prepare_insert(Insert& x) + { + return nullptr; + } + + template + size_t run_prepared_insert(const PreparedInsert& x) + { + return 0; + } + + template + _prepared_statement_t prepare_select(Select& x) + { + return nullptr; + } + + template + result_t run_prepared_select(PreparedSelect& x) + { + return {}; + } + }; #endif diff --git a/tests/PreparedTest.cpp b/tests/PreparedTest.cpp index 2dc53876..7e6103ae 100644 --- a/tests/PreparedTest.cpp +++ b/tests/PreparedTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -31,7 +31,7 @@ #include -DbMock db = {}; +MockDb db = {}; int main() { @@ -88,6 +88,7 @@ int main() // Wonderful, now take a look at the parameter list of a select { auto s = select(all_of(t)).from(t).where(t.beta.like(parameter(t.beta)) and t.alpha == parameter(t.alpha) or t.gamma != parameter(t.gamma)); + auto p = db.prepare(s); using S = decltype(s); using T = sqlpp::make_parameter_list_t::type; T npl; diff --git a/tests/RemoveTest.cpp b/tests/RemoveTest.cpp index 616a2eaf..f4ce1302 100644 --- a/tests/RemoveTest.cpp +++ b/tests/RemoveTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -25,14 +25,13 @@ #include #include -#include #include "Sample.h" #include "MockDb.h" #include "is_regular.h" -DbMock db; -DbMock::_context_t printer(std::cerr); +MockDb db; +MockDb::_serializer_context_t printer; int main() { @@ -53,17 +52,19 @@ int main() } { - using T = decltype(dynamic_remove_from(db, t).dynamic_using_().dynamic_where()); + using T = decltype(dynamic_remove_from(db, t).dynamic_using().dynamic_where()); static_assert(sqlpp::is_regular::value, "type requirement"); } - interpret(remove_from(t), printer).flush(); - interpret(remove_from(t).where(t.beta != "transparent"), printer).flush(); - interpret(remove_from(t).using_(t), printer).flush(); - auto r = dynamic_remove_from(db, t).dynamic_using_().dynamic_where(); - r = r.add_using_(t); - r = r.add_where(t.beta != "transparent"); - interpret(r, printer).flush(); + serialize(remove_from(t), printer).str(); + serialize(remove_from(t).where(t.beta != "transparent"), printer).str(); + serialize(remove_from(t).using_(t), printer).str(); + auto r = dynamic_remove_from(db, t).dynamic_using().dynamic_where(); + r.add_using(t); + r.add_where(t.beta != "transparent"); + serialize(r, printer).str(); + + db(r); return 0; } diff --git a/tests/SelectTest.cpp b/tests/SelectTest.cpp index 94b2b790..c82f1dc2 100644 --- a/tests/SelectTest.cpp +++ b/tests/SelectTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -23,6 +23,7 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include "Sample.h" #include "MockDb.h" #include "is_regular.h" @@ -31,10 +32,9 @@ #include #include -#include -DbMock db = {}; -DbMock::_context_t printer(std::cerr); +MockDb db = {}; +MockDb::_serializer_context_t printer; namespace alias { @@ -49,328 +49,39 @@ int main() test::TabFoo f; test::TabBar t; - // Test a table + for (const auto& row : db(select(all_of(t)).from(t).where(true))) { - using T = decltype(t); - static_assert(not sqlpp::is_numeric_t::value, "type requirement"); - static_assert(not sqlpp::is_integral_t::value, "type requirement"); - static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); - static_assert(not sqlpp::is_expression_t::value, "type requirement"); - static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(not sqlpp::is_alias_t::value, "type requirement"); - static_assert(sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); + int64_t a = row.alpha; + const std::string b = row.beta; } - // Test an alias of table + for (const auto& row : db(select(all_of(t).as(t)).from(t).where(true))) { - using T = decltype(t.as(alias::a)); - static_assert(not sqlpp::is_numeric_t::value, "type requirement"); - static_assert(not sqlpp::is_integral_t::value, "type requirement"); - static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); - static_assert(not sqlpp::is_expression_t::value, "type requirement"); - static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(sqlpp::is_alias_t::value, "type requirement"); - static_assert(sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); + int64_t a = row.tabBar.alpha; + const std::string b = row.tabBar.beta; } - // Test an integral column of an alias of table + for (const auto& row : db(select(all_of(t).as(t), t.gamma).from(t).where(t.alpha > 7))) { - using T = decltype(t.as(alias::a).alpha); - static_assert(sqlpp::is_numeric_t::value, "type requirement"); - static_assert(sqlpp::is_integral_t::value, "type requirement"); - static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); - static_assert(sqlpp::is_expression_t::value, "type requirement"); - static_assert(sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(not sqlpp::is_alias_t::value, "type requirement"); - static_assert(not sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); + int64_t a = row.tabBar.alpha; + const std::string b = row.tabBar.beta; + const bool g = row.gamma; } - - // Test an integral table column + auto s = dynamic_select(db).dynamic_columns(all_of(t)).dynamic_flags().dynamic_from(t).extra_tables(f,t).dynamic_where().dynamic_group_by(t.alpha).dynamic_order_by().dynamic_having(t.gamma).dynamic_limit().dynamic_offset(); + s.add_flag(sqlpp::distinct); + s.add_column(f.omega); + s.add_from(f); + s.add_where(t.alpha > 7); + s.add_having(t.alpha > 7); + s.set_limit(3); + s.set_offset(3); + s.add_group_by(t.beta); + s.add_order_by(t.beta.asc()); + for (const auto& row : db(s)) { - using T = decltype(t.alpha); - static_assert(sqlpp::is_numeric_t::value, "type requirement"); - static_assert(sqlpp::is_integral_t::value, "type requirement"); - static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); - static_assert(sqlpp::is_expression_t::value, "type requirement"); - static_assert(sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(not sqlpp::is_alias_t::value, "type requirement"); - static_assert(not sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); + int64_t a = row.alpha; } - // Test a floating point table column - { - using T = decltype(f.omega); - static_assert(sqlpp::is_numeric_t::value, "type requirement"); - static_assert(not sqlpp::is_integral_t::value, "type requirement"); - static_assert(sqlpp::is_floating_point_t::value, "type requirement"); - static_assert(sqlpp::is_expression_t::value, "type requirement"); - static_assert(sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(not sqlpp::is_alias_t::value, "type requirement"); - static_assert(not sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); - } - - // Test a an alias of a numeric table column - { - using T = decltype(t.alpha.as(alias::a)); - static_assert(sqlpp::is_numeric_t::value, "type requirement"); - static_assert(not sqlpp::is_expression_t::value, "type requirement"); - static_assert(sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(sqlpp::is_alias_t::value, "type requirement"); - static_assert(not sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); - } - - // Test a select of a single column without a from - { - using T = decltype(select(t.alpha)); // Hint: The current rule is pretty crude (a from is required), but certainly better than nothing - static_assert(not sqlpp::is_numeric_t::value, "type requirement"); - static_assert(not sqlpp::is_expression_t::value, "type requirement"); - static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(not sqlpp::is_alias_t::value, "type requirement"); - static_assert(not sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); - } - - // Test a select of a single numeric table column - { - using T = decltype(select(t.alpha).from(t)); - static_assert(sqlpp::is_numeric_t::value, "type requirement"); - static_assert(sqlpp::is_expression_t::value, "type requirement"); - static_assert(sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(not sqlpp::is_alias_t::value, "type requirement"); - static_assert(not sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); - } - - // Test a select of an alias of a single numeric table column - { - using T = decltype(select(t.alpha.as(alias::a)).from(t)); - static_assert(sqlpp::is_numeric_t::value, "type requirement"); - static_assert(sqlpp::is_expression_t::value, "type requirement"); - static_assert(sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(not sqlpp::is_alias_t::value, "type requirement"); - static_assert(not sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); - } - - // Test an alias of a select of a single numeric table column - { - using T = decltype(select(t.alpha).from(t).as(alias::b)); - static_assert(not sqlpp::is_numeric_t::value, "type requirement"); - static_assert(not sqlpp::is_expression_t::value, "type requirement"); - static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "red to not be boolean"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(sqlpp::is_alias_t::value, "type requirement"); - static_assert(sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); - } - - // Test the column of an alias of a select of an alias of a single numeric table column - { - using T = decltype(select(t.alpha.as(alias::a)).from(t).as(alias::b)); - static_assert(not sqlpp::is_numeric_t::value, "type requirement"); - static_assert(not sqlpp::is_expression_t::value, "type requirement"); - static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(sqlpp::is_alias_t::value, "type requirement"); - static_assert(sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); - } - - // Test the column of an alias of a select of a single numeric table column - { - using T = decltype(select(t.alpha).from(t).as(alias::b).alpha); - static_assert(sqlpp::is_numeric_t::value, "type requirement"); - static_assert(sqlpp::is_expression_t::value, "type requirement"); - static_assert(sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(not sqlpp::is_alias_t::value, "type requirement"); - static_assert(not sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); - } - - // Test an alias of a select of an alias of a single numeric table column - { - using T = decltype(select(t.alpha.as(alias::a)).from(t).as(alias::b).a); - static_assert(sqlpp::is_numeric_t::value, "type requirement"); - static_assert(sqlpp::is_expression_t::value, "type requirement"); - static_assert(sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(not sqlpp::is_alias_t::value, "type requirement"); - static_assert(not sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); - } - - // Test that select(all_of(tab)) is expanded in select - { - auto a = select(all_of(t)); - auto b = select(t.alpha, t.beta, t.gamma); - //auto c = select(t); - static_assert(std::is_same::value, "all_of(t) has to be expanded by select()"); - //static_assert(std::is_same::value, "t has to be expanded by select()"); - } - - // Test that select(all_of(tab)) is expanded in multi_column - { - auto a = multi_column(alias::a, all_of(t)); - auto b = multi_column(alias::a, t.alpha, t.beta, t.gamma); - static_assert(std::is_same::value, "all_of(t) has to be expanded by multi_column"); - } - - // Test that select(tab) is expanded in multi_column - { - auto a = multi_column(alias::a, all_of(t)); - auto b = multi_column(alias::a, t.alpha, t.beta, t.gamma); - static_assert(std::is_same::value, "t has to be expanded by multi_column"); - } - - // Test that a multicolumn is not a value - { - auto m = multi_column(alias::a, t.alpha, t.beta); - auto a = select(m).from(t).as(alias::b).a; - static_assert(not sqlpp::is_value_t::value, "a multi_column is not a value"); - } - - // Test that result sets with identical name/value combinations have identical types - { - auto a = select(t.alpha); - auto b = select(f.epsilon.as(t.alpha)); - using A = typename decltype(a)::_result_row_t; - using B = typename decltype(b)::_result_row_t; - static_assert(std::is_same< - decltype(t.alpha)::_value_type::_base_value_type, - decltype(f.epsilon)::_value_type::_base_value_type>::value, "Two bigint columns must have identical base_value_type"); - static_assert(std::is_same::value, "select with identical columns(name/value_type) need to have identical result_types"); - } - - { - auto s = dynamic_select(db, all_of(t)).dynamic_from().dynamic_where().dynamic_limit().dynamic_offset(); - s = s.add_from(t); - s = s.add_where(t.alpha > 7 and t.alpha == any(select(t.alpha).from(t).where(t.alpha < 3))); - s = s.set_limit(30); - s = s.set_limit(3); - std::cerr << "------------------------\n"; - interpret(s, printer).flush(); - std::cerr << "------------------------\n"; - using T = decltype(s); - static_assert(sqlpp::is_regular::value, "type requirement"); - } - - // Test that select can be called with zero columns if it is used with dynamic columns. - { - auto s = dynamic_select(db).dynamic_columns().add_column(t.alpha); - interpret(s, printer).flush(); - } - - // Test that verbatim_table compiles - { - auto s = select(t.alpha).from(sqlpp::verbatim_table("my_unknown_table")); - interpret(s, printer).flush(); - } - - - static_assert(sqlpp::is_select_flag_t::value, "sqlpp::all has to be a select_flag"); - using T = sqlpp::vendor::wrap_operand::type; - static_assert(sqlpp::is_regular::value, "type requirement"); - static_assert(T::_is_expression, "T has to be an expression"); - static_assert(std::is_same::value, "T has to be a numeric"); - static_assert(sqlpp::is_numeric_t::value, "T has to be a numeric"); - static_assert(sqlpp::is_numeric_t::value, "TabBar.alpha has to be a numeric"); - ((t.alpha + 7) + 4).asc(); - static_assert(sqlpp::is_boolean_t::value, "Comparison expression have to be boolean"); - auto x = (t.gamma == true) and (t.alpha == 7); - auto y = t.gamma and true and t.gamma; - !t.gamma; - t.beta < "kaesekuchen"; - interpret(t.beta + "hallenhalma", printer).flush(); - static_assert(sqlpp::must_not_insert_t::value, "alpha must not be inserted"); - interpret(t.alpha, printer).flush(); - std::cerr << "\n" << sizeof(test::TabBar) << std::endl; - static_assert(std::is_same::value, "alpha should be a named expression"); - static_assert(sqlpp::is_named_expression_t::value, "alpha should be a named expression"); - static_assert(sqlpp::is_named_expression_t::value, "an alias of alpha should be a named expression"); - static_assert(sqlpp::is_alias_t::value, "an alias of alpha should be an alias"); - auto z = select(t.alpha) == 7; - auto l = t.as(alias::left); - auto r = select(t.gamma.as(alias::a)).from(t).where(t.gamma == true).as(alias::right); - static_assert(sqlpp::is_boolean_t::value, "select(bool) has to be a bool"); - interpret(select(sqlpp::distinct, sqlpp::straight_join, l.alpha, l.beta, select(r.a).from(r)) - .from(l, r) - .where(t.beta == "hello world" and select(t.gamma).from(t))// .as(alias::right)) - .group_by(l.gamma, r.a) - .having(r.a != true) - .order_by(l.beta.asc()) - .limit(17) - .offset(3) - .as(alias::a) - , printer).flush(); - return 0; } diff --git a/tests/SelectTypeTest.cpp b/tests/SelectTypeTest.cpp new file mode 100644 index 00000000..12cf9c56 --- /dev/null +++ b/tests/SelectTypeTest.cpp @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2013-2014, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "Sample.h" +#include "MockDb.h" +#include "is_regular.h" +#include +#include +#include +#include + + +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; + test::TabBar t; + + // Test a table + { + using T = decltype(t); + static_assert(not sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_integral_t::value, "type requirement"); + static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); + static_assert(not sqlpp::is_expression_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(not sqlpp::is_alias_t::value, "type requirement"); + static_assert(sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test an alias of table + { + using T = decltype(t.as(alias::a)); + static_assert(not sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_integral_t::value, "type requirement"); + static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); + static_assert(not sqlpp::is_expression_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(sqlpp::is_alias_t::value, "type requirement"); + static_assert(sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test an integral column of an alias of table + { + using T = decltype(t.as(alias::a).alpha); + static_assert(sqlpp::is_numeric_t::value, "type requirement"); + static_assert(sqlpp::is_integral_t::value, "type requirement"); + static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); + static_assert(sqlpp::is_expression_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(not sqlpp::is_alias_t::value, "type requirement"); + static_assert(not sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + + // Test an integral table column + { + using T = decltype(t.alpha); + static_assert(sqlpp::is_numeric_t::value, "type requirement"); + static_assert(sqlpp::is_integral_t::value, "type requirement"); + static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); + static_assert(sqlpp::is_expression_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(not sqlpp::is_alias_t::value, "type requirement"); + static_assert(not sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test a floating point table column + { + using T = decltype(f.omega); + static_assert(sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_integral_t::value, "type requirement"); + static_assert(sqlpp::is_floating_point_t::value, "type requirement"); + static_assert(sqlpp::is_expression_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(not sqlpp::is_alias_t::value, "type requirement"); + static_assert(not sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test a an alias of a numeric table column + { + using T = decltype(t.alpha.as(alias::a)); + static_assert(sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_expression_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(sqlpp::is_alias_t::value, "type requirement"); + static_assert(not sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test a select of a single column without a from + { + using T = decltype(select(t.alpha)); // Hint: The current rule is pretty crude (a from is required), but certainly better than nothing + static_assert(not sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_expression_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(not sqlpp::is_alias_t::value, "type requirement"); + static_assert(not sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test a select of a single numeric table column + { + using T = decltype(select(t.alpha).from(t)); + static_assert(sqlpp::is_select_column_list_t::value, "Must not be noop"); + static_assert(sqlpp::is_from_t::value, "Must not be noop"); + static_assert(sqlpp::is_numeric_t::value, "type requirement"); + static_assert(sqlpp::is_expression_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(not sqlpp::is_alias_t::value, "type requirement"); + static_assert(not sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test a select of an alias of a single numeric table column + { + using T = decltype(select(t.alpha.as(alias::a)).from(t)); + static_assert(sqlpp::is_numeric_t::value, "type requirement"); + static_assert(sqlpp::is_expression_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(not sqlpp::is_alias_t::value, "type requirement"); + static_assert(not sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test an alias of a select of a single numeric table column + { + using T = decltype(select(t.alpha).from(t).as(alias::b)); + static_assert(not sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_expression_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "red to not be boolean"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(sqlpp::is_alias_t::value, "type requirement"); + static_assert(sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test the column of an alias of a select of an alias of a single numeric table column + { + using T = decltype(select(t.alpha.as(alias::a)).from(t).as(alias::b)); + static_assert(not sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_expression_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(sqlpp::is_alias_t::value, "type requirement"); + static_assert(sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test the column of an alias of a select of a single numeric table column + { + using T = decltype(select(t.alpha).from(t).as(alias::b).alpha); + static_assert(sqlpp::is_numeric_t::value, "type requirement"); + static_assert(sqlpp::is_expression_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(not sqlpp::is_alias_t::value, "type requirement"); + static_assert(not sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test an alias of a select of an alias of a single numeric table column + { + using T = decltype(select(t.alpha.as(alias::a)).from(t).as(alias::b).a); + static_assert(sqlpp::is_numeric_t::value, "type requirement"); + static_assert(sqlpp::is_expression_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(not sqlpp::is_alias_t::value, "type requirement"); + static_assert(not sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test that select(all_of(tab)) is expanded in select + { + auto a = select(all_of(t)); + auto b = select(t.alpha, t.beta, t.gamma, t.delta); + //auto c = select(t); + static_assert(std::is_same::value, "all_of(t) has to be expanded by select()"); + //static_assert(std::is_same::value, "t has to be expanded by select()"); + } + + // Test that select(all_of(tab)) is expanded in multi_column + { + auto a = multi_column(all_of(t)).as(alias::a); + auto b = multi_column(t.alpha, t.beta, t.gamma, t.delta).as(alias::a); + static_assert(std::is_same::value, "all_of(t) has to be expanded by multi_column"); + } + + // Test that a multicolumn is not a value + { + auto m = multi_column(t.alpha, t.beta).as(alias::a); + auto a = select(m).from(t).as(alias::b).a; + static_assert(not sqlpp::is_value_t::value, "a multi_column is not a value"); + } + // Test that result sets with identical name/value combinations have identical types + { + auto a = select(t.alpha); + auto b = select(f.epsilon.as(t.alpha)); + using A = typename decltype(a)::_result_row_t; + using B = typename decltype(b)::_result_row_t; + static_assert(std::is_same< + decltype(t.alpha)::_value_type::_base_value_type, + decltype(f.epsilon)::_value_type::_base_value_type>::value, "Two bigint columns must have identical base_value_type"); + static_assert(std::is_same::value, "select with identical columns(name/value_type) need to have identical result_types"); + } + + for (const auto& row : db(select(all_of(t)).from(t).where(true))) + { + int64_t a = row.alpha; + } + + { + auto s = dynamic_select(db, all_of(t)).dynamic_from().dynamic_where().dynamic_limit().dynamic_offset(); + s.add_from(t); + s.add_where(t.alpha > 7 and t.alpha == any(select(t.alpha).from(t).where(t.alpha < 3))); + s.set_limit(30); + s.set_limit(3); + std::cerr << "------------------------\n"; + serialize(s, printer).str(); + std::cerr << "------------------------\n"; + using T = decltype(s); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test that select can be called with zero columns if it is used with dynamic columns. + { + auto s = dynamic_select(db).dynamic_columns().extra_tables(t); + s.add_column(t.alpha); + serialize(s, printer).str(); + } + + // Test that verbatim_table compiles + { + auto s = select(t.alpha).from(sqlpp::verbatim_table("my_unknown_table")); + serialize(s, printer).str(); + } + + + static_assert(sqlpp::is_select_flag_t::value, "sqlpp::all has to be a select_flag"); + using T = sqlpp::vendor::wrap_operand::type; + static_assert(sqlpp::is_regular::value, "type requirement"); + static_assert(T::_is_expression, "T has to be an expression"); + static_assert(std::is_same::value, "T has to be a numeric"); + static_assert(sqlpp::is_numeric_t::value, "T has to be a numeric"); + static_assert(sqlpp::is_numeric_t::value, "TabBar.alpha has to be a numeric"); + ((t.alpha + 7) + 4).asc(); + static_assert(sqlpp::is_boolean_t::value, "Comparison expression have to be boolean"); + auto x = (t.gamma == true) and (t.alpha == 7); + auto y = t.gamma and true and t.gamma; + !t.gamma; + t.beta < "kaesekuchen"; + serialize(t.beta + "hallenhalma", printer).str(); + static_assert(sqlpp::must_not_insert_t::value, "alpha must not be inserted"); + serialize(t.alpha, printer).str(); + std::cerr << "\n" << sizeof(test::TabBar) << std::endl; + static_assert(std::is_same::value, "alpha should be a named expression"); + static_assert(sqlpp::is_named_expression_t::value, "alpha should be a named expression"); + static_assert(sqlpp::is_named_expression_t::value, "an alias of alpha should be a named expression"); + static_assert(sqlpp::is_alias_t::value, "an alias of alpha should be an alias"); + + auto z = select(t.alpha).from(t) == 7; + auto l = t.as(alias::left); + auto r = select(t.gamma.as(alias::a)).from(t).where(t.gamma == true).as(alias::right); + using R = decltype(r); + static_assert(sqlpp::is_boolean_t::value, "select(bool) has to be a bool"); + auto s = select(r.a).from(r); + using RA = decltype(r.a); + using S = decltype(s); + using SCL = typename S::_column_list_t; + using SF = typename S::_from_t; + static_assert(sqlpp::is_select_column_list_t::value, "no column list"); + static_assert(sqlpp::is_from_t::value, "no from list"); + using SCL_T = typename SCL::_table_set; + using SF_T = typename SF::_table_set; + static_assert(SCL_T::size::value == 1, "unexpected table_set in column_list"); + static_assert(SF_T::size::value == 1, "unexpected table_set in from"); + static_assert(std::is_same::value, "should be the same"); + static_assert(sqlpp::is_boolean_t::value, "select(bool) has to be a bool"); + auto s1 = sqlpp::select().flags(sqlpp::distinct, sqlpp::straight_join).columns(l.alpha, l.beta, select(r.a).from(r)) + .from(r,t,l) + .where(t.beta == "hello world" and select(t.gamma).from(t))// .as(alias::right)) + .group_by(l.gamma, r.a) + .having(r.a != true) + .order_by(l.beta.asc()) + .limit(17) + .offset(3) + .as(alias::a) + ; + + + return 0; +} diff --git a/tests/UpdateTest.cpp b/tests/UpdateTest.cpp index a46c3dbd..fcf0c6d3 100644 --- a/tests/UpdateTest.cpp +++ b/tests/UpdateTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -29,12 +29,13 @@ #include "MockDb.h" #include "is_regular.h" -DbMock db; -DbMock::_context_t printer(std::cerr); +MockDb db; +MockDb::_serializer_context_t printer; int main() { test::TabBar t; + test::TabFoo f; auto x = t.alpha = 7; auto y = t.beta = "kaesekuchen"; @@ -55,12 +56,16 @@ int main() static_assert(sqlpp::is_regular::value, "type requirement"); } - interpret(update(t), printer).flush(); - interpret(update(t).set(t.gamma = false), printer).flush(); - interpret(update(t).set(t.gamma = false).where(t.beta != "transparent"), printer).flush(); + serialize(update(t), printer).str(); + serialize(update(t).set(t.gamma = false), printer).str(); + serialize(update(t).set(t.gamma = false).where(t.beta != "transparent"), printer).str(); + serialize(update(t).set(t.beta = "opaque").where(t.beta != t.beta), printer).str(); auto u = dynamic_update(db, t).dynamic_set(t.gamma = false).dynamic_where(); - u = u.add_set(t.gamma = false); - interpret(u, printer).flush(); + u.add_set(t.gamma = false); + u.add_where(t.gamma != false); + serialize(u, printer).str(); + + db(u); return 0; } diff --git a/tests/is_regular.h b/tests/is_regular.h index 6e99e0e1..190d0838 100644 --- a/tests/is_regular.h +++ b/tests/is_regular.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, diff --git a/tests/sample.sql b/tests/sample.sql index 87e26c94..d70387e3 100644 --- a/tests/sample.sql +++ b/tests/sample.sql @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Roland Bock + * Copyright (c) 2013-2014, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -26,6 +26,7 @@ CREATE TABLE tab_foo ( + delta varchar(255), epsilon bigint, omega double ); @@ -34,6 +35,7 @@ CREATE TABLE tab_bar ( alpha bigint AUTO_INCREMENT, beta varchar(255) NULL DEFAULT "", - gamma bool NOT NULL + gamma bool NOT NULL, + delta int );