Layout tests imported/w3c/web-platform-tests/IndexedDB/*-exception-order.html are...
authorsihui_liu@apple.com <sihui_liu@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 16 Mar 2019 08:57:22 +0000 (08:57 +0000)
committersihui_liu@apple.com <sihui_liu@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 16 Mar 2019 08:57:22 +0000 (08:57 +0000)
https://bugs.webkit.org/show_bug.cgi?id=195650

Reviewed by Ryosuke Niwa.

LayoutTests/imported/w3c:

Updated test expectations to PASS.

* web-platform-tests/IndexedDB/idbdatabase-createObjectStore-exception-order-expected.txt:
* web-platform-tests/IndexedDB/idbdatabase-transaction-exception-order-expected.txt:
* web-platform-tests/IndexedDB/idbindex-query-exception-order-expected.txt:
* web-platform-tests/IndexedDB/idbobjectstore-delete-exception-order-expected.txt:
* web-platform-tests/IndexedDB/idbobjectstore-query-exception-order-expected.txt:

Source/WebCore:

Fix some exception orders in IDB.

* Modules/indexeddb/IDBDatabase.cpp:
(WebCore::IDBDatabase::createObjectStore):
Step 6 of https://www.w3.org/TR/IndexedDB-2/#dom-idbdatabase-createobjectstore.

(WebCore::IDBDatabase::transaction):
Step 1 of https://www.w3.org/TR/IndexedDB-2/#dom-idbdatabase-transaction.

* Modules/indexeddb/IDBIndex.cpp:
(WebCore::IDBIndex::doOpenCursor):
(WebCore::IDBIndex::openCursor):
Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbindex-opencursor.

(WebCore::IDBIndex::doOpenKeyCursor):
(WebCore::IDBIndex::openKeyCursor):
Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbindex-openkeycursor.

(WebCore::IDBIndex::count):
Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbindex-count.

(WebCore::IDBIndex::doCount):
(WebCore::IDBIndex::get):
Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbindex-get.

(WebCore::IDBIndex::doGet):
(WebCore::IDBIndex::getKey):
Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbindex-getkey.

(WebCore::IDBIndex::doGetKey):
(WebCore::IDBIndex::doGetAll):
(WebCore::IDBIndex::getAll):
Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbindex-getkey.
(WebCore::IDBIndex::doGetAllKeys):
(WebCore::IDBIndex::getAllKeys):
Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbindex-getallkeys.

* Modules/indexeddb/IDBIndex.h:
* Modules/indexeddb/IDBObjectStore.cpp:
(WebCore::IDBObjectStore::doOpenCursor):
(WebCore::IDBObjectStore::openCursor):
Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-opencursor.

(WebCore::IDBObjectStore::doOpenKeyCursor):
(WebCore::IDBObjectStore::openKeyCursor):
Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-openkeycursor.

(WebCore::IDBObjectStore::deleteFunction):
(WebCore::IDBObjectStore::doDelete):
(WebCore::IDBObjectStore::count):
Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-count.

(WebCore::IDBObjectStore::doCount):
(WebCore::IDBObjectStore::doGetAll):
(WebCore::IDBObjectStore::getAll):
Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-getall.

(WebCore::IDBObjectStore::doGetAllKeys):
(WebCore::IDBObjectStore::getAllKeys):
Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-getallkeys.
* Modules/indexeddb/IDBObjectStore.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@243039 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/IndexedDB/idbdatabase-createObjectStore-exception-order-expected.txt
LayoutTests/imported/w3c/web-platform-tests/IndexedDB/idbdatabase-transaction-exception-order-expected.txt
LayoutTests/imported/w3c/web-platform-tests/IndexedDB/idbindex-query-exception-order-expected.txt
LayoutTests/imported/w3c/web-platform-tests/IndexedDB/idbobjectstore-delete-exception-order-expected.txt
LayoutTests/imported/w3c/web-platform-tests/IndexedDB/idbobjectstore-query-exception-order-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/Modules/indexeddb/IDBDatabase.cpp
Source/WebCore/Modules/indexeddb/IDBIndex.cpp
Source/WebCore/Modules/indexeddb/IDBIndex.h
Source/WebCore/Modules/indexeddb/IDBKey.h
Source/WebCore/Modules/indexeddb/IDBObjectStore.cpp
Source/WebCore/Modules/indexeddb/IDBObjectStore.h

index 4686e2c..b024b81 100644 (file)
@@ -1,3 +1,18 @@
+2019-03-16  Sihui Liu  <sihui_liu@apple.com>
+
+        Layout tests imported/w3c/web-platform-tests/IndexedDB/*-exception-order.html are failing
+        https://bugs.webkit.org/show_bug.cgi?id=195650
+
+        Reviewed by Ryosuke Niwa.
+
+        Updated test expectations to PASS.
+
+        * web-platform-tests/IndexedDB/idbdatabase-createObjectStore-exception-order-expected.txt:
+        * web-platform-tests/IndexedDB/idbdatabase-transaction-exception-order-expected.txt:
+        * web-platform-tests/IndexedDB/idbindex-query-exception-order-expected.txt:
+        * web-platform-tests/IndexedDB/idbobjectstore-delete-exception-order-expected.txt:
+        * web-platform-tests/IndexedDB/idbobjectstore-query-exception-order-expected.txt:
+
 2019-03-12  Sihui Liu  <sihui_liu@apple.com>
 
         Layout Test imported/w3c/web-platform-tests/IndexedDB/fire-*-event-exception.html are failing
index 0fc0fa0..a4f6dd6 100644 (file)
@@ -1,8 +1,6 @@
 
 PASS IDBDatabase.createObjectStore exception order: InvalidStateError vs. TransactionInactiveError 
 PASS IDBDatabase.createObjectStore exception order: TransactionInactiveError vs. SyntaxError 
-FAIL IDBDatabase.createObjectStore exception order: SyntaxError vs. ConstraintError assert_throws: "Invalid key path" check (SyntaxError) should precede "duplicate store name" check (ConstraintError) function "() => {
-      db.createObjectStore('s', {keyPath: 'not a valid key path'});
-    }" threw object "ConstraintError: Failed to execute 'createObjectStore' on 'IDBDatabase': An object store with the specified name already exists." that is not a DOMException SyntaxError: property "code" is equal to 0, expected 12
+PASS IDBDatabase.createObjectStore exception order: SyntaxError vs. ConstraintError 
 PASS IDBDatabase.createObjectStore exception order: ConstraintError vs. InvalidAccessError 
 
index 4d30f9e..86251c7 100644 (file)
@@ -1,7 +1,5 @@
 
 PASS IDBDatabase.transaction exception order: InvalidStateError vs. NotFoundError 
 PASS IDBDatabase.transaction exception order: InvalidStateError vs. InvalidAccessError 
-FAIL IDBDatabase.transaction exception order: NotFoundError vs. TypeError assert_throws: "No such store" check (NotFoundError) should precede "invalid mode" check (TypeError) function "() => {
-      db.transaction('no-such-store', 'versionchange');
-    }" threw object "TypeError: Type error" that is not a DOMException NotFoundError: property "code" is equal to undefined, expected 8
+PASS IDBDatabase.transaction exception order: NotFoundError vs. TypeError 
 
index 6de4773..df57a0b 100644 (file)
@@ -1,14 +1,14 @@
 
 PASS IDBIndex.get exception order: InvalidStateError vs. TransactionInactiveError 
-FAIL IDBIndex.get exception order: TransactionInactiveError vs. DataError assert_throws: "not active" check (TransactionInactiveError) should precede query check (DataError) function "() => { index[method]({}); }" threw object "DataError: Failed to execute 'get' on 'IDBIndex': The parameter is not a valid key." that is not a DOMException TransactionInactiveError: property "name" is equal to "DataError", expected "TransactionInactiveError"
+PASS IDBIndex.get exception order: TransactionInactiveError vs. DataError 
 PASS IDBIndex.getAll exception order: InvalidStateError vs. TransactionInactiveError 
-FAIL IDBIndex.getAll exception order: TransactionInactiveError vs. DataError assert_throws: "not active" check (TransactionInactiveError) should precede query check (DataError) function "() => { index[method]({}); }" threw object "DataError: Failed to execute 'getAll' on 'IDBIndex': The parameter is not a valid key." that is not a DOMException TransactionInactiveError: property "name" is equal to "DataError", expected "TransactionInactiveError"
+PASS IDBIndex.getAll exception order: TransactionInactiveError vs. DataError 
 PASS IDBIndex.getAllKeys exception order: InvalidStateError vs. TransactionInactiveError 
-FAIL IDBIndex.getAllKeys exception order: TransactionInactiveError vs. DataError assert_throws: "not active" check (TransactionInactiveError) should precede query check (DataError) function "() => { index[method]({}); }" threw object "DataError: Failed to execute 'getAllKeys' on 'IDBIndex': The parameter is not a valid key." that is not a DOMException TransactionInactiveError: property "name" is equal to "DataError", expected "TransactionInactiveError"
+PASS IDBIndex.getAllKeys exception order: TransactionInactiveError vs. DataError 
 PASS IDBIndex.count exception order: InvalidStateError vs. TransactionInactiveError 
-FAIL IDBIndex.count exception order: TransactionInactiveError vs. DataError assert_throws: "not active" check (TransactionInactiveError) should precede query check (DataError) function "() => { index[method]({}); }" threw object "DataError: Failed to execute 'count' on 'IDBIndex': The parameter is not a valid key." that is not a DOMException TransactionInactiveError: property "name" is equal to "DataError", expected "TransactionInactiveError"
+PASS IDBIndex.count exception order: TransactionInactiveError vs. DataError 
 PASS IDBIndex.openCursor exception order: InvalidStateError vs. TransactionInactiveError 
-FAIL IDBIndex.openCursor exception order: TransactionInactiveError vs. DataError assert_throws: "not active" check (TransactionInactiveError) should precede query check (DataError) function "() => { index[method]({}); }" threw object "DataError: Failed to execute 'openCursor' on 'IDBIndex': The parameter is not a valid key." that is not a DOMException TransactionInactiveError: property "name" is equal to "DataError", expected "TransactionInactiveError"
+PASS IDBIndex.openCursor exception order: TransactionInactiveError vs. DataError 
 PASS IDBIndex.openKeyCursor exception order: InvalidStateError vs. TransactionInactiveError 
-FAIL IDBIndex.openKeyCursor exception order: TransactionInactiveError vs. DataError assert_throws: "not active" check (TransactionInactiveError) should precede query check (DataError) function "() => { index[method]({}); }" threw object "DataError: Failed to execute 'openKeyCursor' on 'IDBIndex': The parameter is not a valid key." that is not a DOMException TransactionInactiveError: property "name" is equal to "DataError", expected "TransactionInactiveError"
+PASS IDBIndex.openKeyCursor exception order: TransactionInactiveError vs. DataError 
 
index db9ee2d..f087e34 100644 (file)
@@ -1,5 +1,5 @@
 
 PASS IDBObjectStore.delete exception order: InvalidStateError vs. TransactionInactiveError 
 PASS IDBObjectStore.delete exception order: TransactionInactiveError vs. ReadOnlyError 
-FAIL IDBObjectStore.delete exception order: ReadOnlyError vs. DataError assert_throws: "read only" check (ReadOnlyError) should precede key/data check (DataError) function "() => { store.delete({}); }" threw object "DataError: Failed to execute 'delete' on 'IDBObjectStore': The parameter is not a valid key." that is not a DOMException ReadOnlyError: property "name" is equal to "DataError", expected "ReadOnlyError"
+PASS IDBObjectStore.delete exception order: ReadOnlyError vs. DataError 
 
index 2971641..7b00616 100644 (file)
@@ -2,13 +2,13 @@
 PASS IDBObjectStore.get exception order: InvalidStateError vs. TransactionInactiveError 
 PASS IDBObjectStore.get exception order: TransactionInactiveError vs. DataError 
 PASS IDBObjectStore.getAll exception order: InvalidStateError vs. TransactionInactiveError 
-FAIL IDBObjectStore.getAll exception order: TransactionInactiveError vs. DataError assert_throws: "not active" check (TransactionInactiveError) should precede query check (DataError) function "() => { store[method]({}); }" threw object "DataError: Failed to execute 'getAll' on 'IDBObjectStore': The parameter is not a valid key." that is not a DOMException TransactionInactiveError: property "name" is equal to "DataError", expected "TransactionInactiveError"
+PASS IDBObjectStore.getAll exception order: TransactionInactiveError vs. DataError 
 PASS IDBObjectStore.getAllKeys exception order: InvalidStateError vs. TransactionInactiveError 
-FAIL IDBObjectStore.getAllKeys exception order: TransactionInactiveError vs. DataError assert_throws: "not active" check (TransactionInactiveError) should precede query check (DataError) function "() => { store[method]({}); }" threw object "DataError: Failed to execute 'getAllKeys' on 'IDBObjectStore': The parameter is not a valid key." that is not a DOMException TransactionInactiveError: property "name" is equal to "DataError", expected "TransactionInactiveError"
+PASS IDBObjectStore.getAllKeys exception order: TransactionInactiveError vs. DataError 
 PASS IDBObjectStore.count exception order: InvalidStateError vs. TransactionInactiveError 
-FAIL IDBObjectStore.count exception order: TransactionInactiveError vs. DataError assert_throws: "not active" check (TransactionInactiveError) should precede query check (DataError) function "() => { store[method]({}); }" threw object "DataError: Failed to execute 'count' on 'IDBObjectStore': The parameter is not a valid key." that is not a DOMException TransactionInactiveError: property "name" is equal to "DataError", expected "TransactionInactiveError"
+PASS IDBObjectStore.count exception order: TransactionInactiveError vs. DataError 
 PASS IDBObjectStore.openCursor exception order: InvalidStateError vs. TransactionInactiveError 
-FAIL IDBObjectStore.openCursor exception order: TransactionInactiveError vs. DataError assert_throws: "not active" check (TransactionInactiveError) should precede query check (DataError) function "() => { store[method]({}); }" threw object "DataError: Failed to execute 'openCursor' on 'IDBObjectStore': The parameter is not a valid key." that is not a DOMException TransactionInactiveError: property "name" is equal to "DataError", expected "TransactionInactiveError"
+PASS IDBObjectStore.openCursor exception order: TransactionInactiveError vs. DataError 
 PASS IDBObjectStore.openKeyCursor exception order: InvalidStateError vs. TransactionInactiveError 
-FAIL IDBObjectStore.openKeyCursor exception order: TransactionInactiveError vs. DataError assert_throws: "not active" check (TransactionInactiveError) should precede query check (DataError) function "() => { store[method]({}); }" threw object "DataError: Failed to execute 'openKeyCursor' on 'IDBObjectStore': The parameter is not a valid key or key range." that is not a DOMException TransactionInactiveError: property "name" is equal to "DataError", expected "TransactionInactiveError"
+PASS IDBObjectStore.openKeyCursor exception order: TransactionInactiveError vs. DataError 
 
index 26afe39..c5797e8 100644 (file)
@@ -1,3 +1,72 @@
+2019-03-16  Sihui Liu  <sihui_liu@apple.com>
+
+        Layout tests imported/w3c/web-platform-tests/IndexedDB/*-exception-order.html are failing
+        https://bugs.webkit.org/show_bug.cgi?id=195650
+
+        Reviewed by Ryosuke Niwa.
+
+        Fix some exception orders in IDB.
+
+        * Modules/indexeddb/IDBDatabase.cpp:
+        (WebCore::IDBDatabase::createObjectStore):
+        Step 6 of https://www.w3.org/TR/IndexedDB-2/#dom-idbdatabase-createobjectstore.
+
+        (WebCore::IDBDatabase::transaction):
+        Step 1 of https://www.w3.org/TR/IndexedDB-2/#dom-idbdatabase-transaction.
+
+        * Modules/indexeddb/IDBIndex.cpp:
+        (WebCore::IDBIndex::doOpenCursor):
+        (WebCore::IDBIndex::openCursor):
+        Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbindex-opencursor.
+
+        (WebCore::IDBIndex::doOpenKeyCursor):
+        (WebCore::IDBIndex::openKeyCursor):
+        Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbindex-openkeycursor.
+
+        (WebCore::IDBIndex::count):
+        Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbindex-count.
+
+        (WebCore::IDBIndex::doCount):
+        (WebCore::IDBIndex::get):
+        Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbindex-get.
+
+        (WebCore::IDBIndex::doGet):
+        (WebCore::IDBIndex::getKey):
+        Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbindex-getkey.
+
+        (WebCore::IDBIndex::doGetKey):
+        (WebCore::IDBIndex::doGetAll):
+        (WebCore::IDBIndex::getAll):
+        Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbindex-getkey.
+        (WebCore::IDBIndex::doGetAllKeys):
+        (WebCore::IDBIndex::getAllKeys):
+        Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbindex-getallkeys.
+
+        * Modules/indexeddb/IDBIndex.h:
+        * Modules/indexeddb/IDBObjectStore.cpp:
+        (WebCore::IDBObjectStore::doOpenCursor):
+        (WebCore::IDBObjectStore::openCursor):
+        Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-opencursor.
+
+        (WebCore::IDBObjectStore::doOpenKeyCursor):
+        (WebCore::IDBObjectStore::openKeyCursor):
+        Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-openkeycursor.
+
+        (WebCore::IDBObjectStore::deleteFunction):
+        (WebCore::IDBObjectStore::doDelete):
+        (WebCore::IDBObjectStore::count):
+        Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-count.
+
+        (WebCore::IDBObjectStore::doCount):
+        (WebCore::IDBObjectStore::doGetAll):
+        (WebCore::IDBObjectStore::getAll):
+        Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-getall.
+
+        (WebCore::IDBObjectStore::doGetAllKeys):
+        (WebCore::IDBObjectStore::getAllKeys):
+        Step 5 of https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-getallkeys.
+        * Modules/indexeddb/IDBObjectStore.h:
+
 2019-03-16  Ryosuke Niwa  <rniwa@webkit.org>
 
         Reduce the size of Node::deref by eliminating an explicit parentNode check
index b95e63c..21bd26a 100644 (file)
@@ -144,13 +144,13 @@ ExceptionOr<Ref<IDBObjectStore>> IDBDatabase::createObjectStore(const String& na
     if (!m_versionChangeTransaction->isActive())
         return Exception { TransactionInactiveError };
 
-    if (m_info.hasObjectStore(name))
-        return Exception { ConstraintError, "Failed to execute 'createObjectStore' on 'IDBDatabase': An object store with the specified name already exists."_s };
-
     auto& keyPath = parameters.keyPath;
     if (keyPath && !isIDBKeyPathValid(keyPath.value()))
         return Exception { SyntaxError, "Failed to execute 'createObjectStore' on 'IDBDatabase': The keyPath option is not a valid key path."_s };
 
+    if (m_info.hasObjectStore(name))
+        return Exception { ConstraintError, "Failed to execute 'createObjectStore' on 'IDBDatabase': An object store with the specified name already exists."_s };
+
     if (keyPath && parameters.autoIncrement && ((WTF::holds_alternative<String>(keyPath.value()) && WTF::get<String>(keyPath.value()).isEmpty()) || WTF::holds_alternative<Vector<String>>(keyPath.value())))
         return Exception { InvalidAccessError, "Failed to execute 'createObjectStore' on 'IDBDatabase': The autoIncrement option was set but the keyPath option was empty or an array."_s };
 
@@ -167,6 +167,9 @@ ExceptionOr<Ref<IDBTransaction>> IDBDatabase::transaction(StringOrVectorOfString
 
     ASSERT(&originThread() == &Thread::current());
 
+    if (m_versionChangeTransaction && !m_versionChangeTransaction->isFinishedOrFinishing())
+        return Exception { InvalidStateError, "Failed to execute 'transaction' on 'IDBDatabase': A version change transaction is running."_s };
+
     if (m_closePending)
         return Exception { InvalidStateError, "Failed to execute 'transaction' on 'IDBDatabase': The database connection is closing."_s };
 
@@ -176,15 +179,6 @@ ExceptionOr<Ref<IDBTransaction>> IDBDatabase::transaction(StringOrVectorOfString
     else
         objectStores.append(WTFMove(WTF::get<String>(storeNames)));
 
-    if (objectStores.isEmpty())
-        return Exception { InvalidAccessError, "Failed to execute 'transaction' on 'IDBDatabase': The storeNames parameter was empty."_s };
-
-    if (mode != IDBTransactionMode::Readonly && mode != IDBTransactionMode::Readwrite)
-        return Exception { TypeError };
-
-    if (m_versionChangeTransaction && !m_versionChangeTransaction->isFinishedOrFinishing())
-        return Exception { InvalidStateError, "Failed to execute 'transaction' on 'IDBDatabase': A version change transaction is running."_s };
-
     // It is valid for javascript to pass in a list of object store names with the same name listed twice,
     // so we need to put them all in a set to get a unique list.
     HashSet<String> objectStoreSet;
@@ -199,6 +193,12 @@ ExceptionOr<Ref<IDBTransaction>> IDBDatabase::transaction(StringOrVectorOfString
         return Exception { NotFoundError, "Failed to execute 'transaction' on 'IDBDatabase': One of the specified object stores was not found."_s };
     }
 
+    if (objectStores.isEmpty())
+        return Exception { InvalidAccessError, "Failed to execute 'transaction' on 'IDBDatabase': The storeNames parameter was empty."_s };
+
+    if (mode != IDBTransactionMode::Readonly && mode != IDBTransactionMode::Readwrite)
+        return Exception { TypeError };
+
     auto info = IDBTransactionInfo::clientTransaction(m_connectionProxy.get(), objectStores, mode);
 
     LOG(IndexedDBOperations, "IDB creating transaction: %s", info.loggingString().utf8().data());
index 6c09eaf..31781cf 100644 (file)
@@ -148,7 +148,7 @@ void IDBIndex::rollbackInfoForVersionChangeAbort()
     m_deleted = false;
 }
 
-ExceptionOr<Ref<IDBRequest>> IDBIndex::openCursor(ExecState& execState, IDBKeyRange* range, IDBCursorDirection direction)
+ExceptionOr<Ref<IDBRequest>> IDBIndex::doOpenCursor(ExecState& execState, IDBCursorDirection direction, WTF::Function<ExceptionOr<RefPtr<IDBKeyRange>>()>&& function)
 {
     LOG(IndexedDB, "IDBIndex::openCursor");
     ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
@@ -159,7 +159,11 @@ ExceptionOr<Ref<IDBRequest>> IDBIndex::openCursor(ExecState& execState, IDBKeyRa
     if (!m_objectStore.transaction().isActive())
         return Exception { TransactionInactiveError, "Failed to execute 'openCursor' on 'IDBIndex': The transaction is inactive or finished."_s };
 
-    IDBKeyRangeData rangeData = range;
+    auto keyRange = function();
+    if (keyRange.hasException())
+        return keyRange.releaseException();
+
+    IDBKeyRangeData rangeData = keyRange.returnValue() ? keyRange.releaseReturnValue().get() : nullptr;
     if (rangeData.lowerKey.isNull())
         rangeData.lowerKey = IDBKeyData::minimum();
     if (rangeData.upperKey.isNull())
@@ -169,19 +173,25 @@ ExceptionOr<Ref<IDBRequest>> IDBIndex::openCursor(ExecState& execState, IDBKeyRa
     return m_objectStore.transaction().requestOpenCursor(execState, *this, info);
 }
 
-ExceptionOr<Ref<IDBRequest>> IDBIndex::openCursor(ExecState& execState, JSValue key, IDBCursorDirection direction)
+ExceptionOr<Ref<IDBRequest>> IDBIndex::openCursor(ExecState& execState, RefPtr<IDBKeyRange>&& range, IDBCursorDirection direction)
 {
-    LOG(IndexedDB, "IDBIndex::openCursor");
-    ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
+    return doOpenCursor(execState, direction, [range=WTFMove(range)]() {
+        return range;
+    });
+}
 
-    auto keyRange = IDBKeyRange::only(execState, key);
-    if (keyRange.hasException())
-        return Exception { DataError, "Failed to execute 'openCursor' on 'IDBIndex': The parameter is not a valid key."_s };
+ExceptionOr<Ref<IDBRequest>> IDBIndex::openCursor(ExecState& execState, JSValue key, IDBCursorDirection direction)
+{
+    return doOpenCursor(execState, direction, [state=&execState, key]() {
+        auto onlyResult = IDBKeyRange::only(*state, key);
+        if (onlyResult.hasException())
+            return ExceptionOr<RefPtr<IDBKeyRange>>{ Exception(DataError, "Failed to execute 'openCursor' on 'IDBIndex': The parameter is not a valid key."_s) };
 
-    return openCursor(execState, keyRange.releaseReturnValue().ptr(), direction);
+        return ExceptionOr<RefPtr<IDBKeyRange>> { onlyResult.releaseReturnValue() };
+    });
 }
 
-ExceptionOr<Ref<IDBRequest>> IDBIndex::openKeyCursor(ExecState& execState, IDBKeyRange* range, IDBCursorDirection direction)
+ExceptionOr<Ref<IDBRequest>> IDBIndex::doOpenKeyCursor(ExecState& execState, IDBCursorDirection direction, WTF::Function<ExceptionOr<RefPtr<IDBKeyRange>>()>&& function)
 {
     LOG(IndexedDB, "IDBIndex::openKeyCursor");
     ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
@@ -192,18 +202,31 @@ ExceptionOr<Ref<IDBRequest>> IDBIndex::openKeyCursor(ExecState& execState, IDBKe
     if (!m_objectStore.transaction().isActive())
         return Exception { TransactionInactiveError, "Failed to execute 'openKeyCursor' on 'IDBIndex': The transaction is inactive or finished."_s };
 
-    auto info = IDBCursorInfo::indexCursor(m_objectStore.transaction(), m_objectStore.info().identifier(), m_info.identifier(), range, direction, IndexedDB::CursorType::KeyOnly);
+    auto keyRange = function();
+    if (keyRange.hasException())
+        return keyRange.releaseException();
+
+    auto* keyRangePointer = keyRange.returnValue() ? keyRange.releaseReturnValue().get() : nullptr;
+    auto info = IDBCursorInfo::indexCursor(m_objectStore.transaction(), m_objectStore.info().identifier(), m_info.identifier(), keyRangePointer, direction, IndexedDB::CursorType::KeyOnly);
     return m_objectStore.transaction().requestOpenCursor(execState, *this, info);
 }
 
+ExceptionOr<Ref<IDBRequest>> IDBIndex::openKeyCursor(ExecState& execState, RefPtr<IDBKeyRange>&& range, IDBCursorDirection direction)
+{
+    return doOpenKeyCursor(execState, direction, [range=WTFMove(range)]() {
+        return range;
+    });
+}
+
 ExceptionOr<Ref<IDBRequest>> IDBIndex::openKeyCursor(ExecState& execState, JSValue key, IDBCursorDirection direction)
 {
-    LOG(IndexedDB, "IDBIndex::openKeyCursor");
+    return doOpenKeyCursor(execState, direction, [state=&execState, key]() {
+        auto onlyResult = IDBKeyRange::only(*state, key);
+        if (onlyResult.hasException())
+            return ExceptionOr<RefPtr<IDBKeyRange>>{ Exception(DataError, "Failed to execute 'openKeyCursor' on 'IDBIndex': The parameter is not a valid key."_s) };
 
-    auto keyRange = IDBKeyRange::only(execState, key);
-    if (keyRange.hasException())
-        return Exception { DataError, "Failed to execute 'openKeyCursor' on 'IDBIndex': The parameter is not a valid key."_s };
-    return openKeyCursor(execState, keyRange.releaseReturnValue().ptr(), direction);
+        return ExceptionOr<RefPtr<IDBKeyRange>> { onlyResult.releaseReturnValue() };
+    });
 }
 
 ExceptionOr<Ref<IDBRequest>> IDBIndex::count(ExecState& execState, IDBKeyRange* range)
@@ -218,10 +241,9 @@ ExceptionOr<Ref<IDBRequest>> IDBIndex::count(ExecState& execState, JSValue key)
     LOG(IndexedDB, "IDBIndex::count");
 
     auto idbKey = scriptValueToIDBKey(execState, key);
-    if (!idbKey->isValid())
-        return Exception { DataError, "Failed to execute 'count' on 'IDBIndex': The parameter is not a valid key."_s };
+    auto* idbKeyPointer = idbKey->isValid() ? idbKey.ptr() : nullptr;
 
-    return doCount(execState, IDBKeyRangeData(idbKey.ptr()));
+    return doCount(execState, IDBKeyRangeData(idbKeyPointer));
 }
 
 ExceptionOr<Ref<IDBRequest>> IDBIndex::doCount(ExecState& execState, const IDBKeyRangeData& range)
@@ -231,13 +253,13 @@ ExceptionOr<Ref<IDBRequest>> IDBIndex::doCount(ExecState& execState, const IDBKe
     if (m_deleted || m_objectStore.isDeleted())
         return Exception { InvalidStateError, "Failed to execute 'count' on 'IDBIndex': The index or its object store has been deleted."_s };
 
-    if (!range.isValid())
-        return Exception { DataError };
-
     auto& transaction = m_objectStore.transaction();
     if (!transaction.isActive())
         return Exception { TransactionInactiveError, "Failed to execute 'count' on 'IDBIndex': The transaction is inactive or finished."_s };
 
+    if (!range.isValid())
+        return Exception { DataError, "Failed to execute 'count' on 'IDBIndex': The parameter is not a valid key."_s };
+
     return transaction.requestCount(execState, *this, range);
 }
 
@@ -254,26 +276,30 @@ ExceptionOr<Ref<IDBRequest>> IDBIndex::get(ExecState& execState, JSValue key)
 
     auto idbKey = scriptValueToIDBKey(execState, key);
     if (!idbKey->isValid())
-        return Exception { DataError, "Failed to execute 'get' on 'IDBIndex': The parameter is not a valid key."_s };
+        return doGet(execState, Exception(DataError, "Failed to execute 'get' on 'IDBIndex': The parameter is not a valid key."_s));
 
     return doGet(execState, IDBKeyRangeData(idbKey.ptr()));
 }
 
-ExceptionOr<Ref<IDBRequest>> IDBIndex::doGet(ExecState& execState, const IDBKeyRangeData& range)
+ExceptionOr<Ref<IDBRequest>> IDBIndex::doGet(ExecState& execState, ExceptionOr<IDBKeyRangeData> range)
 {
     ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
 
     if (m_deleted || m_objectStore.isDeleted())
         return Exception { InvalidStateError, "Failed to execute 'get' on 'IDBIndex': The index or its object store has been deleted."_s };
 
-    if (range.isNull)
-        return Exception { DataError };
-
     auto& transaction = m_objectStore.transaction();
     if (!transaction.isActive())
         return Exception { TransactionInactiveError, "Failed to execute 'get' on 'IDBIndex': The transaction is inactive or finished."_s };
 
-    return transaction.requestGetValue(execState, *this, range);
+    if (range.hasException())
+        return range.releaseException();
+    auto keyRange = range.releaseReturnValue();
+
+    if (keyRange.isNull)
+        return Exception { DataError };
+
+    return transaction.requestGetValue(execState, *this, keyRange);
 }
 
 ExceptionOr<Ref<IDBRequest>> IDBIndex::getKey(ExecState& execState, IDBKeyRange* range)
@@ -289,29 +315,33 @@ ExceptionOr<Ref<IDBRequest>> IDBIndex::getKey(ExecState& execState, JSValue key)
 
     auto idbKey = scriptValueToIDBKey(execState, key);
     if (!idbKey->isValid())
-        return Exception { DataError, "Failed to execute 'getKey' on 'IDBIndex': The parameter is not a valid key."_s };
+        return doGetKey(execState, Exception(DataError, "Failed to execute 'getKey' on 'IDBIndex': The parameter is not a valid key."_s));
 
     return doGetKey(execState, IDBKeyRangeData(idbKey.ptr()));
 }
 
-ExceptionOr<Ref<IDBRequest>> IDBIndex::doGetKey(ExecState& execState, const IDBKeyRangeData& range)
+ExceptionOr<Ref<IDBRequest>> IDBIndex::doGetKey(ExecState& execState, ExceptionOr<IDBKeyRangeData> range)
 {
     ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
 
     if (m_deleted || m_objectStore.isDeleted())
         return Exception { InvalidStateError, "Failed to execute 'getKey' on 'IDBIndex': The index or its object store has been deleted."_s };
 
-    if (range.isNull)
-        return Exception { DataError };
-
     auto& transaction = m_objectStore.transaction();
     if (!transaction.isActive())
         return Exception { TransactionInactiveError, "Failed to execute 'getKey' on 'IDBIndex': The transaction is inactive or finished."_s };
 
-    return transaction.requestGetKey(execState, *this, range);
+    if (range.hasException())
+        return range.releaseException();
+    auto keyRange = range.releaseReturnValue();
+    
+    if (keyRange.isNull)
+        return Exception { DataError };
+
+    return transaction.requestGetKey(execState, *this, keyRange);
 }
 
-ExceptionOr<Ref<IDBRequest>> IDBIndex::getAll(ExecState& execState, RefPtr<IDBKeyRange> range, Optional<uint32_t> count)
+ExceptionOr<Ref<IDBRequest>> IDBIndex::doGetAll(ExecState& execState, Optional<uint32_t> count, WTF::Function<ExceptionOr<RefPtr<IDBKeyRange>>()>&& function)
 {
     LOG(IndexedDB, "IDBIndex::getAll");
     ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
@@ -322,19 +352,33 @@ ExceptionOr<Ref<IDBRequest>> IDBIndex::getAll(ExecState& execState, RefPtr<IDBKe
     if (!m_objectStore.transaction().isActive())
         return Exception { TransactionInactiveError, "Failed to execute 'getAll' on 'IDBIndex': The transaction is inactive or finished."_s };
 
-    return m_objectStore.transaction().requestGetAllIndexRecords(execState, *this, range.get(), IndexedDB::GetAllType::Values, count);
+    auto keyRange = function();
+    if (keyRange.hasException())
+        return keyRange.releaseException();
+
+    auto* keyRangePointer = keyRange.returnValue() ? keyRange.releaseReturnValue().get() : nullptr;
+    return m_objectStore.transaction().requestGetAllIndexRecords(execState, *this, keyRangePointer, IndexedDB::GetAllType::Values, count);
+}
+
+ExceptionOr<Ref<IDBRequest>> IDBIndex::getAll(ExecState& execState, RefPtr<IDBKeyRange>&& range, Optional<uint32_t> count)
+{
+    return doGetAll(execState, count, [range = WTFMove(range)]() {
+        return range;
+    });
 }
 
 ExceptionOr<Ref<IDBRequest>> IDBIndex::getAll(ExecState& execState, JSValue key, Optional<uint32_t> count)
 {
-    auto onlyResult = IDBKeyRange::only(execState, key);
-    if (onlyResult.hasException())
-        return Exception { DataError, "Failed to execute 'getAll' on 'IDBIndex': The parameter is not a valid key."_s };
+    return doGetAll(execState, count, [state=&execState, key]() {
+        auto onlyResult = IDBKeyRange::only(*state, key);
+        if (onlyResult.hasException())
+            return ExceptionOr<RefPtr<IDBKeyRange>>{ Exception(DataError, "Failed to execute 'getAll' on 'IDBIndex': The parameter is not a valid key."_s) };
 
-    return getAll(execState, onlyResult.releaseReturnValue(), count);
+        return ExceptionOr<RefPtr<IDBKeyRange>> { onlyResult.releaseReturnValue() };
+    });
 }
 
-ExceptionOr<Ref<IDBRequest>> IDBIndex::getAllKeys(ExecState& execState, RefPtr<IDBKeyRange> range, Optional<uint32_t> count)
+ExceptionOr<Ref<IDBRequest>> IDBIndex::doGetAllKeys(ExecState& execState, Optional<uint32_t> count, WTF::Function<ExceptionOr<RefPtr<IDBKeyRange>>()>&& function)
 {
     LOG(IndexedDB, "IDBIndex::getAllKeys");
     ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
@@ -345,16 +389,30 @@ ExceptionOr<Ref<IDBRequest>> IDBIndex::getAllKeys(ExecState& execState, RefPtr<I
     if (!m_objectStore.transaction().isActive())
         return Exception { TransactionInactiveError, "Failed to execute 'getAllKeys' on 'IDBIndex': The transaction is inactive or finished."_s };
 
-    return m_objectStore.transaction().requestGetAllIndexRecords(execState, *this, range.get(), IndexedDB::GetAllType::Keys, count);
+    auto keyRange = function();
+    if (keyRange.hasException())
+        return keyRange.releaseException();
+
+    auto* keyRangePointer = keyRange.returnValue() ? keyRange.releaseReturnValue().get() : nullptr;
+    return m_objectStore.transaction().requestGetAllIndexRecords(execState, *this, keyRangePointer, IndexedDB::GetAllType::Keys, count);
+}
+
+ExceptionOr<Ref<IDBRequest>> IDBIndex::getAllKeys(ExecState& execState, RefPtr<IDBKeyRange>&& range, Optional<uint32_t> count)
+{
+    return doGetAllKeys(execState, count, [range = WTFMove(range)]() {
+        return range;
+    });
 }
 
 ExceptionOr<Ref<IDBRequest>> IDBIndex::getAllKeys(ExecState& execState, JSValue key, Optional<uint32_t> count)
 {
-    auto onlyResult = IDBKeyRange::only(execState, key);
-    if (onlyResult.hasException())
-        return Exception { DataError, "Failed to execute 'getAllKeys' on 'IDBIndex': The parameter is not a valid key."_s };
+    return doGetAllKeys(execState, count, [state=&execState, key]() {
+        auto onlyResult = IDBKeyRange::only(*state, key);
+        if (onlyResult.hasException())
+            return ExceptionOr<RefPtr<IDBKeyRange>>{ Exception(DataError, "Failed to execute 'getAllKeys' on 'IDBIndex': The parameter is not a valid key."_s) };
 
-    return getAllKeys(execState, onlyResult.releaseReturnValue(), count);
+        return ExceptionOr<RefPtr<IDBKeyRange>> { onlyResult.releaseReturnValue() };
+    });
 }
 
 void IDBIndex::markAsDeleted()
index ff8dbf9..553a429 100644 (file)
@@ -58,9 +58,9 @@ public:
 
     void rollbackInfoForVersionChangeAbort();
 
-    ExceptionOr<Ref<IDBRequest>> openCursor(JSC::ExecState&, IDBKeyRange*, IDBCursorDirection);
+    ExceptionOr<Ref<IDBRequest>> openCursor(JSC::ExecState&, RefPtr<IDBKeyRange>&&, IDBCursorDirection);
     ExceptionOr<Ref<IDBRequest>> openCursor(JSC::ExecState&, JSC::JSValue key, IDBCursorDirection);
-    ExceptionOr<Ref<IDBRequest>> openKeyCursor(JSC::ExecState&, IDBKeyRange*, IDBCursorDirection);
+    ExceptionOr<Ref<IDBRequest>> openKeyCursor(JSC::ExecState&, RefPtr<IDBKeyRange>&&, IDBCursorDirection);
     ExceptionOr<Ref<IDBRequest>> openKeyCursor(JSC::ExecState&, JSC::JSValue key, IDBCursorDirection);
 
     ExceptionOr<Ref<IDBRequest>> count(JSC::ExecState&, IDBKeyRange*);
@@ -71,9 +71,9 @@ public:
     ExceptionOr<Ref<IDBRequest>> getKey(JSC::ExecState&, IDBKeyRange*);
     ExceptionOr<Ref<IDBRequest>> getKey(JSC::ExecState&, JSC::JSValue key);
 
-    ExceptionOr<Ref<IDBRequest>> getAll(JSC::ExecState&, RefPtr<IDBKeyRange>, Optional<uint32_t> count);
+    ExceptionOr<Ref<IDBRequest>> getAll(JSC::ExecState&, RefPtr<IDBKeyRange>&&, Optional<uint32_t> count);
     ExceptionOr<Ref<IDBRequest>> getAll(JSC::ExecState&, JSC::JSValue key, Optional<uint32_t> count);
-    ExceptionOr<Ref<IDBRequest>> getAllKeys(JSC::ExecState&, RefPtr<IDBKeyRange>, Optional<uint32_t> count);
+    ExceptionOr<Ref<IDBRequest>> getAllKeys(JSC::ExecState&, RefPtr<IDBKeyRange>&&, Optional<uint32_t> count);
     ExceptionOr<Ref<IDBRequest>> getAllKeys(JSC::ExecState&, JSC::JSValue key, Optional<uint32_t> count);
 
     const IDBIndexInfo& info() const { return m_info; }
@@ -88,8 +88,12 @@ public:
 
 private:
     ExceptionOr<Ref<IDBRequest>> doCount(JSC::ExecState&, const IDBKeyRangeData&);
-    ExceptionOr<Ref<IDBRequest>> doGet(JSC::ExecState&, const IDBKeyRangeData&);
-    ExceptionOr<Ref<IDBRequest>> doGetKey(JSC::ExecState&, const IDBKeyRangeData&);
+    ExceptionOr<Ref<IDBRequest>> doGet(JSC::ExecState&, ExceptionOr<IDBKeyRangeData>);
+    ExceptionOr<Ref<IDBRequest>> doGetKey(JSC::ExecState&, ExceptionOr<IDBKeyRangeData>);
+    ExceptionOr<Ref<IDBRequest>> doOpenCursor(JSC::ExecState&, IDBCursorDirection, WTF::Function<ExceptionOr<RefPtr<IDBKeyRange>>()> &&);
+    ExceptionOr<Ref<IDBRequest>> doOpenKeyCursor(JSC::ExecState&, IDBCursorDirection, WTF::Function<ExceptionOr<RefPtr<IDBKeyRange>>()> &&);
+    ExceptionOr<Ref<IDBRequest>> doGetAll(JSC::ExecState&, Optional<uint32_t> count, WTF::Function<ExceptionOr<RefPtr<IDBKeyRange>>()> &&);
+    ExceptionOr<Ref<IDBRequest>> doGetAllKeys(JSC::ExecState&, Optional<uint32_t> count, WTF::Function<ExceptionOr<RefPtr<IDBKeyRange>>()> &&);
 
     const char* activeDOMObjectName() const final;
     bool canSuspendForDocumentSuspension() const final;
index 8b3ce23..642c18e 100644 (file)
@@ -85,7 +85,7 @@ public:
                 sizeEstimate += key->m_sizeEstimate;
             }
         }
-        Ref<IDBKey> idbKey = adoptRef(*new IDBKey(result, sizeEstimate));
+        auto idbKey = adoptRef(*new IDBKey(result, sizeEstimate));
         ASSERT(idbKey->isValid());
         return idbKey;
     }
index c175dee..fe198a2 100644 (file)
@@ -149,7 +149,7 @@ bool IDBObjectStore::autoIncrement() const
     return m_info.autoIncrement();
 }
 
-ExceptionOr<Ref<IDBRequest>> IDBObjectStore::openCursor(ExecState& execState, RefPtr<IDBKeyRange> range, IDBCursorDirection direction)
+ExceptionOr<Ref<IDBRequest>> IDBObjectStore::doOpenCursor(ExecState& execState, IDBCursorDirection direction, WTF::Function<ExceptionOr<RefPtr<IDBKeyRange>>()>&& function)
 {
     LOG(IndexedDB, "IDBObjectStore::openCursor");
     ASSERT(&m_transaction.database().originThread() == &Thread::current());
@@ -160,22 +160,36 @@ ExceptionOr<Ref<IDBRequest>> IDBObjectStore::openCursor(ExecState& execState, Re
     if (!m_transaction.isActive())
         return Exception { TransactionInactiveError, "Failed to execute 'openCursor' on 'IDBObjectStore': The transaction is inactive or finished."_s };
 
-    auto info = IDBCursorInfo::objectStoreCursor(m_transaction, m_info.identifier(), range.get(), direction, IndexedDB::CursorType::KeyAndValue);
+    auto keyRange = function();
+    if (keyRange.hasException())
+        return keyRange.releaseException();
+    auto* keyRangePointer = keyRange.returnValue() ? keyRange.releaseReturnValue().get() : nullptr;
+
+    auto info = IDBCursorInfo::objectStoreCursor(m_transaction, m_info.identifier(), keyRangePointer, direction, IndexedDB::CursorType::KeyAndValue);
     return m_transaction.requestOpenCursor(execState, *this, info);
 }
 
+ExceptionOr<Ref<IDBRequest>> IDBObjectStore::openCursor(ExecState& execState, RefPtr<IDBKeyRange>&& range, IDBCursorDirection direction)
+{
+    return doOpenCursor(execState, direction, [range = WTFMove(range)]() {
+        return range;
+    });
+}
+
 ExceptionOr<Ref<IDBRequest>> IDBObjectStore::openCursor(ExecState& execState, JSValue key, IDBCursorDirection direction)
 {
-    auto onlyResult = IDBKeyRange::only(execState, key);
-    if (onlyResult.hasException())
-        return Exception { DataError, "Failed to execute 'openCursor' on 'IDBObjectStore': The parameter is not a valid key."_s };
+    return doOpenCursor(execState, direction, [state=&execState, key]() {
+        auto onlyResult = IDBKeyRange::only(*state, key);
+        if (onlyResult.hasException())
+            return ExceptionOr<RefPtr<IDBKeyRange>>{ Exception(DataError, "Failed to execute 'openCursor' on 'IDBObjectStore': The parameter is not a valid key."_s) };
 
-    return openCursor(execState, onlyResult.releaseReturnValue(), direction);
+        return ExceptionOr<RefPtr<IDBKeyRange>> { onlyResult.releaseReturnValue() };
+    });
 }
 
-ExceptionOr<Ref<IDBRequest>> IDBObjectStore::openKeyCursor(ExecState& execState, RefPtr<IDBKeyRange> range, IDBCursorDirection direction)
+ExceptionOr<Ref<IDBRequest>> IDBObjectStore::doOpenKeyCursor(ExecState& execState, IDBCursorDirection direction, WTF::Function<ExceptionOr<RefPtr<IDBKeyRange>>()>&& function)
 {
-    LOG(IndexedDB, "IDBObjectStore::openCursor");
+    LOG(IndexedDB, "IDBObjectStore::openKeyCursor");
     ASSERT(&m_transaction.database().originThread() == &Thread::current());
 
     if (m_deleted)
@@ -184,17 +198,31 @@ ExceptionOr<Ref<IDBRequest>> IDBObjectStore::openKeyCursor(ExecState& execState,
     if (!m_transaction.isActive())
         return Exception { TransactionInactiveError, "Failed to execute 'openKeyCursor' on 'IDBObjectStore': The transaction is inactive or finished."_s };
 
-    auto info = IDBCursorInfo::objectStoreCursor(m_transaction, m_info.identifier(), range.get(), direction, IndexedDB::CursorType::KeyOnly);
+    auto keyRange = function();
+    if (keyRange.hasException())
+        return keyRange.releaseException();
+
+    auto* keyRangePointer = keyRange.returnValue() ? keyRange.releaseReturnValue().get() : nullptr;
+    auto info = IDBCursorInfo::objectStoreCursor(m_transaction, m_info.identifier(), keyRangePointer, direction, IndexedDB::CursorType::KeyOnly);
     return m_transaction.requestOpenCursor(execState, *this, info);
 }
 
+ExceptionOr<Ref<IDBRequest>> IDBObjectStore::openKeyCursor(ExecState& execState, RefPtr<IDBKeyRange>&& range, IDBCursorDirection direction)
+{
+    return doOpenKeyCursor(execState, direction, [range = WTFMove(range)]() {
+        return range;
+    });
+}
+
 ExceptionOr<Ref<IDBRequest>> IDBObjectStore::openKeyCursor(ExecState& execState, JSValue key, IDBCursorDirection direction)
 {
-    auto onlyResult = IDBKeyRange::only(execState, key);
-    if (onlyResult.hasException())
-        return Exception { DataError, "Failed to execute 'openKeyCursor' on 'IDBObjectStore': The parameter is not a valid key or key range."_s };
+    return doOpenCursor(execState, direction, [state=&execState, key]() {
+        auto onlyResult = IDBKeyRange::only(*state, key);
+        if (onlyResult.hasException())
+            return ExceptionOr<RefPtr<IDBKeyRange>>{ Exception(DataError, "Failed to execute 'openKeyCursor' on 'IDBObjectStore': The parameter is not a valid key."_s) };
 
-    return openKeyCursor(execState, onlyResult.releaseReturnValue(), direction);
+        return ExceptionOr<RefPtr<IDBKeyRange>> { onlyResult.releaseReturnValue() };
+    });
 }
 
 ExceptionOr<Ref<IDBRequest>> IDBObjectStore::get(ExecState& execState, JSValue key)
@@ -362,10 +390,12 @@ ExceptionOr<Ref<IDBRequest>> IDBObjectStore::putOrAdd(ExecState& state, JSValue
 
 ExceptionOr<Ref<IDBRequest>> IDBObjectStore::deleteFunction(ExecState& execState, IDBKeyRange* keyRange)
 {
-    return doDelete(execState, keyRange);
+    return doDelete(execState, [keyRange]() {
+        return makeRefPtr(keyRange);
+    });
 }
 
-ExceptionOr<Ref<IDBRequest>> IDBObjectStore::doDelete(ExecState& execState, IDBKeyRange* keyRange)
+ExceptionOr<Ref<IDBRequest>> IDBObjectStore::doDelete(ExecState& execState, WTF::Function<ExceptionOr<RefPtr<IDBKeyRange>>()>&& function)
 {
     LOG(IndexedDB, "IDBObjectStore::deleteFunction");
     ASSERT(&m_transaction.database().originThread() == &Thread::current());
@@ -384,7 +414,11 @@ ExceptionOr<Ref<IDBRequest>> IDBObjectStore::doDelete(ExecState& execState, IDBK
     if (m_transaction.isReadOnly())
         return Exception { ReadonlyError, "Failed to execute 'delete' on 'IDBObjectStore': The transaction is read-only."_s };
 
-    IDBKeyRangeData keyRangeData(keyRange);
+    auto keyRange = function();
+    if (keyRange.hasException())
+        return keyRange.releaseException();
+
+    IDBKeyRangeData keyRangeData = keyRange.returnValue() ? keyRange.releaseReturnValue().get() : nullptr;
     if (!keyRangeData.isValid())
         return Exception { DataError, "Failed to execute 'delete' on 'IDBObjectStore': The parameter is not a valid key range."_s };
 
@@ -393,10 +427,12 @@ ExceptionOr<Ref<IDBRequest>> IDBObjectStore::doDelete(ExecState& execState, IDBK
 
 ExceptionOr<Ref<IDBRequest>> IDBObjectStore::deleteFunction(ExecState& execState, JSValue key)
 {
-    Ref<IDBKey> idbKey = scriptValueToIDBKey(execState, key);
-    if (!idbKey->isValid())
-        return Exception { DataError, "Failed to execute 'delete' on 'IDBObjectStore': The parameter is not a valid key."_s };
-    return doDelete(execState, IDBKeyRange::create(WTFMove(idbKey)).ptr());
+    return doDelete(execState, [state=&execState, key]() {
+        auto idbKey = scriptValueToIDBKey(*state, key);
+        if (!idbKey->isValid())
+            return ExceptionOr<RefPtr<IDBKeyRange>>{ Exception(DataError, "Failed to execute 'delete' on 'IDBObjectStore': The parameter is not a valid key."_s) };
+        return ExceptionOr<RefPtr<IDBKeyRange>> { (IDBKeyRange::create(WTFMove(idbKey))).ptr() };
+    });
 }
 
 ExceptionOr<Ref<IDBRequest>> IDBObjectStore::clear(ExecState& execState)
@@ -535,11 +571,9 @@ ExceptionOr<Ref<IDBRequest>> IDBObjectStore::count(ExecState& execState, JSValue
 {
     LOG(IndexedDB, "IDBObjectStore::count");
 
-    Ref<IDBKey> idbKey = scriptValueToIDBKey(execState, key);
-    if (!idbKey->isValid())
-        return Exception { DataError, "Failed to execute 'count' on 'IDBObjectStore': The parameter is not a valid key."_s };
+    auto idbKey = scriptValueToIDBKey(execState, key);
 
-    return doCount(execState, IDBKeyRangeData(idbKey.ptr()));
+    return doCount(execState, IDBKeyRangeData(idbKey->isValid() ? idbKey.ptr() : nullptr));
 }
 
 ExceptionOr<Ref<IDBRequest>> IDBObjectStore::count(ExecState& execState, IDBKeyRange* range)
@@ -565,12 +599,12 @@ ExceptionOr<Ref<IDBRequest>> IDBObjectStore::doCount(ExecState& execState, const
         return Exception { TransactionInactiveError, "Failed to execute 'count' on 'IDBObjectStore': The transaction is inactive or finished."_s };
 
     if (!range.isValid())
-        return Exception { DataError };
+        return Exception { DataError, "Failed to execute 'count' on 'IDBObjectStore': The parameter is not a valid key."_s };
 
     return m_transaction.requestCount(execState, *this, range);
 }
 
-ExceptionOr<Ref<IDBRequest>> IDBObjectStore::getAll(ExecState& execState, RefPtr<IDBKeyRange> range, Optional<uint32_t> count)
+ExceptionOr<Ref<IDBRequest>> IDBObjectStore::doGetAll(ExecState& execState, Optional<uint32_t> count, WTF::Function<ExceptionOr<RefPtr<IDBKeyRange>>()>&& function)
 {
     LOG(IndexedDB, "IDBObjectStore::getAll");
     ASSERT(&m_transaction.database().originThread() == &Thread::current());
@@ -581,19 +615,33 @@ ExceptionOr<Ref<IDBRequest>> IDBObjectStore::getAll(ExecState& execState, RefPtr
     if (!m_transaction.isActive())
         return Exception { TransactionInactiveError, "Failed to execute 'getAll' on 'IDBObjectStore': The transaction is inactive or finished."_s };
 
-    return m_transaction.requestGetAllObjectStoreRecords(execState, *this, range.get(), IndexedDB::GetAllType::Values, count);
+    auto keyRange = function();
+    if (keyRange.hasException())
+        return keyRange.releaseException();
+
+    auto* keyRangePointer = keyRange.returnValue() ? keyRange.releaseReturnValue().get() : nullptr;
+    return m_transaction.requestGetAllObjectStoreRecords(execState, *this, keyRangePointer, IndexedDB::GetAllType::Values, count);
+}
+
+ExceptionOr<Ref<IDBRequest>> IDBObjectStore::getAll(ExecState& execState, RefPtr<IDBKeyRange>&& range, Optional<uint32_t> count)
+{
+    return doGetAll(execState, count, [range = WTFMove(range)]() {
+        return range;
+    });
 }
 
 ExceptionOr<Ref<IDBRequest>> IDBObjectStore::getAll(ExecState& execState, JSValue key, Optional<uint32_t> count)
 {
-    auto onlyResult = IDBKeyRange::only(execState, key);
-    if (onlyResult.hasException())
-        return Exception { DataError, "Failed to execute 'getAll' on 'IDBObjectStore': The parameter is not a valid key."_s };
+    return doGetAll(execState, count, [state=&execState, key]() {
+        auto onlyResult = IDBKeyRange::only(*state, key);
+        if (onlyResult.hasException())
+            return ExceptionOr<RefPtr<IDBKeyRange>>{ Exception(DataError, "Failed to execute 'getAll' on 'IDBObjectStore': The parameter is not a valid key."_s) };
 
-    return getAll(execState, onlyResult.releaseReturnValue(), count);
+        return ExceptionOr<RefPtr<IDBKeyRange>> { onlyResult.releaseReturnValue() };
+    });
 }
 
-ExceptionOr<Ref<IDBRequest>> IDBObjectStore::getAllKeys(ExecState& execState, RefPtr<IDBKeyRange> range, Optional<uint32_t> count)
+ExceptionOr<Ref<IDBRequest>> IDBObjectStore::doGetAllKeys(ExecState& execState, Optional<uint32_t> count, WTF::Function<ExceptionOr<RefPtr<IDBKeyRange>>()>&& function)
 {
     LOG(IndexedDB, "IDBObjectStore::getAllKeys");
     ASSERT(&m_transaction.database().originThread() == &Thread::current());
@@ -604,16 +652,30 @@ ExceptionOr<Ref<IDBRequest>> IDBObjectStore::getAllKeys(ExecState& execState, Re
     if (!m_transaction.isActive())
         return Exception { TransactionInactiveError, "Failed to execute 'getAllKeys' on 'IDBObjectStore': The transaction is inactive or finished."_s };
 
-    return m_transaction.requestGetAllObjectStoreRecords(execState, *this, range.get(), IndexedDB::GetAllType::Keys, count);
+    auto keyRange = function();
+    if (keyRange.hasException())
+        return keyRange.releaseException();
+
+    auto* keyRangePointer = keyRange.returnValue() ? keyRange.releaseReturnValue().get() : nullptr;
+    return m_transaction.requestGetAllObjectStoreRecords(execState, *this, keyRangePointer, IndexedDB::GetAllType::Keys, count);
+}
+
+ExceptionOr<Ref<IDBRequest>> IDBObjectStore::getAllKeys(ExecState& execState, RefPtr<IDBKeyRange>&& range, Optional<uint32_t> count)
+{
+    return doGetAllKeys(execState, count, [range = WTFMove(range)]() {
+        return range;
+    });
 }
 
 ExceptionOr<Ref<IDBRequest>> IDBObjectStore::getAllKeys(ExecState& execState, JSValue key, Optional<uint32_t> count)
 {
-    auto onlyResult = IDBKeyRange::only(execState, key);
-    if (onlyResult.hasException())
-        return Exception { DataError, "Failed to execute 'getAllKeys' on 'IDBObjectStore': The parameter is not a valid key."_s };
+    return doGetAllKeys(execState, count, [state=&execState, key]() {
+        auto onlyResult = IDBKeyRange::only(*state, key);
+        if (onlyResult.hasException())
+            return ExceptionOr<RefPtr<IDBKeyRange>>{ Exception(DataError, "Failed to execute 'getAllKeys' on 'IDBObjectStore': The parameter is not a valid key."_s) };
 
-    return getAllKeys(execState, onlyResult.releaseReturnValue(), count);
+        return ExceptionOr<RefPtr<IDBKeyRange>> { onlyResult.releaseReturnValue() };
+    });
 }
 
 void IDBObjectStore::markAsDeleted()
index ddf768f..29f9591 100644 (file)
@@ -73,9 +73,9 @@ public:
         bool multiEntry;
     };
 
-    ExceptionOr<Ref<IDBRequest>> openCursor(JSC::ExecState&, RefPtr<IDBKeyRange>, IDBCursorDirection);
+    ExceptionOr<Ref<IDBRequest>> openCursor(JSC::ExecState&, RefPtr<IDBKeyRange>&&, IDBCursorDirection);
     ExceptionOr<Ref<IDBRequest>> openCursor(JSC::ExecState&, JSC::JSValue key, IDBCursorDirection);
-    ExceptionOr<Ref<IDBRequest>> openKeyCursor(JSC::ExecState&, RefPtr<IDBKeyRange>, IDBCursorDirection);
+    ExceptionOr<Ref<IDBRequest>> openKeyCursor(JSC::ExecState&, RefPtr<IDBKeyRange>&&, IDBCursorDirection);
     ExceptionOr<Ref<IDBRequest>> openKeyCursor(JSC::ExecState&, JSC::JSValue key, IDBCursorDirection);
     ExceptionOr<Ref<IDBRequest>> get(JSC::ExecState&, JSC::JSValue key);
     ExceptionOr<Ref<IDBRequest>> get(JSC::ExecState&, IDBKeyRange*);
@@ -91,9 +91,9 @@ public:
     ExceptionOr<void> deleteIndex(const String& name);
     ExceptionOr<Ref<IDBRequest>> count(JSC::ExecState&, IDBKeyRange*);
     ExceptionOr<Ref<IDBRequest>> count(JSC::ExecState&, JSC::JSValue key);
-    ExceptionOr<Ref<IDBRequest>> getAll(JSC::ExecState&, RefPtr<IDBKeyRange>, Optional<uint32_t> count);
+    ExceptionOr<Ref<IDBRequest>> getAll(JSC::ExecState&, RefPtr<IDBKeyRange>&&, Optional<uint32_t> count);
     ExceptionOr<Ref<IDBRequest>> getAll(JSC::ExecState&, JSC::JSValue key, Optional<uint32_t> count);
-    ExceptionOr<Ref<IDBRequest>> getAllKeys(JSC::ExecState&, RefPtr<IDBKeyRange>, Optional<uint32_t> count);
+    ExceptionOr<Ref<IDBRequest>> getAllKeys(JSC::ExecState&, RefPtr<IDBKeyRange>&&, Optional<uint32_t> count);
     ExceptionOr<Ref<IDBRequest>> getAllKeys(JSC::ExecState&, JSC::JSValue key, Optional<uint32_t> count);
 
     ExceptionOr<Ref<IDBRequest>> putForCursorUpdate(JSC::ExecState&, JSC::JSValue, RefPtr<IDBKey>);
@@ -115,7 +115,11 @@ private:
     enum class InlineKeyCheck { Perform, DoNotPerform };
     ExceptionOr<Ref<IDBRequest>> putOrAdd(JSC::ExecState&, JSC::JSValue, RefPtr<IDBKey>, IndexedDB::ObjectStoreOverwriteMode, InlineKeyCheck);
     ExceptionOr<Ref<IDBRequest>> doCount(JSC::ExecState&, const IDBKeyRangeData&);
-    ExceptionOr<Ref<IDBRequest>> doDelete(JSC::ExecState&, IDBKeyRange*);
+    ExceptionOr<Ref<IDBRequest>> doDelete(JSC::ExecState&, WTF::Function<ExceptionOr<RefPtr<IDBKeyRange>>()> &&);
+    ExceptionOr<Ref<IDBRequest>> doOpenCursor(JSC::ExecState&, IDBCursorDirection, WTF::Function<ExceptionOr<RefPtr<IDBKeyRange>>()>&&);
+    ExceptionOr<Ref<IDBRequest>> doOpenKeyCursor(JSC::ExecState&, IDBCursorDirection, WTF::Function<ExceptionOr<RefPtr<IDBKeyRange>>()>&&);
+    ExceptionOr<Ref<IDBRequest>> doGetAll(JSC::ExecState&, Optional<uint32_t> count, WTF::Function<ExceptionOr<RefPtr<IDBKeyRange>>()> &&);
+    ExceptionOr<Ref<IDBRequest>> doGetAllKeys(JSC::ExecState&, Optional<uint32_t> count, WTF::Function<ExceptionOr<RefPtr<IDBKeyRange>>()> &&);
 
     const char* activeDOMObjectName() const final;
     bool canSuspendForDocumentSuspension() const final;