diff --git a/Userland/Libraries/LibSQL/Forward.h b/Userland/Libraries/LibSQL/Forward.h index 15e85a522e..01cd6fbe79 100644 --- a/Userland/Libraries/LibSQL/Forward.h +++ b/Userland/Libraries/LibSQL/Forward.h @@ -22,6 +22,7 @@ class IndexDef; class Key; class KeyPartDef; class Relation; +class Result; class Row; class SchemaDef; class SQLResult; diff --git a/Userland/Libraries/LibSQL/SQLResult.cpp b/Userland/Libraries/LibSQL/SQLResult.cpp index fc1550247f..57986c355b 100644 --- a/Userland/Libraries/LibSQL/SQLResult.cpp +++ b/Userland/Libraries/LibSQL/SQLResult.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include namespace SQL { @@ -28,4 +29,63 @@ void SQLResult::limit(size_t offset, size_t limit) } } +void Result::insert(Tuple const& row, Tuple const& sort_key) +{ + if (!m_result_set.has_value()) + m_result_set = ResultSet {}; + m_result_set->insert_row(row, sort_key); +} + +void Result::limit(size_t offset, size_t limit) +{ + VERIFY(has_results()); + + if (offset > 0) { + if (offset > m_result_set->size()) { + m_result_set->clear(); + return; + } + + m_result_set->remove(0, offset); + } + + if (m_result_set->size() > limit) + m_result_set->remove(limit, m_result_set->size() - limit); +} + +String Result::error_string() const +{ + VERIFY(is_error()); + + StringView error_code; + StringView error_description; + + switch (m_error) { +#undef __ENUMERATE_SQL_ERROR +#define __ENUMERATE_SQL_ERROR(error, description) \ + case SQLErrorCode::error: \ + error_code = #error##sv; \ + error_description = description##sv; \ + break; + ENUMERATE_SQL_ERRORS(__ENUMERATE_SQL_ERROR) +#undef __ENUMERATE_SQL_ERROR + default: + VERIFY_NOT_REACHED(); + } + + StringBuilder builder; + builder.appendff("{}: ", error_code); + + if (m_error_message.has_value()) { + if (error_description.find("{}"sv).has_value()) + builder.appendff(error_description, *m_error_message); + else + builder.appendff("{}: {}", error_description, *m_error_message); + } else { + builder.append(error_description); + } + + return builder.build(); +} + } diff --git a/Userland/Libraries/LibSQL/SQLResult.h b/Userland/Libraries/LibSQL/SQLResult.h index c4b2ebd9be..da28aa1dca 100644 --- a/Userland/Libraries/LibSQL/SQLResult.h +++ b/Userland/Libraries/LibSQL/SQLResult.h @@ -7,6 +7,8 @@ #pragma once +#include +#include #include #include #include @@ -17,6 +19,7 @@ namespace SQL { #define ENUMERATE_SQL_COMMANDS(S) \ + S(Unknown) \ S(Create) \ S(Delete) \ S(Describe) \ @@ -162,4 +165,76 @@ private: ResultSet m_result_set; }; +class [[nodiscard]] Result { +public: + ALWAYS_INLINE Result(SQLCommand command, size_t update_count = 0, size_t insert_count = 0, size_t delete_count = 0) + : m_command(command) + , m_update_count(update_count) + , m_insert_count(insert_count) + , m_delete_count(delete_count) + { + } + + ALWAYS_INLINE Result(SQLCommand command, SQLErrorCode error) + : m_command(command) + , m_error(error) + { + } + + ALWAYS_INLINE Result(SQLCommand command, SQLErrorCode error, String error_message) + : m_command(command) + , m_error(error) + , m_error_message(move(error_message)) + { + } + + ALWAYS_INLINE Result(Error error) + : m_error(static_cast(error.code())) + , m_error_message(error.string_literal()) + { + } + + Result(Result&&) = default; + Result& operator=(Result&&) = default; + + SQLCommand command() const { return m_command; } + SQLErrorCode error() const { return m_error; } + String error_string() const; + + void insert(Tuple const& row, Tuple const& sort_key); + void limit(size_t offset, size_t limit); + + bool has_results() const { return m_result_set.has_value(); } + ResultSet const& results() const { return m_result_set.value(); } + + size_t updated() const { return m_update_count; } + size_t inserted() const { return m_insert_count; } + size_t deleted() const { return m_delete_count; } + + // These are for compatibility with the TRY() macro in AK. + [[nodiscard]] bool is_error() const { return m_error != SQLErrorCode::NoError; } + [[nodiscard]] ResultSet release_value() { return m_result_set.release_value(); } + Result release_error() + { + VERIFY(is_error()); + + if (m_error_message.has_value()) + return { m_command, m_error, m_error_message.release_value() }; + return { m_command, m_error }; + } + +private: + AK_MAKE_NONCOPYABLE(Result); + + SQLCommand m_command { SQLCommand::Unknown }; + + SQLErrorCode m_error { SQLErrorCode::NoError }; + Optional m_error_message {}; + + Optional m_result_set {}; + size_t m_update_count { 0 }; + size_t m_insert_count { 0 }; + size_t m_delete_count { 0 }; +}; + }