From 9c1e75cd89964744b34a636d809b4625ba652c6e Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Mon, 9 Sep 2013 22:45:34 +0200 Subject: [PATCH] Adjusted insert and update to work with sqlite Introduced first connector trait to change query generation. --- include/sqlpp11/column.h | 6 +++ include/sqlpp11/expression.h | 3 +- include/sqlpp11/insert.h | 31 ++++++----- include/sqlpp11/insert_list.h | 96 +++++++++++++++++++++++++++++++++++ include/sqlpp11/type_traits.h | 14 +++++ 5 files changed, 136 insertions(+), 14 deletions(-) create mode 100644 include/sqlpp11/insert_list.h diff --git a/include/sqlpp11/column.h b/include/sqlpp11/column.h index 94526614..fc286302 100644 --- a/include/sqlpp11/column.h +++ b/include/sqlpp11/column.h @@ -59,6 +59,12 @@ namespace sqlpp os << Table::_name_t::_get_name() << '.' << _name_t::_get_name(); } + template + void serialize_name(std::ostream& os, Db& db) const + { + os << _name_t::_get_name(); + } + template expression_alias_t::type> as(alias_provider&&) const { diff --git a/include/sqlpp11/expression.h b/include/sqlpp11/expression.h index 1aac6902..4a07a3b4 100644 --- a/include/sqlpp11/expression.h +++ b/include/sqlpp11/expression.h @@ -39,11 +39,12 @@ namespace sqlpp { using _is_assignment = tag_yes; using column_type = Lhs; + using value_type = Rhs; template void serialize(std::ostream& os, Db& db) const { - _lhs.serialize(os, db); + _lhs.serialize_name(os, db); if (trivial_value_is_null_t::value and _rhs._is_trivial()) { os << "=NULL"; diff --git a/include/sqlpp11/insert.h b/include/sqlpp11/insert.h index b14dbdcb..9ae7811d 100644 --- a/include/sqlpp11/insert.h +++ b/include/sqlpp11/insert.h @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include @@ -43,29 +43,29 @@ namespace sqlpp // insert. template< typename Table = noop, - typename Assignments = noop + typename InsertList = noop > struct insert_t; template< typename Table, - typename Assignments + typename InsertList > struct insert_t { static_assert(is_noop::value or is_table_t
::value, "invalid 'Table' argument"); - static_assert(is_noop::value or is_assignment_list_t::value, "invalid 'Assignments' arguments"); + static_assert(is_noop::value or is_insert_list_t::value, "invalid 'InsertList' argument"); template - using add_assignments_t = insert_t::type...>>; + using add_insert_list_t = insert_t::type...>>; template - add_assignments_t set(Assignment&&... assignment) + add_insert_list_t set(Assignment&&... assignment) { - static_assert(std::is_same::value, "cannot call set() twice"); + static_assert(std::is_same::value, "cannot call set() twice"); return { _table, - {std::tuple::type...>{std::forward(assignment)...}}, + insert_list_t{std::forward(assignment)...}, }; } @@ -74,10 +74,15 @@ namespace sqlpp { os << "INSERT INTO "; _table.serialize(os, db); - if (is_noop::value) - os << "() VALUES()"; + if (is_noop::value) + { + if (connector_has_empty_list_insert_t::type>::value) + os << " () VALUES()"; + else + os << " DEFAULT VALUES"; + } else - _assignments.serialize(os, db); + _insert_list.serialize(os, db); return *this; } @@ -91,7 +96,7 @@ namespace sqlpp template std::size_t run(Db& db) const { - constexpr bool calledSet = not is_noop::value; + constexpr bool calledSet = not is_noop::value; constexpr bool requireSet = Table::_required_insert_columns::size::value > 0; static_assert(calledSet or not requireSet, "calling set() required for given table"); std::ostringstream oss; @@ -100,7 +105,7 @@ namespace sqlpp } Table _table; - Assignments _assignments; + InsertList _insert_list; }; template diff --git a/include/sqlpp11/insert_list.h b/include/sqlpp11/insert_list.h new file mode 100644 index 00000000..0ab84bae --- /dev/null +++ b/include/sqlpp11/insert_list.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2013, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLPP_INSERT_LIST_H +#define SQLPP_INSERT_LIST_H + +#include +#include +#include + +namespace sqlpp +{ + namespace detail + { + template + struct insert_column + { + template + void serialize(std::ostream& os, Db& db) const + { + _column.serialize_name(os, db); + } + + Column _column; + }; + } + template class ProhibitPredicate, typename... Assignment> + struct insert_list_t + { + // check for at least one order expression + static_assert(sizeof...(Assignment), "at least one select expression required in set()"); + + // check for duplicate assignments + static_assert(not detail::has_duplicates::value, "at least one duplicate argument detected in set()"); + + // check for invalid assignments + using _assignment_set = typename detail::make_set_if::type; + static_assert(_assignment_set::size::value == sizeof...(Assignment), "at least one argument is not an assignment in set()"); + + // check for prohibited assignments + using _prohibited_assignment_set = typename detail::make_set_if::type; + static_assert(_prohibited_assignment_set::size::value == 0, "at least one assignment is prohibited by its column definition in set()"); + + using _is_insert_list = tag_yes; + + insert_list_t(Assignment... assignment): + _columns({assignment._lhs}...), + _values(assignment._rhs...) + {} + + insert_list_t(const insert_list_t&) = default; + insert_list_t(insert_list_t&&) = default; + insert_list_t& operator=(const insert_list_t&) = default; + insert_list_t& operator=(insert_list_t&&) = default; + ~insert_list_t() = default; + + template + void serialize(std::ostream& os, Db& db) const + { + os << " ("; + detail::serialize_tuple(os, db, _columns, ','); + os << ") VALUES ("; + detail::serialize_tuple(os, db, _values, ','); + os << ")"; + } + + std::tuple...> _columns; + std::tuple _values; + }; + +} + +#endif diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index b28172c0..b8d32721 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -64,6 +64,17 @@ namespace sqlpp template\ struct name##_t: detail::name##_impl {}; +#define SQLPP_CONNECTOR_TRAIT_GENERATOR(name) \ + namespace detail\ + {\ + template\ + struct connector_##name##_impl: std::false_type {};\ + template\ + struct connector_##name##_impl::value>::type>: std::true_type {};\ + }\ + template\ + struct connector_##name##_t: detail::connector_##name##_impl {}; + SQLPP_IS_VALUE_TRAIT_GENERATOR(boolean); SQLPP_IS_VALUE_TRAIT_GENERATOR(numeric); SQLPP_IS_VALUE_TRAIT_GENERATOR(text); @@ -96,9 +107,12 @@ namespace sqlpp SQLPP_TYPE_TRAIT_GENERATOR(is_value_list); SQLPP_TYPE_TRAIT_GENERATOR(is_assignment); SQLPP_TYPE_TRAIT_GENERATOR(is_assignment_list); + SQLPP_TYPE_TRAIT_GENERATOR(is_insert_list); SQLPP_TYPE_TRAIT_GENERATOR(is_sort_order); SQLPP_TYPE_TRAIT_GENERATOR(requires_braces); + SQLPP_CONNECTOR_TRAIT_GENERATOR(has_empty_list_insert); + template class IsTag> using copy_type_trait = typename std::conditional::value, detail::tag, void>::type;