diff --git a/Libraries/LibWeb/IndexedDB/IDBDatabase.cpp b/Libraries/LibWeb/IndexedDB/IDBDatabase.cpp index 899ba38c3c7..72d858a26e3 100644 --- a/Libraries/LibWeb/IndexedDB/IDBDatabase.cpp +++ b/Libraries/LibWeb/IndexedDB/IDBDatabase.cpp @@ -132,8 +132,7 @@ WebIDL::ExceptionOr> IDBDatabase::create_object_store(St // Set the created object store's name to name. // If autoIncrement is true, then the created object store uses a key generator. // If keyPath is not null, set the created object store's key path to keyPath. - auto object_store = ObjectStore::create(realm, name, auto_increment, key_path); - database->add_object_store(object_store); + auto object_store = ObjectStore::create(realm, database, name, auto_increment, key_path); // 10. Return a new object store handle associated with store and transaction. return IDBObjectStore::create(realm, object_store, *transaction); diff --git a/Libraries/LibWeb/IndexedDB/IDBObjectStore.cpp b/Libraries/LibWeb/IndexedDB/IDBObjectStore.cpp index bf0e206b200..ddb006c42d7 100644 --- a/Libraries/LibWeb/IndexedDB/IDBObjectStore.cpp +++ b/Libraries/LibWeb/IndexedDB/IDBObjectStore.cpp @@ -21,6 +21,7 @@ IDBObjectStore::IDBObjectStore(JS::Realm& realm, GC::Ref store, GC: : PlatformObject(realm) , m_store(store) , m_transaction(transaction) + , m_name(store->name()) { } @@ -59,4 +60,45 @@ JS::Value IDBObjectStore::key_path() const }); } +// https://w3c.github.io/IndexedDB/#dom-idbobjectstore-name +WebIDL::ExceptionOr IDBObjectStore::set_name(String const& value) +{ + auto& realm = this->realm(); + + // 1. Let name be the given value. + auto const& name = value; + + // 2. Let transaction be this’s transaction. + auto& transaction = m_transaction; + + // 3. Let store be this’s object store. + auto& store = m_store; + + // FIXME: 4. If store has been deleted, throw an "InvalidStateError" DOMException. + + // 5. If transaction is not an upgrade transaction, throw an "InvalidStateError" DOMException. + if (transaction->mode() != Bindings::IDBTransactionMode::Versionchange) + return WebIDL::InvalidStateError::create(realm, "Attempted to set name outside of version change"_string); + + // 6. If transaction’s state is not active, throw a "TransactionInactiveError" DOMException. + if (transaction->state() != IDBTransaction::TransactionState::Active) + return WebIDL::TransactionInactiveError::create(realm, "Transaction is not active"_string); + + // 7. If store’s name is equal to name, terminate these steps. + if (store->name() == name) + return {}; + + // 8. If an object store named name already exists in store’s database, throw a "ConstraintError" DOMException. + if (store->database()->has_object_store_named(name)) + return WebIDL::ConstraintError::create(realm, "Object store with the given name already exists"_string); + + // 9. Set store’s name to name. + store->set_name(name); + + // 10. Set this’s name to name. + m_name = name; + + return {}; +} + } diff --git a/Libraries/LibWeb/IndexedDB/IDBObjectStore.h b/Libraries/LibWeb/IndexedDB/IDBObjectStore.h index 6acf517f005..c22fd5081ee 100644 --- a/Libraries/LibWeb/IndexedDB/IDBObjectStore.h +++ b/Libraries/LibWeb/IndexedDB/IDBObjectStore.h @@ -29,6 +29,8 @@ public: // https://w3c.github.io/IndexedDB/#dom-idbobjectstore-autoincrement // The autoIncrement getter steps are to return true if this’s object store has a key generator, and false otherwise. bool auto_increment() const { return m_store->key_generator().has_value(); } + String name() const { return m_name; } + WebIDL::ExceptionOr set_name(String const& value); protected: explicit IDBObjectStore(JS::Realm&, GC::Ref, GC::Ref); @@ -39,6 +41,9 @@ private: // An object store handle has an associated object store and an associated transaction. GC::Ref m_store; GC::Ref m_transaction; + + // An object store handle has a name, which is initialized to the name of the associated object store when the object store handle is created. + String m_name; }; } diff --git a/Libraries/LibWeb/IndexedDB/IDBObjectStore.idl b/Libraries/LibWeb/IndexedDB/IDBObjectStore.idl index e1790faa374..66dd3ef722d 100644 --- a/Libraries/LibWeb/IndexedDB/IDBObjectStore.idl +++ b/Libraries/LibWeb/IndexedDB/IDBObjectStore.idl @@ -4,7 +4,7 @@ [Exposed=(Window,Worker)] interface IDBObjectStore { - [FIXME] attribute DOMString name; + attribute DOMString name; readonly attribute any keyPath; [FIXME] readonly attribute DOMStringList indexNames; [SameObject] readonly attribute IDBTransaction transaction; diff --git a/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.cpp b/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.cpp index a92cc6096cc..2169030f821 100644 --- a/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.cpp +++ b/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.cpp @@ -12,9 +12,26 @@ GC_DEFINE_ALLOCATOR(ObjectStore); ObjectStore::~ObjectStore() = default; -GC::Ref ObjectStore::create(JS::Realm& realm, String name, bool auto_increment, Optional const& key_path) +GC::Ref ObjectStore::create(JS::Realm& realm, GC::Ref database, String name, bool auto_increment, Optional const& key_path) { - return realm.create(name, auto_increment, key_path); + return realm.create(database, name, auto_increment, key_path); +} + +ObjectStore::ObjectStore(GC::Ref database, String name, bool auto_increment, Optional const& key_path) + : m_database(database) + , m_name(move(name)) + , m_key_path(key_path) +{ + database->add_object_store(*this); + + if (auto_increment) + m_key_generator = KeyGenerator {}; +} + +void ObjectStore::visit_edges(Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(m_database); } } diff --git a/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.h b/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.h index cf2b55adaef..99b7de285ba 100644 --- a/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.h +++ b/Libraries/LibWeb/IndexedDB/Internal/ObjectStore.h @@ -14,6 +14,7 @@ #include #include #include +#include #include namespace Web::IndexedDB { @@ -26,23 +27,26 @@ class ObjectStore : public JS::Cell { GC_DECLARE_ALLOCATOR(ObjectStore); public: - [[nodiscard]] static GC::Ref create(JS::Realm&, String, bool, Optional const&); + [[nodiscard]] static GC::Ref create(JS::Realm&, GC::Ref, String, bool, Optional const&); virtual ~ObjectStore(); String name() const { return m_name; } + void set_name(String name) { m_name = move(name); } Optional key_path() const { return m_key_path; } bool uses_inline_keys() const { return m_key_path.has_value(); } bool uses_out_of_line_keys() const { return !m_key_path.has_value(); } Optional key_generator() const { return m_key_generator; } + GC::Ref database() const { return m_database; } + +protected: + virtual void visit_edges(Visitor&) override; + private: - ObjectStore(String name, bool auto_increment, Optional const& key_path) - : m_name(move(name)) - , m_key_path(key_path) - { - if (auto_increment) - m_key_generator = KeyGenerator {}; - } + ObjectStore(GC::Ref database, String name, bool auto_increment, Optional const& key_path); + + // AD-HOC: An ObjectStore needs to know what Database it belongs to... + GC::Ref m_database; // An object store has a name, which is a name. At any one time, the name is unique within the database to which it belongs. String m_name;