From 4942aeadd03a235f1df4efe15e5b78c39e0c2c2c Mon Sep 17 00:00:00 2001 From: "Dr. Patrick Urbanke" Date: Fri, 25 Apr 2025 04:38:32 +0200 Subject: [PATCH] Implemented insert and execute --- include/sqlgen/postgres/Connection.hpp | 12 ++++- src/sqlgen/postgres/Connection.cpp | 61 ++++++++++++++++---------- 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/include/sqlgen/postgres/Connection.hpp b/include/sqlgen/postgres/Connection.hpp index efb64e6..8865aaf 100644 --- a/include/sqlgen/postgres/Connection.hpp +++ b/include/sqlgen/postgres/Connection.hpp @@ -33,7 +33,7 @@ class Connection : public sqlgen::Connection { Result commit() final { return execute("COMMIT;"); } Result execute(const std::string& _sql) noexcept final { - return error("TODO"); + return exec(_sql).transform([](auto&&) { return Nothing{}; }); } Result> read(const dynamic::SelectFrom& _query) final { @@ -63,9 +63,15 @@ class Connection : public sqlgen::Connection { std::string create_table_to_sql( const dynamic::CreateTable& _stmt) const noexcept; + Result> exec(const std::string& _sql) const noexcept; + + static std::string get_name(const dynamic::Column& _col) { return _col.name; } + std::vector get_primary_keys( const dynamic::CreateTable& _stmt) const noexcept; + std::string insert_to_sql(const dynamic::Insert& _stmt) const noexcept; + static ConnPtr make_conn(const std::string& _conn_str); std::string select_from_to_sql( @@ -73,6 +79,10 @@ class Connection : public sqlgen::Connection { std::string type_to_sql(const dynamic::Type& _type) const noexcept; + static std::string wrap_in_quotes(const std::string& _name) noexcept { + return "\"" + _name + "\""; + } + private: ConnPtr conn_; diff --git a/src/sqlgen/postgres/Connection.cpp b/src/sqlgen/postgres/Connection.cpp index 35fb606..4200351 100644 --- a/src/sqlgen/postgres/Connection.cpp +++ b/src/sqlgen/postgres/Connection.cpp @@ -17,7 +17,7 @@ std::string Connection::add_not_null_if_necessary( std::string Connection::column_to_sql_definition( const dynamic::Column& _col) const noexcept { - return "\"" + _col.name + "\"" + " " + type_to_sql(_col.type) + + return wrap_in_quotes(_col.name) + " " + type_to_sql(_col.type) + add_not_null_if_necessary( _col.type.visit([](const auto& _t) { return _t.properties; })); } @@ -38,9 +38,9 @@ std::string Connection::create_table_to_sql( } if (_stmt.table.schema) { - stream << "\"" << *_stmt.table.schema << "\"."; + stream << wrap_in_quotes(*_stmt.table.schema) << "."; } - stream << "\"" << _stmt.table.name << "\" "; + stream << wrap_in_quotes(_stmt.table.name) << " "; stream << "("; stream << internal::strings::join( @@ -58,6 +58,23 @@ std::string Connection::create_table_to_sql( return stream.str(); } +Result> Connection::exec(const std::string& _sql) const noexcept { + const auto res = PQexec(conn_.get(), _sql.c_str()); + + const auto status = PQresultStatus(res); + + if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK && + status != PGRES_COPY_IN) { + const auto err = error(PQresultErrorMessage(res)); + PQclear(res); + return err; + } + + PQclear(res); + + return Ref::make(std::shared_ptr(res, PQclear)); +} + std::vector Connection::get_primary_keys( const dynamic::CreateTable& _stmt) const noexcept { using namespace std::ranges::views; @@ -67,17 +84,23 @@ std::vector Connection::get_primary_keys( [](const auto& _t) -> bool { return _t.properties.primary; }); }; - const auto get_name = [](const auto& _col) { return _col.name; }; - - const auto wrap_in_quotes = [](const std::string& _name) -> std::string { - return "\"" + _name + "\""; - }; - return internal::collect::vector(_stmt.columns | filter(is_primary_key) | transform(get_name) | transform(wrap_in_quotes)); } +std::string Connection::insert_to_sql( + const dynamic::Insert& _stmt) const noexcept { + using namespace std::ranges::views; + const auto schema = wrap_in_quotes(_stmt.table.schema.value_or("public")); + const auto table = wrap_in_quotes(_stmt.table.name); + const auto colnames = internal::strings::join( + ", ", + internal::collect::vector(_stmt.columns | transform(wrap_in_quotes))); + return "COPY " + schema + "." + table + "(" + colnames + + ") FROM STDIN WITH DELIMITER '\t' NULL '\e' QUOTE '\a';"; +} + rfl::Result> Connection::make( const Credentials& _credentials) noexcept { try { @@ -105,20 +128,16 @@ std::string Connection::select_from_to_sql( const dynamic::SelectFrom& _stmt) const noexcept { using namespace std::ranges::views; - const auto to_str = [](const auto& _col) -> std::string { - return "\"" + _col.name + "\""; - }; - std::stringstream stream; stream << "SELECT "; stream << internal::strings::join( - ", ", internal::collect::vector(_stmt.columns | transform(to_str))); - + ", ", internal::collect::vector(_stmt.columns | transform(get_name) | + transform(wrap_in_quotes))); stream << " FROM "; if (_stmt.table.schema) { - stream << "\"" << *_stmt.table.schema << "\"."; + stream << wrap_in_quotes(*_stmt.table.schema) << "."; } - stream << "\"" << _stmt.table.name << "\";"; + stream << wrap_in_quotes(_stmt.table.name) << ";"; return stream.str(); } @@ -128,14 +147,12 @@ std::string Connection::to_sql(const dynamic::Statement& _stmt) noexcept { using S = std::remove_cvref_t; if constexpr (std::is_same_v) { return create_table_to_sql(_s); - /*} else if constexpr (std::is_same_v) { - return insert_to_sql(_s); - } else*/ + } else if constexpr (std::is_same_v) { + return insert_to_sql(_s); } else if constexpr (std::is_same_v) { return select_from_to_sql(_s); } else { - return "TODO"; - // static_assert(rfl::always_false_v, "Unsupported type."); + static_assert(rfl::always_false_v, "Unsupported type."); } }); }