mirror of
https://github.com/getml/sqlgen.git
synced 2026-05-18 05:59:02 -05:00
Added to_sql
This commit is contained in:
@@ -2,7 +2,9 @@
|
||||
#define SQLGEN_HPP_
|
||||
|
||||
#include "sqlgen/Connection.hpp"
|
||||
#include "sqlgen/CreateTable.hpp"
|
||||
#include "sqlgen/Flatten.hpp"
|
||||
#include "sqlgen/Insert.hpp"
|
||||
#include "sqlgen/Iterator.hpp"
|
||||
#include "sqlgen/IteratorBase.hpp"
|
||||
#include "sqlgen/Literal.hpp"
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef SQLGEN_CREATETABLE_HPP_
|
||||
#define SQLGEN_CREATETABLE_HPP_
|
||||
|
||||
#include <rfl.hpp>
|
||||
|
||||
namespace sqlgen {
|
||||
|
||||
/// Helper class for to_sql.
|
||||
template <class T>
|
||||
struct CreateTable {};
|
||||
|
||||
}; // namespace sqlgen
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef SQLGEN_INSERT_HPP_
|
||||
#define SQLGEN_INSERT_HPP_
|
||||
|
||||
#include <rfl.hpp>
|
||||
|
||||
namespace sqlgen {
|
||||
|
||||
/// Helper class for to_sql.
|
||||
template <class T>
|
||||
struct Insert {};
|
||||
|
||||
}; // namespace sqlgen
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
#include "../sqlgen.hpp"
|
||||
#include "postgres/Credentials.hpp"
|
||||
#include "postgres/connect.hpp"
|
||||
#include "postgres/to_sql.hpp"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -41,11 +41,11 @@ class Connection : public sqlgen::Connection {
|
||||
Result<Ref<IteratorBase>> read(const dynamic::SelectFrom& _query) final;
|
||||
|
||||
std::string to_sql(const dynamic::Statement& _stmt) noexcept final {
|
||||
return postgres::to_sql(_stmt);
|
||||
return postgres::to_sql_impl(_stmt);
|
||||
}
|
||||
|
||||
Result<Nothing> start_write(const dynamic::Insert& _stmt) final {
|
||||
return execute(to_sql(_stmt));
|
||||
return execute(postgres::to_sql_impl(_stmt));
|
||||
}
|
||||
|
||||
Result<Nothing> end_write() final;
|
||||
|
||||
@@ -2,13 +2,25 @@
|
||||
#define SQLGEN_POSTGRES_TO_SQL_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "../dynamic/Statement.hpp"
|
||||
#include "../transpilation/to_sql.hpp"
|
||||
|
||||
namespace sqlgen::postgres {
|
||||
|
||||
/// Transpiles a dynamic general SQL statement to the postgres dialect.
|
||||
std::string to_sql(const dynamic::Statement& _stmt) noexcept;
|
||||
std::string to_sql_impl(const dynamic::Statement& _stmt) noexcept;
|
||||
|
||||
/// Transpiles any SQL statement to the postgres dialect.
|
||||
template <class T>
|
||||
std::string to_sql(const T& _t) noexcept {
|
||||
if constexpr (std::is_same_v<std::remove_cvref_t<T>, dynamic::Statement>) {
|
||||
return to_sql_impl(_t);
|
||||
} else {
|
||||
return to_sql_impl(transpilation::to_sql(_t));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sqlgen::postgres
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ class Connection : public sqlgen::Connection {
|
||||
Result<Ref<IteratorBase>> read(const dynamic::SelectFrom& _query) final;
|
||||
|
||||
std::string to_sql(const dynamic::Statement& _stmt) noexcept final {
|
||||
return sqlite::to_sql(_stmt);
|
||||
return sqlite::to_sql_impl(_stmt);
|
||||
}
|
||||
|
||||
Result<Nothing> start_write(const dynamic::Insert& _stmt) final;
|
||||
|
||||
@@ -4,11 +4,22 @@
|
||||
#include <string>
|
||||
|
||||
#include "../dynamic/Statement.hpp"
|
||||
#include "../transpilation/to_sql.hpp"
|
||||
|
||||
namespace sqlgen::sqlite {
|
||||
|
||||
/// Transpiles a dynamic general SQL statement to the sqlite dialect.
|
||||
std::string to_sql(const dynamic::Statement& _stmt) noexcept;
|
||||
std::string to_sql_impl(const dynamic::Statement& _stmt) noexcept;
|
||||
|
||||
/// Transpiles any SQL statement to the sqlite dialect.
|
||||
template <class T>
|
||||
std::string to_sql(const T& _t) noexcept {
|
||||
if constexpr (std::is_same_v<std::remove_cvref_t<T>, dynamic::Statement>) {
|
||||
return to_sql_impl(_t);
|
||||
} else {
|
||||
return to_sql_impl(transpilation::to_sql(_t));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sqlgen::sqlite
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef SQLGEN_TRANSPILATION_TO_SQL_HPP_
|
||||
#define SQLGEN_TRANSPILATION_TO_SQL_HPP_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "../CreateTable.hpp"
|
||||
#include "../Insert.hpp"
|
||||
#include "../dynamic/Statement.hpp"
|
||||
#include "../read.hpp"
|
||||
#include "to_create_table.hpp"
|
||||
#include "to_insert.hpp"
|
||||
#include "to_select_from.hpp"
|
||||
#include "value_t.hpp"
|
||||
|
||||
namespace sqlgen::transpilation {
|
||||
|
||||
template <class T>
|
||||
struct ToSQL;
|
||||
|
||||
template <class T>
|
||||
struct ToSQL<CreateTable<T>> {
|
||||
dynamic::Statement operator()(const auto&) const {
|
||||
return to_create_table<T>();
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct ToSQL<Insert<T>> {
|
||||
dynamic::Statement operator()(const auto&) const { return to_insert<T>(); }
|
||||
};
|
||||
|
||||
template <class ContainerType, class WhereType, class OrderByType,
|
||||
class LimitType>
|
||||
struct ToSQL<Read<ContainerType, WhereType, OrderByType, LimitType>> {
|
||||
dynamic::Statement operator()(const auto& _read) const {
|
||||
return to_select_from<value_t<ContainerType>, WhereType, OrderByType,
|
||||
LimitType>(_read.where_, _read.limit_);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
dynamic::Statement to_sql(const T& _t) {
|
||||
return ToSQL<std::remove_cvref_t<T>>{}(_t);
|
||||
}
|
||||
|
||||
} // namespace sqlgen::transpilation
|
||||
|
||||
#endif
|
||||
@@ -46,7 +46,7 @@ typename Connection::ConnPtr Connection::make_conn(
|
||||
}
|
||||
|
||||
Result<Ref<IteratorBase>> Connection::read(const dynamic::SelectFrom& _query) {
|
||||
const auto sql = postgres::to_sql(_query);
|
||||
const auto sql = postgres::to_sql_impl(_query);
|
||||
try {
|
||||
return Ref<IteratorBase>(Ref<Iterator>::make(sql, conn_));
|
||||
} catch (std::exception& e) {
|
||||
|
||||
@@ -223,7 +223,7 @@ std::string select_from_to_sql(const dynamic::SelectFrom& _stmt) noexcept {
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
std::string to_sql(const dynamic::Statement& _stmt) noexcept {
|
||||
std::string to_sql_impl(const dynamic::Statement& _stmt) noexcept {
|
||||
return _stmt.visit([&](const auto& _s) -> std::string {
|
||||
using S = std::remove_cvref_t<decltype(_s)>;
|
||||
if constexpr (std::is_same_v<S, dynamic::CreateTable>) {
|
||||
|
||||
@@ -42,7 +42,7 @@ typename Connection::ConnPtr Connection::make_conn(const std::string& _fname) {
|
||||
}
|
||||
|
||||
Result<Ref<IteratorBase>> Connection::read(const dynamic::SelectFrom& _query) {
|
||||
const auto sql = to_sql(_query);
|
||||
const auto sql = to_sql_impl(_query);
|
||||
|
||||
sqlite3_stmt* p_stmt = nullptr;
|
||||
|
||||
@@ -70,7 +70,7 @@ Result<Nothing> Connection::start_write(const dynamic::Insert& _stmt) {
|
||||
".end_write() before you can start another.");
|
||||
}
|
||||
|
||||
const auto sql = to_sql(_stmt);
|
||||
const auto sql = to_sql_impl(_stmt);
|
||||
|
||||
sqlite3_stmt* p_stmt = nullptr;
|
||||
|
||||
|
||||
@@ -210,7 +210,7 @@ std::string select_from_to_sql(const dynamic::SelectFrom& _stmt) noexcept {
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
std::string to_sql(const dynamic::Statement& _stmt) noexcept {
|
||||
std::string to_sql_impl(const dynamic::Statement& _stmt) noexcept {
|
||||
return _stmt.visit([&](const auto& _s) -> std::string {
|
||||
using S = std::remove_cvref_t<decltype(_s)>;
|
||||
if constexpr (std::is_same_v<S, dynamic::CreateTable>) {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <sqlgen.hpp>
|
||||
#include <sqlgen/postgres.hpp>
|
||||
|
||||
namespace test_create_table_dry {
|
||||
|
||||
struct TestTable {
|
||||
std::string field1;
|
||||
int32_t field2;
|
||||
sqlgen::PrimaryKey<uint32_t> id;
|
||||
std::optional<std::string> nullable;
|
||||
};
|
||||
|
||||
TEST(postgres, test_create_table_dry) {
|
||||
const auto query = sqlgen::CreateTable<TestTable>{};
|
||||
|
||||
const auto expected =
|
||||
R"(CREATE TABLE IF NOT EXISTS "TestTable" ("field1" TEXT NOT NULL, "field2" INTEGER NOT NULL, "id" INTEGER NOT NULL, "nullable" TEXT, PRIMARY KEY ("id"));)";
|
||||
|
||||
EXPECT_EQ(sqlgen::postgres::to_sql(query), expected);
|
||||
}
|
||||
} // namespace test_create_table_dry
|
||||
@@ -0,0 +1,24 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <sqlgen.hpp>
|
||||
#include <sqlgen/postgres.hpp>
|
||||
|
||||
namespace test_insert_dry {
|
||||
|
||||
struct TestTable {
|
||||
std::string field1;
|
||||
int32_t field2;
|
||||
sqlgen::PrimaryKey<uint32_t> id;
|
||||
std::optional<std::string> nullable;
|
||||
};
|
||||
|
||||
TEST(postgres, test_insert_dry) {
|
||||
const auto query = sqlgen::Insert<TestTable>{};
|
||||
|
||||
const auto expected =
|
||||
"COPY \"public\".\"TestTable\"(\"field1\", \"field2\", \"id\", "
|
||||
"\"nullable\") FROM STDIN WITH DELIMITER '\t' NULL '\e' QUOTE '\a';";
|
||||
|
||||
EXPECT_EQ(sqlgen::postgres::to_sql(query), expected);
|
||||
}
|
||||
} // namespace test_insert_dry
|
||||
@@ -1,30 +0,0 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <sqlgen.hpp>
|
||||
#include <sqlgen/postgres.hpp>
|
||||
#include <sqlgen/transpilation/to_select_from.hpp>
|
||||
|
||||
namespace test_to_select_from {
|
||||
|
||||
struct TestTable {
|
||||
std::string field1;
|
||||
int32_t field2;
|
||||
sqlgen::PrimaryKey<uint32_t> id;
|
||||
std::optional<std::string> nullable;
|
||||
};
|
||||
|
||||
TEST(postgres, test_to_select_from) {
|
||||
const auto select_from_stmt =
|
||||
sqlgen::transpilation::to_select_from<TestTable>();
|
||||
const auto credentials = sqlgen::postgres::Credentials{.user = "postgres",
|
||||
.password = "postgres",
|
||||
.host = "localhost",
|
||||
.dbname = "postgres",
|
||||
.port = 5432};
|
||||
const auto conn = sqlgen::postgres::connect(credentials).value();
|
||||
const auto expected =
|
||||
R"(SELECT "field1", "field2", "id", "nullable" FROM "TestTable";)";
|
||||
|
||||
EXPECT_EQ(conn->to_sql(select_from_stmt), expected);
|
||||
}
|
||||
} // namespace test_to_select_from
|
||||
@@ -0,0 +1,24 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <sqlgen.hpp>
|
||||
#include <sqlgen/postgres.hpp>
|
||||
#include <sqlgen/transpilation/to_select_from.hpp>
|
||||
|
||||
namespace test_to_select_from_dry {
|
||||
|
||||
struct TestTable {
|
||||
std::string field1;
|
||||
int32_t field2;
|
||||
sqlgen::PrimaryKey<uint32_t> id;
|
||||
std::optional<std::string> nullable;
|
||||
};
|
||||
|
||||
TEST(postgres, test_to_select_from_dry) {
|
||||
const auto query = sqlgen::read<std::vector<TestTable>>;
|
||||
|
||||
const auto expected =
|
||||
R"(SELECT "field1", "field2", "id", "nullable" FROM "TestTable";)";
|
||||
|
||||
EXPECT_EQ(sqlgen::postgres::to_sql(query), expected);
|
||||
}
|
||||
} // namespace test_to_select_from_dry
|
||||
@@ -0,0 +1,29 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <sqlgen.hpp>
|
||||
#include <sqlgen/postgres.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace test_where_dry {
|
||||
|
||||
struct Person {
|
||||
sqlgen::PrimaryKey<uint32_t> id;
|
||||
std::string first_name;
|
||||
std::string last_name;
|
||||
int age;
|
||||
};
|
||||
|
||||
TEST(postgres, test_where_dry) {
|
||||
using namespace sqlgen;
|
||||
|
||||
const auto query = sqlgen::read<std::vector<Person>> |
|
||||
where("age"_c < 18 and "first_name"_c != "Hugo") |
|
||||
order_by("age"_c);
|
||||
|
||||
const auto expected =
|
||||
R"(SELECT "id", "first_name", "last_name", "age" FROM "Person" WHERE ("age" < 18) AND ("first_name" != 'Hugo') ORDER BY "age";)";
|
||||
|
||||
EXPECT_EQ(sqlgen::postgres::to_sql(query), expected);
|
||||
}
|
||||
|
||||
} // namespace test_where_dry
|
||||
Reference in New Issue
Block a user