Merge branch 'feature/policy-based-design' into develop

This commit is contained in:
rbock
2014-02-09 00:35:09 +01:00
31 changed files with 1685 additions and 1495 deletions

View File

@@ -24,47 +24,44 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SQLPP_DETAIL_MAKE_FLAG_TUPLE_H
#define SQLPP_DETAIL_MAKE_FLAG_TUPLE_H
#ifndef SQLPP_DETAIL_COPY_TUPLE_ARGS_H
#define SQLPP_DETAIL_COPY_TUPLE_ARGS_H
#include <tuple>
namespace sqlpp
{
namespace detail
{
// accept select flags
template<typename Expr>
auto make_single_flag_tuple(Expr expr) -> typename std::enable_if<is_select_flag_t<Expr>::value, decltype(std::make_tuple(expr))>::type
template<typename T>
struct as_tuple
{
return std::make_tuple(expr);
static std::tuple<T> _(T t) { return std::tuple<T>{ t }; };
};
// ignore named expressions
template<typename Expr>
auto make_single_flag_tuple(Expr expr) -> typename std::enable_if<is_named_expression_t<Expr>::value, std::tuple<>>::type
template<typename... Args>
struct as_tuple<std::tuple<Args...>>
{
return {};
static std::tuple<Args...> _(std::tuple<Args...> t) { return t; }
};
// ignore tables
template<typename Tab>
auto make_single_flag_tuple(Tab tab) -> typename std::enable_if<is_table_t<Tab>::value, std::tuple<>>::type
template<template<typename, typename...> class Target, typename First, typename T>
struct copy_tuple_args_impl
{
return {};
static_assert(vendor::wrong_t<T>::value, "copy_tuple_args must be called with a tuple");
};
// ignore tuples of expressions
template<typename... Expr>
auto make_single_flag_tuple(std::tuple<Expr...> t) -> std::tuple<>
template<template<typename First, typename...> class Target, typename First, typename... Args>
struct copy_tuple_args_impl<Target, First, std::tuple<Args...>>
{
return {};
using type = Target<First, Args...>;
};
template<typename... Expr>
auto make_flag_tuple(Expr... expr) -> decltype(std::tuple_cat(make_single_flag_tuple(expr)...))
{
return std::tuple_cat(make_single_flag_tuple(expr)...);
};
template<template<typename First, typename...> class Target, typename First, typename T>
using copy_tuple_args_t = typename copy_tuple_args_impl<Target, First, T>::type;
}
}
#endif

View File

@@ -31,114 +31,56 @@
#include <sqlpp11/parameter_list.h>
#include <sqlpp11/prepared_insert.h>
#include <sqlpp11/default_value.h>
#include <sqlpp11/vendor/column_list.h>
#include <sqlpp11/vendor/noop.h>
#include <sqlpp11/vendor/insert_list.h>
#include <sqlpp11/vendor/assignment.h>
#include <sqlpp11/vendor/single_table.h>
#include <sqlpp11/vendor/insert_value_list.h>
#include <sqlpp11/vendor/crtp_wrapper.h>
#include <sqlpp11/vendor/policy.h>
#include <sqlpp11/vendor/policy_update.h>
namespace sqlpp
{
namespace detail
{
template<
typename Table,
typename InsertValueList
>
struct check_insert_t
{
//static_assert(not (vendor::is_noop<InsertList>::value and vendor::is_noop<ColumnList>::value) , "calling set() or default_values()");
static constexpr bool value = true;
};
}
template<
typename Database = void,
typename Table = vendor::noop,
typename InsertList = vendor::noop,
typename ColumnList = vendor::noop,
typename ValueList = vendor::insert_value_list_t<vendor::noop>
>
struct insert_t
template<typename Database, typename... Policies>
struct insert_t: public vendor::policy_t<Policies>..., public vendor::crtp_wrapper_t<insert_t<Database, Policies...>, Policies>...
{
static_assert(vendor::is_noop<Table>::value or is_table_t<Table>::value, "invalid 'Table' argument");
static_assert(vendor::is_noop<InsertList>::value or is_insert_list_t<InsertList>::value, "invalid 'InsertList' argument");
static_assert(vendor::is_noop<ColumnList>::value or is_column_list_t<ColumnList>::value, "invalid 'ColumnList' argument");
static_assert(vendor::is_noop<ValueList>::value or is_insert_value_list_t<ValueList>::value, "invalid 'ValueList' argument");
template<typename Needle, typename Replacement>
using _policy_update_t = insert_t<Database, vendor::policy_update_t<Policies, Needle, Replacement>...>;
using use_default_values_t = insert_t<Database, Table, vendor::insert_default_values_t>;
template<typename AssignmentT>
using set_insert_list_t = insert_t<Database, Table, AssignmentT>;
template<typename ColumnT, typename ValueT>
using set_column_value_list_t = insert_t<Database, Table, InsertList, ColumnT, ValueT>;
using _parameter_tuple_t = std::tuple<Table, InsertList>;
using _database_t = Database;
using _parameter_tuple_t = std::tuple<Policies...>;
using _parameter_list_t = typename make_parameter_list_t<insert_t>::type;
auto default_values()
-> use_default_values_t
{
static_assert(std::is_same<InsertList, vendor::noop>::value, "cannot call default_values() after set() or default_values()");
static_assert(vendor::is_noop<ColumnList>::value, "cannot call default_values() after columns()");
static_assert(Table::_required_insert_columns::size::value == 0, "cannot use default_values, because some columns are configured to require values");
return {
_table,
{},
_column_list,
_value_list,
};
}
insert_t()
{}
template<typename... Assignment>
auto set(Assignment... assignment)
-> set_insert_list_t<vendor::insert_list_t<void, Assignment...>>
{
static_assert(std::is_same<InsertList, vendor::noop>::value, "cannot call set() after set() or default_values()");
static_assert(vendor::is_noop<ColumnList>::value, "cannot call set() after columns()");
// FIXME: Need to check if all required columns are set
return {
_table,
vendor::insert_list_t<void, Assignment...>{assignment...},
_column_list,
_value_list,
};
}
template<typename Whatever>
insert_t(insert_t i, Whatever whatever):
vendor::policy_t<Policies>(i, whatever)...
{}
template<typename... Assignment>
auto dynamic_set(Assignment... assignment)
-> set_insert_list_t<vendor::insert_list_t<Database, Assignment...>>
{
static_assert(std::is_same<InsertList, vendor::noop>::value, "cannot call set() after set() or default_values()");
static_assert(vendor::is_noop<ColumnList>::value, "cannot call set() after columns()");
return {
_table,
vendor::insert_list_t<Database, Assignment...>{assignment...},
_column_list,
_value_list,
};
}
template<typename Insert, typename Whatever>
insert_t(Insert i, Whatever whatever):
vendor::policy_t<Policies>(i, whatever)...
{}
template<typename Assignment>
insert_t add_set(Assignment assignment)
{
static_assert(is_dynamic_t<InsertList>::value, "cannot call add_set() in a non-dynamic set");
_insert_list.add(assignment);
return *this;
}
template<typename... Column>
auto columns(Column... columns)
-> set_column_value_list_t<vendor::column_list_t<Column...>, vendor::insert_value_list_t<vendor::insert_value_t<Column>...>>
{
static_assert(vendor::is_noop<ColumnList>::value, "cannot call columns() twice");
static_assert(vendor::is_noop<InsertList>::value, "cannot call columns() after set() or dynamic_set()");
// FIXME: Need to check if all required columns are set
return {
_table,
_insert_list,
{std::tuple<vendor::simple_column_t<Column>...>{{columns}...}},
vendor::insert_value_list_t<vendor::insert_value_t<Column>...>{},
};
}
template<typename... Value>
insert_t& add_values(Value... values)
{
static_assert(is_insert_value_list_t<ValueList>::value, "cannot call add_values() before columns()");
_value_list.add(typename ValueList::_value_tuple_t{values...});
return *this;
};
insert_t(const insert_t&) = default;
insert_t(insert_t&&) = default;
insert_t& operator=(const insert_t&) = default;
insert_t& operator=(insert_t&&) = default;
~insert_t() = default;
static constexpr size_t _get_static_no_of_parameters()
{
@@ -153,8 +95,8 @@ namespace sqlpp
template<typename Db>
std::size_t _run(Db& db) const
{
static_assert(not (vendor::is_noop<InsertList>::value and vendor::is_noop<ColumnList>::value) , "calling set() or default_values()");
static_assert(_get_static_no_of_parameters() == 0, "cannot run insert directly with parameters, use prepare instead");
static_assert(detail::check_insert_t<Policies...>::value, "Cannot run this insert expression");
return db.insert(*this);
}
@@ -162,60 +104,43 @@ namespace sqlpp
auto _prepare(Db& db) const
-> prepared_insert_t<Db, insert_t>
{
constexpr bool calledSet = not vendor::is_noop<InsertList>::value;
constexpr bool requireSet = Table::_required_insert_columns::size::value > 0;
static_assert(calledSet or not requireSet, "calling set() required for given table");
static_assert(detail::check_insert_t<Policies...>::value, "Cannot prepare this insert expression");
return {{}, db.prepare_insert(*this)};
}
Table _table;
InsertList _insert_list;
ColumnList _column_list;
ValueList _value_list;
};
namespace vendor
{
template<typename Context, typename Database, typename Table, typename InsertList, typename ColumnList, typename ValueList>
struct interpreter_t<Context, insert_t<Database, Table, InsertList, ColumnList, ValueList>>
template<typename Context, typename Database, typename... Policies>
struct interpreter_t<Context, insert_t<Database, Policies...>>
{
using T = insert_t<Database, Table, InsertList, ColumnList, ValueList>;
using T = insert_t<Database, Policies...>;
static Context& _(const T& t, Context& context)
{
if (not vendor::is_noop<decltype(t._insert_list)>::value)
{
context << "INSERT INTO ";
interpret(t._table, context);
interpret(t._insert_list, context);
}
else if (not t._value_list.empty())
{
context << "INSERT INTO ";
interpret(t._table, context);
interpret(t._column_list, context);
interpret(t._value_list, context);
}
else
{
context << "# empty insert";
}
context << "INSERT INTO ";
interpret(t._single_table(), context);
interpret(t._insert_value_list(), context);
return context;
}
};
}
template<typename Database>
using blank_insert_t = insert_t<Database, vendor::no_single_table_t, vendor::no_insert_value_list_t>;
template<typename Table>
insert_t<void, Table> insert_into(Table table)
constexpr auto insert_into(Table table)
-> insert_t<void, vendor::single_table_t<void, Table>, vendor::no_insert_value_list_t>
{
return {table};
return { blank_insert_t<void>(), vendor::single_table_t<void, Table>{table} };
}
template<typename Database, typename Table>
insert_t<Database, Table> dynamic_insert_into(const Database& db, Table table)
constexpr auto dynamic_insert_into(const Database&, Table table)
-> insert_t<Database, vendor::single_table_t<void, Table>, vendor::no_insert_value_list_t>
{
return {table};
return { blank_insert_t<Database>(), vendor::single_table_t<void, Table>{table} };
}
}

View File

@@ -28,39 +28,49 @@
#define SQLPP_MULTI_COLUMN_H
#include <sqlpp11/no_value.h>
#include <sqlpp11/detail/make_expression_tuple.h>
#include <sqlpp11/detail/logic.h>
#include <sqlpp11/detail/copy_tuple_args.h>
namespace sqlpp
{
template<typename AliasProvider, typename T>
template<typename AliasProvider, typename... Columns>
struct multi_column_t
{
static_assert(vendor::wrong_t<T>::value, "invalid argument for multicolumn_t");
};
template<typename AliasProvider, typename... NamedExpr>
struct multi_column_t<AliasProvider, std::tuple<NamedExpr...>>
{
static_assert(detail::and_t<is_named_expression_t, NamedExpr...>::value, "multi_column parameters need to be named expressions");
static_assert(detail::and_t<is_named_expression_t, Columns...>::value, "multi_column parameters need to be named expressions");
using _name_t = typename AliasProvider::_name_t;
multi_column_t(std::tuple<Columns...> columns):
_columns(columns)
{}
multi_column_t(Columns... columns):
_columns(columns...)
{}
multi_column_t(const multi_column_t&) = default;
multi_column_t(multi_column_t&&) = default;
multi_column_t& operator=(const multi_column_t&) = default;
multi_column_t& operator=(multi_column_t&&) = default;
~multi_column_t() = default;
struct _value_type: public no_value_t
{
using _is_named_expression = std::true_type;
};
using _is_multi_column = std::true_type;
std::tuple<NamedExpr...> _columns;
std::tuple<Columns...> _columns;
};
namespace vendor
{
template<typename Context, typename AliasProvider, typename... NamedExpr>
struct interpreter_t<Context, multi_column_t<AliasProvider, NamedExpr...>>
template<typename Context, typename AliasProvider, typename... Columns>
struct interpreter_t<Context, multi_column_t<AliasProvider, Columns...>>
{
using T = multi_column_t<AliasProvider, NamedExpr...>;
using T = multi_column_t<AliasProvider, Columns...>;
static Context& _(const T& t, Context& context)
{
@@ -72,17 +82,20 @@ namespace sqlpp
namespace detail
{
template<typename AliasProvider, typename... Expr>
template<typename AliasProvider, typename... Columns>
using make_multi_column_t =
multi_column_t<AliasProvider, decltype(make_expression_tuple(std::declval<Expr>()...))>;
detail::copy_tuple_args_t<multi_column_t, AliasProvider,
decltype(std::tuple_cat(detail::as_tuple<Columns>::_(std::declval<Columns>())...))>;
}
template<typename AliasProvider, typename... NamedExpr>
detail::make_multi_column_t<AliasProvider, NamedExpr...> multi_column(const AliasProvider& aliasProvider, NamedExpr... namedExpr)
template<typename AliasProvider, typename... Columns>
auto multi_column(const AliasProvider&, Columns... columns)
-> detail::make_multi_column_t<AliasProvider, Columns...>
{
return { detail::make_expression_tuple(namedExpr...)};
return detail::make_multi_column_t<AliasProvider, Columns...>(std::tuple_cat(detail::as_tuple<Columns>::_(columns)...));
}
}
#endif

View File

@@ -31,107 +31,53 @@
#include <sqlpp11/parameter_list.h>
#include <sqlpp11/prepared_remove.h>
#include <sqlpp11/vendor/noop.h>
#include <sqlpp11/vendor/single_table.h>
#include <sqlpp11/vendor/using.h>
#include <sqlpp11/vendor/where.h>
#include <sqlpp11/vendor/crtp_wrapper.h>
#include <sqlpp11/vendor/policy.h>
#include <sqlpp11/vendor/policy_update.h>
namespace sqlpp
{
template<
typename Database,
typename Table,
typename Using = vendor::noop,
typename Where = vendor::noop
>
struct remove_t;
namespace detail
{
template<typename Table, typename Using, typename Where>
struct check_remove_t
{
static_assert(is_where_t<Where>::value, "cannot run remove without having a where condition, use .where(true) to remove all rows");
static constexpr bool value = true;
};
}
template<
typename Database,
typename Table,
typename Using,
typename Where
>
struct remove_t
template<typename Database, typename... Policies>
struct remove_t: public vendor::policy_t<Policies>..., public vendor::crtp_wrapper_t<remove_t<Database, Policies...>, Policies>...
{
static_assert(vendor::is_noop<Table>::value or is_table_t<Table>::value, "invalid 'Table' argument");
static_assert(vendor::is_noop<Using>::value or is_using_t<Using>::value, "invalid 'Using' argument");
static_assert(vendor::is_noop<Where>::value or is_where_t<Where>::value, "invalid 'Where' argument");
template<typename Needle, typename Replacement>
using _policy_update_t = remove_t<Database, vendor::policy_update_t<Policies, Needle, Replacement>...>;
template<typename UsingT>
using set_using_t = remove_t<Database, Table, UsingT, Where>;
template<typename WhereT>
using set_where_t = remove_t<Database, Table, Using, WhereT>;
using _parameter_tuple_t = std::tuple<Table, Using, Where>;
using _database_t = Database;
using _parameter_tuple_t = std::tuple<Policies...>;
using _parameter_list_t = typename make_parameter_list_t<remove_t>::type;
template<typename... Tab>
auto using_(Tab... tab)
-> set_using_t<vendor::using_t<void, Tab...>>
{
static_assert(vendor::is_noop<Using>::value, "cannot call using() twice");
static_assert(vendor::is_noop<Where>::value, "cannot call using() after where()");
return {
_table,
{std::tuple<Tab...>{tab...}},
_where
};
}
remove_t()
{}
template<typename... Tab>
auto dynamic_using_(Tab... tab)
-> set_using_t<vendor::using_t<Database, Tab...>>
{
static_assert(vendor::is_noop<Using>::value, "cannot call using() twice");
static_assert(vendor::is_noop<Where>::value, "cannot call using() after where()");
return {
_table,
{std::tuple<Tab...>{tab...}},
_where
};
}
template<typename Whatever>
remove_t(remove_t r, Whatever whatever):
vendor::policy_t<Policies>(r, whatever)...
{}
template<typename Tab>
remove_t& add_using_(Tab table)
{
static_assert(is_dynamic_t<Using>::value, "cannot call add_using() in a non-dynamic using");
_using.add(table);
template<typename Remove, typename Whatever>
remove_t(Remove r, Whatever whatever):
vendor::policy_t<Policies>(r, whatever)...
{}
return *this;
}
template<typename... Expr>
auto where(Expr... expr)
-> set_where_t<vendor::where_t<void, Expr...>>
{
static_assert(vendor::is_noop<Where>::value, "cannot call where() twice");
return {
_table,
_using,
{std::tuple<Expr...>{expr...}},
};
}
template<typename... Expr>
auto dynamic_where(Expr... expr)
-> set_where_t<vendor::where_t<Database, Expr...>>
{
static_assert(vendor::is_noop<Where>::value, "cannot call where() twice");
return {
_table,
_using,
{std::tuple<Expr...>{expr...}},
};
}
template<typename Expr>
remove_t& add_where(Expr expr)
{
static_assert(is_dynamic_t<Where>::value, "cannot call add_where() in a non-dynamic where");
_where.add(expr);
return *this;
}
remove_t(const remove_t&) = default;
remove_t(remove_t&&) = default;
remove_t& operator=(const remove_t&) = default;
remove_t& operator=(remove_t&&) = default;
~remove_t() = default;
static constexpr size_t _get_static_no_of_parameters()
{
@@ -147,50 +93,52 @@ namespace sqlpp
std::size_t _run(Db& db) const
{
static_assert(_get_static_no_of_parameters() == 0, "cannot run remove directly with parameters, use prepare instead");
static_assert(is_where_t<Where>::value, "cannot run update without having a where condition, use .where(true) to remove all rows");
static_assert(detail::check_remove_t<Policies...>::value, "Cannot run this remove expression");
return db.remove(*this);
}
template<typename Db>
auto _prepare(Db& db) const
-> prepared_remove_t<Db, remove_t>
-> prepared_remove_t<Database, remove_t>
{
static_assert(detail::check_remove_t<Policies...>::value, "Cannot run this remove expression");
return {{}, db.prepare_remove(*this)};
}
Table _table;
Using _using;
Where _where;
};
namespace vendor
{
template<typename Context, typename Database, typename Table, typename Using, typename Where>
struct interpreter_t<Context, remove_t<Database, Table, Using, Where>>
template<typename Context, typename Database, typename... Policies>
struct interpreter_t<Context, remove_t<Database, Policies...>>
{
using T = remove_t<Database, Table, Using, Where>;
using T = remove_t<Database, Policies...>;
static Context& _(const T& t, Context& context)
{
context << "DELETE FROM ";
interpret(t._table, context);
interpret(t._using, context);
interpret(t._where, context);
context << "DELETE FROM";
interpret(t._single_table(), context);
interpret(t._using(), context);
interpret(t._where(), context);
return context;
}
};
}
template<typename Database>
using blank_remove_t = remove_t<Database, vendor::no_single_table_t, vendor::no_using_t, vendor::no_where_t>;
template<typename Table>
constexpr remove_t<void, Table> remove_from(Table table)
constexpr auto remove_from(Table table)
-> remove_t<void, vendor::single_table_t<void, Table>, vendor::no_using_t, vendor::no_where_t>
{
return {table};
return { blank_remove_t<void>(), vendor::single_table_t<void, Table>{table} };
}
template<typename Db, typename Table>
constexpr remove_t<Db, Table> dynamic_remove_from(const Db&, Table table)
template<typename Database, typename Table>
constexpr auto dynamic_remove_from(const Database&, Table table)
-> remove_t<Database, vendor::single_table_t<void, Table>, vendor::no_using_t, vendor::no_where_t>
{
return {table};
return { blank_remove_t<Database>(), vendor::single_table_t<void, Table>{table} };
}
}

View File

@@ -28,7 +28,6 @@
#define SQLPP_SELECT_H
#include <sqlpp11/result.h>
#include <sqlpp11/select_fwd.h>
#include <sqlpp11/parameter_list.h>
#include <sqlpp11/prepared_select.h>
@@ -45,544 +44,98 @@
#include <sqlpp11/vendor/expression.h>
#include <sqlpp11/vendor/interpreter.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_expression_tuple.h>
#include <sstream>
#include <sqlpp11/detail/copy_tuple_args.h>
namespace sqlpp
{
template<
typename Database,
typename FlagList,
typename ColumnList,
typename From,
typename Where,
typename GroupBy,
typename Having,
typename OrderBy,
typename Limit,
typename Offset
>
struct select_t
: public ColumnList::_value_type::template operators<select_t<
Database,
FlagList,
ColumnList,
From,
Where,
GroupBy,
Having,
OrderBy,
Limit,
Offset>>
{
using _Database = Database;
using _From = From;
namespace detail
{
template<
typename FlagList,
typename ColumnList,
typename From,
typename Where,
typename GroupBy,
typename Having,
typename OrderBy,
typename Limit,
typename Offset
>
struct select_helper_t
{
using _column_list_t = ColumnList;
using _from_t = ColumnList;
static_assert(is_select_flag_list_t<FlagList>::value, "invalid list of select flags");
static_assert(is_select_column_list_t<ColumnList>::value, "invalid list of select expressions");
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");
static_assert(vendor::is_noop<GroupBy>::value or is_group_by_t<GroupBy>::value, "invalid 'group by' arguments");
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");
static_assert(vendor::is_noop<Limit>::value or is_limit_t<Limit>::value, "invalid 'limit' arguments");
static_assert(vendor::is_noop<Offset>::value or is_offset_t<Offset>::value, "invalid 'offset' arguments");
using _value_type = typename std::conditional<
sqlpp::is_from_t<From>::value,
typename ColumnList::_value_type,
no_value_t // If there is no from, the select is not complete (this logic is a bit simple, but better than nothing)
>::type;
template<typename Database>
struct can_run_t
{
//static_assert(is_where_t<Where>::value, "cannot select remove without having a where condition, use .where(true) to remove all rows");
//static_assert(not vendor::is_noop<ColumnList>::value, "cannot run select without having selected anything");
//static_assert(is_from_t<From>::value, "cannot run select without a from()");
//static_assert(is_where_t<Where>::value, "cannot run select without having a where condition, use .where(true) to select all rows");
// FIXME: Check for missing aliases (if references are used)
// FIXME: Check for missing tables, well, actually, check for missing tables at the where(), order_by(), etc.
static constexpr bool value = true;
};
};
}
// SELECT
template<typename Database, typename... Policies>
struct select_t: public vendor::policy_t<Policies>..., public vendor::crtp_wrapper_t<select_t<Database, Policies...>, Policies>...,
public detail::select_helper_t<Policies...>::_value_type::template operators<select_t<Database, Policies...>>
{
template<typename Needle, typename Replacement>
using _policy_update_t = select_t<Database, vendor::policy_update_t<Policies, Needle, Replacement>...>;
using _database_t = Database;
using _parameter_tuple_t = std::tuple<Policies...>;
using _parameter_list_t = typename make_parameter_list_t<select_t>::type;
using _column_list_t = typename detail::select_helper_t<Policies...>::_column_list_t;
using _result_row_t = typename _column_list_t::_result_row_t;
using _dynamic_names_t = typename _column_list_t::_dynamic_names_t;
using _is_select = 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 _value_type = typename detail::select_helper_t<Policies...>::_value_type;
using _name_t = typename _column_list_t::_name_t;
using _result_row_t = typename ColumnList::_result_row_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_list_t = typename make_parameter_list_t<select_t>::type;
select_t()
{}
// Indicators
using _value_type = typename std::conditional<
vendor::is_noop<From>::value,
no_value_t, // If there is no from, the select is not complete (this logic is a bit simple, but better than nothing)
typename ColumnList::_value_type>::type;
template<typename Whatever>
select_t(select_t r, Whatever whatever):
vendor::policy_t<Policies>(r, whatever)...
{}
using _name_t = typename ColumnList::_name_t;
template<typename Remove, typename Whatever>
select_t(Remove r, Whatever whatever):
vendor::policy_t<Policies>(r, whatever)...
{}
// The standard constructors, assigment operators and destructor
constexpr select_t(FlagList flag_list, ColumnList column_list, From from,
Where where, GroupBy group_by, Having having,
OrderBy order_by, Limit limit, Offset offset):
_flags(flag_list),
_columns(column_list),
_from(from),
_where(where),
_group_by(group_by),
_having(having),
_order_by(order_by),
_limit(limit),
_offset(offset)
{
}
select_t(const select_t& rhs) = default;
select_t(select_t&& rhs) = default;
select_t& operator=(const select_t& rhs) = default;
select_t& operator=(select_t&& rhs) = default;
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;
// select functions
template<typename... Flag>
auto flags(Flag... flag)
-> set_flag_list_t<vendor::select_flag_list_t<void, std::tuple<Flag...>>>
{
static_assert(not FlagList::size::value, "cannot call dynamic_flags() after specifying them the first time");
static_assert(not ColumnList::size::value, "cannot call columns() after specifying them the first time");
return {
{std::tuple<Flag...>{flag...}},
_columns,
_from,
_where,
_group_by,
_having,
_order_by,
_limit,
_offset
};
}
template<typename... Flag>
auto dynamic_flags(Flag... flag)
-> set_flag_list_t<vendor::select_flag_list_t<Database, std::tuple<Flag...>>>
{
static_assert(not std::is_same<Database, void>::value, "cannot call dynamic_flags() in a non-dynamic select");
static_assert(not FlagList::size::value, "cannot call dynamic_flags() after specifying them the first time");
static_assert(not ColumnList::size::value, "cannot call columns() after specifying them the first time");
return {
{std::tuple<Flag...>{flag...}},
_columns,
_from,
_where,
_group_by,
_having,
_order_by,
_limit,
_offset
};
}
template<typename Flag>
select_t& add_flag(Flag flag)
{
static_assert(is_dynamic_t<FlagList>::value, "cannot call add_flag() in a non-dynamic column list");
_flags.add(flag);
return *this;
}
template<typename... Column>
auto columns(Column... column)
-> set_column_list_t<vendor::select_column_list_t<void, std::tuple<Column...>>>
{
static_assert(not ColumnList::size::value, "cannot call columns() after specifying them the first time");
return {
_flags,
{std::tuple<Column...>{column...}},
_from,
_where,
_group_by,
_having,
_order_by,
_limit,
_offset
};
}
template<typename... Column>
auto dynamic_columns(Column... column)
-> set_column_list_t<vendor::select_column_list_t<Database, std::tuple<Column...>>>
{
static_assert(not std::is_same<Database, void>::value, "cannot call dynamic_columns() in a non-dynamic select");
static_assert(not ColumnList::size::value, "cannot call dynamic_columns() after specifying them the first time");
return {
_flags,
{std::tuple<Column...>{column...}},
_from,
_where,
_group_by,
_having,
_order_by,
_limit,
_offset
};
}
template<typename NamedExpr>
select_t& add_column(NamedExpr namedExpr)
{
static_assert(is_dynamic_t<ColumnList>::value, "cannot call add_column() in a non-dynamic column list");
_columns.add(namedExpr);
return *this;
}
template<typename... Table>
auto from(Table... table)
-> set_from_t<vendor::from_t<void, Table...>>
{
static_assert(not vendor::is_noop<ColumnList>::value, "cannot call from() without having selected anything");
static_assert(vendor::is_noop<From>::value, "cannot call from() twice for a single select");
return {
_flags,
_columns,
{std::tuple<Table...>{table...}},
_where,
_group_by,
_having,
_order_by,
_limit,
_offset
};
}
template<typename... Table>
auto dynamic_from(Table... table)
-> set_from_t<vendor::from_t<Database, Table...>>
{
static_assert(not std::is_same<Database, void>::value, "cannot call dynamic_from() in a non-dynamic select");
static_assert(not vendor::is_noop<ColumnList>::value, "cannot call from() without having selected anything");
static_assert(vendor::is_noop<From>::value, "cannot call from() twice for a single select");
return {
_flags,
_columns,
{std::tuple<Table...>{table...}},
_where,
_group_by,
_having,
_order_by,
_limit,
_offset
};
}
template<typename Table>
select_t& add_from(Table table)
{
static_assert(not vendor::is_noop<ColumnList>::value, "cannot call add_from() without having selected anything");
static_assert(is_dynamic_t<From>::value, "cannot call add_from() in a non-dynamic from");
_from.add(table);
return *this;
}
template<typename... Expr>
auto where(Expr... expr)
-> set_where_t<vendor::where_t<void, Expr...>>
{
static_assert(not vendor::is_noop<From>::value, "cannot call where() without a from()");
static_assert(vendor::is_noop<Where>::value, "cannot call where() or dynamic_where() twice for a single select");
return {
_flags,
_columns,
_from,
{std::tuple<Expr...>{expr...}},
_group_by,
_having,
_order_by,
_limit,
_offset,
};
}
template<typename... Expr>
auto dynamic_where(Expr... expr)
-> set_where_t<vendor::where_t<Database, Expr...>>
{
static_assert(not vendor::is_noop<From>::value, "cannot call dynamic_where() without a from()");
static_assert(vendor::is_noop<Where>::value, "cannot call where() or dynamic_where() twice for a single select");
return {
_flags,
_columns,
_from,
{std::tuple<Expr...>{expr...}},
_group_by,
_having,
_order_by,
_limit,
_offset,
};
}
template<typename Expr>
select_t& add_where(Expr expr)
{
static_assert(is_dynamic_t<Where>::value, "cannot call add_where() with a non-dynamic where");
_where.add(expr);
return *this;
}
template<typename... Col>
auto group_by(Col... column)
-> set_group_by_t<vendor::group_by_t<void, Col...>>
{
static_assert(not vendor::is_noop<From>::value, "cannot call group_by() without a from()");
static_assert(vendor::is_noop<GroupBy>::value, "cannot call group_by() twice for a single select");
return {
_flags,
_columns,
_from,
_where,
{std::tuple<Col...>{column...}},
_having,
_order_by,
_limit,
_offset,
};
}
template<typename... Col>
auto dynamic_group_by(Col... column)
-> set_group_by_t<vendor::group_by_t<Database, Col...>>
{
static_assert(not vendor::is_noop<From>::value, "cannot call group_by() without a from()");
static_assert(vendor::is_noop<GroupBy>::value, "cannot call group_by() twice for a single select");
return {
_flags,
_columns,
_from,
_where,
{std::tuple<Col...>{column...}},
_having,
_order_by,
_limit,
_offset,
};
}
template<typename Expr>
select_t& add_group_by(Expr expr)
{
static_assert(is_dynamic_t<GroupBy>::value, "cannot call add_group_by() in a non-dynamic group_by");
_group_by.add(expr);
return *this;
}
template<typename... Expr>
auto having(Expr... expr)
-> set_having_t<vendor::having_t<void, Expr...>>
{
static_assert(not vendor::is_noop<GroupBy>::value, "cannot call having() without a group_by");
static_assert(vendor::is_noop<Having>::value, "cannot call having() twice for a single select");
return {
_flags,
_columns,
_from,
_where,
_group_by,
{std::tuple<Expr...>{expr...}},
_order_by,
_limit,
_offset,
};
}
template<typename... Expr>
auto dynamic_having(Expr... expr)
-> set_having_t<vendor::having_t<Database, Expr...>>
{
static_assert(not vendor::is_noop<GroupBy>::value, "cannot call having() without a group_by");
static_assert(vendor::is_noop<Having>::value, "cannot call having() twice for a single select");
return {
_flags,
_columns,
_from,
_where,
_group_by,
{std::tuple<Expr...>{expr...}},
_order_by,
_limit,
_offset,
};
}
template<typename Expr>
select_t& add_having(Expr expr)
{
static_assert(is_dynamic_t<Having>::value, "cannot call add_having() in a non-dynamic having");
_having.add(expr);
return *this;
}
template<typename... OrderExpr>
auto order_by(OrderExpr... expr)
-> set_order_by_t<vendor::order_by_t<void, OrderExpr...>>
{
static_assert(not vendor::is_noop<From>::value, "cannot call order_by() without a from()");
static_assert(vendor::is_noop<OrderBy>::value, "cannot call order_by() twice for a single select");
return {
_flags,
_columns,
_from,
_where,
_group_by,
_having,
{std::tuple<OrderExpr...>{expr...}},
_limit,
_offset,
};
}
template<typename... OrderExpr>
auto dynamic_order_by(OrderExpr... expr)
-> set_order_by_t<vendor::order_by_t<Database, OrderExpr...>>
{
static_assert(not vendor::is_noop<From>::value, "cannot call order_by() without a from()");
static_assert(vendor::is_noop<OrderBy>::value, "cannot call order_by() twice for a single select");
return {
_flags,
_columns,
_from,
_where,
_group_by,
_having,
{std::tuple<OrderExpr...>{expr...}},
_limit,
_offset,
};
}
template<typename Expr>
select_t& add_order_by(Expr expr)
{
static_assert(is_dynamic_t<OrderBy>::value, "cannot call add_order_by() in a non-dynamic order_by");
_order_by.add(expr);
return *this;
}
template<typename Expr>
auto limit(Expr limit)
-> set_limit_t<vendor::limit_t<typename vendor::wrap_operand<Expr>::type>>
{
static_assert(not vendor::is_noop<From>::value, "cannot call limit() without a from()");
static_assert(vendor::is_noop<Limit>::value, "cannot call limit() twice for a single select");
return {
_flags,
_columns,
_from,
_where,
_group_by,
_having,
_order_by,
{limit},
_offset,
};
}
auto dynamic_limit(std::size_t limit = 0)
->set_limit_t<vendor::dynamic_limit_t>
{
static_assert(not vendor::is_noop<From>::value, "cannot call limit() without a from()");
static_assert(vendor::is_noop<Limit>::value, "cannot call limit() twice for a single select");
return {
_flags,
_columns,
_from,
_where,
_group_by,
_having,
_order_by,
{limit},
_offset,
};
}
select_t& set_limit(std::size_t limit)
{
static_assert(is_dynamic_t<Limit>::value, "cannot call set_limit() in a non-dynamic limit");
_limit.set(limit);
return *this;
}
template<typename Expr>
auto offset(Expr offset)
-> set_offset_t<vendor::offset_t<typename vendor::wrap_operand<Expr>::type>>
{
static_assert(not vendor::is_noop<Limit>::value, "cannot call offset() without a limit");
static_assert(vendor::is_noop<Offset>::value, "cannot call offset() twice for a single select");
return {
_flags,
_columns,
_from,
_where,
_group_by,
_having,
_order_by,
_limit,
{offset},
};
}
auto dynamic_offset(std::size_t offset = 0)
-> set_offset_t<vendor::dynamic_offset_t>
{
static_assert(not vendor::is_noop<Limit>::value, "cannot call offset() without a limit");
static_assert(vendor::is_noop<Offset>::value, "cannot call offset() twice for a single select");
return {
_flags,
_columns,
_from,
_where,
_group_by,
_having,
_order_by,
_limit,
{offset},
};
}
select_t& set_offset(std::size_t offset)
{
static_assert(is_dynamic_t<Offset>::value, "cannot call set_offset() in a non-dynamic limit");
_offset.set(offset);
return *this;
}
// Indicators
template<typename AliasProvider>
struct _pseudo_table_t
{
using table = typename ColumnList::template _pseudo_table_t<select_t>;
using table = typename _column_list_t::template _pseudo_table_t<select_t>;
using alias = typename table::template _alias_t<AliasProvider>;
};
@@ -593,9 +146,9 @@ namespace sqlpp
*this).as(aliasProvider);
}
const typename ColumnList::_dynamic_names_t& get_dynamic_names() const
const _dynamic_names_t& get_dynamic_names() const
{
return _columns._dynamic_columns._dynamic_expression_names;
return _column_list_t::_dynamic_columns._dynamic_expression_names;
}
static constexpr size_t _get_static_no_of_parameters()
@@ -618,13 +171,8 @@ namespace sqlpp
auto _run(Db& db) const
-> result_t<decltype(db.select(*this)), _result_row_t>
{
static_assert(not vendor::is_noop<ColumnList>::value, "cannot run select without having selected anything");
static_assert(is_from_t<From>::value, "cannot run select without a from()");
static_assert(is_where_t<Where>::value, "cannot run select without having a where condition, use .where(true) to select all rows");
static_assert(detail::select_helper_t<Policies...>::template can_run_t<Db>::value, "Cannot execute select statement");
static_assert(_get_static_no_of_parameters() == 0, "cannot run select directly with parameters, use prepare instead");
// FIXME: Check for missing aliases (if references are used)
// FIXME: Check for missing tables, well, actually, check for missing tables at the where(), order_by(), etc.
return {db.select(*this), get_dynamic_names()};
}
@@ -633,123 +181,84 @@ namespace sqlpp
auto _prepare(Db& db) const
-> prepared_select_t<Db, select_t>
{
static_assert(not vendor::is_noop<ColumnList>::value, "cannot run select without having selected anything");
static_assert(is_from_t<From>::value, "cannot run select without a from()");
// FIXME: Check for missing aliases (if references are used)
// FIXME: Check for missing tables, well, actually, check for missing tables at the where(), order_by(), etc.
static_assert(detail::select_helper_t<Policies...>::template can_run_t<Db>::value, "Cannot prepare select statement");
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
{
template<typename Context,
typename Database,
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>>
template<typename Context, typename Database, typename... Policies>
struct interpreter_t<Context, select_t<Database, Policies...>>
{
using T = select_t<Database,
FlagList,
ColumnList,
From,
Where,
GroupBy,
Having,
OrderBy,
Limit,
Offset>;
using T = select_t<Database, Policies...>;
static Context& _(const T& t, Context& context)
{
context << "SELECT ";
interpret(t._flags, context);
interpret(t._columns, context);
interpret(t._from, context);
interpret(t._where, context);
interpret(t._group_by, context);
interpret(t._having, context);
interpret(t._order_by, context);
interpret(t._limit, context);
interpret(t._offset, context);
interpret(t._flag_list(), context);
interpret(t._column_list(), context);
interpret(t._from(), context);
interpret(t._where(), context);
interpret(t._group_by(), context);
interpret(t._having(), context);
interpret(t._order_by(), context);
interpret(t._limit(), context);
interpret(t._offset(), context);
return context;
}
};
}
template<typename Database>
using blank_select_t = select_t<Database,
vendor::no_select_flag_list_t,
vendor::no_select_column_list_t,
vendor::no_from_t,
vendor::no_where_t,
vendor::no_group_by_t,
vendor::no_having_t,
vendor::no_order_by_t,
vendor::no_limit_t,
vendor::no_offset_t>;
// construct select flag list
namespace detail
{
template<typename Database, typename... Expr>
using make_select_flag_list_t =
vendor::select_flag_list_t<Database, decltype(make_flag_tuple(std::declval<Expr>()...))>;
}
// construct select expression list
namespace detail
{
template<typename Database, typename... Expr>
template<typename Database, typename... Columns>
using make_select_column_list_t =
vendor::select_column_list_t<Database, decltype(make_expression_tuple(std::declval<Expr>()...))>;
copy_tuple_args_t<vendor::select_column_list_t, Database,
decltype(std::tuple_cat(as_tuple<Columns>::_(std::declval<Columns>())...))>;
}
auto select()
-> select_t<void, vendor::select_flag_list_t<void, std::tuple<>>, vendor::select_column_list_t<void, std::tuple<>>>
blank_select_t<void> select() // FIXME: These should be constexpr
{
return { blank_select_t<void>() };
}
template<typename... Columns>
auto select(Columns... columns)
-> vendor::update_policies_t<blank_select_t<void>,
vendor::no_select_column_list_t,
detail::make_select_column_list_t<void, Columns...>>
{
return { {}, vendor::select_column_list_t<void, std::tuple<>>{}, {}, {}, {}, {}, {}, {}, {} };
return { blank_select_t<void>(), detail::make_select_column_list_t<void, Columns...>(std::tuple_cat(detail::as_tuple<Columns>::_(columns)...)) };
}
template<typename... NamedExpr>
auto select(NamedExpr... namedExpr)
-> select_t<void, detail::make_select_flag_list_t<void, NamedExpr...>, detail::make_select_column_list_t<void, NamedExpr...>>
template<typename Database>
blank_select_t<Database> dynamic_select(const Database&)
{
return {
{ detail::make_flag_tuple(namedExpr...) },
{ detail::make_expression_tuple(namedExpr...) },
{}, {}, {}, {}, {}, {}, {}
};
return { blank_select_t<Database>() };
}
template<typename Db, typename... NamedExpr>
auto dynamic_select(const Db& db, NamedExpr... namedExpr)
-> select_t<Db, detail::make_select_flag_list_t<Db, NamedExpr...>, detail::make_select_column_list_t<Db, NamedExpr...>>
template<typename Database, typename... Columns>
auto dynamic_select(const Database&, Columns... columns)
-> vendor::update_policies_t<blank_select_t<Database>, vendor::no_select_column_list_t, detail::make_select_column_list_t<void, Columns...>>
{
return {
{ detail::make_flag_tuple(namedExpr...) },
{ detail::make_expression_tuple(namedExpr...) },
{}, {}, {}, {}, {}, {}, {}
};
return { blank_select_t<Database>(), detail::make_select_column_list_t<void, Columns...>(std::tuple_cat(detail::as_tuple<Columns>::_(columns)...)) };
}
}

View File

@@ -31,27 +31,7 @@
namespace sqlpp
{
namespace vendor
{
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
>
template<typename Database, typename... Policies>
struct select_t;
}
#endif

View File

@@ -30,109 +30,57 @@
#include <sqlpp11/type_traits.h>
#include <sqlpp11/parameter_list.h>
#include <sqlpp11/prepared_update.h>
#include <sqlpp11/vendor/single_table.h>
#include <sqlpp11/vendor/update_list.h>
#include <sqlpp11/vendor/noop.h>
#include <sqlpp11/vendor/where.h>
#include <sqlpp11/vendor/crtp_wrapper.h>
#include <sqlpp11/vendor/policy.h>
#include <sqlpp11/vendor/policy_update.h>
namespace sqlpp
{
template<
typename Database = void,
typename Table = vendor::noop,
typename Assignments = vendor::noop,
typename Where = vendor::noop
>
struct update_t;
template<
typename Database,
typename Table,
typename Assignments,
typename Where
>
struct update_t
namespace detail
{
template<
typename Table,
typename Assignments,
typename Where
>
struct check_update_t
{
static_assert(vendor::is_noop<Table>::value or is_table_t<Table>::value, "invalid 'Table' argument");
static_assert(vendor::is_noop<Assignments>::value or is_update_list_t<Assignments>::value, "invalid 'Assignments' arguments");
static_assert(vendor::is_noop<Where>::value or is_where_t<Where>::value, "invalid 'Where' argument");
static constexpr bool value = true;
};
}
template<typename AssignmentsT>
using set_assignments_t = update_t<Database, Table, AssignmentsT, Where>;
template<typename WhereT>
using set_where_t = update_t<Database, Table, Assignments, WhereT>;
template<typename Database, typename... Policies>
struct update_t: public vendor::policy_t<Policies>..., public vendor::crtp_wrapper_t<update_t<Database, Policies...>, Policies>...
{
template<typename Needle, typename Replacement>
using _policy_update_t = update_t<Database, vendor::policy_update_t<Policies, Needle, Replacement>...>;
using _parameter_tuple_t = std::tuple<Table, Assignments, Where>;
using _database_t = Database;
using _parameter_tuple_t = std::tuple<Policies...>;
using _parameter_list_t = typename make_parameter_list_t<update_t>::type;
template<typename... Assignment>
auto set(Assignment... assignment)
-> set_assignments_t<vendor::update_list_t<void, Assignment...>>
{
static_assert(vendor::is_noop<Assignments>::value, "cannot call set() twice");
return {
_table,
{std::tuple<Assignment...>{assignment...}},
_where,
};
}
update_t()
{}
template<typename... Assignment>
auto dynamic_set(Assignment... assignment)
-> set_assignments_t<vendor::update_list_t<Database, Assignment...>>
{
static_assert(vendor::is_noop<Assignments>::value, "cannot call set() twice");
return {
_table,
{std::tuple<Assignment...>{assignment...}},
_where,
};
}
template<typename Whatever>
update_t(update_t r, Whatever whatever):
vendor::policy_t<Policies>(r, whatever)...
{}
template<typename Assignment>
update_t& add_set(Assignment assignment)
{
static_assert(is_dynamic_t<Assignments>::value, "cannot call add_set() in a non-dynamic set");
template<typename Remove, typename Whatever>
update_t(Remove r, Whatever whatever):
vendor::policy_t<Policies>(r, whatever)...
{}
_assignments.add(assignment);
return *this;
}
template<typename... Expr>
auto where(Expr... expr)
-> set_where_t<vendor::where_t<void, Expr...>>
{
static_assert(not vendor::is_noop<Assignments>::value, "cannot call where() if set() hasn't been called yet");
static_assert(vendor::is_noop<Where>::value, "cannot call where() twice");
return {
_table,
_assignments,
{std::tuple<Expr...>{expr...}},
};
}
template<typename... Expr>
auto dynamic_where(Expr... expr)
-> set_where_t<vendor::where_t<Database, Expr...>>
{
static_assert(not vendor::is_noop<Assignments>::value, "cannot call where() if set() hasn't been called yet");
static_assert(vendor::is_noop<Where>::value, "cannot call where() twice");
return {
_table,
_assignments,
{std::tuple<Expr...>{expr...}},
};
}
template<typename Expr>
update_t& add_where(Expr expr)
{
static_assert(is_dynamic_t<Where>::value, "cannot call add_where() in a non-dynamic where");
_where.add(expr);
return *this;
}
update_t(const update_t&) = default;
update_t(update_t&&) = default;
update_t& operator=(const update_t&) = default;
update_t& operator=(update_t&&) = default;
~update_t() = default;
static constexpr size_t _get_static_no_of_parameters()
{
@@ -147,59 +95,53 @@ namespace sqlpp
template<typename Db>
std::size_t _run(Db& db) const
{
static_assert(not vendor::is_noop<Assignments>::value, "calling set() required before running update");
static_assert(is_where_t<Where>::value, "cannot run update without having a where condition, use .where(true) to update all rows");
static_assert(_get_static_no_of_parameters() == 0, "cannot run update directly with parameters, use prepare instead");
static_assert(detail::check_update_t<Policies...>::value, "Cannot run this update expression");
return db.update(*this);
}
template<typename Db>
auto _prepare(Db& db) const
-> prepared_update_t<Db, update_t>
-> prepared_update_t<Database, update_t>
{
static_assert(not vendor::is_noop<Assignments>::value, "calling set() required before running update");
static_assert(detail::check_update_t<Policies...>::value, "Cannot run this update expression");
return {{}, db.prepare_update(*this)};
}
Table _table;
Assignments _assignments;
Where _where;
};
namespace vendor
{
template<typename Context,
typename Database,
typename Table,
typename Assignments,
typename Where
>
struct interpreter_t<Context, update_t<Database, Table, Assignments, Where>>
{
using T = update_t<Database, Table, Assignments, Where>;
template<typename Context, typename Database, typename... Policies>
struct interpreter_t<Context, update_t<Database, Policies...>>
{
using T = update_t<Database, Policies...>;
static Context& _(const T& t, Context& context)
{
context << "UPDATE ";
interpret(t._table, context);
interpret(t._assignments, context);
interpret(t._where, context);
return context;
}
};
static Context& _(const T& t, Context& context)
{
context << "UPDATE ";
interpret(t._single_table(), context);
interpret(t._update_list(), context);
interpret(t._where(), context);
return context;
}
};
}
template<typename Database>
using blank_update_t = update_t<Database, vendor::no_single_table_t, vendor::no_update_list_t, vendor::no_where_t>;
template<typename Table>
constexpr update_t<void, Table> update(Table table)
constexpr auto update(Table table)
-> update_t<void, vendor::single_table_t<void, Table>, vendor::no_update_list_t, vendor::no_where_t>
{
return {table};
return { blank_update_t<void>(), vendor::single_table_t<void, Table>{table} };
}
template<typename Db, typename Table>
constexpr update_t<Db, Table> dynamic_update(const Db&, Table table)
template<typename Database, typename Table>
constexpr auto dynamic_update(const Database&, Table table)
-> update_t<Database, vendor::single_table_t<void, Table>, vendor::no_update_list_t, vendor::no_where_t>
{
return {table};
return { blank_update_t<Database>(), vendor::single_table_t<void, Table>{table} };
}
}

View File

@@ -24,41 +24,34 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SQLPP_DETAIL_MAKE_EXPRESSION_TUPLE_H
#define SQLPP_DETAIL_MAKE_EXPRESSION_TUPLE_H
#ifndef SQLPP_VENDOR_CRTP_WRAPPER_H
#define SQLPP_VENDOR_CRTP_WRAPPER_H
#include <sqlpp11/vendor/wrong.h>
namespace sqlpp
{
namespace detail
namespace vendor
{
template<typename Expr>
auto make_single_expression_tuple(Expr expr)
-> typename std::enable_if<is_named_expression_t<Expr>::value, decltype(std::make_tuple(expr))>::type
template<typename T>
struct get_database_impl;
template<template<typename, typename...> class Statement, typename Database, typename... Policies>
struct get_database_impl<Statement<Database, Policies...>>
{
return std::make_tuple(expr);
using type = Database;
};
template<typename Expr>
auto make_single_expression_tuple(Expr expr)
-> typename std::enable_if<is_select_flag_t<Expr>::value, std::tuple<>>::type
template<typename T>
using get_database_t = typename get_database_impl<T>::type;
template<typename Derived, typename Policy>
struct crtp_wrapper_t
{
return {};
static_assert(wrong_t<Derived, Policy>::value, "missing crtp policy specialization");
};
template<typename... Expr>
auto make_single_expression_tuple(std::tuple<Expr...> t)
-> std::tuple<Expr...>
{
return t;
};
template<typename... Expr>
auto make_expression_tuple(Expr... expr)
-> decltype(std::tuple_cat(make_single_expression_tuple(expr)...))
{
return std::tuple_cat(make_single_expression_tuple(expr)...);
};
}
}
#endif

View File

@@ -54,7 +54,7 @@ namespace sqlpp
};
template<typename AliasProvider, typename... NamedExpr>
struct make_field_t_impl<multi_column_t<AliasProvider, std::tuple<NamedExpr...>>>
struct make_field_t_impl<multi_column_t<AliasProvider, NamedExpr...>>
{
using type = multi_field_t<AliasProvider, std::tuple<typename make_field_t_impl<NamedExpr>::type...>>;
};

View File

@@ -32,58 +32,112 @@
#include <sqlpp11/vendor/interpretable_list.h>
#include <sqlpp11/vendor/interpret_tuple.h>
#include <sqlpp11/detail/logic.h>
#include <sqlpp11/vendor/policy_update.h>
#include <sqlpp11/vendor/crtp_wrapper.h>
namespace sqlpp
{
namespace vendor
{
template<typename Database, typename... TableOrJoin>
// FROM
template<typename Database, typename... Tables>
struct from_t
{
using _is_from = std::true_type;
using _is_dynamic = typename std::conditional<std::is_same<Database, void>::value, std::false_type, std::true_type>::type;
// ensure one argument at least
static_assert(_is_dynamic::value or sizeof...(TableOrJoin), "at least one table or join argument required in from()");
static_assert(_is_dynamic::value or sizeof...(Tables), "at least one table or join argument required in from()");
// check for duplicate arguments
static_assert(not ::sqlpp::detail::has_duplicates<TableOrJoin...>::value, "at least one duplicate argument detected in from()");
static_assert(not ::sqlpp::detail::has_duplicates<Tables...>::value, "at least one duplicate argument detected in from()");
// check for invalid arguments
static_assert(::sqlpp::detail::and_t<is_table_t, TableOrJoin...>::value, "at least one argument is not a table or join in from()");
static_assert(::sqlpp::detail::and_t<is_table_t, Tables...>::value, "at least one argument is not a table or join in from()");
// FIXME: Joins contain two tables. This is not being dealt with at the moment when looking at duplicates, for instance
from_t(Tables... tables):
_tables(tables...)
{}
from_t(const from_t&) = default;
from_t(from_t&&) = default;
from_t& operator=(const from_t&) = default;
from_t& operator=(from_t&&) = default;
~from_t() = default;
template<typename Table>
void add(Table table)
void add_from(Table table)
{
static_assert(_is_dynamic::value, "add_from can only be called for dynamic_from");
static_assert(is_table_t<Table>::value, "from arguments require to be tables or joins");
_dynamic_tables.emplace_back(table);
}
std::tuple<TableOrJoin...> _tables;
const from_t& _from() const { return *this; }
std::tuple<Tables...> _tables;
vendor::interpretable_list_t<Database> _dynamic_tables;
};
template<typename Context, typename Database, typename... TableOrJoin>
struct interpreter_t<Context, from_t<Database, TableOrJoin...>>
struct no_from_t
{
const no_from_t& _from() const { return *this; }
};
// CRTP Wrappers
template<typename Derived, typename Database, typename... Args>
struct crtp_wrapper_t<Derived, from_t<Database, Args...>>
{
using T = from_t<Database, TableOrJoin...>;
};
template<typename Derived>
struct crtp_wrapper_t<Derived, no_from_t>
{
template<typename... Args>
auto from(Args... args)
-> vendor::update_policies_t<Derived, no_from_t, from_t<void, Args...>>
{
return { static_cast<Derived&>(*this), from_t<void, Args...>(args...) };
}
template<typename... Args>
auto dynamic_from(Args... args)
-> vendor::update_policies_t<Derived, no_from_t, from_t<get_database_t<Derived>, Args...>>
{
static_assert(not std::is_same<get_database_t<Derived>, void>::value, "dynamic_from must not be called in a static statement");
return { static_cast<Derived&>(*this), from_t<get_database_t<Derived>, Args...>(args...) };
}
};
// Interpreters
template<typename Context, typename Database, typename... Tables>
struct interpreter_t<Context, from_t<Database, Tables...>>
{
using T = from_t<Database, Tables...>;
static Context& _(const T& t, Context& context)
{
if (sizeof...(TableOrJoin) == 0 and t._dynamic_tables.empty())
if (sizeof...(Tables) == 0 and t._dynamic_tables.empty())
return context;
context << " FROM ";
interpret_tuple(t._tables, ',', context);
if (sizeof...(TableOrJoin) and not t._dynamic_tables.empty())
if (sizeof...(Tables) and not t._dynamic_tables.empty())
context << ',';
interpret_list(t._dynamic_tables, ',', context);
return context;
}
};
}
template<typename Context>
struct interpreter_t<Context, no_from_t>
{
using T = no_from_t;
static Context& _(const T& t, Context& context)
{
return context;
}
};
}
}
#endif

View File

@@ -32,57 +32,111 @@
#include <sqlpp11/vendor/expression.h>
#include <sqlpp11/vendor/interpret_tuple.h>
#include <sqlpp11/vendor/interpretable_list.h>
#include <sqlpp11/vendor/policy_update.h>
#include <sqlpp11/vendor/crtp_wrapper.h>
#include <sqlpp11/detail/logic.h>
namespace sqlpp
{
namespace vendor
{
template<typename Database, typename... Expr>
// GROUP BY
template<typename Database, typename... Expressions>
struct group_by_t
{
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 _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...(Expr), "at least one expression (e.g. a column) required in group_by()");
static_assert(_is_dynamic::value or sizeof...(Expressions), "at least one expression (e.g. a column) required in group_by()");
// check for duplicate expressions
static_assert(not ::sqlpp::detail::has_duplicates<Expr...>::value, "at least one duplicate argument detected in group_by()");
static_assert(not ::sqlpp::detail::has_duplicates<Expressions...>::value, "at least one duplicate argument detected in group_by()");
// check for invalid expressions
static_assert(::sqlpp::detail::and_t<is_expression_t, Expr...>::value, "at least one argument is not an expression in group_by()");
static_assert(::sqlpp::detail::and_t<is_expression_t, Expressions...>::value, "at least one argument is not an expression in group_by()");
template<typename E>
void add(E expr)
group_by_t(Expressions... expressions):
_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");
_dynamic_expressions.emplace_back(expr);
static_assert(is_table_t<Expression>::value, "from arguments require to be tables or joins");
_dynamic_expressions.emplace_back(expression);
}
const group_by_t& _group_by() const { return *this; }
_parameter_tuple_t _expressions;
vendor::interpretable_list_t<Database> _dynamic_expressions;
};
template<typename Context, typename Database, typename... Expr>
struct interpreter_t<Context, group_by_t<Database, Expr...>>
struct no_group_by_t
{
using _is_group_by = std::true_type;
const no_group_by_t& _group_by() const { return *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)
{
if (sizeof...(Expr) == 0 and t._dynamic_expressions.empty())
if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty())
return context;
context << " GROUP BY ";
interpret_tuple(t._expressions, ',', context);
if (sizeof...(Expr) and not t._dynamic_expressions.empty())
if (sizeof...(Expressions) and not t._dynamic_expressions.empty())
context << ',';
interpret_list(t._dynamic_expressions, ',', 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,110 @@
#include <sqlpp11/vendor/expression.h>
#include <sqlpp11/vendor/interpret_tuple.h>
#include <sqlpp11/vendor/interpretable_list.h>
#include <sqlpp11/vendor/policy_update.h>
#include <sqlpp11/vendor/crtp_wrapper.h>
#include <sqlpp11/detail/logic.h>
namespace sqlpp
{
namespace vendor
{
template<typename Database, typename... Expr>
// HAVING
template<typename Database, typename... Expressions>
struct having_t
{
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 _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(::sqlpp::detail::and_t<is_expression_t, Expr...>::value, "at least one argument is not an expression 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, 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;
template<typename E>
void add(E expr)
having_t(Expressions... expressions):
_expressions(expressions...)
{}
having_t(const having_t&) = default;
having_t(having_t&&) = default;
having_t& operator=(const having_t&) = default;
having_t& operator=(having_t&&) = default;
~having_t() = default;
template<typename Expression>
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);
}
const having_t& _having() const { return *this; }
_parameter_tuple_t _expressions;
vendor::interpretable_list_t<Database> _dynamic_expressions;
};
template<typename Context, typename Database, typename... Expr>
struct interpreter_t<Context, having_t<Database, Expr...>>
struct no_having_t
{
using _is_having = std::true_type;
const no_having_t& _having() const { return *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)
{
if (sizeof...(Expr) == 0 and t._dynamic_expressions.empty())
if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty())
return context;
context << " HAVING ";
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 ";
interpret_list(t._dynamic_expressions, " AND ", 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

@@ -1,141 +0,0 @@
/*
* 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_INSERT_LIST_H
#define SQLPP_INSERT_LIST_H
#include <sqlpp11/type_traits.h>
#include <sqlpp11/vendor/interpret_tuple.h>
#include <sqlpp11/vendor/interpretable_list.h>
#include <sqlpp11/vendor/simple_column.h>
#include <sqlpp11/detail/logic.h>
namespace sqlpp
{
namespace vendor
{
struct insert_default_values_t
{
using _is_insert_list = std::true_type;
using _is_dynamic = std::false_type;
};
template<typename Context>
struct interpreter_t<Context, insert_default_values_t>
{
using T = insert_default_values_t;
static Context& _(const T& t, Context& context)
{
context << " DEFAULT VALUES";
return context;
}
};
template<typename Database, typename... Assignments>
struct insert_list_t
{
using _is_insert_list = std::true_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<Assignments...>;
template<template<typename...> class Target>
using copy_assignments_t = Target<Assignments...>; // FIXME: Nice idea to copy variadic template arguments?
template<template<typename...> class Target, template<typename> class Wrap>
using copy_wrapped_assignments_t = Target<Wrap<Assignments>...>;
// check for at least one order expression
static_assert(_is_dynamic::value or sizeof...(Assignments), "at least one select expression required in set()");
// check for duplicate assignments
static_assert(not ::sqlpp::detail::has_duplicates<Assignments...>::value, "at least one duplicate argument detected in set()");
// check for invalid assignments
static_assert(sqlpp::detail::and_t<is_assignment_t, Assignments...>::value, "at least one argument is not an assignment in set()");
// check for prohibited assignments
static_assert(not sqlpp::detail::or_t<must_not_insert_t, typename Assignments::_column_t...>::value, "at least one assignment is prohibited by its column definition in set()");
insert_list_t(Assignments... assignment):
_assignments(assignment...),
_columns({assignment._lhs}...),
_values(assignment._rhs...)
{}
insert_list_t(const insert_list_t&) = default;
insert_list_t(insert_list_t&&) = default;
insert_list_t& operator=(const insert_list_t&) = default;
insert_list_t& operator=(insert_list_t&&) = default;
~insert_list_t() = default;
template<typename Assignment>
void add(Assignment assignment)
{
static_assert(is_assignment_t<Assignment>::value, "set() arguments require to be assigments");
static_assert(not must_not_insert_t<Assignment>::value, "set() argument must not be used in insert");
_dynamic_columns.emplace_back(simple_column_t<typename Assignment::_column_t>{assignment._lhs});
_dynamic_values.emplace_back(assignment._rhs);
}
std::tuple<simple_column_t<typename Assignments::_column_t>...> _columns;
std::tuple<typename Assignments::value_type...> _values;
std::tuple<Assignments...> _assignments; // FIXME: Need to replace _columns and _values by _assignments (connector-container requires assignments)
typename vendor::interpretable_list_t<Database> _dynamic_columns;
typename vendor::interpretable_list_t<Database> _dynamic_values;
};
template<typename Context, typename Database, typename... Assignments>
struct interpreter_t<Context, insert_list_t<Database, Assignments...>>
{
using T = insert_list_t<Database, Assignments...>;
static Context& _(const T& t, Context& context)
{
if (sizeof...(Assignments) + t._dynamic_columns.size() == 0)
{
interpret(insert_default_values_t(), context);
}
else
{
context << " (";
interpret_tuple(t._columns, ",", context);
if (sizeof...(Assignments) and not t._dynamic_columns.empty())
context << ',';
interpret_list(t._dynamic_columns, ',', context);
context << ") VALUES(";
interpret_tuple(t._values, ",", context);
if (sizeof...(Assignments) and not t._dynamic_values.empty())
context << ',';
interpret_list(t._dynamic_values, ',', context);
context << ")";
}
return context;
}
};
}
}
#endif

View File

@@ -29,28 +29,102 @@
#include <sqlpp11/type_traits.h>
#include <sqlpp11/detail/logic.h>
#include <sqlpp11/vendor/insert_value.h>
#include <sqlpp11/vendor/interpret_tuple.h>
#include <sqlpp11/vendor/insert_value.h>
#include <sqlpp11/vendor/simple_column.h>
#include <sqlpp11/vendor/policy_update.h>
#include <sqlpp11/vendor/crtp_wrapper.h>
namespace sqlpp
{
namespace vendor
{
template<typename... InsertValues>
struct insert_value_list_t
// COLUMN AND VALUE LIST
struct insert_default_values_t
{
using _is_insert_list = std::true_type;
using _is_dynamic = std::false_type;
const insert_default_values_t& _insert_value_list() const { return *this; }
};
template<typename Database, typename... Assignments>
struct insert_list_t
{
using _is_insert_value_list = std::true_type;
using _is_insert_list = std::true_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<Assignments...>;
template<template<typename...> class Target>
using copy_assignments_t = Target<Assignments...>; // FIXME: Nice idea to copy variadic template arguments?
template<template<typename...> class Target, template<typename> class Wrap>
using copy_wrapped_assignments_t = Target<Wrap<Assignments>...>;
static_assert(sizeof...(InsertValues), "at least one insert value required");
static_assert(_is_dynamic::value or sizeof...(Assignments), "at least one select expression required in set()");
// check for invalid arguments
static_assert(::sqlpp::detail::and_t<is_insert_value_t, InsertValues...>::value, "at least one argument is not an insert value");
static_assert(not ::sqlpp::detail::has_duplicates<Assignments...>::value, "at least one duplicate argument detected in set()");
using _value_tuple_t = std::tuple<InsertValues...>;
static_assert(sqlpp::detail::and_t<is_assignment_t, Assignments...>::value, "at least one argument is not an assignment in set()");
void add(_value_tuple_t value_tuple)
static_assert(not sqlpp::detail::or_t<must_not_insert_t, typename Assignments::_column_t...>::value, "at least one assignment is prohibited by its column definition in set()");
insert_list_t(Assignments... assignment):
_assignments(assignment...),
_columns({assignment._lhs}...),
_values(assignment._rhs...)
{}
insert_list_t(const insert_list_t&) = default;
insert_list_t(insert_list_t&&) = default;
insert_list_t& operator=(const insert_list_t&) = default;
insert_list_t& operator=(insert_list_t&&) = default;
~insert_list_t() = default;
template<typename Assignment>
void add_set(Assignment assignment)
{
static_assert(is_assignment_t<Assignment>::value, "set() arguments require to be assigments");
static_assert(not must_not_insert_t<Assignment>::value, "set() argument must not be used in insert");
_dynamic_columns.emplace_back(simple_column_t<typename Assignment::_column_t>{assignment._lhs});
_dynamic_values.emplace_back(assignment._rhs);
}
const insert_list_t& _insert_value_list() const { return *this; }
std::tuple<simple_column_t<typename Assignments::_column_t>...> _columns;
std::tuple<typename Assignments::value_type...> _values;
std::tuple<Assignments...> _assignments; // FIXME: Need to replace _columns and _values by _assignments (connector-container requires assignments)
typename vendor::interpretable_list_t<Database> _dynamic_columns;
typename vendor::interpretable_list_t<Database> _dynamic_values;
};
template<typename... Columns>
struct column_list_t
{
using _is_column_list = std::true_type;
using _parameter_tuple_t = std::tuple<Columns...>;
static_assert(sizeof...(Columns), "at least one column required in columns()");
static_assert(not ::sqlpp::detail::has_duplicates<Columns...>::value, "at least one duplicate argument detected in columns()");
static_assert(::sqlpp::detail::and_t<is_column_t, Columns...>::value, "at least one argument is not a column in columns()");
static_assert(not ::sqlpp::detail::or_t<must_not_insert_t, Columns...>::value, "at least one column argument has a must_not_insert flag in its definition");
using _value_tuple_t = std::tuple<vendor::insert_value_t<Columns>...>;
column_list_t(Columns... columns):
_columns(simple_column_t<Columns>{columns}...)
{}
column_list_t(const column_list_t&) = default;
column_list_t(column_list_t&&) = default;
column_list_t& operator=(const column_list_t&) = default;
column_list_t& operator=(column_list_t&&) = default;
~column_list_t() = default;
void add_values(vendor::insert_value_t<Columns>... values)
{
_insert_values.emplace_back(value_tuple);
_insert_values.emplace_back(values...);
}
bool empty() const
@@ -58,33 +132,95 @@ namespace sqlpp
return _insert_values.empty();
}
const column_list_t& _insert_value_list() const { return *this; }
std::tuple<simple_column_t<Columns>...> _columns;
std::vector<_value_tuple_t> _insert_values;
};
template<>
struct insert_value_list_t<noop>
struct no_insert_value_list_t
{
using _is_insert_value_list = std::true_type;
const no_insert_value_list_t& _insert_value_list() const { return *this; }
};
// CRTP Wrappers
template<typename Derived>
struct crtp_wrapper_t<Derived, insert_default_values_t>
{
using _is_insert_value_list = std::true_type;
using _value_tuple_t = std::tuple<>;
void add(_value_tuple_t value_tuple)
{
}
static constexpr bool empty()
{
return true;
}
};
template<typename Context, typename... InsertValues>
struct interpreter_t<Context, insert_value_list_t<InsertValues...>>
template<typename Derived, typename Database, typename... Args>
struct crtp_wrapper_t<Derived, column_list_t<Database, Args...>>
{
using T = insert_value_list_t<InsertValues...>;
};
template<typename Derived, typename Database, typename... Args>
struct crtp_wrapper_t<Derived, insert_list_t<Database, Args...>>
{
};
template<typename Derived>
struct crtp_wrapper_t<Derived, no_insert_value_list_t>
{
template<typename... Args>
struct delayed_t
{
using type = Derived;
};
template<typename Arg = void>
auto default_values()
-> vendor::update_policies_t<typename delayed_t<Arg>::type, no_insert_value_list_t, insert_default_values_t>
{
return { static_cast<Derived&>(*this), insert_default_values_t{} };
}
template<typename... Args>
auto columns(Args... args)
-> vendor::update_policies_t<Derived, no_insert_value_list_t, column_list_t<Args...>>
{
return { static_cast<Derived&>(*this), column_list_t<Args...>(args...) };
}
template<typename... Args>
auto set(Args... args)
-> vendor::update_policies_t<Derived, no_insert_value_list_t, insert_list_t<void, Args...>>
{
return { static_cast<Derived&>(*this), insert_list_t<void, Args...>(args...) };
}
template<typename... Args>
auto dynamic_set(Args... args)
-> vendor::update_policies_t<Derived, no_insert_value_list_t, insert_list_t<get_database_t<Derived>, Args...>>
{
static_assert(not std::is_same<get_database_t<Derived>, void>::value, "dynamic_insert_list must not be called in a static statement");
return { static_cast<Derived&>(*this), insert_list_t<get_database_t<Derived>, Args...>(args...) };
}
};
// Interpreters
template<typename Context>
struct interpreter_t<Context, insert_default_values_t>
{
using T = insert_default_values_t;
static Context& _(const T& t, Context& context)
{
context << " DEFAULT VALUES";
return context;
}
};
template<typename Context, typename... Columns>
struct interpreter_t<Context, column_list_t<Columns...>>
{
using T = column_list_t<Columns...>;
static Context& _(const T& t, Context& context)
{
context << " (";
interpret_tuple(t._columns, ",", context);
context << ")";
context << " VALUES ";
bool first = true;
for (const auto& row : t._insert_values)
@@ -97,20 +233,51 @@ namespace sqlpp
interpret_tuple(row, ",", context);
context << ')';
}
return context;
}
};
template<typename Context, typename Database, typename... Assignments>
struct interpreter_t<Context, insert_list_t<Database, Assignments...>>
{
using T = insert_list_t<Database, Assignments...>;
static Context& _(const T& t, Context& context)
{
if (sizeof...(Assignments) + t._dynamic_columns.size() == 0)
{
interpret(insert_default_values_t(), context);
}
else
{
context << " (";
interpret_tuple(t._columns, ",", context);
if (sizeof...(Assignments) and not t._dynamic_columns.empty())
context << ',';
interpret_list(t._dynamic_columns, ',', context);
context << ") VALUES(";
interpret_tuple(t._values, ",", context);
if (sizeof...(Assignments) and not t._dynamic_values.empty())
context << ',';
interpret_list(t._dynamic_values, ',', context);
context << ")";
}
return context;
}
};
template<typename Context>
struct interpreter_t<Context, insert_value_list_t<noop>>
struct interpreter_t<Context, no_insert_value_list_t>
{
using T = insert_value_list_t<noop>;
using T = no_insert_value_list_t;
static Context& _(const T& t, Context& context)
{
return context;
}
};
}
}

View File

@@ -24,8 +24,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SQLPP_VENDOR_INTERPRET_H
#define SQLPP_VENDOR_INTERPRET_H
#ifndef SQLPP_VENDOR_INTERPRETER_H
#define SQLPP_VENDOR_INTERPRETER_H
#include <sqlpp11/vendor/wrong.h>

View File

@@ -27,21 +27,132 @@
#ifndef SQLPP_LIMIT_H
#define SQLPP_LIMIT_H
#include <ostream>
#include <sqlpp11/select_fwd.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/vendor/policy_update.h>
#include <sqlpp11/vendor/crtp_wrapper.h>
namespace sqlpp
{
namespace vendor
{
// LIMIT
template<typename Limit>
struct limit_t
{
using _is_limit = std::true_type;
static_assert(is_integral_t<Limit>::value, "limit requires an integral value or integral parameter");
Limit _limit;
limit_t(Limit 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;
const limit_t& _limit() const { return *this; }
Limit _value;
};
template<typename Database>
struct dynamic_limit_t
{
using _is_limit = std::true_type;
using _is_dynamic = std::true_type;
dynamic_limit_t():
_value(noop())
{
}
template<typename Limit>
dynamic_limit_t(Limit value):
_initialized(true),
_value(typename wrap_operand<Limit>::type(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;
template<typename Limit>
void set_limit(Limit value)
{
using arg_t = typename wrap_operand<Limit>::type;
_value = arg_t{value};
_initialized = true;
}
const dynamic_limit_t& _limit() const { return *this; }
bool _initialized = false;
interpretable_t<Database> _value;
};
struct no_limit_t
{
using _is_limit = std::true_type;
const no_limit_t& _limit() const { return *this; }
};
// CRTP Wrappers
template<typename Derived, typename Limit>
struct crtp_wrapper_t<Derived, limit_t<Limit>>
{
};
template<typename Derived, typename Database>
struct crtp_wrapper_t<Derived, dynamic_limit_t<Database>>
{
};
template<typename Derived>
struct crtp_wrapper_t<Derived, no_limit_t>
{
template<typename... Args>
struct delayed_get_database_t
{
using type = get_database_t<Derived>;
};
template<typename Arg>
auto limit(Arg arg)
-> vendor::update_policies_t<Derived, no_limit_t, limit_t<typename wrap_operand<Arg>::type>>
{
typename wrap_operand<Arg>::type value = {arg};
return { static_cast<Derived&>(*this), limit_t<typename wrap_operand<Arg>::type>(value) };
}
template<typename... Args>
auto dynamic_limit(Args... args)
-> vendor::update_policies_t<Derived, no_limit_t, dynamic_limit_t<typename delayed_get_database_t<Args...>::type>>
{
static_assert(sizeof...(Args) < 2, "dynamic_limit must be called with zero or one arguments");
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<typename delayed_get_database_t<Args...>::type>(args...) };
}
};
// Interpreters
template<typename Context, typename Database>
struct interpreter_t<Context, dynamic_limit_t<Database>>
{
using T = dynamic_limit_t<Database>;
static Context& _(const T& t, Context& context)
{
if (t._initialized)
{
context << " LIMIT ";
interpret(t._value, context);
}
return context;
}
};
template<typename Context, typename Limit>
@@ -52,38 +163,23 @@ namespace sqlpp
static Context& _(const T& t, Context& context)
{
context << " LIMIT ";
interpret(t._limit, context);
interpret(t._value, 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>
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)
{
if (t._limit > 0)
context << " LIMIT " << t._limit;
return context;
}
};
}
}
}
#endif

View File

@@ -28,20 +28,117 @@
#define SQLPP_OFFSET_H
#include <sqlpp11/type_traits.h>
#include <sqlpp11/vendor/policy_update.h>
#include <sqlpp11/vendor/crtp_wrapper.h>
namespace sqlpp
{
namespace vendor
{
// OFFSET
template<typename Offset>
struct offset_t
{
using _is_offset = std::true_type;
static_assert(is_integral_t<Offset>::value, "offset requires an integral value or integral parameter");
Offset _offset;
offset_t(Offset 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;
const offset_t& _offset() const { return *this; }
Offset _value;
};
template<typename Database>
struct dynamic_offset_t
{
using _is_offset = std::true_type;
using _is_dynamic = std::true_type;
dynamic_offset_t():
_value(noop())
{
}
template<typename Offset>
dynamic_offset_t(Offset value):
_initialized(true),
_value(typename wrap_operand<Offset>::type(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;
template<typename Offset>
void set_offset(Offset value)
{
using arg_t = typename wrap_operand<Offset>::type;
_value = arg_t(value);
_initialized = true;
}
const dynamic_offset_t& _offset() const { return *this; }
bool _initialized = false;
interpretable_t<Database> _value;
};
struct no_offset_t
{
using _is_offset = std::true_type;
const no_offset_t& _offset() const { return *this; }
};
// CRTP Wrappers
template<typename Derived, typename Offset>
struct crtp_wrapper_t<Derived, offset_t<Offset>>
{
};
template<typename Derived, typename Database>
struct crtp_wrapper_t<Derived, dynamic_offset_t<Database>>
{
};
template<typename Derived>
struct crtp_wrapper_t<Derived, no_offset_t>
{
template<typename... Args>
struct delayed_get_database_t
{
using type = get_database_t<Derived>;
};
template<typename Arg>
auto offset(Arg arg)
-> vendor::update_policies_t<Derived, no_offset_t, offset_t<typename wrap_operand<Arg>::type>>
{
typename wrap_operand<Arg>::type value = {arg};
return { static_cast<Derived&>(*this), offset_t<typename wrap_operand<Arg>::type>(value) };
}
template<typename... Args>
auto dynamic_offset(Args... args)
-> vendor::update_policies_t<Derived, no_offset_t, dynamic_offset_t<typename delayed_get_database_t<Args...>::type>>
{
static_assert(sizeof...(Args) < 2, "dynamic_offset must be called with zero or one arguments");
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<typename delayed_get_database_t<Args...>::type>(args...) };
}
};
// Interpreters
template<typename Context, typename Offset>
struct interpreter_t<Context, offset_t<Offset>>
{
@@ -50,37 +147,37 @@ namespace sqlpp
static Context& _(const T& t, Context& context)
{
context << " OFFSET ";
interpret(t._offset, context);
interpret(t._value, context);
return context;
}
};
struct dynamic_offset_t
{
using _is_offset = std::true_type;
using _is_dynamic = std::true_type;
void set(std::size_t offset)
template<typename Context, typename Database>
struct interpreter_t<Context, dynamic_offset_t<Database>>
{
_offset = offset;
}
std::size_t _offset;
};
template<typename Context>
struct interpreter_t<Context, dynamic_offset_t>
{
using T = dynamic_offset_t;
using T = dynamic_offset_t<Database>;
static Context& _(const T& t, Context& context)
{
if (t._offset > 0)
context << " OFFSET " << t._offset;
if (t._initialized)
{
context << " OFFSET ";
interpret(t._value, 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/vendor/interpret_tuple.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 vendor
{
template<typename Database,typename... Expr>
template<typename Database,typename... Expressions>
struct order_by_t
{
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 _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...(Expr), "at least one sort-order expression required in order_by()");
static_assert(_is_dynamic::value or sizeof...(Expressions), "at least one sort-order expression required in order_by()");
// check for duplicate order expressions
static_assert(not ::sqlpp::detail::has_duplicates<Expr...>::value, "at least one duplicate argument detected in order_by()");
static_assert(not ::sqlpp::detail::has_duplicates<Expressions...>::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, Expr...>::value, "at least one argument is not a sort order expression in order_by()");
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()");
template<typename E>
void add(E expr)
order_by_t(Expressions... expressions):
_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");
_dynamic_expressions.push_back(expr);
static_assert(is_sort_order_t<Expression>::value, "order_by arguments require to be sort-order expressions");
_dynamic_expressions.push_back(expressions);
}
const order_by_t& _order_by() const { return *this; }
_parameter_tuple_t _expressions;
vendor::interpretable_list_t<Database> _dynamic_expressions;
};
template<typename Context, typename Database, typename... Expr>
struct interpreter_t<Context, order_by_t<Database, Expr...>>
struct no_order_by_t
{
using _is_order_by = std::true_type;
const no_order_by_t& _order_by() const { return *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)
{
if (sizeof...(Expr) == 0 and t._dynamic_expressions.empty())
if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty())
return context;
context << " ORDER BY ";
interpret_tuple(t._expressions, ',', context);
if (sizeof...(Expr) and not t._dynamic_expressions.empty())
if (sizeof...(Expressions) and not t._dynamic_expressions.empty())
context << ',';
interpret_list(t._dynamic_expressions, ',', 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;
}
};
}
}

62
include/sqlpp11/vendor/policy.h vendored Normal file
View File

@@ -0,0 +1,62 @@
/*
* 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_VENDOR_POLICY_H
#define SQLPP_VENDOR_POLICY_H
#include <sqlpp11/vendor/wrong.h>
namespace sqlpp
{
namespace vendor
{
template<typename PolicyImpl>
struct policy_t: public PolicyImpl
{
policy_t()
{}
template<typename Whatever>
policy_t(const Whatever&, policy_t policy):
PolicyImpl(policy)
{}
template<typename Whatever>
policy_t(const Whatever&, PolicyImpl impl):
PolicyImpl(impl)
{}
template<typename Derived, typename Whatever>
policy_t(Derived derived, const Whatever&):
PolicyImpl(derived)
{}
};
}
}
#endif

59
include/sqlpp11/vendor/policy_update.h vendored Normal file
View File

@@ -0,0 +1,59 @@
/*
* 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_VENDOR_POLICY_UPDATE_H
#define SQLPP_VENDOR_POLICY_UPDATE_H
#include <sqlpp11/vendor/wrong.h>
namespace sqlpp
{
namespace vendor
{
template<typename Needle, typename Replacement>
struct policy_update_impl
{
template<typename T>
using _policy_t = typename std::conditional<std::is_same<Needle, T>::value, Replacement, T>::type;
};
template<typename T, typename Needle, typename Replacement>
using policy_update_t = typename policy_update_impl<Needle, Replacement>::template _policy_t<T>;
template<typename Original, typename Needle, typename Replacement>
struct update_policies_impl
{
using type = typename Original::template _policy_update_t<Needle, Replacement>;
};
template<typename Original, typename Needle, typename Replacement>
using update_policies_t = typename update_policies_impl<Original, Needle, Replacement>::type;
}
}
#endif

View File

@@ -37,6 +37,8 @@
#include <sqlpp11/vendor/select_pseudo_table.h>
#include <sqlpp11/vendor/named_interpretable.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>
namespace sqlpp
@@ -130,69 +132,118 @@ namespace sqlpp
};
template<typename Database, typename T>
// SELECT COLUMNS
template<typename Database, typename... Columns>
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_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>;
// check for duplicate select expressions
static_assert(not ::sqlpp::detail::has_duplicates<NamedExpr...>::value, "at least one duplicate argument detected");
static_assert(not ::sqlpp::detail::has_duplicates<Columns...>::value, "at least one duplicate argument detected");
// check for invalid select expressions
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>;
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 NamedExpr::_name_t...>::value, "at least one duplicate name detected");
static_assert(not ::sqlpp::detail::has_duplicates<typename Columns::_name_t...>::value, "at least one duplicate name detected");
// provide type information for sub-selects that are used as expressions
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_named_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...(Columns) == 1, std::true_type, std::false_type>::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,
dynamic_result_row_t<make_field_t<NamedExpr>...>,
result_row_t<make_field_t<NamedExpr>...>>::type;
dynamic_result_row_t<make_field_t<Columns>...>,
result_row_t<make_field_t<Columns>...>>::type;
using _dynamic_names_t = typename dynamic_select_column_list<Database>::_names_t;
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>
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(std::tuple<Columns...> columns):
_columns(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>
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_dynamic::value, "cannot add columns to a non-dynamic column list");
_dynamic_columns.push_back(namedExpr);
}
const select_column_list_t& _column_list() const { return *this; }
_parameter_tuple_t _columns;
dynamic_select_column_list<Database> _dynamic_columns;
};
template<typename Context, typename Database, typename Tuple>
struct interpreter_t<Context, select_column_list_t<Database, Tuple>>
struct no_select_column_list_t
{
using _is_select_column_list = std::true_type;
using _result_row_t = ::sqlpp::result_row_t<>;
using _dynamic_names_t = typename dynamic_select_column_list<void>::_names_t;
using _value_type = no_value_t;
struct _name_t {};
template<typename T>
struct _pseudo_table_t
{
static_assert(wrong_t<T>::value, "Cannot use a select as a table when no columns have been selected yet");
};
const no_select_column_list_t& _column_list() const { return *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)
{
@@ -206,6 +257,17 @@ namespace sqlpp
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
#define SQLPP_VENDOR_SELECT_FLAG_LIST_H
#include <tuple>
#include <sqlpp11/select_fwd.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/select_flags.h>
#include <sqlpp11/detail/type_set.h>
#include <sqlpp11/vendor/interpret_tuple.h>
#include <tuple>
#include <sqlpp11/vendor/policy_update.h>
#include <sqlpp11/vendor/crtp_wrapper.h>
namespace sqlpp
{
namespace vendor
{
template<typename Database, typename T>
// SELECT FLAGS
template<typename Database, typename... Flags>
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_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>;
// check for duplicate order expressions
static_assert(not ::sqlpp::detail::has_duplicates<Flag...>::value, "at least one duplicate argument detected in select flag list");
static_assert(not ::sqlpp::detail::has_duplicates<Flags...>::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, Flag...>::value, "at least one argument is not a select flag in select flag list");
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");
template<typename E>
void add(E expr)
select_flag_list_t(Flags... flags):
_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");
_dynamic_flags.emplace_back(expr);
static_assert(is_select_flag_t<Flag>::value, "flag arguments require to be select flags");
_dynamic_flags.emplace_back(flag);
}
const select_flag_list_t& _flag_list() const { return *this; }
_parameter_tuple_t _flags;
vendor::interpretable_list_t<Database> _dynamic_flags;
};
template<typename Context, typename Database, typename... Flag>
struct interpreter_t<Context, select_flag_list_t<Database, std::tuple<Flag...>>>
struct no_select_flag_list_t
{
using _is_select_flag_list = std::true_type;
const no_select_flag_list_t& _flag_list() const { return *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)
{
interpret_tuple(t._flags, ' ', context);
if (sizeof...(Flag))
if (sizeof...(Flags))
context << ' ';
interpret_list(t._dynamic_flags, ',', context);
if (not t._dynamic_flags.empty())
@@ -86,6 +123,17 @@ namespace sqlpp
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

@@ -24,53 +24,70 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SQLPP_COLUMN_LIST_H
#define SQLPP_COLUMN_LIST_H
#ifndef SQLPP_VENDOR_SINGLE_TABLE_H
#define SQLPP_VENDOR_SINGLE_TABLE_H
#include <sqlpp11/type_traits.h>
#include <sqlpp11/detail/logic.h>
#include <sqlpp11/vendor/interpret_tuple.h>
#include <sqlpp11/vendor/simple_column.h>
#include <sqlpp11/vendor/policy_update.h>
#include <sqlpp11/vendor/crtp_wrapper.h>
#include <iostream> // FIXME: REMOVE
namespace sqlpp
{
namespace vendor
{
template<typename... Columns>
struct column_list_t
// A SINGLE TABLE
template<typename Database, typename Table>
struct single_table_t
{
using _is_column_list = std::true_type;
using _parameter_tuple_t = std::tuple<Columns...>;
using _is_single_table = std::true_type;
// check for at least one order column
static_assert(sizeof...(Columns), "at least one column required in columns()");
static_assert(is_table_t<Table>::value, "argument has to be a table");
// check for duplicate columns
static_assert(not ::sqlpp::detail::has_duplicates<Columns...>::value, "at least one duplicate argument detected in columns()");
single_table_t(Table table):
_table(table)
{}
// check for invalid columns
static_assert(::sqlpp::detail::and_t<is_column_t, Columns...>::value, "at least one argument is not a column in columns()");
single_table_t(const single_table_t&) = default;
single_table_t(single_table_t&&) = default;
single_table_t& operator=(const single_table_t&) = default;
single_table_t& operator=(single_table_t&&) = default;
~single_table_t() = default;
// check for prohibited columns
static_assert(not ::sqlpp::detail::or_t<must_not_insert_t, Columns...>::value, "at least one column argument has a must_not_insert flag in its definition");
std::tuple<simple_column_t<Columns>...> _columns;
const single_table_t& _single_table() const { return *this; }
Table _table;
};
template<typename Context, typename... Columns>
struct interpreter_t<Context, column_list_t<Columns...>>
struct no_single_table_t
{
using _is_single_table = std::true_type;
const no_single_table_t& _single_table() const { return *this; }
};
// CRTP Wrappers
template<typename Derived, typename Database, typename Table>
struct crtp_wrapper_t<Derived, single_table_t<Database, Table>>
{
using T = column_list_t<Columns...>;
};
template<typename Derived>
struct crtp_wrapper_t<Derived, no_single_table_t>
{
};
// Interpreters
template<typename Context, typename Database, typename Table>
struct interpreter_t<Context, single_table_t<Database, Table>>
{
using T = single_table_t<Database, Table>;
static Context& _(const T& t, Context& context)
{
context << " (";
interpret_tuple(t._columns, ",", context);
context << ")";
interpret(t._table, context);
return context;
}
};
}
}

View File

@@ -36,6 +36,7 @@ namespace sqlpp
{
namespace vendor
{
// UPDATE ASSIGNMENTS
template<typename Database, typename... Assignments>
struct update_list_t
{
@@ -43,30 +44,69 @@ namespace sqlpp
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<Assignments...>;
// check for at least one order expression
static_assert(_is_dynamic::value or sizeof...(Assignments), "at least one assignment expression required in set()");
// check for duplicate assignments
static_assert(not ::sqlpp::detail::has_duplicates<Assignments...>::value, "at least one duplicate argument detected in set()");
// check for invalid assignments
static_assert(::sqlpp::detail::and_t<is_assignment_t, Assignments...>::value, "at least one argument is not an assignment in set()");
// check for prohibited assignments
static_assert(not ::sqlpp::detail::or_t<must_not_update_t, typename Assignments::_column_t...>::value, "at least one assignment is prohibited by its column definition in set()");
update_list_t(Assignments... assignments):
_assignments(assignments...)
{}
update_list_t(const update_list_t&) = default;
update_list_t(update_list_t&&) = default;
update_list_t& operator=(const update_list_t&) = default;
update_list_t& operator=(update_list_t&&) = default;
~update_list_t() = default;
template<typename Assignment>
void add(Assignment assignment)
void add_set(Assignment assignment)
{
static_assert(is_assignment_t<Assignment>::value, "set() arguments require to be assigments");
static_assert(not must_not_update_t<typename Assignment::_column_t>::value, "set() argument must not be updated");
_dynamic_assignments.emplace_back(assignment);
}
const update_list_t& _update_list() const { return *this; }
_parameter_tuple_t _assignments;
typename vendor::interpretable_list_t<Database> _dynamic_assignments;
};
struct no_update_list_t
{
using _is_update_list = std::true_type;
const no_update_list_t& _update_list() const { return *this; }
};
// CRTP Wrappers
template<typename Derived, typename Database, typename... Args>
struct crtp_wrapper_t<Derived, update_list_t<Database, Args...>>
{
};
template<typename Derived>
struct crtp_wrapper_t<Derived, no_update_list_t>
{
template<typename... Args>
auto set(Args... args)
-> vendor::update_policies_t<Derived, no_update_list_t, update_list_t<void, Args...>>
{
return { static_cast<Derived&>(*this), update_list_t<void, Args...>(args...) };
}
template<typename... Args>
auto dynamic_set(Args... args)
-> vendor::update_policies_t<Derived, no_update_list_t, update_list_t<get_database_t<Derived>, Args...>>
{
static_assert(not std::is_same<get_database_t<Derived>, void>::value, "dynamic_update_list must not be called in a static statement");
return { static_cast<Derived&>(*this), update_list_t<get_database_t<Derived>, Args...>(args...) };
}
};
// Interpreters
template<typename Context, typename Database, typename... Assignments>
struct interpreter_t<Context, update_list_t<Database, Assignments...>>
{
@@ -82,6 +122,18 @@ namespace sqlpp
return context;
}
};
template<typename Context>
struct interpreter_t<Context, no_update_list_t>
{
using T = no_update_list_t;
static Context& _(const T& t, Context& context)
{
return context;
}
};
}
}

View File

@@ -31,55 +31,110 @@
#include <sqlpp11/vendor/interpretable_list.h>
#include <sqlpp11/vendor/interpret_tuple.h>
#include <sqlpp11/detail/type_set.h>
#include <sqlpp11/vendor/policy_update.h>
#include <sqlpp11/vendor/crtp_wrapper.h>
namespace sqlpp
{
namespace vendor
{
template<typename Database, typename... Table>
// USING
template<typename Database, typename... Tables>
struct using_t
{
using _is_using = std::true_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<Table...>;
using _parameter_tuple_t = std::tuple<Tables...>;
static_assert(_is_dynamic::value or sizeof...(Table), "at least one table argument required in using()");
static_assert(_is_dynamic::value or sizeof...(Tables), "at least one table argument required in using()");
// check for duplicate arguments
static_assert(not ::sqlpp::detail::has_duplicates<Table...>::value, "at least one duplicate argument detected in using()");
static_assert(not ::sqlpp::detail::has_duplicates<Tables...>::value, "at least one duplicate argument detected in using()");
// check for invalid arguments
static_assert(::sqlpp::detail::and_t<is_table_t, Table...>::value, "at least one argument is not an table in using()");
static_assert(::sqlpp::detail::and_t<is_table_t, Tables...>::value, "at least one argument is not an table in using()");
using_t(Tables... tables):
_tables(tables...)
{}
using_t(const using_t&) = default;
using_t(using_t&&) = default;
using_t& operator=(const using_t&) = default;
using_t& operator=(using_t&&) = default;
~using_t() = default;
template<typename T>
void add(T table)
template<typename Table>
void add_using(Table table)
{
static_assert(is_table_t<T>::value, "using() arguments require to be tables");
static_assert(_is_dynamic::value, "add_using can only be called for dynamic_using");
static_assert(is_table_t<Table>::value, "using() arguments require to be tables");
_dynamic_tables.emplace_back(table);
}
const using_t& _using() const { return *this; }
_parameter_tuple_t _tables;
vendor::interpretable_list_t<Database> _dynamic_tables;
};
template<typename Context, typename Database, typename... Table>
struct interpreter_t<Context, using_t<Database, Table...>>
struct no_using_t
{
const no_using_t& _using() const { return *this; }
};
// CRTP Wrapper
template<typename Derived, typename Database, typename... Args>
struct crtp_wrapper_t<Derived, using_t<Database, Args...>>
{
using T = using_t<Database, Table...>;
};
template<typename Derived>
struct crtp_wrapper_t<Derived, no_using_t>
{
template<typename... Args>
auto using_(Args... args)
-> vendor::update_policies_t<Derived, no_using_t, using_t<void, Args...>>
{
return { static_cast<Derived&>(*this), using_t<void, Args...>(args...) };
}
template<typename... Args>
auto dynamic_using(Args... args)
-> vendor::update_policies_t<Derived, no_using_t, using_t<get_database_t<Derived>, Args...>>
{
static_assert(not std::is_same<get_database_t<Derived>, void>::value, "dynamic_using must not be called in a static statement");
return { static_cast<Derived&>(*this), using_t<get_database_t<Derived>, Args...>(args...) };
}
};
// Interpreters
template<typename Context, typename Database, typename... Tables>
struct interpreter_t<Context, using_t<Database, Tables...>>
{
using T = using_t<Database, Tables...>;
static Context& _(const T& t, Context& context)
{
if (sizeof...(Table) == 0 and t._dynamic_tables.empty())
if (sizeof...(Tables) == 0 and t._dynamic_tables.empty())
return context;
context << " USING ";
interpret_tuple(t._tables, ',', context);
if (sizeof...(Table) and not t._dynamic_tables.empty())
if (sizeof...(Tables) and not t._dynamic_tables.empty())
context << ',';
interpret_list(t._dynamic_tables, ',', context);
return context;
}
};
template<typename Context>
struct interpreter_t<Context, no_using_t>
{
using T = no_using_t;
static Context& _(const T& t, Context& context)
{
return context;
}
};
}
}

View File

@@ -27,68 +27,123 @@
#ifndef 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/detail/logic.h>
#include <sqlpp11/parameter_list.h>
#include <sqlpp11/vendor/expression.h>
#include <sqlpp11/vendor/interpret_tuple.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 vendor
{
template<typename Database, typename... Expr>
// WHERE
template<typename Database, typename... Expressions>
struct where_t
{
using _is_where = std::true_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 where()");
static_assert(sqlpp::detail::and_t<is_expression_t, Expr...>::value, "at least one argument is not an expression in where()");
static_assert(_is_dynamic::value or sizeof...(Expressions), "at least one expression argument required in where()");
static_assert(sqlpp::detail::and_t<is_expression_t, Expressions...>::value, "at least one argument is not an expression in where()");
using _parameter_list_t = typename make_parameter_list_t<_parameter_tuple_t>::type;
where_t(Expressions... expressions):
_expressions(expressions...)
{}
where_t(const where_t&) = default;
where_t(where_t&&) = default;
where_t& operator=(const where_t&) = default;
where_t& operator=(where_t&&) = default;
~where_t() = default;
template<typename E>
void add(E expr)
void add_where(E expr)
{
static_assert(_is_dynamic::value, "add_where can only be called for dynamic_where");
static_assert(is_expression_t<E>::value, "invalid expression argument in add_where()");
_dynamic_expressions.emplace_back(expr);
}
const where_t& _where() const { return *this; }
_parameter_tuple_t _expressions;
vendor::interpretable_list_t<Database> _dynamic_expressions;
};
template<typename Context, typename Database, typename... Expr>
struct interpreter_t<Context, where_t<Database, Expr...>>
{
using T = where_t<Database, Expr...>;
static Context& _(const T& t, Context& context)
{
if (sizeof...(Expr) == 0 and t._dynamic_expressions.empty())
return context;
context << " WHERE ";
interpret_tuple(t._expressions, " AND ", context);
if (sizeof...(Expr) and not t._dynamic_expressions.empty())
context << " AND ";
interpret_list(t._dynamic_expressions, " AND ", context);
return context;
}
};
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;
where_t(bool condition):
_condition(condition)
{}
where_t(const where_t&) = default;
where_t(where_t&&) = default;
where_t& operator=(const where_t&) = default;
where_t& operator=(where_t&&) = default;
~where_t() = default;
const where_t& _where() const { return *this; }
bool _condition;
};
struct no_where_t
{
using _is_where = std::true_type;
const no_where_t& _where() const { return *this; }
};
// CRTP Wrappers
template<typename Derived, typename Database, typename... Args>
struct crtp_wrapper_t<Derived, where_t<Database, Args...>>
{
};
template<typename Derived>
struct crtp_wrapper_t<Derived, no_where_t>
{
template<typename... Args>
auto where(Args... args)
-> vendor::update_policies_t<Derived, no_where_t, where_t<void, Args...>>
{
return { static_cast<Derived&>(*this), where_t<void, Args...>(args...) };
}
template<typename... Args>
auto dynamic_where(Args... args)
-> vendor::update_policies_t<Derived, no_where_t, where_t<get_database_t<Derived>, Args...>>
{
static_assert(not std::is_same<get_database_t<Derived>, void>::value, "dynamic_where must not be called in a static statement");
return { static_cast<Derived&>(*this), where_t<get_database_t<Derived>, Args...>(args...) };
}
};
// Interpreters
template<typename Context, typename Database, typename... Expressions>
struct interpreter_t<Context, where_t<Database, Expressions...>>
{
using T = where_t<Database, Expressions...>;
static Context& _(const T& t, Context& context)
{
if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty())
return context;
context << " WHERE ";
interpret_tuple(t._expressions, " AND ", context);
if (sizeof...(Expressions) and not t._dynamic_expressions.empty())
context << " AND ";
interpret_list(t._dynamic_expressions, " AND ", context);
return context;
}
};
template<typename Context>
@@ -98,12 +153,23 @@ namespace sqlpp
static Context& _(const T& t, Context& context)
{
if (not std::get<0>(t._condition))
if (not t._condition)
context << " WHERE NULL";
return context;
}
};
template<typename Context>
struct interpreter_t<Context, no_where_t>
{
using T = no_where_t;
static Context& _(const T& t, Context& context)
{
return context;
}
};
}
}

View File

@@ -60,7 +60,7 @@ int main()
interpret(insert_into(t), printer).flush();
interpret(insert_into(t).set(t.beta = "kirschauflauf"), printer).flush();
auto i = dynamic_insert_into(db, t).dynamic_set();
i = i.add_set(t.beta = "kirschauflauf");
i.add_set(t.beta = "kirschauflauf");
interpret(i, printer).flush();
return 0;

View File

@@ -44,15 +44,16 @@ int main()
test::TabBar t;
interpret(insert_into(t).columns(t.gamma, t.beta), printer).flush();
interpret(insert_into(t).columns(t.gamma, t.beta).add_values(t.gamma = true, t.beta = "cheesecake"), printer).flush();
interpret(insert_into(t).columns(t.gamma, t.beta)
.add_values(t.gamma = true, t.beta = "cheesecake")
.add_values(t.gamma = false, t.beta = sqlpp::tvin("coffee"))
.add_values(t.gamma = false, t.beta = sqlpp::tvin(std::string()))
, printer).flush();
interpret(insert_into(t).columns(t.gamma, t.beta)
.add_values(t.gamma = sqlpp::default_value, t.beta = sqlpp::null)
, printer).flush();
{
auto i = insert_into(t).columns(t.gamma, t.beta);
i.add_values(t.gamma = true, t.beta = "cheesecake");
interpret(i, printer).flush();
i.add_values(t.gamma = false, t.beta = sqlpp::tvin("coffee"));
i.add_values(t.gamma = false, t.beta = sqlpp::tvin(std::string()));
interpret(i, printer).flush();
i.add_values(t.gamma = sqlpp::default_value, t.beta = sqlpp::null);
interpret(i, printer).flush();
}
interpret(t.alpha = sqlpp::null, printer).flush();
interpret(t.alpha = sqlpp::default_value, printer).flush();
@@ -69,13 +70,16 @@ int main()
interpret(t.alpha == 7, printer).flush();
interpret(t.beta + "kaesekuchen", printer).flush();
interpret(select(sqlpp::distinct, t.alpha, t.beta), printer).flush();
interpret(select(sqlpp::distinct, t.alpha, t.beta).from(t), printer).flush();
interpret(select(sqlpp::distinct, t.alpha, t.beta).from(t).where(t.alpha == 3), printer).flush();
interpret(select(sqlpp::distinct, t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma), printer).flush();
interpret(select(sqlpp::distinct, t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")), printer).flush();
interpret(select(sqlpp::distinct, t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")).order_by(t.beta.asc()), printer).flush();
interpret(select(sqlpp::distinct, t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")).order_by(t.beta.asc()).limit(17).offset(3), printer).flush();
interpret(sqlpp::select(), printer).flush();
interpret(sqlpp::select().flags(sqlpp::distinct), printer).flush();
interpret(select(t.alpha, t.beta).flags(sqlpp::distinct), printer).flush();
interpret(select(t.alpha, t.beta), printer).flush();
interpret(select(t.alpha, t.beta).from(t), printer).flush();
interpret(select(t.alpha, t.beta).from(t).where(t.alpha == 3), printer).flush();
interpret(select(t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma), printer).flush();
interpret(select(t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")), printer).flush();
interpret(select(t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")).order_by(t.beta.asc()), printer).flush();
interpret(select(t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")).order_by(t.beta.asc()).limit(17).offset(3), printer).flush();
interpret(parameter(sqlpp::bigint(), t.alpha), printer).flush();
interpret(parameter(t.alpha), printer).flush();
@@ -92,6 +96,7 @@ int main()
interpret(update(t).set(t.gamma = true).where(t.beta.in("kaesekuchen", "cheesecake")), printer).flush();
interpret(remove_from(t), printer).flush();
interpret(remove_from(t).using_(t), printer).flush();
interpret(remove_from(t).where(t.alpha == sqlpp::tvin(0)), printer).flush();
interpret(remove_from(t).using_(t).where(t.alpha == sqlpp::tvin(0)), printer).flush();
@@ -123,11 +128,29 @@ int main()
// multi_column
interpret(multi_column(t.alpha, t.alpha, (t.beta + "cake").as(t.gamma)), printer).flush();
interpret(multi_column(t, all_of(t)), printer).flush();
// dynamic select
interpret(dynamic_select(db).dynamic_flags().dynamic_columns(t.alpha).add_column(t.beta).add_column(t.gamma), printer).flush();
interpret(dynamic_select(db).dynamic_flags().add_flag(sqlpp::distinct).dynamic_columns().add_column(t.gamma).add_column(t.beta), printer).flush();
interpret(dynamic_select(db).dynamic_flags(sqlpp::distinct).add_flag(sqlpp::all).dynamic_columns(t.alpha).add_column(t.beta), printer).flush();
{
auto s = dynamic_select(db).dynamic_flags().dynamic_columns();
s.add_column(t.beta);
s.add_column(t.gamma);
interpret(s, printer).flush();
}
{
auto s = dynamic_select(db).dynamic_flags().dynamic_columns();
s.add_flag(sqlpp::distinct);
s.add_column(t.beta);
s.add_column(t.gamma);
interpret(s, printer).flush();
}
{
auto s = dynamic_select(db).dynamic_flags(sqlpp::distinct).dynamic_columns(t.alpha);
s.add_flag(sqlpp::all);
s.add_column(t.beta);
s.add_column(t.gamma);
interpret(s, printer).flush();
}
// distinct aggregate
interpret(count(sqlpp::distinct, t.alpha % 7), printer).flush();
@@ -136,6 +159,5 @@ int main()
interpret(select(all_of(t)).from(t).where(true), printer).flush();
interpret(select(all_of(t)).from(t).where(false), printer).flush();
return 0;
}

View File

@@ -53,16 +53,16 @@ int main()
}
{
using T = decltype(dynamic_remove_from(db, t).dynamic_using_().dynamic_where());
using T = decltype(dynamic_remove_from(db, t).dynamic_using().dynamic_where());
static_assert(sqlpp::is_regular<T>::value, "type requirement");
}
interpret(remove_from(t), printer).flush();
interpret(remove_from(t).where(t.beta != "transparent"), printer).flush();
interpret(remove_from(t).using_(t), printer).flush();
auto r = dynamic_remove_from(db, t).dynamic_using_().dynamic_where();
r = r.add_using_(t);
r = r.add_where(t.beta != "transparent");
auto r = dynamic_remove_from(db, t).dynamic_using().dynamic_where();
r.add_using(t);
r.add_where(t.beta != "transparent");
interpret(r, printer).flush();
return 0;

View File

@@ -297,7 +297,6 @@ int main()
auto a = select(m).from(t).as(alias::b).a;
static_assert(not sqlpp::is_value_t<decltype(a)>::value, "a multi_column is not a value");
}
// Test that result sets with identical name/value combinations have identical types
{
auto a = select(t.alpha);
@@ -312,10 +311,10 @@ int main()
{
auto s = dynamic_select(db, all_of(t)).dynamic_from().dynamic_where().dynamic_limit().dynamic_offset();
s = s.add_from(t);
s = s.add_where(t.alpha > 7 and t.alpha == any(select(t.alpha).from(t).where(t.alpha < 3)));
s = s.set_limit(30);
s = s.set_limit(3);
s.add_from(t);
s.add_where(t.alpha > 7 and t.alpha == any(select(t.alpha).from(t).where(t.alpha < 3)));
s.set_limit(30);
s.set_limit(3);
std::cerr << "------------------------\n";
interpret(s, printer).flush();
std::cerr << "------------------------\n";
@@ -325,7 +324,8 @@ int main()
// Test that select can be called with zero columns if it is used with dynamic columns.
{
auto s = dynamic_select(db).dynamic_columns().add_column(t.alpha);
auto s = dynamic_select(db).dynamic_columns();
s.add_column(t.alpha);
interpret(s, printer).flush();
}
@@ -357,11 +357,11 @@ int main()
static_assert(sqlpp::is_named_expression_t<decltype(t.alpha)>::value, "alpha should be a named expression");
static_assert(sqlpp::is_named_expression_t<decltype(t.alpha.as(alias::a))>::value, "an alias of alpha should be a named expression");
static_assert(sqlpp::is_alias_t<decltype(t.alpha.as(alias::a))>::value, "an alias of alpha should be an alias");
auto z = select(t.alpha) == 7;
auto z = select(t.alpha).from(t) == 7;
auto l = t.as(alias::left);
auto r = select(t.gamma.as(alias::a)).from(t).where(t.gamma == true).as(alias::right);
static_assert(sqlpp::is_boolean_t<decltype(select(t.gamma).from(t))>::value, "select(bool) has to be a bool");
interpret(select(sqlpp::distinct, sqlpp::straight_join, l.alpha, l.beta, select(r.a).from(r))
interpret(sqlpp::select().flags(sqlpp::distinct, sqlpp::straight_join).columns(l.alpha, l.beta, select(r.a).from(r))
.from(l, r)
.where(t.beta == "hello world" and select(t.gamma).from(t))// .as(alias::right))
.group_by(l.gamma, r.a)

View File

@@ -59,7 +59,7 @@ int main()
interpret(update(t).set(t.gamma = false), printer).flush();
interpret(update(t).set(t.gamma = false).where(t.beta != "transparent"), printer).flush();
auto u = dynamic_update(db, t).dynamic_set(t.gamma = false).dynamic_where();
u = u.add_set(t.gamma = false);
u.add_set(t.gamma = false);
interpret(u, printer).flush();
return 0;