| 
									
										
										
										
											2024-11-07 19:00:20 +01:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2025-04-01 19:51:22 +02:00
										 |  |  |  * Copyright (c) 2024-2025, stelar7 <dudedbz@gmail.com> | 
					
						
							| 
									
										
										
										
											2024-11-07 19:00:20 +01:00
										 |  |  |  * | 
					
						
							|  |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-25 18:08:40 +02:00
										 |  |  | #include <LibWeb/Bindings/IDBDatabasePrototype.h>
 | 
					
						
							| 
									
										
										
										
											2024-11-07 19:00:20 +01:00
										 |  |  | #include <LibWeb/Bindings/Intrinsics.h>
 | 
					
						
							| 
									
										
										
										
											2025-04-02 10:28:04 +02:00
										 |  |  | #include <LibWeb/Crypto/Crypto.h>
 | 
					
						
							| 
									
										
										
										
											2024-11-07 19:00:20 +01:00
										 |  |  | #include <LibWeb/HTML/EventNames.h>
 | 
					
						
							| 
									
										
										
										
											2025-04-09 23:24:44 +02:00
										 |  |  | #include <LibWeb/IndexedDB/IDBObjectStore.h>
 | 
					
						
							| 
									
										
										
										
											2024-11-07 19:00:20 +01:00
										 |  |  | #include <LibWeb/IndexedDB/IDBTransaction.h>
 | 
					
						
							| 
									
										
										
										
											2024-12-01 21:58:42 +01:00
										 |  |  | #include <LibWeb/IndexedDB/Internal/Algorithms.h>
 | 
					
						
							| 
									
										
										
										
											2024-11-07 19:00:20 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace Web::IndexedDB { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | GC_DEFINE_ALLOCATOR(IDBTransaction); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | IDBTransaction::~IDBTransaction() = default; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-01 19:51:22 +02:00
										 |  |  | IDBTransaction::IDBTransaction(JS::Realm& realm, GC::Ref<IDBDatabase> connection, Bindings::IDBTransactionMode mode, Bindings::IDBTransactionDurability durability, Vector<GC::Ref<ObjectStore>> scopes) | 
					
						
							| 
									
										
										
										
											2024-11-07 19:00:20 +01:00
										 |  |  |     : EventTarget(realm) | 
					
						
							| 
									
										
										
										
											2025-04-01 19:51:22 +02:00
										 |  |  |     , m_connection(connection) | 
					
						
							|  |  |  |     , m_mode(mode) | 
					
						
							|  |  |  |     , m_durability(durability) | 
					
						
							|  |  |  |     , m_scope(move(scopes)) | 
					
						
							| 
									
										
										
										
											2024-11-07 19:00:20 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-04-02 10:28:04 +02:00
										 |  |  |     m_uuid = MUST(Crypto::generate_random_uuid()); | 
					
						
							| 
									
										
										
										
											2025-04-09 22:59:07 +02:00
										 |  |  |     connection->add_transaction(*this); | 
					
						
							| 
									
										
										
										
											2024-11-07 19:00:20 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-01 19:51:22 +02:00
										 |  |  | GC::Ref<IDBTransaction> IDBTransaction::create(JS::Realm& realm, GC::Ref<IDBDatabase> connection, Bindings::IDBTransactionMode mode, Bindings::IDBTransactionDurability durability = Bindings::IDBTransactionDurability::Default, Vector<GC::Ref<ObjectStore>> scopes = {}) | 
					
						
							| 
									
										
										
										
											2024-11-07 19:00:20 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-04-01 19:51:22 +02:00
										 |  |  |     return realm.create<IDBTransaction>(realm, connection, mode, durability, move(scopes)); | 
					
						
							| 
									
										
										
										
											2024-11-07 19:00:20 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void IDBTransaction::initialize(JS::Realm& realm) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     WEB_SET_PROTOTYPE_FOR_INTERFACE(IDBTransaction); | 
					
						
							| 
									
										
										
										
											2025-04-20 16:22:57 +02:00
										 |  |  |     Base::initialize(realm); | 
					
						
							| 
									
										
										
										
											2024-11-07 19:00:20 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void IDBTransaction::visit_edges(Visitor& visitor) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Base::visit_edges(visitor); | 
					
						
							|  |  |  |     visitor.visit(m_connection); | 
					
						
							|  |  |  |     visitor.visit(m_error); | 
					
						
							| 
									
										
										
										
											2024-12-01 21:57:32 +01:00
										 |  |  |     visitor.visit(m_associated_request); | 
					
						
							| 
									
										
										
										
											2025-04-01 19:51:22 +02:00
										 |  |  |     visitor.visit(m_scope); | 
					
						
							|  |  |  |     visitor.visit(m_cleanup_event_loop); | 
					
						
							| 
									
										
										
										
											2024-11-07 19:00:20 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void IDBTransaction::set_onabort(WebIDL::CallbackType* event_handler) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     set_event_handler_attribute(HTML::EventNames::abort, event_handler); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | WebIDL::CallbackType* IDBTransaction::onabort() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return event_handler_attribute(HTML::EventNames::abort); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void IDBTransaction::set_oncomplete(WebIDL::CallbackType* event_handler) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     set_event_handler_attribute(HTML::EventNames::complete, event_handler); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | WebIDL::CallbackType* IDBTransaction::oncomplete() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return event_handler_attribute(HTML::EventNames::complete); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void IDBTransaction::set_onerror(WebIDL::CallbackType* event_handler) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     set_event_handler_attribute(HTML::EventNames::error, event_handler); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | WebIDL::CallbackType* IDBTransaction::onerror() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return event_handler_attribute(HTML::EventNames::error); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-01 19:51:22 +02:00
										 |  |  | // https://w3c.github.io/IndexedDB/#dom-idbtransaction-abort
 | 
					
						
							| 
									
										
										
										
											2024-12-01 21:58:42 +01:00
										 |  |  | WebIDL::ExceptionOr<void> IDBTransaction::abort() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // 1. If this's state is committing or finished, then throw an "InvalidStateError" DOMException.
 | 
					
						
							|  |  |  |     if (m_state == TransactionState::Committing || m_state == TransactionState::Finished) | 
					
						
							|  |  |  |         return WebIDL::InvalidStateError::create(realm(), "Transaction is ending"_string); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 2. Set this's state to inactive and run abort a transaction with this and null.
 | 
					
						
							|  |  |  |     m_state = TransactionState::Inactive; | 
					
						
							|  |  |  |     abort_a_transaction(*this, nullptr); | 
					
						
							|  |  |  |     return {}; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-01 19:51:22 +02:00
										 |  |  | // https://w3c.github.io/IndexedDB/#dom-idbtransaction-objectstorenames
 | 
					
						
							|  |  |  | GC::Ref<HTML::DOMStringList> IDBTransaction::object_store_names() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // 1. Let names be a list of the names of the object stores in this's scope.
 | 
					
						
							|  |  |  |     Vector<String> names; | 
					
						
							|  |  |  |     for (auto const& object_store : this->scope()) | 
					
						
							|  |  |  |         names.append(object_store->name()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 2. Return the result (a DOMStringList) of creating a sorted name list with names.
 | 
					
						
							|  |  |  |     return create_a_sorted_name_list(realm(), names); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-09 23:11:12 +02:00
										 |  |  | // https://w3c.github.io/IndexedDB/#dom-idbtransaction-commit
 | 
					
						
							|  |  |  | WebIDL::ExceptionOr<void> IDBTransaction::commit() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto& realm = this->realm(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 1. If this's state is not active, then throw an "InvalidStateError" DOMException.
 | 
					
						
							|  |  |  |     if (m_state != TransactionState::Active) | 
					
						
							|  |  |  |         return WebIDL::InvalidStateError::create(realm, "Transaction is not active while commiting"_string); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 2. Run commit a transaction with this.
 | 
					
						
							|  |  |  |     commit_a_transaction(realm, *this); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return {}; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-09 23:24:44 +02:00
										 |  |  | GC::Ptr<ObjectStore> IDBTransaction::object_store_named(String const& name) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     for (auto const& store : m_scope) { | 
					
						
							|  |  |  |         if (store->name() == name) | 
					
						
							|  |  |  |             return store; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return nullptr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // https://w3c.github.io/IndexedDB/#dom-idbtransaction-objectstore
 | 
					
						
							|  |  |  | WebIDL::ExceptionOr<GC::Ref<IDBObjectStore>> IDBTransaction::object_store(String const& name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto& realm = this->realm(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 1. If this's state is finished, then throw an "InvalidStateError" DOMException.
 | 
					
						
							|  |  |  |     if (m_state == TransactionState::Finished) | 
					
						
							|  |  |  |         return WebIDL::InvalidStateError::create(realm, "Transaction is finished"_string); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 2. Let store be the object store named name in this's scope, or throw a "NotFoundError" DOMException if none.
 | 
					
						
							|  |  |  |     auto store = object_store_named(name); | 
					
						
							|  |  |  |     if (!store) | 
					
						
							| 
									
										
										
										
											2025-04-10 00:25:13 +02:00
										 |  |  |         return WebIDL::NotFoundError::create(realm, "Object store not found in transactions scope"_string); | 
					
						
							| 
									
										
										
										
											2025-04-09 23:24:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // 3. Return an object store handle associated with store and this.
 | 
					
						
							|  |  |  |     return IDBObjectStore::create(realm, *store, *this); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-07 19:00:20 +01:00
										 |  |  | } |