Started developing postgres

This commit is contained in:
Dr. Patrick Urbanke
2025-04-19 10:12:12 +02:00
parent a749f5aabd
commit c8ce5f682f
7 changed files with 235 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
#ifndef SQLGEN_POSTGRES_HPP_
#define SQLGEN_POSTGRES_HPP_
#include "../sqlgen.hpp"
#include "postgres/Credentials.hpp"
#include "postgres/connect.hpp"
#endif

View File

@@ -0,0 +1,55 @@
#ifndef SQLGEN_POSTGRES_CONNECTION_HPP_
#define SQLGEN_POSTGRES_CONNECTION_HPP_
#include <libpq-fe.h>
#include <memory>
#include <rfl.hpp>
#include <stdexcept>
#include <string>
#include "../Connection.hpp"
#include "../IteratorBase.hpp"
#include "../Ref.hpp"
#include "../Result.hpp"
#include "../dynamic/Column.hpp"
#include "../dynamic/Statement.hpp"
#include "Credentials.hpp"
namespace sqlgen::postgres {
class Connection : public sqlgen::Connection {
using ConnPtr = Ref<PGconn>;
public:
Connection(const Credentials& _credentials)
: credentials_(_credentials), conn_(make_conn(_credentials.to_str())) {}
static rfl::Result<Ref<sqlgen::Connection>> make(
const Credentials& _credentials) noexcept;
~Connection() = default;
Result<Nothing> commit() final { return execute("COMMIT;"); }
Result<Nothing> execute(const std::string& _sql) noexcept final;
Result<Ref<IteratorBase>> read(const dynamic::SelectFrom& _query) final;
std::string to_sql(const dynamic::Statement& _stmt) noexcept final;
Result<Nothing> start_write(const dynamic::Insert& _stmt) final;
Result<Nothing> end_write() final;
Result<Nothing> write(
const std::vector<std::vector<std::optional<std::string>>>& _data) final;
private:
static rfl::Result<Ref<sqlgen::Connection>> make_conn(
const std::string& _conn_str);
};
} // namespace sqlgen::postgres
#endif

View File

@@ -0,0 +1,23 @@
#ifndef SQLGEN_POSTGRES_CREDENTIALS_HPP_
#define SQLGEN_POSTGRES_CREDENTIALS_HPP_
#include <string>
namespace sqlgen::postgres {
struct Credentials {
std::string user;
std::string password;
std::string host;
std::string dbname;
int port = 5432;
std::string to_str() const {
return "postgresql://" + user + ":" + password + "@" + host + ":" +
std::to_string(port) + "/" + dbname;
}
};
} // namespace sqlgen::postgres
#endif

View File

@@ -0,0 +1,37 @@
#ifndef SQLGEN_POSTGRES_ITERATOR_HPP_
#define SQLGEN_POSTGRES_ITERATOR_HPP_
#include <sqlite3.h>
#include <optional>
#include <string>
#include <vector>
#include "../IteratorBase.hpp"
#include "../Ref.hpp"
#include "../Result.hpp"
#include "Connection.hpp"
namespace sqlgen::postgres {
class Iterator : public sqlgen::IteratorBase {
public:
Iterator(const StmtPtr& _stmt, const ConnPtr& _conn);
~Iterator();
/// Whether the end of the available data has been reached.
bool end() const final;
/// Returns the next batch of rows.
/// If _batch_size is greater than the number of rows left, returns all
/// of the rows left.
Result<std::vector<std::vector<std::optional<std::string>>>> next(
const size_t _batch_size) final;
private:
};
} // namespace sqlgen::postgres
#endif

View File

@@ -0,0 +1,17 @@
#ifndef SQLGEN_POSTGRES_CONNECT_HPP_
#define SQLGEN_POSTGRES_CONNECT_HPP_
#include <string>
#include "Connection.hpp"
#include "Credentials.hpp"
namespace sqlgen::postgres {
inline auto connect(const Credentials& _credentials) {
return Connection::make(_credentials);
}
} // namespace sqlgen::postgres
#endif

View File

@@ -0,0 +1,36 @@
#include "sqlgen/postgres/Connection.hpp"
#include <ranges>
#include <rfl.hpp>
#include <sstream>
#include <stdexcept>
#include "sqlgen/internal/collect/vector.hpp"
#include "sqlgen/internal/strings/strings.hpp"
namespace sqlgen::postgres {
rfl::Result<Ref<sqlgen::Connection>> Connection::make(
const Credentials& _credentials) noexcept {
try {
return Ref<sqlgen::Connection>(Ref<Connection>::make(_credentials));
} catch (std::exception& e) {
return error(e.what());
}
}
typename Connection::ConnPtr Connection::make_conn(
const std::string& _conn_str) {
const auto raw_ptr = PQconnectdb(_conn_str.c_str());
if (PQstatus(raw_ptr) != CONNECTION_OK) {
const auto msg = std::string("Connection to postgres failed: ") +
PQerrorMessage(raw_ptr);
PQfinish(raw_ptr);
throw std::runtime_error(msg.c_str());
}
return ConnPtr::make(std::shared_ptr<PGconn>(raw_ptr, &PQfinish)).value();
}
} // namespace sqlgen::postgres

View File

@@ -0,0 +1,59 @@
#include "sqlgen/sqlite/Iterator.hpp"
#include <ranges>
#include <rfl.hpp>
#include <sstream>
#include "sqlgen/internal/collect/vector.hpp"
#include "sqlgen/internal/strings/strings.hpp"
#include "sqlgen/sqlite/Iterator.hpp"
namespace sqlgen::sqlite {
Iterator::Iterator(const StmtPtr& _stmt, const ConnPtr& _conn)
: end_(false),
rownum_(0),
num_cols_(sqlite3_column_count(_stmt.get())),
stmt_(_stmt),
conn_(_conn) {
step();
}
Iterator::~Iterator() = default;
bool Iterator::end() const { return end_; }
Result<std::vector<std::vector<std::optional<std::string>>>> Iterator::next(
const size_t _batch_size) {
if (end()) {
return error("End is reached.");
}
std::vector<std::vector<std::optional<std::string>>> batch;
for (size_t i = 0; i < _batch_size; ++i) {
std::vector<std::optional<std::string>> new_row;
for (int j = 0; j < num_cols_; ++j) {
auto ptr = sqlite3_column_text(stmt_.get(), j);
if (ptr) {
new_row.emplace_back(
std::string(std::launder(reinterpret_cast<const char*>(ptr))));
} else {
new_row.emplace_back(std::nullopt);
}
}
batch.emplace_back(std::move(new_row));
step();
if (end()) {
return batch;
}
}
return batch;
}
} // namespace sqlgen::sqlite