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

Migrated insert to generic statement

This commit is contained in:
rbock 2014-06-02 23:57:21 +02:00
parent 7e32a0a3ea
commit 8d16b6ab2d
7 changed files with 520 additions and 289 deletions

View File

@ -27,6 +27,7 @@
#ifndef SQLPP_INSERT_H #ifndef SQLPP_INSERT_H
#define SQLPP_INSERT_H #define SQLPP_INSERT_H
#include <sqlpp11/statement.h>
#include <sqlpp11/type_traits.h> #include <sqlpp11/type_traits.h>
#include <sqlpp11/parameter_list.h> #include <sqlpp11/parameter_list.h>
#include <sqlpp11/prepared_insert.h> #include <sqlpp11/prepared_insert.h>
@ -34,13 +35,10 @@
#include <sqlpp11/vendor/noop.h> #include <sqlpp11/vendor/noop.h>
#include <sqlpp11/vendor/single_table.h> #include <sqlpp11/vendor/single_table.h>
#include <sqlpp11/vendor/insert_value_list.h> #include <sqlpp11/vendor/insert_value_list.h>
#include <sqlpp11/vendor/policy_update.h>
#include <sqlpp11/detail/get_last.h>
#include <sqlpp11/detail/pick_arg.h>
namespace sqlpp namespace sqlpp
{ {
#if 0
template<typename Db, typename... Policies> template<typename Db, typename... Policies>
struct insert_t; struct insert_t;
@ -121,39 +119,6 @@ namespace sqlpp
insert_t& operator=(insert_t&&) = default; insert_t& operator=(insert_t&&) = default;
~insert_t() = default; ~insert_t() = default;
// run and prepare
static constexpr size_t _get_static_no_of_parameters()
{
return _parameter_list_t::size::value;
}
size_t _get_no_of_parameters() const
{
return _parameter_list_t::size::value;
}
void _check_consistency() const
{
// FIXME: Read up on what is allowed/prohibited in INSERT
}
template<typename Database>
std::size_t _run(Database& db) const
{
_check_consistency();
static_assert(_get_static_no_of_parameters() == 0, "cannot run insert directly with parameters, use prepare instead");
return db.insert(*this);
}
template<typename Database>
auto _prepare(Database& db) const
-> prepared_insert_t<Database, insert_t>
{
_check_consistency();
return {{}, db.prepare_insert(*this)};
}
}; };
namespace vendor namespace vendor
@ -173,13 +138,14 @@ namespace sqlpp
} }
}; };
} }
#endif
template<typename Database> template<typename Database>
using blank_insert_t = insert_t<Database, using blank_insert_t = statement_t<Database,
vendor::no_single_table_t, vendor::no_single_table_t,
vendor::no_insert_value_list_t>; vendor::no_insert_value_list_t>;
constexpr auto insert() auto insert()
-> blank_insert_t<void> -> blank_insert_t<void>
{ {
return { blank_insert_t<void>() }; return { blank_insert_t<void>() };

View File

@ -27,9 +27,7 @@
#ifndef SQLPP_SELECT_H #ifndef SQLPP_SELECT_H
#define SQLPP_SELECT_H #define SQLPP_SELECT_H
#include <sqlpp11/result.h> #include <sqlpp11/statement.h>
#include <sqlpp11/parameter_list.h>
#include <sqlpp11/prepared_select.h>
#include <sqlpp11/vendor/noop.h> #include <sqlpp11/vendor/noop.h>
#include <sqlpp11/vendor/select_flag_list.h> #include <sqlpp11/vendor/select_flag_list.h>
@ -43,165 +41,13 @@
#include <sqlpp11/vendor/limit.h> #include <sqlpp11/vendor/limit.h>
#include <sqlpp11/vendor/offset.h> #include <sqlpp11/vendor/offset.h>
#include <sqlpp11/vendor/expression.h> #include <sqlpp11/vendor/expression.h>
#include <sqlpp11/vendor/serializer.h>
#include <sqlpp11/vendor/wrong.h> #include <sqlpp11/vendor/wrong.h>
#include <sqlpp11/vendor/policy_update.h>
#include <sqlpp11/detail/get_last.h>
#include <sqlpp11/detail/pick_arg.h>
namespace sqlpp namespace sqlpp
{ {
template<typename Db, typename... Policies>
struct select_t;
#warning STEPS:
#warning deal with different return types in the connector (select could be a single value, update could be a range of rows)
namespace detail
{
template<typename Db = void, typename... Policies>
struct select_policies_t
{
#warning need to check policies' signature, e.g. a _data_t in _member_t template
using _database_t = Db;
using _statement_t = select_t<Db, Policies...>;
struct _methods_t: public Policies::template _methods_t<select_policies_t>...
{};
template<typename Needle, typename Replacement>
struct _policies_update_t
{
static_assert(detail::is_element_of<Needle, make_type_set_t<Policies...>>::value, "policies update for non-policy class detected");
using type = select_t<Db, vendor::policy_update_t<Policies, Needle, Replacement>...>;
};
template<typename Needle, typename Replacement>
using _new_statement_t = typename _policies_update_t<Needle, Replacement>::type;
using _all_required_tables = detail::make_joined_set_t<required_tables_of<Policies>...>;
using _all_provided_tables = detail::make_joined_set_t<provided_tables_of<Policies>...>;
using _all_extra_tables = detail::make_joined_set_t<extra_tables_of<Policies>...>;
using _known_tables = detail::make_joined_set_t<_all_provided_tables, _all_extra_tables>;
template<typename Expression>
using _no_unknown_tables = detail::is_subset_of<required_tables_of<Expression>, _known_tables>;
// The tables not covered by the from.
using _required_tables = detail::make_difference_set_t<
_all_required_tables,
_all_provided_tables // Hint: extra_tables are not used here because they are just a helper for dynamic .add_*()
>;
using _result_type_provider = detail::get_last_if<is_return_value_t, vendor::noop, Policies...>;
struct _result_methods_t: public _result_type_provider::template _result_methods_t<select_policies_t>
{};
// A select can be used as a pseudo table if
// - at least one column is selected
// - the select is complete (leaks no tables)
using _can_be_used_as_table = typename std::conditional<
is_select_column_list_t<_result_type_provider>::value and _required_tables::size::value == 0,
std::true_type,
std::false_type
>::type;
using _value_type = typename std::conditional<
detail::none_t<is_missing_t<Policies>::value...>::value,
value_type_of<_result_type_provider>,
no_value_t // if a required statement part is missing (e.g. columns in a select), then the statement cannot be used as a value
>::type;
using _is_expression = typename std::conditional<
std::is_same<_value_type, no_value_t>::value,
std::false_type,
std::true_type>::type;
using _traits = make_traits<_value_type>;
struct _recursive_traits
{
using _parameters = std::tuple<>; // FIXME
using _required_tables = _required_tables;
using _provided_tables = detail::type_set<>;
using _extra_tables = detail::type_set<>;
};
static void _check_consistency()
{
#warning check for missing terms here, and for missing tables
static_assert(not required_tables_of<select_policies_t>::size::value, "one sub expression requires tables which are otherwise not known in the statement");
}
};
}
// SELECT
template<typename Db,
typename... Policies
>
struct select_t:
public Policies::template _member_t<detail::select_policies_t<Db, Policies...>>...,
public detail::select_policies_t<Db, Policies...>::_value_type::template expression_operators<select_t<Db, Policies...>>,
public detail::select_policies_t<Db, Policies...>::_result_methods_t,
public detail::select_policies_t<Db, Policies...>::_methods_t
{
using _policies_t = typename detail::select_policies_t<Db, Policies...>;
using _traits = make_traits<value_type_of<_policies_t>, ::sqlpp::tag::select, tag::expression_if<typename _policies_t::_is_expression>, tag::named_expression_if<typename _policies_t::_is_expression>>;
using _recursive_traits = typename _policies_t::_recursive_traits;
using _result_type_provider = typename _policies_t::_result_type_provider;
using _requires_braces = std::true_type;
using _name_t = typename _result_type_provider::_name_t;
// Constructors
select_t()
{}
template<typename Statement, typename Term>
select_t(Statement statement, Term term):
Policies::template _member_t<_policies_t>{
typename Policies::template _impl_t<_policies_t>{
detail::pick_arg<typename Policies::template _member_t<_policies_t>>(statement, term)
}}...
//Policies::template _member_t<_policies_t>{{detail::pick_arg<typename Policies::template _member_t<_policies_t>>(statement, term)}}...
{}
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;
};
namespace vendor
{
template<typename Context, typename Database, typename... Policies>
struct serializer_t<Context, select_t<Database, Policies...>>
{
using T = select_t<Database, Policies...>;
using P = ::sqlpp::detail::select_policies_t<Database, Policies...>;
static Context& _(const T& t, Context& context)
{
context << "SELECT ";
using swallow = int[];
(void) swallow{(serialize(static_cast<const typename Policies::template _member_t<P>&>(t)()._data, context), 0)...};
return context;
}
};
}
template<typename Database> template<typename Database>
using blank_select_t = select_t<Database, using blank_select_t = statement_t<Database,
vendor::no_select_flag_list_t, vendor::no_select_flag_list_t,
vendor::no_select_column_list_t, vendor::no_select_column_list_t,
vendor::no_from_t, vendor::no_from_t,

193
include/sqlpp11/statement.h Normal file
View File

@ -0,0 +1,193 @@
/*
* Copyright (c) 2013-2014, 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_STATEMENT_H
#define SQLPP_STATEMENT_H
#include <sqlpp11/result.h>
#include <sqlpp11/parameter_list.h>
#include <sqlpp11/prepared_select.h>
#include <sqlpp11/vendor/policy_update.h>
#include <sqlpp11/vendor/serializer.h>
#include <sqlpp11/detail/get_last.h>
#include <sqlpp11/detail/pick_arg.h>
namespace sqlpp
{
template<typename Db, typename... Policies>
struct statement_t;
#warning STEPS:
#warning deal with different return types in the connector (select could be a single value, update could be a range of rows)
namespace detail
{
template<typename Db = void, typename... Policies>
struct statement_policies_t
{
#warning need to check policies' signature, e.g. a _data_t in _member_t template
using _database_t = Db;
using _statement_t = statement_t<Db, Policies...>;
struct _methods_t: public Policies::template _methods_t<statement_policies_t>...
{};
template<typename Needle, typename Replacement>
struct _policies_update_t
{
static_assert(detail::is_element_of<Needle, make_type_set_t<Policies...>>::value, "policies update for non-policy class detected");
using type = statement_t<Db, vendor::policy_update_t<Policies, Needle, Replacement>...>;
};
template<typename Needle, typename Replacement>
using _new_statement_t = typename _policies_update_t<Needle, Replacement>::type;
using _all_required_tables = detail::make_joined_set_t<required_tables_of<Policies>...>;
using _all_provided_tables = detail::make_joined_set_t<provided_tables_of<Policies>...>;
using _all_extra_tables = detail::make_joined_set_t<extra_tables_of<Policies>...>;
using _known_tables = detail::make_joined_set_t<_all_provided_tables, _all_extra_tables>;
template<typename Expression>
using _no_unknown_tables = detail::is_subset_of<required_tables_of<Expression>, _known_tables>;
// The tables not covered by the from.
using _required_tables = detail::make_difference_set_t<
_all_required_tables,
_all_provided_tables // Hint: extra_tables are not used here because they are just a helper for dynamic .add_*()
>;
using _result_type_provider = detail::get_last_if<is_return_value_t, vendor::noop, Policies...>;
struct _result_methods_t: public _result_type_provider::template _result_methods_t<statement_policies_t>
{};
// A select can be used as a pseudo table if
// - at least one column is selected
// - the select is complete (leaks no tables)
using _can_be_used_as_table = typename std::conditional<
is_select_column_list_t<_result_type_provider>::value and _required_tables::size::value == 0,
std::true_type,
std::false_type
>::type;
using _value_type = typename std::conditional<
detail::none_t<is_missing_t<Policies>::value...>::value,
value_type_of<_result_type_provider>,
no_value_t // if a required statement part is missing (e.g. columns in a select), then the statement cannot be used as a value
>::type;
using _is_expression = typename std::conditional<
std::is_same<_value_type, no_value_t>::value,
std::false_type,
std::true_type>::type;
using _traits = make_traits<_value_type>;
struct _recursive_traits
{
using _parameters = std::tuple<>; // FIXME
using _required_tables = _required_tables;
using _provided_tables = detail::type_set<>;
using _extra_tables = detail::type_set<>;
};
static void _check_consistency()
{
#warning check for missing terms here, and for missing tables
static_assert(not required_tables_of<statement_policies_t>::size::value, "one sub expression requires tables which are otherwise not known in the statement");
}
};
}
// SELECT
template<typename Db,
typename... Policies
>
struct statement_t:
public Policies::template _member_t<detail::statement_policies_t<Db, Policies...>>...,
public detail::statement_policies_t<Db, Policies...>::_value_type::template expression_operators<statement_t<Db, Policies...>>,
public detail::statement_policies_t<Db, Policies...>::_result_methods_t,
public detail::statement_policies_t<Db, Policies...>::_methods_t
{
using _policies_t = typename detail::statement_policies_t<Db, Policies...>;
using _traits = make_traits<value_type_of<_policies_t>, ::sqlpp::tag::select, tag::expression_if<typename _policies_t::_is_expression>, tag::named_expression_if<typename _policies_t::_is_expression>>;
using _recursive_traits = typename _policies_t::_recursive_traits;
using _result_type_provider = typename _policies_t::_result_type_provider;
using _requires_braces = std::true_type;
using _name_t = typename _result_type_provider::_name_t;
// Constructors
statement_t()
{}
template<typename Statement, typename Term>
statement_t(Statement statement, Term term):
Policies::template _member_t<_policies_t>{
typename Policies::template _impl_t<_policies_t>{
detail::pick_arg<typename Policies::template _member_t<_policies_t>>(statement, term)
}}...
//Policies::template _member_t<_policies_t>{{detail::pick_arg<typename Policies::template _member_t<_policies_t>>(statement, term)}}...
{}
statement_t(const statement_t& r) = default;
statement_t(statement_t&& r) = default;
statement_t& operator=(const statement_t& r) = default;
statement_t& operator=(statement_t&& r) = default;
~statement_t() = default;
};
namespace vendor
{
template<typename Context, typename Database, typename... Policies>
struct serializer_t<Context, statement_t<Database, Policies...>>
{
using T = statement_t<Database, Policies...>;
using P = ::sqlpp::detail::statement_policies_t<Database, Policies...>;
static Context& _(const T& t, Context& context)
{
#warning: Need to have a class that provides the "SELECT" or "INSERT", etc
context << "SELECT ";
using swallow = int[];
(void) swallow{(serialize(static_cast<const typename Policies::template _member_t<P>&>(t)()._data, context), 0)...};
return context;
}
};
}
}
#endif

View File

@ -39,17 +39,69 @@ namespace sqlpp
{ {
namespace vendor namespace vendor
{ {
struct insert_default_values_data_t
{};
// COLUMN AND VALUE LIST // COLUMN AND VALUE LIST
struct insert_default_values_t struct insert_default_values_t
{ {
using _traits = make_traits<no_value_t>; using _traits = make_traits<no_value_t>;
using _recursive_traits = make_recursive_traits<>; using _recursive_traits = make_recursive_traits<>;
// Data
using _data_t = insert_default_values_data_t;
// Member implementation with data and methods
template<typename Policies>
struct _impl_t
{
_data_t _data;
};
// Member template for adding the named member to a statement
template<typename Policies>
struct _member_t
{
using _data_t = insert_default_values_data_t;
_impl_t<Policies> default_values;
_impl_t<Policies>& operator()() { return default_values; }
const _impl_t<Policies>& operator()() const { return default_values; }
template<typename T>
static auto _get_member(T t) -> decltype(t.default_values)
{
return t.default_values;
}
};
template<typename Policies> template<typename Policies>
struct _methods_t struct _methods_t
{}; {};
}; };
template<typename Database, typename... Assignments>
struct insert_list_data_t
{
insert_list_data_t(Assignments... assignments):
_assignments(assignments...),
_columns({assignments._lhs}...),
_values(assignments._rhs...)
{}
insert_list_data_t(const insert_list_data_t&) = default;
insert_list_data_t(insert_list_data_t&&) = default;
insert_list_data_t& operator=(const insert_list_data_t&) = default;
insert_list_data_t& operator=(insert_list_data_t&&) = default;
~insert_list_data_t() = default;
std::tuple<simple_column_t<typename Assignments::_column_t>...> _columns;
std::tuple<typename Assignments::_value_t...> _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 Database, typename... Assignments> template<typename Database, typename... Assignments>
struct insert_list_t struct insert_list_t
{ {
@ -81,36 +133,26 @@ namespace sqlpp
static_assert(::sqlpp::detail::is_subset_of<_value_required_tables, _column_required_tables>::value, "set() contains values from foreign tables"); static_assert(::sqlpp::detail::is_subset_of<_value_required_tables, _column_required_tables>::value, "set() contains values from foreign tables");
*/ */
insert_list_t& _insert_value_list() { return *this; } // Data
using _data_t = insert_list_data_t<Database, Assignments...>;
insert_list_t(Assignments... assignment): // Member implementation with data and methods
_assignments(assignment...), template <typename Policies>
_columns({assignment._lhs}...), struct _impl_t
_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 Policies>
struct _methods_t
{ {
template<typename Assignment> template<typename Assignment>
void add_set_ntc(Assignment assignment) void add_ntc(Assignment assignment)
{ {
add_set<Assignment, std::false_type>(assignment); add<Assignment, std::false_type>(assignment);
} }
template<typename Assignment, typename TableCheckRequired = std::true_type> template<typename Assignment, typename TableCheckRequired = std::true_type>
void add_set(Assignment assignment) void add(Assignment assignment)
{ {
static_assert(_is_dynamic::value, "add_set must not be called for static from()"); static_assert(_is_dynamic::value, "add must not be called for static from()");
static_assert(is_assignment_t<Assignment>::value, "add_set() arguments require to be assigments"); static_assert(is_assignment_t<Assignment>::value, "add() arguments require to be assigments");
static_assert(not must_not_insert_t<typename Assignment::_column_t>::value, "add_set() argument must not be used in insert"); static_assert(not must_not_insert_t<typename Assignment::_column_t>::value, "add() argument must not be used in insert");
static_assert(not TableCheckRequired::value or Policies::template _no_unknown_tables<Assignment>::value, "add_set() contains a column from a foreign table"); static_assert(not TableCheckRequired::value or Policies::template _no_unknown_tables<Assignment>::value, "add() contains a column from a foreign table");
using ok = ::sqlpp::detail::all_t< using ok = ::sqlpp::detail::all_t<
_is_dynamic::value, _is_dynamic::value,
@ -118,28 +160,67 @@ namespace sqlpp
not must_not_insert_t<typename Assignment::_column_t>::value, not must_not_insert_t<typename Assignment::_column_t>::value,
(not TableCheckRequired::value or Policies::template _no_unknown_tables<Assignment>::value)>; (not TableCheckRequired::value or Policies::template _no_unknown_tables<Assignment>::value)>;
_add_set_impl(assignment, ok()); // dispatch to prevent compile messages after the static_assert _add_impl(assignment, ok()); // dispatch to prevent compile messages after the static_assert
} }
private: private:
template<typename Assignment> template<typename Assignment>
void _add_set_impl(Assignment assignment, const std::true_type&) void _add_impl(Assignment assignment, const std::true_type&)
{ {
static_cast<typename Policies::_statement_t*>(this)->_insert_value_list()._dynamic_columns.emplace_back(simple_column_t<typename Assignment::_column_t>{assignment._lhs}); _data._dynamic_columns.emplace_back(simple_column_t<typename Assignment::_column_t>{assignment._lhs});
static_cast<typename Policies::_statement_t*>(this)->_insert_value_list()._dynamic_values.emplace_back(assignment._rhs); _data._dynamic_values.emplace_back(assignment._rhs);
} }
template<typename Assignment> template<typename Assignment>
void _add_set_impl(Assignment assignment, const std::false_type&); void _add_impl(Assignment assignment, const std::false_type&);
public:
_data_t _data;
};
// Member template for adding the named member to a statement
template<typename Policies>
struct _member_t
{
using _data_t = insert_list_data_t<Database, Assignments...>;
_impl_t<Policies> insert_list;
_impl_t<Policies>& operator()() { return insert_list; }
const _impl_t<Policies>& operator()() const { return insert_list; }
template<typename T>
static auto _get_member(T t) -> decltype(t.insert_list)
{
return t.insert_list;
}
};
// Additional methods for the statement
template<typename Policies>
struct _methods_t
{
}; };
std::tuple<simple_column_t<typename Assignments::_column_t>...> _columns; };
std::tuple<typename Assignments::_value_t...> _values;
std::tuple<Assignments...> _assignments; // FIXME: Need to replace _columns and _values by _assignments (connector-container requires assignments) template<typename... Columns>
typename vendor::interpretable_list_t<Database> _dynamic_columns; struct column_list_data_t
typename vendor::interpretable_list_t<Database> _dynamic_values; {
column_list_data_t(Columns... columns):
_columns(simple_column_t<Columns>{columns}...)
{}
column_list_data_t(const column_list_data_t&) = default;
column_list_data_t(column_list_data_t&&) = default;
column_list_data_t& operator=(const column_list_data_t&) = default;
column_list_data_t& operator=(column_list_data_t&&) = default;
~column_list_data_t() = default;
#warning need to define just one version of value_tuple_t
using _value_tuple_t = std::tuple<vendor::insert_value_t<Columns>...>;
std::tuple<simple_column_t<Columns>...> _columns;
std::vector<_value_tuple_t> _insert_values;
}; };
template<typename... Columns> template<typename... Columns>
@ -160,23 +241,15 @@ namespace sqlpp
static_assert(required_tables_of<column_list_t>::size::value == 1, "columns from multiple tables in columns()"); static_assert(required_tables_of<column_list_t>::size::value == 1, "columns from multiple tables in columns()");
column_list_t& _insert_value_list() { return *this; } // Data
using _data_t = column_list_data_t<Columns...>;
column_list_t(Columns... columns): // Member implementation with data and methods
_columns(simple_column_t<Columns>{columns}...) template <typename Policies>
{} struct _impl_t
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;
template<typename Policies>
struct _methods_t
{ {
template<typename... Assignments> template<typename... Assignments>
void add_values(Assignments... assignments) void add(Assignments... assignments)
{ {
static_assert(::sqlpp::detail::all_t<is_assignment_t<Assignments>::value...>::value, "add_values() arguments have to be assignments"); static_assert(::sqlpp::detail::all_t<is_assignment_t<Assignments>::value...>::value, "add_values() arguments have to be assignments");
using _arg_value_tuple = std::tuple<vendor::insert_value_t<typename Assignments::_column_t>...>; using _arg_value_tuple = std::tuple<vendor::insert_value_t<typename Assignments::_column_t>...>;
@ -187,35 +260,87 @@ namespace sqlpp
::sqlpp::detail::all_t<is_assignment_t<Assignments>::value...>::value, ::sqlpp::detail::all_t<is_assignment_t<Assignments>::value...>::value,
_args_correct::value>; _args_correct::value>;
_add_values_impl(ok(), assignments...); // dispatch to prevent compile messages after the static_assert _add_impl(ok(), assignments...); // dispatch to prevent compile messages after the static_assert
} }
private: private:
template<typename... Assignments> template<typename... Assignments>
void _add_values_impl(const std::true_type&, Assignments... assignments) void _add_impl(const std::true_type&, Assignments... assignments)
{ {
return static_cast<typename Policies::_statement_t*>(this)->_insert_value_list()._insert_values.emplace_back(vendor::insert_value_t<typename Assignments::_column_t>{assignments}...); return _data._insert_values.emplace_back(vendor::insert_value_t<typename Assignments::_column_t>{assignments}...);
} }
template<typename... Assignments> template<typename... Assignments>
void _add_values_impl(const std::false_type&, Assignments... assignments); void _add_impl(const std::false_type&, Assignments... assignments);
public:
_data_t _data;
}; };
// Member template for adding the named member to a statement
template<typename Policies>
struct _member_t
{
using _data_t = column_list_data_t<Columns...>;
_impl_t<Policies> column_list;
_impl_t<Policies>& operator()() { return column_list; }
const _impl_t<Policies>& operator()() const { return column_list; }
template<typename T>
static auto _get_member(T t) -> decltype(t.column_list)
{
return t.column_list;
}
};
// Additional methods for the statement
template<typename Policies>
struct _methods_t
{
};
/*
bool empty() const bool empty() const
{ {
return _insert_values.empty(); return _insert_values.empty();
} }
*/
std::tuple<simple_column_t<Columns>...> _columns;
std::vector<_value_tuple_t> _insert_values;
}; };
// NO HAVING YET
struct no_insert_value_list_t struct no_insert_value_list_t
{ {
using _traits = make_traits<no_value_t, ::sqlpp::tag::noop>; using _traits = make_traits<no_value_t, ::sqlpp::tag::noop>;
using _recursive_traits = make_recursive_traits<>; using _recursive_traits = make_recursive_traits<>;
// Data
using _data_t = no_data_t;
// Member implementation with data and methods
template<typename Policies>
struct _impl_t
{
_data_t _data;
};
// Member template for adding the named member to a statement
template<typename Policies>
struct _member_t
{
using _data_t = no_data_t;
_impl_t<Policies> no_insert_values;
_impl_t<Policies>& operator()() { return no_insert_values; }
const _impl_t<Policies>& operator()() const { return no_insert_values; }
template<typename T>
static auto _get_member(T t) -> decltype(t.no_insert_values)
{
return t.no_insert_values;
}
};
template<typename Policies> template<typename Policies>
struct _methods_t struct _methods_t
{ {
@ -226,21 +351,21 @@ namespace sqlpp
auto default_values() auto default_values()
-> _new_statement_t<insert_default_values_t> -> _new_statement_t<insert_default_values_t>
{ {
return { *static_cast<typename Policies::_statement_t*>(this), insert_default_values_t{} }; return { *static_cast<typename Policies::_statement_t*>(this), insert_default_values_data_t{} };
} }
template<typename... Args> template<typename... Args>
auto columns(Args... args) auto columns(Args... args)
-> _new_statement_t<column_list_t<Args...>> -> _new_statement_t<column_list_t<Args...>>
{ {
return { *static_cast<typename Policies::_statement_t*>(this), column_list_t<Args...>{args...} }; return { *static_cast<typename Policies::_statement_t*>(this), column_list_data_t<Args...>{args...} };
} }
template<typename... Args> template<typename... Args>
auto set(Args... args) auto set(Args... args)
-> _new_statement_t<insert_list_t<void, Args...>> -> _new_statement_t<insert_list_t<void, Args...>>
{ {
return { *static_cast<typename Policies::_statement_t*>(this), insert_list_t<void, Args...>{args...} }; return { *static_cast<typename Policies::_statement_t*>(this), insert_list_data_t<void, Args...>{args...} };
} }
template<typename... Args> template<typename... Args>
@ -248,16 +373,16 @@ namespace sqlpp
-> _new_statement_t<insert_list_t<_database_t, Args...>> -> _new_statement_t<insert_list_t<_database_t, Args...>>
{ {
static_assert(not std::is_same<_database_t, void>::value, "dynamic_set must not be called in a static statement"); static_assert(not std::is_same<_database_t, void>::value, "dynamic_set must not be called in a static statement");
return { *static_cast<typename Policies::_statement_t*>(this), vendor::insert_list_t<_database_t, Args...>{args...} }; return { *static_cast<typename Policies::_statement_t*>(this), vendor::insert_list_data_t<_database_t, Args...>{args...} };
} }
}; };
}; };
// Interpreters // Interpreters
template<typename Context> template<typename Context>
struct serializer_t<Context, insert_default_values_t> struct serializer_t<Context, insert_default_values_data_t>
{ {
using T = insert_default_values_t; using T = insert_default_values_data_t;
static Context& _(const T& t, Context& context) static Context& _(const T& t, Context& context)
{ {
@ -267,9 +392,9 @@ namespace sqlpp
}; };
template<typename Context, typename... Columns> template<typename Context, typename... Columns>
struct serializer_t<Context, column_list_t<Columns...>> struct serializer_t<Context, column_list_data_t<Columns...>>
{ {
using T = column_list_t<Columns...>; using T = column_list_data_t<Columns...>;
static Context& _(const T& t, Context& context) static Context& _(const T& t, Context& context)
{ {
@ -294,15 +419,15 @@ namespace sqlpp
}; };
template<typename Context, typename Database, typename... Assignments> template<typename Context, typename Database, typename... Assignments>
struct serializer_t<Context, insert_list_t<Database, Assignments...>> struct serializer_t<Context, insert_list_data_t<Database, Assignments...>>
{ {
using T = insert_list_t<Database, Assignments...>; using T = insert_list_data_t<Database, Assignments...>;
static Context& _(const T& t, Context& context) static Context& _(const T& t, Context& context)
{ {
if (sizeof...(Assignments) + t._dynamic_columns.size() == 0) if (sizeof...(Assignments) + t._dynamic_columns.size() == 0)
{ {
serialize(insert_default_values_t(), context); serialize(insert_default_values_data_t(), context);
} }
else else
{ {
@ -322,17 +447,6 @@ namespace sqlpp
} }
}; };
template<typename Context>
struct serializer_t<Context, no_insert_value_list_t>
{
using T = no_insert_value_list_t;
static Context& _(const T& t, Context& context)
{
return context;
}
};
} }
} }

View File

@ -36,39 +36,151 @@ namespace sqlpp
{ {
namespace vendor namespace vendor
{ {
// A SINGLE TABLE DATA
template<typename Database, typename Table>
struct single_table_data_t
{
single_table_data_t(Table table):
_table(table)
{}
single_table_data_t(const single_table_data_t&) = default;
single_table_data_t(single_table_data_t&&) = default;
single_table_data_t& operator=(const single_table_data_t&) = default;
single_table_data_t& operator=(single_table_data_t&&) = default;
~single_table_data_t() = default;
Table _table;
};
// A SINGLE TABLE // A SINGLE TABLE
template<typename Database, typename Table> template<typename Database, typename Table>
struct single_table_t struct single_table_t
{ {
using _traits = make_traits<no_value_t, ::sqlpp::tag::single_table>; using _traits = make_traits<no_value_t, ::sqlpp::tag::single_table, tag::return_value>;
using _recursive_traits = make_recursive_traits<Table>; using _recursive_traits = make_recursive_traits<Table>;
static_assert(is_table_t<Table>::value, "argument has to be a table"); static_assert(is_table_t<Table>::value, "argument has to be a table");
static_assert(required_tables_of<Table>::size::value == 0, "table depends on another table"); static_assert(required_tables_of<Table>::size::value == 0, "table depends on another table");
single_table_t(Table table): using _data_t = single_table_data_t<Database, Table>;
_table(table)
{}
single_table_t(const single_table_t&) = default; struct _name_t {};
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;
// Member implementation with data and methods
template <typename Policies>
struct _impl_t
{
_data_t _data;
};
// Member template for adding the named member to a statement
template<typename Policies>
struct _member_t
{
using _data_t = single_table_data_t<Database, Table>;
_impl_t<Policies> into;
_impl_t<Policies>& operator()() { return into; }
const _impl_t<Policies>& operator()() const { return into; }
template<typename T>
static auto _get_member(T t) -> decltype(t.into)
{
return t.into;
}
};
// Additional methods for the statement
template<typename Policies> template<typename Policies>
struct _methods_t struct _methods_t
{ {
}; };
Table _table; template<typename Policies>
struct _result_methods_t
{
using _statement_t = typename Policies::_statement_t;
const _statement_t& _get_statement() const
{
return static_cast<const _statement_t&>(*this);
}
static constexpr size_t _get_static_no_of_parameters()
{
#warning need to fix this
return 0;
//return _parameter_list_t::size::value;
}
size_t _get_no_of_parameters() const
{
#warning need to fix this
return 0;
//return _parameter_list_t::size::value;
}
void _check_consistency() const
{
// FIXME: Read up on what is allowed/prohibited in INSERT
}
template<typename Db>
auto _run(Db& db) const -> decltype(db.insert(_get_statement()))
{
_check_consistency();
static_assert(_get_static_no_of_parameters() == 0, "cannot run insert directly with parameters, use prepare instead");
return db.insert(*this);
}
/*
template<typename Db>
auto _prepare(Db& db) const
-> prepared_insert_t<Db, insert_t>
{
_check_consistency();
return {{}, db.prepare_insert(*this)};
}
*/
};
}; };
// NO INTO YET
struct no_single_table_t struct no_single_table_t
{ {
using _traits = make_traits<no_value_t, ::sqlpp::tag::noop>; using _traits = make_traits<no_value_t, ::sqlpp::tag::noop>;
using _recursive_traits = make_recursive_traits<>; using _recursive_traits = make_recursive_traits<>;
// Data
using _data_t = no_data_t;
// Member implementation with data and methods
template<typename Policies>
struct _impl_t
{
_data_t _data;
};
// Member template for adding the named member to a statement
template<typename Policies>
struct _member_t
{
using _data_t = no_data_t;
_impl_t<Policies> no_into;
_impl_t<Policies>& operator()() { return no_into; }
const _impl_t<Policies>& operator()() const { return no_into; }
template<typename T>
static auto _get_member(T t) -> decltype(t.no_into)
{
return t.no_into;
}
};
template<typename Policies> template<typename Policies>
struct _methods_t struct _methods_t
{ {
@ -80,7 +192,7 @@ namespace sqlpp
auto into(Args... args) auto into(Args... args)
-> _new_statement_t<single_table_t<void, Args...>> -> _new_statement_t<single_table_t<void, Args...>>
{ {
return { *static_cast<typename Policies::_statement_t*>(this), single_table_t<void, Args...>{args...} }; return { *static_cast<typename Policies::_statement_t*>(this), single_table_data_t<void, Args...>{args...} };
} }
#warning: remove can operate on several tables at once, so it should not use single_table anyway #warning: remove can operate on several tables at once, so it should not use single_table anyway
@ -88,16 +200,16 @@ namespace sqlpp
auto from(Args... args) auto from(Args... args)
-> _new_statement_t<single_table_t<void, Args...>> -> _new_statement_t<single_table_t<void, Args...>>
{ {
return { *static_cast<typename Policies::_statement_t*>(this), single_table_t<void, Args...>{args...} }; return { *static_cast<typename Policies::_statement_t*>(this), single_table_data_t<void, Args...>{args...} };
} }
}; };
}; };
// Interpreters // Interpreters
template<typename Context, typename Database, typename Table> template<typename Context, typename Database, typename Table>
struct serializer_t<Context, single_table_t<Database, Table>> struct serializer_t<Context, single_table_data_t<Database, Table>>
{ {
using T = single_table_t<Database, Table>; using T = single_table_data_t<Database, Table>;
static Context& _(const T& t, Context& context) static Context& _(const T& t, Context& context)
{ {

View File

@ -7,11 +7,11 @@ macro (build_and_run arg)
endmacro () endmacro ()
#build_and_run(InterpretTest) #build_and_run(InterpretTest)
#build_and_run(InsertTest) build_and_run(InsertTest)
#build_and_run(RemoveTest) #build_and_run(RemoveTest)
#build_and_run(UpdateTest) #build_and_run(UpdateTest)
#build_and_run(SelectTest) #build_and_run(SelectTest)
build_and_run(SelectTypeTest) #build_and_run(SelectTypeTest)
#build_and_run(FunctionTest) #build_and_run(FunctionTest)
#build_and_run(PreparedTest) #build_and_run(PreparedTest)

View File

@ -67,10 +67,10 @@ int main()
serialize(insert_into(t).set(t.beta = "kirschauflauf"), printer).str(); serialize(insert_into(t).set(t.beta = "kirschauflauf"), printer).str();
serialize(insert_into(t).columns(t.beta), printer).str(); serialize(insert_into(t).columns(t.beta), printer).str();
auto multi_insert = insert_into(t).columns(t.beta, t.delta); auto multi_insert = insert_into(t).columns(t.beta, t.delta);
multi_insert.add_values(t.beta = "cheesecake", t.delta = 1); multi_insert.column_list.add(t.beta = "cheesecake", t.delta = 1);
multi_insert.add_values(t.beta = sqlpp::default_value, t.delta = sqlpp::default_value); multi_insert.column_list.add(t.beta = sqlpp::default_value, t.delta = sqlpp::default_value);
auto i = dynamic_insert_into(db, t).dynamic_set(); auto i = dynamic_insert_into(db, t).dynamic_set();
i.add_set(t.beta = "kirschauflauf"); i.insert_list.add(t.beta = "kirschauflauf");
serialize(i, printer).str(); serialize(i, printer).str();
db(multi_insert); db(multi_insert);