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,16 +44,19 @@
#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
{
namespace detail
{ {
template< template<
typename Database,
typename FlagList, typename FlagList,
typename ColumnList, typename ColumnList,
typename From, typename From,
@ -65,54 +67,46 @@ namespace sqlpp
typename Limit, typename Limit,
typename Offset typename Offset
> >
struct select_t struct check_select_t
: public ColumnList::_value_type::template operators<select_t<
Database,
FlagList,
ColumnList,
From,
Where,
GroupBy,
Having,
OrderBy,
Limit,
Offset>>
{ {
using _Database = Database; //static_assert(is_where_t<Where>::value, "cannot select remove without having a where condition, use .where(true) to remove all rows");
using _From = From; static constexpr bool value = true;
};
}
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 T = 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...>>
{
};
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 T = 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...>>
{
};
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 T = 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...>>
{
};
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 T = 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...>>
{
};
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 T = 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...>>
{
};
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>>
{ {