diff --git a/backends/postgres/test/CMakeLists.txt b/backends/postgres/test/CMakeLists.txt index ed1497f..01d3804 100644 --- a/backends/postgres/test/CMakeLists.txt +++ b/backends/postgres/test/CMakeLists.txt @@ -12,7 +12,7 @@ list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras) include(CTest) include(Catch) -set(POSTGRES_CONNECTION_STRING "postgres://test:test123@127.0.0.1:15432/test") +set(POSTGRES_CONNECTION_STRING "postgres://test:test123@127.0.0.1:5432/matador_test") configure_file(Connection.hpp.in ${PROJECT_BINARY_DIR}/backends/postgres/test/connection.hpp @ONLY IMMEDIATE) diff --git a/include/matador/utils/result.hpp b/include/matador/utils/result.hpp new file mode 100644 index 0000000..e723ec4 --- /dev/null +++ b/include/matador/utils/result.hpp @@ -0,0 +1,85 @@ +#ifndef QUERY_RESULT_HPP +#define QUERY_RESULT_HPP + +#include + +namespace matador::utils { + +template < typename ValueType, typename ErrorType > +class [[nodiscard]] result; + +template +struct is_result : std::false_type {}; + +template < typename ValueType, typename ErrorType > +struct is_result> : std::true_type {}; + +template < typename ValueType > +class ok +{ +public: + explicit constexpr ok(const ValueType &value) : value_(value) {} + explicit constexpr ok(ValueType &&value) : value_(std::move(value)) {} + + constexpr ValueType&& release() { return std::move(value_); } + const ValueType& value() const { return value_; } + +private: + ValueType value_; +}; + +template < typename ErrorType > +class error +{ +public: + explicit constexpr error(const ErrorType &error) : error_(error) {} + explicit constexpr error(ErrorType &&error) : error_(std::move(error)) {} + + constexpr ErrorType&& release() { return std::move(error_); } + const ErrorType& value() const { return error_; } + +private: + ErrorType error_; +}; + +template < typename ValueType, typename ErrorType > +class result +{ +public: + using value_type = ok; + using error_type = error; + + result(value_type value) : result_(value) {} // NOLINT(*-explicit-constructor) + result(error_type error) : result_(error) {} // NOLINT(*-explicit-constructor) + + operator bool() const { return is_ok(); } // NOLINT(*-explicit-constructor) + + [[nodiscard]] bool is_ok() const { return std::holds_alternative(result_); } + [[nodiscard]] bool is_error() const { return std::holds_alternative(result_); } + + ValueType&& release() { return std::get(result_).release(); } + ErrorType&& release_error() { return std::get(result_).release(); } + + const ValueType& value() const { return std::get(result_).value(); } + const ErrorType& err() const { return std::get(result_).value(); } + ErrorType err() { return std::get(result_).value(); } + + constexpr const ValueType* operator->() const { return &value(); } + constexpr ValueType* operator->() { return &value(); } + + template + result and_then(Func f) { + if (is_ok()) { + return f(value()); + } + + return *this; + } + +private: + std::variant result_; +}; + +} + +#endif //QUERY_RESULT_HPP diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 59839af..f61ad39 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -111,6 +111,7 @@ set(UTILS_HEADER ../include/matador/utils/types.hpp ../include/matador/utils/foreign_attributes.hpp ../include/matador/utils/fetch_type.hpp + ../include/matador/utils/result.hpp ) set(UTILS_SOURCES diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7d3608e..a1ee163 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -41,7 +41,8 @@ add_executable(tests models/book.hpp FieldTest.cpp models/recipe.hpp - ValueTest.cpp) + ValueTest.cpp + ResultTest.cpp) target_link_libraries(tests PRIVATE Catch2::Catch2WithMain diff --git a/test/ResultTest.cpp b/test/ResultTest.cpp new file mode 100644 index 0000000..7dcd7a5 --- /dev/null +++ b/test/ResultTest.cpp @@ -0,0 +1,47 @@ +#include + +#include "matador/utils/result.hpp" + +namespace matador::test { + +enum class math_error : int32_t { + DIVISION_BY_ZERO = 1 +}; + +utils::resultdivide(int x, int y) { + if (y == 0) { + return utils::error(math_error::DIVISION_BY_ZERO); + } + + return utils::ok(float(x) / y); +} + +utils::resultmultiply(int x, int y) { + return utils::ok(float(x) * y); +} + +} + +using namespace matador; + +TEST_CASE("Result tests", "[result]") { + auto res = test::divide(4, 2); + REQUIRE(res); + REQUIRE(res.is_ok()); + REQUIRE(!res.is_error()); + + REQUIRE((res.value() == 2.0)); + + REQUIRE_THROWS(res.err()); + + res = test::divide(4, 0); + REQUIRE(!res); + REQUIRE(!res.is_ok()); + REQUIRE(res.is_error()); + + REQUIRE((res.err() == test::math_error::DIVISION_BY_ZERO)); + + +// res = test::divide(4, 2) +// .and_then<>() +} \ No newline at end of file