diff --git a/docs/dynamic.md b/docs/dynamic.md index 4669ceb..03e51af 100644 --- a/docs/dynamic.md +++ b/docs/dynamic.md @@ -45,6 +45,33 @@ struct Parser { } // namespace sqlgen::parsing ``` +The second step is to specialize `sqlgen::transpilation::ToValue` for `boost::uuids::uuid` and implement `operator()`: + +```cpp +#include +#include +#include +#include +#include + +namespace sqlgen::transpilation { + +template <> +struct ToValue { + dynamic::Value operator()(const boost::uuids::uuid& _u) const { + return dynamic::Value{dynamic::String{.val = boost::uuids::to_string(_u)}}; + } +}; + +} // namespace sqlgen::transpilation +``` + +This second step is necessary to ensure you can use your type in `where(...)` statements +and other conditions. + +The return type must always be `sqlgen::dynamic::Value`. `dynamic::Value` can contain +`dynamic::String` (as in this example), `dynamic::Float` or `dynamic::Integer`. + ### Using `boost::uuids::uuid` in structs You can then automatically generate random UUIDs: diff --git a/include/sqlgen/transpilation/to_value.hpp b/include/sqlgen/transpilation/to_value.hpp index 45372f9..55758a9 100644 --- a/include/sqlgen/transpilation/to_value.hpp +++ b/include/sqlgen/transpilation/to_value.hpp @@ -11,26 +11,36 @@ namespace sqlgen::transpilation { template -dynamic::Value to_value(const T& _t) { - using Type = std::remove_cvref_t; - if constexpr (std::is_floating_point_v) { - return dynamic::Value{dynamic::Float{.val = static_cast(_t)}}; +struct ToValue; - } else if constexpr (std::is_integral_v) { - return dynamic::Value{dynamic::Integer{.val = static_cast(_t)}}; +template +struct ToValue { + dynamic::Value operator()(const T& _t) const { + using Type = std::remove_cvref_t; + if constexpr (std::is_floating_point_v) { + return dynamic::Value{dynamic::Float{.val = static_cast(_t)}}; - } else if constexpr (std::is_convertible_v) { - return dynamic::Value{dynamic::String{.val = std::string(_t)}}; + } else if constexpr (std::is_integral_v) { + return dynamic::Value{dynamic::Integer{.val = static_cast(_t)}}; - } else if constexpr (has_reflection_method) { - return to_value(_t.reflection()); + } else if constexpr (std::is_convertible_v) { + return dynamic::Value{dynamic::String{.val = std::string(_t)}}; - } else if constexpr (std::is_enum_v) { - return dynamic::Value{dynamic::String{.val = rfl::enum_to_string(_t)}}; + } else if constexpr (has_reflection_method) { + return ToValue{}(_t.reflection()); - } else { - static_assert(rfl::always_false_v, "Unsupported type"); + } else if constexpr (std::is_enum_v) { + return dynamic::Value{dynamic::String{.val = rfl::enum_to_string(_t)}}; + + } else { + static_assert(rfl::always_false_v, "Unsupported type"); + } } +}; + +template +dynamic::Value to_value(const T& _t) { + return ToValue>{}(_t); } } // namespace sqlgen::transpilation diff --git a/tests/mysql/test_dynamic_type.cpp b/tests/mysql/test_dynamic_type.cpp index 4e634fa..9be5ab7 100644 --- a/tests/mysql/test_dynamic_type.cpp +++ b/tests/mysql/test_dynamic_type.cpp @@ -38,6 +38,17 @@ struct Parser { } // namespace sqlgen::parsing +namespace sqlgen::transpilation { + +template <> +struct ToValue { + dynamic::Value operator()(const boost::uuids::uuid& _u) const { + return dynamic::Value{dynamic::String{.val = boost::uuids::to_string(_u)}}; + } +}; + +} // namespace sqlgen::transpilation + /// For the JSON serialization - not needed for /// the actual DB operations. namespace rfl { @@ -87,10 +98,10 @@ TEST(mysql, test_dynamic_type) { const auto people2 = sqlgen::write(conn, people1) .and_then(sqlgen::read> | - order_by("age"_c.desc())) + where("id"_c == people1.front().id())) .value(); - const auto json1 = rfl::json::write(people1); + const auto json1 = rfl::json::write(std::vector({people1.front()})); const auto json2 = rfl::json::write(people2); EXPECT_EQ(json1, json2); diff --git a/tests/postgres/test_dynamic_type.cpp b/tests/postgres/test_dynamic_type.cpp index d53e5b9..1afeb23 100644 --- a/tests/postgres/test_dynamic_type.cpp +++ b/tests/postgres/test_dynamic_type.cpp @@ -38,6 +38,17 @@ struct Parser { } // namespace sqlgen::parsing +namespace sqlgen::transpilation { + +template <> +struct ToValue { + dynamic::Value operator()(const boost::uuids::uuid& _u) const { + return dynamic::Value{dynamic::String{.val = boost::uuids::to_string(_u)}}; + } +}; + +} // namespace sqlgen::transpilation + /// For the JSON serialization - not needed for /// the actual DB operations. namespace rfl { @@ -87,10 +98,10 @@ TEST(postgres, test_dynamic_type) { const auto people2 = sqlgen::write(conn, people1) .and_then(sqlgen::read> | - order_by("age"_c.desc())) + where("id"_c == people1.front().id())) .value(); - const auto json1 = rfl::json::write(people1); + const auto json1 = rfl::json::write(std::vector({people1.front()})); const auto json2 = rfl::json::write(people2); EXPECT_EQ(json1, json2); diff --git a/tests/sqlite/test_dynamic_type.cpp b/tests/sqlite/test_dynamic_type.cpp index bac91f4..910f235 100644 --- a/tests/sqlite/test_dynamic_type.cpp +++ b/tests/sqlite/test_dynamic_type.cpp @@ -33,9 +33,19 @@ struct Parser { return sqlgen::dynamic::types::Dynamic{"TEXT"}; } }; - } // namespace sqlgen::parsing +namespace sqlgen::transpilation { + +template <> +struct ToValue { + dynamic::Value operator()(const boost::uuids::uuid& _u) const { + return dynamic::Value{dynamic::String{.val = boost::uuids::to_string(_u)}}; + } +}; + +} // namespace sqlgen::transpilation + /// For the JSON serialization - not needed for /// the actual DB operations. namespace rfl { @@ -79,10 +89,10 @@ TEST(sqlite, test_dynamic_type) { const auto people2 = sqlgen::write(conn, people1) .and_then(sqlgen::read> | - order_by("age"_c.desc())) + where("id"_c == people1.front().id())) .value(); - const auto json1 = rfl::json::write(people1); + const auto json1 = rfl::json::write(std::vector({people1.front()})); const auto json2 = rfl::json::write(people2); EXPECT_EQ(json1, json2);