LibWeb/IDB: Implement IDBCursor::continuePrimaryKey

This commit is contained in:
stelar7 2025-05-13 09:54:13 +02:00 committed by Andrew Kaster
commit 3154ac8988
Notes: github-actions[bot] 2025-05-13 16:50:06 +00:00
3 changed files with 88 additions and 1 deletions

View file

@ -215,4 +215,90 @@ WebIDL::ExceptionOr<void> IDBCursor::advance(WebIDL::UnsignedLong count)
return {};
}
// https://w3c.github.io/IndexedDB/#dom-idbcursor-continueprimarykey
WebIDL::ExceptionOr<void> IDBCursor::continue_primary_key(JS::Value key_param, JS::Value primary_key_param)
{
auto& realm = this->realm();
// 1. Let transaction be thiss transaction.
auto transaction = this->transaction();
// 2. If transactions 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 thiss source or effective object store has been deleted, throw an "InvalidStateError" DOMException.
// 4. If thiss source is not an index throw an "InvalidAccessError" DOMException.
if (!m_source_handle.has<GC::Ref<IDBIndex>>())
return WebIDL::InvalidAccessError::create(realm, "Cursor source is not an index"_string);
// 5. If thiss direction is not "next" or "prev", throw an "InvalidAccessError" DOMException.
if (m_direction != Bindings::IDBCursorDirection::Next && m_direction != Bindings::IDBCursorDirection::Prev)
return WebIDL::InvalidAccessError::create(realm, "Cursor direction is not next or prev"_string);
// 6. If thiss 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 while continuing"_string);
// 7. 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_param));
// 8. If r is invalid, throw a "DataError" DOMException.
if (r->is_invalid())
return WebIDL::DataError::create(realm, r->value_as_string());
// 9. Let key be r.
auto key = r;
// 10. Let r be the result of converting a value to a key with primaryKey. Rethrow any exceptions.
r = TRY(convert_a_value_to_a_key(realm, primary_key_param));
// 11. If r is invalid, throw a "DataError" DOMException.
if (r->is_invalid())
return WebIDL::DataError::create(realm, r->value_as_string());
// 12. Let primaryKey be r.
auto primary_key = r;
// 13. If key is less than thiss position and thiss direction is "next", throw a "DataError" DOMException.
if (Key::less_than(*key, *this->position()) && m_direction == Bindings::IDBCursorDirection::Next)
return WebIDL::DataError::create(realm, "Key is less than cursor's position"_string);
// 14. If key is greater than thiss position and thiss direction is "prev", throw a "DataError" DOMException.
if (Key::greater_than(*key, *this->position()) && m_direction == Bindings::IDBCursorDirection::Prev)
return WebIDL::DataError::create(realm, "Key is greater than cursor's position"_string);
// 15. If key is equal to thiss position and primaryKey is less than or equal to thiss object store position and thiss direction is "next", throw a "DataError" DOMException.
if (Key::equals(*key, *this->position()) && (Key::less_than(*primary_key, *this->object_store_position()) || Key::equals(*primary_key, *this->object_store_position())) && m_direction == Bindings::IDBCursorDirection::Next)
return WebIDL::DataError::create(realm, "Key is equal to cursor's position"_string);
// 16. If key is equal to thiss position and primaryKey is greater than or equal to thiss object store position and thiss direction is "prev", throw a "DataError" DOMException.
if (Key::equals(*key, *this->position()) && (Key::greater_than(*primary_key, *this->object_store_position()) || Key::equals(*primary_key, *this->object_store_position())) && m_direction == Bindings::IDBCursorDirection::Prev)
return WebIDL::DataError::create(realm, "Key is equal to cursor's position"_string);
// 17. Set thiss got value flag to false.
m_got_value = false;
// 18. Let request be thiss request.
auto request = this->request();
// 19. Set requests processed flag to false.
request->set_processed(false);
// 20. Set requests done flag to false.
request->set_done(false);
// 21. Let operation be an algorithm to run iterate a cursor with the current Realm record, this, key, and primaryKey.
auto operation = GC::Function<WebIDL::ExceptionOr<JS::Value>()>::create(realm.heap(), [this, &realm, key, primary_key] -> WebIDL::ExceptionOr<JS::Value> {
return WebIDL::ExceptionOr<JS::Value>(iterate_a_cursor(realm, *this, key, primary_key));
});
// 22. Run asynchronously execute a request with thiss source handle, operation, and request.
asynchronously_execute_a_request(realm, source_handle(), operation, request);
dbgln_if(IDB_DEBUG, "Executing request for cursor continue with primary key with uuid {}", request->uuid());
return {};
}
}

View file

@ -47,6 +47,7 @@ public:
WebIDL::ExceptionOr<void> advance(WebIDL::UnsignedLong);
WebIDL::ExceptionOr<void> continue_(JS::Value);
WebIDL::ExceptionOr<void> continue_primary_key(JS::Value, JS::Value);
[[nodiscard]] JS::Value value() { return m_value.value_or(JS::js_undefined()); }
[[nodiscard]] GC::Ref<IDBKeyRange> range() { return m_range; }

View file

@ -9,7 +9,7 @@ interface IDBCursor {
[SameObject] readonly attribute IDBRequest request;
undefined advance([EnforceRange] unsigned long count);
undefined continue(optional any key);
[FIXME] undefined continuePrimaryKey(any key, any primaryKey);
undefined continuePrimaryKey(any key, any primaryKey);
[FIXME, NewObject] IDBRequest update(any value);
[FIXME, NewObject] IDBRequest delete();
};