diff --git a/include/sqlpp11/detail/named_serializable.h b/include/sqlpp11/detail/named_serializable.h index 1aaa7f17..cb9dc3da 100644 --- a/include/sqlpp11/detail/named_serializable.h +++ b/include/sqlpp11/detail/named_serializable.h @@ -27,9 +27,9 @@ #ifndef SQLPP_NAMED_SERIALIZABLE_H #define SQLPP_NAMED_SERIALIZABLE_H -#include -#include #include +#include +#include namespace sqlpp { @@ -38,11 +38,11 @@ namespace sqlpp template struct named_serializable_t { - template::type, named_serializable_t>::value, int>::type = 0 // prevent accidental overload for copy constructor - > - named_serializable_t(T&& t): - _impl(std::make_shared<_impl_t::type>>(std::forward(t))) + using _context_t = typename Db::context; + + template + named_serializable_t(T t): + _impl(std::make_shared<_impl_t::type>>(t)) {} named_serializable_t(const named_serializable_t&) = default; @@ -51,9 +51,14 @@ namespace sqlpp named_serializable_t& operator=(named_serializable_t&&) = default; ~named_serializable_t() = default; - void serialize(std::ostream& os, Db& db) const + sqlpp::serializer& interpret(sqlpp::serializer& context) const { - _impl->serialize(os, db); + return _impl->interpret(context); + } + + _context_t& interpret(_context_t& context) const + { + return _impl->interpret(context); } std::string _get_name() const @@ -64,13 +69,15 @@ namespace sqlpp private: struct _impl_base { - virtual void serialize(std::ostream& os, Db& db) const = 0; + virtual sqlpp::serializer& interpret(sqlpp::serializer& context) const = 0; + virtual _context_t& interpret(_context_t& context) const = 0; virtual std::string _get_name() const = 0; }; template struct _impl_t: public _impl_base { + static_assert(not make_parameter_list_t::type::size::value, "parameters not supported in dynamic query parts"); _impl_t(const T& t): _t(t) {} @@ -79,9 +86,16 @@ namespace sqlpp _t(std::move(t)) {} - void serialize(std::ostream& os, Db& db) const + sqlpp::serializer& interpret(sqlpp::serializer& context) const { - _t.serialize(os, db); + sqlpp::interpret(_t, context); + return context; + } + + _context_t& interpret(_context_t& context) const + { + sqlpp::interpret(_t, context); + return context; } std::string _get_name() const @@ -95,6 +109,19 @@ namespace sqlpp std::shared_ptr _impl; }; } + + template + struct interpreter_t> + { + using T = detail::named_serializable_t; + + static Context& _(const T& t, Context& context) + { + t.interpret(context); + return context; + } + }; + } #endif diff --git a/include/sqlpp11/detail/serializable.h b/include/sqlpp11/detail/serializable.h index 1f7e754a..6734e479 100644 --- a/include/sqlpp11/detail/serializable.h +++ b/include/sqlpp11/detail/serializable.h @@ -27,9 +27,8 @@ #ifndef SQLPP_SERIALIZABLE_H #define SQLPP_SERIALIZABLE_H -#include -#include #include +#include #include namespace sqlpp @@ -39,11 +38,11 @@ namespace sqlpp template struct serializable_t { - template::type, serializable_t>::value, int>::type = 0 // prevent accidental overload for copy constructor - > - serializable_t(T&& t): - _impl(std::make_shared<_impl_t::type>>(std::forward(t))) + using _context_t = typename Db::context; + + template + serializable_t(T t): + _impl(std::make_shared<_impl_t::type>>(t)) {} serializable_t(const serializable_t&) = default; @@ -52,15 +51,21 @@ namespace sqlpp serializable_t& operator=(serializable_t&&) = default; ~serializable_t() = default; - void serialize(std::ostream& os, Db& db) const + sqlpp::serializer& interpret(sqlpp::serializer& context) const { - _impl->serialize(os, db); + return _impl->interpret(context); + } + + _context_t& interpret(_context_t& context) const + { + return _impl->interpret(context); } private: struct _impl_base { - virtual void serialize(std::ostream& os, Db& db) const = 0; + virtual sqlpp::serializer& interpret(sqlpp::serializer& context) const = 0; + virtual _context_t interpret(_context_t& context) const = 0; }; template @@ -75,16 +80,37 @@ namespace sqlpp _t(std::move(t)) {} - void serialize(std::ostream& os, Db& db) const + sqlpp::serializer& interpret(sqlpp::serializer& context) const { - _t.serialize(os, db); + sqlpp::interpret(_t, context); + return context; } + + _context_t& interpret(_context_t& context) const + { + sqlpp::interpret(_t, context); + return context; + } + T _t; }; std::shared_ptr _impl; }; } + + template + struct interpreter_t> + { + using T = detail::serializable_t; + + static Context& _(const T& t, Context& context) + { + t.interpret(context); + return context; + } + }; + } #endif diff --git a/include/sqlpp11/functions.h b/include/sqlpp11/functions.h index 061cd0ad..7059c84e 100644 --- a/include/sqlpp11/functions.h +++ b/include/sqlpp11/functions.h @@ -88,6 +88,7 @@ namespace sqlpp template auto flatten(const Expression& exp, const Context& context) -> verbatim_t::type::_value_type::_base_value_type> { + static_assert(not make_parameter_list_t::type::size::value, "parameters not supported in flattened expressions"); context.clear(); interpret(exp, context); return { context.str() }; diff --git a/include/sqlpp11/join.h b/include/sqlpp11/join.h index bebc0993..d9dbadd1 100644 --- a/include/sqlpp11/join.h +++ b/include/sqlpp11/join.h @@ -134,23 +134,30 @@ namespace sqlpp return { *this, std::forward(t) }; } - template - void serialize(std::ostream& os, Db& db) const - { - // FIXME: Need to check if db supports the join type. e.g. sqlite does not support right outer or full outer join - static_assert(JoinType::template _is_supported::value, "join type not supported by current database"); - static_assert(not is_noop::value, "joined tables require on()"); - _lhs.serialize(os, db); - os << JoinType::_name; - os << " JOIN "; - _rhs.serialize(os, db); - _on.serialize(os, db); - } - Lhs _lhs; Rhs _rhs; On _on; }; + + // FIXME: Need to check if db supports the join type. e.g. sqlite does not support right outer or full outer join + template + struct interpreter_t> + { + using T = join_t; + + static Context& _(const T& t, Context& context) + { + static_assert(not is_noop::value, "joined tables require on()"); + interpret(t._lhs, context); + context << JoinType::_name; + context << " JOIN "; + context << "("; + interpret(t._rhs, context); + interpret(t._on, context); + return context; + } + }; + } #endif diff --git a/include/sqlpp11/limit.h b/include/sqlpp11/limit.h index 741bbe30..d61a6691 100644 --- a/include/sqlpp11/limit.h +++ b/include/sqlpp11/limit.h @@ -37,8 +37,7 @@ namespace sqlpp struct limit_t { using _is_limit = std::true_type; - static_assert(std::is_integral::value - or (is_parameter_t::value and is_numeric_t::value), "limit requires an integral value or integral parameter"); + static_assert(is_integral_t::value, "limit requires an integral value or integral parameter"); Limit _limit; }; @@ -50,7 +49,8 @@ namespace sqlpp static Context& _(const T& t, Context& context) { - context << " LIMIT " << t._limit; + context << " LIMIT "; + interpret(t._limit, context); return context; } }; @@ -65,16 +65,22 @@ namespace sqlpp _limit = limit; } - template - void serialize(std::ostream& os, Db& db) const - { - static_assert(Db::_supports_limit, "limit not supported by current database"); - if (_limit > 0) - os << " LIMIT " << _limit; - } - std::size_t _limit; }; + + template + struct interpreter_t + { + using T = dynamic_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/offset.h b/include/sqlpp11/offset.h index 9545a8fe..764778df 100644 --- a/include/sqlpp11/offset.h +++ b/include/sqlpp11/offset.h @@ -37,8 +37,7 @@ namespace sqlpp struct offset_t { using _is_offset = std::true_type; - static_assert(std::is_integral::value - or (is_parameter_t::value and is_numeric_t::value), "offset requires an integral value or integral parameter"); + static_assert(is_integral_t::value, "offset requires an integral value or integral parameter"); Offset _offset; }; @@ -50,7 +49,8 @@ namespace sqlpp static Context& _(const T& t, Context& context) { - context << " OFFSET " << t._offset; + context << " OFFSET "; + interpret(t._offset, context); return context; } }; @@ -65,16 +65,22 @@ namespace sqlpp _offset = offset; } - template - void serialize(std::ostream& os, Db& db) const - { - if (_offset > 0) - os << " OFFSET " << _offset; - } - std::size_t _offset; }; + template + struct interpreter_t + { + using T = dynamic_offset_t; + + static Context& _(const T& t, Context& context) + { + if (t._offset > 0) + context << " OFFSET " << t._offset; + return context; + } + }; + } #endif diff --git a/include/sqlpp11/on.h b/include/sqlpp11/on.h index bfadfa9a..f5827210 100644 --- a/include/sqlpp11/on.h +++ b/include/sqlpp11/on.h @@ -51,20 +51,28 @@ namespace sqlpp _dynamic_expressions.emplace_back(std::forward(expr)); } - template - void serialize(std::ostream& os, Db& db) const - { - if (sizeof...(Expr) == 0 and _dynamic_expressions.empty()) - return; - os << " ON "; - detail::serialize_tuple(os, db, _expressions, " AND "); - _dynamic_expressions.serialize(os, db, " AND ", sizeof...(Expr) == 0); - } - std::tuple _expressions; detail::serializable_list _dynamic_expressions; }; + template + struct interpreter_t> + { + using T = on_t; + + static Context& _(const T& t, Context& context) + { + if (sizeof...(Expr) == 0 and t._dynamic_expressions.empty()) + return context; + context << " ON "; + interpret_tuple(t._expressions, " AND ", context); + if (sizeof...(Expr) and not t._dynamic_expressions.empty()) + context << " AND "; + interpret_serializable_list(t._dynamic_expressions, " AND ", context); + return context; + } + }; + } #endif diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 278699a8..13703cba 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -443,7 +443,7 @@ namespace sqlpp template auto limit(Expr limit) - -> set_limit_t::type>> + -> set_limit_t::type>::type>> { static_assert(not is_noop::value, "cannot call limit() without a from()"); static_assert(is_noop::value, "cannot call limit() twice for a single select"); @@ -489,7 +489,7 @@ namespace sqlpp template auto offset(Expr offset) - -> set_offset_t::type>> + -> set_offset_t::type>::type>> { static_assert(not is_noop::value, "cannot call offset() without a limit"); static_assert(is_noop::value, "cannot call offset() twice for a single select"); diff --git a/include/sqlpp11/serializer.h b/include/sqlpp11/serializer.h new file mode 100644 index 00000000..358c0aee --- /dev/null +++ b/include/sqlpp11/serializer.h @@ -0,0 +1,60 @@ +/* + * 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_SERIALIZER_H +#define SQLPP_SERIALIZER_H + +#include + +namespace sqlpp +{ + struct serializer + { + serializer(std::ostream& os): + _os(os) + {} + + template + std::ostream& operator<<(T t) + { + return _os << t; + } + + void flush() + { + _os << std::endl; + } + + std::string escape(std::string arg) + { + return arg; + } + + std::ostream& _os; + }; +} + +#endif + diff --git a/tests/InterpretTest.cpp b/tests/InterpretTest.cpp index 092be1e5..ebd6b2f2 100644 --- a/tests/InterpretTest.cpp +++ b/tests/InterpretTest.cpp @@ -34,7 +34,7 @@ #include DbMock db = {}; -DbMock::Printer printer(std::cerr); +DbMock::context printer(std::cerr); SQLPP_ALIAS_PROVIDER_GENERATOR(kaesekuchen); int main() @@ -89,13 +89,24 @@ int main() interpret(sum(t.alpha), printer).flush(); interpret(sqlpp::verbatim_table("whatever"), printer).flush(); + // alias interpret(t.as(t.alpha), printer).flush(); interpret(t.as(t.alpha).beta, printer).flush(); - interpret(multi_column(t.alpha, t.alpha, (t.beta + "cake").as(t.gamma)), printer).flush(); + // select alias + interpret(select(t.alpha).from(t).where(t.beta > "kaesekuchen").as(t.gamma), printer).flush(); + interpret(t.alpha.is_null(), printer).flush(); - interpret(select(t.alpha).from(t).where(t.beta > "kaesekuchen").as(t.gamma), printer).flush(); + // join + interpret(t.inner_join(t.as(t.alpha)).on(t.beta == t.as(t.alpha).beta), printer).flush(); + + // multi_column + interpret(multi_column(t.alpha, t.alpha, (t.beta + "cake").as(t.gamma)), printer).flush(); + + // dynamic select + interpret(dynamic_select(db, t.alpha).dynamic_columns().add_column(t.beta), printer).flush(); + return 0; } diff --git a/tests/MockDb.h b/tests/MockDb.h index 1a188dfa..484116a9 100644 --- a/tests/MockDb.h +++ b/tests/MockDb.h @@ -31,10 +31,10 @@ class DbMock: public sqlpp::connection { public: - struct Printer + struct context { using _database_t = DbMock; - Printer(std::ostream& os): + context(std::ostream& os): _os(os) {}