9#if defined(_WIN32) || defined(_WIN64)
14#include "Description.hpp"
16#include <reflection-cpp/reflection.hpp>
25#include <source_location>
28#include <system_error>
30#include <unordered_map>
35#if !(defined(__cpp_lib_to_chars) && __cpp_lib_to_chars >= 201611L)
37 #if defined(__APPLE__)
46#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
47 #include <experimental/meta>
56 template <
typename T,
typename... Comps>
57 concept OneOf = (std::same_as<T, Comps> || ...);
60 constexpr auto AlwaysFalse = std::false_type::value;
62 constexpr auto Finally(
auto&& cleanupRoutine)
noexcept
67 std::remove_cvref_t<
decltype(cleanupRoutine)> cleanup;
73 return Finally { std::forward<decltype(cleanupRoutine)>(cleanupRoutine) };
88 requires std::is_floating_point_v<T>
89 [[nodiscard]]
inline std::optional<T> ParseFloat(
char const* first,
char const* last)
noexcept
93#if defined(__cpp_lib_to_chars) && __cpp_lib_to_chars >= 201611L
97 auto const [ptr, ec] = std::from_chars(first, last, value);
98 if (ec != std::errc {} || ptr != last)
106 static ::locale_t
const cLocale = ::newlocale(LC_NUMERIC_MASK,
"C",
static_cast<::locale_t
>(
nullptr));
107 auto const length =
static_cast<std::size_t
>(last - first);
108 std::array<char, 64> stackBuffer {};
109 std::string heapBuffer;
110 char const* text =
nullptr;
111 if (length < stackBuffer.size())
113 std::ranges::copy(first, last, stackBuffer.begin());
114 stackBuffer[length] =
'\0';
115 text = stackBuffer.data();
119 heapBuffer.assign(first, last);
120 text = heapBuffer.c_str();
123 char* parseEnd =
nullptr;
126 if constexpr (std::is_same_v<T, float>)
127 value = ::strtof_l(text, &parseEnd, cLocale);
128 else if constexpr (std::is_same_v<T, long double>)
129 value = ::strtold_l(text, &parseEnd, cLocale);
131 value =
static_cast<T
>(::strtod_l(text, &parseEnd, cLocale));
133 if (errno == ERANGE || parseEnd != text + length)
142 template <
template <
typename...>
class T,
typename U>
143 struct is_specialization_of: std::false_type
147 template <
template <
typename...>
class T,
typename... Us>
148 struct is_specialization_of<T, T<Us...>>: std::true_type
152 template <
typename T>
153 struct MemberClassTypeHelper;
155 template <
typename M,
typename T>
156 struct MemberClassTypeHelper<M T::*>
158 using type = std::remove_cvref_t<T>;
161 template <
typename Record>
162 struct RecordTableNameImpl
164 static constexpr std::string_view Value = []() {
165 if constexpr (
requires { Record::TableName; })
166 return Record::TableName;
169#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
170 return std::meta::identifier_of(^^Record);
172 auto const typeName = Reflection::TypeNameOf<Record>;
173 if (
auto const i = typeName.rfind(
':'); i != std::string_view::npos)
174 return typeName.substr(i + 1);
184 template <
typename First,
typename Second>
185 struct RecordTableNameImpl<std::tuple<First, Second>>
187 static constexpr std::string_view Value = []() {
188 if constexpr (
requires { First::TableName; })
189 return First::TableName;
192#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
193 return std::meta::identifier_of(^^First);
195 auto const typeName = Reflection::TypeNameOf<First>;
196 if (
auto const i = typeName.rfind(
':'); i != std::string_view::npos)
197 return typeName.substr(i + 1);
204 template <
typename FieldType>
205 constexpr auto ColumnNameOverride = []()
consteval {
206 if constexpr (
requires { FieldType::ColumnNameOverride; })
207 return FieldType::ColumnNameOverride;
209 return std::string_view {};
211#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
212 template <auto reflection>
213 struct FieldNameOfImpl
215 using R =
typename[:std::meta::type_of(reflection):];
216 static constexpr std::string_view value = []()
constexpr -> std::string_view {
217 if constexpr (
requires { R::ColumnNameOverride; })
219 if constexpr (!R::ColumnNameOverride.empty())
220 return R::ColumnNameOverride;
222 return std::meta::identifier_of(reflection);
226 template <
typename ReferencedFieldType, auto F>
227 struct FieldNameOfImpl;
229 template <
typename T, auto F,
typename R>
230 struct FieldNameOfImpl<R T::*, F>
232 static constexpr std::string_view value = []()
constexpr -> std::string_view {
233 if constexpr (
requires { R::ColumnNameOverride; })
235 if constexpr (!R::ColumnNameOverride.empty())
236 return R::ColumnNameOverride;
238 return Reflection::NameOf<F>;
243 template <std::
size_t I,
typename Record>
248 if constexpr (HasDescription<Record>)
250 return Description<Record>::FieldNames[I];
254 using FieldType = Reflection::MemberTypeOf<I, Record>;
256 if constexpr (!std::string_view(ColumnNameOverride<FieldType>).empty())
258 return FieldType::ColumnNameOverride;
260 return Reflection::MemberNameOf<I, Record>;
268template <std::
size_t I,
typename Record>
269constexpr inline std::string_view
FieldNameAt = detail::FieldNameAt<I, Record>();
274template <
typename Record>
275constexpr std::string_view
RecordTableName = detail::RecordTableNameImpl<Record>::Value;
277template <
template <
typename...>
class S,
class T>
278concept IsSpecializationOf = detail::is_specialization_of<S, T>::value;
280#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
285template <std::meta::info ReflectionOfField>
286constexpr inline std::string_view FieldNameOf = detail::FieldNameOfImpl<ReflectionOfField>::value;
288template <auto Member>
289using MemberClassType =
typename[:std::meta::parent_of(Member):];
291template <auto Member>
292constexpr size_t MemberIndexOf = []()
consteval ->
size_t {
294 auto members = nonstatic_data_members_of(parent_of(Member), std::meta::access_context::current());
295 if (
auto it = std::ranges::find(members, Member); it != members.end())
297 index = std::distance(members.begin(), it);
298 return static_cast<size_t>(index);
307template <auto ReferencedField>
308constexpr inline std::string_view FieldNameOf = detail::FieldNameOfImpl<
decltype(ReferencedField), ReferencedField>::value;
310template <auto Member>
311constexpr size_t MemberIndexOf = Reflection::MemberIndexOf<Member>;
314using MemberClassType = detail::MemberClassTypeHelper<T>::type;
350template <auto ReferencedField>
352#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
355 .tableName =
RecordTableName<MemberClassType<
decltype(ReferencedField)>>,
357 .columnName = FieldNameOf<ReferencedField>,
362 template <auto ReferencedField>
363 struct FullyQualifiedQuotedNameOfImpl
365#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
366 static constexpr auto ClassName =
RecordTableName<
typename[:std::meta::parent_of(ReferencedField):]>;
368 static constexpr auto ClassName =
RecordTableName<MemberClassType<
decltype(ReferencedField)>>;
370 static constexpr auto FieldName = FieldNameOf<ReferencedField>;
371 static constexpr auto StorageSize = ClassName.size() + FieldName.size() + 6;
374 static constexpr auto Storage = []()
constexpr -> std::array<char, StorageSize> {
376 auto storage = std::array<char, StorageSize> {};
377 std::ranges::copy(
"\"", storage.begin());
378 std::ranges::copy(ClassName, storage.begin() + 1);
379 std::ranges::copy(
"\".\"", storage.begin() + 1 + ClassName.size());
380 std::ranges::copy(FieldName, storage.begin() + 1 + ClassName.size() + 3);
381 std::ranges::copy(
"\"", storage.begin() + 1 + ClassName.size() + 3 + FieldName.size());
382 storage.back() =
'\0';
386 static constexpr auto value = std::string_view(Storage.data(), Storage.size() - 1);
389 template <auto ReferencedField>
390 constexpr inline auto FullyQualifiedQuotedNameOf = FullyQualifiedQuotedNameOfImpl<ReferencedField>::value;
392 template <
auto... ReferencedFields>
393 struct FullyQualifiedNamesOfImpl
395 static constexpr auto StorageSize =
396 1 + (2 * (
sizeof...(ReferencedFields) - 1)) + (0 + ... + FullyQualifiedQuotedNameOf<ReferencedFields>.size());
398 static constexpr std::array<char, StorageSize> Storage = []()
consteval {
399 auto result = std::array<char, StorageSize> {};
405 constexpr auto Delimiter = std::string_view(
", ");
406 std::ranges::copy(Delimiter, result.begin() + offset);
407 offset += Delimiter.size();
409 std::ranges::copy(FullyQualifiedQuotedNameOf<ReferencedFields>, result.begin() + offset);
410 offset += FullyQualifiedQuotedNameOf<ReferencedFields>.size();
413 result.back() =
'\0';
417 static constexpr auto value = std::string_view(Storage.data(), Storage.size() - 1);
422 template <
auto... ReferencedFields>
423 constexpr inline auto FullyQualifiedNamesOf = FullyQualifiedNamesOfImpl<ReferencedFields...>::value;
434enum class SqlFailureAction : uint8_t
440 ThrowInvalidArgument,
460[[nodiscard]] LIGHTWEIGHT_API SqlFailureAction ClassifyOdbcResult(SQLRETURN result, SqlErrorInfo
const& errorInfo)
noexcept;
462LIGHTWEIGHT_API
void LogIfFailed(SQLHSTMT hStmt, SQLRETURN error, std::source_location sourceLocation);
503 [[nodiscard]]
virtual std::optional<SqlErrorInfo>
NextFailure(SQLHSTMT hStmt,
504 std::source_location
const& sourceLocation) = 0;
513LIGHTWEIGHT_API
void SetFaultSource(
SqlFaultSource* source)
noexcept;
516[[nodiscard]] LIGHTWEIGHT_API
SqlFaultSource* GetFaultSource() noexcept;
528LIGHTWEIGHT_API
void RequireSuccess(SQLHSTMT hStmt,
530 std::source_location sourceLocation = std::source_location::current());
533enum class FormatType : uint8_t
546LIGHTWEIGHT_API std::string FormatName(std::string
const& name, FormatType formatType);
549LIGHTWEIGHT_API std::string FormatName(std::string_view name, FormatType formatType);
556 [[nodiscard]] LIGHTWEIGHT_API
bool IsColliding(std::string
const& name)
const noexcept;
559 [[nodiscard]] LIGHTWEIGHT_API std::optional<std::string>
TryDeclareName(std::string name);
562 [[nodiscard]] LIGHTWEIGHT_API std::string
DeclareName(std::string name);
565 std::unordered_map<std::string, size_t> _collisionMap;
Substitutes a scripted failure for an ODBC call that actually succeeded.
virtual std::optional< SqlErrorInfo > NextFailure(SQLHSTMT hStmt, std::source_location const &sourceLocation)=0
Decides whether the next statement-handle check should fail.
Maintains collisions to create unique names.
LIGHTWEIGHT_API std::string DeclareName(std::string name)
Creates a name that is definitely not colliding.
LIGHTWEIGHT_API bool IsColliding(std::string const &name) const noexcept
Tests if the given name is already registered.
LIGHTWEIGHT_API std::optional< std::string > TryDeclareName(std::string name)
Tries to declare a name and returns it, otherwise returns std::nullopt.
constexpr std::string_view RecordTableName
Holds the SQL tabl ename for the given record type.
constexpr std::string_view FieldNameAt
Returns the SQL field name of the given field index in the record.
constexpr auto FullyQualifiedNameOf
Holds the fully qualified column reference (table + column) for the given field.
SqlQualifiedTableColumnName represents a column name qualified with a table name.
std::string_view tableName
The table name.
constexpr std::weak_ordering operator<=>(SqlQualifiedTableColumnName const &) const noexcept=default
Three-way comparison operator.
std::string_view columnName
The column name.