Lightweight 0.1.0
Loading...
Searching...
No Matches
Core.hpp
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4
5#if defined(_WIN32) || defined(_WIN64)
6 #include <Windows.h>
7#endif
8
9#include "../Api.hpp"
10#include "../SqlServerType.hpp"
11
12#include <concepts>
13#include <functional>
14
15#include <sql.h>
16#include <sqlext.h>
17#include <sqltypes.h>
18
19/// @defgroup DataTypes Data Types
20///
21/// @brief Special purpose data types for SQL data binding.
22
23/// Callback interface for SqlDataBinder to allow post-processing of output columns.
24///
25/// This is needed because the SQLBindCol() function does not allow to specify a callback function to be called
26/// after the data has been fetched from the database. This is needed to trim strings to the correct size, for
27/// example.
28class LIGHTWEIGHT_API SqlDataBinderCallback
29{
30 public:
31 SqlDataBinderCallback() = default;
34 SqlDataBinderCallback& operator=(SqlDataBinderCallback&&) = default;
35 SqlDataBinderCallback& operator=(SqlDataBinderCallback const&) = default;
36
37 virtual ~SqlDataBinderCallback() = default;
38
39 virtual void PlanPostExecuteCallback(std::function<void()>&&) = 0;
40 virtual void PlanPostProcessOutputColumn(std::function<void()>&&) = 0;
41 [[nodiscard]] virtual SqlServerType ServerType() const noexcept = 0;
42};
43
44template <typename>
45struct SqlDataBinder;
46
47// Default traits for output string parameters
48// This needs to be implemented for each string type that should be used as output parameter via
49// SqlDataBinder<>. An std::string specialization is provided below. Feel free to add more specializations for
50// other string types, such as CString, etc.
51template <typename>
52struct SqlBasicStringOperations;
53
54// -----------------------------------------------------------------------------------------------
55
56namespace detail
57{
58
59// clang-format off
60template <typename T>
61concept HasGetStringAndGetLength = requires(T const& t) {
62 { t.GetLength() } -> std::same_as<int>;
63 { t.GetString() } -> std::same_as<char const*>;
64};
65
66template <typename T>
67concept HasGetStringAndLength = requires(T const& t)
68{
69 { t.Length() } -> std::same_as<int>;
70 { t.GetString() } -> std::same_as<char const*>;
71};
72// clang-format on
73
74template <typename>
75struct SqlViewHelper;
76
77template <typename T>
78concept HasSqlViewHelper = requires(T const& t) {
79 { SqlViewHelper<T>::View(t) } -> std::convertible_to<std::string_view>;
80};
81
82template <typename CharT>
83struct SqlViewHelper<std::basic_string<CharT>>
84{
85 static LIGHTWEIGHT_FORCE_INLINE std::basic_string_view<CharT> View(std::basic_string<CharT> const& str) noexcept
86 {
87 return { str.data(), str.size() };
88 }
89};
90
91template <detail::HasGetStringAndGetLength CStringLike>
92struct SqlViewHelper<CStringLike>
93{
94 static LIGHTWEIGHT_FORCE_INLINE std::string_view View(CStringLike const& str) noexcept
95 {
96 return { str.GetString(), static_cast<size_t>(str.GetLength()) };
97 }
98};
99
100template <detail::HasGetStringAndLength StringLike>
101struct SqlViewHelper<StringLike>
102{
103 static LIGHTWEIGHT_FORCE_INLINE std::string_view View(StringLike const& str) noexcept
104 {
105 return { str.GetString(), static_cast<size_t>(str.Length()) };
106 }
107};
108
109} // namespace detail
110
111// -----------------------------------------------------------------------------------------------
112
113template <typename T>
114concept SqlInputParameterBinder =
115 requires(SQLHSTMT hStmt, SQLUSMALLINT column, T const& value, SqlDataBinderCallback& cb) {
116 { SqlDataBinder<T>::InputParameter(hStmt, column, value, cb) } -> std::same_as<SQLRETURN>;
117 };
118
119template <typename T>
120concept SqlOutputColumnBinder =
121 requires(SQLHSTMT hStmt, SQLUSMALLINT column, T* result, SQLLEN* indicator, SqlDataBinderCallback& cb) {
122 { SqlDataBinder<T>::OutputColumn(hStmt, column, result, indicator, cb) } -> std::same_as<SQLRETURN>;
123 };
124
125template <typename T>
126concept SqlInputParameterBatchBinder =
127 requires(SQLHSTMT hStmt, SQLUSMALLINT column, std::ranges::range_value_t<T>* result, SqlDataBinderCallback& cb) {
128 {
129 SqlDataBinder<std::ranges::range_value_t<T>>::InputParameter(
130 hStmt, column, std::declval<std::ranges::range_value_t<T>>(), cb)
131 } -> std::same_as<SQLRETURN>;
132 };
133
134template <typename T>
135concept SqlGetColumnNativeType =
136 requires(SQLHSTMT hStmt, SQLUSMALLINT column, T* result, SQLLEN* indicator, SqlDataBinderCallback const& cb) {
137 { SqlDataBinder<T>::GetColumn(hStmt, column, result, indicator, cb) } -> std::same_as<SQLRETURN>;
138 };
139
140template <typename T>
141concept SqlDataBinderSupportsInspect = requires(T const& value) {
142 { SqlDataBinder<std::remove_cvref_t<T>>::Inspect(value) } -> std::convertible_to<std::string>;
143};
144
145// clang-format off
146template <typename StringType, typename CharType>
147concept SqlBasicStringBinderConcept = requires(StringType* str) {
148 { SqlBasicStringOperations<StringType>::Data(str) } -> std::same_as<CharType*>;
149 { SqlBasicStringOperations<StringType>::Size(str) } -> std::same_as<SQLULEN>;
150 { SqlBasicStringOperations<StringType>::Reserve(str, size_t {}) } -> std::same_as<void>;
151 { SqlBasicStringOperations<StringType>::Resize(str, SQLLEN {}) } -> std::same_as<void>;
152 { SqlBasicStringOperations<StringType>::Clear(str) } -> std::same_as<void>;
153};
154// clang-format on