LibWebView: Replace usage of LibSQL with sqlite3

This makes WebView::Database wrap around sqlite3 instead of LibSQL. The
effect on outside callers is pretty minimal. The main consequences are:

1. We must ensure the Cookie table exists before preparing any SQL
   statements involving that table.
2. We can use an INSERT OR REPLACE statement instead of separate INSERT
   and UPDATE statements.
This commit is contained in:
Timothy Flynn 2024-06-04 16:34:32 -04:00 committed by Tim Flynn
commit 30e745ffa7
Notes: sideshowbarker 2024-07-17 18:08:55 +09:00
12 changed files with 206 additions and 304 deletions

View file

@ -9,87 +9,53 @@
#include <AK/Error.h>
#include <AK/Function.h>
#include <AK/HashMap.h>
#include <AK/NonnullRefPtr.h>
#include <AK/Optional.h>
#include <AK/RefCounted.h>
#include <AK/StringView.h>
#include <AK/Vector.h>
#include <LibCore/Promise.h>
#include <LibSQL/SQLClient.h>
#include <LibSQL/Type.h>
#include <LibSQL/Value.h>
struct sqlite3;
struct sqlite3_stmt;
namespace WebView {
class Database : public RefCounted<Database> {
using OnResult = Function<void(ReadonlySpan<SQL::Value>)>;
using OnComplete = Function<void()>;
using OnError = Function<void(StringView)>;
public:
static ErrorOr<NonnullRefPtr<Database>> create();
static ErrorOr<NonnullRefPtr<Database>> create(NonnullRefPtr<SQL::SQLClient>);
~Database();
ErrorOr<SQL::StatementID> prepare_statement(StringView statement);
using StatementID = size_t;
using OnResult = Function<void(StatementID)>;
ErrorOr<StatementID> prepare_statement(StringView statement);
void execute_statement(StatementID, OnResult on_result);
template<typename... PlaceholderValues>
void execute_statement(SQL::StatementID statement_id, OnResult on_result, OnComplete on_complete, OnError on_error, PlaceholderValues&&... placeholder_values)
void execute_statement(StatementID statement_id, OnResult on_result, PlaceholderValues&&... placeholder_values)
{
auto sync_promise = Core::Promise<Empty>::construct();
int index = 1;
(apply_placeholder(statement_id, index++, forward<PlaceholderValues>(placeholder_values)), ...);
PendingExecution pending_execution {
.on_result = move(on_result),
.on_complete = [sync_promise, on_complete = move(on_complete)] {
if (on_complete)
on_complete();
sync_promise->resolve({}); },
.on_error = [sync_promise, on_error = move(on_error)](auto message) {
if (on_error)
on_error(message);
sync_promise->resolve({}); },
};
Vector<SQL::Value> values { SQL::Value(forward<PlaceholderValues>(placeholder_values))... };
execute_statement(statement_id, move(values), move(pending_execution));
MUST(sync_promise->await());
execute_statement(statement_id, move(on_result));
}
template<typename ValueType>
ValueType result_column(StatementID, int column);
private:
struct ExecutionKey {
constexpr bool operator==(ExecutionKey const&) const = default;
explicit Database(sqlite3*);
SQL::StatementID statement_id { 0 };
SQL::ExecutionID execution_id { 0 };
};
template<typename ValueType>
void apply_placeholder(StatementID statement_id, int index, ValueType const& value);
struct PendingExecution {
OnResult on_result { nullptr };
OnComplete on_complete { nullptr };
OnError on_error { nullptr };
};
struct ExecutionKeyTraits : public Traits<ExecutionKey> {
static constexpr unsigned hash(ExecutionKey const& key)
{
return pair_int_hash(u64_hash(key.statement_id), u64_hash(key.execution_id));
}
};
Database(NonnullRefPtr<SQL::SQLClient> sql_client, SQL::ConnectionID connection_id);
void execute_statement(SQL::StatementID statement_id, Vector<SQL::Value> placeholder_values, PendingExecution pending_execution);
template<typename ResultData>
auto take_pending_execution(ResultData const& result_data)
ALWAYS_INLINE sqlite3_stmt* prepared_statement(StatementID statement_id)
{
return m_pending_executions.take({ result_data.statement_id, result_data.execution_id });
VERIFY(statement_id < m_prepared_statements.size());
return m_prepared_statements[statement_id];
}
NonnullRefPtr<SQL::SQLClient> m_sql_client;
SQL::ConnectionID m_connection_id { 0 };
HashMap<ExecutionKey, PendingExecution, ExecutionKeyTraits> m_pending_executions;
sqlite3* m_database { nullptr };
Vector<sqlite3_stmt*> m_prepared_statements;
};
}