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

Redis implementation of database_backend interface. More...

#include <redis_backend.h>

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

Public Member Functions

 redis_backend ()
 Default constructor.
 
 ~redis_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< redis_backend, database_types::redis >
 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< redis_backend, database_types::redis >
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

bool parse_redis_query (const std::string &query_string, std::string &key, std::string &value) const
 Parse Redis query string format.
 

Private Attributes

void * context_ {nullptr}
 Redis context (redisContext*)
 
std::string host_
 Redis host.
 
int port_ {6379}
 Redis port.
 
std::atomic< bool > in_transaction_ {false}
 Transaction state (MULTI/EXEC)
 
std::string last_error_
 Last error message.
 
core::connection_config connection_config_
 Cached connection config.
 
std::mutex redis_mutex_
 Mutex for thread safety.
 

Friends

class core::backend_base< redis_backend, database_types::redis >
 

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< redis_backend, database_types::redis >
std::atomic< bool > initialized_
 Initialization state.
 

Detailed Description

Redis implementation of database_backend interface.

This class implements the database_backend interface for Redis via backend_base CRTP template, using hiredis.

Design Pattern: Strategy pattern with CRTP

  • Extends backend_base for common lifecycle management
  • Uses hiredis for Redis 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("redis");
config.host = "localhost";
config.port = 6379;
if (auto result = backend->initialize(config); !result) {
// Handle error
}
backend->execute_query("SET key value");
auto rows = backend->select_query("key");
Configuration for database connection.

Definition at line 69 of file redis_backend.h.

Constructor & Destructor Documentation

◆ redis_backend()

database::backends::redis_backend::redis_backend ( )

Default constructor.

Definition at line 29 of file redis_backend.cpp.

30 : context_(nullptr), host_("localhost"), port_(6379)
31{
32}
void * context_
Redis context (redisContext*)

◆ ~redis_backend()

database::backends::redis_backend::~redis_backend ( )
overridedefault

Destructor - ensures proper cleanup.

Member Function Documentation

◆ backend_name()

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

Backend name for error messages.

Definition at line 76 of file redis_backend.h.

76{ return "redis_backend"; }

Referenced by TEST_F().

Here is the caller graph for this function:

◆ begin_transaction()

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

Begin a transaction.

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

Implements database::core::database_backend.

Definition at line 305 of file redis_backend.cpp.

306{
307 if (!is_initialized()) {
308 last_error_ = "Backend not initialized";
309 return kcenon::common::error_info{
310 static_cast<int>(database::error_code::invalid_state),
312 "redis_backend"
313 };
314 }
315
316 if (in_transaction_) {
317 last_error_ = "Transaction already active";
318 return kcenon::common::error_info{
319 static_cast<int>(database::error_code::invalid_state),
321 "redis_backend"
322 };
323 }
324
325 // Redis uses MULTI to begin a transaction
326 auto result = execute_query("MULTI");
327 if (result.is_err()) {
328 return result;
329 }
330
331 in_transaction_ = true;
332 last_error_.clear();
333 return kcenon::common::ok();
334}
kcenon::common::VoidResult execute_query(const std::string &query_string) override
Execute a general SQL query (DDL, DML)
std::atomic< bool > in_transaction_
Transaction state (MULTI/EXEC)
std::string last_error_
Last error message.

References execute_query(), in_transaction_, database::invalid_state, database::core::backend_base< redis_backend, database_types::redis >::is_initialized(), and last_error_.

Here is the call graph for this function:

◆ commit_transaction()

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

Commit the current transaction.

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

Implements database::core::database_backend.

Definition at line 336 of file redis_backend.cpp.

337{
338 if (!is_initialized()) {
339 last_error_ = "Backend not initialized";
340 return kcenon::common::error_info{
341 static_cast<int>(database::error_code::invalid_state),
343 "redis_backend"
344 };
345 }
346
347 if (!in_transaction_) {
348 last_error_ = "No active transaction";
349 return kcenon::common::error_info{
350 static_cast<int>(database::error_code::invalid_state),
352 "redis_backend"
353 };
354 }
355
356 // Redis uses EXEC to commit a transaction
357 auto result = execute_query("EXEC");
358 if (result.is_err()) {
359 return result;
360 }
361
362 in_transaction_ = false;
363 last_error_.clear();
364 return kcenon::common::ok();
365}

References execute_query(), in_transaction_, database::invalid_state, database::core::backend_base< redis_backend, database_types::redis >::is_initialized(), and last_error_.

Here is the call graph for this function:

◆ connection_info()

std::map< std::string, std::string > database::backends::redis_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 405 of file redis_backend.cpp.

406{
407 std::map<std::string, std::string> info;
408 info["backend"] = "redis";
409 info["host"] = host_;
410 info["port"] = std::to_string(port_);
411 info["initialized"] = initialized_ ? "true" : "false";
412 info["in_transaction"] = in_transaction_ ? "true" : "false";
413 return info;
414}
@ info
Informational messages (default)

References host_, in_transaction_, database::core::backend_base< redis_backend, database_types::redis >::initialized_, and port_.

◆ do_initialize()

kcenon::common::VoidResult database::backends::redis_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 34 of file redis_backend.cpp.

35{
36 connection_config_ = config;
37 host_ = config.host.empty() ? "localhost" : config.host;
38 port_ = config.port > 0 ? config.port : 6379;
39
40#ifdef USE_REDIS
41 std::lock_guard<std::mutex> lock(redis_mutex_);
42 try {
43 // Create Redis connection
44 redisContext* ctx = redisConnect(host_.c_str(), port_);
45 if (ctx == nullptr || ctx->err) {
46 if (ctx) {
47 last_error_ = std::string("Connection error: ") + ctx->errstr;
48 logger_.error("do_initialize", last_error_);
49 redisFree(ctx);
50 } else {
51 last_error_ = "Connection allocation error";
52 logger_.error("do_initialize", last_error_);
53 }
54 return kcenon::common::error_info{
57 "redis_backend"
58 };
59 }
60
61 context_ = ctx;
62
63 // Authenticate if password provided
64 if (!config.password.empty()) {
65 redisReply* reply = static_cast<redisReply*>(
66 redisCommand(ctx, "AUTH %s", config.password.c_str()));
67 if (reply == nullptr || reply->type == REDIS_REPLY_ERROR) {
68 last_error_ = "Authentication failed";
69 logger_.error("do_initialize", last_error_);
70 if (reply) freeReplyObject(reply);
71 redisFree(ctx);
72 context_ = nullptr;
73 return kcenon::common::error_info{
76 "redis_backend"
77 };
78 }
79 freeReplyObject(reply);
80 }
81
82 // Test connection with PING
83 redisReply* ping_reply = static_cast<redisReply*>(redisCommand(ctx, "PING"));
84 if (ping_reply == nullptr || ping_reply->type == REDIS_REPLY_ERROR) {
85 last_error_ = "PING failed";
86 logger_.error("do_initialize", last_error_);
87 if (ping_reply) freeReplyObject(ping_reply);
88 redisFree(ctx);
89 context_ = nullptr;
90 return kcenon::common::error_info{
93 "redis_backend"
94 };
95 }
96 freeReplyObject(ping_reply);
97
98 last_error_.clear();
99 return kcenon::common::ok();
100 } catch (const std::exception& e) {
101 last_error_ = std::string("Connection error: ") + e.what();
102 logger_.error("do_initialize", last_error_);
103 }
104#else
105 logger_.warning("Redis support not compiled. Mock mode enabled.");
106 // Mock mode for testing without Redis
107 last_error_.clear();
108 return kcenon::common::ok();
109#endif
110
111 if (last_error_.empty()) {
112 last_error_ = "Failed to connect to Redis server";
113 }
114 return kcenon::common::error_info{
117 "redis_backend"
118 };
119}
std::mutex redis_mutex_
Mutex for thread safety.
core::connection_config connection_config_
Cached connection config.

References connection_config_, database::connection_failed, context_, database::core::connection_config::host, host_, last_error_, database::core::connection_config::password, database::core::connection_config::port, port_, and redis_mutex_.

◆ do_shutdown()

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

Database-specific shutdown logic.

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

Definition at line 121 of file redis_backend.cpp.

122{
123 // Discard any active transaction before disconnecting
124 if (in_transaction_) {
126 }
127
128#ifdef USE_REDIS
129 std::lock_guard<std::mutex> lock(redis_mutex_);
130 if (context_) {
131 redisFree(static_cast<redisContext*>(context_));
132 context_ = nullptr;
133 }
134#endif
135
136 last_error_.clear();
137 return kcenon::common::ok();
138}
kcenon::common::VoidResult rollback_transaction() override
Rollback the current transaction.

References context_, in_transaction_, last_error_, redis_mutex_, and rollback_transaction().

Here is the call graph for this function:

◆ execute_query()

kcenon::common::VoidResult database::backends::redis_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 231 of file redis_backend.cpp.

232{
233 if (!is_initialized()) {
234 last_error_ = "Backend not initialized";
235 return kcenon::common::error_info{
236 static_cast<int>(database::error_code::invalid_state),
238 "redis_backend"
239 };
240 }
241
242#ifdef USE_REDIS
243 if (!context_) {
244 last_error_ = "No active Redis connection";
245 logger_.error("execute_query", last_error_);
246 return kcenon::common::error_info{
249 "redis_backend"
250 };
251 }
252
253 std::lock_guard<std::mutex> lock(redis_mutex_);
254 try {
255 redisContext* ctx = static_cast<redisContext*>(context_);
256 redisReply* reply = static_cast<redisReply*>(
257 redisCommand(ctx, "%s", query_string.c_str()));
258
259 if (reply == nullptr) {
260 last_error_ = std::string("Command failed: ") + ctx->errstr;
261 logger_.error("execute_query", last_error_);
262 return kcenon::common::error_info{
263 static_cast<int>(database::error_code::query_failed),
265 "redis_backend"
266 };
267 }
268
269 bool success = true;
270 if (reply->type == REDIS_REPLY_ERROR) {
271 last_error_ = std::string("Execute error: ") + reply->str;
272 logger_.error("execute_query", last_error_);
273 success = false;
274 }
275
276 freeReplyObject(reply);
277
278 if (!success) {
279 return kcenon::common::error_info{
280 static_cast<int>(database::error_code::query_failed),
282 "redis_backend"
283 };
284 }
285
286 last_error_.clear();
287 return kcenon::common::ok();
288 } catch (const std::exception& e) {
289 last_error_ = std::string("Execute error: ") + e.what();
290 logger_.error("execute_query", last_error_);
291 return kcenon::common::error_info{
292 static_cast<int>(database::error_code::query_failed),
294 "redis_backend"
295 };
296 }
297#else
298 // Mock execution
299 logger_.info("Redis support not compiled. Mock execute: " + query_string);
300 last_error_.clear();
301 return kcenon::common::ok();
302#endif
303}

References database::connection_failed, context_, database::invalid_state, database::core::backend_base< redis_backend, database_types::redis >::is_initialized(), last_error_, database::query_failed, redis_mutex_, and database::success.

Referenced by begin_transaction(), commit_transaction(), and rollback_transaction().

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

◆ in_transaction()

bool database::backends::redis_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 395 of file redis_backend.cpp.

396{
397 return in_transaction_;
398}

References in_transaction_.

◆ last_error()

std::string database::backends::redis_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 400 of file redis_backend.cpp.

401{
402 return last_error_;
403}

References last_error_.

◆ parse_redis_query()

bool database::backends::redis_backend::parse_redis_query ( const std::string & query_string,
std::string & key,
std::string & value ) const
private

Parse Redis query string format.

Parameters
query_stringQuery string in format "key:value"
keyOutput key
valueOutput value
Returns
true if parsing succeeded

Definition at line 140 of file redis_backend.cpp.

143{
144 // Parse format: "key:value"
145 std::istringstream ss(query_string);
146 std::string part;
147 std::vector<std::string> parts;
148
149 while (std::getline(ss, part, ':')) {
150 parts.push_back(part);
151 }
152
153 if (parts.size() >= 1) key = parts[0];
154 if (parts.size() >= 2) value = parts[1];
155
156 return !key.empty();
157}

◆ rollback_transaction()

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

Rollback the current transaction.

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

Implements database::core::database_backend.

Definition at line 367 of file redis_backend.cpp.

368{
369 if (!is_initialized()) {
370 last_error_ = "Backend not initialized";
371 return kcenon::common::error_info{
372 static_cast<int>(database::error_code::invalid_state),
374 "redis_backend"
375 };
376 }
377
378 if (!in_transaction_) {
379 // Not an error - already discarded or never started
380 return kcenon::common::ok();
381 }
382
383 // Redis uses DISCARD to rollback a transaction
384 auto result = execute_query("DISCARD");
385 in_transaction_ = false; // Force state reset even on error
386
387 if (result.is_err()) {
388 return result;
389 }
390
391 last_error_.clear();
392 return kcenon::common::ok();
393}

References execute_query(), in_transaction_, database::invalid_state, database::core::backend_base< redis_backend, database_types::redis >::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::redis_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 159 of file redis_backend.cpp.

160{
161 if (!is_initialized()) {
162 last_error_ = "Backend not initialized";
163 return kcenon::common::error_info{
164 static_cast<int>(database::error_code::invalid_state),
166 "redis_backend"
167 };
168 }
169
171
172#ifdef USE_REDIS
173 if (!context_) {
174 last_error_ = "No active connection";
175 return kcenon::common::error_info{
178 "redis_backend"
179 };
180 }
181 std::lock_guard<std::mutex> lock(redis_mutex_);
182 try {
183 // For select, query_string is the key
184 std::string key = query_string;
185
186 redisContext* ctx = static_cast<redisContext*>(context_);
187 redisReply* reply = static_cast<redisReply*>(
188 redisCommand(ctx, "GET %s", key.c_str()));
189
190 if (reply != nullptr && reply->type != REDIS_REPLY_ERROR &&
191 reply->type != REDIS_REPLY_NIL) {
193 row["key"] = key;
194
195 if (reply->type == REDIS_REPLY_STRING) {
196 row["value"] = std::string(reply->str, reply->len);
197 } else if (reply->type == REDIS_REPLY_INTEGER) {
198 row["value"] = static_cast<int64_t>(reply->integer);
199 } else {
200 row["value"] = std::string("");
201 }
202
203 result.push_back(std::move(row));
204 }
205
206 if (reply) freeReplyObject(reply);
207 } catch (const std::exception& e) {
208 last_error_ = std::string("Select error: ") + e.what();
209 logger_.error("select_query", last_error_);
210 return kcenon::common::error_info{
211 static_cast<int>(database::error_code::query_failed),
213 "redis_backend"
214 };
215 }
216#else
217 logger_.warning("Redis support not compiled. Select query: " + query_string.substr(0, 20) + "...");
218 // Return mock data for testing
219 if (!query_string.empty()) {
220 core::database_row mock_row;
221 mock_row["key"] = query_string;
222 mock_row["value"] = std::string("redis_mock_value");
223 result.push_back(mock_row);
224 }
225#endif
226
227 last_error_.clear();
228 return result;
229}
std::vector< database_row > database_result
std::map< std::string, database_value > database_row

References database::connection_failed, context_, database::invalid_state, database::core::backend_base< redis_backend, database_types::redis >::is_initialized(), last_error_, database::query_failed, and redis_mutex_.

Here is the call graph for this function:

Friends And Related Symbol Documentation

◆ core::backend_base< redis_backend, database_types::redis >

Definition at line 104 of file redis_backend.h.

Member Data Documentation

◆ connection_config_

core::connection_config database::backends::redis_backend::connection_config_
private

Cached connection config.

Definition at line 139 of file redis_backend.h.

Referenced by do_initialize().

◆ context_

void* database::backends::redis_backend::context_ {nullptr}
private

Redis context (redisContext*)

Definition at line 134 of file redis_backend.h.

134{nullptr};

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

◆ host_

std::string database::backends::redis_backend::host_
private

Redis host.

Definition at line 135 of file redis_backend.h.

Referenced by connection_info(), and do_initialize().

◆ in_transaction_

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

Transaction state (MULTI/EXEC)

Definition at line 137 of file redis_backend.h.

137{false};

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

◆ last_error_

std::string database::backends::redis_backend::last_error_
mutableprivate

◆ port_

int database::backends::redis_backend::port_ {6379}
private

Redis port.

Definition at line 136 of file redis_backend.h.

136{6379};

Referenced by connection_info(), and do_initialize().

◆ redis_mutex_

std::mutex database::backends::redis_backend::redis_mutex_
mutableprivate

Mutex for thread safety.

Definition at line 140 of file redis_backend.h.

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


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