mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-31 13:19:05 +00:00
LibWeb/IDB: Implement IDBObjectStore::add_or_put
This commit is contained in:
parent
fb17dae42b
commit
a06cec7a3c
Notes:
github-actions[bot]
2025-04-23 18:37:02 +00:00
Author: https://github.com/stelar7
Commit: a06cec7a3c
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4317
Reviewed-by: https://github.com/ADKaster ✅
Reviewed-by: https://github.com/kennethmyhra ✅
3 changed files with 99 additions and 21 deletions
|
@ -222,4 +222,99 @@ WebIDL::ExceptionOr<void> IDBObjectStore::delete_index(String const& name)
|
|||
return {};
|
||||
}
|
||||
|
||||
// https://w3c.github.io/IndexedDB/#add-or-put
|
||||
WebIDL::ExceptionOr<GC::Ref<IDBRequest>> IDBObjectStore::add_or_put(GC::Ref<IDBObjectStore> handle, JS::Value value, Optional<JS::Value> const& key, bool no_overwrite)
|
||||
{
|
||||
auto& realm = this->realm();
|
||||
|
||||
// 1. Let transaction be handle’s transaction.
|
||||
auto transaction = handle->transaction();
|
||||
|
||||
// 2. Let store be handle’s object store.
|
||||
auto& store = *handle->store();
|
||||
|
||||
// FIXME: 3. If 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 running add/put"_string);
|
||||
|
||||
// 5. If transaction is a read-only transaction, throw a "ReadOnlyError" DOMException.
|
||||
if (transaction->is_readonly())
|
||||
return WebIDL::ReadOnlyError::create(realm, "Transaction is read-only"_string);
|
||||
|
||||
auto key_was_given = key.has_value() && key != JS::js_undefined();
|
||||
|
||||
// 6. If store uses in-line keys and key was given, throw a "DataError" DOMException.
|
||||
if (store.uses_inline_keys() && key_was_given)
|
||||
return WebIDL::DataError::create(realm, "Store uses in-line keys and key was given"_string);
|
||||
|
||||
// 7. If store uses out-of-line keys and has no key generator and key was not given, throw a "DataError" DOMException.
|
||||
if (store.uses_out_of_line_keys() && !store.key_generator().has_value() && !key_was_given)
|
||||
return WebIDL::DataError::create(realm, "Store uses out-of-line keys and has no key generator and key was not given"_string);
|
||||
|
||||
GC::Ptr<Key> key_value;
|
||||
// 8. If key was given, then:
|
||||
if (key_was_given) {
|
||||
// 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()));
|
||||
// 2. If r is invalid, throw a "DataError" DOMException.
|
||||
if (maybe_key.is_error())
|
||||
return WebIDL::DataError::create(realm, "Key is invalid"_string);
|
||||
|
||||
// 3. Let key be r.
|
||||
key_value = maybe_key.release_value();
|
||||
}
|
||||
|
||||
// 9. Let targetRealm be a user-agent defined Realm.
|
||||
auto& target_realm = realm;
|
||||
|
||||
// 10. Let clone be a clone of value in targetRealm during transaction. Rethrow any exceptions.
|
||||
auto clone = TRY(clone_in_realm(target_realm, value, transaction));
|
||||
|
||||
// 11. If store uses in-line keys, then:
|
||||
if (store.uses_inline_keys()) {
|
||||
// 1. Let kpk be the result of extracting a key from a value using a key path with clone and store’s 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()));
|
||||
|
||||
// 2. If kpk is invalid, throw a "DataError" DOMException.
|
||||
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.
|
||||
if (!maybe_kpk.is_error()) {
|
||||
key_value = maybe_kpk.release_value();
|
||||
}
|
||||
|
||||
// 4. Otherwise (kpk is failure):
|
||||
else {
|
||||
// 1. If store does not have a key generator, throw a "DataError" DOMException.
|
||||
if (!store.key_generator().has_value())
|
||||
return WebIDL::DataError::create(realm, "Store does not have a key generator"_string);
|
||||
|
||||
// 2. Otherwise, if check that a key could be injected into a value with clone and store’s key path return false, throw a "DataError" DOMException.
|
||||
if (!check_that_a_key_could_be_injected_into_a_value(realm, clone, store.key_path().value()))
|
||||
return WebIDL::DataError::create(realm, "Key could not be injected into value"_string);
|
||||
}
|
||||
}
|
||||
|
||||
// 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 maybe_key = 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 == nullptr)
|
||||
return JS::js_undefined();
|
||||
|
||||
return convert_a_key_to_a_value(realm, GC::Ref(*optional_key));
|
||||
});
|
||||
|
||||
// 13. Return the result (an IDBRequest) of running asynchronously execute a request with handle and operation.
|
||||
auto result = asynchronously_execute_a_request(realm, handle, operation);
|
||||
dbgln_if(IDB_DEBUG, "Executing request for add/put with uuid {}", result->uuid());
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -44,6 +44,8 @@ public:
|
|||
WebIDL::ExceptionOr<GC::Ref<IDBIndex>> index(String const&);
|
||||
WebIDL::ExceptionOr<void> delete_index(String const&);
|
||||
|
||||
[[nodiscard]] WebIDL::ExceptionOr<GC::Ref<IDBRequest>> add_or_put(GC::Ref<IDBObjectStore>, JS::Value, Optional<JS::Value> const&, bool);
|
||||
|
||||
protected:
|
||||
explicit IDBObjectStore(JS::Realm&, GC::Ref<ObjectStore>, GC::Ref<IDBTransaction>);
|
||||
virtual void initialize(JS::Realm&) override;
|
||||
|
|
|
@ -1400,32 +1400,13 @@ WebIDL::ExceptionOr<GC::Ptr<Key>> store_a_record_into_an_object_store(JS::Realm&
|
|||
}
|
||||
}
|
||||
|
||||
// 5. If index’s multiEntry flag is false, or if index key is not an array key
|
||||
// FIXME: 5. If index’s multiEntry flag is false, or if index key is not an array key
|
||||
// then store a record in index containing index key as its key and key as its value.
|
||||
// The record is stored in index’s list of records such that the list is sorted primarily on the records keys,
|
||||
// and secondarily on the records values, in ascending order.
|
||||
if (!index_multi_entry || !index_key_is_array) {
|
||||
// FIXME:
|
||||
// Record index_record = {
|
||||
// .key = index_key_value,
|
||||
// .value = MUST(HTML::structured_serialize_for_storage(realm.vm(), key)),
|
||||
// };
|
||||
// index->store_a_record(index_record);
|
||||
}
|
||||
|
||||
// 6. If index’s multiEntry flag is true and index key is an array key,
|
||||
// // FIXME: 6. If index’s multiEntry flag is true and index key is an array key,
|
||||
// then for each subkey of the subkeys of index key store a record in index containing subkey as its key and key as its value.
|
||||
if (index_multi_entry && index_key_is_array) {
|
||||
for (auto const& subkey : index_key_value->subkeys()) {
|
||||
(void)subkey;
|
||||
// FIXME:
|
||||
// Record index_record = {
|
||||
// .key = *subkey,
|
||||
// .value = MUST(HTML::structured_serialize_for_storage(realm.vm(), key)),
|
||||
// };
|
||||
// index->store_a_record(index_record);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 6. Return key.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue