0
0
mirror of https://github.com/rbock/sqlpp11.git synced 2024-11-15 20:31:16 +08:00

Replaced numeric by integral and floating_point

This commit is contained in:
Roland Bock 2013-11-07 11:31:42 +01:00
parent aa5c2c90a6
commit aae910671e
6 changed files with 262 additions and 34 deletions

View File

@ -22,6 +22,8 @@ This results in several benefits, e.g.
The library supports both static and dynamic queries. The former offers greater benefit in terms of type and consistency checking. The latter makes it easier to construct queries on the flight. The library supports both static and dynamic queries. The former offers greater benefit in terms of type and consistency checking. The latter makes it easier to construct queries on the flight.
Specific traits of databases (e.g. unsupported or non-standard features) are known at compile time as well. This way, the compiler can tell the developer at compile time if a query is not accepted by the database (e.g. if a feature is missing). And the library can form the query in the correct manner, for instance if the engine uses concat instead of operator|| to concatenate strings.
Your help is needed: Your help is needed:
-------------------- --------------------

View File

@ -28,7 +28,8 @@
#define SQLPP_COLUMN_TYPES_H #define SQLPP_COLUMN_TYPES_H
#include <sqlpp11/boolean.h> #include <sqlpp11/boolean.h>
#include <sqlpp11/numeric.h> #include <sqlpp11/integral.h>
#include <sqlpp11/floating_point.h>
#include <sqlpp11/text.h> #include <sqlpp11/text.h>
#endif #endif

View File

@ -28,18 +28,18 @@
#define SQLPP_COUNT_H #define SQLPP_COUNT_H
#include <sstream> #include <sstream>
#include <sqlpp11/numeric.h> #include <sqlpp11/integral.h>
namespace sqlpp namespace sqlpp
{ {
namespace detail namespace detail
{ {
template<typename Expr> template<typename Expr>
struct count_t: public numeric::template operators<count_t<Expr>> struct count_t: public integral::template operators<count_t<Expr>>
{ {
static_assert(is_value_t<Expr>::value, "count() requires a sql value as argument"); static_assert(is_value_t<Expr>::value, "count() requires a sql value as argument");
struct _value_type: public numeric struct _value_type: public integral
{ {
using _is_named_expression = std::true_type; using _is_named_expression = std::true_type;
}; };

View File

@ -35,7 +35,8 @@ namespace sqlpp
namespace detail namespace detail
{ {
struct boolean; struct boolean;
struct numeric; struct integral;
struct floating_point;
struct text; struct text;
struct bool_operand struct bool_operand
@ -62,17 +63,41 @@ namespace sqlpp
}; };
template<typename T> template<typename T>
struct numeric_operand struct integral_operand
{ {
static constexpr bool _is_expression = true; static constexpr bool _is_expression = true;
using _value_type = numeric; using _value_type = integral;
numeric_operand(T t): _t(t) {} integral_operand(T t): _t(t) {}
numeric_operand(const numeric_operand&) = default; integral_operand(const integral_operand&) = default;
numeric_operand(numeric_operand&&) = default; integral_operand(integral_operand&&) = default;
numeric_operand& operator=(const numeric_operand&) = default; integral_operand& operator=(const integral_operand&) = default;
numeric_operand& operator=(numeric_operand&&) = default; integral_operand& operator=(integral_operand&&) = default;
~numeric_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 T>
struct floating_point_operand
{
static constexpr bool _is_expression = true;
using _value_type = 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> template<typename Db>
void serialize(std::ostream& os, Db& db) const void serialize(std::ostream& os, Db& db) const
@ -124,7 +149,13 @@ namespace sqlpp
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>
{ {
using type = numeric_operand<T>; using type = integral_operand<T>;
};
template<typename T>
struct wrap_operand<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
{
using type = floating_point_operand<T>;
}; };
template<typename T> template<typename T>

View File

@ -24,8 +24,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef SQLPP_NUMERIC_H #ifndef SQLPP_FLOATING_POINT_H
#define SQLPP_NUMERIC_H #define SQLPP_FLOATING_POINT_H
#include <cstdlib> #include <cstdlib>
#include <sqlpp11/detail/basic_operators.h> #include <sqlpp11/detail/basic_operators.h>
@ -38,29 +38,30 @@ namespace sqlpp
namespace detail namespace detail
{ {
// numeric value type // floating_point value type
struct numeric struct floating_point
{ {
using _base_value_type = numeric; using _base_value_type = floating_point;
using _is_numeric = std::true_type; using _is_numeric = std::true_type;
using _is_floating_point = std::true_type;
using _is_value = std::true_type; using _is_value = std::true_type;
using _is_expression = std::true_type; using _is_expression = std::true_type;
template<size_t index> template<size_t index>
struct _result_entry_t struct _result_entry_t
{ {
using _value_type = numeric; using _value_type = floating_point;
_result_entry_t(const raw_result_row_t& row): _result_entry_t(const raw_result_row_t& row):
_is_valid(row.data != nullptr), _is_valid(row.data != nullptr),
_is_null(row.data == nullptr or row.data[index] == nullptr), _is_null(row.data == nullptr or row.data[index] == nullptr),
_value(_is_null ? 0 : std::strtoll(row.data[index], nullptr, 10)) _value(_is_null ? 0 : std::strtod(row.data[index], nullptr))
{} {}
_result_entry_t& operator=(const raw_result_row_t& row) _result_entry_t& operator=(const raw_result_row_t& row)
{ {
_is_valid = (row.data != nullptr); _is_valid = (row.data != nullptr);
_is_null = row.data == nullptr or row.data[index] == nullptr; _is_null = row.data == nullptr or row.data[index] == nullptr;
_value = _is_null ? 0 : std::strtoll(row.data[index], nullptr, 10); _value = _is_null ? 0 : std::strtod(row.data[index], nullptr);
return *this; return *this;
} }
@ -79,42 +80,42 @@ namespace sqlpp
return _is_null; return _is_null;
} }
int64_t value() const double value() const
{ {
if (not _is_valid) if (not _is_valid)
throw exception("accessing value in non-existing row"); throw exception("accessing value in non-existing row");
return _value; return _value;
} }
operator int64_t() const { return value(); } operator double() const { return value(); }
private: private:
bool _is_valid; bool _is_valid;
bool _is_null; bool _is_null;
int64_t _value; double _value;
}; };
struct plus_ struct plus_
{ {
using _value_type = numeric; using _value_type = floating_point;
static constexpr const char* _name = "+"; static constexpr const char* _name = "+";
}; };
struct minus_ struct minus_
{ {
using _value_type = numeric; using _value_type = floating_point;
static constexpr const char* _name = "-"; static constexpr const char* _name = "-";
}; };
struct multiplies_ struct multiplies_
{ {
using _value_type = numeric; using _value_type = floating_point;
static constexpr const char* _name = "*"; static constexpr const char* _name = "*";
}; };
struct divides_ struct divides_
{ {
using _value_type = numeric; using _value_type = floating_point;
static constexpr const char* _name = "/"; static constexpr const char* _name = "/";
}; };
@ -177,16 +178,13 @@ namespace sqlpp
}; };
template<size_t index> template<size_t index>
std::ostream& operator<<(std::ostream& os, const numeric::_result_entry_t<index>& e) std::ostream& operator<<(std::ostream& os, const floating_point::_result_entry_t<index>& e)
{ {
return os << e.value(); return os << e.value();
} }
} }
using tinyint = detail::numeric; using floating_point = detail::floating_point;
using smallint = detail::numeric;
using integer = detail::numeric;
using bigint = detail::numeric;
} }
#endif #endif

196
include/sqlpp11/integral.h Normal file
View File

@ -0,0 +1,196 @@
/*
* 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_INTEGRAL_H
#define SQLPP_INTEGRAL_H
#include <cstdlib>
#include <sqlpp11/detail/basic_operators.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/raw_result_row.h>
#include <sqlpp11/exception.h>
namespace sqlpp
{
namespace detail
{
// integral value type
struct integral
{
using _base_value_type = integral;
using _is_numeric = std::true_type;
using _is_floating_point = std::true_type;
using _is_value = std::true_type;
using _is_expression = std::true_type;
template<size_t index>
struct _result_entry_t
{
using _value_type = integral;
_result_entry_t(const raw_result_row_t& row):
_is_valid(row.data != nullptr),
_is_null(row.data == nullptr or row.data[index] == nullptr),
_value(_is_null ? 0 : std::strtoll(row.data[index], nullptr, 10))
{}
_result_entry_t& operator=(const raw_result_row_t& row)
{
_is_valid = (row.data != nullptr);
_is_null = row.data == nullptr or row.data[index] == nullptr;
_value = _is_null ? 0 : std::strtoll(row.data[index], nullptr, 10);
return *this;
}
template<typename Db>
void serialize(std::ostream& os, Db& db) const
{
os << value();
}
bool _is_trivial() const { return value() == 0; }
bool is_null() const
{
if (not _is_valid)
throw exception("accessing is_null in non-existing row");
return _is_null;
}
int64_t value() const
{
if (not _is_valid)
throw exception("accessing value in non-existing row");
return _value;
}
operator int64_t() const { return value(); }
private:
bool _is_valid;
bool _is_null;
int64_t _value;
};
template<typename T>
struct plus_
{
using _value_type = typename wrap_operand<typename std::decay<T>::type>::type::_value_type;
static constexpr const char* _name = "+";
};
template<typename T>
struct minus_
{
using _value_type = typename wrap_operand<typename std::decay<T>::type>::type::_value_type;
static constexpr const char* _name = "-";
};
template<typename T>
struct multiplies_
{
using _value_type = typename wrap_operand<typename std::decay<T>::type>::type::_value_type;
static constexpr const char* _name = "*";
};
struct divides_
{
using _value_type = floating_point;
static constexpr const char* _name = "/";
};
template<typename T>
using _constraint = operand_t<T, is_numeric_t>;
template<typename Base>
struct operators: public basic_operators<Base, _constraint>
{
template<typename T>
binary_expression_t<Base, plus_<T>, typename _constraint<T>::type> operator +(T&& t) const
{
return { *static_cast<const Base*>(this), std::forward<T>(t) };
}
template<typename T>
binary_expression_t<Base, minus_<T>, typename _constraint<T>::type> operator -(T&& t) const
{
return { *static_cast<const Base*>(this), std::forward<T>(t) };
}
template<typename T>
binary_expression_t<Base, multiplies_<T>, typename _constraint<T>::type> operator *(T&& t) const
{
return { *static_cast<const Base*>(this), std::forward<T>(t) };
}
template<typename T>
binary_expression_t<Base, divides_, typename _constraint<T>::type> operator /(T&& t) const
{
return { *static_cast<const Base*>(this), std::forward<T>(t) };
}
template<typename T>
auto operator +=(T&& t) const -> decltype(std::declval<Base>() = std::declval<Base>() + std::forward<T>(t))
{
return *static_cast<const Base*>(this) = operator +(std::forward<T>(t));
}
template<typename T>
auto operator -=(T&& t) const -> decltype(std::declval<Base>() = std::declval<Base>() - std::forward<T>(t))
{
return *static_cast<const Base*>(this) = operator -(std::forward<T>(t));
}
template<typename T>
auto operator /=(T&& t) const -> decltype(std::declval<Base>() = std::declval<Base>() / std::forward<T>(t))
{
return *static_cast<const Base*>(this) = operator /(std::forward<T>(t));
}
template<typename T>
auto operator *=(T&& t) const -> decltype(std::declval<Base>() = std::declval<Base>() * std::forward<T>(t))
{
return *static_cast<const Base*>(this) = operator *(std::forward<T>(t));
}
};
};
template<size_t index>
std::ostream& operator<<(std::ostream& os, const integral::_result_entry_t<index>& e)
{
return os << e.value();
}
}
using tinyint = detail::integral;
using smallint = detail::integral;
using integer = detail::integral;
using bigint = detail::integral;
}
#endif