relx 0.1.0
A Modern C++23 Type-Safe SQL Query Builder
Loading...
Searching...
No Matches
postgresql_connection.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "connection.hpp"
4
5#include <memory>
6#include <sstream>
7#include <string>
8#include <string_view>
9#include <type_traits>
10
11// Forward declarations to avoid including libpq headers in our public API
12struct pg_conn;
13using PGconn = pg_conn;
14struct pg_result;
15using PGresult = pg_result;
16
17// Forward declare statement class
18namespace relx::connection {
19class PostgreSQLStatement;
20} // namespace relx::connection
21
22namespace relx::connection {
23
26public:
30 explicit PostgreSQLConnection(std::string_view connection_string);
31
35
38
39 // Delete copy constructor and assignment operator
42
43 // Allow move operations
46
49 ConnectionResult<void> connect() override;
50
53 ConnectionResult<void> disconnect() override;
54
60 const std::string& sql, const std::vector<std::string>& params = {}) override;
61
67 // TODO make binary type for bytea type in postgresql instead of this hacky function
69 const std::string& sql, const std::vector<std::string>& params,
70 const std::vector<bool>& is_binary); // TODO replace vector bool
71
77 template <typename... Args>
78 ConnectionResult<result::ResultSet> execute_typed(const std::string& sql, Args&&... args) {
79 // Convert each parameter to its string representation
80 std::vector<std::string> param_strings;
81 param_strings.reserve(sizeof...(Args));
82
83 // Helper to convert a parameter to string and add to vector
84 auto add_param = [&param_strings](auto&& param) {
85 using ParamType = std::remove_cvref_t<decltype(param)>;
86
87 if constexpr (std::is_same_v<ParamType, std::nullptr_t>) {
88 // Handle NULL values
89 param_strings.push_back("NULL");
90 } else if constexpr (std::is_same_v<ParamType, std::string> ||
91 std::is_same_v<ParamType, const char*> ||
92 std::is_same_v<ParamType, std::string_view>) {
93 // String types
94 param_strings.push_back(std::string(param));
95 } else if constexpr (std::is_arithmetic_v<ParamType>) {
96 // Numeric types
97 param_strings.push_back(std::to_string(param));
98 } else if constexpr (std::is_same_v<ParamType, bool>) {
99 // Boolean values
100 param_strings.push_back(param ? "t" : "f");
101 } else {
102 // Other types, try to use stream conversion
103 std::ostringstream ss;
104 ss << param;
105 param_strings.push_back(ss.str());
106 }
107 };
108
109 // Add each parameter to the vector
110 (add_param(std::forward<Args>(args)), ...);
111
112 // Call the string-based execute_raw with our converted parameters
113 return execute_raw(sql, param_strings);
114 }
115
118 bool is_connected() const override;
119
124 IsolationLevel isolation_level = IsolationLevel::ReadCommitted) override;
125
129
133
136 bool in_transaction() const override;
137
143 std::unique_ptr<PostgreSQLStatement> prepare_statement(const std::string& name,
144 const std::string& sql, int param_count);
145
148 PGconn* get_pg_conn() { return pg_conn_; }
149
153 static std::string convert_placeholders(const std::string& sql);
154
155private:
156 std::string connection_string_;
157 PGconn* pg_conn_ = nullptr;
158 bool is_connected_ = false;
159 bool in_transaction_ = false;
160
165 ConnectionResult<PGresult*> handle_pg_result(PGresult* result, int expected_status = -1);
166};
167
168} // namespace relx::connection
Abstract base class for database connections.
PostgreSQL implementation of the Connection interface.
bool is_connected() const override
Check if the connection is open.
PostgreSQLConnection(const PostgreSQLConnection &)=delete
ConnectionResult< result::ResultSet > execute_raw(const std::string &sql, const std::vector< std::string > &params={}) override
Execute a raw SQL query with parameters.
ConnectionResult< void > connect() override
Connect to the PostgreSQL database.
ConnectionResult< result::ResultSet > execute_typed(const std::string &sql, Args &&... args)
Execute a raw SQL query with typed parameters.
std::unique_ptr< PostgreSQLStatement > prepare_statement(const std::string &name, const std::string &sql, int param_count)
Create a prepared statement.
PostgreSQLConnection(PostgreSQLConnection &&) noexcept
PostgreSQLConnection(const PostgreSQLConnectionParams &params)
Constructor with structured connection parameters.
PostgreSQLConnection(std::string_view connection_string)
Constructor with connection parameters.
ConnectionResult< void > commit_transaction() override
Commit the current transaction.
ConnectionResult< void > disconnect() override
Disconnect from the PostgreSQL database.
~PostgreSQLConnection() override
Destructor that ensures proper cleanup.
ConnectionResult< result::ResultSet > execute_raw_binary(const std::string &sql, const std::vector< std::string > &params, const std::vector< bool > &is_binary)
Execute a raw SQL query with binary parameters.
PGconn * get_pg_conn()
Get direct access to the PostgreSQL connection.
PostgreSQLConnection & operator=(const PostgreSQLConnection &)=delete
ConnectionResult< void > begin_transaction(IsolationLevel isolation_level=IsolationLevel::ReadCommitted) override
Begin a new transaction with specified isolation level.
ConnectionResult< void > rollback_transaction() override
Rollback the current transaction.
static std::string convert_placeholders(const std::string &sql)
Convert SQL with ? placeholders to PostgreSQL's $n format.
bool in_transaction() const override
Check if a transaction is currently active.
Represents the result set from a database query.
Definition result.hpp:608
IsolationLevel
Transaction isolation levels.
@ ReadCommitted
Prevents dirty reads.
std::expected< T, ConnectionError > ConnectionResult
Type alias for result of connection operations.
STL namespace.
pg_result PGresult
Basic parameters for a PostgreSQL connection.