Skip to main content

script/dom/indexeddb/
idbindex.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4use dom_struct::dom_struct;
5use js::context::JSContext;
6use js::gc::MutableHandleValue;
7use script_bindings::cell::DomRefCell;
8use script_bindings::codegen::GenericBindings::IDBIndexBinding::IDBIndexMethods;
9use script_bindings::codegen::GenericBindings::IDBTransactionBinding::IDBTransactionMode;
10use script_bindings::conversions::SafeToJSValConvertible;
11use script_bindings::error::{Error, ErrorResult};
12use script_bindings::reflector::{Reflector, reflect_dom_object_with_cx};
13use script_bindings::str::DOMString;
14
15use crate::dom::bindings::root::{Dom, DomRoot};
16use crate::dom::globalscope::GlobalScope;
17use crate::dom::idbobjectstore::KeyPath;
18use crate::dom::indexeddb::idbobjectstore::IDBObjectStore;
19
20#[dom_struct]
21pub(crate) struct IDBIndex {
22    reflector_: Reflector,
23    object_store: Dom<IDBObjectStore>,
24    name: DomRefCell<DOMString>,
25    multi_entry: bool,
26    unique: bool,
27    key_path: KeyPath,
28}
29
30impl IDBIndex {
31    pub fn new_inherited(
32        object_store: &IDBObjectStore,
33        name: DOMString,
34        multi_entry: bool,
35        unique: bool,
36        key_path: KeyPath,
37    ) -> IDBIndex {
38        IDBIndex {
39            reflector_: Reflector::new(),
40            object_store: Dom::from_ref(object_store),
41            name: DomRefCell::new(name),
42            multi_entry,
43            unique,
44            key_path,
45        }
46    }
47
48    pub fn new(
49        cx: &mut JSContext,
50        global: &GlobalScope,
51        object_store: &IDBObjectStore,
52        name: DOMString,
53        multi_entry: bool,
54        unique: bool,
55        key_path: KeyPath,
56    ) -> DomRoot<IDBIndex> {
57        reflect_dom_object_with_cx(
58            Box::new(IDBIndex::new_inherited(
59                object_store,
60                name,
61                multi_entry,
62                unique,
63                key_path,
64            )),
65            global,
66            cx,
67        )
68    }
69}
70
71impl IDBIndexMethods<crate::DomTypeHolder> for IDBIndex {
72    /// <https://www.w3.org/TR/IndexedDB/#dom-idbindex-name>
73    fn Name(&self) -> DOMString {
74        self.name.borrow().clone()
75    }
76
77    /// <https://www.w3.org/TR/IndexedDB/#ref-for-dom-idbindex-name%E2%91%A2>
78    fn SetName(&self, name: DOMString) -> ErrorResult {
79        // Step 1: Let name be the given value.
80        // Step 2: Let transaction be this’s transaction.
81        let transaction = self.object_store.transaction();
82
83        // Step 3: Let index be this’s index.
84        // We do not have an explicit object representing the underlying index.
85
86        // Step 4: If transaction is not an upgrade transaction, throw an "InvalidStateError" DOMException.
87        if transaction.get_mode() != IDBTransactionMode::Versionchange {
88            return Err(Error::InvalidState(Some(
89                "Transaction is not an upgrade transaction".to_owned(),
90            )));
91        }
92
93        // Step 5: If transaction’s state is not active, then throw a "TransactionInactiveError" DOMException.
94        if !transaction.is_active() {
95            return Err(Error::TransactionInactive(Some(
96                "Transaction is not active while updating index name".to_owned(),
97            )));
98        }
99
100        // Step 6: If index or index’s object store has been deleted, throw an "InvalidStateError" DOMException.
101        let mut stored_name = self.name.borrow_mut();
102        if !self.object_store.has_index(&stored_name) ||
103            !transaction
104                .get_db()
105                .object_store_exists(&self.object_store.get_name())
106        {
107            return Err(Error::InvalidState(Some(
108                "Index or its object store has been deleted".to_owned(),
109            )));
110        }
111
112        // Step 7: If index’s name is equal to name, terminate these steps.
113        if *stored_name == name {
114            return Ok(());
115        }
116
117        // Step 8: If an index named name already exists in index’s object store, throw a "ConstraintError" DOMException.
118        if self.object_store.has_index(&name) {
119            return Err(Error::Constraint(Some(
120                "An index with the given name already exists".to_owned(),
121            )));
122        }
123
124        // Step 9: Set index’s name to name.
125        self.object_store.rename_index(&stored_name, &name);
126
127        // Step 10: Set this’s name to name.
128        *stored_name = name;
129        Ok(())
130    }
131
132    /// <https://www.w3.org/TR/IndexedDB/#dom-idbindex-objectstore>
133    fn ObjectStore(&self) -> DomRoot<IDBObjectStore> {
134        self.object_store.as_rooted()
135    }
136
137    /// <https://www.w3.org/TR/IndexedDB/#dom-idbindex-multientry>
138    fn MultiEntry(&self) -> bool {
139        self.multi_entry
140    }
141
142    /// <https://www.w3.org/TR/IndexedDB/#dom-idbindex-unique>
143    fn Unique(&self) -> bool {
144        self.unique
145    }
146
147    /// <https://www.w3.org/TR/IndexedDB/#dom-idbindex-keypath>
148    fn KeyPath(&self, cx: &mut JSContext, retval: MutableHandleValue) {
149        match &self.key_path {
150            KeyPath::String(string) => {
151                string.safe_to_jsval(cx, retval);
152            },
153            KeyPath::StringSequence(sequence) => {
154                sequence.safe_to_jsval(cx, retval);
155            },
156        }
157    }
158}