mirror of
https://github.com/rbock/sqlpp11.git
synced 2024-11-16 04:47:18 +08:00
Date/time adjustments, including date cannot be assigned with timestamp
This is inspired by sqlite's behaviour: If you have a date column (say colDate) and update it with colDate = DATETIME('2015-01-01T20:20:20); colDate will contain the date time, not just the date (while the connector would probably just read the date part). In order to prevent this kind of inconsistencies, date can be assigned only with dates, not with timestamps.
This commit is contained in:
parent
73e8f04127
commit
5e83929555
@ -62,6 +62,8 @@ namespace sqlpp
|
||||
|
||||
template <typename 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(const column_t&) = default;
|
||||
@ -87,7 +89,7 @@ namespace sqlpp
|
||||
auto operator=(T t) const -> assignment_t<column_t, 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}}};
|
||||
}
|
||||
|
@ -28,7 +28,7 @@
|
||||
#define SQLPP_DATE_H
|
||||
|
||||
#include <date.h>
|
||||
#include <sqlpp11/date_time_fwd.h>
|
||||
#include <sqlpp11/date_time.h>
|
||||
#include <sqlpp11/basic_expression_operators.h>
|
||||
#include <sqlpp11/type_traits.h>
|
||||
#include <sqlpp11/exception.h>
|
||||
@ -43,10 +43,12 @@ namespace sqlpp
|
||||
{
|
||||
using _traits = make_traits<date, tag::is_value_type>;
|
||||
using _tag = tag::is_date;
|
||||
using _cpp_value_type = cpp::day_point;
|
||||
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>;
|
||||
};
|
||||
|
||||
// date parameter value
|
||||
@ -194,7 +196,7 @@ namespace sqlpp
|
||||
template <typename Target>
|
||||
void _bind(Target& target, size_t i)
|
||||
{
|
||||
target._bind_day_point_result(i, &_value, &_is_null);
|
||||
target._bind_date_result(i, &_value, &_is_null);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -42,7 +42,7 @@ namespace sqlpp
|
||||
{
|
||||
using _traits = make_traits<date_time, tag::is_value_type>;
|
||||
using _tag = tag::is_date_time;
|
||||
using _cpp_value_type = cpp::ms_point;
|
||||
using _cpp_value_type = ::sqlpp::chrono::mus_point;
|
||||
|
||||
template <typename T>
|
||||
using _is_valid_operand = is_time_point_t<T>;
|
||||
@ -109,7 +109,7 @@ namespace sqlpp
|
||||
template <typename Target>
|
||||
void _bind(Target& target, size_t index) const
|
||||
{
|
||||
target._bind_date_parameter(index, &_value, _is_null);
|
||||
target._bind_date_time_parameter(index, &_value, _is_null);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -194,7 +194,7 @@ namespace sqlpp
|
||||
template <typename Target>
|
||||
void _bind(Target& target, size_t i)
|
||||
{
|
||||
target._bind_date_result(i, &_value, &_is_null);
|
||||
target._bind_date_time_result(i, &_value, &_is_null);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -217,8 +217,8 @@ namespace sqlpp
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto dp = ::date::floor<::date::days>(t);
|
||||
const auto time = ::date::make_time(t - dp);
|
||||
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;
|
||||
}
|
||||
|
@ -31,16 +31,16 @@
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
namespace cpp
|
||||
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 ms_point = std::chrono::time_point<std::chrono::system_clock, std::chrono::microseconds>;
|
||||
using mus_point = std::chrono::time_point<std::chrono::system_clock, std::chrono::microseconds>;
|
||||
}
|
||||
|
||||
struct date;
|
||||
struct date_time;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -58,6 +58,27 @@ namespace sqlpp
|
||||
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
|
||||
|
@ -85,10 +85,54 @@ namespace sqlpp
|
||||
}
|
||||
};
|
||||
|
||||
struct date_operand : public alias_operators<date_operand>
|
||||
{
|
||||
using _traits = make_traits<date, 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;
|
||||
|
||||
date_operand() : _t{}
|
||||
{
|
||||
}
|
||||
|
||||
date_operand(_value_t t) : _t(t)
|
||||
{
|
||||
}
|
||||
|
||||
date_operand(const date_operand&) = default;
|
||||
date_operand(date_operand&&) = default;
|
||||
date_operand& operator=(const date_operand&) = default;
|
||||
date_operand& operator=(date_operand&&) = default;
|
||||
~date_operand() = default;
|
||||
|
||||
bool _is_trivial() const
|
||||
{
|
||||
return _t == _value_t{};
|
||||
}
|
||||
|
||||
_value_t _t;
|
||||
};
|
||||
|
||||
template <typename Context>
|
||||
struct serializer_t<Context, date_operand>
|
||||
{
|
||||
using _serialize_check = consistent_t;
|
||||
using Operand = date_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 date_time_operand : public alias_operators<date_time_operand<Period>>
|
||||
{
|
||||
using _traits = make_traits<date, tag::is_expression, tag::is_wrapped_value>;
|
||||
using _traits = make_traits<date_time, tag::is_expression, tag::is_wrapped_value>;
|
||||
using _nodes = detail::type_vector<>;
|
||||
using _is_aggregate_expression = std::true_type;
|
||||
|
||||
@ -132,20 +176,6 @@ namespace sqlpp
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Context>
|
||||
struct serializer_t<Context, date_time_operand<cpp::days>>
|
||||
{
|
||||
using _serialize_check = consistent_t;
|
||||
using Operand = date_time_operand<cpp::days>;
|
||||
|
||||
static Context& _(const Operand& t, Context& context)
|
||||
{
|
||||
const auto ymd = ::date::year_month_day{t._t};
|
||||
context << "DATE '" << ymd << "'";
|
||||
return context;
|
||||
}
|
||||
};
|
||||
|
||||
struct integral_operand : public alias_operators<integral_operand>
|
||||
{
|
||||
using _traits = make_traits<integral, tag::is_expression, tag::is_wrapped_value>;
|
||||
@ -293,6 +323,12 @@ namespace sqlpp
|
||||
using type = date_time_operand<Period>;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct wrap_operand<std::chrono::time_point<std::chrono::system_clock, sqlpp::chrono::days>, void>
|
||||
{
|
||||
using type = date_operand;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct wrap_operand<T, typename std::enable_if<std::is_integral<T>::value>::type>
|
||||
{
|
||||
|
@ -36,32 +36,35 @@ int DateTime(int, char**)
|
||||
MockDb::_serializer_context_t printer;
|
||||
test::TabDateTime t;
|
||||
|
||||
for (const auto& row : db(select(sqlpp::value(std::chrono::system_clock::now()).as(now))))
|
||||
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.colDate;
|
||||
std::cout << row.colDateTime;
|
||||
}
|
||||
printer.reset();
|
||||
std::cerr << serialize(sqlpp::value(std::chrono::system_clock::now()), printer).str() << std::endl;
|
||||
std::cerr << serialize(::sqlpp::value(std::chrono::system_clock::now()), printer).str() << std::endl;
|
||||
|
||||
db(insert_into(t).set(t.colDate = ::date::floor<sqlpp::cpp::days>(std::chrono::system_clock::now())));
|
||||
db(insert_into(t).set(t.colDate = std::chrono::system_clock::now()));
|
||||
db(insert_into(t).set(t.colDateTime = ::date::floor<sqlpp::cpp::days>(std::chrono::system_clock::now())));
|
||||
db(insert_into(t).set(t.colDate = ::date::floor<::sqlpp::chrono::days>(std::chrono::system_clock::now())));
|
||||
db(insert_into(t).set(t.colDateTime = ::date::floor<::sqlpp::chrono::days>(std::chrono::system_clock::now())));
|
||||
db(insert_into(t).set(t.colDateTime = std::chrono::system_clock::now()));
|
||||
|
||||
db(update(t)
|
||||
.set(t.colDate = ::date::floor<sqlpp::cpp::days>(std::chrono::system_clock::now()))
|
||||
.set(t.colDate = ::date::floor<::sqlpp::chrono::days>(std::chrono::system_clock::now()))
|
||||
.where(t.colDate < std::chrono::system_clock::now()));
|
||||
db(update(t).set(t.colDate = std::chrono::system_clock::now()).where(t.colDate < std::chrono::system_clock::now()));
|
||||
db(update(t)
|
||||
.set(t.colDateTime = ::date::floor<sqlpp::cpp::days>(std::chrono::system_clock::now()))
|
||||
.set(t.colDateTime = ::date::floor<::sqlpp::chrono::days>(std::chrono::system_clock::now()))
|
||||
.where(t.colDate < std::chrono::system_clock::now()));
|
||||
db(update(t)
|
||||
.set(t.colDateTime = std::chrono::system_clock::now())
|
||||
.where(t.colDate < std::chrono::system_clock::now()));
|
||||
|
||||
db(remove_from(t).where(t.colDate == ::date::floor<sqlpp::cpp::days>(std::chrono::system_clock::now())));
|
||||
db(remove_from(t).where(t.colDate == ::date::floor<::sqlpp::chrono::days>(std::chrono::system_clock::now())));
|
||||
db(remove_from(t).where(t.colDate == std::chrono::system_clock::now()));
|
||||
db(remove_from(t).where(t.colDateTime == ::date::floor<sqlpp::cpp::days>(std::chrono::system_clock::now())));
|
||||
db(remove_from(t).where(t.colDateTime == ::date::floor<::sqlpp::chrono::days>(std::chrono::system_clock::now())));
|
||||
db(remove_from(t).where(t.colDateTime == std::chrono::system_clock::now()));
|
||||
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user