mirror of
https://github.com/rbock/sqlpp11.git
synced 2026-02-18 04:08:47 -06:00
Merge branch 'release/0.61'
This commit is contained in:
38
.travis.yml
38
.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
|
||||
|
||||
163
CMakeLists.txt
163
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
|
||||
$<BUILD_INTERFACE:${sqlpp11_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||
)
|
||||
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()
|
||||
|
||||
81
README.md
81
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 | [](https://travis-ci.com/rbock/sqlpp11?branch=master) | [](https://ci.appveyor.com/project/rbock/sqlpp11/branch/master) | [](https://coveralls.io/r/rbock/sqlpp11?branch=master)
|
||||
develop | [](https://travis-ci.com/rbock/sqlpp11?branch=develop) | [](https://ci.appveyor.com/project/rbock/sqlpp11/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
|
||||
* [](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)
|
||||
|
||||
|
||||
|
||||
35
cmake/FindMariaDB.cmake
Normal file
35
cmake/FindMariaDB.cmake
Normal file
@@ -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)
|
||||
49
cmake/FindMySQL.cmake
Normal file
49
cmake/FindMySQL.cmake
Normal file
@@ -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)
|
||||
65
cmake/Sqlpp11TargetHelper.cmake
Normal file
65
cmake/Sqlpp11TargetHelper.cmake
Normal file
@@ -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()
|
||||
@@ -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()
|
||||
2
cmake/configs/Sqlpp11MariaDBConfig.cmake
Normal file
2
cmake/configs/Sqlpp11MariaDBConfig.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
include(CMakeFindDependencyMacro)
|
||||
find_dependency(MariaDB)
|
||||
2
cmake/configs/Sqlpp11MySQLConfig.cmake
Normal file
2
cmake/configs/Sqlpp11MySQLConfig.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
include(CMakeFindDependencyMacro)
|
||||
find_dependency(MySQL)
|
||||
2
cmake/configs/Sqlpp11PostgreSQLConfig.cmake
Normal file
2
cmake/configs/Sqlpp11PostgreSQLConfig.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
include(CMakeFindDependencyMacro)
|
||||
find_dependency(PostgreSQL)
|
||||
2
cmake/configs/Sqlpp11SQLCipherConfig.cmake
Normal file
2
cmake/configs/Sqlpp11SQLCipherConfig.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
include(CMakeFindDependencyMacro)
|
||||
find_dependency(SQLCipher)
|
||||
2
cmake/configs/Sqlpp11SQLite3Config.cmake
Normal file
2
cmake/configs/Sqlpp11SQLite3Config.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
include(CMakeFindDependencyMacro)
|
||||
find_dependency(SQLite3)
|
||||
15
dependencies/CMakeLists.txt
vendored
15
dependencies/CMakeLists.txt
vendored
@@ -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)
|
||||
FetchContent_Declare(date
|
||||
GIT_REPOSITORY https://github.com/HowardHinnant/date.git
|
||||
GIT_TAG v3.0.0
|
||||
)
|
||||
|
||||
add_subdirectory(hinnant_date)
|
||||
endif()
|
||||
|
||||
5
dependencies/hinnant_date/CMakeLists.txt
vendored
5
dependencies/hinnant_date/CMakeLists.txt
vendored
@@ -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)
|
||||
# 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}")
|
||||
11
docs/Database.md
Normal file
11
docs/Database.md
Normal file
@@ -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).
|
||||
69
docs/Dynamic-Select.md
Normal file
69
docs/Dynamic-Select.md
Normal file
@@ -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.
|
||||
10
docs/Exception-Handling.md
Normal file
10
docs/Exception-Handling.md
Normal file
@@ -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.
|
||||
86
docs/Functions.md
Normal file
86
docs/Functions.md
Normal file
@@ -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<sqlpp::bigint>(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<sqlpp::boolean>("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
|
||||
```
|
||||
24
docs/Home.md
Normal file
24
docs/Home.md
Normal file
@@ -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)
|
||||
35
docs/Insert.md
Normal file
35
docs/Insert.md
Normal file
@@ -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::integer>(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<std::chrono::system_clock, std::chrono::microseconds>`.
|
||||
|
||||
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::microseconds>(
|
||||
std::chrono::system_clock::now()));
|
||||
```
|
||||
|
||||
Similar for other data types.
|
||||
100
docs/NULL.md
Normal file
100
docs/NULL.md
Normal file
@@ -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<sqlpp::bigint,
|
||||
// ...
|
||||
sqlpp::tag::trivial_value_is_null>;
|
||||
};
|
||||
```
|
||||
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.
|
||||
58
docs/New-Features.md
Normal file
58
docs/New-Features.md
Normal file
@@ -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 <sqlpp11/ppgen.h>
|
||||
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
|
||||
```
|
||||
48
docs/Prepared-Statements.md
Normal file
48
docs/Prepared-Statements.md
Normal file
@@ -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...
|
||||
20
docs/Remove.md
Normal file
20
docs/Remove.md
Normal file
@@ -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
|
||||
));
|
||||
```
|
||||
242
docs/Select.md
Normal file
242
docs/Select.md
Normal file
@@ -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();
|
||||
}
|
||||
128
docs/Tables.md
Normal file
128
docs/Tables.md
Normal file
@@ -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<typename T>
|
||||
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<typename T>
|
||||
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<typename T>
|
||||
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<typename T>
|
||||
struct _member_t
|
||||
{
|
||||
T tabSample;
|
||||
};
|
||||
};
|
||||
template<typename Db>
|
||||
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<typename T>
|
||||
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);
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
5
docs/Update.md
Normal file
5
docs/Update.md
Normal file
@@ -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)));
|
||||
```
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -84,28 +84,22 @@ namespace sqlpp
|
||||
};
|
||||
|
||||
template <typename Context, typename Flag, typename Expr>
|
||||
struct serializer_t<Context, avg_t<Flag, Expr>>
|
||||
Context& serialize(const avg_t<Flag, Expr>& t, Context& context)
|
||||
{
|
||||
using _serialize_check = serialize_check_of<Context, Flag, Expr>;
|
||||
using T = avg_t<Flag, Expr>;
|
||||
|
||||
static Context& _(const T& t, Context& context)
|
||||
context << "AVG(";
|
||||
if (std::is_same<distinct_t, Flag>::value)
|
||||
{
|
||||
context << "AVG(";
|
||||
if (std::is_same<distinct_t, Flag>::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 <typename T>
|
||||
auto avg(T t) -> avg_t<noop, wrap_operand_t<T>>
|
||||
|
||||
@@ -87,28 +87,22 @@ namespace sqlpp
|
||||
};
|
||||
|
||||
template <typename Context, typename Flag, typename Expr>
|
||||
struct serializer_t<Context, count_t<Flag, Expr>>
|
||||
Context& serialize(const count_t<Flag, Expr>& t, Context& context)
|
||||
{
|
||||
using _serialize_check = serialize_check_of<Context, Flag, Expr>;
|
||||
using T = count_t<Flag, Expr>;
|
||||
|
||||
static Context& _(const T& t, Context& context)
|
||||
context << "COUNT(";
|
||||
if (std::is_same<distinct_t, Flag>::value)
|
||||
{
|
||||
context << "COUNT(";
|
||||
if (std::is_same<distinct_t, Flag>::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 <typename T>
|
||||
auto count(T t) -> count_t<noop, wrap_operand_t<T>>
|
||||
|
||||
@@ -80,19 +80,13 @@ namespace sqlpp
|
||||
};
|
||||
|
||||
template <typename Context, typename Expr>
|
||||
struct serializer_t<Context, max_t<Expr>>
|
||||
Context& serialize(const max_t<Expr>& t, Context& context)
|
||||
{
|
||||
using _serialize_check = serialize_check_of<Context, Expr>;
|
||||
using T = max_t<Expr>;
|
||||
|
||||
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 <typename T>
|
||||
auto max(T t) -> max_t<wrap_operand_t<T>>
|
||||
|
||||
@@ -80,19 +80,13 @@ namespace sqlpp
|
||||
};
|
||||
|
||||
template <typename Context, typename Expr>
|
||||
struct serializer_t<Context, min_t<Expr>>
|
||||
Context& serialize(const min_t<Expr>& t, Context& context)
|
||||
{
|
||||
using _serialize_check = serialize_check_of<Context, Expr>;
|
||||
using T = min_t<Expr>;
|
||||
|
||||
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 <typename T>
|
||||
auto min(T t) -> min_t<wrap_operand_t<T>>
|
||||
|
||||
@@ -84,29 +84,22 @@ namespace sqlpp
|
||||
};
|
||||
|
||||
template <typename Context, typename Flag, typename Expr>
|
||||
struct serializer_t<Context, sum_t<Flag, Expr>>
|
||||
Context& serialize(const sum_t<Flag, Expr>& t, Context& context)
|
||||
{
|
||||
using _serialize_check = serialize_check_of<Context, Flag, Expr>;
|
||||
using T = sum_t<Flag, Expr>;
|
||||
|
||||
static Context& _(const T& t, Context& context)
|
||||
context << "SUM(";
|
||||
if (std::is_same<distinct_t, Flag>::value)
|
||||
{
|
||||
context << "SUM(";
|
||||
if (std::is_same<distinct_t, Flag>::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 <typename T>
|
||||
auto sum(T t) -> sum_t<noop, wrap_operand_t<T>>
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#define SQLPP11_ALIAS_H
|
||||
|
||||
#include <sqlpp11/type_traits.h>
|
||||
#include <sqlpp11/serializer.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
@@ -57,19 +56,13 @@ namespace sqlpp
|
||||
};
|
||||
|
||||
template <typename Context, typename Expression, typename AliasProvider>
|
||||
struct serializer_t<Context, expression_alias_t<Expression, AliasProvider>>
|
||||
Context& serialize(const expression_alias_t<Expression, AliasProvider>& t, Context& context)
|
||||
{
|
||||
using _serialize_check = serialize_check_of<Context, Expression>;
|
||||
using T = expression_alias_t<Expression, AliasProvider>;
|
||||
|
||||
static Context& _(const T& t, Context& context)
|
||||
{
|
||||
serialize_operand(t._expression, context);
|
||||
context << " AS ";
|
||||
context << name_of<T>::template char_ptr<Context>();
|
||||
return context;
|
||||
}
|
||||
};
|
||||
serialize_operand(t._expression, context);
|
||||
context << " AS ";
|
||||
context << name_of<expression_alias_t<Expression, AliasProvider>>::template char_ptr<Context>();
|
||||
return context;
|
||||
}
|
||||
} // namespace sqlpp
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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 <sqlpp11/alias.h>
|
||||
#include <sqlpp11/interpret.h>
|
||||
#include <sqlpp11/multi_column.h>
|
||||
#include <sqlpp11/portable_static_assert.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
template <typename Table>
|
||||
struct all_of_t
|
||||
{
|
||||
using _column_tuple_t = typename Table::_column_tuple_t;
|
||||
|
||||
template <typename AliasProvider>
|
||||
detail::copy_tuple_args_t<multi_column_alias_t, AliasProvider, _column_tuple_t> as(const AliasProvider& alias)
|
||||
{
|
||||
return multi_column(_column_tuple_t{}).as(alias);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Table>
|
||||
auto all_of(Table /*unused*/) -> all_of_t<Table>
|
||||
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 <typename Context, typename Table>
|
||||
struct serializer_t<Context, all_of_t<Table>>
|
||||
{
|
||||
using _serialize_check = assert_no_stand_alone_all_of_t;
|
||||
using T = all_of_t<Table>;
|
||||
|
||||
static Context& _(const T& /*unused*/, const Context& /*unused*/)
|
||||
{
|
||||
_serialize_check{};
|
||||
}
|
||||
};
|
||||
} // namespace sqlpp
|
||||
|
||||
#endif
|
||||
|
||||
@@ -53,19 +53,13 @@ namespace sqlpp
|
||||
};
|
||||
|
||||
template <typename Context, typename Select>
|
||||
struct serializer_t<Context, any_t<Select>>
|
||||
Context& serialize(const any_t<Select>& t, Context& context)
|
||||
{
|
||||
using _serialize_check = serialize_check_of<Context, Select>;
|
||||
using T = any_t<Select>;
|
||||
|
||||
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 <typename T>
|
||||
auto any(T t) -> any_t<wrap_operand_t<T>>
|
||||
|
||||
@@ -29,10 +29,7 @@
|
||||
|
||||
#include <sqlpp11/default_value.h>
|
||||
#include <sqlpp11/null.h>
|
||||
#include <sqlpp11/tvin.h>
|
||||
#include <sqlpp11/rhs_wrap.h>
|
||||
#include <sqlpp11/serialize.h>
|
||||
#include <sqlpp11/serializer.h>
|
||||
#include <sqlpp11/simple_column.h>
|
||||
|
||||
namespace sqlpp
|
||||
@@ -42,11 +39,11 @@ namespace sqlpp
|
||||
{
|
||||
using _traits = make_traits<no_value_t, tag::is_assignment>;
|
||||
using _lhs_t = Lhs;
|
||||
using _rhs_t = rhs_wrap_t<allow_tvin_t<Rhs>, 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 <typename Context, typename Lhs, typename Rhs>
|
||||
struct serializer_t<Context, assignment_t<Lhs, Rhs>>
|
||||
Context& serialize(const assignment_t<Lhs, Rhs>& t, Context& context)
|
||||
{
|
||||
using T = assignment_t<Lhs, Rhs>;
|
||||
using _serialize_check = serialize_check_of<Context, typename T::_lhs_t, typename T::_rhs_t>;
|
||||
|
||||
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
|
||||
|
||||
@@ -46,13 +46,7 @@ namespace sqlpp
|
||||
};
|
||||
|
||||
template <typename Context, typename ValueType>
|
||||
struct serializer_t<Context, bad_expression<ValueType>>
|
||||
{
|
||||
using _serialize_check = assert_valid_operands;
|
||||
using T = bad_expression<ValueType>;
|
||||
|
||||
static Context& _(const T&, Context&);
|
||||
};
|
||||
Context serialize(const bad_expression<ValueType>& t, Context& context);
|
||||
} // namespace sqlpp
|
||||
|
||||
#endif
|
||||
|
||||
@@ -127,7 +127,7 @@ namespace sqlpp
|
||||
auto operator==(T t) const -> _new_binary_expression_t<equal_to_t, T>
|
||||
{
|
||||
using rhs = wrap_operand_t<T>;
|
||||
check_comparison_t<Expr, rhs>{};
|
||||
check_comparison_t<Expr, rhs>::verify();
|
||||
|
||||
return {*static_cast<const Expr*>(this), rhs{t}};
|
||||
}
|
||||
@@ -136,7 +136,7 @@ namespace sqlpp
|
||||
auto operator!=(T t) const -> _new_binary_expression_t<not_equal_to_t, T>
|
||||
{
|
||||
using rhs = wrap_operand_t<T>;
|
||||
check_comparison_t<Expr, rhs>{};
|
||||
check_comparison_t<Expr, rhs>::verify();
|
||||
|
||||
return {*static_cast<const Expr*>(this), rhs{t}};
|
||||
}
|
||||
@@ -145,7 +145,7 @@ namespace sqlpp
|
||||
auto operator<(T t) const -> _new_binary_expression_t<less_than_t, T>
|
||||
{
|
||||
using rhs = wrap_operand_t<T>;
|
||||
check_comparison_t<Expr, rhs>{};
|
||||
check_comparison_t<Expr, rhs>::verify();
|
||||
|
||||
return {*static_cast<const Expr*>(this), rhs{t}};
|
||||
}
|
||||
@@ -154,7 +154,7 @@ namespace sqlpp
|
||||
auto operator<=(T t) const -> _new_binary_expression_t<less_equal_t, T>
|
||||
{
|
||||
using rhs = wrap_operand_t<T>;
|
||||
check_comparison_t<Expr, rhs>{};
|
||||
check_comparison_t<Expr, rhs>::verify();
|
||||
|
||||
return {*static_cast<const Expr*>(this), rhs{t}};
|
||||
}
|
||||
@@ -163,7 +163,7 @@ namespace sqlpp
|
||||
auto operator>(T t) const -> _new_binary_expression_t<greater_than_t, T>
|
||||
{
|
||||
using rhs = wrap_operand_t<T>;
|
||||
check_comparison_t<Expr, rhs>{};
|
||||
check_comparison_t<Expr, rhs>::verify();
|
||||
|
||||
return {*static_cast<const Expr*>(this), rhs{t}};
|
||||
}
|
||||
@@ -205,100 +205,114 @@ namespace sqlpp
|
||||
template <typename... T>
|
||||
auto in(T... t) const -> typename _new_nary_expression<in_t, T...>::type
|
||||
{
|
||||
check_in_t<Expr, wrap_operand_t<T>...>{};
|
||||
check_in_t<Expr, wrap_operand_t<T>...>::verify();
|
||||
return {*static_cast<const Expr*>(this), typename wrap_operand<T>::type{t}...};
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
auto not_in(T... t) const -> typename _new_nary_expression<not_in_t, T...>::type
|
||||
{
|
||||
check_in_t<Expr, wrap_operand_t<T>...>{};
|
||||
check_in_t<Expr, wrap_operand_t<T>...>::verify();
|
||||
return {*static_cast<const Expr*>(this), typename wrap_operand<T>::type{t}...};
|
||||
}
|
||||
|
||||
template <typename Defer = void>
|
||||
auto operator not() const -> return_type_not_t<Expr, Defer>
|
||||
{
|
||||
typename return_type_not<Expr, Defer>::check{};
|
||||
return_type_not<Expr, Defer>::check::verify();
|
||||
return {*static_cast<const Expr*>(this)};
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
auto operator and(const R& r) const -> return_type_and_t<Expr, R>
|
||||
{
|
||||
typename return_type_and<Expr, R>::check{};
|
||||
return_type_and<Expr, R>::check::verify();
|
||||
return {*static_cast<const Expr*>(this), wrap_operand_t<R>{r}};
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
auto operator&(const R& r) const -> return_type_bitwise_and_t<Expr, R>
|
||||
{
|
||||
typename return_type_bitwise_and<Expr, R>::check{};
|
||||
return_type_bitwise_and<Expr, R>::check::verify();
|
||||
return {*static_cast<const Expr*>(this), wrap_operand_t<R>{r}};
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
auto operator|(const R& r) const -> return_type_bitwise_or_t<Expr, R>
|
||||
{
|
||||
typename return_type_bitwise_or<Expr, R>::check{};
|
||||
return_type_bitwise_or<Expr, R>::check::verify();
|
||||
return {*static_cast<const Expr*>(this), wrap_operand_t<R>{r}};
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
auto operator or(const R& r) const -> return_type_or_t<Expr, R>
|
||||
{
|
||||
typename return_type_or<Expr, R>::check{};
|
||||
return_type_or<Expr, R>::check::verify();
|
||||
return {*static_cast<const Expr*>(this), wrap_operand_t<R>{r}};
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
auto operator+(const R& r) const -> return_type_plus_t<Expr, R>
|
||||
{
|
||||
typename return_type_plus<Expr, R>::check{};
|
||||
return_type_plus<Expr, R>::check::verify();
|
||||
return {*static_cast<const Expr*>(this), wrap_operand_t<R>{r}};
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
auto operator-(const R& r) const -> return_type_minus_t<Expr, R>
|
||||
{
|
||||
typename return_type_minus<Expr, R>::check{};
|
||||
return_type_minus<Expr, R>::check::verify();
|
||||
return {*static_cast<const Expr*>(this), wrap_operand_t<R>{r}};
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
auto operator*(const R& r) const -> return_type_multiplies_t<Expr, R>
|
||||
{
|
||||
typename return_type_multiplies<Expr, R>::check{};
|
||||
return_type_multiplies<Expr, R>::check::verify();
|
||||
return {*static_cast<const Expr*>(this), wrap_operand_t<R>{r}};
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
auto operator/(const R& r) const -> return_type_divides_t<Expr, R>
|
||||
{
|
||||
typename return_type_divides<Expr, R>::check{};
|
||||
return_type_divides<Expr, R>::check::verify();
|
||||
return {*static_cast<const Expr*>(this), wrap_operand_t<R>{r}};
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
auto operator%(const R& r) const -> return_type_modulus_t<Expr, R>
|
||||
{
|
||||
typename return_type_modulus<Expr, R>::check{};
|
||||
return_type_modulus<Expr, R>::check::verify();
|
||||
return {*static_cast<const Expr*>(this), wrap_operand_t<R>{r}};
|
||||
}
|
||||
|
||||
template <typename Defer = void>
|
||||
auto operator+() const -> return_type_unary_plus_t<Expr, Defer>
|
||||
{
|
||||
typename return_type_unary_plus<Expr, Defer>::check{};
|
||||
return_type_unary_plus<Expr, Defer>::check::verify();
|
||||
return {*static_cast<const Expr*>(this)};
|
||||
}
|
||||
|
||||
template <typename Defer = void>
|
||||
auto operator-() const -> return_type_unary_minus_t<Expr, Defer>
|
||||
{
|
||||
typename return_type_unary_minus<Expr, Defer>::check{};
|
||||
return_type_unary_minus<Expr, Defer>::check::verify();
|
||||
return {*static_cast<const Expr*>(this)};
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
auto operator<<(const R& r) const -> return_type_shift_left_t<Expr, R>
|
||||
{
|
||||
return_type_shift_left<Expr, R>::check::verify();
|
||||
return {*static_cast<const Expr*>(this), wrap_operand_t<R>{r}};
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
auto operator>>(const R& r) const -> return_type_shift_right_t<Expr, R>
|
||||
{
|
||||
return_type_shift_right<Expr, R>::check::verify();
|
||||
return {*static_cast<const Expr*>(this), wrap_operand_t<R>{r}};
|
||||
}
|
||||
};
|
||||
} // namespace sqlpp
|
||||
|
||||
|
||||
@@ -68,16 +68,10 @@ namespace sqlpp
|
||||
}
|
||||
|
||||
template <typename Context, typename Database>
|
||||
struct serializer_t<Context, boolean_expression_t<Database>>
|
||||
Context& serialize(const boolean_expression_t<Database>& t, Context& context)
|
||||
{
|
||||
using _serialize_check = consistent_t;
|
||||
using T = boolean_expression_t<Database>;
|
||||
|
||||
static Context& _(const T& t, Context& context)
|
||||
{
|
||||
return serialize(t._expr, context);
|
||||
}
|
||||
};
|
||||
return serialize(t._expr, context);
|
||||
}
|
||||
} // namespace sqlpp
|
||||
|
||||
#endif
|
||||
|
||||
@@ -151,23 +151,17 @@ namespace sqlpp
|
||||
};
|
||||
|
||||
template <typename Context, typename When, typename Then, typename Else>
|
||||
struct serializer_t<Context, case_t<When, Then, Else>>
|
||||
Context& serialize(const case_t<When, Then, Else>& t, Context& context)
|
||||
{
|
||||
using _serialize_check = serialize_check_of<When, Then, Else>;
|
||||
using T = case_t<When, Then, Else>;
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
@@ -27,10 +27,17 @@
|
||||
#ifndef SQLPP11_CHAR_SEQUENCE_H
|
||||
#define SQLPP11_CHAR_SEQUENCE_H
|
||||
|
||||
#include <type_traits>
|
||||
#include <sqlpp11/detail/index_sequence.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
template <typename Context>
|
||||
std::integral_constant<char, '"'> get_quote_left(const Context&);
|
||||
|
||||
template <typename Context>
|
||||
std::integral_constant<char, '"'> get_quote_right(const Context&);
|
||||
|
||||
template <char... Cs>
|
||||
struct char_sequence
|
||||
{
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace sqlpp
|
||||
{
|
||||
namespace chrono
|
||||
{
|
||||
using days = std::chrono::duration<int, std::ratio_multiply<std::ratio<24>, std::chrono::hours::period>>;
|
||||
using days = std::chrono::duration<int, std::ratio<86400, 1>>;
|
||||
|
||||
using day_point = std::chrono::time_point<std::chrono::system_clock, days>;
|
||||
using microsecond_point = std::chrono::time_point<std::chrono::system_clock, std::chrono::microseconds>;
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#include <sqlpp11/type_traits.h>
|
||||
#include <sqlpp11/assignment.h>
|
||||
#include <sqlpp11/expression.h>
|
||||
#include <sqlpp11/serializer.h>
|
||||
#include <sqlpp11/wrong.h>
|
||||
#include <sqlpp11/detail/type_set.h>
|
||||
|
||||
@@ -109,32 +108,15 @@ namespace sqlpp
|
||||
}
|
||||
};
|
||||
|
||||
// workaround for msvs bug https://connect.microsoft.com/VisualStudio/feedback/details/2173053
|
||||
// template <typename Context, typename... Args>
|
||||
// struct serializer_t<Context, column_t<Args...>>
|
||||
// {
|
||||
// using _serialize_check = consistent_t;
|
||||
// using T = column_t<Args...>;
|
||||
//
|
||||
// static Context& _(const T&, Context& context)
|
||||
// {
|
||||
// context << name_of<typename T::_table>::char_ptr() << '.' << name_of<T>::char_ptr();
|
||||
// return context;
|
||||
// }
|
||||
// };
|
||||
template <typename Context, typename Args1, typename Args2>
|
||||
struct serializer_t<Context, column_t<Args1, Args2>>
|
||||
template <typename Context, typename Table, typename ColumnSpec>
|
||||
Context& serialize(const column_t<Table, ColumnSpec>&, Context& context)
|
||||
{
|
||||
using _serialize_check = consistent_t;
|
||||
using T = column_t<Args1, Args2>;
|
||||
using T = column_t<Table, ColumnSpec>;
|
||||
|
||||
static Context& _(const T& /*unused*/, Context& context)
|
||||
{
|
||||
context << name_of<typename T::_table>::template char_ptr<Context>() << '.'
|
||||
<< name_of<T>::template char_ptr<Context>();
|
||||
return context;
|
||||
}
|
||||
};
|
||||
context << name_of<typename T::_table>::template char_ptr<Context>() << '.'
|
||||
<< name_of<T>::template char_ptr<Context>();
|
||||
return context;
|
||||
}
|
||||
} // namespace sqlpp
|
||||
|
||||
#endif
|
||||
|
||||
@@ -173,12 +173,14 @@ namespace sqlpp
|
||||
|
||||
pool_connection<Connection_config, Reconnect_policy, Connection> get_connection()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(connection_pool_mutex);
|
||||
if (!free_connections.empty())
|
||||
{
|
||||
auto connection = std::move(free_connections.top());
|
||||
free_connections.pop();
|
||||
return pool_connection<Connection_config, Reconnect_policy, Connection>(connection, this);
|
||||
std::lock_guard<std::mutex> lock(connection_pool_mutex);
|
||||
if (!free_connections.empty())
|
||||
{
|
||||
auto connection = std::move(free_connections.top());
|
||||
free_connections.pop();
|
||||
return pool_connection<Connection_config, Reconnect_policy, Connection>(connection, this);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
|
||||
@@ -33,6 +33,10 @@ namespace sqlpp
|
||||
{
|
||||
struct consistent_t : std::true_type
|
||||
{
|
||||
template <typename... T>
|
||||
static constexpr void verify(T&&...)
|
||||
{
|
||||
}
|
||||
};
|
||||
} // namespace sqlpp
|
||||
|
||||
|
||||
@@ -63,21 +63,15 @@ namespace sqlpp
|
||||
|
||||
// Interpreters
|
||||
template <typename Context, typename Flag, typename Lhs, typename Rhs>
|
||||
struct serializer_t<Context, cte_union_t<Flag, Lhs, Rhs>>
|
||||
Context& serialize(const cte_union_t<Flag, Lhs, Rhs>& t, Context& context)
|
||||
{
|
||||
using _serialize_check = serialize_check_of<Context, Lhs, Rhs>;
|
||||
using T = cte_union_t<Flag, Lhs, Rhs>;
|
||||
|
||||
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 <typename AliasProvider, typename Statement, typename... FieldSpecs>
|
||||
struct cte_t;
|
||||
@@ -229,19 +223,14 @@ namespace sqlpp
|
||||
};
|
||||
|
||||
template <typename Context, typename AliasProvider, typename Statement, typename... ColumnSpecs>
|
||||
struct serializer_t<Context, cte_t<AliasProvider, Statement, ColumnSpecs...>>
|
||||
Context& serialize(const cte_t<AliasProvider, Statement, ColumnSpecs...>& t, Context& context)
|
||||
{
|
||||
using _serialize_check = serialize_check_of<Context, Statement>;
|
||||
using T = cte_t<AliasProvider, Statement, ColumnSpecs...>;
|
||||
|
||||
static Context& _(const T& t, Context& context)
|
||||
{
|
||||
context << name_of<T>::template char_ptr<Context>() << " AS (";
|
||||
serialize(t._statement, context);
|
||||
context << ")";
|
||||
return context;
|
||||
}
|
||||
};
|
||||
context << name_of<T>::template char_ptr<Context>() << " 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 <typename Context, typename AliasProvider>
|
||||
struct serializer_t<Context, cte_ref_t<AliasProvider>>
|
||||
Context& serialize(const cte_ref_t<AliasProvider>&, Context& context)
|
||||
{
|
||||
using _serialize_check = consistent_t;
|
||||
using T = cte_ref_t<AliasProvider>;
|
||||
|
||||
static Context& _(const T& /*unused*/, Context& context)
|
||||
{
|
||||
context << name_of<T>::template char_ptr<Context>();
|
||||
return context;
|
||||
}
|
||||
};
|
||||
context << name_of<cte_ref_t<AliasProvider>>::template char_ptr<Context>();
|
||||
return context;
|
||||
}
|
||||
|
||||
template <typename AliasProvider>
|
||||
auto cte(const AliasProvider & /*unused*/) -> cte_ref_t<AliasProvider>
|
||||
|
||||
@@ -92,14 +92,14 @@ namespace sqlpp
|
||||
template <typename Db>
|
||||
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 <typename Db>
|
||||
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 <typename Context, typename Database, typename... Parts>
|
||||
struct serializer_t<Context, custom_query_t<Database, Parts...>>
|
||||
Context& serialize(const custom_query_t<Database, Parts...>& t, Context& context)
|
||||
{
|
||||
using _serialize_check = serialize_check_of<Context, Parts...>;
|
||||
using T = custom_query_t<Database, Parts...>;
|
||||
|
||||
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 <typename... Parts>
|
||||
auto custom_query(Parts... parts) -> custom_query_t<void, wrap_operand_t<Parts>...>
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <vector>
|
||||
#include <sqlpp11/type_traits.h>
|
||||
#include <sqlpp11/alias_operators.h>
|
||||
#include <sqlpp11/serializer.h>
|
||||
|
||||
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 <typename Context>
|
||||
struct serializer_t<Context, blob_operand>
|
||||
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
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include <sqlpp11/data_types/blob/data_type.h>
|
||||
#include <sqlpp11/data_types/blob/wrap_operand.h>
|
||||
#include <sqlpp11/data_types/blob/operand.h>
|
||||
#include <sqlpp11/tvin.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
|
||||
@@ -37,9 +37,9 @@
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
template <typename Db, typename NameType, bool CanBeNull, bool NullIsTrivialValue>
|
||||
struct result_field_t<Db, field_spec_t<NameType, blob, CanBeNull, NullIsTrivialValue>>
|
||||
: public result_field_base<Db, field_spec_t<NameType, blob, CanBeNull, NullIsTrivialValue>>
|
||||
template <typename Db, typename NameType, bool CanBeNull>
|
||||
struct result_field_t<Db, field_spec_t<NameType, blob, CanBeNull>>
|
||||
: public result_field_base<Db, field_spec_t<NameType, blob, CanBeNull>>
|
||||
{
|
||||
const uint8_t* blob{nullptr}; // Non-owning
|
||||
size_t len{};
|
||||
@@ -67,11 +67,11 @@ namespace sqlpp
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Db, typename NameType, bool CanBeNull, bool NullIsTrivialValue>
|
||||
template <typename Db, typename NameType, bool CanBeNull>
|
||||
inline std::ostream& operator<<(
|
||||
std::ostream& os, const result_field_t<Db, field_spec_t<NameType, blob, CanBeNull, NullIsTrivialValue>>& e)
|
||||
std::ostream& os, const result_field_t<Db, field_spec_t<NameType, blob, CanBeNull>>& e)
|
||||
{
|
||||
if (e.is_null() and not NullIsTrivialValue)
|
||||
if (e.is_null())
|
||||
{
|
||||
return os << "NULL";
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
|
||||
#include <sqlpp11/type_traits.h>
|
||||
#include <sqlpp11/alias_operators.h>
|
||||
#include <sqlpp11/serializer.h>
|
||||
|
||||
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 <typename Context>
|
||||
struct serializer_t<Context, boolean_operand>
|
||||
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
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <sqlpp11/data_types/parameter_value.h>
|
||||
#include <sqlpp11/data_types/parameter_value_base.h>
|
||||
#include <sqlpp11/data_types/boolean/data_type.h>
|
||||
#include <sqlpp11/tvin.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
|
||||
@@ -35,9 +35,9 @@
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
template <typename Db, typename NameType, bool CanBeNull, bool NullIsTrivialValue>
|
||||
struct result_field_t<Db, field_spec_t<NameType, boolean, CanBeNull, NullIsTrivialValue>>
|
||||
: public result_field_base<Db, field_spec_t<NameType, boolean, CanBeNull, NullIsTrivialValue>, signed char>
|
||||
template <typename Db, typename NameType, bool CanBeNull>
|
||||
struct result_field_t<Db, field_spec_t<NameType, boolean, CanBeNull>>
|
||||
: public result_field_base<Db, field_spec_t<NameType, boolean, CanBeNull>, signed char>
|
||||
{
|
||||
template <typename Target>
|
||||
void _bind(Target& target, size_t index)
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include <sqlpp11/chrono.h>
|
||||
#include <sqlpp11/type_traits.h>
|
||||
#include <sqlpp11/alias_operators.h>
|
||||
#include <sqlpp11/serializer.h>
|
||||
|
||||
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 <typename Context>
|
||||
struct serializer_t<Context, day_point_operand>
|
||||
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
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include <sqlpp11/data_types/day_point/data_type.h>
|
||||
#include <sqlpp11/data_types/day_point/wrap_operand.h>
|
||||
#include <sqlpp11/data_types/day_point/operand.h>
|
||||
#include <sqlpp11/tvin.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
|
||||
@@ -36,9 +36,9 @@
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
template <typename Db, typename NameType, bool CanBeNull, bool NullIsTrivialValue>
|
||||
struct result_field_t<Db, field_spec_t<NameType, day_point, CanBeNull, NullIsTrivialValue>>
|
||||
: public result_field_base<Db, field_spec_t<NameType, day_point, CanBeNull, NullIsTrivialValue>>
|
||||
template <typename Db, typename NameType, bool CanBeNull>
|
||||
struct result_field_t<Db, field_spec_t<NameType, day_point, CanBeNull>>
|
||||
: public result_field_base<Db, field_spec_t<NameType, day_point, CanBeNull>>
|
||||
{
|
||||
template <typename Target>
|
||||
void _bind(Target& target, size_t index)
|
||||
@@ -53,11 +53,11 @@ namespace sqlpp
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Db, typename NameType, bool CanBeNull, bool NullIsTrivialValue>
|
||||
template <typename Db, typename NameType, bool CanBeNull>
|
||||
inline std::ostream& operator<<(
|
||||
std::ostream& os, const result_field_t<Db, field_spec_t<NameType, day_point, CanBeNull, NullIsTrivialValue>>& e)
|
||||
std::ostream& os, const result_field_t<Db, field_spec_t<NameType, day_point, CanBeNull>>& e)
|
||||
{
|
||||
if (e.is_null() and not NullIsTrivialValue)
|
||||
if (e.is_null())
|
||||
{
|
||||
os << "NULL";
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
|
||||
#include <sqlpp11/type_traits.h>
|
||||
#include <sqlpp11/alias_operators.h>
|
||||
#include <sqlpp11/serializer.h>
|
||||
|
||||
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 <typename Context>
|
||||
struct serializer_t<Context, floating_point_operand>
|
||||
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
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include <sqlpp11/data_types/floating_point/data_type.h>
|
||||
#include <sqlpp11/data_types/floating_point/wrap_operand.h>
|
||||
#include <sqlpp11/data_types/floating_point/operand.h>
|
||||
#include <sqlpp11/tvin.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
|
||||
@@ -36,9 +36,9 @@
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
template <typename Db, typename NameType, bool CanBeNull, bool NullIsTrivialValue>
|
||||
struct result_field_t<Db, field_spec_t<NameType, floating_point, CanBeNull, NullIsTrivialValue>>
|
||||
: public result_field_base<Db, field_spec_t<NameType, floating_point, CanBeNull, NullIsTrivialValue>>
|
||||
template <typename Db, typename NameType, bool CanBeNull>
|
||||
struct result_field_t<Db, field_spec_t<NameType, floating_point, CanBeNull>>
|
||||
: public result_field_base<Db, field_spec_t<NameType, floating_point, CanBeNull>>
|
||||
{
|
||||
template <typename Target>
|
||||
void _bind(Target& target, size_t index)
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace sqlpp
|
||||
using rhs = wrap_operand_t<T>;
|
||||
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand");
|
||||
|
||||
return {*static_cast<const Column*>(this), {{*static_cast<const Column*>(this), rhs{t}}}};
|
||||
return {*static_cast<const Column*>(this), {*static_cast<const Column*>(this), rhs{t}}};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -56,7 +56,7 @@ namespace sqlpp
|
||||
using rhs = wrap_operand_t<T>;
|
||||
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand");
|
||||
|
||||
return {*static_cast<const Column*>(this), {{*static_cast<const Column*>(this), rhs{t}}}};
|
||||
return {*static_cast<const Column*>(this), {*static_cast<const Column*>(this), rhs{t}}};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -65,7 +65,7 @@ namespace sqlpp
|
||||
using rhs = wrap_operand_t<T>;
|
||||
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand");
|
||||
|
||||
return {*static_cast<const Column*>(this), {{*static_cast<const Column*>(this), rhs{t}}}};
|
||||
return {*static_cast<const Column*>(this), {*static_cast<const Column*>(this), rhs{t}}};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -74,7 +74,7 @@ namespace sqlpp
|
||||
using rhs = wrap_operand_t<T>;
|
||||
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand");
|
||||
|
||||
return {*static_cast<const Column*>(this), {{*static_cast<const Column*>(this), rhs{t}}}};
|
||||
return {*static_cast<const Column*>(this), {*static_cast<const Column*>(this), rhs{t}}};
|
||||
}
|
||||
};
|
||||
} // namespace sqlpp
|
||||
|
||||
@@ -132,5 +132,19 @@ namespace sqlpp
|
||||
using check = consistent_t;
|
||||
using type = bitwise_or_t<wrap_operand_t<L>, integral, wrap_operand_t<R>>;
|
||||
};
|
||||
|
||||
template <typename L, typename R>
|
||||
struct return_type_shift_left<L, R, binary_operand_check_t<L, is_integral_t, R, is_unsigned_integral_t>>
|
||||
{
|
||||
using check = consistent_t;
|
||||
using type = shift_left_t<wrap_operand_t<L>, integral, wrap_operand_t<R>>;
|
||||
};
|
||||
|
||||
template <typename L, typename R>
|
||||
struct return_type_shift_right<L, R, binary_operand_check_t<L, is_integral_t, R, is_unsigned_integral_t>>
|
||||
{
|
||||
using check = consistent_t;
|
||||
using type = shift_right_t<wrap_operand_t<L>, integral, wrap_operand_t<R>>;
|
||||
};
|
||||
} // namespace sqlpp
|
||||
#endif
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
|
||||
#include <sqlpp11/type_traits.h>
|
||||
#include <sqlpp11/alias_operators.h>
|
||||
#include <sqlpp11/serializer.h>
|
||||
|
||||
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 <typename Context>
|
||||
struct serializer_t<Context, integral_operand>
|
||||
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
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <sqlpp11/data_types/parameter_value.h>
|
||||
#include <sqlpp11/data_types/parameter_value_base.h>
|
||||
#include <sqlpp11/data_types/integral/data_type.h>
|
||||
#include <sqlpp11/tvin.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
|
||||
@@ -35,9 +35,9 @@
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
template <typename Db, typename NameType, bool CanBeNull, bool NullIsTrivialValue>
|
||||
struct result_field_t<Db, field_spec_t<NameType, integral, CanBeNull, NullIsTrivialValue>>
|
||||
: public result_field_base<Db, field_spec_t<NameType, integral, CanBeNull, NullIsTrivialValue>>
|
||||
template <typename Db, typename NameType, bool CanBeNull>
|
||||
struct result_field_t<Db, field_spec_t<NameType, integral, CanBeNull>>
|
||||
: public result_field_base<Db, field_spec_t<NameType, integral, CanBeNull>>
|
||||
{
|
||||
template <typename Target>
|
||||
void _bind(Target& target, size_t index)
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
template <typename Db, typename NameType, bool CanBeNull, bool NullIsTrivialValue>
|
||||
struct result_field_t<Db, field_spec_t<NameType, no_value_t, CanBeNull, NullIsTrivialValue>>
|
||||
template <typename Db, typename NameType, bool CanBeNull>
|
||||
struct result_field_t<Db, field_spec_t<NameType, no_value_t, CanBeNull>>
|
||||
{
|
||||
template <typename Target>
|
||||
void _bind(Target& /*unused*/, size_t /*unused*/)
|
||||
@@ -60,10 +60,10 @@ namespace sqlpp
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Db, typename NameType, bool CanBeNull, bool NullIsTrivialValue>
|
||||
template <typename Db, typename NameType, bool CanBeNull>
|
||||
inline std::ostream& operator<<(
|
||||
std::ostream& os,
|
||||
const result_field_t<Db, field_spec_t<NameType, no_value_t, CanBeNull, NullIsTrivialValue>>& /*unused*/)
|
||||
const result_field_t<Db, field_spec_t<NameType, no_value_t, CanBeNull>>& /*unused*/)
|
||||
{
|
||||
os << "NULL";
|
||||
return os;
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#define SQLPP11_DATA_TYPES_PARAMETER_VALUE_BASE_H
|
||||
|
||||
#include <sqlpp11/data_types/parameter_value.h>
|
||||
#include <sqlpp11/tvin.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
@@ -54,21 +53,6 @@ namespace sqlpp
|
||||
return *this;
|
||||
}
|
||||
|
||||
parameter_value_base& operator=(const tvin_t<wrap_operand_t<_cpp_value_type>>& t)
|
||||
{
|
||||
if (t._is_trivial())
|
||||
{
|
||||
_value = {};
|
||||
_is_null = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_value = t._value._t;
|
||||
_is_null = false;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void set_null()
|
||||
{
|
||||
_value = {};
|
||||
|
||||
@@ -75,19 +75,13 @@ namespace sqlpp
|
||||
};
|
||||
|
||||
template <typename Context, typename... Args>
|
||||
struct serializer_t<Context, concat_t<Args...>>
|
||||
Context& serialize(const concat_t<Args...>& t, Context& context)
|
||||
{
|
||||
using _serialize_check = serialize_check_of<Context, Args...>;
|
||||
using T = concat_t<Args...>;
|
||||
|
||||
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 <typename... Args>
|
||||
auto concat(Args... args) -> concat_t<Args...>
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace sqlpp
|
||||
template <typename R>
|
||||
auto like(const R& r) const -> return_type_like_t<Expression, R>
|
||||
{
|
||||
typename return_type_like<Expression, R>::check{};
|
||||
return_type_like<Expression, R>::check::verify();
|
||||
return {*static_cast<const Expression*>(this), wrap_operand_t<R>{r}};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -79,20 +79,14 @@ namespace sqlpp
|
||||
};
|
||||
|
||||
template <typename Context, typename Operand, typename Pattern>
|
||||
struct serializer_t<Context, like_t<Operand, Pattern>>
|
||||
Context& serialize(const like_t<Operand, Pattern>& t, Context& context)
|
||||
{
|
||||
using _serialize_check = serialize_check_of<Context, Operand, Pattern>;
|
||||
using T = like_t<Operand, Pattern>;
|
||||
|
||||
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
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#endif
|
||||
#include <sqlpp11/type_traits.h>
|
||||
#include <sqlpp11/alias_operators.h>
|
||||
#include <sqlpp11/serializer.h>
|
||||
|
||||
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 <typename Context>
|
||||
struct serializer_t<Context, text_operand>
|
||||
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
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include <sqlpp11/data_types/text/data_type.h>
|
||||
#include <sqlpp11/data_types/text/wrap_operand.h>
|
||||
#include <sqlpp11/data_types/text/operand.h>
|
||||
#include <sqlpp11/tvin.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
|
||||
@@ -36,9 +36,9 @@
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
template <typename Db, typename NameType, bool CanBeNull, bool NullIsTrivialValue>
|
||||
struct result_field_t<Db, field_spec_t<NameType, text, CanBeNull, NullIsTrivialValue>>
|
||||
: public result_field_base<Db, field_spec_t<NameType, text, CanBeNull, NullIsTrivialValue>>
|
||||
template <typename Db, typename NameType, bool CanBeNull>
|
||||
struct result_field_t<Db, field_spec_t<NameType, text, CanBeNull>>
|
||||
: public result_field_base<Db, field_spec_t<NameType, text, CanBeNull>>
|
||||
{
|
||||
const char* text{nullptr}; // Non-owning
|
||||
size_t len{};
|
||||
@@ -74,11 +74,11 @@ namespace sqlpp
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Db, typename NameType, bool CanBeNull, bool NullIsTrivialValue>
|
||||
template <typename Db, typename NameType, bool CanBeNull>
|
||||
inline std::ostream& operator<<(
|
||||
std::ostream& os, const result_field_t<Db, field_spec_t<NameType, text, CanBeNull, NullIsTrivialValue>>& e)
|
||||
std::ostream& os, const result_field_t<Db, field_spec_t<NameType, text, CanBeNull>>& e)
|
||||
{
|
||||
if (e.is_null() and not NullIsTrivialValue)
|
||||
if (e.is_null())
|
||||
{
|
||||
return os << "NULL";
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <sqlpp11/chrono.h>
|
||||
#include <sqlpp11/type_traits.h>
|
||||
#include <sqlpp11/alias_operators.h>
|
||||
#include <sqlpp11/serializer.h>
|
||||
|
||||
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 <typename Context, typename Period>
|
||||
struct serializer_t<Context, time_of_day_operand<Period>>
|
||||
Context& serialize(const time_of_day_operand<Period>& t, Context& context)
|
||||
{
|
||||
using _serialize_check = consistent_t;
|
||||
using Operand = time_of_day_operand<Period>;
|
||||
|
||||
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
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include <sqlpp11/data_types/time_of_day/data_type.h>
|
||||
#include <sqlpp11/data_types/time_point/wrap_operand.h>
|
||||
#include <sqlpp11/data_types/time_point/operand.h>
|
||||
#include <sqlpp11/tvin.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
|
||||
@@ -37,9 +37,9 @@
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
template <typename Db, typename NameType, bool CanBeNull, bool NullIsTrivialValue>
|
||||
struct result_field_t<Db, field_spec_t<NameType, time_of_day, CanBeNull, NullIsTrivialValue>>
|
||||
: public result_field_base<Db, field_spec_t<NameType, time_of_day, CanBeNull, NullIsTrivialValue>>
|
||||
template <typename Db, typename NameType, bool CanBeNull>
|
||||
struct result_field_t<Db, field_spec_t<NameType, time_of_day, CanBeNull>>
|
||||
: public result_field_base<Db, field_spec_t<NameType, time_of_day, CanBeNull>>
|
||||
{
|
||||
template <typename Target>
|
||||
void _bind(Target& target, size_t i)
|
||||
@@ -54,11 +54,11 @@ namespace sqlpp
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Db, typename NameType, bool CanBeNull, bool NullIsTrivialValue>
|
||||
template <typename Db, typename NameType, bool CanBeNull>
|
||||
inline std::ostream& operator<<(
|
||||
std::ostream& os, const result_field_t<Db, field_spec_t<NameType, time_of_day, CanBeNull, NullIsTrivialValue>>& e)
|
||||
std::ostream& os, const result_field_t<Db, field_spec_t<NameType, time_of_day, CanBeNull>>& e)
|
||||
{
|
||||
if (e.is_null() and not NullIsTrivialValue)
|
||||
if (e.is_null())
|
||||
{
|
||||
os << "NULL";
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <sqlpp11/chrono.h>
|
||||
#include <sqlpp11/type_traits.h>
|
||||
#include <sqlpp11/alias_operators.h>
|
||||
#include <sqlpp11/serializer.h>
|
||||
|
||||
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 <typename Context, typename Period>
|
||||
struct serializer_t<Context, time_point_operand<Period>>
|
||||
Context& serialize(const time_point_operand<Period>& t, Context& context)
|
||||
{
|
||||
using _serialize_check = consistent_t;
|
||||
using Operand = time_point_operand<Period>;
|
||||
|
||||
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
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include <sqlpp11/data_types/time_point/data_type.h>
|
||||
#include <sqlpp11/data_types/time_point/wrap_operand.h>
|
||||
#include <sqlpp11/data_types/time_point/operand.h>
|
||||
#include <sqlpp11/tvin.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
|
||||
@@ -37,9 +37,9 @@
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
template <typename Db, typename NameType, bool CanBeNull, bool NullIsTrivialValue>
|
||||
struct result_field_t<Db, field_spec_t<NameType, time_point, CanBeNull, NullIsTrivialValue>>
|
||||
: public result_field_base<Db, field_spec_t<NameType, time_point, CanBeNull, NullIsTrivialValue>>
|
||||
template <typename Db, typename NameType, bool CanBeNull>
|
||||
struct result_field_t<Db, field_spec_t<NameType, time_point, CanBeNull>>
|
||||
: public result_field_base<Db, field_spec_t<NameType, time_point, CanBeNull>>
|
||||
{
|
||||
template <typename Target>
|
||||
void _bind(Target& target, size_t i)
|
||||
@@ -54,11 +54,11 @@ namespace sqlpp
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Db, typename NameType, bool CanBeNull, bool NullIsTrivialValue>
|
||||
template <typename Db, typename NameType, bool CanBeNull>
|
||||
inline std::ostream& operator<<(
|
||||
std::ostream& os, const result_field_t<Db, field_spec_t<NameType, time_point, CanBeNull, NullIsTrivialValue>>& e)
|
||||
std::ostream& os, const result_field_t<Db, field_spec_t<NameType, time_point, CanBeNull>>& e)
|
||||
{
|
||||
if (e.is_null() and not NullIsTrivialValue)
|
||||
if (e.is_null())
|
||||
{
|
||||
os << "NULL";
|
||||
}
|
||||
|
||||
@@ -113,5 +113,19 @@ namespace sqlpp
|
||||
using check = consistent_t;
|
||||
using type = bitwise_or_t<wrap_operand_t<L>, unsigned_integral, wrap_operand_t<R>>;
|
||||
};
|
||||
|
||||
template <typename L, typename R>
|
||||
struct return_type_shift_left<L, R, binary_operand_check_t<L, is_unsigned_integral_t, R, is_unsigned_integral_t>>
|
||||
{
|
||||
using check = consistent_t;
|
||||
using type = shift_left_t<wrap_operand_t<L>, unsigned_integral, wrap_operand_t<R>>;
|
||||
};
|
||||
|
||||
template <typename L, typename R>
|
||||
struct return_type_shift_right<L, R, binary_operand_check_t<L, is_unsigned_integral_t, R, is_unsigned_integral_t>>
|
||||
{
|
||||
using check = consistent_t;
|
||||
using type = shift_right_t<wrap_operand_t<L>, unsigned_integral, wrap_operand_t<R>>;
|
||||
};
|
||||
} // namespace sqlpp
|
||||
#endif
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
|
||||
#include <sqlpp11/type_traits.h>
|
||||
#include <sqlpp11/alias_operators.h>
|
||||
#include <sqlpp11/serializer.h>
|
||||
|
||||
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 <typename Context>
|
||||
struct serializer_t<Context, unsigned_integral_operand>
|
||||
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
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <sqlpp11/data_types/parameter_value.h>
|
||||
#include <sqlpp11/data_types/parameter_value_base.h>
|
||||
#include <sqlpp11/data_types/unsigned_integral/data_type.h>
|
||||
#include <sqlpp11/tvin.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
|
||||
@@ -35,9 +35,9 @@
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
template <typename Db, typename NameType, bool CanBeNull, bool NullIsTrivialValue>
|
||||
struct result_field_t<Db, field_spec_t<NameType, unsigned_integral, CanBeNull, NullIsTrivialValue>>
|
||||
: public result_field_base<Db, field_spec_t<NameType, unsigned_integral, CanBeNull, NullIsTrivialValue>>
|
||||
template <typename Db, typename NameType, bool CanBeNull>
|
||||
struct result_field_t<Db, field_spec_t<NameType, unsigned_integral, CanBeNull>>
|
||||
: public result_field_base<Db, field_spec_t<NameType, unsigned_integral, CanBeNull>>
|
||||
{
|
||||
template <typename Target>
|
||||
void _bind(Target& target, size_t index)
|
||||
|
||||
@@ -35,25 +35,14 @@ namespace sqlpp
|
||||
{
|
||||
using _traits = make_traits<no_value_t, tag::is_expression>;
|
||||
using _nodes = detail::type_vector<>;
|
||||
|
||||
static constexpr bool _is_trivial()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Context>
|
||||
struct serializer_t<Context, default_value_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
|
||||
|
||||
@@ -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 <tuple>
|
||||
|
||||
#include <sqlpp11/auto_alias.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/** a non-recursive C++14 version
|
||||
template<typename... Args>
|
||||
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 <typename T>
|
||||
std::tuple<auto_alias_t<T>> as_column_tuple(T t)
|
||||
{
|
||||
return 0;
|
||||
return std::tuple<auto_alias_t<T>>(auto_alias_t<T>{t});
|
||||
}
|
||||
|
||||
template <typename Arg, typename... Rest>
|
||||
constexpr std::size_t sum(Arg arg, Rest... rest)
|
||||
template <typename... Args>
|
||||
std::tuple<auto_alias_t<Args>...> as_column_tuple(std::tuple<Args...> t)
|
||||
{
|
||||
return arg + sum(rest...);
|
||||
return t;
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template <typename... Columns>
|
||||
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
|
||||
@@ -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 <tuple>
|
||||
#include <sqlpp11/auto_alias.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
template <typename Table>
|
||||
struct all_of_t;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename T>
|
||||
struct as_column_tuple
|
||||
{
|
||||
static std::tuple<auto_alias_t<T>> _(T t)
|
||||
{
|
||||
return std::tuple<auto_alias_t<T>>(auto_alias_t<T>{t});
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct as_column_tuple<all_of_t<T>>
|
||||
{
|
||||
static typename all_of_t<T>::_column_tuple_t _(all_of_t<T> /*unused*/)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... Args>
|
||||
struct as_column_tuple<std::tuple<Args...>>
|
||||
{
|
||||
static std::tuple<auto_alias_t<Args>...> _(std::tuple<Args...> t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
};
|
||||
|
||||
template <template <typename, typename...> class Target, typename First, typename T>
|
||||
struct copy_tuple_args_impl
|
||||
{
|
||||
static_assert(wrong_t<copy_tuple_args_impl>::value, "copy_tuple_args must be called with a tuple");
|
||||
};
|
||||
|
||||
template <template <typename First, typename...> class Target, typename First, typename... Args>
|
||||
struct copy_tuple_args_impl<Target, First, std::tuple<Args...>>
|
||||
{
|
||||
using type = Target<First, Args...>;
|
||||
};
|
||||
|
||||
template <template <typename First, typename...> class Target, typename First, typename T>
|
||||
using copy_tuple_args_t = typename copy_tuple_args_impl<Target, First, T>::type;
|
||||
|
||||
template <typename... Columns>
|
||||
auto column_tuple_merge(Columns... columns) -> decltype(std::tuple_cat(as_column_tuple<Columns>::_(columns)...))
|
||||
{
|
||||
return std::tuple_cat(as_column_tuple<Columns>::_(columns)...);
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace sqlpp
|
||||
|
||||
#endif
|
||||
@@ -1,86 +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_FIELD_INDEX_SEQUENCE_H
|
||||
#define SQLPP11_DETAIL_FIELD_INDEX_SEQUENCE_H
|
||||
|
||||
#include <type_traits>
|
||||
#include <sqlpp11/field_spec.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <std::size_t NextIndex, std::size_t... Ints>
|
||||
struct field_index_sequence
|
||||
{
|
||||
static constexpr std::size_t _next_index = NextIndex;
|
||||
};
|
||||
|
||||
template <typename T, typename... Fields>
|
||||
struct make_field_index_sequence_impl
|
||||
{
|
||||
static_assert(wrong_t<make_field_index_sequence_impl>::value, "invalid field index sequence arguments");
|
||||
};
|
||||
|
||||
template <std::size_t NextIndex,
|
||||
std::size_t... Ints,
|
||||
typename NameType,
|
||||
typename ValueType,
|
||||
bool CanBeNull,
|
||||
bool NullIsTrivialValue,
|
||||
typename... Rest>
|
||||
struct make_field_index_sequence_impl<field_index_sequence<NextIndex, Ints...>,
|
||||
field_spec_t<NameType, ValueType, CanBeNull, NullIsTrivialValue>,
|
||||
Rest...>
|
||||
{
|
||||
using type = typename make_field_index_sequence_impl<field_index_sequence<NextIndex + 1, Ints..., NextIndex>,
|
||||
Rest...>::type;
|
||||
};
|
||||
|
||||
template <std::size_t NextIndex, std::size_t... Ints, typename AliasProvider, typename FieldTuple, typename... Rest>
|
||||
struct make_field_index_sequence_impl<field_index_sequence<NextIndex, Ints...>,
|
||||
multi_field_spec_t<AliasProvider, FieldTuple>,
|
||||
Rest...>
|
||||
{
|
||||
using type = typename make_field_index_sequence_impl<
|
||||
field_index_sequence<NextIndex + std::tuple_size<FieldTuple>::value, Ints..., NextIndex>,
|
||||
Rest...>::type;
|
||||
};
|
||||
|
||||
template <std::size_t NextIndex, std::size_t... Ints>
|
||||
struct make_field_index_sequence_impl<field_index_sequence<NextIndex, Ints...>>
|
||||
{
|
||||
using type = field_index_sequence<NextIndex, Ints...>;
|
||||
};
|
||||
|
||||
template <std::size_t StartIndex, typename... Fields>
|
||||
using make_field_index_sequence =
|
||||
typename make_field_index_sequence_impl<field_index_sequence<StartIndex>, Fields...>::type;
|
||||
} // namespace detail
|
||||
} // namespace sqlpp
|
||||
|
||||
#endif
|
||||
@@ -49,18 +49,12 @@ namespace sqlpp
|
||||
};
|
||||
|
||||
template <typename Context, typename PreJoin, typename On>
|
||||
struct serializer_t<Context, dynamic_join_t<PreJoin, On>>
|
||||
Context& serialize(const dynamic_join_t<PreJoin, On>& t, Context& context)
|
||||
{
|
||||
using _serialize_check = serialize_check_of<Context, PreJoin, On>;
|
||||
using T = dynamic_join_t<PreJoin, On>;
|
||||
|
||||
static Context& _(const T& t, Context& context)
|
||||
{
|
||||
serialize(t._pre_join, context);
|
||||
serialize(t._on, context);
|
||||
return context;
|
||||
}
|
||||
};
|
||||
serialize(t._pre_join, context);
|
||||
serialize(t._on, context);
|
||||
return context;
|
||||
}
|
||||
} // namespace sqlpp
|
||||
|
||||
#endif
|
||||
|
||||
@@ -105,19 +105,13 @@ namespace sqlpp
|
||||
};
|
||||
|
||||
template <typename Context, typename JoinType, typename Rhs>
|
||||
struct serializer_t<Context, dynamic_pre_join_t<JoinType, Rhs>>
|
||||
Context& serialize(const dynamic_pre_join_t<JoinType, Rhs>& t, Context& context)
|
||||
{
|
||||
using _serialize_check = serialize_check_of<Context, Rhs>;
|
||||
using T = dynamic_pre_join_t<JoinType, Rhs>;
|
||||
|
||||
static Context& _(const T& t, Context& context)
|
||||
{
|
||||
context << JoinType::_name;
|
||||
context << " JOIN ";
|
||||
serialize(t._rhs, context);
|
||||
return context;
|
||||
}
|
||||
};
|
||||
context << JoinType::_name;
|
||||
context << " JOIN ";
|
||||
serialize(t._rhs, context);
|
||||
return context;
|
||||
}
|
||||
|
||||
template <typename JoinType, typename Table>
|
||||
using make_dynamic_pre_join_t = typename std::conditional<check_dynamic_pre_join_t<Table>::value,
|
||||
@@ -127,35 +121,35 @@ namespace sqlpp
|
||||
template <typename Table>
|
||||
auto dynamic_join(Table table) -> make_dynamic_pre_join_t<inner_join_t, Table>
|
||||
{
|
||||
check_dynamic_pre_join_t<Table>{}; // FIXME: Failure return type?
|
||||
check_dynamic_pre_join_t<Table>::verify(); // FIXME: Failure return type?
|
||||
return {table};
|
||||
}
|
||||
|
||||
template <typename Table>
|
||||
auto dynamic_inner_join(Table table) -> make_dynamic_pre_join_t<inner_join_t, Table>
|
||||
{
|
||||
check_dynamic_pre_join_t<Table>{};
|
||||
check_dynamic_pre_join_t<Table>::verify();
|
||||
return {table};
|
||||
}
|
||||
|
||||
template <typename Table>
|
||||
auto dynamic_left_outer_join(Table table) -> make_dynamic_pre_join_t<left_outer_join_t, Table>
|
||||
{
|
||||
check_dynamic_pre_join_t<Table>{};
|
||||
check_dynamic_pre_join_t<Table>::verify();
|
||||
return {table};
|
||||
}
|
||||
|
||||
template <typename Table>
|
||||
auto dynamic_right_outer_join(Table table) -> make_dynamic_pre_join_t<right_outer_join_t, Table>
|
||||
{
|
||||
check_dynamic_pre_join_t<Table>{};
|
||||
check_dynamic_pre_join_t<Table>::verify();
|
||||
return {table};
|
||||
}
|
||||
|
||||
template <typename Table>
|
||||
auto dynamic_outer_join(Table table) -> make_dynamic_pre_join_t<outer_join_t, Table>
|
||||
{
|
||||
check_dynamic_pre_join_t<Table>{};
|
||||
check_dynamic_pre_join_t<Table>::verify();
|
||||
return {table};
|
||||
}
|
||||
|
||||
|
||||
@@ -77,39 +77,29 @@ namespace sqlpp
|
||||
};
|
||||
|
||||
template <typename Context, typename Db>
|
||||
struct serializer_t<Context, dynamic_select_column_list<Db>>
|
||||
Context& serialize(const dynamic_select_column_list<Db>& t, Context& context)
|
||||
{
|
||||
using T = dynamic_select_column_list<Db>;
|
||||
|
||||
static Context& _(const T& t, Context& context)
|
||||
bool first = true;
|
||||
for (const auto& column : t._dynamic_columns)
|
||||
{
|
||||
bool first = true;
|
||||
for (const auto column : t._dynamic_columns)
|
||||
if (first)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
context << ',';
|
||||
}
|
||||
serialize(column, context);
|
||||
first = false;
|
||||
}
|
||||
return context;
|
||||
else
|
||||
{
|
||||
context << ',';
|
||||
}
|
||||
serialize(column, context);
|
||||
}
|
||||
};
|
||||
return context;
|
||||
}
|
||||
|
||||
template <typename Context>
|
||||
struct serializer_t<Context, dynamic_select_column_list<void>>
|
||||
Context& serialize(const dynamic_select_column_list<void>&, Context& context)
|
||||
{
|
||||
using T = dynamic_select_column_list<void>;
|
||||
|
||||
static Context& _(const T& /*unused*/, Context& context)
|
||||
{
|
||||
return context;
|
||||
}
|
||||
};
|
||||
return context;
|
||||
}
|
||||
} // namespace sqlpp
|
||||
|
||||
#endif
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace sqlpp
|
||||
"Expression cannot be used in eval because it requires tables");
|
||||
using _name_type = alias::a_t::_alias_t;
|
||||
using _value_type = value_type_of<Expr>;
|
||||
using _field_spec = field_spec_t<_name_type, _value_type, true, false>;
|
||||
using _field_spec = field_spec_t<_name_type, _value_type, true>;
|
||||
using type = result_field_t<Db, _field_spec>;
|
||||
};
|
||||
|
||||
|
||||
@@ -78,19 +78,13 @@ namespace sqlpp
|
||||
};
|
||||
|
||||
template <typename Context, typename Select>
|
||||
struct serializer_t<Context, exists_t<Select>>
|
||||
Context& serialize(const exists_t<Select>& t, Context& context)
|
||||
{
|
||||
using _serialize_check = serialize_check_of<Context, Select>;
|
||||
using T = exists_t<Select>;
|
||||
|
||||
static Context& _(const T& t, Context& context)
|
||||
{
|
||||
context << "EXISTS(";
|
||||
serialize(t._select, context);
|
||||
context << ")";
|
||||
return context;
|
||||
}
|
||||
};
|
||||
context << "EXISTS(";
|
||||
serialize(t._select, context);
|
||||
context << ")";
|
||||
return context;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto exists(T t) -> exists_t<wrap_operand_t<T>>
|
||||
|
||||
@@ -31,9 +31,6 @@
|
||||
#include <sqlpp11/data_types/boolean.h>
|
||||
#include <sqlpp11/expression_fwd.h>
|
||||
#include <sqlpp11/noop.h>
|
||||
#include <sqlpp11/rhs_wrap.h>
|
||||
#include <sqlpp11/serializer.h>
|
||||
#include <sqlpp11/tvin.h>
|
||||
#include <sqlpp11/wrap_operand.h>
|
||||
|
||||
namespace sqlpp
|
||||
@@ -45,7 +42,7 @@ namespace sqlpp
|
||||
{
|
||||
using _traits = make_traits<boolean, tag::is_expression>;
|
||||
using _lhs_t = Lhs;
|
||||
using _rhs_t = rhs_wrap_t<allow_tvin_t<Rhs>, trivial_value_is_null_t<_lhs_t>::value>;
|
||||
using _rhs_t = Rhs;
|
||||
using _nodes = detail::type_vector<_lhs_t, _rhs_t>;
|
||||
|
||||
binary_expression_t(Lhs lhs, Rhs rhs) : _lhs(lhs), _rhs(rhs)
|
||||
@@ -63,28 +60,15 @@ namespace sqlpp
|
||||
};
|
||||
|
||||
template <typename Context, typename Lhs, typename Rhs>
|
||||
struct serializer_t<Context, binary_expression_t<Lhs, op::equal_to, Rhs>>
|
||||
Context& serialize(const binary_expression_t<Lhs, op::equal_to, Rhs>& t, Context& context)
|
||||
{
|
||||
using T = binary_expression_t<Lhs, op::equal_to, Rhs>;
|
||||
using _serialize_check = serialize_check_of<Context, typename T::_lhs_t, typename T::_rhs_t>;
|
||||
|
||||
static Context& _(const T& t, Context& context)
|
||||
{
|
||||
context << "(";
|
||||
serialize_operand(t._lhs, context);
|
||||
if (t._rhs._is_null())
|
||||
{
|
||||
context << " IS NULL";
|
||||
}
|
||||
else
|
||||
{
|
||||
context << "=";
|
||||
serialize_operand(t._rhs, context);
|
||||
}
|
||||
context << ")";
|
||||
return context;
|
||||
}
|
||||
};
|
||||
context << "(";
|
||||
serialize_operand(t._lhs, context);
|
||||
context << "=";
|
||||
serialize_operand(t._rhs, context);
|
||||
context << ")";
|
||||
return context;
|
||||
}
|
||||
|
||||
template <typename Lhs, typename Rhs>
|
||||
struct binary_expression_t<Lhs, op::not_equal_to, Rhs>
|
||||
@@ -93,7 +77,7 @@ namespace sqlpp
|
||||
{
|
||||
using _traits = make_traits<boolean, tag::is_expression>;
|
||||
using _lhs_t = Lhs;
|
||||
using _rhs_t = rhs_wrap_t<allow_tvin_t<Rhs>, trivial_value_is_null_t<_lhs_t>::value>;
|
||||
using _rhs_t = Rhs;
|
||||
using _nodes = detail::type_vector<_lhs_t, _rhs_t>;
|
||||
|
||||
binary_expression_t(Lhs lhs, Rhs rhs) : _lhs(lhs), _rhs(rhs)
|
||||
@@ -111,28 +95,15 @@ namespace sqlpp
|
||||
};
|
||||
|
||||
template <typename Context, typename Lhs, typename Rhs>
|
||||
struct serializer_t<Context, binary_expression_t<Lhs, op::not_equal_to, Rhs>>
|
||||
Context& serialize(const binary_expression_t<Lhs, op::not_equal_to, Rhs>& t, Context& context)
|
||||
{
|
||||
using T = binary_expression_t<Lhs, op::not_equal_to, Rhs>;
|
||||
using _serialize_check = serialize_check_of<Context, typename T::_lhs_t, typename T::_rhs_t>;
|
||||
|
||||
static Context& _(const T& t, Context& context)
|
||||
{
|
||||
context << "(";
|
||||
serialize_operand(t._lhs, context);
|
||||
if (t._rhs._is_null())
|
||||
{
|
||||
context << " IS NOT NULL";
|
||||
}
|
||||
else
|
||||
{
|
||||
context << "<>";
|
||||
serialize_operand(t._rhs, context);
|
||||
}
|
||||
context << ")";
|
||||
return context;
|
||||
}
|
||||
};
|
||||
context << "(";
|
||||
serialize_operand(t._lhs, context);
|
||||
context << "<>";
|
||||
serialize_operand(t._rhs, context);
|
||||
context << ")";
|
||||
return context;
|
||||
}
|
||||
|
||||
template <typename Rhs>
|
||||
struct unary_expression_t<op::logical_not, Rhs>
|
||||
@@ -156,29 +127,15 @@ namespace sqlpp
|
||||
};
|
||||
|
||||
template <typename Context, typename Rhs>
|
||||
struct serializer_t<Context, unary_expression_t<op::logical_not, Rhs>>
|
||||
Context& serialize(const unary_expression_t<op::logical_not, Rhs>& t, Context& context)
|
||||
{
|
||||
using _serialize_check = serialize_check_of<Context, Rhs>;
|
||||
using T = unary_expression_t<op::logical_not, Rhs>;
|
||||
context << "(";
|
||||
context << "NOT ";
|
||||
serialize_operand(t._rhs, context);
|
||||
context << ")";
|
||||
|
||||
static Context& _(const T& t, Context& context)
|
||||
{
|
||||
context << "(";
|
||||
if (trivial_value_is_null_t<Rhs>::value)
|
||||
{
|
||||
serialize_operand(t._rhs, context);
|
||||
context << " IS NULL ";
|
||||
}
|
||||
else
|
||||
{
|
||||
context << "NOT ";
|
||||
serialize_operand(t._rhs, context);
|
||||
}
|
||||
context << ")";
|
||||
|
||||
return context;
|
||||
}
|
||||
};
|
||||
return context;
|
||||
}
|
||||
|
||||
template <typename Lhs, typename O, typename Rhs>
|
||||
struct binary_expression_t : public expression_operators<binary_expression_t<Lhs, O, Rhs>, value_type_of<O>>,
|
||||
@@ -202,21 +159,15 @@ namespace sqlpp
|
||||
};
|
||||
|
||||
template <typename Context, typename Lhs, typename O, typename Rhs>
|
||||
struct serializer_t<Context, binary_expression_t<Lhs, O, Rhs>>
|
||||
Context& serialize(const binary_expression_t<Lhs, O, Rhs>& t, Context& context)
|
||||
{
|
||||
using _serialize_check = serialize_check_of<Context, Lhs, Rhs>;
|
||||
using T = binary_expression_t<Lhs, O, Rhs>;
|
||||
|
||||
static Context& _(const T& t, Context& context)
|
||||
{
|
||||
context << "(";
|
||||
serialize_operand(t._lhs, context);
|
||||
context << O::_name;
|
||||
serialize_operand(t._rhs, context);
|
||||
context << ")";
|
||||
return context;
|
||||
}
|
||||
};
|
||||
context << "(";
|
||||
serialize_operand(t._lhs, context);
|
||||
context << O::_name;
|
||||
serialize_operand(t._rhs, context);
|
||||
context << ")";
|
||||
return context;
|
||||
}
|
||||
|
||||
template <typename O, typename Rhs>
|
||||
struct unary_expression_t : public expression_operators<unary_expression_t<O, Rhs>, value_type_of<O>>,
|
||||
@@ -239,20 +190,14 @@ namespace sqlpp
|
||||
};
|
||||
|
||||
template <typename Context, typename O, typename Rhs>
|
||||
struct serializer_t<Context, unary_expression_t<O, Rhs>>
|
||||
Context& serialize(const unary_expression_t<O, Rhs>& t, Context& context)
|
||||
{
|
||||
using _serialize_check = serialize_check_of<Context, Rhs>;
|
||||
using T = unary_expression_t<O, Rhs>;
|
||||
|
||||
static Context& _(const T& t, Context& context)
|
||||
{
|
||||
context << "(";
|
||||
context << O::_name;
|
||||
serialize_operand(t._rhs, context);
|
||||
context << ")";
|
||||
return context;
|
||||
}
|
||||
};
|
||||
context << "(";
|
||||
context << O::_name;
|
||||
serialize_operand(t._rhs, context);
|
||||
context << ")";
|
||||
return context;
|
||||
}
|
||||
} // namespace sqlpp
|
||||
|
||||
#endif
|
||||
|
||||
@@ -157,6 +157,20 @@ namespace sqlpp
|
||||
using _traits = make_traits<ValueType>;
|
||||
static constexpr const char* _name = "|";
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
struct shift_left
|
||||
{
|
||||
using _traits = make_traits<ValueType>;
|
||||
static constexpr const char* _name = "<<";
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
struct shift_right
|
||||
{
|
||||
using _traits = make_traits<ValueType>;
|
||||
static constexpr const char* _name = ">>";
|
||||
};
|
||||
} // namespace op
|
||||
|
||||
template <typename Lhs, typename O, typename Rhs>
|
||||
@@ -219,6 +233,12 @@ namespace sqlpp
|
||||
template <typename Lhs, typename ValueType, typename Rhs>
|
||||
using bitwise_or_t = binary_expression_t<Lhs, op::bitwise_or<ValueType>, Rhs>;
|
||||
|
||||
template <typename Lhs, typename ValueType, typename Rhs>
|
||||
using shift_left_t = binary_expression_t<Lhs, op::shift_left<ValueType>, Rhs>;
|
||||
|
||||
template <typename Lhs, typename ValueType, typename Rhs>
|
||||
using shift_right_t = binary_expression_t<Lhs, op::shift_right<ValueType>, Rhs>;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename Expr, typename Enable = void>
|
||||
|
||||
@@ -49,6 +49,24 @@ namespace sqlpp
|
||||
template <typename L, typename R>
|
||||
using return_type_bitwise_and_t = typename return_type_bitwise_and<L, R>::type;
|
||||
|
||||
template <typename L, typename R, typename Enable = void>
|
||||
struct return_type_shift_left
|
||||
{
|
||||
using check = assert_valid_operands;
|
||||
using type = bad_expression<boolean>;
|
||||
};
|
||||
template <typename L, typename R>
|
||||
using return_type_shift_left_t = typename return_type_shift_left<L, R>::type;
|
||||
|
||||
template <typename L, typename R, typename Enable = void>
|
||||
struct return_type_shift_right
|
||||
{
|
||||
using check = assert_valid_operands;
|
||||
using type = bad_expression<boolean>;
|
||||
};
|
||||
template <typename L, typename R>
|
||||
using return_type_shift_right_t = typename return_type_shift_right<L, R>::type;
|
||||
|
||||
template <typename L, typename R, typename Enable = void>
|
||||
struct return_type_or
|
||||
{
|
||||
|
||||
@@ -27,34 +27,21 @@
|
||||
#ifndef SQLPP11_FIELD_SPEC_H
|
||||
#define SQLPP11_FIELD_SPEC_H
|
||||
|
||||
#include <sqlpp11/multi_column.h>
|
||||
#include <sqlpp11/type_traits.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
template <typename NameType, typename ValueType, bool CanBeNull, bool NullIsTrivialValue>
|
||||
template <typename NameType, typename ValueType, bool CanBeNull>
|
||||
struct field_spec_t
|
||||
{
|
||||
using _traits = make_traits<ValueType,
|
||||
tag::is_noop,
|
||||
tag_if<tag::can_be_null, CanBeNull>,
|
||||
tag_if<tag::null_is_trivial_value, NullIsTrivialValue>>;
|
||||
tag_if<tag::can_be_null, CanBeNull>>;
|
||||
using _nodes = detail::type_vector<>;
|
||||
|
||||
using _alias_t = NameType;
|
||||
};
|
||||
|
||||
template <typename AliasProvider, typename FieldSpecTuple>
|
||||
struct multi_field_spec_t
|
||||
{
|
||||
static_assert(wrong_t<AliasProvider, FieldSpecTuple>::value,
|
||||
"multi_field_spec_t needs to be specialized with a tuple");
|
||||
};
|
||||
|
||||
template <typename AliasProvider, typename... FieldSpecs>
|
||||
struct multi_field_spec_t<AliasProvider, std::tuple<FieldSpecs...>>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename Left, typename Right, typename Enable = void>
|
||||
struct is_field_compatible
|
||||
{
|
||||
@@ -64,28 +51,17 @@ namespace sqlpp
|
||||
template <typename LeftName,
|
||||
typename LeftValue,
|
||||
bool LeftCanBeNull,
|
||||
bool LeftNullIsTrivial,
|
||||
typename RightName,
|
||||
typename RightValue,
|
||||
bool RightCanBeNull,
|
||||
bool RightNullIsTrivial>
|
||||
struct is_field_compatible<field_spec_t<LeftName, LeftValue, LeftCanBeNull, LeftNullIsTrivial>,
|
||||
field_spec_t<RightName, RightValue, RightCanBeNull, RightNullIsTrivial>>
|
||||
bool RightCanBeNull>
|
||||
struct is_field_compatible<field_spec_t<LeftName, LeftValue, LeftCanBeNull>,
|
||||
field_spec_t<RightName, RightValue, RightCanBeNull>>
|
||||
{
|
||||
static constexpr auto value =
|
||||
std::is_same<typename LeftName::_name_t, typename RightName::_name_t>::value and
|
||||
std::is_same<LeftValue, RightValue>::value and // Same value type
|
||||
(LeftCanBeNull or !RightCanBeNull) and // The left hand side determines the result row and therefore must allow
|
||||
// NULL if the right hand side allows it
|
||||
(LeftNullIsTrivial or !RightNullIsTrivial); // as above
|
||||
};
|
||||
|
||||
template <typename LeftAlias, typename... LeftFields, typename RightAlias, typename... RightFields>
|
||||
struct is_field_compatible<multi_field_spec_t<LeftAlias, std::tuple<LeftFields...>>,
|
||||
multi_field_spec_t<RightAlias, std::tuple<RightFields...>>,
|
||||
typename std::enable_if<sizeof...(LeftFields) == sizeof...(RightFields)>::type>
|
||||
{
|
||||
static constexpr auto value = logic::all_t<is_field_compatible<LeftFields, RightFields>::value...>::value;
|
||||
(LeftCanBeNull or !RightCanBeNull); // The left hand side determines the result row and therefore must allow
|
||||
// NULL if the right hand side allows it
|
||||
};
|
||||
|
||||
namespace detail
|
||||
@@ -100,15 +76,7 @@ namespace sqlpp
|
||||
|
||||
using type = field_spec_t<typename NamedExpr::_alias_t,
|
||||
value_type_of<NamedExpr>,
|
||||
logic::any_t<_can_be_null, _depends_on_outer_table>::value,
|
||||
null_is_trivial_value_t<NamedExpr>::value>;
|
||||
};
|
||||
|
||||
template <typename Select, typename AliasProvider, typename... NamedExprs>
|
||||
struct make_field_spec_impl<Select, multi_column_alias_t<AliasProvider, NamedExprs...>>
|
||||
{
|
||||
using type =
|
||||
multi_field_spec_t<AliasProvider, std::tuple<typename make_field_spec_impl<Select, NamedExprs>::type...>>;
|
||||
logic::any_t<_can_be_null, _depends_on_outer_table>::value>;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
|
||||
@@ -157,17 +157,11 @@ namespace sqlpp
|
||||
|
||||
// Interpreters
|
||||
template <typename Context>
|
||||
struct serializer_t<Context, for_update_data_t>
|
||||
Context& serialize(const for_update_data_t&, Context& context)
|
||||
{
|
||||
using _serialize_check = serialize_check_of<Context>;
|
||||
using T = for_update_data_t;
|
||||
|
||||
static Context& _(const T& /*unused*/, Context& context)
|
||||
{
|
||||
context << " FOR UPDATE ";
|
||||
return context;
|
||||
}
|
||||
};
|
||||
context << " FOR UPDATE ";
|
||||
return context;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto for_update(T&& t) -> decltype(statement_t<void, no_for_update_t>().for_update(std::forward<T>(t)))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user