0
0
mirror of https://github.com/rbock/sqlpp11.git synced 2024-11-16 04:47:18 +08:00

Merge branch 'feature/date_time2' into develop

This commit is contained in:
rbock 2015-10-29 16:48:53 +01:00
commit d25ed57972
23 changed files with 1586 additions and 121 deletions

View File

@ -29,7 +29,14 @@ enable_testing()
add_library(sqlpp11 INTERFACE) add_library(sqlpp11 INTERFACE)
set(DATE_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../date" CACHE FILEPATH "Path to Howard Hinnant's date library")
if(NOT EXISTS ${DATE_INCLUDE_DIR}/date.h)
message(SEND_ERROR "Can't find date.h in ${DATE_INCLUDE_DIR}")
endif()
target_include_directories(sqlpp11 INTERFACE target_include_directories(sqlpp11 INTERFACE
$<BUILD_INTERFACE:${DATE_INCLUDE_DIR}>
$<BUILD_INTERFACE:${sqlpp11_SOURCE_DIR}/include> $<BUILD_INTERFACE:${sqlpp11_SOURCE_DIR}/include>
) )

View File

@ -28,6 +28,9 @@
#define SQLPP_DETAIL_BASIC_EXPRESSION_OPERATORS_H #define SQLPP_DETAIL_BASIC_EXPRESSION_OPERATORS_H
#include <sqlpp11/value_type_fwd.h> #include <sqlpp11/value_type_fwd.h>
#include <sqlpp11/bad_statement.h>
#include <sqlpp11/portable_static_assert.h>
#include <sqlpp11/consistent.h>
#include <sqlpp11/alias.h> #include <sqlpp11/alias.h>
#include <sqlpp11/sort_order.h> #include <sqlpp11/sort_order.h>
#include <sqlpp11/expression_fwd.h> #include <sqlpp11/expression_fwd.h>
@ -38,72 +41,145 @@
namespace sqlpp namespace sqlpp
{ {
SQLPP_PORTABLE_STATIC_ASSERT(assert_valid_rhs_comparison_operand_t, "invalid rhs operand in comparison");
template <typename LhsValueType, typename RhsType>
using check_rhs_comparison_operand_t =
static_check_t<(is_expression_t<sqlpp::wrap_operand_t<RhsType>>::value // expressions are OK
or
is_multi_expression_t<sqlpp::wrap_operand_t<RhsType>>::value) // multi-expressions like ANY are
// OK for comparisons, too
and
LhsValueType::template _is_valid_operand<
sqlpp::wrap_operand_t<RhsType>>::value, // the correct value type is required, of course
assert_valid_rhs_comparison_operand_t>;
SQLPP_PORTABLE_STATIC_ASSERT(assert_valid_in_arguments_t, "at least one operand of in() is not valid");
template <typename LhsValueType, typename... InTypes>
using check_rhs_in_arguments_t =
static_check_t<logic::all_t<check_rhs_comparison_operand_t<LhsValueType, InTypes>::value...>::value,
assert_valid_in_arguments_t>;
namespace detail
{
template <bool Enable, template <typename Lhs> class Expr, typename Lhs>
struct new_unary_expression_impl
{
using type = bad_statement;
};
template <template <typename Lhs> class Expr, typename Lhs>
struct new_unary_expression_impl<true, Expr, Lhs>
{
using type = Expr<Lhs>;
};
}
template <typename Check, template <typename Lhs> class Expr, typename Lhs>
using new_unary_expression_t = typename detail::new_unary_expression_impl<Check::value, Expr, Lhs>::type;
namespace detail
{
template <bool Enable, template <typename Lhs, typename Rhs> class Expr, typename Lhs, typename Rhs>
struct new_binary_expression_impl
{
using type = bad_statement;
};
template <template <typename Lhs, typename Rhs> class Expr, typename Lhs, typename Rhs>
struct new_binary_expression_impl<true, Expr, Lhs, Rhs>
{
using type = Expr<Lhs, Rhs>;
};
}
template <typename Check, template <typename Lhs, typename Rhs> class Expr, typename Lhs, typename Rhs>
using new_binary_expression_t = typename detail::new_binary_expression_impl<Check::value, Expr, Lhs, Rhs>::type;
namespace detail
{
template <bool Enable, template <typename Lhs, typename... Rhs> class Expr, typename Lhs, typename... Rhs>
struct new_nary_expression_impl
{
using type = bad_statement;
};
template <template <typename Lhs, typename... Rhs> class Expr, typename Lhs, typename... Rhs>
struct new_nary_expression_impl<true, Expr, Lhs, Rhs...>
{
using type = Expr<Lhs, Rhs...>;
};
}
template <typename Check, template <typename Lhs, typename... Rhs> class Expr, typename Lhs, typename... Rhs>
using new_nary_expression_t = typename detail::new_nary_expression_impl<Check::value, Expr, Lhs, Rhs...>::type;
// basic operators // basic operators
template <typename Expr, typename ValueType> template <typename Expr, typename ValueType>
struct basic_expression_operators struct basic_expression_operators
{ {
template <typename T> template <template <typename Lhs, typename Rhs> class NewExpr, typename T>
struct _is_valid_comparison_operand using _new_binary_expression_t =
{ new_binary_expression_t<check_rhs_comparison_operand_t<ValueType, wrap_operand_t<T>>,
static constexpr bool value = NewExpr,
(is_expression_t<T>::value // expressions are OK Expr,
or wrap_operand_t<T>>;
is_multi_expression_t<T>::value) // multi-expressions like ANY are OK for comparisons, too
and template <template <typename Lhs, typename... Rhs> class NewExpr, typename... T>
ValueType::template _is_valid_operand<T>::value // the correct value type is required, of course using _new_nary_expression_t =
; new_nary_expression_t<logic::all_t<check_rhs_comparison_operand_t<ValueType, wrap_operand_t<T>>::value...>,
}; NewExpr,
Expr,
wrap_operand_t<T>...>;
template <typename T> template <typename T>
equal_to_t<Expr, wrap_operand_t<T>> operator==(T t) const _new_binary_expression_t<equal_to_t, T> operator==(T t) const
{ {
using rhs = wrap_operand_t<T>; using rhs = wrap_operand_t<T>;
static_assert(_is_valid_comparison_operand<rhs>::value, "invalid rhs operand in comparison"); check_rhs_comparison_operand_t<ValueType, rhs>::_();
return {*static_cast<const Expr*>(this), {rhs{t}}}; return {*static_cast<const Expr*>(this), {rhs{t}}};
} }
template <typename T> template <typename T>
not_equal_to_t<Expr, wrap_operand_t<T>> operator!=(T t) const _new_binary_expression_t<not_equal_to_t, T> operator!=(T t) const
{ {
using rhs = wrap_operand_t<T>; using rhs = wrap_operand_t<T>;
static_assert(_is_valid_comparison_operand<rhs>::value, "invalid rhs operand in comparison"); check_rhs_comparison_operand_t<ValueType, rhs>::_();
return {*static_cast<const Expr*>(this), {rhs{t}}}; return {*static_cast<const Expr*>(this), {rhs{t}}};
} }
template <typename T> template <typename T>
less_than_t<Expr, wrap_operand_t<T>> operator<(T t) const _new_binary_expression_t<less_than_t, T> operator<(T t) const
{ {
using rhs = wrap_operand_t<T>; using rhs = wrap_operand_t<T>;
static_assert(_is_valid_comparison_operand<rhs>::value, "invalid rhs operand in comparison"); check_rhs_comparison_operand_t<ValueType, rhs>::_();
return {*static_cast<const Expr*>(this), rhs{t}}; return {*static_cast<const Expr*>(this), rhs{t}};
} }
template <typename T> template <typename T>
less_equal_t<Expr, wrap_operand_t<T>> operator<=(T t) const _new_binary_expression_t<less_equal_t, T> operator<=(T t) const
{ {
using rhs = wrap_operand_t<T>; using rhs = wrap_operand_t<T>;
static_assert(_is_valid_comparison_operand<rhs>::value, "invalid rhs operand in comparison"); check_rhs_comparison_operand_t<ValueType, rhs>::_();
return {*static_cast<const Expr*>(this), rhs{t}}; return {*static_cast<const Expr*>(this), rhs{t}};
} }
template <typename T> template <typename T>
greater_than_t<Expr, wrap_operand_t<T>> operator>(T t) const _new_binary_expression_t<greater_than_t, T> operator>(T t) const
{ {
using rhs = wrap_operand_t<T>; using rhs = wrap_operand_t<T>;
static_assert(_is_valid_comparison_operand<rhs>::value, "invalid rhs operand in comparison"); check_rhs_comparison_operand_t<ValueType, rhs>::_();
return {*static_cast<const Expr*>(this), rhs{t}}; return {*static_cast<const Expr*>(this), rhs{t}};
} }
template <typename T> template <typename T>
greater_equal_t<Expr, wrap_operand_t<T>> operator>=(T t) const _new_binary_expression_t<greater_equal_t, T> operator>=(T t) const
{ {
using rhs = wrap_operand_t<T>; using rhs = wrap_operand_t<T>;
static_assert(_is_valid_comparison_operand<rhs>::value, "invalid rhs operand in comparison"); check_rhs_comparison_operand_t<ValueType, rhs>::_();
return {*static_cast<const Expr*>(this), rhs{t}}; return {*static_cast<const Expr*>(this), rhs{t}};
} }
@ -130,18 +206,16 @@ namespace sqlpp
// Hint: use value_list wrapper for containers... // Hint: use value_list wrapper for containers...
template <typename... T> template <typename... T>
in_t<Expr, wrap_operand_t<T>...> in(T... t) const _new_nary_expression_t<in_t, T...> in(T... t) const
{ {
static_assert(logic::all_t<_is_valid_comparison_operand<wrap_operand_t<T>>::value...>::value, check_rhs_in_arguments_t<ValueType, wrap_operand_t<T>...>::_();
"at least one operand of in() is not valid");
return {*static_cast<const Expr*>(this), wrap_operand_t<T>{t}...}; return {*static_cast<const Expr*>(this), wrap_operand_t<T>{t}...};
} }
template <typename... T> template <typename... T>
not_in_t<Expr, wrap_operand_t<T>...> not_in(T... t) const _new_nary_expression_t<not_in_t, T...> not_in(T... t) const
{ {
static_assert(logic::all_t<_is_valid_comparison_operand<wrap_operand_t<T>>::value...>::value, check_rhs_in_arguments_t<ValueType, wrap_operand_t<T>...>::_();
"at least one operand of in() is not valid");
return {*static_cast<const Expr*>(this), wrap_operand_t<T>{t}...}; return {*static_cast<const Expr*>(this), wrap_operand_t<T>{t}...};
} }
}; };

View File

@ -62,6 +62,8 @@ namespace sqlpp
template <typename T> template <typename T>
using _is_valid_operand = is_valid_operand<value_type_of<ColumnSpec>, T>; using _is_valid_operand = is_valid_operand<value_type_of<ColumnSpec>, T>;
template <typename T>
using _is_valid_assignment_operand = is_valid_assignment_operand<value_type_of<ColumnSpec>, T>;
column_t() = default; column_t() = default;
column_t(const column_t&) = default; column_t(const column_t&) = default;
@ -87,7 +89,7 @@ namespace sqlpp
auto operator=(T t) const -> assignment_t<column_t, wrap_operand_t<T>> auto operator=(T t) const -> assignment_t<column_t, wrap_operand_t<T>>
{ {
using rhs = wrap_operand_t<T>; using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand"); static_assert(_is_valid_assignment_operand<rhs>::value, "invalid rhs assignment operand");
return {*this, {rhs{t}}}; return {*this, {rhs{t}}};
} }

View File

@ -28,6 +28,8 @@
#define SQLPP_COLUMN_TYPES_H #define SQLPP_COLUMN_TYPES_H
#include <sqlpp11/boolean.h> #include <sqlpp11/boolean.h>
#include <sqlpp11/day_point.h>
#include <sqlpp11/time_point.h>
#include <sqlpp11/integral.h> #include <sqlpp11/integral.h>
#include <sqlpp11/floating_point.h> #include <sqlpp11/floating_point.h>
#include <sqlpp11/text.h> #include <sqlpp11/text.h>

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2013-2015, 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_CONSISTENT_H
#define SQLPP_CONSISTENT_H
#include <type_traits>
namespace sqlpp
{
struct consistent_t
{
static constexpr bool value = true;
using type = std::true_type;
static void _(){};
};
}
#endif

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2015-2015, 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_DATE_FWD_H
#define SQLPP_DATE_FWD_H
#include <chrono>
namespace sqlpp
{
namespace chrono
{
using days = std::chrono::duration<int, std::ratio_multiply<std::ratio<24>, std::chrono::hours::period>>;
using day_point = std::chrono::time_point<std::chrono::system_clock, days>;
using mus_point = std::chrono::time_point<std::chrono::system_clock, std::chrono::microseconds>;
}
struct day_point;
struct time_point;
}
#endif

236
include/sqlpp11/day_point.h Normal file
View File

@ -0,0 +1,236 @@
/*
* Copyright (c) 2015-2015, 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_DAY_POINT_H
#define SQLPP_DAY_POINT_H
#include <date.h>
#include <sqlpp11/time_point.h>
#include <sqlpp11/basic_expression_operators.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/exception.h>
#include <sqlpp11/value_type.h>
#include <sqlpp11/assignment.h>
#include <sqlpp11/result_field.h>
namespace sqlpp
{
// day_point value type
struct day_point
{
using _traits = make_traits<day_point, tag::is_value_type>;
using _tag = tag::is_date;
using _cpp_value_type = ::sqlpp::chrono::day_point;
template <typename T>
using _is_valid_operand = is_time_point_t<T>;
template <typename T>
using _is_valid_assignment_operand = is_date_t<T>;
};
// day_point parameter value
template <>
struct parameter_value_t<day_point>
{
using _value_type = day_point;
using _cpp_value_type = typename _value_type::_cpp_value_type;
parameter_value_t() : _value{}, _is_null(true)
{
}
explicit parameter_value_t(const _cpp_value_type& val) : _value(val), _is_null(false)
{
}
parameter_value_t& operator=(const _cpp_value_type& val)
{
_value = val;
_is_null = false;
return *this;
}
parameter_value_t& operator=(const tvin_t<wrap_operand_t<_cpp_value_type>>& t)
{
if (t._is_trivial())
{
_value = _cpp_value_type{};
_is_null = true;
}
else
{
_value = t._value._t;
_is_null = false;
}
return *this;
}
void set_null()
{
_value = _cpp_value_type{};
_is_null = true;
}
bool is_null() const
{
return _is_null;
}
const _cpp_value_type& value() const
{
return _value;
}
operator _cpp_value_type() const
{
return _value;
}
template <typename Target>
void _bind(Target& target, size_t index) const
{
target._bind_date_parameter(index, &_value, _is_null);
}
private:
_cpp_value_type _value;
bool _is_null;
};
// day_point expression operators
template <typename Base>
struct expression_operators<Base, day_point> : public basic_expression_operators<Base, day_point>
{
template <typename T>
using _is_valid_operand = is_valid_operand<day_point, T>;
};
// day_point column operators
template <typename Base>
struct column_operators<Base, day_point>
{
template <typename T>
using _is_valid_operand = is_valid_operand<day_point, T>;
};
// day_point result field
template <typename Db, typename FieldSpec>
struct result_field_t<day_point, Db, FieldSpec>
: public result_field_methods_t<result_field_t<day_point, Db, FieldSpec>>
{
static_assert(std::is_same<value_type_of<FieldSpec>, day_point>::value, "field type mismatch");
using _cpp_value_type = typename sqlpp::day_point::_cpp_value_type;
result_field_t() : _is_valid(false), _is_null(true), _value{}
{
}
void _invalidate()
{
_is_valid = false;
_is_null = true;
_value = _cpp_value_type{};
}
void _validate()
{
_is_valid = true;
}
bool is_null() const
{
if (not _is_valid)
throw exception("accessing is_null in non-existing row");
return _is_null;
}
bool _is_trivial() const
{
if (not _is_valid)
throw exception("accessing is_null in non-existing row");
return value() == _cpp_value_type{};
}
_cpp_value_type value() const
{
if (not _is_valid)
throw exception("accessing value in non-existing row");
if (_is_null)
{
if (enforce_null_result_treatment_t<Db>::value and not null_is_trivial_value_t<FieldSpec>::value)
{
throw exception("accessing value of NULL field");
}
else
{
return _cpp_value_type{};
}
}
return _value;
}
template <typename Target>
void _bind(Target& target, size_t i)
{
target._bind_date_result(i, &_value, &_is_null);
}
private:
bool _is_valid;
bool _is_null;
_cpp_value_type _value;
};
template <typename Context, typename Db, typename FieldSpec>
struct serializer_t<Context, result_field_t<day_point, Db, FieldSpec>>
{
using _serialize_check = consistent_t;
using T = result_field_t<day_point, Db, FieldSpec>;
static Context& _(const T& t, Context& context)
{
if (t.is_null() and not null_is_trivial_value_t<FieldSpec>::value)
{
context << "NULL";
}
else
{
const auto ymd = ::date::year_month_day{t.value()};
context << ymd;
}
return context;
}
};
template <typename Db, typename FieldSpec>
inline std::ostream& operator<<(std::ostream& os, const result_field_t<day_point, Db, FieldSpec>& e)
{
return serialize(e, os);
}
}
#endif

View File

@ -28,6 +28,7 @@
#define SQLPP_INSERT_VALUE_LIST_H #define SQLPP_INSERT_VALUE_LIST_H
#include <sqlpp11/type_traits.h> #include <sqlpp11/type_traits.h>
#include <sqlpp11/portable_static_assert.h>
#include <sqlpp11/logic.h> #include <sqlpp11/logic.h>
#include <sqlpp11/column_fwd.h> #include <sqlpp11/column_fwd.h>
#include <sqlpp11/assignment.h> #include <sqlpp11/assignment.h>
@ -127,64 +128,6 @@ namespace sqlpp
interpretable_list_t<Database> _dynamic_values; interpretable_list_t<Database> _dynamic_values;
}; };
#define SQLPP_PORTABLE_STATIC_ASSERT(name, message) \
struct name \
{ \
static constexpr bool value = false; \
using type = std::false_type; \
\
template <typename T = void> \
static void _() \
{ \
static_assert(wrong_t<T>::value, message); \
} \
}
namespace detail
{
template <bool Consistent, typename Assert>
struct static_check_impl
{
using type = Assert;
};
template <typename Assert>
struct static_check_impl<true, Assert>
{
using type = consistent_t;
};
}
template <bool Consistent, typename Assert>
using static_check_t = typename detail::static_check_impl<Consistent, Assert>::type;
namespace detail
{
template <typename... Asserts>
struct static_combined_check_impl;
template <typename Assert, typename... Rest>
struct static_combined_check_impl<Assert, Rest...>
{
using type = Assert;
};
template <typename... Rest>
struct static_combined_check_impl<consistent_t, Rest...>
{
using type = typename static_combined_check_impl<Rest...>::type;
};
template <>
struct static_combined_check_impl<>
{
using type = consistent_t;
};
}
template <typename... Asserts>
using static_combined_check_t = typename detail::static_combined_check_impl<Asserts...>::type;
SQLPP_PORTABLE_STATIC_ASSERT(assert_insert_set_assignments_t, "at least one argument is not an assignment in set()"); SQLPP_PORTABLE_STATIC_ASSERT(assert_insert_set_assignments_t, "at least one argument is not an assignment in set()");
SQLPP_PORTABLE_STATIC_ASSERT(assert_insert_set_no_duplicates_t, "at least one duplicate column detected in set()"); SQLPP_PORTABLE_STATIC_ASSERT(assert_insert_set_no_duplicates_t, "at least one duplicate column detected in set()");
SQLPP_PORTABLE_STATIC_ASSERT(assert_insert_set_prohibited_t, SQLPP_PORTABLE_STATIC_ASSERT(assert_insert_set_prohibited_t,

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2015-2015, 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_PORTABLE_STATIC_ASSERT_H
#define SQLPP_PORTABLE_STATIC_ASSERT_H
namespace sqlpp
{
#define SQLPP_PORTABLE_STATIC_ASSERT(name, message) \
struct name \
{ \
static constexpr bool value = false; \
using type = std::false_type; \
\
template <typename T = void> \
static void _() \
{ \
static_assert(wrong_t<T>::value, message); \
} \
}
namespace detail
{
template <bool Consistent, typename Assert>
struct static_check_impl
{
using type = Assert;
};
template <typename Assert>
struct static_check_impl<true, Assert>
{
using type = consistent_t;
};
}
template <bool Consistent, typename Assert>
using static_check_t = typename detail::static_check_impl<Consistent, Assert>::type;
namespace detail
{
template <typename... Asserts>
struct static_combined_check_impl;
template <typename Assert, typename... Rest>
struct static_combined_check_impl<Assert, Rest...>
{
using type = Assert;
};
template <typename... Rest>
struct static_combined_check_impl<consistent_t, Rest...>
{
using type = typename static_combined_check_impl<Rest...>::type;
};
template <>
struct static_combined_check_impl<>
{
using type = consistent_t;
};
}
template <typename... Asserts>
using static_combined_check_t = typename detail::static_combined_check_impl<Asserts...>::type;
}
#endif

View File

@ -0,0 +1,235 @@
/*
* Copyright (c) 2015-2015, 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_TIME_POINT_H
#define SQLPP_TIME_POINT_H
#include <sqlpp11/date_time_fwd.h>
#include <sqlpp11/basic_expression_operators.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/exception.h>
#include <sqlpp11/value_type.h>
#include <sqlpp11/assignment.h>
#include <sqlpp11/result_field.h>
namespace sqlpp
{
// time_point value type
struct time_point
{
using _traits = make_traits<time_point, tag::is_value_type>;
using _tag = tag::is_date_time;
using _cpp_value_type = ::sqlpp::chrono::mus_point;
template <typename T>
using _is_valid_operand = is_time_point_t<T>;
};
// time_point parameter value
template <>
struct parameter_value_t<time_point>
{
using _value_type = time_point;
using _cpp_value_type = typename _value_type::_cpp_value_type;
parameter_value_t() : _value{}, _is_null(true)
{
}
explicit parameter_value_t(const _cpp_value_type& val) : _value(val), _is_null(false)
{
}
parameter_value_t& operator=(const _cpp_value_type& val)
{
_value = val;
_is_null = false;
return *this;
}
parameter_value_t& operator=(const tvin_t<wrap_operand_t<_cpp_value_type>>& t)
{
if (t._is_trivial())
{
_value = _cpp_value_type{};
_is_null = true;
}
else
{
_value = t._value._t;
_is_null = false;
}
return *this;
}
void set_null()
{
_value = _cpp_value_type{};
_is_null = true;
}
bool is_null() const
{
return _is_null;
}
const _cpp_value_type& value() const
{
return _value;
}
operator _cpp_value_type() const
{
return _value;
}
template <typename Target>
void _bind(Target& target, size_t index) const
{
target._bind_date_time_parameter(index, &_value, _is_null);
}
private:
_cpp_value_type _value;
bool _is_null;
};
// time_point expression operators
template <typename Base>
struct expression_operators<Base, time_point> : public basic_expression_operators<Base, time_point>
{
template <typename T>
using _is_valid_operand = is_valid_operand<time_point, T>;
};
// time_point column operators
template <typename Base>
struct column_operators<Base, time_point>
{
template <typename T>
using _is_valid_operand = is_valid_operand<time_point, T>;
};
// time_point result field
template <typename Db, typename FieldSpec>
struct result_field_t<time_point, Db, FieldSpec>
: public result_field_methods_t<result_field_t<time_point, Db, FieldSpec>>
{
static_assert(std::is_same<value_type_of<FieldSpec>, time_point>::value, "field type mismatch");
using _cpp_value_type = typename time_point::_cpp_value_type;
result_field_t() : _is_valid(false), _is_null(true), _value{}
{
}
void _invalidate()
{
_is_valid = false;
_is_null = true;
_value = _cpp_value_type{};
}
void _validate()
{
_is_valid = true;
}
bool is_null() const
{
if (not _is_valid)
throw exception("accessing is_null in non-existing row");
return _is_null;
}
bool _is_trivial() const
{
if (not _is_valid)
throw exception("accessing is_null in non-existing row");
return value() == _cpp_value_type{};
}
_cpp_value_type value() const
{
if (not _is_valid)
throw exception("accessing value in non-existing row");
if (_is_null)
{
if (enforce_null_result_treatment_t<Db>::value and not null_is_trivial_value_t<FieldSpec>::value)
{
throw exception("accessing value of NULL field");
}
else
{
return _cpp_value_type{};
}
}
return _value;
}
template <typename Target>
void _bind(Target& target, size_t i)
{
target._bind_date_time_result(i, &_value, &_is_null);
}
private:
bool _is_valid;
bool _is_null;
_cpp_value_type _value;
};
template <typename Context, typename Db, typename FieldSpec>
struct serializer_t<Context, result_field_t<time_point, Db, FieldSpec>>
{
using _serialize_check = consistent_t;
using T = result_field_t<time_point, Db, FieldSpec>;
static Context& _(const T& t, Context& context)
{
if (t.is_null() and not null_is_trivial_value_t<FieldSpec>::value)
{
context << "NULL";
}
else
{
const auto dp = ::date::floor<::date::days>(t.value());
const auto time = ::date::make_time(t.value() - dp);
const auto ymd = ::date::year_month_day{dp};
context << ymd << ' ' << time;
}
return context;
}
};
template <typename Db, typename FieldSpec>
inline std::ostream& operator<<(std::ostream& os, const result_field_t<time_point, Db, FieldSpec>& e)
{
return serialize(e, os);
}
}
#endif

View File

@ -29,6 +29,7 @@
#include <type_traits> #include <type_traits>
#include <tuple> #include <tuple>
#include <sqlpp11/consistent.h>
#include <sqlpp11/serializer.h> #include <sqlpp11/serializer.h>
#include <sqlpp11/detail/type_vector.h> #include <sqlpp11/detail/type_vector.h>
#include <sqlpp11/detail/type_set.h> #include <sqlpp11/detail/type_set.h>
@ -89,12 +90,18 @@ namespace sqlpp
SQLPP_VALUE_TRAIT_GENERATOR(is_value_type) SQLPP_VALUE_TRAIT_GENERATOR(is_value_type)
SQLPP_VALUE_TRAIT_GENERATOR(is_sql_null) SQLPP_VALUE_TRAIT_GENERATOR(is_sql_null)
SQLPP_VALUE_TRAIT_GENERATOR(is_boolean) SQLPP_VALUE_TRAIT_GENERATOR(is_boolean)
SQLPP_VALUE_TRAIT_GENERATOR(is_date)
SQLPP_VALUE_TRAIT_GENERATOR(is_date_time)
SQLPP_VALUE_TRAIT_GENERATOR(is_integral) SQLPP_VALUE_TRAIT_GENERATOR(is_integral)
SQLPP_VALUE_TRAIT_GENERATOR(is_floating_point) SQLPP_VALUE_TRAIT_GENERATOR(is_floating_point)
template <typename T> template <typename T>
using is_numeric_t = logic::any_t<detail::is_element_of<tag::is_integral, typename T::_traits::_tags>::value, using is_numeric_t = logic::any_t<detail::is_element_of<tag::is_integral, typename T::_traits::_tags>::value,
detail::is_element_of<tag::is_floating_point, typename T::_traits::_tags>::value>; detail::is_element_of<tag::is_floating_point, typename T::_traits::_tags>::value>;
template <typename T>
using is_time_point_t = logic::any_t<detail::is_element_of<tag::is_date, typename T::_traits::_tags>::value,
detail::is_element_of<tag::is_date_time, typename T::_traits::_tags>::value>;
SQLPP_VALUE_TRAIT_GENERATOR(is_text) SQLPP_VALUE_TRAIT_GENERATOR(is_text)
SQLPP_VALUE_TRAIT_GENERATOR(is_wrapped_value) SQLPP_VALUE_TRAIT_GENERATOR(is_wrapped_value)
SQLPP_VALUE_TRAIT_GENERATOR(is_selectable) SQLPP_VALUE_TRAIT_GENERATOR(is_selectable)
@ -300,14 +307,6 @@ namespace sqlpp
template <typename Policies> template <typename Policies>
using derived_statement_t = typename Policies::_statement_t; using derived_statement_t = typename Policies::_statement_t;
struct consistent_t
{
static constexpr bool value = true;
using type = std::true_type;
static void _(){};
};
template <typename T> template <typename T>
using is_inconsistent_t = using is_inconsistent_t =
typename std::conditional<std::is_same<consistent_t, T>::value, std::false_type, std::true_type>::type; typename std::conditional<std::is_same<consistent_t, T>::value, std::false_type, std::true_type>::type;

View File

@ -58,6 +58,27 @@ namespace sqlpp
and ValueType::template _is_valid_operand<T>::value // the correct value type is required, of course and ValueType::template _is_valid_operand<T>::value // the correct value type is required, of course
; ;
}; };
template <typename ValueType, typename T, typename Enable = void>
struct is_valid_assignment_operand
{
static constexpr bool value =
is_expression_t<T>::value // expressions are OK
and ValueType::template _is_valid_operand<T>::value // the correct value type is required, of course
;
};
template <typename ValueType, typename T>
struct is_valid_assignment_operand<
ValueType,
T,
typename std::enable_if<std::is_class<typename ValueType::template _is_valid_assignment_operand<T>>::value>::type>
{
static constexpr bool value =
is_expression_t<T>::value // expressions are OK
and ValueType::template _is_valid_assignment_operand<T>::value // the correct value type is required, of course
;
};
} }
#endif #endif

View File

@ -27,7 +27,9 @@
#ifndef SQLPP_DETAIL_WRAP_OPERAND_H #ifndef SQLPP_DETAIL_WRAP_OPERAND_H
#define SQLPP_DETAIL_WRAP_OPERAND_H #define SQLPP_DETAIL_WRAP_OPERAND_H
#include <date.h>
#include <string> #include <string>
#include <sqlpp11/date_time_fwd.h>
#include <sqlpp11/wrap_operand_fwd.h> #include <sqlpp11/wrap_operand_fwd.h>
#include <sqlpp11/serializer.h> #include <sqlpp11/serializer.h>
#include <sqlpp11/type_traits.h> #include <sqlpp11/type_traits.h>
@ -83,6 +85,97 @@ namespace sqlpp
} }
}; };
struct day_point_operand : public alias_operators<day_point_operand>
{
using _traits = make_traits<day_point, tag::is_expression, tag::is_wrapped_value>;
using _nodes = detail::type_vector<>;
using _is_aggregate_expression = std::true_type;
using _value_t = ::sqlpp::chrono::day_point;
day_point_operand() : _t{}
{
}
day_point_operand(_value_t t) : _t(t)
{
}
day_point_operand(const day_point_operand&) = default;
day_point_operand(day_point_operand&&) = default;
day_point_operand& operator=(const day_point_operand&) = default;
day_point_operand& operator=(day_point_operand&&) = default;
~day_point_operand() = default;
bool _is_trivial() const
{
return _t == _value_t{};
}
_value_t _t;
};
template <typename Context>
struct serializer_t<Context, day_point_operand>
{
using _serialize_check = consistent_t;
using Operand = day_point_operand;
static Context& _(const Operand& t, Context& context)
{
const auto ymd = ::date::year_month_day{t._t};
context << "DATE '" << ymd << "'";
return context;
}
};
template <typename Period>
struct time_point_operand : public alias_operators<time_point_operand<Period>>
{
using _traits = make_traits<time_point, tag::is_expression, tag::is_wrapped_value>;
using _nodes = detail::type_vector<>;
using _is_aggregate_expression = std::true_type;
using _value_t = std::chrono::time_point<std::chrono::system_clock, Period>;
time_point_operand() : _t{}
{
}
time_point_operand(_value_t t) : _t(t)
{
}
time_point_operand(const time_point_operand&) = default;
time_point_operand(time_point_operand&&) = default;
time_point_operand& operator=(const time_point_operand&) = default;
time_point_operand& operator=(time_point_operand&&) = default;
~time_point_operand() = default;
bool _is_trivial() const
{
return _t == _value_t{};
}
_value_t _t;
};
template <typename Context, typename Period>
struct serializer_t<Context, time_point_operand<Period>>
{
using _serialize_check = consistent_t;
using Operand = time_point_operand<Period>;
static Context& _(const Operand& t, Context& context)
{
const auto dp = ::date::floor<::date::days>(t._t);
const auto time = ::date::make_time(t._t - dp);
const auto ymd = ::date::year_month_day{dp};
context << "TIMESTAMP '" << ymd << ' ' << time << "'";
return context;
}
};
struct integral_operand : public alias_operators<integral_operand> struct integral_operand : public alias_operators<integral_operand>
{ {
using _traits = make_traits<integral, tag::is_expression, tag::is_wrapped_value>; using _traits = make_traits<integral, tag::is_expression, tag::is_wrapped_value>;
@ -224,6 +317,18 @@ namespace sqlpp
using type = boolean_operand; using type = boolean_operand;
}; };
template <typename Period>
struct wrap_operand<std::chrono::time_point<std::chrono::system_clock, Period>, void>
{
using type = time_point_operand<Period>;
};
template <>
struct wrap_operand<std::chrono::time_point<std::chrono::system_clock, sqlpp::chrono::days>, void>
{
using type = day_point_operand;
};
template <typename T> template <typename T>
struct wrap_operand<T, typename std::enable_if<std::is_integral<T>::value>::type> struct wrap_operand<T, typename std::enable_if<std::is_integral<T>::value>::type>
{ {

View File

@ -3,25 +3,25 @@
## ##
# Copyright (c) 2013-2015, Roland Bock # Copyright (c) 2013-2015, Roland Bock
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without modification, # Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met: # are permitted provided that the following conditions are met:
# #
# * Redistributions of source code must retain the above copyright notice, # * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer. # this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice, # * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation # this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution. # and/or other materials provided with the distribution.
# #
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # 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 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # 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, # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # 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 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE # 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 # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE. # OF THE POSSIBILITY OF SUCH DAMAGE.
## ##
@ -67,12 +67,12 @@ ddlDefaultValue = ddlWord("DEFAULT").setResultsName("hasDefaultValue");
ddlAutoValue = ddlWord("AUTO_INCREMENT").setResultsName("hasAutoValue"); ddlAutoValue = ddlWord("AUTO_INCREMENT").setResultsName("hasAutoValue");
ddlColumnComment = Group(ddlWord("COMMENT") + ddlString).setResultsName("comment") ddlColumnComment = Group(ddlWord("COMMENT") + ddlString).setResultsName("comment")
ddlConstraint = Or([ ddlConstraint = Or([
ddlWord("CONSTRAINT"), ddlWord("CONSTRAINT"),
ddlWord("PRIMARY"), ddlWord("PRIMARY"),
ddlWord("FOREIGN"), ddlWord("FOREIGN"),
ddlWord("KEY"), ddlWord("KEY"),
ddlWord("INDEX"), ddlWord("INDEX"),
ddlWord("UNIQUE"), ddlWord("UNIQUE"),
]) ])
ddlColumn = Group(Optional(ddlConstraint).setResultsName("isConstraint") + OneOrMore(MatchFirst([ddlNotNull, ddlAutoValue, ddlDefaultValue, ddlTerm, ddlNum, ddlColumnComment, ddlString, ddlArguments]))) ddlColumn = Group(Optional(ddlConstraint).setResultsName("isConstraint") + OneOrMore(MatchFirst([ddlNotNull, ddlAutoValue, ddlDefaultValue, ddlTerm, ddlNum, ddlColumnComment, ddlString, ddlArguments])))
createTable = Group(ddlWord("CREATE") + ddlWord("TABLE") + ddlTerm.setResultsName("tableName") + "(" + Group(delimitedList(ddlColumn)).setResultsName("columns") + ")").setResultsName("create") createTable = Group(ddlWord("CREATE") + ddlWord("TABLE") + ddlTerm.setResultsName("tableName") + "(" + Group(delimitedList(ddlColumn)).setResultsName("columns") + ")").setResultsName("create")
@ -98,8 +98,11 @@ types = {
'mediumblob': 'blob', 'mediumblob': 'blob',
'longblob': 'blob', 'longblob': 'blob',
'bool': 'boolean', 'bool': 'boolean',
'boolean': 'boolean',
'double': 'floating_point', 'double': 'floating_point',
'float': 'floating_point', 'float': 'floating_point',
'date' : 'day_point',
'datetime' : 'time_point',
} }
# PROCESS DDL # PROCESS DDL
@ -113,6 +116,7 @@ namespace = sys.argv[3]
ddlFile = open(pathToDdl, 'r') ddlFile = open(pathToDdl, 'r')
header = open(pathToHeader, 'w') header = open(pathToHeader, 'w')
print('// generated by ' + ' '.join(sys.argv), file=header)
print('#ifndef '+get_include_guard_name(namespace, pathToHeader), file=header) print('#ifndef '+get_include_guard_name(namespace, pathToHeader), file=header)
print('#define '+get_include_guard_name(namespace, pathToHeader), file=header) print('#define '+get_include_guard_name(namespace, pathToHeader), file=header)
print('', file=header) print('', file=header)

View File

@ -0,0 +1,290 @@
// generated by ../scripts/ddl2cpp ../test_static_asserts/AssertTables.sql ../test_static_asserts/AssertTables test
#ifndef TEST_ASSERTTABLES_H
#define TEST_ASSERTTABLES_H
#include <sqlpp11/table.h>
#include <sqlpp11/column_types.h>
#include <sqlpp11/char_sequence.h>
namespace test
{
namespace TabAllTypes_
{
struct SomeString
{
struct _alias_t
{
static constexpr const char _literal[] = "some_string";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T someString;
T& operator()()
{
return someString;
}
const T& operator()() const
{
return someString;
}
};
};
using _traits = sqlpp::make_traits<sqlpp::varchar, sqlpp::tag::can_be_null>;
};
struct SomeInt
{
struct _alias_t
{
static constexpr const char _literal[] = "some_int";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T someInt;
T& operator()()
{
return someInt;
}
const T& operator()() const
{
return someInt;
}
};
};
using _traits = sqlpp::make_traits<sqlpp::bigint, sqlpp::tag::can_be_null>;
};
struct SomeFloat
{
struct _alias_t
{
static constexpr const char _literal[] = "some_float";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T someFloat;
T& operator()()
{
return someFloat;
}
const T& operator()() const
{
return someFloat;
}
};
};
using _traits = sqlpp::make_traits<sqlpp::floating_point, sqlpp::tag::can_be_null>;
};
struct SomeBool
{
struct _alias_t
{
static constexpr const char _literal[] = "some_bool";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T someBool;
T& operator()()
{
return someBool;
}
const T& operator()() const
{
return someBool;
}
};
};
using _traits = sqlpp::make_traits<sqlpp::boolean, sqlpp::tag::can_be_null>;
};
struct SomeDayPoint
{
struct _alias_t
{
static constexpr const char _literal[] = "some_day_point";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T someDayPoint;
T& operator()()
{
return someDayPoint;
}
const T& operator()() const
{
return someDayPoint;
}
};
};
using _traits = sqlpp::make_traits<sqlpp::day_point, sqlpp::tag::can_be_null>;
};
struct SomeTimePoint
{
struct _alias_t
{
static constexpr const char _literal[] = "some_time_point";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T someTimePoint;
T& operator()()
{
return someTimePoint;
}
const T& operator()() const
{
return someTimePoint;
}
};
};
using _traits = sqlpp::make_traits<sqlpp::time_point, sqlpp::tag::can_be_null>;
};
struct OtherInt
{
struct _alias_t
{
static constexpr const char _literal[] = "other_int";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T otherInt;
T& operator()()
{
return otherInt;
}
const T& operator()() const
{
return otherInt;
}
};
};
using _traits = sqlpp::make_traits<sqlpp::bigint, sqlpp::tag::can_be_null>;
};
struct OtherFloat
{
struct _alias_t
{
static constexpr const char _literal[] = "other_float";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T otherFloat;
T& operator()()
{
return otherFloat;
}
const T& operator()() const
{
return otherFloat;
}
};
};
using _traits = sqlpp::make_traits<sqlpp::floating_point, sqlpp::tag::can_be_null>;
};
struct OtherBool
{
struct _alias_t
{
static constexpr const char _literal[] = "other_bool";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T otherBool;
T& operator()()
{
return otherBool;
}
const T& operator()() const
{
return otherBool;
}
};
};
using _traits = sqlpp::make_traits<sqlpp::boolean, sqlpp::tag::can_be_null>;
};
struct OtherDayPoint
{
struct _alias_t
{
static constexpr const char _literal[] = "other_day_point";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T otherDayPoint;
T& operator()()
{
return otherDayPoint;
}
const T& operator()() const
{
return otherDayPoint;
}
};
};
using _traits = sqlpp::make_traits<sqlpp::day_point, sqlpp::tag::can_be_null>;
};
struct OtherTimePoint
{
struct _alias_t
{
static constexpr const char _literal[] = "other_time_point";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T otherTimePoint;
T& operator()()
{
return otherTimePoint;
}
const T& operator()() const
{
return otherTimePoint;
}
};
};
using _traits = sqlpp::make_traits<sqlpp::time_point, sqlpp::tag::can_be_null>;
};
}
struct TabAllTypes : sqlpp::table_t<TabAllTypes,
TabAllTypes_::SomeString,
TabAllTypes_::SomeInt,
TabAllTypes_::SomeFloat,
TabAllTypes_::SomeBool,
TabAllTypes_::SomeDayPoint,
TabAllTypes_::SomeTimePoint,
TabAllTypes_::OtherInt,
TabAllTypes_::OtherFloat,
TabAllTypes_::OtherBool,
TabAllTypes_::OtherDayPoint,
TabAllTypes_::OtherTimePoint>
{
struct _alias_t
{
static constexpr const char _literal[] = "tab_all_types";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T tabAllTypes;
T& operator()()
{
return tabAllTypes;
}
const T& operator()() const
{
return tabAllTypes;
}
};
};
};
}
#endif

View File

@ -0,0 +1,43 @@
--
-- Copyright (c) 2015-2015, 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.
--
CREATE TABLE tab_all_types
(
some_string varchar(255),
some_int bigint,
some_float double,
some_bool bool,
some_date date,
some_date_time datetime
other_string varchar(255),
other_int bigint,
other_float double,
other_bool bool,
other_date date,
other_date_time datetime
);

View File

@ -30,4 +30,6 @@ endfunction()
test_compile(aggregates) test_compile(aggregates)
test_compile(insert) test_compile(insert)
test_compile(date)
test_compile(date_time)

View File

@ -0,0 +1,90 @@
/*
* Copyright (c) 2015-2015, 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 <iostream>
#include <MockDb.h>
#include "AssertTables.h"
#include <sqlpp11/sqlpp11.h>
namespace
{
constexpr auto t = test::TabAllTypes{};
template <typename T>
void print_type_on_error(std::true_type)
{
}
template <typename T>
void print_type_on_error(std::false_type)
{
T::_print_me_;
}
template <typename Assert, typename Operand>
void static_check_comparison(const Operand& operand)
{
using CheckResult = sqlpp::check_rhs_comparison_operand_t<decltype(t.someDayPoint), Operand>;
using ExpectedCheckResult = std::is_same<CheckResult, Assert>;
static_assert(ExpectedCheckResult::value, "Unexpected check result");
print_type_on_error<CheckResult>(ExpectedCheckResult{});
using ReturnType = sqlpp::detail::make_type_set_t<
decltype(t.someDayPoint < operand), decltype(t.someDayPoint <= operand), decltype(t.someDayPoint == operand),
decltype(t.someDayPoint != operand), decltype(t.someDayPoint >= operand), decltype(t.someDayPoint > operand),
decltype(t.someDayPoint.in(operand)), decltype(t.someDayPoint.in(operand, operand)),
decltype(t.someDayPoint.not_in(operand)), decltype(t.someDayPoint.not_in(operand, operand))>;
using ExpectedReturnType =
sqlpp::logic::all_t<Assert::value xor
std::is_same<ReturnType, sqlpp::detail::type_set<sqlpp::bad_statement>>::value>;
static_assert(ExpectedReturnType::value, "Unexpected return type");
print_type_on_error<ReturnType>(ExpectedReturnType{});
}
void allowed_comparands()
{
static_check_comparison<sqlpp::consistent_t>(std::chrono::system_clock::now());
static_check_comparison<sqlpp::consistent_t>(t.someDayPoint);
static_check_comparison<sqlpp::consistent_t>(t.someTimePoint);
}
void disallowed_comparands()
{
static_check_comparison<sqlpp::assert_valid_rhs_comparison_operand_t>(17);
static_check_comparison<sqlpp::assert_valid_rhs_comparison_operand_t>('a');
static_check_comparison<sqlpp::assert_valid_rhs_comparison_operand_t>(std::string("a"));
static_check_comparison<sqlpp::assert_valid_rhs_comparison_operand_t>(t);
static_check_comparison<sqlpp::assert_valid_rhs_comparison_operand_t>(t.someBool);
static_check_comparison<sqlpp::assert_valid_rhs_comparison_operand_t>(t.someFloat);
static_check_comparison<sqlpp::assert_valid_rhs_comparison_operand_t>(t.someInt);
static_check_comparison<sqlpp::assert_valid_rhs_comparison_operand_t>(t.someString);
}
}
int main(int, char**)
{
allowed_comparands();
disallowed_comparands();
}

View File

@ -0,0 +1,90 @@
/*
* Copyright (c) 2015-2015, 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 <iostream>
#include <MockDb.h>
#include "AssertTables.h"
#include <sqlpp11/sqlpp11.h>
namespace
{
constexpr auto t = test::TabAllTypes{};
template <typename T>
void print_type_on_error(std::true_type)
{
}
template <typename T>
void print_type_on_error(std::false_type)
{
T::_print_me_;
}
template <typename Assert, typename Operand>
void static_check_comparison(const Operand& operand)
{
using CheckResult = sqlpp::check_rhs_comparison_operand_t<decltype(t.someTimePoint), Operand>;
using ExpectedCheckResult = std::is_same<CheckResult, Assert>;
static_assert(ExpectedCheckResult::value, "Unexpected check result");
print_type_on_error<CheckResult>(ExpectedCheckResult{});
using ReturnType = sqlpp::detail::make_type_set_t<
decltype(t.someTimePoint < operand), decltype(t.someTimePoint <= operand), decltype(t.someTimePoint == operand),
decltype(t.someTimePoint != operand), decltype(t.someTimePoint >= operand), decltype(t.someTimePoint > operand),
decltype(t.someTimePoint.in(operand)), decltype(t.someTimePoint.in(operand, operand)),
decltype(t.someTimePoint.not_in(operand)), decltype(t.someTimePoint.not_in(operand, operand))>;
using ExpectedReturnType =
sqlpp::logic::all_t<Assert::value xor
std::is_same<ReturnType, sqlpp::detail::type_set<sqlpp::bad_statement>>::value>;
static_assert(ExpectedReturnType::value, "Unexpected return type");
print_type_on_error<ReturnType>(ExpectedReturnType{});
}
void allowed_comparands()
{
static_check_comparison<sqlpp::consistent_t>(std::chrono::system_clock::now());
static_check_comparison<sqlpp::consistent_t>(t.someDayPoint);
static_check_comparison<sqlpp::consistent_t>(t.someTimePoint);
}
void disallowed_comparands()
{
static_check_comparison<sqlpp::assert_valid_rhs_comparison_operand_t>(17);
static_check_comparison<sqlpp::assert_valid_rhs_comparison_operand_t>('a');
static_check_comparison<sqlpp::assert_valid_rhs_comparison_operand_t>(std::string("a"));
static_check_comparison<sqlpp::assert_valid_rhs_comparison_operand_t>(t);
static_check_comparison<sqlpp::assert_valid_rhs_comparison_operand_t>(t.someBool);
static_check_comparison<sqlpp::assert_valid_rhs_comparison_operand_t>(t.someFloat);
static_check_comparison<sqlpp::assert_valid_rhs_comparison_operand_t>(t.someInt);
static_check_comparison<sqlpp::assert_valid_rhs_comparison_operand_t>(t.someString);
}
}
int main(int, char**)
{
allowed_comparands();
disallowed_comparands();
}

View File

@ -32,6 +32,7 @@ endif ()
set(test_names set(test_names
BooleanExpression BooleanExpression
CustomQuery CustomQuery
DateTime
Interpret Interpret
Insert Insert
Remove Remove

71
tests/DateTime.cpp Normal file
View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2015-2015, 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 <iostream>
#include "Sample.h"
#include "MockDb.h"
#include <sqlpp11/sqlpp11.h>
SQLPP_ALIAS_PROVIDER(now)
int DateTime(int, char**)
{
MockDb db = {};
MockDb::_serializer_context_t printer;
test::TabDateTime t;
for (const auto& row : db(select(::sqlpp::value(std::chrono::system_clock::now()).as(now))))
{
std::cout << row.now;
}
for (const auto& row : db(select(all_of(t)).from(t).where(true)))
{
std::cout << row.colDayPoint;
std::cout << row.colTimePoint;
}
printer.reset();
std::cerr << serialize(::sqlpp::value(std::chrono::system_clock::now()), printer).str() << std::endl;
db(insert_into(t).set(t.colDayPoint = ::date::floor<::sqlpp::chrono::days>(std::chrono::system_clock::now())));
db(insert_into(t).set(t.colTimePoint = ::date::floor<::sqlpp::chrono::days>(std::chrono::system_clock::now())));
db(insert_into(t).set(t.colTimePoint = std::chrono::system_clock::now()));
db(update(t)
.set(t.colDayPoint = ::date::floor<::sqlpp::chrono::days>(std::chrono::system_clock::now()))
.where(t.colDayPoint < std::chrono::system_clock::now()));
db(update(t)
.set(t.colTimePoint = ::date::floor<::sqlpp::chrono::days>(std::chrono::system_clock::now()))
.where(t.colDayPoint < std::chrono::system_clock::now()));
db(update(t)
.set(t.colTimePoint = std::chrono::system_clock::now())
.where(t.colDayPoint < std::chrono::system_clock::now()));
db(remove_from(t).where(t.colDayPoint == ::date::floor<::sqlpp::chrono::days>(std::chrono::system_clock::now())));
db(remove_from(t).where(t.colDayPoint == std::chrono::system_clock::now()));
db(remove_from(t).where(t.colTimePoint == ::date::floor<::sqlpp::chrono::days>(std::chrono::system_clock::now())));
db(remove_from(t).where(t.colTimePoint == std::chrono::system_clock::now()));
return 0;
}

View File

@ -212,5 +212,75 @@ namespace test
}; };
}; };
}; };
namespace TabDateTime_
{
struct ColDayPoint
{
struct _alias_t
{
static constexpr const char _literal[] = "col_day_point";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T colDayPoint;
T& operator()()
{
return colDayPoint;
}
const T& operator()() const
{
return colDayPoint;
}
};
};
using _traits = sqlpp::make_traits<sqlpp::day_point, sqlpp::tag::can_be_null>;
};
struct ColTimePoint
{
struct _alias_t
{
static constexpr const char _literal[] = "col_time_point";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T colTimePoint;
T& operator()()
{
return colTimePoint;
}
const T& operator()() const
{
return colTimePoint;
}
};
};
using _traits = sqlpp::make_traits<sqlpp::time_point, sqlpp::tag::can_be_null>;
};
}
struct TabDateTime : sqlpp::table_t<TabDateTime, TabDateTime_::ColDayPoint, TabDateTime_::ColTimePoint>
{
struct _alias_t
{
static constexpr const char _literal[] = "tab_time_point";
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
template <typename T>
struct _member_t
{
T tabDateTime;
T& operator()()
{
return tabDateTime;
}
const T& operator()() const
{
return tabDateTime;
}
};
};
};
} }
#endif #endif

View File

@ -1,17 +1,17 @@
/* /*
* Copyright (c) 2013-2015, Roland Bock * Copyright (c) 2013-2015, Roland Bock
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, * Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met: * are permitted provided that the following conditions are met:
* *
* Redistributions of source code must retain the above copyright notice, this * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer. * list of conditions and the following disclaimer.
* *
* Redistributions in binary form must reproduce the above copyright notice, this * Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or * list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution. * other materials provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * 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 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE