mirror of
https://github.com/rbock/sqlpp11.git
synced 2026-01-04 04:00:39 -06:00
Merge branch 'feature/custom_query' into develop
This commit is contained in:
137
include/sqlpp11/custom_query.h
Normal file
137
include/sqlpp11/custom_query.h
Normal 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
|
||||
60
include/sqlpp11/detail/get_first.h
Normal file
60
include/sqlpp11/detail/get_first.h
Normal 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
65
include/sqlpp11/hidden.h
Normal 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
|
||||
@@ -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())};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -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>{});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
58
include/sqlpp11/prepared_execute.h
Normal file
58
include/sqlpp11/prepared_execute.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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())};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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())};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
67
tests/CustomQueryTest.cpp
Normal 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;
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user