Database System 0.1.0
Advanced C++20 Database System with Multi-Backend Support
Loading...
Searching...
No Matches
database::backends::mongodb_backend Class Reference

MongoDB implementation of database_backend interface. More...

#include <mongodb_backend.h>

Inheritance diagram for database::backends::mongodb_backend:
Inheritance graph
Collaboration diagram for database::backends::mongodb_backend:
Collaboration graph

Public Member Functions

 mongodb_backend ()
 Default constructor.
 
 ~mongodb_backend () override=default
 Destructor - ensures proper cleanup.
 
kcenon::common::Result< core::database_resultselect_query (const std::string &query_string) override
 Execute a SELECT query.
 
kcenon::common::VoidResult execute_query (const std::string &query_string) override
 Execute a general SQL query (DDL, DML)
 
kcenon::common::VoidResult begin_transaction () override
 Begin a transaction.
 
kcenon::common::VoidResult commit_transaction () override
 Commit the current transaction.
 
kcenon::common::VoidResult rollback_transaction () override
 Rollback the current transaction.
 
bool in_transaction () const override
 Check if backend is currently in a transaction.
 
std::string last_error () const override
 Get last error message from backend.
 
std::map< std::string, std::string > connection_info () const override
 Get backend-specific connection information.
 
- Public Member Functions inherited from database::core::backend_base< mongodb_backend, database_types::mongodb >
 backend_base ()=default
 Default constructor.
 
 backend_base (const backend_base &)=delete
 
 backend_base (backend_base &&) noexcept=delete
 
 ~backend_base () override
 Virtual destructor.
 
backend_baseoperator= (const backend_base &)=delete
 
backend_baseoperator= (backend_base &&) noexcept=delete
 
database_types type () const override
 Get the database type of this backend.
 
kcenon::common::VoidResult initialize (const connection_config &config) override
 Initialize the database backend.
 
kcenon::common::VoidResult shutdown () override
 Shutdown the database backend gracefully.
 
bool is_initialized () const override
 Check if backend is initialized and ready.
 
- Public Member Functions inherited from database::core::database_backend
virtual ~database_backend ()=default
 
virtual kcenon::common::Result< database_resultselect_prepared (const std::string &query, const std::vector< database_value > &params)
 Execute a parameterized SELECT query (prepared statement)
 
virtual kcenon::common::VoidResult execute_prepared (const std::string &query, const std::vector< database_value > &params)
 Execute a parameterized DML/DDL query (prepared statement)
 

Static Public Member Functions

static constexpr const char * backend_name ()
 Backend name for error messages.
 
- Static Public Member Functions inherited from database::core::backend_base< mongodb_backend, database_types::mongodb >
static std::unique_ptr< database_backendcreate ()
 Factory method for backend_registry.
 

Protected Member Functions

kcenon::common::VoidResult do_initialize (const core::connection_config &config)
 Database-specific initialization logic.
 
kcenon::common::VoidResult do_shutdown ()
 Database-specific shutdown logic.
 

Private Member Functions

std::string build_connection_uri (const core::connection_config &config) const
 Convert connection_config to MongoDB connection URI.
 
bool parse_query_string (const std::string &query_string, std::string &collection, std::string &filter, std::string &update) const
 Parse query string format.
 

Private Attributes

void * client_ {nullptr}
 MongoDB client (mongocxx::client*)
 
void * database_ {nullptr}
 MongoDB database (mongocxx::database*)
 
std::string db_name_
 Database name.
 
std::atomic< bool > in_transaction_ {false}
 Transaction state.
 
std::string last_error_
 Last error message.
 
core::connection_config connection_config_
 Cached connection config.
 
std::mutex mongo_mutex_
 Mutex for thread safety.
 

Friends

class core::backend_base< mongodb_backend, database_types::mongodb >
 

Additional Inherited Members

- Static Protected Member Functions inherited from database::core::database_backend
static std::string expand_params (const std::string &query, const std::vector< database_value > &params)
 Expand positional parameters into a SQL string (fallback)
 
- Protected Attributes inherited from database::core::backend_base< mongodb_backend, database_types::mongodb >
std::atomic< bool > initialized_
 Initialization state.
 

Detailed Description

MongoDB implementation of database_backend interface.

This class implements the database_backend interface for MongoDB via backend_base CRTP template, using the MongoDB C++ driver.

Design Pattern: Strategy pattern with CRTP

  • Extends backend_base for common lifecycle management
  • Uses mongocxx driver for database access
  • Provides Result-based error handling
  • Thread-safe with internal mutex

Thread Safety:

  • All operations are thread-safe via mutex
  • Suitable for multi-threaded access

Usage:

// Runtime selection via backend_registry
auto backend = backend_registry::instance().create("mongodb");
config.host = "localhost";
config.port = 27017;
config.database = "mydb";
config.username = "user";
config.password = "pass";
if (auto result = backend->initialize(config); !result) {
// Handle error
}
auto rows = backend->select_query("users:{\"name\":\"John\"}");
Configuration for database connection.

Definition at line 71 of file mongodb_backend.h.

Constructor & Destructor Documentation

◆ mongodb_backend()

database::backends::mongodb_backend::mongodb_backend ( )

Default constructor.

Definition at line 36 of file mongodb_backend.cpp.

37 : client_(nullptr), database_(nullptr)
38{
39}
void * client_
MongoDB client (mongocxx::client*)
void * database_
MongoDB database (mongocxx::database*)

◆ ~mongodb_backend()

database::backends::mongodb_backend::~mongodb_backend ( )
overridedefault

Destructor - ensures proper cleanup.

Member Function Documentation

◆ backend_name()

static constexpr const char * database::backends::mongodb_backend::backend_name ( )
inlinestaticconstexpr

Backend name for error messages.

Definition at line 78 of file mongodb_backend.h.

78{ return "mongodb_backend"; }

Referenced by TEST_F().

Here is the caller graph for this function:

◆ begin_transaction()

kcenon::common::VoidResult database::backends::mongodb_backend::begin_transaction ( )
overridevirtual

Begin a transaction.

Returns
VoidResult::ok() on success, error on failure

Implements database::core::database_backend.

Definition at line 285 of file mongodb_backend.cpp.

286{
287 if (!is_initialized()) {
288 last_error_ = "Backend not initialized";
289 return kcenon::common::error_info{
290 static_cast<int>(database::error_code::invalid_state),
292 "mongodb_backend"
293 };
294 }
295
296 if (in_transaction_) {
297 last_error_ = "Transaction already active";
298 return kcenon::common::error_info{
299 static_cast<int>(database::error_code::invalid_state),
301 "mongodb_backend"
302 };
303 }
304
305 // MongoDB transactions require replica sets or sharded clusters
306 // For simplicity, we'll mark the transaction state
307 in_transaction_ = true;
308 last_error_.clear();
309 return kcenon::common::ok();
310}
std::string last_error_
Last error message.
std::atomic< bool > in_transaction_
Transaction state.

References in_transaction_, database::invalid_state, database::core::backend_base< mongodb_backend, database_types::mongodb >::is_initialized(), and last_error_.

Here is the call graph for this function:

◆ build_connection_uri()

std::string database::backends::mongodb_backend::build_connection_uri ( const core::connection_config & config) const
private

Convert connection_config to MongoDB connection URI.

Parameters
configStructured connection configuration
Returns
Connection URI for MongoDB C++ driver

Format: "mongodb://username:password@host:port/database"

Definition at line 381 of file mongodb_backend.cpp.

382{
383 std::ostringstream oss;
384
385 oss << "mongodb://";
386
387 // Add credentials if provided
388 if (!config.username.empty()) {
389 oss << config.username;
390 if (!config.password.empty()) {
391 oss << ":" << config.password;
392 }
393 oss << "@";
394 }
395
396 // Add host (default to localhost if not specified)
397 if (!config.host.empty()) {
398 oss << config.host;
399 } else {
400 oss << "localhost";
401 }
402
403 // Add port (default to 27017 if not specified)
404 if (config.port > 0) {
405 oss << ":" << config.port;
406 } else {
407 oss << ":27017";
408 }
409
410 // Add database
411 if (!config.database.empty()) {
412 oss << "/" << config.database;
413 }
414
415 // Add additional options
416 if (!config.options.empty()) {
417 oss << "?";
418 bool first = true;
419 for (const auto& [key, value] : config.options) {
420 if (!first) {
421 oss << "&";
422 }
423 oss << key << "=" << value;
424 first = false;
425 }
426 }
427
428 return oss.str();
429}

References database::core::connection_config::database, database::core::connection_config::host, database::core::connection_config::options, database::core::connection_config::password, database::core::connection_config::port, and database::core::connection_config::username.

Referenced by do_initialize().

Here is the caller graph for this function:

◆ commit_transaction()

kcenon::common::VoidResult database::backends::mongodb_backend::commit_transaction ( )
overridevirtual

Commit the current transaction.

Returns
VoidResult::ok() on success, error on failure

Implements database::core::database_backend.

Definition at line 312 of file mongodb_backend.cpp.

313{
314 if (!is_initialized()) {
315 last_error_ = "Backend not initialized";
316 return kcenon::common::error_info{
317 static_cast<int>(database::error_code::invalid_state),
319 "mongodb_backend"
320 };
321 }
322
323 if (!in_transaction_) {
324 last_error_ = "No active transaction";
325 return kcenon::common::error_info{
326 static_cast<int>(database::error_code::invalid_state),
328 "mongodb_backend"
329 };
330 }
331
332 in_transaction_ = false;
333 last_error_.clear();
334 return kcenon::common::ok();
335}

References in_transaction_, database::invalid_state, database::core::backend_base< mongodb_backend, database_types::mongodb >::is_initialized(), and last_error_.

Here is the call graph for this function:

◆ connection_info()

std::map< std::string, std::string > database::backends::mongodb_backend::connection_info ( ) const
overridevirtual

Get backend-specific connection information.

Returns
Map of connection properties (for debugging/monitoring)

Example keys: "server_version", "connection_id", "protocol_version"

Implements database::core::database_backend.

Definition at line 368 of file mongodb_backend.cpp.

369{
370 std::map<std::string, std::string> info;
371 info["backend"] = "mongodb";
372 info["host"] = connection_config_.host;
373 info["port"] = std::to_string(connection_config_.port);
374 info["database"] = connection_config_.database;
375 info["username"] = connection_config_.username;
376 info["initialized"] = initialized_ ? "true" : "false";
377 info["in_transaction"] = in_transaction_ ? "true" : "false";
378 return info;
379}
core::connection_config connection_config_
Cached connection config.
@ info
Informational messages (default)

References connection_config_, database::core::connection_config::database, database::core::connection_config::host, in_transaction_, database::core::backend_base< mongodb_backend, database_types::mongodb >::initialized_, database::core::connection_config::port, and database::core::connection_config::username.

◆ do_initialize()

kcenon::common::VoidResult database::backends::mongodb_backend::do_initialize ( const core::connection_config & config)
protected

Database-specific initialization logic.

Parameters
configConnection configuration
Returns
VoidResult::ok() on success, error on failure

Definition at line 41 of file mongodb_backend.cpp.

42{
43 connection_config_ = config;
44 std::string conn_uri = build_connection_uri(config);
45 db_name_ = config.database;
46
47#ifdef USE_MONGODB
48 std::lock_guard<std::mutex> lock(mongo_mutex_);
49 try {
50 // Initialize MongoDB instance (should only be done once per application)
51 static mongocxx::instance instance{};
52
53 // Create MongoDB URI
54 mongocxx::uri uri{conn_uri};
55
56 // Create MongoDB client
57 auto client = std::make_unique<mongocxx::client>(uri);
58 client_ = client.release();
59
60 // Get database reference
61 auto* mongo_client = static_cast<mongocxx::client*>(client_);
62 auto db = std::make_unique<mongocxx::database>((*mongo_client)[db_name_]);
63 database_ = db.release();
64
65 // Test connection by running a simple command
66 auto* mongo_db = static_cast<mongocxx::database*>(database_);
67 auto result = mongo_db->run_command(bsoncxx::builder::stream::document{} << "ping" << 1 << bsoncxx::builder::stream::finalize);
68
69 last_error_.clear();
70 return kcenon::common::ok();
71 } catch (const std::exception& e) {
72 last_error_ = std::string("Connection error: ") + e.what();
73 logger_.error("do_initialize", last_error_);
74 }
75#else
76 logger_.warning("MongoDB support not compiled. Mock mode enabled.");
77 // Mock mode for testing without MongoDB
78 last_error_.clear();
79 return kcenon::common::ok();
80#endif
81
82 if (last_error_.empty()) {
83 last_error_ = "Failed to connect to MongoDB server";
84 }
85 return kcenon::common::error_info{
88 "mongodb_backend"
89 };
90}
std::mutex mongo_mutex_
Mutex for thread safety.
std::string build_connection_uri(const core::connection_config &config) const
Convert connection_config to MongoDB connection URI.
std::string db_name_
Database name.

References build_connection_uri(), client_, connection_config_, database::connection_failed, database::core::connection_config::database, database_, db_name_, last_error_, and mongo_mutex_.

Here is the call graph for this function:

◆ do_shutdown()

kcenon::common::VoidResult database::backends::mongodb_backend::do_shutdown ( )
protected

Database-specific shutdown logic.

Returns
VoidResult::ok() on success, error on failure

Definition at line 92 of file mongodb_backend.cpp.

93{
94 // Rollback any active transaction before disconnecting
95 if (in_transaction_) {
97 }
98
99#ifdef USE_MONGODB
100 std::lock_guard<std::mutex> lock(mongo_mutex_);
101 if (database_) {
102 delete static_cast<mongocxx::database*>(database_);
103 database_ = nullptr;
104 }
105 if (client_) {
106 delete static_cast<mongocxx::client*>(client_);
107 client_ = nullptr;
108 }
109#endif
110
111 last_error_.clear();
112 return kcenon::common::ok();
113}
kcenon::common::VoidResult rollback_transaction() override
Rollback the current transaction.

References client_, database_, in_transaction_, last_error_, mongo_mutex_, and rollback_transaction().

Here is the call graph for this function:

◆ execute_query()

kcenon::common::VoidResult database::backends::mongodb_backend::execute_query ( const std::string & query_string)
overridevirtual

Execute a general SQL query (DDL, DML)

Parameters
query_stringSQL statement
Returns
VoidResult::ok() on success, error on failure

Implements database::core::database_backend.

Definition at line 226 of file mongodb_backend.cpp.

227{
228 if (!is_initialized()) {
229 last_error_ = "Backend not initialized";
230 return kcenon::common::error_info{
231 static_cast<int>(database::error_code::invalid_state),
233 "mongodb_backend"
234 };
235 }
236
237#ifdef USE_MONGODB
238 if (!database_) {
239 last_error_ = "No active MongoDB connection";
240 logger_.error("execute_query", last_error_);
241 return kcenon::common::error_info{
244 "mongodb_backend"
245 };
246 }
247
248 std::lock_guard<std::mutex> lock(mongo_mutex_);
249 try {
250 auto* mongo_db = static_cast<mongocxx::database*>(database_);
251
252 // Try to parse as MongoDB command (JSON format)
253 try {
254 auto command_doc = bsoncxx::from_json(query_string);
255 auto result = mongo_db->run_command(command_doc.view());
256 last_error_.clear();
257 return kcenon::common::ok();
258 } catch (const std::exception&) {
259 // If JSON parsing fails, treat as collection creation
260 std::string collection_name = query_string;
261 auto collection = (*mongo_db)[collection_name];
262 auto doc = bsoncxx::builder::stream::document{} << "test" << "creation" << bsoncxx::builder::stream::finalize;
263 collection.insert_one(doc.view());
264 collection.delete_one(doc.view());
265 last_error_.clear();
266 return kcenon::common::ok();
267 }
268 } catch (const std::exception& e) {
269 last_error_ = std::string("Execute error: ") + e.what();
270 logger_.error("execute_query", last_error_);
271 return kcenon::common::error_info{
272 static_cast<int>(database::error_code::query_failed),
274 "mongodb_backend"
275 };
276 }
277#else
278 // Mock execution
279 logger_.info("MongoDB support not compiled. Mock execute: " + query_string);
280 last_error_.clear();
281 return kcenon::common::ok();
282#endif
283}

References database::connection_failed, database_, database::invalid_state, database::core::backend_base< mongodb_backend, database_types::mongodb >::is_initialized(), last_error_, mongo_mutex_, and database::query_failed.

Here is the call graph for this function:

◆ in_transaction()

bool database::backends::mongodb_backend::in_transaction ( ) const
overridevirtual

Check if backend is currently in a transaction.

Returns
true if transaction is active

Implements database::core::database_backend.

Definition at line 358 of file mongodb_backend.cpp.

359{
360 return in_transaction_;
361}

References in_transaction_.

◆ last_error()

std::string database::backends::mongodb_backend::last_error ( ) const
overridevirtual

Get last error message from backend.

Returns
Error message, or empty string if no error

Implements database::core::database_backend.

Definition at line 363 of file mongodb_backend.cpp.

364{
365 return last_error_;
366}

References last_error_.

◆ parse_query_string()

bool database::backends::mongodb_backend::parse_query_string ( const std::string & query_string,
std::string & collection,
std::string & filter,
std::string & update ) const
private

Parse query string format.

Parameters
query_stringQuery string in format "collection:filter:update"
collectionOutput collection name
filterOutput filter JSON
updateOutput update JSON (optional)
Returns
true if parsing succeeded

Definition at line 115 of file mongodb_backend.cpp.

119{
120 // Parse format: "collection_name:filter_json" or "collection_name:filter_json:update_json"
121 std::istringstream ss(query_string);
122 std::string part;
123 std::vector<std::string> parts;
124
125 while (std::getline(ss, part, ':')) {
126 parts.push_back(part);
127 }
128
129 if (parts.size() >= 1) collection = parts[0];
130 if (parts.size() >= 2) filter = parts[1];
131 if (parts.size() >= 3) update = parts[2];
132
133 return !collection.empty();
134}

Referenced by select_query().

Here is the caller graph for this function:

◆ rollback_transaction()

kcenon::common::VoidResult database::backends::mongodb_backend::rollback_transaction ( )
overridevirtual

Rollback the current transaction.

Returns
VoidResult::ok() on success, error on failure

Implements database::core::database_backend.

Definition at line 337 of file mongodb_backend.cpp.

338{
339 if (!is_initialized()) {
340 last_error_ = "Backend not initialized";
341 return kcenon::common::error_info{
342 static_cast<int>(database::error_code::invalid_state),
344 "mongodb_backend"
345 };
346 }
347
348 if (!in_transaction_) {
349 // Not an error - already rolled back or never started
350 return kcenon::common::ok();
351 }
352
353 in_transaction_ = false;
354 last_error_.clear();
355 return kcenon::common::ok();
356}

References in_transaction_, database::invalid_state, database::core::backend_base< mongodb_backend, database_types::mongodb >::is_initialized(), and last_error_.

Referenced by do_shutdown().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ select_query()

kcenon::common::Result< core::database_result > database::backends::mongodb_backend::select_query ( const std::string & query_string)
overridevirtual

Execute a SELECT query.

Parameters
query_stringSQL SELECT statement
Returns
Query results as rows, or error

Implements database::core::database_backend.

Definition at line 136 of file mongodb_backend.cpp.

137{
138 if (!is_initialized()) {
139 last_error_ = "Backend not initialized";
140 return kcenon::common::error_info{
141 static_cast<int>(database::error_code::invalid_state),
143 "mongodb_backend"
144 };
145 }
146
148
149#ifdef USE_MONGODB
150 if (!database_) {
151 last_error_ = "No active connection";
152 return kcenon::common::error_info{
155 "mongodb_backend"
156 };
157 }
158 std::lock_guard<std::mutex> lock(mongo_mutex_);
159 try {
160 std::string collection_name, filter_json, unused;
161 if (!parse_query_string(query_string, collection_name, filter_json, unused)) {
162 last_error_ = "Invalid query format";
163 return kcenon::common::error_info{
164 static_cast<int>(database::error_code::query_failed),
166 "mongodb_backend"
167 };
168 }
169
170 auto* mongo_db = static_cast<mongocxx::database*>(database_);
171 auto collection = (*mongo_db)[collection_name];
172
173 // Parse JSON to BSON for filter
174 bsoncxx::document::value filter_doc = filter_json.empty() ?
175 bsoncxx::builder::stream::document{} << bsoncxx::builder::stream::finalize :
176 bsoncxx::from_json(filter_json);
177
178 auto cursor = collection.find(filter_doc.view());
179
180 for (auto&& doc : cursor) {
182
183 // Convert BSON document to core::database_row
184 auto json_string = bsoncxx::to_json(doc);
185 row["_document"] = json_string; // Store full document as JSON string
186
187 // Also extract common fields
188 auto view = doc.view();
189 if (view["_id"]) {
190 row["_id"] = bsoncxx::to_json(view["_id"].get_value());
191 }
192
193 // Extract other fields as strings for compatibility
194 for (auto&& element : view) {
195 std::string key = element.key().to_string();
196 if (key != "_id") { // _id already processed
197 row[key] = bsoncxx::to_json(element.get_value());
198 }
199 }
200
201 result.push_back(std::move(row));
202 }
203 } catch (const std::exception& e) {
204 last_error_ = std::string("Select error: ") + e.what();
205 logger_.error("select_query", last_error_);
206 return kcenon::common::error_info{
207 static_cast<int>(database::error_code::query_failed),
209 "mongodb_backend"
210 };
211 }
212#else
213 logger_.warning("MongoDB support not compiled. Select query: " + query_string.substr(0, 20) + "...");
214 // Return mock data for testing
215 core::database_row mock_row;
216 mock_row["_id"] = std::string("mock_object_id");
217 mock_row["name"] = std::string("mongodb_mock_data");
218 mock_row["_document"] = std::string("{\"_id\":\"mock_object_id\",\"name\":\"mongodb_mock_data\"}");
219 result.push_back(mock_row);
220#endif
221
222 last_error_.clear();
223 return result;
224}
bool parse_query_string(const std::string &query_string, std::string &collection, std::string &filter, std::string &update) const
Parse query string format.
std::vector< database_row > database_result
std::map< std::string, database_value > database_row

References database::connection_failed, database_, database::invalid_state, database::core::backend_base< mongodb_backend, database_types::mongodb >::is_initialized(), last_error_, mongo_mutex_, parse_query_string(), and database::query_failed.

Here is the call graph for this function:

Friends And Related Symbol Documentation

◆ core::backend_base< mongodb_backend, database_types::mongodb >

Definition at line 106 of file mongodb_backend.h.

Member Data Documentation

◆ client_

void* database::backends::mongodb_backend::client_ {nullptr}
private

MongoDB client (mongocxx::client*)

Definition at line 147 of file mongodb_backend.h.

147{nullptr};

Referenced by do_initialize(), and do_shutdown().

◆ connection_config_

core::connection_config database::backends::mongodb_backend::connection_config_
private

Cached connection config.

Definition at line 152 of file mongodb_backend.h.

Referenced by connection_info(), and do_initialize().

◆ database_

void* database::backends::mongodb_backend::database_ {nullptr}
private

MongoDB database (mongocxx::database*)

Definition at line 148 of file mongodb_backend.h.

148{nullptr};

Referenced by do_initialize(), do_shutdown(), execute_query(), and select_query().

◆ db_name_

std::string database::backends::mongodb_backend::db_name_
private

Database name.

Definition at line 149 of file mongodb_backend.h.

Referenced by do_initialize().

◆ in_transaction_

std::atomic<bool> database::backends::mongodb_backend::in_transaction_ {false}
private

Transaction state.

Definition at line 150 of file mongodb_backend.h.

150{false};

Referenced by begin_transaction(), commit_transaction(), connection_info(), do_shutdown(), in_transaction(), and rollback_transaction().

◆ last_error_

std::string database::backends::mongodb_backend::last_error_
mutableprivate

◆ mongo_mutex_

std::mutex database::backends::mongodb_backend::mongo_mutex_
mutableprivate

Mutex for thread safety.

Definition at line 153 of file mongodb_backend.h.

Referenced by do_initialize(), do_shutdown(), execute_query(), and select_query().


The documentation for this class was generated from the following files: