0
0
mirror of https://github.com/rbock/sqlpp11.git synced 2024-11-15 20:31:16 +08:00

Merge branch 'release/0.58'

This commit is contained in:
rbock 2019-04-18 09:15:31 +02:00
commit e9f6f07677
31 changed files with 414 additions and 58 deletions

View File

@ -13,6 +13,7 @@ compiler:
env:
- CONFIG=Release
- CONFIG=Release TESTS_CXX_STD=17
#- CONFIG=Debug
notifications:
@ -37,7 +38,8 @@ before_script:
sudo apt-get install python-pyparsing;
fi
- if [[ "$CXX" = "g++" && "$CONFIG" = "Debug" && "$TRAVIS_OS_NAME" = "linux" ]]; then export CXXFLAGS="--coverage"; fi
- cmake .. -DCMAKE_BUILD_TYPE=$CONFIG -DCMAKE_PREFIX_PATH=$PWD/../date
- if [[ -n "${TESTS_CXX_STD:-}" && "$TRAVIS_OS_NAME" = "osx" ]]; then ADD_OPTS="-DSQLPP11_TESTS_CXX_STD=$TESTS_CXX_STD"; fi
- cmake .. -DCMAKE_BUILD_TYPE=$CONFIG -DCMAKE_PREFIX_PATH=$PWD/../date $ADD_OPTS
script:
- cmake --build . --config $CONFIG

View File

@ -54,18 +54,19 @@ namespace sqlpp
}
};
template <std::size_t N, const char (&s)[N], typename T>
template <std::size_t N, const char* s, typename T>
struct make_char_sequence_impl;
template <std::size_t N, const char (&s)[N], std::size_t... i>
template <std::size_t N, const char* s, std::size_t... i>
struct make_char_sequence_impl<N, s, sqlpp::detail::index_sequence<i...>>
{
using type = char_sequence<s[i]...>;
};
template <std::size_t N, const char (&Input)[N]>
template <std::size_t N, const char* Input>
using make_char_sequence =
typename make_char_sequence_impl<N, Input, sqlpp::detail::make_index_sequence<N - 1>>::type;
} // namespace sqlpp
#endif

View File

@ -33,6 +33,7 @@
#include <sqlpp11/data_types/blob/data_type.h>
#include <sqlpp11/field_spec.h>
#include <ostream>
#include <string>
namespace sqlpp
{
@ -76,7 +77,9 @@ namespace sqlpp
}
else
{
return os << e.value();
std::vector<uint8_t> value = e.value();
std::string value_str(value.begin(), value.end());
return os << value_str;
}
}
} // namespace sqlpp

View File

@ -29,6 +29,9 @@
#include <string>
#include <utility>
#if __cplusplus >= 201703L
#include <string_view>
#endif
#include <sqlpp11/type_traits.h>
#include <sqlpp11/alias_operators.h>
#include <sqlpp11/serializer.h>
@ -50,6 +53,16 @@ namespace sqlpp
text_operand(_value_t t) : _t(std::move(t))
{
}
#if __cplusplus >= 201703L
// allow construction from an std::string_view
text_operand(std::string_view t) : _t(t)
{
}
// additional const char* overload, required to disambiguate
text_operand(const char* t) : _t(t)
{
}
#endif
text_operand(const text_operand&) = default;
text_operand(text_operand&&) = default;

View File

@ -28,6 +28,9 @@
#define SQLPP11_DATA_TYPES_TEXT_WRAP_OPERAND_H
#include <utility>
#if __cplusplus >= 201703L
#include <string_view>
#endif
#include <sqlpp11/type_traits.h>
#include <sqlpp11/wrap_operand.h>
@ -35,10 +38,16 @@ namespace sqlpp
{
struct text_operand;
#if __cplusplus >= 201703L
using checked_type = std::string_view;
#else
using checked_type = std::string;
#endif
template <typename T>
struct wrap_operand<
T,
typename std::enable_if<std::is_convertible<T, std::string>::value and not is_result_field_t<T>::value>::type>
typename std::enable_if<std::is_convertible<T, checked_type>::value and not is_result_field_t<T>::value>::type>
{
using type = text_operand;
};

View File

@ -102,7 +102,7 @@ namespace sqlpp
template <typename Expression>
void _add_impl(Expression expression, const std::true_type& /*unused*/)
{
return _data._dynamic_expressions.emplace_back(expression);
_data._dynamic_expressions.emplace_back(expression);
}
template <typename Expression>

View File

@ -103,7 +103,7 @@ namespace sqlpp
template <typename Expr>
void _add_impl(Expr expression, const std::true_type& /*unused*/)
{
return _data._dynamic_expressions.emplace_back(expression);
_data._dynamic_expressions.emplace_back(expression);
}
template <typename Expr>

View File

@ -30,6 +30,7 @@
#include <sqlpp11/default_value.h>
#include <sqlpp11/null.h>
#include <sqlpp11/tvin.h>
#include <sqlpp11/value_or_null.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/serializer.h>
#include <sqlpp11/detail/type_set.h>
@ -64,6 +65,7 @@ namespace sqlpp
using _pure_value_t = typename value_type_of<Column>::_cpp_value_type;
using _wrapped_value_t = wrap_operand_t<_pure_value_t>;
using _tvin_t = tvin_t<_wrapped_value_t>;
using _value_or_null_t = value_or_null_t<typename Column::_traits::_value_type>;
insert_value_t(rhs_wrap_t<_wrapped_value_t, _trivial_value_is_null> rhs)
: _is_null(rhs._is_null()), _is_default(rhs._is_default()), _value(rhs._expr._t)
@ -85,6 +87,11 @@ namespace sqlpp
{
}
insert_value_t(const rhs_wrap_t<_value_or_null_t, _trivial_value_is_null>& rhs)
: _is_null(rhs._expr._is_null), _is_default(false), _value{rhs._expr._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;

View File

@ -627,17 +627,17 @@ namespace sqlpp
context << " (";
interpret_tuple(t._columns, ",", context);
context << ")";
context << " VALUES ";
bool first = true;
for (const auto& row : t._insert_values)
{
if (not first)
if (first)
{
context << ',';
context << " VALUES ";
first = false;
}
else
{
first = false;
context << ',';
}
context << '(';
interpret_tuple(row, ",", context);
@ -669,7 +669,10 @@ namespace sqlpp
context << ',';
}
interpret_list(t._dynamic_columns, ',', context);
context << ") VALUES(";
context << ")";
if (sizeof...(Assignments) or not t._dynamic_values.empty())
{
context << " VALUES(";
interpret_tuple(t._values, ",", context);
if (sizeof...(Assignments) and not t._dynamic_values.empty())
{
@ -678,6 +681,7 @@ namespace sqlpp
interpret_list(t._dynamic_values, ',', context);
context << ")";
}
}
return context;
}
};

View File

@ -100,7 +100,7 @@ namespace sqlpp
template <typename Expression>
void _add_impl(Expression expression, const std::true_type& /*unused*/)
{
return _data._dynamic_expressions.emplace_back(expression);
_data._dynamic_expressions.emplace_back(expression);
}
template <typename Expression>

View File

@ -147,7 +147,7 @@ namespace sqlpp
template <typename NamedExpression>
void _add_impl(NamedExpression namedExpression, const std::true_type& /*unused*/)
{
return _data._dynamic_columns.emplace_back(auto_alias_t<NamedExpression>{namedExpression});
_data._dynamic_columns.emplace_back(auto_alias_t<NamedExpression>{namedExpression});
}
template <typename NamedExpression>

View File

@ -96,7 +96,7 @@ namespace sqlpp
template <typename Flag>
void _add_impl(Flag flag, const std::true_type& /*unused*/)
{
return _data._dynamic_flags.emplace_back(flag);
_data._dynamic_flags.emplace_back(flag);
}
template <typename Flag>

View File

@ -52,7 +52,7 @@ namespace sqlpp
using _nodes = detail::type_vector<>;
using _provided_tables = detail::type_set<Table>;
static_assert(sizeof...(ColumnSpec), "at least one column required per table");
static_assert(sizeof...(ColumnSpec) > 0, "at least one column required per table");
using _required_insert_columns =
typename detail::make_type_set_if<require_insert_t, column_t<Table, ColumnSpec>...>::type;
using _column_tuple_t = std::tuple<column_t<Table, ColumnSpec>...>;

View File

@ -100,7 +100,7 @@ namespace sqlpp
template <typename Assignment>
void _add_impl(Assignment assignment, const std::true_type& /*unused*/)
{
return _data._dynamic_assignments.emplace_back(assignment);
_data._dynamic_assignments.emplace_back(assignment);
}
template <typename Assignment>

View File

@ -92,7 +92,7 @@ namespace sqlpp
template <typename Table>
void _add_impl(Table table, const std::true_type& /*unused*/)
{
return _data._dynamic_tables.emplace_back(table);
_data._dynamic_tables.emplace_back(table);
}
template <typename Table>

View File

@ -105,7 +105,7 @@ namespace sqlpp
template <typename Expr>
void _add_impl(Expr expression, const std::true_type& /*unused*/)
{
return _data._dynamic_expressions.emplace_back(expression);
_data._dynamic_expressions.emplace_back(expression);
}
template <typename Expr>

View File

@ -85,6 +85,26 @@ def usage(optionalArgs = {}):
Usage: ddl2cpp <path to ddl> <path to target (without extension, e.g. /tmp/MyTable)> <namespace>\n\
ddl2cpp -help')
def beginHeader(pathToHeader, nsList):
header = open(pathToHeader, 'w')
print('// generated by ' + ' '.join(sys.argv), file=header)
print('#ifndef '+get_include_guard_name(namespace, pathToHeader), file=header)
print('#define '+get_include_guard_name(namespace, pathToHeader), file=header)
print('', file=header)
print('#include <' + INCLUDE + '/table.h>', file=header)
print('#include <' + INCLUDE + '/data_types.h>', file=header)
print('#include <' + INCLUDE + '/char_sequence.h>', file=header)
print('', file=header)
for ns in nsList:
print('namespace ' + ns, file=header)
print('{', file=header)
return header
def endHeader(header, nsList):
for ns in nsList:
print('} // namespace ' + ns, file=header)
print('#endif', file=header)
header.close()
def help_message():
arg_string = '\n'
@ -117,7 +137,8 @@ optionalArgs = {
'-fail-on-parse': "abort instead of silent genereation of unusable headers", # failOnParse = True
'-warn-on-parse': "warn about unusable headers, but continue", # warnOnParse = True
'-auto-id': "Assume column 'id' to have an automatic value as if AUTO_INCREMENT was specified (e.g. implicit for SQLite ROWID)", # autoId = True
'-identity-naming': "Use table and column names from the ddl (defaults to UpperCamelCase for tables and lowerCamelCase for columns", # identityNaming = True
'-identity-naming': "Use table and column names from the ddl (defaults to UpperCamelCase for tables and lowerCamelCase for columns)", # identityNaming = True
'-split-tables': "Make a header for each table name, using target as a directory", # splitTables = True
'-help': "show this help"
}
@ -135,6 +156,7 @@ warnOnParse = False
parseError = "Parsing error, possible reason: can't parse default value for a field"
autoId = False
identityNaming = False
splitTables = False
if len(sys.argv) >= 4:
@ -155,7 +177,7 @@ if identityNaming:
pathToDdl = sys.argv[firstPositional]
pathToHeader = sys.argv[firstPositional + 1] + '.h'
pathToHeader = sys.argv[firstPositional + 1] + ('/' if splitTables else '.h')
namespace = sys.argv[firstPositional + 2]
@ -193,6 +215,7 @@ ddlNotNull = Group(ddlWord("NOT") + ddlWord("NULL")).setResultsName("notNull")
ddlDefaultValue = ddlWord("DEFAULT").setResultsName("hasDefaultValue")
ddlAutoValue = Or([
ddlWord("AUTO_INCREMENT"),
ddlWord("AUTOINCREMENT"),
ddlWord("SMALLSERIAL"),
ddlWord("SERIAL"),
ddlWord("BIGSERIAL"),
@ -246,6 +269,7 @@ types = {
'float8': 'floating_point', # PostgreSQL
'float': 'floating_point',
'float4': 'floating_point', # PostgreSQL
'real': 'floating_point',
'numeric': 'floating_point', # PostgreSQL
'date': 'day_point',
'datetime': 'time_point',
@ -298,21 +322,14 @@ def escape_if_reserved(name):
# PROCESS DDL
tableCreations = ddl.parseFile(pathToDdl)
header = open(pathToHeader, 'w')
print('// generated by ' + ' '.join(sys.argv), file=header)
print('#ifndef '+get_include_guard_name(namespace, pathToHeader), file=header)
print('#define '+get_include_guard_name(namespace, pathToHeader), file=header)
print('', file=header)
print('#include <' + INCLUDE + '/table.h>', file=header)
print('#include <' + INCLUDE + '/data_types.h>', file=header)
print('#include <' + INCLUDE + '/char_sequence.h>', file=header)
print('', file=header)
for ns in nsList:
print('namespace ' + ns, file=header)
print('{', file=header)
header = 0
if not splitTables:
header = beginHeader(pathToHeader, nsList)
DataTypeError = False
for create in tableCreations:
sqlTableName = create.tableName
if splitTables:
header = beginHeader(pathToHeader + sqlTableName + '.h', nsList)
tableClass = toClassName(sqlTableName)
tableMember = toMemberName(sqlTableName)
tableNamespace = tableClass + '_'
@ -386,10 +403,11 @@ for create in tableCreations:
print(' };', file=header)
print(' };', file=header)
print(' };', file=header)
if splitTables:
endHeader(header, nsList)
for ns in nsList:
print('} // namespace ' + ns, file=header)
print('#endif', file=header)
if not splitTables:
endHeader(header, nsList)
if (DataTypeError):
print("Error: unsupported datatypes." )
print("Possible solutions:")

199
scripts/sqlite2cpp.py Normal file
View File

@ -0,0 +1,199 @@
#!/usr/bin/env python3
##
# Copyright (c) 2013-2015, Roland Bock
# Copyright (c) 2018, Egor Pugin
# 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.
##
import argparse
import os
import re
import sqlite3
import sys
INCLUDE = 'sqlpp11'
NAMESPACE = 'sqlpp'
# map sqlite3 types
types = {
'integer': 'integer',
'text': 'text',
'blob': 'blob',
'real': 'floating_point',
}
def main():
parser = argparse.ArgumentParser(description='sqlpp11 cpp schema generator')
parser.add_argument('ddl', help='path to ddl')
parser.add_argument('target', help='path to target')
parser.add_argument('namespace', help='namespace')
args = parser.parse_args()
pathToHeader = args.target + '.h'
# execute schema scripts
conn = sqlite3.connect(':memory:')
conn.executescript(open(args.ddl).read())
# set vars
toClassName = class_name_naming_func
toMemberName = member_name_naming_func
DataTypeError = False
header = open(pathToHeader, 'w')
namespace = args.namespace
nsList = namespace.split('::')
# start printing
print('// generated by ' + ' '.join(sys.argv), file=header)
print('#ifndef '+get_include_guard_name(namespace, pathToHeader), file=header)
print('#define '+get_include_guard_name(namespace, pathToHeader), file=header)
print('', file=header)
print('#include <' + INCLUDE + '/table.h>', file=header)
print('#include <' + INCLUDE + '/data_types.h>', file=header)
print('#include <' + INCLUDE + '/char_sequence.h>', file=header)
print('', file=header)
for ns in nsList:
print('namespace ' + ns, file=header)
print('{', file=header)
cursor = conn.cursor()
cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
tables = cursor.fetchall()
for table_name in tables:
table_name = table_name[0]
if table_name.startswith('sqlite_'):
continue
sqlTableName = table_name
tableClass = toClassName(sqlTableName)
tableMember = toMemberName(sqlTableName)
tableNamespace = tableClass + '_'
tableTemplateParameters = tableClass
print(' namespace ' + tableNamespace, file=header)
print(' {', file=header)
columns = cursor.execute("PRAGMA table_info('%s')" % table_name).fetchall()
for column in columns:
sqlColumnName = column[1]
columnClass = toClassName(sqlColumnName)
tableTemplateParameters += ',\n ' + tableNamespace + '::' + columnClass
columnMember = toMemberName(sqlColumnName)
sqlColumnType = column[2].lower()
print(' struct ' + columnClass, file=header)
print(' {', file=header)
print(' struct _alias_t', file=header)
print(' {', file=header)
print(' static constexpr const char _literal[] = "' + escape_if_reserved(sqlColumnName) + '";', file=header)
print(' using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;', file=header)
print(' template<typename T>', file=header)
print(' struct _member_t', file=header)
print(' {', file=header)
print(' T ' + columnMember + ';', file=header)
print(' T& operator()() { return ' + columnMember + '; }', file=header)
print(' const T& operator()() const { return ' + columnMember + '; }', file=header)
print(' };', file=header)
print(' };', file=header)
try:
traitslist = [NAMESPACE + '::' + types[sqlColumnType]]
except KeyError as e:
print ('Error: datatype "' + sqlColumnType + '"" is not supported.')
DataTypeError = True
requireInsert = True
hasAutoValue = sqlColumnName == 'id'
if hasAutoValue:
traitslist.append(NAMESPACE + '::tag::must_not_insert')
traitslist.append(NAMESPACE + '::tag::must_not_update')
requireInsert = False
if column[3] == '0':
traitslist.append(NAMESPACE + '::tag::can_be_null')
requireInsert = False
if column[4]:
requireInsert = False
if requireInsert:
traitslist.append(NAMESPACE + '::tag::require_insert')
print(' using _traits = ' + NAMESPACE + '::make_traits<' + ', '.join(traitslist) + '>;', file=header)
print(' };', file=header)
print(' } // namespace ' + tableNamespace, file=header)
print('', file=header)
print(' struct ' + tableClass + ': ' + NAMESPACE + '::table_t<' + tableTemplateParameters + '>', file=header)
print(' {', file=header)
print(' struct _alias_t', file=header)
print(' {', file=header)
print(' static constexpr const char _literal[] = "' + sqlTableName + '";', file=header)
print(' using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;', file=header)
print(' template<typename T>', file=header)
print(' struct _member_t', file=header)
print(' {', file=header)
print(' T ' + tableMember + ';', file=header)
print(' T& operator()() { return ' + tableMember + '; }', file=header)
print(' const T& operator()() const { return ' + tableMember + '; }', file=header)
print(' };', file=header)
print(' };', file=header)
print(' };', file=header)
for ns in nsList:
print('} // namespace ' + ns, file=header)
print('#endif', file=header)
if (DataTypeError):
print("Error: unsupported datatypes." )
print("Possible solutions:")
print("A) Implement this datatype (examples: sqlpp11/data_types)" )
print("B) Extend/upgrade ddl2cpp (edit types map)" )
print("C) Raise an issue on github" )
sys.exit(10) #return non-zero error code, we might need it for automation
def get_include_guard_name(namespace, inputfile):
val = re.sub("[^A-Za-z0-9]+", "_", namespace + '_' + os.path.basename(inputfile))
return val.upper()
def repl_camel_case_func(m):
if m.group(1) == '_':
return m.group(2).upper()
else:
return m.group(1) + m.group(2).upper()
def class_name_naming_func(s):
return re.sub("(^|\s|[_0-9])(\S)", repl_camel_case_func, s)
def member_name_naming_func(s):
return re.sub("(\s|_|[0-9])(\S)", repl_camel_case_func, s)
def escape_if_reserved(name):
reserved_names = [
'GROUP',
'ORDER',
]
if name.upper() in reserved_names:
return '!{}'.format(name)
return name
if __name__ == '__main__':
main()
sys.exit(0)

View File

@ -31,6 +31,12 @@ function(test_constraint name pattern)
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target ${target}
)
set_property(TEST ${test} PROPERTY PASS_REGULAR_EXPRESSION ${pattern})
# conditionally bump to a higher C++ standard to test compatibility
if (SQLPP11_TESTS_CXX_STD)
set_property(TARGET ${target} PROPERTY CXX_STANDARD ${SQLPP11_TESTS_CXX_STD})
set_property(TARGET ${target} PROPERTY CXX_STANDARD_REQUIRED yes)
set_property(TARGET ${target} PROPERTY CXX_EXTENSIONS no)
endif()
endfunction()
# Compiling these is required to fail (testing some static_assert)

View File

@ -38,6 +38,13 @@ create_test_sourcelist(test_serializer_sources test_serializer_main.cpp ${test_s
add_executable(sqlpp11_test_serializer ${test_serializer_sources})
target_link_libraries(sqlpp11_test_serializer PRIVATE sqlpp11 sqlpp11_testing)
# conditionally bump to a higher C++ standard to test compatibility
if (SQLPP11_TESTS_CXX_STD)
set_property(TARGET sqlpp11_test_serializer PROPERTY CXX_STANDARD ${SQLPP11_TESTS_CXX_STD})
set_property(TARGET sqlpp11_test_serializer PROPERTY CXX_STANDARD_REQUIRED yes)
set_property(TARGET sqlpp11_test_serializer PROPERTY CXX_EXTENSIONS no)
endif()
foreach(test_serializer IN LISTS test_serializer_names)
add_test(NAME sqlpp11.test_serializer.${test_serializer}
COMMAND sqlpp11_test_serializer ${test_serializer}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2016, Roland Bock
* Copyright (c) 2016-2019, Roland Bock
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
@ -38,7 +38,8 @@ int CustomQuery(int, char* [])
auto db = MockDb{};
// Unconditionally
compare(__LINE__, custom_query(sqlpp::select(), select_flags(sqlpp::distinct), select_columns(foo.omega), from(foo),
compare(__LINE__,
custom_query(sqlpp::select(), select_flags(sqlpp::distinct), select_columns(foo.omega), from(foo),
sqlpp::unconditionally()),
"SELECT DISTINCT tab_foo.omega FROM tab_foo ");
@ -68,5 +69,16 @@ int CustomQuery(int, char* [])
custom_query(sqlpp::verbatim("PRAGMA user_version")).with_result_type_of(select(sqlpp::value(1).as(pragma))),
" PRAGMA user_version");
// An insert from select for postgresql
const auto x = 17;
compare(__LINE__,
custom_query(insert_into(foo).columns(foo.omega),
select(sqlpp::value(x).as(foo.omega))
.from(foo)
.where(not exists(select(foo.omega).from(foo).where(foo.omega == x)))),
"INSERT INTO tab_foo (omega) "
"SELECT 17 AS omega FROM tab_foo "
"WHERE (NOT EXISTS(SELECT tab_foo.omega FROM tab_foo WHERE (tab_foo.omega=17)))");
return 0;
}

View File

@ -45,6 +45,12 @@ int Insert(int, char* [])
compare(__LINE__, insert_into(bar).default_values(), "INSERT INTO tab_bar DEFAULT VALUES");
compare(__LINE__, insert_into(bar).set(bar.beta = "cheesecake", bar.gamma = true),
"INSERT INTO tab_bar (beta,gamma) VALUES('cheesecake'," + getTrue() + ")");
#if __cplusplus >= 201703L
// string_view argument
std::string_view cheeseCake = "cheesecake";
compare(__LINE__, insert_into(bar).set(bar.beta = cheeseCake, bar.gamma = true),
"INSERT INTO tab_bar (beta,gamma) VALUES('cheesecake'," + getTrue() + ")");
#endif
return 0;
}

View File

@ -62,6 +62,11 @@ int Where(int, char* [])
compare(__LINE__, where(bar.gamma), " WHERE tab_bar.gamma");
compare(__LINE__, where(bar.gamma == false), " WHERE (tab_bar.gamma=" + getFalse() + ")");
compare(__LINE__, where(bar.beta == "SQL"), " WHERE (tab_bar.beta='SQL')");
#if __cplusplus >= 201703L
// string_view argument
std::string_view sqlString = "SQL";
compare(__LINE__, where(bar.beta == sqlString), " WHERE (tab_bar.beta='SQL')");
#endif
return 0;
}

View File

@ -26,6 +26,12 @@ function(test_compile name)
set(target sqlpp11_assert_${name})
add_executable(${target} ${name}.cpp)
target_link_libraries(${target} PRIVATE sqlpp11 sqlpp11_testing)
# conditionally bump to a higher C++ standard to test compatibility
if (SQLPP11_TESTS_CXX_STD)
set_property(TARGET sqlpp11_assert_${name} PROPERTY CXX_STANDARD ${SQLPP11_TESTS_CXX_STD})
set_property(TARGET sqlpp11_assert_${name} PROPERTY CXX_STANDARD_REQUIRED yes)
set_property(TARGET sqlpp11_assert_${name} PROPERTY CXX_EXTENSIONS no)
endif()
endfunction()
test_compile(aggregates)

View File

@ -26,6 +26,12 @@ function(test_compile name)
set(target sqlpp11_${name})
add_executable(${target} ${name}.cpp)
target_link_libraries(${target} PRIVATE sqlpp11 sqlpp11_testing)
# conditionally bump to a higher C++ standard to test compatibility
if (SQLPP11_TESTS_CXX_STD)
set_property(TARGET sqlpp11_${name} PROPERTY CXX_STANDARD ${SQLPP11_TESTS_CXX_STD})
set_property(TARGET sqlpp11_${name} PROPERTY CXX_STANDARD_REQUIRED yes)
set_property(TARGET sqlpp11_${name} PROPERTY CXX_EXTENSIONS no)
endif()
endfunction()
test_compile(result_row)

View File

@ -34,6 +34,7 @@ int BooleanExpression(int, char* [])
const auto t = test::TabBar{};
auto x = boolean_expression(db, not(t.alpha == 7));
x = sqlpp::boolean_expression(db, true);
x = sqlpp::boolean_expression<MockDb>(t.beta.like("%cheesecake"));
x = x and boolean_expression(db, t.gamma);

View File

@ -57,6 +57,12 @@ endif()
create_test_sourcelist(test_sources test_main.cpp ${test_names})
add_executable(sqlpp11_tests ${test_sources})
target_link_libraries(sqlpp11_tests PRIVATE sqlpp11 sqlpp11_testing)
# conditionally bump to a higher C++ standard to test compatibility
if (SQLPP11_TESTS_CXX_STD)
set_property(TARGET sqlpp11_tests PROPERTY CXX_STANDARD ${SQLPP11_TESTS_CXX_STD})
set_property(TARGET sqlpp11_tests PROPERTY CXX_STANDARD_REQUIRED yes)
set_property(TARGET sqlpp11_tests PROPERTY CXX_EXTENSIONS no)
endif()
foreach(test IN LISTS test_names)
add_test(NAME sqlpp11.tests.${test}

View File

@ -29,6 +29,34 @@
#include <sqlpp11/sqlpp11.h>
#include <sqlpp11/custom_query.h>
namespace
{
struct on_duplicate_key_update
{
std::string _serialized;
template <typename Db, typename Assignment>
on_duplicate_key_update(Db&, Assignment assignment)
{
typename Db::_serializer_context_t context;
_serialized = " ON DUPLICATE KEY UPDATE " + serialize(assignment, context).str();
}
template <typename Db, typename Assignment>
auto operator()(Db&, Assignment assignment) -> on_duplicate_key_update&
{
typename Db::_serializer_context_t context;
_serialized += ", " + serialize(assignment, context).str();
return *this;
}
auto get() const -> sqlpp::verbatim_t<::sqlpp::no_value_t>
{
return ::sqlpp::verbatim(_serialized);
}
};
} // namespace
int CustomQuery(int, char*[])
{
MockDb db = {};
@ -61,6 +89,10 @@ int CustomQuery(int, char* [])
db(custom_query(sqlpp::insert(), sqlpp::verbatim(" OR IGNORE"), into(t),
insert_set(t.beta = "sample", t.gamma = true)));
// Create a MYSQL style custom "insert on duplicate update"
db(custom_query(sqlpp::insert_into(t).set(t.beta = "sample", t.gamma = true),
on_duplicate_key_update(db, t.beta = "sample")(db, t.gamma = false).get()));
// 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();
@ -69,6 +101,10 @@ int CustomQuery(int, char* [])
auto i = db(c);
static_assert(std::is_integral<decltype(i)>::value, "insert yields an integral value");
auto d = custom_query(sqlpp::verbatim("INSERT INTO tab_sample VALUES()")).with_result_type_of(sqlpp::insert());
auto j = db(d);
static_assert(std::is_integral<decltype(j)>::value, "insert yields an integral value");
for (const auto& row :
db(custom_query(sqlpp::verbatim("PRAGMA user_version")).with_result_type_of(select(all_of(t)))))
{

View File

@ -51,6 +51,8 @@ int DateTime(int, char* [])
{
std::cout << row.colDayPoint;
std::cout << row.colTimePoint;
const auto tp = std::chrono::system_clock::time_point{row.colTimePoint.value()};
std::cout << std::chrono::system_clock::to_time_t(tp);
}
printer.reset();
std::cerr << serialize(::sqlpp::value(std::chrono::system_clock::now()), printer).str() << std::endl;

View File

@ -352,9 +352,9 @@ int Function(int, char* [])
using TT = decltype(sqlpp::value("cheesecake"));
static_assert(not sqlpp::is_selectable_t<TB>::value, "type requirement");
static_assert(sqlpp::is_boolean_t<TB>::value, "type requirement");
static_assert(not sqlpp::is_selectable_t<TB>::value, "type requirement");
static_assert(sqlpp::is_integral_t<TI>::value, "type requirement");
static_assert(not sqlpp::is_selectable_t<TI>::value, "type requirement");
static_assert(sqlpp::is_integral_t<TI>::value, "type requirement");
static_assert(not sqlpp::is_selectable_t<TF>::value, "type requirement");
static_assert(sqlpp::is_floating_point_t<TF>::value, "type requirement");
static_assert(not sqlpp::is_selectable_t<TT>::value, "type requirement");
static_assert(sqlpp::is_text_t<TT>::value, "type requirement");
@ -368,9 +368,9 @@ int Function(int, char* [])
using TT = decltype(flatten(t.beta, db));
static_assert(not sqlpp::is_selectable_t<TB>::value, "type requirement");
static_assert(sqlpp::is_boolean_t<TB>::value, "type requirement");
static_assert(not sqlpp::is_selectable_t<TB>::value, "type requirement");
static_assert(sqlpp::is_integral_t<TI>::value, "type requirement");
static_assert(not sqlpp::is_selectable_t<TI>::value, "type requirement");
static_assert(sqlpp::is_integral_t<TI>::value, "type requirement");
static_assert(not sqlpp::is_selectable_t<TF>::value, "type requirement");
static_assert(sqlpp::is_floating_point_t<TF>::value, "type requirement");
static_assert(not sqlpp::is_selectable_t<TT>::value, "type requirement");
static_assert(sqlpp::is_text_t<TT>::value, "type requirement");
@ -392,9 +392,9 @@ int Function(int, char* [])
static_assert(std::is_same<TT, TTN>::value, "type_requirement");
static_assert(not sqlpp::is_selectable_t<TB>::value, "type requirement");
static_assert(sqlpp::is_boolean_t<TB>::value, "type requirement");
static_assert(not sqlpp::is_selectable_t<TB>::value, "type requirement");
static_assert(sqlpp::is_integral_t<TI>::value, "type requirement");
static_assert(not sqlpp::is_selectable_t<TI>::value, "type requirement");
static_assert(sqlpp::is_integral_t<TI>::value, "type requirement");
static_assert(not sqlpp::is_selectable_t<TF>::value, "type requirement");
static_assert(sqlpp::is_floating_point_t<TF>::value, "type requirement");
static_assert(not sqlpp::is_selectable_t<TT>::value, "type requirement");
static_assert(sqlpp::is_text_t<TT>::value, "type requirement");
@ -411,9 +411,9 @@ int Function(int, char* [])
static_assert(sqlpp::is_boolean_t<TB>::value, "type requirement");
static_assert(sqlpp::is_selectable_t<TBS>::value, "type requirement");
static_assert(sqlpp::is_boolean_t<TBS>::value, "type requirement");
static_assert(not sqlpp::is_selectable_t<TB>::value, "type requirement");
static_assert(sqlpp::is_integral_t<TI>::value, "type requirement");
static_assert(not sqlpp::is_selectable_t<TI>::value, "type requirement");
static_assert(sqlpp::is_integral_t<TI>::value, "type requirement");
static_assert(not sqlpp::is_selectable_t<TF>::value, "type requirement");
static_assert(sqlpp::is_floating_point_t<TF>::value, "type requirement");
static_assert(not sqlpp::is_selectable_t<TT>::value, "type requirement");
static_assert(sqlpp::is_text_t<TT>::value, "type requirement");

View File

@ -54,6 +54,8 @@ int Insert(int, char*[])
db(insert_into(t).default_values());
db(insert_into(t).set(t.gamma = true, t.beta = "kirschauflauf"));
db(insert_into(t).set(t.gamma = sqlpp::default_value, t.beta = sqlpp::value_or_null("pie"),
t.delta = sqlpp::value_or_null<sqlpp::integer>(sqlpp::null)));
serialize(insert_into(t).default_values(), printer).str();
@ -64,6 +66,11 @@ int Insert(int, char*[])
multi_insert.values.add(t.gamma = true, t.beta = "cheesecake", t.delta = 1);
multi_insert.values.add(t.gamma = sqlpp::default_value, t.beta = sqlpp::default_value,
t.delta = sqlpp::default_value);
multi_insert.values.add(t.gamma = sqlpp::value_or_null(true), t.beta = sqlpp::value_or_null("pie"),
t.delta = sqlpp::value_or_null<sqlpp::integer>(sqlpp::null));
printer.reset();
std::cerr << serialize(multi_insert, printer).str() << std::endl;
auto i = dynamic_insert_into(db, t).dynamic_set();
i.insert_list.add(t.beta = "kirschauflauf");
printer.reset();