mirror of
https://github.com/getml/sqlgen.git
synced 2025-12-30 22:20:31 -06:00
Added tests
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "vcpkg"]
|
||||
path = vcpkg
|
||||
url = git@github.com:microsoft/vcpkg.git
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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<Nothing> execute(const CreateTable& _stmt) = 0;
|
||||
virtual Result<Nothing> execute(const dynamic::CreateTable& _stmt) = 0;
|
||||
|
||||
/// Reads the results of a SelectFrom statement.
|
||||
virtual Result<Ref<Iterator>> read(const dynamic::SelectFrom& _query) = 0;
|
||||
|
||||
@@ -26,38 +26,42 @@ struct PrimaryKey {
|
||||
template <class U>
|
||||
PrimaryKey(PrimaryKey<U>&& _other) : value_(_other.get()) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, ReflectionType>,
|
||||
bool>::type = true>
|
||||
PrimaryKey(const U& _value) : value_(_value) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, ReflectionType>,
|
||||
bool>::type = true>
|
||||
PrimaryKey(U&& _value) noexcept : value_(std::forward<U>(_value)) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, ReflectionType>,
|
||||
bool>::type = true>
|
||||
PrimaryKey(const PrimaryKey<U>& _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 <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, ReflectionType>,
|
||||
bool>::type = true>
|
||||
auto& operator=(const U& _value) {
|
||||
value_ = _value;
|
||||
return *this;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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 <class T>
|
||||
std::string get_tablename() noexcept {
|
||||
using Type = std::remove_cvref_t<T>;
|
||||
if constexpr (has_tablename<Type>) {
|
||||
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<Type>().str());
|
||||
return internal::remove_namespaces(rfl::type_name_t<Type>().str());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rfl::parsing
|
||||
} // namespace sqlgen::parsing
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace sqlgen::parsing {
|
||||
|
||||
template <typename T>
|
||||
concept has_tablename = requires() {
|
||||
{ typename T::Tablename() } -> std::same_as<typename T::Tablename>;
|
||||
{ typename T::tablename() } -> std::same_as<typename T::tablename>;
|
||||
};
|
||||
|
||||
} // namespace sqlgen::parsing
|
||||
|
||||
@@ -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<typename T::value_type>().visit(set_nullable);
|
||||
}
|
||||
|
||||
} else if constexpr (has_reflection_method_v<T>) {
|
||||
} else if constexpr (has_reflection_method<T>) {
|
||||
return to_type<typename Type::ReflectionType>();
|
||||
|
||||
} else if constexpr (std::is_same_v<T, bool>) {
|
||||
return types::Boolean{};
|
||||
return dynamic::types::Boolean{};
|
||||
|
||||
} else if constexpr (std::is_integral_v<T> && std::is_signed_v<T>) {
|
||||
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<T>, "Unsupported signed integer.");
|
||||
}
|
||||
} else if constexpr (std::is_integral_v<T> && !std::is_signed_v<T>) {
|
||||
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<T>, "Unsupported unsigned integer.");
|
||||
}
|
||||
} else if constexpr (std::is_floating_point_v<T>) {
|
||||
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<T>,
|
||||
"Unsupported floating point value.");
|
||||
}
|
||||
} else if constexpr (std::is_same_v<T, std::string>) {
|
||||
return types::Text{};
|
||||
return dynamic::types::Text{};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,12 +119,12 @@ 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() {
|
||||
using NamedTupleType = rfl::name_tuple_t<std::remove_cvref_t<T>>;
|
||||
using NamedTupleType = rfl::named_tuple_t<std::remove_cvref_t<T>>;
|
||||
using Fields = typename NamedTupleType::Fields;
|
||||
return dynamic::CreateTable{
|
||||
.table = dynamic::Table{.name = get_tablename<T>()},
|
||||
.columns = internal::make_columns<Fields>(
|
||||
std::make_integer_sequence<int, rfl::tuple_size_v<Fields>>),
|
||||
std::make_integer_sequence<int, rfl::tuple_size_v<Fields>>()),
|
||||
.if_not_exists = true};
|
||||
}
|
||||
|
||||
|
||||
24
tests/CMakeLists.txt
Normal file
24
tests/CMakeLists.txt
Normal file
@@ -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"]] <iostream> <string> <functional> <gtest/gtest.h>)
|
||||
|
||||
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)
|
||||
22
tests/test_tablename.cpp
Normal file
22
tests/test_tablename.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <sqlgen.hpp>
|
||||
#include <sqlgen/parsing/to_create_table.hpp>
|
||||
|
||||
namespace test_tablename {
|
||||
|
||||
struct TestTable {
|
||||
using tablename = sqlgen::Literal<"TEST_TABLE">;
|
||||
|
||||
std::string field1;
|
||||
int32_t field2;
|
||||
sqlgen::PrimaryKey<uint32_t> id;
|
||||
std::optional<std::string> nullable;
|
||||
};
|
||||
|
||||
TEST(general, test_tablename) {
|
||||
const auto create_table_stmt = sqlgen::parsing::to_create_table<TestTable>();
|
||||
|
||||
EXPECT_EQ(create_table_stmt.table.name, "TEST_TABLE");
|
||||
}
|
||||
} // namespace test_tablename
|
||||
35
tests/test_to_create_table.cpp
Normal file
35
tests/test_to_create_table.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <sqlgen.hpp>
|
||||
#include <sqlgen/parsing/to_create_table.hpp>
|
||||
|
||||
TEST(general, test_to_create_table) {
|
||||
struct TestTable {
|
||||
std::string field1;
|
||||
int32_t field2;
|
||||
sqlgen::PrimaryKey<uint32_t> id;
|
||||
std::optional<std::string> nullable;
|
||||
};
|
||||
|
||||
const auto create_table_stmt = sqlgen::parsing::to_create_table<TestTable>();
|
||||
|
||||
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);
|
||||
}
|
||||
1
vcpkg
Submodule
1
vcpkg
Submodule
Submodule vcpkg added at 7354f1c8a0
@@ -1,5 +1,9 @@
|
||||
{
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "gtest",
|
||||
"version>=": "1.14.0"
|
||||
},
|
||||
{
|
||||
"name": "reflectcpp",
|
||||
"version>=": "0.18.0"
|
||||
|
||||
Reference in New Issue
Block a user