Added more formal support for create table

This commit is contained in:
Dr. Patrick Urbanke
2025-05-18 14:47:30 +02:00
parent 417463a020
commit b7598c55a6
11 changed files with 111 additions and 24 deletions

View File

@@ -103,14 +103,14 @@ if (PROJECT_IS_TOP_LEVEL)
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/sqlgen"
)
file(GLOB_RECURSE RFL_HEADERS RELATIVE ${CMAKE_CURRENT_LIST_DIR} "${CMAKE_CURRENT_LIST_DIR}/include/*" )
file(GLOB_RECURSE SQLGEN_HEADERS RELATIVE ${CMAKE_CURRENT_LIST_DIR} "${CMAKE_CURRENT_LIST_DIR}/include/*" )
target_sources(sqlgen
PUBLIC
FILE_SET sqlgen_headers
TYPE HEADERS
BASE_DIRS $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
FILES ${RFL_HEADERS})
FILES ${SQLGEN_HEADERS})
install(
TARGETS sqlgen

View File

@@ -14,6 +14,7 @@ Welcome to the sqlgen documentation. This guide provides detailed information ab
- [sqlgen::read](reading.md) - How to read data from a database
- [sqlgen::write](writing.md) - How to write data to a database
- [sqlgen::create_table](create_table.md) - How to create a new table
- [sqlgen::update](update.md) - How to update data in a table
- [sqlgen::delete_from](delete_from.md) - How to delete data from a table
- [sqlgen::drop](drop.md) - How to drop a table
@@ -30,4 +31,4 @@ Welcome to the sqlgen documentation. This guide provides detailed information ab
- [PostgreSQL](postgres.md) - How to interact with PostgreSQL and compatible databases (Redshift, Aurora, Greenplum)
- [SQLite](sqlite.md) - How to interact with SQLite3
For installation instructions, quick start guide, and usage examples, please refer to the [main README](../README.md).
For installation instructions, quick start guide, and usage examples, please refer to the [main README](../README.md).

View File

@@ -91,7 +91,7 @@ struct TestTable {
};
// Create table query
const auto create_query = sqlgen::CreateTable<TestTable>{};
const auto create_query = create_table<TestTable> | if_not_exists;
const auto sql = postgres::to_sql(create_query);
```

View File

@@ -2,7 +2,6 @@
#define SQLGEN_HPP_
#include "sqlgen/Connection.hpp"
#include "sqlgen/CreateTable.hpp"
#include "sqlgen/Flatten.hpp"
#include "sqlgen/Insert.hpp"
#include "sqlgen/Iterator.hpp"
@@ -18,9 +17,11 @@
#include "sqlgen/begin_transaction.hpp"
#include "sqlgen/col.hpp"
#include "sqlgen/commit.hpp"
#include "sqlgen/create_table.hpp"
#include "sqlgen/delete_from.hpp"
#include "sqlgen/drop.hpp"
#include "sqlgen/if_exists.hpp"
#include "sqlgen/if_not_exists.hpp"
#include "sqlgen/limit.hpp"
#include "sqlgen/order_by.hpp"
#include "sqlgen/patterns.hpp"

View File

@@ -1,15 +0,0 @@
#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

View File

@@ -0,0 +1,46 @@
#ifndef SQLGEN_CREATETABLE_HPP_
#define SQLGEN_CREATETABLE_HPP_
#include <rfl.hpp>
#include "transpilation/to_create_table.hpp"
namespace sqlgen {
template <class ValueType>
Result<Ref<Connection>> create_table_impl(const Ref<Connection>& _conn,
const bool _if_not_exists) {
const auto query = transpilation::to_create_table<ValueType>(_if_not_exists);
return _conn->execute(_conn->to_sql(query)).transform([&](const auto&) {
return _conn;
});
}
template <class ValueType>
Result<Ref<Connection>> create_table_impl(const Result<Ref<Connection>>& _res,
const bool _if_not_exists) {
return _res.and_then([&](const auto& _conn) {
return create_table_impl<ValueType>(_conn, _if_not_exists);
});
}
template <class ValueType>
struct CreateTable {
Result<Ref<Connection>> operator()(const auto& _conn) const noexcept {
try {
return create_table_impl<ValueType>(_conn, if_not_exists_);
} catch (std::exception& e) {
return error(e.what());
}
}
bool if_not_exists_;
};
template <class ContainerType>
const auto create_table = CreateTable<ContainerType>{};
}; // namespace sqlgen
#endif

View File

@@ -0,0 +1,19 @@
#ifndef SQLGEN_IF_NOT_EXISTS_HPP_
#define SQLGEN_IF_NOT_EXISTS_HPP_
namespace sqlgen {
struct IfNotExists {};
template <class OtherType>
auto operator|(const OtherType& _o, const IfNotExists&) {
auto o = _o;
o.if_not_exists_ = true;
return o;
}
inline const auto if_not_exists = IfNotExists{};
} // namespace sqlgen
#endif

View File

@@ -18,7 +18,7 @@ namespace sqlgen::transpilation {
template <class T>
requires std::is_class_v<std::remove_cvref_t<T>> &&
std::is_aggregate_v<std::remove_cvref_t<T>>
dynamic::CreateTable to_create_table() {
dynamic::CreateTable to_create_table(const bool _if_not_exists = true) {
using NamedTupleType = rfl::named_tuple_t<std::remove_cvref_t<T>>;
using Fields = typename NamedTupleType::Fields;
return dynamic::CreateTable{
@@ -26,7 +26,7 @@ dynamic::CreateTable to_create_table() {
dynamic::Table{.name = get_tablename<T>(), .schema = get_schema<T>()},
.columns = make_columns<Fields>(
std::make_integer_sequence<int, rfl::tuple_size_v<Fields>>()),
.if_not_exists = true};
.if_not_exists = _if_not_exists};
}
} // namespace sqlgen::transpilation

View File

@@ -3,8 +3,8 @@
#include <vector>
#include "../CreateTable.hpp"
#include "../Insert.hpp"
#include "../create_table.hpp"
#include "../delete_from.hpp"
#include "../drop.hpp"
#include "../dynamic/Statement.hpp"

View File

@@ -1,5 +1,6 @@
@PACKAGE_INIT@
set(SQLGEN_POSTGRES @SQLGEN_POSTGRES@)
set(SQLGEN_SQLITE3 @SQLGEN_SQLITE3@)
include(CMakeFindDependencyMacro)
@@ -8,8 +9,12 @@ include(${CMAKE_CURRENT_LIST_DIR}/sqlgen-exports.cmake)
find_dependency(reflectcpp)
if(SQLGEN_POSTGRES)
find_dependency(PostgreSQL)
endif()
if(SQLGEN_SQLITE3)
find_dependency(sqlite3)
find_dependency(unofficial-sqlite3)
endif()
check_required_components(sqlgen)

View File

@@ -0,0 +1,30 @@
#include <gtest/gtest.h>
#include <rfl.hpp>
#include <rfl/json.hpp>
#include <sqlgen.hpp>
#include <sqlgen/sqlite.hpp>
#include <vector>
namespace test_create_table {
struct Person {
sqlgen::PrimaryKey<uint32_t> id;
std::string first_name;
std::string last_name;
int age;
};
TEST(sqlite, test_create_table) {
using namespace sqlgen;
const auto people = sqlgen::sqlite::connect()
.and_then(create_table<Person> | if_not_exists)
.and_then(sqlgen::read<std::vector<Person>>);
const std::string expected = R"([])";
EXPECT_EQ(rfl::json::write(people), expected);
}
} // namespace test_create_table