1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_OBJECT_STORE_H_
27 #define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_OBJECT_STORE_H_
28 
29 #include "base/memory/scoped_refptr.h"
30 #include "third_party/blink/public/common/indexeddb/web_idb_types.h"
31 #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
32 #include "third_party/blink/renderer/bindings/modules/v8/v8_idb_index_parameters.h"
33 #include "third_party/blink/renderer/modules/indexeddb/idb_cursor.h"
34 #include "third_party/blink/renderer/modules/indexeddb/idb_index.h"
35 #include "third_party/blink/renderer/modules/indexeddb/idb_key.h"
36 #include "third_party/blink/renderer/modules/indexeddb/idb_key_range.h"
37 #include "third_party/blink/renderer/modules/indexeddb/idb_metadata.h"
38 #include "third_party/blink/renderer/modules/indexeddb/idb_request.h"
39 #include "third_party/blink/renderer/modules/indexeddb/idb_transaction.h"
40 #include "third_party/blink/renderer/modules/indexeddb/web_idb_cursor.h"
41 #include "third_party/blink/renderer/modules/indexeddb/web_idb_database.h"
42 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
43 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
44 
45 namespace blink {
46 
47 class DOMStringList;
48 class ExceptionState;
49 
50 class MODULES_EXPORT IDBObjectStore final : public ScriptWrappable {
51   DEFINE_WRAPPERTYPEINFO();
52 
53  public:
54   IDBObjectStore(scoped_refptr<IDBObjectStoreMetadata>, IDBTransaction*);
55   ~IDBObjectStore() override = default;
56 
57   void Trace(Visitor*) override;
58 
Metadata()59   const IDBObjectStoreMetadata& Metadata() const { return *metadata_; }
IdbKeyPath()60   const IDBKeyPath& IdbKeyPath() const { return Metadata().key_path; }
61 
62   // Per spec prose, keyPath attribute should return the same object each time
63   // (if it is not just a primitive type). The IDL cannot use [SameObject]
64   // because the key path may not be an 'object'. So use [CachedAttribute],
65   // but never dirty the cache.
IsKeyPathDirty()66   bool IsKeyPathDirty() const { return false; }
67 
68   // Implement the IDBObjectStore IDL
Id()69   int64_t Id() const { return Metadata().id; }
name()70   const String& name() const { return Metadata().name; }
71   void setName(const String& name, ExceptionState&);
72   ScriptValue keyPath(ScriptState*) const;
73   DOMStringList* indexNames() const;
transaction()74   IDBTransaction* transaction() const { return transaction_.Get(); }
autoIncrement()75   bool autoIncrement() const { return Metadata().auto_increment; }
76 
77   IDBRequest* openCursor(ScriptState*,
78                          const ScriptValue& range,
79                          const String& direction,
80                          ExceptionState&);
81   IDBRequest* openKeyCursor(ScriptState*,
82                             const ScriptValue& range,
83                             const String& direction,
84                             ExceptionState&);
85   IDBRequest* get(ScriptState*, const ScriptValue& key, ExceptionState&);
86   IDBRequest* getKey(ScriptState*, const ScriptValue& key, ExceptionState&);
87   IDBRequest* getAll(ScriptState*,
88                      const ScriptValue& range,
89                      uint32_t max_count,
90                      ExceptionState&);
91   IDBRequest* getAll(ScriptState*, const ScriptValue& range, ExceptionState&);
92   IDBRequest* getAllKeys(ScriptState*,
93                          const ScriptValue& range,
94                          uint32_t max_count,
95                          ExceptionState&);
96   IDBRequest* getAllKeys(ScriptState*,
97                          const ScriptValue& range,
98                          ExceptionState&);
99   IDBRequest* add(ScriptState*, const ScriptValue& value, ExceptionState&);
100   IDBRequest* add(ScriptState*,
101                   const ScriptValue& value,
102                   const ScriptValue& key,
103                   ExceptionState&);
104   IDBRequest* put(ScriptState*, const ScriptValue& value, ExceptionState&);
105   IDBRequest* put(ScriptState*,
106                   const ScriptValue& value,
107                   const ScriptValue& key,
108                   ExceptionState&);
109   IDBRequest* Delete(ScriptState*, const ScriptValue& key, ExceptionState&);
110   IDBRequest* clear(ScriptState*, ExceptionState&);
111 
createIndex(ScriptState * script_state,const String & name,const StringOrStringSequence & key_path,const IDBIndexParameters * options,ExceptionState & exception_state)112   IDBIndex* createIndex(ScriptState* script_state,
113                         const String& name,
114                         const StringOrStringSequence& key_path,
115                         const IDBIndexParameters* options,
116                         ExceptionState& exception_state) {
117     return createIndex(script_state, name, IDBKeyPath(key_path), options,
118                        exception_state);
119   }
120   IDBIndex* index(const String& name, ExceptionState&);
121   void deleteIndex(const String& name, ExceptionState&);
122 
123   IDBRequest* count(ScriptState*, const ScriptValue& range, ExceptionState&);
124 
125   // Exposed for the use of IDBCursor::update().
126   IDBRequest* DoPut(ScriptState*,
127                     mojom::IDBPutMode,
128                     const IDBRequest::Source&,
129                     const ScriptValue&,
130                     const IDBKey*,
131                     ExceptionState&);
132 
133   // Used internally and by InspectorIndexedDBAgent:
134   IDBRequest* openCursor(
135       ScriptState*,
136       IDBKeyRange*,
137       mojom::IDBCursorDirection,
138       mojom::IDBTaskType = mojom::IDBTaskType::Normal,
139       IDBRequest::AsyncTraceState = IDBRequest::AsyncTraceState());
140   IDBRequest* deleteFunction(
141       ScriptState*,
142       IDBKeyRange*,
143       IDBRequest::AsyncTraceState = IDBRequest::AsyncTraceState());
144   IDBRequest* getKeyGeneratorCurrentNumber(
145       ScriptState*,
146       IDBRequest::AsyncTraceState = IDBRequest::AsyncTraceState());
147 
148   void MarkDeleted();
IsDeleted()149   bool IsDeleted() const { return deleted_; }
150 
151   // True if this object store was created in its associated transaction.
152   // Only valid if the store's associated transaction is a versionchange.
IsNewlyCreated()153   bool IsNewlyCreated() const {
154     DCHECK(transaction_->IsVersionChange());
155     // Object store IDs are allocated sequentially, so we can tell if an object
156     // store was created in this transaction by comparing its ID against the
157     // database's maximum object store ID at the time when the transaction was
158     // started.
159     return Id() > transaction_->OldMaxObjectStoreId();
160   }
161 
162   // Clears the cache used to implement the index() method.
163   //
164   // This should be called when the store's transaction clears its reference
165   // to this IDBObjectStore instance, so the store can clear its references to
166   // IDBIndex instances. This way, Oilpan can garbage-collect the instances
167   // that are not referenced in JavaScript.
168   //
169   // For most stores, the condition above is met when the transaction
170   // finishes. The exception is stores that are created and deleted in the
171   // same transaction. Those stores will remain marked for deletion even if
172   // the transaction aborts, so the transaction can forget about them (and
173   // clear their index caches) right when they are deleted.
174   void ClearIndexCache();
175 
176   // Sets the object store's metadata to a previous version.
177   //
178   // The reverting process includes reverting the metadata for the IDBIndex
179   // instances that are still tracked by the store. It does not revert the
180   // IDBIndex metadata for indexes that were deleted in this transaction.
181   //
182   // Used when a versionchange transaction is aborted.
183   void RevertMetadata(scoped_refptr<IDBObjectStoreMetadata> previous_metadata);
184   // This relies on the changes made by RevertMetadata().
185   void RevertDeletedIndexMetadata(IDBIndex& deleted_index);
186 
187   // Used by IDBIndex::setName:
ContainsIndex(const String & name)188   bool ContainsIndex(const String& name) const {
189     return FindIndexId(name) != IDBIndexMetadata::kInvalidId;
190   }
191   void RenameIndex(int64_t index_id, const String& new_name);
192 
193   WebIDBDatabase* BackendDB() const;
194 
195  private:
196   using IDBIndexMap = HeapHashMap<String, Member<IDBIndex>>;
197 
198   IDBIndex* createIndex(ScriptState*,
199                         const String& name,
200                         const IDBKeyPath&,
201                         const IDBIndexParameters*,
202                         ExceptionState&);
203   IDBRequest* DoPut(ScriptState*,
204                     mojom::IDBPutMode,
205                     const ScriptValue&,
206                     const ScriptValue& key_value,
207                     ExceptionState&);
208 
209   int64_t FindIndexId(const String& name) const;
210 
211   // The IDBObjectStoreMetadata is shared with the object store map in the
212   // database's metadata.
213   scoped_refptr<IDBObjectStoreMetadata> metadata_;
214   Member<IDBTransaction> transaction_;
215   bool deleted_ = false;
216 
217   // Caches the IDBIndex instances returned by the index() method.
218   //
219   // The spec requires that an object store's index() returns the same
220   // IDBIndex instance for a specific index, so this cache is necessary
221   // for correctness.
222   //
223   // index() throws for completed/aborted transactions, so this is not used
224   // after a transaction is finished, and can be cleared.
225   IDBIndexMap index_map_;
226 
227 #if DCHECK_IS_ON()
228   bool clear_index_cache_called_ = false;
229 #endif  // DCHECK_IS_ON()
230 };
231 
232 }  // namespace blink
233 
234 #endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_OBJECT_STORE_H_
235