mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-20 11:36:10 +00:00
LibWeb/IDB: Implement IDBObjectStore::createIndex
This commit is contained in:
parent
a235dd4300
commit
3367352991
Notes:
github-actions[bot]
2025-04-09 17:50:46 +00:00
Author: https://github.com/stelar7 Commit: https://github.com/LadybirdBrowser/ladybird/commit/3367352991e Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4178 Reviewed-by: https://github.com/ADKaster ✅ Reviewed-by: https://github.com/AtkinsSJ
7 changed files with 88 additions and 14 deletions
|
@ -71,14 +71,16 @@ WebIDL::ExceptionOr<void> IDBIndex::set_name(String const& value)
|
|||
return {};
|
||||
|
||||
// 8. If an index named name already exists in index’s object store, throw a "ConstraintError" DOMException.
|
||||
for (auto const& existing_index : m_object_store_handle->index_set()) {
|
||||
if (existing_index->name() == name)
|
||||
return WebIDL::ConstraintError::create(realm, "An index with the given name already exists"_string);
|
||||
}
|
||||
if (index->object_store()->index_set().contains(name))
|
||||
return WebIDL::ConstraintError::create(realm, "An index with the given name already exists"_string);
|
||||
|
||||
// 9. Set index’s name to name.
|
||||
index->set_name(name);
|
||||
|
||||
// NOTE: Update the key in the map so it still matches the name
|
||||
auto old_value = m_object_store_handle->index_set().take(m_name).release_value();
|
||||
m_object_store_handle->index_set().set(name, old_value);
|
||||
|
||||
// 10. Set this’s name to name.
|
||||
m_name = name;
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <LibWeb/Bindings/IDBObjectStorePrototype.h>
|
||||
#include <LibWeb/Bindings/Intrinsics.h>
|
||||
#include <LibWeb/HTML/EventNames.h>
|
||||
#include <LibWeb/IndexedDB/IDBIndex.h>
|
||||
#include <LibWeb/IndexedDB/IDBObjectStore.h>
|
||||
|
||||
namespace Web::IndexedDB {
|
||||
|
@ -41,6 +42,7 @@ void IDBObjectStore::visit_edges(Visitor& visitor)
|
|||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_store);
|
||||
visitor.visit(m_transaction);
|
||||
visitor.visit(m_indexes);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/IndexedDB/#dom-idbobjectstore-keypath
|
||||
|
@ -101,4 +103,54 @@ WebIDL::ExceptionOr<void> IDBObjectStore::set_name(String const& value)
|
|||
return {};
|
||||
}
|
||||
|
||||
// https://w3c.github.io/IndexedDB/#dom-idbobjectstore-createindex
|
||||
WebIDL::ExceptionOr<GC::Ref<IDBIndex>> IDBObjectStore::create_index(String const& name, KeyPath key_path, IDBIndexParameters options)
|
||||
{
|
||||
auto& realm = this->realm();
|
||||
|
||||
// 1. Let transaction be this's transaction.
|
||||
auto transaction = this->transaction();
|
||||
|
||||
// 2. Let store be this's object store.
|
||||
auto store = this->store();
|
||||
|
||||
// 3. If transaction is not an upgrade transaction, throw an "InvalidStateError" DOMException.
|
||||
if (transaction->mode() != Bindings::IDBTransactionMode::Versionchange)
|
||||
return WebIDL::InvalidStateError::create(realm, "Transaction is not an upgrade transaction"_string);
|
||||
|
||||
// FIXME: 4. If store has been deleted, throw an "InvalidStateError" DOMException.
|
||||
|
||||
// 5. 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 creating index"_string);
|
||||
|
||||
// 6. If an index named name already exists in store, throw a "ConstraintError" DOMException.
|
||||
if (store->index_set().contains(name))
|
||||
return WebIDL::ConstraintError::create(realm, "An index with the given name already exists"_string);
|
||||
|
||||
// 7. If keyPath is not a valid key path, throw a "SyntaxError" DOMException.
|
||||
if (!is_valid_key_path(key_path))
|
||||
return WebIDL::SyntaxError::create(realm, "Key path is not valid"_string);
|
||||
|
||||
// 8. Let unique be options’s unique member.
|
||||
auto unique = options.unique;
|
||||
|
||||
// 9. Let multiEntry be options’s multiEntry member.
|
||||
auto multi_entry = options.multi_entry;
|
||||
|
||||
// 10. If keyPath is a sequence and multiEntry is true, throw an "InvalidAccessError" DOMException.
|
||||
if (key_path.has<Vector<String>>() && multi_entry)
|
||||
return WebIDL::InvalidAccessError::create(realm, "Key path is a sequence and multiEntry is true"_string);
|
||||
|
||||
// 11. Let index be a new index in store.
|
||||
// Set index’s name to name, key path to keyPath, unique flag to unique, and multiEntry flag to multiEntry.
|
||||
auto index = Index::create(realm, store, name, key_path, unique, multi_entry);
|
||||
|
||||
// 12. Add index to this's index set.
|
||||
this->index_set().set(name, index);
|
||||
|
||||
// 13. Return a new index handle associated with index and this.
|
||||
return IDBIndex::create(realm, index, *this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/HashMap.h>
|
||||
#include <LibGC/Heap.h>
|
||||
#include <LibWeb/Bindings/PlatformObject.h>
|
||||
#include <LibWeb/IndexedDB/IDBTransaction.h>
|
||||
|
@ -13,6 +14,11 @@
|
|||
|
||||
namespace Web::IndexedDB {
|
||||
|
||||
struct IDBIndexParameters {
|
||||
bool unique { false };
|
||||
bool multi_entry { false };
|
||||
};
|
||||
|
||||
// https://w3c.github.io/IndexedDB/#object-store-interface
|
||||
// https://w3c.github.io/IndexedDB/#object-store-handle-construct
|
||||
class IDBObjectStore : public Bindings::PlatformObject {
|
||||
|
@ -23,14 +29,17 @@ public:
|
|||
virtual ~IDBObjectStore() override;
|
||||
[[nodiscard]] static GC::Ref<IDBObjectStore> create(JS::Realm&, GC::Ref<ObjectStore>, GC::Ref<IDBTransaction>);
|
||||
|
||||
JS::Value key_path() const;
|
||||
GC::Ref<IDBTransaction> transaction() const { return m_transaction; }
|
||||
|
||||
// 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(); }
|
||||
JS::Value key_path() const;
|
||||
String name() const { return m_name; }
|
||||
WebIDL::ExceptionOr<void> set_name(String const& value);
|
||||
GC::Ref<IDBTransaction> transaction() const { return m_transaction; }
|
||||
GC::Ref<ObjectStore> store() const { return m_store; }
|
||||
AK::HashMap<String, GC::Ref<Index>>& index_set() { return m_indexes; }
|
||||
|
||||
WebIDL::ExceptionOr<GC::Ref<IDBIndex>> create_index(String const&, KeyPath, IDBIndexParameters options);
|
||||
|
||||
protected:
|
||||
explicit IDBObjectStore(JS::Realm&, GC::Ref<ObjectStore>, GC::Ref<IDBTransaction>);
|
||||
|
@ -44,6 +53,9 @@ private:
|
|||
|
||||
// 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;
|
||||
|
||||
// An object store handle has an index set
|
||||
AK::HashMap<String, GC::Ref<Index>> m_indexes;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ interface IDBObjectStore {
|
|||
[FIXME, NewObject] IDBRequest openCursor(optional any query, optional IDBCursorDirection direction = "next");
|
||||
[FIXME, NewObject] IDBRequest openKeyCursor(optional any query, optional IDBCursorDirection direction = "next");
|
||||
[FIXME] IDBIndex index(DOMString name);
|
||||
[FIXME, NewObject] IDBIndex createIndex(DOMString name, (DOMString or sequence<DOMString>) keyPath, optional IDBIndexParameters options = {});
|
||||
[NewObject] IDBIndex createIndex(DOMString name, (DOMString or sequence<DOMString>) keyPath, optional IDBIndexParameters options = {});
|
||||
[FIXME] undefined deleteIndex(DOMString name);
|
||||
};
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ Index::Index(GC::Ref<ObjectStore> store, String name, KeyPath const& key_path, b
|
|||
, m_multi_entry(multi_entry)
|
||||
, m_key_path(key_path)
|
||||
{
|
||||
store->add_index(*this);
|
||||
store->index_set().set(name, *this);
|
||||
}
|
||||
|
||||
void Index::visit_edges(Visitor& visitor)
|
||||
|
@ -39,4 +39,13 @@ void Index::visit_edges(Visitor& visitor)
|
|||
}
|
||||
}
|
||||
|
||||
void Index::set_name(String name)
|
||||
{
|
||||
// NOTE: Update the key in the map so it still matches the name
|
||||
auto old_value = m_object_store->index_set().take(m_name).release_value();
|
||||
m_object_store->index_set().set(name, old_value);
|
||||
|
||||
m_name = move(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ public:
|
|||
[[nodiscard]] static GC::Ref<Index> create(JS::Realm&, GC::Ref<ObjectStore>, String, KeyPath const&, bool, bool);
|
||||
virtual ~Index();
|
||||
|
||||
void set_name(String name) { m_name = move(name); }
|
||||
void set_name(String name);
|
||||
[[nodiscard]] String name() const { return m_name; }
|
||||
[[nodiscard]] bool unique() const { return m_unique; }
|
||||
[[nodiscard]] bool multi_entry() const { return m_multi_entry; }
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/Variant.h>
|
||||
|
@ -37,12 +38,10 @@ public:
|
|||
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<KeyGenerator> key_generator() const { return m_key_generator; }
|
||||
AK::HashMap<String, GC::Ref<Index>>& index_set() { return m_indexes; }
|
||||
|
||||
GC::Ref<Database> database() const { return m_database; }
|
||||
|
||||
void add_index(GC::Ref<Index> index) { m_indexes.append(index); }
|
||||
ReadonlySpan<GC::Ref<Index>> index_set() const { return m_indexes; }
|
||||
|
||||
protected:
|
||||
virtual void visit_edges(Visitor&) override;
|
||||
|
||||
|
@ -53,7 +52,7 @@ private:
|
|||
GC::Ref<Database> m_database;
|
||||
|
||||
// AD-HOC: An Index has referenced ObjectStores, we also need the reverse mapping
|
||||
Vector<GC::Ref<Index>> m_indexes;
|
||||
AK::HashMap<String, GC::Ref<Index>> m_indexes;
|
||||
|
||||
// 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;
|
||||
|
|
Loading…
Add table
Reference in a new issue