Database System 0.1.0
Advanced C++20 Database System with Multi-Backend Support
Loading...
Searching...
No Matches
connection_string_builder.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
6
7#include <sstream>
8
9namespace database::integrated {
10
12 host_ = std::string(h);
13 return *this;
14}
15
17 port_ = p;
18 return *this;
19}
20
22 database_ = std::string(db);
23 return *this;
24}
25
27 user_ = std::string(u);
28 return *this;
29}
30
32 password_ = std::string(p);
33 return *this;
34}
35
40
42 connect_timeout_ = seconds;
43 return *this;
44}
45
47 application_name_ = std::string(name);
48 return *this;
49}
50
55
56connection_string_builder& connection_string_builder::option(std::string_view key, std::string_view value) {
57 custom_options_.emplace_back(std::string(key), std::string(value));
58 return *this;
59}
60
61kcenon::common::Result<std::string> connection_string_builder::build(backend_type type) const {
62 switch (type) {
64 return build_postgres();
66 return build_sqlite();
68 return build_mongodb();
70 return build_redis();
71 default:
72 return kcenon::common::Result<std::string>::err(
73 -1, "Unknown backend type", "connection_string_builder");
74 }
75}
76
90
91kcenon::common::Result<std::string> connection_string_builder::build_postgres() const {
92 std::ostringstream oss;
93 bool first = true;
94
95 auto append = [&oss, &first](const std::string& key, const std::string& value) {
96 if (!first) {
97 oss << ' ';
98 }
99 oss << key << '=' << value;
100 first = false;
101 };
102
103 // PostgreSQL uses space-separated key=value pairs
104 if (host_.has_value()) {
105 append("host", *host_);
106 }
107
108 if (port_.has_value()) {
109 append("port", std::to_string(*port_));
110 }
111
112 if (database_.has_value()) {
113 append("dbname", *database_);
114 }
115
116 if (user_.has_value()) {
117 append("user", *user_);
118 }
119
120 if (password_.has_value()) {
121 append("password", *password_);
122 }
123
124 if (ssl_mode_.has_value()) {
125 append("sslmode", ssl_mode_to_postgres_string(*ssl_mode_));
126 }
127
128 if (connect_timeout_.has_value()) {
129 append("connect_timeout", std::to_string(*connect_timeout_));
130 }
131
132 if (application_name_.has_value()) {
133 append("application_name", *application_name_);
134 }
135
136 for (const auto& [key, value] : custom_options_) {
137 append(key, value);
138 }
139
140 return kcenon::common::Result<std::string>::ok(oss.str());
141}
142
143kcenon::common::Result<std::string> connection_string_builder::build_sqlite() const {
144 // SQLite uses file path or :memory: for in-memory database
145 if (in_memory_) {
146 return kcenon::common::Result<std::string>::ok(":memory:");
147 }
148
149 if (!database_.has_value() || database_->empty()) {
150 return kcenon::common::Result<std::string>::err(
151 -1, "SQLite requires a database file path or in_memory() to be set",
152 "connection_string_builder");
153 }
154
155 return kcenon::common::Result<std::string>::ok(*database_);
156}
157
158kcenon::common::Result<std::string> connection_string_builder::build_mongodb() const {
159 // MongoDB uses URI format: mongodb://[user:password@]host[:port]/[database]
160 std::ostringstream oss;
161 oss << "mongodb://";
162
163 if (user_.has_value() && password_.has_value()) {
164 oss << *user_ << ':' << *password_ << '@';
165 }
166
167 if (host_.has_value()) {
168 oss << *host_;
169 } else {
170 oss << "localhost";
171 }
172
173 if (port_.has_value()) {
174 oss << ':' << *port_;
175 }
176
177 if (database_.has_value()) {
178 oss << '/' << *database_;
179 }
180
181 // Add options as query parameters
182 if (!custom_options_.empty() || ssl_mode_.has_value() || connect_timeout_.has_value()) {
183 oss << '?';
184 bool first = true;
185
186 auto append_param = [&oss, &first](const std::string& key, const std::string& value) {
187 if (!first) {
188 oss << '&';
189 }
190 oss << key << '=' << value;
191 first = false;
192 };
193
194 if (ssl_mode_.has_value()) {
195 bool use_ssl = *ssl_mode_ != ssl_mode::disable;
196 append_param("ssl", use_ssl ? "true" : "false");
197 }
198
199 if (connect_timeout_.has_value()) {
200 append_param("connectTimeoutMS", std::to_string(*connect_timeout_ * 1000));
201 }
202
203 for (const auto& [key, value] : custom_options_) {
204 append_param(key, value);
205 }
206 }
207
208 return kcenon::common::Result<std::string>::ok(oss.str());
209}
210
211kcenon::common::Result<std::string> connection_string_builder::build_redis() const {
212 // Redis uses URI format: redis://[user:password@]host[:port][/database]
213 std::ostringstream oss;
214 oss << "redis://";
215
216 if (user_.has_value() && password_.has_value()) {
217 oss << *user_ << ':' << *password_ << '@';
218 } else if (password_.has_value()) {
219 // Redis often uses just password without username
220 oss << ':' << *password_ << '@';
221 }
222
223 if (host_.has_value()) {
224 oss << *host_;
225 } else {
226 oss << "localhost";
227 }
228
229 if (port_.has_value()) {
230 oss << ':' << *port_;
231 }
232
233 if (database_.has_value()) {
234 // Redis database is a number (0-15 typically)
235 oss << '/' << *database_;
236 }
237
238 return kcenon::common::Result<std::string>::ok(oss.str());
239}
240
242 switch (mode) {
244 return "disable";
245 case ssl_mode::allow:
246 return "allow";
247 case ssl_mode::prefer:
248 return "prefer";
250 return "require";
252 return "verify-ca";
254 return "verify-full";
255 default:
256 return "prefer";
257 }
258}
259
260} // namespace database::integrated
Fluent builder for constructing database connection strings.
kcenon::common::Result< std::string > build_sqlite() const
connection_string_builder & database(std::string_view db)
Set the database name.
connection_string_builder & user(std::string_view u)
Set the username for authentication.
connection_string_builder & port(uint16_t p)
Set the database port.
connection_string_builder & host(std::string_view h)
Set the database host.
connection_string_builder & ssl_mode(enum ssl_mode mode)
Set the SSL connection mode.
connection_string_builder & application_name(std::string_view name)
Set the application name (for PostgreSQL)
kcenon::common::Result< std::string > build_postgres() const
connection_string_builder & reset()
Reset the builder to initial state.
std::vector< std::pair< std::string, std::string > > custom_options_
static std::string ssl_mode_to_postgres_string(enum ssl_mode mode)
kcenon::common::Result< std::string > build_redis() const
connection_string_builder & option(std::string_view key, std::string_view value)
Add a custom option.
connection_string_builder & in_memory()
Configure SQLite to use in-memory database.
connection_string_builder & password(std::string_view p)
Set the password for authentication.
kcenon::common::Result< std::string > build_mongodb() const
connection_string_builder & connect_timeout(uint32_t seconds)
Set the connection timeout.
kcenon::common::Result< std::string > build(backend_type type) const
Build the connection string for the specified backend.
Fluent builder for constructing type-safe database connection strings.
ssl_mode
SSL connection mode for database connections.
@ prefer
Try SSL first, fall back to non-SSL.
@ verify_ca
Require SSL with CA verification.
@ allow
Try SSL, fall back to non-SSL.
@ verify_full
Require SSL with full verification.
@ require
Require SSL, no verification.
backend_type
Database backend type enumeration.
@ mongodb
MongoDB NoSQL database.
@ sqlite
SQLite embedded database.
@ redis
Redis key-value store.
@ postgres
PostgreSQL database.