diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..53e4058 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "vcpkg"] + path = vcpkg + url = git@github.com:microsoft/vcpkg.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 103a97c..4a3c23d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,9 +5,13 @@ option(SQLGEN_BUILD_SHARED "Build shared library" ${BUILD_SHARED_LIBS}) option(SQLGEN_SQLITE3 "Enable sqlite3 support" ON) # enabled by default #option(SQLGEN_BUILD_BENCHMARKS "Build benchmarks" OFF) -#option(SQLGEN_BUILD_TESTS "Build tests" OFF) +option(SQLGEN_BUILD_TESTS "Build tests" OFF) set(CMAKE_CXX_STANDARD_REQUIRED ON) +if (NOT DEFINED CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 20) +endif() + set(SQLGEN_USE_VCPKG_DEFAULT ON) diff --git a/include/sqlgen/Connection.hpp b/include/sqlgen/Connection.hpp index f67f79a..2d946d1 100644 --- a/include/sqlgen/Connection.hpp +++ b/include/sqlgen/Connection.hpp @@ -23,7 +23,7 @@ struct Connection { /// Executes a statement. Note that in order for the statement to take effect, /// you must call .commit() afterwards. /// TODO: Abstract away the different statements using rfl::TaggedUnion. - virtual Result execute(const CreateTable& _stmt) = 0; + virtual Result execute(const dynamic::CreateTable& _stmt) = 0; /// Reads the results of a SelectFrom statement. virtual Result> read(const dynamic::SelectFrom& _query) = 0; diff --git a/include/sqlgen/PrimaryKey.hpp b/include/sqlgen/PrimaryKey.hpp index 295aaca..7708f78 100644 --- a/include/sqlgen/PrimaryKey.hpp +++ b/include/sqlgen/PrimaryKey.hpp @@ -26,38 +26,42 @@ struct PrimaryKey { template PrimaryKey(PrimaryKey&& _other) : value_(_other.get()) {} - template , - bool>::type = true> + template , + bool>::type = true> PrimaryKey(const U& _value) : value_(_value) {} - template , - bool>::type = true> + template , + bool>::type = true> PrimaryKey(U&& _value) noexcept : value_(std::forward(_value)) {} - template , - bool>::type = true> + template , + bool>::type = true> PrimaryKey(const PrimaryKey& _other) : value_(_other.value()) {} ~PrimaryKey() = default; /// Returns the underlying object. - const Type& get() const { return value_; } + const ReflectionType& get() const { return value_; } /// Returns the underlying object. - Type& operator()() { return value_; } + ReflectionType& operator()() { return value_; } /// Returns the underlying object. - const Type& operator()() const { return value_; } + const ReflectionType& operator()() const { return value_; } /// Assigns the underlying object. - auto& operator=(const Type& _value) { + auto& operator=(const ReflectionType& _value) { value_ = _value; return *this; } /// Assigns the underlying object. - template , - bool>::type = true> + template , + bool>::type = true> auto& operator=(const U& _value) { value_ = _value; return *this; diff --git a/include/sqlgen/dynamic/types.hpp b/include/sqlgen/dynamic/types.hpp index b979427..67c1f3a 100644 --- a/include/sqlgen/dynamic/types.hpp +++ b/include/sqlgen/dynamic/types.hpp @@ -44,6 +44,22 @@ struct Int64 { Properties properties; }; +struct UInt8 { + Properties properties; +}; + +struct UInt16 { + Properties properties; +}; + +struct UInt32 { + Properties properties; +}; + +struct UInt64 { + Properties properties; +}; + struct Text { Properties properties; }; diff --git a/include/sqlgen/parsing/get_tablename.hpp b/include/sqlgen/parsing/get_tablename.hpp index 89b628f..3018839 100644 --- a/include/sqlgen/parsing/get_tablename.hpp +++ b/include/sqlgen/parsing/get_tablename.hpp @@ -6,11 +6,11 @@ #include "has_tablename.hpp" -namespace rfl::parsing { +namespace sqlgen::parsing { namespace internal { -std::string remove_namespaces(const std::string& _str) { +inline std::string remove_namespaces(const std::string& _str) { const auto pos = _str.find_last_of(':'); if (pos == std::string::npos) { return _str; @@ -24,13 +24,13 @@ template std::string get_tablename() noexcept { using Type = std::remove_cvref_t; if constexpr (has_tablename) { - using LiteralType = typename Type::Tablename; - return remove_namespaces(LiteralType().str()); + using LiteralType = typename Type::tablename; + return internal::remove_namespaces(LiteralType().str()); } else { - return remove_namespaces(rfl::type_name_t().str()); + return internal::remove_namespaces(rfl::type_name_t().str()); } } -} // namespace rfl::parsing +} // namespace sqlgen::parsing #endif diff --git a/include/sqlgen/parsing/has_tablename.hpp b/include/sqlgen/parsing/has_tablename.hpp index 06f3234..200679e 100644 --- a/include/sqlgen/parsing/has_tablename.hpp +++ b/include/sqlgen/parsing/has_tablename.hpp @@ -7,7 +7,7 @@ namespace sqlgen::parsing { template concept has_tablename = requires() { - { typename T::Tablename() } -> std::same_as; + { typename T::tablename() } -> std::same_as; }; } // namespace sqlgen::parsing diff --git a/include/sqlgen/parsing/to_create_table.hpp b/include/sqlgen/parsing/to_create_table.hpp index 7879654..1053383 100644 --- a/include/sqlgen/parsing/to_create_table.hpp +++ b/include/sqlgen/parsing/to_create_table.hpp @@ -11,6 +11,7 @@ #include "../dynamic/CreateTable.hpp" #include "../dynamic/Table.hpp" #include "../dynamic/Type.hpp" +#include "../dynamic/types.hpp" #include "get_tablename.hpp" #include "has_reflection_method.hpp" #include "is_nullable.hpp" @@ -46,57 +47,57 @@ dynamic::Type to_type() { return to_type().visit(set_nullable); } - } else if constexpr (has_reflection_method_v) { + } else if constexpr (has_reflection_method) { return to_type(); } else if constexpr (std::is_same_v) { - return types::Boolean{}; + return dynamic::types::Boolean{}; } else if constexpr (std::is_integral_v && std::is_signed_v) { if constexpr (sizeof(T) == 1) { - return types::Int8{}; + return dynamic::types::Int8{}; } else if constexpr (sizeof(T) == 2) { - return types::Int16{}; + return dynamic::types::Int16{}; } else if constexpr (sizeof(T) == 4) { - return types::Int32{}; + return dynamic::types::Int32{}; } else if constexpr (sizeof(T) == 8) { - return types::Int64{}; + 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 types::UInt8{}; + return dynamic::types::UInt8{}; } else if constexpr (sizeof(T) == 2) { - return types::UInt16{}; + return dynamic::types::UInt16{}; } else if constexpr (sizeof(T) == 4) { - return types::UInt32{}; + return dynamic::types::UInt32{}; } else if constexpr (sizeof(T) == 8) { - return types::UInt64{}; + 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 types::Float32{}; + return dynamic::types::Float32{}; } else if constexpr (sizeof(T) == 8) { - return types::Float64{}; + return dynamic::types::Float64{}; } else { static_assert(rfl::always_false_v, "Unsupported floating point value."); } } else if constexpr (std::is_same_v) { - return types::Text{}; + return dynamic::types::Text{}; } } @@ -118,12 +119,12 @@ template requires std::is_class_v> && std::is_aggregate_v> dynamic::CreateTable to_create_table() { - using NamedTupleType = rfl::name_tuple_t>; + using NamedTupleType = rfl::named_tuple_t>; using Fields = typename NamedTupleType::Fields; return dynamic::CreateTable{ .table = dynamic::Table{.name = get_tablename()}, .columns = internal::make_columns( - std::make_integer_sequence>), + std::make_integer_sequence>()), .if_not_exists = true}; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..6ab3ad5 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,24 @@ +project(sqlgen-tests) + +file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS "*.cpp") + +add_executable( + sqlgen-tests + ${SOURCES} +) +target_precompile_headers(sqlgen-tests PRIVATE [["sqlgen.hpp"]] ) + +if (MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std:c++20") +else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wall -Werror -ggdb") +endif() + +target_link_libraries( + sqlgen-tests + PRIVATE + "${SQLGEN_GTEST_LIB}" +) + +find_package(GTest) +gtest_discover_tests(sqlgen-tests) diff --git a/tests/test_tablename.cpp b/tests/test_tablename.cpp new file mode 100644 index 0000000..36900c7 --- /dev/null +++ b/tests/test_tablename.cpp @@ -0,0 +1,22 @@ +#include + +#include +#include + +namespace test_tablename { + +struct TestTable { + using tablename = sqlgen::Literal<"TEST_TABLE">; + + std::string field1; + int32_t field2; + sqlgen::PrimaryKey id; + std::optional nullable; +}; + +TEST(general, test_tablename) { + const auto create_table_stmt = sqlgen::parsing::to_create_table(); + + EXPECT_EQ(create_table_stmt.table.name, "TEST_TABLE"); +} +} // namespace test_tablename diff --git a/tests/test_to_create_table.cpp b/tests/test_to_create_table.cpp new file mode 100644 index 0000000..a0356e2 --- /dev/null +++ b/tests/test_to_create_table.cpp @@ -0,0 +1,35 @@ +#include + +#include +#include + +TEST(general, test_to_create_table) { + struct TestTable { + std::string field1; + int32_t field2; + sqlgen::PrimaryKey id; + std::optional nullable; + }; + + const auto create_table_stmt = sqlgen::parsing::to_create_table(); + + const auto get_properties = [](const auto& _t) { return _t.properties; }; + + EXPECT_EQ(create_table_stmt.table.name, "TestTable"); + + EXPECT_EQ(create_table_stmt.columns.size(), 4); + + EXPECT_EQ(create_table_stmt.columns.at(0).name, "field1"); + EXPECT_EQ(create_table_stmt.columns.at(1).name, "field2"); + EXPECT_EQ(create_table_stmt.columns.at(2).name, "id"); + EXPECT_EQ(create_table_stmt.columns.at(3).name, "nullable"); + + EXPECT_EQ(create_table_stmt.columns.at(0).type.visit(get_properties).primary, + false); + EXPECT_EQ(create_table_stmt.columns.at(0).type.visit(get_properties).nullable, + false); + EXPECT_EQ(create_table_stmt.columns.at(2).type.visit(get_properties).primary, + true); + EXPECT_EQ(create_table_stmt.columns.at(3).type.visit(get_properties).nullable, + true); +} diff --git a/vcpkg b/vcpkg new file mode 160000 index 0000000..7354f1c --- /dev/null +++ b/vcpkg @@ -0,0 +1 @@ +Subproject commit 7354f1c8a0a276072e8d73d7eb6df6ca0ce8ccb1 diff --git a/vcpkg.json b/vcpkg.json index bb091b0..29196a9 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,5 +1,9 @@ { "dependencies": [ + { + "name": "gtest", + "version>=": "1.14.0" + }, { "name": "reflectcpp", "version>=": "0.18.0"