diff --git a/.travis.yml b/.travis.yml index 8b3185e2..e143ced8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,11 +2,20 @@ language: cpp os: - linux - - osx -dist: bionic +dist: focal sudo: required +services: + - mysql + +addons: + apt: + packages: + - sqlite3 + - libboost-dev + - python-pyparsing + compiler: - clang - gcc @@ -21,29 +30,12 @@ notifications: on_success: change on_failure: always -install: - - g++ --version - - 'if [ "$TRAVIS_OS_NAME" = "osx" ]; then - brew upgrade cmake; - else - wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null && - sudo apt-add-repository -y "deb https://apt.kitware.com/ubuntu/ bionic main" && - sudo apt-get update -qq -y && - sudo apt-get install -y cmake && - sudo rm -r /usr/local/cmake-3.12.4/; - fi' - before_script: - - mkdir build - - cd build - - if [[ "$CONFIG" = "Debug" && "$TRAVIS_OS_NAME" = "linux" ]]; then - cp -r ../scripts/ . && - cp -r ../test_scripts/ . && - sudo apt-get install python-pyparsing; - fi + - mysql --version + - (while ! mysqladmin -u root status ; do sleep 1; done) # wait for mysql to start + - mysqladmin -u root create sqlpp_mysql - if [[ "$CXX" = "g++" && "$CONFIG" = "Debug" && "$TRAVIS_OS_NAME" = "linux" ]]; then export CXXFLAGS="--coverage"; fi - - 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 + - cmake -B build -DCMAKE_BUILD_TYPE=$CONFIG -DBUILD_MYSQL_CONNECTOR=ON -DBUILD_SQLITE3_CONNECTOR=ON script: - cmake --build . --config $CONFIG diff --git a/CMakeLists.txt b/CMakeLists.txt index b8de9fa4..a83ac431 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2013-2016, Roland Bock +# Copyright (c) 2013-2021, Roland Bock # Copyright (c) 2016 Christian Dávid # All rights reserved. # @@ -30,97 +30,124 @@ project(sqlpp11 VERSION 0.1 LANGUAGES CXX) ### Project Wide Setup list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") +include(GNUInstallDirs) include(CTest) +option(BUILD_MYSQL_CONNECTOR "Build MySQL Connector" OFF) +option(BUILD_MARIADB_CONNECTOR "Build MariaDB Connector" OFF) +option(BUILD_POSTGRESQL_CONNECTOR "Build PostgreSQL Connector" OFF) +option(BUILD_SQLITE3_CONNECTOR "Build SQLite3 Connector" OFF) +option(BUILD_SQLCIPHER_CONNECTOR "Build SQLite3 Connector with SQLCipher" OFF) + +option(DEPENDENCY_CHECK "Check for dependencies of connector and the library" ON) + +option(USE_SYSTEM_DATE "\ + Use find_package to find installed HowardHinnant's \ + date library instead of fetching it from github" OFF +) + +set(SQLPP11_INSTALL_CMAKEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/Sqlpp11 CACHE STRING "Path to sqlpp11 cmake files") + +### Dependencies +if(DEPENDENCY_CHECK AND BUILD_MYSQL_CONNECTOR) + find_package(MySQL REQUIRED) +endif() + +if(DEPENDENCY_CHECK AND BUILD_MARIADB_CONNECTOR) + find_package(MariaDB REQUIRED) +endif() + +if(DEPENDENCY_CHECK AND BUILD_POSTGRESQL_CONNECTOR) + find_package(PostgreSQL REQUIRED) +endif() + +if(DEPENDENCY_CHECK AND BUILD_SQLITE3_CONNECTOR) + find_package(SQLite3 REQUIRED) +endif() + +if(DEPENDENCY_CHECK AND BUILD_SQLCIPHER_CONNECTOR) + find_package(SQLCipher REQUIRED) +endif() + +if(DEPENDENCY_CHECK AND USE_SYSTEM_DATE) + find_package(date REQUIRED) +endif() -### Dependencies add_subdirectory(dependencies) -### Main targets +### Core targets +include(Sqlpp11TargetHelper) + add_library(sqlpp11 INTERFACE) add_library(sqlpp11::sqlpp11 ALIAS sqlpp11) target_link_libraries(sqlpp11 INTERFACE date::date) - target_include_directories(sqlpp11 INTERFACE - $ - $ - ) + $ +) +target_compile_features(sqlpp11 INTERFACE cxx_std_11) -target_compile_features(sqlpp11 INTERFACE - cxx_alias_templates - cxx_auto_type - cxx_constexpr - cxx_decltype - cxx_defaulted_functions - cxx_defaulted_move_initializers - cxx_deleted_functions - cxx_explicit_conversions - cxx_lambdas - cxx_noexcept - cxx_nullptr - cxx_range_for - cxx_right_angle_brackets - cxx_rvalue_references - cxx_static_assert - cxx_trailing_return_types - cxx_uniform_initialization - cxx_template_template_parameters - cxx_variadic_templates - ) + +if(BUILD_SQLITE3_CONNECTOR) + add_component(NAME sqlite3 DEPENDENCIES SQLite::SQLite3) +endif() + +if(BUILD_SQLCIPHER_CONNECTOR) + add_component(NAME sqlcipher DEPENDENCIES SQLite::SQLCipher) + target_compile_definitions(sqlpp11_sqlcipher INTERFACE SQLPP_USE_SQLCIPHER) +endif() + +if(BUILD_MYSQL_CONNECTOR) + add_component(NAME mysql DEPENDENCIES MySQL::MySQL) +endif() + +if(BUILD_MARIADB_CONNECTOR) + add_component(NAME mariadb DEPENDENCIES MariaDB::MariaDB) +endif() + +if(BUILD_POSTGRESQL_CONNECTOR) + add_component(NAME postgresql DEPENDENCIES PostgreSQL::PostgreSQL) +endif() ### Packaging -install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/sqlpp11" - DESTINATION include -) - -install(TARGETS sqlpp11 - EXPORT Sqlpp11Targets -) - -install(PROGRAMS "${PROJECT_SOURCE_DIR}/scripts/ddl2cpp" +install(PROGRAMS ${PROJECT_SOURCE_DIR}/scripts/ddl2cpp RENAME sqlpp11-ddl2cpp - DESTINATION bin + DESTINATION ${CMAKE_INSTALL_BINDIR} ) -include(CMakePackageConfigHelpers) - -write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/cmake/Sqlpp11ConfigVersion.cmake" - VERSION ${PROJECT_VERSION} - COMPATIBILITY AnyNewerVersion +write_basic_package_version_file(Sqlpp11ConfigVersion.cmake + COMPATIBILITY SameMajorVersion + ARCH_INDEPENDENT ) -export(EXPORT Sqlpp11Targets - FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/Sqlpp11Targets.cmake" +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Sqlpp11ConfigVersion.cmake + DESTINATION ${SQLPP11_INSTALL_CMAKEDIR} ) -configure_file(cmake/Sqlpp11Config.cmake - "${CMAKE_CURRENT_BINARY_DIR}/cmake/Sqlpp11Config.cmake" - COPYONLY -) +install_component(NAME Sqlpp11 TARGETS sqlpp11 DIRECTORY) -set(ConfigPackageLocation lib/cmake/Sqlpp11) -install(EXPORT Sqlpp11Targets - NAMESPACE sqlpp11:: - DESTINATION - ${ConfigPackageLocation} -) +if(BUILD_SQLITE3_CONNECTOR) + install_component(NAME Sqlpp11SQLite3 TARGETS sqlpp11_sqlite3 DIRECTORY sqlite3) +endif() + +if(BUILD_SQLCIPHER_CONNECTOR) + install_component(NAME Sqlpp11SQLCipher TARGETS sqlpp11_sqlcipher DIRECTORY sqlite3) +endif() + +if(BUILD_MYSQL_CONNECTOR) + install_component(NAME Sqlpp11MySQL TARGETS sqlpp11_mysql DIRECTORY mysql) +endif() + +if(BUILD_MARIADB_CONNECTOR) + install_component(NAME Sqlpp11MariaDB TARGETS sqlpp11_mariadb DIRECTORY mysql) +endif() + +if(BUILD_POSTGRESQL_CONNECTOR) + install_component(NAME Sqlpp11PostgreSQL TARGETS sqlpp11_postgresql DIRECTORY postgresql) +endif() -install( - FILES - "cmake/Sqlpp11Config.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/cmake/Sqlpp11ConfigVersion.cmake" - DESTINATION - ${ConfigPackageLocation} -) ### Tests if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING) add_subdirectory(tests) - add_subdirectory(test_types) - add_subdirectory(test_serializer) - add_subdirectory(test_static_asserts) - add_subdirectory(test_constraints) - add_subdirectory(test_scripts) endif() diff --git a/README.md b/README.md index 10a1893c..bf4c19a0 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ sqlpp11 ======= A type safe embedded domain specific language for SQL queries and results in C++ -Documentation is found in the [wiki](https://github.com/rbock/sqlpp11/wiki) +Documentation is found in [docs](docs/Home.md). So what is this about? ---------------------- @@ -20,9 +20,15 @@ This results in several benefits, e.g. * the compiler reports many kinds of errors long before the code enters unit testing or production, * the library hides the gory details of string construction for queries and interpreting results returned by select calls. -The library supports both static and dynamic queries. The former offers greater benefit in terms of type and consistency checking. The latter makes it easier to construct queries on the flight. +The library supports both static and dynamic queries. The former offers greater benefit in terms of type and consistency checking. The latter makes it easier to construct queries in flight. -sqlpp11 is vendor-neutral. Specific traits of databases (e.g. unsupported or non-standard features) are handled by connector libraries. Connector libraries can inform the developer of missing features at compile time. They also interpret expressions specifically where needed. For example, the connector could use the operator|| or the concat method for string concatenation without the developer being required to change the statement. +sqlpp11’s core is vendor-neutral. +Specific traits of databases (e.g. unsupported or non-standard features) are handled by connector libraries. +Connector libraries can inform the developer of missing features at compile time. +They also interpret expressions specifically where needed. +For example, the connector could use the operator|| or the concat method for string concatenation without the developer being required to change the statement. + +Connectors for MySQL, MariaDB, sqlite3, sqlcipher are included in this repository. The library is already used in production but it is certainly not complete yet. Feature requests, bug reports, contributions to code or documentation are most welcome. @@ -88,8 +94,8 @@ sqlpp11 is distributed under the [BSD 2-Clause License](https://github.com/rbock Status: ------- -Branch / Compiler | clang-3.4, gcc-4.9, Xcode-7 | MSVC 2015/2017 | Test Coverage -------------------| -------------------------------|-------------|--------------- +Branch / Compiler | clang, gcc | MSVC | Test Coverage +------------------|-------------|--------|--------------- master | [![Build Status](https://travis-ci.com/rbock/sqlpp11.svg?branch=master)](https://travis-ci.com/rbock/sqlpp11?branch=master) | [![Build status](https://ci.appveyor.com/api/projects/status/eid7mwqgavo0h61h/branch/master?svg=true)](https://ci.appveyor.com/project/rbock/sqlpp11/branch/master) | [![Coverage Status](https://coveralls.io/repos/rbock/sqlpp11/badge.svg?branch=master)](https://coveralls.io/r/rbock/sqlpp11?branch=master) develop | [![Build Status](https://travis-ci.com/rbock/sqlpp11.svg?branch=develop)](https://travis-ci.com/rbock/sqlpp11?branch=develop) | [![Build status](https://ci.appveyor.com/api/projects/status/eid7mwqgavo0h61h/branch/develop?svg=true)](https://ci.appveyor.com/project/rbock/sqlpp11/branch/develop) | [![Coverage Status](https://coveralls.io/repos/rbock/sqlpp11/badge.svg?branch=develop)](https://coveralls.io/r/rbock/sqlpp11?branch=develop) @@ -108,8 +114,6 @@ Past talks about sqlpp11 and some coding concepts used within the library: * 2014-02-27: [Selected C++11 Template Toffees From sqlpp11, Part1](https://www.youtube.com/watch?v=hXnGFYNbmXg), [Part2](https://www.youtube.com/watch?v=WPCV6dvxZ_U), [Part 3](https://www.youtube.com/watch?v=eB7hd_KjTig), [Part 4](https://www.youtube.com/watch?v=NBfqzcN0_EQ) - - Requirements: ------------- __Compiler:__ @@ -125,17 +129,20 @@ sqlpp11 makes heavy use of C++11 and requires a recent compiler and STL. The fol __Database Connector:__ sqlpp11 requires a certain api in order to connect with the database, see database/api.h. - * MySQL: https://github.com/rbock/sqlpp11-connector-mysql - * Sqlite3: https://github.com/rbock/sqlpp11-connector-sqlite3 - * PostgreSQL: https://github.com/matthijs/sqlpp11-connector-postgresql +This repository includes the following connectors: + +* MySQL +* MariaDB +* SQLite3 +* SQLCipher +* PostgreSQL + +Other connectors can be found here: + * ODBC: https://github.com/Erroneous1/sqlpp11-connector-odbc (experimental) -To demonstrate that sqlpp11 can work with other backends as well, here is an experimental backend for structs in standard containers: - - * STL Container: https://github.com/rbock/sqlpp11-connector-stl - __Date Library:__ -sqlpp11 requires [Howard Hinnant's date library](https://github.com/HowardHinnant/date) for `date` and `date_time` data types. Sqlpp11 uses FetchContent to pull the library automatically in the project. +sqlpp11 requires [Howard Hinnant’s date library](https://github.com/HowardHinnant/date) for `date` and `date_time` data types. By default, sqlpp11 uses FetchContent to pull the library automatically in the project. If you want to use an already installed version of the library with `find_package`, set `USE_SYSTEM_DATE` option to `ON`. Build and Install ----------------- @@ -151,7 +158,24 @@ cmake -B build cmake --build build --target install ``` -The last step will build the library and install it system wide, therefore it might need admins right. +The last step will build the library and install it system wide, therefore it might need admins rights. + +By default only the core library will be installed. To also install connectors set the appropriate variable to `ON`: + +* `BUILD_MYSQL_CONNECTOR` +* `BUILD_MARIADB_CONNECTOR` +* `BUILD_POSTGRESQL_CONNECTOR` +* `BUILD_SQLITE3_CONNECTOR` +* `BUILD_SQLCIPHER_CONNECTOR` + +The library will check if all required dependencies are installed on the system. If connectors should be installed even if the dependencies are not yet available on the system, set `DEPENDENCY_CHECK` to `OFF`. + +Example: Install the core library, sqlite3 connector and postgresql connector. Don’t check if the dependencies such as Sqlite3 are installed and don’t build any tests: + +```bash +cmake -B build -DBUILD_POSTGRESQL_CONNECTOR=ON -DBUILD_SQLITE3_CONNECTOR=ON -DDEPENDENCY_CHECK=OFF -DBUILD_TESTING=OFF +cmake --build build --target install +``` __Install via Homebrew (MacOS):__ @@ -184,10 +208,20 @@ Basic usage: ------------- __Use with cmake__: The library officially supports two ways how it can be used with cmake. -You can find examples for both methods in the example folder. +You can find examples for both methods in the examples folder. -1. Fetch content (Recommend, no installation required) -1. Find package (installation required, see above) +1. FetchContent (Recommended, no installation required) +1. FindPackage (installation required, see above) + +Both methods will provide the `sqlpp11::sqlpp11` target as well as targets for each connector: + +* sqlpp11::mysql +* sqlpp11::mariadb +* sqlpp11::sqlite3 +* sqlpp11::sqlcipher +* sqlpp11::postgresql + +These targets will make sure all required dependencies are available and correctly linked and include directories are set correctly. __Create DDL files__: ``` @@ -199,9 +233,9 @@ Create headers for them with provided Python script: ``` %sqlpp11_dir%/scripts/ddl2cpp ~/temp/MyTable.ddl ~/temp/MyTable %DatabaseNamespaceForExample% ``` -(In case you're getting notes about unsupported column type take a look at the other datatypes in sqlpp11/data_types. They are not hard to implement.) +(In case you’re getting notes about unsupported column type take a look at the other datatypes in sqlpp11/data_types. They are not hard to implement.) -Include generated header (MyTable.h), that's all. +Include generated header (MyTable.h), that’s all. If you prefer Ruby over Python, you might want to take a look at https://github.com/douyw/sqlpp11gen @@ -211,8 +245,3 @@ Contact: * email at rbock at eudoxos dot de * [![Join the chat at https://gitter.im/sqlpp11/Lobby](https://badges.gitter.im/sqlpp11/Lobby.svg)](https://gitter.im/sqlpp11/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -Breaking changes in 0.36: -------------------------- -See [Changes](ChangeLog.md) - - diff --git a/cmake/FindMariaDB.cmake b/cmake/FindMariaDB.cmake new file mode 100644 index 00000000..89c2f82a --- /dev/null +++ b/cmake/FindMariaDB.cmake @@ -0,0 +1,35 @@ +# FindMySQL.cmake + +if(DEFINED MSVC) + find_path(MySQL_INCLUDE_DIR + NAMES mariadb_version.h + PATH_SUFFIXES include + ) + find_library(MySQL_LIBRARY + NAMES libmariadb + PATH_SUFFIXES lib + ) +else() + find_path(MySQL_INCLUDE_DIR + NAMES mariadb_version.h + PATH_SUFFIXES mariadb mysql + ) + find_library(MySQL_LIBRARY NAMES mariadb) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + MySQL + MySQL_INCLUDE_DIR + MySQL_LIBRARY +) + +if(MySQL_FOUND AND NOT TARGET MySQL::MySQL) + add_library(MySQL::MySQL UNKNOWN IMPORTED) + target_include_directories(MySQL::MySQL INTERFACE "${MySQL_INCLUDE_DIR}") + set_target_properties(MySQL::MySQL PROPERTIES + IMPORTED_LOCATION "${MySQL_LIBRARY}" + IMPORTED_LINK_INTERFACE_LANGUAGES "C") +endif() + +mark_as_advanced(MySQL_INCLUDE_DIR MySQL_LIBRARY) diff --git a/cmake/FindMySQL.cmake b/cmake/FindMySQL.cmake new file mode 100644 index 00000000..e1488df1 --- /dev/null +++ b/cmake/FindMySQL.cmake @@ -0,0 +1,49 @@ +# FindMySQL.cmake + +if(DEFINED MSVC) + set(SEARCH_PATHS + "$ENV{ProgramFiles}/MySQL/MySQL Server 8.0" + "$ENV{ProgramFiles}/MySQL/MySQL Server 5.7" + "$ENV{ProgramFiles}/MySQL/MySQL Server 5.6" + "$ENV{ProgramFiles\(x86\)}/MySQL/MySQL Server 8.0" + "$ENV{ProgramFiles\(x86\)}/MySQL/MySQL Server 5.7" + "$ENV{ProgramFiles\(x86\)}/MySQL/MySQL Server 5.6" + ) + find_path(MySQL_INCLUDE_DIR + NAMES mysql_version.h + PATHS ${SEARCH_PATHS} + PATH_SUFFIXES include + ) + find_library(MySQL_LIBRARY + NAMES libmysql + PATHS ${SEARCH_PATHS} + PATH_SUFFIXES lib + ) +else() + find_path(MySQL_INCLUDE_DIR + NAMES mysql_version.h + PATH_SUFFIXES mysql + ) + find_library(MySQL_LIBRARY + NAMES mysqlclient mysqlclient_r + PATH_SUFFIXES mysql # for CentOS 7 + ) + +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + MySQL + MySQL_INCLUDE_DIR + MySQL_LIBRARY +) + +if(MySQL_FOUND AND NOT TARGET MySQL::MySQL) + add_library(MySQL::MySQL UNKNOWN IMPORTED) + target_include_directories(MySQL::MySQL INTERFACE "${MySQL_INCLUDE_DIR}") + set_target_properties(MySQL::MySQL PROPERTIES + IMPORTED_LOCATION "${MySQL_LIBRARY}" + IMPORTED_LINK_INTERFACE_LANGUAGES "C") +endif() + +mark_as_advanced(MySQL_INCLUDE_DIR MySQL_LIBRARY) diff --git a/cmake/Sqlpp11TargetHelper.cmake b/cmake/Sqlpp11TargetHelper.cmake new file mode 100644 index 00000000..33063935 --- /dev/null +++ b/cmake/Sqlpp11TargetHelper.cmake @@ -0,0 +1,65 @@ +# Copyright (c) 2021, Leon De Andrade +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. 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(GNUInstallDirs) +include(CMakePackageConfigHelpers) + +function(add_component) + set(options) + set(oneValueArgs NAME) + set(multiValueArgs DEPENDENCIES) + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + add_library(sqlpp11_${ARG_NAME} INTERFACE) + add_library(sqlpp11::${ARG_NAME} ALIAS sqlpp11_${ARG_NAME}) + set_target_properties(sqlpp11_${ARG_NAME} PROPERTIES EXPORT_NAME ${ARG_NAME}) + target_link_libraries(sqlpp11_${ARG_NAME} INTERFACE sqlpp11 ${ARG_DEPENDENCIES}) +endfunction() + +function(install_component) + set(options) + set(oneValueArgs NAME DIRECTORY) + set(multiValueArgs TARGETS) + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + install(FILES ${PROJECT_SOURCE_DIR}/cmake/configs/${ARG_NAME}Config.cmake + DESTINATION ${SQLPP11_INSTALL_CMAKEDIR} + ) + + install(TARGETS ${ARG_TARGETS} + EXPORT Sqlpp11Targets + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) + + install(EXPORT Sqlpp11Targets + DESTINATION ${SQLPP11_INSTALL_CMAKEDIR} + NAMESPACE sqlpp11:: + ) + + install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/sqlpp11/${ARG_DIRECTORY} + DESTINATION include/sqlpp11 + FILES_MATCHING + PATTERN *.h + ) +endfunction() \ No newline at end of file diff --git a/cmake/Sqlpp11Config.cmake b/cmake/configs/Sqlpp11Config.cmake similarity index 68% rename from cmake/Sqlpp11Config.cmake rename to cmake/configs/Sqlpp11Config.cmake index ed7b6900..c50a71a6 100644 --- a/cmake/Sqlpp11Config.cmake +++ b/cmake/configs/Sqlpp11Config.cmake @@ -23,12 +23,31 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") - include(CMakeFindDependencyMacro) +find_dependency(Threads) find_dependency(date REQUIRED) -include("${CMAKE_CURRENT_LIST_DIR}/Sqlpp11Targets.cmake") +# Work out the set of components to load +if(${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS) + set(${CMAKE_FIND_PACKAGE_NAME}_comps ${${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS}) +endif() + +# Check all required components are available before trying to load any +foreach(comp IN LISTS ${CMAKE_FIND_PACKAGE_NAME}_comps) + if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED_${comp} AND NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/Sqlpp11${comp}Config.cmake) + set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE "Sqlpp11 missing required component: ${comp}") + set(${CMAKE_FIND_PACKAGE_NAME}_FOUND FALSE) + return() + endif() +endforeach() + +# Add the target file +include(${CMAKE_CURRENT_LIST_DIR}/Sqlpp11Targets.cmake) + +# Load any optional components +foreach(comp IN LISTS ${CMAKE_FIND_PACKAGE_NAME}_comps) + include(${CMAKE_CURRENT_LIST_DIR}/Sqlpp11${comp}Config.cmake OPTIONAL) +endforeach() # Import "ddl2cpp" script if(NOT TARGET sqlpp11::ddl2cpp) @@ -41,4 +60,4 @@ if(NOT TARGET sqlpp11::ddl2cpp) IMPORTED_LOCATION "${sqlpp11_ddl2cpp_location}" ) unset(sqlpp11_ddl2cpp_location) -endif() +endif() \ No newline at end of file diff --git a/cmake/configs/Sqlpp11MariaDBConfig.cmake b/cmake/configs/Sqlpp11MariaDBConfig.cmake new file mode 100644 index 00000000..32a594a9 --- /dev/null +++ b/cmake/configs/Sqlpp11MariaDBConfig.cmake @@ -0,0 +1,2 @@ +include(CMakeFindDependencyMacro) +find_dependency(MariaDB) \ No newline at end of file diff --git a/cmake/configs/Sqlpp11MySQLConfig.cmake b/cmake/configs/Sqlpp11MySQLConfig.cmake new file mode 100644 index 00000000..0d2a5b3b --- /dev/null +++ b/cmake/configs/Sqlpp11MySQLConfig.cmake @@ -0,0 +1,2 @@ +include(CMakeFindDependencyMacro) +find_dependency(MySQL) \ No newline at end of file diff --git a/cmake/configs/Sqlpp11PostgreSQLConfig.cmake b/cmake/configs/Sqlpp11PostgreSQLConfig.cmake new file mode 100644 index 00000000..9e4fffa0 --- /dev/null +++ b/cmake/configs/Sqlpp11PostgreSQLConfig.cmake @@ -0,0 +1,2 @@ +include(CMakeFindDependencyMacro) +find_dependency(PostgreSQL) \ No newline at end of file diff --git a/cmake/configs/Sqlpp11SQLCipherConfig.cmake b/cmake/configs/Sqlpp11SQLCipherConfig.cmake new file mode 100644 index 00000000..08926312 --- /dev/null +++ b/cmake/configs/Sqlpp11SQLCipherConfig.cmake @@ -0,0 +1,2 @@ +include(CMakeFindDependencyMacro) +find_dependency(SQLCipher) \ No newline at end of file diff --git a/cmake/configs/Sqlpp11SQLite3Config.cmake b/cmake/configs/Sqlpp11SQLite3Config.cmake new file mode 100644 index 00000000..cf1098b8 --- /dev/null +++ b/cmake/configs/Sqlpp11SQLite3Config.cmake @@ -0,0 +1,2 @@ +include(CMakeFindDependencyMacro) +find_dependency(SQLite3) \ No newline at end of file diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt index 90010ff9..e9886fbe 100644 --- a/dependencies/CMakeLists.txt +++ b/dependencies/CMakeLists.txt @@ -22,11 +22,14 @@ # (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(FetchContent) -FetchContent_Declare(date - GIT_REPOSITORY https://github.com/HowardHinnant/date.git - GIT_TAG v3.0.0 -) +if(NOT USE_SYSTEM_DATE AND NOT TARGET date::date) + include(FetchContent) -add_subdirectory(hinnant_date) \ No newline at end of file + FetchContent_Declare(date + GIT_REPOSITORY https://github.com/HowardHinnant/date.git + GIT_TAG v3.0.0 + ) + + add_subdirectory(hinnant_date) +endif() diff --git a/dependencies/hinnant_date/CMakeLists.txt b/dependencies/hinnant_date/CMakeLists.txt index 27a9d2b3..d15b1764 100644 --- a/dependencies/hinnant_date/CMakeLists.txt +++ b/dependencies/hinnant_date/CMakeLists.txt @@ -21,5 +21,8 @@ # 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. +FetchContent_MakeAvailable(date) -FetchContent_MakeAvailable(date) \ No newline at end of file +# Make date a system library (no warnings for date headers when compiling) +get_property(date_include_dirs TARGET date PROPERTY INTERFACE_INCLUDE_DIRECTORIES) +set_property(TARGET date PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${date_include_dirs}") \ No newline at end of file diff --git a/docs/Database.md b/docs/Database.md new file mode 100644 index 00000000..90b6abc8 --- /dev/null +++ b/docs/Database.md @@ -0,0 +1,11 @@ +#Introduction +sqlpp11 is a library mainly for constructing queries and interpreting results. It does not know how to talk to a database on its own. It needs database connectors for that. Depending on the database you want to use, you can use an existing connector, for instance + + * MySQL: https://github.com/rbock/sqlpp11-connector-mysql + * sqlite3: https://github.com/rbock/sqlpp11-connector-sqlite3 + * PostgreSQL: https://github.com/matthijs/sqlpp11-connector-postgresql + * STL Container (highly experimental): https://github.com/rbock/sqlpp11-connector-stl + +Or you have to write your own connector. Don't worry, it is not that hard. + +The api is documented [here](https://github.com/rbock/sqlpp11/blob/master/connector_api/connection.h). \ No newline at end of file diff --git a/docs/Dynamic-Select.md b/docs/Dynamic-Select.md new file mode 100644 index 00000000..f6ce6ff6 --- /dev/null +++ b/docs/Dynamic-Select.md @@ -0,0 +1,69 @@ +# Introduction +_This page explains dynamic select statements. Before studying this page, you should read about [static select statements](Select.md)._ + +If you know the exact structure of your queries at compile time, statically constructed select statements are perfect. But if the structure depends on runtime information like user input, you will need dynamic select statements. Depending on your needs, you can choose the required dosage. + +# A Basic Example +So let us construct select query with a dynamic part +```C++ +auto s = dynamic_select(db, all_of(foo)).from(foo).dynamic_where(); +if (runtimeQuery.id) + s.where.add(foo.id == runtimeQuery.id); +if (!runtimeQuery.name.empty()) + s.where.add(foo.name == runtimeQuery.name); +``` +Admittedly, a rather lame example (please suggest nicer ones), but anyway, this is what's happening: +```C++ +dynamic_select(db, ...) +``` +This initializes a dynamic select. One major difference between `dynamic_select` and `select` is the first argument of `dynamic_select`: a database connection. This is used to evaluate the dynamic parts of the query as they are added. + +```C++ +.dynamic_where(); +... +s.where.add(foo.name == runtimeQuery.name); +s.where.add(foo.id == runtimeQuery.id); +``` +The first part creates a new select object that accepts a dynamically constructed where expression. In this case the user can determine whether to search for a certain name or a certain id, or neither or both. + +# Dynamic Select +## Dynamic Columns +If the (some) selected columns are not known at compile time, you can do something like this: +```C++ +auto s = dynamic_select(db).dynamic_columns(foo.id).from(foo).unconditionally(); +if (someCondition) + s.selected_columns.add(foo.name); +if (someOtherCondition) + s.selected_columns.add(foo.hasFun); +``` +In this example, the column id is always selected. The other two columns may or may not be selected. This is determined at runtime. This impacts the way the results are accessed because the type of the result row is not known at the same level of detail as in the static case. The dynamic fields can be accessed via name lookup like in a map: +```C++ +for (const auto& row : db(s)) +{ + long id = row.id; + if (someCondition) + std::string name = row.at("name"); + if (someOtherCondition) + std::string hasFun = row.at("hasFun"); +} +``` +This also shows another difference. Dynamic fields are of text type. It would be possible to add conversion methods for other types as well, but this has not been coded yet. Please let me know you wishes. + +## Dynamic From +In a static query the compiler can verify whether the `from()` clause is sufficient to support all other aspects of the query. + +With a dynamic from, the compile cannot know tables that going into the `from()`. Such checks would therefore be impossible. But it allows you to add joins at runtime! + +```C++ +auto s = dynamic_select(db, all_of(foo)).dynamic_from(foo).dynamic_where(); +if (someOtherCondition) + s.from.add(dynamic_join(bar).on(foo.barId == bar.id)); +``` + +In this example, the user may want to include `bar` into the query. + +## Dynamic Where +As shown in other examples, the where condition can be constructed dynamically using the methods `dynamic_where()` and `where.add()`. The former prepares the select to accept dynamic where conditions, the latter adds a condition. Several calls to add_where will be combined into one condition by `and`. + +## Dynamic Having, Group By, OrderBy, Limit and Offset +Similar to the dynamic where, you can use `dynamic_having`, `dynamic_group_by`, `dynamic_order_by`, `dynamic_limit` and `dynamic_offset` to prepare the select statement to accept certain dynamic aspects. Using `having.add`, `group_by.add`, `order_by.add`, `limit.set` and `offset.set` you can then adjust those query parts according to the runtime information. diff --git a/docs/Exception-Handling.md b/docs/Exception-Handling.md new file mode 100644 index 00000000..b0411855 --- /dev/null +++ b/docs/Exception-Handling.md @@ -0,0 +1,10 @@ +## When to expect an exception + +sqlpp11 connectors throw the majority of `sqlpp::exception`s so check your connector's documentation. Generally, you should expect an exception when: + +- Connecting to a database +- Preparing a statement +- Executing a statement +- Retrieving and iterating through result rows + +Additionally, the date library used by sqlpp11 may throw `std::runtime_error`. As of 2017-04-08 this only happens when formatting a date using a format string. \ No newline at end of file diff --git a/docs/Functions.md b/docs/Functions.md new file mode 100644 index 00000000..f23bea07 --- /dev/null +++ b/docs/Functions.md @@ -0,0 +1,86 @@ +sqlpp11 offers equivalents for quite a few SQL functions. It also has some additional functions to make the developer's life easier, see [Misc Functions](#Misc-Functions). + +If functions can be used as select columns, the column's name is the name of the function. You can use `.as()` of course to give it another name, see [Select](Select.md). There are just a few exceptions like `any()` which cannot be named. + +# Member Functions +## in and not_in +The methods `in()` and `not_in()` can be used are available for pretty much any expression. They take zero or more value expressions. You can make the list dynamic by using a container of values. + +```C++ +tab.a.in(); // not valid SQL but certainly useful for generic code, evaluates to a false expression (version 0.35 and later). +tab.a.in(x, ...); // x, ... being one or more value expressions +tab.a.in(sub_select); // sub_select being a select expression with one result column of appropriate type. +tab.a.in(sqlpp::value_list(some_container_of_values)); // evaluates to a false expression in case of an empty container +``` + +## is_null +## like + +# Aggregate Functions +The following aggregate functions are supported + * avg + * count + * max + * min + * sum + +For example: +```C++ +for (const auto& row : db(select(tab.name, avg(tab.value)) + .from(tab) + .where(tab.id > 17) + .group_by(tab.name))) +{ + std::cerr << row.name << ": " << row.avg << std::endl; +} +``` + +# Text Functions +## concat +Just use the + operator :-) + +# Sub-Query Functions +## exists +## any +## some + +# Misc Functions +sqlpp11 offers a few functions that do not mimic SQL but are there to make your life easier. + +## value +The `value` function turns the argument into an unnamed SQL expression, e.g. an `int` into an `sqlpp::integral` or a `std::string` into an `sqlpp::text`. You probably don't need to use this function too often, because in most cases, sqlpp expressions do the conversion themselves. For instance +```C++ +tab.foo + 17 +``` +is a perfectly valid expression if `tab.foo` represents an SQL integral value. But when doing some generic query programming you might get into the situation that you want to select a constant value. For instance: +```C++ +for (const auto& row : select(sqlpp::value(7).as(sql::alias::a)).from(tab))) +{ + int64_t a = row.a; +} +``` + +##value_list +`value_list` is a helper function that takes a container of values and turns it into an sqlpp11 construct that is understood by the `in()` member function of expressions, see above. + +## verbatim +sqlpp11 supports quite a few aspects of SQL. But it does certainly not cover everything, nor will it ever. So what if you need to use something that is not supported? At least for expressions there is an easy way to use unsupported features, the `verbatim()` method. It requires a template parameter to determine the SQL type and a string argument containing the expression, for instance: +```C++ +select(all_of(tab)).from(tab).where(tab.foo == 42 and sqlpp::verbatim("mighty special feature")); +``` +_Use with care_, as sqlpp11 does not bother to look into the string you provide. That means you have to handle type checking, syntax checking, escaping of injected evil data from your users, etc. + +## flatten +Say `tab.foo` and `tab.bar` represent two bigint columns. Then the type of `tab.foo` and `tab.bar` is different. Also `tab.foo + 17` and `tab.bar + 17` are expressions of different type. This is because the expression carries information about required tables for instance (and that is going to be used to check if `from()` contains all the required tables. +The expression templates can get in your way though, if you want to create parts of your query dynamically: +```C++ +auto e = (tab.foo == 17); +if (userWantsBar) + e = (tab.bar == 17); // won't compile +``` +You can use [dynamic select](Dynamic-Select.md), but there is an alternative, the `flatten()` method, which turns the expression into a more generic expression type (it just "remembers" whether it is a text, boolean etc). +```C++ +auto e = flatten(tab.foo == 17); +if (userWantsBar) + e = flatten(tab.bar == 17); // will compile +``` diff --git a/docs/Home.md b/docs/Home.md new file mode 100644 index 00000000..0bf6ca06 --- /dev/null +++ b/docs/Home.md @@ -0,0 +1,24 @@ +# Introduction +Lets see: +* You know C++? +* You know some SQL? +* You want to use SQL in your C++ program? +* You think C++ and SQL should play well together? +* You know which tables you want to use in a database? +* You can cope with a few template error messages in case something is wrong? + +You have come to the right place! + +sqlpp11 offers you to code SQL in C++ almost naturally. You can use tables, columns and functions. Everything has strong types which allow the compiler to help you a lot. At compile time, it will tell about most of those pesky oversight errors you can make (typos, comparing apples with oranges, forgetting tables in a select statement, etc). And it does not stop at query construction. Results have ranges, and strongly typed members, so that you can browse through results in a type-safe manner, worthy of modern C++. + +The following pages will tell you how to use it: +* [Database](Database.md) +* [Tables](Tables.md) +* [Insert](Insert.md) +* [Select](Select.md) <- You might want to read this first as an appetizer +* [Update](Update.md) +* [Remove](Remove.md) +* [Functions](Functions.md) +* [Prepared Statements](Prepared-Statements.md) +* [NULL](NULL.md) +* [New Features](New-Features.md) diff --git a/docs/Insert.md b/docs/Insert.md new file mode 100644 index 00000000..f1375046 --- /dev/null +++ b/docs/Insert.md @@ -0,0 +1,35 @@ +Haven't found the time to document this in any detail, yet, but this is an example: + +```C++ +db(insert_into(tab).set(tab.gamma = true)); +db(insert_into(tabDateTime) + .set(tabDateTime.colTimePoint = std::chrono::system_clock::now())); +``` + +This is how you could insert multiple rows at a time: + +```C++ +auto multi_insert = insert_into(t).columns(t.gamma, t.beta, t.delta); +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::null)); +db(multi_insert); +``` + +Note that `add` currently requires precise value types, equal to the respective column's value +type. For instance, time point columns are represented as +`std::chrono::time_point`. + +Thus, when using such a column in a `multi_insert`, you might have to cast to the right +time point. + +``` + auto multi_time_insert = insert_into(tabDateTime).columns(tabDateTime.colTimePoint); + multi_time_insert.values.add(tabDateTime.colTimePoint = std::chrono::time_point_cast( + std::chrono::system_clock::now())); +``` + +Similar for other data types. diff --git a/docs/NULL.md b/docs/NULL.md new file mode 100644 index 00000000..6b8a7d8f --- /dev/null +++ b/docs/NULL.md @@ -0,0 +1,100 @@ +# Introduction +Database NULL is a strange beast. It can be compared to anything but that comparison never returns true. It also never returns false, it returns NULL. Even + +```SQL +NULL != NULL -> NULL +NULL = NULL -> NULL +``` + +A value like that would be pretty unusual in C++. Especially since fields in a result could be either a decent value or NULL. And this can change from result row to result row. + +Also, in `where` or `having` conditions, you have to change the expression (not just parameters) if you want to NULL instead of a value: + +```SQL +a = 7 +a IS NULL +``` + +# Obtaining potential NULL values from a select +sqlpp11 can determine whether a result field can be null, based on the columns involved and the structure of your query. If in doubt (for instance due to dynamic parts), it will assume that a field can be NULL. + +You can check if a field is NULL by calling the `is_null()` method. That's easy. + +When it comes to accessing the value, there are two options, though. These can be controlled by the connection class and the columns of your tables. + +## Option 1: No conversion operator +```C++ +class connection: public sqlpp::connection +{ + public: + using _traits = ::sqlpp::make_traits<::sqlpp::no_value_t, + ::sqlpp::tag::enforce_null_result_treatment + >; +``` +If this tag is used in the connection's traits and the respective column does not override it, then there is no conversion operator for fields that can be NULL. You have to access the value through the `value()` method. +If the field is NULL, this method will throw an `sqlpp::exception`. + +## Option 2: Conversion operator, converting NULL to trivial value +If the `tag::enforce_null_result_treatment` is not used in the connection class or the respective column uses `tag::enforce_null_result_treatment`, then there is a conversion operator. Both the conversion operator and the `value()` method will not throw in case of a NULL value. Instead, the will return the trivial value for the field's type, e.g. 0 for numbers or "" for texts. + +## Alternatives: +One often discussed alternative would be boost::optional or (in the future) std::optional. There is one drawbacks (correct me if I am wrong, please): + +`optional` cannot be used for binding result values because it is unclear whether there already is a value to bind to. + +# Handling NULL in statements +When adding potential NULL values to a statement, you have two options: + +## Manually +```C++ +auto s = dynamic_select(db, all_of(tab)).from(tab).dynamic_where(); +if (i_do_have_a_decent_value_of_alpha) + s.add_where(tab.alpha == alpha); +else + s.add_where(tab.alpha.is_null()); +``` + +## tvin() +`tvin()` is a free function that can be used with `std::string` and build-in types like `int` or `float` or `bool`. `tvin` stands for Trivial Value Is NULL. It is used in combination with `operator==()`, `operator!=()` and `operator=()`. These operators will behave the way they should, e.g. + +```C++ +select(all_of(tab)).from(tab).where(tab.alpha == sqlpp::tvin(a)); +``` + +This will evaluate to + +```SQL +SELECT tab.* FROM tab WHERE alpha = 7; +-- OR +SELECT tab.* FROM tab WHERE alpha IS NULL; +``` + +Similar with insert: + +```C++ +insert_into(tab).set(tab.alpha = sqlpp::tvin(a)); +``` + +This will evaluate to + +```SQL +INSERT INTO tab (alpha) VALUES(7); +-- OR +INSERT INTO tab (alpha) VALUES(NULL); +``` + +## Using Column Type +Like to accessing values in select results, setting values can be controlled via the column type: + +```C++ +struct Alpha +{ + struct _name_t; + using _traits = sqlpp::make_traits; +}; +``` +With this tag, you do not need to use `tvin()` for operators `=`, `==`, `!=`. It is used automatically. It translates operator `!` into `IS NULL`. + +**Hint**: Please be aware that trivial_value_is_null will not work with parameters in prepared statements. \ No newline at end of file diff --git a/docs/New-Features.md b/docs/New-Features.md new file mode 100644 index 00000000..0d28b414 --- /dev/null +++ b/docs/New-Features.md @@ -0,0 +1,58 @@ +# New Features + +There are a bunch of new features, that are not fully documented yet. If you would like to contribute documentation, please let me know. + +## Preprocessor generator for columns/tables +You'll need boost 1.50 or greater to use this feature by niXman: + +```C++ +#include +SQLPP_DECLARE_TABLE( + (tab_person) + , + (id , int , SQLPP_AUTO_INCREMENT) + (name , varchar(255), SQLPP_NOT_NULL ) + (feature, int , SQLPP_NOT_NULL ) +) +``` + +See `examples/ppgen.hpp`. + +## Union +Unions are now supported. The arguments need to have the same names and types in their columns. + +```C++ +db(select(t.alpha).from(t).where(true) + .union_distinct(select(f.epsilon.as(t.alpha)).from(f).where(true))); +db(select(t.alpha).from(t).where(true) + .union_all(select(f.epsilon.as(t.alpha)).from(f).where(true))); +``` + +## With +sqlpp11 supports common table expressions: + +```C++ +auto x = sqlpp::cte(sqlpp::alias::x).as(select(all_of(t)).from(t)); + +db(with(x)(select(x.alpha).from(x).where(true))); +``` +## Custom Queries +This allows you to combine building blocks of sqlpp11 into custom queries, for instance a SELECT..INTO which is not supported yet. + +```C++ +// 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. +db(custom_query(select(all_of(t)).from(t), into(f)) + .with_result_type_of(insert_into(f))); +``` + +## Schema-qualified tables +sqlpp11 assumes that you're connection addresses one database, normally. But you can tell it about other databases using the `sqlpp::schema_t` and instantiating schema-qualified tables with it: + +```C++ +auto schema = db.attach("lorem_ipsum"); +auto s = schema_qualified_table(schema, TabSample{}).as(sqlpp::alias::x) +// s now represents "lorem_ipsum.tab_sample as x" +// s can be used like any other table in the code +``` diff --git a/docs/Prepared-Statements.md b/docs/Prepared-Statements.md new file mode 100644 index 00000000..53981104 --- /dev/null +++ b/docs/Prepared-Statements.md @@ -0,0 +1,48 @@ +# Introduction +Executing a statement in a database is typically done in two phases: First, the statement is prepared (parsed, compiled, optimized). Then, it is run against the database. Since statements often differ only in parameters, not in structure, many databases offer to store prepared statements. These prepared statements can then be executed repeatedly, typically with some parameters. + +sqlpp11 supports prepared statements. + +## Parameters +Currently there are two overloads to specify a parameter: + +```C++ +parameter(const ValueType&, const AliasProvider&); + +parameter(const NamedExpression&) +``` + +Value types are sqlpp::bigint, sqlpp::text, etc., Alias providers can be generated by using the SQLPP_ALIAS_PROVIDER macro, and named expressions are combinations of the former, e.g. columns of a table. + +For instance, you could use: +```C++ +SQLPP_ALIAS_PROVIDER(cheese); +parameter(sqlpp::bigint(), cheese); + +parameter(tab.id); +``` + +## Prepare and execute statements +insert, update, remove and select statements can be prepared by calling the `prepare()` method of a database connection object. + +```C++ +auto prepared_statement = db.prepare(some_statement); +``` + +You can now set the parameters and execute the prepared statement multiple times, e.g. + +```C++ +auto prepared_insert = db.prepare( + insert_into(tab).set( + tab.alpha = parameter(tab.alpha), + tab.beta = parameter(sqlpp::text(), cheese) + )); +for (const auto& input : input_values) +{ + prepared_insert.params.alpha = input.first; + prepared_insert.params.cheese = input.second; + db(prepared_insert); +} +``` + +Note: need nicer examples... diff --git a/docs/Remove.md b/docs/Remove.md new file mode 100644 index 00000000..c2251e74 --- /dev/null +++ b/docs/Remove.md @@ -0,0 +1,20 @@ +Since `delete` is keyword in C++ that has a different meaning than `delete` in SQL, sqlpp11 calls the method remove. There is no detailed documentation available yet, but here is an example that might help if you have read about [select statements](Select.md) already: + +```C++ +db(remove_from(tab).where(tab.alpha == tab.alpha + 3)); +``` + +## Removing using multiple tables as condition: + +```C++ +test_sqlpp::Users usr; +test_sqlpp::UsersForms usr_forms; +test_sqlpp::Forms form_; + +db(remove_from(usr_forms).using_(usr, form_, usr_forms).where( + usr_forms.iduser == usr.id + and usr.username == username + and usr_forms.idform == form_.id + and form_.name == form_name + )); +``` diff --git a/docs/Select.md b/docs/Select.md new file mode 100644 index 00000000..ac2e24ba --- /dev/null +++ b/docs/Select.md @@ -0,0 +1,242 @@ +# Introduction +_This page explains select statements with a static structure. If you want to learn about constructing select statements at runtime, you should still read this page first and then move on to [dynamic select statements](Dynamic-Select.md)._ + +Lets assume we have a table representing + +```SQL +CREATE TABLE foo ( + id bigint, + name varchar(50), + hasFun bool +); +``` +(This is SQL for brevity, not C++, see [here](Tables.md) for details on how to define types representing the tables and columns you want to work with) + +Lets also assume we have an object `db` representing a connection to your [database](Database.md). + +# A Basic example +This shows how you can select some data from table and iterate over the results: +```C++ +for (const auto& row : db(select(foo.name, foo.hasFun) + .from(foo) + .where(foo.id > 17 and foo.name.like("%bar%")))) +{ + if (row.name.is_null()) + std::cerr << "name is null" << std::endl; + else + std::string name = row.name; // string-like fields are implicitly convertible to string + bool hasFun = row.hasFun; // bool fields are implicitly convertible to bool +} +``` +So, what's happening here? Lets ignore the gory details for a moment. Well, there is a select statement. +```C++ +select(foo.name, foo.hasFun) + .from(foo) + .where(foo.id > 17 and foo.name.like("%bar%")) +``` +It selects two columns `name` and `hasFun` from table `foo` for rows which match the criteria given in the where condition. That's about as close to _real_ SQL as it can get... + +The select expression is fed into the call operator of the connection object `db`. This method sends the select statement to the database and returns an object representing the results. In the case of select statements, the result object represents zero or more rows. + +One way of accessing the rows is to iterate over them in a range-based for loop. + +```C++ +for (const auto& row : ...) +``` +Ok, so the variable row is an object that represents a single result row. You really want to use `auto` here, because you don't want to write down the actual type. Trust me. But the wonderful thing about the `row` object is that it has appropriately named and typed members representing the columns you selected. This is one of the utterly cool parts of this library. + +# The Select Statement +## Select +The `select` method takes zero or more named expression arguments. + +Named expressions are expressions with a name. No surprise there. But what kind of expressions have a name? Table columns, for instance. In our example, that would be `foo.id`, `foo.name` and `foo.hasFun`. Most [function](Functions.md) calls also result in named expressions, like `count(foo.id)`. + +So what about unnamed expressions? Results of binary operators like `(foo.id + 17) * 4` have no name. But you can give them a name using the `as(alias)` method. The easiest way is to use a named expression as alias, for instance `((foo.id + 17) * 4).as(foo.id)`, e.g. + +```C++ +for (const auto& row : db(select(((foo.id + 17) * 4).as(foo.id)).from(tab))) +{ + std::cout << row.id << std::endl; +} +``` + +Another option is to define an alias like this: + +```C++ +SQLPP_ALIAS_PROVIDER(total); +for (const auto& row : db(select(sum(id).as(total)).as(foo.id)).from(tab))) +{ + std::cout << row.total << std::endl; +} +``` +Using aliases also comes in handy when you join tables and have several columns of the same name, because no two named expressions in a select must have the same name. So if you want to do something like + +```C++ +select(foo.id, bar.id); // compile error +``` + +One of the columns needs an alias. +```C++ +SQLPP_ALIAS_PROVIDER(barId); +select(foo.id, bar.id.as(barId)); +``` +### Select Columns +All examples above called the `select()` function with one or more arguments, but `select()` can also be called with no arguments. In that case, the selected columns have to be added afterwards + +```C++ +sqlpp::select().columns(foo.id, foo.name); +``` + +See also [dynamic select statements](Dynamic-Select.md). + +### Select Flags +The following flags are currently supported: + +* sqlpp::all +* sqlpp::distinct + +Flags are added via the `flags()` method: + +```C++ +sqlpp::select().flags(sqlpp::all).columns(foo.id, foo.name); +``` + +or + +```C++ +select(foo.id, foo.name).flags(sqlpp::all); +``` + +The latter is shorter than the former, but the former is closer to SQL syntax and probably easier to read. + +### Sub-Select +A select statement with one column also is named expression. This means you can use one select as a sub-select column of another select. For example: +``` +for (const auto& row : db( + select(all_of(foo), + select(sum(bar.value)).from(bar).where(bar.id > foo.id)) + .from(foo))) +{ + int x = row.id; + int a = row.sum; + } +``` +The name of the sub select is the name of the one column. If required, you can rename it using `as()`, as usual. + +### Select All Columns +Statements like `SELECT * from foo` is used pretty often in SQL. sqlpp11 offers something similar: + +```C++ +select(all_of(foo)); +``` + +## From +The `from` method expects one argument. The following subsections expand on the types of valid arguments: +* tables +* tables with an alias (via the `as` method) +* sub-selects with an alias +* joins + +### Tables +This is the most simple case. +```C++ +select(all_of(foo)).from(foo); +``` + +### Aliased Tables +Table aliases are useful in self-joins. +```C++ +SQLPP_ALIAS_PROVIDER(left); +SQLPP_ALIAS_PROVIDER(right); +auto l = foo.as(left); +auto r = foo.as(right); +select(all_of(l)).from(l.join(r).on(l.x == r.y)); +``` +Aliased tables might also be used to increase the readability of generated SQL code, for instance if you have very long table names. + +### Aliased Sub-Select +A select can be used as a pseudo table in another select. You just have to give it a name. +```C++ +SQLPP_ALIAS_PROVIDER(sub); +auto sub_select = select(all_of(foo)).from(foo).as(sub); +``` +The variable `sub_select` can be used as a table now. + +### Joins +You can join two tables like this: +```C++ +foo.join(bar).on(foo.id == bar.foo); +``` +If you want to join more tables, you can chain joins. +```C++ +foo.join(bar).on(foo.id == bar.foo).left_outer_join(baz).on(bar.id == baz.ref); +``` +_Hint_: Omitting the call to `on` will result in mildly horrible error messages... + +## Where +The where condition can be set via the `where` method, which takes a boolean expression argument, for instance: +```C++ +select(all_of(foo)).from(foo).where(foo.id != 17 and foo.name.like("%cake")); +``` + +## Group By +The method `group_by` takes one or more expression arguments, for instance: +```C++ +select(all_of(foo)).from(foo).group_by(foo.name); +``` + +## Having +The having condition can be set via the `having` method, just like the `where` method. + +## Order By +The `order_by` method takes one of more order expression, which are normal expression adorned with `.asc()` or `.desc()`, e.g. +```C++ +select(all_of(foo)).from(foo).order_by(foo.name.asc()); +``` + +## Limit And Offset +The methods `limit` and `offset` take a size_t argument, for instance: +```C++ +select(all_of(foo)).from(foo).limit(10u).offset(20u); +``` +## For Update +The `for_update` method modifies the query with a simplified "FOR UPDATE" clause without columns. +```C++ +select(all_of(foo)).from(foo).where(foo.id != 17).for_update(); +``` + +# Running The Statement +OK, so now we know how to create a select statement. But the statement does not really do anything unless we hand it over to the database: +```C++ +db(select(all_of(foo)).from(foo)); +``` +This call returns a result object of a pretty complex type. Thus, you would normally want to use `auto`: + +```C++ +auto result = db(select(all_of(foo)).from(foo)); +``` + +# Accessing The Results +The `result` object created by executing a `select` query is a container of result rows. + +## Range-based For Loops +Not surprisingly, you can iterate over the rows using a range-based for-loop like this: +```C++ +for (const auto& row : db(select(all_of(foo)).from(foo))) +{ + std::cerr << row.id << std::endl; + std::cerr << row.name << std::endl; +} +``` +Lovely, isn't it? The row objects have types specifically tailored for the select query you wrote. You can access their member by name, and these members have the expected type. + +## Function-based Access +If for some reason, you don't want to use range-based for-loops, you can use `front()` and `pop_front()` on the result, like this: +```C++ +while(!result.empty()) +{ + const auto& row = result.front(); + std::cerr << row.id << std::endl; + std::cerr << row.name << std::endl; + result.pop_front(); +} diff --git a/docs/Tables.md b/docs/Tables.md new file mode 100644 index 00000000..602e9ea6 --- /dev/null +++ b/docs/Tables.md @@ -0,0 +1,128 @@ +This page will tell you about how to define tables for sqlpp11, once I get around to writing it. Until then, here is an example, taken from [here](https://github.com/rbock/sqlpp11/blob/master/tests/Sample.h): + +```C++ +namespace TabSample_ +{ + struct Alpha + { + struct _name_t + { + static constexpr const char* _get_name() { return "alpha"; } + template + struct _member_t + { + T alpha; + }; + }; + using _value_type = sqlpp::bigint; + struct _column_type + { + using _must_not_insert = std::true_type; + using _must_not_update = std::true_type; + using _can_be_null = std::true_type; + using _trivial_value_is_null = std::true_type; + using _foreign_key = decltype(TabFoo::omega); + }; + }; + + struct Beta + { + struct _name_t + { + static constexpr const char* _get_name() { return "beta"; } + template + struct _member_t + { + T beta; + }; + }; + using _value_type = sqlpp::varchar; + struct _column_type + { + using _can_be_null = std::true_type; + using _trivial_value_is_null = std::true_type; + using _must_not_update = std::true_type; + }; + }; + + struct Gamma + { + struct _name_t + { + static constexpr const char* _get_name() { return "gamma"; } + template + struct _member_t + { + T gamma; + }; + }; + using _value_type = sqlpp::boolean; + struct _column_type + { + using _require_insert = std::true_type; + }; + }; +} + +struct TabSample: sqlpp::table_base_t< + TabSample, + TabSample_::Alpha, + TabSample_::Beta, + TabSample_::Gamma + > +{ + using _value_type = sqlpp::no_value_t; + struct _name_t + { + static constexpr const char* _get_name() { return "tab_sample"; } + template + struct _member_t + { + T tabSample; + }; + }; + template + void serialize_impl(std::ostream& os, Db& db) const + { + os << _name_t::_get_name(); + } +}; +``` +Not too complex, I hope? + +Not lean enough to be fun writing though, right? A sample code generator (DDL -> C++) written in python can be found [here](https://github.com/rbock/sqlpp11/blob/master/scripts/ddl2cpp). + +## Names with reserved SQL keywords +In case the SQL entity uses a reserved keyword it is required to escape the name using the target's RDBMS rule. For example: + +```SQL +SELECT "order" FROM orders; +``` +Here the column order is the same as the reserved keyword ORDER from the "ORDER BY" SQL clause. As such in for example PostgreSQL you need to put the name in quotes. Pay attention that the rules are RDBMS specific and that some RDBMS then consider the name case sensitive and that the select may fail due to incorrect case of the entity name. To achieve this you need to amend the column literal. For example: + +```C++ +namespace TabSample_ +{ + struct Order + { + struct _name_t + { + static constexpr const char* _get_name() { return "\"order\""; } + template + struct _member_t + { + T order; + }; + }; + using _value_type = sqlpp::bigint; + struct _column_type + { + using _must_not_insert = std::true_type; + using _must_not_update = std::true_type; + using _can_be_null = std::true_type; + using _trivial_value_is_null = std::true_type; + using _foreign_key = decltype(TabFoo::omega); + }; + }; +} +``` diff --git a/docs/Update.md b/docs/Update.md new file mode 100644 index 00000000..bd4c10a8 --- /dev/null +++ b/docs/Update.md @@ -0,0 +1,5 @@ +The detailed documentation is still missing here, but here is an example that might help if you have read about [select statements](Select.md). + +```C++ +db(update(tab).set(tab.gamma = false).where(tab.alpha.in(1))); +``` diff --git a/examples/usage_fetch_content/dependencies/sqlpp11/CMakeLists.txt b/examples/usage_fetch_content/dependencies/sqlpp11/CMakeLists.txt index 2c86850e..6f082628 100644 --- a/examples/usage_fetch_content/dependencies/sqlpp11/CMakeLists.txt +++ b/examples/usage_fetch_content/dependencies/sqlpp11/CMakeLists.txt @@ -22,5 +22,13 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# Configure before sqlpp11 +# Configure the project here as needed +# set(BUILD_MYSQL_CONNECTOR ON) +# set(BUILD_MARIADB_CONNECTOR ON) +# set(BUILD_POSTGRESQL_CONNECTOR ON) +# set(BUILD_SQLITE3_CONNECTOR ON) +# set(BUILD_SQLCIPHER_CONNECTOR ON) + +# set(USE_SYSTEM_DATE ON) + FetchContent_MakeAvailable(sqlpp11) \ No newline at end of file diff --git a/examples/usage_fetch_content/src/CMakeLists.txt b/examples/usage_fetch_content/src/CMakeLists.txt index cf207bf3..ebe64c74 100644 --- a/examples/usage_fetch_content/src/CMakeLists.txt +++ b/examples/usage_fetch_content/src/CMakeLists.txt @@ -23,7 +23,16 @@ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. add_executable(Test) -target_link_libraries(Test PRIVATE sqlpp11::sqlpp11) +target_link_libraries(Test + PRIVATE + sqlpp11::sqlpp11 + # Corresponding targets for the connectors. These connectors need to be enabled in the the dependencies/sqlpp11 folder. These targets automatically link against sqlpp11::sqlpp11 and therefore sqlpp11::sqlpp11 doesn't need to be linked manually again + # sqlpp11::sqlite3 + # sqlpp11::sqlcipher + # sqlpp11::mysql + # sqlpp11::mariadb + # sqlpp11::postgresql +) target_sources(Test PRIVATE diff --git a/examples/usage_find_package/CMakeLists.txt b/examples/usage_find_package/CMakeLists.txt index e3eee50c..262f36bb 100644 --- a/examples/usage_find_package/CMakeLists.txt +++ b/examples/usage_find_package/CMakeLists.txt @@ -32,7 +32,11 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) ### Dependencies ### -find_package(Sqlpp11 REQUIRED) +find_package(Sqlpp11 + # Optionally specify connectors needed to get corresponding targets. Only possible if connectors have been installed on the system as documented in the README + # COMPONENTS SQLite3 SQLCipher MySQL MariaDB PostgreSQL + REQUIRED +) ### Main Targets ### add_subdirectory(src) \ No newline at end of file diff --git a/examples/usage_find_package/src/CMakeLists.txt b/examples/usage_find_package/src/CMakeLists.txt index cf207bf3..9c17c3f9 100644 --- a/examples/usage_find_package/src/CMakeLists.txt +++ b/examples/usage_find_package/src/CMakeLists.txt @@ -23,8 +23,16 @@ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. add_executable(Test) -target_link_libraries(Test PRIVATE sqlpp11::sqlpp11) - +target_link_libraries(Test + PRIVATE + sqlpp11::sqlpp11 + # Corresponding targets for the Components specified in the find_package call + # sqlpp11::sqlite3 + # sqlpp11::sqlcipher + # sqlpp11::mysql + # sqlpp11::mariadb + # sqlpp11::postgresql +) target_sources(Test PRIVATE main.cpp diff --git a/include/sqlpp11/aggregate_functions/avg.h b/include/sqlpp11/aggregate_functions/avg.h index f34ac297..129cb643 100644 --- a/include/sqlpp11/aggregate_functions/avg.h +++ b/include/sqlpp11/aggregate_functions/avg.h @@ -84,28 +84,22 @@ namespace sqlpp }; template - struct serializer_t> + Context& serialize(const avg_t& t, Context& context) { - using _serialize_check = serialize_check_of; - using T = avg_t; - - static Context& _(const T& t, Context& context) + context << "AVG("; + if (std::is_same::value) { - context << "AVG("; - if (std::is_same::value) - { - serialize(Flag(), context); - context << ' '; - serialize_operand(t._expr, context); - } - else - { - serialize(t._expr, context); - } - context << ")"; - return context; + serialize(Flag(), context); + context << ' '; + serialize_operand(t._expr, context); } - }; + else + { + serialize(t._expr, context); + } + context << ")"; + return context; + } template auto avg(T t) -> avg_t> diff --git a/include/sqlpp11/aggregate_functions/count.h b/include/sqlpp11/aggregate_functions/count.h index 91f7a830..542a978e 100644 --- a/include/sqlpp11/aggregate_functions/count.h +++ b/include/sqlpp11/aggregate_functions/count.h @@ -87,28 +87,22 @@ namespace sqlpp }; template - struct serializer_t> + Context& serialize(const count_t& t, Context& context) { - using _serialize_check = serialize_check_of; - using T = count_t; - - static Context& _(const T& t, Context& context) + context << "COUNT("; + if (std::is_same::value) { - context << "COUNT("; - if (std::is_same::value) - { - serialize(Flag(), context); - context << ' '; - serialize_operand(t._expr, context); - } - else - { - serialize(t._expr, context); - } - context << ")"; - return context; + serialize(Flag(), context); + context << ' '; + serialize_operand(t._expr, context); } - }; + else + { + serialize(t._expr, context); + } + context << ")"; + return context; + } template auto count(T t) -> count_t> diff --git a/include/sqlpp11/aggregate_functions/max.h b/include/sqlpp11/aggregate_functions/max.h index 1c601809..90dabe4b 100644 --- a/include/sqlpp11/aggregate_functions/max.h +++ b/include/sqlpp11/aggregate_functions/max.h @@ -80,19 +80,13 @@ namespace sqlpp }; template - struct serializer_t> + Context& serialize(const max_t& t, Context& context) { - using _serialize_check = serialize_check_of; - using T = max_t; - - static Context& _(const T& t, Context& context) - { - context << "MAX("; - serialize(t._expr, context); - context << ")"; - return context; - } - }; + context << "MAX("; + serialize(t._expr, context); + context << ")"; + return context; + } template auto max(T t) -> max_t> diff --git a/include/sqlpp11/aggregate_functions/min.h b/include/sqlpp11/aggregate_functions/min.h index 54b663c8..e46cbfaa 100644 --- a/include/sqlpp11/aggregate_functions/min.h +++ b/include/sqlpp11/aggregate_functions/min.h @@ -80,19 +80,13 @@ namespace sqlpp }; template - struct serializer_t> + Context& serialize(const min_t& t, Context& context) { - using _serialize_check = serialize_check_of; - using T = min_t; - - static Context& _(const T& t, Context& context) - { - context << "MIN("; - serialize(t._expr, context); - context << ")"; - return context; - } - }; + context << "MIN("; + serialize(t._expr, context); + context << ")"; + return context; + } template auto min(T t) -> min_t> diff --git a/include/sqlpp11/aggregate_functions/sum.h b/include/sqlpp11/aggregate_functions/sum.h index 33396c28..56a1e33a 100644 --- a/include/sqlpp11/aggregate_functions/sum.h +++ b/include/sqlpp11/aggregate_functions/sum.h @@ -84,29 +84,22 @@ namespace sqlpp }; template - struct serializer_t> + Context& serialize(const sum_t& t, Context& context) { - using _serialize_check = serialize_check_of; - using T = sum_t; - - static Context& _(const T& t, Context& context) + context << "SUM("; + if (std::is_same::value) { - context << "SUM("; - if (std::is_same::value) - { - serialize(Flag(), context); - context << ' '; - serialize_operand(t._expr, context); - } - else - { - serialize(t._expr, context); - } - - context << ")"; - return context; + serialize(Flag(), context); + context << ' '; + serialize_operand(t._expr, context); } - }; + else + { + serialize(t._expr, context); + } + context << ")"; + return context; + } template auto sum(T t) -> sum_t> diff --git a/include/sqlpp11/alias.h b/include/sqlpp11/alias.h index ea2c28ee..328ce5b9 100644 --- a/include/sqlpp11/alias.h +++ b/include/sqlpp11/alias.h @@ -28,7 +28,6 @@ #define SQLPP11_ALIAS_H #include -#include namespace sqlpp { @@ -57,19 +56,13 @@ namespace sqlpp }; template - struct serializer_t> + Context& serialize(const expression_alias_t& t, Context& context) { - using _serialize_check = serialize_check_of; - using T = expression_alias_t; - - static Context& _(const T& t, Context& context) - { - serialize_operand(t._expression, context); - context << " AS "; - context << name_of::template char_ptr(); - return context; - } - }; + serialize_operand(t._expression, context); + context << " AS "; + context << name_of>::template char_ptr(); + return context; + } } // namespace sqlpp #endif diff --git a/include/sqlpp11/all_of.h b/include/sqlpp11/all_of.h index 0a23a168..373792f0 100644 --- a/include/sqlpp11/all_of.h +++ b/include/sqlpp11/all_of.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, Roland Bock + * Copyright (c) 2013-2021, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -27,44 +27,13 @@ #ifndef SQLPP11_ALL_OF_H #define SQLPP11_ALL_OF_H -#include -#include -#include -#include - namespace sqlpp { template - struct all_of_t - { - using _column_tuple_t = typename Table::_column_tuple_t; - - template - detail::copy_tuple_args_t as(const AliasProvider& alias) - { - return multi_column(_column_tuple_t{}).as(alias); - } - }; - - template - auto all_of(Table /*unused*/) -> all_of_t + auto all_of(Table /*unused*/) -> typename Table::_column_tuple_t { return {}; } - - SQLPP_PORTABLE_STATIC_ASSERT(assert_no_stand_alone_all_of_t, "all_of(table) seems to be used outside of select"); - - template - struct serializer_t> - { - using _serialize_check = assert_no_stand_alone_all_of_t; - using T = all_of_t
; - - static Context& _(const T& /*unused*/, const Context& /*unused*/) - { - _serialize_check{}; - } - }; } // namespace sqlpp #endif diff --git a/include/sqlpp11/any.h b/include/sqlpp11/any.h index d8e86d04..d0ea8b1c 100644 --- a/include/sqlpp11/any.h +++ b/include/sqlpp11/any.h @@ -53,19 +53,13 @@ namespace sqlpp }; template - struct serializer_t> + Context& serialize(const any_t; - - static Context& _(const T& t, Context& context) - { - context << "ANY("; - serialize(t._select, context); - context << ")"; - return context; - } - }; + context << "ANY("; + serialize(t._select, context); + context << ")"; + return context; + } template auto any(T t) -> any_t> diff --git a/include/sqlpp11/assignment.h b/include/sqlpp11/assignment.h index 529d20ae..469acd96 100644 --- a/include/sqlpp11/assignment.h +++ b/include/sqlpp11/assignment.h @@ -29,10 +29,7 @@ #include #include -#include -#include #include -#include #include namespace sqlpp @@ -42,11 +39,11 @@ namespace sqlpp { using _traits = make_traits; using _lhs_t = Lhs; - using _rhs_t = rhs_wrap_t, trivial_value_is_null_t<_lhs_t>::value>; + using _rhs_t = Rhs; using _nodes = detail::type_vector<_lhs_t, _rhs_t>; static_assert(can_be_null_t<_lhs_t>::value ? true - : not(std::is_same<_rhs_t, null_t>::value or is_tvin_t<_rhs_t>::value), + : not std::is_same<_rhs_t, null_t>::value, "column must not be null"); assignment_t(_lhs_t lhs, _rhs_t rhs) : _lhs(lhs), _rhs(rhs) @@ -64,19 +61,13 @@ namespace sqlpp }; template - struct serializer_t> + Context& serialize(const assignment_t& t, Context& context) { - using T = assignment_t; - using _serialize_check = serialize_check_of; - - static Context& _(const T& t, Context& context) - { - serialize(simple_column(t._lhs), context); - context << "="; - serialize_operand(t._rhs, context); - return context; - } - }; + serialize(simple_column(t._lhs), context); + context << "="; + serialize_operand(t._rhs, context); + return context; + } } // namespace sqlpp #endif diff --git a/include/sqlpp11/bad_expression.h b/include/sqlpp11/bad_expression.h index c8c37712..97aaca9d 100644 --- a/include/sqlpp11/bad_expression.h +++ b/include/sqlpp11/bad_expression.h @@ -46,13 +46,7 @@ namespace sqlpp }; template - struct serializer_t> - { - using _serialize_check = assert_valid_operands; - using T = bad_expression; - - static Context& _(const T&, Context&); - }; + Context serialize(const bad_expression& t, Context& context); } // namespace sqlpp #endif diff --git a/include/sqlpp11/basic_expression_operators.h b/include/sqlpp11/basic_expression_operators.h index c924f964..637d807d 100644 --- a/include/sqlpp11/basic_expression_operators.h +++ b/include/sqlpp11/basic_expression_operators.h @@ -127,7 +127,7 @@ namespace sqlpp auto operator==(T t) const -> _new_binary_expression_t { using rhs = wrap_operand_t; - check_comparison_t{}; + check_comparison_t::verify(); return {*static_cast(this), rhs{t}}; } @@ -136,7 +136,7 @@ namespace sqlpp auto operator!=(T t) const -> _new_binary_expression_t { using rhs = wrap_operand_t; - check_comparison_t{}; + check_comparison_t::verify(); return {*static_cast(this), rhs{t}}; } @@ -145,7 +145,7 @@ namespace sqlpp auto operator<(T t) const -> _new_binary_expression_t { using rhs = wrap_operand_t; - check_comparison_t{}; + check_comparison_t::verify(); return {*static_cast(this), rhs{t}}; } @@ -154,7 +154,7 @@ namespace sqlpp auto operator<=(T t) const -> _new_binary_expression_t { using rhs = wrap_operand_t; - check_comparison_t{}; + check_comparison_t::verify(); return {*static_cast(this), rhs{t}}; } @@ -163,7 +163,7 @@ namespace sqlpp auto operator>(T t) const -> _new_binary_expression_t { using rhs = wrap_operand_t; - check_comparison_t{}; + check_comparison_t::verify(); return {*static_cast(this), rhs{t}}; } @@ -205,100 +205,114 @@ namespace sqlpp template auto in(T... t) const -> typename _new_nary_expression::type { - check_in_t...>{}; + check_in_t...>::verify(); return {*static_cast(this), typename wrap_operand::type{t}...}; } template auto not_in(T... t) const -> typename _new_nary_expression::type { - check_in_t...>{}; + check_in_t...>::verify(); return {*static_cast(this), typename wrap_operand::type{t}...}; } template auto operator not() const -> return_type_not_t { - typename return_type_not::check{}; + return_type_not::check::verify(); return {*static_cast(this)}; } template auto operator and(const R& r) const -> return_type_and_t { - typename return_type_and::check{}; + return_type_and::check::verify(); return {*static_cast(this), wrap_operand_t{r}}; } template auto operator&(const R& r) const -> return_type_bitwise_and_t { - typename return_type_bitwise_and::check{}; + return_type_bitwise_and::check::verify(); return {*static_cast(this), wrap_operand_t{r}}; } template auto operator|(const R& r) const -> return_type_bitwise_or_t { - typename return_type_bitwise_or::check{}; + return_type_bitwise_or::check::verify(); return {*static_cast(this), wrap_operand_t{r}}; } template auto operator or(const R& r) const -> return_type_or_t { - typename return_type_or::check{}; + return_type_or::check::verify(); return {*static_cast(this), wrap_operand_t{r}}; } template auto operator+(const R& r) const -> return_type_plus_t { - typename return_type_plus::check{}; + return_type_plus::check::verify(); return {*static_cast(this), wrap_operand_t{r}}; } template auto operator-(const R& r) const -> return_type_minus_t { - typename return_type_minus::check{}; + return_type_minus::check::verify(); return {*static_cast(this), wrap_operand_t{r}}; } template auto operator*(const R& r) const -> return_type_multiplies_t { - typename return_type_multiplies::check{}; + return_type_multiplies::check::verify(); return {*static_cast(this), wrap_operand_t{r}}; } template auto operator/(const R& r) const -> return_type_divides_t { - typename return_type_divides::check{}; + return_type_divides::check::verify(); return {*static_cast(this), wrap_operand_t{r}}; } template auto operator%(const R& r) const -> return_type_modulus_t { - typename return_type_modulus::check{}; + return_type_modulus::check::verify(); return {*static_cast(this), wrap_operand_t{r}}; } template auto operator+() const -> return_type_unary_plus_t { - typename return_type_unary_plus::check{}; + return_type_unary_plus::check::verify(); return {*static_cast(this)}; } template auto operator-() const -> return_type_unary_minus_t { - typename return_type_unary_minus::check{}; + return_type_unary_minus::check::verify(); return {*static_cast(this)}; } + + template + auto operator<<(const R& r) const -> return_type_shift_left_t + { + return_type_shift_left::check::verify(); + return {*static_cast(this), wrap_operand_t{r}}; + } + + template + auto operator>>(const R& r) const -> return_type_shift_right_t + { + return_type_shift_right::check::verify(); + return {*static_cast(this), wrap_operand_t{r}}; + } }; } // namespace sqlpp diff --git a/include/sqlpp11/boolean_expression.h b/include/sqlpp11/boolean_expression.h index 8da7fc7a..d4580710 100644 --- a/include/sqlpp11/boolean_expression.h +++ b/include/sqlpp11/boolean_expression.h @@ -68,16 +68,10 @@ namespace sqlpp } template - struct serializer_t> + Context& serialize(const boolean_expression_t& t, Context& context) { - using _serialize_check = consistent_t; - using T = boolean_expression_t; - - static Context& _(const T& t, Context& context) - { - return serialize(t._expr, context); - } - }; + return serialize(t._expr, context); + } } // namespace sqlpp #endif diff --git a/include/sqlpp11/case.h b/include/sqlpp11/case.h index beface1a..12b0e2ae 100644 --- a/include/sqlpp11/case.h +++ b/include/sqlpp11/case.h @@ -151,23 +151,17 @@ namespace sqlpp }; template - struct serializer_t> + Context& serialize(const case_t& t, Context& context) { - using _serialize_check = serialize_check_of; - using T = case_t; - - static Context& _(const T& t, Context& context) - { - context << "(CASE WHEN "; - serialize(t._when, context); - context << " THEN "; - serialize(t._then, context); - context << " ELSE "; - serialize(t._else, context); - context << " END)"; - return context; - } - }; + context << "(CASE WHEN "; + serialize(t._when, context); + context << " THEN "; + serialize(t._then, context); + context << " ELSE "; + serialize(t._else, context); + context << " END)"; + return context; + } namespace detail { diff --git a/include/sqlpp11/char_sequence.h b/include/sqlpp11/char_sequence.h index 4d6144c1..2e6b51c8 100644 --- a/include/sqlpp11/char_sequence.h +++ b/include/sqlpp11/char_sequence.h @@ -27,10 +27,17 @@ #ifndef SQLPP11_CHAR_SEQUENCE_H #define SQLPP11_CHAR_SEQUENCE_H +#include #include namespace sqlpp { + template + std::integral_constant get_quote_left(const Context&); + + template + std::integral_constant get_quote_right(const Context&); + template struct char_sequence { diff --git a/include/sqlpp11/chrono.h b/include/sqlpp11/chrono.h index 10c03c7c..8ad24142 100644 --- a/include/sqlpp11/chrono.h +++ b/include/sqlpp11/chrono.h @@ -33,7 +33,7 @@ namespace sqlpp { namespace chrono { - using days = std::chrono::duration, std::chrono::hours::period>>; + using days = std::chrono::duration>; using day_point = std::chrono::time_point; using microsecond_point = std::chrono::time_point; diff --git a/include/sqlpp11/column.h b/include/sqlpp11/column.h index b22dd3b8..7b347ad7 100644 --- a/include/sqlpp11/column.h +++ b/include/sqlpp11/column.h @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -109,32 +108,15 @@ namespace sqlpp } }; - // workaround for msvs bug https://connect.microsoft.com/VisualStudio/feedback/details/2173053 - // template - // struct serializer_t> - // { - // using _serialize_check = consistent_t; - // using T = column_t; - // - // static Context& _(const T&, Context& context) - // { - // context << name_of::char_ptr() << '.' << name_of::char_ptr(); - // return context; - // } - // }; - template - struct serializer_t> + template + Context& serialize(const column_t&, Context& context) { - using _serialize_check = consistent_t; - using T = column_t; + using T = column_t; - static Context& _(const T& /*unused*/, Context& context) - { - context << name_of::template char_ptr() << '.' - << name_of::template char_ptr(); - return context; - } - }; + context << name_of::template char_ptr() << '.' + << name_of::template char_ptr(); + return context; + } } // namespace sqlpp #endif diff --git a/include/sqlpp11/connection_pool.h b/include/sqlpp11/connection_pool.h index 14e4e81b..e2d057fa 100644 --- a/include/sqlpp11/connection_pool.h +++ b/include/sqlpp11/connection_pool.h @@ -173,12 +173,14 @@ namespace sqlpp pool_connection get_connection() { - std::lock_guard lock(connection_pool_mutex); - if (!free_connections.empty()) { - auto connection = std::move(free_connections.top()); - free_connections.pop(); - return pool_connection(connection, this); + std::lock_guard lock(connection_pool_mutex); + if (!free_connections.empty()) + { + auto connection = std::move(free_connections.top()); + free_connections.pop(); + return pool_connection(connection, this); + } } try diff --git a/include/sqlpp11/consistent.h b/include/sqlpp11/consistent.h index 0b38593c..a83db633 100644 --- a/include/sqlpp11/consistent.h +++ b/include/sqlpp11/consistent.h @@ -33,6 +33,10 @@ namespace sqlpp { struct consistent_t : std::true_type { + template + static constexpr void verify(T&&...) + { + } }; } // namespace sqlpp diff --git a/include/sqlpp11/cte.h b/include/sqlpp11/cte.h index eaa1129e..2fd4a9d4 100644 --- a/include/sqlpp11/cte.h +++ b/include/sqlpp11/cte.h @@ -63,21 +63,15 @@ namespace sqlpp // Interpreters template - struct serializer_t> + Context& serialize(const cte_union_t& t, Context& context) { - using _serialize_check = serialize_check_of; - using T = cte_union_t; - - static Context& _(const T& t, Context& context) - { - serialize(t._lhs, context); - context << " UNION "; - serialize(Flag{}, context); - context << " "; - serialize(t._rhs, context); - return context; - } - }; + serialize(t._lhs, context); + context << " UNION "; + serialize(Flag{}, context); + context << " "; + serialize(t._rhs, context); + return context; + } template struct cte_t; @@ -229,19 +223,14 @@ namespace sqlpp }; template - struct serializer_t> + Context& serialize(const cte_t& t, Context& context) { - using _serialize_check = serialize_check_of; using T = cte_t; - - static Context& _(const T& t, Context& context) - { - context << name_of::template char_ptr() << " AS ("; - serialize(t._statement, context); - context << ")"; - return context; - } - }; + context << name_of::template char_ptr() << " AS ("; + serialize(t._statement, context); + context << ")"; + return context; + } // The cte_t is displayed as AliasProviderName except within the with: // - the with needs the @@ -273,17 +262,11 @@ namespace sqlpp }; template - struct serializer_t> + Context& serialize(const cte_ref_t&, Context& context) { - using _serialize_check = consistent_t; - using T = cte_ref_t; - - static Context& _(const T& /*unused*/, Context& context) - { - context << name_of::template char_ptr(); - return context; - } - }; + context << name_of>::template char_ptr(); + return context; + } template auto cte(const AliasProvider & /*unused*/) -> cte_ref_t diff --git a/include/sqlpp11/custom_query.h b/include/sqlpp11/custom_query.h index 7099f306..1f217b15 100644 --- a/include/sqlpp11/custom_query.h +++ b/include/sqlpp11/custom_query.h @@ -92,14 +92,14 @@ namespace sqlpp template auto _run(Db& db) const -> decltype(std::declval<_methods_t>()._run(db, *this)) { - _run_check{}; // FIXME: dispatch here? + _run_check::verify(); return _methods_t::_run(db, *this); } template auto _prepare(Db& db) const -> decltype(std::declval<_methods_t>()._prepare(db, *this)) { - _prepare_check{}; // FIXME: dispatch here? + _prepare_check::verify(); return _methods_t::_prepare(db, *this); } @@ -123,17 +123,11 @@ namespace sqlpp }; template - struct serializer_t> + Context& serialize(const custom_query_t& t, Context& context) { - using _serialize_check = serialize_check_of; - using T = custom_query_t; - - static Context& _(const T& t, Context& context) - { - interpret_tuple_without_braces(t._parts, " ", context); - return context; - } - }; + interpret_tuple_without_braces(t._parts, " ", context); + return context; + } template auto custom_query(Parts... parts) -> custom_query_t...> diff --git a/include/sqlpp11/data_types/blob/operand.h b/include/sqlpp11/data_types/blob/operand.h index df0983ee..67772fa2 100644 --- a/include/sqlpp11/data_types/blob/operand.h +++ b/include/sqlpp11/data_types/blob/operand.h @@ -30,7 +30,6 @@ #include #include #include -#include namespace sqlpp { @@ -63,32 +62,21 @@ namespace sqlpp blob_operand& operator=(blob_operand&&) = default; ~blob_operand() = default; - bool _is_trivial() const - { - return _t.empty(); - } - _value_t _t; }; template - struct serializer_t + Context& serialize(const blob_operand& t, Context& context) { - using _serialize_check = consistent_t; - using Operand = blob_operand; - - static Context& _(const Operand& t, Context& context) + constexpr char hexChars[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + context << "x'"; + for (const auto c : t._t) { - constexpr char hexChars[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; - context << "x'"; - for (const auto c : t._t) - { - context << hexChars[c >> 4] << hexChars[c & 0x0F]; - } - context << '\''; - - return context; + context << hexChars[c >> 4] << hexChars[c & 0x0F]; } - }; + context << '\''; + + return context; + } } // namespace sqlpp #endif diff --git a/include/sqlpp11/data_types/blob/parameter_value.h b/include/sqlpp11/data_types/blob/parameter_value.h index 39b57fd1..f36cd311 100644 --- a/include/sqlpp11/data_types/blob/parameter_value.h +++ b/include/sqlpp11/data_types/blob/parameter_value.h @@ -32,7 +32,6 @@ #include #include #include -#include namespace sqlpp { diff --git a/include/sqlpp11/data_types/blob/result_field.h b/include/sqlpp11/data_types/blob/result_field.h index b6fadccb..6839fc58 100644 --- a/include/sqlpp11/data_types/blob/result_field.h +++ b/include/sqlpp11/data_types/blob/result_field.h @@ -37,9 +37,9 @@ namespace sqlpp { - template - struct result_field_t> - : public result_field_base> + template + struct result_field_t> + : public result_field_base> { const uint8_t* blob{nullptr}; // Non-owning size_t len{}; @@ -67,11 +67,11 @@ namespace sqlpp } }; - template + template inline std::ostream& operator<<( - std::ostream& os, const result_field_t>& e) + std::ostream& os, const result_field_t>& e) { - if (e.is_null() and not NullIsTrivialValue) + if (e.is_null()) { return os << "NULL"; } diff --git a/include/sqlpp11/data_types/boolean/operand.h b/include/sqlpp11/data_types/boolean/operand.h index b211dab3..d82f5e8f 100644 --- a/include/sqlpp11/data_types/boolean/operand.h +++ b/include/sqlpp11/data_types/boolean/operand.h @@ -31,7 +31,6 @@ #include #include -#include namespace sqlpp { @@ -59,26 +58,15 @@ namespace sqlpp boolean_operand& operator=(boolean_operand&&) = default; ~boolean_operand() = default; - bool _is_trivial() const - { - return not _t; - } - _value_t _t; }; template - struct serializer_t + Context& serialize(const boolean_operand& t, Context& context) { - using _serialize_check = consistent_t; - using Operand = boolean_operand; - - static Context& _(const Operand& t, Context& context) - { - context << t._t; - return context; - } - }; + context << t._t; + return context; + } } // namespace sqlpp #endif diff --git a/include/sqlpp11/data_types/boolean/parameter_value.h b/include/sqlpp11/data_types/boolean/parameter_value.h index ee6375d0..0e854abe 100644 --- a/include/sqlpp11/data_types/boolean/parameter_value.h +++ b/include/sqlpp11/data_types/boolean/parameter_value.h @@ -30,7 +30,6 @@ #include #include #include -#include namespace sqlpp { diff --git a/include/sqlpp11/data_types/boolean/result_field.h b/include/sqlpp11/data_types/boolean/result_field.h index a2c6db39..6b4586ce 100644 --- a/include/sqlpp11/data_types/boolean/result_field.h +++ b/include/sqlpp11/data_types/boolean/result_field.h @@ -35,9 +35,9 @@ namespace sqlpp { - template - struct result_field_t> - : public result_field_base, signed char> + template + struct result_field_t> + : public result_field_base, signed char> { template void _bind(Target& target, size_t index) diff --git a/include/sqlpp11/data_types/day_point/operand.h b/include/sqlpp11/data_types/day_point/operand.h index 28b592b6..66eedfe5 100644 --- a/include/sqlpp11/data_types/day_point/operand.h +++ b/include/sqlpp11/data_types/day_point/operand.h @@ -31,7 +31,6 @@ #include #include #include -#include namespace sqlpp { @@ -57,26 +56,15 @@ namespace sqlpp day_point_operand& operator=(day_point_operand&&) = default; ~day_point_operand() = default; - bool _is_trivial() const - { - return std::chrono::operator==(_t, _value_t{}); - } - _value_t _t; }; template - struct serializer_t + Context& serialize(const day_point_operand& t, Context& context) { - using _serialize_check = consistent_t; - using Operand = day_point_operand; - - static Context& _(const Operand& t, Context& context) - { - const auto ymd = ::date::year_month_day{t._t}; - context << "DATE '" << ymd << "'"; - return context; - } - }; + const auto ymd = ::date::year_month_day{t._t}; + context << "DATE '" << ymd << "'"; + return context; + } } // namespace sqlpp #endif diff --git a/include/sqlpp11/data_types/day_point/parameter_value.h b/include/sqlpp11/data_types/day_point/parameter_value.h index bb8b5387..05077a11 100644 --- a/include/sqlpp11/data_types/day_point/parameter_value.h +++ b/include/sqlpp11/data_types/day_point/parameter_value.h @@ -32,7 +32,6 @@ #include #include #include -#include namespace sqlpp { diff --git a/include/sqlpp11/data_types/day_point/result_field.h b/include/sqlpp11/data_types/day_point/result_field.h index 520615ee..ad60b02f 100644 --- a/include/sqlpp11/data_types/day_point/result_field.h +++ b/include/sqlpp11/data_types/day_point/result_field.h @@ -36,9 +36,9 @@ namespace sqlpp { - template - struct result_field_t> - : public result_field_base> + template + struct result_field_t> + : public result_field_base> { template void _bind(Target& target, size_t index) @@ -53,11 +53,11 @@ namespace sqlpp } }; - template + template inline std::ostream& operator<<( - std::ostream& os, const result_field_t>& e) + std::ostream& os, const result_field_t>& e) { - if (e.is_null() and not NullIsTrivialValue) + if (e.is_null()) { os << "NULL"; } diff --git a/include/sqlpp11/data_types/floating_point/operand.h b/include/sqlpp11/data_types/floating_point/operand.h index 5a375288..8e754900 100644 --- a/include/sqlpp11/data_types/floating_point/operand.h +++ b/include/sqlpp11/data_types/floating_point/operand.h @@ -29,7 +29,6 @@ #include #include -#include namespace sqlpp { @@ -55,25 +54,14 @@ namespace sqlpp floating_point_operand& operator=(floating_point_operand&&) = default; ~floating_point_operand() = default; - bool _is_trivial() const - { - return _t == 0; - } - _value_t _t; }; template - struct serializer_t + Context& serialize(const floating_point_operand& t, Context& context) { - using _serialize_check = consistent_t; - using Operand = floating_point_operand; - - static Context& _(const Operand& t, Context& context) - { - context << t._t; - return context; - } - }; + context << t._t; + return context; + } } // namespace sqlpp #endif diff --git a/include/sqlpp11/data_types/floating_point/parameter_value.h b/include/sqlpp11/data_types/floating_point/parameter_value.h index 11df153f..beec2d37 100644 --- a/include/sqlpp11/data_types/floating_point/parameter_value.h +++ b/include/sqlpp11/data_types/floating_point/parameter_value.h @@ -32,7 +32,6 @@ #include #include #include -#include namespace sqlpp { diff --git a/include/sqlpp11/data_types/floating_point/result_field.h b/include/sqlpp11/data_types/floating_point/result_field.h index 2d298337..4a267919 100644 --- a/include/sqlpp11/data_types/floating_point/result_field.h +++ b/include/sqlpp11/data_types/floating_point/result_field.h @@ -36,9 +36,9 @@ namespace sqlpp { - template - struct result_field_t> - : public result_field_base> + template + struct result_field_t> + : public result_field_base> { template void _bind(Target& target, size_t index) diff --git a/include/sqlpp11/data_types/integral/column_operators.h b/include/sqlpp11/data_types/integral/column_operators.h index 75872df5..9b017fb1 100644 --- a/include/sqlpp11/data_types/integral/column_operators.h +++ b/include/sqlpp11/data_types/integral/column_operators.h @@ -47,7 +47,7 @@ namespace sqlpp using rhs = wrap_operand_t; static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); - return {*static_cast(this), {{*static_cast(this), rhs{t}}}}; + return {*static_cast(this), {*static_cast(this), rhs{t}}}; } template @@ -56,7 +56,7 @@ namespace sqlpp using rhs = wrap_operand_t; static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); - return {*static_cast(this), {{*static_cast(this), rhs{t}}}}; + return {*static_cast(this), {*static_cast(this), rhs{t}}}; } template @@ -65,7 +65,7 @@ namespace sqlpp using rhs = wrap_operand_t; static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); - return {*static_cast(this), {{*static_cast(this), rhs{t}}}}; + return {*static_cast(this), {*static_cast(this), rhs{t}}}; } template @@ -74,7 +74,7 @@ namespace sqlpp using rhs = wrap_operand_t; static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); - return {*static_cast(this), {{*static_cast(this), rhs{t}}}}; + return {*static_cast(this), {*static_cast(this), rhs{t}}}; } }; } // namespace sqlpp diff --git a/include/sqlpp11/data_types/integral/expression_operators.h b/include/sqlpp11/data_types/integral/expression_operators.h index 79006c2b..b8cd39a9 100644 --- a/include/sqlpp11/data_types/integral/expression_operators.h +++ b/include/sqlpp11/data_types/integral/expression_operators.h @@ -132,5 +132,19 @@ namespace sqlpp using check = consistent_t; using type = bitwise_or_t, integral, wrap_operand_t>; }; + + template + struct return_type_shift_left> + { + using check = consistent_t; + using type = shift_left_t, integral, wrap_operand_t>; + }; + + template + struct return_type_shift_right> + { + using check = consistent_t; + using type = shift_right_t, integral, wrap_operand_t>; + }; } // namespace sqlpp #endif diff --git a/include/sqlpp11/data_types/integral/operand.h b/include/sqlpp11/data_types/integral/operand.h index 06a00e14..6338f2b7 100644 --- a/include/sqlpp11/data_types/integral/operand.h +++ b/include/sqlpp11/data_types/integral/operand.h @@ -29,7 +29,6 @@ #include #include -#include namespace sqlpp { @@ -57,26 +56,15 @@ namespace sqlpp integral_operand& operator=(integral_operand&&) = default; ~integral_operand() = default; - bool _is_trivial() const - { - return _t == 0; - } - _value_t _t; }; template - struct serializer_t + Context& serialize(const integral_operand& t, Context& context) { - using _serialize_check = consistent_t; - using Operand = integral_operand; - - static Context& _(const Operand& t, Context& context) - { - context << t._t; - return context; - } - }; + context << t._t; + return context; + } } // namespace sqlpp #endif diff --git a/include/sqlpp11/data_types/integral/parameter_value.h b/include/sqlpp11/data_types/integral/parameter_value.h index af98bb62..244de247 100644 --- a/include/sqlpp11/data_types/integral/parameter_value.h +++ b/include/sqlpp11/data_types/integral/parameter_value.h @@ -30,7 +30,6 @@ #include #include #include -#include namespace sqlpp { diff --git a/include/sqlpp11/data_types/integral/result_field.h b/include/sqlpp11/data_types/integral/result_field.h index aee172f9..e8051655 100644 --- a/include/sqlpp11/data_types/integral/result_field.h +++ b/include/sqlpp11/data_types/integral/result_field.h @@ -35,9 +35,9 @@ namespace sqlpp { - template - struct result_field_t> - : public result_field_base> + template + struct result_field_t> + : public result_field_base> { template void _bind(Target& target, size_t index) diff --git a/include/sqlpp11/data_types/no_value/result_field.h b/include/sqlpp11/data_types/no_value/result_field.h index 1aa55222..8c677a15 100644 --- a/include/sqlpp11/data_types/no_value/result_field.h +++ b/include/sqlpp11/data_types/no_value/result_field.h @@ -33,8 +33,8 @@ namespace sqlpp { - template - struct result_field_t> + template + struct result_field_t> { template void _bind(Target& /*unused*/, size_t /*unused*/) @@ -60,10 +60,10 @@ namespace sqlpp } }; - template + template inline std::ostream& operator<<( std::ostream& os, - const result_field_t>& /*unused*/) + const result_field_t>& /*unused*/) { os << "NULL"; return os; diff --git a/include/sqlpp11/data_types/parameter_value_base.h b/include/sqlpp11/data_types/parameter_value_base.h index b75f78ca..c7e103d5 100644 --- a/include/sqlpp11/data_types/parameter_value_base.h +++ b/include/sqlpp11/data_types/parameter_value_base.h @@ -28,7 +28,6 @@ #define SQLPP11_DATA_TYPES_PARAMETER_VALUE_BASE_H #include -#include namespace sqlpp { @@ -54,21 +53,6 @@ namespace sqlpp return *this; } - parameter_value_base& operator=(const tvin_t>& t) - { - if (t._is_trivial()) - { - _value = {}; - _is_null = true; - } - else - { - _value = t._value._t; - _is_null = false; - } - return *this; - } - void set_null() { _value = {}; diff --git a/include/sqlpp11/data_types/text/concat.h b/include/sqlpp11/data_types/text/concat.h index 6102cc24..f488f12b 100644 --- a/include/sqlpp11/data_types/text/concat.h +++ b/include/sqlpp11/data_types/text/concat.h @@ -75,19 +75,13 @@ namespace sqlpp }; template - struct serializer_t> + Context& serialize(const concat_t& t, Context& context) { - using _serialize_check = serialize_check_of; - using T = concat_t; - - static Context& _(const T& t, Context& context) - { - context << "("; - interpret_tuple(t._args, "||", context); - context << ")"; - return context; - } - }; + context << "("; + interpret_tuple(t._args, "||", context); + context << ")"; + return context; + } template auto concat(Args... args) -> concat_t diff --git a/include/sqlpp11/data_types/text/expression_operators.h b/include/sqlpp11/data_types/text/expression_operators.h index 440ce546..7355af9a 100644 --- a/include/sqlpp11/data_types/text/expression_operators.h +++ b/include/sqlpp11/data_types/text/expression_operators.h @@ -57,7 +57,7 @@ namespace sqlpp template auto like(const R& r) const -> return_type_like_t { - typename return_type_like::check{}; + return_type_like::check::verify(); return {*static_cast(this), wrap_operand_t{r}}; } }; diff --git a/include/sqlpp11/data_types/text/like.h b/include/sqlpp11/data_types/text/like.h index 288e4cdb..fc7e5710 100644 --- a/include/sqlpp11/data_types/text/like.h +++ b/include/sqlpp11/data_types/text/like.h @@ -79,20 +79,14 @@ namespace sqlpp }; template - struct serializer_t> + Context& serialize(const like_t& t, Context& context) { - using _serialize_check = serialize_check_of; - using T = like_t; - - static Context& _(const T& t, Context& context) - { - serialize_operand(t._operand, context); - context << " LIKE("; - serialize(t._pattern, context); - context << ")"; - return context; - } - }; + serialize_operand(t._operand, context); + context << " LIKE("; + serialize(t._pattern, context); + context << ")"; + return context; + } } // namespace sqlpp #endif diff --git a/include/sqlpp11/data_types/text/operand.h b/include/sqlpp11/data_types/text/operand.h index 1bf169be..8a0b9ca2 100644 --- a/include/sqlpp11/data_types/text/operand.h +++ b/include/sqlpp11/data_types/text/operand.h @@ -34,7 +34,6 @@ #endif #include #include -#include namespace sqlpp { @@ -70,25 +69,14 @@ namespace sqlpp text_operand& operator=(text_operand&&) = default; ~text_operand() = default; - bool _is_trivial() const - { - return _t.empty(); - } - _value_t _t; }; template - struct serializer_t + Context& serialize(const text_operand& t, Context& context) { - using _serialize_check = consistent_t; - using Operand = text_operand; - - static Context& _(const Operand& t, Context& context) - { - context << '\'' << context.escape(t._t) << '\''; - return context; - } - }; + context << '\'' << context.escape(t._t) << '\''; + return context; + } } // namespace sqlpp #endif diff --git a/include/sqlpp11/data_types/text/parameter_value.h b/include/sqlpp11/data_types/text/parameter_value.h index cf7bbf07..e1ac1bd0 100644 --- a/include/sqlpp11/data_types/text/parameter_value.h +++ b/include/sqlpp11/data_types/text/parameter_value.h @@ -32,7 +32,6 @@ #include #include #include -#include namespace sqlpp { diff --git a/include/sqlpp11/data_types/text/result_field.h b/include/sqlpp11/data_types/text/result_field.h index 6d82cf51..01a3d0f5 100644 --- a/include/sqlpp11/data_types/text/result_field.h +++ b/include/sqlpp11/data_types/text/result_field.h @@ -36,9 +36,9 @@ namespace sqlpp { - template - struct result_field_t> - : public result_field_base> + template + struct result_field_t> + : public result_field_base> { const char* text{nullptr}; // Non-owning size_t len{}; @@ -74,11 +74,11 @@ namespace sqlpp } }; - template + template inline std::ostream& operator<<( - std::ostream& os, const result_field_t>& e) + std::ostream& os, const result_field_t>& e) { - if (e.is_null() and not NullIsTrivialValue) + if (e.is_null()) { return os << "NULL"; } diff --git a/include/sqlpp11/data_types/time_of_day/operand.h b/include/sqlpp11/data_types/time_of_day/operand.h index b628b95c..a7b20064 100644 --- a/include/sqlpp11/data_types/time_of_day/operand.h +++ b/include/sqlpp11/data_types/time_of_day/operand.h @@ -30,7 +30,6 @@ #include #include #include -#include namespace sqlpp { @@ -59,25 +58,14 @@ namespace sqlpp time_of_day_operand& operator=(time_of_day_operand&&) = default; ~time_of_day_operand() = default; - bool _is_trivial() const - { - return std::chrono::operator==(_t, _value_t{}); - } - _value_t _t; }; template - struct serializer_t> + Context& serialize(const time_of_day_operand& t, Context& context) { - using _serialize_check = consistent_t; - using Operand = time_of_day_operand; - - static Context& _(const Operand& t, Context& context) - { - context << '\'' << ::date::make_time(t._t) << '\''; - return context; - } - }; + context << '\'' << ::date::make_time(t._t) << '\''; + return context; + } } // namespace sqlpp #endif diff --git a/include/sqlpp11/data_types/time_of_day/parameter_value.h b/include/sqlpp11/data_types/time_of_day/parameter_value.h index e062c32f..b7a0e8c1 100644 --- a/include/sqlpp11/data_types/time_of_day/parameter_value.h +++ b/include/sqlpp11/data_types/time_of_day/parameter_value.h @@ -32,7 +32,6 @@ #include #include #include -#include namespace sqlpp { diff --git a/include/sqlpp11/data_types/time_of_day/result_field.h b/include/sqlpp11/data_types/time_of_day/result_field.h index 17e6bfd8..fe659ff4 100644 --- a/include/sqlpp11/data_types/time_of_day/result_field.h +++ b/include/sqlpp11/data_types/time_of_day/result_field.h @@ -37,9 +37,9 @@ namespace sqlpp { - template - struct result_field_t> - : public result_field_base> + template + struct result_field_t> + : public result_field_base> { template void _bind(Target& target, size_t i) @@ -54,11 +54,11 @@ namespace sqlpp } }; - template + template inline std::ostream& operator<<( - std::ostream& os, const result_field_t>& e) + std::ostream& os, const result_field_t>& e) { - if (e.is_null() and not NullIsTrivialValue) + if (e.is_null()) { os << "NULL"; } diff --git a/include/sqlpp11/data_types/time_point/operand.h b/include/sqlpp11/data_types/time_point/operand.h index d3053acd..7bd5893f 100644 --- a/include/sqlpp11/data_types/time_point/operand.h +++ b/include/sqlpp11/data_types/time_point/operand.h @@ -30,7 +30,6 @@ #include #include #include -#include namespace sqlpp { @@ -59,28 +58,17 @@ namespace sqlpp time_point_operand& operator=(time_point_operand&&) = default; ~time_point_operand() = default; - bool _is_trivial() const - { - return std::chrono::operator==(_t, _value_t{}); - } - _value_t _t; }; template - struct serializer_t> + Context& serialize(const time_point_operand& t, Context& context) { - using _serialize_check = consistent_t; - using Operand = time_point_operand; - - static Context& _(const Operand& t, Context& context) - { - const auto dp = ::sqlpp::chrono::floor<::date::days>(t._t); - const auto time = ::date::make_time(t._t - dp); - const auto ymd = ::date::year_month_day{dp}; - context << "TIMESTAMP '" << ymd << ' ' << time << "'"; - return context; - } - }; + const auto dp = ::sqlpp::chrono::floor<::date::days>(t._t); + const auto time = ::date::make_time(t._t - dp); + const auto ymd = ::date::year_month_day{dp}; + context << "TIMESTAMP '" << ymd << ' ' << time << "'"; + return context; + } } // namespace sqlpp #endif diff --git a/include/sqlpp11/data_types/time_point/parameter_value.h b/include/sqlpp11/data_types/time_point/parameter_value.h index a05b0cf6..e2ed62f6 100644 --- a/include/sqlpp11/data_types/time_point/parameter_value.h +++ b/include/sqlpp11/data_types/time_point/parameter_value.h @@ -32,7 +32,6 @@ #include #include #include -#include namespace sqlpp { diff --git a/include/sqlpp11/data_types/time_point/result_field.h b/include/sqlpp11/data_types/time_point/result_field.h index 2b6c4031..7bc17c6d 100644 --- a/include/sqlpp11/data_types/time_point/result_field.h +++ b/include/sqlpp11/data_types/time_point/result_field.h @@ -37,9 +37,9 @@ namespace sqlpp { - template - struct result_field_t> - : public result_field_base> + template + struct result_field_t> + : public result_field_base> { template void _bind(Target& target, size_t i) @@ -54,11 +54,11 @@ namespace sqlpp } }; - template + template inline std::ostream& operator<<( - std::ostream& os, const result_field_t>& e) + std::ostream& os, const result_field_t>& e) { - if (e.is_null() and not NullIsTrivialValue) + if (e.is_null()) { os << "NULL"; } diff --git a/include/sqlpp11/data_types/unsigned_integral/expression_operators.h b/include/sqlpp11/data_types/unsigned_integral/expression_operators.h index 49f2a2f4..dca8529e 100644 --- a/include/sqlpp11/data_types/unsigned_integral/expression_operators.h +++ b/include/sqlpp11/data_types/unsigned_integral/expression_operators.h @@ -113,5 +113,19 @@ namespace sqlpp using check = consistent_t; using type = bitwise_or_t, unsigned_integral, wrap_operand_t>; }; + + template + struct return_type_shift_left> + { + using check = consistent_t; + using type = shift_left_t, unsigned_integral, wrap_operand_t>; + }; + + template + struct return_type_shift_right> + { + using check = consistent_t; + using type = shift_right_t, unsigned_integral, wrap_operand_t>; + }; } // namespace sqlpp #endif diff --git a/include/sqlpp11/data_types/unsigned_integral/operand.h b/include/sqlpp11/data_types/unsigned_integral/operand.h index 7c6037e7..0e146b8e 100644 --- a/include/sqlpp11/data_types/unsigned_integral/operand.h +++ b/include/sqlpp11/data_types/unsigned_integral/operand.h @@ -29,7 +29,6 @@ #include #include -#include namespace sqlpp { @@ -57,26 +56,15 @@ namespace sqlpp unsigned_integral_operand& operator=(unsigned_integral_operand&&) = default; ~unsigned_integral_operand() = default; - bool _is_trivial() const - { - return _t == 0; - } - _value_t _t; }; template - struct serializer_t + Context& serialize(const unsigned_integral_operand& t, Context& context) { - using _serialize_check = consistent_t; - using Operand = unsigned_integral_operand; - - static Context& _(const Operand& t, Context& context) - { - context << t._t; - return context; - } - }; + context << t._t; + return context; + } } // namespace sqlpp #endif diff --git a/include/sqlpp11/data_types/unsigned_integral/parameter_value.h b/include/sqlpp11/data_types/unsigned_integral/parameter_value.h index 64e0b81d..c847d728 100644 --- a/include/sqlpp11/data_types/unsigned_integral/parameter_value.h +++ b/include/sqlpp11/data_types/unsigned_integral/parameter_value.h @@ -30,7 +30,6 @@ #include #include #include -#include namespace sqlpp { diff --git a/include/sqlpp11/data_types/unsigned_integral/result_field.h b/include/sqlpp11/data_types/unsigned_integral/result_field.h index 19f68037..ded6ff15 100644 --- a/include/sqlpp11/data_types/unsigned_integral/result_field.h +++ b/include/sqlpp11/data_types/unsigned_integral/result_field.h @@ -35,9 +35,9 @@ namespace sqlpp { - template - struct result_field_t> - : public result_field_base> + template + struct result_field_t> + : public result_field_base> { template void _bind(Target& target, size_t index) diff --git a/include/sqlpp11/default_value.h b/include/sqlpp11/default_value.h index a3fe714b..9ac64144 100644 --- a/include/sqlpp11/default_value.h +++ b/include/sqlpp11/default_value.h @@ -35,25 +35,14 @@ namespace sqlpp { using _traits = make_traits; using _nodes = detail::type_vector<>; - - static constexpr bool _is_trivial() - { - return false; - } }; template - struct serializer_t + Context& serialize(const default_value_t&, Context& context) { - using _serialize_check = consistent_t; - using Operand = default_value_t; - - static Context& _(const Operand& /*unused*/, Context& context) - { - context << "DEFAULT"; - return context; - } - }; + context << "DEFAULT"; + return context; + } constexpr default_value_t default_value = {}; } // namespace sqlpp diff --git a/include/sqlpp11/detail/sum.h b/include/sqlpp11/detail/column_tuple_merge.h similarity index 69% rename from include/sqlpp11/detail/sum.h rename to include/sqlpp11/detail/column_tuple_merge.h index 8a0b762b..1851a030 100644 --- a/include/sqlpp11/detail/sum.h +++ b/include/sqlpp11/detail/column_tuple_merge.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, Roland Bock + * Copyright (c) 2021-2021, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -24,37 +24,35 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SQLPP11_DETAIL_SUM_H -#define SQLPP11_DETAIL_SUM_H +#ifndef SQLPP11_COLUMN_TUPLE_MERGE_H +#define SQLPP11_COLUMN_TUPLE_MERGE_H + +#include + +#include namespace sqlpp { namespace detail { - /** a non-recursive C++14 version - template - constexpr std::size_t sum(Args... args) - { - std::size_t result = 0; - - using swallow = int[]; - (void) swallow{(result += args, 0)...}; - - return result; - } - */ - - constexpr std::size_t sum() + template + std::tuple> as_column_tuple(T t) { - return 0; + return std::tuple>(auto_alias_t{t}); } - template - constexpr std::size_t sum(Arg arg, Rest... rest) + template + std::tuple...> as_column_tuple(std::tuple t) { - return arg + sum(rest...); + return t; } - } // namespace detail + + template + auto column_tuple_merge(Columns... columns) -> decltype(std::tuple_cat(as_column_tuple(columns)...)) + { + return std::tuple_cat(as_column_tuple(columns)...); + } + } } // namespace sqlpp #endif diff --git a/include/sqlpp11/detail/copy_tuple_args.h b/include/sqlpp11/detail/copy_tuple_args.h deleted file mode 100644 index 5b94c2cb..00000000 --- a/include/sqlpp11/detail/copy_tuple_args.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2013-2015, 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 SQLPP11_DETAIL_COPY_TUPLE_ARGS_H -#define SQLPP11_DETAIL_COPY_TUPLE_ARGS_H - -#include -#include - -namespace sqlpp -{ - template - struct all_of_t; - - namespace detail - { - template - struct as_column_tuple - { - static std::tuple> _(T t) - { - return std::tuple>(auto_alias_t{t}); - } - }; - - template - struct as_column_tuple> - { - static typename all_of_t::_column_tuple_t _(all_of_t /*unused*/) - { - return {}; - } - }; - - template - struct as_column_tuple> - { - static std::tuple...> _(std::tuple t) - { - return t; - } - }; - - template