diff --git a/Libraries/LibWeb/IndexedDB/IDBCursor.cpp b/Libraries/LibWeb/IndexedDB/IDBCursor.cpp index e6d5fc5729f..91e3c9a74c0 100644 --- a/Libraries/LibWeb/IndexedDB/IDBCursor.cpp +++ b/Libraries/LibWeb/IndexedDB/IDBCursor.cpp @@ -66,4 +66,70 @@ JS::Value IDBCursor::key() return convert_a_key_to_a_value(realm(), *m_key); } +// https://w3c.github.io/IndexedDB/#dom-idbcursor-continue +WebIDL::ExceptionOr IDBCursor::continue_(JS::Value key) +{ + auto& realm = this->realm(); + + // 1. Let transaction be this's transaction. + auto transaction = this->transaction(); + + // 2. 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 continuing cursor"_string); + + // FIXME: 3. If this's source or effective object store has been deleted, throw an "InvalidStateError" DOMException + + // 4. If this's got value flag is false, indicating that the cursor is being iterated or has iterated past its end, throw an "InvalidStateError" DOMException. + if (!m_got_value) + return WebIDL::InvalidStateError::create(realm, "Cursor is active or EOL"_string); + + // 5. If key is given, then: + GC::Ptr key_value; + if (!key.is_undefined()) { + // 1. Let r be the result of converting a value to a key with key. Rethrow any exceptions. + auto r = TRY(convert_a_value_to_a_key(realm, key)); + + // 2. If r is invalid, throw a "DataError" DOMException. + if (r->is_invalid()) + return WebIDL::DataError::create(realm, r->value_as_string()); + + // 3. Let key be r. + key_value = r; + + // 4. If key is less than or equal to this's position and this's direction is "next" or "nextunique", then throw a "DataError" DOMException. + auto is_less_than_or_equal_to = Key::less_than(*key_value, *this->position()) || Key::equals(*key_value, *this->position()); + if (is_less_than_or_equal_to && (m_direction == Bindings::IDBCursorDirection::Next || m_direction == Bindings::IDBCursorDirection::Nextunique)) + return WebIDL::DataError::create(realm, "Key is less than or equal to cursor's position"_string); + + // 5. If key is greater than or equal to this's position and this's direction is "prev" or "prevunique", then throw a "DataError" DOMException. + auto is_greater_than_or_equal_to = Key::greater_than(*key_value, *this->position()) || Key::equals(*key_value, *this->position()); + if (is_greater_than_or_equal_to && (m_direction == Bindings::IDBCursorDirection::Prev || m_direction == Bindings::IDBCursorDirection::Prevunique)) + return WebIDL::DataError::create(realm, "Key is greater than or equal to cursor's position"_string); + } + + // 6. Set this's got value flag to false. + m_got_value = false; + + // 7. Let request be this's request. + auto request = this->request(); + + // 8. Set request’s processed flag to false. + request->set_processed(false); + + // 9. Set request’s done flag to false. + request->set_done(false); + + // 10. Let operation be an algorithm to run iterate a cursor with the current Realm record, this, and key (if given). + auto operation = GC::Function()>::create(realm.heap(), [this, &realm, key_value] -> WebIDL::ExceptionOr { + 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); + 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 14054e7653a..e1085380688 100644 --- a/Libraries/LibWeb/IndexedDB/IDBCursor.h +++ b/Libraries/LibWeb/IndexedDB/IDBCursor.h @@ -47,6 +47,8 @@ public: void set_value(JS::Value value) { m_value = value; } void set_object_store_position(GC::Ptr object_store_position) { m_object_store_position = object_store_position; } + 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); virtual void initialize(JS::Realm&) override; diff --git a/Libraries/LibWeb/IndexedDB/IDBCursor.idl b/Libraries/LibWeb/IndexedDB/IDBCursor.idl index 331468f3f0a..9cd47afbc4d 100644 --- a/Libraries/LibWeb/IndexedDB/IDBCursor.idl +++ b/Libraries/LibWeb/IndexedDB/IDBCursor.idl @@ -8,7 +8,7 @@ interface IDBCursor { [FIXME] readonly attribute any primaryKey; [SameObject] readonly attribute IDBRequest request; [FIXME] undefined advance([EnforceRange] unsigned long count); - [FIXME] undefined continue(optional any key); + undefined continue(optional any key); [FIXME] undefined continuePrimaryKey(any key, any primaryKey); [FIXME, NewObject] IDBRequest update(any value); [FIXME, NewObject] IDBRequest delete(); diff --git a/Tests/LibWeb/Text/expected/wpt-import/IndexedDB/keyorder.txt b/Tests/LibWeb/Text/expected/wpt-import/IndexedDB/keyorder.txt index 57e32d8af87..6361358f8ab 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/IndexedDB/keyorder.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/IndexedDB/keyorder.txt @@ -2,29 +2,28 @@ Harness status: OK Found 24 tests -12 Pass -12 Fail -Fail Database readback sort - String < Array +24 Pass +Pass Database readback sort - String < Array Pass IDBKey.cmp sorted - String < Array -Fail Database readback sort - float < String +Pass Database readback sort - float < String Pass IDBKey.cmp sorted - float < String -Fail Database readback sort - float < Date +Pass Database readback sort - float < Date Pass IDBKey.cmp sorted - float < Date -Fail Database readback sort - float < Date < String < Array +Pass Database readback sort - float < Date < String < Array Pass IDBKey.cmp sorted - float < Date < String < Array -Fail Database readback sort - Date(1 sec ago) < Date(now) < Date(1 minute in future) +Pass Database readback sort - Date(1 sec ago) < Date(now) < Date(1 minute in future) Pass IDBKey.cmp sorted - Date(1 sec ago) < Date(now) < Date(1 minute in future) -Fail Database readback sort - -1.1 < 1 < 1.01337 < 1.013373 < 2 +Pass Database readback sort - -1.1 < 1 < 1.01337 < 1.013373 < 2 Pass IDBKey.cmp sorted - -1.1 < 1 < 1.01337 < 1.013373 < 2 -Fail Database readback sort - -Infinity < -0.01 < 0 < Infinity +Pass Database readback sort - -Infinity < -0.01 < 0 < Infinity Pass IDBKey.cmp sorted - -Infinity < -0.01 < 0 < Infinity -Fail Database readback sort - "" < "a" < "ab" < "b" < "ba" +Pass Database readback sort - "" < "a" < "ab" < "b" < "ba" Pass IDBKey.cmp sorted - "" < "a" < "ab" < "b" < "ba" -Fail Database readback sort - Arrays +Pass Database readback sort - Arrays Pass IDBKey.cmp sorted - Arrays -Fail Database readback sort - Array.length: 10,000 < Array.length: 10,001 +Pass Database readback sort - Array.length: 10,000 < Array.length: 10,001 Pass IDBKey.cmp sorted - Array.length: 10,000 < Array.length: 10,001 -Fail Database readback sort - Infinity inside arrays +Pass Database readback sort - Infinity inside arrays Pass IDBKey.cmp sorted - Infinity inside arrays -Fail Database readback sort - Test different stuff at once +Pass Database readback sort - Test different stuff at once Pass IDBKey.cmp sorted - Test different stuff at once \ No newline at end of file