diff --git a/include/sqlpp11/core/clause/insert_value_list.h b/include/sqlpp11/core/clause/insert_value_list.h index 8a8bf629..26f29fa6 100644 --- a/include/sqlpp11/core/clause/insert_value_list.h +++ b/include/sqlpp11/core/clause/insert_value_list.h @@ -27,6 +27,7 @@ */ #include +#include #include #include #include @@ -81,6 +82,7 @@ namespace sqlpp _data_t _data; +#warning: Need to check that all columns actually have a default value! using _consistency_check = consistent_t; }; }; @@ -89,7 +91,7 @@ namespace sqlpp struct insert_list_data_t { insert_list_data_t(std::tuple assignments) - : _assignments(assignments), _columns(columns_from_tuple(assignments)), _values(values_from_tuple(assignments)) + : _assignments(std::move(assignments)) { } @@ -99,39 +101,7 @@ namespace sqlpp insert_list_data_t& operator=(insert_list_data_t&&) = default; ~insert_list_data_t() = default; - std::tuple _assignments; // FIXME: Need to replace _columns and _values by _assignments - // (connector-container requires assignments) - std::tuple>...> _columns; - std::tuple...> _values; - - private: - template - auto columns_from_tuple(::sqlpp::index_sequence, std::tuple assignments) - -> decltype(_columns) - { - (void)assignments; - return decltype(_columns)(std::get(assignments)._l...); - } - - auto columns_from_tuple(std::tuple assignments) -> decltype(_columns) - { - const auto seq = ::sqlpp::make_index_sequence{}; - return columns_from_tuple(seq, assignments); - } - - template - auto values_from_tuple(::sqlpp::index_sequence, std::tuple assignments) - -> decltype(_values) - { - (void)assignments; - return decltype(_values)(std::get(assignments)._r...); - } - - auto values_from_tuple(std::tuple assignments) -> decltype(_values) - { - const auto seq = ::sqlpp::make_index_sequence{}; - return values_from_tuple(seq, assignments); - } + std::tuple _assignments; }; SQLPP_PORTABLE_STATIC_ASSERT(assert_insert_set_assignments_t, "at least one argument is not an assignment in set()"); @@ -145,35 +115,29 @@ namespace sqlpp SQLPP_PORTABLE_STATIC_ASSERT(assert_insert_dynamic_set_statement_dynamic_t, "dynamic_set must not be called in a static statement"); - template - using check_insert_set_t = static_combined_check_t< - static_check_t::value...>::value, - assert_insert_set_assignments_t>, - static_check_t::type...>::value, - assert_insert_set_no_duplicates_t>, - static_check_t::type>...>::are_same(), - assert_insert_set_single_table_t>>; - // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269 // template - // using check_insert_static_set_t = + // using check_insert_set_t = // static_combined_check_t, // static_check_t, // static_check_t...>::value, // assert_insert_static_set_all_required_t>>; template - struct check_insert_static_set + struct check_insert_set { using type = static_combined_check_t< - check_insert_set_t, + static_check_t::value...>::value, assert_insert_set_assignments_t>, + static_check_t::type...>::value, + assert_insert_set_no_duplicates_t>, + static_check_t::type>...>::are_same(), + assert_insert_set_single_table_t>, static_check_t, static_check_t::type...>::value, assert_insert_static_set_all_required_t>>; }; template - using check_insert_static_set_t = typename check_insert_static_set::type; + using check_insert_set_t = typename check_insert_set...>::type; SQLPP_PORTABLE_STATIC_ASSERT( assert_no_unknown_tables_in_insert_assignments_t, @@ -230,7 +194,7 @@ namespace sqlpp ~column_list_data_t() = default; using _value_tuple_t = std::tuple...>; - std::tuple...> _columns; + std::tuple _columns; std::vector<_value_tuple_t> _insert_values; }; @@ -347,17 +311,17 @@ namespace sqlpp template auto set(Assignments... assignments) const - -> _new_statement_t, insert_list_t> + -> _new_statement_t, insert_list_t> { - using Check = check_insert_static_set_t; + using Check = check_insert_set_t; return _set_impl(Check{}, std::make_tuple(assignments...)); } template auto set(std::tuple assignments) const - -> _new_statement_t, insert_list_t> + -> _new_statement_t, insert_list_t> { - using Check = check_insert_static_set_t; + using Check = check_insert_set_t; return _set_impl(Check{}, assignments); } @@ -426,17 +390,74 @@ namespace sqlpp return result; } + // Used to serialize left hand side of assignment tuple that should ignore dynamic elements. + struct tuple_lhs_assignment_operand_no_dynamic + { + template + auto operator()(Context& context, const assign_expression&, size_t ) const -> std::string + { + const auto prefix = need_prefix ? std::string{separator} : std::string{}; + need_prefix = true; + return prefix + name_to_sql_string(context, name_tag_of_t::name); + } + + template + auto operator()(Context& context, const sqlpp::dynamic_t& t, size_t index) const -> std::string + { + if (t._condition) + { + return operator()(context, t._expr, index); + } + return ""; + } + + sqlpp::string_view separator; + mutable bool need_prefix = false; + }; + + // Used to serialize right hand side of assignment tuple that should ignore dynamic elements. + struct tuple_rhs_assignment_operand_no_dynamic + { + template + auto operator()(Context& context, const assign_expression& t, size_t ) const -> std::string + { + const auto prefix = need_prefix ? std::string{separator} : std::string{}; + need_prefix = true; + return prefix + operand_to_sql_string(context, t._r); + } + + template + auto operator()(Context& context, const sqlpp::dynamic_t& t, size_t index) const -> std::string + { + if (t._condition) + { + return operator()(context, t._expr, index); + } + return ""; + } + + sqlpp::string_view separator; + mutable bool need_prefix = false; + }; + template auto to_sql_string(Context& context, const insert_list_data_t& t) -> std::string { auto result = std::string{" ("}; - result += tuple_to_sql_string(context, t._columns, tuple_operand{", "}); + result += tuple_to_sql_string(context, t._assignments, tuple_lhs_assignment_operand_no_dynamic{", "}); result += ") VALUES("; - result += tuple_to_sql_string(context, t._values, tuple_operand{", "}); + result += tuple_to_sql_string(context, t._assignments, tuple_rhs_assignment_operand_no_dynamic{", "}); result += ")"; return result; } + template + auto insert_default_values() + -> decltype(statement_t().default_values()) + { + return statement_t().default_values(); + } + template auto insert_set(Assignments... assignments) -> decltype(statement_t().set(assignments...)) diff --git a/include/sqlpp11/core/clause/update_list.h b/include/sqlpp11/core/clause/update_list.h index 88cef6e6..039d4735 100644 --- a/include/sqlpp11/core/clause/update_list.h +++ b/include/sqlpp11/core/clause/update_list.h @@ -26,6 +26,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include diff --git a/include/sqlpp11/core/tuple_to_sql_string.h b/include/sqlpp11/core/tuple_to_sql_string.h index cde6ff39..2d7e2033 100644 --- a/include/sqlpp11/core/tuple_to_sql_string.h +++ b/include/sqlpp11/core/tuple_to_sql_string.h @@ -45,7 +45,7 @@ namespace sqlpp sqlpp::string_view separator; }; - // Used to serialize tuple tuples that should ignore dynamic elements. + // Used to serialize tuple that should ignore dynamic elements. struct tuple_operand_no_dynamic { template diff --git a/include/sqlpp11/core/type_traits.h b/include/sqlpp11/core/type_traits.h index 4dce2a45..7c3b9d8e 100644 --- a/include/sqlpp11/core/type_traits.h +++ b/include/sqlpp11/core/type_traits.h @@ -299,6 +299,12 @@ namespace sqlpp using type = void; }; + template + struct lhs> + { + using type = dynamic_t::type>; + }; + template using lhs_t = typename lhs::type; @@ -308,6 +314,12 @@ namespace sqlpp using type = void; }; + template + struct rhs> + { + using type = dynamic_t::type>; + }; + template using rhs_t = typename rhs::type; diff --git a/tests/core/serialize/clause/CMakeLists.txt b/tests/core/serialize/clause/CMakeLists.txt index fab2aa63..17b9603a 100644 --- a/tests/core/serialize/clause/CMakeLists.txt +++ b/tests/core/serialize/clause/CMakeLists.txt @@ -30,6 +30,8 @@ function(create_test name) endfunction() create_test(group_by) +create_test(insert_default_values) +create_test(insert_set) create_test(select_columns) create_test(select_flags) create_test(update_set) diff --git a/tests/core/serialize/clause/insert_default_values.cpp b/tests/core/serialize/clause/insert_default_values.cpp new file mode 100644 index 00000000..e48ed44d --- /dev/null +++ b/tests/core/serialize/clause/insert_default_values.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024, 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 "../compare.h" +#include + +int main(int, char* []) +{ + +#warning: This looks different for MySQL + SQLPP_COMPARE(sqlpp::insert_default_values(), " DEFAULT VALUES"); + + return 0; +} diff --git a/tests/core/serialize/clause/insert_set.cpp b/tests/core/serialize/clause/insert_set.cpp new file mode 100644 index 00000000..317a1760 --- /dev/null +++ b/tests/core/serialize/clause/insert_set.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024, 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 "Sample.h" +#include "../compare.h" +#include + +SQLPP_CREATE_NAME_TAG(v); + +int main(int, char* []) +{ + const auto val = sqlpp::value(17); + const auto expr = sqlpp::value(17) + 4; + + const auto foo = test::TabFoo{}; + + // Plain assignments. + SQLPP_COMPARE(insert_set(foo.id = 7), " (id) VALUES(7)"); + SQLPP_COMPARE(insert_set(foo.id = 7, foo.textNnD = "cheesecake"), " (id, text_nn_d) VALUES(7, 'cheesecake')"); + + // Dynamic assignments. + SQLPP_COMPARE(insert_set(sqlpp::dynamic(true, foo.id = 7), sqlpp::dynamic(false, foo.textNnD = "cheesecake")), + " (id) VALUES(7)"); + SQLPP_COMPARE(insert_set(sqlpp::dynamic(false, foo.id = 7), sqlpp::dynamic(true, foo.textNnD = "cheesecake")), + " (text_nn_d) VALUES('cheesecake')"); + + return 0; +} diff --git a/tests/core/serialize/clause/update_set.cpp b/tests/core/serialize/clause/update_set.cpp index ddb4e6cf..73d7c194 100644 --- a/tests/core/serialize/clause/update_set.cpp +++ b/tests/core/serialize/clause/update_set.cpp @@ -27,13 +27,8 @@ #include "../compare.h" #include -SQLPP_CREATE_NAME_TAG(v); - int main(int, char* []) { - const auto val = sqlpp::value(17); - const auto expr = sqlpp::value(17) + 4; - const auto foo = test::TabFoo{}; // Plain assignments.