LibWeb: Implement most of upgrade_a_database for IndexedDB

This commit is contained in:
stelar7 2024-11-07 20:54:13 +01:00 committed by Jelle Raaijmakers
commit 1656d8fe07
Notes: github-actions[bot] 2024-11-26 13:51:49 +00:00
7 changed files with 81 additions and 17 deletions

View file

@ -32,6 +32,7 @@ void IDBRequest::visit_edges(Visitor& visitor)
Base::visit_edges(visitor);
visitor.visit(m_error);
visitor.visit(m_result);
visitor.visit(m_transaction);
}
// https://w3c.github.io/IndexedDB/#dom-idbrequest-onsuccess

View file

@ -10,11 +10,13 @@
#include <LibWeb/Bindings/IDBRequestPrototype.h>
#include <LibWeb/DOM/EventTarget.h>
#include <LibWeb/IndexedDB/IDBTransaction.h>
namespace Web::IndexedDB {
using IDBRequestSource = Variant<Empty, GC::Ref<IDBObjectStore>, GC::Ref<IDBIndex>, GC::Ref<IDBCursor>>;
// https://w3c.github.io/IndexedDB/#request-api
class IDBRequest : public DOM::EventTarget {
WEB_PLATFORM_OBJECT(IDBRequest, DOM::EventTarget);
GC_DECLARE_ALLOCATOR(IDBRequest);
@ -25,6 +27,7 @@ public:
[[nodiscard]] bool done() const { return m_done; }
[[nodiscard]] bool processed() const { return m_processed; }
[[nodiscard]] IDBRequestSource source() const { return m_source; }
[[nodiscard]] GC::Ptr<IDBTransaction> transaction() const { return m_transaction; }
[[nodiscard]] Bindings::IDBRequestReadyState ready_state() const;
[[nodiscard]] WebIDL::ExceptionOr<GC::Ptr<WebIDL::DOMException>> error() const;
@ -35,6 +38,7 @@ public:
void set_error(GC::Ptr<WebIDL::DOMException> error) { m_error = error; }
void set_processed(bool processed) { m_processed = processed; }
void set_source(IDBRequestSource source) { m_source = source; }
void set_transaction(GC::Ref<IDBTransaction> transaction) { m_transaction = transaction; }
void set_onsuccess(WebIDL::CallbackType*);
WebIDL::CallbackType* onsuccess();
@ -57,7 +61,8 @@ private:
GC::Ptr<WebIDL::DOMException> m_error;
// A request has a source object.
IDBRequestSource m_source;
// FIXME: A request has a transaction which is initially null.
// A request has a transaction which is initially null.
GC::Ptr<IDBTransaction> m_transaction;
};
}

View file

@ -15,6 +15,7 @@
#include <LibWeb/HTML/EventNames.h>
#include <LibWeb/IndexedDB/IDBDatabase.h>
#include <LibWeb/IndexedDB/IDBRequest.h>
#include <LibWeb/IndexedDB/IDBTransaction.h>
#include <LibWeb/IndexedDB/IDBVersionChangeEvent.h>
#include <LibWeb/IndexedDB/Internal/Algorithms.h>
#include <LibWeb/IndexedDB/Internal/ConnectionQueueHandler.h>
@ -106,9 +107,8 @@ WebIDL::ExceptionOr<GC::Ref<IDBDatabase>> open_a_database_connection(JS::Realm&
return true;
}));
// FIXME: 6. Run upgrade a database using connection, version and request.
// NOTE: upgrade a database sets this flag, so we set it manually temporarily.
request->set_processed(true);
// 6. Run upgrade a database using connection, version and request.
upgrade_a_database(realm, connection, version, request);
// 7. If connection was closed, return a newly created "AbortError" DOMException and abort these steps.
if (connection->state() == IDBDatabase::ConnectionState::Closed) {
@ -282,4 +282,57 @@ void close_a_database_connection(IDBDatabase& connection, bool forced)
connection.dispatch_event(DOM::Event::create(connection.realm(), HTML::EventNames::close));
}
void upgrade_a_database(JS::Realm& realm, GC::Ref<IDBDatabase> connection, u64 version, GC::Ref<IDBRequest> request)
{
// 1. Let db be connections database.
auto db = connection->associated_database();
// 2. Let transaction be a new upgrade transaction with connection used as connection.
auto transaction = IDBTransaction::create(realm, connection);
// FIXME: 3. Set transactions scope to connections object store set.
// 4. Set dbs upgrade transaction to transaction.
db->set_upgrade_transaction(transaction);
// 5. Set transactions state to inactive.
transaction->set_state(IDBTransaction::TransactionState::Inactive);
// FIXME: 6. Start transaction.
// 7. Let old version be dbs version.
auto old_version = db->version();
// 8. Set dbs version to version. This change is considered part of the transaction, and so if the transaction is aborted, this change is reverted.
db->set_version(version);
// 9. Set requests processed flag to true.
request->set_processed(true);
// 10. Queue a task to run these steps:
HTML::queue_a_task(HTML::Task::Source::DatabaseAccess, nullptr, nullptr, GC::create_function(realm.vm().heap(), [&realm, request, connection, transaction, old_version, version]() {
// 1. Set requests result to connection.
request->set_result(connection);
// 2. Set requests transaction to transaction.
request->set_transaction(transaction);
// 3. Set requests done flag to true.
request->set_done(true);
// 4. Set transactions state to active.
transaction->set_state(IDBTransaction::TransactionState::Active);
// 5. Let didThrow be the result of firing a version change event named upgradeneeded at request with old version and version.
[[maybe_unused]] auto did_throw = fire_a_version_change_event(realm, HTML::EventNames::upgradeneeded, request, old_version, version);
// 6. Set transactions state to inactive.
transaction->set_state(IDBTransaction::TransactionState::Inactive);
// FIXME: 7. If didThrow is true, run abort a transaction with transaction and a newly created "AbortError" DOMException.
}));
// FIXME: 11. Wait for transaction to finish.
}
}

View file

@ -17,5 +17,6 @@ WebIDL::ExceptionOr<GC::Ref<IDBDatabase>> open_a_database_connection(JS::Realm&,
bool fire_a_version_change_event(JS::Realm&, FlyString const&, GC::Ref<DOM::EventTarget>, u64, Optional<u64>);
ErrorOr<Key> convert_a_value_to_a_key(JS::Realm&, JS::Value, Vector<JS::Value> = {});
void close_a_database_connection(IDBDatabase&, bool forced = false);
void upgrade_a_database(JS::Realm&, GC::Ref<IDBDatabase>, u64, GC::Ref<IDBRequest>);
}

View file

@ -25,6 +25,7 @@ void Database::visit_edges(Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_associated_connections);
visitor.visit(m_upgrade_transaction);
}
ConnectionQueue& ConnectionQueueHandler::for_key_and_name(StorageAPI::StorageKey& key, String& name)

View file

@ -25,6 +25,8 @@ public:
u64 version() const { return m_version; }
String name() const { return m_name; }
void set_upgrade_transaction(GC::Ptr<IDBTransaction> transaction) { m_upgrade_transaction = transaction; }
void associate(GC::Ref<IDBDatabase> connection) { m_associated_connections.append(connection); }
ReadonlySpan<GC::Ref<IDBDatabase>> associated_connections() { return m_associated_connections; }
Vector<GC::Root<IDBDatabase>> associated_connections_except(IDBDatabase& connection)
@ -66,7 +68,8 @@ private:
// A database has a version. When a database is first created, its version is 0 (zero).
u64 m_version { 0 };
// FIXME: A database has at most one associated upgrade transaction, which is either null or an upgrade transaction, and is initially null.
// A database has at most one associated upgrade transaction, which is either null or an upgrade transaction, and is initially null.
GC::Ptr<IDBTransaction> m_upgrade_transaction;
};
}

View file

@ -9,27 +9,27 @@ Found 24 tests
12 Pass
12 Fail
Details
Result Test Name MessageFail Database readback sort - String < Array Cannot access property "transaction" on undefined object "db"
Result Test Name MessageFail Database readback sort - String < Array undefined is not a function (evaluated from 'db.createObjectStore')
Pass IDBKey.cmp sorted - String < Array
Fail Database readback sort - float < String Cannot access property "transaction" on undefined object "db"
Fail Database readback sort - float < String undefined is not a function (evaluated from 'db.createObjectStore')
Pass IDBKey.cmp sorted - float < String
Fail Database readback sort - float < Date Cannot access property "transaction" on undefined object "db"
Fail Database readback sort - float < Date undefined is not a function (evaluated from 'db.createObjectStore')
Pass IDBKey.cmp sorted - float < Date
Fail Database readback sort - float < Date < String < Array Cannot access property "transaction" on undefined object "db"
Fail Database readback sort - float < Date < String < Array undefined is not a function (evaluated from 'db.createObjectStore')
Pass IDBKey.cmp sorted - float < Date < String < Array
Fail Database readback sort - Date(1 sec ago) < Date(now) < Date(1 minute in future) Cannot access property "transaction" on undefined object "db"
Fail Database readback sort - Date(1 sec ago) < Date(now) < Date(1 minute in future) undefined is not a function (evaluated from 'db.createObjectStore')
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 Cannot access property "transaction" on undefined object "db"
Fail Database readback sort - -1.1 < 1 < 1.01337 < 1.013373 < 2 undefined is not a function (evaluated from 'db.createObjectStore')
Pass IDBKey.cmp sorted - -1.1 < 1 < 1.01337 < 1.013373 < 2
Fail Database readback sort - -Infinity < -0.01 < 0 < Infinity Cannot access property "transaction" on undefined object "db"
Fail Database readback sort - -Infinity < -0.01 < 0 < Infinity undefined is not a function (evaluated from 'db.createObjectStore')
Pass IDBKey.cmp sorted - -Infinity < -0.01 < 0 < Infinity
Fail Database readback sort - "" < "a" < "ab" < "b" < "ba" Cannot access property "transaction" on undefined object "db"
Fail Database readback sort - "" < "a" < "ab" < "b" < "ba" undefined is not a function (evaluated from 'db.createObjectStore')
Pass IDBKey.cmp sorted - "" < "a" < "ab" < "b" < "ba"
Fail Database readback sort - Arrays Cannot access property "transaction" on undefined object "db"
Fail Database readback sort - Arrays undefined is not a function (evaluated from 'db.createObjectStore')
Pass IDBKey.cmp sorted - Arrays
Fail Database readback sort - Array.length: 10,000 < Array.length: 10,001 Cannot access property "transaction" on undefined object "db"
Fail Database readback sort - Array.length: 10,000 < Array.length: 10,001 undefined is not a function (evaluated from 'db.createObjectStore')
Pass IDBKey.cmp sorted - Array.length: 10,000 < Array.length: 10,001
Fail Database readback sort - Infinity inside arrays Cannot access property "transaction" on undefined object "db"
Fail Database readback sort - Infinity inside arrays undefined is not a function (evaluated from 'db.createObjectStore')
Pass IDBKey.cmp sorted - Infinity inside arrays
Fail Database readback sort - Test different stuff at once Cannot access property "transaction" on undefined object "db"
Fail Database readback sort - Test different stuff at once undefined is not a function (evaluated from 'db.createObjectStore')
Pass IDBKey.cmp sorted - Test different stuff at once