diff --git a/Libraries/LibWeb/IndexedDB/IDBCursor.cpp b/Libraries/LibWeb/IndexedDB/IDBCursor.cpp index 91e3c9a74c0..bb65e5d220a 100644 --- a/Libraries/LibWeb/IndexedDB/IDBCursor.cpp +++ b/Libraries/LibWeb/IndexedDB/IDBCursor.cpp @@ -16,23 +16,22 @@ GC_DEFINE_ALLOCATOR(IDBCursor); IDBCursor::~IDBCursor() = default; -IDBCursor::IDBCursor(JS::Realm& realm, GC::Ref transaction, GC::Ptr position, Bindings::IDBCursorDirection direction, bool got_value, GC::Ptr key, JS::Value value, CursorSource source, GC::Ref range, bool key_only) +IDBCursor::IDBCursor(JS::Realm& realm, CursorSourceHandle source_handle, GC::Ptr position, Bindings::IDBCursorDirection direction, bool got_value, GC::Ptr key, JS::Value value, GC::Ref range, bool key_only) : PlatformObject(realm) - , m_transaction(transaction) , m_position(position) , m_direction(direction) , m_got_value(got_value) , m_key(key) , m_value(value) - , m_source(source) + , m_source_handle(source_handle) , m_range(range) , m_key_only(key_only) { } -GC::Ref IDBCursor::create(JS::Realm& realm, GC::Ref transaction, GC::Ptr position, Bindings::IDBCursorDirection direction, bool got_value, GC::Ptr key, JS::Value value, CursorSource source, GC::Ref range, bool key_only) +GC::Ref IDBCursor::create(JS::Realm& realm, CursorSourceHandle source_handle, GC::Ptr position, Bindings::IDBCursorDirection direction, bool got_value, GC::Ptr key, JS::Value value, GC::Ref range, bool key_only) { - return realm.create(realm, transaction, position, direction, got_value, key, value, source, range, key_only); + return realm.create(realm, source_handle, position, direction, got_value, key, value, range, key_only); } void IDBCursor::initialize(JS::Realm& realm) @@ -44,18 +43,35 @@ void IDBCursor::initialize(JS::Realm& realm) void IDBCursor::visit_edges(Visitor& visitor) { Base::visit_edges(visitor); - visitor.visit(m_transaction); visitor.visit(m_position); visitor.visit(m_object_store_position); visitor.visit(m_key); visitor.visit(m_range); visitor.visit(m_request); - m_source.visit([&](auto& source) { + m_source_handle.visit([&](auto& source) { visitor.visit(source); }); } +// https://w3c.github.io/IndexedDB/#cursor-transaction +GC::Ref IDBCursor::transaction() +{ + // A cursor has a transaction, which is the transaction from the cursor’s source handle. + return m_source_handle.visit( + [](GC::Ref object_store) { return object_store->transaction(); }, + [](GC::Ref index) { return index->transaction(); }); +} + +// https://w3c.github.io/IndexedDB/#cursor-source +CursorSource IDBCursor::internal_source() +{ + // A cursor has a source, which is an index or an object store from the cursor’s source handle. + return m_source_handle.visit( + [](GC::Ref object_store) -> CursorSource { return object_store->store(); }, + [](GC::Ref index) -> CursorSource { return index->index(); }); +} + // https://w3c.github.io/IndexedDB/#dom-idbcursor-key JS::Value IDBCursor::key() { @@ -125,8 +141,8 @@ WebIDL::ExceptionOr IDBCursor::continue_(JS::Value key) return WebIDL::ExceptionOr(iterate_a_cursor(realm, *this, key_value)); }); - // 11. Run asynchronously execute a request with this's source, operation, and request. - asynchronously_execute_a_request(realm, GC::Ref(*this), operation, request); + // 11. Run asynchronously execute a request with this’s source handle, operation, and request. + asynchronously_execute_a_request(realm, source_handle(), operation, request); dbgln_if(IDB_DEBUG, "Executing request for cursor continue with uuid {}", request->uuid()); return {}; diff --git a/Libraries/LibWeb/IndexedDB/IDBCursor.h b/Libraries/LibWeb/IndexedDB/IDBCursor.h index e1085380688..ba0b09de8e2 100644 --- a/Libraries/LibWeb/IndexedDB/IDBCursor.h +++ b/Libraries/LibWeb/IndexedDB/IDBCursor.h @@ -17,7 +17,8 @@ namespace Web::IndexedDB { -using CursorSource = Variant, GC::Ref>; +using CursorSourceHandle = Variant, GC::Ref>; +using CursorSource = Variant, GC::Ref>; // https://w3c.github.io/IndexedDB/#cursor-interface class IDBCursor : public Bindings::PlatformObject { @@ -26,20 +27,22 @@ class IDBCursor : public Bindings::PlatformObject { public: virtual ~IDBCursor() override; - [[nodiscard]] static GC::Ref create(JS::Realm&, GC::Ref, GC::Ptr, Bindings::IDBCursorDirection, bool, GC::Ptr, JS::Value, CursorSource, GC::Ref, bool); + [[nodiscard]] static GC::Ref create(JS::Realm&, CursorSourceHandle, GC::Ptr, Bindings::IDBCursorDirection, bool, GC::Ptr, JS::Value, GC::Ref, bool); - [[nodiscard]] CursorSource source() { return m_source; } + [[nodiscard]] CursorSourceHandle source_handle() { return m_source_handle; } [[nodiscard]] Bindings::IDBCursorDirection direction() { return m_direction; } [[nodiscard]] JS::Value key(); [[nodiscard]] JS::Value value() { return m_value.value_or(JS::js_undefined()); } [[nodiscard]] GC::Ptr request() { return m_request; } - [[nodiscard]] GC::Ref transaction() { return m_transaction; } [[nodiscard]] GC::Ref range() { return m_range; } [[nodiscard]] GC::Ptr position() { return m_position; } [[nodiscard]] GC::Ptr object_store_position() { return m_object_store_position; } [[nodiscard]] bool key_only() const { return m_key_only; } [[nodiscard]] bool got_value() const { return m_got_value; } + [[nodiscard]] GC::Ref transaction(); + [[nodiscard]] CursorSource internal_source(); + void set_request(GC::Ptr request) { m_request = request; } void set_position(GC::Ptr position) { m_position = position; } void set_got_value(bool got_value) { m_got_value = got_value; } @@ -50,14 +53,11 @@ public: WebIDL::ExceptionOr continue_(JS::Value); protected: - explicit IDBCursor(JS::Realm&, GC::Ref, GC::Ptr, Bindings::IDBCursorDirection, bool, GC::Ptr, JS::Value, CursorSource, GC::Ref, bool); + explicit IDBCursor(JS::Realm&, CursorSourceHandle, GC::Ptr, Bindings::IDBCursorDirection, bool, GC::Ptr, JS::Value, GC::Ref, bool); virtual void initialize(JS::Realm&) override; virtual void visit_edges(Visitor& visitor) override; private: - // A cursor has a transaction, the transaction that was active when the cursor was created. - GC::Ref m_transaction; - // A cursor has a position within its range. GC::Ptr m_position; @@ -74,8 +74,8 @@ private: GC::Ptr m_key; Optional m_value; - // A cursor has a source that indicates which index or an object store is associated with the records over which the cursor is iterating. - CursorSource m_source; + // A cursor has a source handle, which is the index handle or the object store handle that opened the cursor. + CursorSourceHandle m_source_handle; // A cursor has a range of records in either an index or an object store. GC::Ref m_range; diff --git a/Libraries/LibWeb/IndexedDB/IDBCursor.idl b/Libraries/LibWeb/IndexedDB/IDBCursor.idl index 9cd47afbc4d..f6d735198bc 100644 --- a/Libraries/LibWeb/IndexedDB/IDBCursor.idl +++ b/Libraries/LibWeb/IndexedDB/IDBCursor.idl @@ -2,7 +2,7 @@ [Exposed=(Window,Worker)] interface IDBCursor { - readonly attribute (IDBObjectStore or IDBIndex) source; + [ImplementedAs=source_handle] readonly attribute (IDBObjectStore or IDBIndex) source; readonly attribute IDBCursorDirection direction; readonly attribute any key; [FIXME] readonly attribute any primaryKey; diff --git a/Libraries/LibWeb/IndexedDB/IDBIndex.cpp b/Libraries/LibWeb/IndexedDB/IDBIndex.cpp index 56920cd80e8..8d4df08df87 100644 --- a/Libraries/LibWeb/IndexedDB/IDBIndex.cpp +++ b/Libraries/LibWeb/IndexedDB/IDBIndex.cpp @@ -101,19 +101,4 @@ JS::Value IDBIndex::key_path() const }); } -// https://w3c.github.io/IndexedDB/#index-referenced-value -HTML::SerializationRecord IDBIndex::get_referenced_value(IndexRecord const& index_record) const -{ - // Records in an index are said to have a referenced value. - // This is the value of the record in the index’s referenced object store which has a key equal to the index’s record’s value. - return m_index - ->object_store() - ->records() - .first_matching([&](auto const& store_record) { - return Key::equals(store_record.key, index_record.value); - }) - .value() - .value; -} - } diff --git a/Libraries/LibWeb/IndexedDB/IDBIndex.h b/Libraries/LibWeb/IndexedDB/IDBIndex.h index 2189a9b4167..bdf5fc8c48c 100644 --- a/Libraries/LibWeb/IndexedDB/IDBIndex.h +++ b/Libraries/LibWeb/IndexedDB/IDBIndex.h @@ -33,8 +33,6 @@ public: GC::Ref transaction() { return m_object_store_handle->transaction(); } GC::Ref index() { return m_index; } - HTML::SerializationRecord get_referenced_value(IndexRecord const& index_record) const; - protected: explicit IDBIndex(JS::Realm&, GC::Ref, GC::Ref); virtual void initialize(JS::Realm&) override; diff --git a/Libraries/LibWeb/IndexedDB/IDBObjectStore.cpp b/Libraries/LibWeb/IndexedDB/IDBObjectStore.cpp index 6a05040553d..5641bfb8edc 100644 --- a/Libraries/LibWeb/IndexedDB/IDBObjectStore.cpp +++ b/Libraries/LibWeb/IndexedDB/IDBObjectStore.cpp @@ -419,9 +419,9 @@ WebIDL::ExceptionOr> IDBObjectStore::open_cursor(JS::Value q // 5. Let range be the result of converting a value to a key range with query. Rethrow any exceptions. auto range = TRY(convert_a_value_to_a_key_range(realm, query, false)); - // 6. Let cursor be a new cursor with its transaction set to transaction, undefined position, direction set to direction, - // got value flag set to false, undefined key and value, source set to store, range set to range, and key only flag set to false. - auto cursor = IDBCursor::create(realm, transaction, {}, direction, false, {}, {}, GC::Ref(*this), range, false); + // 6. Let cursor be a new cursor with its source handle set to this, undefined position, direction set to direction, + // got value flag set to false, undefined key and value, range set to range, and key only flag set to false. + auto cursor = IDBCursor::create(realm, GC::Ref(*this), {}, direction, false, {}, {}, range, false); // 7. Let operation be an algorithm to run iterate a cursor with the current Realm record and cursor. auto operation = GC::Function()>::create(realm.heap(), [&realm, cursor] -> WebIDL::ExceptionOr { diff --git a/Libraries/LibWeb/IndexedDB/Internal/Algorithms.cpp b/Libraries/LibWeb/IndexedDB/Internal/Algorithms.cpp index 2824ed3aecd..c094b0815aa 100644 --- a/Libraries/LibWeb/IndexedDB/Internal/Algorithms.cpp +++ b/Libraries/LibWeb/IndexedDB/Internal/Algorithms.cpp @@ -1481,7 +1481,7 @@ WebIDL::ExceptionOr retrieve_a_value_from_an_object_store(JS::Realm& GC::Ptr iterate_a_cursor(JS::Realm& realm, GC::Ref cursor, GC::Ptr key, GC::Ptr primary_key, u64 count) { // 1. Let source be cursor’s source. - auto source = cursor->source(); + auto source = cursor->internal_source(); // 2. Let direction be cursor’s direction. auto direction = cursor->direction(); @@ -1489,15 +1489,15 @@ GC::Ptr iterate_a_cursor(JS::Realm& realm, GC::Ref cursor, // 3. Assert: if primaryKey is given, source is an index and direction is "next" or "prev". auto direction_is_next_or_prev = direction == Bindings::IDBCursorDirection::Next || direction == Bindings::IDBCursorDirection::Prev; if (primary_key) - VERIFY(source.has>() && direction_is_next_or_prev); + VERIFY(source.has>() && direction_is_next_or_prev); // 4. Let records be the list of records in source. Variant, ReadonlySpan> records = source.visit( - [](GC::Ref object_store) -> Variant, ReadonlySpan> { - return object_store->store()->records(); + [](GC::Ref object_store) -> Variant, ReadonlySpan> { + return object_store->records(); }, - [](GC::Ref index) -> Variant, ReadonlySpan> { - return index->index()->records(); + [](GC::Ref index) -> Variant, ReadonlySpan> { + return index->records(); }); // 5. Let range be cursor’s range. @@ -1540,7 +1540,7 @@ GC::Ptr iterate_a_cursor(JS::Realm& realm, GC::Ref cursor, } // * If position is defined, and source is an object store, - if (position && source.has>()) { + if (position && source.has>()) { auto const& inner_record = record.get(); // * the record’s key is greater than position. @@ -1549,7 +1549,7 @@ GC::Ptr iterate_a_cursor(JS::Realm& realm, GC::Ref cursor, } // * If position is defined, and source is an index, - if (position && source.has>()) { + if (position && source.has>()) { auto const& inner_record = record.get(); // * the record’s key is equal to position and the record’s value is greater than object store position @@ -1636,7 +1636,7 @@ GC::Ptr iterate_a_cursor(JS::Realm& realm, GC::Ref cursor, } // * If position is defined, and source is an object store, - if (position && source.has>()) { + if (position && source.has>()) { auto const& inner_record = record.get(); // * the record’s key is less than position. @@ -1645,7 +1645,7 @@ GC::Ptr iterate_a_cursor(JS::Realm& realm, GC::Ref cursor, } // * If position is defined, and source is an index, - if (position && source.has>()) { + if (position && source.has>()) { auto const& inner_record = record.get(); // * the record’s key is equal to position and the record’s value is less than object store position @@ -1780,7 +1780,7 @@ GC::Ptr iterate_a_cursor(JS::Realm& realm, GC::Ref cursor, cursor->set_key(nullptr); // 2. If source is an index, set cursor’s object store position to undefined. - if (source.has>()) + if (source.has>()) cursor->set_object_store_position(nullptr); // 3. If cursor’s key only flag is false, set cursor’s value to undefined. @@ -1797,7 +1797,7 @@ GC::Ptr iterate_a_cursor(JS::Realm& realm, GC::Ref cursor, [](auto val) { return val.key; }); // 4. If source is an index, let object store position be found record’s value. - if (source.has>()) + if (source.has>()) object_store_position = found_record.get().value; // 5. Decrease count by 1. @@ -1808,7 +1808,7 @@ GC::Ptr iterate_a_cursor(JS::Realm& realm, GC::Ref cursor, cursor->set_position(position); // 11. If source is an index, set cursor’s object store position to object store position. - if (source.has>()) + if (source.has>()) cursor->set_object_store_position(object_store_position); // 12. Set cursor’s key to found record’s key. @@ -1821,11 +1821,11 @@ GC::Ptr iterate_a_cursor(JS::Realm& realm, GC::Ref cursor, // 1. Let serialized be found record’s value if source is an object store, or found record’s referenced value otherwise. auto serialized = source.visit( - [&](GC::Ref) { + [&](GC::Ref) { return found_record.get().value; }, - [&](GC::Ref index) { - return index->get_referenced_value(found_record.get()); + [&](GC::Ref index) { + return index->referenced_value(found_record.get()); }); // 2. Set cursor’s value to ! StructuredDeserialize(serialized, targetRealm) diff --git a/Libraries/LibWeb/IndexedDB/Internal/Index.cpp b/Libraries/LibWeb/IndexedDB/Internal/Index.cpp index 8ebc95c101f..04becff6d3a 100644 --- a/Libraries/LibWeb/IndexedDB/Internal/Index.cpp +++ b/Libraries/LibWeb/IndexedDB/Internal/Index.cpp @@ -57,4 +57,18 @@ bool Index::has_record_with_key(GC::Ref key) return index != m_records.end(); } +// https://w3c.github.io/IndexedDB/#index-referenced-value +HTML::SerializationRecord Index::referenced_value(IndexRecord const& index_record) const +{ + // Records in an index are said to have a referenced value. + // This is the value of the record in the index’s referenced object store which has a key equal to the index’s record’s value. + return m_object_store + ->records() + .first_matching([&](auto const& store_record) { + return Key::equals(store_record.key, index_record.value); + }) + .value() + .value; +} + } diff --git a/Libraries/LibWeb/IndexedDB/Internal/Index.h b/Libraries/LibWeb/IndexedDB/Internal/Index.h index 130526f1845..83903e89eb9 100644 --- a/Libraries/LibWeb/IndexedDB/Internal/Index.h +++ b/Libraries/LibWeb/IndexedDB/Internal/Index.h @@ -41,6 +41,8 @@ public: [[nodiscard]] bool has_record_with_key(GC::Ref key); + HTML::SerializationRecord referenced_value(IndexRecord const& index_record) const; + protected: virtual void visit_edges(Visitor&) override;