diff --git a/include/sqlgen/internal/collect.hpp b/include/sqlgen/internal/collect.hpp deleted file mode 100644 index f9d25c0..0000000 --- a/include/sqlgen/internal/collect.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef SQLGEN_INTERNAL_COLLECT_HPP_ -#define SQLGEN_INTERNAL_COLLECT_HPP_ - -namespace sqlgen::internal::collect {} - -#endif diff --git a/include/sqlgen/parsing/make_columns.hpp b/include/sqlgen/parsing/make_columns.hpp new file mode 100644 index 0000000..d7dd9e4 --- /dev/null +++ b/include/sqlgen/parsing/make_columns.hpp @@ -0,0 +1,111 @@ +#ifndef SQLGEN_PARSING_MAKE_COLUMNS_HPP_ +#define SQLGEN_PARSING_MAKE_COLUMNS_HPP_ + +#include +#include +#include + +#include "../dynamic/Column.hpp" +#include "../dynamic/Type.hpp" +#include "../dynamic/types.hpp" +#include "has_reflection_method.hpp" +#include "is_nullable.hpp" +#include "is_primary_key.hpp" + +namespace sqlgen::parsing { + +template +std::string to_colname() { + return Name().str(); +} + +template +dynamic::Type to_type() { + using T = std::remove_cvref_t; + if constexpr (is_primary_key_v) { + return to_type().visit( + [](auto _t) -> dynamic::Type { + _t.properties.primary = true; + return _t; + }); + + } else if constexpr (is_nullable_v) { + const auto set_nullable = [](auto _t) -> dynamic::Type { + _t.properties.nullable = true; + return _t; + }; + if constexpr (is_ptr::value) { + return to_type().visit(set_nullable); + } else { + return to_type().visit(set_nullable); + } + + } else if constexpr (has_reflection_method) { + return to_type(); + + } else if constexpr (std::is_same_v) { + return dynamic::types::Boolean{}; + + } else if constexpr (std::is_integral_v && std::is_signed_v) { + if constexpr (sizeof(T) == 1) { + return dynamic::types::Int8{}; + + } else if constexpr (sizeof(T) == 2) { + return dynamic::types::Int16{}; + + } else if constexpr (sizeof(T) == 4) { + return dynamic::types::Int32{}; + + } else if constexpr (sizeof(T) == 8) { + return dynamic::types::Int64{}; + + } else { + static_assert(rfl::always_false_v, "Unsupported signed integer."); + } + } else if constexpr (std::is_integral_v && !std::is_signed_v) { + if constexpr (sizeof(T) == 1) { + return dynamic::types::UInt8{}; + + } else if constexpr (sizeof(T) == 2) { + return dynamic::types::UInt16{}; + + } else if constexpr (sizeof(T) == 4) { + return dynamic::types::UInt32{}; + + } else if constexpr (sizeof(T) == 8) { + return dynamic::types::UInt64{}; + + } else { + static_assert(rfl::always_false_v, "Unsupported unsigned integer."); + } + } else if constexpr (std::is_floating_point_v) { + if constexpr (sizeof(T) == 4) { + return dynamic::types::Float32{}; + + } else if constexpr (sizeof(T) == 8) { + return dynamic::types::Float64{}; + + } else { + static_assert(rfl::always_false_v, + "Unsupported floating point value."); + } + } else if constexpr (std::is_same_v) { + return dynamic::types::Text{}; + } +} + +template +dynamic::Column to_column() { + return dynamic::Column{.name = to_colname(), + .type = to_type()}; +} + +template +std::vector make_columns(std::integer_sequence) { + return std::vector( + {to_column>()...}); +} + +} // namespace sqlgen::parsing + +#endif diff --git a/include/sqlgen/parsing/to_create_table.hpp b/include/sqlgen/parsing/to_create_table.hpp index 0bce577..a21a55b 100644 --- a/include/sqlgen/parsing/to_create_table.hpp +++ b/include/sqlgen/parsing/to_create_table.hpp @@ -7,115 +7,14 @@ #include #include -#include "../dynamic/Column.hpp" #include "../dynamic/CreateTable.hpp" #include "../dynamic/Table.hpp" -#include "../dynamic/Type.hpp" -#include "../dynamic/types.hpp" #include "get_schema.hpp" #include "get_tablename.hpp" -#include "has_reflection_method.hpp" -#include "is_nullable.hpp" -#include "is_primary_key.hpp" +#include "make_columns.hpp" namespace sqlgen::parsing { -namespace internal { - -template -std::string to_colname() { - return Name().str(); -} - -template -dynamic::Type to_type() { - using T = std::remove_cvref_t; - if constexpr (is_primary_key_v) { - return to_type().visit( - [](auto _t) -> dynamic::Type { - _t.properties.primary = true; - return _t; - }); - - } else if constexpr (is_nullable_v) { - const auto set_nullable = [](auto _t) -> dynamic::Type { - _t.properties.nullable = true; - return _t; - }; - if constexpr (is_ptr::value) { - return to_type().visit(set_nullable); - } else { - return to_type().visit(set_nullable); - } - - } else if constexpr (has_reflection_method) { - return to_type(); - - } else if constexpr (std::is_same_v) { - return dynamic::types::Boolean{}; - - } else if constexpr (std::is_integral_v && std::is_signed_v) { - if constexpr (sizeof(T) == 1) { - return dynamic::types::Int8{}; - - } else if constexpr (sizeof(T) == 2) { - return dynamic::types::Int16{}; - - } else if constexpr (sizeof(T) == 4) { - return dynamic::types::Int32{}; - - } else if constexpr (sizeof(T) == 8) { - return dynamic::types::Int64{}; - - } else { - static_assert(rfl::always_false_v, "Unsupported signed integer."); - } - } else if constexpr (std::is_integral_v && !std::is_signed_v) { - if constexpr (sizeof(T) == 1) { - return dynamic::types::UInt8{}; - - } else if constexpr (sizeof(T) == 2) { - return dynamic::types::UInt16{}; - - } else if constexpr (sizeof(T) == 4) { - return dynamic::types::UInt32{}; - - } else if constexpr (sizeof(T) == 8) { - return dynamic::types::UInt64{}; - - } else { - static_assert(rfl::always_false_v, "Unsupported unsigned integer."); - } - } else if constexpr (std::is_floating_point_v) { - if constexpr (sizeof(T) == 4) { - return dynamic::types::Float32{}; - - } else if constexpr (sizeof(T) == 8) { - return dynamic::types::Float64{}; - - } else { - static_assert(rfl::always_false_v, - "Unsupported floating point value."); - } - } else if constexpr (std::is_same_v) { - return dynamic::types::Text{}; - } -} - -template -dynamic::Column to_column() { - return dynamic::Column{.name = to_colname(), - .type = to_type()}; -} - -template -std::vector make_columns(std::integer_sequence) { - return std::vector( - {to_column>()...}); -} - -} // namespace internal - template requires std::is_class_v> && std::is_aggregate_v> @@ -125,7 +24,7 @@ dynamic::CreateTable to_create_table() { return dynamic::CreateTable{ .table = dynamic::Table{.name = get_tablename(), .schema = get_schema()}, - .columns = internal::make_columns( + .columns = make_columns( std::make_integer_sequence>()), .if_not_exists = true}; } diff --git a/include/sqlgen/parsing/to_insert.hpp b/include/sqlgen/parsing/to_insert.hpp new file mode 100644 index 0000000..b1b36f3 --- /dev/null +++ b/include/sqlgen/parsing/to_insert.hpp @@ -0,0 +1,42 @@ +#ifndef SQLGEN_PARSING_TO_INSERT_HPP_ +#define SQLGEN_PARSING_TO_INSERT_HPP_ + +#include +#include +#include +#include +#include +#include + +#include "../dynamic/Insert.hpp" +#include "../dynamic/Table.hpp" +#include "../internal/collect/vector.hpp" +#include "get_schema.hpp" +#include "get_tablename.hpp" +#include "make_columns.hpp" + +namespace sqlgen::parsing { + +template + requires std::is_class_v> && + std::is_aggregate_v> +dynamic::Insert to_insert() { + using namespace std::ranges::views; + + using NamedTupleType = rfl::named_tuple_t>; + using Fields = typename NamedTupleType::Fields; + + const auto columns = make_columns( + std::make_integer_sequence>()); + + const auto get_name = [](const auto& _col) { return _col.name; }; + + return dynamic::Insert{.table = dynamic::Table{.name = get_tablename(), + .schema = get_schema()}, + .columns = sqlgen::internal::collect::vector( + columns | transform(get_name))}; +} + +} // namespace sqlgen::parsing + +#endif diff --git a/tests/test_to_insert.cpp b/tests/test_to_insert.cpp new file mode 100644 index 0000000..b772c9e --- /dev/null +++ b/tests/test_to_insert.cpp @@ -0,0 +1,26 @@ +#include + +#include +#include +#include + +namespace test_to_insert { + +struct TestTable { + std::string field1; + int32_t field2; + sqlgen::PrimaryKey id; + std::optional nullable; +}; + +TEST(general, test_to_insert) { + const auto insert_stmt = sqlgen::parsing::to_insert(); + + const std::string expected = + R"({"table":{"name":"TestTable"},"columns":["field1","field2","id","nullable"]})"; + + const auto json_str = rfl::json::write(insert_stmt); + + EXPECT_EQ(json_str, expected); +} +} // namespace test_to_insert