/* * Copyright (c) 2025, stelar7 * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Web::IndexedDB { using KeyPath = Variant>; // https://w3c.github.io/IndexedDB/#object-store-construct class ObjectStore : public JS::Cell { GC_CELL(ObjectStore, JS::Cell); GC_DECLARE_ALLOCATOR(ObjectStore); public: [[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(); } KeyGenerator& key_generator() { return *m_key_generator; } bool uses_a_key_generator() const { return m_key_generator.has_value(); } AK::HashMap>& index_set() { return m_indexes; } [[nodiscard]] bool is_deleted() const { return m_deleted; } void set_deleted(bool deleted) { m_deleted = deleted; } GC::Ref database() const { return m_database; } ReadonlySpan records() const { return m_records; } void remove_records_in_range(GC::Ref range); bool has_record_with_key(GC::Ref key); void store_a_record(ObjectStoreRecord record); void remove_record_with_key(GC::Ref key); u64 count_records_in_range(GC::Ref range); Optional first_in_range(GC::Ref range); void clear_records(); GC::ConservativeVector first_n_in_range(GC::Ref range, Optional count); GC::ConservativeVector last_n_in_range(GC::Ref range, Optional count); // https://w3c.github.io/IndexedDB/#generate-a-key ErrorOr generate_a_key(); // https://w3c.github.io/IndexedDB/#possibly-update-the-key-generator void possibly_update_the_key_generator(GC::Ref); // Mutation log access. The log is set externally by the readwrite transaction that owns it. GC::Ptr mutation_log() const { return m_mutation_log; } void set_mutation_log(GC::Ptr log) { m_mutation_log = log; } [[nodiscard]] size_t mutation_log_position() const; void revert_mutations_from(size_t position); protected: virtual void visit_edges(Visitor&) override; private: 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; // AD-HOC: An Index has referenced ObjectStores, we also need the reverse mapping AK::HashMap> 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; // An object store optionally has a key path. If the object store has a key path it is said to use in-line keys. Otherwise it is said to use out-of-line keys. Optional m_key_path; // An object store optionally has a key generator. Optional m_key_generator; // An object store has a list of records Vector m_records; bool m_deleted { false }; // AD-HOC: Tracks mutations for revert on request failure or transaction abort. GC::Ptr m_mutation_log; }; }