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
This commit is contained in:
rbock
2014-01-11 21:51:57 +01:00
parent bef7cea6a6
commit 47ae6a2e76
13 changed files with 215 additions and 208 deletions

View File

@@ -85,9 +85,10 @@ namespace sqlpp
{
using T = column_t<Args...>;
template<typename Context>
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;
}
};

View File

@@ -29,12 +29,11 @@
#include <sstream>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/interpret_tuple.h>
#include <sqlpp11/detail/set.h>
namespace sqlpp
{
namespace detail
{
template<typename First, typename... Args>
struct concat_t: public First::_value_type::template operators<concat_t<First, Args...>>
{
@@ -71,31 +70,27 @@ namespace sqlpp
concat_t& operator=(concat_t&&) = default;
~concat_t() = default;
template<typename Db>
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<First, Args...> _args;
};
}
//FIXME: Write partial specialization for mysql
template<typename Db, typename First, typename... Args>
struct interpreter_t<Db, concat_t<First, Args...>>
{
using T = concat_t<First, Args...>;
template<typename Context>
static Context& _(const T& t, Context& context)
{
context << "(";
interpret_tuple(t._args, "||", context);
context << ")";
return context;
}
};
template<typename... T>
auto concat(T&&... t) -> typename detail::concat_t<typename operand_t<T, is_text_t>::type...>
auto concat(T&&... t) -> concat_t<typename operand_t<T, is_text_t>::type...>
{
return { std::forward<T>(t)... };
}

View File

@@ -27,7 +27,7 @@
#ifndef SQLPP_DETAIL_BASIC_OPERATORS_H
#define SQLPP_DETAIL_BASIC_OPERATORS_H
#include <sqlpp11/expression.h>
#include <sqlpp11/expression_fwd.h>
#include <sqlpp11/alias.h>
#include <sqlpp11/sort_order.h>
#include <sqlpp11/in.h>

View File

@@ -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 <tuple>
#include <ostream>
#include <sqlpp11/type_traits.h>
namespace sqlpp
{
namespace detail
{
template<std::size_t begin, std::size_t index, std::size_t end>
struct tuple_serializer_impl
{
template<typename Db, typename Tuple, typename Separator>
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<index>(flags_and_columns);
using entry_type = typename std::tuple_element<index, Tuple>::type;
if (requires_braces_t<entry_type>::value)
os << "(";
entry.serialize(os, db);
if (requires_braces_t<entry_type>::value)
os << ")";
tuple_serializer_impl<begin, index + 1, end>::serialize(os, db, flags_and_columns, separator);
}
};
template<std::size_t begin, std::size_t end>
struct tuple_serializer_impl<begin, end, end>
{
template<typename Db, typename Tuple, typename Separator>
static void serialize(std::ostream& os, Db& db, const Tuple& flags_and_columns, const Separator& separator)
{
}
};
template<typename Db, typename Tuple, typename Separator>
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<Tuple>::value>::serialize(os, db, flags_and_columns, separator);
}
}
}
#endif

View File

@@ -27,7 +27,6 @@
#ifndef SQLPP_DETAIL_WRAP_OPERAND_H
#define SQLPP_DETAIL_WRAP_OPERAND_H
#include <ostream>
#include <sqlpp11/interpreter.h>
// 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<typename Db>
void serialize(std::ostream& os, Db& db) const
{
os << _t;
}
bool _is_trivial() const { return _t == false; }
bool _t;
};
template<typename Db>
struct interpreter_t<Db, boolean_operand>
{
using Operand = boolean_operand;
template<typename Context>
static void _(const Operand& t, Context& context)
{
context << t._t;
}
};
template<typename T>
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<typename Db>
void serialize(std::ostream& os, Db& db) const
{
os << _t;
}
bool _is_trivial() const { return _t == 0; }
T _t;
};
template<typename Db, typename T>
struct interpreter_t<Db, integral_operand<T>>
{
using Operand = integral_operand<T>;
template<typename Context>
static void _(const Operand& t, Context& context)
{
context << t._t;
}
};
template<typename Db, typename T>
struct interpreter_t<Db, integral_operand<T>>
{
using Operand = integral_operand<T>;
template<typename Context>
static void _(const Operand& t, Context& context)
{
context << t._t;
}
};
template<typename T>
@@ -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<typename Db>
void serialize(std::ostream& os, Db& db) const
{
os << _t;
}
bool _is_trivial() const { return _t == 0; }
T _t;
};
template<typename T>
template<typename Db, typename T>
struct interpreter_t<Db, floating_point_operand<T>>
{
using Operand = floating_point_operand<T>;
template<typename Context>
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<typename Db>
void serialize(std::ostream& os, Db& db) const
{
os << '\'' << db.escape(_t) << '\'';
}
bool _is_trivial() const { return _t.empty(); }
std::string _t;
};
template<typename Db>
struct interpreter_t<Db, text_operand>
{
using Operand = text_operand;
template<typename Context>
static void _(const Operand& t, Context& context)
{
context << '\'' << context.escape(t._t) << '\'';
}
};
template<typename T, typename Enable = void>
struct wrap_operand
{
@@ -158,7 +137,7 @@ namespace sqlpp
template<>
struct wrap_operand<bool, void>
{
using type = bool_operand;
using type = boolean_operand;
};
template<typename T>
@@ -176,7 +155,7 @@ namespace sqlpp
template<typename T>
struct wrap_operand<T, typename std::enable_if<std::is_convertible<T, std::string>::value>::type>
{
using type = text_operand<T>;
using type = text_operand;
};
}

View File

@@ -28,7 +28,9 @@
#define SQLPP_EXPRESSION_H
#include <sqlpp11/alias.h>
#include <sqlpp11/boolean.h>
#include <sqlpp11/noop.h>
#include <sqlpp11/expression_fwd.h>
#include <sqlpp11/interpreter.h>
#include <sqlpp11/detail/wrap_operand.h>
#include <sqlpp11/detail/serialize_tuple.h>
@@ -51,7 +53,7 @@ namespace sqlpp
{
using T = assignment_t<Lhs, Rhs>;
template<typename Context>
static void _(const T& t, Context& context)
static Context& _(const T& t, Context& context)
{
interpret(t._lhs, context);
if (trivial_value_is_null_t<Lhs>::value and t._rhs._is_trivial())
@@ -63,14 +65,15 @@ namespace sqlpp
context << "=";
interpret(t._rhs, context);
}
return context;
}
};
template<typename Lhs, typename Rhs, typename ValueType = detail::boolean>
struct equal_t: public ValueType::template operators<equal_t<Lhs, Rhs>>
template<typename Lhs, typename Rhs>
struct equal_t: public detail::boolean::template operators<equal_t<Lhs, Rhs>>
{
using _value_type = ValueType; // FIXME: Can we use boolean directly here?
using _value_type = detail::boolean;
template<typename L, typename R>
equal_t(L&& l, R&& r):
@@ -89,16 +92,16 @@ namespace sqlpp
Rhs _rhs;
};
template<typename Db, typename... Args>
struct interpreter_t<Db, equal_t<Args...>>
template<typename Db, typename Lhs, typename Rhs>
struct interpreter_t<Db, equal_t<Lhs, Rhs>>
{
using T = equal_t<Args...>;
using T = equal_t<Lhs, Rhs>;
template<typename Context>
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<typename T::Lhs>::value and t._rhs._is_trivial())
if (trivial_value_is_null_t<Lhs>::value and t._rhs._is_trivial())
{
context << "IS NULL";
}
@@ -108,13 +111,14 @@ namespace sqlpp
interpret(t._rhs, context);
}
context << ")";
return context;
}
};
template<typename Lhs, typename Rhs, typename ValueType = detail::boolean>
struct not_equal_t: public ValueType::template operators<not_equal_t<Lhs, Rhs>>
template<typename Lhs, typename Rhs>
struct not_equal_t: public detail::boolean::template operators<not_equal_t<Lhs, Rhs>>
{
using _value_type = ValueType;
using _value_type = detail::boolean;
template<typename L, typename R>
not_equal_t(L&& l, R&& r):
@@ -132,16 +136,16 @@ namespace sqlpp
Rhs _rhs;
};
template<typename Db, typename... Args>
struct interpreter_t<Db, not_equal_t<Args...>>
template<typename Db, typename Lhs, typename Rhs>
struct interpreter_t<Db, not_equal_t<Lhs, Rhs>>
{
using T = not_equal_t<Args...>;
using T = not_equal_t<Lhs, Rhs>;
template<typename Context>
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<typename T::Lhs>::value and t._rhs._is_trivial())
if (trivial_value_is_null_t<Lhs>::value and t._rhs._is_trivial())
{
context << "IS NOT NULL";
}
@@ -151,13 +155,14 @@ namespace sqlpp
interpret(t._rhs, context);
}
context << ")";
return context;
}
};
template<typename Lhs, typename ValueType = detail::boolean>
struct not_t: public ValueType::template operators<not_t<Lhs>>
template<typename Lhs>
struct not_t: public detail::boolean::template operators<not_t<Lhs>>
{
using _value_type = ValueType;
using _value_type = detail::boolean;
not_t(Lhs l):
_lhs(l)
@@ -172,15 +177,15 @@ namespace sqlpp
Lhs _lhs;
};
template<typename Db, typename... Args>
struct interpreter_t<Db, not_t<Args...>>
template<typename Db, typename Lhs>
struct interpreter_t<Db, not_t<Lhs>>
{
using T = not_t<Args...>;
using T = not_t<Lhs>;
template<typename Context>
static void interpret(const T& t, Context& context)
static Context& interpret(const T& t, Context& context)
{
context << "(";
if (trivial_value_is_null_t<typename T::Lhs>::value and t._lhs._is_trivial())
if (trivial_value_is_null_t<Lhs>::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<typename Db, typename... Args>
struct interpreter_t<Db, binary_expression_t<Args...>>
template<typename Db, typename Lhs, typename O, typename Rhs>
struct interpreter_t<Db, binary_expression_t<Lhs, O, Rhs>>
{
using T = binary_expression_t<Args...>;
using T = binary_expression_t<Lhs, O, Rhs>;
template<typename Context>
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;
}
};

View File

@@ -29,11 +29,20 @@
namespace sqlpp
{
template<typename T>
struct is_expression_t;
template<typename Lhs, typename Rhs>
struct assignment_t;
template<typename T>
struct is_named_expression_t;
template<typename Lhs, typename Rhs>
struct equal_t;
template<typename Lhs, typename Rhs>
struct not_equal_t;
template<typename Lhs>
struct not_t;
template<typename Lhs, typename O, typename Rhs>
struct binary_expression_t;
}
#endif

View File

@@ -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 << ")";
}

View File

@@ -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 <tuple>
#include <ostream>
#include <sqlpp11/type_traits.h>
namespace sqlpp
{
template<typename Db, typename Tuple>
struct tuple_interpreter_t
{
template<typename Separator, typename Context>
static void _(const Tuple& t, const Separator& separator, Context& context)
{
_impl(t, separator, context, type<0>());
};
private:
template<size_t> struct type {};
template<typename Separator, typename Context, size_t index>
static void _impl(const Tuple& t, const Separator& separator, Context& context, const type<index>&)
{
if (index)
context << separator;
const auto& entry = std::get<index>(t);
using entry_type = typename std::tuple_element<index, Tuple>::type;
if (requires_braces_t<entry_type>::value)
context << "(";
interpret(entry, context);
if (requires_braces_t<entry_type>::value)
context << ")";
_impl(t, separator, context, type<index + 1>());
}
template<typename Separator, typename Context>
static void _impl(const Tuple& t, const Separator& separator, Context& context, const type<std::tuple_size<Tuple>::value>&)
{
}
};
template<typename Tuple, typename Separator, typename Context>
auto interpret_tuple(const Tuple& t, const Separator& separator, Context& context)
-> decltype(tuple_interpreter_t<typename std::decay<Context>::type::_database_t, typename std::decay<Tuple>::type>::_(t, separator, context))
{
return tuple_interpreter_t<typename std::decay<Context>::type::_database_t, typename std::decay<Tuple>::type>::_(t, separator, context);
}
}
#endif

View File

@@ -42,11 +42,11 @@ namespace sqlpp
}
};
template<typename Context, typename T>
void interpret(const T& t, Context& context)
template<typename T, typename Context>
auto interpret(const T& t, Context& context)
-> decltype(interpreter_t<typename std::decay<Context>::type::_database_t, typename std::decay<T>::type>::_(t, context))
{
using Db = typename std::decay<Context>::type::_database_t;
interpreter_t<Db, typename std::decay<T>::type>::_(t, context);
return interpreter_t<typename std::decay<Context>::type::_database_t, typename std::decay<T>::type>::_(t, context);
}
}

View File

@@ -196,10 +196,10 @@ namespace sqlpp
struct operators: public basic_operators<Base, _constraint>
{
template<typename T>
detail::concat_t<Base, typename _constraint<T>::type> operator+(T&& t) const
concat_t<Base, typename _constraint<T>::type> operator+(T&& t) const
{
static_assert(not is_multi_expression_t<Base>::value, "multi-expression cannot be used as left hand side operand");
return { *static_cast<const Base*>(this), std::forward<T>(t) };
return { *static_cast<const Base*>(this), {std::forward<T>(t)} };
}
template<typename T>

View File

@@ -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;
}

View File

@@ -39,11 +39,21 @@ public:
{}
template<typename T>
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;
};