Merge branch 'feature/custom_query' into develop

This commit is contained in:
rbock
2014-11-09 16:29:40 +01:00
19 changed files with 626 additions and 54 deletions

View File

@@ -0,0 +1,137 @@
/*
* 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_CUSTOM_QUERY_H
#define SQLPP_CUSTOM_QUERY_H
#include <sqlpp11/connection.h>
#include <sqlpp11/interpret_tuple.h>
#include <sqlpp11/hidden.h>
#include <sqlpp11/detail/get_first.h>
namespace sqlpp
{
template<typename Database, typename... Parts>
struct custom_query_t;
namespace detail
{
template<typename Db, typename... Parts>
struct custom_parts_t
{
using _custom_query_t = custom_query_t<Db, Parts...>;
using _result_type_provider = detail::get_first_if<is_return_value_t, noop, Parts...>;
using _result_methods_t = typename _result_type_provider::template _result_methods_t<_result_type_provider>;
};
}
template<typename Database, typename... Parts>
struct custom_query_t:
private detail::custom_parts_t<Database, Parts...>::_result_methods_t
{
using _methods_t = typename detail::custom_parts_t<Database, Parts...>::_result_methods_t;
using _traits = make_traits<no_value_t>;
using _recursive_traits = make_recursive_traits<Parts...>;
custom_query_t(Parts... parts):
_parts(parts...)
{}
custom_query_t(std::tuple<Parts...> parts):
_parts(parts)
{}
custom_query_t(const custom_query_t&) = default;
custom_query_t(custom_query_t&&) = default;
custom_query_t& operator=(const custom_query_t&) = default;
custom_query_t& operator=(custom_query_t&&) = default;
~custom_query_t() = default;
static void _check_consistency() {};
template<typename Db>
auto _run(Db& db) const -> decltype(_methods_t::_run(db, *this))
{
return _methods_t::_run(db, *this);
}
template<typename Db>
auto _prepare(Db& db) const -> decltype(_methods_t::_prepare(db, *this))
{
return _methods_t::_prepare(db, *this);
}
static constexpr size_t _get_static_no_of_parameters()
{
return std::tuple_size<parameters_of<custom_query_t>>::value;
}
size_t _get_no_of_parameters() const
{
return _get_static_no_of_parameters();
}
template<typename Part>
auto with_result_type_of(Part part)
-> custom_query_t<Database, Part, Parts...>
{
return {tuple_cat(std::make_tuple(part), _parts)};
}
std::tuple<Parts...> _parts;
};
template<typename Context, typename Database, typename... Parts>
struct serializer_t<Context, custom_query_t<Database, Parts...>>
{
using T = custom_query_t<Database, Parts...>;
static Context& _(const T& t, Context& context)
{
interpret_tuple_without_braces(t._parts, " ", context);
return context;
}
};
template<typename... Parts>
auto custom_query(Parts... parts)
-> custom_query_t<void, wrap_operand_t<Parts>...>
{
static_assert(sizeof...(Parts) > 0, "custom query requires at least one argument");
return custom_query_t<void, wrap_operand_t<Parts>...>(parts...);
}
template<typename Database, typename... Parts>
auto dynamic_custom_query(const Database&, Parts... parts)
-> custom_query_t<Database, wrap_operand_t<Parts>...>
{
static_assert(sizeof...(Parts) > 0, "custom query requires at least one query argument");
static_assert(std::is_base_of<connection, Database>::value, "Invalid database parameter");
return custom_query_t<Database, wrap_operand_t<Parts>...>(parts...);
}
}
#endif

View File

@@ -0,0 +1,60 @@
/*
* 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_DETAIL_GET_FIRST_H
#define SQLPP_DETAIL_GET_FIRST_H
#include <type_traits>
namespace sqlpp
{
namespace detail
{
template<template<typename> class Predicate, typename Default, typename... T>
struct get_first_if_impl;
template<template<typename> class Predicate, typename Default>
struct get_first_if_impl<Predicate, Default>
{
using type = Default;
};
template<template<typename> class Predicate, typename Default, typename T, typename... Rest>
struct get_first_if_impl<Predicate, Default, T, Rest...>
{
using rest = typename get_first_if_impl<Predicate, Default, Rest...>::type;
using type = typename std::conditional<Predicate<T>::value,
T,
rest>::type;
};
template<template<typename> class Predicate, typename Default, typename... T>
using get_first_if = typename get_first_if_impl<Predicate, Default, T...>::type;
}
}
#endif

65
include/sqlpp11/hidden.h Normal file
View File

@@ -0,0 +1,65 @@
/*
* 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_HIDDEN_H
#define SQLPP_HIDDEN_H
namespace sqlpp
{
template<typename Part>
struct hidden_t:
public Part
{
hidden_t(Part part):
Part(part)
{}
hidden_t(const hidden_t&) = default;
hidden_t(hidden_t&&) = default;
hidden_t& operator=(const hidden_t&) = default;
hidden_t& operator=(hidden_t&&) = default;
~hidden_t() = default;
};
template<typename Context, typename Part>
struct serializer_t<Context, hidden_t<Part>>
{
using T = hidden_t<Part>;
static Context& _(const T& t, Context& context)
{
return context;
}
};
template<typename Part>
auto hidden(Part part)
-> hidden_t<Part>
{
return {part};
}
}
#endif

View File

@@ -46,16 +46,27 @@ namespace sqlpp
using _traits = make_traits<no_value_t, tag::is_return_value>;
struct _name_t {};
template<typename Policies>
template<typename Statement>
struct _result_methods_t
{
using _statement_t = derived_statement_t<Policies>;
using _statement_t = Statement;
const _statement_t& _get_statement() const
{
return static_cast<const _statement_t&>(*this);
}
// Execute
template<typename Db, typename Composite>
auto _run(Db& db, const Composite& composite) const
-> decltype(db.insert(composite))
{
Composite::_check_consistency();
static_assert(Composite::_get_static_no_of_parameters() == 0, "cannot run insert directly with parameters, use prepare instead");
return db.insert(composite);
}
template<typename Db>
auto _run(Db& db) const -> decltype(db.insert(this->_get_statement()))
{
@@ -65,14 +76,24 @@ namespace sqlpp
return db.insert(_get_statement());
}
template<typename Db>
auto _prepare(Db& db) const
-> prepared_insert_t<Db, _statement_t>
{
_statement_t::_check_consistency();
// Prepare
template<typename Db, typename Composite>
auto _prepare(Db& db, const Composite& composite) const
-> prepared_insert_t<Db, Composite>
{
Composite::_check_consistency();
return {{}, db.prepare_insert(_get_statement())};
}
return {{}, db.prepare_insert(composite)};
}
template<typename Db>
auto _prepare(Db& db) const
-> prepared_insert_t<Db, _statement_t>
{
_statement_t::_check_consistency();
return {{}, db.prepare_insert(_get_statement())};
}
};
};

View File

@@ -34,20 +34,20 @@
namespace sqlpp
{
template<typename Element, typename Separator, typename Context>
static void interpret_tuple_element(const Element& element, const Separator& separator, Context& context, size_t index)
template<typename Element, typename Separator, typename Context, typename UseBraces>
static void interpret_tuple_element(const Element& element, const Separator& separator, Context& context, const UseBraces&, size_t index)
{
if (index)
context << separator;
if (requires_braces_t<Element>::value)
if (UseBraces::value and requires_braces_t<Element>::value)
context << "(";
serialize(element, context);
if (requires_braces_t<Element>::value)
if (UseBraces::value and requires_braces_t<Element>::value)
context << ")";
}
template<typename Tuple, typename Separator, typename Context, size_t... Is>
auto interpret_tuple_impl(const Tuple& t, const Separator& separator, Context& context, const detail::index_sequence<Is...>&)
template<typename Tuple, typename Separator, typename Context, typename UseBraces, size_t... Is>
auto interpret_tuple_impl(const Tuple& t, const Separator& separator, Context& context, const UseBraces& useBraces, const detail::index_sequence<Is...>&)
-> Context&
{
// Note: A braced-init-list does guarantee the order of evaluation according to 12.6.1 [class.explicit.init] paragraph 2 and 8.5.4 [dcl.init.list] paragraph 4.
@@ -55,7 +55,7 @@ namespace sqlpp
// See also: "http://stackoverflow.com/questions/6245735/pretty-print-stdtuple/6245777#6245777"
// Beware of gcc-bug: "http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51253", otherwise an empty swallow struct could be used
using swallow = int[];
(void) swallow{(interpret_tuple_element(std::get<Is>(t), separator, context, Is), 0)...};
(void) swallow{(interpret_tuple_element(std::get<Is>(t), separator, context, useBraces, Is), 0)...};
return context;
}
@@ -63,7 +63,14 @@ namespace sqlpp
auto interpret_tuple(const Tuple& t, const Separator& separator, Context& context)
-> Context&
{
return interpret_tuple_impl(t, separator, context, detail::make_index_sequence<std::tuple_size<Tuple>::value>{});
return interpret_tuple_impl(t, separator, context, std::true_type{}, detail::make_index_sequence<std::tuple_size<Tuple>::value>{});
}
template<typename Tuple, typename Separator, typename Context>
auto interpret_tuple_without_braces(const Tuple& t, const Separator& separator, Context& context)
-> Context&
{
return interpret_tuple_impl(t, separator, context, std::false_type{}, detail::make_index_sequence<std::tuple_size<Tuple>::value>{});
}
}

View File

@@ -27,6 +27,7 @@
#ifndef SQLPP_INTO_H
#define SQLPP_INTO_H
#include <sqlpp11/statement_fwd.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/no_value.h>
#include <sqlpp11/no_data.h>
@@ -168,6 +169,11 @@ namespace sqlpp
}
};
template<typename... T>
auto into(T&&... t) -> decltype(statement_t<void, no_into_t>().into(std::forward<T>(t)...))
{
return statement_t<void, no_into_t>().into(std::forward<T>(t)...);
}
}
#endif

View File

@@ -30,6 +30,7 @@
#include <type_traits>
#include <sqlpp11/no_value.h>
#include <sqlpp11/serializer.h>
#include <sqlpp11/prepared_execute.h>
namespace sqlpp
{
@@ -40,9 +41,54 @@ namespace sqlpp
struct _name_t {};
template<typename Policies>
template<typename Statement>
struct _result_methods_t
{};
{
using _statement_t = Statement;
const _statement_t& _get_statement() const
{
return static_cast<const _statement_t&>(*this);
}
// Execute
template<typename Db, typename Composite>
auto _run(Db& db, const Composite& composite) const -> void
{
Composite::_check_consistency();
static_assert(Composite::_get_static_no_of_parameters() == 0, "cannot run execute directly with parameters, use prepare instead");
return db.execute(composite);
}
template<typename Db>
auto _run(Db& db) const -> void
{
_statement_t::_check_consistency();
static_assert(_statement_t::_get_static_no_of_parameters() == 0, "cannot run insert directly with parameters, use prepare instead");
return db.execute(_get_statement());
}
// Prepare
template<typename Db, typename Composite>
auto _prepare(Db& db, const Composite& composite) const
-> prepared_execute_t<Db, Composite>
{
Composite::_check_consistency();
return {{}, db.prepare_execute(composite)};
}
template<typename Db>
auto _prepare(Db& db) const
-> prepared_execute_t<Db, _statement_t>
{
_statement_t::_check_consistency();
return {{}, db.prepare_execute(_get_statement())};
}
};
};
template<typename Context>

View File

@@ -0,0 +1,58 @@
/*
* 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_PREPARED_EXECUTE_H
#define SQLPP_PREPARED_EXECUTE_H
#include <sqlpp11/parameter_list.h>
#include <sqlpp11/result.h>
namespace sqlpp
{
template<typename Db, typename Statement>
struct prepared_execute_t
{
using _parameter_list_t = make_parameter_list_t<Statement>;
using _prepared_statement_t = typename Db::_prepared_statement_t;
auto _run(Db& db) const
-> void
{
return db.run_prepared_execute(*this);
}
void _bind_params() const
{
params._bind(_prepared_statement);
}
_parameter_list_t params;
mutable _prepared_statement_t _prepared_statement;
};
}
#endif

View File

@@ -32,12 +32,12 @@
namespace sqlpp
{
template<typename Database, typename Select>
template<typename Database, typename Statement, typename Composite = Statement>
struct prepared_select_t
{
using _result_row_t = typename Select::template _result_row_t<Database>;
using _parameter_list_t = make_parameter_list_t<Select>;
using _dynamic_names_t = typename Select::_dynamic_names_t;
using _result_row_t = typename Statement::template _result_row_t<Database>;
using _parameter_list_t = make_parameter_list_t<Composite>;
using _dynamic_names_t = typename Statement::_dynamic_names_t;
using _prepared_statement_t = typename Database::_prepared_statement_t;
auto _run(Database& db) const

View File

@@ -46,16 +46,27 @@ namespace sqlpp
using _traits = make_traits<no_value_t, tag::is_return_value>;
struct _name_t {};
template<typename Policies>
template<typename Statement>
struct _result_methods_t
{
using _statement_t = derived_statement_t<Policies>;
using _statement_t = Statement;
const _statement_t& _get_statement() const
{
return static_cast<const _statement_t&>(*this);
}
// Execute
template<typename Db, typename Composite>
auto _run(Db& db, const Composite& composite) const
-> decltype(db.remove(composite))
{
Composite::_check_consistency();
static_assert(Composite::_get_static_no_of_parameters() == 0, "cannot run remove directly with parameters, use prepare instead");
return db.remove(composite);
}
template<typename Db>
auto _run(Db& db) const -> decltype(db.remove(this->_get_statement()))
{
@@ -65,14 +76,24 @@ namespace sqlpp
return db.remove(_get_statement());
}
template<typename Db>
auto _prepare(Db& db) const
-> prepared_remove_t<Db, _statement_t>
{
_statement_t::_check_consistency();
// Prepare
template<typename Db, typename Composite>
auto _prepare(Db& db, const Composite& composite) const
-> prepared_remove_t<Db, Composite>
{
Composite::_check_consistency();
return {{}, db.prepare_remove(_get_statement())};
}
return {{}, db.prepare_remove(composite)};
}
template<typename Db>
auto _prepare(Db& db) const
-> prepared_remove_t<Db, _statement_t>
{
_statement_t::_check_consistency();
return {{}, db.prepare_remove(_get_statement())};
}
};
};

View File

@@ -235,10 +235,10 @@ namespace sqlpp
};
// Result methods
template<typename Policies>
template<typename Statement>
struct _result_methods_t
{
using _statement_t = derived_statement_t<Policies>;
using _statement_t = Statement;
const _statement_t& _get_statement() const
{
@@ -277,7 +277,7 @@ namespace sqlpp
template<typename AliasProvider>
_alias_t<AliasProvider> as(const AliasProvider& aliasProvider) const
{
static_assert(Policies::_can_be_used_as_table::value, "statement cannot be used as table, e.g. due to missing tables");
static_assert(_statement_t::_can_be_used_as_table(), "statement cannot be used as table, e.g. due to missing tables");
static_assert(detail::none_t<is_multi_column_t<Columns>::value...>::value, "cannot use multi-columns in sub selects");
return _table_t<AliasProvider>(_get_statement()).as(aliasProvider);
}
@@ -293,9 +293,19 @@ namespace sqlpp
}
// Execute
template<typename Db, typename Composite>
auto _run(Db& db, const Composite& composite) const
-> result_t<decltype(db.select(composite)), _result_row_t<Db>>
{
Composite::_check_consistency();
static_assert(Composite::_get_static_no_of_parameters() == 0, "cannot run select directly with parameters, use prepare instead");
return {db.select(composite), get_dynamic_names()};
}
template<typename Db>
auto _run(Db& db) const
-> result_t<decltype(db.select(this->_get_statement())), _result_row_t<Db>>
-> result_t<decltype(db.select(_get_statement())), _result_row_t<Db>>
{
_statement_t::_check_consistency();
static_assert(_statement_t::_get_static_no_of_parameters() == 0, "cannot run select directly with parameters, use prepare instead");
@@ -304,6 +314,15 @@ namespace sqlpp
}
// Prepare
template<typename Db, typename Composite>
auto _prepare(Db& db, const Composite& composite) const
-> prepared_select_t<Db, _statement_t, Composite>
{
Composite::_check_consistency();
return {make_parameter_list_t<Composite>{}, get_dynamic_names(), db.prepare_select(composite)};
}
template<typename Db>
auto _prepare(Db& db) const
-> prepared_select_t<Db, _statement_t>

View File

@@ -79,18 +79,19 @@ namespace sqlpp
using _result_type_provider = detail::get_last_if<is_return_value_t, noop, Policies...>;
struct _result_methods_t: public _result_type_provider::template _result_methods_t<statement_policies_t>
struct _result_methods_t: public _result_type_provider::template _result_methods_t<_statement_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;
static constexpr bool _can_be_used_as_table()
{
return is_select_column_list_t<_result_type_provider>::value and _required_tables::size::value == 0
? true
: false;
}
using _value_type = typename std::conditional<
detail::none_t<is_missing_t<Policies>::value...>::value,
@@ -131,17 +132,19 @@ namespace sqlpp
public Policies::template _methods_t<detail::statement_policies_t<Db, Policies...>>...
{
using _policies_t = typename detail::statement_policies_t<Db, Policies...>;
using _result_type_provider = typename _policies_t::_result_type_provider;
template<typename Composite>
using _result_methods_t = typename _result_type_provider::template _result_methods_t<Composite>;
using _traits = make_traits<value_type_of<_policies_t>,
tag::is_select,
tag_if<tag::is_expression, is_expression_t<_policies_t>::value>,
tag_if<tag::is_selectable, is_expression_t<_policies_t>::value>,
tag_if<tag::is_return_value, detail::none_t<is_noop_t<_result_type_provider>::value>::value>,
tag::requires_braces>;
using _recursive_traits = typename _policies_t::_recursive_traits;
using _used_outer_tables = typename _policies_t::_all_provided_outer_tables;
using _result_type_provider = typename _policies_t::_result_type_provider;
using _name_t = typename _result_type_provider::_name_t;
// Constructors
@@ -173,6 +176,11 @@ namespace sqlpp
return _get_static_no_of_parameters();
}
static constexpr bool _can_be_used_as_table()
{
return _policies_t::_can_be_used_as_table();
}
static void _check_consistency()
{
static_assert(not required_tables_of<_policies_t>::size::value, "one sub expression requires tables which are otherwise not known in the statement");

View File

@@ -46,16 +46,27 @@ namespace sqlpp
using _traits = make_traits<no_value_t, tag::is_return_value>;
struct _name_t {};
template<typename Policies>
template<typename Statement>
struct _result_methods_t
{
using _statement_t = derived_statement_t<Policies>;
using _statement_t = Statement;
const _statement_t& _get_statement() const
{
return static_cast<const _statement_t&>(*this);
}
// Execute
template<typename Db, typename Composite>
auto _run(Db& db, const Composite& composite) const
-> decltype(db.update(composite))
{
Composite::_check_consistency();
static_assert(Composite::_get_static_no_of_parameters() == 0, "cannot run update directly with parameters, use prepare instead");
return db.update(composite);
}
template<typename Db>
auto _run(Db& db) const -> decltype(db.update(this->_get_statement()))
{
@@ -65,14 +76,24 @@ namespace sqlpp
return db.update(_get_statement());
}
template<typename Db>
auto _prepare(Db& db) const
-> prepared_update_t<Db, _statement_t>
{
_statement_t::_check_consistency();
// Prepare
template<typename Db, typename Composite>
auto _prepare(Db& db, const Composite& composite) const
-> prepared_update_t<Db, Composite>
{
Composite::_check_consistency();
return {{}, db.prepare_update(_get_statement())};
}
return {{}, db.prepare_update(composite)};
}
template<typename Db>
auto _prepare(Db& db) const
-> prepared_update_t<Db, _statement_t>
{
_statement_t::_check_consistency();
return {{}, db.prepare_update(_get_statement())};
}
};
};

View File

@@ -27,6 +27,7 @@
#ifndef SQLPP_VERBATIM_H
#define SQLPP_VERBATIM_H
#include <sqlpp11/no_value.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/serialize.h>
@@ -71,6 +72,11 @@ namespace sqlpp
return { s };
}
auto verbatim(std::string s) -> verbatim_t<no_value_t>
{
return { s };
}
}
#endif

View File

@@ -27,6 +27,7 @@
#ifndef SQLPP_WHERE_H
#define SQLPP_WHERE_H
#include <sqlpp11/statement_fwd.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/parameter_list.h>
#include <sqlpp11/expression.h>
@@ -278,6 +279,11 @@ namespace sqlpp
}
};
template<typename... T>
auto where(T&&... t) -> decltype(statement_t<void, no_where_t<false>>().where(std::forward<T>(t)...))
{
return statement_t<void, no_where_t<false>>().where(std::forward<T>(t)...);
}
}
#endif

View File

@@ -7,6 +7,7 @@ macro (build_and_run arg)
endmacro ()
build_and_run(BooleanExpressionTest)
build_and_run(CustomQueryTest)
build_and_run(InterpretTest)
build_and_run(InsertTest)
build_and_run(RemoveTest)

67
tests/CustomQueryTest.cpp Normal file
View File

@@ -0,0 +1,67 @@
/*
* 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.
*/
#include <iostream>
#include "Sample.h"
#include "MockDb.h"
#include <sqlpp11/sqlpp11.h>
#include <sqlpp11/custom_query.h>
MockDb db = {};
MockDb::_serializer_context_t printer;
int main()
{
test::TabFoo f;
test::TabBar t;
// A void custom query
printer.reset();
auto x = custom_query(sqlpp::verbatim("PRAGMA writeable_schema = "), true);
std::cerr << serialize(x, printer).str() << std::endl;
db(x);
// Syntactically, it is possible to use this void query as a prepared statement, too, not sure, whether this makes sense very often...
db(db.prepare(x));
// A prepared custom select
// The return type of the custom query is determined from the first argument which does have a return type, in this case the select
auto p = db.prepare(custom_query(select(all_of(t)).from(t), where(t.alpha > sqlpp::parameter(t.alpha))));
p.params.alpha = 8;
for (const auto& row : db(p))
{
std::cerr << row.alpha << std::endl;
}
// A custom (select ... into) with adjusted return type
// The first argument with a return type is the select, but the custom query is really an insert. Thus, we tell it so.
printer.reset();
auto c = custom_query(select(all_of(t)).from(t), into(f)).with_result_type_of(insert_into(f));
std::cerr << serialize(c, printer).str() << std::endl;
auto i = db(c);
static_assert(std::is_integral<decltype(i)>::value, "insert yields an integral value");
return 0;
}

View File

@@ -112,6 +112,16 @@ struct MockDbT: public sqlpp::connection
return t._run(*this);
}
void execute(const std::string& command);
template<typename Statement,
typename Enable = typename std::enable_if<not std::is_convertible<Statement, std::string>::value, void>::type>
void execute(const Statement& x)
{
_serializer_context_t context;
::sqlpp::serialize(x, context);
}
template<typename Insert>
size_t insert(const Insert& x)
{
@@ -154,6 +164,14 @@ struct MockDbT: public sqlpp::connection
}
template<typename Statement>
_prepared_statement_t prepare_execute(Statement& x)
{
_serializer_context_t context;
::sqlpp::serialize(x, context);
return nullptr;
}
template<typename Insert>
_prepared_statement_t prepare_insert(Insert& x)
{
@@ -162,6 +180,11 @@ struct MockDbT: public sqlpp::connection
return nullptr;
}
template<typename PreparedExecute>
void run_prepared_execute(const PreparedExecute& x)
{
}
template<typename PreparedInsert>
size_t run_prepared_insert(const PreparedInsert& x)
{

View File

@@ -300,7 +300,7 @@ int main()
multi_column(all_of(t)).as(alias::right), // index 8 (including 8, 9, 10, 11)
t.alpha.as(alias::a) // index 12
).from(t).where(true)); // next index is 13
using ResultRow = typename Select::_result_methods_t::template _result_row_t<MockDb>;
using ResultRow = typename Select::_result_methods_t<Select>::template _result_row_t<MockDb>;
using IndexSequence = ResultRow::_field_index_sequence;
static_assert(std::is_same<IndexSequence, sqlpp::detail::field_index_sequence<13, 0, 1, 2, 3, 4, 8, 12>>::value, "invalid field sequence");
}