diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index 55ca653d986..b9f3eab6734 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -567,6 +567,7 @@ set(SOURCES IndexedDB/IDBVersionChangeEvent.cpp IndexedDB/Internal/Algorithms.cpp IndexedDB/Internal/Database.cpp + IndexedDB/Internal/Index.cpp IndexedDB/Internal/Key.cpp IndexedDB/Internal/ObjectStore.cpp IndexedDB/Internal/RequestList.cpp diff --git a/Libraries/LibWeb/Forward.h b/Libraries/LibWeb/Forward.h index 8a9eca06696..0271a0c1d39 100644 --- a/Libraries/LibWeb/Forward.h +++ b/Libraries/LibWeb/Forward.h @@ -625,6 +625,7 @@ class IDBOpenDBRequest; class IDBRequest; class IDBTransaction; class IDBVersionChangeEvent; +class Index; class ObjectStore; class RequestList; } diff --git a/Libraries/LibWeb/IndexedDB/Internal/Index.cpp b/Libraries/LibWeb/IndexedDB/Internal/Index.cpp new file mode 100644 index 00000000000..38ea6e1e27e --- /dev/null +++ b/Libraries/LibWeb/IndexedDB/Internal/Index.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025, stelar7 + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace Web::IndexedDB { + +GC_DEFINE_ALLOCATOR(Index); + +Index::~Index() = default; + +GC::Ref Index::create(JS::Realm& realm, GC::Ref store, String name, KeyPath const& key_path, bool unique, bool multi_entry) +{ + return realm.create(store, name, key_path, unique, multi_entry); +} + +Index::Index(GC::Ref store, String name, KeyPath const& key_path, bool unique, bool multi_entry) + : m_object_store(store) + , m_name(move(name)) + , m_unique(unique) + , m_multi_entry(multi_entry) + , m_key_path(key_path) +{ + store->add_index(*this); +} + +void Index::visit_edges(Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(m_object_store); + + for (auto& record : m_records) { + visitor.visit(record.key); + visitor.visit(record.value); + } +} + +} diff --git a/Libraries/LibWeb/IndexedDB/Internal/Index.h b/Libraries/LibWeb/IndexedDB/Internal/Index.h new file mode 100644 index 00000000000..e984ffbc1b4 --- /dev/null +++ b/Libraries/LibWeb/IndexedDB/Internal/Index.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2025, stelar7 + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace Web::IndexedDB { + +using KeyPath = Variant>; + +// https://w3c.github.io/IndexedDB/#index-list-of-records +struct IndexRecord { + GC::Ref key; + GC::Ref value; +}; + +// https://w3c.github.io/IndexedDB/#index-construct +class Index : public JS::Cell { + GC_CELL(Index, JS::Cell); + GC_DECLARE_ALLOCATOR(Index); + +public: + [[nodiscard]] static GC::Ref create(JS::Realm&, GC::Ref, String, KeyPath const&, bool, bool); + virtual ~Index(); + + void set_name(String name) { m_name = move(name); } + [[nodiscard]] String name() const { return m_name; } + [[nodiscard]] bool unique() const { return m_unique; } + [[nodiscard]] bool multi_entry() const { return m_multi_entry; } + [[nodiscard]] GC::Ref object_store() const { return m_object_store; } + [[nodiscard]] AK::ReadonlySpan records() const { return m_records; } + [[nodiscard]] KeyPath const& key_path() const { return m_key_path; } + +protected: + virtual void visit_edges(Visitor&) override; + +private: + Index(GC::Ref, String, KeyPath const&, bool, bool); + + // An index [...] has a referenced object store. + GC::Ref m_object_store; + + // The index has a list of records which hold the data stored in the index. + Vector m_records; + + // An index has a name, which is a name. At any one time, the name is unique within index’s referenced object store. + String m_name; + + // An index has a unique flag. When true, the index enforces that no two records in the index has the same key. + bool m_unique { false }; + + // An index has a multiEntry flag. This flag affects how the index behaves when the result of evaluating the index’s key path yields an array key. + bool m_multi_entry { false }; + + // The keys are derived from the referenced object store’s values using a key path. + KeyPath m_key_path; +}; + +} diff --git a/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.cpp b/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.cpp index 2169030f821..3fe00e26cd2 100644 --- a/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.cpp +++ b/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.cpp @@ -32,6 +32,7 @@ void ObjectStore::visit_edges(Visitor& visitor) { Base::visit_edges(visitor); visitor.visit(m_database); + visitor.visit(m_indexes); } } diff --git a/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.h b/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.h index 99b7de285ba..d7f400e37bc 100644 --- a/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.h +++ b/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.h @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace Web::IndexedDB { @@ -39,6 +40,9 @@ public: GC::Ref database() const { return m_database; } + void add_index(GC::Ref index) { m_indexes.append(index); } + ReadonlySpan> index_set() const { return m_indexes; } + protected: virtual void visit_edges(Visitor&) override; @@ -48,6 +52,9 @@ private: // AD-HOC: An ObjectStore needs to know what Database it belongs to... GC::Ref m_database; + // AD-HOC: An Index has referenced ObjectStores, we also need the reverse mapping + Vector> m_indexes; + // An object store has a name, which is a name. At any one time, the name is unique within the database to which it belongs. String m_name;