relx 0.1.0
A Modern C++23 Type-Safe SQL Query Builder
Loading...
Searching...
No Matches
core.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "fixed_string.hpp"
4
5#include <optional>
6#include <string>
7#include <string_view>
8#include <tuple>
9#include <type_traits>
10#include <utility>
11
12namespace relx::schema {
13
15
17template <typename T>
20 static constexpr auto sql_type_name = "TEXT";
21
23 static constexpr bool nullable = false;
24
26 static std::string to_sql_string(const T& value);
27
29 static T from_sql_string(const std::string& value);
30};
31
32// Specializations for common types
33
34template <>
35struct column_traits<int> {
36 static constexpr auto sql_type_name = "INTEGER";
37 static constexpr bool nullable = false;
38
39 static std::string to_sql_string(const int& value) { return std::to_string(value); }
40
41 static int from_sql_string(const std::string& value) { return std::stoi(value); }
42};
43
44template <>
45struct column_traits<double> {
46 static constexpr auto sql_type_name = "REAL";
47 static constexpr bool nullable = false;
48
49 static std::string to_sql_string(const double& value) { return std::to_string(value); }
50
51 static double from_sql_string(const std::string& value) { return std::stod(value); }
52};
53
54template <>
55struct column_traits<std::string> {
56 static constexpr auto sql_type_name = "TEXT";
57 static constexpr bool nullable = false;
58
59 static std::string to_sql_string(const std::string& value) {
60 // Escape single quotes by doubling them
61 std::string escaped = value;
62 size_t pos = 0;
63 while ((pos = escaped.find('\'', pos)) != std::string::npos) {
64 escaped.insert(pos, 1, '\'');
65 pos += 2;
66 }
67 return "'" + escaped + "'";
68 }
69
70 static std::string from_sql_string(const std::string& value) {
71 // Remove surrounding quotes if present
72 if (value.size() >= 2 && value.front() == '\'' && value.back() == '\'') {
73 std::string unquoted = value.substr(1, value.size() - 2);
74 // Unescape doubled single quotes
75 size_t pos = 0;
76 while ((pos = unquoted.find("''", pos)) != std::string::npos) {
77 unquoted.erase(pos, 1);
78 pos += 1;
79 }
80 return unquoted;
81 }
82 return value;
83 }
84};
85
86template <>
87struct column_traits<bool> {
88 static constexpr auto sql_type_name = "BOOLEAN";
89 static constexpr bool nullable = false;
90
91 static std::string to_sql_string(const bool& value) { return value ? "1" : "0"; }
92
93 static bool from_sql_string(const std::string& value) {
94 return value == "1" || value == "true" || value == "TRUE";
95 }
96};
97
98template <>
99struct column_traits<float> {
100 static constexpr auto sql_type_name = "REAL";
101 static constexpr bool nullable = false;
102
103 static std::string to_sql_string(const float& value) { return std::to_string(value); }
104
105 static float from_sql_string(const std::string& value) { return std::stof(value); }
106};
107
108template <>
109struct column_traits<long> {
110 static constexpr auto sql_type_name = "INTEGER";
111 static constexpr bool nullable = false;
112
113 static std::string to_sql_string(const long& value) { return std::to_string(value); }
114
115 static long from_sql_string(const std::string& value) { return std::stol(value); }
116};
117
118template <>
119struct column_traits<long long> {
120 static constexpr auto sql_type_name = "INTEGER";
121 static constexpr bool nullable = false;
122
123 static std::string to_sql_string(const long long& value) { return std::to_string(value); }
124
125 static long long from_sql_string(const std::string& value) { return std::stoll(value); }
126};
127
128// Add specialization for std::optional types
129template <typename T>
130struct column_traits<std::optional<T>> {
132 static constexpr bool nullable = true;
133
134 static std::string to_sql_string(const std::optional<T>& value) {
135 if (value) {
136 return column_traits<T>::to_sql_string(*value);
137 }
138 return "NULL";
139 }
140
141 static std::optional<T> from_sql_string(const std::string& value) {
142 if (value == "NULL") {
143 return std::nullopt;
144 }
146 }
147};
148
149// Specialization for std::nullopt_t
150template <>
151struct column_traits<std::nullopt_t> {
152 static constexpr auto sql_type_name = "TEXT";
153 static constexpr bool nullable = true;
154
155 static std::string to_sql_string(const std::nullopt_t&) { return "NULL"; }
156
157 static std::nullopt_t from_sql_string(const std::string& /*value*/) { return std::nullopt; }
158};
159
160// Concept for defining what is a valid SQL column type
161template <typename T>
162concept ColumnTypeConcept = requires {
163 { column_traits<T>::sql_type_name } -> std::convertible_to<std::string_view>;
164 { column_traits<T>::nullable } -> std::convertible_to<bool>;
165 { column_traits<T>::to_sql_string(std::declval<T>()) } -> std::convertible_to<std::string>;
166 { column_traits<T>::from_sql_string(std::declval<std::string>()) } -> std::convertible_to<T>;
167};
168
169} // namespace relx::schema
STL namespace.
static bool from_sql_string(const std::string &value)
Definition core.hpp:93
static std::string to_sql_string(const bool &value)
Definition core.hpp:91
static std::string to_sql_string(const double &value)
Definition core.hpp:49
static double from_sql_string(const std::string &value)
Definition core.hpp:51
static float from_sql_string(const std::string &value)
Definition core.hpp:105
static std::string to_sql_string(const float &value)
Definition core.hpp:103
static std::string to_sql_string(const int &value)
Definition core.hpp:39
static int from_sql_string(const std::string &value)
Definition core.hpp:41
static std::string to_sql_string(const long &value)
Definition core.hpp:113
static long from_sql_string(const std::string &value)
Definition core.hpp:115
static std::string to_sql_string(const long long &value)
Definition core.hpp:123
static long long from_sql_string(const std::string &value)
Definition core.hpp:125
static std::string to_sql_string(const std::nullopt_t &)
Definition core.hpp:155
static std::nullopt_t from_sql_string(const std::string &)
Definition core.hpp:157
static std::string to_sql_string(const std::optional< T > &value)
Definition core.hpp:134
static std::optional< T > from_sql_string(const std::string &value)
Definition core.hpp:141
static std::string to_sql_string(const std::string &value)
Definition core.hpp:59
static std::string from_sql_string(const std::string &value)
Definition core.hpp:70
Contains schema definition components.
Definition core.hpp:18
static constexpr bool nullable
Whether this type can be NULL.
Definition core.hpp:23
static T from_sql_string(const std::string &value)
Parse a SQL string representation to a C++ value.
static std::string to_sql_string(const T &value)
Convert a C++ value to a SQL string representation.
static constexpr auto sql_type_name
The SQL type name for this C++ type.
Definition core.hpp:20