diff --git a/include/sqlpp11/column.h b/include/sqlpp11/column.h index 3f852406..98f31ae7 100644 --- a/include/sqlpp11/column.h +++ b/include/sqlpp11/column.h @@ -43,6 +43,7 @@ namespace sqlpp template struct column_t: public ColumnSpec::_value_type::template operators> { + using _is_column = std::true_type; using _table = Table; using _column_type = typename ColumnSpec::_column_type; struct _value_type: ColumnSpec::_value_type diff --git a/include/sqlpp11/insert.h b/include/sqlpp11/insert.h index 0ca58d1e..7947f546 100644 --- a/include/sqlpp11/insert.h +++ b/include/sqlpp11/insert.h @@ -28,10 +28,12 @@ #define SQLPP_INSERT_H #include +#include #include +#include #include #include -#include +#include namespace sqlpp { @@ -39,16 +41,22 @@ namespace sqlpp template< typename Database = void, typename Table = vendor::noop, - typename InsertList = vendor::noop + typename InsertList = vendor::noop, + typename ColumnList = vendor::noop, + typename ValueList = vendor::insert_value_list_t > struct insert_t { static_assert(vendor::is_noop::value or is_table_t
::value, "invalid 'Table' argument"); static_assert(vendor::is_noop::value or is_insert_list_t::value, "invalid 'InsertList' argument"); + static_assert(vendor::is_noop::value or is_column_list_t::value, "invalid 'ColumnList' argument"); + static_assert(vendor::is_noop::value or is_insert_value_list_t::value, "invalid 'ValueList' argument"); + using use_default_values_t = insert_t; template using set_insert_list_t = insert_t; - using use_default_values_t = insert_t; + template + using set_column_value_list_t = insert_t; using _parameter_tuple_t = std::tuple; using _parameter_list_t = typename make_parameter_list_t::type; @@ -57,10 +65,13 @@ namespace sqlpp -> use_default_values_t { static_assert(std::is_same::value, "cannot call default_values() after set() or default_values()"); + static_assert(vendor::is_noop::value, "cannot call default_values() after columns()"); static_assert(Table::_required_insert_columns::size::value == 0, "cannot use default_values, because some columns are configured to require values"); return { _table, {}, + _column_list, + _value_list, }; } @@ -69,10 +80,13 @@ namespace sqlpp -> set_insert_list_t::type...>> { static_assert(std::is_same::value, "cannot call set() after set() or default_values()"); + static_assert(vendor::is_noop::value, "cannot call set() after columns()"); // FIXME: Need to check if all required columns are set return { _table, vendor::insert_list_t::type...>{std::forward(assignment)...}, + _column_list, + _value_list, }; } @@ -81,9 +95,12 @@ namespace sqlpp -> set_insert_list_t::type...>> { static_assert(std::is_same::value, "cannot call set() after set() or default_values()"); + static_assert(vendor::is_noop::value, "cannot call set() after columns()"); return { _table, vendor::insert_list_t::type...>{std::forward(assignment)...}, + _column_list, + _value_list, }; } @@ -97,6 +114,34 @@ namespace sqlpp return *this; } + template + //using _insert_value_t = vendor::insert_value_t::type>; + using _insert_value_t = vendor::insert_value_t; + + template + auto columns(Column... columns) + -> set_column_value_list_t, vendor::insert_value_list_t<_insert_value_t...>> + { + static_assert(vendor::is_noop::value, "cannot call columns() twice"); + static_assert(vendor::is_noop::value, "cannot call columns() after set() or dynamic_set()"); + // FIXME: Need to check if all required columns are set + + return { + _table, + _insert_list, + {std::tuple{columns...}}, + vendor::insert_value_list_t<_insert_value_t...>{}, + }; + } + + template + insert_t& add_values(Value... values) + { + static_assert(is_insert_value_list_t::value, "cannot call add_values() before columns()"); + _value_list.add(typename ValueList::_value_tuple_t{values...}); + return *this; + }; + static constexpr size_t _get_static_no_of_parameters() { return _parameter_list_t::size::value; @@ -128,20 +173,36 @@ namespace sqlpp Table _table; InsertList _insert_list; + ColumnList _column_list; + ValueList _value_list; }; namespace vendor { - template - struct interpreter_t> + template + struct interpreter_t> { - using T = insert_t; + using T = insert_t; static Context& _(const T& t, Context& context) { - context << "INSERT INTO "; - interpret(t._table, context); - interpret(t._insert_list, context); + if (not vendor::is_noop::value) + { + context << "INSERT INTO "; + interpret(t._table, context); + interpret(t._insert_list, context); + } + else if (not t._value_list.empty()) + { + context << "INSERT INTO "; + interpret(t._table, context); + interpret(t._column_list, context); + interpret(t._value_list, context); + } + else + { + context << "# empty insert"; + } return context; } }; diff --git a/include/sqlpp11/tvin.h b/include/sqlpp11/tvin.h index f3c43f94..c161008d 100644 --- a/include/sqlpp11/tvin.h +++ b/include/sqlpp11/tvin.h @@ -50,6 +50,11 @@ namespace sqlpp tvin_t& operator=(tvin_t&&) = default; ~tvin_t() = default; + bool _is_trivial() const + { + return _value._is_trivial(); + } + _operand_t _value; }; diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index f2b3c36e..b0c3708d 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -95,6 +95,7 @@ namespace sqlpp SQLPP_TYPE_TRAIT_GENERATOR(is_table); SQLPP_TYPE_TRAIT_GENERATOR(is_pseudo_table); + SQLPP_TYPE_TRAIT_GENERATOR(is_column); SQLPP_TYPE_TRAIT_GENERATOR(is_select); SQLPP_TYPE_TRAIT_GENERATOR(is_select_flag_list); SQLPP_TYPE_TRAIT_GENERATOR(is_select_column_list); @@ -114,6 +115,8 @@ namespace sqlpp SQLPP_TYPE_TRAIT_GENERATOR(is_assignment); SQLPP_TYPE_TRAIT_GENERATOR(is_update_list); SQLPP_TYPE_TRAIT_GENERATOR(is_insert_list); + SQLPP_TYPE_TRAIT_GENERATOR(is_insert_value); + SQLPP_TYPE_TRAIT_GENERATOR(is_insert_value_list); SQLPP_TYPE_TRAIT_GENERATOR(is_sort_order); SQLPP_TYPE_TRAIT_GENERATOR(requires_braces); SQLPP_TYPE_TRAIT_GENERATOR(is_parameter); diff --git a/include/sqlpp11/vendor/column_list.h b/include/sqlpp11/vendor/column_list.h new file mode 100644 index 00000000..24e8a9a5 --- /dev/null +++ b/include/sqlpp11/vendor/column_list.h @@ -0,0 +1,78 @@ +/* + * 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_COLUMN_LIST_H +#define SQLPP_COLUMN_LIST_H + +#include +#include +#include + +namespace sqlpp +{ + namespace vendor + { + template + struct column_list_t + { + using _is_column_list = std::true_type; + using _parameter_tuple_t = std::tuple; + + // check for at least one order column + static_assert(sizeof...(Columns), "at least one column required in columns()"); + + // check for duplicate columns + static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in columns()"); + + // check for invalid columns + using _column_set = typename ::sqlpp::detail::make_set_if::type; + static_assert(_column_set::size::value == sizeof...(Columns), "at least one argument is not a column in columns()"); + + // check for prohibited columns + using _prohibited_column_set = typename ::sqlpp::detail::make_set_if::type; + static_assert(_prohibited_column_set::size::value == 0, "at least one column argument has a must_not_insert flag in its definition"); + + _parameter_tuple_t _columns; + }; + + template + struct interpreter_t> + { + using T = column_list_t; + + static Context& _(const T& t, Context& context) + { + context << " ("; + interpret_tuple(t._columns, ",", context); + context << ")"; + + return context; + } + }; + } +} + +#endif diff --git a/include/sqlpp11/vendor/insert_value.h b/include/sqlpp11/vendor/insert_value.h new file mode 100644 index 00000000..9c6fdf33 --- /dev/null +++ b/include/sqlpp11/vendor/insert_value.h @@ -0,0 +1,101 @@ +/* + * 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_VALUE_H +#define SQLPP_INSERT_VALUE_H + +#include +#include +#include +#include +#include + +namespace sqlpp +{ + namespace vendor + { + template + struct insert_value_t + { + using _is_insert_value = std::true_type; + using _value_t = ValueType; + + insert_value_t(_value_t value): + _is_null(false), + _is_default(false), + _value({value}) + {} + + insert_value_t(tvin_t<_value_t> tvin): + _is_null(tvin._is_trivial()), + _is_default(false), + _value({tvin._value}) + {} + + insert_value_t(const ::sqlpp::null_t&): + _is_null(true), + _is_default(false), + _value() + {} + + insert_value_t(const ::sqlpp::default_value_t&): + _is_null(false), + _is_default(true), + _value() + {} + + insert_value_t(const insert_value_t&) = default; + insert_value_t(insert_value_t&&) = default; + insert_value_t& operator=(const insert_value_t&) = default; + insert_value_t& operator=(insert_value_t&&) = default; + ~insert_value_t() = default; + + bool _is_null; + bool _is_default; + typename wrap_operand<_value_t>::type _value; + }; + + template + struct interpreter_t> + { + using T = insert_value_t; + + static Context& _(const T& t, Context& context) + { + if (t._is_null) + context << "NULL"; + else if (t._is_default) + context << "DEFAULT"; + else + interpret(t._value, context); + return context; + } + }; + + } +} + +#endif diff --git a/include/sqlpp11/vendor/insert_value_list.h b/include/sqlpp11/vendor/insert_value_list.h new file mode 100644 index 00000000..785bbbd1 --- /dev/null +++ b/include/sqlpp11/vendor/insert_value_list.h @@ -0,0 +1,113 @@ +/* + * 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_VALUE_LIST_H +#define SQLPP_INSERT_VALUE_LIST_H + +#include +#include +#include +#include + +namespace sqlpp +{ + namespace vendor + { + template + struct insert_value_list_t + { + using _is_insert_value_list = std::true_type; + + static_assert(sizeof...(InsertValues), "at least one insert value required"); + + // check for invalid arguments + using _insert_values_set = typename ::sqlpp::detail::make_set_if::type; + static_assert(_insert_values_set::size::value == sizeof...(InsertValues), "at least one argument is not an insert value"); + + using _value_tuple_t = std::tuple; + + void add(_value_tuple_t value_tuple) + { + _insert_values.emplace_back(value_tuple); + } + + bool empty() const + { + return _insert_values.empty(); + } + + std::vector<_value_tuple_t> _insert_values; + }; + + template<> + struct insert_value_list_t + { + using _is_insert_value_list = std::true_type; + + using _value_tuple_t = std::tuple<>; + + void add(_value_tuple_t value_tuple) + { + } + + static constexpr bool empty() + { + return true; + } + }; + + template + struct interpreter_t> + { + using T = insert_value_list_t; + + static Context& _(const T& t, Context& context) + { + context << " VALUES "; + for (const auto& row : t._insert_values) + { + context << '('; + interpret_tuple(row, ",", context); + context << ')'; + } + return context; + } + }; + + template + struct interpreter_t> + { + using T = insert_value_list_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; + } +} + +#endif diff --git a/tests/InterpretTest.cpp b/tests/InterpretTest.cpp index 80ad465a..a58e7328 100644 --- a/tests/InterpretTest.cpp +++ b/tests/InterpretTest.cpp @@ -43,6 +43,11 @@ int main() TabSample t; TabFoo f; + interpret(insert_into(t).columns(t.gamma, t.beta), printer).flush(); + interpret(insert_into(t).columns(t.gamma, t.beta).add_values(true, "cheesecake"), printer).flush(); + interpret(insert_into(t).columns(t.gamma, t.beta).add_values(true, "cheesecake").add_values(false, sqlpp::tvin(std::string("coffee"))).add_values(false, sqlpp::tvin(std::string())), printer).flush(); + interpret(insert_into(t).columns(t.gamma, t.beta).add_values(sqlpp::default_value, sqlpp::null), printer).flush(); + interpret(insert_into(t).columns(t.gamma, t.beta), printer).flush(); interpret(t.alpha = sqlpp::null, printer).flush(); interpret(t.alpha = sqlpp::default_value, printer).flush(); interpret(t.alpha, printer).flush();