mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 920800 - 'Add openKeyCursor() to IDBObjectStore'. r=janv.
--HG-- extra : transplant_source : H%ED%F8%E08%98/%26%0F%82%9C%0E%B0l%92%A6%C0%A1%A3%B4
This commit is contained in:
parent
d457c68e85
commit
983128e384
@ -36,8 +36,7 @@ using mozilla::dom::OwningIDBObjectStoreOrIDBIndex;
|
||||
using mozilla::ErrorResult;
|
||||
|
||||
static_assert(sizeof(size_t) >= sizeof(IDBCursor::Direction),
|
||||
"Relying on conversion between size_t and "
|
||||
"IDBCursor::Direction");
|
||||
"Relying on conversion between size_t and IDBCursor::Direction");
|
||||
|
||||
namespace {
|
||||
|
||||
@ -62,6 +61,9 @@ public:
|
||||
UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~CursorHelper()
|
||||
{ }
|
||||
|
||||
nsRefPtr<IDBCursor> mCursor;
|
||||
|
||||
private:
|
||||
@ -79,19 +81,17 @@ public:
|
||||
int32_t aCount)
|
||||
: CursorHelper(aCursor), mCount(aCount)
|
||||
{
|
||||
NS_ASSERTION(aCount > 0, "Must have a count!");
|
||||
}
|
||||
|
||||
~ContinueHelper()
|
||||
{
|
||||
IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aCursor);
|
||||
MOZ_ASSERT(aCount > 0);
|
||||
}
|
||||
|
||||
virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult GetSuccessResult(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE;
|
||||
JS::MutableHandle<JS::Value> aVal)
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
|
||||
|
||||
@ -106,6 +106,11 @@ public:
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
virtual ~ContinueHelper()
|
||||
{
|
||||
IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo);
|
||||
}
|
||||
|
||||
virtual nsresult
|
||||
BindArgumentsToStatement(mozIStorageStatement* aStatement) = 0;
|
||||
|
||||
@ -124,10 +129,10 @@ protected:
|
||||
|
||||
if (mKey.IsUnset()) {
|
||||
mCursor->mHaveValue = false;
|
||||
}
|
||||
else {
|
||||
NS_ASSERTION(mCursor->mType == IDBCursor::OBJECTSTORE ||
|
||||
!mObjectKey.IsUnset(), "Bad key!");
|
||||
} else {
|
||||
MOZ_ASSERT(mCursor->mType == IDBCursor::OBJECTSTORE ||
|
||||
mCursor->mType == IDBCursor::OBJECTSTOREKEY ||
|
||||
!mObjectKey.IsUnset());
|
||||
|
||||
// Set new values.
|
||||
mCursor->mKey = mKey;
|
||||
@ -153,11 +158,31 @@ public:
|
||||
: ContinueHelper(aCursor, aCount)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
virtual ~ContinueObjectStoreHelper()
|
||||
{ }
|
||||
|
||||
private:
|
||||
nsresult BindArgumentsToStatement(mozIStorageStatement* aStatement);
|
||||
nsresult GatherResultsFromStatement(mozIStorageStatement* aStatement);
|
||||
};
|
||||
|
||||
class ContinueObjectStoreKeyHelper : public ContinueObjectStoreHelper
|
||||
{
|
||||
public:
|
||||
ContinueObjectStoreKeyHelper(IDBCursor* aCursor,
|
||||
uint32_t aCount)
|
||||
: ContinueObjectStoreHelper(aCursor, aCount)
|
||||
{ }
|
||||
|
||||
private:
|
||||
virtual ~ContinueObjectStoreKeyHelper()
|
||||
{ }
|
||||
|
||||
virtual nsresult
|
||||
GatherResultsFromStatement(mozIStorageStatement* aStatement) MOZ_OVERRIDE;
|
||||
};
|
||||
|
||||
class ContinueIndexHelper : public ContinueHelper
|
||||
{
|
||||
public:
|
||||
@ -166,6 +191,10 @@ public:
|
||||
: ContinueHelper(aCursor, aCount)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
virtual ~ContinueIndexHelper()
|
||||
{ }
|
||||
|
||||
private:
|
||||
nsresult BindArgumentsToStatement(mozIStorageStatement* aStatement);
|
||||
nsresult GatherResultsFromStatement(mozIStorageStatement* aStatement);
|
||||
@ -180,6 +209,9 @@ public:
|
||||
{ }
|
||||
|
||||
private:
|
||||
virtual ~ContinueIndexObjectHelper()
|
||||
{ }
|
||||
|
||||
nsresult GatherResultsFromStatement(mozIStorageStatement* aStatement);
|
||||
};
|
||||
|
||||
@ -213,6 +245,32 @@ IDBCursor::Create(IDBRequest* aRequest,
|
||||
return cursor.forget();
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<IDBCursor>
|
||||
IDBCursor::Create(IDBRequest* aRequest,
|
||||
IDBTransaction* aTransaction,
|
||||
IDBObjectStore* aObjectStore,
|
||||
Direction aDirection,
|
||||
const Key& aRangeKey,
|
||||
const nsACString& aContinueQuery,
|
||||
const nsACString& aContinueToQuery,
|
||||
const Key& aKey)
|
||||
{
|
||||
MOZ_ASSERT(aObjectStore);
|
||||
MOZ_ASSERT(!aKey.IsUnset());
|
||||
|
||||
nsRefPtr<IDBCursor> cursor =
|
||||
IDBCursor::CreateCommon(aRequest, aTransaction, aObjectStore, aDirection,
|
||||
aRangeKey, aContinueQuery, aContinueToQuery);
|
||||
NS_ASSERTION(cursor, "This shouldn't fail!");
|
||||
|
||||
cursor->mObjectStore = aObjectStore;
|
||||
cursor->mType = OBJECTSTOREKEY;
|
||||
cursor->mKey = aKey;
|
||||
|
||||
return cursor.forget();
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<IDBCursor>
|
||||
IDBCursor::Create(IDBRequest* aRequest,
|
||||
@ -293,7 +351,7 @@ IDBCursor::ConvertDirection(mozilla::dom::IDBCursorDirection aDirection)
|
||||
return PREV_UNIQUE;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Unknown direction!");
|
||||
MOZ_ASSUME_UNREACHABLE("Unknown direction!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -396,8 +454,8 @@ IDBCursor::DropJSObjects()
|
||||
void
|
||||
IDBCursor::ContinueInternal(const Key& aKey, int32_t aCount, ErrorResult& aRv)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(aCount > 0, "Must have a count!");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aCount > 0);
|
||||
|
||||
if (!mTransaction->IsOpen()) {
|
||||
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
|
||||
@ -411,10 +469,7 @@ IDBCursor::ContinueInternal(const Key& aKey, int32_t aCount, ErrorResult& aRv)
|
||||
|
||||
mContinueToKey = aKey;
|
||||
|
||||
#ifdef DEBUG
|
||||
NS_ASSERTION(mRequest->ReadyState() == IDBRequestReadyState::Done,
|
||||
"Should be DONE!");
|
||||
#endif
|
||||
MOZ_ASSERT(mRequest->ReadyState() == IDBRequestReadyState::Done);
|
||||
|
||||
mRequest->Reset();
|
||||
|
||||
@ -424,6 +479,10 @@ IDBCursor::ContinueInternal(const Key& aKey, int32_t aCount, ErrorResult& aRv)
|
||||
helper = new ContinueObjectStoreHelper(this, aCount);
|
||||
break;
|
||||
|
||||
case OBJECTSTOREKEY:
|
||||
helper = new ContinueObjectStoreKeyHelper(this, aCount);
|
||||
break;
|
||||
|
||||
case INDEXKEY:
|
||||
helper = new ContinueIndexHelper(this, aCount);
|
||||
break;
|
||||
@ -433,7 +492,7 @@ IDBCursor::ContinueInternal(const Key& aKey, int32_t aCount, ErrorResult& aRv)
|
||||
break;
|
||||
|
||||
default:
|
||||
NS_NOTREACHED("Unknown cursor type!");
|
||||
MOZ_ASSUME_UNREACHABLE("Unknown cursor type!");
|
||||
}
|
||||
|
||||
nsresult rv = helper->DispatchToTransactionPool();
|
||||
@ -489,15 +548,26 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBCursor)
|
||||
JSObject*
|
||||
IDBCursor::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
|
||||
{
|
||||
return mType != INDEXKEY
|
||||
? IDBCursorWithValueBinding::Wrap(aCx, aScope, this)
|
||||
: IDBCursorBinding::Wrap(aCx, aScope, this);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
switch (mType) {
|
||||
case OBJECTSTORE:
|
||||
case INDEXOBJECT:
|
||||
return IDBCursorWithValueBinding::Wrap(aCx, aScope, this);
|
||||
|
||||
case OBJECTSTOREKEY:
|
||||
case INDEXKEY:
|
||||
return IDBCursorBinding::Wrap(aCx, aScope, this);
|
||||
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("Bad type!");
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::dom::IDBCursorDirection
|
||||
IDBCursor::GetDirection() const
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
switch (mDirection) {
|
||||
case NEXT:
|
||||
@ -512,33 +582,39 @@ IDBCursor::GetDirection() const
|
||||
case PREV_UNIQUE:
|
||||
return mozilla::dom::IDBCursorDirection::Prevunique;
|
||||
|
||||
case DIRECTION_INVALID:
|
||||
default:
|
||||
MOZ_CRASH("Unknown direction!");
|
||||
return mozilla::dom::IDBCursorDirection::Next;
|
||||
MOZ_ASSUME_UNREACHABLE("Bad direction!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
IDBCursor::GetSource(OwningIDBObjectStoreOrIDBIndex& aSource) const
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mType == OBJECTSTORE) {
|
||||
aSource.SetAsIDBObjectStore() = mObjectStore;
|
||||
}
|
||||
else {
|
||||
aSource.SetAsIDBIndex() = mIndex;
|
||||
switch (mType) {
|
||||
case OBJECTSTORE:
|
||||
case OBJECTSTOREKEY:
|
||||
MOZ_ASSERT(mObjectStore);
|
||||
aSource.SetAsIDBObjectStore() = mObjectStore;
|
||||
break;
|
||||
|
||||
case INDEXKEY:
|
||||
case INDEXOBJECT:
|
||||
MOZ_ASSERT(mIndex);
|
||||
aSource.SetAsIDBIndex() = mIndex;
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("Bad type!");
|
||||
}
|
||||
}
|
||||
|
||||
JS::Value
|
||||
IDBCursor::GetKey(JSContext* aCx, ErrorResult& aRv)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
NS_ASSERTION(!mKey.IsUnset() || !mHaveValue, "Bad key!");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mKey.IsUnset() || !mHaveValue);
|
||||
|
||||
if (!mHaveValue) {
|
||||
return JSVAL_VOID;
|
||||
@ -562,7 +638,7 @@ IDBCursor::GetKey(JSContext* aCx, ErrorResult& aRv)
|
||||
JS::Value
|
||||
IDBCursor::GetPrimaryKey(JSContext* aCx, ErrorResult& aRv)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mHaveValue) {
|
||||
return JSVAL_VOID;
|
||||
@ -574,12 +650,9 @@ IDBCursor::GetPrimaryKey(JSContext* aCx, ErrorResult& aRv)
|
||||
mRooted = true;
|
||||
}
|
||||
|
||||
JSAutoRequest ar(aCx);
|
||||
|
||||
NS_ASSERTION(mType == OBJECTSTORE ? !mKey.IsUnset() :
|
||||
!mObjectKey.IsUnset(), "Bad key!");
|
||||
|
||||
const Key& key = mType == OBJECTSTORE ? mKey : mObjectKey;
|
||||
const Key& key =
|
||||
(mType == OBJECTSTORE || mType == OBJECTSTOREKEY) ? mKey : mObjectKey;
|
||||
MOZ_ASSERT(!key.IsUnset());
|
||||
|
||||
aRv = key.ToJSVal(aCx, mCachedPrimaryKey);
|
||||
ENSURE_SUCCESS(aRv, JSVAL_VOID);
|
||||
@ -593,8 +666,8 @@ IDBCursor::GetPrimaryKey(JSContext* aCx, ErrorResult& aRv)
|
||||
JS::Value
|
||||
IDBCursor::GetValue(JSContext* aCx, ErrorResult& aRv)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(mType != INDEXKEY, "GetValue shouldn't exist on index keys");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mType == OBJECTSTORE || mType == INDEXOBJECT);
|
||||
|
||||
if (!mHaveValue) {
|
||||
return JSVAL_VOID;
|
||||
@ -626,7 +699,7 @@ IDBCursor::Continue(JSContext* aCx,
|
||||
const Optional<JS::Handle<JS::Value> >& aKey,
|
||||
ErrorResult &aRv)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
Key key;
|
||||
if (aKey.WasPassed()) {
|
||||
@ -653,7 +726,7 @@ IDBCursor::Continue(JSContext* aCx,
|
||||
break;
|
||||
|
||||
default:
|
||||
NS_NOTREACHED("Unknown direction type!");
|
||||
MOZ_ASSUME_UNREACHABLE("Unknown direction type!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -663,7 +736,7 @@ IDBCursor::Continue(JSContext* aCx,
|
||||
}
|
||||
|
||||
#ifdef IDB_PROFILER_USE_MARKS
|
||||
if (mType == OBJECTSTORE) {
|
||||
if (mType == OBJECTSTORE || mType == OBJECTSTOREKEY) {
|
||||
IDB_PROFILER_MARK("IndexedDB Request %llu: "
|
||||
"database(%s).transaction(%s).objectStore(%s).cursor(%s)."
|
||||
"continue(%s)",
|
||||
@ -695,7 +768,7 @@ already_AddRefed<IDBRequest>
|
||||
IDBCursor::Update(JSContext* aCx, JS::Handle<JS::Value> aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mTransaction->IsOpen()) {
|
||||
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
|
||||
@ -707,18 +780,17 @@ IDBCursor::Update(JSContext* aCx, JS::Handle<JS::Value> aValue,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mHaveValue || mType == INDEXKEY) {
|
||||
if (!mHaveValue || mType == OBJECTSTOREKEY || mType == INDEXKEY) {
|
||||
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NS_ASSERTION(mObjectStore, "This cannot be null!");
|
||||
NS_ASSERTION(!mKey.IsUnset() , "Bad key!");
|
||||
NS_ASSERTION(mType != INDEXOBJECT || !mObjectKey.IsUnset(), "Bad key!");
|
||||
MOZ_ASSERT(mObjectStore);
|
||||
MOZ_ASSERT(!mKey.IsUnset());
|
||||
MOZ_ASSERT(mType == OBJECTSTORE || mType == INDEXOBJECT);
|
||||
MOZ_ASSERT_IF(mType == INDEXOBJECT, !mObjectKey.IsUnset());
|
||||
|
||||
JSAutoRequest ar(aCx);
|
||||
|
||||
Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
|
||||
const Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
|
||||
|
||||
nsRefPtr<IDBRequest> request;
|
||||
if (mObjectStore->HasValidKeyPath()) {
|
||||
@ -796,7 +868,7 @@ IDBCursor::Update(JSContext* aCx, JS::Handle<JS::Value> aValue,
|
||||
already_AddRefed<IDBRequest>
|
||||
IDBCursor::Delete(JSContext* aCx, ErrorResult& aRv)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mTransaction->IsOpen()) {
|
||||
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
|
||||
@ -808,24 +880,23 @@ IDBCursor::Delete(JSContext* aCx, ErrorResult& aRv)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mHaveValue || mType == INDEXKEY) {
|
||||
if (!mHaveValue || mType == OBJECTSTOREKEY || mType == INDEXKEY) {
|
||||
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NS_ASSERTION(mObjectStore, "This cannot be null!");
|
||||
NS_ASSERTION(!mKey.IsUnset() , "Bad key!");
|
||||
MOZ_ASSERT(mObjectStore);
|
||||
MOZ_ASSERT(mType == OBJECTSTORE || mType == INDEXOBJECT);
|
||||
MOZ_ASSERT(!mKey.IsUnset());
|
||||
|
||||
Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
|
||||
const Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
|
||||
|
||||
JS::Rooted<JS::Value> key(aCx);
|
||||
aRv = objectKey.ToJSVal(aCx, &key);
|
||||
ENSURE_SUCCESS(aRv, nullptr);
|
||||
|
||||
nsRefPtr<IDBRequest> request = mObjectStore->Delete(aCx, key, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
ENSURE_SUCCESS(aRv, nullptr);
|
||||
|
||||
#ifdef IDB_PROFILER_USE_MARKS
|
||||
{
|
||||
@ -866,7 +937,7 @@ IDBCursor::Delete(JSContext* aCx, ErrorResult& aRv)
|
||||
void
|
||||
IDBCursor::Advance(uint32_t aCount, ErrorResult &aRv)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (aCount < 1) {
|
||||
aRv.ThrowTypeError(MSG_INVALID_ADVANCE_COUNT);
|
||||
@ -879,7 +950,7 @@ IDBCursor::Advance(uint32_t aCount, ErrorResult &aRv)
|
||||
|
||||
#ifdef IDB_PROFILER_USE_MARKS
|
||||
{
|
||||
if (mType == OBJECTSTORE) {
|
||||
if (mType == OBJECTSTORE || mType == OBJECTSTOREKEY) {
|
||||
IDB_PROFILER_MARK("IndexedDB Request %llu: "
|
||||
"database(%s).transaction(%s).objectStore(%s)."
|
||||
"cursor(%s).advance(%ld)",
|
||||
@ -1135,6 +1206,9 @@ nsresult
|
||||
ContinueObjectStoreHelper::BindArgumentsToStatement(
|
||||
mozIStorageStatement* aStatement)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aStatement);
|
||||
|
||||
// Bind object store id.
|
||||
nsresult rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"),
|
||||
mCursor->mObjectStore->Id());
|
||||
@ -1166,12 +1240,29 @@ nsresult
|
||||
ContinueObjectStoreHelper::GatherResultsFromStatement(
|
||||
mozIStorageStatement* aStatement)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aStatement);
|
||||
|
||||
// Figure out what kind of key we have next.
|
||||
nsresult rv = mKey.SetFromStatement(aStatement, 0);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(aStatement, 1, 2,
|
||||
mDatabase, mCloneReadInfo);
|
||||
mDatabase,
|
||||
mCloneReadInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ContinueObjectStoreKeyHelper::GatherResultsFromStatement(
|
||||
mozIStorageStatement* aStatement)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aStatement);
|
||||
|
||||
nsresult rv = mKey.SetFromStatement(aStatement, 0);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
|
@ -55,6 +55,7 @@ public:
|
||||
enum Type
|
||||
{
|
||||
OBJECTSTORE = 0,
|
||||
OBJECTSTOREKEY,
|
||||
INDEXKEY,
|
||||
INDEXOBJECT
|
||||
};
|
||||
@ -83,6 +84,18 @@ public:
|
||||
const Key& aKey,
|
||||
StructuredCloneReadInfo& aCloneReadInfo);
|
||||
|
||||
// For OBJECTSTOREKEY cursors.
|
||||
static
|
||||
already_AddRefed<IDBCursor>
|
||||
Create(IDBRequest* aRequest,
|
||||
IDBTransaction* aTransaction,
|
||||
IDBObjectStore* aObjectStore,
|
||||
Direction aDirection,
|
||||
const Key& aRangeKey,
|
||||
const nsACString& aContinueQuery,
|
||||
const nsACString& aContinueToQuery,
|
||||
const Key& aKey);
|
||||
|
||||
// For INDEXKEY cursors.
|
||||
static
|
||||
already_AddRefed<IDBCursor>
|
||||
|
@ -1989,7 +1989,7 @@ OpenKeyCursorHelper::PackArgumentsForParentProcess(IndexRequestParams& aParams)
|
||||
|
||||
PROFILER_MAIN_THREAD_LABEL("IndexedDB",
|
||||
"OpenKeyCursorHelper::"
|
||||
"PackArgumentsForParentProcess");
|
||||
"PackArgumentsForParentProcess [IDBIndex.cpp]");
|
||||
|
||||
OpenKeyCursorParams params;
|
||||
|
||||
|
@ -345,6 +345,57 @@ private:
|
||||
SerializedStructuredCloneReadInfo mSerializedCloneReadInfo;
|
||||
};
|
||||
|
||||
class OpenKeyCursorHelper MOZ_FINAL : public ObjectStoreHelper
|
||||
{
|
||||
public:
|
||||
OpenKeyCursorHelper(IDBTransaction* aTransaction,
|
||||
IDBRequest* aRequest,
|
||||
IDBObjectStore* aObjectStore,
|
||||
IDBKeyRange* aKeyRange,
|
||||
IDBCursor::Direction aDirection)
|
||||
: ObjectStoreHelper(aTransaction, aRequest, aObjectStore),
|
||||
mKeyRange(aKeyRange), mDirection(aDirection)
|
||||
{ }
|
||||
|
||||
virtual nsresult
|
||||
DoDatabaseWork(mozIStorageConnection* aConnection) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult
|
||||
GetSuccessResult(JSContext* aCx, JS::MutableHandleValue aVal) MOZ_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
ReleaseMainThreadObjects() MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult
|
||||
PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE;
|
||||
|
||||
virtual ChildProcessSendResult
|
||||
SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult
|
||||
UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
~OpenKeyCursorHelper()
|
||||
{ }
|
||||
|
||||
nsresult EnsureCursor();
|
||||
|
||||
// In-params.
|
||||
nsRefPtr<IDBKeyRange> mKeyRange;
|
||||
const IDBCursor::Direction mDirection;
|
||||
|
||||
// Out-params.
|
||||
Key mKey;
|
||||
nsCString mContinueQuery;
|
||||
nsCString mContinueToQuery;
|
||||
Key mRangeKey;
|
||||
|
||||
// Only used in the parent process.
|
||||
nsRefPtr<IDBCursor> mCursor;
|
||||
};
|
||||
|
||||
class CreateIndexHelper : public NoRequestObjectStoreHelper
|
||||
{
|
||||
public:
|
||||
@ -2368,6 +2419,69 @@ IDBObjectStore::OpenCursorFromChildProcess(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
IDBObjectStore::OpenCursorFromChildProcess(IDBRequest* aRequest,
|
||||
size_t aDirection,
|
||||
const Key& aKey,
|
||||
IDBCursor** _retval)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aRequest);
|
||||
|
||||
auto direction = static_cast<IDBCursor::Direction>(aDirection);
|
||||
|
||||
nsRefPtr<IDBCursor> cursor =
|
||||
IDBCursor::Create(aRequest, mTransaction, this, direction, Key(),
|
||||
EmptyCString(), EmptyCString(), aKey);
|
||||
NS_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
cursor.forget(_retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<IDBRequest>
|
||||
IDBObjectStore::OpenKeyCursorInternal(IDBKeyRange* aKeyRange, size_t aDirection,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mTransaction->IsOpen()) {
|
||||
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<IDBRequest> request = GenerateRequest(this);
|
||||
if (!request) {
|
||||
NS_WARNING("Failed to generate request!");
|
||||
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto direction = static_cast<IDBCursor::Direction>(aDirection);
|
||||
|
||||
nsRefPtr<OpenKeyCursorHelper> helper =
|
||||
new OpenKeyCursorHelper(mTransaction, request, this, aKeyRange, direction);
|
||||
|
||||
nsresult rv = helper->DispatchToTransactionPool();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to dispatch!");
|
||||
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IDB_PROFILER_MARK("IndexedDB Request %llu: "
|
||||
"database(%s).transaction(%s).objectStore(%s)."
|
||||
"openKeyCursor(%s, %s)",
|
||||
"IDBRequest[%llu] MT IDBObjectStore.openKeyCursor()",
|
||||
request->GetSerialNumber(),
|
||||
IDB_PROFILER_STRING(Transaction()->Database()),
|
||||
IDB_PROFILER_STRING(Transaction()),
|
||||
IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange),
|
||||
IDB_PROFILER_STRING(direction));
|
||||
|
||||
return request.forget();
|
||||
}
|
||||
|
||||
void
|
||||
IDBObjectStore::SetInfo(ObjectStoreInfo* aInfo)
|
||||
{
|
||||
@ -2875,6 +2989,29 @@ IDBObjectStore::GetAllKeys(JSContext* aCx,
|
||||
return GetAllKeysInternal(keyRange, limit, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<IDBRequest>
|
||||
IDBObjectStore::OpenKeyCursor(JSContext* aCx,
|
||||
const Optional<JS::HandleValue>& aRange,
|
||||
IDBCursorDirection aDirection, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mTransaction->IsOpen()) {
|
||||
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<IDBKeyRange> keyRange;
|
||||
if (aRange.WasPassed()) {
|
||||
aRv = IDBKeyRange::FromJSVal(aCx, aRange.Value(), getter_AddRefs(keyRange));
|
||||
ENSURE_SUCCESS(aRv, nullptr);
|
||||
}
|
||||
|
||||
IDBCursor::Direction direction = IDBCursor::ConvertDirection(aDirection);
|
||||
|
||||
return OpenKeyCursorInternal(keyRange, static_cast<size_t>(direction), aRv);
|
||||
}
|
||||
|
||||
inline nsresult
|
||||
CopyData(nsIInputStream* aInputStream, nsIOutputStream* aOutputStream)
|
||||
{
|
||||
@ -3912,7 +4049,7 @@ OpenCursorHelper::SendResponseToChildProcess(nsresult aResultCode)
|
||||
params.requestParent() = requestActor;
|
||||
params.direction() = mDirection;
|
||||
params.key() = mKey;
|
||||
params.cloneInfo() = mSerializedCloneReadInfo;
|
||||
params.optionalCloneInfo() = mSerializedCloneReadInfo;
|
||||
params.blobsParent().SwapElements(blobsParent);
|
||||
|
||||
if (!objectStoreActor->OpenCursor(mCursor, params, openCursorResponse)) {
|
||||
@ -3968,6 +4105,311 @@ OpenCursorHelper::UnpackResponseFromParentProcess(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess());
|
||||
|
||||
PROFILER_LABEL("IndexedDB",
|
||||
"OpenKeyCursorHelper::DoDatabaseWork [IDBObjectStore.cpp]");
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(keyValue, "key_value");
|
||||
NS_NAMED_LITERAL_CSTRING(id, "id");
|
||||
NS_NAMED_LITERAL_CSTRING(openLimit, " LIMIT ");
|
||||
|
||||
nsAutoCString queryStart = NS_LITERAL_CSTRING("SELECT ") + keyValue +
|
||||
NS_LITERAL_CSTRING(" FROM object_data WHERE "
|
||||
"object_store_id = :") +
|
||||
id;
|
||||
|
||||
nsAutoCString keyRangeClause;
|
||||
if (mKeyRange) {
|
||||
mKeyRange->GetBindingClause(keyValue, keyRangeClause);
|
||||
}
|
||||
|
||||
nsAutoCString directionClause = NS_LITERAL_CSTRING(" ORDER BY ") + keyValue;
|
||||
switch (mDirection) {
|
||||
case IDBCursor::NEXT:
|
||||
case IDBCursor::NEXT_UNIQUE:
|
||||
directionClause.AppendLiteral(" ASC");
|
||||
break;
|
||||
|
||||
case IDBCursor::PREV:
|
||||
case IDBCursor::PREV_UNIQUE:
|
||||
directionClause.AppendLiteral(" DESC");
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("Unknown direction type!");
|
||||
}
|
||||
|
||||
nsCString firstQuery = queryStart + keyRangeClause + directionClause +
|
||||
openLimit + NS_LITERAL_CSTRING("1");
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> stmt =
|
||||
mTransaction->GetCachedStatement(firstQuery);
|
||||
NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
mozStorageStatementScoper scoper(stmt);
|
||||
|
||||
nsresult rv = stmt->BindInt64ByName(id, mObjectStore->Id());
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
if (mKeyRange) {
|
||||
rv = mKeyRange->BindToStatement(stmt);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
bool hasResult;
|
||||
rv = stmt->ExecuteStep(&hasResult);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
if (!hasResult) {
|
||||
mKey.Unset();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
rv = mKey.SetFromStatement(stmt, 0);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Now we need to make the query to get the next match.
|
||||
keyRangeClause.Truncate();
|
||||
nsAutoCString continueToKeyRangeClause;
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(currentKey, "current_key");
|
||||
NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key");
|
||||
|
||||
switch (mDirection) {
|
||||
case IDBCursor::NEXT:
|
||||
case IDBCursor::NEXT_UNIQUE:
|
||||
AppendConditionClause(keyValue, currentKey, false, false,
|
||||
keyRangeClause);
|
||||
AppendConditionClause(keyValue, currentKey, false, true,
|
||||
continueToKeyRangeClause);
|
||||
if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
|
||||
AppendConditionClause(keyValue, rangeKey, true,
|
||||
!mKeyRange->IsUpperOpen(), keyRangeClause);
|
||||
AppendConditionClause(keyValue, rangeKey, true,
|
||||
!mKeyRange->IsUpperOpen(),
|
||||
continueToKeyRangeClause);
|
||||
mRangeKey = mKeyRange->Upper();
|
||||
}
|
||||
break;
|
||||
|
||||
case IDBCursor::PREV:
|
||||
case IDBCursor::PREV_UNIQUE:
|
||||
AppendConditionClause(keyValue, currentKey, true, false, keyRangeClause);
|
||||
AppendConditionClause(keyValue, currentKey, true, true,
|
||||
continueToKeyRangeClause);
|
||||
if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
|
||||
AppendConditionClause(keyValue, rangeKey, false,
|
||||
!mKeyRange->IsLowerOpen(), keyRangeClause);
|
||||
AppendConditionClause(keyValue, rangeKey, false,
|
||||
!mKeyRange->IsLowerOpen(),
|
||||
continueToKeyRangeClause);
|
||||
mRangeKey = mKeyRange->Lower();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("Unknown direction type!");
|
||||
}
|
||||
|
||||
mContinueQuery = queryStart + keyRangeClause + directionClause + openLimit;
|
||||
mContinueToQuery = queryStart + continueToKeyRangeClause + directionClause +
|
||||
openLimit;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
OpenKeyCursorHelper::EnsureCursor()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
PROFILER_MAIN_THREAD_LABEL("IndexedDB",
|
||||
"OpenKeyCursorHelper::EnsureCursor "
|
||||
"[IDBObjectStore.cpp]");
|
||||
|
||||
if (mCursor || mKey.IsUnset()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mCursor = IDBCursor::Create(mRequest, mTransaction, mObjectStore, mDirection,
|
||||
mRangeKey, mContinueQuery, mContinueToQuery,
|
||||
mKey);
|
||||
NS_ENSURE_TRUE(mCursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
OpenKeyCursorHelper::GetSuccessResult(JSContext* aCx,
|
||||
JS::MutableHandleValue aVal)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
PROFILER_MAIN_THREAD_LABEL("IndexedDB",
|
||||
"OpenKeyCursorHelper::GetSuccessResult "
|
||||
"[IDBObjectStore.cpp]");
|
||||
|
||||
nsresult rv = EnsureCursor();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mCursor) {
|
||||
rv = WrapNative(aCx, mCursor, aVal);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
}
|
||||
else {
|
||||
aVal.setUndefined();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
OpenKeyCursorHelper::ReleaseMainThreadObjects()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mKeyRange = nullptr;
|
||||
mCursor = nullptr;
|
||||
|
||||
ObjectStoreHelper::ReleaseMainThreadObjects();
|
||||
}
|
||||
|
||||
nsresult
|
||||
OpenKeyCursorHelper::PackArgumentsForParentProcess(
|
||||
ObjectStoreRequestParams& aParams)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!IndexedDatabaseManager::IsMainProcess());
|
||||
|
||||
PROFILER_MAIN_THREAD_LABEL("IndexedDB",
|
||||
"OpenKeyCursorHelper::"
|
||||
"PackArgumentsForParentProcess "
|
||||
"[IDBObjectStore.cpp]");
|
||||
|
||||
OpenKeyCursorParams params;
|
||||
|
||||
if (mKeyRange) {
|
||||
KeyRange keyRange;
|
||||
mKeyRange->ToSerializedKeyRange(keyRange);
|
||||
params.optionalKeyRange() = keyRange;
|
||||
}
|
||||
else {
|
||||
params.optionalKeyRange() = mozilla::void_t();
|
||||
}
|
||||
|
||||
params.direction() = mDirection;
|
||||
|
||||
aParams = params;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AsyncConnectionHelper::ChildProcessSendResult
|
||||
OpenKeyCursorHelper::SendResponseToChildProcess(nsresult aResultCode)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess());
|
||||
MOZ_ASSERT(!mCursor);
|
||||
|
||||
PROFILER_MAIN_THREAD_LABEL("IndexedDB",
|
||||
"OpenKeyCursorHelper::SendResponseToChildProcess "
|
||||
"[IDBObjectStore.cpp]");
|
||||
|
||||
IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
|
||||
MOZ_ASSERT(actor);
|
||||
|
||||
if (NS_SUCCEEDED(aResultCode)) {
|
||||
nsresult rv = EnsureCursor();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("EnsureCursor failed!");
|
||||
aResultCode = rv;
|
||||
}
|
||||
}
|
||||
|
||||
ResponseValue response;
|
||||
if (NS_FAILED(aResultCode)) {
|
||||
response = aResultCode;
|
||||
} else {
|
||||
OpenCursorResponse openCursorResponse;
|
||||
|
||||
if (!mCursor) {
|
||||
openCursorResponse = mozilla::void_t();
|
||||
}
|
||||
else {
|
||||
IndexedDBObjectStoreParent* objectStoreActor =
|
||||
mObjectStore->GetActorParent();
|
||||
MOZ_ASSERT(objectStoreActor);
|
||||
|
||||
IndexedDBRequestParentBase* requestActor = mRequest->GetActorParent();
|
||||
MOZ_ASSERT(requestActor);
|
||||
|
||||
ObjectStoreCursorConstructorParams params;
|
||||
params.requestParent() = requestActor;
|
||||
params.direction() = mDirection;
|
||||
params.key() = mKey;
|
||||
params.optionalCloneInfo() = mozilla::void_t();
|
||||
|
||||
if (!objectStoreActor->OpenCursor(mCursor, params, openCursorResponse)) {
|
||||
return Error;
|
||||
}
|
||||
}
|
||||
|
||||
response = openCursorResponse;
|
||||
}
|
||||
|
||||
if (!actor->SendResponse(response)) {
|
||||
return Error;
|
||||
}
|
||||
|
||||
return Success_Sent;
|
||||
}
|
||||
|
||||
nsresult
|
||||
OpenKeyCursorHelper::UnpackResponseFromParentProcess(
|
||||
const ResponseValue& aResponseValue)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!IndexedDatabaseManager::IsMainProcess());
|
||||
MOZ_ASSERT(aResponseValue.type() == ResponseValue::TOpenCursorResponse);
|
||||
MOZ_ASSERT(aResponseValue.get_OpenCursorResponse().type() ==
|
||||
OpenCursorResponse::Tvoid_t ||
|
||||
aResponseValue.get_OpenCursorResponse().type() ==
|
||||
OpenCursorResponse::TPIndexedDBCursorChild);
|
||||
MOZ_ASSERT(!mCursor);
|
||||
|
||||
PROFILER_MAIN_THREAD_LABEL("IndexedDB",
|
||||
"OpenKeyCursorHelper::"
|
||||
"UnpackResponseFromParentProcess "
|
||||
"[IDBObjectStore.cpp]");
|
||||
|
||||
const OpenCursorResponse& response =
|
||||
aResponseValue.get_OpenCursorResponse();
|
||||
|
||||
switch (response.type()) {
|
||||
case OpenCursorResponse::Tvoid_t:
|
||||
break;
|
||||
|
||||
case OpenCursorResponse::TPIndexedDBCursorChild: {
|
||||
IndexedDBCursorChild* actor =
|
||||
static_cast<IndexedDBCursorChild*>(
|
||||
response.get_PIndexedDBCursorChild());
|
||||
|
||||
mCursor = actor->ForgetStrongCursor();
|
||||
NS_ASSERTION(mCursor, "This should never be null!");
|
||||
|
||||
} break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Unknown response union type!");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CreateIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
{
|
||||
|
@ -239,6 +239,11 @@ public:
|
||||
size_t aDirection,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<IDBRequest>
|
||||
OpenKeyCursorInternal(IDBKeyRange* aKeyRange,
|
||||
size_t aDirection,
|
||||
ErrorResult& aRv);
|
||||
|
||||
nsresult
|
||||
OpenCursorFromChildProcess(
|
||||
IDBRequest* aRequest,
|
||||
@ -248,6 +253,12 @@ public:
|
||||
nsTArray<StructuredCloneFile>& aBlobs,
|
||||
IDBCursor** _retval);
|
||||
|
||||
nsresult
|
||||
OpenCursorFromChildProcess(IDBRequest* aRequest,
|
||||
size_t aDirection,
|
||||
const Key& aKey,
|
||||
IDBCursor** _retval);
|
||||
|
||||
void
|
||||
SetInfo(ObjectStoreInfo* aInfo);
|
||||
|
||||
@ -347,6 +358,10 @@ public:
|
||||
GetAllKeys(JSContext* aCx, const Optional<JS::HandleValue>& aKey,
|
||||
const Optional<uint32_t>& aLimit, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<IDBRequest>
|
||||
OpenKeyCursor(JSContext* aCx, const Optional<JS::HandleValue>& aRange,
|
||||
IDBCursorDirection aDirection, ErrorResult& aRv);
|
||||
|
||||
protected:
|
||||
IDBObjectStore();
|
||||
~IDBObjectStore();
|
||||
|
@ -742,17 +742,40 @@ IndexedDBObjectStoreChild::RecvPIndexedDBCursorConstructor(
|
||||
|
||||
size_t direction = static_cast<size_t>(aParams.direction());
|
||||
|
||||
nsTArray<StructuredCloneFile> blobs;
|
||||
IDBObjectStore::ConvertActorsToBlobs(aParams.blobsChild(), blobs);
|
||||
|
||||
nsRefPtr<IDBCursor> cursor;
|
||||
nsresult rv =
|
||||
mObjectStore->OpenCursorFromChildProcess(request, direction, aParams.key(),
|
||||
aParams.cloneInfo(), blobs,
|
||||
getter_AddRefs(cursor));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
nsresult rv;
|
||||
|
||||
MOZ_ASSERT(blobs.IsEmpty(), "Should have swapped blob elements!");
|
||||
typedef ipc::OptionalStructuredCloneReadInfo CursorUnionType;
|
||||
|
||||
switch (aParams.optionalCloneInfo().type()) {
|
||||
case CursorUnionType::TSerializedStructuredCloneReadInfo: {
|
||||
nsTArray<StructuredCloneFile> blobs;
|
||||
IDBObjectStore::ConvertActorsToBlobs(aParams.blobsChild(), blobs);
|
||||
|
||||
const SerializedStructuredCloneReadInfo& cloneInfo =
|
||||
aParams.optionalCloneInfo().get_SerializedStructuredCloneReadInfo();
|
||||
|
||||
rv = mObjectStore->OpenCursorFromChildProcess(request, direction,
|
||||
aParams.key(), cloneInfo,
|
||||
blobs,
|
||||
getter_AddRefs(cursor));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
MOZ_ASSERT(blobs.IsEmpty(), "Should have swapped blob elements!");
|
||||
} break;
|
||||
|
||||
case CursorUnionType::Tvoid_t:
|
||||
MOZ_ASSERT(aParams.blobsChild().IsEmpty());
|
||||
|
||||
rv = mObjectStore->OpenCursorFromChildProcess(request, direction,
|
||||
aParams.key(),
|
||||
getter_AddRefs(cursor));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Unknown union type!");
|
||||
}
|
||||
|
||||
actor->SetCursor(cursor);
|
||||
return true;
|
||||
@ -1088,7 +1111,8 @@ IndexedDBObjectStoreRequestChild::Recv__delete__(const ResponseValue& aResponse)
|
||||
MOZ_ASSERT(mRequestType == ParamsUnionType::TCountParams);
|
||||
break;
|
||||
case ResponseValue::TOpenCursorResponse:
|
||||
MOZ_ASSERT(mRequestType == ParamsUnionType::TOpenCursorParams);
|
||||
MOZ_ASSERT(mRequestType == ParamsUnionType::TOpenCursorParams ||
|
||||
mRequestType == ParamsUnionType::TOpenKeyCursorParams);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -6,6 +6,7 @@ include "mozilla/dom/indexedDB/SerializationHelpers.h";
|
||||
|
||||
using mozilla::dom::indexedDB::Key;
|
||||
using mozilla::dom::indexedDB::IDBCursor::Direction;
|
||||
using mozilla::dom::indexedDB::SerializedStructuredCloneReadInfo;
|
||||
|
||||
using mozilla::void_t;
|
||||
|
||||
@ -57,6 +58,18 @@ struct OpenCursorParams
|
||||
Direction direction;
|
||||
};
|
||||
|
||||
struct OpenKeyCursorParams
|
||||
{
|
||||
OptionalKeyRange optionalKeyRange;
|
||||
Direction direction;
|
||||
};
|
||||
|
||||
union OptionalStructuredCloneReadInfo
|
||||
{
|
||||
SerializedStructuredCloneReadInfo;
|
||||
void_t;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace indexedDB
|
||||
} // namespace dom
|
||||
|
@ -1118,6 +1118,9 @@ IndexedDBObjectStoreParent::RecvPIndexedDBRequestConstructor(
|
||||
case ObjectStoreRequestParams::TOpenCursorParams:
|
||||
return actor->OpenCursor(aParams.get_OpenCursorParams());
|
||||
|
||||
case ObjectStoreRequestParams::TOpenKeyCursorParams:
|
||||
return actor->OpenKeyCursor(aParams.get_OpenKeyCursorParams());
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Unknown type!");
|
||||
}
|
||||
@ -1775,6 +1778,47 @@ IndexedDBObjectStoreRequestParent::OpenCursor(const OpenCursorParams& aParams)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IndexedDBObjectStoreRequestParent::OpenKeyCursor(
|
||||
const OpenKeyCursorParams& aParams)
|
||||
{
|
||||
MOZ_ASSERT(mRequestType == ParamsUnionType::TOpenKeyCursorParams);
|
||||
MOZ_ASSERT(mObjectStore);
|
||||
|
||||
const ipc::OptionalKeyRange keyRangeUnion = aParams.optionalKeyRange();
|
||||
|
||||
nsRefPtr<IDBKeyRange> keyRange;
|
||||
|
||||
switch (keyRangeUnion.type()) {
|
||||
case ipc::OptionalKeyRange::TKeyRange:
|
||||
keyRange =
|
||||
IDBKeyRange::FromSerializedKeyRange(keyRangeUnion.get_KeyRange());
|
||||
break;
|
||||
|
||||
case ipc::OptionalKeyRange::Tvoid_t:
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Unknown param type!");
|
||||
}
|
||||
|
||||
size_t direction = static_cast<size_t>(aParams.direction());
|
||||
|
||||
nsRefPtr<IDBRequest> request;
|
||||
|
||||
{
|
||||
AutoSetCurrentTransaction asct(mObjectStore->Transaction());
|
||||
|
||||
ErrorResult rv;
|
||||
request = mObjectStore->OpenKeyCursorInternal(keyRange, direction, rv);
|
||||
ENSURE_SUCCESS(rv, false);
|
||||
}
|
||||
|
||||
request->SetActor(this);
|
||||
mRequest.swap(request);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* IndexedDBIndexRequestParent
|
||||
******************************************************************************/
|
||||
|
@ -710,6 +710,7 @@ class IndexedDBObjectStoreRequestParent : public IndexedDBRequestParentBase
|
||||
typedef ipc::GetAllKeysParams GetAllKeysParams;
|
||||
typedef ipc::CountParams CountParams;
|
||||
typedef ipc::OpenCursorParams OpenCursorParams;
|
||||
typedef ipc::OpenKeyCursorParams OpenKeyCursorParams;
|
||||
|
||||
public:
|
||||
IndexedDBObjectStoreRequestParent(IDBObjectStore* aObjectStore,
|
||||
@ -743,6 +744,9 @@ public:
|
||||
bool
|
||||
OpenCursor(const OpenCursorParams& aParams);
|
||||
|
||||
bool
|
||||
OpenKeyCursor(const OpenKeyCursorParams& aParams);
|
||||
|
||||
protected:
|
||||
void
|
||||
ConvertBlobActors(const InfallibleTArray<PBlobParent*>& aActors,
|
||||
|
@ -9,8 +9,6 @@ include protocol PIndexedDBRequest;
|
||||
|
||||
include IndexedDBParams;
|
||||
|
||||
using mozilla::dom::indexedDB::SerializedStructuredCloneReadInfo;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace indexedDB {
|
||||
@ -22,12 +20,6 @@ struct GetKeyParams
|
||||
KeyRange keyRange;
|
||||
};
|
||||
|
||||
struct OpenKeyCursorParams
|
||||
{
|
||||
OptionalKeyRange optionalKeyRange;
|
||||
Direction direction;
|
||||
};
|
||||
|
||||
union IndexRequestParams
|
||||
{
|
||||
GetParams;
|
||||
@ -39,12 +31,6 @@ union IndexRequestParams
|
||||
OpenKeyCursorParams;
|
||||
};
|
||||
|
||||
union OptionalStructuredCloneReadInfo
|
||||
{
|
||||
SerializedStructuredCloneReadInfo;
|
||||
void_t;
|
||||
};
|
||||
|
||||
struct IndexCursorConstructorParams
|
||||
{
|
||||
PIndexedDBRequest request;
|
||||
|
@ -12,7 +12,6 @@ include IndexedDBParams;
|
||||
|
||||
using mozilla::dom::indexedDB::IndexInfo;
|
||||
using mozilla::dom::indexedDB::IndexUpdateInfo;
|
||||
using mozilla::dom::indexedDB::SerializedStructuredCloneReadInfo;
|
||||
using mozilla::dom::indexedDB::SerializedStructuredCloneWriteInfo;
|
||||
|
||||
namespace mozilla {
|
||||
@ -59,6 +58,7 @@ union ObjectStoreRequestParams
|
||||
ClearParams;
|
||||
CountParams;
|
||||
OpenCursorParams;
|
||||
OpenKeyCursorParams;
|
||||
};
|
||||
|
||||
struct CreateIndexParams
|
||||
@ -82,7 +82,7 @@ struct ObjectStoreCursorConstructorParams
|
||||
PIndexedDBRequest request;
|
||||
Direction direction;
|
||||
Key key;
|
||||
SerializedStructuredCloneReadInfo cloneInfo;
|
||||
OptionalStructuredCloneReadInfo optionalCloneInfo;
|
||||
PBlob[] blobs;
|
||||
};
|
||||
|
||||
|
@ -38,6 +38,7 @@ tail =
|
||||
[test_objectCursors.js]
|
||||
[test_objectStore_getAllKeys.js]
|
||||
[test_objectStore_inline_autoincrement_key_added_on_put.js]
|
||||
[test_objectStore_openKeyCursor.js]
|
||||
[test_objectStore_remove_values.js]
|
||||
[test_odd_result_order.js]
|
||||
[test_open_empty_db.js]
|
||||
|
@ -73,6 +73,7 @@ MOCHITEST_FILES = \
|
||||
test_objectCursors.html \
|
||||
test_objectStore_getAllKeys.html \
|
||||
test_objectStore_inline_autoincrement_key_added_on_put.html \
|
||||
test_objectStore_openKeyCursor.html \
|
||||
test_objectStore_remove_values.html \
|
||||
test_object_identity.html \
|
||||
test_odd_result_order.html \
|
||||
|
19
dom/indexedDB/test/test_objectStore_openKeyCursor.html
Normal file
19
dom/indexedDB/test/test_objectStore_openKeyCursor.html
Normal file
@ -0,0 +1,19 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Property Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7" src="unit/test_objectStore_openKeyCursor.js"></script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
@ -42,6 +42,7 @@ MOCHITEST_FILES = \
|
||||
test_objectCursors.js \
|
||||
test_objectStore_getAllKeys.js \
|
||||
test_objectStore_inline_autoincrement_key_added_on_put.js \
|
||||
test_objectStore_openKeyCursor.js \
|
||||
test_objectStore_remove_values.js \
|
||||
test_odd_result_order.js \
|
||||
test_open_empty_db.js \
|
||||
|
400
dom/indexedDB/test/unit/test_objectStore_openKeyCursor.js
Normal file
400
dom/indexedDB/test/unit/test_objectStore_openKeyCursor.js
Normal file
@ -0,0 +1,400 @@
|
||||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
let testGenerator = testSteps();
|
||||
|
||||
function testSteps() {
|
||||
const dbName = this.window ?
|
||||
window.location.pathname :
|
||||
"test_objectStore_openKeyCursor";
|
||||
const dbVersion = 1;
|
||||
const objectStoreName = "foo";
|
||||
const keyCount = 100;
|
||||
|
||||
let request = indexedDB.open(dbName, dbVersion);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
|
||||
let event = yield undefined;
|
||||
|
||||
info("Creating database");
|
||||
|
||||
let db = event.target.result;
|
||||
let objectStore = db.createObjectStore(objectStoreName);
|
||||
for (let i = 0; i < keyCount; i++) {
|
||||
objectStore.add(true, i);
|
||||
}
|
||||
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
|
||||
event = yield undefined;
|
||||
|
||||
db = event.target.result;
|
||||
objectStore = db.transaction(objectStoreName, "readwrite")
|
||||
.objectStore(objectStoreName);
|
||||
|
||||
info("Getting all keys");
|
||||
objectStore.getAllKeys().onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
const allKeys = event.target.result;
|
||||
|
||||
ok(Array.isArray(allKeys), "Got an array result");
|
||||
is(allKeys.length, keyCount, "Got correct array length");
|
||||
|
||||
info("Opening normal key cursor");
|
||||
|
||||
let seenKeys = [];
|
||||
objectStore.openKeyCursor().onsuccess = event => {
|
||||
let cursor = event.target.result;
|
||||
if (!cursor) {
|
||||
continueToNextStepSync();
|
||||
return;
|
||||
}
|
||||
|
||||
is(cursor.source, objectStore, "Correct source");
|
||||
is(cursor.direction, "next", "Correct direction");
|
||||
|
||||
let exception = null;
|
||||
try {
|
||||
cursor.update(10);
|
||||
} catch(e) {
|
||||
exception = e;
|
||||
}
|
||||
ok(!!exception, "update() throws for key cursor");
|
||||
|
||||
exception = null;
|
||||
try {
|
||||
cursor.delete();
|
||||
} catch(e) {
|
||||
exception = e;
|
||||
}
|
||||
ok(!!exception, "delete() throws for key cursor");
|
||||
|
||||
is(cursor.key, cursor.primaryKey, "key and primaryKey match");
|
||||
ok(!("value" in cursor), "No 'value' property on key cursor");
|
||||
|
||||
seenKeys.push(cursor.key);
|
||||
cursor.continue();
|
||||
};
|
||||
yield undefined;
|
||||
|
||||
is(seenKeys.length, allKeys.length, "Saw the right number of keys");
|
||||
|
||||
let match = true;
|
||||
for (let i = 0; i < seenKeys.length; i++) {
|
||||
if (seenKeys[i] !== allKeys[i]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ok(match, "All keys matched");
|
||||
|
||||
info("Opening key cursor with keyRange");
|
||||
|
||||
let keyRange = IDBKeyRange.bound(10, 20, false, true);
|
||||
|
||||
seenKeys = [];
|
||||
objectStore.openKeyCursor(keyRange).onsuccess = event => {
|
||||
let cursor = event.target.result;
|
||||
if (!cursor) {
|
||||
continueToNextStepSync();
|
||||
return;
|
||||
}
|
||||
|
||||
is(cursor.source, objectStore, "Correct source");
|
||||
is(cursor.direction, "next", "Correct direction");
|
||||
|
||||
let exception = null;
|
||||
try {
|
||||
cursor.update(10);
|
||||
} catch(e) {
|
||||
exception = e;
|
||||
}
|
||||
ok(!!exception, "update() throws for key cursor");
|
||||
|
||||
exception = null;
|
||||
try {
|
||||
cursor.delete();
|
||||
} catch(e) {
|
||||
exception = e;
|
||||
}
|
||||
ok(!!exception, "delete() throws for key cursor");
|
||||
|
||||
is(cursor.key, cursor.primaryKey, "key and primaryKey match");
|
||||
ok(!("value" in cursor), "No 'value' property on key cursor");
|
||||
|
||||
seenKeys.push(cursor.key);
|
||||
cursor.continue();
|
||||
};
|
||||
yield undefined;
|
||||
|
||||
is(seenKeys.length, 10, "Saw the right number of keys");
|
||||
|
||||
match = true;
|
||||
for (let i = 0; i < seenKeys.length; i++) {
|
||||
if (seenKeys[i] !== allKeys[i + 10]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ok(match, "All keys matched");
|
||||
|
||||
info("Opening key cursor with unmatched keyRange");
|
||||
|
||||
keyRange = IDBKeyRange.bound(10000, 200000);
|
||||
|
||||
seenKeys = [];
|
||||
objectStore.openKeyCursor(keyRange).onsuccess = event => {
|
||||
let cursor = event.target.result;
|
||||
if (!cursor) {
|
||||
continueToNextStepSync();
|
||||
return;
|
||||
}
|
||||
|
||||
ok(false, "Shouldn't have any keys here");
|
||||
cursor.continue();
|
||||
};
|
||||
yield undefined;
|
||||
|
||||
is(seenKeys.length, 0, "Saw the right number of keys");
|
||||
|
||||
info("Opening reverse key cursor");
|
||||
|
||||
seenKeys = [];
|
||||
objectStore.openKeyCursor(null, "prev").onsuccess = event => {
|
||||
let cursor = event.target.result;
|
||||
if (!cursor) {
|
||||
continueToNextStepSync();
|
||||
return;
|
||||
}
|
||||
|
||||
is(cursor.source, objectStore, "Correct source");
|
||||
is(cursor.direction, "prev", "Correct direction");
|
||||
|
||||
let exception = null;
|
||||
try {
|
||||
cursor.update(10);
|
||||
} catch(e) {
|
||||
exception = e;
|
||||
}
|
||||
ok(!!exception, "update() throws for key cursor");
|
||||
|
||||
exception = null;
|
||||
try {
|
||||
cursor.delete();
|
||||
} catch(e) {
|
||||
exception = e;
|
||||
}
|
||||
ok(!!exception, "delete() throws for key cursor");
|
||||
|
||||
is(cursor.key, cursor.primaryKey, "key and primaryKey match");
|
||||
ok(!("value" in cursor), "No 'value' property on key cursor");
|
||||
|
||||
seenKeys.push(cursor.key);
|
||||
cursor.continue();
|
||||
};
|
||||
yield undefined;
|
||||
|
||||
is(seenKeys.length, allKeys.length, "Saw the right number of keys");
|
||||
|
||||
seenKeys.reverse();
|
||||
|
||||
match = true;
|
||||
for (let i = 0; i < seenKeys.length; i++) {
|
||||
if (seenKeys[i] !== allKeys[i]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ok(match, "All keys matched");
|
||||
|
||||
info("Opening reverse key cursor with key range");
|
||||
|
||||
keyRange = IDBKeyRange.bound(10, 20, false, true);
|
||||
|
||||
seenKeys = [];
|
||||
objectStore.openKeyCursor(keyRange, "prev").onsuccess = event => {
|
||||
let cursor = event.target.result;
|
||||
if (!cursor) {
|
||||
continueToNextStepSync();
|
||||
return;
|
||||
}
|
||||
|
||||
is(cursor.source, objectStore, "Correct source");
|
||||
is(cursor.direction, "prev", "Correct direction");
|
||||
|
||||
let exception = null;
|
||||
try {
|
||||
cursor.update(10);
|
||||
} catch(e) {
|
||||
exception = e;
|
||||
}
|
||||
ok(!!exception, "update() throws for key cursor");
|
||||
|
||||
exception = null;
|
||||
try {
|
||||
cursor.delete();
|
||||
} catch(e) {
|
||||
exception = e;
|
||||
}
|
||||
ok(!!exception, "delete() throws for key cursor");
|
||||
|
||||
is(cursor.key, cursor.primaryKey, "key and primaryKey match");
|
||||
ok(!("value" in cursor), "No 'value' property on key cursor");
|
||||
|
||||
seenKeys.push(cursor.key);
|
||||
cursor.continue();
|
||||
};
|
||||
yield undefined;
|
||||
|
||||
is(seenKeys.length, 10, "Saw the right number of keys");
|
||||
|
||||
seenKeys.reverse();
|
||||
|
||||
match = true;
|
||||
for (let i = 0; i < 10; i++) {
|
||||
if (seenKeys[i] !== allKeys[i + 10]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ok(match, "All keys matched");
|
||||
|
||||
info("Opening reverse key cursor with unmatched key range");
|
||||
|
||||
keyRange = IDBKeyRange.bound(10000, 200000);
|
||||
|
||||
seenKeys = [];
|
||||
objectStore.openKeyCursor(keyRange, "prev").onsuccess = event => {
|
||||
let cursor = event.target.result;
|
||||
if (!cursor) {
|
||||
continueToNextStepSync();
|
||||
return;
|
||||
}
|
||||
|
||||
ok(false, "Shouldn't have any keys here");
|
||||
cursor.continue();
|
||||
};
|
||||
yield undefined;
|
||||
|
||||
is(seenKeys.length, 0, "Saw the right number of keys");
|
||||
|
||||
info("Opening key cursor with advance");
|
||||
|
||||
seenKeys = [];
|
||||
objectStore.openKeyCursor().onsuccess = event => {
|
||||
let cursor = event.target.result;
|
||||
if (!cursor) {
|
||||
continueToNextStepSync();
|
||||
return;
|
||||
}
|
||||
|
||||
is(cursor.source, objectStore, "Correct source");
|
||||
is(cursor.direction, "next", "Correct direction");
|
||||
|
||||
let exception = null;
|
||||
try {
|
||||
cursor.update(10);
|
||||
} catch(e) {
|
||||
exception = e;
|
||||
}
|
||||
ok(!!exception, "update() throws for key cursor");
|
||||
|
||||
exception = null;
|
||||
try {
|
||||
cursor.delete();
|
||||
} catch(e) {
|
||||
exception = e;
|
||||
}
|
||||
ok(!!exception, "delete() throws for key cursor");
|
||||
|
||||
is(cursor.key, cursor.primaryKey, "key and primaryKey match");
|
||||
ok(!("value" in cursor), "No 'value' property on key cursor");
|
||||
|
||||
seenKeys.push(cursor.key);
|
||||
if (seenKeys.length == 1) {
|
||||
cursor.advance(10);
|
||||
} else {
|
||||
cursor.continue();
|
||||
}
|
||||
};
|
||||
yield undefined;
|
||||
|
||||
is(seenKeys.length, allKeys.length - 9, "Saw the right number of keys");
|
||||
|
||||
let match = true;
|
||||
for (let i = 0, j = 0; i < seenKeys.length; i++) {
|
||||
if (seenKeys[i] !== allKeys[i + j]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
if (i == 0) {
|
||||
j = 9;
|
||||
}
|
||||
}
|
||||
ok(match, "All keys matched");
|
||||
|
||||
info("Opening key cursor with continue-to-key");
|
||||
|
||||
seenKeys = [];
|
||||
objectStore.openKeyCursor().onsuccess = event => {
|
||||
let cursor = event.target.result;
|
||||
if (!cursor) {
|
||||
continueToNextStepSync();
|
||||
return;
|
||||
}
|
||||
|
||||
is(cursor.source, objectStore, "Correct source");
|
||||
is(cursor.direction, "next", "Correct direction");
|
||||
|
||||
let exception = null;
|
||||
try {
|
||||
cursor.update(10);
|
||||
} catch(e) {
|
||||
exception = e;
|
||||
}
|
||||
ok(!!exception, "update() throws for key cursor");
|
||||
|
||||
exception = null;
|
||||
try {
|
||||
cursor.delete();
|
||||
} catch(e) {
|
||||
exception = e;
|
||||
}
|
||||
ok(!!exception, "delete() throws for key cursor");
|
||||
|
||||
is(cursor.key, cursor.primaryKey, "key and primaryKey match");
|
||||
ok(!("value" in cursor), "No 'value' property on key cursor");
|
||||
|
||||
seenKeys.push(cursor.key);
|
||||
|
||||
if (seenKeys.length == 1) {
|
||||
cursor.continue(10);
|
||||
} else {
|
||||
cursor.continue();
|
||||
}
|
||||
};
|
||||
yield undefined;
|
||||
|
||||
is(seenKeys.length, allKeys.length - 9, "Saw the right number of keys");
|
||||
|
||||
let match = true;
|
||||
for (let i = 0, j = 0; i < seenKeys.length; i++) {
|
||||
if (seenKeys[i] !== allKeys[i + j]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
if (i == 0) {
|
||||
j = 9;
|
||||
}
|
||||
}
|
||||
ok(match, "All keys matched");
|
||||
|
||||
finishTest();
|
||||
yield undefined;
|
||||
}
|
@ -51,6 +51,7 @@ skip-if = os == "mac" || os == "android"
|
||||
[test_objectCursors.js]
|
||||
[test_objectStore_getAllKeys.js]
|
||||
[test_objectStore_inline_autoincrement_key_added_on_put.js]
|
||||
[test_objectStore_openKeyCursor.js]
|
||||
[test_objectStore_remove_values.js]
|
||||
[test_odd_result_order.js]
|
||||
[test_open_empty_db.js]
|
||||
|
@ -71,4 +71,7 @@ partial interface IDBObjectStore {
|
||||
|
||||
[Pref="dom.indexedDB.experimental", Throws]
|
||||
IDBRequest getAllKeys (optional any key, optional unsigned long limit);
|
||||
|
||||
[Pref="dom.indexedDB.experimental", Throws]
|
||||
IDBRequest openKeyCursor (optional any range, optional IDBCursorDirection direction = "next");
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user