IDBCursor.h (9764B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_dom_idbcursor_h__ 8 #define mozilla_dom_idbcursor_h__ 9 10 #include "IDBCursorType.h" 11 #include "IndexedDatabase.h" 12 #include "js/RootingAPI.h" 13 #include "mozilla/InitializedOnce.h" 14 #include "mozilla/dom/IDBCursorBinding.h" 15 #include "mozilla/dom/IDBTransaction.h" 16 #include "mozilla/dom/indexedDB/Key.h" 17 #include "mozilla/dom/quota/CheckedUnsafePtr.h" 18 #include "nsCycleCollectionParticipant.h" 19 #include "nsWrapperCache.h" 20 21 class nsIGlobalObject; 22 23 namespace mozilla { 24 25 class ErrorResult; 26 27 namespace dom { 28 29 class IDBIndex; 30 class IDBObjectStore; 31 class IDBRequest; 32 class OwningIDBObjectStoreOrIDBIndex; 33 34 class IDBObjectStoreCursor; 35 class IDBObjectStoreKeyCursor; 36 class IDBIndexCursor; 37 class IDBIndexKeyCursor; 38 39 namespace indexedDB { 40 class BackgroundCursorChildBase; 41 template <IDBCursorType CursorType> 42 class BackgroundCursorChild; 43 } // namespace indexedDB 44 45 class IDBCursor : public nsISupports, public nsWrapperCache { 46 public: 47 using Key = indexedDB::Key; 48 using StructuredCloneReadInfoChild = indexedDB::StructuredCloneReadInfoChild; 49 50 using Direction = IDBCursorDirection; 51 using Type = IDBCursorType; 52 53 protected: 54 InitializedOnce<const NotNull<indexedDB::BackgroundCursorChildBase*>> 55 mBackgroundActor; 56 57 // TODO: mRequest could be made const if Bug 1575173 is resolved. It is 58 // initialized in the constructor and never modified/cleared. 59 RefPtr<IDBRequest> mRequest; 60 61 // Sub-classes' mSource will hold this alive. 62 CheckedUnsafePtr<IDBTransaction> mTransaction; 63 64 protected: 65 // These are cycle-collected! 66 JS::Heap<JS::Value> mCachedKey; 67 JS::Heap<JS::Value> mCachedPrimaryKey; 68 JS::Heap<JS::Value> mCachedValue; 69 70 const Direction mDirection; 71 72 bool mHaveCachedKey : 1; 73 bool mHaveCachedPrimaryKey : 1; 74 bool mHaveCachedValue : 1; 75 bool mRooted : 1; 76 bool mContinueCalled : 1; 77 bool mHaveValue : 1; 78 79 public: 80 [[nodiscard]] static RefPtr<IDBObjectStoreCursor> Create( 81 indexedDB::BackgroundCursorChild<Type::ObjectStore>* aBackgroundActor, 82 Key aKey, StructuredCloneReadInfoChild&& aCloneInfo); 83 84 [[nodiscard]] static RefPtr<IDBObjectStoreKeyCursor> Create( 85 indexedDB::BackgroundCursorChild<Type::ObjectStoreKey>* aBackgroundActor, 86 Key aKey); 87 88 [[nodiscard]] static RefPtr<IDBIndexCursor> Create( 89 indexedDB::BackgroundCursorChild<Type::Index>* aBackgroundActor, Key aKey, 90 Key aSortKey, Key aPrimaryKey, StructuredCloneReadInfoChild&& aCloneInfo); 91 92 [[nodiscard]] static RefPtr<IDBIndexKeyCursor> Create( 93 indexedDB::BackgroundCursorChild<Type::IndexKey>* aBackgroundActor, 94 Key aKey, Key aSortKey, Key aPrimaryKey); 95 96 void AssertIsOnOwningThread() const 97 #ifdef DEBUG 98 ; 99 #else 100 { 101 } 102 #endif 103 104 nsIGlobalObject* GetParentObject() const; 105 106 // XXX: The virtual methods that are used by the DOM binding could be removed 107 // on the base class, if we provided a non-polymorphic wrapper instead, which 108 // uses a custom dispatch to the actual implementation type. Don't know if 109 // this is worth it. 110 111 virtual void GetSource(OwningIDBObjectStoreOrIDBIndex& aSource) const = 0; 112 113 IDBCursorDirection GetDirection() const; 114 115 RefPtr<IDBRequest> Request() const; 116 117 virtual void GetKey(JSContext* aCx, JS::MutableHandle<JS::Value> aResult, 118 ErrorResult& aRv) = 0; 119 120 virtual void GetPrimaryKey(JSContext* aCx, 121 JS::MutableHandle<JS::Value> aResult, 122 ErrorResult& aRv) = 0; 123 124 // XXX: We could move this to a sub-class, since this is only present on 125 // IDBCursorWithValue. 126 virtual void GetValue(JSContext* aCx, JS::MutableHandle<JS::Value> aResult, 127 ErrorResult& aRv) = 0; 128 129 virtual void Continue(JSContext* aCx, JS::Handle<JS::Value> aKey, 130 ErrorResult& aRv) = 0; 131 132 virtual void ContinuePrimaryKey(JSContext* aCx, JS::Handle<JS::Value> aKey, 133 JS::Handle<JS::Value> aPrimaryKey, 134 ErrorResult& aRv) = 0; 135 136 virtual void Advance(uint32_t aCount, ErrorResult& aRv) = 0; 137 138 [[nodiscard]] virtual RefPtr<IDBRequest> Update(JSContext* aCx, 139 JS::Handle<JS::Value> aValue, 140 ErrorResult& aRv) = 0; 141 142 [[nodiscard]] virtual RefPtr<IDBRequest> Delete(JSContext* aCx, 143 ErrorResult& aRv) = 0; 144 145 void ClearBackgroundActor() { 146 AssertIsOnOwningThread(); 147 148 mBackgroundActor.destroy(); 149 } 150 151 virtual void InvalidateCachedResponses() = 0; 152 153 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 154 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IDBCursor) 155 156 protected: 157 IDBCursor(indexedDB::BackgroundCursorChildBase* aBackgroundActor); 158 159 // TODO: Check if we can remove virtual by changing cycle collection. 160 virtual ~IDBCursor() = default; 161 162 void ResetBase(); 163 }; 164 165 template <IDBCursor::Type CursorType> 166 class IDBTypedCursor : public IDBCursor { 167 public: 168 template <typename... DataArgs> 169 explicit IDBTypedCursor( 170 indexedDB::BackgroundCursorChild<CursorType>* aBackgroundActor, 171 DataArgs&&... aDataArgs); 172 173 static constexpr Type GetType() { return CursorType; } 174 175 // Checks if this is a locale aware cursor (ie. the index's sortKey is unset) 176 bool IsLocaleAware() const; 177 178 void GetSource(OwningIDBObjectStoreOrIDBIndex& aSource) const final; 179 180 void GetKey(JSContext* aCx, JS::MutableHandle<JS::Value> aResult, 181 ErrorResult& aRv) final; 182 183 void GetPrimaryKey(JSContext* aCx, JS::MutableHandle<JS::Value> aResult, 184 ErrorResult& aRv) final; 185 186 void GetValue(JSContext* aCx, JS::MutableHandle<JS::Value> aResult, 187 ErrorResult& aRv) final; 188 189 void Continue(JSContext* aCx, JS::Handle<JS::Value> aKey, 190 ErrorResult& aRv) final; 191 192 void ContinuePrimaryKey(JSContext* aCx, JS::Handle<JS::Value> aKey, 193 JS::Handle<JS::Value> aPrimaryKey, 194 ErrorResult& aRv) final; 195 196 void Advance(uint32_t aCount, ErrorResult& aRv) final; 197 198 [[nodiscard]] RefPtr<IDBRequest> Update(JSContext* aCx, 199 JS::Handle<JS::Value> aValue, 200 ErrorResult& aRv) final; 201 202 [[nodiscard]] RefPtr<IDBRequest> Delete(JSContext* aCx, 203 ErrorResult& aRv) final; 204 205 // nsWrapperCache 206 JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) final; 207 208 void InvalidateCachedResponses() final; 209 210 void Reset(); 211 212 void Reset(CursorData<CursorType>&& aCursorData); 213 214 private: 215 static constexpr bool IsObjectStoreCursor = 216 CursorTypeTraits<CursorType>::IsObjectStoreCursor; 217 static constexpr bool IsKeyOnlyCursor = 218 CursorTypeTraits<CursorType>::IsKeyOnlyCursor; 219 220 CursorSourceType<CursorType>& GetSourceRef() const { 221 MOZ_ASSERT(mSource); 222 return *mSource; 223 } 224 225 IDBObjectStore& GetSourceObjectStoreRef() const { 226 if constexpr (IsObjectStoreCursor) { 227 return GetSourceRef(); 228 } else { 229 MOZ_ASSERT(!GetSourceRef().IsDeleted()); 230 231 auto res = GetSourceRef().ObjectStore(); 232 MOZ_ASSERT(res); 233 return *res; 234 } 235 } 236 237 indexedDB::BackgroundCursorChild<CursorType>& GetTypedBackgroundActorRef() 238 const { 239 // We can safely downcast to BackgroundCursorChild<CursorType>*, since we 240 // initialized that in the constructor from that type. We just want to avoid 241 // having a second typed field. 242 return *static_cast<indexedDB::BackgroundCursorChild<CursorType>*>( 243 mBackgroundActor->get()); 244 } 245 246 bool IsSourceDeleted() const; 247 248 protected: 249 virtual ~IDBTypedCursor() override; 250 251 void DropJSObjects(); 252 253 CursorData<CursorType> mData; 254 255 // TODO: mSource could be made const if Bug 1575173 is resolved. It is 256 // initialized in the constructor and never modified/cleared. 257 RefPtr<CursorSourceType<CursorType>> mSource; 258 }; 259 260 // The subclasses defined by this macro are only needed to be able to use the 261 // cycle collector macros, which do not support templates. If spelled out, the 262 // cycle collection could be implemented directly on IDBTypedCursor, and these 263 // classes were not needed. 264 #define CONCRETE_IDBCURSOR_SUBCLASS(_subclassName, _cursorType) \ 265 class _subclassName final : public IDBTypedCursor<_cursorType> { \ 266 public: \ 267 NS_DECL_ISUPPORTS_INHERITED \ 268 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(_subclassName, IDBCursor) \ 269 \ 270 using IDBTypedCursor<_cursorType>::IDBTypedCursor; \ 271 \ 272 private: \ 273 ~_subclassName() final = default; \ 274 }; 275 276 CONCRETE_IDBCURSOR_SUBCLASS(IDBObjectStoreCursor, IDBCursor::Type::ObjectStore) 277 CONCRETE_IDBCURSOR_SUBCLASS(IDBObjectStoreKeyCursor, 278 IDBCursor::Type::ObjectStoreKey) 279 CONCRETE_IDBCURSOR_SUBCLASS(IDBIndexCursor, IDBCursor::Type::Index) 280 CONCRETE_IDBCURSOR_SUBCLASS(IDBIndexKeyCursor, IDBCursor::Type::IndexKey) 281 282 template <IDBCursor::Type CursorType> 283 using IDBCursorImpl = typename CursorTypeTraits<CursorType>::Type; 284 285 } // namespace dom 286 } // namespace mozilla 287 288 #endif // mozilla_dom_idbcursor_h__