From 47ae6a2e76524aac3c4bc7ab91c0b58782a7db8d Mon Sep 17 00:00:00 2001 From: rbock Date: Sat, 11 Jan 2014 21:51:57 +0100 Subject: [PATCH] Continued to implement standard serializing interpreters Everything that is interpreted also has to move out of detail namespace, because it might have to be specialized for a database connector --- include/sqlpp11/column.h | 3 +- include/sqlpp11/concat.h | 41 ++++---- include/sqlpp11/detail/basic_operators.h | 2 +- include/sqlpp11/detail/serialize_tuple.h | 73 --------------- include/sqlpp11/detail/wrap_operand.h | 113 +++++++++-------------- include/sqlpp11/expression.h | 65 +++++++------ include/sqlpp11/expression_fwd.h | 17 +++- include/sqlpp11/in.h | 2 +- include/sqlpp11/interpret_tuple.h | 77 +++++++++++++++ include/sqlpp11/interpreter.h | 8 +- include/sqlpp11/text.h | 4 +- tests/InterpretTest.cpp | 6 +- tests/MockDb.h | 12 ++- 13 files changed, 215 insertions(+), 208 deletions(-) delete mode 100644 include/sqlpp11/detail/serialize_tuple.h create mode 100644 include/sqlpp11/interpret_tuple.h diff --git a/include/sqlpp11/column.h b/include/sqlpp11/column.h index 8fdb5cae..e87795e8 100644 --- a/include/sqlpp11/column.h +++ b/include/sqlpp11/column.h @@ -85,9 +85,10 @@ namespace sqlpp { using T = column_t; template - static void _(const T& t, Context& context) + static Context& _(const T& t, Context& context) { context << T::_table::_name_t::_get_name() << '.' << T::_name_t::_get_name(); + return context; } }; diff --git a/include/sqlpp11/concat.h b/include/sqlpp11/concat.h index 842e54f3..c0da8d66 100644 --- a/include/sqlpp11/concat.h +++ b/include/sqlpp11/concat.h @@ -29,12 +29,11 @@ #include #include +#include #include namespace sqlpp { - namespace detail - { template struct concat_t: public First::_value_type::template operators> { @@ -71,31 +70,27 @@ namespace sqlpp concat_t& operator=(concat_t&&) = default; ~concat_t() = default; - template - void serialize(std::ostream& os, Db& db) const - { - static_assert(Db::_use_concat_operator or Db::_use_concat_function, "neither concat operator nor concat function supported by current database"); - if (Db::_use_concat_operator) - { - os << "("; - detail::serialize_tuple(os, db, _args, "||"); - os << ")"; - } - else if (Db::_use_concat_function) - { - os << "CONCAT("; - detail::serialize_tuple(os, db, _args, ','); - os << ")"; - } - } - - private: std::tuple _args; }; - } + + //FIXME: Write partial specialization for mysql + template + struct interpreter_t> + { + using T = concat_t; + template + static Context& _(const T& t, Context& context) + { + context << "("; + interpret_tuple(t._args, "||", context); + context << ")"; + return context; + } + }; + template - auto concat(T&&... t) -> typename detail::concat_t::type...> + auto concat(T&&... t) -> concat_t::type...> { return { std::forward(t)... }; } diff --git a/include/sqlpp11/detail/basic_operators.h b/include/sqlpp11/detail/basic_operators.h index 630555eb..7498ea05 100644 --- a/include/sqlpp11/detail/basic_operators.h +++ b/include/sqlpp11/detail/basic_operators.h @@ -27,7 +27,7 @@ #ifndef SQLPP_DETAIL_BASIC_OPERATORS_H #define SQLPP_DETAIL_BASIC_OPERATORS_H -#include +#include #include #include #include diff --git a/include/sqlpp11/detail/serialize_tuple.h b/include/sqlpp11/detail/serialize_tuple.h deleted file mode 100644 index d73d9ba9..00000000 --- a/include/sqlpp11/detail/serialize_tuple.h +++ /dev/null @@ -1,73 +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_DETAIL_SERIALIZE_TUPLE_H -#define SQLPP_DETAIL_SERIALIZE_TUPLE_H - -#include -#include -#include - -namespace sqlpp -{ - namespace detail - { - template - struct tuple_serializer_impl - { - template - static void serialize(std::ostream& os, Db& db, const Tuple& flags_and_columns, const Separator& separator) - { - if (index > begin) - os << separator; - const auto& entry = std::get(flags_and_columns); - using entry_type = typename std::tuple_element::type; - if (requires_braces_t::value) - os << "("; - entry.serialize(os, db); - if (requires_braces_t::value) - os << ")"; - tuple_serializer_impl::serialize(os, db, flags_and_columns, separator); - } - }; - template - struct tuple_serializer_impl - { - template - static void serialize(std::ostream& os, Db& db, const Tuple& flags_and_columns, const Separator& separator) - { - } - }; - - template - static void serialize_tuple(std::ostream& os, Db& db, const Tuple& flags_and_columns, const Separator& separator) - { - tuple_serializer_impl<0, 0, std::tuple_size::value>::serialize(os, db, flags_and_columns, separator); - } - } -} - -#endif diff --git a/include/sqlpp11/detail/wrap_operand.h b/include/sqlpp11/detail/wrap_operand.h index 7ff0c3ab..00f22cb5 100644 --- a/include/sqlpp11/detail/wrap_operand.h +++ b/include/sqlpp11/detail/wrap_operand.h @@ -27,7 +27,6 @@ #ifndef SQLPP_DETAIL_WRAP_OPERAND_H #define SQLPP_DETAIL_WRAP_OPERAND_H -#include #include // FIXME: must leave detail, since it is interpreted (and might require specializations) @@ -42,63 +41,48 @@ namespace sqlpp struct text; } - struct bool_operand + struct boolean_operand { static constexpr bool _is_expression = true; using _value_type = detail::boolean; - bool_operand(bool t): _t(t) {} - bool_operand(const bool_operand&) = default; - bool_operand(bool_operand&&) = default; - bool_operand& operator=(const bool_operand&) = default; - bool_operand& operator=(bool_operand&&) = default; - ~bool_operand() = default; - - template - void serialize(std::ostream& os, Db& db) const - { - os << _t; - } - bool _is_trivial() const { return _t == false; } bool _t; }; + template + struct interpreter_t + { + using Operand = boolean_operand; + template + static void _(const Operand& t, Context& context) + { + context << t._t; + } + }; + template struct integral_operand { static constexpr bool _is_expression = true; using _value_type = detail::integral; - integral_operand(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; - - template - void serialize(std::ostream& os, Db& db) const - { - os << _t; - } - bool _is_trivial() const { return _t == 0; } T _t; }; - template - struct interpreter_t> - { - using Operand = integral_operand; - template - static void _(const Operand& t, Context& context) - { - context << t._t; - } - }; + template + struct interpreter_t> + { + using Operand = integral_operand; + template + static void _(const Operand& t, Context& context) + { + context << t._t; + } + }; template @@ -107,48 +91,43 @@ namespace sqlpp static constexpr bool _is_expression = true; using _value_type = detail::floating_point; - floating_point_operand(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; - - template - void serialize(std::ostream& os, Db& db) const - { - os << _t; - } - bool _is_trivial() const { return _t == 0; } T _t; }; - template + template + struct interpreter_t> + { + using Operand = floating_point_operand; + template + static void _(const Operand& t, Context& context) + { + context << t._t; + } + }; + struct text_operand { static constexpr bool _is_expression = true; using _value_type = detail::text; - text_operand(const 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; - - template - void serialize(std::ostream& os, Db& db) const - { - os << '\'' << db.escape(_t) << '\''; - } - bool _is_trivial() const { return _t.empty(); } std::string _t; }; + template + struct interpreter_t + { + using Operand = text_operand; + template + static void _(const Operand& t, Context& context) + { + context << '\'' << context.escape(t._t) << '\''; + } + }; + template struct wrap_operand { @@ -158,7 +137,7 @@ namespace sqlpp template<> struct wrap_operand { - using type = bool_operand; + using type = boolean_operand; }; template @@ -176,7 +155,7 @@ namespace sqlpp template struct wrap_operand::value>::type> { - using type = text_operand; + using type = text_operand; }; } diff --git a/include/sqlpp11/expression.h b/include/sqlpp11/expression.h index e2f829c1..590e0ca2 100644 --- a/include/sqlpp11/expression.h +++ b/include/sqlpp11/expression.h @@ -28,7 +28,9 @@ #define SQLPP_EXPRESSION_H #include +#include #include +#include #include #include #include @@ -51,7 +53,7 @@ namespace sqlpp { using T = assignment_t; template - static void _(const T& t, Context& context) + static Context& _(const T& t, Context& context) { interpret(t._lhs, context); if (trivial_value_is_null_t::value and t._rhs._is_trivial()) @@ -63,14 +65,15 @@ namespace sqlpp context << "="; interpret(t._rhs, context); } + return context; } }; - template - struct equal_t: public ValueType::template operators> + template + struct equal_t: public detail::boolean::template operators> { - using _value_type = ValueType; // FIXME: Can we use boolean directly here? + using _value_type = detail::boolean; template equal_t(L&& l, R&& r): @@ -89,16 +92,16 @@ namespace sqlpp Rhs _rhs; }; - template - struct interpreter_t> + template + struct interpreter_t> { - using T = equal_t; + using T = equal_t; template - static void interpret(const T& t, Context& context) + static Context& interpret(const T& t, Context& context) { context << "("; interpret(t._lhs, context); - if (trivial_value_is_null_t::value and t._rhs._is_trivial()) + if (trivial_value_is_null_t::value and t._rhs._is_trivial()) { context << "IS NULL"; } @@ -108,13 +111,14 @@ namespace sqlpp interpret(t._rhs, context); } context << ")"; + return context; } }; - template - struct not_equal_t: public ValueType::template operators> + template + struct not_equal_t: public detail::boolean::template operators> { - using _value_type = ValueType; + using _value_type = detail::boolean; template not_equal_t(L&& l, R&& r): @@ -132,16 +136,16 @@ namespace sqlpp Rhs _rhs; }; - template - struct interpreter_t> + template + struct interpreter_t> { - using T = not_equal_t; + using T = not_equal_t; template - static void interpret(const T& t, Context& context) + static Context& interpret(const T& t, Context& context) { context << "("; interpret(t._lhs, context); - if (trivial_value_is_null_t::value and t._rhs._is_trivial()) + if (trivial_value_is_null_t::value and t._rhs._is_trivial()) { context << "IS NOT NULL"; } @@ -151,13 +155,14 @@ namespace sqlpp interpret(t._rhs, context); } context << ")"; + return context; } }; - template - struct not_t: public ValueType::template operators> + template + struct not_t: public detail::boolean::template operators> { - using _value_type = ValueType; + using _value_type = detail::boolean; not_t(Lhs l): _lhs(l) @@ -172,15 +177,15 @@ namespace sqlpp Lhs _lhs; }; - template - struct interpreter_t> + template + struct interpreter_t> { - using T = not_t; + using T = not_t; template - static void interpret(const T& t, Context& context) + static Context& interpret(const T& t, Context& context) { context << "("; - if (trivial_value_is_null_t::value and t._lhs._is_trivial()) + if (trivial_value_is_null_t::value and t._lhs._is_trivial()) { interpret(t._lhs, context); context << "IS NULL"; @@ -191,6 +196,7 @@ namespace sqlpp interpret(t._lhs, context); } context << ")"; + return context; } }; @@ -214,18 +220,19 @@ namespace sqlpp Rhs _rhs; }; - template - struct interpreter_t> + template + struct interpreter_t> { - using T = binary_expression_t; + using T = binary_expression_t; template - static void interpret(const T& t, Context& context) + static Context& interpret(const T& t, Context& context) { context << "("; interpret(t._lhs, context); context << T::O::_name; interpret(t._rhs, context); context << ")"; + return context; } }; diff --git a/include/sqlpp11/expression_fwd.h b/include/sqlpp11/expression_fwd.h index e2c71b00..cdab55bc 100644 --- a/include/sqlpp11/expression_fwd.h +++ b/include/sqlpp11/expression_fwd.h @@ -29,11 +29,20 @@ namespace sqlpp { - template - struct is_expression_t; + template + struct assignment_t; - template - struct is_named_expression_t; + template + struct equal_t; + + template + struct not_equal_t; + + template + struct not_t; + + template + struct binary_expression_t; } #endif diff --git a/include/sqlpp11/in.h b/include/sqlpp11/in.h index 9a864363..9cb501cc 100644 --- a/include/sqlpp11/in.h +++ b/include/sqlpp11/in.h @@ -80,7 +80,7 @@ namespace sqlpp or (_inverted and Db::_supports_not_in), "in() and/or not_in() not supported by current database"); _operand.serialize(os, db); os << (_inverted ? " NOT IN(" : " IN("); - detail::serialize_tuple(os, db, _args, ','); + serialize_tuple(os, db, _args, ','); os << ")"; } diff --git a/include/sqlpp11/interpret_tuple.h b/include/sqlpp11/interpret_tuple.h new file mode 100644 index 00000000..e3b4a094 --- /dev/null +++ b/include/sqlpp11/interpret_tuple.h @@ -0,0 +1,77 @@ +/* + * 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_INTERPRET_TUPLE_H +#define SQLPP_INTERPRET_TUPLE_H + +#include +#include +#include + +namespace sqlpp +{ + template + struct tuple_interpreter_t + { + template + static void _(const Tuple& t, const Separator& separator, Context& context) + { + _impl(t, separator, context, type<0>()); + }; + + private: + template struct type {}; + + template + static void _impl(const Tuple& t, const Separator& separator, Context& context, const type&) + { + if (index) + context << separator; + const auto& entry = std::get(t); + using entry_type = typename std::tuple_element::type; + if (requires_braces_t::value) + context << "("; + interpret(entry, context); + if (requires_braces_t::value) + context << ")"; + _impl(t, separator, context, type()); + } + + template + static void _impl(const Tuple& t, const Separator& separator, Context& context, const type::value>&) + { + } + }; + + template + auto interpret_tuple(const Tuple& t, const Separator& separator, Context& context) + -> decltype(tuple_interpreter_t::type::_database_t, typename std::decay::type>::_(t, separator, context)) + { + return tuple_interpreter_t::type::_database_t, typename std::decay::type>::_(t, separator, context); + } +} + +#endif diff --git a/include/sqlpp11/interpreter.h b/include/sqlpp11/interpreter.h index e72ab8cb..518c6834 100644 --- a/include/sqlpp11/interpreter.h +++ b/include/sqlpp11/interpreter.h @@ -42,11 +42,11 @@ namespace sqlpp } }; - template - void interpret(const T& t, Context& context) + template + auto interpret(const T& t, Context& context) + -> decltype(interpreter_t::type::_database_t, typename std::decay::type>::_(t, context)) { - using Db = typename std::decay::type::_database_t; - interpreter_t::type>::_(t, context); + return interpreter_t::type::_database_t, typename std::decay::type>::_(t, context); } } diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index f003c115..da31c35b 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -196,10 +196,10 @@ namespace sqlpp struct operators: public basic_operators { template - detail::concat_t::type> operator+(T&& t) const + concat_t::type> operator+(T&& t) const { static_assert(not is_multi_expression_t::value, "multi-expression cannot be used as left hand side operand"); - return { *static_cast(this), std::forward(t) }; + return { *static_cast(this), {std::forward(t)} }; } template diff --git a/tests/InterpretTest.cpp b/tests/InterpretTest.cpp index 4f5d3f31..6c48d56b 100644 --- a/tests/InterpretTest.cpp +++ b/tests/InterpretTest.cpp @@ -36,8 +36,10 @@ int main() { TabSample t; - interpret(t.alpha, printer); - interpret(t.alpha = 7, printer); + interpret(t.alpha, printer).flush(); + interpret(t.alpha = 7, printer).flush(); + sqlpp::text_operand o = {"kaesekuchen"}; + interpret(t.beta + "kaesekuchen", printer).flush(); return 0; } diff --git a/tests/MockDb.h b/tests/MockDb.h index f0165be0..1a188dfa 100644 --- a/tests/MockDb.h +++ b/tests/MockDb.h @@ -39,11 +39,21 @@ public: {} template - std::ostream& operator<<(const T& t) + std::ostream& operator<<(T t) { return _os << t; } + void flush() + { + _os << std::endl; + } + + std::string escape(std::string arg) + { + return arg; + } + std::ostream& _os; };