/src/serenity/Userland/Libraries/LibSQL/Result.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2021, Jan de Visser <jan@de-visser.net> |
3 | | * Copyright (c) 2021, Mahmoud Mandour <ma.mandourr@gmail.com> |
4 | | * |
5 | | * SPDX-License-Identifier: BSD-2-Clause |
6 | | */ |
7 | | |
8 | | #pragma once |
9 | | |
10 | | #include <AK/ByteString.h> |
11 | | #include <AK/Error.h> |
12 | | #include <AK/Noncopyable.h> |
13 | | #include <LibSQL/Type.h> |
14 | | |
15 | | namespace SQL { |
16 | | |
17 | | #define ENUMERATE_SQL_COMMANDS(S) \ |
18 | | S(Unknown) \ |
19 | | S(Create) \ |
20 | | S(Delete) \ |
21 | | S(Describe) \ |
22 | | S(Insert) \ |
23 | | S(Select) \ |
24 | | S(Update) |
25 | | |
26 | | enum class SQLCommand { |
27 | | #undef __ENUMERATE_SQL_COMMAND |
28 | | #define __ENUMERATE_SQL_COMMAND(command) command, |
29 | | ENUMERATE_SQL_COMMANDS(__ENUMERATE_SQL_COMMAND) |
30 | | #undef __ENUMERATE_SQL_COMMAND |
31 | | }; |
32 | | |
33 | | constexpr char const* command_tag(SQLCommand command) |
34 | 0 | { |
35 | 0 | switch (command) { |
36 | 0 | #undef __ENUMERATE_SQL_COMMAND |
37 | 0 | #define __ENUMERATE_SQL_COMMAND(command) \ |
38 | 0 | case SQLCommand::command: \ |
39 | 0 | return #command; |
40 | 0 | ENUMERATE_SQL_COMMANDS(__ENUMERATE_SQL_COMMAND) |
41 | 0 | #undef __ENUMERATE_SQL_COMMAND |
42 | 0 | } |
43 | 0 | } |
44 | | |
45 | | #define ENUMERATE_SQL_ERRORS(S) \ |
46 | | S(AmbiguousColumnName, "Column name '{}' is ambiguous") \ |
47 | | S(BooleanOperatorTypeMismatch, "Cannot apply '{}' operator to non-boolean operands") \ |
48 | | S(ColumnDoesNotExist, "Column '{}' does not exist") \ |
49 | | S(DatabaseDoesNotExist, "Database '{}' does not exist") \ |
50 | | S(DatabaseUnavailable, "Database Unavailable") \ |
51 | | S(IntegerOperatorTypeMismatch, "Cannot apply '{}' operator to non-numeric operands") \ |
52 | | S(IntegerOverflow, "Operation would cause integer overflow") \ |
53 | | S(InternalError, "{}") \ |
54 | | S(InvalidDatabaseName, "Invalid database name '{}'") \ |
55 | | S(InvalidNumberOfPlaceholderValues, "Number of values does not match number of placeholders") \ |
56 | | S(InvalidNumberOfValues, "Number of values does not match number of columns") \ |
57 | | S(InvalidOperator, "Invalid operator '{}'") \ |
58 | | S(InvalidType, "Invalid type '{}'") \ |
59 | | S(InvalidValueType, "Invalid type for attribute '{}'") \ |
60 | | S(NoError, "No error") \ |
61 | | S(NotYetImplemented, "{}") \ |
62 | | S(NumericOperatorTypeMismatch, "Cannot apply '{}' operator to non-numeric operands") \ |
63 | | S(SchemaDoesNotExist, "Schema '{}' does not exist") \ |
64 | | S(SchemaExists, "Schema '{}' already exist") \ |
65 | | S(StatementUnavailable, "Statement with id '{}' Unavailable") \ |
66 | | S(SyntaxError, "Syntax Error") \ |
67 | | S(TableDoesNotExist, "Table '{}' does not exist") \ |
68 | | S(TableExists, "Table '{}' already exist") |
69 | | |
70 | | enum class SQLErrorCode { |
71 | | #undef __ENUMERATE_SQL_ERROR |
72 | | #define __ENUMERATE_SQL_ERROR(error, description) error, |
73 | | ENUMERATE_SQL_ERRORS(__ENUMERATE_SQL_ERROR) |
74 | | #undef __ENUMERATE_SQL_ERROR |
75 | | }; |
76 | | |
77 | | class [[nodiscard]] Result { |
78 | | AK_MAKE_NONCOPYABLE(Result); |
79 | | AK_MAKE_DEFAULT_MOVABLE(Result); |
80 | | |
81 | | public: |
82 | | ALWAYS_INLINE Result(SQLCommand command) |
83 | | : m_command(command) |
84 | 0 | { |
85 | 0 | } |
86 | | |
87 | | ALWAYS_INLINE Result(SQLCommand command, SQLErrorCode error) |
88 | 0 | : m_command(command) |
89 | 0 | , m_error(error) |
90 | 0 | { |
91 | 0 | } |
92 | | |
93 | | ALWAYS_INLINE Result(SQLCommand command, SQLErrorCode error, ByteString error_message) |
94 | 0 | : m_command(command) |
95 | 0 | , m_error(error) |
96 | 0 | , m_error_message(move(error_message)) |
97 | 0 | { |
98 | 0 | } |
99 | | |
100 | | ALWAYS_INLINE Result(Error error) |
101 | 0 | : m_error(SQLErrorCode::InternalError) |
102 | 0 | , m_error_message(error.string_literal()) |
103 | 0 | { |
104 | 0 | } |
105 | | |
106 | 0 | SQLCommand command() const { return m_command; } |
107 | 0 | SQLErrorCode error() const { return m_error; } |
108 | | ByteString error_string() const; |
109 | | |
110 | | // These are for compatibility with the TRY() macro in AK. |
111 | 0 | [[nodiscard]] bool is_error() const { return m_error != SQLErrorCode::NoError; } |
112 | 0 | [[nodiscard]] Result release_value() { return move(*this); } |
113 | | Result release_error() |
114 | 0 | { |
115 | 0 | VERIFY(is_error()); |
116 | 0 |
|
117 | 0 | if (m_error_message.has_value()) |
118 | 0 | return { m_command, m_error, m_error_message.release_value() }; |
119 | 0 | return { m_command, m_error }; |
120 | 0 | } |
121 | | |
122 | | private: |
123 | | SQLCommand m_command { SQLCommand::Unknown }; |
124 | | |
125 | | SQLErrorCode m_error { SQLErrorCode::NoError }; |
126 | | Optional<ByteString> m_error_message {}; |
127 | | }; |
128 | | |
129 | | template<typename ValueType> |
130 | | using ResultOr = ErrorOr<ValueType, Result>; |
131 | | |
132 | | } |