summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVittorio Romeo <vittorio.romeo@outlook.com>2021-11-12 18:58:09 +0000
committerGitHub <noreply@github.com>2021-11-12 18:58:09 +0000
commitce42f7ebcdeac94f13214b3cb725806c41cccdee (patch)
tree14e9967891942ccc45ea6cc2f31cc53d17a062f3
parent13f8c1bb2f6f39cbddf0821536b3c7537d9f9bf9 (diff)
parentf5acb339115bbf3d6c14c24d190d82189c1bbfcb (diff)
Merge pull request #361 from SuperV1234/2.1.2
Open Hexagon v2.1.2
-rw-r--r--CMakeLists.txt43
-rw-r--r--_RELEASE/Assets/assets.json1
-rw-r--r--_RELEASE/Assets/smallCircle.pngbin0 -> 274 bytes
-rw-r--r--_RELEASE/Packs/tutorial/Scripts/Levels/babysteps.lua2
-rw-r--r--_RELEASE/config.json8
-rw-r--r--art/eventcover.pngbin172566 -> 172546 bytes
-rw-r--r--art/eventcover.psdbin576402 -> 576230 bytes
-rw-r--r--build/make_debug_client_win10_msys_0_cmake.sh2
-rw-r--r--buildrel/make_release_client_win10_msys_2_copy.sh1
-rw-r--r--include/SSVOpenHexagon/Components/CPlayer.hpp15
-rw-r--r--include/SSVOpenHexagon/Core/HGStatus.hpp1
-rw-r--r--include/SSVOpenHexagon/Core/HexagonGame.hpp12
-rw-r--r--include/SSVOpenHexagon/Global/Config.hpp12
-rw-r--r--include/SSVOpenHexagon/Global/Version.hpp4
-rw-r--r--include/SSVOpenHexagon/Online/Shared.hpp5
-rw-r--r--include/SSVOpenHexagon/Utils/MoveTowards.hpp57
-rw-r--r--prepare_release.sh6
-rw-r--r--public/sqlite_orm/sqlite_orm.h8710
-rw-r--r--run_prepared_release_test.sh4
-rw-r--r--src/SSVOpenHexagon/Components/CPlayer.cpp79
-rw-r--r--src/SSVOpenHexagon/Core/HGGraphics.cpp17
-rw-r--r--src/SSVOpenHexagon/Core/HGUpdate.cpp78
-rw-r--r--src/SSVOpenHexagon/Core/HexagonGame.cpp10
-rw-r--r--src/SSVOpenHexagon/Core/LuaScripting.cpp6
-rw-r--r--src/SSVOpenHexagon/Core/MenuGame.cpp30
-rw-r--r--src/SSVOpenHexagon/Global/Config.cpp66
-rw-r--r--webpage/index.html30
27 files changed, 6742 insertions, 2457 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b2f42b65..89322263 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -317,11 +317,18 @@ vrm_cmake_include_vc_dependency_once(vc_detection)
# Targets
# -----------------------------------------------------------------------------
+if(WIN32 AND "${vrm_cmake_build_type_lower}" STREQUAL "release")
+ set(SSVOH_BUILD_WIN32_CONSOLE TRUE)
+else()
+ set(SSVOH_BUILD_WIN32_CONSOLE FALSE)
+endif()
+
add_library(SSVOpenHexagonLibC STATIC ${C_SRC_LIST})
add_library(SSVOpenHexagonLib STATIC ${SRC_LIST})
-if(WIN32 AND "${vrm_cmake_build_type_lower}" STREQUAL "release")
+if(SSVOH_BUILD_WIN32_CONSOLE)
add_executable(SSVOpenHexagon WIN32 ${MAIN_FILE})
+ add_executable(SSVOpenHexagon-Console ${MAIN_FILE})
else()
add_executable(SSVOpenHexagon ${MAIN_FILE})
endif()
@@ -339,6 +346,10 @@ target_precompile_headers(
target_precompile_headers(SSVOpenHexagon REUSE_FROM SSVOpenHexagonLib)
+if(SSVOH_BUILD_WIN32_CONSOLE)
+ target_precompile_headers(SSVOpenHexagon-Console REUSE_FROM SSVOpenHexagonLib)
+endif()
+
#
#
# -----------------------------------------------------------------------------
@@ -405,20 +416,29 @@ ssvoh_find_extlib_for_target(SSVOpenHexagonLib SSVStart)
target_link_libraries(SSVOpenHexagon SSVOpenHexagonLib SSVOpenHexagonLibC)
-if(WIN32 AND "${vrm_cmake_build_type_lower}" STREQUAL "release")
+if(SSVOH_BUILD_WIN32_CONSOLE)
target_link_libraries(SSVOpenHexagon "${CMAKE_SOURCE_DIR}/art/icon.res" sfml-main)
target_compile_options(SSVOpenHexagon PRIVATE "-Wl,-subsystem,windows")
+ target_link_libraries(SSVOpenHexagon-Console SSVOpenHexagonLib SSVOpenHexagonLibC)
endif()
+set(SSVOH_INCLUDE_DIRECTORIES ${SFML_SOURCE_DIR}/include
+ ${PUBLIC_INCLUDE_DIRS}
+ ${zlib_SOURCE_DIR}
+ ${zlib_BINARY_DIR}
+ ${LUASRC}
+ ${imgui_SOURCE_DIR})
+
target_include_directories(
- SSVOpenHexagon SYSTEM PUBLIC ${SFML_SOURCE_DIR}/include
- PUBLIC ${PUBLIC_INCLUDE_DIRS}
- PUBLIC ${zlib_SOURCE_DIR}
- PUBLIC ${zlib_BINARY_DIR}
- PUBLIC ${LUASRC}
- PUBLIC ${imgui_SOURCE_DIR}
+ SSVOpenHexagon SYSTEM PUBLIC ${SSVOH_INCLUDE_DIRECTORIES}
)
+if(SSVOH_BUILD_WIN32_CONSOLE)
+ target_include_directories(
+ SSVOpenHexagon-Console SYSTEM PUBLIC ${SSVOH_INCLUDE_DIRECTORIES}
+ )
+endif()
+
if(UNIX AND NOT APPLE)
target_link_libraries(SSVOpenHexagonLib pthread)
endif()
@@ -427,6 +447,13 @@ install(
TARGETS SSVOpenHexagon RUNTIME DESTINATION ${CMAKE_SOURCE_DIR}/_RELEASE/
)
+if(SSVOH_BUILD_WIN32_CONSOLE)
+ install(
+ TARGETS SSVOpenHexagon-Console RUNTIME DESTINATION ${CMAKE_SOURCE_DIR}/_RELEASE/
+ )
+endif()
+
+
#
#
# -----------------------------------------------------------------------------
diff --git a/_RELEASE/Assets/assets.json b/_RELEASE/Assets/assets.json
index 180c13b8..72785956 100644
--- a/_RELEASE/Assets/assets.json
+++ b/_RELEASE/Assets/assets.json
@@ -20,6 +20,7 @@
"onlineIcon.png",
"onlineIconFail.png",
"replayIcon.png",
+ "smallCircle.png",
"starParticle.png",
"titleBar.png"
],
diff --git a/_RELEASE/Assets/smallCircle.png b/_RELEASE/Assets/smallCircle.png
new file mode 100644
index 00000000..7bb504f7
--- /dev/null
+++ b/_RELEASE/Assets/smallCircle.png
Binary files differ
diff --git a/_RELEASE/Packs/tutorial/Scripts/Levels/babysteps.lua b/_RELEASE/Packs/tutorial/Scripts/Levels/babysteps.lua
index f56e51ef..a7bd3ea7 100644
--- a/_RELEASE/Packs/tutorial/Scripts/Levels/babysteps.lua
+++ b/_RELEASE/Packs/tutorial/Scripts/Levels/babysteps.lua
@@ -172,7 +172,7 @@ function onUpdate(mFrameTime)
step35 = true
l_clearTracked()
- l_addTracked("challengeFailedText", "surived until the end")
+ l_addTracked("challengeFailedText", "survived until the end")
l_resetTime()
l_setIncTime(15)
diff --git a/_RELEASE/config.json b/_RELEASE/config.json
index 0a2c6165..eb793cac 100644
--- a/_RELEASE/config.json
+++ b/_RELEASE/config.json
@@ -3,11 +3,13 @@
"3D_enabled" : true,
"3D_max_depth" : 100,
"3D_multiplier" : 1.0,
+ "angle_tilt_intensity" : 1.0,
"antialiasing_level" : 16,
"auto_restart" : false,
"auto_zoom_factor" : true,
"beatpulse_enabled" : true,
"black_and_white" : false,
+ "camera_shake_multiplier" : 1.000002622604370,
"darken_uneven_background_chunk" : true,
"debug" : true,
"draw_text_outlines" : true,
@@ -48,12 +50,15 @@
"player_focus_speed" : 4.6250,
"player_size" : 7.300000190734863,
"player_speed" : 9.449999809265137,
+ "player_trail_alpha" : 255,
+ "player_trail_decay" : 0.50,
+ "player_trail_scale" : 1.0,
"pulse_enabled" : true,
"rotate_to_start" : false,
"save_last_login_username" : true,
"save_local_best_replay_to_file" : true,
"server_control_port" : 50506,
- "server_ip" : "127.0.0.1",
+ "server_ip" : "139.162.199.162",
"server_level_whitelist" :
[
"ohvrvanilla_vittorio_romeo_cube_1_apeirogon_m_0.35",
@@ -129,6 +134,7 @@
"show_level_info" : true,
"show_login_at_startup" : false,
"show_messages" : true,
+ "show_player_trail" : true,
"show_status_text" : true,
"show_timer" : true,
"show_tracked_variables" : true,
diff --git a/art/eventcover.png b/art/eventcover.png
index e15e1426..7835aaf9 100644
--- a/art/eventcover.png
+++ b/art/eventcover.png
Binary files differ
diff --git a/art/eventcover.psd b/art/eventcover.psd
index c72a3e56..e933605d 100644
--- a/art/eventcover.psd
+++ b/art/eventcover.psd
Binary files differ
diff --git a/build/make_debug_client_win10_msys_0_cmake.sh b/build/make_debug_client_win10_msys_0_cmake.sh
index b63dab6c..5641acb6 100644
--- a/build/make_debug_client_win10_msys_0_cmake.sh
+++ b/build/make_debug_client_win10_msys_0_cmake.sh
@@ -17,7 +17,7 @@ cmake .. -G"Ninja" \
-DCMAKE_CXX_COMPILER="g++" \
-DCMAKE_CXX_FLAGS="\
-fuse-ld=lld \
- -O0 -fno-omit-frame-pointer \
+ -Og -g3 -fno-omit-frame-pointer \
-Wall -Wextra -Wpedantic -Wno-braced-scalar-init -Wno-missing-field-initializers \
-D_GLIBCXX_ASSERTIONS=1 -D_FORTIFY_SOURCE=2 \
-fstack-protector -Wno-pragmas\
diff --git a/buildrel/make_release_client_win10_msys_2_copy.sh b/buildrel/make_release_client_win10_msys_2_copy.sh
index b63d450c..c29110a7 100644
--- a/buildrel/make_release_client_win10_msys_2_copy.sh
+++ b/buildrel/make_release_client_win10_msys_2_copy.sh
@@ -10,6 +10,7 @@ echo "--------------------------------------------------------------------"
echo ""
cp ./SSVOpenHexagon.exe ../_RELEASE
+cp ./SSVOpenHexagon-Console.exe ../_RELEASE
cp ./OHWorkshopUploader.exe ../_RELEASE
cp ./OHServerControl.exe ../_RELEASE
diff --git a/include/SSVOpenHexagon/Components/CPlayer.hpp b/include/SSVOpenHexagon/Components/CPlayer.hpp
index 2ff20ad7..4e008e06 100644
--- a/include/SSVOpenHexagon/Components/CPlayer.hpp
+++ b/include/SSVOpenHexagon/Components/CPlayer.hpp
@@ -64,6 +64,8 @@ private:
Ticker _swapBlinkTimer;
Ticker _deadEffectTimer;
+ float _currTiltedAngle;
+
void drawPivot(const unsigned int sides, const sf::Color& colorMain,
Utils::FastVertexVectorQuads& wallQuads,
Utils::FastVertexVectorTris& capTris, const sf::Color& capColor);
@@ -112,10 +114,14 @@ public:
void updatePosition(const float radius);
+ [[nodiscard]] sf::Color getColorAdjustedForSwap(
+ const sf::Color& colorPlayer) const;
+
void draw(const unsigned int sides, const sf::Color& colorMain,
const sf::Color& colorPlayer, Utils::FastVertexVectorQuads& wallQuads,
Utils::FastVertexVectorTris& capTris,
- Utils::FastVertexVectorTris& playerTris, const sf::Color& capColor);
+ Utils::FastVertexVectorTris& playerTris, const sf::Color& capColor,
+ const float angleTiltIntensity);
[[nodiscard]] bool push(const int movementDir, const float radius,
const CWall& wall, const sf::Vector2f& mCenterPos,
@@ -126,10 +132,15 @@ public:
[[nodiscard]] bool getJustSwapped() const noexcept;
- [[nodiscard]] bool isReadyToSwap() const noexcept
+ [[nodiscard, gnu::always_inline]] bool isReadyToSwap() const noexcept
{
return !_swapTimer.isRunning();
}
+
+ [[nodiscard, gnu::always_inline]] bool hasChangedAngle() const noexcept
+ {
+ return _angle != _lastAngle;
+ }
};
} // namespace hg
diff --git a/include/SSVOpenHexagon/Core/HGStatus.hpp b/include/SSVOpenHexagon/Core/HGStatus.hpp
index 06e79a63..b5c54f0c 100644
--- a/include/SSVOpenHexagon/Core/HGStatus.hpp
+++ b/include/SSVOpenHexagon/Core/HGStatus.hpp
@@ -58,6 +58,7 @@ public:
bool started{false};
std::string restartInput;
std::string replayInput;
+ bool showPlayerTrail{true};
// Reset all the time points and signal that we started
void start() noexcept;
diff --git a/include/SSVOpenHexagon/Core/HexagonGame.hpp b/include/SSVOpenHexagon/Core/HexagonGame.hpp
index 55909b18..265acfb4 100644
--- a/include/SSVOpenHexagon/Core/HexagonGame.hpp
+++ b/include/SSVOpenHexagon/Core/HexagonGame.hpp
@@ -174,7 +174,17 @@ private:
float angularVelocity;
};
+ struct TrailParticle
+ {
+ sf::Sprite sprite;
+ float angle;
+ };
+
+ sf::Texture* txStarParticle;
+ sf::Texture* txSmallCircle;
+
std::vector<Particle> particles;
+ std::vector<TrailParticle> trailParticles;
bool mustSpawnPBParticles{false};
float nextPBParticleSpawn{0.f};
float pbTextGrowth{0.f};
@@ -333,6 +343,7 @@ private:
void updateKeyIcons();
void updateLevelInfo();
void updateParticles(ssvu::FT mFT);
+ void updateTrailParticles(ssvu::FT mFT);
// Post update methods
void postUpdate();
@@ -353,6 +364,7 @@ private:
void drawKeyIcons();
void drawLevelInfo();
void drawParticles();
+ void drawTrailParticles();
void drawImguiLuaConsole();
// Data-related methods
diff --git a/include/SSVOpenHexagon/Global/Config.hpp b/include/SSVOpenHexagon/Global/Config.hpp
index dbb9e9a7..a3916f3f 100644
--- a/include/SSVOpenHexagon/Global/Config.hpp
+++ b/include/SSVOpenHexagon/Global/Config.hpp
@@ -83,6 +83,12 @@ void setSaveLastLoginUsername(bool mX);
void setLastLoginUsername(const std::string& mX);
void setShowLoginAtStartup(bool mX);
void setCameraShakeMultiplier(float x);
+void setAngleTiltIntensity(float x);
+void setShowPlayerTrail(bool mX);
+void setPlayerTrailAlpha(unsigned int x);
+void setPlayerTrailScale(float x);
+void setPlayerTrailDecay(float x);
+void setPlayerTrailHasSwapColor(bool x);
[[nodiscard]] bool getOfficial();
[[nodiscard]] const std::string& getUneligibilityReason();
@@ -150,6 +156,12 @@ void setCameraShakeMultiplier(float x);
[[nodiscard]] const std::string& getLastLoginUsername();
[[nodiscard]] bool getShowLoginAtStartup();
[[nodiscard]] float getCameraShakeMultiplier();
+[[nodiscard]] float getAngleTiltIntensity();
+[[nodiscard]] bool getShowPlayerTrail();
+[[nodiscard]] unsigned int getPlayerTrailAlpha();
+[[nodiscard]] float getPlayerTrailScale();
+[[nodiscard]] float getPlayerTrailDecay();
+[[nodiscard]] bool getPlayerTrailHasSwapColor();
// keyboard binds
diff --git a/include/SSVOpenHexagon/Global/Version.hpp b/include/SSVOpenHexagon/Global/Version.hpp
index 6837b03a..4080a03e 100644
--- a/include/SSVOpenHexagon/Global/Version.hpp
+++ b/include/SSVOpenHexagon/Global/Version.hpp
@@ -43,7 +43,7 @@ struct GameVersion
}
};
-inline constexpr GameVersion GAME_VERSION{2, 1, 1};
-inline constexpr auto& GAME_VERSION_STR = "2.1.1";
+inline constexpr GameVersion GAME_VERSION{2, 1, 2};
+inline constexpr auto& GAME_VERSION_STR = "2.1.2";
} // namespace hg
diff --git a/include/SSVOpenHexagon/Online/Shared.hpp b/include/SSVOpenHexagon/Online/Shared.hpp
index 789d44bb..aa918875 100644
--- a/include/SSVOpenHexagon/Online/Shared.hpp
+++ b/include/SSVOpenHexagon/Online/Shared.hpp
@@ -143,8 +143,3 @@ template <typename T>
sf::Packet& p);
} // namespace hg
-
-// TODO (P1): leaderboards article on /r/gamedev
-// - fast math issue
-// - rng advance for graphical things
-// - check devlogs
diff --git a/include/SSVOpenHexagon/Utils/MoveTowards.hpp b/include/SSVOpenHexagon/Utils/MoveTowards.hpp
new file mode 100644
index 00000000..55c4525a
--- /dev/null
+++ b/include/SSVOpenHexagon/Utils/MoveTowards.hpp
@@ -0,0 +1,57 @@
+// Copyright (c) 2013-2020 Vittorio Romeo
+// License: Academic Free License ("AFL") v. 3.0
+// AFL License page: https://opensource.org/licenses/AFL-3.0
+
+#pragma once
+
+#include "SSVOpenHexagon/Global/Assert.hpp"
+
+#include <algorithm>
+#include <cmath>
+
+namespace hg::Utils {
+
+[[nodiscard, gnu::always_inline, gnu::const]] inline constexpr float
+getMoveTowards(float value, const float target, const float step) noexcept
+{
+ SSVOH_ASSERT(step >= 0);
+
+ if(value < target)
+ {
+ value += step;
+ if(value > target)
+ {
+ value = target;
+ }
+ }
+ else if(value > target)
+ {
+ value -= step;
+ if(value < target)
+ {
+ value = target;
+ }
+ }
+
+ return value;
+}
+
+[[nodiscard, gnu::always_inline, gnu::const]] inline constexpr float
+getMoveTowardsZero(const float value, const float step) noexcept
+{
+ return getMoveTowards(value, 0.f, step);
+}
+
+[[gnu::always_inline]] inline constexpr void moveTowards(
+ float& value, const float target, const float step) noexcept
+{
+ value = getMoveTowards(value, target, step);
+}
+
+[[gnu::always_inline]] inline constexpr void moveTowardsZero(
+ float& value, const float step) noexcept
+{
+ value = getMoveTowardsZero(value, step);
+}
+
+} // namespace hg::Utils
diff --git a/prepare_release.sh b/prepare_release.sh
index d43469db..731c3bb2 100644
--- a/prepare_release.sh
+++ b/prepare_release.sh
@@ -17,6 +17,7 @@ cp -r ./_RELEASE/Packs/orthoplex ./_PREPARED_RELEASE/Packs
mkdir -p ./_PREPARED_RELEASE/Profiles
cp ./_RELEASE/SSVOpenHexagon.exe ./_PREPARED_RELEASE
+cp ./_RELEASE/SSVOpenHexagon-Console.exe ./_PREPARED_RELEASE
cp ./_RELEASE/libzlib1.dll ./_PREPARED_RELEASE
cp ./_RELEASE/openal32.dll ./_PREPARED_RELEASE
@@ -47,4 +48,9 @@ cp ./_RELEASE/noaudio.bat ./_PREPARED_RELEASE
cp ./_RELEASE/OHWorkshopUploader.exe ./_PREPARED_RELEASE
+cd ./_PREPARED_RELEASE
+upx -9 ./*.dll
+upx -9 ./*.exe
+cd ..
+
cp -r ./_PREPARED_RELEASE ./_PREPARED_RELEASE_TEST
diff --git a/public/sqlite_orm/sqlite_orm.h b/public/sqlite_orm/sqlite_orm.h
index a591940c..67df39aa 100644
--- a/public/sqlite_orm/sqlite_orm.h
+++ b/public/sqlite_orm/sqlite_orm.h
@@ -18,6 +18,8 @@ __pragma(push_macro("min"))
#if __cplusplus >= 201703L // use of C++17 or higher
// Enables use of std::optional in SQLITE_ORM.
#define SQLITE_ORM_OPTIONAL_SUPPORTED
+#define SQLITE_ORM_STRING_VIEW_SUPPORTED
+#define SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED
#endif
#pragma once
@@ -44,6 +46,10 @@ __pragma(push_macro("min"))
failed_to_init_a_backup,
unknown_member_value,
incorrect_order,
+ cannot_use_default_value,
+ arguments_count_does_not_match,
+ function_not_found,
+ index_is_out_of_bounds,
};
}
@@ -51,7 +57,7 @@ namespace sqlite_orm {
class orm_error_category : public std::error_category {
public:
- const char *name() const noexcept override final {
+ const char* name() const noexcept override final {
return "ORM error";
}
@@ -83,6 +89,14 @@ namespace sqlite_orm {
return "Unknown member value";
case orm_error_code::incorrect_order:
return "Incorrect order";
+ case orm_error_code::cannot_use_default_value:
+ return "The statement 'INSERT INTO * DEFAULT VALUES' can be used with only one row";
+ case orm_error_code::arguments_count_does_not_match:
+ return "Arguments count does not match";
+ case orm_error_code::function_not_found:
+ return "Function not found";
+ case orm_error_code::index_is_out_of_bounds:
+ return "Index is out of bounds";
default:
return "unknown error";
}
@@ -91,7 +105,7 @@ namespace sqlite_orm {
class sqlite_error_category : public std::error_category {
public:
- const char *name() const noexcept override final {
+ const char* name() const noexcept override final {
return "SQLite error";
}
@@ -100,18 +114,18 @@ namespace sqlite_orm {
}
};
- inline const orm_error_category &get_orm_error_category() {
+ inline const orm_error_category& get_orm_error_category() {
static orm_error_category res;
return res;
}
- inline const sqlite_error_category &get_sqlite_error_category() {
+ inline const sqlite_error_category& get_sqlite_error_category() {
static sqlite_error_category res;
return res;
}
template<typename... T>
- std::string get_error_message(sqlite3 *db, T &&... args) {
+ std::string get_error_message(sqlite3* db, T&&... args) {
std::ostringstream stream;
using unpack = int[];
static_cast<void>(unpack{0, (static_cast<void>(static_cast<void>(stream << args)), 0)...});
@@ -120,7 +134,7 @@ namespace sqlite_orm {
}
template<typename... T>
- [[noreturn]] void throw_error(sqlite3 *db, T &&... args) {
+ [[noreturn]] void throw_error(sqlite3* db, T&&... args) {
throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
get_error_message(db, std::forward<T>(args)...));
}
@@ -136,7 +150,7 @@ namespace std {
}
#pragma once
-#include <tuple> // std::tuple, std::get
+#include <tuple> // std::tuple, std::get, std::tuple_element, std::tuple_size
#include <type_traits> // std::false_type, std::true_type
// #include "static_magic.h"
@@ -150,27 +164,27 @@ namespace sqlite_orm {
namespace internal {
static inline decltype(auto) empty_callable() {
- static auto res = [](auto &&...) {};
+ static auto res = [](auto&&...) {};
return (res);
}
template<typename T, typename F>
- decltype(auto) static_if(std::true_type, const T &t, const F &) {
+ decltype(auto) static_if(std::true_type, const T& t, const F&) {
return (t);
}
template<typename T, typename F>
- decltype(auto) static_if(std::false_type, const T &, const F &f) {
+ decltype(auto) static_if(std::false_type, const T&, const F& f) {
return (f);
}
template<bool B, typename T, typename F>
- decltype(auto) static_if(const T &t, const F &f) {
+ decltype(auto) static_if(const T& t, const F& f) {
return static_if(std::integral_constant<bool, B>{}, t, f);
}
template<bool B, typename T>
- decltype(auto) static_if(const T &t) {
+ decltype(auto) static_if(const T& t) {
return static_if(std::integral_constant<bool, B>{}, t, empty_callable());
}
@@ -185,6 +199,9 @@ namespace sqlite_orm {
// got from here http://stackoverflow.com/questions/25958259/how-do-i-find-out-if-a-tuple-contains-a-type
namespace tuple_helper {
+ /**
+ * HAS_TYPE type trait
+ */
template<typename T, typename Tuple>
struct has_type;
@@ -200,62 +217,152 @@ namespace sqlite_orm {
template<typename T, typename Tuple>
using tuple_contains_type = typename has_type<T, Tuple>::type;
+ /**
+ * HAS_SOME_TYPE type trait
+ */
+ template<template<class> class TT, typename Tuple>
+ struct has_some_type;
+
+ template<template<class> class TT>
+ struct has_some_type<TT, std::tuple<>> : std::false_type {};
+
+ template<template<class> class TT, typename U, typename... Ts>
+ struct has_some_type<TT, std::tuple<U, Ts...>> : has_some_type<TT, std::tuple<Ts...>> {};
+
+ template<template<class> class TT, typename T, typename... Ts>
+ struct has_some_type<TT, std::tuple<TT<T>, Ts...>> : std::true_type {};
+
+ template<template<class> class TT, typename Tuple>
+ using tuple_contains_some_type = typename has_some_type<TT, Tuple>::type;
+
template<size_t N, class... Args>
- struct iterator {
+ struct iterator_impl {
template<class L>
- void operator()(const std::tuple<Args...> &t, const L &l, bool reverse = true) {
+ void operator()(const std::tuple<Args...>& tuple, const L& lambda, bool reverse = true) {
if(reverse) {
- l(std::get<N>(t));
- iterator<N - 1, Args...>()(t, l, reverse);
+ lambda(std::get<N>(tuple));
+ iterator_impl<N - 1, Args...>()(tuple, lambda, reverse);
} else {
- iterator<N - 1, Args...>()(t, l, reverse);
- l(std::get<N>(t));
+ iterator_impl<N - 1, Args...>()(tuple, lambda, reverse);
+ lambda(std::get<N>(tuple));
}
}
+
+ template<class L>
+ void operator()(const L& lambda) {
+ iterator_impl<N - 1, Args...>()(lambda);
+ lambda((const typename std::tuple_element<N - 1, std::tuple<Args...>>::type*)nullptr);
+ }
};
template<class... Args>
- struct iterator<0, Args...> {
+ struct iterator_impl<0, Args...> {
+
+ template<class L>
+ void operator()(const std::tuple<Args...>& tuple, const L& lambda, bool /*reverse*/ = true) {
+ lambda(std::get<0>(tuple));
+ }
template<class L>
- void operator()(const std::tuple<Args...> &t, const L &l, bool /*reverse*/ = true) {
- l(std::get<0>(t));
+ void operator()(const L& lambda) {
+ lambda((const typename std::tuple_element<0, std::tuple<Args...>>::type*)nullptr);
}
};
template<size_t N>
- struct iterator<N> {
+ struct iterator_impl<N> {
+
+ template<class L>
+ void operator()(const std::tuple<>&, const L&, bool /*reverse*/ = true) {
+ //..
+ }
+
+ template<class L>
+ void operator()(const L&) {
+ //..
+ }
+ };
+
+ template<class... Args>
+ struct iterator_impl2;
+
+ template<>
+ struct iterator_impl2<> {
template<class L>
- void operator()(const std::tuple<> &, const L &, bool /*reverse*/ = true) {
+ void operator()(const L&) const {
//..
}
};
+ template<class H, class... Tail>
+ struct iterator_impl2<H, Tail...> {
+
+ template<class L>
+ void operator()(const L& lambda) const {
+ lambda((const H*)nullptr);
+ iterator_impl2<Tail...>{}(lambda);
+ }
+ };
+
+ template<class T>
+ struct iterator;
+
+ template<class... Args>
+ struct iterator<std::tuple<Args...>> {
+
+ template<class L>
+ void operator()(const L& lambda) const {
+ iterator_impl2<Args...>{}(lambda);
+ }
+ };
+ }
+
+ namespace internal {
+
+ // got it form here https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer
+ template<class Function, class FunctionPointer, class Tuple, size_t... I>
+ auto call_impl(Function& f, FunctionPointer functionPointer, Tuple t, std::index_sequence<I...>) {
+ return (f.*functionPointer)(std::get<I>(t)...);
+ }
+
+ template<class Function, class FunctionPointer, class Tuple>
+ auto call(Function& f, FunctionPointer functionPointer, Tuple t) {
+ static constexpr auto size = std::tuple_size<Tuple>::value;
+ return call_impl(f, functionPointer, move(t), std::make_index_sequence<size>{});
+ }
+
+ template<class Function, class Tuple>
+ auto call(Function& f, Tuple t) {
+ return call(f, &Function::operator(), move(t));
+ }
+
template<size_t N, size_t I, class L, class R>
- void move_tuple_impl(L &lhs, R &rhs) {
+ void move_tuple_impl(L& lhs, R& rhs) {
std::get<I>(lhs) = std::move(std::get<I>(rhs));
- internal::static_if<std::integral_constant<bool, N != I + 1>{}>([](auto &l, auto &r) {
+ internal::static_if<std::integral_constant<bool, N != I + 1>{}>([](auto& l, auto& r) {
move_tuple_impl<N, I + 1>(l, r);
})(lhs, rhs);
}
- }
-
- namespace internal {
template<size_t N, class L, class R>
- void move_tuple(L &lhs, R &rhs) {
+ void move_tuple(L& lhs, R& rhs) {
using bool_type = std::integral_constant<bool, N != 0>;
- static_if<bool_type{}>([](auto &l, auto &r) {
- tuple_helper::move_tuple_impl<N, 0>(l, r);
+ static_if<bool_type{}>([](auto& l, auto& r) {
+ move_tuple_impl<N, 0>(l, r);
})(lhs, rhs);
}
template<class L, class... Args>
- void iterate_tuple(const std::tuple<Args...> &t, const L &l) {
+ void iterate_tuple(const std::tuple<Args...>& tuple, const L& lambda) {
using tuple_type = std::tuple<Args...>;
- tuple_helper::iterator<std::tuple_size<tuple_type>::value - 1, Args...>()(t, l, false);
+ tuple_helper::iterator_impl<std::tuple_size<tuple_type>::value - 1, Args...>()(tuple, lambda, false);
+ }
+
+ template<class T, class L>
+ void iterate_tuple(const L& lambda) {
+ tuple_helper::iterator<T>{}(lambda);
}
template<typename... input_t>
@@ -265,6 +372,57 @@ namespace sqlite_orm {
struct conc_tuple {
using type = tuple_cat_t<Args...>;
};
+ }
+}
+#pragma once
+
+#include <tuple> // std::tuple
+#include <type_traits> // std::enable_if
+
+namespace sqlite_orm {
+ namespace internal {
+
+ template<class T, template<class> class C, class SFINAE = void>
+ struct find_in_tuple;
+
+ template<template<class> class C>
+ struct find_in_tuple<std::tuple<>, C, void> {
+ using type = void;
+ };
+
+ template<class H, class... Args, template<class> class C>
+ struct find_in_tuple<std::tuple<H, Args...>, C, typename std::enable_if<C<H>::value>::type> {
+ using type = H;
+ };
+
+ template<class H, class... Args, template<class> class C>
+ struct find_in_tuple<std::tuple<H, Args...>, C, typename std::enable_if<!C<H>::value>::type> {
+ using type = typename find_in_tuple<std::tuple<Args...>, C>::type;
+ };
+ }
+}
+#pragma once
+
+#include <tuple> // std::tuple
+
+namespace sqlite_orm {
+ namespace internal {
+
+ template<class T, template<class C> class F>
+ struct tuple_transformer;
+
+ template<class... Args, template<class C> class F>
+ struct tuple_transformer<std::tuple<Args...>, F> {
+ using type = std::tuple<typename F<Args>::type...>;
+ };
+ }
+}
+#pragma once
+
+#include <tuple> // std::tuple
+
+namespace sqlite_orm {
+ namespace internal {
template<class T, template<class> class C>
struct count_tuple;
@@ -282,6 +440,41 @@ namespace sqlite_orm {
}
#pragma once
+namespace sqlite_orm {
+ namespace internal {
+
+ /**
+ * Accepts any number of arguments and evaluates `type` alias as T if all arguments are the same or void otherwise
+ */
+ template<class... Args>
+ struct same_or_void {
+ using type = void;
+ };
+
+ template<class A>
+ struct same_or_void<A> {
+ using type = A;
+ };
+
+ template<class A, class B>
+ struct same_or_void<A, B> {
+ using type = void;
+ };
+
+ template<class A>
+ struct same_or_void<A, A> {
+ using type = A;
+ };
+
+ template<class A, class... Args>
+ struct same_or_void<A, A, Args...> {
+ using type = typename same_or_void<A, Args...>::type;
+ };
+
+ }
+}
+#pragma once
+
#include <string> // std::string
#include <memory> // std::shared_ptr, std::unique_ptr
#include <vector> // std::vector
@@ -298,28 +491,28 @@ namespace sqlite_orm {
struct type_printer;
struct integer_printer {
- inline const std::string &print() {
+ inline const std::string& print() {
static const std::string res = "INTEGER";
return res;
}
};
struct text_printer {
- inline const std::string &print() {
+ inline const std::string& print() {
static const std::string res = "TEXT";
return res;
}
};
struct real_printer {
- inline const std::string &print() {
+ inline const std::string& print() {
static const std::string res = "REAL";
return res;
}
};
struct blob_printer {
- inline const std::string &print() {
+ inline const std::string& print() {
static const std::string res = "BLOB";
return res;
}
@@ -369,7 +562,7 @@ namespace sqlite_orm {
struct type_printer<std::wstring, void> : public text_printer {};
template<>
- struct type_printer<const char *, void> : public text_printer {};
+ struct type_printer<const char*, void> : public text_printer {};
template<>
struct type_printer<float, void> : public real_printer {};
@@ -413,9 +606,364 @@ namespace sqlite_orm {
#include <type_traits> // std::is_base_of, std::false_type, std::true_type
#include <ostream> // std::ostream
+// #include "table_type.h"
+
+#include <type_traits> // std::enable_if, std::is_member_pointer, std::is_member_function_pointer
+
+// #include "member_traits/getter_traits.h"
+
+// #include "getters.h"
+
+namespace sqlite_orm {
+ namespace internal {
+
+ template<class O, class T>
+ using getter_by_value_const = T (O::*)() const;
+
+ template<class O, class T>
+ using getter_by_value = T (O::*)();
+
+ template<class O, class T>
+ using getter_by_ref_const = T& (O::*)() const;
+
+ template<class O, class T>
+ using getter_by_ref = T& (O::*)();
+
+ template<class O, class T>
+ using getter_by_const_ref_const = const T& (O::*)() const;
+
+ template<class O, class T>
+ using getter_by_const_ref = const T& (O::*)();
+#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED
+ template<class O, class T>
+ using getter_by_value_const_noexcept = T (O::*)() const noexcept;
+
+ template<class O, class T>
+ using getter_by_value_noexcept = T (O::*)() noexcept;
+
+ template<class O, class T>
+ using getter_by_ref_const_noexcept = T& (O::*)() const noexcept;
+
+ template<class O, class T>
+ using getter_by_ref_noexcept = T& (O::*)() noexcept;
+
+ template<class O, class T>
+ using getter_by_const_ref_const_noexcept = const T& (O::*)() const noexcept;
+
+ template<class O, class T>
+ using getter_by_const_ref_noexcept = const T& (O::*)() noexcept;
+#endif
+ }
+}
+
namespace sqlite_orm {
+ namespace internal {
+
+ template<class T>
+ struct getter_traits;
+
+ template<class O, class T>
+ struct getter_traits<getter_by_value_const<O, T>> {
+ using object_type = O;
+ using field_type = T;
+
+ static constexpr const bool returns_lvalue = false;
+ };
- namespace constraints {
+ template<class O, class T>
+ struct getter_traits<getter_by_value<O, T>> {
+ using object_type = O;
+ using field_type = T;
+
+ static constexpr const bool returns_lvalue = false;
+ };
+
+ template<class O, class T>
+ struct getter_traits<getter_by_ref_const<O, T>> {
+ using object_type = O;
+ using field_type = T;
+
+ static constexpr const bool returns_lvalue = true;
+ };
+
+ template<class O, class T>
+ struct getter_traits<getter_by_ref<O, T>> {
+ using object_type = O;
+ using field_type = T;
+
+ static constexpr const bool returns_lvalue = true;
+ };
+
+ template<class O, class T>
+ struct getter_traits<getter_by_const_ref_const<O, T>> {
+ using object_type = O;
+ using field_type = T;
+
+ static constexpr const bool returns_lvalue = true;
+ };
+
+ template<class O, class T>
+ struct getter_traits<getter_by_const_ref<O, T>> {
+ using object_type = O;
+ using field_type = T;
+
+ static constexpr const bool returns_lvalue = true;
+ };
+#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED
+ template<class O, class T>
+ struct getter_traits<getter_by_value_const_noexcept<O, T>> {
+ using object_type = O;
+ using field_type = T;
+
+ static constexpr const bool returns_lvalue = false;
+ };
+
+ template<class O, class T>
+ struct getter_traits<getter_by_value_noexcept<O, T>> {
+ using object_type = O;
+ using field_type = T;
+
+ static constexpr const bool returns_lvalue = false;
+ };
+
+ template<class O, class T>
+ struct getter_traits<getter_by_ref_const_noexcept<O, T>> {
+ using object_type = O;
+ using field_type = T;
+
+ static constexpr const bool returns_lvalue = true;
+ };
+
+ template<class O, class T>
+ struct getter_traits<getter_by_ref_noexcept<O, T>> {
+ using object_type = O;
+ using field_type = T;
+
+ static constexpr const bool returns_lvalue = true;
+ };
+
+ template<class O, class T>
+ struct getter_traits<getter_by_const_ref_const_noexcept<O, T>> {
+ using object_type = O;
+ using field_type = T;
+
+ static constexpr const bool returns_lvalue = true;
+ };
+
+ template<class O, class T>
+ struct getter_traits<getter_by_const_ref_noexcept<O, T>> {
+ using object_type = O;
+ using field_type = T;
+
+ static constexpr const bool returns_lvalue = true;
+ };
+#endif
+ }
+}
+
+// #include "member_traits/setter_traits.h"
+
+// #include "setters.h"
+
+namespace sqlite_orm {
+ namespace internal {
+
+ template<class O, class T>
+ using setter_by_value = void (O::*)(T);
+
+ template<class O, class T>
+ using setter_by_ref = void (O::*)(T&);
+
+ template<class O, class T>
+ using setter_by_const_ref = void (O::*)(const T&);
+#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED
+ template<class O, class T>
+ using setter_by_value_noexcept = void (O::*)(T) noexcept;
+
+ template<class O, class T>
+ using setter_by_ref_noexcept = void (O::*)(T&) noexcept;
+
+ template<class O, class T>
+ using setter_by_const_ref_noexcept = void (O::*)(const T&) noexcept;
+#endif
+ }
+}
+
+namespace sqlite_orm {
+ namespace internal {
+
+ template<class T>
+ struct setter_traits;
+
+ template<class O, class T>
+ struct setter_traits<setter_by_value<O, T>> {
+ using object_type = O;
+ using field_type = T;
+ };
+
+ template<class O, class T>
+ struct setter_traits<setter_by_ref<O, T>> {
+ using object_type = O;
+ using field_type = T;
+ };
+
+ template<class O, class T>
+ struct setter_traits<setter_by_const_ref<O, T>> {
+ using object_type = O;
+ using field_type = T;
+ };
+#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED
+ template<class O, class T>
+ struct setter_traits<setter_by_value_noexcept<O, T>> {
+ using object_type = O;
+ using field_type = T;
+ };
+
+ template<class O, class T>
+ struct setter_traits<setter_by_ref_noexcept<O, T>> {
+ using object_type = O;
+ using field_type = T;
+ };
+
+ template<class O, class T>
+ struct setter_traits<setter_by_const_ref_noexcept<O, T>> {
+ using object_type = O;
+ using field_type = T;
+ };
+#endif
+ }
+}
+
+// #include "member_traits/is_getter.h"
+
+#include <type_traits> // std::false_type, std::true_type
+
+// #include "getters.h"
+
+namespace sqlite_orm {
+ namespace internal {
+
+ template<class T>
+ struct is_getter : std::false_type {};
+
+ template<class O, class T>
+ struct is_getter<getter_by_value_const<O, T>> : std::true_type {};
+
+ template<class O, class T>
+ struct is_getter<getter_by_value<O, T>> : std::true_type {};
+
+ template<class O, class T>
+ struct is_getter<getter_by_ref_const<O, T>> : std::true_type {};
+
+ template<class O, class T>
+ struct is_getter<getter_by_ref<O, T>> : std::true_type {};
+
+ template<class O, class T>
+ struct is_getter<getter_by_const_ref_const<O, T>> : std::true_type {};
+
+ template<class O, class T>
+ struct is_getter<getter_by_const_ref<O, T>> : std::true_type {};
+#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED
+ template<class O, class T>
+ struct is_getter<getter_by_value_const_noexcept<O, T>> : std::true_type {};
+
+ template<class O, class T>
+ struct is_getter<getter_by_value_noexcept<O, T>> : std::true_type {};
+
+ template<class O, class T>
+ struct is_getter<getter_by_ref_const_noexcept<O, T>> : std::true_type {};
+
+ template<class O, class T>
+ struct is_getter<getter_by_ref_noexcept<O, T>> : std::true_type {};
+
+ template<class O, class T>
+ struct is_getter<getter_by_const_ref_const_noexcept<O, T>> : std::true_type {};
+
+ template<class O, class T>
+ struct is_getter<getter_by_const_ref_noexcept<O, T>> : std::true_type {};
+#endif
+ }
+}
+
+// #include "member_traits/is_setter.h"
+
+// #include "setters.h"
+
+namespace sqlite_orm {
+ namespace internal {
+
+ template<class T>
+ struct is_setter : std::false_type {};
+
+ template<class O, class T>
+ struct is_setter<setter_by_value<O, T>> : std::true_type {};
+
+ template<class O, class T>
+ struct is_setter<setter_by_ref<O, T>> : std::true_type {};
+
+ template<class O, class T>
+ struct is_setter<setter_by_const_ref<O, T>> : std::true_type {};
+#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED
+ template<class O, class T>
+ struct is_setter<setter_by_value_noexcept<O, T>> : std::true_type {};
+
+ template<class O, class T>
+ struct is_setter<setter_by_ref_noexcept<O, T>> : std::true_type {};
+
+ template<class O, class T>
+ struct is_setter<setter_by_const_ref_noexcept<O, T>> : std::true_type {};
+#endif
+ }
+}
+
+namespace sqlite_orm {
+
+ namespace internal {
+
+ template<class T, class F>
+ struct column_pointer;
+
+ /**
+ * Trait class used to define table mapped type by setter/getter/member
+ * T - member pointer
+ * `type` is a type which is mapped.
+ * E.g.
+ * - `table_type<decltype(&User::id)>::type` is `User`
+ * - `table_type<decltype(&User::getName)>::type` is `User`
+ * - `table_type<decltype(&User::setName)>::type` is `User`
+ */
+ template<class T, class SFINAE = void>
+ struct table_type;
+
+ template<class O, class F>
+ struct table_type<F O::*,
+ typename std::enable_if<std::is_member_pointer<F O::*>::value &&
+ !std::is_member_function_pointer<F O::*>::value>::type> {
+ using type = O;
+ };
+
+ template<class T>
+ struct table_type<T, typename std::enable_if<is_getter<T>::value>::type> {
+ using type = typename getter_traits<T>::object_type;
+ };
+
+ template<class T>
+ struct table_type<T, typename std::enable_if<is_setter<T>::value>::type> {
+ using type = typename setter_traits<T>::object_type;
+ };
+
+ template<class T, class F>
+ struct table_type<column_pointer<T, F>, void> {
+ using type = T;
+ };
+ }
+}
+
+// #include "tuple_helper/tuple_helper.h"
+
+namespace sqlite_orm {
+
+ namespace internal {
/**
* AUTOINCREMENT constraint class.
@@ -455,7 +1003,7 @@ namespace sqlite_orm {
/**
* PRIMARY KEY constraint class.
* Cs is parameter pack which contains columns (member pointers and/or function pointers). Can be empty when
- * used withen `make_column` function.
+ * used withen `make_column` function.
*/
template<class... Cs>
struct primary_key_t : primary_key_base {
@@ -533,7 +1081,7 @@ namespace sqlite_orm {
cascade,
};
- inline std::ostream &operator<<(std::ostream &os, foreign_key_action action) {
+ inline std::ostream& operator<<(std::ostream& os, foreign_key_action action) {
switch(action) {
case decltype(action)::no_action:
os << "NO ACTION";
@@ -575,7 +1123,7 @@ namespace sqlite_orm {
struct on_update_delete_t : on_update_delete_base {
using foreign_key_type = F;
- const foreign_key_type &fk;
+ const foreign_key_type& fk;
on_update_delete_t(decltype(fk) fk_, decltype(update) update_, foreign_key_action action_) :
on_update_delete_base{update_}, fk(fk_), _action(action_) {}
@@ -637,12 +1185,27 @@ namespace sqlite_orm {
}
};
+ template<class F>
+ bool operator==(const on_update_delete_t<F>& lhs, const on_update_delete_t<F>& rhs) {
+ return lhs._action == rhs._action;
+ }
+
template<class... Cs, class... Rs>
struct foreign_key_t<std::tuple<Cs...>, std::tuple<Rs...>> {
using columns_type = std::tuple<Cs...>;
using references_type = std::tuple<Rs...>;
using self = foreign_key_t<columns_type, references_type>;
+ /**
+ * Holds obect type of all referenced columns.
+ */
+ using target_type = typename same_or_void<typename table_type<Rs>::type...>::type;
+
+ /**
+ * Holds obect type of all source columns.
+ */
+ using source_type = typename same_or_void<typename table_type<Cs>::type...>::type;
+
columns_type columns;
references_type references;
@@ -651,16 +1214,17 @@ namespace sqlite_orm {
static_assert(std::tuple_size<columns_type>::value == std::tuple_size<references_type>::value,
"Columns size must be equal to references tuple");
+ static_assert(!std::is_same<target_type, void>::value, "All references must have the same type");
foreign_key_t(columns_type columns_, references_type references_) :
- columns(std::move(columns_)), references(std::move(references_)),
+ columns(move(columns_)), references(move(references_)),
on_update(*this, true, foreign_key_action::none), on_delete(*this, false, foreign_key_action::none) {}
- foreign_key_t(const self &other) :
+ foreign_key_t(const self& other) :
columns(other.columns), references(other.references), on_update(*this, true, other.on_update._action),
on_delete(*this, false, other.on_delete._action) {}
- self &operator=(const self &other) {
+ self& operator=(const self& other) {
this->columns = other.columns;
this->references = other.references;
this->on_update = {*this, true, other.on_update._action};
@@ -669,7 +1233,7 @@ namespace sqlite_orm {
}
template<class L>
- void for_each_column(const L &) {}
+ void for_each_column(const L&) {}
template<class... Opts>
constexpr bool has_every() const {
@@ -677,6 +1241,12 @@ namespace sqlite_orm {
}
};
+ template<class A, class B>
+ bool operator==(const foreign_key_t<A, B>& lhs, const foreign_key_t<A, B>& rhs) {
+ return lhs.columns == rhs.columns && lhs.references == rhs.references && lhs.on_update == rhs.on_update &&
+ lhs.on_delete == rhs.on_delete;
+ }
+
/**
* Cs can be a class member pointer, a getter function member pointer or setter
* func member pointer
@@ -697,10 +1267,10 @@ namespace sqlite_orm {
};
#endif
- struct collate_t {
+ struct collate_constraint_t {
internal::collate_argument argument = internal::collate_argument::binary;
- collate_t(internal::collate_argument argument_) : argument(argument_) {}
+ collate_constraint_t(internal::collate_argument argument_) : argument(argument_) {}
operator std::string() const {
std::string res = "COLLATE " + this->string_from_collate_argument(this->argument);
@@ -754,7 +1324,7 @@ namespace sqlite_orm {
struct is_constraint<foreign_key_t<C, R>> : std::true_type {};
template<>
- struct is_constraint<collate_t> : std::true_type {};
+ struct is_constraint<collate_constraint_t> : std::true_type {};
template<class T>
struct is_constraint<check_t<T>> : std::true_type {};
@@ -780,7 +1350,7 @@ namespace sqlite_orm {
* Available in SQLite 3.6.19 or higher
*/
template<class... Cs>
- constraints::foreign_key_intermediate_t<Cs...> foreign_key(Cs... columns) {
+ internal::foreign_key_intermediate_t<Cs...> foreign_key(Cs... columns) {
return {std::make_tuple(std::forward<Cs>(columns)...)};
}
#endif
@@ -789,46 +1359,46 @@ namespace sqlite_orm {
* UNIQUE constraint builder function.
*/
template<class... Args>
- constraints::unique_t<Args...> unique(Args... args) {
+ internal::unique_t<Args...> unique(Args... args) {
return {std::make_tuple(std::forward<Args>(args)...)};
}
- inline constraints::unique_t<> unique() {
+ inline internal::unique_t<> unique() {
return {{}};
}
- inline constraints::autoincrement_t autoincrement() {
+ inline internal::autoincrement_t autoincrement() {
return {};
}
template<class... Cs>
- constraints::primary_key_t<Cs...> primary_key(Cs... cs) {
+ internal::primary_key_t<Cs...> primary_key(Cs... cs) {
return {std::make_tuple(std::forward<Cs>(cs)...)};
}
- inline constraints::primary_key_t<> primary_key() {
+ inline internal::primary_key_t<> primary_key() {
return {{}};
}
template<class T>
- constraints::default_t<T> default_value(T t) {
+ internal::default_t<T> default_value(T t) {
return {std::move(t)};
}
- inline constraints::collate_t collate_nocase() {
+ inline internal::collate_constraint_t collate_nocase() {
return {internal::collate_argument::nocase};
}
- inline constraints::collate_t collate_binary() {
+ inline internal::collate_constraint_t collate_binary() {
return {internal::collate_argument::binary};
}
- inline constraints::collate_t collate_rtrim() {
+ inline internal::collate_constraint_t collate_rtrim() {
return {internal::collate_argument::rtrim};
}
template<class T>
- constraints::check_t<T> check(T t) {
+ internal::check_t<T> check(T t) {
return {std::move(t)};
}
@@ -844,7 +1414,7 @@ namespace sqlite_orm {
* FOREIGN KEY traits. Specialized case
*/
template<class C, class R>
- struct is_foreign_key<constraints::foreign_key_t<C, R>> : std::true_type {};
+ struct is_foreign_key<internal::foreign_key_t<C, R>> : std::true_type {};
/**
* PRIMARY KEY traits. Common case
@@ -856,7 +1426,24 @@ namespace sqlite_orm {
* PRIMARY KEY traits. Specialized case
*/
template<class... Cs>
- struct is_primary_key<constraints::primary_key_t<Cs...>> : public std::true_type {};
+ struct is_primary_key<internal::primary_key_t<Cs...>> : public std::true_type {};
+
+ /**
+ * PRIMARY KEY INSERTABLE traits.
+ */
+ template<typename T>
+ struct is_primary_key_insertable {
+ using field_type = typename T::field_type;
+ using constraints_type = typename T::constraints_type;
+
+ static_assert((tuple_helper::tuple_contains_type<primary_key_t<>, constraints_type>::value),
+ "an unexpected type was passed");
+
+ static constexpr bool value =
+ (tuple_helper::tuple_contains_some_type<default_t, constraints_type>::value ||
+ tuple_helper::tuple_contains_type<autoincrement_t, constraints_type>::value ||
+ std::is_base_of<integer_printer, type_printer<field_type>>::value);
+ };
}
}
@@ -879,7 +1466,7 @@ namespace sqlite_orm {
*/
template<class T>
struct type_is_nullable : public std::false_type {
- bool operator()(const T &) const {
+ bool operator()(const T&) const {
return true;
}
};
@@ -889,7 +1476,7 @@ namespace sqlite_orm {
*/
template<class T>
struct type_is_nullable<std::shared_ptr<T>> : public std::true_type {
- bool operator()(const std::shared_ptr<T> &t) const {
+ bool operator()(const std::shared_ptr<T>& t) const {
return static_cast<bool>(t);
}
};
@@ -899,7 +1486,7 @@ namespace sqlite_orm {
*/
template<class T>
struct type_is_nullable<std::unique_ptr<T>> : public std::true_type {
- bool operator()(const std::unique_ptr<T> &t) const {
+ bool operator()(const std::unique_ptr<T>& t) const {
return static_cast<bool>(t);
}
};
@@ -910,7 +1497,7 @@ namespace sqlite_orm {
*/
template<class T>
struct type_is_nullable<std::optional<T>> : public std::true_type {
- bool operator()(const std::optional<T> &t) const {
+ bool operator()(const std::optional<T>& t) const {
return t.has_value();
}
};
@@ -937,8 +1524,8 @@ namespace sqlite_orm {
bool use_parentheses = true;
template<class O, class F>
- std::string column_name(F O::*) const {
- return {};
+ const std::string* column_name(F O::*) const {
+ return nullptr;
}
};
@@ -946,12 +1533,12 @@ namespace sqlite_orm {
struct serializator_context : serializator_context_base {
using impl_type = I;
- const impl_type &impl;
+ const impl_type& impl;
- serializator_context(const impl_type &impl_) : impl(impl_) {}
+ serializator_context(const impl_type& impl_) : impl(impl_) {}
template<class O, class F>
- std::string column_name(F O::*m) const {
+ const std::string* column_name(F O::*m) const {
return this->impl.column_name(m);
}
};
@@ -961,13 +1548,13 @@ namespace sqlite_orm {
using storage_type = S;
using impl_type = typename storage_type::impl_type;
- serializator_context_builder(const storage_type &storage_) : storage(storage_) {}
+ serializator_context_builder(const storage_type& storage_) : storage(storage_) {}
serializator_context<impl_type> operator()() const {
return {this->storage.impl};
}
- const storage_type &storage;
+ const storage_type& storage;
};
}
@@ -978,9 +1565,6 @@ namespace sqlite_orm {
namespace internal {
- template<class T>
- std::string serialize(const T &t);
-
/**
* This class is used in tuple interation to know whether tuple constains `default_value_t`
* constraint class and what it's value if it is
@@ -988,12 +1572,12 @@ namespace sqlite_orm {
struct default_value_extractor {
template<class A>
- std::unique_ptr<std::string> operator()(const A &) {
+ std::unique_ptr<std::string> operator()(const A&) {
return {};
}
template<class T>
- std::unique_ptr<std::string> operator()(const constraints::default_t<T> &t) {
+ std::unique_ptr<std::string> operator()(const default_t<T>& t) {
serializator_context_base context;
return std::make_unique<std::string>(serialize(t.value, context));
}
@@ -1005,12 +1589,19 @@ namespace sqlite_orm {
#pragma once
#include <type_traits> // std::false_type, std::true_type
-
-// #include "negatable.h"
+#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
+#include <optional> // std::nullopt
+#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
+// #include "tags.h"
namespace sqlite_orm {
namespace internal {
struct negatable_t {};
+
+ /**
+ * Inherit from this class if target class can be chained with other conditions with '&&' and '||' operators
+ */
+ struct condition_t {};
}
}
@@ -1094,7 +1685,7 @@ namespace sqlite_orm {
template<class L, class R>
using div_t = binary_operator<L, R, div_string, arithmetic_t, negatable_t>;
- struct mod_string {
+ struct mod_operator_string {
operator std::string() const {
return "%";
}
@@ -1104,7 +1695,7 @@ namespace sqlite_orm {
* Result of mod % operator
*/
template<class L, class R>
- using mod_t = binary_operator<L, R, mod_string, arithmetic_t, negatable_t>;
+ using mod_t = binary_operator<L, R, mod_operator_string, arithmetic_t, negatable_t>;
struct bitwise_shift_left_string {
operator std::string() const {
@@ -1113,8 +1704,8 @@ namespace sqlite_orm {
};
/**
- * Result of bitwise shift left << operator
- */
+ * Result of bitwise shift left << operator
+ */
template<class L, class R>
using bitwise_shift_left_t = binary_operator<L, R, bitwise_shift_left_string, arithmetic_t, negatable_t>;
@@ -1125,8 +1716,8 @@ namespace sqlite_orm {
};
/**
- * Result of bitwise shift right >> operator
- */
+ * Result of bitwise shift right >> operator
+ */
template<class L, class R>
using bitwise_shift_right_t = binary_operator<L, R, bitwise_shift_right_string, arithmetic_t, negatable_t>;
@@ -1137,8 +1728,8 @@ namespace sqlite_orm {
};
/**
- * Result of bitwise and & operator
- */
+ * Result of bitwise and & operator
+ */
template<class L, class R>
using bitwise_and_t = binary_operator<L, R, bitwise_and_string, arithmetic_t, negatable_t>;
@@ -1149,8 +1740,8 @@ namespace sqlite_orm {
};
/**
- * Result of bitwise or | operator
- */
+ * Result of bitwise or | operator
+ */
template<class L, class R>
using bitwise_or_t = binary_operator<L, R, bitwise_or_string, arithmetic_t, negatable_t>;
@@ -1161,8 +1752,8 @@ namespace sqlite_orm {
};
/**
- * Result of bitwise not ~ operator
- */
+ * Result of bitwise not ~ operator
+ */
template<class T>
struct bitwise_not_t : bitwise_not_string, arithmetic_t, negatable_t {
using argument_type = T;
@@ -1177,6 +1768,7 @@ namespace sqlite_orm {
return "=";
}
};
+
/**
* Result of assign = operator
*/
@@ -1195,34 +1787,9 @@ namespace sqlite_orm {
template<class L, class R>
struct is_assign_t<assign_t<L, R>> : public std::true_type {};
- /**
- * Is not an operator but a result of c(...) function. Has operator= overloaded which returns assign_t
- */
- template<class T>
- struct expression_t {
- T t;
-
- expression_t(T t_) : t(std::move(t_)) {}
-
- template<class R>
- assign_t<T, R> operator=(R r) const {
- return {this->t, std::move(r)};
- }
-
- assign_t<T, std::nullptr_t> operator=(std::nullptr_t) const {
- return {this->t, nullptr};
- }
- };
-
- }
+ template<class L, class... Args>
+ struct in_t;
- /**
- * Public interface for syntax sugar for columns. Example: `where(c(&User::id) == 5)` or
- * `storage.update(set(c(&User::name) = "Dua Lipa"));
- */
- template<class T>
- internal::expression_t<T> c(T t) {
- return {std::move(t)};
}
/**
@@ -1243,23 +1810,34 @@ namespace sqlite_orm {
}
/**
- * Public interface for - operator. Example: `select(add(&User::age, 1));` => SELECT age - 1 FROM users
+ * Public interface for - operator. Example: `select(sub(&User::age, 1));` => SELECT age - 1 FROM users
*/
template<class L, class R>
internal::sub_t<L, R> sub(L l, R r) {
return {std::move(l), std::move(r)};
}
+ /**
+ * Public interface for * operator. Example: `select(mul(&User::salary, 2));` => SELECT salary * 2 FROM users
+ */
template<class L, class R>
internal::mul_t<L, R> mul(L l, R r) {
return {std::move(l), std::move(r)};
}
+ /**
+ * Public interface for / operator. Example: `select(div(&User::salary, 3));` => SELECT salary / 3 FROM users
+ * @note Please notice that ::div function already exists in pure C standard library inside <cstdlib> header.
+ * If you use `using namespace sqlite_orm` directive you an specify which `div` you call explicitly using `::div` or `sqlite_orm::div` statements.
+ */
template<class L, class R>
internal::div_t<L, R> div(L l, R r) {
return {std::move(l), std::move(r)};
}
+ /**
+ * Public interface for % operator. Example: `select(mod(&User::age, 5));` => SELECT age % 5 FROM users
+ */
template<class L, class R>
internal::mod_t<L, R> mod(L l, R r) {
return {std::move(l), std::move(r)};
@@ -1305,16 +1883,21 @@ namespace sqlite_orm {
// #include "type_is_nullable.h"
-// #include "tuple_helper.h"
+// #include "tuple_helper/tuple_helper.h"
// #include "default_value_extractor.h"
// #include "constraints.h"
-// #include "getter_traits.h"
+// #include "member_traits/member_traits.h"
-namespace sqlite_orm {
+#include <type_traits> // std::enable_if
+// #include "is_field_member_pointer.h"
+
+#include <type_traits> // std::false_type, std::true_type, std::is_member_pointer, std::is_member_function_pointer
+
+namespace sqlite_orm {
namespace internal {
template<class T, class SFINAE = void>
@@ -1325,153 +1908,39 @@ namespace sqlite_orm {
typename std::enable_if<std::is_member_pointer<T>::value &&
!std::is_member_function_pointer<T>::value>::type>
: std::true_type {};
+ }
+}
- template<class T, class SFINAE = void>
- struct field_member_traits;
-
- template<class O, class F>
- struct field_member_traits<F O::*, typename std::enable_if<is_field_member_pointer<F O::*>::value>::type> {
- using object_type = O;
- using field_type = F;
- };
-
- /**
- * Getters aliases
- */
- template<class O, class T>
- using getter_by_value_const = T (O::*)() const;
-
- template<class O, class T>
- using getter_by_value = T (O::*)();
-
- template<class O, class T>
- using getter_by_ref_const = T &(O::*)() const;
-
- template<class O, class T>
- using getter_by_ref = T &(O::*)();
-
- template<class O, class T>
- using getter_by_const_ref_const = const T &(O::*)() const;
-
- template<class O, class T>
- using getter_by_const_ref = const T &(O::*)();
-
- /**
- * Setters aliases
- */
- template<class O, class T>
- using setter_by_value = void (O::*)(T);
-
- template<class O, class T>
- using setter_by_ref = void (O::*)(T &);
-
- template<class O, class T>
- using setter_by_const_ref = void (O::*)(const T &);
-
- template<class T>
- struct is_getter : std::false_type {};
-
- template<class O, class T>
- struct is_getter<getter_by_value_const<O, T>> : std::true_type {};
-
- template<class O, class T>
- struct is_getter<getter_by_value<O, T>> : std::true_type {};
-
- template<class O, class T>
- struct is_getter<getter_by_ref_const<O, T>> : std::true_type {};
-
- template<class O, class T>
- struct is_getter<getter_by_ref<O, T>> : std::true_type {};
-
- template<class O, class T>
- struct is_getter<getter_by_const_ref_const<O, T>> : std::true_type {};
-
- template<class O, class T>
- struct is_getter<getter_by_const_ref<O, T>> : std::true_type {};
-
- template<class T>
- struct is_setter : std::false_type {};
-
- template<class O, class T>
- struct is_setter<setter_by_value<O, T>> : std::true_type {};
-
- template<class O, class T>
- struct is_setter<setter_by_ref<O, T>> : std::true_type {};
-
- template<class O, class T>
- struct is_setter<setter_by_const_ref<O, T>> : std::true_type {};
-
- template<class T>
- struct getter_traits;
-
- template<class O, class T>
- struct getter_traits<getter_by_value_const<O, T>> {
- using object_type = O;
- using field_type = T;
-
- static constexpr const bool returns_lvalue = false;
- };
-
- template<class O, class T>
- struct getter_traits<getter_by_value<O, T>> {
- using object_type = O;
- using field_type = T;
-
- static constexpr const bool returns_lvalue = false;
- };
-
- template<class O, class T>
- struct getter_traits<getter_by_ref_const<O, T>> {
- using object_type = O;
- using field_type = T;
+// #include "is_getter.h"
- static constexpr const bool returns_lvalue = true;
- };
+// #include "field_member_traits.h"
- template<class O, class T>
- struct getter_traits<getter_by_ref<O, T>> {
- using object_type = O;
- using field_type = T;
+#include <type_traits> // std::enable_if
- static constexpr const bool returns_lvalue = true;
- };
+// #include "is_field_member_pointer.h"
- template<class O, class T>
- struct getter_traits<getter_by_const_ref_const<O, T>> {
- using object_type = O;
- using field_type = T;
+namespace sqlite_orm {
+ namespace internal {
- static constexpr const bool returns_lvalue = true;
- };
+ template<class T, class SFINAE = void>
+ struct field_member_traits;
- template<class O, class T>
- struct getter_traits<getter_by_const_ref<O, T>> {
+ template<class O, class F>
+ struct field_member_traits<F O::*, typename std::enable_if<is_field_member_pointer<F O::*>::value>::type> {
using object_type = O;
- using field_type = T;
-
- static constexpr const bool returns_lvalue = true;
+ using field_type = F;
};
+ }
+}
- template<class T>
- struct setter_traits;
+// #include "is_setter.h"
- template<class O, class T>
- struct setter_traits<setter_by_value<O, T>> {
- using object_type = O;
- using field_type = T;
- };
+// #include "getter_traits.h"
- template<class O, class T>
- struct setter_traits<setter_by_ref<O, T>> {
- using object_type = O;
- using field_type = T;
- };
+// #include "setter_traits.h"
- template<class O, class T>
- struct setter_traits<setter_by_const_ref<O, T>> {
- using object_type = O;
- using field_type = T;
- };
+namespace sqlite_orm {
+ namespace internal {
template<class T, class SFINAE = void>
struct member_traits;
@@ -1500,7 +1969,7 @@ namespace sqlite_orm {
namespace internal {
- struct column_base {
+ struct basic_column {
/**
* Column name. Specified during construction in `make_column`.
@@ -1515,7 +1984,7 @@ namespace sqlite_orm {
* Op... is a constraints pack, e.g. primary_key_t, autoincrement_t etc
*/
template<class O, class T, class G /* = const T& (O::*)() const*/, class S /* = void (O::*)(T)*/, class... Op>
- struct column_t : column_base {
+ struct column_t : basic_column {
using object_type = O;
using field_type = T;
using constraints_type = std::tuple<Op...>;
@@ -1549,7 +2018,7 @@ namespace sqlite_orm {
getter_type getter_,
setter_type setter_,
constraints_type constraints_) :
- column_base{std::move(name_)},
+ basic_column{move(name_)},
member_pointer(member_pointer_), getter(getter_), setter(setter_), constraints(move(constraints_)) {}
/**
@@ -1584,7 +2053,7 @@ namespace sqlite_orm {
*/
std::unique_ptr<std::string> default_value() const {
std::unique_ptr<std::string> res;
- iterate_tuple(this->constraints, [&res](auto &v) {
+ iterate_tuple(this->constraints, [&res](auto& v) {
auto dft = internal::default_value_extractor()(v);
if(dft) {
res = std::move(dft);
@@ -1594,6 +2063,48 @@ namespace sqlite_orm {
}
};
+ // we are compelled to wrap all sfinae-implemented traits to prevent "error: type/value mismatch at argument 2 in template parameter list"
+ namespace sfinae {
+ /**
+ * Column with insertable primary key traits. Common case.
+ */
+ template<class T, class SFINAE = void>
+ struct is_column_with_insertable_primary_key : public std::false_type {};
+
+ /**
+ * Column with insertable primary key traits. Specialized case case.
+ */
+ template<class O, class T, class... Op>
+ struct is_column_with_insertable_primary_key<
+ column_t<O, T, Op...>,
+ typename std::enable_if<(tuple_helper::tuple_contains_type<
+ primary_key_t<>,
+ typename column_t<O, T, Op...>::constraints_type>::value)>::type> {
+ using column_type = column_t<O, T, Op...>;
+ static constexpr bool value = is_primary_key_insertable<column_type>::value;
+ };
+
+ /**
+ * Column with noninsertable primary key traits. Common case.
+ */
+ template<class T, class SFINAE = void>
+ struct is_column_with_noninsertable_primary_key : public std::false_type {};
+
+ /**
+ * Column with noninsertable primary key traits. Specialized case case.
+ */
+ template<class O, class T, class... Op>
+ struct is_column_with_noninsertable_primary_key<
+ column_t<O, T, Op...>,
+ typename std::enable_if<(tuple_helper::tuple_contains_type<
+ primary_key_t<>,
+ typename column_t<O, T, Op...>::constraints_type>::value)>::type> {
+ using column_type = column_t<O, T, Op...>;
+ static constexpr bool value = !is_primary_key_insertable<column_type>::value;
+ };
+
+ }
+
/**
* Column traits. Common case.
*/
@@ -1606,6 +2117,18 @@ namespace sqlite_orm {
template<class O, class T, class... Op>
struct is_column<column_t<O, T, Op...>> : public std::true_type {};
+ /**
+ * Column with insertable primary key traits.
+ */
+ template<class T>
+ struct is_column_with_insertable_primary_key : public sfinae::is_column_with_insertable_primary_key<T> {};
+
+ /**
+ * Column with noninsertable primary key traits.
+ */
+ template<class T>
+ struct is_column_with_noninsertable_primary_key : public sfinae::is_column_with_noninsertable_primary_key<T> {};
+
template<class T>
struct column_field_type {
using type = void;
@@ -1635,9 +2158,9 @@ namespace sqlite_orm {
class T,
typename = typename std::enable_if<!std::is_member_function_pointer<T O::*>::value>::type,
class... Op>
- internal::column_t<O, T, const T &(O::*)() const, void (O::*)(T), Op...>
- make_column(const std::string &name, T O::*m, Op... constraints) {
- static_assert(constraints::template constraints_size<Op...>::value == std::tuple_size<std::tuple<Op...>>::value,
+ internal::column_t<O, T, const T& (O::*)() const, void (O::*)(T), Op...>
+ make_column(const std::string& name, T O::*m, Op... constraints) {
+ static_assert(internal::template constraints_size<Op...>::value == std::tuple_size<std::tuple<Op...>>::value,
"Incorrect constraints pack");
static_assert(internal::is_field_member_pointer<T O::*>::value,
"second argument expected as a member field pointer, not member function pointer");
@@ -1657,11 +2180,11 @@ namespace sqlite_orm {
G,
S,
Op...>
- make_column(const std::string &name, S setter, G getter, Op... constraints) {
+ make_column(const std::string& name, S setter, G getter, Op... constraints) {
static_assert(std::is_same<typename internal::setter_traits<S>::field_type,
typename internal::getter_traits<G>::field_type>::value,
"Getter and setter must get and set same data type");
- static_assert(constraints::template constraints_size<Op...>::value == std::tuple_size<std::tuple<Op...>>::value,
+ static_assert(internal::template constraints_size<Op...>::value == std::tuple_size<std::tuple<Op...>>::value,
"Incorrect constraints pack");
return {name, nullptr, getter, setter, std::make_tuple(constraints...)};
}
@@ -1680,11 +2203,11 @@ namespace sqlite_orm {
G,
S,
Op...>
- make_column(const std::string &name, G getter, S setter, Op... constraints) {
+ make_column(const std::string& name, G getter, S setter, Op... constraints) {
static_assert(std::is_same<typename internal::setter_traits<S>::field_type,
typename internal::getter_traits<G>::field_type>::value,
"Getter and setter must get and set same data type");
- static_assert(constraints::template constraints_size<Op...>::value == std::tuple_size<std::tuple<Op...>>::value,
+ static_assert(internal::template constraints_size<Op...>::value == std::tuple_size<std::tuple<Op...>>::value,
"Incorrect constraints pack");
return {name, nullptr, getter, setter, std::make_tuple(constraints...)};
}
@@ -1707,9 +2230,9 @@ namespace sqlite_orm {
* Is used to print members mapped to objects in storage_t::dump member function.
* Other developers can create own specialization to map custom types
*/
- template<class T>
+ template<class T, typename Enable = void>
struct field_printer {
- std::string operator()(const T &t) const {
+ std::string operator()(const T& t) const {
std::stringstream stream;
stream << t;
return stream.str();
@@ -1720,8 +2243,8 @@ namespace sqlite_orm {
* Upgrade to integer is required when using unsigned char(uint8_t)
*/
template<>
- struct field_printer<unsigned char> {
- std::string operator()(const unsigned char &t) const {
+ struct field_printer<unsigned char, void> {
+ std::string operator()(const unsigned char& t) const {
std::stringstream stream;
stream << +t;
return stream.str();
@@ -1732,8 +2255,8 @@ namespace sqlite_orm {
* Upgrade to integer is required when using signed char(int8_t)
*/
template<>
- struct field_printer<signed char> {
- std::string operator()(const signed char &t) const {
+ struct field_printer<signed char, void> {
+ std::string operator()(const signed char& t) const {
std::stringstream stream;
stream << +t;
return stream.str();
@@ -1744,8 +2267,8 @@ namespace sqlite_orm {
* char is neigher signer char nor unsigned char so it has its own specialization
*/
template<>
- struct field_printer<char> {
- std::string operator()(const char &t) const {
+ struct field_printer<char, void> {
+ std::string operator()(const char& t) const {
std::stringstream stream;
stream << +t;
return stream.str();
@@ -1753,15 +2276,15 @@ namespace sqlite_orm {
};
template<>
- struct field_printer<std::string> {
- std::string operator()(const std::string &t) const {
+ struct field_printer<std::string, void> {
+ std::string operator()(const std::string& t) const {
return t;
}
};
template<>
- struct field_printer<std::vector<char>> {
- std::string operator()(const std::vector<char> &t) const {
+ struct field_printer<std::vector<char>, void> {
+ std::string operator()(const std::vector<char>& t) const {
std::stringstream ss;
ss << std::hex;
for(auto c: t) {
@@ -1772,15 +2295,22 @@ namespace sqlite_orm {
};
template<>
- struct field_printer<std::nullptr_t> {
- std::string operator()(const std::nullptr_t &) const {
+ struct field_printer<std::nullptr_t, void> {
+ std::string operator()(const std::nullptr_t&) const {
return "null";
}
};
-
+#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
+ template<>
+ struct field_printer<std::nullopt_t, void> {
+ std::string operator()(const std::nullopt_t&) const {
+ return "null";
+ }
+ };
+#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
template<class T>
- struct field_printer<std::shared_ptr<T>> {
- std::string operator()(const std::shared_ptr<T> &t) const {
+ struct field_printer<std::shared_ptr<T>, void> {
+ std::string operator()(const std::shared_ptr<T>& t) const {
if(t) {
return field_printer<T>()(*t);
} else {
@@ -1790,8 +2320,8 @@ namespace sqlite_orm {
};
template<class T>
- struct field_printer<std::unique_ptr<T>> {
- std::string operator()(const std::unique_ptr<T> &t) const {
+ struct field_printer<std::unique_ptr<T>, void> {
+ std::string operator()(const std::unique_ptr<T>& t) const {
if(t) {
return field_printer<T>()(*t);
} else {
@@ -1802,8 +2332,8 @@ namespace sqlite_orm {
#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
template<class T>
- struct field_printer<std::optional<T>> {
- std::string operator()(const std::optional<T> &t) const {
+ struct field_printer<std::optional<T>, void> {
+ std::string operator()(const std::optional<T>& t) const {
if(t.has_value()) {
return field_printer<T>()(*t);
} else {
@@ -1818,7 +2348,8 @@ namespace sqlite_orm {
#include <string> // std::string
#include <type_traits> // std::enable_if, std::is_same
#include <vector> // std::vector
-#include <tuple> // std::tuple
+#include <tuple> // std::tuple, std::tuple_size
+#include <sstream> // std::stringstream
// #include "collate_argument.h"
@@ -1841,7 +2372,7 @@ namespace sqlite_orm {
type field;
template<class L>
- void apply(const L &l) const {
+ void apply(const L& l) const {
l(this->field);
}
};
@@ -1851,20 +2382,93 @@ namespace sqlite_orm {
using type = void;
template<class L>
- void apply(const L &) const {
+ void apply(const L&) const {
//..
}
};
}
}
-// #include "negatable.h"
+// #include "tags.h"
+
+// #include "expression.h"
+// #include "operators.h"
namespace sqlite_orm {
namespace internal {
- struct arithmetic_t;
+
+ template<class L, class R>
+ struct and_condition_t;
+
+ template<class L, class R>
+ struct or_condition_t;
+
+ /**
+ * Is not an operator but a result of c(...) function. Has operator= overloaded which returns assign_t
+ */
+ template<class T>
+ struct expression_t : condition_t {
+ T value;
+
+ expression_t(T value_) : value(std::move(value_)) {}
+
+ template<class R>
+ assign_t<T, R> operator=(R r) const {
+ return {this->value, std::move(r)};
+ }
+
+ assign_t<T, std::nullptr_t> operator=(std::nullptr_t) const {
+ return {this->value, nullptr};
+ }
+#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
+ assign_t<T, std::nullopt_t> operator=(std::nullopt_t) const {
+ return {this->value, std::nullopt};
+ }
+#endif
+ template<class... Args>
+ in_t<T, Args...> in(Args... args) const {
+ return {this->value, std::make_tuple(std::forward<Args>(args)...), false};
+ }
+
+ template<class... Args>
+ in_t<T, Args...> not_in(Args... args) const {
+ return {this->value, std::make_tuple(std::forward<Args>(args)...), true};
+ }
+
+ template<class R>
+ and_condition_t<T, R> and_(R right) const {
+ return {this->value, std::move(right)};
+ }
+
+ template<class R>
+ or_condition_t<T, R> or_(R right) const {
+ return {this->value, std::move(right)};
+ }
+ };
+
+ template<class T>
+ T get_from_expression(T value) {
+ return std::move(value);
+ }
+
+ template<class T>
+ T get_from_expression(expression_t<T> expression) {
+ return std::move(expression.value);
+ }
+ }
+
+ /**
+ * Public interface for syntax sugar for columns. Example: `where(c(&User::id) == 5)` or
+ * `storage.update(set(c(&User::name) = "Dua Lipa"));
+ */
+ template<class T>
+ internal::expression_t<T> c(T value) {
+ return {std::move(value)};
}
+}
+
+namespace sqlite_orm {
namespace internal {
@@ -1880,7 +2484,7 @@ namespace sqlite_orm {
template<class T, bool has_offset, bool offset_is_implicit, class O>
struct limit_t : limit_string {
T lim;
- internal::optional_container<O> off;
+ optional_container<O> off;
limit_t() = default;
@@ -1910,22 +2514,17 @@ namespace sqlite_orm {
struct is_offset<offset_t<T>> : std::true_type {};
/**
- * Inherit from this class if target class can be chained with other conditions with '&&' and '||' operators
- */
- struct condition_t {};
-
- /**
* Collated something
*/
template<class T>
struct collate_t : public condition_t {
T expr;
- internal::collate_argument argument;
+ collate_argument argument;
- collate_t(T expr_, internal::collate_argument argument_) : expr(std::move(expr_)), argument(argument_) {}
+ collate_t(T expr_, collate_argument argument_) : expr(std::move(expr_)), argument(argument_) {}
operator std::string() const {
- return constraints::collate_t{this->argument};
+ return collate_constraint_t{this->argument};
}
};
@@ -1965,11 +2564,16 @@ namespace sqlite_orm {
/**
* Base class for binary conditions
+ * L is left argument type
+ * R is right argument type
+ * S is 'string' class (a class which has cast to `std::string` operator)
+ * Res is result type
*/
- template<class L, class R>
- struct binary_condition : public condition_t {
+ template<class L, class R, class S, class Res>
+ struct binary_condition : condition_t, S {
using left_type = L;
using right_type = R;
+ using result_type = Res;
left_type l;
right_type r;
@@ -1989,12 +2593,17 @@ namespace sqlite_orm {
* Result of and operator
*/
template<class L, class R>
- struct and_condition_t : binary_condition<L, R>, and_condition_string {
- using super = binary_condition<L, R>;
+ struct and_condition_t : binary_condition<L, R, and_condition_string, bool> {
+ using super = binary_condition<L, R, and_condition_string, bool>;
using super::super;
};
+ template<class L, class R>
+ and_condition_t<L, R> make_and_condition(L left, R right) {
+ return {std::move(left), std::move(right)};
+ }
+
struct or_condition_string {
operator std::string() const {
return "OR";
@@ -2005,12 +2614,17 @@ namespace sqlite_orm {
* Result of or operator
*/
template<class L, class R>
- struct or_condition_t : binary_condition<L, R>, or_condition_string {
- using super = binary_condition<L, R>;
+ struct or_condition_t : binary_condition<L, R, or_condition_string, bool> {
+ using super = binary_condition<L, R, or_condition_string, bool>;
using super::super;
};
+ template<class L, class R>
+ or_condition_t<L, R> make_or_condition(L left, R right) {
+ return {std::move(left), std::move(right)};
+ }
+
struct is_equal_string {
operator std::string() const {
return "=";
@@ -2021,26 +2635,35 @@ namespace sqlite_orm {
* = and == operators object
*/
template<class L, class R>
- struct is_equal_t : binary_condition<L, R>, is_equal_string, internal::negatable_t {
+ struct is_equal_t : binary_condition<L, R, is_equal_string, bool>, negatable_t {
using self = is_equal_t<L, R>;
- using binary_condition<L, R>::binary_condition;
+ using binary_condition<L, R, is_equal_string, bool>::binary_condition;
collate_t<self> collate_binary() const {
- return {*this, internal::collate_argument::binary};
+ return {*this, collate_argument::binary};
}
collate_t<self> collate_nocase() const {
- return {*this, internal::collate_argument::nocase};
+ return {*this, collate_argument::nocase};
}
collate_t<self> collate_rtrim() const {
- return {*this, internal::collate_argument::rtrim};
+ return {*this, collate_argument::rtrim};
}
named_collate<self> collate(std::string name) const {
return {*this, std::move(name)};
}
+
+ template<class C>
+ named_collate<self> collate() const {
+ std::stringstream ss;
+ ss << C::name();
+ auto name = ss.str();
+ ss.flush();
+ return {*this, std::move(name)};
+ }
};
struct is_not_equal_string {
@@ -2053,21 +2676,21 @@ namespace sqlite_orm {
* != operator object
*/
template<class L, class R>
- struct is_not_equal_t : binary_condition<L, R>, is_not_equal_string, internal::negatable_t {
+ struct is_not_equal_t : binary_condition<L, R, is_not_equal_string, bool>, negatable_t {
using self = is_not_equal_t<L, R>;
- using binary_condition<L, R>::binary_condition;
+ using binary_condition<L, R, is_not_equal_string, bool>::binary_condition;
collate_t<self> collate_binary() const {
- return {*this, internal::collate_argument::binary};
+ return {*this, collate_argument::binary};
}
collate_t<self> collate_nocase() const {
- return {*this, internal::collate_argument::nocase};
+ return {*this, collate_argument::nocase};
}
collate_t<self> collate_rtrim() const {
- return {*this, internal::collate_argument::rtrim};
+ return {*this, collate_argument::rtrim};
}
};
@@ -2081,21 +2704,21 @@ namespace sqlite_orm {
* > operator object.
*/
template<class L, class R>
- struct greater_than_t : binary_condition<L, R>, greater_than_string, internal::negatable_t {
+ struct greater_than_t : binary_condition<L, R, greater_than_string, bool>, negatable_t {
using self = greater_than_t<L, R>;
- using binary_condition<L, R>::binary_condition;
+ using binary_condition<L, R, greater_than_string, bool>::binary_condition;
collate_t<self> collate_binary() const {
- return {*this, internal::collate_argument::binary};
+ return {*this, collate_argument::binary};
}
collate_t<self> collate_nocase() const {
- return {*this, internal::collate_argument::nocase};
+ return {*this, collate_argument::nocase};
}
collate_t<self> collate_rtrim() const {
- return {*this, internal::collate_argument::rtrim};
+ return {*this, collate_argument::rtrim};
}
};
@@ -2109,21 +2732,21 @@ namespace sqlite_orm {
* >= operator object.
*/
template<class L, class R>
- struct greater_or_equal_t : binary_condition<L, R>, greater_or_equal_string, internal::negatable_t {
+ struct greater_or_equal_t : binary_condition<L, R, greater_or_equal_string, bool>, negatable_t {
using self = greater_or_equal_t<L, R>;
- using binary_condition<L, R>::binary_condition;
+ using binary_condition<L, R, greater_or_equal_string, bool>::binary_condition;
collate_t<self> collate_binary() const {
- return {*this, internal::collate_argument::binary};
+ return {*this, collate_argument::binary};
}
collate_t<self> collate_nocase() const {
- return {*this, internal::collate_argument::nocase};
+ return {*this, collate_argument::nocase};
}
collate_t<self> collate_rtrim() const {
- return {*this, internal::collate_argument::rtrim};
+ return {*this, collate_argument::rtrim};
}
};
@@ -2137,21 +2760,21 @@ namespace sqlite_orm {
* < operator object.
*/
template<class L, class R>
- struct lesser_than_t : binary_condition<L, R>, lesser_than_string, internal::negatable_t {
+ struct lesser_than_t : binary_condition<L, R, lesser_than_string, bool>, negatable_t {
using self = lesser_than_t<L, R>;
- using binary_condition<L, R>::binary_condition;
+ using binary_condition<L, R, lesser_than_string, bool>::binary_condition;
collate_t<self> collate_binary() const {
- return {*this, internal::collate_argument::binary};
+ return {*this, collate_argument::binary};
}
collate_t<self> collate_nocase() const {
- return {*this, internal::collate_argument::nocase};
+ return {*this, collate_argument::nocase};
}
collate_t<self> collate_rtrim() const {
- return {*this, internal::collate_argument::rtrim};
+ return {*this, collate_argument::rtrim};
}
};
@@ -2165,21 +2788,21 @@ namespace sqlite_orm {
* <= operator object.
*/
template<class L, class R>
- struct lesser_or_equal_t : binary_condition<L, R>, lesser_or_equal_string, internal::negatable_t {
+ struct lesser_or_equal_t : binary_condition<L, R, lesser_or_equal_string, bool>, negatable_t {
using self = lesser_or_equal_t<L, R>;
- using binary_condition<L, R>::binary_condition;
+ using binary_condition<L, R, lesser_or_equal_string, bool>::binary_condition;
collate_t<self> collate_binary() const {
- return {*this, internal::collate_argument::binary};
+ return {*this, collate_argument::binary};
}
collate_t<self> collate_nocase() const {
- return {*this, internal::collate_argument::nocase};
+ return {*this, collate_argument::nocase};
}
collate_t<self> collate_rtrim() const {
- return {*this, internal::collate_argument::rtrim};
+ return {*this, collate_argument::rtrim};
}
};
@@ -2199,13 +2822,23 @@ namespace sqlite_orm {
* IN operator object.
*/
template<class L, class A>
- struct in_t : condition_t, in_base, internal::negatable_t {
- using self = in_t<L, A>;
+ struct dynamic_in_t : condition_t, in_base, negatable_t {
+ using self = dynamic_in_t<L, A>;
- L l; // left expression
- A arg; // in arg
+ L left; // left expression
+ A argument; // in arg
- in_t(L l_, A arg_, bool negative_) : in_base{negative_}, l(l_), arg(std::move(arg_)) {}
+ dynamic_in_t(L left_, A argument_, bool negative_) :
+ in_base{negative_}, left(std::move(left_)), argument(std::move(argument_)) {}
+ };
+
+ template<class L, class... Args>
+ struct in_t : condition_t, in_base, negatable_t {
+ L left;
+ std::tuple<Args...> argument;
+
+ in_t(L left_, decltype(argument) argument_, bool negative_) :
+ in_base{negative_}, left(std::move(left_)), argument(std::move(argument_)) {}
};
struct is_null_string {
@@ -2218,7 +2851,7 @@ namespace sqlite_orm {
* IS NULL operator object.
*/
template<class T>
- struct is_null_t : is_null_string, internal::negatable_t {
+ struct is_null_t : is_null_string, negatable_t {
using self = is_null_t<T>;
T t;
@@ -2236,7 +2869,7 @@ namespace sqlite_orm {
* IS NOT NULL operator object.
*/
template<class T>
- struct is_not_null_t : is_not_null_string, internal::negatable_t {
+ struct is_not_null_t : is_not_null_string, negatable_t {
using self = is_not_null_t<T>;
T t;
@@ -2244,32 +2877,14 @@ namespace sqlite_orm {
is_not_null_t(T t_) : t(std::move(t_)) {}
};
- struct where_string {
- operator std::string() const {
- return "WHERE";
- }
- };
-
- /**
- * WHERE argument holder.
- * C is conditions type. Can be any condition like: is_equal_t, is_null_t, exists_t etc
- */
- template<class C>
- struct where_t : where_string {
- C c;
-
- where_t(C c_) : c(std::move(c_)) {}
- };
-
- template<class T>
- struct is_where : std::false_type {};
-
- template<class T>
- struct is_where<where_t<T>> : std::true_type {};
-
struct order_by_base {
int asc_desc = 0; // 1: asc, -1: desc
std::string _collate_argument;
+
+ order_by_base() = default;
+
+ order_by_base(decltype(asc_desc) asc_desc_, decltype(_collate_argument) _collate_argument_) :
+ asc_desc(asc_desc_), _collate_argument(move(_collate_argument_)) {}
};
struct order_by_string {
@@ -2283,11 +2898,12 @@ namespace sqlite_orm {
*/
template<class O>
struct order_by_t : order_by_base, order_by_string {
- using self = order_by_t<O>;
+ using expression_type = O;
+ using self = order_by_t<expression_type>;
- O o;
+ expression_type expression;
- order_by_t(O o_) : o(std::move(o_)) {}
+ order_by_t(expression_type expression_) : order_by_base(), expression(std::move(expression_)) {}
self asc() {
auto res = *this;
@@ -2303,22 +2919,22 @@ namespace sqlite_orm {
self collate_binary() const {
auto res = *this;
- res._collate_argument = constraints::collate_t::string_from_collate_argument(
- sqlite_orm::internal::collate_argument::binary);
+ res._collate_argument =
+ collate_constraint_t::string_from_collate_argument(sqlite_orm::internal::collate_argument::binary);
return res;
}
self collate_nocase() const {
auto res = *this;
- res._collate_argument = constraints::collate_t::string_from_collate_argument(
- sqlite_orm::internal::collate_argument::nocase);
+ res._collate_argument =
+ collate_constraint_t::string_from_collate_argument(sqlite_orm::internal::collate_argument::nocase);
return res;
}
self collate_rtrim() const {
auto res = *this;
res._collate_argument =
- constraints::collate_t::string_from_collate_argument(sqlite_orm::internal::collate_argument::rtrim);
+ collate_constraint_t::string_from_collate_argument(sqlite_orm::internal::collate_argument::rtrim);
return res;
}
@@ -2327,6 +2943,15 @@ namespace sqlite_orm {
res._collate_argument = std::move(name);
return res;
}
+
+ template<class C>
+ self collate() const {
+ std::stringstream ss;
+ ss << C::name();
+ auto name = ss.str();
+ ss.flush();
+ return this->collate(move(name));
+ }
};
/**
@@ -2338,7 +2963,7 @@ namespace sqlite_orm {
args_type args;
- multi_order_by_t(args_type &&args_) : args(std::move(args_)) {}
+ multi_order_by_t(args_type&& args_) : args(std::move(args_)) {}
};
struct dynamic_order_by_entry_t : order_by_base {
@@ -2357,13 +2982,13 @@ namespace sqlite_orm {
using entry_t = dynamic_order_by_entry_t;
using const_iterator = typename std::vector<entry_t>::const_iterator;
- dynamic_order_by_t(const context_t &context_) : context(context_) {}
+ dynamic_order_by_t(const context_t& context_) : context(context_) {}
template<class O>
void push_back(order_by_t<O> order_by) {
auto newContext = this->context;
newContext.skip_table_name = true;
- auto columnName = serialize(order_by.o, newContext);
+ auto columnName = serialize(order_by.expression, newContext);
entries.emplace_back(move(columnName), order_by.asc_desc, move(order_by._collate_argument));
}
@@ -2410,7 +3035,7 @@ namespace sqlite_orm {
using args_type = std::tuple<Args...>;
args_type args;
- group_by_t(args_type &&args_) : args(std::move(args_)) {}
+ group_by_t(args_type&& args_) : args(std::move(args_)) {}
};
template<class T>
@@ -2452,7 +3077,7 @@ namespace sqlite_orm {
* LIKE operator object.
*/
template<class A, class T, class E>
- struct like_t : condition_t, like_string, internal::negatable_t {
+ struct like_t : condition_t, like_string, negatable_t {
using self = like_t<A, T, E>;
using arg_t = A;
using pattern_t = T;
@@ -2460,15 +3085,14 @@ namespace sqlite_orm {
arg_t arg;
pattern_t pattern;
- sqlite_orm::internal::optional_container<escape_t>
- arg3; // not escape cause escape exists as a function here
+ optional_container<escape_t> arg3; // not escape cause escape exists as a function here
- like_t(arg_t arg_, pattern_t pattern_, sqlite_orm::internal::optional_container<escape_t> escape_) :
+ like_t(arg_t arg_, pattern_t pattern_, optional_container<escape_t> escape_) :
arg(std::move(arg_)), pattern(std::move(pattern_)), arg3(std::move(escape_)) {}
template<class C>
like_t<A, T, C> escape(C c) const {
- sqlite_orm::internal::optional_container<C> newArg3{std::move(c)};
+ optional_container<C> newArg3{std::move(c)};
return {std::move(this->arg), std::move(this->pattern), std::move(newArg3)};
}
};
@@ -2699,6 +3323,26 @@ namespace sqlite_orm {
cast_t(expression_type expression_) : expression(std::move(expression_)) {}
};
+ template<class... Args>
+ struct from_t {
+ using tuple_type = std::tuple<Args...>;
+ };
+
+ template<class T>
+ struct is_from : std::false_type {};
+
+ template<class... Args>
+ struct is_from<from_t<Args...>> : std::true_type {};
+ }
+
+ /**
+ * Explicit FROM function. Usage:
+ * `storage.select(&User::id, from<User>());`
+ */
+ template<class... Args>
+ internal::from_t<Args...> from() {
+ static_assert(std::tuple_size<std::tuple<Args...>>::value > 0, "");
+ return {};
}
template<class T, typename = typename std::enable_if<std::is_base_of<internal::negatable_t, T>::value>::type>
@@ -2711,152 +3355,152 @@ namespace sqlite_orm {
*/
template<class T, class R>
internal::lesser_than_t<T, R> operator<(internal::expression_t<T> expr, R r) {
- return {std::move(expr.t), std::move(r)};
+ return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
internal::lesser_than_t<L, T> operator<(L l, internal::expression_t<T> expr) {
- return {std::move(l), std::move(expr.t)};
+ return {std::move(l), std::move(expr.value)};
}
template<class T, class R>
internal::lesser_or_equal_t<T, R> operator<=(internal::expression_t<T> expr, R r) {
- return {std::move(expr.t), std::move(r)};
+ return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
internal::lesser_or_equal_t<L, T> operator<=(L l, internal::expression_t<T> expr) {
- return {std::move(l), std::move(expr.t)};
+ return {std::move(l), std::move(expr.value)};
}
template<class T, class R>
internal::greater_than_t<T, R> operator>(internal::expression_t<T> expr, R r) {
- return {std::move(expr.t), std::move(r)};
+ return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
internal::greater_than_t<L, T> operator>(L l, internal::expression_t<T> expr) {
- return {std::move(l), std::move(expr.t)};
+ return {std::move(l), std::move(expr.value)};
}
template<class T, class R>
internal::greater_or_equal_t<T, R> operator>=(internal::expression_t<T> expr, R r) {
- return {std::move(expr.t), std::move(r)};
+ return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
internal::greater_or_equal_t<L, T> operator>=(L l, internal::expression_t<T> expr) {
- return {std::move(l), std::move(expr.t)};
+ return {std::move(l), std::move(expr.value)};
}
template<class T, class R>
internal::is_equal_t<T, R> operator==(internal::expression_t<T> expr, R r) {
- return {std::move(expr.t), std::move(r)};
+ return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
internal::is_equal_t<L, T> operator==(L l, internal::expression_t<T> expr) {
- return {std::move(l), std::move(expr.t)};
+ return {std::move(l), std::move(expr.value)};
}
template<class T, class R>
internal::is_not_equal_t<T, R> operator!=(internal::expression_t<T> expr, R r) {
- return {std::move(expr.t), std::move(r)};
+ return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
internal::is_not_equal_t<L, T> operator!=(L l, internal::expression_t<T> expr) {
- return {std::move(l), std::move(expr.t)};
+ return {std::move(l), std::move(expr.value)};
}
template<class T, class R>
internal::conc_t<T, R> operator||(internal::expression_t<T> expr, R r) {
- return {std::move(expr.t), std::move(r)};
+ return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
internal::conc_t<L, T> operator||(L l, internal::expression_t<T> expr) {
- return {std::move(l), std::move(expr.t)};
+ return {std::move(l), std::move(expr.value)};
}
template<class L, class R>
internal::conc_t<L, R> operator||(internal::expression_t<L> l, internal::expression_t<R> r) {
- return {std::move(l.t), std::move(r.t)};
+ return {std::move(l.value), std::move(r.value)};
}
template<class T, class R>
internal::add_t<T, R> operator+(internal::expression_t<T> expr, R r) {
- return {std::move(expr.t), std::move(r)};
+ return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
internal::add_t<L, T> operator+(L l, internal::expression_t<T> expr) {
- return {std::move(l), std::move(expr.t)};
+ return {std::move(l), std::move(expr.value)};
}
template<class L, class R>
internal::add_t<L, R> operator+(internal::expression_t<L> l, internal::expression_t<R> r) {
- return {std::move(l.t), std::move(r.t)};
+ return {std::move(l.value), std::move(r.value)};
}
template<class T, class R>
internal::sub_t<T, R> operator-(internal::expression_t<T> expr, R r) {
- return {std::move(expr.t), std::move(r)};
+ return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
internal::sub_t<L, T> operator-(L l, internal::expression_t<T> expr) {
- return {std::move(l), std::move(expr.t)};
+ return {std::move(l), std::move(expr.value)};
}
template<class L, class R>
internal::sub_t<L, R> operator-(internal::expression_t<L> l, internal::expression_t<R> r) {
- return {std::move(l.t), std::move(r.t)};
+ return {std::move(l.value), std::move(r.value)};
}
template<class T, class R>
internal::mul_t<T, R> operator*(internal::expression_t<T> expr, R r) {
- return {std::move(expr.t), std::move(r)};
+ return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
internal::mul_t<L, T> operator*(L l, internal::expression_t<T> expr) {
- return {std::move(l), std::move(expr.t)};
+ return {std::move(l), std::move(expr.value)};
}
template<class L, class R>
internal::mul_t<L, R> operator*(internal::expression_t<L> l, internal::expression_t<R> r) {
- return {std::move(l.t), std::move(r.t)};
+ return {std::move(l.value), std::move(r.value)};
}
template<class T, class R>
internal::div_t<T, R> operator/(internal::expression_t<T> expr, R r) {
- return {std::move(expr.t), std::move(r)};
+ return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
internal::div_t<L, T> operator/(L l, internal::expression_t<T> expr) {
- return {std::move(l), std::move(expr.t)};
+ return {std::move(l), std::move(expr.value)};
}
template<class L, class R>
internal::div_t<L, R> operator/(internal::expression_t<L> l, internal::expression_t<R> r) {
- return {std::move(l.t), std::move(r.t)};
+ return {std::move(l.value), std::move(r.value)};
}
template<class T, class R>
internal::mod_t<T, R> operator%(internal::expression_t<T> expr, R r) {
- return {std::move(expr.t), std::move(r)};
+ return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
internal::mod_t<L, T> operator%(L l, internal::expression_t<T> expr) {
- return {std::move(l), std::move(expr.t)};
+ return {std::move(l), std::move(expr.value)};
}
template<class L, class R>
internal::mod_t<L, R> operator%(internal::expression_t<L> l, internal::expression_t<R> r) {
- return {std::move(l.t), std::move(r.t)};
+ return {std::move(l.value), std::move(r.value)};
}
template<class F, class O>
@@ -2924,16 +3568,30 @@ namespace sqlite_orm {
class R,
typename = typename std::enable_if<std::is_base_of<internal::condition_t, L>::value ||
std::is_base_of<internal::condition_t, R>::value>::type>
- internal::and_condition_t<L, R> operator&&(L l, R r) {
- return {std::move(l), std::move(r)};
+ auto operator&&(L l, R r) {
+ using internal::get_from_expression;
+ return internal::make_and_condition(std::move(get_from_expression(l)), std::move(get_from_expression(r)));
+ }
+
+ template<class L, class R>
+ auto and_(L l, R r) {
+ using internal::get_from_expression;
+ return internal::make_and_condition(std::move(get_from_expression(l)), std::move(get_from_expression(r)));
}
template<class L,
class R,
typename = typename std::enable_if<std::is_base_of<internal::condition_t, L>::value ||
std::is_base_of<internal::condition_t, R>::value>::type>
- internal::or_condition_t<L, R> operator||(L l, R r) {
- return {std::move(l), std::move(r)};
+ auto operator||(L l, R r) {
+ using internal::get_from_expression;
+ return internal::make_or_condition(std::move(get_from_expression(l)), std::move(get_from_expression(r)));
+ }
+
+ template<class L, class R>
+ auto or_(L l, R r) {
+ using internal::get_from_expression;
+ return internal::make_or_condition(std::move(get_from_expression(l)), std::move(get_from_expression(r)));
}
template<class T>
@@ -2947,32 +3605,32 @@ namespace sqlite_orm {
}
template<class L, class E>
- internal::in_t<L, std::vector<E>> in(L l, std::vector<E> values) {
+ internal::dynamic_in_t<L, std::vector<E>> in(L l, std::vector<E> values) {
return {std::move(l), std::move(values), false};
}
template<class L, class E>
- internal::in_t<L, std::vector<E>> in(L l, std::initializer_list<E> values) {
+ internal::dynamic_in_t<L, std::vector<E>> in(L l, std::initializer_list<E> values) {
return {std::move(l), std::move(values), false};
}
template<class L, class A>
- internal::in_t<L, A> in(L l, A arg) {
+ internal::dynamic_in_t<L, A> in(L l, A arg) {
return {std::move(l), std::move(arg), false};
}
template<class L, class E>
- internal::in_t<L, std::vector<E>> not_in(L l, std::vector<E> values) {
+ internal::dynamic_in_t<L, std::vector<E>> not_in(L l, std::vector<E> values) {
return {std::move(l), std::move(values), true};
}
template<class L, class E>
- internal::in_t<L, std::vector<E>> not_in(L l, std::initializer_list<E> values) {
+ internal::dynamic_in_t<L, std::vector<E>> not_in(L l, std::initializer_list<E> values) {
return {std::move(l), std::move(values), true};
}
template<class L, class A>
- internal::in_t<L, A> not_in(L l, A arg) {
+ internal::dynamic_in_t<L, A> not_in(L l, A arg) {
return {std::move(l), std::move(arg), true};
}
@@ -3036,11 +3694,6 @@ namespace sqlite_orm {
return {std::move(l), std::move(r)};
}
- template<class C>
- internal::where_t<C> where(C c) {
- return {std::move(c)};
- }
-
/**
* ORDER BY column
* Example: storage.select(&User::name, order_by(&User::id))
@@ -3055,7 +3708,7 @@ namespace sqlite_orm {
* Example: storage.get_all<Singer>(multi_order_by(order_by(&Singer::name).asc(), order_by(&Singer::gender).desc())
*/
template<class... Args>
- internal::multi_order_by_t<Args...> multi_order_by(Args &&... args) {
+ internal::multi_order_by_t<Args...> multi_order_by(Args&&... args) {
return {std::make_tuple(std::forward<Args>(args)...)};
}
@@ -3073,7 +3726,7 @@ namespace sqlite_orm {
*/
template<class S>
internal::dynamic_order_by_t<internal::serializator_context<typename S::impl_type>>
- dynamic_order_by(const S &storage) {
+ dynamic_order_by(const S& storage) {
internal::serializator_context_builder<S> builder(storage);
return builder();
}
@@ -3083,7 +3736,7 @@ namespace sqlite_orm {
* Example: storage.get_all<Employee>(group_by(&Employee::name))
*/
template<class... Args>
- internal::group_by_t<Args...> group_by(Args &&... args) {
+ internal::group_by_t<Args...> group_by(Args&&... args) {
return {std::make_tuple(std::forward<Args>(args)...)};
}
@@ -3195,7 +3848,7 @@ namespace sqlite_orm {
alias_column_t(){};
- alias_column_t(column_type column_) : column(column_) {}
+ alias_column_t(column_type column_) : column(std::move(column_)) {}
};
template<class T, class SFINAE = void>
@@ -3217,6 +3870,9 @@ namespace sqlite_orm {
}
};
+ /**
+ * Used to store alias for expression
+ */
template<class T, class E>
struct as_t {
using alias_type = T;
@@ -3314,19 +3970,13 @@ namespace sqlite_orm {
namespace internal {
template<class... Args>
- struct join_iterator {
-
- template<class L>
- void operator()(const L &) {
- //..
- }
- };
+ struct join_iterator;
template<>
struct join_iterator<> {
template<class L>
- void operator()(const L &) {
+ void operator()(const L&) const {
//..
}
};
@@ -3336,7 +3986,7 @@ namespace sqlite_orm {
using super = join_iterator<Tail...>;
template<class L>
- void operator()(const L &l) {
+ void operator()(const L& l) const {
this->super::operator()(l);
}
};
@@ -3347,7 +3997,7 @@ namespace sqlite_orm {
using join_type = cross_join_t<T>;
template<class L>
- void operator()(const L &l) {
+ void operator()(const L& l) const {
l(*this);
this->super::operator()(l);
}
@@ -3359,7 +4009,7 @@ namespace sqlite_orm {
using join_type = natural_join_t<T>;
template<class L>
- void operator()(const L &l) {
+ void operator()(const L& l) const {
l(*this);
this->super::operator()(l);
}
@@ -3371,7 +4021,7 @@ namespace sqlite_orm {
using join_type = left_join_t<T, O>;
template<class L>
- void operator()(const L &l) {
+ void operator()(const L& l) const {
l(*this);
this->super::operator()(l);
}
@@ -3383,7 +4033,7 @@ namespace sqlite_orm {
using join_type = join_t<T, O>;
template<class L>
- void operator()(const L &l) {
+ void operator()(const L& l) const {
l(*this);
this->super::operator()(l);
}
@@ -3395,7 +4045,7 @@ namespace sqlite_orm {
using join_type = left_outer_join_t<T, O>;
template<class L>
- void operator()(const L &l) {
+ void operator()(const L& l) const {
l(*this);
this->super::operator()(l);
}
@@ -3407,7 +4057,7 @@ namespace sqlite_orm {
using join_type = inner_join_t<T, O>;
template<class L>
- void operator()(const L &l) {
+ void operator()(const L& l) const {
l(*this);
this->super::operator()(l);
}
@@ -3442,11 +4092,11 @@ namespace sqlite_orm {
template<template<typename...> class Base, typename Derived>
struct is_base_of_template_impl {
template<typename... Ts>
- static constexpr std::true_type test(const Base<Ts...> *);
+ static constexpr std::true_type test(const Base<Ts...>*);
static constexpr std::false_type test(...);
- using type = decltype(test(std::declval<Derived *>()));
+ using type = decltype(test(std::declval<Derived*>()));
};
template<typename Derived, template<typename...> class Base>
@@ -3454,22 +4104,46 @@ namespace sqlite_orm {
#else
template<template<typename...> class C, typename... Ts>
- std::true_type is_base_of_template_impl(const C<Ts...> *);
+ std::true_type is_base_of_template_impl(const C<Ts...>*);
template<template<typename...> class C>
std::false_type is_base_of_template_impl(...);
template<typename T, template<typename...> class C>
- using is_base_of_template = decltype(is_base_of_template_impl<C>(std::declval<T *>()));
+ using is_base_of_template = decltype(is_base_of_template_impl<C>(std::declval<T*>()));
+#endif
+ }
+}
+
+// #include "serialize_result_type.h"
+
+#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED
+#include <string_view> // string_view
+#else
+#include <string> // std::string
+#endif
+
+namespace sqlite_orm {
+ namespace internal {
+#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED
+ using serialize_result_type = std::string_view;
+#else
+ using serialize_result_type = std::string;
#endif
}
}
namespace sqlite_orm {
+ using int64 = sqlite_int64;
+ using uint64 = sqlite_uint64;
+
namespace internal {
template<class T>
+ struct is_into;
+
+ template<class T>
struct unique_ptr_result_of {};
/**
@@ -3479,7 +4153,7 @@ namespace sqlite_orm {
* Args - function arguments types
*/
template<class R, class S, class... Args>
- struct core_function_t : S, internal::arithmetic_t {
+ struct built_in_function_t : S, arithmetic_t {
using return_type = R;
using string_type = S;
using args_type = std::tuple<Args...>;
@@ -3488,89 +4162,113 @@ namespace sqlite_orm {
args_type args;
- core_function_t(args_type &&args_) : args(std::move(args_)) {}
+ built_in_function_t(args_type&& args_) : args(std::move(args_)) {}
+ };
+
+ struct typeof_string {
+ serialize_result_type serialize() const {
+ return "TYPEOF";
+ }
+ };
+
+ struct unicode_string {
+ serialize_result_type serialize() const {
+ return "UNICODE";
+ }
};
struct length_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "LENGTH";
}
};
struct abs_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "ABS";
}
};
struct lower_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "LOWER";
}
};
struct upper_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "UPPER";
}
};
+ struct last_insert_rowid_string {
+ serialize_result_type serialize() const {
+ return "LAST_INSERT_ROWID";
+ }
+ };
+
+ struct total_changes_string {
+ serialize_result_type serialize() const {
+ return "TOTAL_CHANGES";
+ }
+ };
+
struct changes_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "CHANGES";
}
};
struct trim_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "TRIM";
}
};
struct ltrim_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "LTRIM";
}
};
struct rtrim_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "RTRIM";
}
};
struct hex_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "HEX";
}
};
struct quote_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "QUOTE";
}
};
struct randomblob_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "RANDOMBLOB";
}
};
struct instr_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "INSTR";
}
};
struct replace_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "REPLACE";
}
};
struct round_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "ROUND";
}
};
@@ -3578,13 +4276,13 @@ namespace sqlite_orm {
#if SQLITE_VERSION_NUMBER >= 3007016
struct char_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "CHAR";
}
};
struct random_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "RANDOM";
}
};
@@ -3592,73 +4290,79 @@ namespace sqlite_orm {
#endif
struct coalesce_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "COALESCE";
}
};
+ struct ifnull_string {
+ serialize_result_type serialize() const {
+ return "IFNULL";
+ }
+ };
+
struct date_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "DATE";
}
};
struct time_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "TIME";
}
};
struct datetime_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "DATETIME";
}
};
struct julianday_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "JULIANDAY";
}
};
struct strftime_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "STRFTIME";
}
};
struct zeroblob_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "ZEROBLOB";
}
};
struct substr_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "SUBSTR";
}
};
#ifdef SQLITE_SOUNDEX
struct soundex_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "SOUNDEX";
}
};
#endif
struct total_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "TOTAL";
}
};
struct sum_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "SUM";
}
};
struct count_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "COUNT";
}
};
@@ -3696,123 +4400,1254 @@ namespace sqlite_orm {
struct count_asterisk_without_type : count_string {};
struct avg_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "AVG";
}
};
struct max_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "MAX";
}
};
struct min_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "MIN";
}
};
struct group_concat_string {
- operator std::string() const {
+ serialize_result_type serialize() const {
return "GROUP_CONCAT";
}
};
+#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
+ struct acos_string {
+ serialize_result_type serialize() const {
+ return "ACOS";
+ }
+ };
+
+ struct acosh_string {
+ serialize_result_type serialize() const {
+ return "ACOSH";
+ }
+ };
+
+ struct asin_string {
+ serialize_result_type serialize() const {
+ return "ASIN";
+ }
+ };
+
+ struct asinh_string {
+ serialize_result_type serialize() const {
+ return "ASINH";
+ }
+ };
+
+ struct atan_string {
+ serialize_result_type serialize() const {
+ return "ATAN";
+ }
+ };
+
+ struct atan2_string {
+ serialize_result_type serialize() const {
+ return "ATAN2";
+ }
+ };
+
+ struct atanh_string {
+ serialize_result_type serialize() const {
+ return "ATANH";
+ }
+ };
+
+ struct ceil_string {
+ serialize_result_type serialize() const {
+ return "CEIL";
+ }
+ };
+ struct ceiling_string {
+ serialize_result_type serialize() const {
+ return "CEILING";
+ }
+ };
+
+ struct cos_string {
+ serialize_result_type serialize() const {
+ return "COS";
+ }
+ };
+
+ struct cosh_string {
+ serialize_result_type serialize() const {
+ return "COSH";
+ }
+ };
+
+ struct degrees_string {
+ serialize_result_type serialize() const {
+ return "DEGREES";
+ }
+ };
+
+ struct exp_string {
+ serialize_result_type serialize() const {
+ return "EXP";
+ }
+ };
+
+ struct floor_string {
+ serialize_result_type serialize() const {
+ return "FLOOR";
+ }
+ };
+
+ struct ln_string {
+ serialize_result_type serialize() const {
+ return "LN";
+ }
+ };
+
+ struct log_string {
+ serialize_result_type serialize() const {
+ return "LOG";
+ }
+ };
+
+ struct log10_string {
+ serialize_result_type serialize() const {
+ return "LOG10";
+ }
+ };
+
+ struct log2_string {
+ serialize_result_type serialize() const {
+ return "LOG2";
+ }
+ };
+
+ struct mod_string {
+ serialize_result_type serialize() const {
+ return "MOD";
+ }
+ };
+
+ struct pi_string {
+ serialize_result_type serialize() const {
+ return "PI";
+ }
+ };
+
+ struct pow_string {
+ serialize_result_type serialize() const {
+ return "POW";
+ }
+ };
+
+ struct power_string {
+ serialize_result_type serialize() const {
+ return "POWER";
+ }
+ };
+
+ struct radians_string {
+ serialize_result_type serialize() const {
+ return "RADIANS";
+ }
+ };
+
+ struct sin_string {
+ serialize_result_type serialize() const {
+ return "SIN";
+ }
+ };
+
+ struct sinh_string {
+ serialize_result_type serialize() const {
+ return "SINH";
+ }
+ };
+
+ struct sqrt_string {
+ serialize_result_type serialize() const {
+ return "SQRT";
+ }
+ };
+
+ struct tan_string {
+ serialize_result_type serialize() const {
+ return "TAN";
+ }
+ };
+
+ struct tanh_string {
+ serialize_result_type serialize() const {
+ return "TANH";
+ }
+ };
+
+ struct trunc_string {
+ serialize_result_type serialize() const {
+ return "TRUNC";
+ }
+ };
+
+#endif // SQLITE_ENABLE_MATH_FUNCTIONS
+#ifdef SQLITE_ENABLE_JSON1
+ struct json_string {
+ serialize_result_type serialize() const {
+ return "JSON";
+ }
+ };
+
+ struct json_array_string {
+ serialize_result_type serialize() const {
+ return "JSON_ARRAY";
+ }
+ };
+
+ struct json_array_length_string {
+ serialize_result_type serialize() const {
+ return "JSON_ARRAY_LENGTH";
+ }
+ };
+
+ struct json_extract_string {
+ serialize_result_type serialize() const {
+ return "JSON_EXTRACT";
+ }
+ };
+
+ struct json_insert_string {
+ serialize_result_type serialize() const {
+ return "JSON_INSERT";
+ }
+ };
+
+ struct json_replace_string {
+ serialize_result_type serialize() const {
+ return "JSON_REPLACE";
+ }
+ };
+
+ struct json_set_string {
+ serialize_result_type serialize() const {
+ return "JSON_SET";
+ }
+ };
+
+ struct json_object_string {
+ serialize_result_type serialize() const {
+ return "JSON_OBJECT";
+ }
+ };
+
+ struct json_patch_string {
+ serialize_result_type serialize() const {
+ return "JSON_PATCH";
+ }
+ };
+
+ struct json_remove_string {
+ serialize_result_type serialize() const {
+ return "JSON_REMOVE";
+ }
+ };
+
+ struct json_type_string {
+ serialize_result_type serialize() const {
+ return "JSON_TYPE";
+ }
+ };
+
+ struct json_valid_string {
+ serialize_result_type serialize() const {
+ return "JSON_VALID";
+ }
+ };
+
+ struct json_quote_string {
+ serialize_result_type serialize() const {
+ return "JSON_QUOTE";
+ }
+ };
+
+ struct json_group_array_string {
+ serialize_result_type serialize() const {
+ return "JSON_GROUP_ARRAY";
+ }
+ };
+
+ struct json_group_object_string {
+ serialize_result_type serialize() const {
+ return "JSON_GROUP_OBJECT";
+ }
+ };
+#endif // SQLITE_ENABLE_JSON1
}
/**
* Cute operators for core functions
*/
-
- template<
- class F,
- class R,
- typename = typename std::enable_if<internal::is_base_of_template<F, internal::core_function_t>::value>::type>
+ template<class F,
+ class R,
+ typename =
+ typename std::enable_if<internal::is_base_of_template<F, internal::built_in_function_t>::value>::type>
internal::lesser_than_t<F, R> operator<(F f, R r) {
return {std::move(f), std::move(r)};
}
- template<
- class F,
- class R,
- typename = typename std::enable_if<internal::is_base_of_template<F, internal::core_function_t>::value>::type>
+ template<class F,
+ class R,
+ typename =
+ typename std::enable_if<internal::is_base_of_template<F, internal::built_in_function_t>::value>::type>
internal::lesser_or_equal_t<F, R> operator<=(F f, R r) {
return {std::move(f), std::move(r)};
}
- template<
- class F,
- class R,
- typename = typename std::enable_if<internal::is_base_of_template<F, internal::core_function_t>::value>::type>
+ template<class F,
+ class R,
+ typename =
+ typename std::enable_if<internal::is_base_of_template<F, internal::built_in_function_t>::value>::type>
internal::greater_than_t<F, R> operator>(F f, R r) {
return {std::move(f), std::move(r)};
}
- template<
- class F,
- class R,
- typename = typename std::enable_if<internal::is_base_of_template<F, internal::core_function_t>::value>::type>
+ template<class F,
+ class R,
+ typename =
+ typename std::enable_if<internal::is_base_of_template<F, internal::built_in_function_t>::value>::type>
internal::greater_or_equal_t<F, R> operator>=(F f, R r) {
return {std::move(f), std::move(r)};
}
- template<
- class F,
- class R,
- typename = typename std::enable_if<internal::is_base_of_template<F, internal::core_function_t>::value>::type>
+ template<class F,
+ class R,
+ typename =
+ typename std::enable_if<internal::is_base_of_template<F, internal::built_in_function_t>::value>::type>
internal::is_equal_t<F, R> operator==(F f, R r) {
return {std::move(f), std::move(r)};
}
- template<
- class F,
- class R,
- typename = typename std::enable_if<internal::is_base_of_template<F, internal::core_function_t>::value>::type>
+ template<class F,
+ class R,
+ typename =
+ typename std::enable_if<internal::is_base_of_template<F, internal::built_in_function_t>::value>::type>
internal::is_not_equal_t<F, R> operator!=(F f, R r) {
return {std::move(f), std::move(r)};
}
+#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
+
+ /**
+ * ACOS(X) function https://www.sqlite.org/lang_mathfunc.html#acos
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::acos(&Triangle::cornerA)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::acos_string, X> acos(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * ACOS(X) function https://www.sqlite.org/lang_mathfunc.html#acos
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::acos<std::optional<double>>(&Triangle::cornerA)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::acos_string, X> acos(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * ACOSH(X) function https://www.sqlite.org/lang_mathfunc.html#acosh
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::acosh(&Triangle::cornerA)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::acosh_string, X> acosh(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * ACOSH(X) function https://www.sqlite.org/lang_mathfunc.html#acosh
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::acosh<std::optional<double>>(&Triangle::cornerA)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::acosh_string, X> acosh(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * ASIN(X) function https://www.sqlite.org/lang_mathfunc.html#asin
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::asin(&Triangle::cornerA)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::asin_string, X> asin(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * ASIN(X) function https://www.sqlite.org/lang_mathfunc.html#asin
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::asin<std::optional<double>>(&Triangle::cornerA)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::asin_string, X> asin(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * ASINH(X) function https://www.sqlite.org/lang_mathfunc.html#asinh
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::asinh(&Triangle::cornerA)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::asinh_string, X> asinh(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * ASINH(X) function https://www.sqlite.org/lang_mathfunc.html#asinh
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::asinh<std::optional<double>>(&Triangle::cornerA)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::asinh_string, X> asinh(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * ATAN(X) function https://www.sqlite.org/lang_mathfunc.html#atan
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::atan(1)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::atan_string, X> atan(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * ATAN(X) function https://www.sqlite.org/lang_mathfunc.html#atan
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::atan<std::optional<double>>(1)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::atan_string, X> atan(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * ATAN2(X, Y) function https://www.sqlite.org/lang_mathfunc.html#atan2
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::atan2(1, 3)); // decltype(rows) is std::vector<double>
+ */
+ template<class X, class Y>
+ internal::built_in_function_t<double, internal::atan2_string, X, Y> atan2(X x, Y y) {
+ return {std::tuple<X, Y>{std::forward<X>(x), std::forward<Y>(y)}};
+ }
+
+ /**
+ * ATAN2(X, Y) function https://www.sqlite.org/lang_mathfunc.html#atan2
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::atan2<std::optional<double>>(1, 3)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X, class Y>
+ internal::built_in_function_t<R, internal::atan2_string, X, Y> atan2(X x, Y y) {
+ return {std::tuple<X, Y>{std::forward<X>(x), std::forward<Y>(y)}};
+ }
+
+ /**
+ * ATANH(X) function https://www.sqlite.org/lang_mathfunc.html#atanh
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::atanh(1)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::atanh_string, X> atanh(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * ATANH(X) function https://www.sqlite.org/lang_mathfunc.html#atanh
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::atanh<std::optional<double>>(1)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::atanh_string, X> atanh(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * CEIL(X) function https://www.sqlite.org/lang_mathfunc.html#ceil
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::ceil(&User::rating)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::ceil_string, X> ceil(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * CEIL(X) function https://www.sqlite.org/lang_mathfunc.html#ceil
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::ceil<std::optional<double>>(&User::rating)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::ceil_string, X> ceil(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * CEILING(X) function https://www.sqlite.org/lang_mathfunc.html#ceil
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::ceiling(&User::rating)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::ceiling_string, X> ceiling(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * CEILING(X) function https://www.sqlite.org/lang_mathfunc.html#ceil
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::ceiling<std::optional<double>>(&User::rating)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::ceiling_string, X> ceiling(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * COS(X) function https://www.sqlite.org/lang_mathfunc.html#cos
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::cos(&Triangle::cornerB)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::cos_string, X> cos(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * COS(X) function https://www.sqlite.org/lang_mathfunc.html#cos
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::cos<std::optional<double>>(&User::rating)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::cos_string, X> cos(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * COSH(X) function https://www.sqlite.org/lang_mathfunc.html#cosh
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::cosh(&Triangle::cornerB)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::cosh_string, X> cosh(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * COSH(X) function https://www.sqlite.org/lang_mathfunc.html#cosh
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::cosh<std::optional<double>>(&User::rating)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::cosh_string, X> cosh(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * DEGREES(X) function https://www.sqlite.org/lang_mathfunc.html#degrees
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::degrees(&Triangle::cornerB)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::degrees_string, X> degrees(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * DEGREES(X) function https://www.sqlite.org/lang_mathfunc.html#degrees
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::degrees<std::optional<double>>(&User::rating)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::degrees_string, X> degrees(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * EXP(X) function https://www.sqlite.org/lang_mathfunc.html#exp
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::exp(&Triangle::cornerB)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::exp_string, X> exp(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * EXP(X) function https://www.sqlite.org/lang_mathfunc.html#exp
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::exp<std::optional<double>>(&User::rating)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::exp_string, X> exp(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * FLOOR(X) function https://www.sqlite.org/lang_mathfunc.html#floor
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::floor(&User::rating)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::floor_string, X> floor(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * FLOOR(X) function https://www.sqlite.org/lang_mathfunc.html#floor
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::floor<std::optional<double>>(&User::rating)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::floor_string, X> floor(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * LN(X) function https://www.sqlite.org/lang_mathfunc.html#ln
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::ln(200)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::ln_string, X> ln(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * LN(X) function https://www.sqlite.org/lang_mathfunc.html#ln
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::ln<std::optional<double>>(200)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::ln_string, X> ln(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * LOG(X) function https://www.sqlite.org/lang_mathfunc.html#log
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::log(100)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::log_string, X> log(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * LOG(X) function https://www.sqlite.org/lang_mathfunc.html#log
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::log<std::optional<double>>(100)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::log_string, X> log(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * LOG10(X) function https://www.sqlite.org/lang_mathfunc.html#log
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::log10(100)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::log10_string, X> log10(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * LOG10(X) function https://www.sqlite.org/lang_mathfunc.html#log
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::log10<std::optional<double>>(100)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::log10_string, X> log10(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * LOG(B, X) function https://www.sqlite.org/lang_mathfunc.html#log
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::log(10, 100)); // decltype(rows) is std::vector<double>
+ */
+ template<class B, class X>
+ internal::built_in_function_t<double, internal::log_string, B, X> log(B b, X x) {
+ return {std::tuple<B, X>{std::forward<B>(b), std::forward<X>(x)}};
+ }
+
+ /**
+ * LOG(B, X) function https://www.sqlite.org/lang_mathfunc.html#log
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::log<std::optional<double>>(10, 100)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class B, class X>
+ internal::built_in_function_t<R, internal::log_string, B, X> log(B b, X x) {
+ return {std::tuple<B, X>{std::forward<B>(b), std::forward<X>(x)}};
+ }
+
+ /**
+ * LOG2(X) function https://www.sqlite.org/lang_mathfunc.html#log2
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::log2(64)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::log2_string, X> log2(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * LOG2(X) function https://www.sqlite.org/lang_mathfunc.html#log2
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::log2<std::optional<double>>(64)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::log2_string, X> log2(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * MOD(X, Y) function https://www.sqlite.org/lang_mathfunc.html#mod
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::mod_f(6, 5)); // decltype(rows) is std::vector<double>
+ */
+ template<class X, class Y>
+ internal::built_in_function_t<double, internal::mod_string, X, Y> mod_f(X x, Y y) {
+ return {std::tuple<X, Y>{std::forward<X>(x), std::forward<Y>(y)}};
+ }
+
+ /**
+ * MOD(X, Y) function https://www.sqlite.org/lang_mathfunc.html#mod
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::mod_f<std::optional<double>>(6, 5)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X, class Y>
+ internal::built_in_function_t<R, internal::mod_string, X, Y> mod_f(X x, Y y) {
+ return {std::tuple<X, Y>{std::forward<X>(x), std::forward<Y>(y)}};
+ }
+
+ /**
+ * PI() function https://www.sqlite.org/lang_mathfunc.html#pi
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::pi()); // decltype(rows) is std::vector<double>
+ */
+ inline internal::built_in_function_t<double, internal::pi_string> pi() {
+ return {{}};
+ }
+
+ /**
+ * PI() function https://www.sqlite.org/lang_mathfunc.html#pi
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, etc.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::pi<float>()); // decltype(rows) is std::vector<float>
+ */
+ template<class R>
+ internal::built_in_function_t<R, internal::pi_string> pi() {
+ return {{}};
+ }
+
+ /**
+ * POW(X, Y) function https://www.sqlite.org/lang_mathfunc.html#pow
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::pow(2, 5)); // decltype(rows) is std::vector<double>
+ */
+ template<class X, class Y>
+ internal::built_in_function_t<double, internal::pow_string, X, Y> pow(X x, Y y) {
+ return {std::tuple<X, Y>{std::forward<X>(x), std::forward<Y>(y)}};
+ }
+
+ /**
+ * POW(X, Y) function https://www.sqlite.org/lang_mathfunc.html#pow
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::pow<std::optional<double>>(2, 5)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X, class Y>
+ internal::built_in_function_t<R, internal::pow_string, X, Y> pow(X x, Y y) {
+ return {std::tuple<X, Y>{std::forward<X>(x), std::forward<Y>(y)}};
+ }
+
+ /**
+ * POWER(X, Y) function https://www.sqlite.org/lang_mathfunc.html#pow
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::power(2, 5)); // decltype(rows) is std::vector<double>
+ */
+ template<class X, class Y>
+ internal::built_in_function_t<double, internal::power_string, X, Y> power(X x, Y y) {
+ return {std::tuple<X, Y>{std::forward<X>(x), std::forward<Y>(y)}};
+ }
+
+ /**
+ * POWER(X, Y) function https://www.sqlite.org/lang_mathfunc.html#pow
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::power<std::optional<double>>(2, 5)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X, class Y>
+ internal::built_in_function_t<R, internal::power_string, X, Y> power(X x, Y y) {
+ return {std::tuple<X, Y>{std::forward<X>(x), std::forward<Y>(y)}};
+ }
+
+ /**
+ * RADIANS(X) function https://www.sqlite.org/lang_mathfunc.html#radians
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::radians(&Triangle::cornerAInDegrees)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::radians_string, X> radians(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * RADIANS(X) function https://www.sqlite.org/lang_mathfunc.html#radians
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::radians<std::optional<double>>(&Triangle::cornerAInDegrees)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::radians_string, X> radians(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * SIN(X) function https://www.sqlite.org/lang_mathfunc.html#sin
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::sin(&Triangle::cornerA)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::sin_string, X> sin(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * SIN(X) function https://www.sqlite.org/lang_mathfunc.html#sin
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::sin<std::optional<double>>(&Triangle::cornerA)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::sin_string, X> sin(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * SINH(X) function https://www.sqlite.org/lang_mathfunc.html#sinh
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::sinh(&Triangle::cornerA)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::sinh_string, X> sinh(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * SINH(X) function https://www.sqlite.org/lang_mathfunc.html#sinh
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::sinh<std::optional<double>>(&Triangle::cornerA)); // decltype(rows) is std::vector<std::optional<double>>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::sinh_string, X> sinh(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * SQRT(X) function https://www.sqlite.org/lang_mathfunc.html#sqrt
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::sqrt(25)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::sqrt_string, X> sqrt(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * SQRT(X) function https://www.sqlite.org/lang_mathfunc.html#sqrt
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::sqrt<int>(25)); // decltype(rows) is std::vector<int>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::sqrt_string, X> sqrt(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * TAN(X) function https://www.sqlite.org/lang_mathfunc.html#tan
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::tan(&Triangle::cornerC)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::tan_string, X> tan(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * TAN(X) function https://www.sqlite.org/lang_mathfunc.html#tan
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::tan<float>(&Triangle::cornerC)); // decltype(rows) is std::vector<float>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::tan_string, X> tan(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * TANH(X) function https://www.sqlite.org/lang_mathfunc.html#tanh
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::tanh(&Triangle::cornerC)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::tanh_string, X> tanh(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * TANH(X) function https://www.sqlite.org/lang_mathfunc.html#tanh
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::tanh<float>(&Triangle::cornerC)); // decltype(rows) is std::vector<float>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::tanh_string, X> tanh(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * TRUNC(X) function https://www.sqlite.org/lang_mathfunc.html#trunc
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::trunc(5.5)); // decltype(rows) is std::vector<double>
+ */
+ template<class X>
+ internal::built_in_function_t<double, internal::trunc_string, X> trunc(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ /**
+ * TRUNC(X) function https://www.sqlite.org/lang_mathfunc.html#trunc
+ *
+ * Difference with the previous function is that previous override has `double` as return type but this
+ * override accepts return type from you as a template argument. You can use any bindable type:
+ * `float`, `int`, `std::optional<double>` etc. This override is handy when you expect `null` as result.
+ *
+ * Example:
+ *
+ * auto rows = storage.select(sqlite_orm::trunc<float>(5.5)); // decltype(rows) is std::vector<float>
+ */
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::trunc_string, X> trunc(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+#endif // SQLITE_ENABLE_MATH_FUNCTIONS
+ /**
+ * TYPEOF(x) function https://sqlite.org/lang_corefunc.html#typeof
+ */
+ template<class T>
+ internal::built_in_function_t<std::string, internal::typeof_string, T> typeof_(T t) {
+ return {std::tuple<T>{std::forward<T>(t)}};
+ }
+
+ /**
+ * UNICODE(x) function https://sqlite.org/lang_corefunc.html#unicode
+ */
+ template<class T>
+ internal::built_in_function_t<int, internal::unicode_string, T> unicode(T t) {
+ return {std::tuple<T>{std::forward<T>(t)}};
+ }
/**
* LENGTH(x) function https://sqlite.org/lang_corefunc.html#length
*/
template<class T>
- internal::core_function_t<int, internal::length_string, T> length(T t) {
- std::tuple<T> args{std::forward<T>(t)};
- return {move(args)};
+ internal::built_in_function_t<int, internal::length_string, T> length(T t) {
+ return {std::tuple<T>{std::forward<T>(t)}};
}
/**
* ABS(x) function https://sqlite.org/lang_corefunc.html#abs
*/
template<class T>
- internal::core_function_t<std::unique_ptr<double>, internal::abs_string, T> abs(T t) {
- std::tuple<T> args{std::forward<T>(t)};
- return {move(args)};
+ internal::built_in_function_t<std::unique_ptr<double>, internal::abs_string, T> abs(T t) {
+ return {std::tuple<T>{std::forward<T>(t)}};
}
/**
* LOWER(x) function https://sqlite.org/lang_corefunc.html#lower
*/
template<class T>
- internal::core_function_t<std::string, internal::lower_string, T> lower(T t) {
- std::tuple<T> args{std::forward<T>(t)};
- return {move(args)};
+ internal::built_in_function_t<std::string, internal::lower_string, T> lower(T t) {
+ return {std::tuple<T>{std::forward<T>(t)}};
}
/**
* UPPER(x) function https://sqlite.org/lang_corefunc.html#upper
*/
template<class T>
- internal::core_function_t<std::string, internal::upper_string, T> upper(T t) {
- std::tuple<T> args{std::forward<T>(t)};
- return {move(args)};
+ internal::built_in_function_t<std::string, internal::upper_string, T> upper(T t) {
+ return {std::tuple<T>{std::forward<T>(t)}};
+ }
+
+ /**
+ * LAST_INSERT_ROWID(x) function https://www.sqlite.org/lang_corefunc.html#last_insert_rowid
+ */
+ inline internal::built_in_function_t<int64, internal::last_insert_rowid_string> last_insert_rowid() {
+ return {{}};
+ }
+
+ /**
+ * TOTAL_CHANGES() function https://sqlite.org/lang_corefunc.html#total_changes
+ */
+ inline internal::built_in_function_t<int, internal::total_changes_string> total_changes() {
+ return {{}};
}
/**
* CHANGES() function https://sqlite.org/lang_corefunc.html#changes
*/
- inline internal::core_function_t<int, internal::changes_string> changes() {
+ inline internal::built_in_function_t<int, internal::changes_string> changes() {
return {{}};
}
@@ -3820,117 +5655,106 @@ namespace sqlite_orm {
* TRIM(X) function https://sqlite.org/lang_corefunc.html#trim
*/
template<class T>
- internal::core_function_t<std::string, internal::trim_string, T> trim(T t) {
- std::tuple<T> args{std::forward<T>(t)};
- return {move(args)};
+ internal::built_in_function_t<std::string, internal::trim_string, T> trim(T t) {
+ return {std::tuple<T>{std::forward<T>(t)}};
}
/**
* TRIM(X,Y) function https://sqlite.org/lang_corefunc.html#trim
*/
template<class X, class Y>
- internal::core_function_t<std::string, internal::trim_string, X, Y> trim(X x, Y y) {
- std::tuple<X, Y> args{std::forward<X>(x), std::forward<Y>(y)};
- return {move(args)};
+ internal::built_in_function_t<std::string, internal::trim_string, X, Y> trim(X x, Y y) {
+ return {std::tuple<X, Y>{std::forward<X>(x), std::forward<Y>(y)}};
}
/**
* LTRIM(X) function https://sqlite.org/lang_corefunc.html#ltrim
*/
template<class X>
- internal::core_function_t<std::string, internal::ltrim_string, X> ltrim(X x) {
- std::tuple<X> args{std::forward<X>(x)};
- return {move(args)};
+ internal::built_in_function_t<std::string, internal::ltrim_string, X> ltrim(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
}
/**
* LTRIM(X,Y) function https://sqlite.org/lang_corefunc.html#ltrim
*/
template<class X, class Y>
- internal::core_function_t<std::string, internal::ltrim_string, X, Y> ltrim(X x, Y y) {
- std::tuple<X, Y> args{std::forward<X>(x), std::forward<Y>(y)};
- return {move(args)};
+ internal::built_in_function_t<std::string, internal::ltrim_string, X, Y> ltrim(X x, Y y) {
+ return {std::tuple<X, Y>{std::forward<X>(x), std::forward<Y>(y)}};
}
/**
* RTRIM(X) function https://sqlite.org/lang_corefunc.html#rtrim
*/
template<class X>
- internal::core_function_t<std::string, internal::rtrim_string, X> rtrim(X x) {
- std::tuple<X> args{std::forward<X>(x)};
- return {move(args)};
+ internal::built_in_function_t<std::string, internal::rtrim_string, X> rtrim(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
}
/**
* RTRIM(X,Y) function https://sqlite.org/lang_corefunc.html#rtrim
*/
template<class X, class Y>
- internal::core_function_t<std::string, internal::rtrim_string, X, Y> rtrim(X x, Y y) {
- std::tuple<X, Y> args{std::forward<X>(x), std::forward<Y>(y)};
- return {move(args)};
+ internal::built_in_function_t<std::string, internal::rtrim_string, X, Y> rtrim(X x, Y y) {
+ return {std::tuple<X, Y>{std::forward<X>(x), std::forward<Y>(y)}};
}
/**
* HEX(X) function https://sqlite.org/lang_corefunc.html#hex
*/
template<class X>
- internal::core_function_t<std::string, internal::hex_string, X> hex(X x) {
- std::tuple<X> args{std::forward<X>(x)};
- return {move(args)};
+ internal::built_in_function_t<std::string, internal::hex_string, X> hex(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
}
/**
* QUOTE(X) function https://sqlite.org/lang_corefunc.html#quote
*/
template<class X>
- internal::core_function_t<std::string, internal::quote_string, X> quote(X x) {
- std::tuple<X> args{std::forward<X>(x)};
- return {move(args)};
+ internal::built_in_function_t<std::string, internal::quote_string, X> quote(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
}
/**
* RANDOMBLOB(X) function https://sqlite.org/lang_corefunc.html#randomblob
*/
template<class X>
- internal::core_function_t<std::vector<char>, internal::randomblob_string, X> randomblob(X x) {
- std::tuple<X> args{std::forward<X>(x)};
- return {move(args)};
+ internal::built_in_function_t<std::vector<char>, internal::randomblob_string, X> randomblob(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
}
/**
* INSTR(X) function https://sqlite.org/lang_corefunc.html#instr
*/
template<class X, class Y>
- internal::core_function_t<int, internal::instr_string, X, Y> instr(X x, Y y) {
- std::tuple<X, Y> args{std::forward<X>(x), std::forward<Y>(y)};
- return {move(args)};
+ internal::built_in_function_t<int, internal::instr_string, X, Y> instr(X x, Y y) {
+ return {std::tuple<X, Y>{std::forward<X>(x), std::forward<Y>(y)}};
}
/**
* REPLACE(X) function https://sqlite.org/lang_corefunc.html#replace
*/
template<class X, class Y, class Z>
- internal::core_function_t<std::string, internal::replace_string, X, Y, Z> replace(X x, Y y, Z z) {
- std::tuple<X, Y, Z> args{std::forward<X>(x), std::forward<Y>(y), std::forward<Z>(z)};
- return {move(args)};
+ typename std::enable_if<internal::count_tuple<std::tuple<X, Y, Z>, internal::is_into>::value == 0,
+ internal::built_in_function_t<std::string, internal::replace_string, X, Y, Z>>::type
+ replace(X x, Y y, Z z) {
+ return {std::tuple<X, Y, Z>{std::forward<X>(x), std::forward<Y>(y), std::forward<Z>(z)}};
}
/**
* ROUND(X) function https://sqlite.org/lang_corefunc.html#round
*/
template<class X>
- internal::core_function_t<double, internal::round_string, X> round(X x) {
- std::tuple<X> args{std::forward<X>(x)};
- return {move(args)};
+ internal::built_in_function_t<double, internal::round_string, X> round(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
}
/**
* ROUND(X, Y) function https://sqlite.org/lang_corefunc.html#round
*/
template<class X, class Y>
- internal::core_function_t<double, internal::round_string, X, Y> round(X x, Y y) {
- std::tuple<X, Y> args{std::forward<X>(x), std::forward<Y>(y)};
- return {move(args)};
+ internal::built_in_function_t<double, internal::round_string, X, Y> round(X x, Y y) {
+ return {std::tuple<X, Y>{std::forward<X>(x), std::forward<Y>(y)}};
}
#if SQLITE_VERSION_NUMBER >= 3007016
@@ -3939,14 +5763,14 @@ namespace sqlite_orm {
* CHAR(X1,X2,...,XN) function https://sqlite.org/lang_corefunc.html#char
*/
template<class... Args>
- internal::core_function_t<std::string, internal::char_string, Args...> char_(Args... args) {
+ internal::built_in_function_t<std::string, internal::char_string, Args...> char_(Args... args) {
return {std::make_tuple(std::forward<Args>(args)...)};
}
/**
* RANDOM() function https://www.sqlite.org/lang_corefunc.html#random
*/
- inline internal::core_function_t<int, internal::random_string> random() {
+ inline internal::built_in_function_t<int, internal::random_string> random() {
return {{}};
}
@@ -3956,80 +5780,80 @@ namespace sqlite_orm {
* COALESCE(X,Y,...) function https://www.sqlite.org/lang_corefunc.html#coalesce
*/
template<class R, class... Args>
- internal::core_function_t<R, internal::coalesce_string, Args...> coalesce(Args... args) {
+ internal::built_in_function_t<R, internal::coalesce_string, Args...> coalesce(Args... args) {
return {std::make_tuple(std::forward<Args>(args)...)};
}
/**
+ * IFNULL(X,Y) function https://www.sqlite.org/lang_corefunc.html#ifnull
+ */
+ template<class R, class X, class Y>
+ internal::built_in_function_t<R, internal::ifnull_string, X, Y> ifnull(X x, Y y) {
+ return {std::make_tuple(std::move(x), std::move(y))};
+ }
+
+ /**
* DATE(timestring, modifier, modifier, ...) function https://www.sqlite.org/lang_datefunc.html
*/
template<class... Args>
- internal::core_function_t<std::string, internal::date_string, Args...> date(Args... args) {
- std::tuple<Args...> t{std::forward<Args>(args)...};
- return {move(t)};
+ internal::built_in_function_t<std::string, internal::date_string, Args...> date(Args... args) {
+ return {std::tuple<Args...>{std::forward<Args>(args)...}};
}
/**
* TIME(timestring, modifier, modifier, ...) function https://www.sqlite.org/lang_datefunc.html
*/
template<class... Args>
- internal::core_function_t<std::string, internal::time_string, Args...> time(Args... args) {
- std::tuple<Args...> t{std::forward<Args>(args)...};
- return {move(t)};
+ internal::built_in_function_t<std::string, internal::time_string, Args...> time(Args... args) {
+ return {std::tuple<Args...>{std::forward<Args>(args)...}};
}
/**
* DATETIME(timestring, modifier, modifier, ...) function https://www.sqlite.org/lang_datefunc.html
*/
template<class... Args>
- internal::core_function_t<std::string, internal::datetime_string, Args...> datetime(Args... args) {
- std::tuple<Args...> t{std::forward<Args>(args)...};
- return {move(t)};
+ internal::built_in_function_t<std::string, internal::datetime_string, Args...> datetime(Args... args) {
+ return {std::tuple<Args...>{std::forward<Args>(args)...}};
}
/**
* JULIANDAY(timestring, modifier, modifier, ...) function https://www.sqlite.org/lang_datefunc.html
*/
template<class... Args>
- internal::core_function_t<double, internal::julianday_string, Args...> julianday(Args... args) {
- std::tuple<Args...> t{std::forward<Args>(args)...};
- return {move(t)};
+ internal::built_in_function_t<double, internal::julianday_string, Args...> julianday(Args... args) {
+ return {std::tuple<Args...>{std::forward<Args>(args)...}};
}
/**
* STRFTIME(timestring, modifier, modifier, ...) function https://www.sqlite.org/lang_datefunc.html
*/
template<class... Args>
- internal::core_function_t<std::string, internal::strftime_string, Args...> strftime(Args... args) {
- std::tuple<Args...> t{std::forward<Args>(args)...};
- return {move(t)};
+ internal::built_in_function_t<std::string, internal::strftime_string, Args...> strftime(Args... args) {
+ return {std::tuple<Args...>{std::forward<Args>(args)...}};
}
/**
* ZEROBLOB(N) function https://www.sqlite.org/lang_corefunc.html#zeroblob
*/
template<class N>
- internal::core_function_t<std::vector<char>, internal::zeroblob_string, N> zeroblob(N n) {
- std::tuple<N> args{std::forward<N>(n)};
- return {move(args)};
+ internal::built_in_function_t<std::vector<char>, internal::zeroblob_string, N> zeroblob(N n) {
+ return {std::tuple<N>{std::forward<N>(n)}};
}
/**
* SUBSTR(X,Y) function https://www.sqlite.org/lang_corefunc.html#substr
*/
template<class X, class Y>
- internal::core_function_t<std::string, internal::substr_string, X, Y> substr(X x, Y y) {
- std::tuple<X, Y> args{std::forward<X>(x), std::forward<Y>(y)};
- return {move(args)};
+ internal::built_in_function_t<std::string, internal::substr_string, X, Y> substr(X x, Y y) {
+ return {std::tuple<X, Y>{std::forward<X>(x), std::forward<Y>(y)}};
}
/**
* SUBSTR(X,Y,Z) function https://www.sqlite.org/lang_corefunc.html#substr
*/
template<class X, class Y, class Z>
- internal::core_function_t<std::string, internal::substr_string, X, Y, Z> substr(X x, Y y, Z z) {
- std::tuple<X, Y, Z> args{std::forward<X>(x), std::forward<Y>(y), std::forward<Z>(z)};
- return {move(args)};
+ internal::built_in_function_t<std::string, internal::substr_string, X, Y, Z> substr(X x, Y y, Z z) {
+ return {std::tuple<X, Y, Z>{std::forward<X>(x), std::forward<Y>(y), std::forward<Z>(z)}};
}
#ifdef SQLITE_SOUNDEX
@@ -4038,8 +5862,7 @@ namespace sqlite_orm {
*/
template<class X>
internal::core_function_t<std::string, internal::soundex_string, X> soundex(X x) {
- std::tuple<X> args{std::forward<X>(x)};
- return {move(args)};
+ return {std::tuple<X>{std::forward<X>(x)}};
}
#endif
@@ -4047,27 +5870,24 @@ namespace sqlite_orm {
* TOTAL(X) aggregate function.
*/
template<class X>
- internal::core_function_t<double, internal::total_string, X> total(X x) {
- std::tuple<X> args{std::forward<X>(x)};
- return {move(args)};
+ internal::built_in_function_t<double, internal::total_string, X> total(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
}
/**
* SUM(X) aggregate function.
*/
template<class X>
- internal::core_function_t<std::unique_ptr<double>, internal::sum_string, X> sum(X x) {
- std::tuple<X> args{std::forward<X>(x)};
- return {move(args)};
+ internal::built_in_function_t<std::unique_ptr<double>, internal::sum_string, X> sum(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
}
/**
* COUNT(X) aggregate function.
*/
template<class X>
- internal::core_function_t<int, internal::count_string, X> count(X x) {
- std::tuple<X> args{std::forward<X>(x)};
- return {move(args)};
+ internal::built_in_function_t<int, internal::count_string, X> count(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
}
/**
@@ -4090,47 +5910,164 @@ namespace sqlite_orm {
* AVG(X) aggregate function.
*/
template<class X>
- internal::core_function_t<double, internal::avg_string, X> avg(X x) {
- std::tuple<X> args{std::forward<X>(x)};
- return {move(args)};
+ internal::built_in_function_t<double, internal::avg_string, X> avg(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
}
/**
* MAX(X) aggregate function.
*/
template<class X>
- internal::core_function_t<internal::unique_ptr_result_of<X>, internal::max_string, X> max(X x) {
- std::tuple<X> args{std::forward<X>(x)};
- return {move(args)};
+ internal::built_in_function_t<internal::unique_ptr_result_of<X>, internal::max_string, X> max(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
}
/**
* MIN(X) aggregate function.
*/
template<class X>
- internal::core_function_t<internal::unique_ptr_result_of<X>, internal::min_string, X> min(X x) {
- std::tuple<X> args{std::forward<X>(x)};
- return {move(args)};
+ internal::built_in_function_t<internal::unique_ptr_result_of<X>, internal::min_string, X> min(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
}
/**
* GROUP_CONCAT(X) aggregate function.
*/
template<class X>
- internal::core_function_t<std::string, internal::group_concat_string, X> group_concat(X x) {
- std::tuple<X> args{std::forward<X>(x)};
- return {move(args)};
+ internal::built_in_function_t<std::string, internal::group_concat_string, X> group_concat(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
}
/**
* GROUP_CONCAT(X, Y) aggregate function.
*/
template<class X, class Y>
- internal::core_function_t<std::string, internal::group_concat_string, X, Y> group_concat(X x, Y y) {
- std::tuple<X, Y> args{std::forward<X>(x), std::forward<Y>(y)};
- return {move(args)};
+ internal::built_in_function_t<std::string, internal::group_concat_string, X, Y> group_concat(X x, Y y) {
+ return {std::tuple<X, Y>{std::forward<X>(x), std::forward<Y>(y)}};
+ }
+#ifdef SQLITE_ENABLE_JSON1
+ template<class X>
+ internal::built_in_function_t<std::string, internal::json_string, X> json(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ template<class... Args>
+ internal::built_in_function_t<std::string, internal::json_array_string, Args...> json_array(Args... args) {
+ return {std::tuple<Args...>{std::forward<Args>(args)...}};
+ }
+
+ template<class X>
+ internal::built_in_function_t<int, internal::json_array_length_string, X> json_array_length(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::json_array_length_string, X> json_array_length(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ template<class X, class Y>
+ internal::built_in_function_t<int, internal::json_array_length_string, X, Y> json_array_length(X x, Y y) {
+ return {std::tuple<X, Y>{std::forward<X>(x), std::forward<Y>(y)}};
+ }
+
+ template<class R, class X, class Y>
+ internal::built_in_function_t<R, internal::json_array_length_string, X, Y> json_array_length(X x, Y y) {
+ return {std::tuple<X, Y>{std::forward<X>(x), std::forward<Y>(y)}};
+ }
+
+ template<class R, class X, class... Args>
+ internal::built_in_function_t<R, internal::json_extract_string, X, Args...> json_extract(X x, Args... args) {
+ return {std::tuple<X, Args...>{std::forward<X>(x), std::forward<Args>(args)...}};
+ }
+
+ template<class X, class... Args>
+ internal::built_in_function_t<std::string, internal::json_insert_string, X, Args...> json_insert(X x,
+ Args... args) {
+ static_assert(std::tuple_size<std::tuple<Args...>>::value % 2 == 0,
+ "number of arguments in json_insert must be odd");
+ return {std::tuple<X, Args...>{std::forward<X>(x), std::forward<Args>(args)...}};
+ }
+
+ template<class X, class... Args>
+ internal::built_in_function_t<std::string, internal::json_replace_string, X, Args...> json_replace(X x,
+ Args... args) {
+ static_assert(std::tuple_size<std::tuple<Args...>>::value % 2 == 0,
+ "number of arguments in json_replace must be odd");
+ return {std::tuple<X, Args...>{std::forward<X>(x), std::forward<Args>(args)...}};
+ }
+
+ template<class X, class... Args>
+ internal::built_in_function_t<std::string, internal::json_set_string, X, Args...> json_set(X x, Args... args) {
+ static_assert(std::tuple_size<std::tuple<Args...>>::value % 2 == 0,
+ "number of arguments in json_set must be odd");
+ return {std::tuple<X, Args...>{std::forward<X>(x), std::forward<Args>(args)...}};
+ }
+
+ template<class... Args>
+ internal::built_in_function_t<std::string, internal::json_object_string, Args...> json_object(Args... args) {
+ static_assert(std::tuple_size<std::tuple<Args...>>::value % 2 == 0,
+ "number of arguments in json_object must be even");
+ return {std::tuple<Args...>{std::forward<Args>(args)...}};
+ }
+
+ template<class X, class Y>
+ internal::built_in_function_t<std::string, internal::json_patch_string, X, Y> json_patch(X x, Y y) {
+ return {std::tuple<X, Y>{std::forward<X>(x), std::forward<Y>(y)}};
+ }
+
+ template<class X, class... Args>
+ internal::built_in_function_t<std::string, internal::json_remove_string, X, Args...> json_remove(X x,
+ Args... args) {
+ return {std::tuple<X, Args...>{std::forward<X>(x), std::forward<Args>(args)...}};
+ }
+
+ template<class R, class X, class... Args>
+ internal::built_in_function_t<R, internal::json_remove_string, X, Args...> json_remove(X x, Args... args) {
+ return {std::tuple<X, Args...>{std::forward<X>(x), std::forward<Args>(args)...}};
+ }
+
+ template<class X>
+ internal::built_in_function_t<std::string, internal::json_type_string, X> json_type(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::json_type_string, X> json_type(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ template<class X, class Y>
+ internal::built_in_function_t<std::string, internal::json_type_string, X, Y> json_type(X x, Y y) {
+ return {std::tuple<X, Y>{std::forward<X>(x), std::forward<Y>(y)}};
+ }
+
+ template<class R, class X, class Y>
+ internal::built_in_function_t<R, internal::json_type_string, X, Y> json_type(X x, Y y) {
+ return {std::tuple<X, Y>{std::forward<X>(x), std::forward<Y>(y)}};
+ }
+
+ template<class X>
+ internal::built_in_function_t<bool, internal::json_valid_string, X> json_valid(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ template<class R, class X>
+ internal::built_in_function_t<R, internal::json_quote_string, X> json_quote(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
+ }
+
+ template<class X>
+ internal::built_in_function_t<std::string, internal::json_group_array_string, X> json_group_array(X x) {
+ return {std::tuple<X>{std::forward<X>(x)}};
}
+ template<class X, class Y>
+ internal::built_in_function_t<std::string, internal::json_group_object_string, X, Y> json_group_object(X x, Y y) {
+ return {std::tuple<X, Y>{std::forward<X>(x), std::forward<Y>(y)}};
+ }
+
+#endif // SQLITE_ENABLE_JSON1
template<class L,
class R,
typename = typename std::enable_if<(std::is_base_of<internal::arithmetic_t, L>::value +
@@ -4187,20 +6124,20 @@ namespace sqlite_orm {
*/
template<class L, class R>
struct typed_comparator {
- bool operator()(const L &, const R &) const {
+ bool operator()(const L&, const R&) const {
return false;
}
};
template<class O>
struct typed_comparator<O, O> {
- bool operator()(const O &lhs, const O &rhs) const {
+ bool operator()(const O& lhs, const O& rhs) const {
return lhs == rhs;
}
};
template<class L, class R>
- bool compare_any(const L &lhs, const R &rhs) {
+ bool compare_any(const L& lhs, const R& rhs) {
return typed_comparator<L, R>()(lhs, rhs);
}
}
@@ -4210,41 +6147,127 @@ namespace sqlite_orm {
#include <string> // std::string
#include <utility> // std::declval
#include <tuple> // std::tuple, std::get, std::tuple_size
+#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
+#include <optional> // std::optional
+#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
// #include "is_base_of_template.h"
-// #include "tuple_helper.h"
+// #include "tuple_helper/tuple_helper.h"
// #include "optional_container.h"
+// #include "ast/where.h"
+
+// #include "../serialize_result_type.h"
+
+#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED
+#include <string_view> // string_view
+#else
+#include <string> // std::string
+#endif
+
namespace sqlite_orm {
+ namespace internal {
+#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED
+ using serialize_result_type = std::string_view;
+#else
+ using serialize_result_type = std::string;
+#endif
+ }
+}
+namespace sqlite_orm {
namespace internal {
+ struct where_string {
+ serialize_result_type serialize() const {
+ return "WHERE";
+ }
+ };
+
/**
- * DISCTINCT generic container.
+ * WHERE argument holder.
+ * C is expression type. Can be any expression like: is_equal_t, is_null_t, exists_t etc
+ * Don't construct it manually. Call `where(...)` function instead.
*/
+ template<class C>
+ struct where_t : where_string {
+ using expression_type = C;
+
+ expression_type expression;
+
+ where_t(expression_type expression_) : expression(std::move(expression_)) {}
+ };
+
template<class T>
- struct distinct_t {
- T t;
+ struct is_where : std::false_type {};
+
+ template<class T>
+ struct is_where<where_t<T>> : std::true_type {};
+ }
+
+ /**
+ * WHERE clause. Use it to add WHERE conditions wherever you like.
+ * C is expression type. Can be any expression like: is_equal_t, is_null_t, exists_t etc
+ * @example
+ * // SELECT name
+ * // FROM letters
+ * // WHERE id > 3
+ * auto rows = storage.select(&Letter::name, where(greater_than(&Letter::id, 3)));
+ */
+ template<class C>
+ internal::where_t<C> where(C expression) {
+ return {std::move(expression)};
+ }
+}
+
+namespace sqlite_orm {
+ namespace internal {
+#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
+ template<class T>
+ struct as_optional_t {
+ using value_type = T;
+
+ value_type value;
+ };
+#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
+
+ struct distinct_string {
operator std::string() const {
return "DISTINCT";
}
};
/**
- * ALL generic container.
+ * DISCTINCT generic container.
*/
template<class T>
- struct all_t {
- T t;
+ struct distinct_t : distinct_string {
+ using value_type = T;
+ value_type value;
+
+ distinct_t(value_type value_) : value(std::move(value_)) {}
+ };
+
+ struct all_string {
operator std::string() const {
return "ALL";
}
};
+ /**
+ * ALL generic container.
+ */
+ template<class T>
+ struct all_t : all_string {
+ T value;
+
+ all_t(T value_) : value(std::move(value_)) {}
+ };
+
template<class... Args>
struct columns_t {
using columns_type = std::tuple<Args...>;
@@ -4255,6 +6278,12 @@ namespace sqlite_orm {
static constexpr const int count = std::tuple_size<columns_type>::value;
};
+ template<class T>
+ struct is_columns : std::false_type {};
+
+ template<class... Args>
+ struct is_columns<columns_t<Args...>> : std::true_type {};
+
struct set_string {
operator std::string() const {
return "SET";
@@ -4276,10 +6305,41 @@ namespace sqlite_orm {
*/
template<class T, class F>
struct column_pointer {
+ using self = column_pointer<T, F>;
using type = T;
using field_type = F;
field_type field;
+
+ template<class R>
+ internal::is_equal_t<self, R> operator==(R rhs) const {
+ return {*this, std::move(rhs)};
+ }
+
+ template<class R>
+ internal::is_not_equal_t<self, R> operator!=(R rhs) const {
+ return {*this, std::move(rhs)};
+ }
+
+ template<class R>
+ internal::lesser_than_t<self, R> operator<(R rhs) const {
+ return {*this, std::move(rhs)};
+ }
+
+ template<class R>
+ internal::lesser_or_equal_t<self, R> operator<=(R rhs) const {
+ return {*this, std::move(rhs)};
+ }
+
+ template<class R>
+ internal::greater_than_t<self, R> operator>(R rhs) const {
+ return {*this, std::move(rhs)};
+ }
+
+ template<class R>
+ internal::greater_or_equal_t<self, R> operator>=(R rhs) const {
+ return {*this, std::move(rhs)};
+ }
};
/**
@@ -4295,6 +6355,12 @@ namespace sqlite_orm {
bool highest_level = false;
};
+ template<class T>
+ struct is_select : std::false_type {};
+
+ template<class T, class... Args>
+ struct is_select<select_t<T, Args...>> : std::true_type {};
+
/**
* Base for UNION, UNION ALL, EXCEPT and INTERSECT
*/
@@ -4338,48 +6404,51 @@ namespace sqlite_orm {
union_t(left_type l, right_type r) : union_t(std::move(l), std::move(r), false) {}
};
+ struct except_string {
+ operator std::string() const {
+ return "EXCEPT";
+ }
+ };
+
/**
* EXCEPT object type.
*/
template<class L, class R>
- struct except_t : public compound_operator<L, R> {
+ struct except_t : compound_operator<L, R>, except_string {
using super = compound_operator<L, R>;
using left_type = typename super::left_type;
using right_type = typename super::right_type;
using super::super;
+ };
+ struct intersect_string {
operator std::string() const {
- return "EXCEPT";
+ return "INTERSECT";
}
};
-
/**
* INTERSECT object type.
*/
template<class L, class R>
- struct intersect_t : public compound_operator<L, R> {
+ struct intersect_t : compound_operator<L, R>, intersect_string {
using super = compound_operator<L, R>;
using left_type = typename super::left_type;
using right_type = typename super::right_type;
using super::super;
-
- operator std::string() const {
- return "INTERSECT";
- }
};
/**
* Generic way to get DISTINCT value from any type.
*/
template<class T>
- bool get_distinct(const T &) {
+ bool get_distinct(const T&) {
return false;
}
template<class... Args>
- bool get_distinct(const columns_t<Args...> &cols) {
+ bool get_distinct(const columns_t<Args...>& cols) {
return cols.distinct;
}
@@ -4454,9 +6523,16 @@ namespace sqlite_orm {
static_assert(count_tuple<T, is_group_by>::value <= 1, "a single query cannot contain > 1 GROUP BY blocks");
static_assert(count_tuple<T, is_order_by>::value <= 1, "a single query cannot contain > 1 ORDER BY blocks");
static_assert(count_tuple<T, is_limit>::value <= 1, "a single query cannot contain > 1 LIMIT blocks");
+ static_assert(count_tuple<T, is_from>::value <= 1, "a single query cannot contain > 1 FROM blocks");
}
}
+#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
+ template<class T>
+ internal::as_optional_t<T> as_optional(T value) {
+ return {std::move(value)};
+ }
+#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
template<class T>
internal::then_t<T> then(T t) {
return {std::move(t)};
@@ -4587,48 +6663,6 @@ namespace sqlite_orm {
}
#pragma once
-#include <type_traits> // std::enable_if, std::is_member_pointer
-
-// #include "select_constraints.h"
-
-// #include "column.h"
-
-namespace sqlite_orm {
-
- namespace internal {
-
- /**
- * Trait class used to define table mapped type by setter/getter/member
- * T - member pointer
- */
- template<class T, class SFINAE = void>
- struct table_type;
-
- template<class O, class F>
- struct table_type<F O::*,
- typename std::enable_if<std::is_member_pointer<F O::*>::value &&
- !std::is_member_function_pointer<F O::*>::value>::type> {
- using type = O;
- };
-
- template<class T>
- struct table_type<T, typename std::enable_if<is_getter<T>::value>::type> {
- using type = typename getter_traits<T>::object_type;
- };
-
- template<class T>
- struct table_type<T, typename std::enable_if<is_setter<T>::value>::type> {
- using type = typename setter_traits<T>::object_type;
- };
-
- template<class T, class F>
- struct table_type<column_pointer<T, F>, void> {
- using type = T;
- };
- }
-}
-#pragma once
-
#include <string> // std::string
namespace sqlite_orm {
@@ -4640,27 +6674,32 @@ namespace sqlite_orm {
bool notnull = false;
std::string dflt_value;
int pk = 0;
+
+ table_info(decltype(cid) cid_,
+ decltype(name) name_,
+ decltype(type) type_,
+ decltype(notnull) notnull_,
+ decltype(dflt_value) dflt_value_,
+ decltype(pk) pk_) :
+ cid(cid_),
+ name(move(name_)), type(move(type_)), notnull(notnull_), dflt_value(move(dflt_value_)), pk(pk_) {}
};
}
#pragma once
+#include <memory> // std::unique_ptr
#include <sqlite3.h>
+#include <type_traits> // std::integral_constant
namespace sqlite_orm {
/**
* Guard class which finalizes `sqlite3_stmt` in dtor
*/
- struct statement_finalizer {
- sqlite3_stmt *stmt = nullptr;
+ using statement_finalizer =
+ std::unique_ptr<sqlite3_stmt, std::integral_constant<decltype(&sqlite3_finalize), sqlite3_finalize>>;
- statement_finalizer(decltype(stmt) stmt_) : stmt(stmt_) {}
-
- inline ~statement_finalizer() {
- sqlite3_finalize(this->stmt);
- }
- };
}
#pragma once
@@ -4697,6 +6736,7 @@ namespace sqlite_orm {
#include <cstddef> // std::nullptr_t
#include <utility> // std::declval
#include <locale> // std::wstring_convert
+#include <cstring> // ::strncpy, ::strlen
// #include "is_std_ptr.h"
@@ -4712,7 +6752,7 @@ namespace sqlite_orm {
struct is_std_ptr<std::shared_ptr<T>> : std::true_type {
using element_type = T;
- static std::shared_ptr<T> make(const T &v) {
+ static std::shared_ptr<T> make(const T& v) {
return std::make_shared<T>(v);
}
};
@@ -4721,7 +6761,7 @@ namespace sqlite_orm {
struct is_std_ptr<std::unique_ptr<T>> : std::true_type {
using element_type = T;
- static std::unique_ptr<T> make(const T &v) {
+ static std::unique_ptr<T> make(const T& v) {
return std::make_unique<T>(v);
}
};
@@ -4740,24 +6780,41 @@ namespace sqlite_orm {
*/
template<class V>
struct statement_binder<V, std::enable_if_t<std::is_arithmetic<V>::value>> {
- int bind(sqlite3_stmt *stmt, int index, const V &value) {
- return bind(stmt, index, value, tag());
+
+ int bind(sqlite3_stmt* stmt, int index, const V& value) const {
+ return this->bind(stmt, index, value, tag());
+ }
+
+ void result(sqlite3_context* context, const V& value) const {
+ this->result(context, value, tag());
}
private:
using tag = arithmetic_tag_t<V>;
- int bind(sqlite3_stmt *stmt, int index, const V &value, const int_or_smaller_tag &) {
+ int bind(sqlite3_stmt* stmt, int index, const V& value, const int_or_smaller_tag&) const {
return sqlite3_bind_int(stmt, index, static_cast<int>(value));
}
- int bind(sqlite3_stmt *stmt, int index, const V &value, const bigint_tag &) {
+ void result(sqlite3_context* context, const V& value, const int_or_smaller_tag&) const {
+ sqlite3_result_int(context, static_cast<int>(value));
+ }
+
+ int bind(sqlite3_stmt* stmt, int index, const V& value, const bigint_tag&) const {
return sqlite3_bind_int64(stmt, index, static_cast<sqlite3_int64>(value));
}
- int bind(sqlite3_stmt *stmt, int index, const V &value, const real_tag &) {
+ void result(sqlite3_context* context, const V& value, const bigint_tag&) const {
+ sqlite3_result_int64(context, static_cast<sqlite3_int64>(value));
+ }
+
+ int bind(sqlite3_stmt* stmt, int index, const V& value, const real_tag&) const {
return sqlite3_bind_double(stmt, index, static_cast<double>(value));
}
+
+ void result(sqlite3_context* context, const V& value, const real_tag&) const {
+ sqlite3_result_double(context, static_cast<double>(value));
+ }
};
/**
@@ -4766,18 +6823,33 @@ namespace sqlite_orm {
template<class V>
struct statement_binder<
V,
- std::enable_if_t<std::is_same<V, std::string>::value || std::is_same<V, const char *>::value>> {
- int bind(sqlite3_stmt *stmt, int index, const V &value) {
- return sqlite3_bind_text(stmt, index, string_data(value), -1, SQLITE_TRANSIENT);
+ std::enable_if_t<std::is_same<V, std::string>::value || std::is_same<V, const char*>::value>> {
+
+ int bind(sqlite3_stmt* stmt, int index, const V& value) const {
+ auto stringData = this->string_data(value);
+ return sqlite3_bind_text(stmt, index, std::get<0>(stringData), std::get<1>(stringData), SQLITE_TRANSIENT);
+ }
+
+ void result(sqlite3_context* context, const V& value) const {
+ auto stringData = this->string_data(value);
+ auto stringDataLength = std::get<1>(stringData);
+ auto dataCopy = new char[stringDataLength + 1];
+ auto stringChars = std::get<0>(stringData);
+ ::strncpy(dataCopy, stringChars, stringDataLength + 1);
+ sqlite3_result_text(context, dataCopy, stringDataLength, [](void* pointer) {
+ auto charPointer = (char*)pointer;
+ delete[] charPointer;
+ });
}
private:
- const char *string_data(const std::string &s) const {
- return s.c_str();
+ std::tuple<const char*, int> string_data(const std::string& s) const {
+ return {s.c_str(), int(s.size())};
}
- const char *string_data(const char *s) const {
- return s;
+ std::tuple<const char*, int> string_data(const char* s) const {
+ auto length = int(::strlen(s));
+ return {s, length};
}
};
@@ -4788,12 +6860,17 @@ namespace sqlite_orm {
template<class V>
struct statement_binder<
V,
- std::enable_if_t<std::is_same<V, std::wstring>::value || std::is_same<V, const wchar_t *>::value>> {
- int bind(sqlite3_stmt *stmt, int index, const V &value) {
+ std::enable_if_t<std::is_same<V, std::wstring>::value || std::is_same<V, const wchar_t*>::value>> {
+
+ int bind(sqlite3_stmt* stmt, int index, const V& value) const {
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::string utf8Str = converter.to_bytes(value);
return statement_binder<decltype(utf8Str)>().bind(stmt, index, utf8Str);
}
+
+ void result(sqlite3_context* context, const V& value) const {
+ sqlite3_result_text16(context, (const void*)value.data(), int(value.length()), nullptr);
+ }
};
#endif // SQLITE_ORM_OMITS_CODECVT
@@ -4802,17 +6879,28 @@ namespace sqlite_orm {
*/
template<>
struct statement_binder<std::nullptr_t, void> {
- int bind(sqlite3_stmt *stmt, int index, const std::nullptr_t &) {
+ int bind(sqlite3_stmt* stmt, int index, const std::nullptr_t&) const {
return sqlite3_bind_null(stmt, index);
}
+
+ void result(sqlite3_context* context, const std::nullptr_t&) const {
+ sqlite3_result_null(context);
+ }
};
#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
+ /**
+ * Specialization for std::nullopt_t.
+ */
template<>
struct statement_binder<std::nullopt_t, void> {
- int bind(sqlite3_stmt *stmt, int index, const std::nullopt_t &) {
+ int bind(sqlite3_stmt* stmt, int index, const std::nullopt_t&) const {
return sqlite3_bind_null(stmt, index);
}
+
+ void result(sqlite3_context* context, const std::nullopt_t&) const {
+ sqlite3_result_null(context);
+ }
};
#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
@@ -4820,13 +6908,21 @@ namespace sqlite_orm {
struct statement_binder<V, std::enable_if_t<is_std_ptr<V>::value>> {
using value_type = typename is_std_ptr<V>::element_type;
- int bind(sqlite3_stmt *stmt, int index, const V &value) {
+ int bind(sqlite3_stmt* stmt, int index, const V& value) const {
if(value) {
return statement_binder<value_type>().bind(stmt, index, *value);
} else {
return statement_binder<std::nullptr_t>().bind(stmt, index, nullptr);
}
}
+
+ void result(sqlite3_context* context, const V& value) const {
+ if(value) {
+ statement_binder<value_type>().result(context, value);
+ } else {
+ statement_binder<std::nullptr_t>().result(context, nullptr);
+ }
+ }
};
/**
@@ -4834,17 +6930,21 @@ namespace sqlite_orm {
*/
template<>
struct statement_binder<std::vector<char>, void> {
- int bind(sqlite3_stmt *stmt, int index, const std::vector<char> &value) {
+ int bind(sqlite3_stmt* stmt, int index, const std::vector<char>& value) const {
if(value.size()) {
- return sqlite3_bind_blob(stmt,
- index,
- (const void *)&value.front(),
- int(value.size()),
- SQLITE_TRANSIENT);
+ return sqlite3_bind_blob(stmt, index, (const void*)&value.front(), int(value.size()), SQLITE_TRANSIENT);
} else {
return sqlite3_bind_blob(stmt, index, "", 0, SQLITE_TRANSIENT);
}
}
+
+ void result(sqlite3_context* context, const std::vector<char>& value) const {
+ if(value.size()) {
+ sqlite3_result_blob(context, (const void*)&value.front(), int(value.size()), nullptr);
+ } else {
+ sqlite3_result_blob(context, "", 0, nullptr);
+ }
+ }
};
#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
@@ -4852,13 +6952,21 @@ namespace sqlite_orm {
struct statement_binder<std::optional<T>, void> {
using value_type = T;
- int bind(sqlite3_stmt *stmt, int index, const std::optional<T> &value) {
+ int bind(sqlite3_stmt* stmt, int index, const std::optional<T>& value) const {
if(value) {
return statement_binder<value_type>().bind(stmt, index, *value);
} else {
return statement_binder<std::nullopt_t>().bind(stmt, index, std::nullopt);
}
}
+
+ void result(sqlite3_context* context, const std::optional<T>& value) const {
+ if(value) {
+ statement_binder<value_type>().result(context, value);
+ } else {
+ statement_binder<std::nullopt_t>().result(context, std::nullopt);
+ }
+ }
};
#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
@@ -4868,8 +6976,8 @@ namespace sqlite_orm {
using is_bindable = std::integral_constant<bool, !std::is_base_of<std::false_type, statement_binder<T>>::value>;
struct conditional_binder_base {
- sqlite3_stmt *stmt = nullptr;
- int &index;
+ sqlite3_stmt* stmt = nullptr;
+ int& index;
conditional_binder_base(decltype(stmt) stmt_, decltype(index) index_) : stmt(stmt_), index(index_) {}
};
@@ -4882,7 +6990,7 @@ namespace sqlite_orm {
using conditional_binder_base::conditional_binder_base;
- int operator()(const T &t) const {
+ int operator()(const T& t) const {
return statement_binder<T>().bind(this->stmt, this->index++, t);
}
};
@@ -4891,24 +6999,35 @@ namespace sqlite_orm {
struct conditional_binder<T, std::false_type> : conditional_binder_base {
using conditional_binder_base::conditional_binder_base;
- int operator()(const T &) const {
+ int operator()(const T&) const {
return SQLITE_OK;
}
};
- template<class T, class SFINAE = void>
- struct bindable_filter_single;
+ template<class T, template<class C> class F, class SFINAE = void>
+ struct tuple_filter_single;
- template<class T>
- struct bindable_filter_single<T, typename std::enable_if<is_bindable<T>::value>::type> {
+ template<class T, template<class C> class F>
+ struct tuple_filter_single<T, F, typename std::enable_if<F<T>::value>::type> {
using type = std::tuple<T>;
};
- template<class T>
- struct bindable_filter_single<T, typename std::enable_if<!is_bindable<T>::value>::type> {
+ template<class T, template<class C> class F>
+ struct tuple_filter_single<T, F, typename std::enable_if<!F<T>::value>::type> {
using type = std::tuple<>;
};
+ template<class T, template<class C> class F>
+ struct tuple_filter;
+
+ template<class... Args, template<class C> class F>
+ struct tuple_filter<std::tuple<Args...>, F> {
+ using type = typename conc_tuple<typename tuple_filter_single<Args, F>::type...>::type;
+ };
+
+ template<class T>
+ struct bindable_filter_single : tuple_filter_single<T, is_bindable> {};
+
template<class T>
struct bindable_filter;
@@ -4922,7 +7041,7 @@ namespace sqlite_orm {
#include <sqlite3.h>
#include <type_traits> // std::enable_if_t, std::is_arithmetic, std::is_same, std::enable_if
-#include <cstdlib> // atof, atoi, atoll
+#include <stdlib.h> // atof, atoi, atoll
#include <string> // std::string, std::wstring
#ifndef SQLITE_ORM_OMITS_CODECVT
#include <codecvt> // std::wstring_convert, std::codecvt_utf8_utf16
@@ -4962,7 +7081,7 @@ namespace sqlite_orm {
namespace internal {
- inline const std::string &to_string(journal_mode j) {
+ inline const std::string& to_string(journal_mode j) {
static std::string res[] = {
"DELETE",
"TRUNCATE",
@@ -4974,7 +7093,7 @@ namespace sqlite_orm {
return res[static_cast<int>(j)];
}
- inline std::unique_ptr<journal_mode> journal_mode_from_string(const std::string &str) {
+ inline std::unique_ptr<journal_mode> journal_mode_from_string(const std::string& str) {
std::string upper_str;
std::transform(str.begin(), str.end(), std::back_inserter(upper_str), [](char c) {
return static_cast<char>(std::toupper(static_cast<int>(c)));
@@ -5009,10 +7128,13 @@ namespace sqlite_orm {
template<class V, typename Enable = void>
struct row_extractor {
// used in sqlite3_exec (select)
- V extract(const char *row_value);
+ V extract(const char* row_value) const;
// used in sqlite_column (iteration, get_all)
- V extract(sqlite3_stmt *stmt, int columnIndex);
+ V extract(sqlite3_stmt* stmt, int columnIndex) const;
+
+ // used in user defined functions
+ V extract(sqlite3_value* value) const;
};
/**
@@ -5020,40 +7142,56 @@ namespace sqlite_orm {
*/
template<class V>
struct row_extractor<V, std::enable_if_t<std::is_arithmetic<V>::value>> {
- V extract(const char *row_value) {
- return extract(row_value, tag());
+ V extract(const char* row_value) const {
+ return this->extract(row_value, tag());
}
- V extract(sqlite3_stmt *stmt, int columnIndex) {
- return extract(stmt, columnIndex, tag());
+ V extract(sqlite3_stmt* stmt, int columnIndex) const {
+ return this->extract(stmt, columnIndex, tag());
+ }
+
+ V extract(sqlite3_value* value) const {
+ return this->extract(value, tag());
}
private:
using tag = arithmetic_tag_t<V>;
- V extract(const char *row_value, const int_or_smaller_tag &) {
+ V extract(const char* row_value, const int_or_smaller_tag&) const {
return static_cast<V>(atoi(row_value));
}
- V extract(sqlite3_stmt *stmt, int columnIndex, const int_or_smaller_tag &) {
+ V extract(sqlite3_stmt* stmt, int columnIndex, const int_or_smaller_tag&) const {
return static_cast<V>(sqlite3_column_int(stmt, columnIndex));
}
- V extract(const char *row_value, const bigint_tag &) {
+ V extract(sqlite3_value* value, const int_or_smaller_tag&) const {
+ return static_cast<V>(sqlite3_value_int(value));
+ }
+
+ V extract(const char* row_value, const bigint_tag&) const {
return static_cast<V>(atoll(row_value));
}
- V extract(sqlite3_stmt *stmt, int columnIndex, const bigint_tag &) {
+ V extract(sqlite3_stmt* stmt, int columnIndex, const bigint_tag&) const {
return static_cast<V>(sqlite3_column_int64(stmt, columnIndex));
}
- V extract(const char *row_value, const real_tag &) {
+ V extract(sqlite3_value* value, const bigint_tag&) const {
+ return static_cast<V>(sqlite3_value_int64(value));
+ }
+
+ V extract(const char* row_value, const real_tag&) const {
return static_cast<V>(atof(row_value));
}
- V extract(sqlite3_stmt *stmt, int columnIndex, const real_tag &) {
+ V extract(sqlite3_stmt* stmt, int columnIndex, const real_tag&) const {
return static_cast<V>(sqlite3_column_double(stmt, columnIndex));
}
+
+ V extract(sqlite3_value* value, const real_tag&) const {
+ return static_cast<V>(sqlite3_value_double(value));
+ }
};
/**
@@ -5061,7 +7199,7 @@ namespace sqlite_orm {
*/
template<>
struct row_extractor<std::string, void> {
- std::string extract(const char *row_value) {
+ std::string extract(const char* row_value) const {
if(row_value) {
return row_value;
} else {
@@ -5069,9 +7207,16 @@ namespace sqlite_orm {
}
}
- std::string extract(sqlite3_stmt *stmt, int columnIndex) {
- auto cStr = (const char *)sqlite3_column_text(stmt, columnIndex);
- if(cStr) {
+ std::string extract(sqlite3_stmt* stmt, int columnIndex) const {
+ if(auto cStr = (const char*)sqlite3_column_text(stmt, columnIndex)) {
+ return cStr;
+ } else {
+ return {};
+ }
+ }
+
+ std::string extract(sqlite3_value* value) const {
+ if(auto cStr = (const char*)sqlite3_value_text(value)) {
return cStr;
} else {
return {};
@@ -5084,7 +7229,7 @@ namespace sqlite_orm {
*/
template<>
struct row_extractor<std::wstring, void> {
- std::wstring extract(const char *row_value) {
+ std::wstring extract(const char* row_value) const {
if(row_value) {
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
return converter.from_bytes(row_value);
@@ -5093,8 +7238,8 @@ namespace sqlite_orm {
}
}
- std::wstring extract(sqlite3_stmt *stmt, int columnIndex) {
- auto cStr = (const char *)sqlite3_column_text(stmt, columnIndex);
+ std::wstring extract(sqlite3_stmt* stmt, int columnIndex) const {
+ auto cStr = (const char*)sqlite3_column_text(stmt, columnIndex);
if(cStr) {
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
return converter.from_bytes(cStr);
@@ -5102,6 +7247,14 @@ namespace sqlite_orm {
return {};
}
}
+
+ std::wstring extract(sqlite3_value* value) const {
+ if(auto cStr = (const wchar_t*)sqlite3_value_text16(value)) {
+ return cStr;
+ } else {
+ return {};
+ }
+ }
};
#endif // SQLITE_ORM_OMITS_CODECVT
@@ -5109,7 +7262,7 @@ namespace sqlite_orm {
struct row_extractor<V, std::enable_if_t<is_std_ptr<V>::value>> {
using value_type = typename is_std_ptr<V>::element_type;
- V extract(const char *row_value) {
+ V extract(const char* row_value) const {
if(row_value) {
return is_std_ptr<V>::make(row_extractor<value_type>().extract(row_value));
} else {
@@ -5117,7 +7270,7 @@ namespace sqlite_orm {
}
}
- V extract(sqlite3_stmt *stmt, int columnIndex) {
+ V extract(sqlite3_stmt* stmt, int columnIndex) const {
auto type = sqlite3_column_type(stmt, columnIndex);
if(type != SQLITE_NULL) {
return is_std_ptr<V>::make(row_extractor<value_type>().extract(stmt, columnIndex));
@@ -5125,6 +7278,15 @@ namespace sqlite_orm {
return {};
}
}
+
+ V extract(sqlite3_value* value) const {
+ auto type = sqlite3_value_type(value);
+ if(type != SQLITE_NULL) {
+ return is_std_ptr<V>::make(row_extractor<value_type>().extract(value));
+ } else {
+ return {};
+ }
+ }
};
#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
@@ -5132,7 +7294,7 @@ namespace sqlite_orm {
struct row_extractor<std::optional<T>, void> {
using value_type = T;
- std::optional<T> extract(const char *row_value) {
+ std::optional<T> extract(const char* row_value) const {
if(row_value) {
return std::make_optional(row_extractor<value_type>().extract(row_value));
} else {
@@ -5140,7 +7302,7 @@ namespace sqlite_orm {
}
}
- std::optional<T> extract(sqlite3_stmt *stmt, int columnIndex) {
+ std::optional<T> extract(sqlite3_stmt* stmt, int columnIndex) const {
auto type = sqlite3_column_type(stmt, columnIndex);
if(type != SQLITE_NULL) {
return std::make_optional(row_extractor<value_type>().extract(stmt, columnIndex));
@@ -5148,6 +7310,15 @@ namespace sqlite_orm {
return std::nullopt;
}
}
+
+ std::optional<T> extract(sqlite3_value* value) const {
+ auto type = sqlite3_value_type(value);
+ if(type != SQLITE_NULL) {
+ return std::make_optional(row_extractor<value_type>().extract(value));
+ } else {
+ return std::nullopt;
+ }
+ }
};
#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
/**
@@ -5155,7 +7326,7 @@ namespace sqlite_orm {
*/
template<>
struct row_extractor<std::vector<char>> {
- std::vector<char> extract(const char *row_value) {
+ std::vector<char> extract(const char* row_value) const {
if(row_value) {
auto len = ::strlen(row_value);
return this->go(row_value, len);
@@ -5164,14 +7335,20 @@ namespace sqlite_orm {
}
}
- std::vector<char> extract(sqlite3_stmt *stmt, int columnIndex) {
- auto bytes = static_cast<const char *>(sqlite3_column_blob(stmt, columnIndex));
+ std::vector<char> extract(sqlite3_stmt* stmt, int columnIndex) const {
+ auto bytes = static_cast<const char*>(sqlite3_column_blob(stmt, columnIndex));
auto len = static_cast<size_t>(sqlite3_column_bytes(stmt, columnIndex));
return this->go(bytes, len);
}
+ std::vector<char> extract(sqlite3_value* value) const {
+ auto bytes = static_cast<const char*>(sqlite3_value_blob(value));
+ auto len = static_cast<size_t>(sqlite3_value_bytes(value));
+ return this->go(bytes, len);
+ }
+
protected:
- std::vector<char> go(const char *bytes, size_t len) {
+ std::vector<char> go(const char* bytes, size_t len) const {
if(len) {
std::vector<char> res;
res.reserve(len);
@@ -5186,40 +7363,40 @@ namespace sqlite_orm {
template<class... Args>
struct row_extractor<std::tuple<Args...>> {
- std::tuple<Args...> extract(char **argv) {
+ std::tuple<Args...> extract(char** argv) const {
std::tuple<Args...> res;
this->extract<std::tuple_size<decltype(res)>::value>(res, argv);
return res;
}
- std::tuple<Args...> extract(sqlite3_stmt *stmt, int /*columnIndex*/) {
+ std::tuple<Args...> extract(sqlite3_stmt* stmt, int /*columnIndex*/) const {
std::tuple<Args...> res;
this->extract<std::tuple_size<decltype(res)>::value>(res, stmt);
return res;
}
protected:
- template<size_t I, typename std::enable_if<I != 0>::type * = nullptr>
- void extract(std::tuple<Args...> &t, sqlite3_stmt *stmt) {
+ template<size_t I, typename std::enable_if<I != 0>::type* = nullptr>
+ void extract(std::tuple<Args...>& t, sqlite3_stmt* stmt) const {
using tuple_type = typename std::tuple_element<I - 1, typename std::tuple<Args...>>::type;
std::get<I - 1>(t) = row_extractor<tuple_type>().extract(stmt, I - 1);
this->extract<I - 1>(t, stmt);
}
- template<size_t I, typename std::enable_if<I == 0>::type * = nullptr>
- void extract(std::tuple<Args...> &, sqlite3_stmt *) {
+ template<size_t I, typename std::enable_if<I == 0>::type* = nullptr>
+ void extract(std::tuple<Args...>&, sqlite3_stmt*) const {
//..
}
- template<size_t I, typename std::enable_if<I != 0>::type * = nullptr>
- void extract(std::tuple<Args...> &t, char **argv) {
+ template<size_t I, typename std::enable_if<I != 0>::type* = nullptr>
+ void extract(std::tuple<Args...>& t, char** argv) const {
using tuple_type = typename std::tuple_element<I - 1, typename std::tuple<Args...>>::type;
std::get<I - 1>(t) = row_extractor<tuple_type>().extract(argv[I - 1]);
this->extract<I - 1>(t, argv);
}
- template<size_t I, typename std::enable_if<I == 0>::type * = nullptr>
- void extract(std::tuple<Args...> &, char **) {
+ template<size_t I, typename std::enable_if<I == 0>::type* = nullptr>
+ void extract(std::tuple<Args...>&, char**) const {
//..
}
};
@@ -5229,7 +7406,7 @@ namespace sqlite_orm {
*/
template<>
struct row_extractor<journal_mode, void> {
- journal_mode extract(const char *row_value) {
+ journal_mode extract(const char* row_value) const {
if(row_value) {
if(auto res = internal::journal_mode_from_string(row_value)) {
return std::move(*res);
@@ -5241,14 +7418,58 @@ namespace sqlite_orm {
}
}
- journal_mode extract(sqlite3_stmt *stmt, int columnIndex) {
- auto cStr = (const char *)sqlite3_column_text(stmt, columnIndex);
+ journal_mode extract(sqlite3_stmt* stmt, int columnIndex) const {
+ auto cStr = (const char*)sqlite3_column_text(stmt, columnIndex);
return this->extract(cStr);
}
};
}
#pragma once
+#include <sqlite3.h>
+#include <string> // std::string
+#include <system_error> // std::system_error, std::error_code
+
+namespace sqlite_orm {
+
+ namespace internal {
+ inline void perform_step(sqlite3* db, sqlite3_stmt* stmt) {
+ auto rc = sqlite3_step(stmt);
+ if(rc == SQLITE_DONE) {
+ // done..
+ } else {
+ throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
+ sqlite3_errmsg(db));
+ }
+ }
+
+ static void perform_void_exec(sqlite3* db, const std::string& query) {
+ int rc = sqlite3_exec(db, query.c_str(), nullptr, nullptr, nullptr);
+ if(rc != SQLITE_OK) {
+ throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
+ sqlite3_errmsg(db));
+ }
+ }
+
+ template<class T>
+ inline auto call_insert_impl_and_catch_constraint_failed(const T& insert_impl) {
+ try {
+ return insert_impl();
+ } catch(const std::system_error& e) {
+ if(e.code() == std::error_code(SQLITE_CONSTRAINT, get_sqlite_error_category())) {
+ std::stringstream ss;
+ ss << "Attempting to execute 'insert' request resulted in an error like \"" << e.what()
+ << "\". Perhaps ordinary 'insert' is not acceptable for this table and you should try "
+ "'replace' or 'insert' with explicit column listing?";
+ throw std::system_error(e.code(), ss.str());
+ }
+ throw;
+ }
+ }
+ }
+}
+#pragma once
+
#include <ostream>
namespace sqlite_orm {
@@ -5290,7 +7511,7 @@ namespace sqlite_orm {
dropped_and_recreated,
};
- inline std::ostream &operator<<(std::ostream &os, sync_schema_result value) {
+ inline std::ostream& operator<<(std::ostream& os, sync_schema_result value) {
switch(value) {
case sync_schema_result::new_table_created:
return os << "new table created";
@@ -5326,6 +7547,9 @@ namespace sqlite_orm {
struct indexed_column_t {
using column_type = C;
+ indexed_column_t(column_type _column_or_expression) :
+ column_or_expression(std::move(_column_or_expression)) {}
+
column_type column_or_expression;
std::string _collation_name;
int _order = 0; // -1 = desc, 1 = asc, 0 = not specified
@@ -5395,26 +7619,26 @@ namespace sqlite_orm {
bool unique = false;
};
- template<class... Cols>
+ template<class... Els>
struct index_t : index_base {
- using columns_type = std::tuple<Cols...>;
+ using elements_type = std::tuple<Els...>;
using object_type = void;
- index_t(std::string name_, bool unique_, columns_type columns_) :
- index_base{move(name_), unique_}, columns(move(columns_)) {}
+ index_t(std::string name_, bool unique_, elements_type elements_) :
+ index_base{move(name_), unique_}, elements(move(elements_)) {}
- columns_type columns;
+ elements_type elements;
};
}
template<class... Cols>
- internal::index_t<typename internal::indexed_column_maker<Cols>::type...> make_index(const std::string &name,
+ internal::index_t<typename internal::indexed_column_maker<Cols>::type...> make_index(const std::string& name,
Cols... cols) {
return {name, false, std::make_tuple(internal::make_indexed_column(cols)...)};
}
template<class... Cols>
- internal::index_t<typename internal::indexed_column_maker<Cols>::type...> make_unique_index(const std::string &name,
+ internal::index_t<typename internal::indexed_column_maker<Cols>::type...> make_unique_index(const std::string& name,
Cols... cols) {
return {name, true, std::make_tuple(internal::make_indexed_column(cols)...)};
}
@@ -5540,9 +7764,12 @@ namespace sqlite_orm {
template<class... Ts>
struct storage_impl;
- template<class T, class... Args>
+ template<class T, bool WithoutRowId, class... Cs>
struct table_t;
+ template<class A, class B>
+ struct foreign_key_t;
+
namespace storage_traits {
/**
@@ -5604,7 +7831,7 @@ namespace sqlite_orm {
S,
T,
typename std::enable_if<std::is_same<T, typename S::table_type::object_type>::value>::type>
- : std::integral_constant<int, S::table_type::columns_count> {};
+ : std::integral_constant<int, S::table_type::elements_count> {};
template<class S, class T>
struct storage_columns_count_impl<
@@ -5622,9 +7849,12 @@ namespace sqlite_orm {
/**
* type is std::tuple of field types of mapped colums.
*/
- template<class T, class... Args>
- struct table_types<table_t<T, Args...>> {
- using type = std::tuple<typename Args::field_type...>;
+ template<class T, bool WithoutRowId, class... Args>
+ struct table_types<table_t<T, WithoutRowId, Args...>> {
+ using args_tuple = std::tuple<Args...>;
+ using columns_tuple = typename tuple_filter<args_tuple, is_column>::type;
+
+ using type = typename tuple_transformer<columns_tuple, column_field_type>::type;
};
/**
@@ -5665,14 +7895,428 @@ namespace sqlite_orm {
typename std::enable_if<!std::is_same<T, typename S::table_type::object_type>::value>::type>
: storage_mapped_columns_impl<typename S::super, T> {};
+ /**
+ * C is any column type: column_t or constraint type
+ * O - object type references in FOREIGN KEY
+ */
+ template<class C, class O>
+ struct column_foreign_keys_count : std::integral_constant<int, 0> {};
+
+ template<class A, class B, class O>
+ struct column_foreign_keys_count<foreign_key_t<A, B>, O> {
+ using target_type = typename foreign_key_t<A, B>::target_type;
+
+ static constexpr const int value = std::is_same<O, target_type>::value ? 1 : 0;
+ };
+
+ /**
+ * O - object type references in FOREIGN KEY
+ * Cs - column types which are stored in table_t::columns_type
+ */
+ template<class O, class... Cs>
+ struct table_foreign_keys_count_impl;
+
+ template<class O>
+ struct table_foreign_keys_count_impl<O> {
+ static constexpr const int value = 0;
+ };
+
+ template<class O, class H, class... Tail>
+ struct table_foreign_keys_count_impl<O, H, Tail...> {
+ static constexpr const int value =
+ column_foreign_keys_count<H, O>::value + table_foreign_keys_count_impl<O, Tail...>::value;
+ };
+
+ /**
+ * T is table_t type
+ * O is object type which is the reference target (e.g. foreign_key(&Visit::userId).references(&User::id) has O = User)
+ */
+ template<class T, class O>
+ struct table_foreign_keys_count;
+
+ template<class T, class... Cs, class O>
+ struct table_foreign_keys_count<table_t<T, false, Cs...>, O> {
+ using table_type = table_t<T, false, Cs...>;
+
+ static constexpr const int value = table_foreign_keys_count_impl<O, Cs...>::value;
+ };
+
+ /**
+ * S - storage class
+ * O - type mapped to S
+ */
+ template<class S, class O>
+ struct storage_foreign_keys_count_impl;
+
+ template<class O>
+ struct storage_foreign_keys_count_impl<storage_impl<>, O> : std::integral_constant<int, 0> {};
+
+ template<class H, class... Ts, class O>
+ struct storage_foreign_keys_count_impl<storage_impl<H, Ts...>, O> {
+ static constexpr const int value = table_foreign_keys_count<H, O>::value +
+ storage_foreign_keys_count_impl<storage_impl<Ts...>, O>::value;
+ };
+
+ /**
+ * S - storage class
+ * O - type mapped to S
+ * This class tells how many types mapped to S have foreign keys to O
+ */
+ template<class S, class O>
+ struct storage_foreign_keys_count {
+ using impl_type = typename S::impl_type;
+
+ static constexpr const int value = storage_foreign_keys_count_impl<impl_type, O>::value;
+ };
+
+ /**
+ * C is any table element type: column_t or constraint type
+ * O - object type references in FOREIGN KEY
+ */
+ template<class C, class O, class SFINAE = void>
+ struct column_fk_references {
+ using type = std::tuple<>;
+ };
+
+ template<class C, class O, class SFINAE = void>
+ struct column_foreign_keys {
+ using type = std::tuple<>;
+ };
+
+ template<class A, class B, class O>
+ struct column_foreign_keys<
+ foreign_key_t<A, B>,
+ O,
+ typename std::enable_if<std::is_same<O, typename foreign_key_t<A, B>::target_type>::value>::type> {
+ using type = std::tuple<foreign_key_t<A, B>>;
+ };
+
+ template<class A, class B, class O>
+ struct column_foreign_keys<
+ foreign_key_t<A, B>,
+ O,
+ typename std::enable_if<!std::is_same<O, typename foreign_key_t<A, B>::target_type>::value>::type> {
+ using type = std::tuple<>;
+ };
+
+ template<class A, class B, class O>
+ struct column_fk_references<
+ foreign_key_t<A, B>,
+ O,
+ typename std::enable_if<std::is_same<O, typename foreign_key_t<A, B>::target_type>::value>::type> {
+ using target_type = typename foreign_key_t<A, B>::source_type;
+
+ using type = std::tuple<target_type>;
+ };
+
+ template<class A, class B, class O>
+ struct column_fk_references<
+ foreign_key_t<A, B>,
+ O,
+ typename std::enable_if<!std::is_same<O, typename foreign_key_t<A, B>::target_type>::value>::type> {
+ using type = std::tuple<>;
+ };
+
+ /**
+ * O - object type references in FOREIGN KEY
+ * Cs - column types which are stored in table_t::columns_type
+ */
+ template<class O, class... Cs>
+ struct table_fk_references_impl;
+
+ template<class O, class... Cs>
+ struct table_foreign_keys_impl;
+
+ template<class O>
+ struct table_fk_references_impl<O> {
+ using type = std::tuple<>;
+ };
+
+ template<class O>
+ struct table_foreign_keys_impl<O> {
+ using type = std::tuple<>;
+ };
+
+ template<class O, class H, class... Tail>
+ struct table_fk_references_impl<O, H, Tail...> {
+ using head_tuple = typename column_fk_references<H, O>::type;
+ using tail_tuple = typename table_fk_references_impl<O, Tail...>::type;
+ using type = typename conc_tuple<head_tuple, tail_tuple>::type;
+ };
+
+ template<class O, class H, class... Tail>
+ struct table_foreign_keys_impl<O, H, Tail...> {
+ using head_tuple = typename column_foreign_keys<H, O>::type;
+ using tail_tuple = typename table_foreign_keys_impl<O, Tail...>::type;
+ using type = typename conc_tuple<head_tuple, tail_tuple>::type;
+ };
+
+ /**
+ * T is table_t type
+ * O is object type which is the reference target (e.g. foreign_key(&Visit::userId).references(&User::id) has O = User)
+ */
+ template<class T, class O>
+ struct table_fk_references;
+
+ template<class T, class O>
+ struct table_foreign_keys;
+
+ template<class T, bool WithoutRowId, class... Cs, class O>
+ struct table_fk_references<table_t<T, WithoutRowId, Cs...>, O> {
+ using table_type = table_t<T, WithoutRowId, Cs...>;
+
+ using type = typename table_fk_references_impl<O, Cs...>::type;
+ };
+
+ template<class T, bool WithoutRowId, class... Cs, class O>
+ struct table_foreign_keys<table_t<T, WithoutRowId, Cs...>, O> {
+ using table_type = table_t<T, WithoutRowId, Cs...>;
+
+ using type = typename table_foreign_keys_impl<O, Cs...>::type;
+ };
+
+ /**
+ * S - storage class
+ * O - type mapped to S
+ */
+ template<class S, class O>
+ struct storage_fk_references_impl;
+
+ template<class S, class O>
+ struct storage_foreign_keys_impl;
+
+ template<class O>
+ struct storage_fk_references_impl<storage_impl<>, O> {
+ using type = std::tuple<>;
+ };
+
+ template<class O>
+ struct storage_foreign_keys_impl<storage_impl<>, O> {
+ using type = std::tuple<>;
+ };
+
+ template<class H, class... Ts, class O>
+ struct storage_fk_references_impl<storage_impl<H, Ts...>, O> {
+ using head_tuple = typename table_fk_references<H, O>::type;
+ using tail_tuple = typename storage_fk_references_impl<storage_impl<Ts...>, O>::type;
+ using type = typename conc_tuple<head_tuple, tail_tuple>::type;
+ };
+
+ template<class H, class... Ts, class O>
+ struct storage_foreign_keys_impl<storage_impl<H, Ts...>, O> {
+ using head_tuple = typename table_foreign_keys<H, O>::type;
+ using tail_tuple = typename storage_foreign_keys_impl<storage_impl<Ts...>, O>::type;
+ using type = typename conc_tuple<head_tuple, tail_tuple>::type;
+ };
+
+ /**
+ * S - storage class
+ * O - type mapped to S
+ * type holds `std::tuple` with types that has references to O as foreign keys
+ */
+ template<class S, class O>
+ struct storage_fk_references {
+ using impl_type = typename S::impl_type;
+
+ using type = typename storage_fk_references_impl<impl_type, O>::type;
+ };
+
+ template<class S, class O>
+ struct storage_foreign_keys {
+ using impl_type = typename S::impl_type;
+
+ using type = typename storage_foreign_keys_impl<impl_type, O>::type;
+ };
+
}
}
}
+// #include "function.h"
+
+#include <string> // std::string
+#include <sqlite3.h>
+#include <tuple> // std::tuple
+#include <functional> // std::function
+
namespace sqlite_orm {
- using int64 = sqlite_int64;
- using uint64 = sqlite_uint64;
+ struct arg_values;
+
+ namespace internal {
+
+ struct function_base {
+ using func_call = std::function<
+ void(sqlite3_context* context, void* functionPointer, int argsCount, sqlite3_value** values)>;
+ using final_call = std::function<void(sqlite3_context* context, void* functionPointer)>;
+
+ std::string name;
+ int argumentsCount = 0;
+ std::function<int*()> create;
+ void (*destroy)(int*) = nullptr;
+
+ function_base(decltype(name) name_,
+ decltype(argumentsCount) argumentsCount_,
+ decltype(create) create_,
+ decltype(destroy) destroy_) :
+ name(move(name_)),
+ argumentsCount(argumentsCount_), create(move(create_)), destroy(destroy_) {}
+ };
+
+ struct scalar_function_t : function_base {
+ func_call run;
+
+ scalar_function_t(decltype(name) name_,
+ int argumentsCount_,
+ decltype(create) create_,
+ decltype(run) run_,
+ decltype(destroy) destroy_) :
+ function_base{move(name_), argumentsCount_, move(create_), destroy_},
+ run(move(run_)) {}
+ };
+
+ struct aggregate_function_t : function_base {
+ func_call step;
+ final_call finalCall;
+
+ aggregate_function_t(decltype(name) name_,
+ int argumentsCount_,
+ decltype(create) create_,
+ decltype(step) step_,
+ decltype(finalCall) finalCall_,
+ decltype(destroy) destroy_) :
+ function_base{move(name_), argumentsCount_, move(create_), destroy_},
+ step(move(step_)), finalCall(move(finalCall_)) {}
+ };
+
+ // got it from here https://stackoverflow.com/questions/87372/check-if-a-class-has-a-member-function-of-a-given-signature
+ template<class F>
+ struct is_scalar_function_impl {
+
+ template<class U, class T>
+ struct SFINAE;
+
+ template<class U, class R>
+ struct SFINAE<U, R (U::*)() const> {};
+
+ template<class U>
+ static char test(SFINAE<U, decltype(&U::operator())>*);
+
+ template<class U>
+ static int test(...);
+
+ static constexpr bool has = sizeof(test<F>(0)) == sizeof(char);
+ };
+
+ template<class F>
+ struct is_aggregate_function_impl {
+
+ template<class U, class T>
+ struct SFINAE;
+
+ template<class U, class R>
+ struct SFINAE<U, R (U::*)() const> {};
+
+ template<class U>
+ static char test(SFINAE<U, decltype(&U::step)>*);
+
+ template<class U>
+ static int test(...);
+
+ template<class U>
+ static char test2(SFINAE<U, decltype(&U::fin)>*);
+
+ template<class U>
+ static int test2(...);
+
+ static constexpr bool has = sizeof(test<F>(0)) == sizeof(char);
+ static constexpr bool has2 = sizeof(test2<F>(0)) == sizeof(char);
+ static constexpr bool has_both = has && has2;
+ };
+
+ template<class F>
+ struct is_scalar_function : std::integral_constant<bool, is_scalar_function_impl<F>::has> {};
+
+ template<class F>
+ struct is_aggregate_function : std::integral_constant<bool, is_aggregate_function_impl<F>::has_both> {};
+
+ template<class F>
+ struct scalar_run_member_pointer {
+ using type = decltype(&F::operator());
+ };
+
+ template<class F>
+ struct aggregate_run_member_pointer {
+ using step_type = decltype(&F::step);
+ using fin_type = decltype(&F::fin);
+ };
+
+ template<class T>
+ struct member_function_arguments;
+
+ template<class O, class R, class... Args>
+ struct member_function_arguments<R (O::*)(Args...) const> {
+ using member_function_type = R (O::*)(Args...) const;
+ using tuple_type = std::tuple<typename std::decay<Args>::type...>;
+ using return_type = R;
+ };
+
+ template<class O, class R, class... Args>
+ struct member_function_arguments<R (O::*)(Args...)> {
+ using member_function_type = R (O::*)(Args...);
+ using tuple_type = std::tuple<typename std::decay<Args>::type...>;
+ using return_type = R;
+ };
+
+ template<class F, bool IsScalar>
+ struct callable_arguments_impl;
+
+ template<class F>
+ struct callable_arguments_impl<F, true> {
+ using function_member_pointer = typename scalar_run_member_pointer<F>::type;
+ using args_tuple = typename member_function_arguments<function_member_pointer>::tuple_type;
+ using return_type = typename member_function_arguments<function_member_pointer>::return_type;
+ };
+
+ template<class F>
+ struct callable_arguments_impl<F, false> {
+ using step_function_member_pointer = typename aggregate_run_member_pointer<F>::step_type;
+ using fin_function_member_pointer = typename aggregate_run_member_pointer<F>::fin_type;
+ using args_tuple = typename member_function_arguments<step_function_member_pointer>::tuple_type;
+ using return_type = typename member_function_arguments<fin_function_member_pointer>::return_type;
+ };
+
+ template<class F>
+ struct callable_arguments : callable_arguments_impl<F, is_scalar_function<F>::value> {};
+
+ template<class F, class... Args>
+ struct function_call {
+ using function_type = F;
+ using args_tuple = std::tuple<Args...>;
+
+ args_tuple args;
+ };
+ }
+
+ /**
+ * Used to call user defined function: `func<MyFunc>(...);`
+ */
+ template<class F, class... Args>
+ internal::function_call<F, Args...> func(Args... args) {
+ using args_tuple = std::tuple<Args...>;
+ using function_args_tuple = typename internal::callable_arguments<F>::args_tuple;
+ constexpr auto argsCount = std::tuple_size<args_tuple>::value;
+ constexpr auto functionArgsCount = std::tuple_size<function_args_tuple>::value;
+ static_assert(
+ (argsCount == functionArgsCount && !std::is_same<function_args_tuple, std::tuple<arg_values>>::value) ||
+ std::is_same<function_args_tuple, std::tuple<arg_values>>::value,
+ "Arguments amount does not match");
+ return {std::make_tuple(std::forward<Args>(args)...)};
+ }
+
+}
+
+namespace sqlite_orm {
namespace internal {
@@ -5688,6 +8332,14 @@ namespace sqlite_orm {
template<class St, class T, class SFINAE = void>
struct column_result_t;
+#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
+ template<class St, class T>
+ struct column_result_t<St, as_optional_t<T>, void> {
+ using type = std::optional<typename column_result_t<St, T>::type>;
+ };
+
+#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
+
template<class St, class O, class F>
struct column_result_t<St,
F O::*,
@@ -5696,6 +8348,16 @@ namespace sqlite_orm {
using type = F;
};
+ template<class St, class L, class A>
+ struct column_result_t<St, dynamic_in_t<L, A>, void> {
+ using type = bool;
+ };
+
+ template<class St, class L, class... Args>
+ struct column_result_t<St, in_t<L, Args...>, void> {
+ using type = bool;
+ };
+
/**
* Common case for all getter types. Getter types are defined in column.h file
*/
@@ -5713,12 +8375,17 @@ namespace sqlite_orm {
};
template<class St, class R, class S, class... Args>
- struct column_result_t<St, internal::core_function_t<R, S, Args...>, void> {
+ struct column_result_t<St, built_in_function_t<R, S, Args...>, void> {
using type = R;
};
+ template<class St, class F, class... Args>
+ struct column_result_t<St, function_call<F, Args...>, void> {
+ using type = typename callable_arguments<F>::return_type;
+ };
+
template<class St, class X, class S>
- struct column_result_t<St, core_function_t<internal::unique_ptr_result_of<X>, S, X>, void> {
+ struct column_result_t<St, built_in_function_t<internal::unique_ptr_result_of<X>, S, X>, void> {
using type = std::unique_ptr<typename column_result_t<St, X>::type>;
};
@@ -5854,6 +8521,11 @@ namespace sqlite_orm {
using type = left_result;
};
+ template<class St, class T>
+ struct column_result_t<St, T, typename std::enable_if<is_base_of_template<T, binary_condition>::value>::type> {
+ using type = typename T::result_type;
+ };
+
/**
* Result for the most simple queries like `SELECT 1`
*/
@@ -5866,7 +8538,7 @@ namespace sqlite_orm {
* Result for the most simple queries like `SELECT 'ototo'`
*/
template<class St>
- struct column_result_t<St, const char *, void> {
+ struct column_result_t<St, const char*, void> {
using type = std::string;
};
@@ -5933,7 +8605,7 @@ namespace sqlite_orm {
// #include "constraints.h"
-// #include "tuple_helper.h"
+// #include "tuple_helper/tuple_helper.h"
// #include "table_info.h"
@@ -5945,44 +8617,41 @@ namespace sqlite_orm {
namespace internal {
- struct table_base {
+ struct basic_table {
/**
* Table name.
*/
std::string name;
-
- bool _without_rowid = false;
};
/**
- * Table interface class. Implementation is hidden in `table_impl` class.
+ * Table class.
*/
- template<class T, class... Cs>
- struct table_t : table_base {
+ template<class T, bool WithoutRowId, class... Cs>
+ struct table_t : basic_table {
+ using super = basic_table;
using object_type = T;
- using columns_type = std::tuple<Cs...>;
+ using elements_type = std::tuple<Cs...>;
- static constexpr const int columns_count = static_cast<int>(std::tuple_size<columns_type>::value);
+ static constexpr const int elements_count = static_cast<int>(std::tuple_size<elements_type>::value);
+ static constexpr const bool is_without_rowid = WithoutRowId;
- columns_type columns;
+ elements_type elements;
- table_t(decltype(name) name_, columns_type columns_) :
- table_base{std::move(name_)}, columns(std::move(columns_)) {}
+ table_t(std::string name_, elements_type elements_) : super{move(name_)}, elements{move(elements_)} {}
- table_t<T, Cs...> without_rowid() const {
- auto res = *this;
- res._without_rowid = true;
- return res;
+ table_t<T, true, Cs...> without_rowid() const {
+ return {this->name, this->elements};
}
/**
* Function used to get field value from object by mapped member pointer/setter/getter
*/
template<class F, class C>
- const F *get_object_field_pointer(const object_type &obj, C c) const {
- const F *res = nullptr;
- this->for_each_column_with_field_type<F>([&res, &c, &obj](auto &col) {
+ const F* get_object_field_pointer(const object_type& obj, C c) const {
+ const F* res = nullptr;
+ this->for_each_column_with_field_type<F>([&res, &c, &obj](auto& col) {
using column_type = typename std::remove_reference<decltype(col)>::type;
using member_pointer_t = typename column_type::member_pointer_t;
using getter_type = typename column_type::getter_type;
@@ -5990,21 +8659,21 @@ namespace sqlite_orm {
// Make static_if have at least one input as a workaround for GCC bug:
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64095
if(!res) {
- static_if<std::is_same<C, member_pointer_t>{}>([&res, &obj, &col](const C &c_) {
+ static_if<std::is_same<C, member_pointer_t>{}>([&res, &obj, &col](const C& c_) {
if(compare_any(col.member_pointer, c_)) {
res = &(obj.*col.member_pointer);
}
})(c);
}
if(!res) {
- static_if<std::is_same<C, getter_type>{}>([&res, &obj, &col](const C &c_) {
+ static_if<std::is_same<C, getter_type>{}>([&res, &obj, &col](const C& c_) {
if(compare_any(col.getter, c_)) {
res = &((obj).*(col.getter))();
}
})(c);
}
if(!res) {
- static_if<std::is_same<C, setter_type>{}>([&res, &obj, &col](const C &c_) {
+ static_if<std::is_same<C, setter_type>{}>([&res, &obj, &col](const C& c_) {
if(compare_any(col.setter, c_)) {
res = &((obj).*(col.getter))();
}
@@ -6014,13 +8683,19 @@ namespace sqlite_orm {
return res;
}
- /**
- * @return vector of column names of table.
- */
- std::vector<std::string> column_names() const {
- std::vector<std::string> res;
- this->for_each_column([&res](auto &c) {
- res.push_back(c.name);
+ template<class C>
+ bool exists_in_composite_primary_key(const C& column) const {
+ auto res = false;
+ this->for_each_primary_key([&column, &res](auto& primaryKey) {
+ iterate_tuple(primaryKey.columns, [&res, &column](auto& value) {
+ if(!res) {
+ if(column.member_pointer) {
+ res = compare_any(value, column.member_pointer);
+ } else {
+ res = compare_any(value, column.getter) || compare_any(value, column.setter);
+ }
+ }
+ });
});
return res;
}
@@ -6029,16 +8704,16 @@ namespace sqlite_orm {
* Calls **l** with every primary key dedicated constraint
*/
template<class L>
- void for_each_primary_key(const L &l) const {
- iterate_tuple(this->columns, [&l](auto &column) {
- using column_type = typename std::decay<decltype(column)>::type;
- static_if<internal::is_primary_key<column_type>{}>(l)(column);
+ void for_each_primary_key(const L& lambda) const {
+ iterate_tuple(this->elements, [&lambda](auto& element) {
+ using element_type = typename std::decay<decltype(element)>::type;
+ static_if<is_primary_key<element_type>{}>(lambda)(element);
});
}
std::vector<std::string> composite_key_columns_names() const {
std::vector<std::string> res;
- this->for_each_primary_key([this, &res](auto &c) {
+ this->for_each_primary_key([this, &res](auto& c) {
res = this->composite_key_columns_names(c);
});
return res;
@@ -6046,7 +8721,7 @@ namespace sqlite_orm {
std::vector<std::string> primary_key_column_names() const {
std::vector<std::string> res;
- this->for_each_column_with<constraints::primary_key_t<>>([&res](auto &c) {
+ this->for_each_column_with<primary_key_t<>>([&res](auto& c) {
res.push_back(c.name);
});
if(!res.size()) {
@@ -6056,12 +8731,16 @@ namespace sqlite_orm {
}
template<class... Args>
- std::vector<std::string> composite_key_columns_names(const constraints::primary_key_t<Args...> &pk) const {
+ std::vector<std::string> composite_key_columns_names(const primary_key_t<Args...>& pk) const {
std::vector<std::string> res;
using pk_columns_tuple = decltype(pk.columns);
res.reserve(std::tuple_size<pk_columns_tuple>::value);
- iterate_tuple(pk.columns, [this, &res](auto &v) {
- res.push_back(this->find_column_name(v));
+ iterate_tuple(pk.columns, [this, &res](auto& v) {
+ if(auto columnName = this->find_column_name(v)) {
+ res.push_back(*columnName);
+ } else {
+ res.push_back({});
+ }
});
return res;
}
@@ -6074,11 +8753,11 @@ namespace sqlite_orm {
class O,
typename = typename std::enable_if<std::is_member_pointer<F O::*>::value &&
!std::is_member_function_pointer<F O::*>::value>::type>
- std::string find_column_name(F O::*m) const {
- std::string res;
- this->template for_each_column_with_field_type<F>([&res, m](auto &c) {
+ const std::string* find_column_name(F O::*m) const {
+ const std::string* res = nullptr;
+ this->template for_each_column_with_field_type<F>([&res, m](auto& c) {
if(c.member_pointer == m) {
- res = c.name;
+ res = &c.name;
}
});
return res;
@@ -6089,13 +8768,13 @@ namespace sqlite_orm {
* @return column name or empty string if nothing found.
*/
template<class G>
- std::string find_column_name(G getter,
- typename std::enable_if<is_getter<G>::value>::type * = nullptr) const {
- std::string res;
+ const std::string* find_column_name(G getter,
+ typename std::enable_if<is_getter<G>::value>::type* = nullptr) const {
+ const std::string* res = nullptr;
using field_type = typename getter_traits<G>::field_type;
- this->template for_each_column_with_field_type<field_type>([&res, getter](auto &c) {
+ this->template for_each_column_with_field_type<field_type>([&res, getter](auto& c) {
if(compare_any(c.getter, getter)) {
- res = c.name;
+ res = &c.name;
}
});
return res;
@@ -6106,39 +8785,55 @@ namespace sqlite_orm {
* @return column name or empty string if nothing found.
*/
template<class S>
- std::string find_column_name(S setter,
- typename std::enable_if<is_setter<S>::value>::type * = nullptr) const {
- std::string res;
+ const std::string* find_column_name(S setter,
+ typename std::enable_if<is_setter<S>::value>::type* = nullptr) const {
+ const std::string* res = nullptr;
using field_type = typename setter_traits<S>::field_type;
- this->template for_each_column_with_field_type<field_type>([&res, setter](auto &c) {
+ this->template for_each_column_with_field_type<field_type>([&res, setter](auto& c) {
if(compare_any(c.setter, setter)) {
- res = c.name;
+ res = &c.name;
}
});
return res;
}
+ int count_columns_amount() const {
+ auto res = 0;
+ this->for_each_column([&res](auto&) {
+ ++res;
+ });
+ return res;
+ }
+
/**
- * Iterates all columns and fires passed lambda. Lambda must have one and only templated argument Otherwise
- * code will not compile. Excludes table constraints (e.g. foreign_key_t) at the end of the columns list. To
- * iterate columns with table constraints use iterate_tuple(columns, ...) instead. L is lambda type. Do
- * not specify it explicitly.
- * @param l Lambda to be called per column itself. Must have signature like this [] (auto col) -> void {}
+ * Iterates all columns and fires passed lambda. Lambda must have one and only templated argument. Otherwise
+ * code will not compile. Excludes table constraints (e.g. foreign_key_t) at the end of the columns list. To
+ * iterate columns with table constraints use iterate_tuple(columns, ...) instead. L is lambda type. Do
+ * not specify it explicitly.
+ * @param lambda Lambda to be called per column itself. Must have signature like this [] (auto col) -> void {}
*/
template<class L>
- void for_each_column(const L &l) const {
- iterate_tuple(this->columns, [&l](auto &column) {
- using column_type = typename std::decay<decltype(column)>::type;
- static_if<is_column<column_type>{}>(l)(column);
+ void for_each_column(const L& lambda) const {
+ iterate_tuple(this->elements, [&lambda](auto& element) {
+ using element_type = typename std::decay<decltype(element)>::type;
+ static_if<is_column<element_type>{}>(lambda)(element);
+ });
+ }
+
+ template<class L>
+ void for_each_foreign_key(const L& lambda) const {
+ iterate_tuple(this->elements, [&lambda](auto& element) {
+ using element_type = typename std::decay<decltype(element)>::type;
+ static_if<is_foreign_key<element_type>{}>(lambda)(element);
});
}
template<class F, class L>
- void for_each_column_with_field_type(const L &l) const {
- iterate_tuple(this->columns, [&l](auto &column) {
+ void for_each_column_with_field_type(const L& lambda) const {
+ this->for_each_column([&lambda](auto& column) {
using column_type = typename std::decay<decltype(column)>::type;
using field_type = typename column_field_type<column_type>::type;
- static_if<std::is_same<F, field_type>{}>(l)(column);
+ static_if<std::is_same<F, field_type>{}>(lambda)(column);
});
}
@@ -6146,22 +8841,22 @@ namespace sqlite_orm {
* Iterates all columns that have specified constraints and fires passed lambda.
* Lambda must have one and only templated argument Otherwise code will not compile.
* L is lambda type. Do not specify it explicitly.
- * @param l Lambda to be called per column itself. Must have signature like this [] (auto col) -> void {}
+ * @param lambda Lambda to be called per column itself. Must have signature like this [] (auto col) -> void {}
*/
template<class Op, class L>
- void for_each_column_with(const L &l) const {
- using tuple_helper::tuple_contains_type;
- iterate_tuple(this->columns, [&l](auto &column) {
+ void for_each_column_with(const L& lambda) const {
+ this->for_each_column([&lambda](auto& column) {
+ using tuple_helper::tuple_contains_type;
using column_type = typename std::decay<decltype(column)>::type;
using constraints_type = typename column_constraints_type<column_type>::type;
- static_if<tuple_contains_type<Op, constraints_type>{}>(l)(column);
+ static_if<tuple_contains_type<Op, constraints_type>{}>(lambda)(column);
});
}
std::vector<table_info> get_table_info() const {
std::vector<table_info> res;
- res.reserve(size_t(this->columns_count));
- this->for_each_column([&res](auto &col) {
+ res.reserve(size_t(this->elements_count));
+ this->for_each_column([&res](auto& col) {
std::string dft;
using field_type = typename std::decay<decltype(col)>::type::field_type;
if(auto d = col.default_value()) {
@@ -6173,14 +8868,14 @@ namespace sqlite_orm {
type_printer<field_type>().print(),
col.not_null(),
dft,
- col.template has<constraints::primary_key_t<>>(),
+ col.template has<primary_key_t<>>(),
};
res.emplace_back(i);
});
auto compositeKeyColumnNames = this->composite_key_columns_names();
for(size_t i = 0; i < compositeKeyColumnNames.size(); ++i) {
- auto &columnName = compositeKeyColumnNames[i];
- auto it = std::find_if(res.begin(), res.end(), [&columnName](const table_info &ti) {
+ auto& columnName = compositeKeyColumnNames[i];
+ auto it = std::find_if(res.begin(), res.end(), [&columnName](const table_info& ti) {
return ti.name == columnName;
});
if(it != res.end()) {
@@ -6197,12 +8892,12 @@ namespace sqlite_orm {
* cause table class is templated and its constructing too (just like std::make_unique or std::make_pair).
*/
template<class... Cs, class T = typename std::tuple_element<0, std::tuple<Cs...>>::type::object_type>
- internal::table_t<T, Cs...> make_table(const std::string &name, Cs... args) {
+ internal::table_t<T, false, Cs...> make_table(const std::string& name, Cs... args) {
return {name, std::make_tuple<Cs...>(std::forward<Cs>(args)...)};
}
template<class T, class... Cs>
- internal::table_t<T, Cs...> make_table(const std::string &name, Cs... args) {
+ internal::table_t<T, false, Cs...> make_table(const std::string& name, Cs... args) {
return {name, std::make_tuple<Cs...>(std::forward<Cs>(args)...)};
}
}
@@ -6213,7 +8908,7 @@ namespace sqlite_orm {
#include <cstddef> // std::nullptr_t
#include <system_error> // std::system_error, std::error_code
#include <sstream> // std::stringstream
-#include <cstdlib> // std::atoi
+#include <stdlib.h> // std::atoi
#include <type_traits> // std::forward, std::enable_if, std::is_same, std::remove_reference, std::false_type, std::true_type
#include <utility> // std::pair, std::make_pair
#include <vector> // std::vector
@@ -6226,6 +8921,8 @@ namespace sqlite_orm {
// #include "row_extractor.h"
+// #include "util.h"
+
// #include "constraints.h"
// #include "select_constraints.h"
@@ -6252,7 +8949,7 @@ namespace sqlite_orm {
struct field_value_holder<T, typename std::enable_if<getter_traits<T>::returns_lvalue>::type> {
using type = typename getter_traits<T>::field_type;
- const type &value;
+ const type& value;
};
template<class T>
@@ -6270,7 +8967,7 @@ namespace sqlite_orm {
struct storage_impl_base {
- bool table_exists(const std::string &tableName, sqlite3 *db) const {
+ bool table_exists(const std::string& tableName, sqlite3* db) const {
auto result = false;
std::stringstream ss;
ss << "SELECT COUNT(*) FROM sqlite_master WHERE type = '"
@@ -6280,8 +8977,8 @@ namespace sqlite_orm {
auto rc = sqlite3_exec(
db,
query.c_str(),
- [](void *data, int argc, char **argv, char * * /*azColName*/) -> int {
- auto &res = *(bool *)data;
+ [](void* data, int argc, char** argv, char** /*azColName*/) -> int {
+ auto& res = *(bool*)data;
if(argc) {
res = !!std::atoi(argv[0]);
}
@@ -6296,28 +8993,15 @@ namespace sqlite_orm {
return result;
}
- void rename_table(sqlite3 *db, const std::string &oldName, const std::string &newName) const {
+ void rename_table(sqlite3* db, const std::string& oldName, const std::string& newName) const {
std::stringstream ss;
ss << "ALTER TABLE " << oldName << " RENAME TO " << newName;
- auto query = ss.str();
- sqlite3_stmt *stmt;
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- statement_finalizer finalizer{stmt};
- if(sqlite3_step(stmt) == SQLITE_DONE) {
- // done..
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ perform_void_exec(db, ss.str());
}
- static bool get_remove_add_columns(std::vector<table_info *> &columnsToAdd,
- std::vector<table_info> &storageTableInfo,
- std::vector<table_info> &dbTableInfo) {
+ static bool calculate_remove_add_columns(std::vector<table_info*>& columnsToAdd,
+ std::vector<table_info>& storageTableInfo,
+ std::vector<table_info>& dbTableInfo) {
bool notEqual = false;
// iterate through storage columns
@@ -6325,15 +9009,15 @@ namespace sqlite_orm {
++storageColumnInfoIndex) {
// get storage's column info
- auto &storageColumnInfo = storageTableInfo[storageColumnInfoIndex];
- auto &columnName = storageColumnInfo.name;
+ auto& storageColumnInfo = storageTableInfo[storageColumnInfoIndex];
+ auto& columnName = storageColumnInfo.name;
// search for a column in db eith the same name
- auto dbColumnInfoIt = std::find_if(dbTableInfo.begin(), dbTableInfo.end(), [&columnName](auto &ti) {
+ auto dbColumnInfoIt = std::find_if(dbTableInfo.begin(), dbTableInfo.end(), [&columnName](auto& ti) {
return ti.name == columnName;
});
if(dbColumnInfoIt != dbTableInfo.end()) {
- auto &dbColumnInfo = *dbColumnInfoIt;
+ auto& dbColumnInfo = *dbColumnInfoIt;
auto columnsAreEqual =
dbColumnInfo.name == storageColumnInfo.name &&
dbColumnInfo.notnull == storageColumnInfo.notnull &&
@@ -6354,14 +9038,14 @@ namespace sqlite_orm {
return notEqual;
}
- std::vector<table_info> get_table_info(const std::string &tableName, sqlite3 *db) const {
+ std::vector<table_info> get_table_info(const std::string& tableName, sqlite3* db) const {
std::vector<table_info> result;
auto query = "PRAGMA table_info('" + tableName + "')";
auto rc = sqlite3_exec(
db,
query.c_str(),
- [](void *data, int argc, char **argv, char **) -> int {
- auto &res = *(std::vector<table_info> *)data;
+ [](void* data, int argc, char** argv, char**) -> int {
+ auto& res = *(std::vector<table_info>*)data;
if(argc) {
auto index = 0;
auto cid = std::atoi(argv[index++]);
@@ -6371,7 +9055,7 @@ namespace sqlite_orm {
std::string dflt_value = argv[index] ? argv[index] : "";
index++;
auto pk = std::atoi(argv[index++]);
- res.push_back(table_info{cid, name, type, notnull, dflt_value, pk});
+ res.push_back(table_info(cid, name, type, notnull, dflt_value, pk));
}
return 0;
},
@@ -6401,7 +9085,7 @@ namespace sqlite_orm {
table_type table;
template<class L>
- void for_each(const L &l) {
+ void for_each(const L& l) {
this->super::for_each(l);
l(*this);
}
@@ -6413,8 +9097,8 @@ namespace sqlite_orm {
*/
int foreign_keys_count() {
auto res = 0;
- iterate_tuple(this->table.columns, [&res](auto &c) {
- if(internal::is_foreign_key<typename std::decay<decltype(c)>::type>::value) {
+ iterate_tuple(this->table.elements, [&res](auto& c) {
+ if(is_foreign_key<typename std::decay<decltype(c)>::type>::value) {
++res;
}
});
@@ -6429,7 +9113,7 @@ namespace sqlite_orm {
* `column_name` has SFINAE check for type equality but `column_name_simple` has not.
*/
template<class O, class F>
- std::string column_name_simple(F O::*m) const {
+ const std::string* column_name_simple(F O::*m) const {
return this->table.find_column_name(m);
}
@@ -6438,8 +9122,8 @@ namespace sqlite_orm {
* skip inequal type O.
*/
template<class O, class F, class HH = typename H::object_type>
- std::string column_name(F O::*m,
- typename std::enable_if<std::is_same<O, HH>::value>::type * = nullptr) const {
+ const std::string* column_name(F O::*m,
+ typename std::enable_if<std::is_same<O, HH>::value>::type* = nullptr) const {
return this->table.find_column_name(m);
}
@@ -6447,50 +9131,51 @@ namespace sqlite_orm {
* Opposite version of function defined above. Just calls same function in superclass.
*/
template<class O, class F, class HH = typename H::object_type>
- std::string column_name(F O::*m,
- typename std::enable_if<!std::is_same<O, HH>::value>::type * = nullptr) const {
+ const std::string*
+ column_name(F O::*m, typename std::enable_if<!std::is_same<O, HH>::value>::type* = nullptr) const {
return this->super::column_name(m);
}
template<class T, class F, class HH = typename H::object_type>
- std::string column_name(const column_pointer<T, F> &c,
- typename std::enable_if<std::is_same<T, HH>::value>::type * = nullptr) const {
+ const std::string* column_name(const column_pointer<T, F>& c,
+ typename std::enable_if<std::is_same<T, HH>::value>::type* = nullptr) const {
return this->column_name_simple(c.field);
}
template<class T, class F, class HH = typename H::object_type>
- std::string column_name(const column_pointer<T, F> &c,
- typename std::enable_if<!std::is_same<T, HH>::value>::type * = nullptr) const {
+ const std::string*
+ column_name(const column_pointer<T, F>& c,
+ typename std::enable_if<!std::is_same<T, HH>::value>::type* = nullptr) const {
return this->super::column_name(c);
}
template<class O, class HH = typename H::object_type>
- const auto &get_impl(typename std::enable_if<std::is_same<O, HH>::value>::type * = nullptr) const {
+ const auto& get_impl(typename std::enable_if<std::is_same<O, HH>::value>::type* = nullptr) const {
return *this;
}
template<class O, class HH = typename H::object_type>
- const auto &get_impl(typename std::enable_if<!std::is_same<O, HH>::value>::type * = nullptr) const {
+ const auto& get_impl(typename std::enable_if<!std::is_same<O, HH>::value>::type* = nullptr) const {
return this->super::template get_impl<O>();
}
template<class O, class HH = typename H::object_type>
- auto &get_impl(typename std::enable_if<std::is_same<O, HH>::value>::type * = nullptr) {
+ auto& get_impl(typename std::enable_if<std::is_same<O, HH>::value>::type* = nullptr) {
return *this;
}
template<class O, class HH = typename H::object_type>
- auto &get_impl(typename std::enable_if<!std::is_same<O, HH>::value>::type * = nullptr) {
+ auto& get_impl(typename std::enable_if<!std::is_same<O, HH>::value>::type* = nullptr) {
return this->super::template get_impl<O>();
}
template<class O, class HH = typename H::object_type>
- const auto *find_table(typename std::enable_if<std::is_same<O, HH>::value>::type * = nullptr) const {
+ const auto* find_table(typename std::enable_if<std::is_same<O, HH>::value>::type* = nullptr) const {
return &this->table;
}
template<class O, class HH = typename H::object_type>
- const auto *find_table(typename std::enable_if<!std::is_same<O, HH>::value>::type * = nullptr) const {
+ const auto* find_table(typename std::enable_if<!std::is_same<O, HH>::value>::type* = nullptr) const {
return this->super::template find_table<O>();
}
@@ -6503,34 +9188,20 @@ namespace sqlite_orm {
}
}
- void add_column(const table_info &ti, sqlite3 *db) const {
+ void add_column(const table_info& ti, sqlite3* db) const {
std::stringstream ss;
- ss << "ALTER TABLE " << this->table.name << " ADD COLUMN " << ti.name << " ";
- ss << ti.type << " ";
+ ss << "ALTER TABLE " << this->table.name << " ADD COLUMN " << ti.name;
+ ss << " " << ti.type;
if(ti.pk) {
- ss << "PRIMARY KEY ";
+ ss << " PRIMARY KEY";
}
if(ti.notnull) {
- ss << "NOT NULL ";
+ ss << " NOT NULL";
}
if(ti.dflt_value.length()) {
- ss << "DEFAULT " << ti.dflt_value << " ";
- }
- auto query = ss.str();
- sqlite3_stmt *stmt;
- auto prepareResult = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr);
- if(prepareResult == SQLITE_OK) {
- statement_finalizer finalizer{stmt};
- if(sqlite3_step(stmt) == SQLITE_DONE) {
- //..
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
+ ss << " DEFAULT " << ti.dflt_value;
}
+ perform_void_exec(db, ss.str());
}
/**
@@ -6538,13 +9209,11 @@ namespace sqlite_orm {
* Performs CREATE TABLE %name% AS SELECT %this->table.columns_names()% FROM &this->table.name%;
*/
void
- copy_table(sqlite3 *db, const std::string &name, const std::vector<table_info *> &columnsToIgnore) const {
- std::ignore = columnsToIgnore;
-
+ copy_table(sqlite3* db, const std::string& name, const std::vector<table_info*>& columnsToIgnore) const {
std::stringstream ss;
std::vector<std::string> columnNames;
- this->table.for_each_column([&columnNames, &columnsToIgnore](auto &c) {
- auto &columnName = c.name;
+ this->table.for_each_column([&columnNames, &columnsToIgnore](auto& c) {
+ auto& columnName = c.name;
auto columnToIgnoreIt = std::find_if(columnsToIgnore.begin(),
columnsToIgnore.end(),
[&columnName](auto tableInfoPointer) {
@@ -6568,28 +9237,14 @@ namespace sqlite_orm {
for(size_t i = 0; i < columnNamesCount; ++i) {
ss << columnNames[i];
if(i < columnNamesCount - 1) {
- ss << ",";
- }
- ss << " ";
- }
- ss << "FROM '" << this->table.name << "' ";
- auto query = ss.str();
- sqlite3_stmt *stmt;
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- statement_finalizer finalizer{stmt};
- if(sqlite3_step(stmt) == SQLITE_DONE) {
- //..
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
+ ss << ", ";
}
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
}
+ ss << " FROM '" << this->table.name << "' ";
+ perform_void_exec(db, ss.str());
}
- sync_schema_result schema_status(sqlite3 *db, bool preserve) const {
+ sync_schema_result schema_status(sqlite3* db, bool preserve) const {
auto res = sync_schema_result::already_in_sync;
@@ -6604,9 +9259,9 @@ namespace sqlite_orm {
auto dbTableInfo = this->get_table_info(this->table.name, db);
// this vector will contain pointers to columns that gotta be added..
- std::vector<table_info *> columnsToAdd;
+ std::vector<table_info*> columnsToAdd;
- if(this->get_remove_add_columns(columnsToAdd, storageTableInfo, dbTableInfo)) {
+ if(this->calculate_remove_add_columns(columnsToAdd, storageTableInfo, dbTableInfo)) {
gottaCreateTable = true;
}
@@ -6665,14 +9320,14 @@ namespace sqlite_orm {
}
template<class L>
- void for_each(const L &) {}
+ void for_each(const L&) {}
int foreign_keys_count() {
return 0;
}
template<class O>
- const void *find_table() const {
+ const void* find_table() const {
return nullptr;
}
};
@@ -6725,7 +9380,7 @@ namespace sqlite_orm {
namespace internal {
struct object_from_column_builder_base {
- sqlite3_stmt *stmt = nullptr;
+ sqlite3_stmt* stmt = nullptr;
mutable int index = 0;
};
@@ -6736,13 +9391,13 @@ namespace sqlite_orm {
struct object_from_column_builder : object_from_column_builder_base {
using object_type = O;
- object_type &object;
+ object_type& object;
- object_from_column_builder(object_type &object_, sqlite3_stmt *stmt_) :
+ object_from_column_builder(object_type& object_, sqlite3_stmt* stmt_) :
object_from_column_builder_base{stmt_}, object(object_) {}
template<class C>
- void operator()(const C &c) const {
+ void operator()(const C& c) const {
using field_type = typename C::field_type;
auto value = row_extractor<field_type>().extract(this->stmt, this->index++);
if(c.member_pointer) {
@@ -6761,27 +9416,27 @@ namespace sqlite_orm {
namespace internal {
/**
- * This is a private row extractor class. It is used for extracting rows as objects instead of tuple.
- * Main difference from regular `row_extractor` is that this class takes table info which is required
- * for constructing objects by member pointers. To construct please use `row_extractor_builder` class
- * Type arguments:
- * V is value type just like regular `row_extractor` has
- * T is table info class `table_t`
- */
+ * This is a private row extractor class. It is used for extracting rows as objects instead of tuple.
+ * Main difference from regular `row_extractor` is that this class takes table info which is required
+ * for constructing objects by member pointers. To construct please use `row_extractor_builder` class
+ * Type arguments:
+ * V is value type just like regular `row_extractor` has
+ * T is table info class `table_t`
+ */
template<class V, class T>
struct mapped_row_extractor {
using table_info_t = T;
- mapped_row_extractor(const table_info_t &tableInfo_) : tableInfo(tableInfo_) {}
+ mapped_row_extractor(const table_info_t& tableInfo_) : tableInfo(tableInfo_) {}
- V extract(sqlite3_stmt *stmt, int /*columnIndex*/) {
+ V extract(sqlite3_stmt* stmt, int /*columnIndex*/) {
V res;
object_from_column_builder<V> builder{res, stmt};
this->tableInfo.for_each_column(builder);
return res;
}
- const table_info_t &tableInfo;
+ const table_info_t& tableInfo;
};
}
@@ -6793,18 +9448,18 @@ namespace sqlite_orm {
namespace internal {
/**
- * This builder is used to construct different row extractors depending on type.
- * It has two specializations: for mapped to storage types (e.g. User, Visit etc) and
- * for non-mapped (e.g. std::string, QString, int etc). For non mapped its operator() returns
- * generic `row_extractor`, for mapped it returns `mapped_row_extractor` instance.
- */
+ * This builder is used to construct different row extractors depending on type.
+ * It has two specializations: for mapped to storage types (e.g. User, Visit etc) and
+ * for non-mapped (e.g. std::string, QString, int etc). For non mapped its operator() returns
+ * generic `row_extractor`, for mapped it returns `mapped_row_extractor` instance.
+ */
template<class T, bool IsMapped, class I>
struct row_extractor_builder;
template<class T, class I>
struct row_extractor_builder<T, false, I> {
- row_extractor<T> operator()(const I * /*tableInfo*/) const {
+ row_extractor<T> operator()(const I* /*tableInfo*/) const {
return {};
}
};
@@ -6812,13 +9467,13 @@ namespace sqlite_orm {
template<class T, class I>
struct row_extractor_builder<T, true, I> {
- mapped_row_extractor<T, I> operator()(const I *tableInfo) const {
+ mapped_row_extractor<T, I> operator()(const I* tableInfo) const {
return {*tableInfo};
}
};
template<class T, bool IsMapped, class I>
- auto make_row_extractor(const I *tableInfo) {
+ auto make_row_extractor(const I* tableInfo) {
using builder_t = row_extractor_builder<T, IsMapped, I>;
return builder_t{}(tableInfo);
}
@@ -6831,7 +9486,7 @@ namespace sqlite_orm {
// #include "type_printer.h"
-// #include "tuple_helper.h"
+// #include "tuple_helper/tuple_helper.h"
// #include "constraints.h"
@@ -6915,8 +9570,10 @@ namespace sqlite_orm {
* call. When one finishes iterating it the pointer
* inside the shared_ptr is nulled out in all copies.
*/
- std::shared_ptr<sqlite3_stmt *> stmt;
- view_type &view;
+ std::shared_ptr<statement_finalizer> stmt;
+
+ // only null for the default constructed iterator
+ view_type* view;
/**
* shared_ptr is used over unique_ptr here
@@ -6924,68 +9581,53 @@ namespace sqlite_orm {
*/
std::shared_ptr<value_type> current;
- void extract_value(std::unique_ptr<value_type> &temp) {
- temp = std::make_unique<value_type>();
- auto &storage = this->view.storage;
- auto &impl = storage.template get_impl<value_type>();
- object_from_column_builder<value_type> builder{*temp, *this->stmt};
+ void extract_value() {
+ auto& storage = this->view->storage;
+ auto& impl = storage.template get_impl<value_type>();
+ this->current = std::make_shared<value_type>();
+ object_from_column_builder<value_type> builder{*this->current, this->stmt->get()};
impl.table.for_each_column(builder);
}
public:
using difference_type = std::ptrdiff_t;
- using pointer = value_type *;
- using reference = value_type &;
+ using pointer = value_type*;
+ using reference = value_type&;
using iterator_category = std::input_iterator_tag;
- iterator_t(sqlite3_stmt *stmt_, view_type &view_) :
- stmt(std::make_shared<sqlite3_stmt *>(stmt_)), view(view_) {
- this->operator++();
- }
-
- iterator_t(const iterator_t &) = default;
-
- iterator_t(iterator_t &&) = default;
-
- iterator_t &operator=(iterator_t &&) = default;
+ iterator_t() : view(nullptr){};
- iterator_t &operator=(const iterator_t &) = default;
-
- ~iterator_t() {
- if(this->stmt) {
- statement_finalizer f{*this->stmt};
- }
+ iterator_t(sqlite3_stmt* stmt_, view_type& view_) :
+ stmt(std::make_shared<statement_finalizer>(stmt_)), view(&view_) {
+ next();
}
- value_type &operator*() {
- if(!this->stmt) {
+ const value_type& operator*() const {
+ if(!this->stmt || !this->current) {
throw std::system_error(std::make_error_code(orm_error_code::trying_to_dereference_null_iterator));
}
- if(!this->current) {
- std::unique_ptr<value_type> value;
- this->extract_value(value);
- this->current = move(value);
- }
return *this->current;
}
- value_type *operator->() {
+ const value_type* operator->() const {
return &(this->operator*());
}
- void operator++() {
- if(this->stmt && *this->stmt) {
- auto ret = sqlite3_step(*this->stmt);
+ private:
+ void next() {
+ this->current.reset();
+ if(this->stmt) {
+ auto statementPointer = this->stmt->get();
+ auto ret = sqlite3_step(statementPointer);
switch(ret) {
case SQLITE_ROW:
- this->current = nullptr;
+ this->extract_value();
+ break;
+ case SQLITE_DONE:
+ this->stmt.reset();
break;
- case SQLITE_DONE: {
- statement_finalizer f{*this->stmt};
- *this->stmt = nullptr;
- } break;
default: {
- auto db = this->view.connection.get();
+ auto db = this->view->connection.get();
throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
sqlite3_errmsg(db));
}
@@ -6993,23 +9635,21 @@ namespace sqlite_orm {
}
}
+ public:
+ iterator_t<V>& operator++() {
+ next();
+ return *this;
+ }
+
void operator++(int) {
this->operator++();
}
- bool operator==(const iterator_t &other) const {
- if(this->stmt && other.stmt) {
- return *this->stmt == *other.stmt;
- } else {
- if(!this->stmt && !other.stmt) {
- return true;
- } else {
- return false;
- }
- }
+ bool operator==(const iterator_t& other) const {
+ return this->current == other.current;
}
- bool operator!=(const iterator_t &other) const {
+ bool operator!=(const iterator_t& other) const {
return !(*this == other);
}
};
@@ -7027,7 +9667,7 @@ namespace sqlite_orm {
// #include "operators.h"
-// #include "tuple_helper.h"
+// #include "tuple_helper/tuple_helper.h"
// #include "core_functions.h"
@@ -7077,7 +9717,7 @@ namespace sqlite_orm {
}
}
- sqlite3 *get() const {
+ sqlite3* get() const {
return this->db;
}
@@ -7088,20 +9728,20 @@ namespace sqlite_orm {
const std::string filename;
protected:
- sqlite3 *db = nullptr;
+ sqlite3* db = nullptr;
int _retain_count = 0;
};
struct connection_ref {
- connection_ref(connection_holder &holder_) : holder(holder_) {
+ connection_ref(connection_holder& holder_) : holder(holder_) {
this->holder.retain();
}
- connection_ref(const connection_ref &other) : holder(other.holder) {
+ connection_ref(const connection_ref& other) : holder(other.holder) {
this->holder.retain();
}
- connection_ref(connection_ref &&other) : holder(other.holder) {
+ connection_ref(connection_ref&& other) : holder(other.holder) {
this->holder.retain();
}
@@ -7109,24 +9749,67 @@ namespace sqlite_orm {
this->holder.release();
}
- sqlite3 *get() const {
+ sqlite3* get() const {
return this->holder.get();
}
protected:
- connection_holder &holder;
+ connection_holder& holder;
};
}
}
// #include "select_constraints.h"
+// #include "values.h"
+
+#include <vector> // std::vector
+#include <initializer_list>
+#include <tuple> // std::tuple
+#include <type_traits> // std::false_type, std::true_type
+
+namespace sqlite_orm {
+
+ namespace internal {
+
+ template<class... Args>
+ struct values_t {
+ using args_tuple = std::tuple<Args...>;
+
+ args_tuple tuple;
+ };
+
+ template<class T>
+ struct is_values : std::false_type {};
+
+ template<class... Args>
+ struct is_values<values_t<Args...>> : std::true_type {};
+
+ template<class T>
+ struct dynamic_values_t {
+ std::vector<T> vector;
+ };
+
+ }
+
+ template<class... Args>
+ internal::values_t<Args...> values(Args... args) {
+ return {{std::forward<Args>(args)...}};
+ }
+
+ template<class T>
+ internal::dynamic_values_t<T> values(std::vector<T> vector) {
+ return {{move(vector)}};
+ }
+
+}
+
namespace sqlite_orm {
namespace internal {
struct prepared_statement_base {
- sqlite3_stmt *stmt = nullptr;
+ sqlite3_stmt* stmt = nullptr;
connection_ref con;
~prepared_statement_base() {
@@ -7184,7 +9867,7 @@ namespace sqlite_orm {
expression_type t;
- prepared_statement_t(T t_, sqlite3_stmt *stmt_, connection_ref con_) :
+ prepared_statement_t(T t_, sqlite3_stmt* stmt_, connection_ref con_) :
prepared_statement_base{stmt_, std::move(con_)}, t(std::move(t_)) {}
};
@@ -7297,6 +9980,12 @@ namespace sqlite_orm {
type obj;
};
+ template<class T>
+ struct is_insert : std::false_type {};
+
+ template<class T>
+ struct is_insert<insert_t<T>> : std::true_type {};
+
template<class T, class... Cols>
struct insert_explicit {
using type = T;
@@ -7313,40 +10002,358 @@ namespace sqlite_orm {
type obj;
};
- template<class It>
+ template<class T>
+ struct is_replace : std::false_type {};
+
+ template<class T>
+ struct is_replace<replace_t<T>> : std::true_type {};
+
+ template<class It, class L, class O>
struct insert_range_t {
using iterator_type = It;
- using object_type = typename std::iterator_traits<iterator_type>::value_type;
+ using container_object_type = typename std::iterator_traits<iterator_type>::value_type;
+ using transformer_type = L;
+ using object_type = O;
std::pair<iterator_type, iterator_type> range;
+ transformer_type transformer;
};
- template<class It>
+ template<class T>
+ struct is_insert_range : std::false_type {};
+
+ template<class It, class L, class O>
+ struct is_insert_range<insert_range_t<It, L, O>> : std::true_type {};
+
+ template<class It, class L, class O>
struct replace_range_t {
using iterator_type = It;
- using object_type = typename std::iterator_traits<iterator_type>::value_type;
+ using container_object_type = typename std::iterator_traits<iterator_type>::value_type;
+ using transformer_type = L;
+ using object_type = O;
std::pair<iterator_type, iterator_type> range;
+ transformer_type transformer;
};
+
+ template<class T>
+ struct is_replace_range : std::false_type {};
+
+ template<class It, class L, class O>
+ struct is_replace_range<replace_range_t<It, L, O>> : std::true_type {};
+
+ template<class... Args>
+ struct insert_raw_t {
+ using args_tuple = std::tuple<Args...>;
+
+ args_tuple args;
+ };
+
+ template<class T>
+ struct is_insert_raw : std::false_type {};
+
+ template<class... Args>
+ struct is_insert_raw<insert_raw_t<Args...>> : std::true_type {};
+
+ template<class... Args>
+ struct replace_raw_t {
+ using args_tuple = std::tuple<Args...>;
+
+ args_tuple args;
+ };
+
+ template<class T>
+ struct is_replace_raw : std::false_type {};
+
+ template<class... Args>
+ struct is_replace_raw<replace_raw_t<Args...>> : std::true_type {};
+
+ template<class T>
+ struct into_t {
+ using type = T;
+ };
+
+ template<class T>
+ struct is_into : std::false_type {};
+
+ template<class T>
+ struct is_into<into_t<T>> : std::true_type {};
+
+ struct default_transformer {
+
+ template<class T>
+ const T& operator()(const T& object) const {
+ return object;
+ }
+ };
+
+ struct default_values_t {};
+
+ template<class T>
+ using is_default_values = std::is_same<default_values_t, T>;
+
+ enum class insert_constraint {
+ abort,
+ fail,
+ ignore,
+ replace,
+ rollback,
+ };
+
+ template<class T>
+ using is_insert_constraint = std::is_same<insert_constraint, T>;
+
+ template<class T>
+ struct is_upsert_clause;
+ }
+
+ inline internal::insert_constraint or_rollback() {
+ return internal::insert_constraint::rollback;
+ }
+
+ inline internal::insert_constraint or_replace() {
+ return internal::insert_constraint::replace;
+ }
+
+ inline internal::insert_constraint or_ignore() {
+ return internal::insert_constraint::ignore;
+ }
+
+ inline internal::insert_constraint or_fail() {
+ return internal::insert_constraint::fail;
+ }
+
+ inline internal::insert_constraint or_abort() {
+ return internal::insert_constraint::abort;
+ }
+
+ /**
+ * Use this function to add `DEFAULT VALUES` modifier to raw `INSERT`.
+ *
+ * @example
+ * ```
+ * storage.insert(into<Singer>(), default_values());
+ * ```
+ */
+ inline internal::default_values_t default_values() {
+ return {};
+ }
+
+ template<class T>
+ internal::into_t<T> into() {
+ return {};
+ }
+
+ /**
+ * Raw insert statement creation routine. Use this if `insert` with object does not fit you. This insert is designed to be able
+ * to call any type of `INSERT` query with no limitations.
+ * @example
+ * ```sql
+ * INSERT INTO users (id, name) VALUES(5, 'Little Mix')
+ * ```
+ * will be
+ * ```c++
+ * auto statement = storage.prepare(insert(into<User>, columns(&User::id, &User::name), values(std::make_tuple(5, "Little Mix"))));
+ * storage.execute(statement));
+ * ```
+ * One more example:
+ * ```sql
+ * INSERT INTO singers (name) VALUES ('Sofia Reyes')('Kungs')
+ * ```
+ * will be
+ * ```c++
+ * auto statement = storage.prepare(insert(into<Singer>(), columns(&Singer::name), values(std::make_tuple("Sofia Reyes"), std::make_tuple("Kungs"))));
+ * storage.execute(statement));
+ * ```
+ * One can use `default_values` to add `DEFAULT VALUES` modifier:
+ * ```sql
+ * INSERT INTO users DEFAULT VALUES
+ * ```
+ * will be
+ * ```c++
+ * auto statement = storage.prepare(insert(into<Singer>(), default_values()));
+ * storage.execute(statement));
+ * ```
+ * Also one can use `INSERT OR ABORT`/`INSERT OR FAIL`/`INSERT OR IGNORE`/`INSERT OR REPLACE`/`INSERT ROLLBACK`:
+ * ```c++
+ * auto statement = storage.prepare(insert(or_ignore(), into<Singer>(), columns(&Singer::name), values(std::make_tuple("Sofia Reyes"), std::make_tuple("Kungs"))));
+ * auto statement2 = storage.prepare(insert(or_rollback(), into<Singer>(), default_values()));
+ * auto statement3 = storage.prepare(insert(or_abort(), into<User>, columns(&User::id, &User::name), values(std::make_tuple(5, "Little Mix"))));
+ * ```
+ */
+ template<class... Args>
+ internal::insert_raw_t<Args...> insert(Args... args) {
+ using args_tuple = std::tuple<Args...>;
+ using internal::count_tuple;
+ using internal::is_columns;
+ using internal::is_insert_constraint;
+ using internal::is_into;
+ using internal::is_select;
+ using internal::is_upsert_clause;
+ using internal::is_values;
+
+ constexpr int orArgsCount = count_tuple<args_tuple, is_insert_constraint>::value;
+ static_assert(orArgsCount < 2, "Raw insert must have only one OR... argument");
+
+ constexpr int intoArgsCount = count_tuple<args_tuple, is_into>::value;
+ static_assert(intoArgsCount != 0, "Raw insert must have into<T> argument");
+ static_assert(intoArgsCount < 2, "Raw insert must have only one into<T> argument");
+
+ constexpr int columnsArgsCount = count_tuple<args_tuple, is_columns>::value;
+ static_assert(columnsArgsCount < 2, "Raw insert must have only one columns(...) argument");
+
+ constexpr int valuesArgsCount = count_tuple<args_tuple, is_values>::value;
+ static_assert(valuesArgsCount < 2, "Raw insert must have only one values(...) argument");
+
+ constexpr int defaultValuesCount = count_tuple<args_tuple, internal::is_default_values>::value;
+ static_assert(defaultValuesCount < 2, "Raw insert must have only one default_values() argument");
+
+ constexpr int selectsArgsCount = count_tuple<args_tuple, is_select>::value;
+ static_assert(selectsArgsCount < 2, "Raw insert must have only one select(...) argument");
+
+ constexpr int upsertClausesCount = count_tuple<args_tuple, is_upsert_clause>::value;
+ static_assert(upsertClausesCount <= 2, "Raw insert can contain 2 instances of upsert clause maximum");
+
+ constexpr int argsCount = int(std::tuple_size<args_tuple>::value);
+ static_assert(argsCount == intoArgsCount + columnsArgsCount + valuesArgsCount + defaultValuesCount +
+ selectsArgsCount + orArgsCount + upsertClausesCount,
+ "Raw insert has invalid arguments");
+
+ return {{std::forward<Args>(args)...}};
+ }
+
+ /**
+ * Raw replace statement creation routine. Use this if `replace` with object does not fit you. This replace is designed to be able
+ * to call any type of `REPLACE` query with no limitations. Actually this is the same query as raw insert except `OR...` option existance.
+ * @example
+ * ```sql
+ * REPLACE INTO users (id, name) VALUES(5, 'Little Mix')
+ * ```
+ * will be
+ * ```c++
+ * auto statement = storage.prepare(replace(into<User>, columns(&User::id, &User::name), values(std::make_tuple(5, "Little Mix"))));
+ * storage.execute(statement));
+ * ```
+ * One more example:
+ * ```sql
+ * REPLACE INTO singers (name) VALUES ('Sofia Reyes')('Kungs')
+ * ```
+ * will be
+ * ```c++
+ * auto statement = storage.prepare(replace(into<Singer>(), columns(&Singer::name), values(std::make_tuple("Sofia Reyes"), std::make_tuple("Kungs"))));
+ * storage.execute(statement));
+ * ```
+ * One can use `default_values` to add `DEFAULT VALUES` modifier:
+ * ```sql
+ * REPLACE INTO users DEFAULT VALUES
+ * ```
+ * will be
+ * ```c++
+ * auto statement = storage.prepare(replace(into<Singer>(), default_values()));
+ * storage.execute(statement));
+ * ```
+ */
+ template<class... Args>
+ internal::replace_raw_t<Args...> replace(Args... args) {
+ using args_tuple = std::tuple<Args...>;
+ using internal::count_tuple;
+ using internal::is_columns;
+ using internal::is_into;
+ using internal::is_values;
+
+ constexpr int intoArgsCount = count_tuple<args_tuple, is_into>::value;
+ static_assert(intoArgsCount != 0, "Raw replace must have into<T> argument");
+ static_assert(intoArgsCount < 2, "Raw replace must have only one into<T> argument");
+
+ constexpr int columnsArgsCount = count_tuple<args_tuple, is_columns>::value;
+ static_assert(columnsArgsCount < 2, "Raw replace must have only one columns(...) argument");
+
+ constexpr int valuesArgsCount = count_tuple<args_tuple, is_values>::value;
+ static_assert(valuesArgsCount < 2, "Raw replace must have only one values(...) argument");
+
+ constexpr int defaultValuesCount = count_tuple<args_tuple, internal::is_default_values>::value;
+ static_assert(defaultValuesCount < 2, "Raw replace must have only one default_values() argument");
+
+ constexpr int selectsArgsCount = count_tuple<args_tuple, internal::is_select>::value;
+ static_assert(selectsArgsCount < 2, "Raw replace must have only one select(...) argument");
+
+ constexpr int argsCount = int(std::tuple_size<args_tuple>::value);
+ static_assert(argsCount ==
+ intoArgsCount + columnsArgsCount + valuesArgsCount + defaultValuesCount + selectsArgsCount,
+ "Raw replace has invalid arguments");
+
+ return {{std::forward<Args>(args)...}};
}
/**
* Create a replace range statement
+ *
+ * @example
+ * ```
+ * std::vector<User> users;
+ * users.push_back(User{1, "Leony"});
+ * auto statement = storage.prepare(replace_range(users.begin(), users.end()));
+ * storage.execute(statement);
+ * ```
*/
template<class It>
- internal::replace_range_t<It> replace_range(It from, It to) {
+ internal::replace_range_t<It, internal::default_transformer, typename std::iterator_traits<It>::value_type>
+ replace_range(It from, It to) {
return {{std::move(from), std::move(to)}};
}
/**
+ * Create an replace range statement with explicit transformer. Transformer is used to apply containers with no strict objects with other kind of objects like pointers,
+ * optionals or whatever.
+ * @example
+ * ```
+ * std::vector<std::unique_ptr<User>> userPointers;
+ * userPointers.push_back(std::make_unique<User>(1, "Eneli"));
+ * auto statement = storage.prepare(replace_range<User>(userPointers.begin(), userPointers.end(), [](const std::unique_ptr<User> &userPointer) -> const User & {
+ * return *userPointer;
+ * }));
+ * storage.execute(statement);
+ * ```
+ */
+ template<class T, class It, class L>
+ internal::replace_range_t<It, L, T> replace_range(It from, It to, L transformer) {
+ return {{std::move(from), std::move(to)}, std::move(transformer)};
+ }
+
+ /**
* Create an insert range statement
+ * @example
+ * ```
+ * std::vector<User> users;
+ * users.push_back(User{1, "Leony"});
+ * auto statement = storage.prepare(insert_range(users.begin(), users.end()));
+ * storage.execute(statement);
+ * ```
*/
template<class It>
- internal::insert_range_t<It> insert_range(It from, It to) {
- return {{std::move(from), std::move(to)}};
+ internal::insert_range_t<It, internal::default_transformer, typename std::iterator_traits<It>::value_type>
+ insert_range(It from, It to) {
+ return {{std::move(from), std::move(to)}, internal::default_transformer{}};
}
/**
+ * Create an insert range statement with explicit transformer. Transformer is used to apply containers with no strict objects with other kind of objects like pointers,
+ * optionals or whatever.
+ * @example
+ * ```
+ * std::vector<std::unique_ptr<User>> userPointers;
+ * userPointers.push_back(std::make_unique<User>(1, "Eneli"));
+ * auto statement = storage.prepare(insert_range<User>(userPointers.begin(), userPointers.end(), [](const std::unique_ptr<User> &userPointer) -> const User & {
+ * return *userPointer;
+ * }));
+ * storage.execute(statement);
+ * ```
+ */
+ template<class T, class It, class L>
+ internal::insert_range_t<It, L, T> insert_range(It from, It to, L transformer) {
+ return {{std::move(from), std::move(to)}, std::move(transformer)};
+ }
+ /**
* Create a replace statement.
* T is an object type mapped to a storage.
* Usage: storage.replace(myUserInstance);
@@ -7551,38 +10558,91 @@ namespace sqlite_orm {
// #include "values.h"
-#include <vector> // std::vector
-#include <initializer_list>
-#include <tuple> // std::tuple
+// #include "function.h"
+
+// #include "ast/excluded.h"
namespace sqlite_orm {
+ namespace internal {
+
+ template<class T>
+ struct excluded_t {
+ using expression_type = T;
+
+ expression_type expression;
+ };
+ }
+
+ template<class T>
+ internal::excluded_t<T> excluded(T expression) {
+ return {std::move(expression)};
+ }
+}
+// #include "ast/upsert_clause.h"
+
+#include <tuple> // std::tuple
+#include <type_traits> // std::false_type, std::true_type
+
+namespace sqlite_orm {
namespace internal {
+ template<class T, class A>
+ struct upsert_clause;
+
template<class... Args>
- struct values_t {
- std::tuple<Args...> tuple;
+ struct conflict_target {
+ using args_tuple = std::tuple<Args...>;
+
+ args_tuple args;
+
+ upsert_clause<args_tuple, std::tuple<>> do_nothing() {
+ return {std::move(this->args), {}};
+ }
+
+ template<class... ActionsArgs>
+ upsert_clause<args_tuple, std::tuple<ActionsArgs...>> do_update(ActionsArgs... actions) {
+ return {std::move(this->args), {std::make_tuple(std::forward<ActionsArgs>(actions)...)}};
+ }
};
- template<class T>
- struct dynamic_values_t {
- std::vector<T> vector;
+ template<class... TargetArgs, class... ActionsArgs>
+ struct upsert_clause<std::tuple<TargetArgs...>, std::tuple<ActionsArgs...>> {
+ using target_args_tuple = std::tuple<TargetArgs...>;
+ using actions_tuple = std::tuple<ActionsArgs...>;
+
+ target_args_tuple target_args;
+
+ actions_tuple actions;
};
- }
+ template<class T>
+ struct is_upsert_clause : std::false_type {};
- template<class... Args>
- internal::values_t<Args...> values(Args... args) {
- return {{std::forward<Args>(args)...}};
+ template<class T, class A>
+ struct is_upsert_clause<upsert_clause<T, A>> : std::true_type {};
}
- template<class T>
- internal::dynamic_values_t<T> values(std::vector<T> vector) {
- return {{move(vector)}};
+ /**
+ * ON CONFLICT upsert clause builder function.
+ * @example
+ * storage.insert(into<Employee>(),
+ * columns(&Employee::id, &Employee::name, &Employee::age, &Employee::address, &Employee::salary),
+ * values(std::make_tuple(3, "Sofia", 26, "Madrid", 15000.0),
+ * std::make_tuple(4, "Doja", 26, "LA", 25000.0)),
+ * on_conflict(&Employee::id).do_update(set(c(&Employee::name) = excluded(&Employee::name),
+ * c(&Employee::age) = excluded(&Employee::age),
+ * c(&Employee::address) = excluded(&Employee::address),
+ * c(&Employee::salary) = excluded(&Employee::salary))));
+ */
+ template<class... Args>
+ internal::conflict_target<Args...> on_conflict(Args... args) {
+ return {std::tuple<Args...>(std::forward<Args>(args)...)};
}
-
}
+// #include "ast/where.h"
+
namespace sqlite_orm {
namespace internal {
@@ -7604,7 +10664,7 @@ namespace sqlite_orm {
* L is a callable type. Mostly is a templated lambda
*/
template<class L>
- void operator()(const T &t, const L &l) const {
+ void operator()(const T& t, const L& l) const {
l(t);
}
};
@@ -7613,18 +10673,50 @@ namespace sqlite_orm {
* Simplified API
*/
template<class T, class L>
- void iterate_ast(const T &t, const L &l) {
+ void iterate_ast(const T& t, const L& l) {
ast_iterator<T> iterator;
iterator(t, l);
}
+#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
+ template<class T>
+ struct ast_iterator<as_optional_t<T>, void> {
+ using node_type = as_optional_t<T>;
+
+ template<class L>
+ void operator()(const node_type& node, const L& lambda) const {
+ iterate_ast(node.value, lambda);
+ }
+ };
+#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
+
template<class T>
struct ast_iterator<std::reference_wrapper<T>, void> {
using node_type = std::reference_wrapper<T>;
template<class L>
- void operator()(const node_type &r, const L &l) const {
- iterate_ast(r.get(), l);
+ void operator()(const node_type& r, const L& lambda) const {
+ iterate_ast(r.get(), lambda);
+ }
+ };
+
+ template<class T>
+ struct ast_iterator<excluded_t<T>, void> {
+ using node_type = excluded_t<T>;
+
+ template<class L>
+ void operator()(const node_type& expression, const L& lambda) const {
+ iterate_ast(expression.expression, lambda);
+ }
+ };
+
+ template<class... TargetArgs, class... ActionsArgs>
+ struct ast_iterator<upsert_clause<std::tuple<TargetArgs...>, std::tuple<ActionsArgs...>>, void> {
+ using node_type = upsert_clause<std::tuple<TargetArgs...>, std::tuple<ActionsArgs...>>;
+
+ template<class L>
+ void operator()(const node_type& expression, const L& lambda) const {
+ iterate_ast(expression.actions, lambda);
}
};
@@ -7633,8 +10725,8 @@ namespace sqlite_orm {
using node_type = where_t<C>;
template<class L>
- void operator()(const node_type &where, const L &l) const {
- iterate_ast(where.c, l);
+ void operator()(const node_type& expression, const L& lambda) const {
+ iterate_ast(expression.expression, lambda);
}
};
@@ -7643,7 +10735,7 @@ namespace sqlite_orm {
using node_type = T;
template<class L>
- void operator()(const node_type &binaryCondition, const L &l) const {
+ void operator()(const node_type& binaryCondition, const L& l) const {
iterate_ast(binaryCondition.l, l);
iterate_ast(binaryCondition.r, l);
}
@@ -7654,7 +10746,7 @@ namespace sqlite_orm {
using node_type = binary_operator<L, R, Ds...>;
template<class C>
- void operator()(const node_type &binaryOperator, const C &l) const {
+ void operator()(const node_type& binaryOperator, const C& l) const {
iterate_ast(binaryOperator.lhs, l);
iterate_ast(binaryOperator.rhs, l);
}
@@ -7665,19 +10757,30 @@ namespace sqlite_orm {
using node_type = columns_t<Args...>;
template<class L>
- void operator()(const node_type &cols, const L &l) const {
+ void operator()(const node_type& cols, const L& l) const {
iterate_ast(cols.columns, l);
}
};
template<class L, class A>
- struct ast_iterator<in_t<L, A>, void> {
- using node_type = in_t<L, A>;
+ struct ast_iterator<dynamic_in_t<L, A>, void> {
+ using node_type = dynamic_in_t<L, A>;
+
+ template<class C>
+ void operator()(const node_type& in, const C& l) const {
+ iterate_ast(in.left, l);
+ iterate_ast(in.argument, l);
+ }
+ };
+
+ template<class L, class... Args>
+ struct ast_iterator<in_t<L, Args...>, void> {
+ using node_type = in_t<L, Args...>;
template<class C>
- void operator()(const node_type &in, const C &l) const {
- iterate_ast(in.l, l);
- iterate_ast(in.arg, l);
+ void operator()(const node_type& in, const C& l) const {
+ iterate_ast(in.left, l);
+ iterate_ast(in.argument, l);
}
};
@@ -7686,8 +10789,8 @@ namespace sqlite_orm {
using node_type = std::vector<T>;
template<class L>
- void operator()(const node_type &vec, const L &l) const {
- for(auto &i: vec) {
+ void operator()(const node_type& vec, const L& l) const {
+ for(auto& i: vec) {
iterate_ast(i, l);
}
}
@@ -7698,7 +10801,7 @@ namespace sqlite_orm {
using node_type = std::vector<char>;
template<class L>
- void operator()(const node_type &vec, const L &l) const {
+ void operator()(const node_type& vec, const L& l) const {
l(vec);
}
};
@@ -7708,18 +10811,48 @@ namespace sqlite_orm {
using node_type = T;
template<class L>
- void operator()(const node_type &c, const L &l) const {
+ void operator()(const node_type& c, const L& l) const {
iterate_ast(c.left, l);
iterate_ast(c.right, l);
}
};
+ template<class T>
+ struct ast_iterator<into_t<T>, void> {
+ using node_type = into_t<T>;
+
+ template<class L>
+ void operator()(const node_type& node, const L& l) const {
+ //..
+ }
+ };
+
+ template<class... Args>
+ struct ast_iterator<insert_raw_t<Args...>, void> {
+ using node_type = insert_raw_t<Args...>;
+
+ template<class L>
+ void operator()(const node_type& node, const L& l) const {
+ iterate_ast(node.args, l);
+ }
+ };
+
+ template<class... Args>
+ struct ast_iterator<replace_raw_t<Args...>, void> {
+ using node_type = replace_raw_t<Args...>;
+
+ template<class L>
+ void operator()(const node_type& node, const L& l) const {
+ iterate_ast(node.args, l);
+ }
+ };
+
template<class T, class... Args>
struct ast_iterator<select_t<T, Args...>, void> {
using node_type = select_t<T, Args...>;
template<class L>
- void operator()(const node_type &sel, const L &l) const {
+ void operator()(const node_type& sel, const L& l) const {
iterate_ast(sel.col, l);
iterate_ast(sel.conditions, l);
}
@@ -7730,7 +10863,7 @@ namespace sqlite_orm {
using node_type = get_all_t<T, R, Args...>;
template<class L>
- void operator()(const node_type &get, const L &l) const {
+ void operator()(const node_type& get, const L& l) const {
iterate_ast(get.conditions, l);
}
};
@@ -7740,7 +10873,7 @@ namespace sqlite_orm {
using node_type = get_all_pointer_t<T, Args...>;
template<class L>
- void operator()(const node_type &get, const L &l) const {
+ void operator()(const node_type& get, const L& l) const {
iterate_ast(get.conditions, l);
}
};
@@ -7751,7 +10884,7 @@ namespace sqlite_orm {
using node_type = get_all_optional_t<T, Args...>;
template<class L>
- void operator()(const node_type &get, const L &l) const {
+ void operator()(const node_type& get, const L& l) const {
iterate_ast(get.conditions, l);
}
};
@@ -7762,7 +10895,7 @@ namespace sqlite_orm {
using node_type = update_all_t<set_t<Args...>, Wargs...>;
template<class L>
- void operator()(const node_type &u, const L &l) const {
+ void operator()(const node_type& u, const L& l) const {
iterate_ast(u.set, l);
iterate_ast(u.conditions, l);
}
@@ -7773,7 +10906,7 @@ namespace sqlite_orm {
using node_type = remove_all_t<T, Args...>;
template<class L>
- void operator()(const node_type &r, const L &l) const {
+ void operator()(const node_type& r, const L& l) const {
iterate_ast(r.conditions, l);
}
};
@@ -7783,7 +10916,7 @@ namespace sqlite_orm {
using node_type = set_t<Args...>;
template<class L>
- void operator()(const node_type &s, const L &l) const {
+ void operator()(const node_type& s, const L& l) const {
iterate_ast(s.assigns, l);
}
};
@@ -7793,8 +10926,8 @@ namespace sqlite_orm {
using node_type = std::tuple<Args...>;
template<class L>
- void operator()(const node_type &tuple, const L &l) const {
- iterate_tuple(tuple, [&l](auto &v) {
+ void operator()(const node_type& tuple, const L& l) const {
+ iterate_tuple(tuple, [&l](auto& v) {
iterate_ast(v, l);
});
}
@@ -7805,7 +10938,7 @@ namespace sqlite_orm {
using node_type = having_t<T>;
template<class L>
- void operator()(const node_type &hav, const L &l) const {
+ void operator()(const node_type& hav, const L& l) const {
iterate_ast(hav.t, l);
}
};
@@ -7815,7 +10948,7 @@ namespace sqlite_orm {
using node_type = cast_t<T, E>;
template<class L>
- void operator()(const node_type &c, const L &l) const {
+ void operator()(const node_type& c, const L& l) const {
iterate_ast(c.expression, l);
}
};
@@ -7825,7 +10958,7 @@ namespace sqlite_orm {
using node_type = exists_t<T>;
template<class L>
- void operator()(const node_type &e, const L &l) const {
+ void operator()(const node_type& e, const L& l) const {
iterate_ast(e.t, l);
}
};
@@ -7835,10 +10968,10 @@ namespace sqlite_orm {
using node_type = like_t<A, T, E>;
template<class L>
- void operator()(const node_type &lk, const L &l) const {
+ void operator()(const node_type& lk, const L& l) const {
iterate_ast(lk.arg, l);
iterate_ast(lk.pattern, l);
- lk.arg3.apply([&l](auto &value) {
+ lk.arg3.apply([&l](auto& value) {
iterate_ast(value, l);
});
}
@@ -7849,7 +10982,7 @@ namespace sqlite_orm {
using node_type = glob_t<A, T>;
template<class L>
- void operator()(const node_type &lk, const L &l) const {
+ void operator()(const node_type& lk, const L& l) const {
iterate_ast(lk.arg, l);
iterate_ast(lk.pattern, l);
}
@@ -7860,7 +10993,7 @@ namespace sqlite_orm {
using node_type = between_t<A, T>;
template<class L>
- void operator()(const node_type &b, const L &l) const {
+ void operator()(const node_type& b, const L& l) const {
iterate_ast(b.expr, l);
iterate_ast(b.b1, l);
iterate_ast(b.b2, l);
@@ -7872,7 +11005,7 @@ namespace sqlite_orm {
using node_type = named_collate<T>;
template<class L>
- void operator()(const node_type &col, const L &l) const {
+ void operator()(const node_type& col, const L& l) const {
iterate_ast(col.expr, l);
}
};
@@ -7882,7 +11015,7 @@ namespace sqlite_orm {
using node_type = negated_condition_t<C>;
template<class L>
- void operator()(const node_type &neg, const L &l) const {
+ void operator()(const node_type& neg, const L& l) const {
iterate_ast(neg.c, l);
}
};
@@ -7892,7 +11025,7 @@ namespace sqlite_orm {
using node_type = is_null_t<T>;
template<class L>
- void operator()(const node_type &i, const L &l) const {
+ void operator()(const node_type& i, const L& l) const {
iterate_ast(i.t, l);
}
};
@@ -7902,17 +11035,27 @@ namespace sqlite_orm {
using node_type = is_not_null_t<T>;
template<class L>
- void operator()(const node_type &i, const L &l) const {
+ void operator()(const node_type& i, const L& l) const {
iterate_ast(i.t, l);
}
};
+ template<class F, class... Args>
+ struct ast_iterator<function_call<F, Args...>, void> {
+ using node_type = function_call<F, Args...>;
+
+ template<class L>
+ void operator()(const node_type& f, const L& l) const {
+ iterate_ast(f.args, l);
+ }
+ };
+
template<class R, class S, class... Args>
- struct ast_iterator<core_function_t<R, S, Args...>, void> {
- using node_type = core_function_t<R, S, Args...>;
+ struct ast_iterator<built_in_function_t<R, S, Args...>, void> {
+ using node_type = built_in_function_t<R, S, Args...>;
template<class L>
- void operator()(const node_type &f, const L &l) const {
+ void operator()(const node_type& f, const L& l) const {
iterate_ast(f.args, l);
}
};
@@ -7922,7 +11065,7 @@ namespace sqlite_orm {
using node_type = left_join_t<T, O>;
template<class L>
- void operator()(const node_type &j, const L &l) const {
+ void operator()(const node_type& j, const L& l) const {
iterate_ast(j.constraint, l);
}
};
@@ -7932,7 +11075,7 @@ namespace sqlite_orm {
using node_type = on_t<T>;
template<class L>
- void operator()(const node_type &o, const L &l) const {
+ void operator()(const node_type& o, const L& l) const {
iterate_ast(o.arg, l);
}
};
@@ -7942,7 +11085,7 @@ namespace sqlite_orm {
using node_type = join_t<T, O>;
template<class L>
- void operator()(const node_type &j, const L &l) const {
+ void operator()(const node_type& j, const L& l) const {
iterate_ast(j.constraint, l);
}
};
@@ -7952,7 +11095,7 @@ namespace sqlite_orm {
using node_type = left_outer_join_t<T, O>;
template<class L>
- void operator()(const node_type &j, const L &l) const {
+ void operator()(const node_type& j, const L& l) const {
iterate_ast(j.constraint, l);
}
};
@@ -7962,7 +11105,7 @@ namespace sqlite_orm {
using node_type = inner_join_t<T, O>;
template<class L>
- void operator()(const node_type &j, const L &l) const {
+ void operator()(const node_type& j, const L& l) const {
iterate_ast(j.constraint, l);
}
};
@@ -7972,15 +11115,15 @@ namespace sqlite_orm {
using node_type = simple_case_t<R, T, E, Args...>;
template<class L>
- void operator()(const node_type &c, const L &l) const {
- c.case_expression.apply([&l](auto &c_) {
+ void operator()(const node_type& c, const L& l) const {
+ c.case_expression.apply([&l](auto& c_) {
iterate_ast(c_, l);
});
- iterate_tuple(c.args, [&l](auto &pair) {
+ iterate_tuple(c.args, [&l](auto& pair) {
iterate_ast(pair.first, l);
iterate_ast(pair.second, l);
});
- c.else_expression.apply([&l](auto &el) {
+ c.else_expression.apply([&l](auto& el) {
iterate_ast(el, l);
});
}
@@ -7991,7 +11134,7 @@ namespace sqlite_orm {
using node_type = as_t<T, E>;
template<class L>
- void operator()(const node_type &a, const L &l) const {
+ void operator()(const node_type& a, const L& l) const {
iterate_ast(a.expression, l);
}
};
@@ -8001,7 +11144,7 @@ namespace sqlite_orm {
using node_type = limit_t<T, false, OI, void>;
template<class L>
- void operator()(const node_type &a, const L &l) const {
+ void operator()(const node_type& a, const L& l) const {
iterate_ast(a.lim, l);
}
};
@@ -8011,9 +11154,9 @@ namespace sqlite_orm {
using node_type = limit_t<T, true, false, O>;
template<class L>
- void operator()(const node_type &a, const L &l) const {
+ void operator()(const node_type& a, const L& l) const {
iterate_ast(a.lim, l);
- a.off.apply([&l](auto &value) {
+ a.off.apply([&l](auto& value) {
iterate_ast(value, l);
});
}
@@ -8024,8 +11167,8 @@ namespace sqlite_orm {
using node_type = limit_t<T, true, true, O>;
template<class L>
- void operator()(const node_type &a, const L &l) const {
- a.off.apply([&l](auto &value) {
+ void operator()(const node_type& a, const L& l) const {
+ a.off.apply([&l](auto& value) {
iterate_ast(value, l);
});
iterate_ast(a.lim, l);
@@ -8037,8 +11180,8 @@ namespace sqlite_orm {
using node_type = distinct_t<T>;
template<class L>
- void operator()(const node_type &a, const L &l) const {
- iterate_ast(a.t, l);
+ void operator()(const node_type& a, const L& l) const {
+ iterate_ast(a.value, l);
}
};
@@ -8047,8 +11190,8 @@ namespace sqlite_orm {
using node_type = all_t<T>;
template<class L>
- void operator()(const node_type &a, const L &l) const {
- iterate_ast(a.t, l);
+ void operator()(const node_type& a, const L& l) const {
+ iterate_ast(a.value, l);
}
};
@@ -8057,7 +11200,7 @@ namespace sqlite_orm {
using node_type = bitwise_not_t<T>;
template<class L>
- void operator()(const node_type &a, const L &l) const {
+ void operator()(const node_type& a, const L& l) const {
iterate_ast(a.argument, l);
}
};
@@ -8067,7 +11210,7 @@ namespace sqlite_orm {
using node_type = values_t<Args...>;
template<class L>
- void operator()(const node_type &node, const L &l) const {
+ void operator()(const node_type& node, const L& l) const {
iterate_ast(node.tuple, l);
}
};
@@ -8077,7 +11220,7 @@ namespace sqlite_orm {
using node_type = dynamic_values_t<T>;
template<class L>
- void operator()(const node_type &node, const L &l) const {
+ void operator()(const node_type& node, const L& l) const {
iterate_ast(node.vector, l);
}
};
@@ -8087,7 +11230,7 @@ namespace sqlite_orm {
using node_type = collate_t<T>;
template<class L>
- void operator()(const node_type &node, const L &l) const {
+ void operator()(const node_type& node, const L& l) const {
iterate_ast(node.expr, l);
}
};
@@ -8103,17 +11246,26 @@ namespace sqlite_orm {
namespace internal {
+ /**
+ * This class does not related to SQL view. This is a container like class which is returned by
+ * by storage_t::iterate function. This class contains STL functions:
+ * - size_t size()
+ * - bool empty()
+ * - iterator end()
+ * - iterator begin()
+ * All these functions are not right const cause all of them may open SQLite connections.
+ */
template<class T, class S, class... Args>
struct view_t {
using mapped_type = T;
using storage_type = S;
using self = view_t<T, S, Args...>;
- storage_type &storage;
+ storage_type& storage;
connection_ref connection;
get_all_t<T, std::vector<T>, Args...> args;
- view_t(storage_type &stor, decltype(connection) conn, Args &&... args_) :
+ view_t(storage_type& stor, decltype(connection) conn, Args&&... args_) :
storage(stor), connection(std::move(conn)), args{std::make_tuple(std::forward<Args>(args_)...)} {}
size_t size() {
@@ -8124,12 +11276,8 @@ namespace sqlite_orm {
return !this->size();
}
- iterator_t<self> end() {
- return {nullptr, *this};
- }
-
iterator_t<self> begin() {
- sqlite3_stmt *stmt = nullptr;
+ sqlite3_stmt* stmt = nullptr;
auto db = this->connection.get();
using context_t = serializator_context<typename storage_type::impl_type>;
context_t context{this->storage.impl};
@@ -8139,7 +11287,7 @@ namespace sqlite_orm {
auto ret = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr);
if(ret == SQLITE_OK) {
auto index = 1;
- iterate_ast(this->args.conditions, [&index, stmt, db](auto &node) {
+ iterate_ast(this->args.conditions, [&index, stmt, db](auto& node) {
using node_type = typename std::decay<decltype(node)>::type;
conditional_binder<node_type, is_bindable<node_type>> binder{stmt, index};
if(SQLITE_OK != binder(node)) {
@@ -8153,6 +11301,10 @@ namespace sqlite_orm {
sqlite3_errmsg(db));
}
}
+
+ iterator_t<self> end() {
+ return {};
+ }
};
}
}
@@ -8179,9 +11331,12 @@ namespace sqlite_orm {
#include <sqlite3.h>
#include <functional> // std::function
#include <memory> // std::shared_ptr
+#include <vector> // std::vector
// #include "error_code.h"
+// #include "util.h"
+
// #include "row_extractor.h"
// #include "journal_mode.h"
@@ -8192,126 +11347,141 @@ namespace sqlite_orm {
namespace internal {
struct storage_base;
- }
-
- struct pragma_t {
- using get_connection_t = std::function<internal::connection_ref()>;
- pragma_t(get_connection_t get_connection_) : get_connection(std::move(get_connection_)) {}
-
- void busy_timeout(int value) {
- this->set_pragma("busy_timeout", value);
+ template<class T>
+ int getPragmaCallback(void* data, int argc, char** argv, char**) {
+ auto& res = *(T*)data;
+ if(argc) {
+ res = row_extractor<T>().extract(argv[0]);
+ }
+ return 0;
}
- int busy_timeout() {
- return this->get_pragma<int>("busy_timeout");
+ template<>
+ inline int getPragmaCallback<std::vector<std::string>>(void* data, int argc, char** argv, char**) {
+ auto& res = *(std::vector<std::string>*)data;
+ res.reserve(argc);
+ for(decltype(argc) i = 0; i < argc; ++i) {
+ auto rowString = row_extractor<std::string>().extract(argv[i]);
+ res.push_back(move(rowString));
+ }
+ return 0;
}
- sqlite_orm::journal_mode journal_mode() {
- return this->get_pragma<sqlite_orm::journal_mode>("journal_mode");
- }
+ struct pragma_t {
+ using get_connection_t = std::function<internal::connection_ref()>;
- void journal_mode(sqlite_orm::journal_mode value) {
- this->_journal_mode = -1;
- this->set_pragma("journal_mode", value);
- this->_journal_mode = static_cast<decltype(this->_journal_mode)>(value);
- }
+ pragma_t(get_connection_t get_connection_) : get_connection(move(get_connection_)) {}
- int synchronous() {
- return this->get_pragma<int>("synchronous");
- }
+ void busy_timeout(int value) {
+ this->set_pragma("busy_timeout", value);
+ }
- void synchronous(int value) {
- this->_synchronous = -1;
- this->set_pragma("synchronous", value);
- this->_synchronous = value;
- }
+ int busy_timeout() {
+ return this->get_pragma<int>("busy_timeout");
+ }
- int user_version() {
- return this->get_pragma<int>("user_version");
- }
+ sqlite_orm::journal_mode journal_mode() {
+ return this->get_pragma<sqlite_orm::journal_mode>("journal_mode");
+ }
- void user_version(int value) {
- this->set_pragma("user_version", value);
- }
+ void journal_mode(sqlite_orm::journal_mode value) {
+ this->_journal_mode = -1;
+ this->set_pragma("journal_mode", value);
+ this->_journal_mode = static_cast<decltype(this->_journal_mode)>(value);
+ }
- int auto_vacuum() {
- return this->get_pragma<int>("auto_vacuum");
- }
+ int synchronous() {
+ return this->get_pragma<int>("synchronous");
+ }
- void auto_vacuum(int value) {
- this->set_pragma("auto_vacuum", value);
- }
+ void synchronous(int value) {
+ this->_synchronous = -1;
+ this->set_pragma("synchronous", value);
+ this->_synchronous = value;
+ }
- protected:
- friend struct storage_base;
+ int user_version() {
+ return this->get_pragma<int>("user_version");
+ }
- public:
- int _synchronous = -1;
- signed char _journal_mode = -1; // if != -1 stores static_cast<sqlite_orm::journal_mode>(journal_mode)
- get_connection_t get_connection;
-
- template<class T>
- T get_pragma(const std::string &name) {
- auto connection = this->get_connection();
- auto query = "PRAGMA " + name;
- T result;
- auto db = connection.get();
- auto rc = sqlite3_exec(
- db,
- query.c_str(),
- [](void *data, int argc, char **argv, char **) -> int {
- auto &res = *(T *)data;
- if(argc) {
- res = row_extractor<T>().extract(argv[0]);
- }
- return 0;
- },
- &result,
- nullptr);
- if(rc == SQLITE_OK) {
- return result;
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
+ void user_version(int value) {
+ this->set_pragma("user_version", value);
}
- }
- /**
- * Yevgeniy Zakharov: I wanted to refactore this function with statements and value bindings
- * but it turns out that bindings in pragma statements are not supported.
- */
- template<class T>
- void set_pragma(const std::string &name, const T &value, sqlite3 *db = nullptr) {
- auto con = this->get_connection();
- if(!db) {
- db = con.get();
+ int auto_vacuum() {
+ return this->get_pragma<int>("auto_vacuum");
}
- std::stringstream ss;
- ss << "PRAGMA " << name << " = " << value;
- auto query = ss.str();
- auto rc = sqlite3_exec(db, query.c_str(), nullptr, nullptr, nullptr);
- if(rc != SQLITE_OK) {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
+
+ void auto_vacuum(int value) {
+ this->set_pragma("auto_vacuum", value);
}
- }
- void set_pragma(const std::string &name, const sqlite_orm::journal_mode &value, sqlite3 *db = nullptr) {
- auto con = this->get_connection();
- if(!db) {
- db = con.get();
+ std::vector<std::string> integrity_check() {
+ return this->get_pragma<std::vector<std::string>>("integrity_check");
}
- std::stringstream ss;
- ss << "PRAGMA " << name << " = " << internal::to_string(value);
- auto query = ss.str();
- auto rc = sqlite3_exec(db, query.c_str(), nullptr, nullptr, nullptr);
- if(rc != SQLITE_OK) {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
+
+ template<class T>
+ std::vector<std::string> integrity_check(T table_name) {
+ std::ostringstream oss;
+ oss << "integrity_check(" << table_name << ")";
+ return this->get_pragma<std::vector<std::string>>(oss.str());
}
- }
- };
+
+ std::vector<std::string> integrity_check(int n) {
+ std::ostringstream oss;
+ oss << "integrity_check(" << n << ")";
+ return this->get_pragma<std::vector<std::string>>(oss.str());
+ }
+
+ private:
+ friend struct storage_base;
+
+ int _synchronous = -1;
+ signed char _journal_mode = -1; // if != -1 stores static_cast<sqlite_orm::journal_mode>(journal_mode)
+ get_connection_t get_connection;
+
+ template<class T>
+ T get_pragma(const std::string& name) {
+ auto connection = this->get_connection();
+ auto query = "PRAGMA " + name;
+ T result;
+ auto db = connection.get();
+ auto rc = sqlite3_exec(db, query.c_str(), getPragmaCallback<T>, &result, nullptr);
+ if(rc == SQLITE_OK) {
+ return result;
+ } else {
+ throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
+ sqlite3_errmsg(db));
+ }
+ }
+
+ /**
+ * Yevgeniy Zakharov: I wanted to refactor this function with statements and value bindings
+ * but it turns out that bindings in pragma statements are not supported.
+ */
+ template<class T>
+ void set_pragma(const std::string& name, const T& value, sqlite3* db = nullptr) {
+ auto con = this->get_connection();
+ if(!db) {
+ db = con.get();
+ }
+ std::stringstream ss;
+ ss << "PRAGMA " << name << " = " << value;
+ internal::perform_void_exec(db, ss.str());
+ }
+
+ void set_pragma(const std::string& name, const sqlite_orm::journal_mode& value, sqlite3* db = nullptr) {
+ auto con = this->get_connection();
+ if(!db) {
+ db = con.get();
+ }
+ std::stringstream ss;
+ ss << "PRAGMA " << name << " = " << internal::to_string(value);
+ internal::perform_void_exec(db, ss.str());
+ }
+ };
+ }
}
// #include "limit_accesor.h"
@@ -8526,10 +11696,12 @@ namespace sqlite_orm {
// #include "type_printer.h"
-// #include "tuple_helper.h"
+// #include "tuple_helper/tuple_helper.h"
// #include "row_extractor.h"
+// #include "util.h"
+
// #include "connection_holder.h"
// #include "backup.h"
@@ -8554,9 +11726,9 @@ namespace sqlite_orm {
*/
struct backup_t {
backup_t(connection_ref to_,
- const std::string &zDestName,
+ const std::string& zDestName,
connection_ref from_,
- const std::string &zSourceName,
+ const std::string& zSourceName,
std::unique_ptr<connection_holder> holder_) :
handle(sqlite3_backup_init(to_.get(), zDestName.c_str(), from_.get(), zSourceName.c_str())),
to(to_), from(from_), holder(move(holder_)) {
@@ -8565,7 +11737,7 @@ namespace sqlite_orm {
}
}
- backup_t(backup_t &&other) :
+ backup_t(backup_t&& other) :
handle(other.handle), to(other.to), from(other.from), holder(move(other.holder)) {
other.handle = nullptr;
}
@@ -8599,7 +11771,7 @@ namespace sqlite_orm {
}
protected:
- sqlite3_backup *handle = nullptr;
+ sqlite3_backup* handle = nullptr;
connection_ref to;
connection_ref from;
std::unique_ptr<connection_holder> holder;
@@ -8607,14 +11779,206 @@ namespace sqlite_orm {
}
}
+// #include "function.h"
+
+// #include "values_to_tuple.h"
+
+#include <sqlite3.h>
+#include <tuple> // std::get, std::tuple_element
+
+// #include "row_extractor.h"
+
+// #include "arg_values.h"
+
+#include <sqlite3.h>
+
+// #include "row_extractor.h"
+
+namespace sqlite_orm {
+
+ struct arg_value {
+
+ arg_value() : arg_value(nullptr) {}
+
+ arg_value(sqlite3_value* value_) : value(value_) {}
+
+ template<class T>
+ T get() const {
+ return row_extractor<T>().extract(this->value);
+ }
+
+ bool is_null() const {
+ auto type = sqlite3_value_type(this->value);
+ return type == SQLITE_NULL;
+ }
+
+ bool is_text() const {
+ auto type = sqlite3_value_type(this->value);
+ return type == SQLITE_TEXT;
+ }
+
+ bool is_integer() const {
+ auto type = sqlite3_value_type(this->value);
+ return type == SQLITE_INTEGER;
+ }
+
+ bool is_float() const {
+ auto type = sqlite3_value_type(this->value);
+ return type == SQLITE_FLOAT;
+ }
+
+ bool is_blob() const {
+ auto type = sqlite3_value_type(this->value);
+ return type == SQLITE_BLOB;
+ }
+
+ bool empty() const {
+ return this->value == nullptr;
+ }
+
+ private:
+ sqlite3_value* value = nullptr;
+ };
+
+ struct arg_values {
+
+ struct iterator {
+
+ iterator(const arg_values& container_, int index_) :
+ container(container_), index(index_),
+ currentValue(index_ < int(container_.size()) ? container_[index_] : arg_value()) {}
+
+ iterator& operator++() {
+ ++this->index;
+ if(this->index < int(this->container.size())) {
+ this->currentValue = this->container[this->index];
+ } else {
+ this->currentValue = {};
+ }
+ return *this;
+ }
+
+ iterator operator++(int) {
+ auto res = *this;
+ ++this->index;
+ if(this->index < int(this->container.size())) {
+ this->currentValue = this->container[this->index];
+ } else {
+ this->currentValue = {};
+ }
+ return res;
+ }
+
+ arg_value operator*() const {
+ if(this->index < int(this->container.size()) && this->index >= 0) {
+ return this->currentValue;
+ } else {
+ throw std::system_error(std::make_error_code(orm_error_code::index_is_out_of_bounds));
+ }
+ }
+
+ arg_value* operator->() const {
+ return &this->currentValue;
+ }
+
+ bool operator==(const iterator& other) const {
+ return &other.container == &this->container && other.index == this->index;
+ }
+
+ bool operator!=(const iterator& other) const {
+ return !(*this == other);
+ }
+
+ private:
+ const arg_values& container;
+ int index = 0;
+ mutable arg_value currentValue;
+ };
+
+ arg_values() : arg_values(0, nullptr) {}
+
+ arg_values(int argsCount_, sqlite3_value** values_) : argsCount(argsCount_), values(values_) {}
+
+ size_t size() const {
+ return this->argsCount;
+ }
+
+ bool empty() const {
+ return 0 == this->argsCount;
+ }
+
+ arg_value operator[](int index) const {
+ if(index < this->argsCount && index >= 0) {
+ auto valuePointer = this->values[index];
+ return {valuePointer};
+ } else {
+ throw std::system_error(std::make_error_code(orm_error_code::index_is_out_of_bounds));
+ }
+ }
+
+ arg_value at(int index) const {
+ return this->operator[](index);
+ }
+
+ iterator begin() const {
+ return {*this, 0};
+ }
+
+ iterator end() const {
+ return {*this, this->argsCount};
+ }
+
+ private:
+ int argsCount = 0;
+ sqlite3_value** values = nullptr;
+ };
+}
+
+namespace sqlite_orm {
+
+ namespace internal {
+
+ /**
+ * T is a std::tuple type
+ * I is index to extract value from values C array to tuple. I must me < std::tuple_size<T>::value
+ */
+ template<class T, int I>
+ struct values_to_tuple {
+
+ void extract(sqlite3_value** values, T& tuple, int argsCount) const {
+ using element_type = typename std::tuple_element<I, T>::type;
+ std::get<I>(tuple) = row_extractor<element_type>().extract(values[I]);
+
+ values_to_tuple<T, I - 1>().extract(values, tuple, argsCount);
+ }
+ };
+
+ template<class T>
+ struct values_to_tuple<T, -1> {
+ void extract(sqlite3_value** values, T& tuple, int argsCount) const {
+ //..
+ }
+ };
+
+ template<>
+ struct values_to_tuple<std::tuple<arg_values>, 0> {
+ void extract(sqlite3_value** values, std::tuple<arg_values>& tuple, int argsCount) const {
+ std::get<0>(tuple) = arg_values(argsCount, values);
+ }
+ };
+ }
+}
+
+// #include "arg_values.h"
+
namespace sqlite_orm {
namespace internal {
struct storage_base {
- using collating_function = std::function<int(int, const void *, int, const void *)>;
+ using collating_function = std::function<int(int, const void*, int, const void*)>;
- std::function<void(sqlite3 *)> on_open;
+ std::function<void(sqlite3*)> on_open;
pragma_t pragma;
limit_accesor limit;
@@ -8625,50 +11989,20 @@ namespace sqlite_orm {
return {this->get_connection(), move(commitFunc), move(rollbackFunc)};
}
- void drop_index(const std::string &indexName) {
- auto con = this->get_connection();
- auto db = con.get();
+ void drop_index(const std::string& indexName) {
std::stringstream ss;
ss << "DROP INDEX '" << indexName + "'";
- auto query = ss.str();
- sqlite3_stmt *stmt;
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- statement_finalizer finalizer{stmt};
- if(sqlite3_step(stmt) == SQLITE_DONE) {
- // done..
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ perform_void_exec(get_connection().get(), ss.str());
}
void vacuum() {
- auto con = this->get_connection();
- auto db = con.get();
- std::string query = "VACUUM";
- sqlite3_stmt *stmt;
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- statement_finalizer finalizer{stmt};
- if(sqlite3_step(stmt) == SQLITE_DONE) {
- // done..
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ perform_void_exec(get_connection().get(), "VACUUM");
}
/**
* Drops table with given name.
*/
- void drop_table(const std::string &tableName) {
+ void drop_table(const std::string& tableName) {
auto con = this->get_connection();
this->drop_table_internal(tableName, con.get());
}
@@ -8676,11 +12010,10 @@ namespace sqlite_orm {
/**
* Rename table named `from` to `to`.
*/
- void rename_table(const std::string &from, const std::string &to) {
- auto con = this->get_connection();
+ void rename_table(const std::string& from, const std::string& to) {
std::stringstream ss;
ss << "ALTER TABLE '" << from << "' RENAME TO '" << to << "'";
- this->perform_query_without_result(ss.str(), con.get());
+ perform_void_exec(get_connection().get(), ss.str());
}
/**
@@ -8716,13 +12049,13 @@ namespace sqlite_orm {
return sqlite3_libversion();
}
- bool transaction(const std::function<bool()> &f) {
- this->begin_transaction();
+ bool transaction(const std::function<bool()>& f) {
+ auto guard = transaction_guard();
auto shouldCommit = f();
if(shouldCommit) {
- this->commit();
+ guard.commit();
} else {
- this->rollback();
+ guard.rollback();
}
return shouldCommit;
}
@@ -8759,8 +12092,8 @@ namespace sqlite_orm {
int res = sqlite3_exec(
db,
sql.c_str(),
- [](void *data, int argc, char **argv, char * * /*columnName*/) -> int {
- auto &tableNames_ = *(data_t *)data;
+ [](void* data, int argc, char** argv, char** /*columnName*/) -> int {
+ auto& tableNames_ = *(data_t*)data;
for(int i = 0; i < argc; i++) {
if(argv[i]) {
tableNames_.push_back(argv[i]);
@@ -8786,9 +12119,166 @@ namespace sqlite_orm {
}
}
- void create_collation(const std::string &name, collating_function f) {
- collating_function *functionPointer = nullptr;
- if(f) {
+ /**
+ * Call this to create user defined scalar function. Can be called at any time no matter connection is opened or no.
+ * T - function class. T must have operator() overload and static name function like this:
+ * ```
+ * struct SqrtFunction {
+ *
+ * double operator()(double arg) const {
+ * return std::sqrt(arg);
+ * }
+ *
+ * static const char *name() {
+ * return "SQRT";
+ * }
+ * };
+ * ```
+ */
+ template<class F>
+ void create_scalar_function() {
+ static_assert(is_scalar_function<F>::value, "F cannot be a scalar function");
+
+ std::stringstream ss;
+ ss << F::name();
+ auto name = ss.str();
+ using args_tuple = typename callable_arguments<F>::args_tuple;
+ using return_type = typename callable_arguments<F>::return_type;
+ auto argsCount = int(std::tuple_size<args_tuple>::value);
+ if(std::is_same<args_tuple, std::tuple<arg_values>>::value) {
+ argsCount = -1;
+ }
+ this->scalarFunctions.emplace_back(new scalar_function_t{
+ move(name),
+ argsCount,
+ []() -> int* {
+ return (int*)(new F());
+ },
+ /* call = */
+ [](sqlite3_context* context, void* functionVoidPointer, int argsCount, sqlite3_value** values) {
+ auto& functionPointer = *static_cast<F*>(functionVoidPointer);
+ args_tuple argsTuple;
+ using tuple_size = std::tuple_size<args_tuple>;
+ values_to_tuple<args_tuple, tuple_size::value - 1>().extract(values, argsTuple, argsCount);
+ auto result = call(functionPointer, std::move(argsTuple));
+ statement_binder<return_type>().result(context, result);
+ },
+ delete_function_callback<F>,
+ });
+
+ if(this->connection->retain_count() > 0) {
+ auto db = this->connection->get();
+ try_to_create_function(db, static_cast<scalar_function_t&>(*this->scalarFunctions.back()));
+ }
+ }
+
+ /**
+ * Call this to create user defined aggregate function. Can be called at any time no matter connection is opened or no.
+ * T - function class. T must have step member function, fin member function and static name function like this:
+ * ```
+ * struct MeanFunction {
+ * double total = 0;
+ * int count = 0;
+ *
+ * void step(double value) {
+ * total += value;
+ * ++count;
+ * }
+ *
+ * int fin() const {
+ * return total / count;
+ * }
+ *
+ * static std::string name() {
+ * return "MEAN";
+ * }
+ * };
+ * ```
+ */
+ template<class F>
+ void create_aggregate_function() {
+ static_assert(is_aggregate_function<F>::value, "F cannot be an aggregate function");
+
+ std::stringstream ss;
+ ss << F::name();
+ auto name = ss.str();
+ using args_tuple = typename callable_arguments<F>::args_tuple;
+ using return_type = typename callable_arguments<F>::return_type;
+ auto argsCount = int(std::tuple_size<args_tuple>::value);
+ if(std::is_same<args_tuple, std::tuple<arg_values>>::value) {
+ argsCount = -1;
+ }
+ this->aggregateFunctions.emplace_back(new aggregate_function_t{
+ move(name),
+ argsCount,
+ /* create = */
+ []() -> int* {
+ return (int*)(new F());
+ },
+ /* step = */
+ [](sqlite3_context* context, void* functionVoidPointer, int argsCount, sqlite3_value** values) {
+ auto& functionPointer = *static_cast<F*>(functionVoidPointer);
+ args_tuple argsTuple;
+ using tuple_size = std::tuple_size<args_tuple>;
+ values_to_tuple<args_tuple, tuple_size::value - 1>().extract(values, argsTuple, argsCount);
+ call(functionPointer, &F::step, move(argsTuple));
+ },
+ /* finalCall = */
+ [](sqlite3_context* context, void* functionVoidPointer) {
+ auto& functionPointer = *static_cast<F*>(functionVoidPointer);
+ auto result = functionPointer.fin();
+ statement_binder<return_type>().result(context, result);
+ },
+ delete_function_callback<F>,
+ });
+
+ if(this->connection->retain_count() > 0) {
+ auto db = this->connection->get();
+ try_to_create_function(db, static_cast<aggregate_function_t&>(*this->aggregateFunctions.back()));
+ }
+ }
+
+ /**
+ * Use it to delete scalar function you created before. Can be called at any time no matter connection is open or no.
+ */
+ template<class F>
+ void delete_scalar_function() {
+ static_assert(is_scalar_function<F>::value, "F cannot be a scalar function");
+ std::stringstream ss;
+ ss << F::name();
+ auto name = ss.str();
+ this->delete_function_impl(name, this->scalarFunctions);
+ }
+
+ /**
+ * Use it to delete aggregate function you created before. Can be called at any time no matter connection is open or no.
+ */
+ template<class F>
+ void delete_aggregate_function() {
+ static_assert(is_aggregate_function<F>::value, "F cannot be an aggregate function");
+ std::stringstream ss;
+ ss << F::name();
+ auto name = ss.str();
+ this->delete_function_impl(name, this->aggregateFunctions);
+ }
+
+ template<class C>
+ void create_collation() {
+ collating_function func = [](int leftLength, const void* lhs, int rightLength, const void* rhs) {
+ C collatingObject;
+ return collatingObject(leftLength, lhs, rightLength, rhs);
+ };
+ std::stringstream ss;
+ ss << C::name();
+ auto name = ss.str();
+ ss.flush();
+ this->create_collation(name, move(func));
+ }
+
+ void create_collation(const std::string& name, collating_function f) {
+ collating_function* functionPointer = nullptr;
+ const auto functionExists = bool(f);
+ if(functionExists) {
functionPointer = &(collatingFunctions[name] = std::move(f));
} else {
collatingFunctions.erase(name);
@@ -8797,29 +12287,39 @@ namespace sqlite_orm {
// create collations if db is open
if(this->connection->retain_count() > 0) {
auto db = this->connection->get();
- if(sqlite3_create_collation(db,
- name.c_str(),
- SQLITE_UTF8,
- functionPointer,
- f ? collate_callback : nullptr) != SQLITE_OK) {
+ auto resultCode = sqlite3_create_collation(db,
+ name.c_str(),
+ SQLITE_UTF8,
+ functionPointer,
+ functionExists ? collate_callback : nullptr);
+ if(resultCode != SQLITE_OK) {
throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
sqlite3_errmsg(db));
}
}
}
+ template<class C>
+ void delete_collation() {
+ std::stringstream ss;
+ ss << C::name();
+ auto name = ss.str();
+ ss.flush();
+ this->create_collation(name, {});
+ }
+
void begin_transaction() {
this->connection->retain();
if(1 == this->connection->retain_count()) {
this->on_open_internal(this->connection->get());
}
auto db = this->connection->get();
- this->begin_transaction(db);
+ perform_void_exec(db, "BEGIN TRANSACTION");
}
void commit() {
auto db = this->connection->get();
- this->commit(db);
+ perform_void_exec(db, "COMMIT");
this->connection->release();
if(this->connection->retain_count() < 0) {
throw std::system_error(std::make_error_code(orm_error_code::no_active_transaction));
@@ -8828,54 +12328,54 @@ namespace sqlite_orm {
void rollback() {
auto db = this->connection->get();
- this->rollback(db);
+ perform_void_exec(db, "ROLLBACK");
this->connection->release();
if(this->connection->retain_count() < 0) {
throw std::system_error(std::make_error_code(orm_error_code::no_active_transaction));
}
}
- void backup_to(const std::string &filename) {
+ void backup_to(const std::string& filename) {
auto backup = this->make_backup_to(filename);
backup.step(-1);
}
- void backup_to(storage_base &other) {
+ void backup_to(storage_base& other) {
auto backup = this->make_backup_to(other);
backup.step(-1);
}
- void backup_from(const std::string &filename) {
+ void backup_from(const std::string& filename) {
auto backup = this->make_backup_from(filename);
backup.step(-1);
}
- void backup_from(storage_base &other) {
+ void backup_from(storage_base& other) {
auto backup = this->make_backup_from(other);
backup.step(-1);
}
- backup_t make_backup_to(const std::string &filename) {
+ backup_t make_backup_to(const std::string& filename) {
auto holder = std::make_unique<connection_holder>(filename);
connection_ref conRef{*holder};
return {conRef, "main", this->get_connection(), "main", move(holder)};
}
- backup_t make_backup_to(storage_base &other) {
+ backup_t make_backup_to(storage_base& other) {
return {other.get_connection(), "main", this->get_connection(), "main", {}};
}
- backup_t make_backup_from(const std::string &filename) {
+ backup_t make_backup_from(const std::string& filename) {
auto holder = std::make_unique<connection_holder>(filename);
connection_ref conRef{*holder};
return {this->get_connection(), "main", conRef, "main", move(holder)};
}
- backup_t make_backup_from(storage_base &other) {
+ backup_t make_backup_from(storage_base& other) {
return {this->get_connection(), "main", other.get_connection(), "main", {}};
}
- const std::string &filename() const {
+ const std::string& filename() const {
return this->connection->filename;
}
@@ -8901,7 +12401,7 @@ namespace sqlite_orm {
}
protected:
- storage_base(const std::string &filename_, int foreignKeysCount) :
+ storage_base(const std::string& filename_, int foreignKeysCount) :
pragma(std::bind(&storage_base::get_connection, this)),
limit(std::bind(&storage_base::get_connection, this)),
inMemory(filename_.empty() || filename_ == ":memory:"),
@@ -8912,7 +12412,7 @@ namespace sqlite_orm {
}
}
- storage_base(const storage_base &other) :
+ storage_base(const storage_base& other) :
on_open(other.on_open), pragma(std::bind(&storage_base::get_connection, this)),
limit(std::bind(&storage_base::get_connection, this)), inMemory(other.inMemory),
connection(std::make_unique<connection_holder>(other.connection->filename)),
@@ -8932,13 +12432,6 @@ namespace sqlite_orm {
}
}
- const bool inMemory;
- bool isOpenedForever = false;
- std::unique_ptr<connection_holder> connection;
- std::map<std::string, collating_function> collatingFunctions;
- const int cachedForeignKeysCount;
- std::function<int(int)> _busy_handler;
-
public:
connection_ref get_connection() {
connection_ref res{*this->connection};
@@ -8948,28 +12441,22 @@ namespace sqlite_orm {
return res;
}
- protected:
#if SQLITE_VERSION_NUMBER >= 3006019
- void foreign_keys(sqlite3 *db, bool value) {
+ void foreign_keys(sqlite3* db, bool value) {
std::stringstream ss;
ss << "PRAGMA foreign_keys = " << value;
- auto query = ss.str();
- auto rc = sqlite3_exec(db, query.c_str(), nullptr, nullptr, nullptr);
- if(rc != SQLITE_OK) {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ perform_void_exec(db, ss.str());
}
- bool foreign_keys(sqlite3 *db) {
+ bool foreign_keys(sqlite3* db) {
std::string query = "PRAGMA foreign_keys";
auto result = false;
auto rc = sqlite3_exec(
db,
query.c_str(),
- [](void *data, int argc, char **argv, char **) -> int {
- auto &res = *(bool *)data;
+ [](void* data, int argc, char** argv, char**) -> int {
+ auto& res = *(bool*)data;
if(argc) {
res = row_extractor<bool>().extract(argv[0]);
}
@@ -8985,7 +12472,7 @@ namespace sqlite_orm {
}
#endif
- void on_open_internal(sqlite3 *db) {
+ void on_open_internal(sqlite3* db) {
#if SQLITE_VERSION_NUMBER >= 3006019
if(this->cachedForeignKeysCount) {
@@ -9000,15 +12487,16 @@ namespace sqlite_orm {
this->pragma.set_pragma("journal_mode", static_cast<journal_mode>(this->pragma._journal_mode), db);
}
- for(auto &p: this->collatingFunctions) {
- if(sqlite3_create_collation(db, p.first.c_str(), SQLITE_UTF8, &p.second, collate_callback) !=
- SQLITE_OK) {
+ for(auto& p: this->collatingFunctions) {
+ auto resultCode =
+ sqlite3_create_collation(db, p.first.c_str(), SQLITE_UTF8, &p.second, collate_callback);
+ if(resultCode != SQLITE_OK) {
throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
sqlite3_errmsg(db));
}
}
- for(auto &p: this->limit.limits) {
+ for(auto& p: this->limit.limits) {
sqlite3_limit(db, p.first, p.second);
}
@@ -9016,69 +12504,120 @@ namespace sqlite_orm {
sqlite3_busy_handler(this->connection->get(), busy_handler_callback, this);
}
+ for(auto& functionPointer: this->scalarFunctions) {
+ try_to_create_function(db, static_cast<scalar_function_t&>(*functionPointer));
+ }
+
+ for(auto& functionPointer: this->aggregateFunctions) {
+ try_to_create_function(db, static_cast<aggregate_function_t&>(*functionPointer));
+ }
+
if(this->on_open) {
this->on_open(db);
}
}
- void begin_transaction(sqlite3 *db) {
- std::stringstream ss;
- ss << "BEGIN TRANSACTION";
- auto query = ss.str();
- sqlite3_stmt *stmt;
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- statement_finalizer finalizer{stmt};
- if(sqlite3_step(stmt) == SQLITE_DONE) {
- // done..
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
+ void delete_function_impl(const std::string& name,
+ std::vector<std::unique_ptr<function_base>>& functionsVector) const {
+ auto it = find_if(functionsVector.begin(), functionsVector.end(), [&name](auto& functionPointer) {
+ return functionPointer->name == name;
+ });
+ if(it != functionsVector.end()) {
+ functionsVector.erase(it);
+ it = functionsVector.end();
+
+ if(this->connection->retain_count() > 0) {
+ auto db = this->connection->get();
+ auto resultCode = sqlite3_create_function_v2(db,
+ name.c_str(),
+ 0,
+ SQLITE_UTF8,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr);
+ if(resultCode != SQLITE_OK) {
+ throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
+ sqlite3_errmsg(db));
+ }
}
} else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
+ throw std::system_error(std::make_error_code(orm_error_code::function_not_found));
}
}
- void commit(sqlite3 *db) {
- std::stringstream ss;
- ss << "COMMIT";
- auto query = ss.str();
- sqlite3_stmt *stmt;
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- statement_finalizer finalizer{stmt};
- if(sqlite3_step(stmt) == SQLITE_DONE) {
- // done..
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
- } else {
+ void try_to_create_function(sqlite3* db, scalar_function_t& function) {
+ auto resultCode = sqlite3_create_function_v2(db,
+ function.name.c_str(),
+ function.argumentsCount,
+ SQLITE_UTF8,
+ &function,
+ scalar_function_callback,
+ nullptr,
+ nullptr,
+ nullptr);
+ if(resultCode != SQLITE_OK) {
throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
sqlite3_errmsg(db));
}
}
- void rollback(sqlite3 *db) {
- std::stringstream ss;
- ss << "ROLLBACK";
- auto query = ss.str();
- sqlite3_stmt *stmt;
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- statement_finalizer finalizer{stmt};
- if(sqlite3_step(stmt) == SQLITE_DONE) {
- // done..
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
+ void try_to_create_function(sqlite3* db, aggregate_function_t& function) {
+ auto resultCode = sqlite3_create_function(db,
+ function.name.c_str(),
+ function.argumentsCount,
+ SQLITE_UTF8,
+ &function,
+ nullptr,
+ aggregate_function_step_callback,
+ aggregate_function_final_callback);
+ if(resultCode != SQLITE_OK) {
+ throw std::system_error(std::error_code(resultCode, get_sqlite_error_category()),
+ sqlite3_errstr(resultCode));
+ }
+ }
+
+ static void
+ aggregate_function_step_callback(sqlite3_context* context, int argsCount, sqlite3_value** values) {
+ auto functionVoidPointer = sqlite3_user_data(context);
+ auto functionPointer = static_cast<aggregate_function_t*>(functionVoidPointer);
+ auto aggregateContextVoidPointer = sqlite3_aggregate_context(context, sizeof(int**));
+ auto aggregateContextIntPointer = static_cast<int**>(aggregateContextVoidPointer);
+ if(*aggregateContextIntPointer == nullptr) {
+ *aggregateContextIntPointer = functionPointer->create();
+ }
+ functionPointer->step(context, *aggregateContextIntPointer, argsCount, values);
+ }
+
+ static void aggregate_function_final_callback(sqlite3_context* context) {
+ auto functionVoidPointer = sqlite3_user_data(context);
+ auto functionPointer = static_cast<aggregate_function_t*>(functionVoidPointer);
+ auto aggregateContextVoidPointer = sqlite3_aggregate_context(context, sizeof(int**));
+ auto aggregateContextIntPointer = static_cast<int**>(aggregateContextVoidPointer);
+ functionPointer->finalCall(context, *aggregateContextIntPointer);
+ functionPointer->destroy(*aggregateContextIntPointer);
+ }
+
+ static void scalar_function_callback(sqlite3_context* context, int argsCount, sqlite3_value** values) {
+ auto functionVoidPointer = sqlite3_user_data(context);
+ auto functionPointer = static_cast<scalar_function_t*>(functionVoidPointer);
+ std::unique_ptr<int, void (*)(int*)> callablePointer(functionPointer->create(),
+ functionPointer->destroy);
+ if(functionPointer->argumentsCount != -1 && functionPointer->argumentsCount != argsCount) {
+ throw std::system_error(std::make_error_code(orm_error_code::arguments_count_does_not_match));
}
+ functionPointer->run(context, functionPointer, argsCount, values);
}
- std::string current_timestamp(sqlite3 *db) {
+ template<class F>
+ static void delete_function_callback(int* pointer) {
+ auto voidPointer = static_cast<void*>(pointer);
+ auto fPointer = static_cast<F*>(voidPointer);
+ delete fPointer;
+ }
+
+ std::string current_timestamp(sqlite3* db) {
std::string result;
std::stringstream ss;
ss << "SELECT CURRENT_TIMESTAMP";
@@ -9086,8 +12625,8 @@ namespace sqlite_orm {
auto rc = sqlite3_exec(
db,
query.c_str(),
- [](void *data, int argc, char **argv, char **) -> int {
- auto &res = *(std::string *)data;
+ [](void* data, int argc, char** argv, char**) -> int {
+ auto& res = *(std::string*)data;
if(argc) {
if(argv[0]) {
res = row_extractor<std::string>().extract(argv[0]);
@@ -9104,35 +12643,19 @@ namespace sqlite_orm {
return result;
}
- void drop_table_internal(const std::string &tableName, sqlite3 *db) {
+ void drop_table_internal(const std::string& tableName, sqlite3* db) {
std::stringstream ss;
ss << "DROP TABLE '" << tableName + "'";
- this->perform_query_without_result(ss.str(), db);
+ perform_void_exec(db, ss.str());
}
- void perform_query_without_result(const std::string &query, sqlite3 *db) {
- sqlite3_stmt *stmt;
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- statement_finalizer finalizer{stmt};
- if(sqlite3_step(stmt) == SQLITE_DONE) {
- // done..
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
- }
-
- static int collate_callback(void *arg, int leftLen, const void *lhs, int rightLen, const void *rhs) {
- auto &f = *(collating_function *)arg;
+ static int collate_callback(void* arg, int leftLen, const void* lhs, int rightLen, const void* rhs) {
+ auto& f = *(collating_function*)arg;
return f(leftLen, lhs, rightLen, rhs);
}
- static int busy_handler_callback(void *selfPointer, int triesCount) {
- auto &storage = *static_cast<storage_base *>(selfPointer);
+ static int busy_handler_callback(void* selfPointer, int triesCount) {
+ auto& storage = *static_cast<storage_base*>(selfPointer);
if(storage._busy_handler) {
return storage._busy_handler(triesCount);
} else {
@@ -9142,13 +12665,22 @@ namespace sqlite_orm {
// returns foreign keys count in storage definition
template<class T>
- static int foreign_keys_count(T &storageImpl) {
+ static int foreign_keys_count(T& storageImpl) {
auto res = 0;
- storageImpl.for_each([&res](auto &impl) {
+ storageImpl.for_each([&res](auto& impl) {
res += impl.foreign_keys_count();
});
return res;
}
+
+ const bool inMemory;
+ bool isOpenedForever = false;
+ std::unique_ptr<connection_holder> connection;
+ std::map<std::string, collating_function> collatingFunctions;
+ const int cachedForeignKeysCount;
+ std::function<int(int)> _busy_handler;
+ std::vector<std::unique_ptr<function_base>> scalarFunctions;
+ std::vector<std::unique_ptr<function_base>> aggregateFunctions;
};
}
}
@@ -9189,6 +12721,16 @@ namespace sqlite_orm {
using type = typename std::decay<T>::type;
};
+ template<class It, class L, class O>
+ struct expression_object_type<replace_range_t<It, L, O>> {
+ using type = typename replace_range_t<It, L, O>::object_type;
+ };
+
+ template<class It, class L, class O>
+ struct expression_object_type<replace_range_t<std::reference_wrapper<It>, L, O>> {
+ using type = typename replace_range_t<std::reference_wrapper<It>, L, O>::object_type;
+ };
+
template<class T>
struct expression_object_type<insert_t<T>> {
using type = typename std::decay<T>::type;
@@ -9199,6 +12741,17 @@ namespace sqlite_orm {
using type = typename std::decay<T>::type;
};
+ template<class It, class L, class O>
+ struct expression_object_type<insert_range_t<It, L, O>> {
+ using transformer_type = L;
+ using type = typename insert_range_t<It, L, O>::object_type;
+ };
+
+ template<class It, class L, class O>
+ struct expression_object_type<insert_range_t<std::reference_wrapper<It>, L, O>> {
+ using type = typename insert_range_t<std::reference_wrapper<It>, L, O>::object_type;
+ };
+
template<class T, class... Cols>
struct expression_object_type<insert_explicit<T, Cols...>> {
using type = typename std::decay<T>::type;
@@ -9213,7 +12766,7 @@ namespace sqlite_orm {
struct get_ref_t {
template<class O>
- auto &operator()(O &t) const {
+ auto& operator()(O& t) const {
return t;
}
};
@@ -9222,13 +12775,13 @@ namespace sqlite_orm {
struct get_ref_t<std::reference_wrapper<T>> {
template<class O>
- auto &operator()(O &t) const {
+ auto& operator()(O& t) const {
return t.get();
}
};
template<class T>
- auto &get_ref(T &t) {
+ auto& get_ref(T& t) {
using arg_type = typename std::decay<T>::type;
get_ref_t<arg_type> g;
return g(t);
@@ -9241,7 +12794,7 @@ namespace sqlite_orm {
struct get_object_t<const T> : get_object_t<T> {};
template<class T>
- auto &get_object(T &t) {
+ auto& get_object(T& t) {
using expression_type = typename std::decay<T>::type;
get_object_t<expression_type> obj;
return obj(t);
@@ -9252,7 +12805,7 @@ namespace sqlite_orm {
using expression_type = replace_t<T>;
template<class O>
- auto &operator()(O &e) const {
+ auto& operator()(O& e) const {
return get_ref(e.obj);
}
};
@@ -9262,7 +12815,7 @@ namespace sqlite_orm {
using expression_type = insert_t<T>;
template<class O>
- auto &operator()(O &e) const {
+ auto& operator()(O& e) const {
return get_ref(e.obj);
}
};
@@ -9272,7 +12825,7 @@ namespace sqlite_orm {
using expression_type = update_t<T>;
template<class O>
- auto &operator()(O &e) const {
+ auto& operator()(O& e) const {
return get_ref(e.obj);
}
};
@@ -9283,9 +12836,12 @@ namespace sqlite_orm {
#include <sstream> // std::stringstream
#include <string> // std::string
-#include <type_traits> // std::enable_if
+#include <type_traits> // std::enable_if, std::remove_pointer
#include <vector> // std::vector
#include <algorithm> // std::iter_swap
+#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
+#include <optional>
+#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
// #include "core_functions.h"
@@ -9323,8 +12879,12 @@ namespace sqlite_orm {
find_table_name_t find_table_name;
mutable table_name_set table_names;
+ table_name_collector() = default;
+
+ table_name_collector(find_table_name_t _find_table_name) : find_table_name(std::move(_find_table_name)) {}
+
template<class T>
- table_name_set operator()(const T &) const {
+ table_name_set operator()(const T&) const {
return {};
}
@@ -9336,19 +12896,19 @@ namespace sqlite_orm {
}
template<class T, class F>
- void operator()(const column_pointer<T, F> &) const {
+ void operator()(const column_pointer<T, F>&) const {
if(this->find_table_name) {
table_names.insert({this->find_table_name(typeid(T)), ""});
}
}
template<class T, class C>
- void operator()(const alias_column_t<T, C> &a) const {
+ void operator()(const alias_column_t<T, C>& a) const {
(*this)(a.column, alias_extractor<T>::get());
}
template<class T>
- void operator()(const count_asterisk_t<T> &) const {
+ void operator()(const count_asterisk_t<T>&) const {
if(this->find_table_name) {
auto tableName = this->find_table_name(typeid(T));
if(!tableName.empty()) {
@@ -9358,7 +12918,31 @@ namespace sqlite_orm {
}
template<class T>
- void operator()(const asterisk_t<T> &) const {
+ void operator()(const asterisk_t<T>&) const {
+ if(this->find_table_name) {
+ auto tableName = this->find_table_name(typeid(T));
+ table_names.insert(std::make_pair(move(tableName), ""));
+ }
+ }
+
+ template<class T>
+ void operator()(const object_t<T>&) const {
+ if(this->find_table_name) {
+ auto tableName = this->find_table_name(typeid(T));
+ table_names.insert(std::make_pair(move(tableName), ""));
+ }
+ }
+
+ template<class T>
+ void operator()(const table_rowid_t<T>&) const {
+ if(this->find_table_name) {
+ auto tableName = this->find_table_name(typeid(T));
+ table_names.insert(std::make_pair(move(tableName), ""));
+ }
+ }
+
+ template<class T>
+ void operator()(const table_oid_t<T>&) const {
if(this->find_table_name) {
auto tableName = this->find_table_name(typeid(T));
table_names.insert(std::make_pair(move(tableName), ""));
@@ -9366,7 +12950,7 @@ namespace sqlite_orm {
}
template<class T>
- void operator()(const object_t<T> &) const {
+ void operator()(const table__rowid_t<T>&) const {
if(this->find_table_name) {
auto tableName = this->find_table_name(typeid(T));
table_names.insert(std::make_pair(move(tableName), ""));
@@ -9393,14 +12977,14 @@ namespace sqlite_orm {
namespace internal {
template<class T, class C>
- std::string serialize(const T &t, const C &context);
+ std::string serialize(const T& t, const C& context);
template<class T, class SFINAE = void>
struct column_names_getter {
using expression_type = T;
template<class C>
- std::vector<std::string> operator()(const expression_type &t, const C &context) {
+ std::vector<std::string> operator()(const expression_type& t, const C& context) {
auto newContext = context;
newContext.skip_table_name = false;
auto columnName = serialize(t, newContext);
@@ -9413,7 +12997,7 @@ namespace sqlite_orm {
};
template<class T, class C>
- std::vector<std::string> get_column_names(const T &t, const C &context) {
+ std::vector<std::string> get_column_names(const T& t, const C& context) {
column_names_getter<T> serializator;
return serializator(t, context);
}
@@ -9423,7 +13007,7 @@ namespace sqlite_orm {
using expression_type = std::reference_wrapper<T>;
template<class C>
- std::vector<std::string> operator()(const expression_type &expression, const C &context) {
+ std::vector<std::string> operator()(const expression_type& expression, const C& context) {
return get_column_names(expression.get(), context);
}
};
@@ -9433,7 +13017,7 @@ namespace sqlite_orm {
using expression_type = asterisk_t<T>;
template<class C>
- std::vector<std::string> operator()(const expression_type &, const C &) {
+ std::vector<std::string> operator()(const expression_type&, const C&) {
std::vector<std::string> res;
res.push_back("*");
return res;
@@ -9445,7 +13029,7 @@ namespace sqlite_orm {
using expression_type = object_t<T>;
template<class C>
- std::vector<std::string> operator()(const expression_type &, const C &) {
+ std::vector<std::string> operator()(const expression_type&, const C&) {
std::vector<std::string> res;
res.push_back("*");
return res;
@@ -9457,12 +13041,12 @@ namespace sqlite_orm {
using expression_type = columns_t<Args...>;
template<class C>
- std::vector<std::string> operator()(const expression_type &cols, const C &context) {
+ std::vector<std::string> operator()(const expression_type& cols, const C& context) {
std::vector<std::string> columnNames;
columnNames.reserve(static_cast<size_t>(cols.count));
auto newContext = context;
newContext.skip_table_name = false;
- iterate_tuple(cols.columns, [&columnNames, &newContext](auto &m) {
+ iterate_tuple(cols.columns, [&columnNames, &newContext](auto& m) {
auto columnName = serialize(m, newContext);
if(columnName.length()) {
columnNames.push_back(columnName);
@@ -9491,7 +13075,7 @@ namespace sqlite_orm {
struct order_by_serializator;
template<class T, class C>
- std::string serialize_order_by(const T &t, const C &context) {
+ std::string serialize_order_by(const T& t, const C& context) {
order_by_serializator<T> serializator;
return serializator(t, context);
}
@@ -9501,11 +13085,11 @@ namespace sqlite_orm {
using statement_type = order_by_t<O>;
template<class C>
- std::string operator()(const statement_type &orderBy, const C &context) const {
+ std::string operator()(const statement_type& orderBy, const C& context) const {
std::stringstream ss;
auto newContext = context;
newContext.skip_table_name = false;
- auto columnName = serialize(orderBy.o, newContext);
+ auto columnName = serialize(orderBy.expression, newContext);
ss << columnName << " ";
if(orderBy._collate_argument.length()) {
ss << "COLLATE " << orderBy._collate_argument << " ";
@@ -9527,9 +13111,9 @@ namespace sqlite_orm {
using statement_type = dynamic_order_by_t<S>;
template<class C>
- std::string operator()(const statement_type &orderBy, const C &) const {
+ std::string operator()(const statement_type& orderBy, const C&) const {
std::vector<std::string> expressions;
- for(auto &entry: orderBy) {
+ for(auto& entry: orderBy) {
std::string entryString;
{
std::stringstream ss;
@@ -9571,6 +13155,12 @@ namespace sqlite_orm {
// #include "indexed_column.h"
+// #include "function.h"
+
+// #include "ast/upsert_clause.h"
+
+// #include "ast/excluded.h"
+
namespace sqlite_orm {
namespace internal {
@@ -9579,7 +13169,7 @@ namespace sqlite_orm {
struct statement_serializator;
template<class T, class C>
- std::string serialize(const T &t, const C &context) {
+ std::string serialize(const T& t, const C& context) {
statement_serializator<T> serializator;
return serializator(t, context);
}
@@ -9589,7 +13179,7 @@ namespace sqlite_orm {
using statement_type = T;
template<class C>
- std::string operator()(const statement_type &statement, const C &context) {
+ std::string operator()(const statement_type& statement, const C& context) {
if(context.replace_bindable_with_question) {
return "?";
} else {
@@ -9599,11 +13189,38 @@ namespace sqlite_orm {
};
template<class T>
+ struct statement_serializator<excluded_t<T>, void> {
+ using statement_type = excluded_t<T>;
+
+ template<class C>
+ std::string operator()(const statement_type& statement, const C& context) {
+ std::stringstream ss;
+ ss << "excluded.";
+ if(auto columnNamePointer = context.impl.column_name(statement.expression)) {
+ ss << "\"" << *columnNamePointer << "\"";
+ } else {
+ throw std::system_error(std::make_error_code(orm_error_code::column_not_found));
+ }
+ return ss.str();
+ }
+ };
+#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
+ template<class T>
+ struct statement_serializator<as_optional_t<T>, void> {
+ using statement_type = as_optional_t<T>;
+
+ template<class C>
+ std::string operator()(const statement_type& statement, const C& context) {
+ return serialize(statement.value, context);
+ }
+ };
+#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
+ template<class T>
struct statement_serializator<std::reference_wrapper<T>, void> {
using statement_type = std::reference_wrapper<T>;
template<class C>
- std::string operator()(const statement_type &s, const C &context) {
+ std::string operator()(const statement_type& s, const C& context) {
return serialize(s.get(), context);
}
};
@@ -9613,33 +13230,78 @@ namespace sqlite_orm {
using statement_type = std::nullptr_t;
template<class C>
- std::string operator()(const statement_type &, const C &) {
+ std::string operator()(const statement_type&, const C&) {
return "?";
}
};
+#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
+ template<>
+ struct statement_serializator<std::nullopt_t, void> {
+ using statement_type = std::nullopt_t;
+ template<class C>
+ std::string operator()(const statement_type&, const C&) {
+ return "?";
+ }
+ };
+#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
template<class T>
struct statement_serializator<alias_holder<T>, void> {
using statement_type = alias_holder<T>;
template<class C>
- std::string operator()(const statement_type &, const C &) {
+ std::string operator()(const statement_type&, const C&) {
return T::get();
}
};
+ template<class... TargetArgs, class... ActionsArgs>
+ struct statement_serializator<upsert_clause<std::tuple<TargetArgs...>, std::tuple<ActionsArgs...>>, void> {
+ using statement_type = upsert_clause<std::tuple<TargetArgs...>, std::tuple<ActionsArgs...>>;
+
+ template<class C>
+ std::string operator()(const statement_type& statement, const C& context) const {
+ std::stringstream ss;
+ ss << "ON CONFLICT";
+ iterate_tuple(statement.target_args, [&ss, &context](auto& value) {
+ using value_type = typename std::decay<decltype(value)>::type;
+ auto needParenthesis = std::is_member_pointer<value_type>::value;
+ ss << ' ';
+ if(needParenthesis) {
+ ss << '(';
+ }
+ ss << serialize(value, context);
+ if(needParenthesis) {
+ ss << ')';
+ }
+ });
+ ss << ' ' << "DO";
+ if(std::tuple_size<typename statement_type::actions_tuple>::value == 0) {
+ ss << " NOTHING";
+ } else {
+ ss << " UPDATE";
+ auto updateContext = context;
+ updateContext.use_parentheses = false;
+ iterate_tuple(statement.actions, [&ss, &updateContext](auto& value) {
+ ss << ' ' << serialize(value, updateContext);
+ });
+ }
+ return ss.str();
+ }
+ };
+
template<class R, class S, class... Args>
- struct statement_serializator<core_function_t<R, S, Args...>, void> {
- using statement_type = core_function_t<R, S, Args...>;
+ struct statement_serializator<built_in_function_t<R, S, Args...>, void> {
+ using statement_type = built_in_function_t<R, S, Args...>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& statement, const C& context) const {
std::stringstream ss;
- ss << static_cast<std::string>(c) << "(";
+ ss << statement.serialize() << "(";
std::vector<std::string> args;
- using args_type = typename std::decay<decltype(c)>::type::args_type;
+ using args_type = typename std::decay<decltype(statement)>::type::args_type;
args.reserve(std::tuple_size<args_type>::value);
- iterate_tuple(c.args, [&args, &context](auto &v) {
+ iterate_tuple(statement.args, [&args, &context](auto& v) {
args.push_back(serialize(v, context));
});
for(size_t i = 0; i < args.size(); ++i) {
@@ -9653,12 +13315,36 @@ namespace sqlite_orm {
}
};
+ template<class F, class... Args>
+ struct statement_serializator<function_call<F, Args...>, void> {
+ using statement_type = function_call<F, Args...>;
+
+ template<class C>
+ std::string operator()(const statement_type& statement, const C& context) const {
+ using args_tuple = std::tuple<Args...>;
+
+ std::stringstream ss;
+ ss << F::name() << "(";
+ auto index = 0;
+ iterate_tuple(statement.args, [&context, &ss, &index](auto& v) {
+ auto value = serialize(v, context);
+ ss << value;
+ if(index < std::tuple_size<args_tuple>::value - 1) {
+ ss << ", ";
+ }
+ ++index;
+ });
+ ss << ")";
+ return ss.str();
+ }
+ };
+
template<class T, class E>
struct statement_serializator<as_t<T, E>, void> {
using statement_type = as_t<T, E>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
auto tableAliasString = alias_extractor<T>::get();
return serialize(c.expression, context) + " AS " + tableAliasString;
}
@@ -9669,7 +13355,7 @@ namespace sqlite_orm {
using statement_type = alias_column_t<T, P>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
std::stringstream ss;
if(!context.skip_table_name) {
ss << "'" << T::get() << "'.";
@@ -9686,21 +13372,21 @@ namespace sqlite_orm {
using statement_type = std::string;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
if(context.replace_bindable_with_question) {
return "?";
} else {
- return "\"" + c + "\"";
+ return "\'" + c + "\'";
}
}
};
template<>
- struct statement_serializator<const char *, void> {
- using statement_type = const char *;
+ struct statement_serializator<const char*, void> {
+ using statement_type = const char*;
template<class C>
- std::string operator()(const char *c, const C &context) const {
+ std::string operator()(const char* c, const C& context) const {
if(context.replace_bindable_with_question) {
return "?";
} else {
@@ -9714,12 +13400,16 @@ namespace sqlite_orm {
using statement_type = F O::*;
template<class C>
- std::string operator()(const statement_type &m, const C &context) const {
+ std::string operator()(const statement_type& m, const C& context) const {
std::stringstream ss;
if(!context.skip_table_name) {
ss << "\"" << context.impl.find_table_name(typeid(O)) << "\".";
}
- ss << "\"" << context.column_name(m) << "\"";
+ if(auto columnnamePointer = context.column_name(m)) {
+ ss << "\"" << *columnnamePointer << "\"";
+ } else {
+ throw std::system_error(std::make_error_code(orm_error_code::column_not_found));
+ }
return ss.str();
}
};
@@ -9729,7 +13419,7 @@ namespace sqlite_orm {
using statement_type = rowid_t;
template<class C>
- std::string operator()(const statement_type &s, const C &) {
+ std::string operator()(const statement_type& s, const C&) {
return static_cast<std::string>(s);
}
};
@@ -9739,7 +13429,7 @@ namespace sqlite_orm {
using statement_type = oid_t;
template<class C>
- std::string operator()(const statement_type &s, const C &) {
+ std::string operator()(const statement_type& s, const C&) {
return static_cast<std::string>(s);
}
};
@@ -9749,7 +13439,7 @@ namespace sqlite_orm {
using statement_type = _rowid_t;
template<class C>
- std::string operator()(const statement_type &s, const C &) {
+ std::string operator()(const statement_type& s, const C&) {
return static_cast<std::string>(s);
}
};
@@ -9759,7 +13449,7 @@ namespace sqlite_orm {
using statement_type = table_rowid_t<O>;
template<class C>
- std::string operator()(const statement_type &s, const C &context) {
+ std::string operator()(const statement_type& s, const C& context) {
std::stringstream ss;
if(!context.skip_table_name) {
ss << "'" << context.impl.find_table_name(typeid(O)) << "'.";
@@ -9774,7 +13464,7 @@ namespace sqlite_orm {
using statement_type = table_oid_t<O>;
template<class C>
- std::string operator()(const statement_type &s, const C &context) {
+ std::string operator()(const statement_type& s, const C& context) {
std::stringstream ss;
if(!context.skip_table_name) {
ss << "'" << context.impl.find_table_name(typeid(O)) << "'.";
@@ -9789,7 +13479,7 @@ namespace sqlite_orm {
using statement_type = table__rowid_t<O>;
template<class C>
- std::string operator()(const statement_type &s, const C &context) {
+ std::string operator()(const statement_type& s, const C& context) {
std::stringstream ss;
if(!context.skip_table_name) {
ss << "'" << context.impl.find_table_name(typeid(O)) << "'.";
@@ -9804,11 +13494,17 @@ namespace sqlite_orm {
using statement_type = binary_operator<L, R, Ds...>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
auto lhs = serialize(c.lhs, context);
auto rhs = serialize(c.rhs, context);
std::stringstream ss;
- ss << "(" << lhs << " " << static_cast<std::string>(c) << " " << rhs << ")";
+ if(context.use_parentheses) {
+ ss << '(';
+ }
+ ss << lhs << " " << static_cast<std::string>(c) << " " << rhs;
+ if(context.use_parentheses) {
+ ss << ')';
+ }
return ss.str();
}
};
@@ -9818,7 +13514,7 @@ namespace sqlite_orm {
using statement_type = count_asterisk_t<T>;
template<class C>
- std::string operator()(const statement_type &, const C &context) const {
+ std::string operator()(const statement_type&, const C& context) const {
return serialize(count_asterisk_without_type{}, context);
}
};
@@ -9828,9 +13524,10 @@ namespace sqlite_orm {
using statement_type = count_asterisk_without_type;
template<class C>
- std::string operator()(const statement_type &c, const C &) const {
+ std::string operator()(const statement_type& c, const C&) const {
std::stringstream ss;
- ss << static_cast<std::string>(c) << "(*)";
+ auto functionName = c.serialize();
+ ss << functionName << "(*)";
return ss.str();
}
};
@@ -9840,9 +13537,9 @@ namespace sqlite_orm {
using statement_type = distinct_t<T>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
std::stringstream ss;
- auto expr = serialize(c.t, context);
+ auto expr = serialize(c.value, context);
ss << static_cast<std::string>(c) << "(" << expr << ")";
return ss.str();
}
@@ -9853,9 +13550,9 @@ namespace sqlite_orm {
using statement_type = all_t<T>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
std::stringstream ss;
- auto expr = serialize(c.t, context);
+ auto expr = serialize(c.value, context);
ss << static_cast<std::string>(c) << "(" << expr << ")";
return ss.str();
}
@@ -9866,12 +13563,16 @@ namespace sqlite_orm {
using statement_type = column_pointer<T, F>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
std::stringstream ss;
if(!context.skip_table_name) {
ss << "'" << context.impl.find_table_name(typeid(T)) << "'.";
}
- ss << "\"" << context.impl.column_name_simple(c.field) << "\"";
+ if(auto columnNamePointer = context.impl.column_name_simple(c.field)) {
+ ss << "\"" << *columnNamePointer << "\"";
+ } else {
+ throw std::system_error(std::make_error_code(orm_error_code::column_not_found));
+ }
return ss.str();
}
};
@@ -9881,7 +13582,7 @@ namespace sqlite_orm {
using statement_type = cast_t<T, E>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
std::stringstream ss;
ss << static_cast<std::string>(c) << " (";
ss << serialize(c.expression, context) << " AS " << type_printer<T>().print() << ")";
@@ -9895,7 +13596,7 @@ namespace sqlite_orm {
using statement_type = T;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
std::stringstream ss;
ss << serialize(c.left, context) << " ";
ss << static_cast<std::string>(c) << " ";
@@ -9909,17 +13610,17 @@ namespace sqlite_orm {
using statement_type = simple_case_t<R, T, E, Args...>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
std::stringstream ss;
ss << "CASE ";
- c.case_expression.apply([&ss, context](auto &c_) {
+ c.case_expression.apply([&ss, context](auto& c_) {
ss << serialize(c_, context) << " ";
});
- iterate_tuple(c.args, [&ss, context](auto &pair) {
+ iterate_tuple(c.args, [&ss, context](auto& pair) {
ss << "WHEN " << serialize(pair.first, context) << " ";
ss << "THEN " << serialize(pair.second, context) << " ";
});
- c.else_expression.apply([&ss, context](auto &el) {
+ c.else_expression.apply([&ss, context](auto& el) {
ss << "ELSE " << serialize(el, context) << " ";
});
ss << "END";
@@ -9932,7 +13633,7 @@ namespace sqlite_orm {
using statement_type = is_null_t<T>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
std::stringstream ss;
ss << serialize(c.t, context) << " " << static_cast<std::string>(c);
return ss.str();
@@ -9944,7 +13645,7 @@ namespace sqlite_orm {
using statement_type = is_not_null_t<T>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
std::stringstream ss;
ss << serialize(c.t, context) << " " << static_cast<std::string>(c);
return ss.str();
@@ -9956,7 +13657,7 @@ namespace sqlite_orm {
using statement_type = bitwise_not_t<T>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
std::stringstream ss;
ss << static_cast<std::string>(c) << " ";
auto cString = serialize(c.argument, context);
@@ -9970,7 +13671,7 @@ namespace sqlite_orm {
using statement_type = negated_condition_t<T>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
std::stringstream ss;
ss << static_cast<std::string>(c) << " ";
auto cString = serialize(c.c, context);
@@ -9985,7 +13686,7 @@ namespace sqlite_orm {
using statement_type = T;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
auto leftString = serialize(c.l, context);
auto rightString = serialize(c.r, context);
std::stringstream ss;
@@ -10005,7 +13706,7 @@ namespace sqlite_orm {
using statement_type = named_collate<T>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
auto newContext = context;
newContext.use_parentheses = false;
auto res = serialize(c.expr, newContext);
@@ -10018,7 +13719,7 @@ namespace sqlite_orm {
using statement_type = collate_t<T>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
auto newContext = context;
newContext.use_parentheses = false;
auto res = serialize(c.expr, newContext);
@@ -10027,44 +13728,64 @@ namespace sqlite_orm {
};
template<class L, class A>
- struct statement_serializator<in_t<L, A>, void> {
- using statement_type = in_t<L, A>;
+ struct statement_serializator<dynamic_in_t<L, A>, void> {
+ using statement_type = dynamic_in_t<L, A>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
std::stringstream ss;
- auto leftString = serialize(c.l, context);
+ auto leftString = serialize(c.left, context);
ss << leftString << " " << static_cast<std::string>(c) << " ";
auto newContext = context;
newContext.use_parentheses = true;
- ss << serialize(c.arg, newContext);
+ ss << serialize(c.argument, newContext);
return ss.str();
}
};
template<class L, class E>
- struct statement_serializator<in_t<L, std::vector<E>>, void> {
- using statement_type = in_t<L, std::vector<E>>;
+ struct statement_serializator<dynamic_in_t<L, std::vector<E>>, void> {
+ using statement_type = dynamic_in_t<L, std::vector<E>>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
std::stringstream ss;
- auto leftString = serialize(c.l, context);
- if(context.use_parentheses) {
- ss << '(';
- }
- ss << leftString << " " << static_cast<std::string>(c) << " ( ";
- for(size_t index = 0; index < c.arg.size(); ++index) {
- auto &value = c.arg[index];
- ss << " " << serialize(value, context);
- if(index < c.arg.size() - 1) {
+ auto leftString = serialize(c.left, context);
+ ss << leftString << " " << static_cast<std::string>(c) << " (";
+ for(size_t index = 0; index < c.argument.size(); ++index) {
+ auto& value = c.argument[index];
+ ss << serialize(value, context);
+ if(index < c.argument.size() - 1) {
ss << ", ";
}
}
- ss << " )";
- if(context.use_parentheses) {
- ss << ')';
+ ss << ")";
+ return ss.str();
+ }
+ };
+
+ template<class L, class... Args>
+ struct statement_serializator<in_t<L, Args...>, void> {
+ using statement_type = in_t<L, Args...>;
+
+ template<class C>
+ std::string operator()(const statement_type& c, const C& context) const {
+ std::stringstream ss;
+ auto leftString = serialize(c.left, context);
+ ss << leftString << " " << static_cast<std::string>(c) << " (";
+ std::vector<std::string> args;
+ using args_type = std::tuple<Args...>;
+ args.reserve(std::tuple_size<args_type>::value);
+ iterate_tuple(c.argument, [&args, &context](auto& v) {
+ args.push_back(serialize(v, context));
+ });
+ for(size_t i = 0; i < args.size(); ++i) {
+ ss << args[i];
+ if(i < args.size() - 1) {
+ ss << ", ";
+ }
}
+ ss << ")";
return ss.str();
}
};
@@ -10074,12 +13795,12 @@ namespace sqlite_orm {
using statement_type = like_t<A, T, E>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
std::stringstream ss;
ss << serialize(c.arg, context) << " ";
ss << static_cast<std::string>(c) << " ";
ss << serialize(c.pattern, context);
- c.arg3.apply([&ss, &context](auto &value) {
+ c.arg3.apply([&ss, &context](auto& value) {
ss << " ESCAPE " << serialize(value, context);
});
return ss.str();
@@ -10091,7 +13812,7 @@ namespace sqlite_orm {
using statement_type = glob_t<A, T>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
std::stringstream ss;
ss << serialize(c.arg, context) << " ";
ss << static_cast<std::string>(c) << " ";
@@ -10105,7 +13826,7 @@ namespace sqlite_orm {
using statement_type = between_t<A, T>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
std::stringstream ss;
auto expr = serialize(c.expr, context);
ss << expr << " " << static_cast<std::string>(c) << " ";
@@ -10121,7 +13842,7 @@ namespace sqlite_orm {
using statement_type = exists_t<T>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
std::stringstream ss;
ss << static_cast<std::string>(c) << " ";
ss << serialize(c.t, context);
@@ -10130,33 +13851,37 @@ namespace sqlite_orm {
};
template<>
- struct statement_serializator<constraints::autoincrement_t, void> {
- using statement_type = constraints::autoincrement_t;
+ struct statement_serializator<autoincrement_t, void> {
+ using statement_type = autoincrement_t;
template<class C>
- std::string operator()(const statement_type &c, const C &) const {
+ std::string operator()(const statement_type& c, const C&) const {
return static_cast<std::string>(c);
}
};
template<class... Cs>
- struct statement_serializator<constraints::primary_key_t<Cs...>, void> {
- using statement_type = constraints::primary_key_t<Cs...>;
+ struct statement_serializator<primary_key_t<Cs...>, void> {
+ using statement_type = primary_key_t<Cs...>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
auto res = static_cast<std::string>(c);
using columns_tuple = typename statement_type::columns_tuple;
auto columnsCount = std::tuple_size<columns_tuple>::value;
if(columnsCount) {
res += "(";
decltype(columnsCount) columnIndex = 0;
- iterate_tuple(c.columns, [&context, &res, &columnIndex, columnsCount](auto &column) {
- res += context.column_name(column);
- if(columnIndex < columnsCount - 1) {
- res += ", ";
+ iterate_tuple(c.columns, [&context, &res, &columnIndex, columnsCount](auto& column) {
+ if(auto columnNamePointer = context.column_name(column)) {
+ res += *columnNamePointer;
+ if(columnIndex < columnsCount - 1) {
+ res += ", ";
+ }
+ ++columnIndex;
+ } else {
+ throw std::system_error(std::make_error_code(orm_error_code::column_not_found));
}
- ++columnIndex;
});
res += ")";
}
@@ -10165,23 +13890,27 @@ namespace sqlite_orm {
};
template<class... Args>
- struct statement_serializator<constraints::unique_t<Args...>, void> {
- using statement_type = constraints::unique_t<Args...>;
+ struct statement_serializator<unique_t<Args...>, void> {
+ using statement_type = unique_t<Args...>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
auto res = static_cast<std::string>(c);
using columns_tuple = typename statement_type::columns_tuple;
auto columnsCount = std::tuple_size<columns_tuple>::value;
if(columnsCount) {
res += "(";
decltype(columnsCount) columnIndex = 0;
- iterate_tuple(c.columns, [&context, &res, &columnIndex, columnsCount](auto &column) {
- res += context.column_name(column);
- if(columnIndex < columnsCount - 1) {
- res += ", ";
+ iterate_tuple(c.columns, [&context, &res, &columnIndex, columnsCount](auto& column) {
+ if(auto columnNamePointer = context.column_name(column)) {
+ res += *columnNamePointer;
+ if(columnIndex < columnsCount - 1) {
+ res += ", ";
+ }
+ ++columnIndex;
+ } else {
+ throw std::system_error(std::make_error_code(orm_error_code::column_not_found));
}
- ++columnIndex;
});
res += ")";
}
@@ -10190,38 +13919,42 @@ namespace sqlite_orm {
};
template<>
- struct statement_serializator<constraints::collate_t, void> {
- using statement_type = constraints::collate_t;
+ struct statement_serializator<collate_constraint_t, void> {
+ using statement_type = collate_constraint_t;
template<class C>
- std::string operator()(const statement_type &c, const C &) const {
+ std::string operator()(const statement_type& c, const C&) const {
return static_cast<std::string>(c);
}
};
template<class T>
- struct statement_serializator<constraints::default_t<T>, void> {
- using statement_type = constraints::default_t<T>;
+ struct statement_serializator<default_t<T>, void> {
+ using statement_type = default_t<T>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
return static_cast<std::string>(c) + " (" + serialize(c.value, context) + ")";
}
};
template<class... Cs, class... Rs>
- struct statement_serializator<constraints::foreign_key_t<std::tuple<Cs...>, std::tuple<Rs...>>, void> {
- using statement_type = constraints::foreign_key_t<std::tuple<Cs...>, std::tuple<Rs...>>;
+ struct statement_serializator<foreign_key_t<std::tuple<Cs...>, std::tuple<Rs...>>, void> {
+ using statement_type = foreign_key_t<std::tuple<Cs...>, std::tuple<Rs...>>;
template<class C>
- std::string operator()(const statement_type &fk, const C &context) const {
+ std::string operator()(const statement_type& fk, const C& context) const {
std::stringstream ss;
std::vector<std::string> columnNames;
using columns_type_t = typename std::decay<decltype(fk)>::type::columns_type;
constexpr const size_t columnsCount = std::tuple_size<columns_type_t>::value;
columnNames.reserve(columnsCount);
- iterate_tuple(fk.columns, [&columnNames, &context](auto &v) {
- columnNames.push_back(context.impl.column_name(v));
+ iterate_tuple(fk.columns, [&columnNames, &context](auto& v) {
+ if(auto columnNamePointer = context.impl.column_name(v)) {
+ columnNames.push_back(*columnNamePointer);
+ } else {
+ columnNames.push_back({});
+ }
});
ss << "FOREIGN KEY(";
for(size_t i = 0; i < columnNames.size(); ++i) {
@@ -10241,8 +13974,12 @@ namespace sqlite_orm {
auto refTableName = context.impl.find_table_name(typeid(first_reference_mapped_type));
ss << '\'' << refTableName << '\'';
}
- iterate_tuple(fk.references, [&referencesNames, &context](auto &v) {
- referencesNames.push_back(context.impl.column_name(v));
+ iterate_tuple(fk.references, [&referencesNames, &context](auto& v) {
+ if(auto columnNamePointer = context.impl.column_name(v)) {
+ referencesNames.push_back(*columnNamePointer);
+ } else {
+ referencesNames.push_back({});
+ }
});
ss << "(";
for(size_t i = 0; i < referencesNames.size(); ++i) {
@@ -10263,11 +14000,11 @@ namespace sqlite_orm {
};
template<class T>
- struct statement_serializator<constraints::check_t<T>, void> {
- using statement_type = constraints::check_t<T>;
+ struct statement_serializator<check_t<T>, void> {
+ using statement_type = check_t<T>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
return static_cast<std::string>(c) + " " + serialize(c.expression, context);
}
};
@@ -10277,7 +14014,7 @@ namespace sqlite_orm {
using statement_type = column_t<O, T, G, S, Op...>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
std::stringstream ss;
ss << "'" << c.name << "' ";
using column_type = typename std::decay<decltype(c)>::type;
@@ -10293,12 +14030,12 @@ namespace sqlite_orm {
int tupleIndex = 0;
iterate_tuple(
c.constraints,
- [&constraintsStrings, &primaryKeyIndex, &autoincrementIndex, &tupleIndex, &context](auto &v) {
+ [&constraintsStrings, &primaryKeyIndex, &autoincrementIndex, &tupleIndex, &context](auto& v) {
using constraint_type = typename std::decay<decltype(v)>::type;
constraintsStrings.push_back(serialize(v, context));
if(is_primary_key<constraint_type>::value) {
primaryKeyIndex = tupleIndex;
- } else if(std::is_same<constraints::autoincrement_t, constraint_type>::value) {
+ } else if(std::is_same<autoincrement_t, constraint_type>::value) {
autoincrementIndex = tupleIndex;
}
++tupleIndex;
@@ -10307,7 +14044,7 @@ namespace sqlite_orm {
iter_swap(constraintsStrings.begin() + primaryKeyIndex,
constraintsStrings.begin() + autoincrementIndex);
}
- for(auto &str: constraintsStrings) {
+ for(auto& str: constraintsStrings) {
ss << str << ' ';
}
}
@@ -10323,11 +14060,11 @@ namespace sqlite_orm {
using statement_type = remove_all_t<T, Args...>;
template<class C>
- std::string operator()(const statement_type &rem, const C &context) const {
- auto &tImpl = context.impl.template get_impl<T>();
+ std::string operator()(const statement_type& rem, const C& context) const {
+ auto& tImpl = context.impl.template get_impl<T>();
std::stringstream ss;
ss << "DELETE FROM '" << tImpl.table.name << "' ";
- iterate_tuple(rem.conditions, [&context, &ss](auto &v) {
+ iterate_tuple(rem.conditions, [&context, &ss](auto& v) {
ss << serialize(v, context);
});
return ss.str();
@@ -10339,33 +14076,8 @@ namespace sqlite_orm {
using statement_type = replace_t<T>;
template<class C>
- std::string operator()(const statement_type &rep, const C &context) const {
- using expression_type = typename std::decay<decltype(rep)>::type;
- using object_type = typename expression_object_type<expression_type>::type;
- auto &tImpl = context.impl.template get_impl<object_type>();
- std::stringstream ss;
- ss << "REPLACE INTO '" << tImpl.table.name << "' (";
- auto columnNames = tImpl.table.column_names();
- auto columnNamesCount = columnNames.size();
- for(size_t i = 0; i < columnNamesCount; ++i) {
- ss << "\"" << columnNames[i] << "\"";
- if(i < columnNamesCount - 1) {
- ss << ",";
- } else {
- ss << ")";
- }
- ss << " ";
- }
- ss << "VALUES(";
- for(size_t i = 0; i < columnNamesCount; ++i) {
- ss << "?";
- if(i < columnNamesCount - 1) {
- ss << ", ";
- } else {
- ss << ")";
- }
- }
- return ss.str();
+ std::string operator()(const statement_type& rep, const C& context) const {
+ return serialize_replace_range_impl(rep, context, 1);
}
};
@@ -10374,12 +14086,12 @@ namespace sqlite_orm {
using statement_type = insert_explicit<T, Cols...>;
template<class C>
- std::string operator()(const statement_type &ins, const C &context) const {
+ std::string operator()(const statement_type& ins, const C& context) const {
constexpr const size_t colsCount = std::tuple_size<std::tuple<Cols...>>::value;
static_assert(colsCount > 0, "Use insert or replace with 1 argument instead");
using expression_type = typename std::decay<decltype(ins)>::type;
using object_type = typename expression_object_type<expression_type>::type;
- auto &tImpl = context.impl.template get_impl<object_type>();
+ auto& tImpl = context.impl.template get_impl<object_type>();
std::stringstream ss;
ss << "INSERT INTO '" << tImpl.table.name << "' ";
std::vector<std::string> columnNames;
@@ -10387,7 +14099,7 @@ namespace sqlite_orm {
{
auto columnsContext = context;
columnsContext.skip_table_name = true;
- iterate_tuple(ins.columns.columns, [&columnNames, &columnsContext](auto &m) {
+ iterate_tuple(ins.columns.columns, [&columnNames, &columnsContext](auto& m) {
auto columnName = serialize(m, columnsContext);
if(!columnName.empty()) {
columnNames.push_back(columnName);
@@ -10425,52 +14137,77 @@ namespace sqlite_orm {
using statement_type = update_t<T>;
template<class C>
- std::string operator()(const statement_type &upd, const C &context) const {
+ std::string operator()(const statement_type& upd, const C& context) const {
using expression_type = typename std::decay<decltype(upd)>::type;
using object_type = typename expression_object_type<expression_type>::type;
- auto &tImpl = context.impl.template get_impl<object_type>();
+ auto& tImpl = context.impl.template get_impl<object_type>();
std::stringstream ss;
- ss << "UPDATE '" << tImpl.table.name << "' SET ";
+ ss << "UPDATE '" << tImpl.table.name << "' SET";
std::vector<std::string> setColumnNames;
- tImpl.table.for_each_column([&setColumnNames](auto &c) {
- if(!c.template has<constraints::primary_key_t<>>()) {
- setColumnNames.emplace_back(c.name);
+ tImpl.table.for_each_column([&setColumnNames, &tImpl](auto& column) {
+ if(!column.template has<primary_key_t<>>() &&
+ !tImpl.table.exists_in_composite_primary_key(column)) {
+ setColumnNames.emplace_back(column.name);
}
});
for(size_t i = 0; i < setColumnNames.size(); ++i) {
- ss << "\"" << setColumnNames[i] << "\""
+ ss << " \"" << setColumnNames[i] << "\""
<< " = ?";
if(i < setColumnNames.size() - 1) {
ss << ",";
}
- ss << " ";
}
- ss << "WHERE ";
+ ss << " WHERE";
auto primaryKeyColumnNames = tImpl.table.primary_key_column_names();
for(size_t i = 0; i < primaryKeyColumnNames.size(); ++i) {
- ss << "\"" << primaryKeyColumnNames[i] << "\""
+ ss << " \"" << primaryKeyColumnNames[i] << "\""
<< " = ?";
if(i < primaryKeyColumnNames.size() - 1) {
ss << " AND";
}
- ss << " ";
}
return ss.str();
}
};
+ template<class... Args>
+ struct statement_serializator<set_t<Args...>, void> {
+ using statement_type = set_t<Args...>;
+
+ template<class C>
+ std::string operator()(const statement_type& statement, const C& context) const {
+ std::stringstream ss;
+ ss << static_cast<std::string>(statement);
+ auto assignsCount = std::tuple_size<typename statement_type::assigns_type>::value;
+ decltype(assignsCount) assignIndex = 0;
+ auto leftContext = context;
+ leftContext.skip_table_name = true;
+ iterate_tuple(statement.assigns,
+ [&ss, &context, &leftContext, &assignIndex, assignsCount](auto& value) {
+ ss << ' ' << serialize(value.lhs, leftContext);
+ ss << ' ' << static_cast<std::string>(value) << ' ';
+ ss << serialize(value.rhs, context);
+ if(assignIndex < assignsCount - 1) {
+ ss << ",";
+ }
+ ++assignIndex;
+ });
+ return ss.str();
+ }
+ };
+
template<class... Args, class... Wargs>
struct statement_serializator<update_all_t<set_t<Args...>, Wargs...>, void> {
using statement_type = update_all_t<set_t<Args...>, Wargs...>;
template<class C>
- std::string operator()(const statement_type &upd, const C &context) const {
+ std::string operator()(const statement_type& upd, const C& context) const {
std::stringstream ss;
ss << "UPDATE ";
- table_name_collector collector{[&context](std::type_index ti) {
+ table_name_collector collector([&context](std::type_index ti) {
return context.impl.find_table_name(ti);
- }};
+ });
iterate_ast(upd.set.assigns, collector);
if(!collector.table_names.empty()) {
if(collector.table_names.size() == 1) {
@@ -10479,7 +14216,7 @@ namespace sqlite_orm {
std::vector<std::string> setPairs;
auto leftContext = context;
leftContext.skip_table_name = true;
- iterate_tuple(upd.set.assigns, [&context, &leftContext, &setPairs](auto &asgn) {
+ iterate_tuple(upd.set.assigns, [&context, &leftContext, &setPairs](auto& asgn) {
std::stringstream sss;
sss << serialize(asgn.lhs, leftContext);
sss << " " << static_cast<std::string>(asgn) << " ";
@@ -10493,7 +14230,7 @@ namespace sqlite_orm {
ss << ", ";
}
}
- iterate_tuple(upd.conditions, [&context, &ss](auto &v) {
+ iterate_tuple(upd.conditions, [&context, &ss](auto& v) {
ss << serialize(v, context);
});
return ss.str();
@@ -10506,55 +14243,148 @@ namespace sqlite_orm {
}
};
+ template<class T, class C>
+ std::string serialize_insert_range_impl(const T& /*statement*/, const C& context, const int valuesCount) {
+ using object_type = typename expression_object_type<T>::type;
+ auto& tImpl = context.impl.template get_impl<object_type>();
+
+ std::stringstream ss;
+ ss << "INSERT INTO '" << tImpl.table.name << "' ";
+ std::vector<std::string> columnNames;
+ auto compositeKeyColumnNames = tImpl.table.composite_key_columns_names();
+
+ tImpl.table.for_each_column([&columnNames, &compositeKeyColumnNames](auto& c) {
+ using table_type = typename std::decay<decltype(tImpl.table)>::type;
+ if(table_type::is_without_rowid || !c.template has<primary_key_t<>>()) {
+ auto it = find(compositeKeyColumnNames.begin(), compositeKeyColumnNames.end(), c.name);
+ if(it == compositeKeyColumnNames.end()) {
+ columnNames.emplace_back(c.name);
+ }
+ }
+ });
+
+ const auto columnNamesCount = columnNames.size();
+ if(columnNamesCount) {
+ ss << "(";
+ for(size_t i = 0; i < columnNamesCount; ++i) {
+ ss << "\"" << columnNames[i] << "\"";
+ if(i < columnNamesCount - 1) {
+ ss << ",";
+ } else {
+ ss << ")";
+ }
+ ss << " ";
+ }
+ } else {
+ ss << "DEFAULT ";
+ }
+ ss << "VALUES ";
+ if(columnNamesCount) {
+ auto valuesString = [columnNamesCount] {
+ std::stringstream ss_;
+ ss_ << "(";
+ for(size_t i = 0; i < columnNamesCount; ++i) {
+ ss_ << "?";
+ if(i < columnNamesCount - 1) {
+ ss_ << ", ";
+ } else {
+ ss_ << ")";
+ }
+ }
+ return ss_.str();
+ }();
+ for(auto i = 0; i < valuesCount; ++i) {
+ ss << valuesString;
+ if(i < valuesCount - 1) {
+ ss << ",";
+ }
+ ss << " ";
+ }
+ } else if(valuesCount != 1) {
+ throw std::system_error(std::make_error_code(orm_error_code::cannot_use_default_value));
+ }
+
+ return ss.str();
+ }
+
template<class T>
struct statement_serializator<insert_t<T>, void> {
using statement_type = insert_t<T>;
template<class C>
- std::string operator()(const statement_type &, const C &context) const {
- using object_type = typename expression_object_type<statement_type>::type;
- auto &tImpl = context.impl.template get_impl<object_type>();
+ std::string operator()(const statement_type& statement, const C& context) const {
+ return serialize_insert_range_impl(statement, context, 1);
+ }
+ };
+
+ template<class T>
+ struct statement_serializator<into_t<T>, void> {
+ using statement_type = into_t<T>;
+
+ template<class C>
+ std::string operator()(const statement_type& statement, const C& context) const {
std::stringstream ss;
- ss << "INSERT INTO '" << tImpl.table.name << "' ";
- std::vector<std::string> columnNames;
- auto compositeKeyColumnNames = tImpl.table.composite_key_columns_names();
+ auto& tImpl = context.impl.template get_impl<T>();
+ ss << "INTO " << tImpl.table.name;
+ return ss.str();
+ }
+ };
- tImpl.table.for_each_column([&tImpl, &columnNames, &compositeKeyColumnNames](auto &c) {
- if(tImpl.table._without_rowid || !c.template has<constraints::primary_key_t<>>()) {
- auto it = find(compositeKeyColumnNames.begin(), compositeKeyColumnNames.end(), c.name);
- if(it == compositeKeyColumnNames.end()) {
- columnNames.emplace_back(c.name);
- }
+ template<class... Args>
+ struct statement_serializator<columns_t<Args...>, void> {
+ using statement_type = columns_t<Args...>;
+
+ template<class C>
+ std::string operator()(const statement_type& statement, const C& context) const {
+ std::stringstream ss;
+ auto index = 0;
+ if(context.use_parentheses) {
+ ss << '(';
+ }
+ iterate_tuple(statement.columns, [&context, &ss, &index](auto& value) {
+ ss << serialize(value, context);
+ if(index < int(std::tuple_size<std::tuple<Args...>>::value) - 1) {
+ ss << ", ";
}
+ ++index;
});
+ if(context.use_parentheses) {
+ ss << ')';
+ }
+ return ss.str();
+ }
+ };
- auto columnNamesCount = columnNames.size();
- if(columnNamesCount) {
- ss << "(";
- for(size_t i = 0; i < columnNamesCount; ++i) {
- ss << "\"" << columnNames[i] << "\"";
- if(i < columnNamesCount - 1) {
- ss << ",";
- } else {
- ss << ")";
- }
- ss << " ";
- }
+ template<class T>
+ struct statement_serializator<
+ T,
+ typename std::enable_if<is_insert_raw<T>::value || is_replace_raw<T>::value>::type> {
+ using statement_type = T;
+
+ template<class C>
+ std::string operator()(const statement_type& statement, const C& context) const {
+ std::stringstream ss;
+ if(is_insert_raw<T>::value) {
+ ss << "INSERT";
} else {
- ss << "DEFAULT ";
+ ss << "REPLACE";
}
- ss << "VALUES ";
- if(columnNamesCount) {
- ss << "(";
- for(size_t i = 0; i < columnNamesCount; ++i) {
- ss << "?";
- if(i < columnNamesCount - 1) {
- ss << ", ";
- } else {
- ss << ")";
- }
+ iterate_tuple(statement.args, [&context, &ss](auto& value) {
+ using value_type = typename std::decay<decltype(value)>::type;
+ ss << ' ';
+ if(is_columns<value_type>::value) {
+ auto newContext = context;
+ newContext.skip_table_name = true;
+ newContext.use_parentheses = true;
+ ss << serialize(value, newContext);
+ } else if(is_values<value_type>::value || is_select<value_type>::value) {
+ auto newContext = context;
+ newContext.use_parentheses = false;
+ ss << serialize(value, newContext);
+ } else {
+ ss << serialize(value, context);
}
- }
+ });
return ss.str();
}
};
@@ -10564,8 +14394,8 @@ namespace sqlite_orm {
using statement_type = remove_t<T, Ids...>;
template<class C>
- std::string operator()(const statement_type &, const C &context) const {
- auto &tImpl = context.impl.template get_impl<T>();
+ std::string operator()(const statement_type&, const C& context) const {
+ auto& tImpl = context.impl.template get_impl<T>();
std::stringstream ss;
ss << "DELETE FROM '" << tImpl.table.name << "' ";
ss << "WHERE ";
@@ -10581,110 +14411,73 @@ namespace sqlite_orm {
}
};
- template<class It>
- struct statement_serializator<replace_range_t<It>, void> {
- using statement_type = replace_range_t<It>;
+ template<class T, class C>
+ std::string serialize_replace_range_impl(const T& rep, const C& context, const int valuesCount) {
+ using expression_type = typename std::decay<decltype(rep)>::type;
+ using object_type = typename expression_object_type<expression_type>::type;
+ auto& tImpl = context.impl.template get_impl<object_type>();
+ std::stringstream ss;
+ ss << "REPLACE INTO '" << tImpl.table.name << "' (";
- template<class C>
- std::string operator()(const statement_type &rep, const C &context) const {
- using expression_type = typename std::decay<decltype(rep)>::type;
- using object_type = typename expression_type::object_type;
- auto &tImpl = context.impl.template get_impl<object_type>();
- std::stringstream ss;
- ss << "REPLACE INTO '" << tImpl.table.name << "' (";
- auto columnNames = tImpl.table.column_names();
- auto columnNamesCount = columnNames.size();
- for(size_t i = 0; i < columnNamesCount; ++i) {
- ss << "\"" << columnNames[i] << "\"";
- if(i < columnNamesCount - 1) {
- ss << ", ";
+ auto columnIndex = 0;
+ auto columnsCount = tImpl.table.count_columns_amount();
+ tImpl.table.for_each_column([&ss, &columnIndex, columnsCount](auto& column) {
+ ss << " \"" << column.name << "\"";
+ if(columnIndex < columnsCount - 1) {
+ ss << ",";
+ } else {
+ ss << ")";
+ }
+ ++columnIndex;
+ });
+ ss << " VALUES ";
+ auto valuesString = [columnsCount] {
+ std::stringstream ss_;
+ ss_ << "(";
+ for(auto i = 0; i < columnsCount; ++i) {
+ ss_ << "?";
+ if(i < columnsCount - 1) {
+ ss_ << ", ";
} else {
- ss << ") ";
+ ss_ << ")";
}
}
- ss << "VALUES ";
- auto valuesString = [columnNamesCount] {
- std::stringstream ss_;
- ss_ << "(";
- for(size_t i = 0; i < columnNamesCount; ++i) {
- ss_ << "?";
- if(i < columnNamesCount - 1) {
- ss_ << ", ";
- } else {
- ss_ << ")";
- }
- }
- return ss_.str();
- }();
- auto valuesCount = static_cast<int>(std::distance(rep.range.first, rep.range.second));
- for(auto i = 0; i < valuesCount; ++i) {
- ss << valuesString;
- if(i < valuesCount - 1) {
- ss << ",";
- }
- ss << " ";
+ return ss_.str();
+ }();
+ for(auto i = 0; i < valuesCount; ++i) {
+ ss << valuesString;
+ if(i < valuesCount - 1) {
+ ss << ",";
}
- return ss.str();
+ ss << " ";
}
- };
+ return ss.str();
+ }
- template<class It>
- struct statement_serializator<insert_range_t<It>, void> {
- using statement_type = insert_range_t<It>;
+ template<class It, class L, class O>
+ struct statement_serializator<replace_range_t<It, L, O>, void> {
+ using statement_type = replace_range_t<It, L, O>;
template<class C>
- std::string operator()(const statement_type &statement, const C &context) const {
- using expression_type = typename std::decay<decltype(statement)>::type;
- using object_type = typename expression_type::object_type;
- auto &tImpl = context.impl.template get_impl<object_type>();
+ std::string operator()(const statement_type& rep, const C& context) const {
+ auto valuesCount = static_cast<int>(std::distance(rep.range.first, rep.range.second));
+ return serialize_replace_range_impl(rep, context, valuesCount);
+ }
+ };
- std::stringstream ss;
- ss << "INSERT INTO '" << tImpl.table.name << "' (";
- std::vector<std::string> columnNames;
- tImpl.table.for_each_column([&columnNames](auto &c) {
- if(!c.template has<constraints::primary_key_t<>>()) {
- columnNames.emplace_back(c.name);
- }
- });
+ template<class It, class L, class O>
+ struct statement_serializator<insert_range_t<It, L, O>, void> {
+ using statement_type = insert_range_t<It, L, O>;
- auto columnNamesCount = columnNames.size();
- for(size_t i = 0; i < columnNamesCount; ++i) {
- ss << "\"" << columnNames[i] << "\"";
- if(i < columnNamesCount - 1) {
- ss << ",";
- } else {
- ss << ")";
- }
- ss << " ";
- }
- ss << "VALUES ";
- auto valuesString = [columnNamesCount] {
- std::stringstream ss_;
- ss_ << "(";
- for(size_t i = 0; i < columnNamesCount; ++i) {
- ss_ << "?";
- if(i < columnNamesCount - 1) {
- ss_ << ", ";
- } else {
- ss_ << ")";
- }
- }
- return ss_.str();
- }();
- auto valuesCount = static_cast<int>(std::distance(statement.range.first, statement.range.second));
- for(auto i = 0; i < valuesCount; ++i) {
- ss << valuesString;
- if(i < valuesCount - 1) {
- ss << ",";
- }
- ss << " ";
- }
- return ss.str();
+ template<class C>
+ std::string operator()(const statement_type& statement, const C& context) const {
+ const auto valuesCount = static_cast<int>(std::distance(statement.range.first, statement.range.second));
+ return serialize_insert_range_impl(statement, context, valuesCount);
}
};
template<class T, class C>
- std::string serialize_get_all_impl(const T &get, const C &context) {
+ std::string serialize_get_all_impl(const T& get, const C& context) {
using primary_type = typename T::type;
table_name_collector collector;
@@ -10692,23 +14485,23 @@ namespace sqlite_orm {
std::make_pair(context.impl.find_table_name(typeid(primary_type)), std::string{}));
iterate_ast(get.conditions, collector);
std::stringstream ss;
- ss << "SELECT ";
- auto &tImpl = context.impl.template get_impl<primary_type>();
- auto columnNames = tImpl.table.column_names();
- for(size_t i = 0; i < columnNames.size(); ++i) {
- ss << "\"" << tImpl.table.name << "\"."
- << "\"" << columnNames[i] << "\"";
- if(i < columnNames.size() - 1) {
- ss << ", ";
- } else {
- ss << " ";
+ ss << "SELECT";
+ auto& tImpl = context.impl.template get_impl<primary_type>();
+ auto columnIndex = 0;
+ auto columnsCount = tImpl.table.count_columns_amount();
+ tImpl.table.for_each_column([&ss, &columnIndex, columnsCount, &tImpl](auto& column) {
+ ss << " \"" << tImpl.table.name << "\"."
+ << "\"" << column.name << "\"";
+ if(columnIndex < columnsCount - 1) {
+ ss << ",";
}
- }
- ss << "FROM ";
+ ++columnIndex;
+ });
+ ss << " FROM ";
std::vector<std::pair<std::string, std::string>> tableNames(collector.table_names.begin(),
collector.table_names.end());
for(size_t i = 0; i < tableNames.size(); ++i) {
- auto &tableNamePair = tableNames[i];
+ auto& tableNamePair = tableNames[i];
ss << "'" << tableNamePair.first << "' ";
if(!tableNamePair.second.empty()) {
ss << tableNamePair.second << " ";
@@ -10718,7 +14511,7 @@ namespace sqlite_orm {
}
ss << " ";
}
- iterate_tuple(get.conditions, [&context, &ss](auto &v) {
+ iterate_tuple(get.conditions, [&context, &ss](auto& v) {
ss << serialize(v, context);
});
return ss.str();
@@ -10730,7 +14523,7 @@ namespace sqlite_orm {
using statement_type = get_all_optional_t<T, R, Args...>;
template<class C>
- std::string operator()(const statement_type &get, const C &context) const {
+ std::string operator()(const statement_type& get, const C& context) const {
return serialize_get_all_impl(get, context);
}
};
@@ -10741,7 +14534,7 @@ namespace sqlite_orm {
using statement_type = get_all_pointer_t<T, R, Args...>;
template<class C>
- std::string operator()(const statement_type &get, const C &context) const {
+ std::string operator()(const statement_type& get, const C& context) const {
return serialize_get_all_impl(get, context);
}
};
@@ -10751,35 +14544,35 @@ namespace sqlite_orm {
using statement_type = get_all_t<T, R, Args...>;
template<class C>
- std::string operator()(const statement_type &get, const C &context) const {
+ std::string operator()(const statement_type& get, const C& context) const {
return serialize_get_all_impl(get, context);
}
};
template<class T, class C>
- std::string serialize_get_impl(const T &, const C &context) {
+ std::string serialize_get_impl(const T&, const C& context) {
using primary_type = typename T::type;
- auto &tImpl = context.impl.template get_impl<primary_type>();
+ auto& tImpl = context.impl.template get_impl<primary_type>();
std::stringstream ss;
- ss << "SELECT ";
- auto columnNames = tImpl.table.column_names();
- for(size_t i = 0; i < columnNames.size(); ++i) {
- ss << "\"" << columnNames[i] << "\"";
- if(i < columnNames.size() - 1) {
- ss << ",";
+ ss << "SELECT";
+ auto columnIndex = 0;
+ auto columnsCount = tImpl.table.count_columns_amount();
+ tImpl.table.for_each_column([&ss, &columnIndex, columnsCount](auto& column) {
+ ss << " \"" << column.name << "\"";
+ if(columnIndex < columnsCount - 1) {
+ ss << ", ";
}
- ss << " ";
- }
- ss << "FROM '" << tImpl.table.name << "' WHERE ";
+ ++columnIndex;
+ });
+ ss << " FROM '" << tImpl.table.name << "' WHERE ";
auto primaryKeyColumnNames = tImpl.table.primary_key_column_names();
if(!primaryKeyColumnNames.empty()) {
for(size_t i = 0; i < primaryKeyColumnNames.size(); ++i) {
- ss << "\"" << primaryKeyColumnNames[i] << "\""
- << " = ? ";
+ ss << " \"" << primaryKeyColumnNames[i] << "\""
+ << " = ?";
if(i < primaryKeyColumnNames.size() - 1) {
- ss << "AND";
+ ss << " AND";
}
- ss << ' ';
}
return ss.str();
} else {
@@ -10792,7 +14585,7 @@ namespace sqlite_orm {
using statement_type = get_t<T, Ids...>;
template<class C>
- std::string operator()(const statement_type &get, const C &context) const {
+ std::string operator()(const statement_type& get, const C& context) const {
return serialize_get_impl(get, context);
}
};
@@ -10802,8 +14595,29 @@ namespace sqlite_orm {
using statement_type = get_pointer_t<T, Ids...>;
template<class C>
- std::string operator()(const statement_type &get, const C &context) const {
- return serialize_get_impl(get, context);
+ std::string operator()(const statement_type& statement, const C& context) const {
+ return serialize_get_impl(statement, context);
+ }
+ };
+
+ template<>
+ struct statement_serializator<insert_constraint, void> {
+ using statement_type = insert_constraint;
+
+ template<class C>
+ std::string operator()(const statement_type& statement, const C& context) const {
+ switch(statement) {
+ case insert_constraint::abort:
+ return "OR ABORT";
+ case insert_constraint::fail:
+ return "OR FAIL";
+ case insert_constraint::ignore:
+ return "OR IGNORE";
+ case insert_constraint::replace:
+ return "OR REPLACE";
+ case insert_constraint::rollback:
+ return "OR ROLLBACK";
+ }
}
};
@@ -10813,7 +14627,7 @@ namespace sqlite_orm {
using statement_type = get_optional_t<T, Ids...>;
template<class C>
- std::string operator()(const statement_type &get, const C &context) const {
+ std::string operator()(const statement_type& get, const C& context) const {
return serialize_get_impl(get, context);
}
};
@@ -10823,11 +14637,12 @@ namespace sqlite_orm {
using statement_type = select_t<T, Args...>;
template<class C>
- std::string operator()(const statement_type &sel, const C &context) const {
+ std::string operator()(const statement_type& sel, const C& context) const {
std::stringstream ss;
- if(!is_base_of_template<T, compound_operator>::value) {
- if(!sel.highest_level) {
- ss << "( ";
+ const auto isCompoundOperator = is_base_of_template<T, compound_operator>::value;
+ if(!isCompoundOperator) {
+ if(!sel.highest_level && context.use_parentheses) {
+ ss << "(";
}
ss << "SELECT ";
}
@@ -10838,46 +14653,47 @@ namespace sqlite_orm {
for(size_t i = 0; i < columnNames.size(); ++i) {
ss << columnNames[i];
if(i < columnNames.size() - 1) {
- ss << ",";
+ ss << ", ";
}
- ss << " ";
}
- table_name_collector collector{[&context](std::type_index ti) {
+ table_name_collector collector([&context](std::type_index ti) {
return context.impl.find_table_name(ti);
- }};
- iterate_ast(sel.col, collector);
- iterate_ast(sel.conditions, collector);
- internal::join_iterator<Args...>()([&collector, &context](const auto &c) {
- using original_join_type = typename std::decay<decltype(c)>::type::join_type::type;
- using cross_join_type = typename internal::mapped_type_proxy<original_join_type>::type;
- auto crossJoinedTableName = context.impl.find_table_name(typeid(cross_join_type));
- auto tableAliasString = alias_extractor<original_join_type>::get();
- std::pair<std::string, std::string> tableNameWithAlias(std::move(crossJoinedTableName),
- std::move(tableAliasString));
- collector.table_names.erase(tableNameWithAlias);
});
- if(!collector.table_names.empty()) {
- ss << "FROM ";
- std::vector<std::pair<std::string, std::string>> tableNames(collector.table_names.begin(),
- collector.table_names.end());
- for(size_t i = 0; i < tableNames.size(); ++i) {
- auto &tableNamePair = tableNames[i];
- ss << "'" << tableNamePair.first << "' ";
- if(!tableNamePair.second.empty()) {
- ss << tableNamePair.second << " ";
- }
- if(int(i) < int(tableNames.size()) - 1) {
- ss << ",";
+ const auto explicitFromItemsCount = count_tuple<std::tuple<Args...>, is_from>::value;
+ if(!explicitFromItemsCount) {
+ iterate_ast(sel.col, collector);
+ iterate_ast(sel.conditions, collector);
+ join_iterator<Args...>()([&collector, &context](const auto& c) {
+ using original_join_type = typename std::decay<decltype(c)>::type::join_type::type;
+ using cross_join_type = typename internal::mapped_type_proxy<original_join_type>::type;
+ auto crossJoinedTableName = context.impl.find_table_name(typeid(cross_join_type));
+ auto tableAliasString = alias_extractor<original_join_type>::get();
+ std::pair<std::string, std::string> tableNameWithAlias(std::move(crossJoinedTableName),
+ std::move(tableAliasString));
+ collector.table_names.erase(tableNameWithAlias);
+ });
+ if(!collector.table_names.empty() && !isCompoundOperator) {
+ ss << " FROM ";
+ std::vector<std::pair<std::string, std::string>> tableNames(collector.table_names.begin(),
+ collector.table_names.end());
+ for(size_t i = 0; i < tableNames.size(); ++i) {
+ auto& tableNamePair = tableNames[i];
+ ss << "'" << tableNamePair.first << "'";
+ if(!tableNamePair.second.empty()) {
+ ss << ' ' << tableNamePair.second;
+ }
+ if(int(i) < int(tableNames.size()) - 1) {
+ ss << ", ";
+ }
}
- ss << " ";
}
}
- iterate_tuple(sel.conditions, [&context, &ss](auto &v) {
- ss << serialize(v, context);
+ iterate_tuple(sel.conditions, [&context, &ss](auto& v) {
+ ss << ' ' << serialize(v, context);
});
if(!is_base_of_template<T, compound_operator>::value) {
- if(!sel.highest_level) {
- ss << ") ";
+ if(!sel.highest_level && context.use_parentheses) {
+ ss << ")";
}
}
return ss.str();
@@ -10889,7 +14705,7 @@ namespace sqlite_orm {
using statement_type = indexed_column_t<T>;
template<class C>
- std::string operator()(const statement_type &statement, const C &context) const {
+ std::string operator()(const statement_type& statement, const C& context) const {
std::stringstream ss;
ss << serialize(statement.column_or_expression, context);
if(!statement._collation_name.empty()) {
@@ -10916,23 +14732,24 @@ namespace sqlite_orm {
using statement_type = index_t<Cols...>;
template<class C>
- std::string operator()(const statement_type &statement, const C &context) const {
+ std::string operator()(const statement_type& statement, const C& context) const {
std::stringstream ss;
ss << "CREATE ";
if(statement.unique) {
ss << "UNIQUE ";
}
- using columns_type = typename std::decay<decltype(statement)>::type::columns_type;
- using head_t = typename std::tuple_element<0, columns_type>::type::column_type;
+ using elements_type = typename std::decay<decltype(statement)>::type::elements_type;
+ using head_t = typename std::tuple_element<0, elements_type>::type::column_type;
using indexed_type = typename table_type<head_t>::type;
ss << "INDEX IF NOT EXISTS '" << statement.name << "' ON '"
<< context.impl.find_table_name(typeid(indexed_type)) << "' (";
std::vector<std::string> columnNames;
- iterate_tuple(statement.columns, [&columnNames, &context](auto &v) {
- columnNames.push_back(context.column_name(v.column_or_expression));
+ iterate_tuple(statement.elements, [&columnNames, &context](auto& v) {
+ auto columnName = serialize(v, context);
+ columnNames.push_back(move(columnName));
});
for(size_t i = 0; i < columnNames.size(); ++i) {
- ss << "'" << columnNames[i] << "'";
+ ss << columnNames[i];
if(i < columnNames.size() - 1) {
ss << ", ";
}
@@ -10942,15 +14759,44 @@ namespace sqlite_orm {
}
};
+ template<class... Args>
+ struct statement_serializator<from_t<Args...>, void> {
+ using statement_type = from_t<Args...>;
+
+ template<class C>
+ std::string operator()(const statement_type& statement, const C& context) const {
+ using tuple = std::tuple<Args...>;
+
+ std::stringstream ss;
+ ss << "FROM ";
+ size_t index = 0;
+ iterate_tuple<tuple>([&context, &ss, &index](auto* itemPointer) {
+ using mapped_type = typename std::remove_pointer<decltype(itemPointer)>::type;
+
+ auto aliasString = alias_extractor<mapped_type>::get();
+ ss << "'" << context.impl.find_table_name(typeid(typename mapped_type_proxy<mapped_type>::type))
+ << "'";
+ if(aliasString.length()) {
+ ss << " '" << aliasString << "'";
+ }
+ if(index < std::tuple_size<tuple>::value - 1) {
+ ss << ", ";
+ }
+ ++index;
+ });
+ return ss.str();
+ }
+ };
+
template<class T>
struct statement_serializator<where_t<T>, void> {
using statement_type = where_t<T>;
template<class C>
- std::string operator()(const statement_type &w, const C &context) const {
+ std::string operator()(const statement_type& statement, const C& context) const {
std::stringstream ss;
- ss << static_cast<std::string>(w) << " ";
- auto whereString = serialize(w.c, context);
+ ss << statement.serialize() << " ";
+ auto whereString = serialize(statement.expression, context);
ss << "( " << whereString << ") ";
return ss.str();
}
@@ -10961,7 +14807,7 @@ namespace sqlite_orm {
using statement_type = order_by_t<O>;
template<class C>
- std::string operator()(const statement_type &orderBy, const C &context) const {
+ std::string operator()(const statement_type& orderBy, const C& context) const {
std::stringstream ss;
ss << static_cast<std::string>(orderBy) << " ";
auto orderByString = serialize_order_by(orderBy, context);
@@ -10975,7 +14821,7 @@ namespace sqlite_orm {
using statement_type = dynamic_order_by_t<C>;
template<class CC>
- std::string operator()(const statement_type &orderBy, const CC &context) const {
+ std::string operator()(const statement_type& orderBy, const CC& context) const {
return serialize_order_by(orderBy, context);
}
};
@@ -10985,10 +14831,10 @@ namespace sqlite_orm {
using statement_type = multi_order_by_t<Args...>;
template<class C>
- std::string operator()(const statement_type &orderBy, const C &context) const {
+ std::string operator()(const statement_type& orderBy, const C& context) const {
std::stringstream ss;
std::vector<std::string> expressions;
- iterate_tuple(orderBy.args, [&expressions, &context](auto &v) {
+ iterate_tuple(orderBy.args, [&expressions, &context](auto& v) {
auto expression = serialize_order_by(v, context);
expressions.push_back(move(expression));
});
@@ -11009,7 +14855,7 @@ namespace sqlite_orm {
using statement_type = cross_join_t<O>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
std::stringstream ss;
ss << static_cast<std::string>(c) << " ";
ss << " '" << context.impl.find_table_name(typeid(O)) << "'";
@@ -11022,7 +14868,7 @@ namespace sqlite_orm {
using statement_type = inner_join_t<T, O>;
template<class C>
- std::string operator()(const statement_type &l, const C &context) const {
+ std::string operator()(const statement_type& l, const C& context) const {
std::stringstream ss;
ss << static_cast<std::string>(l) << " ";
auto aliasString = alias_extractor<T>::get();
@@ -11040,7 +14886,7 @@ namespace sqlite_orm {
using statement_type = on_t<T>;
template<class C>
- std::string operator()(const statement_type &t, const C &context) const {
+ std::string operator()(const statement_type& t, const C& context) const {
std::stringstream ss;
auto newContext = context;
newContext.skip_table_name = false;
@@ -11054,10 +14900,14 @@ namespace sqlite_orm {
using statement_type = join_t<T, O>;
template<class C>
- std::string operator()(const statement_type &l, const C &context) const {
+ std::string operator()(const statement_type& l, const C& context) const {
std::stringstream ss;
ss << static_cast<std::string>(l) << " ";
- ss << " '" << context.impl.find_table_name(typeid(T)) << "' ";
+ auto aliasString = alias_extractor<T>::get();
+ ss << " '" << context.impl.find_table_name(typeid(typename mapped_type_proxy<T>::type)) << "' ";
+ if(aliasString.length()) {
+ ss << "'" << aliasString << "' ";
+ }
ss << serialize(l.constraint, context);
return ss.str();
}
@@ -11068,10 +14918,14 @@ namespace sqlite_orm {
using statement_type = left_join_t<T, O>;
template<class C>
- std::string operator()(const statement_type &l, const C &context) const {
+ std::string operator()(const statement_type& l, const C& context) const {
std::stringstream ss;
ss << static_cast<std::string>(l) << " ";
- ss << " '" << context.impl.find_table_name(typeid(T)) << "' ";
+ auto aliasString = alias_extractor<T>::get();
+ ss << " '" << context.impl.find_table_name(typeid(typename mapped_type_proxy<T>::type)) << "' ";
+ if(aliasString.length()) {
+ ss << "'" << aliasString << "' ";
+ }
ss << serialize(l.constraint, context);
return ss.str();
}
@@ -11082,10 +14936,14 @@ namespace sqlite_orm {
using statement_type = left_outer_join_t<T, O>;
template<class C>
- std::string operator()(const statement_type &l, const C &context) const {
+ std::string operator()(const statement_type& l, const C& context) const {
std::stringstream ss;
ss << static_cast<std::string>(l) << " ";
- ss << " '" << context.impl.find_table_name(typeid(T)) << "' ";
+ auto aliasString = alias_extractor<T>::get();
+ ss << " '" << context.impl.find_table_name(typeid(typename mapped_type_proxy<T>::type)) << "' ";
+ if(aliasString.length()) {
+ ss << "'" << aliasString << "' ";
+ }
ss << serialize(l.constraint, context);
return ss.str();
}
@@ -11096,7 +14954,7 @@ namespace sqlite_orm {
using statement_type = natural_join_t<O>;
template<class C>
- std::string operator()(const statement_type &c, const C &context) const {
+ std::string operator()(const statement_type& c, const C& context) const {
std::stringstream ss;
ss << static_cast<std::string>(c) << " ";
ss << " '" << context.impl.find_table_name(typeid(O)) << "'";
@@ -11109,12 +14967,12 @@ namespace sqlite_orm {
using statement_type = group_by_t<Args...>;
template<class C>
- std::string operator()(const statement_type &groupBy, const C &context) const {
+ std::string operator()(const statement_type& groupBy, const C& context) const {
std::stringstream ss;
std::vector<std::string> expressions;
auto newContext = context;
newContext.skip_table_name = false;
- iterate_tuple(groupBy.args, [&expressions, &newContext](auto &v) {
+ iterate_tuple(groupBy.args, [&expressions, &newContext](auto& v) {
auto expression = serialize(v, newContext);
expressions.push_back(expression);
});
@@ -11135,7 +14993,7 @@ namespace sqlite_orm {
using statement_type = having_t<T>;
template<class C>
- std::string operator()(const statement_type &hav, const C &context) const {
+ std::string operator()(const statement_type& hav, const C& context) const {
std::stringstream ss;
auto newContext = context;
newContext.skip_table_name = false;
@@ -11154,21 +15012,21 @@ namespace sqlite_orm {
using statement_type = limit_t<T, HO, OI, O>;
template<class C>
- std::string operator()(const statement_type &limt, const C &context) const {
+ std::string operator()(const statement_type& limt, const C& context) const {
auto newContext = context;
newContext.skip_table_name = false;
std::stringstream ss;
ss << static_cast<std::string>(limt) << " ";
if(HO) {
if(OI) {
- limt.off.apply([&newContext, &ss](auto &value) {
+ limt.off.apply([&newContext, &ss](auto& value) {
ss << serialize(value, newContext);
});
ss << ", ";
ss << serialize(limt.lim, newContext);
} else {
ss << serialize(limt.lim, newContext) << " OFFSET ";
- limt.off.apply([&newContext, &ss](auto &value) {
+ limt.off.apply([&newContext, &ss](auto& value) {
ss << serialize(value, newContext);
});
}
@@ -11179,12 +15037,22 @@ namespace sqlite_orm {
}
};
+ template<>
+ struct statement_serializator<default_values_t, void> {
+ using statement_type = default_values_t;
+
+ template<class C>
+ std::string operator()(const statement_type& statement, const C& context) const {
+ return "DEFAULT VALUES";
+ }
+ };
+
template<class F, class O>
struct statement_serializator<using_t<F, O>, void> {
using statement_type = using_t<F, O>;
template<class C>
- std::string operator()(const statement_type &statement, const C &context) const {
+ std::string operator()(const statement_type& statement, const C& context) const {
auto newContext = context;
newContext.skip_table_name = true;
return static_cast<std::string>(statement) + " (" + serialize(statement.column, newContext) + " )";
@@ -11196,12 +15064,12 @@ namespace sqlite_orm {
using statement_type = std::tuple<Args...>;
template<class C>
- std::string operator()(const statement_type &statement, const C &context) const {
+ std::string operator()(const statement_type& statement, const C& context) const {
std::stringstream ss;
ss << '(';
auto index = 0;
using TupleSize = std::tuple_size<statement_type>;
- iterate_tuple(statement, [&context, &index, &ss](auto &value) {
+ iterate_tuple(statement, [&context, &index, &ss](auto& value) {
ss << serialize(value, context);
if(index < TupleSize::value - 1) {
ss << ", ";
@@ -11218,7 +15086,7 @@ namespace sqlite_orm {
using statement_type = values_t<Args...>;
template<class C>
- std::string operator()(const statement_type &statement, const C &context) const {
+ std::string operator()(const statement_type& statement, const C& context) const {
std::stringstream ss;
if(context.use_parentheses) {
ss << '(';
@@ -11226,10 +15094,10 @@ namespace sqlite_orm {
ss << "VALUES ";
{
auto index = 0;
- auto &tuple = statement.tuple;
+ auto& tuple = statement.tuple;
using tuple_type = typename std::decay<decltype(tuple)>::type;
using TupleSize = std::tuple_size<tuple_type>;
- iterate_tuple(tuple, [&context, &index, &ss](auto &value) {
+ iterate_tuple(tuple, [&context, &index, &ss](auto& value) {
ss << serialize(value, context);
if(index < TupleSize::value - 1) {
ss << ", ";
@@ -11249,7 +15117,7 @@ namespace sqlite_orm {
using statement_type = dynamic_values_t<T>;
template<class C>
- std::string operator()(const statement_type &statement, const C &context) const {
+ std::string operator()(const statement_type& statement, const C& context) const {
std::stringstream ss;
if(context.use_parentheses) {
ss << '(';
@@ -11258,7 +15126,7 @@ namespace sqlite_orm {
{
auto vectorSize = statement.vector.size();
for(decltype(vectorSize) index = 0; index < vectorSize; ++index) {
- auto &value = statement.vector[index];
+ auto& value = statement.vector[index];
ss << serialize(value, context);
if(index < vectorSize - 1) {
ss << ", ";
@@ -11279,6 +15147,10 @@ namespace sqlite_orm {
// #include "object_from_column_builder.h"
+// #include "table.h"
+
+// #include "column.h"
+
namespace sqlite_orm {
namespace internal {
@@ -11296,10 +15168,10 @@ namespace sqlite_orm {
* @param filename database filename.
* @param impl_ storage_impl head
*/
- storage_t(const std::string &filename, impl_type impl_) :
+ storage_t(const std::string& filename, impl_type impl_) :
storage_base{filename, foreign_keys_count(impl_)}, impl(std::move(impl_)) {}
- storage_t(const storage_t &other) : storage_base(other), impl(other.impl) {}
+ storage_t(const storage_t& other) : storage_base(other), impl(other.impl) {}
protected:
impl_type impl;
@@ -11317,42 +15189,30 @@ namespace sqlite_orm {
friend struct serializator_context_builder;
template<class I>
- void create_table(sqlite3 *db, const std::string &tableName, const I &tableImpl) {
+ void create_table(sqlite3* db, const std::string& tableName, const I& tableImpl) {
+ using table_type = typename std::decay<decltype(tableImpl.table)>::type;
std::stringstream ss;
ss << "CREATE TABLE '" << tableName << "' ( ";
- auto columnsCount = tableImpl.table.columns_count;
+ auto elementsCount = tableImpl.table.elements_count;
auto index = 0;
using context_t = serializator_context<impl_type>;
context_t context{this->impl};
- iterate_tuple(tableImpl.table.columns, [columnsCount, &index, &ss, &context](auto &c) {
- ss << serialize(c, context);
- if(index < columnsCount - 1) {
+ iterate_tuple(tableImpl.table.elements, [elementsCount, &index, &ss, &context](auto& element) {
+ ss << serialize(element, context);
+ if(index < elementsCount - 1) {
ss << ", ";
}
index++;
});
- ss << ") ";
- if(tableImpl.table._without_rowid) {
- ss << "WITHOUT ROWID ";
- }
- auto query = ss.str();
- sqlite3_stmt *stmt;
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- statement_finalizer finalizer{stmt};
- if(sqlite3_step(stmt) == SQLITE_DONE) {
- // done..
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
+ ss << ")";
+ if(table_type::is_without_rowid) {
+ ss << " WITHOUT ROWID";
}
+ perform_void_exec(db, ss.str());
}
template<class I>
- void backup_table(sqlite3 *db, const I &tableImpl, const std::vector<table_info *> &columnsToIgnore) {
+ void backup_table(sqlite3* db, const I& tableImpl, const std::vector<table_info*>& columnsToIgnore) {
// here we copy source table to another with a name with '_backup' suffix, but in case table with such
// a name already exists we append suffix 1, then 2, etc until we find a free name..
@@ -11387,18 +15247,43 @@ namespace sqlite_orm {
}
template<class O>
- auto &get_impl() const {
+ void assert_insertable_type() const {
+ auto& tImpl = this->get_impl<O>();
+ using table_type = typename std::decay<decltype(tImpl.table)>::type;
+ using elements_type = typename std::decay<decltype(tImpl.table.elements)>::type;
+
+ using is_without_rowid = std::integral_constant<bool, table_type::is_without_rowid>;
+
+ static_if<is_without_rowid{}>(
+ [](auto&) {}, // all right. it's a "without_rowid" table
+ [](auto& tImpl) { // unfortunately, this static_assert's can't see an composite keys((
+ std::ignore = tImpl;
+ static_assert(
+ count_tuple<elements_type, is_column_with_insertable_primary_key>::value <= 1,
+ "Attempting to execute 'insert' request into an noninsertable table was detected. "
+ "Insertable table cannot contain > 1 primary keys. Please use 'replace' instead of "
+ "'insert', or you can use 'insert' with explicit column listing.");
+ static_assert(
+ count_tuple<elements_type, is_column_with_noninsertable_primary_key>::value == 0,
+ "Attempting to execute 'insert' request into an noninsertable table was detected. "
+ "Insertable table cannot contain non-standard primary keys. Please use 'replace' instead "
+ "of 'insert', or you can use 'insert' with explicit column listing.");
+ })(tImpl);
+ }
+
+ template<class O>
+ auto& get_impl() const {
return this->impl.template get_impl<O>();
}
template<class O>
- auto &get_impl() {
+ auto& get_impl() {
return this->impl.template get_impl<O>();
}
public:
template<class T, class... Args>
- view_t<T, self, Args...> iterate(Args &&... args) {
+ view_t<T, self, Args...> iterate(Args&&... args) {
this->assert_mapped_type<T>();
auto con = this->get_connection();
@@ -11413,7 +15298,7 @@ namespace sqlite_orm {
* @example: storage.remove_all<User>(where(in(&User::id, {5, 6, 7}))); - DELETE FROM users WHERE id IN (5, 6, 7)
*/
template<class O, class... Args>
- void remove_all(Args &&... args) {
+ void remove_all(Args&&... args) {
this->assert_mapped_type<O>();
auto statement = this->prepare(sqlite_orm::remove_all<O>(std::forward<Args>(args)...));
this->execute(statement);
@@ -11438,7 +15323,7 @@ namespace sqlite_orm {
* @param o object to be updated.
*/
template<class O>
- void update(const O &o) {
+ void update(const O& o) {
this->assert_mapped_type<O>();
auto statement = this->prepare(sqlite_orm::update(std::ref(o)));
this->execute(statement);
@@ -11452,7 +15337,7 @@ namespace sqlite_orm {
protected:
template<class F, class O, class... Args>
- std::string group_concat_internal(F O::*m, std::unique_ptr<std::string> y, Args &&... args) {
+ std::string group_concat_internal(F O::*m, std::unique_ptr<std::string> y, Args&&... args) {
this->assert_mapped_type<O>();
std::vector<std::string> rows;
if(y) {
@@ -11477,7 +15362,7 @@ namespace sqlite_orm {
* @example: storage.get_all<User>(where(like(&User::name, "N%")), order_by(&User::id)); - SELECT * FROM users WHERE name LIKE 'N%' ORDER BY id
*/
template<class O, class... Args>
- auto get_all(Args &&... args) {
+ auto get_all(Args&&... args) {
this->assert_mapped_type<O>();
auto statement = this->prepare(sqlite_orm::get_all<O>(std::forward<Args>(args)...));
return this->execute(statement);
@@ -11492,7 +15377,7 @@ namespace sqlite_orm {
* @example: storage.get_all<User, std::list<User>>(where(like(&User::name, "N%")), order_by(&User::id)); - SELECT * FROM users WHERE name LIKE 'N%' ORDER BY id
*/
template<class O, class R, class... Args>
- auto get_all(Args &&... args) {
+ auto get_all(Args&&... args) {
this->assert_mapped_type<O>();
auto statement = this->prepare(sqlite_orm::get_all<O, R>(std::forward<Args>(args)...));
return this->execute(statement);
@@ -11507,7 +15392,7 @@ namespace sqlite_orm {
* @example: storage.get_all_pointer<User>(where(length(&User::name) > 6)); - SELECT * FROM users WHERE LENGTH(name) > 6
*/
template<class O, class... Args>
- auto get_all_pointer(Args &&... args) {
+ auto get_all_pointer(Args&&... args) {
this->assert_mapped_type<O>();
auto statement = this->prepare(sqlite_orm::get_all_pointer<O>(std::forward<Args>(args)...));
return this->execute(statement);
@@ -11522,7 +15407,7 @@ namespace sqlite_orm {
* @example: storage.get_all_pointer<User, std::list<User>>(where(length(&User::name) > 6)); - SELECT * FROM users WHERE LENGTH(name) > 6
*/
template<class O, class R, class... Args>
- auto get_all_pointer(Args &&... args) {
+ auto get_all_pointer(Args&&... args) {
this->assert_mapped_type<O>();
auto statement = this->prepare(sqlite_orm::get_all_pointer<O, R>(std::forward<Args>(args)...));
return this->execute(statement);
@@ -11590,7 +15475,7 @@ namespace sqlite_orm {
* @return Number of O object in table.
*/
template<class O, class... Args, class R = typename mapped_type_proxy<O>::type>
- int count(Args &&... args) {
+ int count(Args&&... args) {
this->assert_mapped_type<R>();
auto rows = this->select(sqlite_orm::count<R>(), std::forward<Args>(args)...);
if(!rows.empty()) {
@@ -11603,9 +15488,10 @@ namespace sqlite_orm {
/**
* SELECT COUNT(X) https://www.sqlite.org/lang_aggfunc.html#count
* @param m member pointer to class mapped to the storage.
+ * @return count of `m` values from database.
*/
template<class F, class O, class... Args>
- int count(F O::*m, Args &&... args) {
+ int count(F O::*m, Args&&... args) {
this->assert_mapped_type<O>();
auto rows = this->select(sqlite_orm::count(m), std::forward<Args>(args)...);
if(!rows.empty()) {
@@ -11618,10 +15504,10 @@ namespace sqlite_orm {
/**
* AVG(X) query. https://www.sqlite.org/lang_aggfunc.html#avg
* @param m is a class member pointer (the same you passed into make_column).
- * @return average value from db.
+ * @return average value from database.
*/
template<class F, class O, class... Args>
- double avg(F O::*m, Args &&... args) {
+ double avg(F O::*m, Args&&... args) {
this->assert_mapped_type<O>();
auto rows = this->select(sqlite_orm::avg(m), std::forward<Args>(args)...);
if(!rows.empty()) {
@@ -11646,7 +15532,7 @@ namespace sqlite_orm {
class... Args,
class Tuple = std::tuple<Args...>,
typename sfinae = typename std::enable_if<std::tuple_size<Tuple>::value >= 1>::type>
- std::string group_concat(F O::*m, Args &&... args) {
+ std::string group_concat(F O::*m, Args&&... args) {
return this->group_concat_internal(m, {}, std::forward<Args>(args)...);
}
@@ -11656,14 +15542,14 @@ namespace sqlite_orm {
* @return group_concat query result.
*/
template<class F, class O, class... Args>
- std::string group_concat(F O::*m, std::string y, Args &&... args) {
+ std::string group_concat(F O::*m, std::string y, Args&&... args) {
return this->group_concat_internal(m,
std::make_unique<std::string>(move(y)),
std::forward<Args>(args)...);
}
template<class F, class O, class... Args>
- std::string group_concat(F O::*m, const char *y, Args &&... args) {
+ std::string group_concat(F O::*m, const char* y, Args&&... args) {
std::unique_ptr<std::string> str;
if(y) {
str = std::make_unique<std::string>(y);
@@ -11679,7 +15565,7 @@ namespace sqlite_orm {
* @return std::unique_ptr with max value or null if sqlite engine returned null.
*/
template<class F, class O, class... Args, class Ret = typename column_result_t<self, F O::*>::type>
- std::unique_ptr<Ret> max(F O::*m, Args &&... args) {
+ std::unique_ptr<Ret> max(F O::*m, Args&&... args) {
this->assert_mapped_type<O>();
auto rows = this->select(sqlite_orm::max(m), std::forward<Args>(args)...);
if(!rows.empty()) {
@@ -11695,7 +15581,7 @@ namespace sqlite_orm {
* @return std::unique_ptr with min value or null if sqlite engine returned null.
*/
template<class F, class O, class... Args, class Ret = typename column_result_t<self, F O::*>::type>
- std::unique_ptr<Ret> min(F O::*m, Args &&... args) {
+ std::unique_ptr<Ret> min(F O::*m, Args&&... args) {
this->assert_mapped_type<O>();
auto rows = this->select(sqlite_orm::min(m), std::forward<Args>(args)...);
if(!rows.empty()) {
@@ -11711,7 +15597,7 @@ namespace sqlite_orm {
* @return std::unique_ptr with sum value or null if sqlite engine returned null.
*/
template<class F, class O, class... Args, class Ret = typename column_result_t<self, F O::*>::type>
- std::unique_ptr<Ret> sum(F O::*m, Args &&... args) {
+ std::unique_ptr<Ret> sum(F O::*m, Args&&... args) {
this->assert_mapped_type<O>();
std::vector<std::unique_ptr<double>> rows =
this->select(sqlite_orm::sum(m), std::forward<Args>(args)...);
@@ -11733,7 +15619,7 @@ namespace sqlite_orm {
* https://www.sqlite.org/lang_aggfunc.html)
*/
template<class F, class O, class... Args>
- double total(F O::*m, Args &&... args) {
+ double total(F O::*m, Args&&... args) {
this->assert_mapped_type<O>();
auto rows = this->select(sqlite_orm::total(m), std::forward<Args>(args)...);
if(!rows.empty()) {
@@ -11759,7 +15645,7 @@ namespace sqlite_orm {
template<class T>
typename std::enable_if<is_prepared_statement<T>::value, std::string>::type
- dump(const T &preparedStatement) const {
+ dump(const T& preparedStatement) const {
using context_t = serializator_context<impl_type>;
context_t context{this->impl};
return serialize(preparedStatement.t, context);
@@ -11771,13 +15657,13 @@ namespace sqlite_orm {
*/
template<class O>
typename std::enable_if<storage_traits::type_is_mapped<self, O>::value, std::string>::type
- dump(const O &o) {
- auto &tImpl = this->get_impl<O>();
+ dump(const O& o) {
+ auto& tImpl = this->get_impl<O>();
std::stringstream ss;
ss << "{ ";
using pair = std::pair<std::string, std::string>;
std::vector<pair> pairs;
- tImpl.table.for_each_column([&pairs, &o](auto &c) {
+ tImpl.table.for_each_column([&pairs, &o](auto& c) {
using column_type = typename std::decay<decltype(c)>::type;
using field_type = typename column_type::field_type;
pair p{c.name, std::string()};
@@ -11791,7 +15677,7 @@ namespace sqlite_orm {
pairs.push_back(move(p));
});
for(size_t i = 0; i < pairs.size(); ++i) {
- auto &p = pairs[i];
+ auto& p = pairs[i];
ss << p.first << " : '" << p.second << "'";
if(i < pairs.size() - 1) {
ss << ", ";
@@ -11809,7 +15695,7 @@ namespace sqlite_orm {
* id and creates own one.
*/
template<class O>
- void replace(const O &o) {
+ void replace(const O& o) {
this->assert_mapped_type<O>();
auto statement = this->prepare(sqlite_orm::replace(std::ref(o)));
this->execute(statement);
@@ -11827,8 +15713,19 @@ namespace sqlite_orm {
this->execute(statement);
}
+ template<class T, class It, class L>
+ void replace_range(It from, It to, L transformer) {
+ this->assert_mapped_type<T>();
+ if(from == to) {
+ return;
+ }
+
+ auto statement = this->prepare(sqlite_orm::replace_range<T>(from, to, std::move(transformer)));
+ this->execute(statement);
+ }
+
template<class O, class... Cols>
- int insert(const O &o, columns_t<Cols...> cols) {
+ int insert(const O& o, columns_t<Cols...> cols) {
constexpr const size_t colsCount = std::tuple_size<std::tuple<Cols...>>::value;
static_assert(colsCount > 0, "Use insert or replace with 1 argument instead");
this->assert_mapped_type<O>();
@@ -11842,22 +15739,116 @@ namespace sqlite_orm {
* @return id of just created object.
*/
template<class O>
- int insert(const O &o) {
+ int insert(const O& o) {
this->assert_mapped_type<O>();
- auto statement = this->prepare(sqlite_orm::insert(std::ref(o)));
- return int(this->execute(statement));
+ this->assert_insertable_type<O>();
+
+ return call_insert_impl_and_catch_constraint_failed([this, &o]() {
+ auto statement = this->prepare(sqlite_orm::insert(std::ref(o)));
+ return int(this->execute(statement));
+ });
+ }
+
+ /**
+ * Raw insert routine. Use this if `insert` with object does not fit you. This insert is designed to be able
+ * to call any type of `INSERT` query with no limitations.
+ * @example
+ * ```sql
+ * INSERT INTO users (id, name) VALUES(5, 'Little Mix')
+ * ```
+ * will be
+ * ```c++
+ * storage.insert(into<User>, columns(&User::id, &User::name), values(std::make_tuple(5, "Little Mix")));
+ * ```
+ * One more example:
+ * ```sql
+ * INSERT INTO singers (name) VALUES ('Sofia Reyes')('Kungs')
+ * ```
+ * will be
+ * ```c++
+ * storage.insert(into<Singer>(), columns(&Singer::name), values(std::make_tuple("Sofia Reyes"), std::make_tuple("Kungs")));
+ * ```
+ * One can use `default_values` to add `DEFAULT VALUES` modifier:
+ * ```sql
+ * INSERT INTO users DEFAULT VALUES
+ * ```
+ * will be
+ * ```c++
+ * storage.insert(into<Singer>(), default_values());
+ * ```
+ * Also one can use `INSERT OR ABORT`/`INSERT OR FAIL`/`INSERT OR IGNORE`/`INSERT OR REPLACE`/`INSERT ROLLBACK`:
+ * ```c++
+ * storage.insert(or_ignore(), into<Singer>(), columns(&Singer::name), values(std::make_tuple("Sofia Reyes"), std::make_tuple("Kungs")));
+ * storage.insert(or_rollback(), into<Singer>(), default_values());
+ * storage.insert(or_abort(), into<User>, columns(&User::id, &User::name), values(std::make_tuple(5, "Little Mix")));
+ * ```
+ */
+ template<class... Args>
+ void insert(Args... args) {
+ auto statement = this->prepare(sqlite_orm::insert(std::forward<Args>(args)...));
+ this->execute(statement);
+ }
+
+ /**
+ * Raw replace statement creation routine. Use this if `replace` with object does not fit you. This replace is designed to be able
+ * to call any type of `REPLACE` query with no limitations. Actually this is the same query as raw insert except `OR...` option existance.
+ * @example
+ * ```sql
+ * REPLACE INTO users (id, name) VALUES(5, 'Little Mix')
+ * ```
+ * will be
+ * ```c++
+ * storage.prepare(replace(into<User>, columns(&User::id, &User::name), values(std::make_tuple(5, "Little Mix"))));
+ * ```
+ * One more example:
+ * ```sql
+ * REPLACE INTO singers (name) VALUES ('Sofia Reyes')('Kungs')
+ * ```
+ * will be
+ * ```c++
+ * storage.prepare(replace(into<Singer>(), columns(&Singer::name), values(std::make_tuple("Sofia Reyes"), std::make_tuple("Kungs"))));
+ * ```
+ * One can use `default_values` to add `DEFAULT VALUES` modifier:
+ * ```sql
+ * REPLACE INTO users DEFAULT VALUES
+ * ```
+ * will be
+ * ```c++
+ * storage.prepare(replace(into<Singer>(), default_values()));
+ * ```
+ */
+ template<class... Args>
+ void replace(Args... args) {
+ auto statement = this->prepare(sqlite_orm::replace(std::forward<Args>(args)...));
+ this->execute(statement);
}
template<class It>
void insert_range(It from, It to) {
using O = typename std::iterator_traits<It>::value_type;
this->assert_mapped_type<O>();
+ this->assert_insertable_type<O>();
if(from == to) {
return;
}
- auto statement = this->prepare(sqlite_orm::insert_range(from, to));
- this->execute(statement);
+ call_insert_impl_and_catch_constraint_failed([this, from, to]() {
+ auto statement = this->prepare(sqlite_orm::insert_range(from, to));
+ this->execute(statement);
+ });
+ }
+
+ template<class T, class It, class L>
+ void insert_range(It from, It to, L transformer) {
+ this->assert_mapped_type<T>();
+ this->assert_insertable_type<T>();
+ if(from == to) {
+ return;
+ }
+ call_insert_impl_and_catch_constraint_failed([this, from, to, transformer = std::move(transformer)]() {
+ auto statement = this->prepare(sqlite_orm::insert_range<T>(from, to, std::move(transformer)));
+ this->execute(statement);
+ });
}
/**
@@ -11867,7 +15858,7 @@ namespace sqlite_orm {
template<class O>
void rename_table(std::string name) {
this->assert_mapped_type<O>();
- auto &tImpl = this->get_impl<O>();
+ auto& tImpl = this->get_impl<O>();
tImpl.table.name = move(name);
}
@@ -11878,30 +15869,44 @@ namespace sqlite_orm {
* any SQLite queries
*/
template<class O>
- const std::string &tablename() const {
+ const std::string& tablename() const {
this->assert_mapped_type<O>();
- auto &tImpl = this->get_impl<O>();
+ auto& tImpl = this->get_impl<O>();
return tImpl.table.name;
}
+ template<class F, class O>
+ const std::string* column_name(F O::*memberPointer) const {
+ return this->impl.column_name(memberPointer);
+ }
+
protected:
template<class... Tss, class... Cols>
- sync_schema_result sync_table(const storage_impl<index_t<Cols...>, Tss...> &tableImpl, sqlite3 *db, bool) {
+ sync_schema_result schema_status(const storage_impl<index_t<Cols...>, Tss...>&, sqlite3*, bool) {
+ return sync_schema_result::already_in_sync;
+ }
+
+ template<class T, bool WithoutRowId, class... Cs, class... Tss>
+ sync_schema_result schema_status(const storage_impl<table_t<T, WithoutRowId, Cs...>, Tss...>& tImpl,
+ sqlite3* db,
+ bool preserve) {
+ return tImpl.schema_status(db, preserve);
+ }
+
+ template<class... Tss, class... Cols>
+ sync_schema_result sync_table(const storage_impl<index_t<Cols...>, Tss...>& tableImpl, sqlite3* db, bool) {
auto res = sync_schema_result::already_in_sync;
using context_t = serializator_context<impl_type>;
context_t context{this->impl};
auto query = serialize(tableImpl.table, context);
- auto rc = sqlite3_exec(db, query.c_str(), nullptr, nullptr, nullptr);
- if(rc != SQLITE_OK) {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ perform_void_exec(db, query);
return res;
}
- template<class... Tss, class... Cs>
- sync_schema_result
- sync_table(const storage_impl<table_t<Cs...>, Tss...> &tImpl, sqlite3 *db, bool preserve) {
+ template<class T, bool WithoutRowId, class... Args, class... Tss>
+ sync_schema_result sync_table(const storage_impl<table_t<T, WithoutRowId, Args...>, Tss...>& tImpl,
+ sqlite3* db,
+ bool preserve) {
auto res = sync_schema_result::already_in_sync;
auto schema_stat = tImpl.schema_status(db, preserve);
@@ -11921,9 +15926,9 @@ namespace sqlite_orm {
auto dbTableInfo = tImpl.get_table_info(tImpl.table.name, db);
// this vector will contain pointers to columns that gotta be added..
- std::vector<table_info *> columnsToAdd;
+ std::vector<table_info*> columnsToAdd;
- tImpl.get_remove_add_columns(columnsToAdd, storageTableInfo, dbTableInfo);
+ tImpl.calculate_remove_add_columns(columnsToAdd, storageTableInfo, dbTableInfo);
if(schema_stat == sync_schema_result::old_columns_removed) {
@@ -11955,6 +15960,24 @@ namespace sqlite_orm {
return res;
}
+ template<typename S>
+ prepared_statement_t<S> prepare_impl(S statement) {
+ auto con = this->get_connection();
+ sqlite3_stmt* stmt;
+ auto db = con.get();
+ using context_t = serializator_context<impl_type>;
+ context_t context{this->impl};
+ context.skip_table_name = false;
+ context.replace_bindable_with_question = true;
+ auto query = serialize(statement, context);
+ if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
+ return prepared_statement_t<S>{std::forward<S>(statement), stmt, con};
+ } else {
+ throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
+ sqlite3_errmsg(db));
+ }
+ }
+
public:
/**
* This is a cute function used to replace migration up/down functionality.
@@ -11987,9 +16010,9 @@ namespace sqlite_orm {
auto con = this->get_connection();
std::map<std::string, sync_schema_result> result;
auto db = con.get();
- this->impl.for_each([&result, db, preserve, this](auto &tableImpl) {
- auto res = this->sync_table(tableImpl, db, preserve);
- result.insert({tableImpl.table.name, res});
+ this->impl.for_each([&result, db, preserve, this](auto& storageImpl) {
+ auto res = this->sync_table(storageImpl, db, preserve);
+ result.insert({storageImpl.table.name, res});
});
return result;
}
@@ -12003,8 +16026,9 @@ namespace sqlite_orm {
auto con = this->get_connection();
std::map<std::string, sync_schema_result> result;
auto db = con.get();
- this->impl.for_each([&result, db, preserve](auto tableImpl) {
- result.insert({tableImpl.table.name, tableImpl.schema_status(db, preserve)});
+ this->impl.for_each([&result, db, preserve, this](auto& tableImpl) {
+ auto schemaStatus = this->schema_status(tableImpl, db, preserve);
+ result.insert({tableImpl.table.name, schemaStatus});
});
return result;
}
@@ -12014,7 +16038,7 @@ namespace sqlite_orm {
* Note: table can be not mapped to a storage
* @return true if table with a given name exists in db, false otherwise.
*/
- bool table_exists(const std::string &tableName) {
+ bool table_exists(const std::string& tableName) {
auto con = this->get_connection();
return this->impl.table_exists(tableName, con.get());
}
@@ -12022,305 +16046,147 @@ namespace sqlite_orm {
template<class T, class... Args>
prepared_statement_t<select_t<T, Args...>> prepare(select_t<T, Args...> sel) {
sel.highest_level = true;
- auto con = this->get_connection();
- sqlite3_stmt *stmt;
- auto db = con.get();
- using context_t = serializator_context<impl_type>;
- context_t context{this->impl};
- context.skip_table_name = false;
- context.replace_bindable_with_question = true;
- auto query = serialize(sel, context);
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- return {std::move(sel), stmt, con};
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ return prepare_impl<select_t<T, Args...>>(std::move(sel));
}
template<class T, class... Args>
prepared_statement_t<get_all_t<T, Args...>> prepare(get_all_t<T, Args...> get_) {
- auto con = this->get_connection();
- sqlite3_stmt *stmt;
- auto db = con.get();
- using context_t = serializator_context<impl_type>;
- context_t context{this->impl};
- context.skip_table_name = false;
- context.replace_bindable_with_question = true;
- auto query = serialize(get_, context);
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- return {std::move(get_), stmt, con};
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ return prepare_impl<get_all_t<T, Args...>>(std::move(get_));
}
template<class T, class... Args>
prepared_statement_t<get_all_pointer_t<T, Args...>> prepare(get_all_pointer_t<T, Args...> get_) {
- auto con = this->get_connection();
- sqlite3_stmt *stmt;
- auto db = con.get();
- using context_t = serializator_context<impl_type>;
- context_t context{this->impl};
- context.skip_table_name = false;
- context.replace_bindable_with_question = true;
- auto query = serialize(get_, context);
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- return {std::move(get_), stmt, con};
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ return prepare_impl<get_all_pointer_t<T, Args...>>(std::move(get_));
+ }
+
+ template<class... Args>
+ prepared_statement_t<replace_raw_t<Args...>> prepare(replace_raw_t<Args...> ins) {
+ return prepare_impl<replace_raw_t<Args...>>(std::move(ins));
+ }
+
+ template<class... Args>
+ prepared_statement_t<insert_raw_t<Args...>> prepare(insert_raw_t<Args...> ins) {
+ return prepare_impl<insert_raw_t<Args...>>(std::move(ins));
}
#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
template<class T, class R, class... Args>
prepared_statement_t<get_all_optional_t<T, R, Args...>> prepare(get_all_optional_t<T, R, Args...> get_) {
- auto con = this->get_connection();
- sqlite3_stmt *stmt;
- auto db = con.get();
- using context_t = serializator_context<impl_type>;
- context_t context{this->impl};
- context.skip_table_name = false;
- context.replace_bindable_with_question = true;
- auto query = serialize(get_, context);
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- return {std::move(get_), stmt, con};
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ return prepare_impl<get_all_optional_t<T, R, Args...>>(std::move(get_));
}
#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
template<class... Args, class... Wargs>
prepared_statement_t<update_all_t<set_t<Args...>, Wargs...>>
prepare(update_all_t<set_t<Args...>, Wargs...> upd) {
- auto con = this->get_connection();
- sqlite3_stmt *stmt;
- auto db = con.get();
- using context_t = serializator_context<impl_type>;
- context_t context{this->impl};
- context.skip_table_name = false;
- context.replace_bindable_with_question = true;
- auto query = serialize(upd, context);
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- return {std::move(upd), stmt, con};
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ return prepare_impl<update_all_t<set_t<Args...>, Wargs...>>(std::move(upd));
}
template<class T, class... Args>
prepared_statement_t<remove_all_t<T, Args...>> prepare(remove_all_t<T, Args...> rem) {
- auto con = this->get_connection();
- sqlite3_stmt *stmt;
- auto db = con.get();
- using context_t = serializator_context<impl_type>;
- context_t context{this->impl};
- context.skip_table_name = false;
- context.replace_bindable_with_question = true;
- auto query = serialize(rem, context);
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- return {std::move(rem), stmt, std::move(con)};
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ return prepare_impl<remove_all_t<T, Args...>>(std::move(rem));
}
template<class T, class... Ids>
prepared_statement_t<get_t<T, Ids...>> prepare(get_t<T, Ids...> get_) {
- auto con = this->get_connection();
- sqlite3_stmt *stmt;
- auto db = con.get();
- using context_t = serializator_context<impl_type>;
- context_t context{this->impl};
- context.skip_table_name = false;
- context.replace_bindable_with_question = true;
- auto query = serialize(get_, context);
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- return {std::move(get_), stmt, con};
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ return prepare_impl<get_t<T, Ids...>>(std::move(get_));
}
template<class T, class... Ids>
prepared_statement_t<get_pointer_t<T, Ids...>> prepare(get_pointer_t<T, Ids...> get_) {
- auto con = this->get_connection();
- sqlite3_stmt *stmt;
- auto db = con.get();
- using context_t = serializator_context<impl_type>;
- context_t context{this->impl};
- context.skip_table_name = false;
- context.replace_bindable_with_question = true;
- auto query = serialize(get_, context);
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- return {std::move(get_), stmt, con};
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ return prepare_impl<get_pointer_t<T, Ids...>>(std::move(get_));
}
#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
template<class T, class... Ids>
prepared_statement_t<get_optional_t<T, Ids...>> prepare(get_optional_t<T, Ids...> get_) {
- auto con = this->get_connection();
- sqlite3_stmt *stmt;
- auto db = con.get();
- using context_t = serializator_context<impl_type>;
- context_t context{this->impl};
- context.skip_table_name = false;
- context.replace_bindable_with_question = true;
- auto query = serialize(get_, context);
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- return {std::move(get_), stmt, con};
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ return prepare_impl<get_optional_t<T, Ids...>>(std::move(get_));
}
#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
template<class T>
prepared_statement_t<update_t<T>> prepare(update_t<T> upd) {
- auto con = this->get_connection();
- sqlite3_stmt *stmt;
- auto db = con.get();
- using context_t = serializator_context<impl_type>;
- context_t context{this->impl};
- context.skip_table_name = false;
- context.replace_bindable_with_question = true;
- auto query = serialize(upd, context);
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- return {std::move(upd), stmt, con};
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ return prepare_impl<update_t<T>>(std::move(upd));
}
template<class T, class... Ids>
prepared_statement_t<remove_t<T, Ids...>> prepare(remove_t<T, Ids...> rem) {
- auto con = this->get_connection();
- sqlite3_stmt *stmt;
- auto db = con.get();
- using context_t = serializator_context<impl_type>;
- context_t context{this->impl};
- context.skip_table_name = false;
- context.replace_bindable_with_question = true;
- auto query = serialize(rem, context);
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- return {std::move(rem), stmt, con};
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ return prepare_impl<remove_t<T, Ids...>>(std::move(rem));
}
template<class T>
prepared_statement_t<insert_t<T>> prepare(insert_t<T> ins) {
using object_type = typename expression_object_type<decltype(ins)>::type;
this->assert_mapped_type<object_type>();
- auto con = this->get_connection();
- sqlite3_stmt *stmt;
- auto db = con.get();
- using context_t = serializator_context<impl_type>;
- context_t context{this->impl};
- context.skip_table_name = false;
- context.replace_bindable_with_question = true;
- auto query = serialize(ins, context);
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- return {std::move(ins), stmt, con};
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ this->assert_insertable_type<object_type>();
+ return prepare_impl<insert_t<T>>(std::move(ins));
}
template<class T>
prepared_statement_t<replace_t<T>> prepare(replace_t<T> rep) {
- auto con = this->get_connection();
- sqlite3_stmt *stmt;
using object_type = typename expression_object_type<decltype(rep)>::type;
this->assert_mapped_type<object_type>();
- auto db = con.get();
- using context_t = serializator_context<impl_type>;
- context_t context{this->impl};
- context.skip_table_name = false;
- context.replace_bindable_with_question = true;
- auto query = serialize(rep, context);
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- return {std::move(rep), stmt, con};
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ return prepare_impl<replace_t<T>>(std::move(rep));
}
- template<class It>
- prepared_statement_t<insert_range_t<It>> prepare(insert_range_t<It> statement) {
- auto con = this->get_connection();
- sqlite3_stmt *stmt;
- auto db = con.get();
- using context_t = serializator_context<impl_type>;
- context_t context{this->impl};
- context.skip_table_name = false;
- context.replace_bindable_with_question = true;
- auto query = serialize(statement, context);
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- return {std::move(statement), stmt, con};
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ template<class It, class L, class O>
+ prepared_statement_t<insert_range_t<It, L, O>> prepare(insert_range_t<It, L, O> statement) {
+ using object_type = typename expression_object_type<decltype(statement)>::type;
+ this->assert_mapped_type<object_type>();
+ this->assert_insertable_type<object_type>();
+ return prepare_impl<insert_range_t<It, L, O>>(std::move(statement));
}
- template<class It>
- prepared_statement_t<replace_range_t<It>> prepare(replace_range_t<It> rep) {
- auto con = this->get_connection();
- sqlite3_stmt *stmt;
- auto db = con.get();
- using context_t = serializator_context<impl_type>;
- context_t context{this->impl};
- context.skip_table_name = false;
- context.replace_bindable_with_question = true;
- auto query = serialize(rep, context);
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- return {std::move(rep), stmt, con};
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ template<class It, class L, class O>
+ prepared_statement_t<replace_range_t<It, L, O>> prepare(replace_range_t<It, L, O> rep) {
+ return prepare_impl<replace_range_t<It, L, O>>(std::move(rep));
}
template<class T, class... Cols>
prepared_statement_t<insert_explicit<T, Cols...>> prepare(insert_explicit<T, Cols...> ins) {
using object_type = typename expression_object_type<decltype(ins)>::type;
this->assert_mapped_type<object_type>();
+ return prepare_impl<insert_explicit<T, Cols...>>(std::move(ins));
+ }
+
+ template<class... Args>
+ void execute(const prepared_statement_t<replace_raw_t<Args...>>& statement) {
auto con = this->get_connection();
- sqlite3_stmt *stmt;
auto db = con.get();
- using context_t = serializator_context<impl_type>;
- context_t context{this->impl};
- context.skip_table_name = false;
- context.replace_bindable_with_question = true;
- auto query = serialize(ins, context);
- if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
- return {std::move(ins), stmt, con};
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ auto stmt = statement.stmt;
+ sqlite3_reset(stmt);
+ auto index = 1;
+ iterate_ast(statement.t.args, [stmt, &index, db](auto& node) {
+ using node_type = typename std::decay<decltype(node)>::type;
+ conditional_binder<node_type, is_bindable<node_type>> binder{stmt, index};
+ if(SQLITE_OK != binder(node)) {
+ throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
+ sqlite3_errmsg(db));
+ }
+ });
+ perform_step(db, stmt);
+ }
+
+ template<class... Args>
+ void execute(const prepared_statement_t<insert_raw_t<Args...>>& statement) {
+ auto con = this->get_connection();
+ auto db = con.get();
+ auto stmt = statement.stmt;
+ sqlite3_reset(stmt);
+ auto index = 1;
+ iterate_ast(statement.t.args, [stmt, &index, db](auto& node) {
+ using node_type = typename std::decay<decltype(node)>::type;
+ conditional_binder<node_type, is_bindable<node_type>> binder{stmt, index};
+ if(SQLITE_OK != binder(node)) {
+ throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
+ sqlite3_errmsg(db));
+ }
+ });
+ perform_step(db, stmt);
}
template<class T, class... Cols>
- int64 execute(const prepared_statement_t<insert_explicit<T, Cols...>> &statement) {
+ int64 execute(const prepared_statement_t<insert_explicit<T, Cols...>>& statement) {
using statement_type = typename std::decay<decltype(statement)>::type;
using expression_type = typename statement_type::expression_type;
using object_type = typename expression_object_type<expression_type>::type;
@@ -12328,40 +16194,37 @@ namespace sqlite_orm {
auto con = this->get_connection();
auto db = con.get();
auto stmt = statement.stmt;
- auto &tImpl = this->get_impl<object_type>();
- auto &o = statement.t.obj;
+ auto& tImpl = this->get_impl<object_type>();
+ auto& o = statement.t.obj;
sqlite3_reset(stmt);
- iterate_tuple(statement.t.columns.columns, [&o, &index, &stmt, &tImpl, db](auto &m) {
+ iterate_tuple(statement.t.columns.columns, [&o, &index, &stmt, &tImpl, db](auto& m) {
using column_type = typename std::decay<decltype(m)>::type;
using field_type = typename column_result_t<self, column_type>::type;
- const field_type *value = tImpl.table.template get_object_field_pointer<field_type>(o, m);
+ const field_type* value = tImpl.table.template get_object_field_pointer<field_type>(o, m);
if(SQLITE_OK != statement_binder<field_type>().bind(stmt, index++, *value)) {
throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
sqlite3_errmsg(db));
}
});
- if(sqlite3_step(stmt) == SQLITE_DONE) {
- return sqlite3_last_insert_rowid(db);
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ perform_step(db, stmt);
+ return sqlite3_last_insert_rowid(db);
}
- template<class It>
- void execute(const prepared_statement_t<replace_range_t<It>> &statement) {
+ template<class T,
+ typename std::enable_if<(is_replace_range<T>::value || is_replace<T>::value)>::type* = nullptr>
+ void execute(const prepared_statement_t<T>& statement) {
using statement_type = typename std::decay<decltype(statement)>::type;
using expression_type = typename statement_type::expression_type;
- using object_type = typename expression_type::object_type;
- auto &tImpl = this->get_impl<object_type>();
+ using object_type = typename expression_object_type<expression_type>::type;
+ auto& tImpl = this->get_impl<object_type>();
auto index = 1;
auto con = this->get_connection();
auto db = con.get();
auto stmt = statement.stmt;
sqlite3_reset(stmt);
- for(auto it = statement.t.range.first; it != statement.t.range.second; ++it) {
- auto &o = *it;
- tImpl.table.for_each_column([&o, &index, &stmt, db](auto &c) {
+
+ auto processObject = [&index, &stmt, &tImpl, db](auto& o) {
+ tImpl.table.for_each_column([&](auto& c) {
using column_type = typename std::decay<decltype(c)>::type;
using field_type = typename column_type::field_type;
if(c.member_pointer) {
@@ -12380,184 +16243,126 @@ namespace sqlite_orm {
}
}
});
- }
- if(sqlite3_step(stmt) == SQLITE_DONE) {
- //..
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
- }
+ };
- template<class It>
- void execute(const prepared_statement_t<insert_range_t<It>> &statement) {
- using statement_type = typename std::decay<decltype(statement)>::type;
- using expression_type = typename statement_type::expression_type;
- using object_type = typename expression_type::object_type;
- auto index = 1;
- auto con = this->get_connection();
- auto db = con.get();
- auto stmt = statement.stmt;
- auto &tImpl = this->get_impl<object_type>();
- sqlite3_reset(stmt);
- for(auto it = statement.t.range.first; it != statement.t.range.second; ++it) {
- auto &o = *it;
- tImpl.table.for_each_column([&o, &index, &stmt, db](auto &c) {
- if(!c.template has<constraints::primary_key_t<>>()) {
- using column_type = typename std::decay<decltype(c)>::type;
- using field_type = typename column_type::field_type;
- if(c.member_pointer) {
- if(SQLITE_OK !=
- statement_binder<field_type>().bind(stmt, index++, o.*c.member_pointer)) {
- throw std::system_error(
- std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
- } else {
- using getter_type = typename column_type::getter_type;
- field_value_holder<getter_type> valueHolder{((o).*(c.getter))()};
- if(SQLITE_OK != statement_binder<field_type>().bind(stmt, index++, valueHolder.value)) {
- throw std::system_error(
- std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
- }
- }
- });
- }
- if(sqlite3_step(stmt) == SQLITE_DONE) {
- //..
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ static_if<is_replace_range<T>{}>(
+ [&processObject](auto& statement) {
+ auto& transformer = statement.t.transformer;
+ std::for_each( ///
+ statement.t.range.first,
+ statement.t.range.second,
+ [&processObject, &transformer](auto& object) {
+ auto& realObject = transformer(object);
+ processObject(realObject);
+ });
+ },
+ [&processObject](auto& statement) {
+ auto& o = get_object(statement.t);
+ processObject(o);
+ })(statement);
+ perform_step(db, stmt);
}
- template<class T>
- void execute(const prepared_statement_t<replace_t<T>> &statement) {
+ template<class T,
+ typename std::enable_if<(is_insert_range<T>::value || is_insert<T>::value)>::type* = nullptr>
+ int64 execute(const prepared_statement_t<T>& statement) {
using statement_type = typename std::decay<decltype(statement)>::type;
using expression_type = typename statement_type::expression_type;
using object_type = typename expression_object_type<expression_type>::type;
- auto con = this->get_connection();
- auto db = con.get();
- auto stmt = statement.stmt;
auto index = 1;
- auto &o = get_object(statement.t);
- auto &tImpl = this->get_impl<object_type>();
- sqlite3_reset(stmt);
- tImpl.table.for_each_column([&o, &index, &stmt, db](auto &c) {
- using column_type = typename std::decay<decltype(c)>::type;
- using field_type = typename column_type::field_type;
- if(c.member_pointer) {
- if(SQLITE_OK != statement_binder<field_type>().bind(stmt, index++, o.*c.member_pointer)) {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
- } else {
- using getter_type = typename column_type::getter_type;
- field_value_holder<getter_type> valueHolder{((o).*(c.getter))()};
- if(SQLITE_OK != statement_binder<field_type>().bind(stmt, index++, valueHolder.value)) {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
- }
- });
- if(sqlite3_step(stmt) == SQLITE_DONE) {
- //..
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
- }
-
- template<class T>
- int64 execute(const prepared_statement_t<insert_t<T>> &statement) {
- using statement_type = typename std::decay<decltype(statement)>::type;
- using expression_type = typename statement_type::expression_type;
- using object_type = typename expression_object_type<expression_type>::type;
- int64 res = 0;
auto con = this->get_connection();
auto db = con.get();
auto stmt = statement.stmt;
- auto index = 1;
- auto &tImpl = this->get_impl<object_type>();
- auto &o = get_object(statement.t);
+ auto& tImpl = this->get_impl<object_type>();
auto compositeKeyColumnNames = tImpl.table.composite_key_columns_names();
sqlite3_reset(stmt);
- tImpl.table.for_each_column([&o, &index, &stmt, &tImpl, &compositeKeyColumnNames, db](auto &c) {
- if(tImpl.table._without_rowid || !c.template has<constraints::primary_key_t<>>()) {
- auto it = std::find(compositeKeyColumnNames.begin(), compositeKeyColumnNames.end(), c.name);
- if(it == compositeKeyColumnNames.end()) {
- using column_type = typename std::decay<decltype(c)>::type;
- using field_type = typename column_type::field_type;
- if(c.member_pointer) {
- if(SQLITE_OK !=
- statement_binder<field_type>().bind(stmt, index++, o.*c.member_pointer)) {
- throw std::system_error(
- std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
- } else {
- using getter_type = typename column_type::getter_type;
- field_value_holder<getter_type> valueHolder{((o).*(c.getter))()};
- if(SQLITE_OK != statement_binder<field_type>().bind(stmt, index++, valueHolder.value)) {
- throw std::system_error(
- std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
+ auto processObject = [&index, &stmt, &tImpl, &compositeKeyColumnNames, db](auto& o) {
+ tImpl.table.for_each_column([&](auto& c) {
+ using table_type = typename std::decay<decltype(tImpl.table)>::type;
+ if(table_type::is_without_rowid || !c.template has<primary_key_t<>>()) {
+ auto it = std::find(compositeKeyColumnNames.begin(), compositeKeyColumnNames.end(), c.name);
+ if(it == compositeKeyColumnNames.end()) {
+ using column_type = typename std::decay<decltype(c)>::type;
+ using field_type = typename column_type::field_type;
+ if(c.member_pointer) {
+ if(SQLITE_OK !=
+ statement_binder<field_type>().bind(stmt, index++, o.*c.member_pointer)) {
+ throw std::system_error(
+ std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
+ sqlite3_errmsg(db));
+ }
+ } else {
+ using getter_type = typename column_type::getter_type;
+ field_value_holder<getter_type> valueHolder{((o).*(c.getter))()};
+ if(SQLITE_OK !=
+ statement_binder<field_type>().bind(stmt, index++, valueHolder.value)) {
+ throw std::system_error(
+ std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
+ sqlite3_errmsg(db));
+ }
}
}
}
- }
- });
- if(sqlite3_step(stmt) == SQLITE_DONE) {
- res = sqlite3_last_insert_rowid(db);
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
- return res;
+ });
+ };
+
+ static_if<is_insert_range<T>{}>(
+ [&processObject](auto& statement) {
+ auto& transformer = statement.t.transformer;
+ std::for_each( ///
+ statement.t.range.first,
+ statement.t.range.second,
+ [&processObject, &transformer](auto& object) {
+ auto& realObject = transformer(object);
+ processObject(realObject);
+ });
+ },
+ [&processObject](auto& statement) {
+ auto& o = get_object(statement.t);
+ processObject(o);
+ })(statement);
+
+ perform_step(db, stmt);
+ return sqlite3_last_insert_rowid(db);
}
template<class T, class... Ids>
- void execute(const prepared_statement_t<remove_t<T, Ids...>> &statement) {
+ void execute(const prepared_statement_t<remove_t<T, Ids...>>& statement) {
auto con = this->get_connection();
auto db = con.get();
auto stmt = statement.stmt;
auto index = 1;
sqlite3_reset(stmt);
- iterate_ast(statement.t.ids, [stmt, &index, db](auto &v) {
+ iterate_ast(statement.t.ids, [stmt, &index, db](auto& v) {
using field_type = typename std::decay<decltype(v)>::type;
if(SQLITE_OK != statement_binder<field_type>().bind(stmt, index++, v)) {
throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
sqlite3_errmsg(db));
}
});
- if(sqlite3_step(stmt) == SQLITE_DONE) {
- // done..
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ perform_step(db, stmt);
}
template<class T>
- void execute(const prepared_statement_t<update_t<T>> &statement) {
+ void execute(const prepared_statement_t<update_t<T>>& statement) {
using statement_type = typename std::decay<decltype(statement)>::type;
using expression_type = typename statement_type::expression_type;
using object_type = typename expression_object_type<expression_type>::type;
auto con = this->get_connection();
auto db = con.get();
- auto &tImpl = this->get_impl<object_type>();
+ auto& tImpl = this->get_impl<object_type>();
auto stmt = statement.stmt;
auto index = 1;
- auto &o = get_object(statement.t);
+ auto& o = get_object(statement.t);
sqlite3_reset(stmt);
- tImpl.table.for_each_column([&o, stmt, &index, db](auto &c) {
- if(!c.template has<constraints::primary_key_t<>>()) {
- using column_type = typename std::decay<decltype(c)>::type;
+ tImpl.table.for_each_column([&o, stmt, &index, db, &tImpl](auto& column) {
+ if(!column.template has<primary_key_t<>>() &&
+ !tImpl.table.exists_in_composite_primary_key(column)) {
+ using column_type = typename std::decay<decltype(column)>::type;
using field_type = typename column_type::field_type;
- if(c.member_pointer) {
- auto bind_res = statement_binder<field_type>().bind(stmt, index++, o.*c.member_pointer);
+ if(column.member_pointer) {
+ auto bind_res =
+ statement_binder<field_type>().bind(stmt, index++, o.*column.member_pointer);
if(SQLITE_OK != bind_res) {
throw std::system_error(
std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
@@ -12565,7 +16370,7 @@ namespace sqlite_orm {
}
} else {
using getter_type = typename column_type::getter_type;
- field_value_holder<getter_type> valueHolder{((o).*(c.getter))()};
+ field_value_holder<getter_type> valueHolder{((o).*(column.getter))()};
if(SQLITE_OK != statement_binder<field_type>().bind(stmt, index++, valueHolder.value)) {
throw std::system_error(
std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
@@ -12574,19 +16379,20 @@ namespace sqlite_orm {
}
}
});
- tImpl.table.for_each_column([&o, stmt, &index, db](auto &c) {
- if(c.template has<constraints::primary_key_t<>>()) {
- using column_type = typename std::decay<decltype(c)>::type;
+ tImpl.table.for_each_column([&o, stmt, &index, db, &tImpl](auto& column) {
+ if(column.template has<primary_key_t<>>() || tImpl.table.exists_in_composite_primary_key(column)) {
+ using column_type = typename std::decay<decltype(column)>::type;
using field_type = typename column_type::field_type;
- if(c.member_pointer) {
- if(SQLITE_OK != statement_binder<field_type>().bind(stmt, index++, o.*c.member_pointer)) {
+ if(column.member_pointer) {
+ if(SQLITE_OK !=
+ statement_binder<field_type>().bind(stmt, index++, o.*column.member_pointer)) {
throw std::system_error(
std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
sqlite3_errmsg(db));
}
} else {
using getter_type = typename column_type::getter_type;
- field_value_holder<getter_type> valueHolder{((o).*(c.getter))()};
+ field_value_holder<getter_type> valueHolder{((o).*(column.getter))()};
if(SQLITE_OK != statement_binder<field_type>().bind(stmt, index++, valueHolder.value)) {
throw std::system_error(
std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
@@ -12595,23 +16401,18 @@ namespace sqlite_orm {
}
}
});
- if(sqlite3_step(stmt) == SQLITE_DONE) {
- // done..
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ perform_step(db, stmt);
}
template<class T, class... Ids>
- std::unique_ptr<T> execute(const prepared_statement_t<get_pointer_t<T, Ids...>> &statement) {
- auto &tImpl = this->get_impl<T>();
+ std::unique_ptr<T> execute(const prepared_statement_t<get_pointer_t<T, Ids...>>& statement) {
+ auto& tImpl = this->get_impl<T>();
auto con = this->get_connection();
auto db = con.get();
auto stmt = statement.stmt;
auto index = 1;
sqlite3_reset(stmt);
- iterate_ast(statement.t.ids, [stmt, &index, db](auto &v) {
+ iterate_ast(statement.t.ids, [stmt, &index, db](auto& v) {
using field_type = typename std::decay<decltype(v)>::type;
if(SQLITE_OK != statement_binder<field_type>().bind(stmt, index++, v)) {
throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
@@ -12638,14 +16439,14 @@ namespace sqlite_orm {
#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
template<class T, class... Ids>
- std::optional<T> execute(const prepared_statement_t<get_optional_t<T, Ids...>> &statement) {
- auto &tImpl = this->get_impl<T>();
+ std::optional<T> execute(const prepared_statement_t<get_optional_t<T, Ids...>>& statement) {
+ auto& tImpl = this->get_impl<T>();
auto con = this->get_connection();
auto db = con.get();
auto stmt = statement.stmt;
auto index = 1;
sqlite3_reset(stmt);
- iterate_ast(statement.t.ids, [stmt, &index, db](auto &v) {
+ iterate_ast(statement.t.ids, [stmt, &index, db](auto& v) {
using field_type = typename std::decay<decltype(v)>::type;
if(SQLITE_OK != statement_binder<field_type>().bind(stmt, index++, v)) {
throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
@@ -12672,14 +16473,14 @@ namespace sqlite_orm {
#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
template<class T, class... Ids>
- T execute(const prepared_statement_t<get_t<T, Ids...>> &statement) {
- auto &tImpl = this->get_impl<T>();
+ T execute(const prepared_statement_t<get_t<T, Ids...>>& statement) {
+ auto& tImpl = this->get_impl<T>();
auto con = this->get_connection();
auto db = con.get();
auto stmt = statement.stmt;
auto index = 1;
sqlite3_reset(stmt);
- iterate_ast(statement.t.ids, [stmt, &index, db](auto &v) {
+ iterate_ast(statement.t.ids, [stmt, &index, db](auto& v) {
using field_type = typename std::decay<decltype(v)>::type;
if(SQLITE_OK != statement_binder<field_type>().bind(stmt, index++, v)) {
throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
@@ -12705,13 +16506,13 @@ namespace sqlite_orm {
}
template<class T, class... Args>
- void execute(const prepared_statement_t<remove_all_t<T, Args...>> &statement) {
+ void execute(const prepared_statement_t<remove_all_t<T, Args...>>& statement) {
auto con = this->get_connection();
auto db = con.get();
auto stmt = statement.stmt;
auto index = 1;
sqlite3_reset(stmt);
- iterate_ast(statement.t.conditions, [stmt, &index, db](auto &node) {
+ iterate_ast(statement.t.conditions, [stmt, &index, db](auto& node) {
using node_type = typename std::decay<decltype(node)>::type;
conditional_binder<node_type, is_bindable<node_type>> binder{stmt, index};
if(SQLITE_OK != binder(node)) {
@@ -12719,23 +16520,18 @@ namespace sqlite_orm {
sqlite3_errmsg(db));
}
});
- if(sqlite3_step(stmt) == SQLITE_DONE) {
- // done..
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ perform_step(db, stmt);
}
template<class... Args, class... Wargs>
- void execute(const prepared_statement_t<update_all_t<set_t<Args...>, Wargs...>> &statement) {
+ void execute(const prepared_statement_t<update_all_t<set_t<Args...>, Wargs...>>& statement) {
auto con = this->get_connection();
auto db = con.get();
auto stmt = statement.stmt;
auto index = 1;
sqlite3_reset(stmt);
- iterate_tuple(statement.t.set.assigns, [&index, stmt, db](auto &setArg) {
- iterate_ast(setArg, [&index, stmt, db](auto &node) {
+ iterate_tuple(statement.t.set.assigns, [&index, stmt, db](auto& setArg) {
+ iterate_ast(setArg, [&index, stmt, db](auto& node) {
using node_type = typename std::decay<decltype(node)>::type;
conditional_binder<node_type, is_bindable<node_type>> binder{stmt, index};
if(SQLITE_OK != binder(node)) {
@@ -12744,7 +16540,7 @@ namespace sqlite_orm {
}
});
});
- iterate_ast(statement.t.conditions, [stmt, &index, db](auto &node) {
+ iterate_ast(statement.t.conditions, [stmt, &index, db](auto& node) {
using node_type = typename std::decay<decltype(node)>::type;
conditional_binder<node_type, is_bindable<node_type>> binder{stmt, index};
if(SQLITE_OK != binder(node)) {
@@ -12752,22 +16548,17 @@ namespace sqlite_orm {
sqlite3_errmsg(db));
}
});
- if(sqlite3_step(stmt) == SQLITE_DONE) {
- // done..
- } else {
- throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
- sqlite3_errmsg(db));
- }
+ perform_step(db, stmt);
}
template<class T, class... Args, class R = typename column_result_t<self, T>::type>
- std::vector<R> execute(const prepared_statement_t<select_t<T, Args...>> &statement) {
+ std::vector<R> execute(const prepared_statement_t<select_t<T, Args...>>& statement) {
auto con = this->get_connection();
auto db = con.get();
auto stmt = statement.stmt;
auto index = 1;
sqlite3_reset(stmt);
- iterate_ast(statement.t, [stmt, &index, db](auto &node) {
+ iterate_ast(statement.t, [stmt, &index, db](auto& node) {
using node_type = typename std::decay<decltype(node)>::type;
conditional_binder<node_type, is_bindable<node_type>> binder{stmt, index};
if(SQLITE_OK != binder(node)) {
@@ -12801,14 +16592,14 @@ namespace sqlite_orm {
}
template<class T, class R, class... Args>
- R execute(const prepared_statement_t<get_all_t<T, R, Args...>> &statement) {
- auto &tImpl = this->get_impl<T>();
+ R execute(const prepared_statement_t<get_all_t<T, R, Args...>>& statement) {
+ auto& tImpl = this->get_impl<T>();
auto con = this->get_connection();
auto db = con.get();
auto stmt = statement.stmt;
auto index = 1;
sqlite3_reset(stmt);
- iterate_ast(statement.t, [stmt, &index, db](auto &node) {
+ iterate_ast(statement.t, [stmt, &index, db](auto& node) {
using node_type = typename std::decay<decltype(node)>::type;
conditional_binder<node_type, is_bindable<node_type>> binder{stmt, index};
if(SQLITE_OK != binder(node)) {
@@ -12839,14 +16630,14 @@ namespace sqlite_orm {
}
template<class T, class R, class... Args>
- R execute(const prepared_statement_t<get_all_pointer_t<T, R, Args...>> &statement) {
- auto &tImpl = this->get_impl<T>();
+ R execute(const prepared_statement_t<get_all_pointer_t<T, R, Args...>>& statement) {
+ auto& tImpl = this->get_impl<T>();
auto con = this->get_connection();
auto db = con.get();
auto stmt = statement.stmt;
auto index = 1;
sqlite3_reset(stmt);
- iterate_ast(statement.t, [stmt, &index, db](auto &node) {
+ iterate_ast(statement.t, [stmt, &index, db](auto& node) {
using node_type = typename std::decay<decltype(node)>::type;
conditional_binder<node_type, is_bindable<node_type>> binder{stmt, index};
if(SQLITE_OK != binder(node)) {
@@ -12878,14 +16669,14 @@ namespace sqlite_orm {
#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
template<class T, class R, class... Args>
- R execute(const prepared_statement_t<get_all_optional_t<T, R, Args...>> &statement) {
- auto &tImpl = this->get_impl<T>();
+ R execute(const prepared_statement_t<get_all_optional_t<T, R, Args...>>& statement) {
+ auto& tImpl = this->get_impl<T>();
auto con = this->get_connection();
auto db = con.get();
auto stmt = statement.stmt;
auto index = 1;
sqlite3_reset(stmt);
- iterate_ast(statement.t, [stmt, &index, db](auto &node) {
+ iterate_ast(statement.t, [stmt, &index, db](auto& node) {
using node_type = typename std::decay<decltype(node)>::type;
conditional_binder<node_type, is_bindable<node_type>> binder{stmt, index};
if(SQLITE_OK != binder(node)) {
@@ -12915,6 +16706,88 @@ namespace sqlite_orm {
return res;
}
#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
+
+ template<class O>
+ bool has_dependent_rows(const O& object) {
+ auto res = false;
+ this->impl.for_each([this, &object, &res](auto& storageImpl) {
+ if(res) {
+ return;
+ }
+ storageImpl.table.for_each_foreign_key([&storageImpl, this, &object, &res](auto& foreignKey) {
+ using ForeignKey = typename std::decay<decltype(foreignKey)>::type;
+ using TargetType = typename ForeignKey::target_type;
+ if(std::is_same<TargetType, O>::value) {
+ std::stringstream ss;
+ ss << "SELECT COUNT(*)";
+ ss << " FROM " << storageImpl.table.name;
+ ss << " WHERE";
+ auto columnIndex = 0;
+ iterate_tuple(foreignKey.columns, [&ss, &columnIndex, &storageImpl](auto& column) {
+ if(columnIndex > 0) {
+ ss << " AND";
+ }
+ if(auto columnName = storageImpl.table.find_column_name(column)) {
+ ss << ' ' << *columnName << " = ?";
+ } else {
+ throw std::system_error(
+ std::make_error_code(sqlite_orm::orm_error_code::column_not_found));
+ }
+ ++columnIndex;
+ });
+ auto query = ss.str();
+ ss.flush();
+ auto con = this->get_connection();
+ sqlite3_stmt* stmt;
+ auto db = con.get();
+ if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
+ statement_finalizer finalizer(stmt);
+ columnIndex = 1;
+ iterate_tuple(
+ foreignKey.references,
+ [&columnIndex, stmt, &object, db](auto& memberPointer) {
+ using MemberPointer = typename std::decay<decltype(memberPointer)>::type;
+ using field_type = typename member_traits<MemberPointer>::field_type;
+ // if(column.member_pointer) {
+ if(SQLITE_OK != statement_binder<field_type>().bind(stmt,
+ columnIndex++,
+ object.*memberPointer)) {
+ throw std::system_error(
+ std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
+ sqlite3_errmsg(db));
+ }
+ /*} else {
+ using getter_type = typename column_type::getter_type;
+ field_value_holder<getter_type> valueHolder{((object).*(column.getter))()};
+ if(SQLITE_OK != statement_binder<field_type>().bind(stmt, columnIndex++, valueHolder.value)) {
+ throw std::system_error(
+ std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
+ sqlite3_errmsg(db));
+ }
+ }*/
+ });
+ if(SQLITE_ROW != sqlite3_step(stmt)) {
+ throw std::system_error(
+ std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
+ sqlite3_errmsg(db));
+ }
+ auto countResult = sqlite3_column_int(stmt, 0);
+ res = countResult > 0;
+ if(SQLITE_DONE != sqlite3_step(stmt)) {
+ throw std::system_error(
+ std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
+ sqlite3_errmsg(db));
+ }
+ } else {
+ throw std::system_error(
+ std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
+ sqlite3_errmsg(db));
+ }
+ }
+ });
+ });
+ return res;
+ }
}; // struct storage_t
template<class T>
@@ -12925,8 +16798,8 @@ namespace sqlite_orm {
}
template<class... Ts>
- internal::storage_t<Ts...> make_storage(const std::string &filename, Ts... tables) {
- return {filename, internal::storage_impl<Ts...>(tables...)};
+ internal::storage_t<Ts...> make_storage(const std::string& filename, Ts... tables) {
+ return {filename, internal::storage_impl<Ts...>(std::forward<Ts>(tables)...)};
}
/**
@@ -12953,6 +16826,9 @@ __pragma(pop_macro("min"))
#include <tuple> // std::tuple
#include <utility> // std::pair
#include <functional> // std::reference_wrapper
+#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
+#include <optional> // std::optional
+#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
// #include "conditions.h"
@@ -12966,6 +16842,14 @@ __pragma(pop_macro("min"))
// #include "core_functions.h"
+ // #include "function.h"
+
+ // #include "ast/excluded.h"
+
+ // #include "ast/upsert_clause.h"
+
+ // #include "ast/where.h"
+
namespace sqlite_orm {
namespace internal {
@@ -12979,12 +16863,32 @@ __pragma(pop_macro("min"))
struct node_tuple<void, void> {
using type = std::tuple<>;
};
-
+#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
+ template<class T>
+ struct node_tuple<as_optional_t<T>, void> {
+ using type = typename node_tuple<T>::type;
+ };
+#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
template<class T>
struct node_tuple<std::reference_wrapper<T>, void> {
using type = typename node_tuple<T>::type;
};
+ template<class... TargetArgs, class... ActionsArgs>
+ struct node_tuple<upsert_clause<std::tuple<TargetArgs...>, std::tuple<ActionsArgs...>>, void> {
+ using type = typename node_tuple<std::tuple<ActionsArgs...>>::type;
+ };
+
+ template<class... Args>
+ struct node_tuple<set_t<Args...>, void> {
+ using type = typename conc_tuple<typename node_tuple<Args>::type...>::type;
+ };
+
+ template<class T>
+ struct node_tuple<excluded_t<T>, void> {
+ using type = typename node_tuple<T>::type;
+ };
+
template<class C>
struct node_tuple<where_t<C>, void> {
using node_type = where_t<C>;
@@ -13018,13 +16922,21 @@ __pragma(pop_macro("min"))
};
template<class L, class A>
- struct node_tuple<in_t<L, A>, void> {
- using node_type = in_t<L, A>;
+ struct node_tuple<dynamic_in_t<L, A>, void> {
+ using node_type = dynamic_in_t<L, A>;
using left_tuple = typename node_tuple<L>::type;
using right_tuple = typename node_tuple<A>::type;
using type = typename conc_tuple<left_tuple, right_tuple>::type;
};
+ template<class L, class... Args>
+ struct node_tuple<in_t<L, Args...>, void> {
+ using node_type = in_t<L, Args...>;
+ using left_tuple = typename node_tuple<L>::type;
+ using right_tuple = typename conc_tuple<typename node_tuple<Args>::type...>::type;
+ using type = typename conc_tuple<left_tuple, right_tuple>::type;
+ };
+
template<class T>
struct node_tuple<T, typename std::enable_if<is_base_of_template<T, compound_operator>::value>::type> {
using node_type = T;
@@ -13043,6 +16955,36 @@ __pragma(pop_macro("min"))
using type = typename conc_tuple<columns_tuple, args_tuple>::type;
};
+ template<class... Args>
+ struct node_tuple<insert_raw_t<Args...>, void> {
+ using node_type = insert_raw_t<Args...>;
+ using type = typename conc_tuple<typename node_tuple<Args>::type...>::type;
+ };
+
+ template<class... Args>
+ struct node_tuple<replace_raw_t<Args...>, void> {
+ using node_type = replace_raw_t<Args...>;
+ using type = typename conc_tuple<typename node_tuple<Args>::type...>::type;
+ };
+
+ template<class T>
+ struct node_tuple<into_t<T>, void> {
+ using node_type = into_t<T>;
+ using type = std::tuple<>;
+ };
+
+ template<class... Args>
+ struct node_tuple<values_t<Args...>, void> {
+ using node_type = values_t<Args...>;
+ using type = typename conc_tuple<typename node_tuple<Args>::type...>::type;
+ };
+
+ template<class... Args>
+ struct node_tuple<std::tuple<Args...>, void> {
+ using node_type = std::tuple<Args...>;
+ using type = typename conc_tuple<typename node_tuple<Args>::type...>::type;
+ };
+
template<class T, class R, class... Args>
struct node_tuple<get_all_t<T, R, Args...>, void> {
using node_type = get_all_t<T, R, Args...>;
@@ -13158,8 +17100,14 @@ __pragma(pop_macro("min"))
};
template<class R, class S, class... Args>
- struct node_tuple<core_function_t<R, S, Args...>, void> {
- using node_type = core_function_t<R, S, Args...>;
+ struct node_tuple<built_in_function_t<R, S, Args...>, void> {
+ using node_type = built_in_function_t<R, S, Args...>;
+ using type = typename conc_tuple<typename node_tuple<Args>::type...>::type;
+ };
+
+ template<class F, class... Args>
+ struct node_tuple<function_call<F, Args...>, void> {
+ using node_type = function_call<F, Args...>;
using type = typename conc_tuple<typename node_tuple<Args>::type...>::type;
};
@@ -13249,132 +17197,132 @@ __pragma(pop_macro("min"))
namespace sqlite_orm {
- template<int N, class It>
- auto &get(internal::prepared_statement_t<internal::insert_range_t<It>> &statement) {
+ template<int N, class It, class L, class O>
+ auto& get(internal::prepared_statement_t<internal::insert_range_t<It, L, O>>& statement) {
return std::get<N>(statement.t.range);
}
- template<int N, class It>
- const auto &get(const internal::prepared_statement_t<internal::insert_range_t<It>> &statement) {
+ template<int N, class It, class L, class O>
+ const auto& get(const internal::prepared_statement_t<internal::insert_range_t<It, L, O>>& statement) {
return std::get<N>(statement.t.range);
}
- template<int N, class It>
- auto &get(internal::prepared_statement_t<internal::replace_range_t<It>> &statement) {
+ template<int N, class It, class L, class O>
+ auto& get(internal::prepared_statement_t<internal::replace_range_t<It, L, O>>& statement) {
return std::get<N>(statement.t.range);
}
- template<int N, class It>
- const auto &get(const internal::prepared_statement_t<internal::replace_range_t<It>> &statement) {
+ template<int N, class It, class L, class O>
+ const auto& get(const internal::prepared_statement_t<internal::replace_range_t<It, L, O>>& statement) {
return std::get<N>(statement.t.range);
}
template<int N, class T, class... Ids>
- auto &get(internal::prepared_statement_t<internal::get_t<T, Ids...>> &statement) {
+ auto& get(internal::prepared_statement_t<internal::get_t<T, Ids...>>& statement) {
return internal::get_ref(std::get<N>(statement.t.ids));
}
template<int N, class T, class... Ids>
- const auto &get(const internal::prepared_statement_t<internal::get_t<T, Ids...>> &statement) {
+ const auto& get(const internal::prepared_statement_t<internal::get_t<T, Ids...>>& statement) {
return internal::get_ref(std::get<N>(statement.t.ids));
}
template<int N, class T, class... Ids>
- auto &get(internal::prepared_statement_t<internal::get_pointer_t<T, Ids...>> &statement) {
+ auto& get(internal::prepared_statement_t<internal::get_pointer_t<T, Ids...>>& statement) {
return internal::get_ref(std::get<N>(statement.t.ids));
}
template<int N, class T, class... Ids>
- const auto &get(const internal::prepared_statement_t<internal::get_pointer_t<T, Ids...>> &statement) {
+ const auto& get(const internal::prepared_statement_t<internal::get_pointer_t<T, Ids...>>& statement) {
return internal::get_ref(std::get<N>(statement.t.ids));
}
#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
template<int N, class T, class... Ids>
- auto &get(internal::prepared_statement_t<internal::get_optional_t<T, Ids...>> &statement) {
+ auto& get(internal::prepared_statement_t<internal::get_optional_t<T, Ids...>>& statement) {
return internal::get_ref(std::get<N>(statement.t.ids));
}
template<int N, class T, class... Ids>
- const auto &get(const internal::prepared_statement_t<internal::get_optional_t<T, Ids...>> &statement) {
+ const auto& get(const internal::prepared_statement_t<internal::get_optional_t<T, Ids...>>& statement) {
return internal::get_ref(std::get<N>(statement.t.ids));
}
#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
template<int N, class T, class... Ids>
- auto &get(internal::prepared_statement_t<internal::remove_t<T, Ids...>> &statement) {
+ auto& get(internal::prepared_statement_t<internal::remove_t<T, Ids...>>& statement) {
return internal::get_ref(std::get<N>(statement.t.ids));
}
template<int N, class T, class... Ids>
- const auto &get(const internal::prepared_statement_t<internal::remove_t<T, Ids...>> &statement) {
+ const auto& get(const internal::prepared_statement_t<internal::remove_t<T, Ids...>>& statement) {
return internal::get_ref(std::get<N>(statement.t.ids));
}
template<int N, class T>
- auto &get(internal::prepared_statement_t<internal::update_t<T>> &statement) {
+ auto& get(internal::prepared_statement_t<internal::update_t<T>>& statement) {
static_assert(N == 0, "get<> works only with 0 argument for update statement");
return internal::get_ref(statement.t.obj);
}
template<int N, class T>
- const auto &get(const internal::prepared_statement_t<internal::update_t<T>> &statement) {
+ const auto& get(const internal::prepared_statement_t<internal::update_t<T>>& statement) {
static_assert(N == 0, "get<> works only with 0 argument for update statement");
return internal::get_ref(statement.t.obj);
}
template<int N, class T, class... Cols>
- auto &get(internal::prepared_statement_t<internal::insert_explicit<T, Cols...>> &statement) {
+ auto& get(internal::prepared_statement_t<internal::insert_explicit<T, Cols...>>& statement) {
static_assert(N == 0, "get<> works only with 0 argument for insert statement");
return internal::get_ref(statement.t.obj);
}
template<int N, class T, class... Cols>
- const auto &get(const internal::prepared_statement_t<internal::insert_explicit<T, Cols...>> &statement) {
+ const auto& get(const internal::prepared_statement_t<internal::insert_explicit<T, Cols...>>& statement) {
static_assert(N == 0, "get<> works only with 0 argument for insert statement");
return internal::get_ref(statement.t.obj);
}
template<int N, class T>
- auto &get(internal::prepared_statement_t<internal::replace_t<T>> &statement) {
+ auto& get(internal::prepared_statement_t<internal::replace_t<T>>& statement) {
static_assert(N == 0, "get<> works only with 0 argument for replace statement");
return internal::get_ref(statement.t.obj);
}
template<int N, class T>
- const auto &get(const internal::prepared_statement_t<internal::replace_t<T>> &statement) {
+ const auto& get(const internal::prepared_statement_t<internal::replace_t<T>>& statement) {
static_assert(N == 0, "get<> works only with 0 argument for replace statement");
return internal::get_ref(statement.t.obj);
}
template<int N, class T>
- auto &get(internal::prepared_statement_t<internal::insert_t<T>> &statement) {
+ auto& get(internal::prepared_statement_t<internal::insert_t<T>>& statement) {
static_assert(N == 0, "get<> works only with 0 argument for insert statement");
return internal::get_ref(statement.t.obj);
}
template<int N, class T>
- const auto &get(const internal::prepared_statement_t<internal::insert_t<T>> &statement) {
+ const auto& get(const internal::prepared_statement_t<internal::insert_t<T>>& statement) {
static_assert(N == 0, "get<> works only with 0 argument for insert statement");
return internal::get_ref(statement.t.obj);
}
template<int N, class T>
- const auto &get(const internal::prepared_statement_t<T> &statement) {
+ const auto& get(const internal::prepared_statement_t<T>& statement) {
using statement_type = typename std::decay<decltype(statement)>::type;
using expression_type = typename statement_type::expression_type;
using node_tuple = typename internal::node_tuple<expression_type>::type;
using bind_tuple = typename internal::bindable_filter<node_tuple>::type;
- using result_tupe = typename std::tuple_element<N, bind_tuple>::type;
- const result_tupe *result = nullptr;
+ using result_tupe = typename std::tuple_element<static_cast<size_t>(N), bind_tuple>::type;
+ const result_tupe* result = nullptr;
auto index = -1;
- internal::iterate_ast(statement.t, [&result, &index](auto &node) {
+ internal::iterate_ast(statement.t, [&result, &index](auto& node) {
using node_type = typename std::decay<decltype(node)>::type;
if(internal::is_bindable<node_type>::value) {
++index;
}
if(index == N) {
- internal::static_if<std::is_same<result_tupe, node_type>{}>([](auto &r, auto &n) {
+ internal::static_if<std::is_same<result_tupe, node_type>{}>([](auto& r, auto& n) {
r = const_cast<typename std::remove_reference<decltype(r)>::type>(&n);
})(result, node);
}
@@ -13383,21 +17331,21 @@ namespace sqlite_orm {
}
template<int N, class T>
- auto &get(internal::prepared_statement_t<T> &statement) {
+ auto& get(internal::prepared_statement_t<T>& statement) {
using statement_type = typename std::decay<decltype(statement)>::type;
using expression_type = typename statement_type::expression_type;
using node_tuple = typename internal::node_tuple<expression_type>::type;
using bind_tuple = typename internal::bindable_filter<node_tuple>::type;
- using result_tupe = typename std::tuple_element<N, bind_tuple>::type;
- result_tupe *result = nullptr;
+ using result_tupe = typename std::tuple_element<static_cast<size_t>(N), bind_tuple>::type;
+ result_tupe* result = nullptr;
auto index = -1;
- internal::iterate_ast(statement.t, [&result, &index](auto &node) {
+ internal::iterate_ast(statement.t, [&result, &index](auto& node) {
using node_type = typename std::decay<decltype(node)>::type;
if(internal::is_bindable<node_type>::value) {
++index;
}
if(index == N) {
- internal::static_if<std::is_same<result_tupe, node_type>{}>([](auto &r, auto &n) {
+ internal::static_if<std::is_same<result_tupe, node_type>{}>([](auto& r, auto& n) {
r = const_cast<typename std::remove_reference<decltype(r)>::type>(&n);
})(result, node);
}
diff --git a/run_prepared_release_test.sh b/run_prepared_release_test.sh
new file mode 100644
index 00000000..65bad643
--- /dev/null
+++ b/run_prepared_release_test.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+cd ./_PREPARED_RELEASE_TEST
+./SSVOpenHexagon.exe
diff --git a/src/SSVOpenHexagon/Components/CPlayer.cpp b/src/SSVOpenHexagon/Components/CPlayer.cpp
index 27bcb239..dc112760 100644
--- a/src/SSVOpenHexagon/Components/CPlayer.cpp
+++ b/src/SSVOpenHexagon/Components/CPlayer.cpp
@@ -3,21 +3,27 @@
// AFL License page: https://opensource.org/licenses/AFL-3.0
#include "SSVOpenHexagon/Components/CPlayer.hpp"
-#include "SSVOpenHexagon/Components/CWall.hpp"
+
#include "SSVOpenHexagon/Components/CCustomWall.hpp"
+#include "SSVOpenHexagon/Components/CWall.hpp"
+
#include "SSVOpenHexagon/Utils/Color.hpp"
-#include "SSVOpenHexagon/Utils/Ticker.hpp"
-#include "SSVOpenHexagon/Utils/PointInPolygon.hpp"
-#include "SSVOpenHexagon/Utils/Geometry.hpp"
#include "SSVOpenHexagon/Utils/Easing.hpp"
+#include "SSVOpenHexagon/Utils/Geometry.hpp"
+#include "SSVOpenHexagon/Utils/MoveTowards.hpp"
+#include "SSVOpenHexagon/Utils/PointInPolygon.hpp"
+#include "SSVOpenHexagon/Utils/Ticker.hpp"
#include <SSVStart/Utils/SFML.hpp>
#include <SSVUtils/Core/Common/Frametime.hpp>
#include <SSVUtils/Core/Utils/Math.hpp>
-#include <SFML/System/Vector2.hpp>
#include <SFML/Graphics/Color.hpp>
+#include <SFML/System/Vector2.hpp>
+
+#include <algorithm>
+#include <cmath>
namespace hg {
@@ -48,14 +54,29 @@ CPlayer::CPlayer(const sf::Vector2f& pos, const float swapCooldown,
_triangleWidth{unfocusedTriangleWidth},
_triangleWidthTransitionTime{0.f},
_swapTimer{swapCooldown},
- _swapBlinkTimer{swapCooldown / 6.f},
- _deadEffectTimer{80.f, false}
+ _swapBlinkTimer{6.f},
+ _deadEffectTimer{80.f, false},
+ _currTiltedAngle{0}
{}
+[[nodiscard]] sf::Color CPlayer::getColorAdjustedForSwap(
+ const sf::Color& colorPlayer) const
+{
+ if(!_swapTimer.isRunning() && !_dead)
+ {
+ return Utils::getColorFromHue(
+ std::fmod(_swapBlinkTimer.getCurrent() / 12.f, 0.2f));
+ }
+
+ return !_deadEffectTimer.isRunning() ? colorPlayer
+ : Utils::getColorFromHue(_hue / 360.f);
+}
+
void CPlayer::draw(const unsigned int sides, const sf::Color& colorMain,
const sf::Color& colorPlayer, Utils::FastVertexVectorQuads& wallQuads,
Utils::FastVertexVectorTris& capTris,
- Utils::FastVertexVectorTris& playerTris, const sf::Color& capColor)
+ Utils::FastVertexVectorTris& playerTris, const sf::Color& capColor,
+ const float angleTiltIntensity)
{
drawPivot(sides, colorMain, wallQuads, capTris, capColor);
@@ -64,25 +85,18 @@ void CPlayer::draw(const unsigned int sides, const sf::Color& colorMain,
drawDeathEffect(wallQuads);
}
- sf::Color adjustedColorMain{!_deadEffectTimer.isRunning()
- ? colorPlayer
- : Utils::getColorFromHue(_hue / 360.f)};
+ const float tiltedAngle =
+ _angle + (_currTiltedAngle * ssvu::toRad(24.f) * angleTiltIntensity);
const sf::Vector2f pLeft = ssvs::getOrbitRad(
- _pos, _angle - ssvu::toRad(100.f), _size + _triangleWidth);
+ _pos, tiltedAngle - ssvu::toRad(100.f), _size + _triangleWidth);
const sf::Vector2f pRight = ssvs::getOrbitRad(
- _pos, _angle + ssvu::toRad(100.f), _size + _triangleWidth);
-
- if(!_swapTimer.isRunning() && !_dead)
- {
- adjustedColorMain =
- Utils::getColorFromHue((_swapBlinkTimer.getCurrent() * 15) / 360.f);
- }
+ _pos, tiltedAngle + ssvu::toRad(100.f), _size + _triangleWidth);
playerTris.reserve_more(3);
- playerTris.batch_unsafe_emplace_back(adjustedColorMain,
- ssvs::getOrbitRad(_pos, _angle, _size), pLeft, pRight);
+ playerTris.batch_unsafe_emplace_back(getColorAdjustedForSwap(colorPlayer),
+ ssvs::getOrbitRad(_pos, tiltedAngle, _size), pLeft, pRight);
}
void CPlayer::drawPivot(const unsigned int sides, const sf::Color& colorMain,
@@ -388,19 +402,11 @@ void CPlayer::updateTriangleWidthTransition(
{
if(focused && _triangleWidthTransitionTime < 1.f)
{
- _triangleWidthTransitionTime += ft * 0.1f;
- if(_triangleWidthTransitionTime > 1.f)
- {
- _triangleWidthTransitionTime = 1.f;
- }
+ Utils::moveTowards(_triangleWidthTransitionTime, 1.f, ft * 0.1f);
}
else if(!focused && _triangleWidthTransitionTime > 0.f)
{
- _triangleWidthTransitionTime -= ft * 0.1f;
- if(_triangleWidthTransitionTime < 0.f)
- {
- _triangleWidthTransitionTime = 0.f;
- }
+ Utils::moveTowardsZero(_triangleWidthTransitionTime, ft * 0.1f);
}
_triangleWidth =
@@ -436,7 +442,7 @@ void CPlayer::update(
}
}
- _swapBlinkTimer.update(ft);
+ _swapBlinkTimer.update(ft / 3.f);
if(swapEnabled && _swapTimer.update(ft))
{
@@ -452,12 +458,19 @@ void CPlayer::updateInputMovement(const float movementDir,
{
_currentSpeed = playerSpeedMult * (focused ? _focusSpeed : _speed) * ft;
_angle += ssvu::toRad(_currentSpeed * movementDir);
+
+ const float inc = ft / 10.f;
+
+ _currTiltedAngle =
+ (movementDir == 0.f)
+ ? Utils::getMoveTowardsZero(_currTiltedAngle, inc)
+ : Utils::getMoveTowards(_currTiltedAngle, movementDir, inc * 2.f);
}
void CPlayer::resetSwap(const float swapCooldown)
{
_swapTimer.restart(swapCooldown);
- _swapBlinkTimer.restart(swapCooldown / 6.f);
+ _swapBlinkTimer.restart(6.f);
}
void CPlayer::setJustSwapped(const bool value)
diff --git a/src/SSVOpenHexagon/Core/HGGraphics.cpp b/src/SSVOpenHexagon/Core/HGGraphics.cpp
index 95abd3a2..ae1e085d 100644
--- a/src/SSVOpenHexagon/Core/HGGraphics.cpp
+++ b/src/SSVOpenHexagon/Core/HGGraphics.cpp
@@ -114,7 +114,8 @@ void HexagonGame::draw()
if(status.started)
{
player.draw(getSides(), getColorMain(), getColorPlayer(), pivotQuads,
- capTris, playerTris, getColorCap());
+ capTris, playerTris, getColorCap(),
+ Config::getAngleTiltIntensity());
}
if(Config::get3D())
@@ -228,6 +229,12 @@ void HexagonGame::draw()
render(wallQuads3D);
render(pivotQuads3D);
render(playerTris3D);
+
+ if(Config::getShowPlayerTrail() && status.showPlayerTrail)
+ {
+ drawTrailParticles();
+ }
+
render(wallQuads);
render(capTris);
render(pivotQuads);
@@ -356,6 +363,14 @@ void HexagonGame::drawParticles()
}
}
+void HexagonGame::drawTrailParticles()
+{
+ for(TrailParticle& p : trailParticles)
+ {
+ render(p.sprite);
+ }
+}
+
void HexagonGame::updateText(ssvu::FT mFT)
{
if(window == nullptr)
diff --git a/src/SSVOpenHexagon/Core/HGUpdate.cpp b/src/SSVOpenHexagon/Core/HGUpdate.cpp
index afe5eb47..bf742ffb 100644
--- a/src/SSVOpenHexagon/Core/HGUpdate.cpp
+++ b/src/SSVOpenHexagon/Core/HGUpdate.cpp
@@ -5,20 +5,24 @@
#include "SSVOpenHexagon/Core/HexagonGame.hpp"
#include "SSVOpenHexagon/Components/CWall.hpp"
+
#include "SSVOpenHexagon/Global/Assert.hpp"
#include "SSVOpenHexagon/Global/Assets.hpp"
-#include "SSVOpenHexagon/Global/Config.hpp"
#include "SSVOpenHexagon/Global/Audio.hpp"
+#include "SSVOpenHexagon/Global/Config.hpp"
+
#include "SSVOpenHexagon/Utils/Concat.hpp"
#include "SSVOpenHexagon/Utils/Easing.hpp"
#include "SSVOpenHexagon/Utils/LevelValidator.hpp"
+#include "SSVOpenHexagon/Utils/MoveTowards.hpp"
#include "SSVOpenHexagon/Utils/Split.hpp"
#include "SSVOpenHexagon/Utils/String.hpp"
-#include "SSVOpenHexagon/Core/HexagonClient.hpp"
-#include "SSVOpenHexagon/Core/Steam.hpp"
+
#include "SSVOpenHexagon/Core/Discord.hpp"
+#include "SSVOpenHexagon/Core/HexagonClient.hpp"
#include "SSVOpenHexagon/Core/Joystick.hpp"
#include "SSVOpenHexagon/Core/LuaScripting.hpp"
+#include "SSVOpenHexagon/Core/Steam.hpp"
#include <imgui.h>
#include <misc/cpp/imgui_stdlib.h>
@@ -29,6 +33,10 @@
#include <SSVUtils/Core/Common/Frametime.hpp>
#include <SSVUtils/Core/Utils/Containers.hpp>
+#include <SFML/Config.hpp>
+#include <SFML/Graphics/Color.hpp>
+#include <SFML/System/Vector2.hpp>
+
#include <array>
#include <cstring>
#include <optional>
@@ -333,6 +341,12 @@ void HexagonGame::update(ssvu::FT mFT, const float timescale)
SSVOH_ASSERT(backgroundCamera.has_value());
updateParticles(mFT);
+
+ if(Config::getShowPlayerTrail() && status.showPlayerTrail)
+ {
+ updateTrailParticles(mFT);
+ }
+
overlayCamera->update(mFT);
backgroundCamera->update(mFT);
}
@@ -875,7 +889,8 @@ void HexagonGame::updateParticles(ssvu::FT mFT)
{
Particle p;
- p.sprite.setTexture(assets.getTextureOrNullTexture("starParticle.png"));
+ SSVOH_ASSERT(txStarParticle != nullptr);
+ p.sprite.setTexture(*txStarParticle);
p.sprite.setPosition(
{ssvu::getRndR(-64.f, Config::getWidth() + 64.f), -64.f});
p.sprite.setRotation(ssvu::getRndR(0.f, 360.f));
@@ -913,6 +928,61 @@ void HexagonGame::updateParticles(ssvu::FT mFT)
}
}
+void HexagonGame::updateTrailParticles(ssvu::FT mFT)
+{
+ SSVOH_ASSERT(window != nullptr);
+
+ const auto isDead = [&](const TrailParticle& p)
+ { return p.sprite.getColor().a <= 3; };
+
+ const auto makeTrailParticle = [this]
+ {
+ TrailParticle p;
+
+ SSVOH_ASSERT(txSmallCircle != nullptr);
+ p.sprite.setTexture(*txSmallCircle);
+ p.sprite.setPosition(player.getPosition());
+ p.sprite.setOrigin(sf::Vector2f{txSmallCircle->getSize()} / 2.f);
+
+ const float scale = Config::getPlayerTrailScale();
+ p.sprite.setScale({scale, scale});
+
+ sf::Color c = Config::getPlayerTrailHasSwapColor()
+ ? player.getColorAdjustedForSwap(getColorPlayer())
+ : getColorPlayer();
+
+ c.a = Config::getPlayerTrailAlpha();
+ p.sprite.setColor(c);
+
+ p.angle = player.getPlayerAngle();
+
+ return p;
+ };
+
+ ssvu::eraseRemoveIf(trailParticles, isDead);
+
+ for(TrailParticle& p : trailParticles)
+ {
+ sf::Color color = p.sprite.getColor();
+
+ const float newAlpha = Utils::getMoveTowardsZero(
+ static_cast<float>(color.a), Config::getPlayerTrailDecay() * mFT);
+
+ color.a = static_cast<sf::Uint8>(newAlpha);
+ p.sprite.setColor(color);
+
+ p.sprite.setScale(p.sprite.getScale() * 0.98f);
+
+ p.sprite.setPosition(
+ ssvs::getVecFromRad(p.angle, status.radius + 2.4f));
+ }
+
+ if(player.hasChangedAngle())
+ {
+ trailParticles.emplace_back(makeTrailParticle());
+ }
+}
+
static int ilcTextEditCallbackStub(ImGuiInputTextCallbackData* data)
{
auto hg = (HexagonGame*)data->UserData;
diff --git a/src/SSVOpenHexagon/Core/HexagonGame.cpp b/src/SSVOpenHexagon/Core/HexagonGame.cpp
index d70f3a11..f6d99a90 100644
--- a/src/SSVOpenHexagon/Core/HexagonGame.cpp
+++ b/src/SSVOpenHexagon/Core/HexagonGame.cpp
@@ -194,7 +194,7 @@ void HexagonGame::updateLevelInfo()
return s;
};
- levelInfoTextLevel.setFillColor(styleData.getMainColor());
+ levelInfoTextLevel.setFillColor(getColorText());
levelInfoTextLevel.setCharacterSize(20.f / Config::getZoomFactor());
levelInfoTextLevel.setString(trim(Utils::toUppercase(levelData->name)));
levelInfoTextLevel.setOrigin(ssvs::getLocalNW(levelInfoTextLevel));
@@ -204,7 +204,7 @@ void HexagonGame::updateLevelInfo()
const auto prepareText = [&](sf::Text& text, const float characterSize,
const std::string& string)
{
- text.setFillColor(styleData.getTextColor());
+ text.setFillColor(getColorText());
text.setCharacterSize(characterSize / Config::getZoomFactor());
text.setString(string);
};
@@ -287,6 +287,8 @@ HexagonGame::HexagonGame(Steam::steam_manager* mSteamManager,
levelStatus{Config::getMusicSpeedDMSync(), Config::getSpawnDistance()},
messageText{initText("", font, 38.f)},
pbText{initText("", fontBold, 65.f)},
+ txStarParticle{nullptr},
+ txSmallCircle{nullptr},
levelInfoTextLevel{"", font},
levelInfoTextPack{"", font},
levelInfoTextAuthor{"", font},
@@ -311,6 +313,9 @@ HexagonGame::HexagonGame(Steam::steam_manager* mSteamManager,
overlayCamera.emplace(
*window, sf::View{sf::Vector2f{width / 2.f, height / 2.f},
sf::Vector2f{width, height}});
+
+ txStarParticle = &assets.getTextureOrNullTexture("starParticle.png");
+ txSmallCircle = &assets.getTextureOrNullTexture("smallCircle.png");
}
@@ -665,6 +670,7 @@ void HexagonGame::newGame(const std::string& mPackId, const std::string& mId,
mustSpawnPBParticles = false;
nextPBParticleSpawn = 0.f;
particles.clear();
+ trailParticles.clear();
if(window != nullptr)
{
diff --git a/src/SSVOpenHexagon/Core/LuaScripting.cpp b/src/SSVOpenHexagon/Core/LuaScripting.cpp
index b6d32580..7208dcfa 100644
--- a/src/SSVOpenHexagon/Core/LuaScripting.cpp
+++ b/src/SSVOpenHexagon/Core/LuaScripting.cpp
@@ -922,6 +922,12 @@ static void initLevelControl(
"`0` and `l_getBeatPulseDelayMax()` unless manually overridden.",
"Sets the current beat pulse delay value to `$0`.");
+
+ sVar("ShowPlayerTrail", &HexagonGameStatus::showPlayerTrail,
+ "Gets whether the current level allows player trails to be shown.",
+
+ "Sets whether the current level allows player trails to be shown to "
+ "`$0`.");
}
static void initStyleControl(Lua::LuaContext& lua, StyleData& styleData)
diff --git a/src/SSVOpenHexagon/Core/MenuGame.cpp b/src/SSVOpenHexagon/Core/MenuGame.cpp
index ecf39222..7ab255a0 100644
--- a/src/SSVOpenHexagon/Core/MenuGame.cpp
+++ b/src/SSVOpenHexagon/Core/MenuGame.cpp
@@ -1394,7 +1394,24 @@ void MenuGame::initMenus()
visfx.create<i::Toggle>("flash", &Config::getFlash, &Config::setFlash);
visfx.create<i::Slider>("shake mult.", &Config::getCameraShakeMultiplier,
&Config::setCameraShakeMultiplier, 0.f, 5.f, 0.1f);
- visfx.create<i::GoBack>("back");
+
+ auto& playervisfx(optionsMenu.createCategory("player visual fxs"));
+ gfx.create<i::Goto>("player visual fxs", playervisfx);
+ playervisfx.create<i::Slider>("angle tilt mult.",
+ &Config::getAngleTiltIntensity, &Config::setAngleTiltIntensity, 0.f,
+ 5.f, 0.1f);
+ playervisfx.create<i::Toggle>(
+ "show trail", &Config::getShowPlayerTrail, &Config::setShowPlayerTrail);
+ playervisfx.create<i::Slider>("trail alpha", &Config::getPlayerTrailAlpha,
+ &Config::setPlayerTrailAlpha, 0, 255, 5);
+ playervisfx.create<i::Slider>("trail scale", &Config::getPlayerTrailScale,
+ &Config::setPlayerTrailScale, 0.05f, 1.f, 0.05f);
+ playervisfx.create<i::Slider>("trail decay", &Config::getPlayerTrailDecay,
+ &Config::setPlayerTrailDecay, 0.5f, 50.f, 2.5f);
+ playervisfx.create<i::Toggle>("trail has swap color",
+ &Config::getPlayerTrailHasSwapColor,
+ &Config::setPlayerTrailHasSwapColor);
+ playervisfx.create<i::GoBack>("back");
auto& fps(optionsMenu.createCategory("fps settings"));
gfx.create<i::Goto>("fps settings", fps);
@@ -2650,8 +2667,13 @@ void MenuGame::update(ssvu::FT mFT)
auto& items = getCurrentMenu()->getItems();
if(static_cast<int>(items.size()) > *mustUseMenuItem)
{
- playSoundOverride("beep.ogg");
- items.at(*mustUseMenuItem)->exec();
+ ssvms::ItemBase& item = *items.at(*mustUseMenuItem);
+
+ if(item.isEnabled())
+ {
+ playSoundOverride("beep.ogg");
+ item.exec();
+ }
}
}
@@ -3711,7 +3733,7 @@ void MenuGame::drawMainMenu(
// TODO (P2): cleanup mouse control
if(mouseOverlap && !mustUseMenuItem.has_value() &&
- mouseLeftRisingEdge())
+ mouseLeftRisingEdge() && items[i]->isEnabled())
{
mustUseMenuItem = i;
}
diff --git a/src/SSVOpenHexagon/Global/Config.cpp b/src/SSVOpenHexagon/Global/Config.cpp
index 84a15c67..11ee4577 100644
--- a/src/SSVOpenHexagon/Global/Config.cpp
+++ b/src/SSVOpenHexagon/Global/Config.cpp
@@ -215,6 +215,12 @@ using cil = std::initializer_list<cmb>;
X(lastLoginUsername, std::string, "last_login_username", "") \
X(showLoginAtStartup, bool, "show_login_at_startup", false) \
X(cameraShakeMultiplier, float, "camera_shake_multiplier", 1.f) \
+ X(angleTiltIntensity, float, "angle_tilt_intensity", 1.f) \
+ X(showPlayerTrail, bool, "show_player_trail", true) \
+ X(playerTrailAlpha, uint, "player_trail_alpha", 35) \
+ X(playerTrailScale, float, "player_trail_scale", 0.9f) \
+ X(playerTrailDecay, float, "player_trail_decay", 3.0f) \
+ X(playerTrailHasSwapColor, bool, "player_trail_has_swap_color", true) \
X_LINKEDVALUES_BINDS
namespace hg::Config {
@@ -736,6 +742,36 @@ void setCameraShakeMultiplier(float x)
cameraShakeMultiplier() = x;
}
+void setAngleTiltIntensity(float x)
+{
+ angleTiltIntensity() = x;
+}
+
+void setShowPlayerTrail(bool x)
+{
+ showPlayerTrail() = x;
+}
+
+void setPlayerTrailAlpha(unsigned int x)
+{
+ playerTrailAlpha() = x;
+}
+
+void setPlayerTrailScale(float x)
+{
+ playerTrailScale() = x;
+}
+
+void setPlayerTrailDecay(float x)
+{
+ playerTrailDecay() = x;
+}
+
+void setPlayerTrailHasSwapColor(bool x)
+{
+ playerTrailHasSwapColor() = x;
+}
+
[[nodiscard]] bool getOfficial()
{
return official();
@@ -1066,6 +1102,36 @@ void setCameraShakeMultiplier(float x)
return cameraShakeMultiplier();
}
+[[nodiscard]] float getAngleTiltIntensity()
+{
+ return angleTiltIntensity();
+}
+
+[[nodiscard]] bool getShowPlayerTrail()
+{
+ return showPlayerTrail();
+}
+
+[[nodiscard]] unsigned int getPlayerTrailAlpha()
+{
+ return playerTrailAlpha();
+}
+
+[[nodiscard]] float getPlayerTrailScale()
+{
+ return playerTrailScale();
+}
+
+[[nodiscard]] float getPlayerTrailDecay()
+{
+ return playerTrailDecay();
+}
+
+[[nodiscard]] bool getPlayerTrailHasSwapColor()
+{
+ return playerTrailHasSwapColor();
+}
+
//***********************************************************
//
// KEYBOARD/MOUSE BINDS
diff --git a/webpage/index.html b/webpage/index.html
index 87ab1613..a24acb82 100644
--- a/webpage/index.html
+++ b/webpage/index.html
@@ -11237,27 +11237,33 @@
style="color: black; background-color: white; padding-top:0rem!important;padding-bottom:3rem!important;">
<div class="container">
<div class="row">
- <div class="col-lg-4 col-md-6 text-center">
+ <div class="col-lg-3 col-md-6 text-center">
<div class="mt-5">
- <h3 class="h4 mb-2" style="font-weight: 900;">Only Three Buttons</h3>
- <p class="mb-0" style="font-weight: 500">Open Hexagon is easy to learn but extremely hard to
- master. There are
- three main actions you can perform: <i>rotate clockwise</i>, <i>rotate
- counter-clockwise</i>, and <i>swap by 180° degrees</i>.
+ <h3 class="h4 mb-2" style="font-weight: 900;">Only Four Buttons</h3>
+ <p class="mb-0" style="font-weight: 500">Open Hexagon is easy to learn but hard to
+ master. There are four main actions you can perform: <i>rotate clockwise</i>, <i>rotate
+ counter-clockwise</i>, <i>swap by 180° degrees</i>, and <i>focus</i>.
</p>
</div>
</div>
- <div class="col-lg-4 col-md-6 text-center">
+ <div class="col-lg-3 col-md-6 text-center">
<div class="mt-5">
<h3 class="h4 mb-2" style="font-weight: 900;">Only One Goal: Survive</h3>
<p class="mb-0" style="font-weight: 500">Simplicity and minimalism are key features of Open
Hexagon. While
- certain levels might have special quirks and mechanics, the goal is always the same:
+ some levels might have special quirks and mechanics, the goal is always the same:
<i>survive</i>
as long as possible.</p>
</div>
</div>
- <div class="col-lg-4 col-md-6 text-center">
+ <div class="col-lg-3 col-md-6 text-center">
+ <div class="mt-5">
+ <h3 class="h4 mb-2" style="font-weight: 900;">Innovative Mechanics</h3>
+ <p class="mb-0" style="font-weight: 500" ;>The game's main concept comes from <i>Super Hexagon</i> by <i>Terry Cavanagh</i>. Open Hexagon expands on the formula by introducing a <i>180° swap</i>, <i>curving/accelerating walls</i>, <i>scripting</i>, and much more.
+ </p>
+ </div>
+ </div>
+ <div class="col-lg-3 col-md-6 text-center">
<div class="mt-5">
<h3 class="h4 mb-2" style="font-weight: 900;">Designed For Modding</h3>
<p class="mb-0" style="font-weight: 500" ;>Open Hexagon was developed with the goal of being
@@ -11279,11 +11285,11 @@
<div class="container">
<div class="row justify-content-center">
- <iframe width="560" height="315" src="https://www.youtube.com/embed/TlSJZlQrVJ4"
+ <iframe width="560" height="315" src="https://www.youtube.com/embed/06y7mEsAMHM"
style="margin-bottom: 4rem; margin-right: 1rem" frameborder="0"
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen></iframe>
- <iframe width="560" height="315" src="https://www.youtube.com/embed/gSRoCNDOvkA"
+ <iframe width="560" height="315" src="https://www.youtube.com/embed/h4Jfj3lzWD4"
style="margin-bottom: 4rem" frameborder="0"
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen></iframe>
@@ -11447,7 +11453,7 @@
<!-- Footer-->
<footer class="bg-primary py-5">
<div class="container">
- <div class="text-center text-white">Copyright © 2020 - Vittorio Romeo</div>
+ <div class="text-center text-white">Copyright © 2020-2021 - Vittorio Romeo</div>
</div>
</footer>
<!-- Bootstrap core JS-->