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

Migrated select components to support policy based select

This commit is contained in:
rbock 2014-02-07 22:52:02 +01:00
parent 9c4832df0f
commit 62b828ef8f
11 changed files with 604 additions and 272 deletions

View File

@ -28,7 +28,6 @@
#define SQLPP_SELECT_H #define SQLPP_SELECT_H
#include <sqlpp11/result.h> #include <sqlpp11/result.h>
#include <sqlpp11/select_fwd.h>
#include <sqlpp11/parameter_list.h> #include <sqlpp11/parameter_list.h>
#include <sqlpp11/prepared_select.h> #include <sqlpp11/prepared_select.h>
@ -45,74 +44,69 @@
#include <sqlpp11/vendor/expression.h> #include <sqlpp11/vendor/expression.h>
#include <sqlpp11/vendor/interpreter.h> #include <sqlpp11/vendor/interpreter.h>
#include <sqlpp11/vendor/wrong.h> #include <sqlpp11/vendor/wrong.h>
#include <sqlpp11/vendor/crtp_wrapper.h>
#include <sqlpp11/vendor/policy.h>
#include <sqlpp11/vendor/policy_update.h>
#include <sqlpp11/detail/make_flag_tuple.h> #include <sqlpp11/detail/make_flag_tuple.h>
#include <sqlpp11/detail/make_expression_tuple.h> #include <sqlpp11/detail/make_expression_tuple.h>
#include <sstream>
namespace sqlpp namespace sqlpp
{ {
template< namespace detail
typename Database, {
typename FlagList, template<
typename ColumnList, typename FlagList,
typename From, typename ColumnList,
typename Where, typename From,
typename GroupBy, typename Where,
typename Having, typename GroupBy,
typename OrderBy, typename Having,
typename Limit, typename OrderBy,
typename Offset typename Limit,
> typename Offset
struct select_t >
: public ColumnList::_value_type::template operators<select_t< struct check_select_t
Database, {
FlagList, //static_assert(is_where_t<Where>::value, "cannot select remove without having a where condition, use .where(true) to remove all rows");
ColumnList, static constexpr bool value = true;
From, };
Where, }
GroupBy,
Having,
OrderBy,
Limit,
Offset>>
{
using _Database = Database;
using _From = From;
static_assert(is_select_flag_list_t<FlagList>::value, "invalid list of select flags"); template<typename Database, typename... Policies>
static_assert(is_select_column_list_t<ColumnList>::value, "invalid list of select expressions"); struct select_t: public vendor::policy_t<Policies>..., public vendor::crtp_wrapper_t<select_t<Database, Policies...>, Policies>...
static_assert(vendor::is_noop<From>::value or is_from_t<From>::value, "invalid 'from' argument"); {
static_assert(vendor::is_noop<Where>::value or is_where_t<Where>::value, "invalid 'where' argument"); template<typename Needle, typename Replacement>
static_assert(vendor::is_noop<GroupBy>::value or is_group_by_t<GroupBy>::value, "invalid 'group by' arguments"); using _policy_update_t = select_t<Database, vendor::policy_update_t<Policies, Needle, Replacement>...>;
static_assert(vendor::is_noop<Having>::value or is_having_t<Having>::value, "invalid 'having' arguments");
static_assert(vendor::is_noop<OrderBy>::value or is_order_by_t<OrderBy>::value, "invalid 'order by' arguments"); using _database_t = Database;
static_assert(vendor::is_noop<Limit>::value or is_limit_t<Limit>::value, "invalid 'limit' arguments"); using _parameter_tuple_t = std::tuple<Policies...>;
static_assert(vendor::is_noop<Offset>::value or is_offset_t<Offset>::value, "invalid 'offset' arguments"); using _parameter_list_t = typename make_parameter_list_t<select_t>::type;
select_t()
{}
template<typename Whatever>
select_t(select_t r, Whatever whatever):
vendor::policy_t<Policies>(r, whatever)...
{}
template<typename Remove, typename Whatever>
select_t(Remove r, Whatever whatever):
vendor::policy_t<Policies>(r, whatever)...
{}
select_t(const select_t& r) = default;
select_t(select_t&& r) = default;
select_t& operator=(const select_t& r) = default;
select_t& operator=(select_t&& r) = default;
~select_t() = default;
using _is_select = std::true_type; using _is_select = std::true_type;
using _requires_braces = std::true_type; using _requires_braces = std::true_type;
template<typename FlagListT> /*
using set_flag_list_t = select_t<Database, FlagListT, ColumnList, From, Where, GroupBy, Having, OrderBy, Limit, Offset>;
template<typename ColumnListT>
using set_column_list_t = select_t<Database, FlagList, ColumnListT, From, Where, GroupBy, Having, OrderBy, Limit, Offset>;
template<typename FromT>
using set_from_t = select_t<Database, FlagList, ColumnList, FromT, Where, GroupBy, Having, OrderBy, Limit, Offset>;
template<typename WhereT>
using set_where_t = select_t<Database, FlagList, ColumnList, From, WhereT, GroupBy, Having, OrderBy, Limit, Offset>;
template<typename GroupByT>
using set_group_by_t = select_t<Database, FlagList, ColumnList, From, Where, GroupByT, Having, OrderBy, Limit, Offset>;
template<typename HavingT>
using set_having_t = select_t<Database, FlagList, ColumnList, From, Where, GroupBy, HavingT, OrderBy, Limit, Offset>;
template<typename OrderByT>
using set_order_by_t = select_t<Database, FlagList, ColumnList, From, Where, GroupBy, Having, OrderByT, Limit, Offset>;
template<typename LimitT>
using set_limit_t = select_t<Database, FlagList, ColumnList, From, Where, GroupBy, Having, OrderBy, LimitT, Offset>;
template<typename OffsetT>
using set_offset_t = select_t<Database, FlagList, ColumnList, From, Where, GroupBy, Having, OrderBy, Limit, OffsetT>;
using _result_row_t = typename ColumnList::_result_row_t; using _result_row_t = typename ColumnList::_result_row_t;
using _dynamic_names_t = typename ColumnList::_dynamic_names_t; using _dynamic_names_t = typename ColumnList::_dynamic_names_t;
using _parameter_tuple_t = std::tuple<ColumnList, Where, GroupBy, Having, OrderBy, Limit, Offset>; using _parameter_tuple_t = std::tuple<ColumnList, Where, GroupBy, Having, OrderBy, Limit, Offset>;
@ -640,58 +634,21 @@ namespace sqlpp
return {{}, get_dynamic_names(), db.prepare_select(*this)}; return {{}, get_dynamic_names(), db.prepare_select(*this)};
} }
*/
FlagList _flags;
ColumnList _columns;
From _from;
Where _where;
GroupBy _group_by;
Having _having;
OrderBy _order_by;
Limit _limit;
Offset _offset;
}; };
namespace vendor namespace vendor
{ {
template<typename Context, template<typename Context, typename Database, typename... Policies>
typename Database, struct interpreter_t<Context, select_t<Database, Policies...>>
typename FlagList,
typename ColumnList,
typename From,
typename Where,
typename GroupBy,
typename Having,
typename OrderBy,
typename Limit,
typename Offset
>
struct interpreter_t<Context, select_t<Database,
FlagList,
ColumnList,
From,
Where,
GroupBy,
Having,
OrderBy,
Limit,
Offset>>
{ {
using T = select_t<Database, using T = select_t<Database, Policies...>;
FlagList,
ColumnList,
From,
Where,
GroupBy,
Having,
OrderBy,
Limit,
Offset>;
static Context& _(const T& t, Context& context) static Context& _(const T& t, Context& context)
{ {
context << "SELECT "; context << "SELECT ";
/*
interpret(t._flags, context); interpret(t._flags, context);
interpret(t._columns, context); interpret(t._columns, context);
interpret(t._from, context); interpret(t._from, context);
@ -701,6 +658,7 @@ namespace sqlpp
interpret(t._order_by, context); interpret(t._order_by, context);
interpret(t._limit, context); interpret(t._limit, context);
interpret(t._offset, context); interpret(t._offset, context);
*/
return context; return context;
} }
@ -708,6 +666,8 @@ namespace sqlpp
} }
/*
// construct select flag list // construct select flag list
namespace detail namespace detail
{ {
@ -751,6 +711,7 @@ namespace sqlpp
{}, {}, {}, {}, {}, {}, {} {}, {}, {}, {}, {}, {}, {}
}; };
} }
*/
} }
#endif #endif

View File

@ -31,27 +31,7 @@
namespace sqlpp namespace sqlpp
{ {
namespace vendor template<typename Database, typename... Policies>
{
struct noop;
}
// select flags
struct all_t;
struct distinct_t;
struct straight_join_t;
template<
typename Db,
typename Flags = vendor::noop,
typename ExpressionList = vendor::noop,
typename From = vendor::noop,
typename Where = vendor::noop,
typename GroupBy = vendor::noop,
typename Having = vendor::noop,
typename OrderBy = vendor::noop,
typename Limit = vendor::noop,
typename Offset = vendor::noop
>
struct select_t; struct select_t;
} }
#endif #endif

View File

@ -83,7 +83,6 @@ namespace sqlpp
no_from_t& _from = *this; no_from_t& _from = *this;
}; };
// CRTP Wrappers // CRTP Wrappers
template<typename Derived, typename Database, typename... Args> template<typename Derived, typename Database, typename... Args>
struct crtp_wrapper_t<Derived, from_t<Database, Args...>> struct crtp_wrapper_t<Derived, from_t<Database, Args...>>
@ -109,7 +108,6 @@ namespace sqlpp
} }
}; };
// Interpreters // Interpreters
template<typename Context, typename Database, typename... Tables> template<typename Context, typename Database, typename... Tables>
struct interpreter_t<Context, from_t<Database, Tables...>> struct interpreter_t<Context, from_t<Database, Tables...>>
@ -139,8 +137,8 @@ namespace sqlpp
return context; return context;
} }
}; };
}
}
} }
#endif #endif

View File

@ -32,57 +32,111 @@
#include <sqlpp11/vendor/expression.h> #include <sqlpp11/vendor/expression.h>
#include <sqlpp11/vendor/interpret_tuple.h> #include <sqlpp11/vendor/interpret_tuple.h>
#include <sqlpp11/vendor/interpretable_list.h> #include <sqlpp11/vendor/interpretable_list.h>
#include <sqlpp11/vendor/policy_update.h>
#include <sqlpp11/vendor/crtp_wrapper.h>
#include <sqlpp11/detail/logic.h> #include <sqlpp11/detail/logic.h>
namespace sqlpp namespace sqlpp
{ {
namespace vendor namespace vendor
{ {
template<typename Database, typename... Expr> // GROUP BY
template<typename Database, typename... Expressions>
struct group_by_t struct group_by_t
{ {
using _is_group_by = std::true_type; using _is_group_by = std::true_type;
using _is_dynamic = typename std::conditional<std::is_same<Database, void>::value, std::false_type, std::true_type>::type; using _is_dynamic = typename std::conditional<std::is_same<Database, void>::value, std::false_type, std::true_type>::type;
using _parameter_tuple_t = std::tuple<Expr...>; using _parameter_tuple_t = std::tuple<Expressions...>;
// ensure one argument at least static_assert(_is_dynamic::value or sizeof...(Expressions), "at least one expression (e.g. a column) required in group_by()");
static_assert(_is_dynamic::value or sizeof...(Expr), "at least one expression (e.g. a column) required in group_by()");
// check for duplicate expressions static_assert(not ::sqlpp::detail::has_duplicates<Expressions...>::value, "at least one duplicate argument detected in group_by()");
static_assert(not ::sqlpp::detail::has_duplicates<Expr...>::value, "at least one duplicate argument detected in group_by()");
// check for invalid expressions static_assert(::sqlpp::detail::and_t<is_expression_t, Expressions...>::value, "at least one argument is not an expression in group_by()");
static_assert(::sqlpp::detail::and_t<is_expression_t, Expr...>::value, "at least one argument is not an expression in group_by()");
template<typename E> group_by_t(Expressions... expressions):
void add(E expr) _expressions(expressions...)
{}
group_by_t(const group_by_t&) = default;
group_by_t(group_by_t&&) = default;
group_by_t& operator=(const group_by_t&) = default;
group_by_t& operator=(group_by_t&&) = default;
~group_by_t() = default;
template<typename Expression>
void add_group_by(Expression expression)
{ {
static_assert(is_table_t<E>::value, "from arguments require to be tables or joins"); static_assert(is_table_t<Expression>::value, "from arguments require to be tables or joins");
_dynamic_expressions.emplace_back(expr); _dynamic_expressions.emplace_back(expression);
} }
group_by_t& _group_by = *this;
_parameter_tuple_t _expressions; _parameter_tuple_t _expressions;
vendor::interpretable_list_t<Database> _dynamic_expressions; vendor::interpretable_list_t<Database> _dynamic_expressions;
}; };
template<typename Context, typename Database, typename... Expr> struct no_group_by_t
struct interpreter_t<Context, group_by_t<Database, Expr...>> {
using _is_group_by = std::true_type;
no_group_by_t& _group_by = *this;
};
// CRTP Wrappers
template<typename Derived, typename Database, typename... Args>
struct crtp_wrapper_t<Derived, group_by_t<Database, Args...>>
{ {
using T = group_by_t<Database, Expr...>; };
template<typename Derived>
struct crtp_wrapper_t<Derived, no_group_by_t>
{
template<typename... Args>
auto group_by(Args... args)
-> vendor::update_policies_t<Derived, no_group_by_t, group_by_t<void, Args...>>
{
return { static_cast<Derived&>(*this), group_by_t<void, Args...>(args...) };
}
template<typename... Args>
auto dynamic_group_by(Args... args)
-> vendor::update_policies_t<Derived, no_group_by_t, group_by_t<get_database_t<Derived>, Args...>>
{
static_assert(not std::is_same<get_database_t<Derived>, void>::value, "dynamic_group_by must not be called in a static statement");
return { static_cast<Derived&>(*this), group_by_t<get_database_t<Derived>, Args...>(args...) };
}
};
// Interpreters
template<typename Context, typename Database, typename... Expressions>
struct interpreter_t<Context, group_by_t<Database, Expressions...>>
{
using T = group_by_t<Database, Expressions...>;
static Context& _(const T& t, Context& context) static Context& _(const T& t, Context& context)
{ {
if (sizeof...(Expr) == 0 and t._dynamic_expressions.empty()) if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty())
return context; return context;
context << " GROUP BY "; context << " GROUP BY ";
interpret_tuple(t._expressions, ',', context); interpret_tuple(t._expressions, ',', context);
if (sizeof...(Expr) and not t._dynamic_expressions.empty()) if (sizeof...(Expressions) and not t._dynamic_expressions.empty())
context << ','; context << ',';
interpret_list(t._dynamic_expressions, ',', context); interpret_list(t._dynamic_expressions, ',', context);
return context; return context;
} }
}; };
template<typename Context>
struct interpreter_t<Context, no_group_by_t>
{
using T = no_group_by_t;
static Context& _(const T& t, Context& context)
{
return context;
}
};
} }
} }

View File

@ -31,52 +31,100 @@
#include <sqlpp11/vendor/expression.h> #include <sqlpp11/vendor/expression.h>
#include <sqlpp11/vendor/interpret_tuple.h> #include <sqlpp11/vendor/interpret_tuple.h>
#include <sqlpp11/vendor/interpretable_list.h> #include <sqlpp11/vendor/interpretable_list.h>
#include <sqlpp11/vendor/policy_update.h>
#include <sqlpp11/vendor/crtp_wrapper.h>
#include <sqlpp11/detail/logic.h> #include <sqlpp11/detail/logic.h>
namespace sqlpp namespace sqlpp
{ {
namespace vendor namespace vendor
{ {
template<typename Database, typename... Expr> // HAVING
template<typename Database, typename... Expressions>
struct having_t struct having_t
{ {
using _is_having = std::true_type; using _is_having = std::true_type;
using _is_dynamic = typename std::conditional<std::is_same<Database, void>::value, std::false_type, std::true_type>::type; using _is_dynamic = typename std::conditional<std::is_same<Database, void>::value, std::false_type, std::true_type>::type;
using _parameter_tuple_t = std::tuple<Expr...>; using _parameter_tuple_t = std::tuple<Expressions...>;
static_assert(_is_dynamic::value or sizeof...(Expr), "at least one expression argument required in having()"); static_assert(_is_dynamic::value or sizeof...(Expressions), "at least one expression argument required in having()");
static_assert(::sqlpp::detail::and_t<is_expression_t, Expr...>::value, "at least one argument is not an expression in having()"); static_assert(::sqlpp::detail::and_t<is_expression_t, Expressions...>::value, "at least one argument is not an expression in having()");
using _parameter_list_t = typename make_parameter_list_t<_parameter_tuple_t>::type; using _parameter_list_t = typename make_parameter_list_t<_parameter_tuple_t>::type;
template<typename E> template<typename Expression>
void add(E expr) void add(Expression expr)
{ {
static_assert(is_expression_t<E>::value, "invalid expression argument in add_having()"); static_assert(is_expression_t<Expression>::value, "invalid expression argument in add_having()");
_dynamic_expressions.emplace_back(expr); _dynamic_expressions.emplace_back(expr);
} }
having_t& _having = *this;
_parameter_tuple_t _expressions; _parameter_tuple_t _expressions;
vendor::interpretable_list_t<Database> _dynamic_expressions; vendor::interpretable_list_t<Database> _dynamic_expressions;
}; };
template<typename Context, typename Database, typename... Expr> struct no_having_t
struct interpreter_t<Context, having_t<Database, Expr...>> {
using _is_having = std::true_type;
no_having_t& _having = *this;
};
// CRTP Wrappers
template<typename Derived, typename Database, typename... Args>
struct crtp_wrapper_t<Derived, having_t<Database, Args...>>
{ {
using T = having_t<Database, Expr...>; };
template<typename Derived>
struct crtp_wrapper_t<Derived, no_having_t>
{
template<typename... Args>
auto having(Args... args)
-> vendor::update_policies_t<Derived, no_having_t, having_t<void, Args...>>
{
return { static_cast<Derived&>(*this), having_t<void, Args...>(args...) };
}
template<typename... Args>
auto dynamic_having(Args... args)
-> vendor::update_policies_t<Derived, no_having_t, having_t<get_database_t<Derived>, Args...>>
{
static_assert(not std::is_same<get_database_t<Derived>, void>::value, "dynamic_having must not be called in a static statement");
return { static_cast<Derived&>(*this), having_t<get_database_t<Derived>, Args...>(args...) };
}
};
// Interpreters
template<typename Context, typename Database, typename... Expressions>
struct interpreter_t<Context, having_t<Database, Expressions...>>
{
using T = having_t<Database, Expressions...>;
static Context& _(const T& t, Context& context) static Context& _(const T& t, Context& context)
{ {
if (sizeof...(Expr) == 0 and t._dynamic_expressions.empty()) if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty())
return context; return context;
context << " HAVING "; context << " HAVING ";
interpret_tuple(t._expressions, " AND ", context); interpret_tuple(t._expressions, " AND ", context);
if (sizeof...(Expr) and not t._dynamic_expressions.empty()) if (sizeof...(Expressions) and not t._dynamic_expressions.empty())
context << " AND "; context << " AND ";
interpret_list(t._dynamic_expressions, " AND ", context); interpret_list(t._dynamic_expressions, " AND ", context);
return context; return context;
} }
}; };
template<typename Context>
struct interpreter_t<Context, no_having_t>
{
using T = no_having_t;
static Context& _(const T& t, Context& context)
{
return context;
}
};
} }
} }

View File

@ -27,21 +27,106 @@
#ifndef SQLPP_LIMIT_H #ifndef SQLPP_LIMIT_H
#define SQLPP_LIMIT_H #define SQLPP_LIMIT_H
#include <ostream>
#include <sqlpp11/select_fwd.h>
#include <sqlpp11/type_traits.h> #include <sqlpp11/type_traits.h>
#include <sqlpp11/vendor/policy_update.h>
#include <sqlpp11/vendor/crtp_wrapper.h>
namespace sqlpp namespace sqlpp
{ {
namespace vendor namespace vendor
{ {
// LIMIT
template<typename Limit> template<typename Limit>
struct limit_t struct limit_t
{ {
using _is_limit = std::true_type; using _is_limit = std::true_type;
static_assert(is_integral_t<Limit>::value, "limit requires an integral value or integral parameter"); static_assert(is_integral_t<Limit>::value, "limit requires an integral value or integral parameter");
Limit _limit; limit_t(size_t value):
_value(value)
{}
limit_t(const limit_t&) = default;
limit_t(limit_t&&) = default;
limit_t& operator=(const limit_t&) = default;
limit_t& operator=(limit_t&&) = default;
~limit_t() = default;
limit_t& _limit = *this;
Limit _value;
};
struct dynamic_limit_t
{
using _is_limit = std::true_type;
using _is_dynamic = std::true_type;
dynamic_limit_t(size_t value):
_value(value)
{}
dynamic_limit_t(const dynamic_limit_t&) = default;
dynamic_limit_t(dynamic_limit_t&&) = default;
dynamic_limit_t& operator=(const dynamic_limit_t&) = default;
dynamic_limit_t& operator=(dynamic_limit_t&&) = default;
~dynamic_limit_t() = default;
void set_limit(std::size_t limit)
{
_value = limit;
}
dynamic_limit_t& _limit = *this;
std::size_t _value; // FIXME: This should be a serializable!
};
struct no_limit_t
{
using _is_limit = std::true_type;
no_limit_t& _limit = *this;
};
// CRTP Wrappers
template<typename Derived, typename Limit>
struct crtp_wrapper_t<Derived, limit_t<Limit>>
{
};
template<typename Derived>
struct crtp_wrapper_t<Derived, dynamic_limit_t>
{
};
template<typename Derived>
struct crtp_wrapper_t<Derived, no_limit_t>
{
template<typename Arg>
auto limit(Arg arg)
-> vendor::update_policies_t<Derived, no_limit_t, limit_t<Arg>>
{
return { static_cast<Derived&>(*this), limit_t<Arg>(arg) };
}
auto dynamic_limit(size_t arg)
-> vendor::update_policies_t<Derived, no_limit_t, dynamic_limit_t>
{
static_assert(not std::is_same<get_database_t<Derived>, void>::value, "dynamic_limit must not be called in a static statement");
return { static_cast<Derived&>(*this), dynamic_limit_t(arg) };
}
};
// Interpreters
template<typename Context>
struct interpreter_t<Context, dynamic_limit_t>
{
using T = dynamic_limit_t;
static Context& _(const T& t, Context& context)
{
if (t._value > 0)
context << " LIMIT " << t._limit;
return context;
}
}; };
template<typename Context, typename Limit> template<typename Context, typename Limit>
@ -52,38 +137,23 @@ namespace sqlpp
static Context& _(const T& t, Context& context) static Context& _(const T& t, Context& context)
{ {
context << " LIMIT "; context << " LIMIT ";
interpret(t._limit, context); interpret(t._value, context);
return context; return context;
} }
}; };
struct dynamic_limit_t
{
using _is_limit = std::true_type;
using _is_dynamic = std::true_type;
void set(std::size_t limit)
{
_limit = limit;
}
std::size_t _limit;
};
template<typename Context> template<typename Context>
struct interpreter_t<Context, dynamic_limit_t> struct interpreter_t<Context, no_limit_t>
{ {
using T = dynamic_limit_t; using T = no_limit_t;
static Context& _(const T& t, Context& context) static Context& _(const T& t, Context& context)
{ {
if (t._limit > 0)
context << " LIMIT " << t._limit;
return context; return context;
} }
}; };
}
}
} }
#endif #endif

View File

@ -28,20 +28,94 @@
#define SQLPP_OFFSET_H #define SQLPP_OFFSET_H
#include <sqlpp11/type_traits.h> #include <sqlpp11/type_traits.h>
#include <sqlpp11/vendor/policy_update.h>
#include <sqlpp11/vendor/crtp_wrapper.h>
namespace sqlpp namespace sqlpp
{ {
namespace vendor namespace vendor
{ {
// OFFSET
template<typename Offset> template<typename Offset>
struct offset_t struct offset_t
{ {
using _is_offset = std::true_type; using _is_offset = std::true_type;
static_assert(is_integral_t<Offset>::value, "offset requires an integral value or integral parameter"); static_assert(is_integral_t<Offset>::value, "offset requires an integral value or integral parameter");
Offset _offset; offset_t(size_t value):
_value(value)
{}
offset_t(const offset_t&) = default;
offset_t(offset_t&&) = default;
offset_t& operator=(const offset_t&) = default;
offset_t& operator=(offset_t&&) = default;
~offset_t() = default;
offset_t& _offset = *this;
Offset _value;
}; };
struct dynamic_offset_t
{
using _is_offset = std::true_type;
using _is_dynamic = std::true_type;
dynamic_offset_t(size_t value):
_value(value)
{}
dynamic_offset_t(const dynamic_offset_t&) = default;
dynamic_offset_t(dynamic_offset_t&&) = default;
dynamic_offset_t& operator=(const dynamic_offset_t&) = default;
dynamic_offset_t& operator=(dynamic_offset_t&&) = default;
~dynamic_offset_t() = default;
void set_offset(std::size_t offset)
{
_value = offset;
}
dynamic_offset_t& _offset = *this;
std::size_t _value; // FIXME: This should be a serializable!
};
struct no_offset_t
{
using _is_offset = std::true_type;
no_offset_t& _offset = *this;
};
// CRTP Wrappers
template<typename Derived, typename Limit>
struct crtp_wrapper_t<Derived, offset_t<Limit>>
{
};
template<typename Derived>
struct crtp_wrapper_t<Derived, dynamic_offset_t>
{
};
template<typename Derived>
struct crtp_wrapper_t<Derived, no_offset_t>
{
template<typename Arg>
auto offset(Arg arg)
-> vendor::update_policies_t<Derived, no_offset_t, offset_t<Arg>>
{
return { static_cast<Derived&>(*this), offset_t<Arg>(arg) };
}
auto dynamic_offset(size_t arg)
-> vendor::update_policies_t<Derived, no_offset_t, dynamic_offset_t>
{
static_assert(not std::is_same<get_database_t<Derived>, void>::value, "dynamic_offset must not be called in a static statement");
return { static_cast<Derived&>(*this), dynamic_offset_t(arg) };
}
};
// Interpreters
template<typename Context, typename Offset> template<typename Context, typename Offset>
struct interpreter_t<Context, offset_t<Offset>> struct interpreter_t<Context, offset_t<Offset>>
{ {
@ -55,19 +129,6 @@ namespace sqlpp
} }
}; };
struct dynamic_offset_t
{
using _is_offset = std::true_type;
using _is_dynamic = std::true_type;
void set(std::size_t offset)
{
_offset = offset;
}
std::size_t _offset;
};
template<typename Context> template<typename Context>
struct interpreter_t<Context, dynamic_offset_t> struct interpreter_t<Context, dynamic_offset_t>
{ {
@ -75,12 +136,22 @@ namespace sqlpp
static Context& _(const T& t, Context& context) static Context& _(const T& t, Context& context)
{ {
if (t._offset > 0) if (t._value > 0)
context << " OFFSET " << t._offset; context << " OFFSET " << t._offset;
return context; return context;
} }
}; };
template<typename Context>
struct interpreter_t<Context, no_offset_t>
{
using T = no_offset_t;
static Context& _(const T& t, Context& context)
{
return context;
}
};
} }
} }

View File

@ -32,55 +32,110 @@
#include <sqlpp11/type_traits.h> #include <sqlpp11/type_traits.h>
#include <sqlpp11/vendor/interpret_tuple.h> #include <sqlpp11/vendor/interpret_tuple.h>
#include <sqlpp11/vendor/interpretable.h> #include <sqlpp11/vendor/interpretable.h>
#include <sqlpp11/vendor/policy_update.h>
#include <sqlpp11/vendor/crtp_wrapper.h>
#include <sqlpp11/detail/logic.h>
namespace sqlpp namespace sqlpp
{ {
namespace vendor namespace vendor
{ {
template<typename Database,typename... Expr> template<typename Database,typename... Expressions>
struct order_by_t struct order_by_t
{ {
using _is_order_by = std::true_type; using _is_order_by = std::true_type;
using _is_dynamic = typename std::conditional<std::is_same<Database, void>::value, std::false_type, std::true_type>::type; using _is_dynamic = typename std::conditional<std::is_same<Database, void>::value, std::false_type, std::true_type>::type;
using _parameter_tuple_t = std::tuple<Expr...>; using _parameter_tuple_t = std::tuple<Expressions...>;
// check for at least one order expression static_assert(_is_dynamic::value or sizeof...(Expressions), "at least one sort-order expression required in order_by()");
static_assert(_is_dynamic::value or sizeof...(Expr), "at least one sort-order expression required in order_by()");
// check for duplicate order expressions static_assert(not ::sqlpp::detail::has_duplicates<Expressions...>::value, "at least one duplicate argument detected in order_by()");
static_assert(not ::sqlpp::detail::has_duplicates<Expr...>::value, "at least one duplicate argument detected in order_by()");
// check for invalid order expressions static_assert(::sqlpp::detail::and_t<is_sort_order_t, Expressions...>::value, "at least one argument is not a sort order expression in order_by()");
static_assert(::sqlpp::detail::and_t<is_sort_order_t, Expr...>::value, "at least one argument is not a sort order expression in order_by()");
template<typename E> order_by_t(Expressions... expressions):
void add(E expr) _expressions(expressions...)
{}
order_by_t(const order_by_t&) = default;
order_by_t(order_by_t&&) = default;
order_by_t& operator=(const order_by_t&) = default;
order_by_t& operator=(order_by_t&&) = default;
~order_by_t() = default;
template<typename Expression>
void add_order_by(Expression expressions)
{ {
static_assert(is_sort_order_t<E>::value, "order_by arguments require to be sort-order expressions"); static_assert(is_sort_order_t<Expression>::value, "order_by arguments require to be sort-order expressions");
_dynamic_expressions.push_back(expr); _dynamic_expressions.push_back(expressions);
} }
order_by_t& _order_by = *this;
_parameter_tuple_t _expressions; _parameter_tuple_t _expressions;
vendor::interpretable_list_t<Database> _dynamic_expressions; vendor::interpretable_list_t<Database> _dynamic_expressions;
}; };
template<typename Context, typename Database, typename... Expr> struct no_order_by_t
struct interpreter_t<Context, order_by_t<Database, Expr...>> {
using _is_order_by = std::true_type;
no_order_by_t& _order_by = *this;
};
// CRTP Wrappers
template<typename Derived, typename Database, typename... Args>
struct crtp_wrapper_t<Derived, order_by_t<Database, Args...>>
{ {
using T = order_by_t<Database, Expr...>; };
template<typename Derived>
struct crtp_wrapper_t<Derived, no_order_by_t>
{
template<typename... Args>
auto order_by(Args... args)
-> vendor::update_policies_t<Derived, no_order_by_t, order_by_t<void, Args...>>
{
return { static_cast<Derived&>(*this), order_by_t<void, Args...>(args...) };
}
template<typename... Args>
auto dynamic_order_by(Args... args)
-> vendor::update_policies_t<Derived, no_order_by_t, order_by_t<get_database_t<Derived>, Args...>>
{
static_assert(not std::is_same<get_database_t<Derived>, void>::value, "dynamic_order_by must not be called in a static statement");
return { static_cast<Derived&>(*this), order_by_t<get_database_t<Derived>, Args...>(args...) };
}
};
// Interpreters
template<typename Context, typename Database, typename... Expressions>
struct interpreter_t<Context, order_by_t<Database, Expressions...>>
{
using T = order_by_t<Database, Expressions...>;
static Context& _(const T& t, Context& context) static Context& _(const T& t, Context& context)
{ {
if (sizeof...(Expr) == 0 and t._dynamic_expressions.empty()) if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty())
return context; return context;
context << " ORDER BY "; context << " ORDER BY ";
interpret_tuple(t._expressions, ',', context); interpret_tuple(t._expressions, ',', context);
if (sizeof...(Expr) and not t._dynamic_expressions.empty()) if (sizeof...(Expressions) and not t._dynamic_expressions.empty())
context << ','; context << ',';
interpret_list(t._dynamic_expressions, ',', context); interpret_list(t._dynamic_expressions, ',', context);
return context; return context;
} }
}; };
template<typename Context>
struct interpreter_t<Context, no_order_by_t>
{
using T = no_order_by_t;
static Context& _(const T& t, Context& context)
{
return context;
}
};
} }
} }

View File

@ -37,6 +37,8 @@
#include <sqlpp11/vendor/select_pseudo_table.h> #include <sqlpp11/vendor/select_pseudo_table.h>
#include <sqlpp11/vendor/named_interpretable.h> #include <sqlpp11/vendor/named_interpretable.h>
#include <sqlpp11/vendor/interpret_tuple.h> #include <sqlpp11/vendor/interpret_tuple.h>
#include <sqlpp11/vendor/policy_update.h>
#include <sqlpp11/vendor/crtp_wrapper.h>
#include <sqlpp11/detail/type_set.h> #include <sqlpp11/detail/type_set.h>
namespace sqlpp namespace sqlpp
@ -130,69 +132,103 @@ namespace sqlpp
}; };
template<typename Database, typename T> // SELECT COLUMNS
template<typename Database, typename... Columns>
struct select_column_list_t struct select_column_list_t
{
static_assert(::sqlpp::vendor::wrong_t<Database, T>::value, "invalid template argument for select_column_list");
};
template<typename Database, typename... NamedExpr>
struct select_column_list_t<Database, std::tuple<NamedExpr...>>
{ {
using _is_select_column_list = std::true_type; using _is_select_column_list = std::true_type;
using _is_dynamic = typename std::conditional<std::is_same<Database, void>::value, std::false_type, std::true_type>::type; using _is_dynamic = typename std::conditional<std::is_same<Database, void>::value, std::false_type, std::true_type>::type;
using _parameter_tuple_t = std::tuple<NamedExpr...>; using _parameter_tuple_t = std::tuple<Columns...>;
using size = std::tuple_size<_parameter_tuple_t>; using size = std::tuple_size<_parameter_tuple_t>;
// check for duplicate select expressions static_assert(not ::sqlpp::detail::has_duplicates<Columns...>::value, "at least one duplicate argument detected");
static_assert(not ::sqlpp::detail::has_duplicates<NamedExpr...>::value, "at least one duplicate argument detected");
// check for invalid select expressions
template<typename T> template<typename T>
using is_valid_expression_t = std::integral_constant<bool, is_named_expression_t<T>::value or is_multi_column_t<T>::value>; using is_valid_expression_t = std::integral_constant<bool, is_named_expression_t<T>::value or is_multi_column_t<T>::value>;
static_assert(::sqlpp::detail::and_t<is_valid_expression_t, NamedExpr...>::value, "at least one argument is not a named expression"); static_assert(::sqlpp::detail::and_t<is_valid_expression_t, Columns...>::value, "at least one argument is not a named expression");
// check for duplicate select expression names static_assert(not ::sqlpp::detail::has_duplicates<typename Columns::_name_t...>::value, "at least one duplicate name detected");
static_assert(not ::sqlpp::detail::has_duplicates<typename NamedExpr::_name_t...>::value, "at least one duplicate name detected");
// provide type information for sub-selects that are used as expressions
struct _column_type {}; struct _column_type {};
struct _value_type: ::sqlpp::detail::get_first_argument_if_unique<NamedExpr...>::_value_type struct _value_type: ::sqlpp::detail::get_first_argument_if_unique<Columns...>::_value_type
{ {
using _is_expression = typename std::conditional<sizeof...(NamedExpr) == 1, std::true_type, std::false_type>::type; using _is_expression = typename std::conditional<sizeof...(Columns) == 1, std::true_type, std::false_type>::type;
using _is_named_expression = typename std::conditional<sizeof...(NamedExpr) == 1, std::true_type, std::false_type>::type; using _is_named_expression = typename std::conditional<sizeof...(Columns) == 1, std::true_type, std::false_type>::type;
using _is_alias = std::false_type; using _is_alias = std::false_type;
}; };
using _name_t = typename ::sqlpp::detail::get_first_argument_if_unique<NamedExpr...>::_name_t; using _name_t = typename ::sqlpp::detail::get_first_argument_if_unique<Columns...>::_name_t;
using _result_row_t = typename std::conditional<_is_dynamic::value, using _result_row_t = typename std::conditional<_is_dynamic::value,
dynamic_result_row_t<make_field_t<NamedExpr>...>, dynamic_result_row_t<make_field_t<Columns>...>,
result_row_t<make_field_t<NamedExpr>...>>::type; result_row_t<make_field_t<Columns>...>>::type;
using _dynamic_names_t = typename dynamic_select_column_list<Database>::_names_t; using _dynamic_names_t = typename dynamic_select_column_list<Database>::_names_t;
template <typename Select> template <typename Select>
using _pseudo_table_t = select_pseudo_table_t<Select, NamedExpr...>; using _pseudo_table_t = select_pseudo_table_t<Select, Columns...>;
template <typename Db> template <typename Db>
using _dynamic_t = select_column_list_t<Db, std::tuple<NamedExpr...>>; using _dynamic_t = select_column_list_t<Db, std::tuple<Columns...>>;
select_column_list_t(Columns... columns):
_columns(columns...)
{}
select_column_list_t(const select_column_list_t&) = default;
select_column_list_t(select_column_list_t&&) = default;
select_column_list_t& operator=(const select_column_list_t&) = default;
select_column_list_t& operator=(select_column_list_t&&) = default;
~select_column_list_t() = default;
template<typename Expr> template<typename Expr>
void add(Expr namedExpr) void add_column(Expr namedExpr)
{ {
static_assert(is_named_expression_t<Expr>::value, "select() arguments require to be named expressions"); static_assert(is_named_expression_t<Expr>::value, "select() arguments require to be named expressions");
static_assert(_is_dynamic::value, "cannot add columns to a non-dynamic column list"); static_assert(_is_dynamic::value, "cannot add columns to a non-dynamic column list");
_dynamic_columns.push_back(namedExpr); _dynamic_columns.push_back(namedExpr);
} }
select_column_list_t& _column_list = *this;
_parameter_tuple_t _columns; _parameter_tuple_t _columns;
dynamic_select_column_list<Database> _dynamic_columns; dynamic_select_column_list<Database> _dynamic_columns;
}; };
template<typename Context, typename Database, typename Tuple> struct no_select_column_list_t
struct interpreter_t<Context, select_column_list_t<Database, Tuple>> {
using _is_select_column_list = std::true_type;
no_select_column_list_t& _column_list = *this;
};
// CRTP Wrappers
template<typename Derived, typename Database, typename... Args>
struct crtp_wrapper_t<Derived, select_column_list_t<Database, Args...>>
{ {
using T = select_column_list_t<Database, Tuple>; };
template<typename Derived>
struct crtp_wrapper_t<Derived, no_select_column_list_t>
{
template<typename... Args>
auto columns(Args... args)
-> vendor::update_policies_t<Derived, no_select_column_list_t, select_column_list_t<void, Args...>>
{
return { static_cast<Derived&>(*this), select_column_list_t<void, Args...>(args...) };
}
template<typename... Args>
auto dynamic_columns(Args... args)
-> vendor::update_policies_t<Derived, no_select_column_list_t, select_column_list_t<get_database_t<Derived>, Args...>>
{
static_assert(not std::is_same<get_database_t<Derived>, void>::value, "dynamic_columns must not be called in a static statement");
return { static_cast<Derived&>(*this), select_column_list_t<get_database_t<Derived>, Args...>(args...) };
}
};
// Interpreters
template<typename Context, typename Database, typename... Columns>
struct interpreter_t<Context, select_column_list_t<Database, Columns...>>
{
using T = select_column_list_t<Database, Columns...>;
static Context& _(const T& t, Context& context) static Context& _(const T& t, Context& context)
{ {
@ -206,6 +242,17 @@ namespace sqlpp
return context; return context;
} }
}; };
template<typename Context>
struct interpreter_t<Context, no_select_column_list_t>
{
using T = no_select_column_list_t;
static Context& _(const T& t, Context& context)
{
return context;
}
};
} }
} }

View File

@ -27,58 +27,95 @@
#ifndef SQLPP_VENDOR_SELECT_FLAG_LIST_H #ifndef SQLPP_VENDOR_SELECT_FLAG_LIST_H
#define SQLPP_VENDOR_SELECT_FLAG_LIST_H #define SQLPP_VENDOR_SELECT_FLAG_LIST_H
#include <tuple>
#include <sqlpp11/select_fwd.h> #include <sqlpp11/select_fwd.h>
#include <sqlpp11/type_traits.h> #include <sqlpp11/type_traits.h>
#include <sqlpp11/select_flags.h> #include <sqlpp11/select_flags.h>
#include <sqlpp11/detail/type_set.h> #include <sqlpp11/detail/type_set.h>
#include <sqlpp11/vendor/interpret_tuple.h> #include <sqlpp11/vendor/interpret_tuple.h>
#include <tuple> #include <sqlpp11/vendor/policy_update.h>
#include <sqlpp11/vendor/crtp_wrapper.h>
namespace sqlpp namespace sqlpp
{ {
namespace vendor namespace vendor
{ {
template<typename Database, typename T> // SELECT FLAGS
template<typename Database, typename... Flags>
struct select_flag_list_t struct select_flag_list_t
{
static_assert(::sqlpp::vendor::wrong_t<T>::value, "invalid argument for select_flag_list");
};
// select_flag_list_t
template<typename Database, typename... Flag>
struct select_flag_list_t<Database, std::tuple<Flag...>>
{ {
using _is_select_flag_list = std::true_type; using _is_select_flag_list = std::true_type;
using _is_dynamic = typename std::conditional<std::is_same<Database, void>::value, std::false_type, std::true_type>::type; using _is_dynamic = typename std::conditional<std::is_same<Database, void>::value, std::false_type, std::true_type>::type;
using _parameter_tuple_t = std::tuple<Flag...>; using _parameter_tuple_t = std::tuple<Flags...>;
using size = std::tuple_size<_parameter_tuple_t>; using size = std::tuple_size<_parameter_tuple_t>;
// check for duplicate order expressions static_assert(not ::sqlpp::detail::has_duplicates<Flags...>::value, "at least one duplicate argument detected in select flag list");
static_assert(not ::sqlpp::detail::has_duplicates<Flag...>::value, "at least one duplicate argument detected in select flag list");
// check for invalid order expressions static_assert(::sqlpp::detail::and_t<is_select_flag_t, Flags...>::value, "at least one argument is not a select flag in select flag list");
static_assert(::sqlpp::detail::and_t<is_select_flag_t, Flag...>::value, "at least one argument is not a select flag in select flag list");
template<typename E> select_flag_list_t(Flags... flags):
void add(E expr) _flags(flags...)
{}
select_flag_list_t(const select_flag_list_t&) = default;
select_flag_list_t(select_flag_list_t&&) = default;
select_flag_list_t& operator=(const select_flag_list_t&) = default;
select_flag_list_t& operator=(select_flag_list_t&&) = default;
~select_flag_list_t() = default;
template<typename Flag>
void add_flag(Flag flag)
{ {
static_assert(is_select_flag_t<E>::value, "flag arguments require to be select flags"); static_assert(is_select_flag_t<Flag>::value, "flag arguments require to be select flags");
_dynamic_flags.emplace_back(expr); _dynamic_flags.emplace_back(flag);
} }
select_flag_list_t& _flag_list = *this;
_parameter_tuple_t _flags; _parameter_tuple_t _flags;
vendor::interpretable_list_t<Database> _dynamic_flags; vendor::interpretable_list_t<Database> _dynamic_flags;
}; };
template<typename Context, typename Database, typename... Flag> struct no_select_flag_list_t
struct interpreter_t<Context, select_flag_list_t<Database, std::tuple<Flag...>>> {
using _is_select_flag_list = std::true_type;
no_select_flag_list_t& _flag_list = *this;
};
// CRTP Wrappers
template<typename Derived, typename Database, typename... Args>
struct crtp_wrapper_t<Derived, select_flag_list_t<Database, Args...>>
{ {
using T = select_flag_list_t<Database, std::tuple<Flag...>>; };
template<typename Derived>
struct crtp_wrapper_t<Derived, no_select_flag_list_t>
{
template<typename... Args>
auto flags(Args... args)
-> vendor::update_policies_t<Derived, no_select_flag_list_t, select_flag_list_t<void, Args...>>
{
return { static_cast<Derived&>(*this), select_flag_list_t<void, Args...>(args...) };
}
template<typename... Args>
auto dynamic_flags(Args... args)
-> vendor::update_policies_t<Derived, no_select_flag_list_t, select_flag_list_t<get_database_t<Derived>, Args...>>
{
static_assert(not std::is_same<get_database_t<Derived>, void>::value, "dynamic_flags must not be called in a static statement");
return { static_cast<Derived&>(*this), select_flag_list_t<get_database_t<Derived>, Args...>(args...) };
}
};
// Interpreters
template<typename Context, typename Database, typename... Flags>
struct interpreter_t<Context, select_flag_list_t<Database, Flags...>>
{
using T = select_flag_list_t<Database, Flags...>;
static Context& _(const T& t, Context& context) static Context& _(const T& t, Context& context)
{ {
interpret_tuple(t._flags, ' ', context); interpret_tuple(t._flags, ' ', context);
if (sizeof...(Flag)) if (sizeof...(Flags))
context << ' '; context << ' ';
interpret_list(t._dynamic_flags, ',', context); interpret_list(t._dynamic_flags, ',', context);
if (not t._dynamic_flags.empty()) if (not t._dynamic_flags.empty())
@ -86,6 +123,17 @@ namespace sqlpp
return context; return context;
} }
}; };
template<typename Context>
struct interpreter_t<Context, no_select_flag_list_t>
{
using T = no_select_flag_list_t;
static Context& _(const T& t, Context& context)
{
return context;
}
};
} }
} }

View File

@ -27,14 +27,14 @@
#ifndef SQLPP_WHERE_H #ifndef SQLPP_WHERE_H
#define SQLPP_WHERE_H #define SQLPP_WHERE_H
#include <ostream>
#include <sqlpp11/select_fwd.h>
#include <sqlpp11/vendor/expression.h>
#include <sqlpp11/type_traits.h> #include <sqlpp11/type_traits.h>
#include <sqlpp11/detail/logic.h> #include <sqlpp11/parameter_list.h>
#include <sqlpp11/vendor/expression.h>
#include <sqlpp11/vendor/interpret_tuple.h> #include <sqlpp11/vendor/interpret_tuple.h>
#include <sqlpp11/vendor/interpretable_list.h> #include <sqlpp11/vendor/interpretable_list.h>
#include <sqlpp11/parameter_list.h> #include <sqlpp11/vendor/policy_update.h>
#include <sqlpp11/vendor/crtp_wrapper.h>
#include <sqlpp11/detail/logic.h>
namespace sqlpp namespace sqlpp
{ {
@ -76,8 +76,18 @@ namespace sqlpp
vendor::interpretable_list_t<Database> _dynamic_expressions; vendor::interpretable_list_t<Database> _dynamic_expressions;
}; };
template<>
struct where_t<void, bool>
{
using _is_where = std::true_type;
using _is_dynamic = std::false_type;
std::tuple<bool> _condition;
};
struct no_where_t struct no_where_t
{ {
using _is_where = std::true_type;
no_where_t& _where = *this; no_where_t& _where = *this;
}; };
@ -125,16 +135,6 @@ namespace sqlpp
} }
}; };
template<>
struct where_t<void, bool>
{
using _is_where = std::true_type;
using _is_dynamic = std::false_type;
using _parameter_tuple_t = std::tuple<>;
std::tuple<bool> _condition;
};
template<typename Context> template<typename Context>
struct interpreter_t<Context, where_t<void, bool>> struct interpreter_t<Context, where_t<void, bool>>
{ {