NS_IMETHODIMP IDBCursor::Continue(const jsval &aKey, JSContext* aCx, PRUint8 aOptionalArgCount, PRBool* _retval) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); if (!mObjectStore->TransactionIsOpen()) { return NS_ERROR_UNEXPECTED; } if (mContinueCalled) { return NS_ERROR_NOT_AVAILABLE; } Key key; nsresult rv = IDBObjectStore::GetKeyFromJSVal(aKey, key); NS_ENSURE_SUCCESS(rv, rv); if (key.IsNull()) { if (aOptionalArgCount) { return NS_ERROR_INVALID_ARG; } else { key = Key::UNSETKEY; } } TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate(); NS_ENSURE_TRUE(pool, NS_ERROR_FAILURE); nsRefPtr<ContinueRunnable> runnable(new ContinueRunnable(this, key)); rv = pool->Dispatch(mTransaction, runnable, false, nsnull); NS_ENSURE_SUCCESS(rv, rv); mTransaction->OnNewRequest(); mContinueCalled = true; *_retval = PR_TRUE; return NS_OK; }
NS_IMETHODIMP ContinueRunnable::Run() { nsresult rv; if (!NS_IsMainThread()) { rv = NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } // Remove cached stuff from last time. mCursor->mCachedKey = nsnull; mCursor->mCachedValue = JSVAL_VOID; mCursor->mHaveCachedValue = false; mCursor->mContinueCalled = false; if (mCursor->mType == IDBCursor::INDEX) { mCursor->mKeyData.RemoveElementAt(mCursor->mDataIndex); } else { mCursor->mData.RemoveElementAt(mCursor->mDataIndex); } if (mCursor->mDataIndex) { mCursor->mDataIndex--; } nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance(NS_VARIANT_CONTRACTID); if (!variant) { NS_ERROR("Couldn't create variant!"); return NS_ERROR_FAILURE; } PRBool empty = mCursor->mType == IDBCursor::INDEX ? mCursor->mKeyData.IsEmpty() : mCursor->mData.IsEmpty(); if (empty) { rv = variant->SetAsEmpty(); NS_ENSURE_SUCCESS(rv, rv); } else { if (!mKey.IsUnset()) { NS_ASSERTION(!mKey.IsNull(), "Huh?!"); NS_WARNING("Using a slow O(n) search for continue(key), do something " "smarter!"); // Skip ahead to our next key match. PRInt32 index = PRInt32(mCursor->mDataIndex); if (mCursor->mType == IDBCursor::INDEX) { while (index >= 0) { const Key& key = mCursor->mKeyData[index].key; if (mKey == key) { break; } if (key < mKey) { index--; continue; } index = -1; break; } if (index >= 0) { mCursor->mDataIndex = PRUint32(index); mCursor->mKeyData.RemoveElementsAt(index + 1, mCursor->mKeyData.Length() - index - 1); } } else { while (index >= 0) { const Key& key = mCursor->mData[index].key; if (mKey == key) { break; } if (key < mKey) { index--; continue; } index = -1; break; } if (index >= 0) { mCursor->mDataIndex = PRUint32(index); mCursor->mData.RemoveElementsAt(index + 1, mCursor->mData.Length() - index - 1); } } } rv = variant->SetAsISupports(static_cast<IDBRequest::Generator*>(mCursor)); NS_ENSURE_SUCCESS(rv, rv); } rv = variant->SetWritable(PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIDOMEvent> event = IDBSuccessEvent::Create(mCursor->mRequest, variant, mCursor->mTransaction); if (!event) { NS_ERROR("Failed to create event!"); return NS_ERROR_FAILURE; } PRBool dummy; mCursor->mRequest->DispatchEvent(event, &dummy); mCursor->mTransaction->OnRequestFinished(); mCursor = nsnull; return NS_OK; }
NS_IMETHODIMP IDBCursor::Update(const jsval &aValue, JSContext* aCx, nsIIDBRequest** _retval) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); if (mType != OBJECTSTORE) { NS_NOTYETIMPLEMENTED("Implement me!"); return NS_ERROR_NOT_IMPLEMENTED; } if (!mObjectStore->TransactionIsOpen()) { return NS_ERROR_UNEXPECTED; } if (!mObjectStore->IsWriteAllowed()) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } const Key& key = mData[mDataIndex].key; NS_ASSERTION(!key.IsUnset() && !key.IsNull(), "Bad key!"); JSAutoRequest ar(aCx); js::AutoValueRooter clone(aCx); nsresult rv = nsContentUtils::CreateStructuredClone(aCx, aValue, clone.jsval_addr()); if (NS_FAILED(rv)) { return rv; } if (!mObjectStore->KeyPath().IsEmpty()) { // Make sure the object given has the correct keyPath value set on it or // we will add it. const nsString& keyPath = mObjectStore->KeyPath(); const jschar* keyPathChars = reinterpret_cast<const jschar*>(keyPath.get()); const size_t keyPathLen = keyPath.Length(); js::AutoValueRooter prop(aCx); JSBool ok = JS_GetUCProperty(aCx, JSVAL_TO_OBJECT(clone.jsval_value()), keyPathChars, keyPathLen, prop.jsval_addr()); NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); if (JSVAL_IS_VOID(prop.jsval_value())) { rv = IDBObjectStore::GetJSValFromKey(key, aCx, prop.jsval_addr()); NS_ENSURE_SUCCESS(rv, rv); ok = JS_DefineUCProperty(aCx, JSVAL_TO_OBJECT(clone.jsval_value()), keyPathChars, keyPathLen, prop.jsval_value(), nsnull, nsnull, JSPROP_ENUMERATE); NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); } else { Key newKey; rv = IDBObjectStore::GetKeyFromJSVal(prop.jsval_value(), newKey); NS_ENSURE_SUCCESS(rv, rv); if (newKey.IsUnset() || newKey.IsNull() || newKey != key) { return NS_ERROR_INVALID_ARG; } } } nsTArray<IndexUpdateInfo> indexUpdateInfo; rv = IDBObjectStore::GetIndexUpdateInfo(mObjectStore->GetObjectStoreInfo(), aCx, clone.jsval_value(), indexUpdateInfo); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIJSON> json(new nsJSON()); nsString jsonValue; rv = json->EncodeFromJSVal(clone.jsval_addr(), aCx, jsonValue); NS_ENSURE_SUCCESS(rv, rv); nsRefPtr<IDBRequest> request = GenerateWriteRequest(mTransaction->ScriptContext(), mTransaction->Owner()); NS_ENSURE_TRUE(request, NS_ERROR_FAILURE); nsRefPtr<UpdateHelper> helper = new UpdateHelper(mTransaction, request, mObjectStore->Id(), jsonValue, key, mObjectStore->IsAutoIncrement(), indexUpdateInfo); rv = helper->DispatchToTransactionPool(); NS_ENSURE_SUCCESS(rv, rv); request.forget(_retval); return NS_OK; }