Bumping manifests a=b2g-bump
[gecko.git] / dom / datastore / DataStoreDB.cpp
blob1f998d190dd4d3680454cb200169537c1fc27617
1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
2 /* vim: set ts=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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "DataStoreDB.h"
9 #include "DataStoreCallbacks.h"
10 #include "jsapi.h"
11 #include "mozilla/dom/IDBDatabaseBinding.h"
12 #include "mozilla/dom/IDBFactoryBinding.h"
13 #include "mozilla/dom/IDBObjectStoreBinding.h"
14 #include "mozilla/dom/indexedDB/IDBDatabase.h"
15 #include "mozilla/dom/indexedDB/IDBEvents.h"
16 #include "mozilla/dom/indexedDB/IDBFactory.h"
17 #include "mozilla/dom/indexedDB/IDBIndex.h"
18 #include "mozilla/dom/indexedDB/IDBObjectStore.h"
19 #include "mozilla/dom/indexedDB/IDBRequest.h"
20 #include "mozilla/dom/indexedDB/IDBTransaction.h"
21 #include "nsComponentManagerUtils.h"
22 #include "nsContentUtils.h"
23 #include "nsIDOMEvent.h"
24 #include "nsIPrincipal.h"
25 #include "nsIXPConnect.h"
27 #define DATASTOREDB_VERSION 1
28 #define DATASTOREDB_NAME "DataStoreDB"
29 #define DATASTOREDB_REVISION_INDEX "revisionIndex"
31 using namespace mozilla::dom::indexedDB;
33 namespace mozilla {
34 namespace dom {
36 class VersionChangeListener MOZ_FINAL : public nsIDOMEventListener
38 public:
39 NS_DECL_ISUPPORTS
41 explicit VersionChangeListener(IDBDatabase* aDatabase)
42 : mDatabase(aDatabase)
45 // nsIDOMEventListener
46 NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) MOZ_OVERRIDE
48 nsString type;
49 nsresult rv = aEvent->GetType(type);
50 if (NS_WARN_IF(NS_FAILED(rv))) {
51 return rv;
54 if (!type.EqualsASCII("versionchange")) {
55 MOZ_ASSERT_UNREACHABLE("Expected a versionchange event");
56 return NS_ERROR_FAILURE;
59 rv = mDatabase->RemoveEventListener(NS_LITERAL_STRING("versionchange"),
60 this, false);
61 if (NS_WARN_IF(NS_FAILED(rv))) {
62 return rv;
65 #ifdef DEBUG
66 nsCOMPtr<IDBVersionChangeEvent> event = do_QueryInterface(aEvent);
67 MOZ_ASSERT(event);
69 Nullable<uint64_t> version = event->GetNewVersion();
70 MOZ_ASSERT(version.IsNull());
71 #endif
73 mDatabase->Close();
75 return NS_OK;
78 private:
79 IDBDatabase* mDatabase;
81 ~VersionChangeListener() {}
84 NS_IMPL_ISUPPORTS(VersionChangeListener, nsIDOMEventListener)
86 NS_IMPL_ISUPPORTS(DataStoreDB, nsIDOMEventListener)
88 DataStoreDB::DataStoreDB(const nsAString& aManifestURL, const nsAString& aName)
89 : mState(Inactive)
90 , mCreatedSchema(false)
92 mDatabaseName.Assign(aName);
93 mDatabaseName.Append('|');
94 mDatabaseName.Append(aManifestURL);
97 DataStoreDB::~DataStoreDB()
101 nsresult
102 DataStoreDB::CreateFactoryIfNeeded()
104 if (!mFactory) {
105 nsresult rv;
106 nsCOMPtr<nsIPrincipal> principal =
107 do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
108 if (NS_WARN_IF(NS_FAILED(rv))) {
109 return rv;
112 nsIXPConnect* xpc = nsContentUtils::XPConnect();
113 MOZ_ASSERT(xpc);
115 AutoSafeJSContext cx;
117 nsCOMPtr<nsIXPConnectJSObjectHolder> globalHolder;
118 rv = xpc->CreateSandbox(cx, principal, getter_AddRefs(globalHolder));
119 if (NS_WARN_IF(NS_FAILED(rv))) {
120 return rv;
123 JS::Rooted<JSObject*> global(cx, globalHolder->GetJSObject());
124 if (NS_WARN_IF(NS_FAILED(rv))) {
125 return NS_ERROR_UNEXPECTED;
128 // The CreateSandbox call returns a proxy to the actual sandbox object. We
129 // don't need a proxy here.
130 global = js::UncheckedUnwrap(global);
132 JSAutoCompartment ac(cx, global);
134 rv = IDBFactory::CreateForDatastore(cx, global, getter_AddRefs(mFactory));
135 if (NS_WARN_IF(NS_FAILED(rv))) {
136 return rv;
140 return NS_OK;
143 nsresult
144 DataStoreDB::Open(IDBTransactionMode aMode, const Sequence<nsString>& aDbs,
145 DataStoreDBCallback* aCallback)
147 MOZ_ASSERT(mState == Inactive);
149 nsresult rv = CreateFactoryIfNeeded();
150 if (NS_WARN_IF(NS_FAILED(rv))) {
151 return rv;
154 ErrorResult error;
155 mRequest = mFactory->Open(mDatabaseName, DATASTOREDB_VERSION, error);
156 if (NS_WARN_IF(error.Failed())) {
157 return error.ErrorCode();
160 rv = AddEventListeners();
161 if (NS_WARN_IF(NS_FAILED(rv))) {
162 return rv;
165 mState = Active;
166 mTransactionMode = aMode;
167 mObjectStores = aDbs;
168 mCallback = aCallback;
169 return NS_OK;
172 NS_IMETHODIMP
173 DataStoreDB::HandleEvent(nsIDOMEvent* aEvent)
175 nsString type;
176 nsresult rv = aEvent->GetType(type);
177 if (NS_WARN_IF(NS_FAILED(rv))) {
178 return rv;
181 if (type.EqualsASCII("success")) {
182 RemoveEventListeners();
183 mState = Inactive;
185 rv = DatabaseOpened();
186 if (NS_WARN_IF(NS_FAILED(rv))) {
187 mCallback->Run(this, DataStoreDBCallback::Error);
188 } else {
189 mCallback->Run(this, mCreatedSchema
190 ? DataStoreDBCallback::CreatedSchema :
191 DataStoreDBCallback::Success);
194 mRequest = nullptr;
195 return NS_OK;
198 if (type.EqualsASCII("upgradeneeded")) {
199 return UpgradeSchema(aEvent);
202 if (type.EqualsASCII("error") || type.EqualsASCII("blocked")) {
203 RemoveEventListeners();
204 mState = Inactive;
205 mCallback->Run(this, DataStoreDBCallback::Error);
206 mRequest = nullptr;
207 return NS_OK;
210 MOZ_CRASH("This should not happen");
213 nsresult
214 DataStoreDB::UpgradeSchema(nsIDOMEvent* aEvent)
216 MOZ_ASSERT(NS_IsMainThread());
218 // This DB has been just created and we have to inform the callback about
219 // this.
220 mCreatedSchema = true;
222 #ifdef DEBUG
223 nsCOMPtr<IDBVersionChangeEvent> event = do_QueryInterface(aEvent);
224 MOZ_ASSERT(event);
226 Nullable<uint64_t> version = event->GetNewVersion();
227 MOZ_ASSERT(!version.IsNull());
228 MOZ_ASSERT(version.Value() == DATASTOREDB_VERSION);
229 #endif
231 AutoSafeJSContext cx;
233 ErrorResult error;
234 JS::Rooted<JS::Value> result(cx);
235 mRequest->GetResult(&result, error);
236 if (NS_WARN_IF(error.Failed())) {
237 return error.ErrorCode();
240 MOZ_ASSERT(result.isObject());
242 IDBDatabase* database = nullptr;
243 nsresult rv = UNWRAP_OBJECT(IDBDatabase, &result.toObject(), database);
244 if (NS_FAILED(rv)) {
245 NS_WARNING("Didn't get the object we expected!");
246 return rv;
250 IDBObjectStoreParameters params;
251 params.Init(NS_LITERAL_STRING("{ \"autoIncrement\": true }"));
252 nsRefPtr<IDBObjectStore> store =
253 database->CreateObjectStore(NS_LITERAL_STRING(DATASTOREDB_NAME),
254 params, error);
255 if (NS_WARN_IF(error.Failed())) {
256 return error.ErrorCode();
260 nsRefPtr<IDBObjectStore> store;
263 IDBObjectStoreParameters params;
264 params.Init(NS_LITERAL_STRING("{ \"autoIncrement\": true, \"keyPath\": \"internalRevisionId\" }"));
266 store =
267 database->CreateObjectStore(NS_LITERAL_STRING(DATASTOREDB_REVISION),
268 params, error);
269 if (NS_WARN_IF(error.Failed())) {
270 return error.ErrorCode();
275 IDBIndexParameters params;
276 params.Init(NS_LITERAL_STRING("{ \"unique\": true }"));
277 nsRefPtr<IDBIndex> index =
278 store->CreateIndex(NS_LITERAL_STRING(DATASTOREDB_REVISION_INDEX),
279 NS_LITERAL_STRING("revisionId"), params, error);
280 if (NS_WARN_IF(error.Failed())) {
281 return error.ErrorCode();
285 return NS_OK;
288 nsresult
289 DataStoreDB::DatabaseOpened()
291 MOZ_ASSERT(NS_IsMainThread());
293 AutoSafeJSContext cx;
295 ErrorResult error;
296 JS::Rooted<JS::Value> result(cx);
297 mRequest->GetResult(&result, error);
298 if (NS_WARN_IF(error.Failed())) {
299 return error.ErrorCode();
302 MOZ_ASSERT(result.isObject());
304 nsresult rv = UNWRAP_OBJECT(IDBDatabase, &result.toObject(), mDatabase);
305 if (NS_FAILED(rv)) {
306 NS_WARNING("Didn't get the object we expected!");
307 return rv;
310 nsRefPtr<VersionChangeListener> listener =
311 new VersionChangeListener(mDatabase);
312 rv = mDatabase->EventTarget::AddEventListener(
313 NS_LITERAL_STRING("versionchange"), listener, false);
314 if (NS_WARN_IF(NS_FAILED(rv))) {
315 return rv;
318 nsRefPtr<IDBTransaction> txn = mDatabase->Transaction(mObjectStores,
319 mTransactionMode,
320 error);
321 if (NS_WARN_IF(error.Failed())) {
322 return error.ErrorCode();
325 mTransaction = txn.forget();
326 return NS_OK;
329 nsresult
330 DataStoreDB::Delete()
332 MOZ_ASSERT(mState == Inactive);
334 nsresult rv = CreateFactoryIfNeeded();
335 if (NS_WARN_IF(NS_FAILED(rv))) {
336 return rv;
339 mTransaction = nullptr;
341 if (mDatabase) {
342 mDatabase->Close();
343 mDatabase = nullptr;
346 ErrorResult error;
347 nsRefPtr<IDBOpenDBRequest> request =
348 mFactory->DeleteDatabase(mDatabaseName, IDBOpenDBOptions(), error);
349 if (NS_WARN_IF(error.Failed())) {
350 return error.ErrorCode();
353 return NS_OK;
356 indexedDB::IDBTransaction*
357 DataStoreDB::Transaction() const
359 MOZ_ASSERT(mTransaction);
360 MOZ_ASSERT(mTransaction->IsOpen());
361 return mTransaction;
364 nsresult
365 DataStoreDB::AddEventListeners()
367 nsresult rv;
368 rv = mRequest->EventTarget::AddEventListener(NS_LITERAL_STRING("success"),
369 this, false);
370 if (NS_WARN_IF(NS_FAILED(rv))) {
371 return rv;
374 rv = mRequest->EventTarget::AddEventListener(NS_LITERAL_STRING("upgradeneeded"),
375 this, false);
376 if (NS_WARN_IF(NS_FAILED(rv))) {
377 return rv;
380 rv = mRequest->EventTarget::AddEventListener(NS_LITERAL_STRING("error"),
381 this, false);
382 if (NS_WARN_IF(NS_FAILED(rv))) {
383 return rv;
386 rv = mRequest->EventTarget::AddEventListener(NS_LITERAL_STRING("blocked"),
387 this, false);
388 if (NS_WARN_IF(NS_FAILED(rv))) {
389 return rv;
392 return NS_OK;
395 nsresult
396 DataStoreDB::RemoveEventListeners()
398 nsresult rv;
399 rv = mRequest->RemoveEventListener(NS_LITERAL_STRING("success"),
400 this, false);
401 if (NS_WARN_IF(NS_FAILED(rv))) {
402 return rv;
405 rv = mRequest->RemoveEventListener(NS_LITERAL_STRING("upgradeneeded"),
406 this, false);
407 if (NS_WARN_IF(NS_FAILED(rv))) {
408 return rv;
411 rv = mRequest->RemoveEventListener(NS_LITERAL_STRING("error"),
412 this, false);
413 if (NS_WARN_IF(NS_FAILED(rv))) {
414 return rv;
417 rv = mRequest->RemoveEventListener(NS_LITERAL_STRING("blocked"),
418 this, false);
419 if (NS_WARN_IF(NS_FAILED(rv))) {
420 return rv;
423 return NS_OK;
426 } // namespace dom
427 } // namespace mozilla