mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-24 21:45:20 +00:00
LibWeb/IDB: Implement IDBDatabase::createObjectStore
This commit is contained in:
parent
3c5578cc87
commit
1057c88fdd
Notes:
github-actions[bot]
2025-03-27 15:49:41 +00:00
Author: https://github.com/stelar7 Commit: https://github.com/LadybirdBrowser/ladybird/commit/1057c88fdda Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4077 Reviewed-by: https://github.com/AtkinsSJ Reviewed-by: https://github.com/gmta ✅
7 changed files with 102 additions and 10 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024, stelar7 <dudedbz@gmail.com>
|
||||
* Copyright (c) 2024-2025, stelar7 <dudedbz@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -8,6 +8,7 @@
|
|||
#include <LibWeb/Bindings/Intrinsics.h>
|
||||
#include <LibWeb/HTML/EventNames.h>
|
||||
#include <LibWeb/IndexedDB/IDBDatabase.h>
|
||||
#include <LibWeb/IndexedDB/IDBObjectStore.h>
|
||||
#include <LibWeb/IndexedDB/Internal/Algorithms.h>
|
||||
|
||||
namespace Web::IndexedDB {
|
||||
|
@ -90,4 +91,52 @@ void IDBDatabase::close()
|
|||
close_a_database_connection(*this);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/IndexedDB/#dom-idbdatabase-createobjectstore
|
||||
WebIDL::ExceptionOr<GC::Ref<IDBObjectStore>> IDBDatabase::create_object_store(String const& name, IDBObjectStoreParameters const& options)
|
||||
{
|
||||
auto& realm = this->realm();
|
||||
|
||||
// 1. Let database be this's associated database.
|
||||
auto database = associated_database();
|
||||
|
||||
// 2. Let transaction be database’s upgrade transaction if it is not null, or throw an "InvalidStateError" DOMException otherwise.
|
||||
auto transaction = database->upgrade_transaction();
|
||||
if (!transaction)
|
||||
return WebIDL::InvalidStateError::create(realm, "Upgrade transaction is null"_string);
|
||||
|
||||
// 3. 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"_string);
|
||||
|
||||
// 4. Let keyPath be options’s keyPath member if it is not undefined or null, or null otherwise.
|
||||
auto key_path = options.key_path;
|
||||
|
||||
// 5. If keyPath is not null and is not a valid key path, throw a "SyntaxError" DOMException.
|
||||
if (key_path.has_value() && !is_valid_key_path(key_path.value()))
|
||||
return WebIDL::SyntaxError::create(realm, "Invalid key path"_string);
|
||||
|
||||
// 6. If an object store named name already exists in database throw a "ConstraintError" DOMException.
|
||||
if (database->has_object_store_named(name))
|
||||
return WebIDL::ConstraintError::create(realm, "Object store already exists"_string);
|
||||
|
||||
// 7. Let autoIncrement be options’s autoIncrement member.
|
||||
auto auto_increment = options.auto_increment;
|
||||
|
||||
bool is_empty_key_path_or_sequence = key_path.has_value() && key_path.value().visit([](String const& value) -> bool { return value.is_empty(); }, [](Vector<String> const&) -> bool { return true; });
|
||||
|
||||
// 8. If autoIncrement is true and keyPath is an empty string or any sequence (empty or otherwise), throw an "InvalidAccessError" DOMException.
|
||||
if (auto_increment && is_empty_key_path_or_sequence)
|
||||
return WebIDL::InvalidAccessError::create(realm, "Auto increment is true and key path is empty or sequence"_string);
|
||||
|
||||
// 9. Let store be a new object store in database.
|
||||
// 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);
|
||||
|
||||
// 10. Return a new object store handle associated with store and transaction.
|
||||
return IDBObjectStore::create(realm, object_store, *transaction);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024, stelar7 <dudedbz@gmail.com>
|
||||
* Copyright (c) 2024-2025, stelar7 <dudedbz@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -11,10 +11,19 @@
|
|||
#include <LibWeb/HTML/DOMStringList.h>
|
||||
#include <LibWeb/IndexedDB/IDBRequest.h>
|
||||
#include <LibWeb/IndexedDB/Internal/Database.h>
|
||||
#include <LibWeb/IndexedDB/Internal/ObjectStore.h>
|
||||
#include <LibWeb/StorageAPI/StorageKey.h>
|
||||
|
||||
namespace Web::IndexedDB {
|
||||
|
||||
using KeyPath = Variant<String, Vector<String>>;
|
||||
|
||||
// https://w3c.github.io/IndexedDB/#dictdef-idbobjectstoreparameters
|
||||
struct IDBObjectStoreParameters {
|
||||
Optional<KeyPath> key_path;
|
||||
bool auto_increment { false };
|
||||
};
|
||||
|
||||
// FIXME: I'm not sure if this object should do double duty as both the connection and the interface
|
||||
// but the spec treats it as such...?
|
||||
// https://w3c.github.io/IndexedDB/#IDBDatabase-interface
|
||||
|
@ -44,6 +53,8 @@ public:
|
|||
[[nodiscard]] ConnectionState state() const { return m_state; }
|
||||
[[nodiscard]] GC::Ref<Database> associated_database() { return m_associated_database; }
|
||||
|
||||
WebIDL::ExceptionOr<GC::Ref<IDBObjectStore>> create_object_store(String const&, IDBObjectStoreParameters const&);
|
||||
|
||||
void close();
|
||||
|
||||
void set_onabort(WebIDL::CallbackType*);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#import <DOM/EventTarget.idl>
|
||||
#import <DOM/EventHandler.idl>
|
||||
#import <IndexedDB/IDBObjectStore.idl>
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBDatabase : EventTarget {
|
||||
|
@ -9,7 +10,7 @@ interface IDBDatabase : EventTarget {
|
|||
|
||||
[FIXME, NewObject] IDBTransaction transaction((DOMString or sequence<DOMString>) storeNames, optional IDBTransactionMode mode = "readonly", optional IDBTransactionOptions options = {});
|
||||
undefined close();
|
||||
[FIXME, NewObject] IDBObjectStore createObjectStore(DOMString name, optional IDBObjectStoreParameters options = {});
|
||||
[NewObject] IDBObjectStore createObjectStore(DOMString name, optional IDBObjectStoreParameters options = {});
|
||||
[FIXME] undefined deleteObjectStore(DOMString name);
|
||||
|
||||
// Event handlers:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024, stelar7 <dudedbz@gmail.com>
|
||||
* Copyright (c) 2024-2025, stelar7 <dudedbz@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -15,14 +15,16 @@ GC_DEFINE_ALLOCATOR(IDBObjectStore);
|
|||
|
||||
IDBObjectStore::~IDBObjectStore() = default;
|
||||
|
||||
IDBObjectStore::IDBObjectStore(JS::Realm& realm)
|
||||
IDBObjectStore::IDBObjectStore(JS::Realm& realm, GC::Ref<ObjectStore> store, GC::Ref<IDBTransaction> transaction)
|
||||
: PlatformObject(realm)
|
||||
, m_store(store)
|
||||
, m_transaction(transaction)
|
||||
{
|
||||
}
|
||||
|
||||
GC::Ref<IDBObjectStore> IDBObjectStore::create(JS::Realm& realm)
|
||||
GC::Ref<IDBObjectStore> IDBObjectStore::create(JS::Realm& realm, GC::Ref<ObjectStore> store, GC::Ref<IDBTransaction> transaction)
|
||||
{
|
||||
return realm.create<IDBObjectStore>(realm);
|
||||
return realm.create<IDBObjectStore>(realm, store, transaction);
|
||||
}
|
||||
|
||||
void IDBObjectStore::initialize(JS::Realm& realm)
|
||||
|
@ -31,4 +33,11 @@ void IDBObjectStore::initialize(JS::Realm& realm)
|
|||
WEB_SET_PROTOTYPE_FOR_INTERFACE(IDBObjectStore);
|
||||
}
|
||||
|
||||
void IDBObjectStore::visit_edges(Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_store);
|
||||
visitor.visit(m_transaction);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024, stelar7 <dudedbz@gmail.com>
|
||||
* Copyright (c) 2024-2025, stelar7 <dudedbz@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -8,21 +8,30 @@
|
|||
|
||||
#include <LibGC/Heap.h>
|
||||
#include <LibWeb/Bindings/PlatformObject.h>
|
||||
#include <LibWeb/IndexedDB/IDBTransaction.h>
|
||||
#include <LibWeb/IndexedDB/Internal/ObjectStore.h>
|
||||
|
||||
namespace Web::IndexedDB {
|
||||
|
||||
// https://w3c.github.io/IndexedDB/#object-store-interface
|
||||
// https://w3c.github.io/IndexedDB/#object-store-handle-construct
|
||||
class IDBObjectStore : public Bindings::PlatformObject {
|
||||
WEB_PLATFORM_OBJECT(IDBObjectStore, Bindings::PlatformObject);
|
||||
GC_DECLARE_ALLOCATOR(IDBObjectStore);
|
||||
|
||||
public:
|
||||
virtual ~IDBObjectStore() override;
|
||||
[[nodiscard]] static GC::Ref<IDBObjectStore> create(JS::Realm&);
|
||||
[[nodiscard]] static GC::Ref<IDBObjectStore> create(JS::Realm&, GC::Ref<ObjectStore>, GC::Ref<IDBTransaction>);
|
||||
|
||||
protected:
|
||||
explicit IDBObjectStore(JS::Realm&);
|
||||
explicit IDBObjectStore(JS::Realm&, GC::Ref<ObjectStore>, GC::Ref<IDBTransaction>);
|
||||
virtual void initialize(JS::Realm&) override;
|
||||
virtual void visit_edges(Visitor& visitor) override;
|
||||
|
||||
private:
|
||||
// An object store handle has an associated object store and an associated transaction.
|
||||
GC::Ref<ObjectStore> m_store;
|
||||
GC::Ref<IDBTransaction> m_transaction;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -29,6 +29,16 @@ void Database::visit_edges(Visitor& visitor)
|
|||
visitor.visit(m_object_stores);
|
||||
}
|
||||
|
||||
bool Database::has_object_store_named(String const& name) const
|
||||
{
|
||||
for (auto const& object_store : m_object_stores) {
|
||||
if (object_store->name() == name)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector<GC::Root<Database>> Database::for_key(StorageAPI::StorageKey const& key)
|
||||
{
|
||||
Vector<GC::Root<Database>> databases;
|
||||
|
|
|
@ -40,6 +40,9 @@ public:
|
|||
return connections;
|
||||
}
|
||||
|
||||
bool has_object_store_named(String const& name) const;
|
||||
void add_object_store(GC::Ref<ObjectStore> object_store) { m_object_stores.append(object_store); }
|
||||
|
||||
[[nodiscard]] static Vector<GC::Root<Database>> for_key(StorageAPI::StorageKey const&);
|
||||
[[nodiscard]] static Optional<GC::Root<Database> const&> for_key_and_name(StorageAPI::StorageKey&, String&);
|
||||
[[nodiscard]] static ErrorOr<GC::Root<Database>> create_for_key_and_name(JS::Realm&, StorageAPI::StorageKey&, String&);
|
||||
|
|
Loading…
Add table
Reference in a new issue