Database System 0.1.0
Advanced C++20 Database System with Multi-Backend Support
Loading...
Searching...
No Matches
sql_dialect.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 "sql_dialect.h"
6#include <stdexcept>
7
8namespace database::query {
9
10// Factory method
11std::unique_ptr<sql_dialect> sql_dialect::create(database_types type) {
12 switch (type) {
14 return std::make_unique<postgresql_dialect>();
16 return std::make_unique<sqlite_dialect>();
17 default:
18 throw std::invalid_argument("Unsupported database type for SQL dialect");
19 }
20}
21
22// PostgreSQL Dialect Implementation
23
24std::string postgresql_dialect::placeholder(int index) const {
25 return "$" + std::to_string(index);
26}
27
28std::string postgresql_dialect::quote_identifier(std::string_view name) const {
29 std::string result;
30 result.reserve(name.size() + 2);
31 result += '"';
32 for (char c : name) {
33 if (c == '"') {
34 result += "\"\""; // Escape double quotes by doubling
35 } else {
36 result += c;
37 }
38 }
39 result += '"';
40 return result;
41}
42
43std::string postgresql_dialect::escape_string(std::string_view str) const {
44 std::string result;
45 result.reserve(str.size());
46 for (char c : str) {
47 if (c == '\'') {
48 result += "''"; // Escape single quotes by doubling
49 } else if (c == '\\') {
50 result += "\\\\"; // Escape backslashes
51 } else {
52 result += c;
53 }
54 }
55 return result;
56}
57
58std::string postgresql_dialect::returning_clause(std::string_view column) const {
59 if (column.empty()) {
60 return " RETURNING *";
61 }
62 return " RETURNING " + quote_identifier(column);
63}
64
66 const std::vector<std::string>& conflict_columns,
67 const std::vector<std::string>& update_columns) const {
68
69 if (conflict_columns.empty()) {
70 return "";
71 }
72
73 std::string result = "ON CONFLICT (";
74 for (size_t i = 0; i < conflict_columns.size(); ++i) {
75 if (i > 0) result += ", ";
76 result += quote_identifier(conflict_columns[i]);
77 }
78 result += ")";
79
80 if (update_columns.empty()) {
81 result += " DO NOTHING";
82 } else {
83 result += " DO UPDATE SET ";
84 for (size_t i = 0; i < update_columns.size(); ++i) {
85 if (i > 0) result += ", ";
86 std::string quoted = quote_identifier(update_columns[i]);
87 result += quoted + " = EXCLUDED." + quoted;
88 }
89 }
90 return result;
91}
92
93std::string postgresql_dialect::limit_clause(size_t limit, size_t offset) const {
94 std::string clause = "LIMIT " + std::to_string(limit);
95 if (offset > 0) {
96 clause += " OFFSET " + std::to_string(offset);
97 }
98 return clause;
99}
100
102 return "SERIAL";
103}
104
106 return "CURRENT_TIMESTAMP";
107}
108
110 return "||";
111}
112
113bool postgresql_dialect::supports_feature(const std::string& feature) const {
114 // PostgreSQL supports most SQL features
115 if (feature == "window_functions") return true;
116 if (feature == "cte") return true; // Common Table Expressions
117 if (feature == "recursive_cte") return true;
118 if (feature == "json") return true;
119 if (feature == "full_outer_join") return true;
120 if (feature == "returning") return true; // RETURNING clause
121 if (feature == "array") return true;
122 if (feature == "upsert") return true; // ON CONFLICT
123 return false;
124}
125
126// SQLite Dialect Implementation
127
128std::string sqlite_dialect::placeholder(int index) const {
129 return "?" + std::to_string(index);
130}
131
132std::string sqlite_dialect::quote_identifier(std::string_view name) const {
133 std::string result;
134 result.reserve(name.size() + 2);
135 result += '"';
136 for (char c : name) {
137 if (c == '"') {
138 result += "\"\""; // Escape double quotes by doubling
139 } else {
140 result += c;
141 }
142 }
143 result += '"';
144 return result;
145}
146
147std::string sqlite_dialect::escape_string(std::string_view str) const {
148 std::string result;
149 result.reserve(str.size());
150 for (char c : str) {
151 if (c == '\'') {
152 result += "''"; // Escape single quotes by doubling
153 } else {
154 result += c;
155 }
156 }
157 return result;
158}
159
160std::string sqlite_dialect::returning_clause(std::string_view column) const {
161 // SQLite 3.35+ supports RETURNING
162 if (column.empty()) {
163 return " RETURNING *";
164 }
165 return " RETURNING " + quote_identifier(column);
166}
167
169 const std::vector<std::string>& conflict_columns,
170 const std::vector<std::string>& update_columns) const {
171
172 if (conflict_columns.empty()) {
173 return "";
174 }
175
176 std::string result = "ON CONFLICT (";
177 for (size_t i = 0; i < conflict_columns.size(); ++i) {
178 if (i > 0) result += ", ";
179 result += quote_identifier(conflict_columns[i]);
180 }
181 result += ")";
182
183 if (update_columns.empty()) {
184 result += " DO NOTHING";
185 } else {
186 result += " DO UPDATE SET ";
187 for (size_t i = 0; i < update_columns.size(); ++i) {
188 if (i > 0) result += ", ";
189 std::string quoted = quote_identifier(update_columns[i]);
190 result += quoted + " = excluded." + quoted;
191 }
192 }
193 return result;
194}
195
196std::string sqlite_dialect::limit_clause(size_t limit, size_t offset) const {
197 std::string clause = "LIMIT " + std::to_string(limit);
198 if (offset > 0) {
199 clause += " OFFSET " + std::to_string(offset);
200 }
201 return clause;
202}
203
205 return "AUTOINCREMENT";
206}
207
209 return "CURRENT_TIMESTAMP";
210}
211
213 return "||";
214}
215
216bool sqlite_dialect::supports_feature(const std::string& feature) const {
217 if (feature == "window_functions") return true; // SQLite 3.25+
218 if (feature == "cte") return true;
219 if (feature == "recursive_cte") return true;
220 if (feature == "json") return true; // SQLite 3.38+
221 if (feature == "full_outer_join") return false; // Not supported
222 if (feature == "returning") return true; // SQLite 3.35+
223 if (feature == "array") return false; // Not supported
224 if (feature == "upsert") return true; // ON CONFLICT
225 return false;
226}
227
228} // namespace database::query
std::string quote_identifier(std::string_view name) const override
Quote an identifier (table or column name)
std::string auto_increment() const override
Get auto-increment column definition.
bool supports_feature(const std::string &feature) const override
Check if database supports specific feature.
std::string returning_clause(std::string_view column="") const override
Generate RETURNING clause for INSERT/UPDATE.
std::string upsert_clause(const std::vector< std::string > &conflict_columns, const std::vector< std::string > &update_columns) const override
Generate UPSERT (INSERT OR UPDATE) clause.
std::string concat_operator() const override
Get string concatenation operator.
std::string current_timestamp() const override
Get current timestamp function.
std::string limit_clause(size_t limit, size_t offset) const override
Generate LIMIT clause.
std::string placeholder(int index) const override
Generate parameter placeholder.
std::string escape_string(std::string_view str) const override
Escape a string value for safe SQL inclusion.
static std::unique_ptr< sql_dialect > create(database_types type)
Factory method to create appropriate dialect.
std::string upsert_clause(const std::vector< std::string > &conflict_columns, const std::vector< std::string > &update_columns) const override
Generate UPSERT (INSERT OR UPDATE) clause.
bool supports_feature(const std::string &feature) const override
Check if database supports specific feature.
std::string quote_identifier(std::string_view name) const override
Quote an identifier (table or column name)
std::string current_timestamp() const override
Get current timestamp function.
std::string concat_operator() const override
Get string concatenation operator.
std::string placeholder(int index) const override
Generate parameter placeholder.
std::string auto_increment() const override
Get auto-increment column definition.
std::string returning_clause(std::string_view column="") const override
Generate RETURNING clause for INSERT/UPDATE.
std::string limit_clause(size_t limit, size_t offset) const override
Generate LIMIT clause.
std::string escape_string(std::string_view str) const override
Escape a string value for safe SQL inclusion.
database_types
Represents various database backends or modes.
@ sqlite
Indicates a SQLite database.
@ postgres
Indicates a PostgreSQL database.