Database System 0.1.0
Advanced C++20 Database System with Multi-Backend Support
Loading...
Searching...
No Matches
value_formatter.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
5#include "value_formatter.h"
6#include <sstream>
7#include <iomanip>
8#include <cmath>
9#include <variant>
10
11namespace database::query {
12
14 : db_type_(db_type) {}
15
16std::string value_formatter::format(const core::database_value& value) const {
17 return std::visit([this](auto&& arg) -> std::string {
18 using T = std::decay_t<decltype(arg)>;
19
20 if constexpr (std::is_same_v<T, std::monostate>) {
21 return null_literal();
22 }
23 else if constexpr (std::is_same_v<T, std::string>) {
24 return format_string(arg);
25 }
26 else if constexpr (std::is_same_v<T, int>) {
27 return format_int(arg);
28 }
29 else if constexpr (std::is_same_v<T, int64_t>) {
30 return format_int(arg);
31 }
32 else if constexpr (std::is_same_v<T, double>) {
33 return format_double(arg);
34 }
35 else if constexpr (std::is_same_v<T, bool>) {
36 return format_bool(arg);
37 }
38 else if constexpr (std::is_same_v<T, std::vector<uint8_t>>) {
39 return format_blob(arg);
40 }
41 else {
42 return null_literal();
43 }
44 }, value);
45}
46
47std::string value_formatter::escape_string(const std::string& str) const {
48 switch (db_type_) {
50 return escape_postgresql_string(str);
52 return escape_sqlite_string(str);
55 // NoSQL databases handle escaping differently
56 return str;
57 default:
58 return escape_sqlite_string(str); // Safe default
59 }
60}
61
62std::string value_formatter::escape_identifier(const std::string& identifier) const {
63 switch (db_type_) {
65 return "\"" + identifier + "\"";
67 return "\"" + identifier + "\"";
70 return identifier; // NoSQL doesn't quote identifiers
71 default:
72 return "\"" + identifier + "\"";
73 }
74}
75
76std::string value_formatter::null_literal() const {
77 return "NULL";
78}
79
80std::string value_formatter::bool_literal(bool val) const {
81 switch (db_type_) {
84 return val ? "TRUE" : "FALSE";
86 return val ? "true" : "false";
88 return val ? "1" : "0";
89 default:
90 return val ? "1" : "0";
91 }
92}
93
94// Private formatting methods
95
96std::string value_formatter::format_string(const std::string& str) const {
97 return "'" + escape_string(str) + "'";
98}
99
100std::string value_formatter::format_int(int64_t num) const {
101 return std::to_string(num);
102}
103
104std::string value_formatter::format_double(double num) const {
105 // Handle special values
106 if (std::isnan(num)) {
107 return "'NaN'";
108 }
109 if (std::isinf(num)) {
110 return num > 0 ? "'Infinity'" : "'-Infinity'";
111 }
112
113 // Format with appropriate precision
114 std::ostringstream oss;
115 oss << std::setprecision(15) << num;
116 return oss.str();
117}
118
119std::string value_formatter::format_bool(bool val) const {
120 return bool_literal(val);
121}
122
123std::string value_formatter::format_blob(const std::vector<uint8_t>& data) const {
124 switch (db_type_) {
126 // PostgreSQL hex format: '\x...'
127 std::ostringstream oss;
128 oss << "'\\x";
129 for (uint8_t byte : data) {
130 oss << std::hex << std::setw(2) << std::setfill('0')
131 << static_cast<int>(byte);
132 }
133 oss << "'";
134 return oss.str();
135 }
137 // SQLite hex format: X'...'
138 std::ostringstream oss;
139 oss << "X'";
140 for (uint8_t byte : data) {
141 oss << std::hex << std::setw(2) << std::setfill('0')
142 << static_cast<int>(byte);
143 }
144 oss << "'";
145 return oss.str();
146 }
147 default:
148 return "NULL"; // Unsupported for this database
149 }
150}
151
152// Database-specific string escaping
153
154std::string value_formatter::escape_postgresql_string(const std::string& str) const {
155 std::string result;
156 result.reserve(str.length() + 10);
157
158 for (char c : str) {
159 switch (c) {
160 case '\'':
161 result += "''"; // PostgreSQL escapes single quotes by doubling
162 break;
163 case '\\':
164 result += "\\\\"; // Escape backslashes
165 break;
166 case '\0':
167 result += "\\0"; // NULL byte
168 break;
169 case '\n':
170 result += "\\n"; // Newline
171 break;
172 case '\r':
173 result += "\\r"; // Carriage return
174 break;
175 case '\t':
176 result += "\\t"; // Tab
177 break;
178 default:
179 result += c;
180 }
181 }
182
183 return result;
184}
185
186std::string value_formatter::escape_sqlite_string(const std::string& str) const {
187 std::string result;
188 result.reserve(str.length() + 10);
189
190 for (char c : str) {
191 if (c == '\'') {
192 result += "''"; // SQLite escapes single quotes by doubling
193 } else {
194 result += c;
195 }
196 }
197
198 return result;
199}
200
201} // namespace database::query
std::string format_bool(bool val) const
std::string escape_identifier(const std::string &identifier) const
Quote and escape an identifier (table/column name)
value_formatter(database_types db_type)
Construct formatter for specific database type.
std::string format_int(int64_t num) const
std::string escape_string(const std::string &str) const
Escape a string value.
std::string escape_sqlite_string(const std::string &str) const
std::string escape_postgresql_string(const std::string &str) const
std::string format(const core::database_value &value) const
Format a database value.
std::string format_blob(const std::vector< uint8_t > &data) const
std::string format_double(double num) const
std::string format_string(const std::string &str) const
std::string bool_literal(bool val) const
Get boolean literal.
std::string null_literal() const
Get NULL literal for this database.
std::variant< std::string, int64_t, double, bool, std::nullptr_t > database_value
database_types
Represents various database backends or modes.
@ mongodb
Indicates a MongoDB database (future implementation).
@ sqlite
Indicates a SQLite database.
@ redis
Indicates a Redis database (future implementation).
@ postgres
Indicates a PostgreSQL database.