LibWeb/IDB: Introduce an Invalid KeyType

This cleans up the code around failure/invalid/exception a bit
This commit is contained in:
stelar7 2025-04-25 17:59:06 +02:00 committed by Jelle Raaijmakers
commit facfcd87c2
Notes: github-actions[bot] 2025-04-28 09:32:57 +00:00
7 changed files with 68 additions and 56 deletions

View file

@ -108,18 +108,18 @@ WebIDL::ExceptionOr<i8> IDBFactory::cmp(JS::Value first, JS::Value second)
auto a = TRY(convert_a_value_to_a_key(realm(), first)); auto a = TRY(convert_a_value_to_a_key(realm(), first));
// 2. If a is invalid, throw a "DataError" DOMException. // 2. If a is invalid, throw a "DataError" DOMException.
if (a.is_error()) if (a->is_invalid())
return WebIDL::DataError::create(realm(), "Failed to convert a value to a key"_string); return WebIDL::DataError::create(realm(), "Failed to convert a value to a key"_string);
// 3. Let b be the result of converting a value to a key with second. Rethrow any exceptions. // 3. Let b be the result of converting a value to a key with second. Rethrow any exceptions.
auto b = TRY(convert_a_value_to_a_key(realm(), second)); auto b = TRY(convert_a_value_to_a_key(realm(), second));
// 4. If b is invalid, throw a "DataError" DOMException. // 4. If b is invalid, throw a "DataError" DOMException.
if (b.is_error()) if (b->is_invalid())
return WebIDL::DataError::create(realm(), "Failed to convert a value to a key"_string); return WebIDL::DataError::create(realm(), "Failed to convert a value to a key"_string);
// 5. Return the results of comparing two keys with a and b. // 5. Return the results of comparing two keys with a and b.
return Key::compare_two_keys(a.release_value(), b.release_value()); return Key::compare_two_keys(a, b);
} }
// https://w3c.github.io/IndexedDB/#dom-idbfactory-deletedatabase // https://w3c.github.io/IndexedDB/#dom-idbfactory-deletedatabase

View file

@ -64,14 +64,12 @@ WebIDL::ExceptionOr<GC::Ref<IDBKeyRange>> IDBKeyRange::only(JS::VM& vm, JS::Valu
auto& realm = *vm.current_realm(); auto& realm = *vm.current_realm();
// 1. Let key be the result of converting a value to a key with value. Rethrow any exceptions. // 1. Let key be the result of converting a value to a key with value. Rethrow any exceptions.
auto maybe_key = TRY(convert_a_value_to_a_key(realm, value)); auto key = TRY(convert_a_value_to_a_key(realm, value));
// 2. If key is invalid, throw a "DataError" DOMException. // 2. If key is invalid, throw a "DataError" DOMException.
if (maybe_key.is_error()) if (key->is_invalid())
return WebIDL::DataError::create(realm, "Value is invalid"_string); return WebIDL::DataError::create(realm, "Value is invalid"_string);
auto key = maybe_key.release_value();
// 3. Create and return a new key range containing only key. // 3. Create and return a new key range containing only key.
return IDBKeyRange::create(realm, key, key, false, false); return IDBKeyRange::create(realm, key, key, false, false);
} }
@ -82,14 +80,14 @@ WebIDL::ExceptionOr<GC::Ref<IDBKeyRange>> IDBKeyRange::lower_bound(JS::VM& vm, J
auto& realm = *vm.current_realm(); auto& realm = *vm.current_realm();
// 1. Let lowerKey be the result of converting a value to a key with lower. Rethrow any exceptions. // 1. Let lowerKey be the result of converting a value to a key with lower. Rethrow any exceptions.
auto lower_key = TRY(convert_a_value_to_a_key(realm, lower)); auto key = TRY(convert_a_value_to_a_key(realm, lower));
// 2. If lowerKey is invalid, throw a "DataError" DOMException. // 2. If lowerKey is invalid, throw a "DataError" DOMException.
if (lower_key.is_error()) if (key->is_invalid())
return WebIDL::DataError::create(realm, "Value is invalid"_string); return WebIDL::DataError::create(realm, "Value is invalid"_string);
// 3. Create and return a new key range with lower bound set to lowerKey, lower open flag set to open, upper bound set to null, and upper open flag set to true. // 3. Create and return a new key range with lower bound set to lowerKey, lower open flag set to open, upper bound set to null, and upper open flag set to true.
return IDBKeyRange::create(realm, lower_key.release_value(), {}, open, true); return IDBKeyRange::create(realm, key, {}, open, true);
} }
// https://w3c.github.io/IndexedDB/#dom-idbkeyrange-upperbound // https://w3c.github.io/IndexedDB/#dom-idbkeyrange-upperbound
@ -98,14 +96,14 @@ WebIDL::ExceptionOr<GC::Ref<IDBKeyRange>> IDBKeyRange::upper_bound(JS::VM& vm, J
auto& realm = *vm.current_realm(); auto& realm = *vm.current_realm();
// 1. Let upperKey be the result of converting a value to a key with upper. Rethrow any exceptions. // 1. Let upperKey be the result of converting a value to a key with upper. Rethrow any exceptions.
auto upper_key = TRY(convert_a_value_to_a_key(realm, upper)); auto key = TRY(convert_a_value_to_a_key(realm, upper));
// 2. If upperKey is invalid, throw a "DataError" DOMException. // 2. If upperKey is invalid, throw a "DataError" DOMException.
if (upper_key.is_error()) if (key->is_invalid())
return WebIDL::DataError::create(realm, "Value is invalid"_string); return WebIDL::DataError::create(realm, "Value is invalid"_string);
// 3. Create and return a new key range with lower bound set to null, lower open flag set to true, upper bound set to upperKey, and upper open flag set to open. // 3. Create and return a new key range with lower bound set to null, lower open flag set to true, upper bound set to upperKey, and upper open flag set to open.
return IDBKeyRange::create(realm, {}, upper_key.release_value(), true, open); return IDBKeyRange::create(realm, {}, key, true, open);
} }
// https://w3c.github.io/IndexedDB/#dom-idbkeyrange-bound // https://w3c.github.io/IndexedDB/#dom-idbkeyrange-bound
@ -117,22 +115,22 @@ WebIDL::ExceptionOr<GC::Ref<IDBKeyRange>> IDBKeyRange::bound(JS::VM& vm, JS::Val
auto lower_key = TRY(convert_a_value_to_a_key(realm, lower)); auto lower_key = TRY(convert_a_value_to_a_key(realm, lower));
// 2. If lowerKey is invalid, throw a "DataError" DOMException. // 2. If lowerKey is invalid, throw a "DataError" DOMException.
if (lower_key.is_error()) if (lower_key->is_invalid())
return WebIDL::DataError::create(realm, "Value is invalid"_string); return WebIDL::DataError::create(realm, "Value is invalid"_string);
// 3. Let upperKey be the result of converting a value to a key with upper. Rethrow any exceptions. // 3. Let upperKey be the result of converting a value to a key with upper. Rethrow any exceptions.
auto upper_key = TRY(convert_a_value_to_a_key(realm, upper)); auto upper_key = TRY(convert_a_value_to_a_key(realm, upper));
// 4. If upperKey is invalid, throw a "DataError" DOMException. // 4. If upperKey is invalid, throw a "DataError" DOMException.
if (upper_key.is_error()) if (upper_key->is_invalid())
return WebIDL::DataError::create(realm, "Value is invalid"_string); return WebIDL::DataError::create(realm, "Value is invalid"_string);
// 5. If lowerKey is greater than upperKey, throw a "DataError" DOMException. // 5. If lowerKey is greater than upperKey, throw a "DataError" DOMException.
if (Key::less_than(upper_key.release_value(), lower_key.release_value())) if (Key::less_than(upper_key, lower_key))
return WebIDL::DataError::create(realm, "Lower key is greater than upper key"_string); return WebIDL::DataError::create(realm, "Lower key is greater than upper key"_string);
// 6. Create and return a new key range with lower bound set to lowerKey, lower open flag set to lowerOpen, upper bound set to upperKey and upper open flag set to upperOpen. // 6. Create and return a new key range with lower bound set to lowerKey, lower open flag set to lowerOpen, upper bound set to upperKey and upper open flag set to upperOpen.
return IDBKeyRange::create(realm, lower_key.release_value(), upper_key.release_value(), lower_open, upper_open); return IDBKeyRange::create(realm, lower_key, upper_key, lower_open, upper_open);
} }
// https://w3c.github.io/IndexedDB/#dom-idbkeyrange-includes // https://w3c.github.io/IndexedDB/#dom-idbkeyrange-includes
@ -144,11 +142,11 @@ WebIDL::ExceptionOr<bool> IDBKeyRange::includes(JS::Value key)
auto k = TRY(convert_a_value_to_a_key(realm, key)); auto k = TRY(convert_a_value_to_a_key(realm, key));
// 2. If k is invalid, throw a "DataError" DOMException. // 2. If k is invalid, throw a "DataError" DOMException.
if (k.is_error()) if (k->is_invalid())
return WebIDL::DataError::create(realm, "Value is invalid"_string); return WebIDL::DataError::create(realm, "Value is invalid"_string);
// 3. Return true if k is in this range, and false otherwise. // 3. Return true if k is in this range, and false otherwise.
return is_in_range(k.release_value()); return is_in_range(k);
} }
// https://w3c.github.io/IndexedDB/#dom-idbkeyrange-lower // https://w3c.github.io/IndexedDB/#dom-idbkeyrange-lower

View file

@ -257,13 +257,14 @@ WebIDL::ExceptionOr<GC::Ref<IDBRequest>> IDBObjectStore::add_or_put(GC::Ref<IDBO
// 8. If key was given, then: // 8. If key was given, then:
if (key_was_given) { if (key_was_given) {
// 1. Let r be the result of converting a value to a key with key. Rethrow any exceptions. // 1. Let r be the result of converting a value to a key with key. Rethrow any exceptions.
auto maybe_key = TRY(convert_a_value_to_a_key(realm, key.value())); auto r = TRY(convert_a_value_to_a_key(realm, key.value()));
// 2. If r is invalid, throw a "DataError" DOMException. // 2. If r is invalid, throw a "DataError" DOMException.
if (maybe_key.is_error()) if (r->is_invalid())
return WebIDL::DataError::create(realm, "Key is invalid"_string); return WebIDL::DataError::create(realm, "Key is invalid"_string);
// 3. Let key be r. // 3. Let key be r.
key_value = maybe_key.release_value(); key_value = r;
} }
// 9. Let targetRealm be a user-agent defined Realm. // 9. Let targetRealm be a user-agent defined Realm.
@ -277,13 +278,14 @@ WebIDL::ExceptionOr<GC::Ref<IDBRequest>> IDBObjectStore::add_or_put(GC::Ref<IDBO
// 1. Let kpk be the result of extracting a key from a value using a key path with clone and stores key path. Rethrow any exceptions. // 1. Let kpk be the result of extracting a key from a value using a key path with clone and stores key path. Rethrow any exceptions.
auto maybe_kpk = TRY(extract_a_key_from_a_value_using_a_key_path(realm, clone, store.key_path().value())); auto maybe_kpk = TRY(extract_a_key_from_a_value_using_a_key_path(realm, clone, store.key_path().value()));
// 2. If kpk is invalid, throw a "DataError" DOMException. // NOTE: Step 2 and 3 is reversed here, since we check for failure before validity.
if (maybe_kpk.is_error())
return WebIDL::DataError::create(realm, "Key path is invalid"_string);
// 3. If kpk is not failure, let key be kpk. // 3. If kpk is not failure, let key be kpk.
if (!maybe_kpk.is_error()) { if (!maybe_kpk.is_error()) {
key_value = maybe_kpk.release_value(); key_value = maybe_kpk.release_value();
// 2. If kpk is invalid, throw a "DataError" DOMException.
if (key_value->is_invalid())
return WebIDL::DataError::create(realm, "Key path is invalid"_string);
} }
// 4. Otherwise (kpk is failure): // 4. Otherwise (kpk is failure):
@ -300,12 +302,9 @@ WebIDL::ExceptionOr<GC::Ref<IDBRequest>> IDBObjectStore::add_or_put(GC::Ref<IDBO
// 12. Let operation be an algorithm to run store a record into an object store with store, clone, key, and no-overwrite flag. // 12. Let operation be an algorithm to run store a record into an object store with store, clone, key, and no-overwrite flag.
auto operation = GC::Function<WebIDL::ExceptionOr<JS::Value>()>::create(realm.heap(), [&realm, &store, clone, key_value, no_overwrite] -> WebIDL::ExceptionOr<JS::Value> { auto operation = GC::Function<WebIDL::ExceptionOr<JS::Value>()>::create(realm.heap(), [&realm, &store, clone, key_value, no_overwrite] -> WebIDL::ExceptionOr<JS::Value> {
auto maybe_key = store_a_record_into_an_object_store(realm, store, clone, key_value, no_overwrite); auto optional_key = TRY(store_a_record_into_an_object_store(realm, store, clone, key_value, no_overwrite));
if (maybe_key.is_error())
return maybe_key.release_error();
auto optional_key = maybe_key.release_value(); if (!optional_key || optional_key->is_invalid())
if (optional_key == nullptr)
return JS::js_undefined(); return JS::js_undefined();
return convert_a_key_to_a_value(realm, GC::Ref(*optional_key)); return convert_a_key_to_a_value(realm, GC::Ref(*optional_key));

View file

@ -207,14 +207,14 @@ bool fire_a_version_change_event(JS::Realm& realm, FlyString const& event_name,
} }
// https://w3c.github.io/IndexedDB/#convert-value-to-key // https://w3c.github.io/IndexedDB/#convert-value-to-key
WebIDL::ExceptionOr<ErrorOr<GC::Ref<Key>>> convert_a_value_to_a_key(JS::Realm& realm, JS::Value input, Vector<JS::Value> seen) WebIDL::ExceptionOr<GC::Ref<Key>> convert_a_value_to_a_key(JS::Realm& realm, JS::Value input, Vector<JS::Value> seen)
{ {
// 1. If seen was not given, then let seen be a new empty set. // 1. If seen was not given, then let seen be a new empty set.
// NOTE: This is handled by the caller. // NOTE: This is handled by the caller.
// 2. If seen contains input, then return invalid. // 2. If seen contains input, then return invalid.
if (seen.contains_slow(input)) if (seen.contains_slow(input))
return Error::from_string_literal("Already seen key"); return Key::create_invalid(realm, "Already seen key"_string);
// 3. Jump to the appropriate step below: // 3. Jump to the appropriate step below:
@ -223,7 +223,7 @@ WebIDL::ExceptionOr<ErrorOr<GC::Ref<Key>>> convert_a_value_to_a_key(JS::Realm& r
// 1. If input is NaN then return invalid. // 1. If input is NaN then return invalid.
if (input.is_nan()) if (input.is_nan())
return Error::from_string_literal("NaN key"); return Key::create_invalid(realm, "NaN key"_string);
// 2. Otherwise, return a new key with type number and value input. // 2. Otherwise, return a new key with type number and value input.
return Key::create_number(realm, input.as_double()); return Key::create_number(realm, input.as_double());
@ -238,7 +238,7 @@ WebIDL::ExceptionOr<ErrorOr<GC::Ref<Key>>> convert_a_value_to_a_key(JS::Realm& r
// 2. If ms is NaN then return invalid. // 2. If ms is NaN then return invalid.
if (isnan(ms)) if (isnan(ms))
return Error::from_string_literal("NaN key"); return Key::create_invalid(realm, "NaN key"_string);
// 3. Otherwise, return a new key with type date and value ms. // 3. Otherwise, return a new key with type date and value ms.
return Key::create_date(realm, ms); return Key::create_date(realm, ms);
@ -256,10 +256,10 @@ WebIDL::ExceptionOr<ErrorOr<GC::Ref<Key>>> convert_a_value_to_a_key(JS::Realm& r
// 1. If input is detached then return invalid. // 1. If input is detached then return invalid.
if (WebIDL::is_buffer_source_detached(input)) if (WebIDL::is_buffer_source_detached(input))
return Error::from_string_literal("Detached buffer is not supported as key"); return Key::create_invalid(realm, "Detached buffer is not supported as key"_string);
// 2. Let bytes be the result of getting a copy of the bytes held by the buffer source input. // 2. Let bytes be the result of getting a copy of the bytes held by the buffer source input.
auto data_buffer = TRY(WebIDL::get_buffer_source_copy(input.as_object())); auto data_buffer = MUST(WebIDL::get_buffer_source_copy(input.as_object()));
// 3. Return a new key with type binary and value bytes. // 3. Return a new key with type binary and value bytes.
return Key::create_binary(realm, data_buffer); return Key::create_binary(realm, data_buffer);
@ -287,15 +287,18 @@ WebIDL::ExceptionOr<ErrorOr<GC::Ref<Key>>> convert_a_value_to_a_key(JS::Realm& r
// 2. If hop is false, return invalid. // 2. If hop is false, return invalid.
if (!hop) if (!hop)
return Error::from_string_literal("Array-like object has no property"); return Key::create_invalid(realm, "Array-like object has no property"_string);
// 3. Let entry be ? Get(input, index). // 3. Let entry be ? Get(input, index).
auto entry = TRY(input.as_object().get(index)); auto entry = TRY(input.as_object().get(index));
// 4. Let key be the result of converting a value to a key with arguments entry and seen. // 4. Let key be the result of converting a value to a key with arguments entry and seen.
// 5. ReturnIfAbrupt(key). // 5. ReturnIfAbrupt(key).
auto key = TRY(convert_a_value_to_a_key(realm, entry, seen));
// 6. If key is invalid abort these steps and return invalid. // 6. If key is invalid abort these steps and return invalid.
auto key = TRY(TRY(convert_a_value_to_a_key(realm, entry, seen))); if (key->is_invalid())
return key;
// 7. Append key to keys. // 7. Append key to keys.
keys.append(key); keys.append(key);
@ -309,7 +312,8 @@ WebIDL::ExceptionOr<ErrorOr<GC::Ref<Key>>> convert_a_value_to_a_key(JS::Realm& r
} }
// - Otherwise // - Otherwise
return Error::from_string_literal("Unknown key type"); // Return invalid.
return Key::create_invalid(realm, "Unable to convert value to key. Its not of a known type"_string);
} }
// https://w3c.github.io/IndexedDB/#close-a-database-connection // https://w3c.github.io/IndexedDB/#close-a-database-connection
@ -682,6 +686,8 @@ JS::Value convert_a_key_to_a_value(JS::Realm& realm, GC::Ref<Key> key)
// 6. Return array. // 6. Return array.
return array; return array;
} }
case Key::KeyType::Invalid:
VERIFY_NOT_REACHED();
} }
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
@ -812,7 +818,7 @@ WebIDL::ExceptionOr<JS::Value> clone_in_realm(JS::Realm& target_realm, JS::Value
} }
// https://w3c.github.io/IndexedDB/#convert-a-value-to-a-multientry-key // https://w3c.github.io/IndexedDB/#convert-a-value-to-a-multientry-key
WebIDL::ExceptionOr<ErrorOr<GC::Ref<Key>>> convert_a_value_to_a_multi_entry_key(JS::Realm& realm, JS::Value value) WebIDL::ExceptionOr<GC::Ref<Key>> convert_a_value_to_a_multi_entry_key(JS::Realm& realm, JS::Value value)
{ {
// 1. If input is an Array exotic object, then: // 1. If input is an Array exotic object, then:
if (value.is_object() && is<JS::Array>(value.as_object())) { if (value.is_object() && is<JS::Array>(value.as_object())) {
@ -843,16 +849,12 @@ WebIDL::ExceptionOr<ErrorOr<GC::Ref<Key>>> convert_a_value_to_a_multi_entry_key(
// 2. If key is not invalid or an abrupt completion, and there is no item in keys equal to key, then append key to keys. // 2. If key is not invalid or an abrupt completion, and there is no item in keys equal to key, then append key to keys.
if (!completion_key.is_error()) { if (!completion_key.is_error()) {
auto maybe_key = completion_key.release_value(); auto key = completion_key.release_value();
if (!maybe_key.is_error()) { if (!key->is_invalid() && !keys.contains_slow(key))
auto key = maybe_key.release_value();
if (!keys.contains_slow(key))
keys.append(key); keys.append(key);
} }
} }
}
// 3. Increase index by 1. // 3. Increase index by 1.
index++; index++;
@ -1368,15 +1370,22 @@ WebIDL::ExceptionOr<GC::Ptr<Key>> store_a_record_into_an_object_store(JS::Realm&
// 5. For each index which references store: // 5. For each index which references store:
for (auto const& [name, index] : store->index_set()) { for (auto const& [name, index] : store->index_set()) {
// 1. Let index key be the result of extracting a key from a value using a key path with value, indexs key path, and indexs multiEntry flag. // 1. Let index key be the result of extracting a key from a value using a key path with value, indexs key path, and indexs multiEntry flag.
auto index_key = TRY(extract_a_key_from_a_value_using_a_key_path(realm, value, index->key_path(), index->multi_entry())); auto completion_index_key = extract_a_key_from_a_value_using_a_key_path(realm, value, index->key_path(), index->multi_entry());
// 2. If index key is an exception, or invalid, or failure, take no further actions for index, and continue these steps for the next index. // 2. If index key is an exception, or invalid, or failure, take no further actions for index, and continue these steps for the next index.
if (index_key.is_error()) if (completion_index_key.is_error())
continue;
auto failure_index_key = completion_index_key.release_value();
if (failure_index_key.is_error())
continue;
auto index_key = failure_index_key.release_value();
if (index_key->is_invalid())
continue; continue;
auto index_key_value = index_key.value();
auto index_multi_entry = index->multi_entry(); auto index_multi_entry = index->multi_entry();
auto index_key_is_array = index_key_value->type() == Key::KeyType::Array; auto index_key_is_array = index_key->type() == Key::KeyType::Array;
auto index_is_unique = index->unique(); auto index_is_unique = index->unique();
// 3. If indexs multiEntry flag is false, or if index key is not an array key, // 3. If indexs multiEntry flag is false, or if index key is not an array key,
@ -1384,7 +1393,7 @@ WebIDL::ExceptionOr<GC::Ptr<Key>> store_a_record_into_an_object_store(JS::Realm&
// and indexs unique flag is true, // and indexs unique flag is true,
// then this operation failed with a "ConstraintError" DOMException. // then this operation failed with a "ConstraintError" DOMException.
// Abort this algorithm without taking any further steps. // Abort this algorithm without taking any further steps.
if ((!index_multi_entry || !index_key_is_array) && index_is_unique && index->has_record_with_key(index_key_value)) if ((!index_multi_entry || !index_key_is_array) && index_is_unique && index->has_record_with_key(index_key))
return WebIDL::ConstraintError::create(realm, "Record already exists in index"_string); return WebIDL::ConstraintError::create(realm, "Record already exists in index"_string);
// 4. If indexs multiEntry flag is true and index key is an array key, // 4. If indexs multiEntry flag is true and index key is an array key,
@ -1393,7 +1402,7 @@ WebIDL::ExceptionOr<GC::Ptr<Key>> store_a_record_into_an_object_store(JS::Realm&
// then this operation failed with a "ConstraintError" DOMException. // then this operation failed with a "ConstraintError" DOMException.
// Abort this algorithm without taking any further steps. // Abort this algorithm without taking any further steps.
if (index_multi_entry && index_key_is_array && index_is_unique) { if (index_multi_entry && index_key_is_array && index_is_unique) {
for (auto const& subkey : index_key_value->subkeys()) { for (auto const& subkey : index_key->subkeys()) {
if (index->has_record_with_key(*subkey)) if (index->has_record_with_key(*subkey))
return WebIDL::ConstraintError::create(realm, "Record already exists in index"_string); return WebIDL::ConstraintError::create(realm, "Record already exists in index"_string);
} }

View file

@ -19,7 +19,7 @@ using KeyPath = Variant<String, Vector<String>>;
WebIDL::ExceptionOr<GC::Ref<IDBDatabase>> open_a_database_connection(JS::Realm&, StorageAPI::StorageKey, String, Optional<u64>, GC::Ref<IDBRequest>); WebIDL::ExceptionOr<GC::Ref<IDBDatabase>> open_a_database_connection(JS::Realm&, StorageAPI::StorageKey, String, Optional<u64>, GC::Ref<IDBRequest>);
bool fire_a_version_change_event(JS::Realm&, FlyString const&, GC::Ref<DOM::EventTarget>, u64, Optional<u64>); bool fire_a_version_change_event(JS::Realm&, FlyString const&, GC::Ref<DOM::EventTarget>, u64, Optional<u64>);
WebIDL::ExceptionOr<ErrorOr<GC::Ref<Key>>> convert_a_value_to_a_key(JS::Realm&, JS::Value, Vector<JS::Value> = {}); WebIDL::ExceptionOr<GC::Ref<Key>> convert_a_value_to_a_key(JS::Realm&, JS::Value, Vector<JS::Value> = {});
void close_a_database_connection(GC::Ref<IDBDatabase>, bool forced = false); void close_a_database_connection(GC::Ref<IDBDatabase>, bool forced = false);
GC::Ref<IDBTransaction> upgrade_a_database(JS::Realm&, GC::Ref<IDBDatabase>, u64, GC::Ref<IDBRequest>); GC::Ref<IDBTransaction> upgrade_a_database(JS::Realm&, GC::Ref<IDBDatabase>, u64, GC::Ref<IDBRequest>);
WebIDL::ExceptionOr<u64> delete_a_database(JS::Realm&, StorageAPI::StorageKey, String, GC::Ref<IDBRequest>); WebIDL::ExceptionOr<u64> delete_a_database(JS::Realm&, StorageAPI::StorageKey, String, GC::Ref<IDBRequest>);
@ -29,7 +29,7 @@ bool is_valid_key_path(KeyPath const&);
GC::Ref<HTML::DOMStringList> create_a_sorted_name_list(JS::Realm&, Vector<String>); GC::Ref<HTML::DOMStringList> create_a_sorted_name_list(JS::Realm&, Vector<String>);
void commit_a_transaction(JS::Realm&, GC::Ref<IDBTransaction>); void commit_a_transaction(JS::Realm&, GC::Ref<IDBTransaction>);
WebIDL::ExceptionOr<JS::Value> clone_in_realm(JS::Realm&, JS::Value, GC::Ref<IDBTransaction>); WebIDL::ExceptionOr<JS::Value> clone_in_realm(JS::Realm&, JS::Value, GC::Ref<IDBTransaction>);
WebIDL::ExceptionOr<ErrorOr<GC::Ref<Key>>> convert_a_value_to_a_multi_entry_key(JS::Realm&, JS::Value); WebIDL::ExceptionOr<GC::Ref<Key>> convert_a_value_to_a_multi_entry_key(JS::Realm&, JS::Value);
WebIDL::ExceptionOr<ErrorOr<JS::Value>> evaluate_key_path_on_a_value(JS::Realm&, JS::Value, KeyPath const&); WebIDL::ExceptionOr<ErrorOr<JS::Value>> evaluate_key_path_on_a_value(JS::Realm&, JS::Value, KeyPath const&);
WebIDL::ExceptionOr<ErrorOr<GC::Ref<Key>>> extract_a_key_from_a_value_using_a_key_path(JS::Realm&, JS::Value, KeyPath const&, bool = false); WebIDL::ExceptionOr<ErrorOr<GC::Ref<Key>>> extract_a_key_from_a_value_using_a_key_path(JS::Realm&, JS::Value, KeyPath const&, bool = false);
bool check_that_a_key_could_be_injected_into_a_value(JS::Realm&, JS::Value, KeyPath const&); bool check_that_a_key_could_be_injected_into_a_value(JS::Realm&, JS::Value, KeyPath const&);

View file

@ -73,6 +73,8 @@ i8 Key::compare_two_keys(GC::Ref<Key> a, GC::Ref<Key> b)
// 6. Switch on ta: // 6. Switch on ta:
switch (ta) { switch (ta) {
case KeyType::Invalid:
VERIFY_NOT_REACHED();
// number // number
// date // date
case KeyType::Number: case KeyType::Number:

View file

@ -31,6 +31,7 @@ class Key : public JS::Cell {
// A key has an associated type which is one of: number, date, string, binary, or array. // A key has an associated type which is one of: number, date, string, binary, or array.
enum KeyType { enum KeyType {
Invalid,
Number, Number,
Date, Date,
String, String,
@ -45,6 +46,8 @@ public:
[[nodiscard]] KeyType type() { return m_type; } [[nodiscard]] KeyType type() { return m_type; }
[[nodiscard]] KeyValue value() { return m_value; } [[nodiscard]] KeyValue value() { return m_value; }
[[nodiscard]] bool is_invalid() { return m_type == Invalid; }
[[nodiscard]] double value_as_double() { return m_value.get<double>(); } [[nodiscard]] double value_as_double() { return m_value.get<double>(); }
[[nodiscard]] AK::String value_as_string() { return m_value.get<AK::String>(); } [[nodiscard]] AK::String value_as_string() { return m_value.get<AK::String>(); }
[[nodiscard]] ByteBuffer value_as_byte_buffer() { return m_value.get<ByteBuffer>(); } [[nodiscard]] ByteBuffer value_as_byte_buffer() { return m_value.get<ByteBuffer>(); }
@ -60,6 +63,7 @@ public:
[[nodiscard]] static GC::Ref<Key> create_string(JS::Realm& realm, AK::String const& value) { return create(realm, String, value); } [[nodiscard]] static GC::Ref<Key> create_string(JS::Realm& realm, AK::String const& value) { return create(realm, String, value); }
[[nodiscard]] static GC::Ref<Key> create_binary(JS::Realm& realm, ByteBuffer const& value) { return create(realm, Binary, value); } [[nodiscard]] static GC::Ref<Key> create_binary(JS::Realm& realm, ByteBuffer const& value) { return create(realm, Binary, value); }
[[nodiscard]] static GC::Ref<Key> create_array(JS::Realm& realm, Vector<GC::Root<Key>> const& value) { return create(realm, Array, value); } [[nodiscard]] static GC::Ref<Key> create_array(JS::Realm& realm, Vector<GC::Root<Key>> const& value) { return create(realm, Array, value); }
[[nodiscard]] static GC::Ref<Key> create_invalid(JS::Realm& realm, AK::String const& value) { return create(realm, Invalid, value); }
[[nodiscard]] static i8 compare_two_keys(GC::Ref<Key> a, GC::Ref<Key> b); [[nodiscard]] static i8 compare_two_keys(GC::Ref<Key> a, GC::Ref<Key> b);
[[nodiscard]] static bool equals(GC::Ref<Key> a, GC::Ref<Key> b) { return compare_two_keys(a, b) == 0; } [[nodiscard]] static bool equals(GC::Ref<Key> a, GC::Ref<Key> b) { return compare_two_keys(a, b) == 0; }