diff --git a/Libraries/LibWeb/IndexedDB/Internal/Algorithms.cpp b/Libraries/LibWeb/IndexedDB/Internal/Algorithms.cpp index b0f7ab5ad1e..4f0515a6844 100644 --- a/Libraries/LibWeb/IndexedDB/Internal/Algorithms.cpp +++ b/Libraries/LibWeb/IndexedDB/Internal/Algorithms.cpp @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -1869,4 +1870,35 @@ JS::Value retrieve_a_key_from_an_object_store(JS::Realm& realm, GC::Ref retrieve_multiple_values_from_an_object_store(JS::Realm& realm, GC::Ref store, GC::Ref range, Optional count) +{ + // 1. If count is not given or is 0 (zero), let count be infinity. + if (count.has_value() && *count == 0) + count = OptionalNone(); + + // 2. Let records be a list containing the first count records in store’s list of records whose key is in range. + auto records = store->first_n_in_range(range, count); + + // 3. Let list be an empty list. + auto list = MUST(JS::Array::create(realm, records.size())); + + // 4. For each record of records: + for (u32 i = 0; i < records.size(); ++i) { + auto& record = records[i]; + + // 1. Let serialized be record’s value. If an error occurs while reading the value from the underlying storage, return a newly created "NotReadableError" DOMException. + auto serialized = record.value; + + // 2. Let entry be ! StructuredDeserialize(serialized, targetRealm). + auto entry = MUST(HTML::structured_deserialize(realm.vm(), serialized, realm)); + + // 3. Append entry to list. + MUST(list->create_data_property_or_throw(i, entry)); + } + + // 5. Return list converted to a sequence. + return list; +} + } diff --git a/Libraries/LibWeb/IndexedDB/Internal/Algorithms.h b/Libraries/LibWeb/IndexedDB/Internal/Algorithms.h index c1f8cfe914b..ce18d2baa05 100644 --- a/Libraries/LibWeb/IndexedDB/Internal/Algorithms.h +++ b/Libraries/LibWeb/IndexedDB/Internal/Algorithms.h @@ -12,6 +12,7 @@ #include #include #include +#include namespace Web::IndexedDB { @@ -47,5 +48,6 @@ WebIDL::ExceptionOr retrieve_a_value_from_an_object_store(JS::Realm&, GC::Ptr iterate_a_cursor(JS::Realm&, GC::Ref, GC::Ptr = nullptr, GC::Ptr = nullptr, u64 = 1); 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); } diff --git a/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.cpp b/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.cpp index d2d114f9b2a..7423b934348 100644 --- a/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.cpp +++ b/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.cpp @@ -89,4 +89,18 @@ void ObjectStore::clear_records() m_records.clear(); } +GC::ConservativeVector ObjectStore::first_n_in_range(GC::Ref range, Optional count) +{ + GC::ConservativeVector records(range->heap()); + for (auto const& record : m_records) { + if (range->is_in_range(record.key)) + records.append(record); + + if (count.has_value() && records.size() >= *count) + break; + } + + return records; +} + } diff --git a/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.h b/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.h index 3f8ad31da91..0376636af97 100644 --- a/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.h +++ b/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.h @@ -56,6 +56,7 @@ public: u64 count_records_in_range(GC::Ref range); Optional first_in_range(GC::Ref range); void clear_records(); + GC::ConservativeVector first_n_in_range(GC::Ref range, Optional count); protected: virtual void visit_edges(Visitor&) override;