From e74e571b561deb6b21890a58d109a9f6514c1968 Mon Sep 17 00:00:00 2001 From: stelar7 Date: Tue, 13 May 2025 22:18:14 +0200 Subject: [PATCH] LibWeb/IDB: Implement IDBIndex::get --- Libraries/LibWeb/IndexedDB/IDBIndex.cpp | 31 +++++++++++++++++++ Libraries/LibWeb/IndexedDB/IDBIndex.h | 5 +-- Libraries/LibWeb/IndexedDB/IDBIndex.idl | 2 +- .../LibWeb/IndexedDB/Internal/Algorithms.cpp | 17 ++++++++++ .../LibWeb/IndexedDB/Internal/Algorithms.h | 2 ++ Libraries/LibWeb/IndexedDB/Internal/Index.cpp | 7 +++++ Libraries/LibWeb/IndexedDB/Internal/Index.h | 1 + 7 files changed, 62 insertions(+), 3 deletions(-) diff --git a/Libraries/LibWeb/IndexedDB/IDBIndex.cpp b/Libraries/LibWeb/IndexedDB/IDBIndex.cpp index 75095c2ab08..e0dd15b7910 100644 --- a/Libraries/LibWeb/IndexedDB/IDBIndex.cpp +++ b/Libraries/LibWeb/IndexedDB/IDBIndex.cpp @@ -141,4 +141,35 @@ WebIDL::ExceptionOr> IDBIndex::open_cursor(JS::Value query, return request; } +// https://w3c.github.io/IndexedDB/#dom-idbindex-get +WebIDL::ExceptionOr> IDBIndex::get(JS::Value query) +{ + auto& realm = this->realm(); + + // 1. Let transaction be this’s transaction. + auto transaction = this->transaction(); + + // 2. Let index be this’s index. + auto index = this->index(); + + // FIXME: 3. If index or index’s object store has been deleted, throw an "InvalidStateError" DOMException. + + // 4. If transaction’s state is not active, then throw a "TransactionInactiveError" DOMException. + if (transaction->state() != IDBTransaction::TransactionState::Active) + return WebIDL::TransactionInactiveError::create(realm, "Transaction is not active while getting"_string); + + // 5. Let range be the result of converting a value to a key range with query and true. Rethrow any exceptions. + auto range = TRY(convert_a_value_to_a_key_range(realm, query, true)); + + // 6. Let operation be an algorithm to run retrieve a referenced value from an index with the current Realm record, index, and range. + auto operation = GC::Function()>::create(realm.heap(), [&realm, index, range] -> WebIDL::ExceptionOr { + return retrieve_a_referenced_value_from_an_index(realm, index, range); + }); + + // 7. Return the result (an IDBRequest) of running asynchronously execute a request with this and operation. + auto result = asynchronously_execute_a_request(realm, GC::Ref(*this), operation); + dbgln_if(IDB_DEBUG, "Executing request for get with uuid {}", result->uuid()); + return result; +} + } diff --git a/Libraries/LibWeb/IndexedDB/IDBIndex.h b/Libraries/LibWeb/IndexedDB/IDBIndex.h index 007bee2b77a..6579437e13b 100644 --- a/Libraries/LibWeb/IndexedDB/IDBIndex.h +++ b/Libraries/LibWeb/IndexedDB/IDBIndex.h @@ -29,12 +29,13 @@ public: bool multi_entry() const { return m_index->multi_entry(); } bool unique() const { return m_index->unique(); } + [[nodiscard]] WebIDL::ExceptionOr> get(JS::Value); + [[nodiscard]] WebIDL::ExceptionOr> open_cursor(JS::Value, Bindings::IDBCursorDirection = Bindings::IDBCursorDirection::Next); + // The transaction of an index handle is the transaction of its associated object store handle. GC::Ref transaction() { return m_object_store_handle->transaction(); } GC::Ref index() { return m_index; } - [[nodiscard]] WebIDL::ExceptionOr> open_cursor(JS::Value, Bindings::IDBCursorDirection = Bindings::IDBCursorDirection::Next); - protected: explicit IDBIndex(JS::Realm&, GC::Ref, GC::Ref); virtual void initialize(JS::Realm&) override; diff --git a/Libraries/LibWeb/IndexedDB/IDBIndex.idl b/Libraries/LibWeb/IndexedDB/IDBIndex.idl index bc477a890a3..c2f2b45c670 100644 --- a/Libraries/LibWeb/IndexedDB/IDBIndex.idl +++ b/Libraries/LibWeb/IndexedDB/IDBIndex.idl @@ -7,7 +7,7 @@ interface IDBIndex { readonly attribute any keyPath; readonly attribute boolean multiEntry; readonly attribute boolean unique; - [FIXME, NewObject] IDBRequest get(any query); + [NewObject] IDBRequest get(any query); [FIXME, NewObject] IDBRequest getKey(any query); [FIXME, NewObject] IDBRequest getAll(optional any query, optional [EnforceRange] unsigned long count); [FIXME, NewObject] IDBRequest getAllKeys(optional any query, optional [EnforceRange] unsigned long count); diff --git a/Libraries/LibWeb/IndexedDB/Internal/Algorithms.cpp b/Libraries/LibWeb/IndexedDB/Internal/Algorithms.cpp index 08e8794bca7..4da8ec07058 100644 --- a/Libraries/LibWeb/IndexedDB/Internal/Algorithms.cpp +++ b/Libraries/LibWeb/IndexedDB/Internal/Algorithms.cpp @@ -1929,4 +1929,21 @@ GC::Ref retrieve_multiple_keys_from_an_object_store(JS::Realm& realm, return list; } +// https://w3c.github.io/IndexedDB/#retrieve-a-referenced-value-from-an-index +JS::Value retrieve_a_referenced_value_from_an_index(JS::Realm& realm, GC::Ref index, GC::Ref range) +{ + // 1. Let record be the first record in index’s list of records whose key is in range, if any. + auto record = index->first_in_range(range); + + // 2. If record was not found, return undefined. + if (!record.has_value()) + return JS::js_undefined(); + + // 3. Let serialized be record’s referenced value. + auto serialized = index->referenced_value(*record); + + // 4. Return ! StructuredDeserialize(serialized, targetRealm). + return MUST(HTML::structured_deserialize(realm.vm(), serialized, realm)); +} + } diff --git a/Libraries/LibWeb/IndexedDB/Internal/Algorithms.h b/Libraries/LibWeb/IndexedDB/Internal/Algorithms.h index 1e809d2bfb6..0bc4f76fdbc 100644 --- a/Libraries/LibWeb/IndexedDB/Internal/Algorithms.h +++ b/Libraries/LibWeb/IndexedDB/Internal/Algorithms.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -50,5 +51,6 @@ JS::Value clear_an_object_store(GC::Ref); JS::Value retrieve_a_key_from_an_object_store(JS::Realm&, GC::Ref, GC::Ref); GC::Ref retrieve_multiple_values_from_an_object_store(JS::Realm&, GC::Ref, GC::Ref, Optional); GC::Ref retrieve_multiple_keys_from_an_object_store(JS::Realm&, GC::Ref, GC::Ref, Optional); +JS::Value retrieve_a_referenced_value_from_an_index(JS::Realm&, GC::Ref, GC::Ref); } diff --git a/Libraries/LibWeb/IndexedDB/Internal/Index.cpp b/Libraries/LibWeb/IndexedDB/Internal/Index.cpp index b71fc0f5a3c..1689fec1336 100644 --- a/Libraries/LibWeb/IndexedDB/Internal/Index.cpp +++ b/Libraries/LibWeb/IndexedDB/Internal/Index.cpp @@ -76,4 +76,11 @@ void Index::clear_records() m_records.clear(); } +Optional Index::first_in_range(GC::Ref range) +{ + return m_records.first_matching([&](auto const& record) { + return range->is_in_range(record.key); + }); +} + } diff --git a/Libraries/LibWeb/IndexedDB/Internal/Index.h b/Libraries/LibWeb/IndexedDB/Internal/Index.h index bad62d0cd47..a71dfeb040d 100644 --- a/Libraries/LibWeb/IndexedDB/Internal/Index.h +++ b/Libraries/LibWeb/IndexedDB/Internal/Index.h @@ -41,6 +41,7 @@ public: [[nodiscard]] bool has_record_with_key(GC::Ref key); void clear_records(); + Optional first_in_range(GC::Ref range); HTML::SerializationRecord referenced_value(IndexRecord const& index_record) const;