ladybird/Userland/Applications/Browser/Database.cpp
Timothy Flynn d6dee8c0e8 LibSQL+Userland: Pass SQL IPC results to clients in a structure
SQLClient exists as a wrapper around SQL IPC to provide a bit friendlier
interface for clients to deal with. Though right now, it mostly forwards
values as-is from IPC to the clients. This makes it a bit verbose to add
values to IPC responses, as we then have to add it to the callbacks used
by all clients. It's also a bit confusing seeing a sea of "auto" as the
parameter types for these callbacks.

This patch moves these response values to named structures instead. This
will allow adding values without needing to simultaneously update all
clients. We can then separately handle the new values in interested
clients only.
2023-02-03 20:34:45 +01:00

96 lines
3.3 KiB
C++

/*
* Copyright (c) 2022, Tim Flynn <trflynn89@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "Database.h"
#include <AK/StringView.h>
namespace Browser {
static constexpr auto database_name = "Browser"sv;
ErrorOr<NonnullRefPtr<Database>> Database::create()
{
auto sql_client = TRY(SQL::SQLClient::try_create());
return create(move(sql_client));
}
ErrorOr<NonnullRefPtr<Database>> Database::create(NonnullRefPtr<SQL::SQLClient> sql_client)
{
auto connection_id = sql_client->connect(database_name);
if (!connection_id.has_value())
return Error::from_string_view("Could not connect to SQL database"sv);
return adopt_nonnull_ref_or_enomem(new (nothrow) Database(move(sql_client), *connection_id));
}
Database::Database(NonnullRefPtr<SQL::SQLClient> sql_client, SQL::ConnectionID connection_id)
: m_sql_client(move(sql_client))
, m_connection_id(connection_id)
{
m_sql_client->on_execution_success = [this](auto result) {
if (result.has_results)
return;
if (auto it = find_pending_execution(result); it != m_pending_executions.end()) {
auto in_progress_statement = move(it->value);
m_pending_executions.remove(it);
if (in_progress_statement.on_complete)
in_progress_statement.on_complete();
}
};
m_sql_client->on_next_result = [this](auto result) {
if (auto it = find_pending_execution(result); it != m_pending_executions.end()) {
if (it->value.on_result)
it->value.on_result(result.values);
}
};
m_sql_client->on_results_exhausted = [this](auto result) {
if (auto it = find_pending_execution(result); it != m_pending_executions.end()) {
auto in_progress_statement = move(it->value);
m_pending_executions.remove(it);
if (in_progress_statement.on_complete)
in_progress_statement.on_complete();
}
};
m_sql_client->on_execution_error = [this](auto result) {
if (auto it = find_pending_execution(result); it != m_pending_executions.end()) {
auto in_progress_statement = move(it->value);
m_pending_executions.remove(it);
if (in_progress_statement.on_error)
in_progress_statement.on_error(result.error_message);
}
};
}
ErrorOr<SQL::StatementID> Database::prepare_statement(StringView statement)
{
if (auto statement_id = m_sql_client->prepare_statement(m_connection_id, statement); statement_id.has_value())
return *statement_id;
return Error::from_string_view(statement);
}
void Database::execute_statement(SQL::StatementID statement_id, Vector<SQL::Value> placeholder_values, PendingExecution pending_execution)
{
Core::deferred_invoke([this, statement_id, placeholder_values = move(placeholder_values), pending_execution = move(pending_execution)]() mutable {
auto execution_id = m_sql_client->execute_statement(statement_id, move(placeholder_values));
if (!execution_id.has_value()) {
if (pending_execution.on_error)
pending_execution.on_error("Could not execute statement"sv);
return;
}
m_pending_executions.set({ statement_id, *execution_id }, move(pending_execution));
});
}
}