LibDatabase+LibWebView: Extract our SQLite wrapper to its own library

It currently lives in LibWebView as it was only used for cookies and
local storage, both of which are managed in the UI process. Let's move
it to its own library now to allow other processes to use it, without
having to depend on LibWebView (and therefore LibWeb).
This commit is contained in:
Timothy Flynn 2025-10-07 14:35:22 -04:00 committed by Andreas Kling
parent e433dee543
commit 187d02c45d
13 changed files with 68 additions and 45 deletions

View File

@ -1,5 +1,6 @@
add_subdirectory(LibCompress)
add_subdirectory(LibCrypto)
add_subdirectory(LibDatabase)
add_subdirectory(LibDiff)
add_subdirectory(LibDNS)
add_subdirectory(LibGC)

View File

@ -0,0 +1,8 @@
set(SOURCES
Database.cpp
)
find_package(SQLite3 REQUIRED)
ladybird_lib(LibDatabase database EXPLICIT_SYMBOL_EXPORT)
target_link_libraries(LibDatabase PRIVATE LibCore SQLite::SQLite3)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022-2024, Tim Flynn <trflynn89@serenityos.org>
* Copyright (c) 2022-2025, Tim Flynn <trflynn89@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -8,12 +8,11 @@
#include <AK/String.h>
#include <AK/Time.h>
#include <LibCore/Directory.h>
#include <LibCore/StandardPaths.h>
#include <LibWebView/Database.h>
#include <LibDatabase/Database.h>
#include <sqlite3.h>
namespace WebView {
namespace Database {
static constexpr StringView sql_error(int error_code)
{
@ -39,13 +38,10 @@ static constexpr StringView sql_error(int error_code)
} \
})
ErrorOr<NonnullRefPtr<Database>> Database::create()
ErrorOr<NonnullRefPtr<Database>> Database::create(ByteString const& directory, StringView name)
{
// FIXME: Move this to a generic "Ladybird data directory" helper.
auto database_path = ByteString::formatted("{}/Ladybird", Core::StandardPaths::user_data_directory());
TRY(Core::Directory::create(database_path, Core::Directory::CreateDirectories::Yes));
auto database_file = ByteString::formatted("{}/Ladybird.db", database_path);
TRY(Core::Directory::create(directory, Core::Directory::CreateDirectories::Yes));
auto database_file = ByteString::formatted("{}/{}.db", directory, name);
sqlite3* m_database { nullptr };
SQL_TRY(sqlite3_open(database_file.characters(), &m_database));
@ -67,7 +63,7 @@ Database::~Database()
sqlite3_close(m_database);
}
ErrorOr<Database::StatementID> Database::prepare_statement(StringView statement)
ErrorOr<StatementID> Database::prepare_statement(StringView statement)
{
sqlite3_stmt* prepared_statement { nullptr };
SQL_TRY(sqlite3_prepare_v2(m_database, statement.characters_without_null_termination(), static_cast<int>(statement.length()), &prepared_statement, nullptr));
@ -119,10 +115,10 @@ void Database::apply_placeholder(StatementID statement_id, int index, ValueType
}
}
template void Database::apply_placeholder(StatementID, int, String const&);
template void Database::apply_placeholder(StatementID, int, UnixDateTime const&);
template void Database::apply_placeholder(StatementID, int, int const&);
template void Database::apply_placeholder(StatementID, int, bool const&);
template DATABASE_API void Database::apply_placeholder(StatementID, int, String const&);
template DATABASE_API void Database::apply_placeholder(StatementID, int, UnixDateTime const&);
template DATABASE_API void Database::apply_placeholder(StatementID, int, int const&);
template DATABASE_API void Database::apply_placeholder(StatementID, int, bool const&);
template<typename ValueType>
ValueType Database::result_column(StatementID statement_id, int column)
@ -144,9 +140,9 @@ ValueType Database::result_column(StatementID statement_id, int column)
VERIFY_NOT_REACHED();
}
template String Database::result_column(StatementID, int);
template UnixDateTime Database::result_column(StatementID, int);
template int Database::result_column(StatementID, int);
template bool Database::result_column(StatementID, int);
template DATABASE_API String Database::result_column(StatementID, int);
template DATABASE_API UnixDateTime Database::result_column(StatementID, int);
template DATABASE_API int Database::result_column(StatementID, int);
template DATABASE_API bool Database::result_column(StatementID, int);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022-2024, Tim Flynn <trflynn89@serenityos.org>
* Copyright (c) 2022-2025, Tim Flynn <trflynn89@ladybird.org>
* Copyright (c) 2023, Jelle Raaijmakers <jelle@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
@ -13,19 +13,18 @@
#include <AK/RefCounted.h>
#include <AK/StringView.h>
#include <AK/Vector.h>
#include <LibWebView/Forward.h>
#include <LibDatabase/Forward.h>
struct sqlite3;
struct sqlite3_stmt;
namespace WebView {
namespace Database {
class WEBVIEW_API Database : public RefCounted<Database> {
class DATABASE_API Database : public RefCounted<Database> {
public:
static ErrorOr<NonnullRefPtr<Database>> create();
static ErrorOr<NonnullRefPtr<Database>> create(ByteString const& directory, StringView name);
~Database();
using StatementID = size_t;
using OnResult = Function<void(StatementID)>;
ErrorOr<StatementID> prepare_statement(StringView statement);

View File

@ -0,0 +1,18 @@
/*
* Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Types.h>
#include <LibDatabase/Export.h>
namespace Database {
class Database;
using StatementID = size_t;
}

View File

@ -10,6 +10,7 @@
#include <LibCore/StandardPaths.h>
#include <LibCore/System.h>
#include <LibCore/TimeZoneWatcher.h>
#include <LibDatabase/Database.h>
#include <LibDevTools/DevToolsServer.h>
#include <LibFileSystem/FileSystem.h>
#include <LibImageDecoderClient/Client.h>
@ -17,7 +18,6 @@
#include <LibWeb/Loader/UserAgent.h>
#include <LibWebView/Application.h>
#include <LibWebView/CookieJar.h>
#include <LibWebView/Database.h>
#include <LibWebView/HeadlessWebView.h>
#include <LibWebView/HelperProcess.h>
#include <LibWebView/Menu.h>
@ -347,9 +347,12 @@ ErrorOr<void> Application::launch_services()
};
if (m_browser_options.disable_sql_database == DisableSQLDatabase::No) {
m_database = Database::create().release_value_but_fixme_should_propagate_errors();
m_cookie_jar = CookieJar::create(*m_database).release_value_but_fixme_should_propagate_errors();
m_storage_jar = StorageJar::create(*m_database).release_value_but_fixme_should_propagate_errors();
// FIXME: Move this to a generic "Ladybird data directory" helper.
auto database_path = ByteString::formatted("{}/Ladybird", Core::StandardPaths::user_data_directory());
m_database = TRY(Database::Database::create(database_path, "Ladybird"sv));
m_cookie_jar = TRY(CookieJar::create(*m_database));
m_storage_jar = TRY(StorageJar::create(*m_database));
} else {
m_cookie_jar = CookieJar::create();
m_storage_jar = StorageJar::create();

View File

@ -12,6 +12,7 @@
#include <AK/Swift.h>
#include <LibCore/EventLoop.h>
#include <LibCore/Forward.h>
#include <LibDatabase/Forward.h>
#include <LibDevTools/DevToolsDelegate.h>
#include <LibDevTools/Forward.h>
#include <LibImageDecoderClient/Client.h>
@ -181,7 +182,7 @@ private:
RefPtr<WebContentClient> m_spare_web_content_process;
bool m_has_queued_task_to_launch_spare_web_content_process { false };
RefPtr<Database> m_database;
RefPtr<Database::Database> m_database;
OwnPtr<CookieJar> m_cookie_jar;
OwnPtr<StorageJar> m_storage_jar;

View File

@ -7,7 +7,6 @@ set(SOURCES
BrowserProcess.cpp
ConsoleOutput.cpp
CookieJar.cpp
Database.cpp
DOMNodeProperties.cpp
HeadlessWebView.cpp
HelperProcess.cpp
@ -70,16 +69,13 @@ set(GENERATED_SOURCES
)
ladybird_lib(LibWebView webview EXPLICIT_SYMBOL_EXPORT)
target_link_libraries(LibWebView PRIVATE LibCore LibDevTools LibFileSystem LibGfx LibImageDecoderClient LibIPC LibRequests LibJS LibWeb LibUnicode LibURL LibSyntax LibTextCodec)
target_link_libraries(LibWebView PRIVATE LibCore LibDatabase LibDevTools LibFileSystem LibGfx LibImageDecoderClient LibIPC LibRequests LibJS LibWeb LibUnicode LibURL LibSyntax LibTextCodec)
if (APPLE)
target_link_libraries(LibWebView PRIVATE LibThreading)
endif()
# Third-party
find_package(SQLite3 REQUIRED)
target_link_libraries(LibWebView PRIVATE SQLite::SQLite3)
if (HAS_FONTCONFIG)
target_link_libraries(LibWebView PRIVATE Fontconfig::Fontconfig)
endif()

View File

@ -11,6 +11,7 @@
#include <AK/StringBuilder.h>
#include <AK/Time.h>
#include <AK/Vector.h>
#include <LibDatabase/Database.h>
#include <LibURL/URL.h>
#include <LibWeb/Cookie/ParsedCookie.h>
#include <LibWebView/CookieJar.h>
@ -20,7 +21,7 @@ namespace WebView {
static constexpr auto DATABASE_SYNCHRONIZATION_TIMER = AK::Duration::from_seconds(30);
ErrorOr<NonnullOwnPtr<CookieJar>> CookieJar::create(Database& database)
ErrorOr<NonnullOwnPtr<CookieJar>> CookieJar::create(Database::Database& database)
{
Statements statements {};
@ -665,7 +666,7 @@ void CookieJar::PersistedStorage::insert_cookie(Web::Cookie::Cookie const& cooki
cookie.persistent);
}
static Web::Cookie::Cookie parse_cookie(Database& database, Database::StatementID statement_id)
static Web::Cookie::Cookie parse_cookie(Database::Database& database, Database::StatementID statement_id)
{
int column = 0;
auto convert_text = [&](auto& field) { field = database.result_column<String>(statement_id, column++); };

View File

@ -13,10 +13,10 @@
#include <AK/StringView.h>
#include <AK/Traits.h>
#include <LibCore/Timer.h>
#include <LibDatabase/Forward.h>
#include <LibURL/Forward.h>
#include <LibWeb/Cookie/Cookie.h>
#include <LibWeb/Forward.h>
#include <LibWebView/Database.h>
#include <LibWebView/Forward.h>
namespace WebView {
@ -76,13 +76,13 @@ class WEBVIEW_API CookieJar {
void insert_cookie(Web::Cookie::Cookie const& cookie);
TransientStorage::Cookies select_all_cookies();
Database& database;
Database::Database& database;
Statements statements;
RefPtr<Core::Timer> synchronization_timer {};
};
public:
static ErrorOr<NonnullOwnPtr<CookieJar>> create(Database&);
static ErrorOr<NonnullOwnPtr<CookieJar>> create(Database::Database&);
static NonnullOwnPtr<CookieJar> create();
~CookieJar();

View File

@ -16,7 +16,6 @@ class Action;
class Application;
class Autocomplete;
class CookieJar;
class Database;
class Menu;
class OutOfProcessWebView;
class ProcessManager;

View File

@ -6,6 +6,7 @@
#include <AK/NonnullOwnPtr.h>
#include <AK/StdLibExtras.h>
#include <LibDatabase/Database.h>
#include <LibWebView/StorageJar.h>
namespace WebView {
@ -13,7 +14,7 @@ namespace WebView {
// Quota size is specified in https://storage.spec.whatwg.org/#registered-storage-endpoints
static constexpr size_t LOCAL_STORAGE_QUOTA = 5 * MiB;
ErrorOr<NonnullOwnPtr<StorageJar>> StorageJar::create(Database& database)
ErrorOr<NonnullOwnPtr<StorageJar>> StorageJar::create(Database::Database& database)
{
Statements statements {};

View File

@ -9,8 +9,8 @@
#include <AK/HashMap.h>
#include <AK/String.h>
#include <AK/Traits.h>
#include <LibDatabase/Forward.h>
#include <LibWeb/StorageAPI/StorageEndpoint.h>
#include <LibWebView/Database.h>
#include <LibWebView/Forward.h>
#include <LibWebView/StorageOperationError.h>
@ -31,7 +31,7 @@ class WEBVIEW_API StorageJar {
AK_MAKE_NONMOVABLE(StorageJar);
public:
static ErrorOr<NonnullOwnPtr<StorageJar>> create(Database&);
static ErrorOr<NonnullOwnPtr<StorageJar>> create(Database::Database&);
static NonnullOwnPtr<StorageJar> create();
~StorageJar();
@ -71,7 +71,7 @@ private:
void clear(StorageEndpointType storage_endpoint, String const& storage_key);
Vector<String> get_keys(StorageEndpointType storage_endpoint, String const& storage_key);
Database& database;
Database::Database& database;
Statements statements;
};