Changed to the Parser pattern, just like reflect-cpp

This commit is contained in:
Dr. Patrick Urbanke
2025-04-06 16:36:45 +02:00
parent 075bcb894a
commit 1718c19f62
11 changed files with 357 additions and 134 deletions

View File

@@ -6,58 +6,14 @@
#include <type_traits>
#include "../Result.hpp"
#include "../parsing/has_reflection_method.hpp"
#include "../parsing/is_nullable.hpp"
#include "../parsing/Parser.hpp"
namespace sqlgen::internal {
template <class T>
Result<T> from_str(const std::optional<std::string>& _str) {
using Type = std::remove_cvref_t<T>;
if constexpr (parsing::has_reflection_method<Type>) {
return from_str<typename Type::ReflectionType>(_str).transform(
[](auto&& _v) { return Type(std::move(_v)); });
} else if constexpr (parsing::is_nullable_v<Type>) {
if (!_str) {
return Type();
}
if constexpr (parsing::is_ptr<Type>::value) {
return from_str<typename Type::element_type>(_str).transform(
[](auto&& _v) { return Type(std::move(_v)); });
} else {
return from_str<typename Type::value_type>(_str).transform(
[](auto&& _v) { return Type(std::move(_v)); });
}
} else {
if (!_str) {
return error("Encountered NULL value.");
}
if constexpr (std::is_same_v<Type, std::string>) {
return *_str;
} else {
try {
if constexpr (std::is_floating_point_v<Type>) {
return static_cast<Type>(std::stod(*_str));
} else if constexpr (std::is_integral_v<Type>) {
return static_cast<type>(std::stoll(*_str));
} else if (std::is_same_v<Type, bool>) {
return std::stoi(*_str) != 0;
} else {
static_assert(rfl::always_false<Type>, "Unsupported type");
}
} catch (std::exception& e) {
return error(e.what());
}
}
}
return Parser<Type>::read(_str);
}
} // namespace sqlgen::internal

View File

@@ -5,30 +5,14 @@
#include <string>
#include <type_traits>
#include "../parsing/has_reflection_method.hpp"
#include "../parsing/is_nullable.hpp"
#include "../parsing/Parser.hpp"
namespace sqlgen::internal {
template <class T>
std::optional<std::string> to_str(const T& _val) {
using Type = std::remove_cvref_t<T>;
if constexpr (parsing::is_nullable_v<Type>) {
if (!_val) {
return std::nullopt;
} else {
return to_str(*_val);
}
} else if constexpr (parsing::has_reflection_method<Type>) {
return to_str(_val.reflection());
} else if constexpr (std::is_same_v<Type, std::string>) {
return _val;
} else {
return std::to_string(_val);
}
return parsing::Parser<Type>::write(_val);
}
} // namespace sqlgen::internal

View File

@@ -0,0 +1,12 @@
#ifndef SQLGEN_PARSING_PARSER_HPP_
#define SQLGEN_PARSING_PARSER_HPP_
#include "Parser_base.hpp"
#include "Parser_default.hpp"
#include "Parser_optional.hpp"
#include "Parser_primary_key.hpp"
#include "Parser_shared_ptr.hpp"
#include "Parser_string.hpp"
#include "Parser_unique_ptr.hpp"
#endif

View File

@@ -0,0 +1,11 @@
#ifndef SQLGEN_PARSING_PARSER_BASE_HPP_
#define SQLGEN_PARSING_PARSER_BASE_HPP_
namespace sqlgen::parsing {
template <class T>
struct Parser;
}
#endif

View File

@@ -0,0 +1,119 @@
#ifndef SQLGEN_PARSING_PARSER_DEFAULT_HPP_
#define SQLGEN_PARSING_PARSER_DEFAULT_HPP_
#include <rfl.hpp>
#include <string>
#include <type_traits>
#include "../Result.hpp"
#include "../dynamic/Type.hpp"
#include "../dynamic/types.hpp"
#include "Parser_base.hpp"
#include "has_reflection_method.hpp"
namespace sqlgen::parsing {
template <class T>
struct Parser {
using Type = std::remove_cvref_t<T>;
static Result<T> read(const std::optional<std::string>& _str) noexcept {
if constexpr (has_reflection_method<Type>) {
return Parser<std::remove_cvref_t<typename Type::ReflectionType>>::read(
_str)
.transform([](auto&& _t) { return Type(std::move(_t)); });
} else {
if (!_str) {
return error("NULL value encounted: Numeric value cannot be NULL.");
}
try {
if constexpr (std::is_floating_point_v<Type>) {
return static_cast<Type>(std::stod(*_str));
} else if constexpr (std::is_integral_v<Type>) {
return static_cast<Type>(std::stoll(*_str));
} else if (std::is_same_v<Type, bool>) {
return std::stoi(*_str) != 0;
} else {
static_assert(rfl::always_false_v<Type>, "Unsupported type");
}
} catch (std::exception& e) {
return error(e.what());
}
}
}
static std::optional<std::string> write(const T& _t) noexcept {
if constexpr (has_reflection_method<Type>) {
return Parser<std::remove_cvref_t<typename Type::ReflectionType>>::write(
_t.reflection());
} else {
return std::to_string(_t);
}
}
static dynamic::Type to_type() noexcept {
if constexpr (has_reflection_method<Type>) {
return Parser<
std::remove_cvref_t<typename Type::ReflectionType>>::to_type();
} else if constexpr (std::is_same_v<T, bool>) {
return dynamic::types::Boolean{};
} else if constexpr (std::is_integral_v<T> && std::is_signed_v<T>) {
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<T>, "Unsupported signed integer.");
}
} else if constexpr (std::is_integral_v<T> && !std::is_signed_v<T>) {
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<T>, "Unsupported unsigned integer.");
}
} else if constexpr (std::is_floating_point_v<T>) {
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<T>,
"Unsupported floating point value.");
}
} else {
static_assert(rfl::always_false_v<T>, "Unsupported type.");
}
}
};
} // namespace sqlgen::parsing
#endif

View File

@@ -0,0 +1,45 @@
#ifndef SQLGEN_PARSING_PARSER_OPTIONAL_HPP_
#define SQLGEN_PARSING_PARSER_OPTIONAL_HPP_
#include <optional>
#include <string>
#include <type_traits>
#include "../Result.hpp"
#include "../dynamic/Type.hpp"
#include "Parser_base.hpp"
namespace sqlgen::parsing {
template <class T>
struct Parser<std::optional<T>> {
static Result<std::optional<T>> read(
const std::optional<std::string>& _str) noexcept {
if (!_str) {
return std::optional<T>();
}
return Parser<std::remove_cvref_t<T>>::read(_str).transform(
[](auto&& _t) -> std::optional<T> {
return std::make_optional<T>(std::move(_t));
});
}
static std::optional<std::string> write(const std::optional<T>& _o) noexcept {
if (!_o) {
return std::nullopt;
}
return Parser<std::remove_cvref_t<T>>::write(*_o);
}
static dynamic::Type to_type() noexcept {
return Parser<std::remove_cvref_t<T>>::to_type().visit(
[](auto _t) -> dynamic::Type {
_t.properties.nullable = true;
return _t;
});
}
};
} // namespace sqlgen::parsing
#endif

View File

@@ -0,0 +1,39 @@
#ifndef SQLGEN_PARSING_PARSER_PRIMARY_KEY_HPP_
#define SQLGEN_PARSING_PARSER_PRIMARY_KEY_HPP_
#include <string>
#include <type_traits>
#include "../PrimaryKey.hpp"
#include "../Result.hpp"
#include "../dynamic/Type.hpp"
#include "Parser_base.hpp"
namespace sqlgen::parsing {
template <class T>
struct Parser<PrimaryKey<T>> {
static Result<PrimaryKey<T>> read(
const std::optional<std::string>& _str) noexcept {
return Parser<std::remove_cvref_t<T>>::read(_str).transform(
[](auto&& _t) -> PrimaryKey<T> {
return PrimaryKey<T>(std::move(_t));
});
}
static std::optional<std::string> write(const PrimaryKey<T>& _p) noexcept {
return Parser<std::remove_cvref_t<T>>::write(_p.value());
}
static dynamic::Type to_type() noexcept {
return Parser<std::remove_cvref_t<T>>::to_type().visit(
[](auto _t) -> dynamic::Type {
_t.properties.primary = true;
return _t;
});
}
};
} // namespace sqlgen::parsing
#endif

View File

@@ -0,0 +1,46 @@
#ifndef SQLGEN_PARSING_PARSER_SHARED_PTR_HPP_
#define SQLGEN_PARSING_PARSER_SHARED_PTR_HPP_
#include <memory>
#include <string>
#include <type_traits>
#include "../Result.hpp"
#include "../dynamic/Type.hpp"
#include "Parser_base.hpp"
namespace sqlgen::parsing {
template <class T>
struct Parser<std::shared_ptr<T>> {
static Result<std::shared_ptr<T>> read(
const std::optional<std::string>& _str) noexcept {
if (!_str) {
return std::shared_ptr<T>();
}
return Parser<std::remove_cvref_t<T>>::read(_str).transform(
[](auto&& _t) -> std::shared_ptr<T> {
return std::make_shared<T>(std::move(_t));
});
}
static std::optional<std::string> write(
const std::shared_ptr<T>& _ptr) noexcept {
if (!_ptr) {
return std::nullopt;
}
return Parser<std::remove_cvref_t<T>>::write(*_ptr);
}
static dynamic::Type to_type() noexcept {
return Parser<std::remove_cvref_t<T>>::to_type().visit(
[](auto _t) -> dynamic::Type {
_t.properties.nullable = true;
return _t;
});
}
};
} // namespace sqlgen::parsing
#endif

View File

@@ -0,0 +1,33 @@
#ifndef SQLGEN_PARSING_PARSER_STRING_HPP_
#define SQLGEN_PARSING_PARSER_STRING_HPP_
#include <string>
#include <type_traits>
#include "../Result.hpp"
#include "../dynamic/Type.hpp"
#include "../dynamic/types.hpp"
#include "Parser_base.hpp"
namespace sqlgen::parsing {
template <>
struct Parser<std::string> {
static Result<std::string> read(
const std::optional<std::string>& _str) noexcept {
if (!_str) {
return error("NULL value encounted: String value cannot be NULL.");
}
return *_str;
}
static std::optional<std::string> write(const std::string& _str) noexcept {
return _str;
}
static dynamic::Type to_type() noexcept { return dynamic::types::Text{}; }
};
} // namespace sqlgen::parsing
#endif

View File

@@ -0,0 +1,46 @@
#ifndef SQLGEN_PARSING_PARSER_UNIQUE_PTR_HPP_
#define SQLGEN_PARSING_PARSER_UNIQUE_PTR_HPP_
#include <memory>
#include <string>
#include <type_traits>
#include "../Result.hpp"
#include "../dynamic/Type.hpp"
#include "Parser_base.hpp"
namespace sqlgen::parsing {
template <class T>
struct Parser<std::unique_ptr<T>> {
static Result<std::unique_ptr<T>> read(
const std::optional<std::string>& _str) noexcept {
if (!_str) {
return std::unique_ptr<T>();
}
return Parser<std::remove_cvref_t<T>>::read(_str).transform(
[](auto&& _t) -> std::unique_ptr<T> {
return std::make_unique<T>(std::move(_t));
});
}
static std::optional<std::string> write(
const std::unique_ptr<T>& _ptr) noexcept {
if (!_ptr) {
return std::nullopt;
}
return Parser<std::remove_cvref_t<T>>::write(*_ptr);
}
static dynamic::Type to_type() noexcept {
return Parser<std::remove_cvref_t<T>>::to_type().visit(
[](auto _t) -> dynamic::Type {
_t.properties.nullable = true;
return _t;
});
}
};
} // namespace sqlgen::parsing
#endif

View File

@@ -8,6 +8,7 @@
#include "../dynamic/Column.hpp"
#include "../dynamic/Type.hpp"
#include "../dynamic/types.hpp"
#include "Parser.hpp"
#include "has_reflection_method.hpp"
#include "is_nullable.hpp"
#include "is_primary_key.hpp"
@@ -22,76 +23,7 @@ std::string to_colname() {
template <class Type>
dynamic::Type to_type() {
using T = std::remove_cvref_t<Type>;
if constexpr (is_primary_key_v<T>) {
return to_type<typename T::ReflectionType>().visit(
[](auto _t) -> dynamic::Type {
_t.properties.primary = true;
return _t;
});
} else if constexpr (is_nullable_v<T>) {
const auto set_nullable = [](auto _t) -> dynamic::Type {
_t.properties.nullable = true;
return _t;
};
if constexpr (is_ptr<T>::value) {
return to_type<typename T::element_type>().visit(set_nullable);
} else {
return to_type<typename T::value_type>().visit(set_nullable);
}
} else if constexpr (has_reflection_method<T>) {
return to_type<typename Type::ReflectionType>();
} else if constexpr (std::is_same_v<T, bool>) {
return dynamic::types::Boolean{};
} else if constexpr (std::is_integral_v<T> && std::is_signed_v<T>) {
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<T>, "Unsupported signed integer.");
}
} else if constexpr (std::is_integral_v<T> && !std::is_signed_v<T>) {
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<T>, "Unsupported unsigned integer.");
}
} else if constexpr (std::is_floating_point_v<T>) {
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<T>,
"Unsupported floating point value.");
}
} else if constexpr (std::is_same_v<T, std::string>) {
return dynamic::types::Text{};
}
return Parser<T>::to_type();
}
template <class FieldType>