IndexedDB 2.0: Implement IDBObjectStore.getKey().
authorbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 1 Dec 2016 21:33:17 +0000 (21:33 +0000)
committerbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 1 Dec 2016 21:33:17 +0000 (21:33 +0000)
https://bugs.webkit.org/show_bug.cgi?id=165256

Reviewed by Alex Christensen.

Source/WebCore:

Tests: storage/indexeddb/modern/idbobjectstore-getkey-1-private.html
       storage/indexeddb/modern/idbobjectstore-getkey-1.html

* Modules/indexeddb/IDBObjectStore.cpp:
(WebCore::IDBObjectStore::get):
(WebCore::IDBObjectStore::getKey):
* Modules/indexeddb/IDBObjectStore.h:
* Modules/indexeddb/IDBObjectStore.idl:

* Modules/indexeddb/IDBRequest.cpp:
(WebCore::IDBRequest::createObjectStoreGet):
(WebCore::IDBRequest::IDBRequest):
(WebCore::IDBRequest::requestedObjectStoreRecordType):
* Modules/indexeddb/IDBRequest.h:

* Modules/indexeddb/IDBTransaction.cpp:
(WebCore::IDBTransaction::requestGetRecord):
(WebCore::IDBTransaction::requestIndexRecord):
(WebCore::IDBTransaction::didGetRecordOnServer):

* Modules/indexeddb/IndexedDB.h:

* Modules/indexeddb/server/IDBBackingStore.h:

* Modules/indexeddb/server/MemoryIDBBackingStore.cpp:
(WebCore::IDBServer::MemoryIDBBackingStore::getRecord):
* Modules/indexeddb/server/MemoryIDBBackingStore.h:

* Modules/indexeddb/server/MemoryObjectStore.h:

* Modules/indexeddb/server/SQLiteIDBBackingStore.cpp:
(WebCore::IDBServer::SQLiteIDBBackingStore::getRecord):
* Modules/indexeddb/server/SQLiteIDBBackingStore.h:

* Modules/indexeddb/server/UniqueIDBDatabase.cpp:
(WebCore::IDBServer::UniqueIDBDatabase::getRecord):
(WebCore::IDBServer::UniqueIDBDatabase::performGetRecord):
* Modules/indexeddb/server/UniqueIDBDatabase.h:

* Modules/indexeddb/shared/IDBGetRecordData.cpp:
(WebCore::IDBGetRecordData::isolatedCopy):
* Modules/indexeddb/shared/IDBGetRecordData.h:
(WebCore::IDBGetRecordData::encode):
(WebCore::IDBGetRecordData::decode):

LayoutTests:

* storage/indexeddb/modern/idbobjectstore-getkey-1-expected.txt: Added.
* storage/indexeddb/modern/idbobjectstore-getkey-1-private-expected.txt: Added.
* storage/indexeddb/modern/idbobjectstore-getkey-1-private.html: Added.
* storage/indexeddb/modern/idbobjectstore-getkey-1.html: Added.
* storage/indexeddb/modern/resources/idbobjectstore-getkey-1.js: Added.

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

24 files changed:
LayoutTests/ChangeLog
LayoutTests/storage/indexeddb/modern/idbobjectstore-getkey-1-expected.txt [new file with mode: 0644]
LayoutTests/storage/indexeddb/modern/idbobjectstore-getkey-1-private-expected.txt [new file with mode: 0644]
LayoutTests/storage/indexeddb/modern/idbobjectstore-getkey-1-private.html [new file with mode: 0644]
LayoutTests/storage/indexeddb/modern/idbobjectstore-getkey-1.html [new file with mode: 0644]
LayoutTests/storage/indexeddb/modern/resources/idbobjectstore-getkey-1.js [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/Modules/indexeddb/IDBObjectStore.cpp
Source/WebCore/Modules/indexeddb/IDBObjectStore.h
Source/WebCore/Modules/indexeddb/IDBObjectStore.idl
Source/WebCore/Modules/indexeddb/IDBRequest.cpp
Source/WebCore/Modules/indexeddb/IDBRequest.h
Source/WebCore/Modules/indexeddb/IDBTransaction.cpp
Source/WebCore/Modules/indexeddb/IndexedDB.h
Source/WebCore/Modules/indexeddb/server/IDBBackingStore.h
Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.cpp
Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.h
Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.h
Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp
Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.h
Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp
Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h
Source/WebCore/Modules/indexeddb/shared/IDBGetRecordData.cpp
Source/WebCore/Modules/indexeddb/shared/IDBGetRecordData.h

index a5d3199..725de3b 100644 (file)
@@ -1,3 +1,16 @@
+2016-12-01  Brady Eidson  <beidson@apple.com>
+
+        IndexedDB 2.0: Implement IDBObjectStore.getKey().
+        https://bugs.webkit.org/show_bug.cgi?id=165256
+
+        Reviewed by Alex Christensen.
+
+        * storage/indexeddb/modern/idbobjectstore-getkey-1-expected.txt: Added.
+        * storage/indexeddb/modern/idbobjectstore-getkey-1-private-expected.txt: Added.
+        * storage/indexeddb/modern/idbobjectstore-getkey-1-private.html: Added.
+        * storage/indexeddb/modern/idbobjectstore-getkey-1.html: Added.
+        * storage/indexeddb/modern/resources/idbobjectstore-getkey-1.js: Added.
+
 2016-12-01  Antoine Quint  <graouts@apple.com>
 
         [Modern Media Controls] Turn off text selection
diff --git a/LayoutTests/storage/indexeddb/modern/idbobjectstore-getkey-1-expected.txt b/LayoutTests/storage/indexeddb/modern/idbobjectstore-getkey-1-expected.txt
new file mode 100644 (file)
index 0000000..346d7b6
--- /dev/null
@@ -0,0 +1,20 @@
+Test IDBObjectStore.getKey()
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+indexedDB = self.indexedDB || self.webkitIndexedDB || self.mozIndexedDB || self.msIndexedDB || self.OIndexedDB;
+
+indexedDB.deleteDatabase(dbname)
+indexedDB.open(dbname)
+Initial upgrade needed: Old version - 0 New version - 1
+getKey(6) result is: undefined
+getKey(3) result is: 3
+getKey(IDBKeyRange.only(5)) result is: 5
+getKey(IDBKeyRange.lowerBound(2)) result is: 2
+getKey(IDBKeyRange.upperBound(2)) result is: 1
+getKey(IDBKeyRange.bound(2, 4)) result is: 2
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/storage/indexeddb/modern/idbobjectstore-getkey-1-private-expected.txt b/LayoutTests/storage/indexeddb/modern/idbobjectstore-getkey-1-private-expected.txt
new file mode 100644 (file)
index 0000000..346d7b6
--- /dev/null
@@ -0,0 +1,20 @@
+Test IDBObjectStore.getKey()
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+indexedDB = self.indexedDB || self.webkitIndexedDB || self.mozIndexedDB || self.msIndexedDB || self.OIndexedDB;
+
+indexedDB.deleteDatabase(dbname)
+indexedDB.open(dbname)
+Initial upgrade needed: Old version - 0 New version - 1
+getKey(6) result is: undefined
+getKey(3) result is: 3
+getKey(IDBKeyRange.only(5)) result is: 5
+getKey(IDBKeyRange.lowerBound(2)) result is: 2
+getKey(IDBKeyRange.upperBound(2)) result is: 1
+getKey(IDBKeyRange.bound(2, 4)) result is: 2
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/storage/indexeddb/modern/idbobjectstore-getkey-1-private.html b/LayoutTests/storage/indexeddb/modern/idbobjectstore-getkey-1-private.html
new file mode 100644 (file)
index 0000000..d8d5890
--- /dev/null
@@ -0,0 +1,13 @@
+<html>
+<head>
+<script>
+enablePrivateBrowsing = true;
+</script>
+<script src="../../../resources/js-test.js"></script>
+<script src="../resources/shared.js"></script>
+</head>
+<body>
+
+<script src="resources/idbobjectstore-getkey-1.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/storage/indexeddb/modern/idbobjectstore-getkey-1.html b/LayoutTests/storage/indexeddb/modern/idbobjectstore-getkey-1.html
new file mode 100644 (file)
index 0000000..e636ed2
--- /dev/null
@@ -0,0 +1,10 @@
+<html>
+<head>
+<script src="../../../resources/js-test.js"></script>
+<script src="../resources/shared.js"></script>
+</head>
+<body>
+
+<script src="resources/idbobjectstore-getkey-1.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/storage/indexeddb/modern/resources/idbobjectstore-getkey-1.js b/LayoutTests/storage/indexeddb/modern/resources/idbobjectstore-getkey-1.js
new file mode 100644 (file)
index 0000000..b1d7190
--- /dev/null
@@ -0,0 +1,90 @@
+description("Test IDBObjectStore.getKey()");
+
+indexedDBTest(prepareDatabase);
+
+function done()
+{
+    finishJSTest();
+}
+
+function log(message)
+{
+    debug(message);
+}
+
+var testGenerator;
+
+function continueWithEvent(event)
+{
+    testGenerator.next(event);
+}
+
+function asyncContinue()
+{
+    setTimeout("testGenerator.next();", 0);
+}
+
+function idbRequest(request)
+{
+    request.onerror = continueWithEvent;
+    request.onsuccess = continueWithEvent;
+       return request;
+}
+
+var db;
+
+function prepareDatabase(event)
+{
+    debug("Initial upgrade needed: Old version - " + event.oldVersion + " New version - " + event.newVersion);
+
+    db = event.target.result;
+    os = db.createObjectStore("foo");
+       os.add(false, 1);
+       os.add(-10, 2);
+       os.add(10, 3);
+       os.add("hello", 4);
+       os.add("hellothere", 5);
+
+    event.target.transaction.oncomplete = function() {
+        testGenerator = testSteps();
+        testGenerator.next();
+    };
+}
+
+function* testSteps()
+{
+    objectStore = db.transaction("foo").objectStore("foo");
+       
+       // Non-existent key
+    req = idbRequest(objectStore.getKey(6));
+    event = yield;    
+       debug("getKey(6) result is: " + req.result);
+
+       // Existent key
+    req = idbRequest(objectStore.getKey(3));
+    event = yield;    
+       debug("getKey(3) result is: " + req.result);
+       
+       // Key range only
+    req = idbRequest(objectStore.getKey(IDBKeyRange.only(5)));
+    event = yield;    
+       debug("getKey(IDBKeyRange.only(5)) result is: " + req.result);
+
+       // Key range lower bound
+    req = idbRequest(objectStore.getKey(IDBKeyRange.lowerBound(2)));
+    event = yield;    
+       debug("getKey(IDBKeyRange.lowerBound(2)) result is: " + req.result);
+
+       // Key range upper bound
+    req = idbRequest(objectStore.getKey(IDBKeyRange.upperBound(2)));
+    event = yield;    
+       debug("getKey(IDBKeyRange.upperBound(2)) result is: " + req.result);
+
+       // Key range bound
+    req = idbRequest(objectStore.getKey(IDBKeyRange.bound(2, 4)));
+    event = yield;    
+       debug("getKey(IDBKeyRange.bound(2, 4)) result is: " + req.result);
+    
+    finishJSTest();
+ }
\ No newline at end of file
index 5fe40a9..05466d0 100644 (file)
@@ -1,3 +1,55 @@
+2016-12-01  Brady Eidson  <beidson@apple.com>
+
+        IndexedDB 2.0: Implement IDBObjectStore.getKey().
+        https://bugs.webkit.org/show_bug.cgi?id=165256
+
+        Reviewed by Alex Christensen.
+
+        Tests: storage/indexeddb/modern/idbobjectstore-getkey-1-private.html
+               storage/indexeddb/modern/idbobjectstore-getkey-1.html
+
+        * Modules/indexeddb/IDBObjectStore.cpp:
+        (WebCore::IDBObjectStore::get):
+        (WebCore::IDBObjectStore::getKey):
+        * Modules/indexeddb/IDBObjectStore.h:
+        * Modules/indexeddb/IDBObjectStore.idl:
+
+        * Modules/indexeddb/IDBRequest.cpp:
+        (WebCore::IDBRequest::createObjectStoreGet):
+        (WebCore::IDBRequest::IDBRequest):
+        (WebCore::IDBRequest::requestedObjectStoreRecordType):
+        * Modules/indexeddb/IDBRequest.h:
+
+        * Modules/indexeddb/IDBTransaction.cpp:
+        (WebCore::IDBTransaction::requestGetRecord):
+        (WebCore::IDBTransaction::requestIndexRecord):
+        (WebCore::IDBTransaction::didGetRecordOnServer):
+
+        * Modules/indexeddb/IndexedDB.h:
+
+        * Modules/indexeddb/server/IDBBackingStore.h:
+
+        * Modules/indexeddb/server/MemoryIDBBackingStore.cpp:
+        (WebCore::IDBServer::MemoryIDBBackingStore::getRecord):
+        * Modules/indexeddb/server/MemoryIDBBackingStore.h:
+
+        * Modules/indexeddb/server/MemoryObjectStore.h:
+
+        * Modules/indexeddb/server/SQLiteIDBBackingStore.cpp:
+        (WebCore::IDBServer::SQLiteIDBBackingStore::getRecord):
+        * Modules/indexeddb/server/SQLiteIDBBackingStore.h:
+
+        * Modules/indexeddb/server/UniqueIDBDatabase.cpp:
+        (WebCore::IDBServer::UniqueIDBDatabase::getRecord):
+        (WebCore::IDBServer::UniqueIDBDatabase::performGetRecord):
+        * Modules/indexeddb/server/UniqueIDBDatabase.h:
+
+        * Modules/indexeddb/shared/IDBGetRecordData.cpp:
+        (WebCore::IDBGetRecordData::isolatedCopy):
+        * Modules/indexeddb/shared/IDBGetRecordData.h:
+        (WebCore::IDBGetRecordData::encode):
+        (WebCore::IDBGetRecordData::decode):
+
 2016-12-01  Joseph Pecoraro  <pecoraro@apple.com>
 
         Misc. cleanup in Modules/fetch
index f5684e8..ac9c2d8 100644 (file)
@@ -220,7 +220,7 @@ ExceptionOr<Ref<IDBRequest>> IDBObjectStore::get(ExecState& execState, JSValue k
     if (!idbKey->isValid())
         return Exception { IDBDatabaseException::DataError, ASCIILiteral("Failed to execute 'get' on 'IDBObjectStore': The parameter is not a valid key.") };
 
-    return m_transaction.requestGetRecord(execState, *this, { idbKey.ptr() });
+    return m_transaction.requestGetRecord(execState, *this, { idbKey.ptr(), IDBGetRecordDataType::KeyAndValue });
 }
 
 ExceptionOr<Ref<IDBRequest>> IDBObjectStore::get(ExecState& execState, IDBKeyRange* keyRange)
@@ -238,7 +238,43 @@ ExceptionOr<Ref<IDBRequest>> IDBObjectStore::get(ExecState& execState, IDBKeyRan
     if (!keyRangeData.isValid())
         return Exception { IDBDatabaseException::DataError };
 
-    return m_transaction.requestGetRecord(execState, *this, { keyRangeData });
+    return m_transaction.requestGetRecord(execState, *this, { keyRangeData, IDBGetRecordDataType::KeyAndValue });
+}
+
+ExceptionOr<Ref<IDBRequest>> IDBObjectStore::getKey(ExecState& execState, JSValue key)
+{
+    LOG(IndexedDB, "IDBObjectStore::getKey");
+    ASSERT(currentThread() == m_transaction.database().originThreadID());
+
+    if (m_deleted)
+        return Exception { IDBDatabaseException::InvalidStateError, ASCIILiteral("Failed to execute 'getKey' on 'IDBObjectStore': The object store has been deleted.") };
+
+    if (!m_transaction.isActive())
+        return Exception { IDBDatabaseException::TransactionInactiveError, ASCIILiteral("Failed to execute 'getKey' on 'IDBObjectStore': The transaction is inactive or finished.") };
+
+    auto idbKey = scriptValueToIDBKey(execState, key);
+    if (!idbKey->isValid())
+        return Exception { IDBDatabaseException::DataError, ASCIILiteral("Failed to execute 'getKey' on 'IDBObjectStore': The parameter is not a valid key.") };
+
+    return m_transaction.requestGetRecord(execState, *this, { idbKey.ptr(), IDBGetRecordDataType::KeyOnly });
+}
+
+ExceptionOr<Ref<IDBRequest>> IDBObjectStore::getKey(ExecState& execState, IDBKeyRange* keyRange)
+{
+    LOG(IndexedDB, "IDBObjectStore::getKey");
+    ASSERT(currentThread() == m_transaction.database().originThreadID());
+
+    if (m_deleted)
+        return Exception { IDBDatabaseException::InvalidStateError, ASCIILiteral("Failed to execute 'getKey' on 'IDBObjectStore': The object store has been deleted.") };
+
+    if (!m_transaction.isActive())
+        return Exception { IDBDatabaseException::TransactionInactiveError, ASCIILiteral("Failed to execute 'getKey' on 'IDBObjectStore': The transaction is inactive or finished.") };
+
+    IDBKeyRangeData keyRangeData(keyRange);
+    if (!keyRangeData.isValid())
+        return Exception { IDBDatabaseException::DataError, ASCIILiteral("Failed to execute 'getKey' on 'IDBObjectStore': The parameter is not a valid key range.") };
+
+    return m_transaction.requestGetRecord(execState, *this, { keyRangeData, IDBGetRecordDataType::KeyOnly });
 }
 
 ExceptionOr<Ref<IDBRequest>> IDBObjectStore::add(ExecState& execState, JSValue value, JSValue key)
index 081700b..b62b030 100644 (file)
@@ -77,6 +77,8 @@ public:
     ExceptionOr<Ref<IDBRequest>> openKeyCursor(JSC::ExecState&, JSC::JSValue key, const String& direction);
     ExceptionOr<Ref<IDBRequest>> get(JSC::ExecState&, JSC::JSValue key);
     ExceptionOr<Ref<IDBRequest>> get(JSC::ExecState&, IDBKeyRange*);
+    ExceptionOr<Ref<IDBRequest>> getKey(JSC::ExecState&, JSC::JSValue key);
+    ExceptionOr<Ref<IDBRequest>> getKey(JSC::ExecState&, IDBKeyRange*);
     ExceptionOr<Ref<IDBRequest>> add(JSC::ExecState&, JSC::JSValue, JSC::JSValue key);
     ExceptionOr<Ref<IDBRequest>> put(JSC::ExecState&, JSC::JSValue, JSC::JSValue key);
     ExceptionOr<Ref<IDBRequest>> deleteFunction(JSC::ExecState&, IDBKeyRange*);
index edd78e9..d39a11f 100644 (file)
@@ -42,6 +42,8 @@
     [CallWith=ScriptState, ImplementedAs=deleteFunction, MayThrowException] IDBRequest delete(any key);
     [CallWith=ScriptState, MayThrowException] IDBRequest get(IDBKeyRange? key);
     [CallWith=ScriptState, MayThrowException] IDBRequest get(any key);
+    [CallWith=ScriptState, MayThrowException] IDBRequest getKey(IDBKeyRange? key);
+    [CallWith=ScriptState, MayThrowException] IDBRequest getKey(any key);
     [CallWith=ScriptState, MayThrowException] IDBRequest clear();
     [CallWith=ScriptState, MayThrowException] IDBRequest openCursor(optional IDBKeyRange? range = null, optional DOMString direction = "next");
     [CallWith=ScriptState, MayThrowException] IDBRequest openCursor(any key, optional DOMString direction = "next");
index 7e73292..9d9c960 100644 (file)
@@ -68,6 +68,11 @@ Ref<IDBRequest> IDBRequest::create(ScriptExecutionContext& context, IDBIndex& in
     return adoptRef(*new IDBRequest(context, index, transaction));
 }
 
+Ref<IDBRequest> IDBRequest::createObjectStoreGet(ScriptExecutionContext& context, IDBObjectStore& objectStore, IndexedDB::ObjectStoreRecordType type, IDBTransaction& transaction)
+{
+    return adoptRef(*new IDBRequest(context, objectStore, type, transaction));
+}
+
 Ref<IDBRequest> IDBRequest::createIndexGet(ScriptExecutionContext& context, IDBIndex& index, IndexedDB::IndexRecordType requestedRecordType, IDBTransaction& transaction)
 {
     return adoptRef(*new IDBRequest(context, index, requestedRecordType, transaction));
@@ -115,6 +120,17 @@ IDBRequest::IDBRequest(ScriptExecutionContext& context, IDBIndex& index, IDBTran
     suspendIfNeeded();
 }
 
+IDBRequest::IDBRequest(ScriptExecutionContext& context, IDBObjectStore& objectStore, IndexedDB::ObjectStoreRecordType type, IDBTransaction& transaction)
+    : IDBActiveDOMObject(&context)
+    , m_transaction(&transaction)
+    , m_resourceIdentifier(transaction.connectionProxy())
+    , m_objectStoreSource(&objectStore)
+    , m_requestedObjectStoreRecordType(type)
+    , m_connectionProxy(transaction.database().connectionProxy())
+{
+    suspendIfNeeded();
+}
+
 IDBRequest::IDBRequest(ScriptExecutionContext& context, IDBIndex& index, IndexedDB::IndexRecordType requestedRecordType, IDBTransaction& transaction)
     : IDBRequest(context, index, transaction)
 {
@@ -198,6 +214,13 @@ uint64_t IDBRequest::sourceIndexIdentifier() const
     return m_indexSource->info().identifier();
 }
 
+IndexedDB::ObjectStoreRecordType IDBRequest::requestedObjectStoreRecordType() const
+{
+    ASSERT(currentThread() == originThreadID());
+
+    return m_requestedObjectStoreRecordType;
+}
+
 IndexedDB::IndexRecordType IDBRequest::requestedIndexRecordType() const
 {
     ASSERT(currentThread() == originThreadID());
index 8f53dc9..4ceb207 100644 (file)
@@ -60,6 +60,7 @@ public:
     static Ref<IDBRequest> create(ScriptExecutionContext&, IDBObjectStore&, IDBTransaction&);
     static Ref<IDBRequest> create(ScriptExecutionContext&, IDBCursor&, IDBTransaction&);
     static Ref<IDBRequest> create(ScriptExecutionContext&, IDBIndex&, IDBTransaction&);
+    static Ref<IDBRequest> createObjectStoreGet(ScriptExecutionContext&, IDBObjectStore&, IndexedDB::ObjectStoreRecordType, IDBTransaction&);
     static Ref<IDBRequest> createIndexGet(ScriptExecutionContext&, IDBIndex&, IndexedDB::IndexRecordType, IDBTransaction&);
 
     const IDBResourceIdentifier& resourceIdentifier() const { return m_resourceIdentifier; }
@@ -80,6 +81,7 @@ public:
 
     uint64_t sourceObjectStoreIdentifier() const;
     uint64_t sourceIndexIdentifier() const;
+    IndexedDB::ObjectStoreRecordType requestedObjectStoreRecordType() const;
     IndexedDB::IndexRecordType requestedIndexRecordType() const;
 
     ScriptExecutionContext* scriptExecutionContext() const final { return ActiveDOMObject::scriptExecutionContext(); }
@@ -132,6 +134,7 @@ private:
     IDBRequest(ScriptExecutionContext&, IDBObjectStore&, IDBTransaction&);
     IDBRequest(ScriptExecutionContext&, IDBCursor&, IDBTransaction&);
     IDBRequest(ScriptExecutionContext&, IDBIndex&, IDBTransaction&);
+    IDBRequest(ScriptExecutionContext&, IDBObjectStore&, IndexedDB::ObjectStoreRecordType, IDBTransaction&);
     IDBRequest(ScriptExecutionContext&, IDBIndex&, IndexedDB::IndexRecordType, IDBTransaction&);
 
     void clearResult();
@@ -168,7 +171,8 @@ private:
     RefPtr<IDBCursor> m_cursorSource;
 
     bool m_hasPendingActivity { true };
-    IndexedDB::IndexRecordType m_requestedIndexRecordType;
+    IndexedDB::ObjectStoreRecordType m_requestedObjectStoreRecordType { IndexedDB::ObjectStoreRecordType::ValueOnly };
+    IndexedDB::IndexRecordType m_requestedIndexRecordType { IndexedDB::IndexRecordType::Key };
 
     RefPtr<IDBCursor> m_pendingCursor;
 
index 4497347..05da02f 100644 (file)
@@ -952,7 +952,9 @@ Ref<IDBRequest> IDBTransaction::requestGetRecord(ExecState& state, IDBObjectStor
 
     ASSERT_UNUSED(state, scriptExecutionContext() == scriptExecutionContextFromExecState(&state));
 
-    auto request = IDBRequest::create(*scriptExecutionContext(), objectStore, *this);
+    IndexedDB::ObjectStoreRecordType type = getRecordData.type == IDBGetRecordDataType::KeyAndValue ? IndexedDB::ObjectStoreRecordType::ValueOnly : IndexedDB::ObjectStoreRecordType::KeyOnly;
+
+    auto request = IDBRequest::createObjectStoreGet(*scriptExecutionContext(), objectStore, type, *this);
     addRequest(request.get());
 
     scheduleOperation(IDBClient::createTransactionOperation(*this, request.get(), &IDBTransaction::didGetRecordOnServer, &IDBTransaction::getRecordOnServer, getRecordData));
@@ -988,7 +990,7 @@ Ref<IDBRequest> IDBTransaction::requestIndexRecord(ExecState& state, IDBIndex& i
     auto request = IDBRequest::createIndexGet(*scriptExecutionContext(), index, type, *this);
     addRequest(request.get());
 
-    IDBGetRecordData getRecordData = { range };
+    IDBGetRecordData getRecordData = { range, IDBGetRecordDataType::KeyAndValue };
     scheduleOperation(IDBClient::createTransactionOperation(*this, request.get(), &IDBTransaction::didGetRecordOnServer, &IDBTransaction::getRecordOnServer, getRecordData));
 
     return request;
@@ -1014,9 +1016,13 @@ void IDBTransaction::didGetRecordOnServer(IDBRequest& request, const IDBResultDa
 
     ASSERT(resultData.type() == IDBResultType::GetRecordSuccess);
 
+    bool useResultKey = request.sourceIndexIdentifier() && request.requestedIndexRecordType() == IndexedDB::IndexRecordType::Key;
+    if (!useResultKey)
+        useResultKey = request.requestedObjectStoreRecordType() == IndexedDB::ObjectStoreRecordType::KeyOnly;
+
     const IDBGetResult& result = resultData.getResult();
 
-    if (request.sourceIndexIdentifier() && request.requestedIndexRecordType() == IndexedDB::IndexRecordType::Key) {
+    if (useResultKey) {
         if (!result.keyData().isNull())
             request.setResult(result.keyData());
         else
index 0109d59..d7df0e1 100644 (file)
@@ -74,6 +74,11 @@ enum class IndexRecordType {
     Value,
 };
 
+enum class ObjectStoreRecordType {
+    ValueOnly,
+    KeyOnly,
+};
+
 // In order of the least to the highest precedent in terms of sort order.
 enum KeyType {
     Max = -1,
index 5969bca..490b908 100644 (file)
@@ -43,6 +43,8 @@ class IDBTransactionInfo;
 class IDBValue;
 class ThreadSafeDataBuffer;
 
+enum class IDBGetRecordDataType;
+
 struct IDBGetAllRecordsData;
 struct IDBIterateCursorData;
 struct IDBKeyRangeData;
@@ -80,7 +82,7 @@ public:
     virtual IDBError keyExistsInObjectStore(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData&, bool& keyExists) = 0;
     virtual IDBError deleteRange(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData&) = 0;
     virtual IDBError addRecord(const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo&, const IDBKeyData&, const IDBValue&) = 0;
-    virtual IDBError getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData&, IDBGetResult& outValue) = 0;
+    virtual IDBError getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData&, IDBGetRecordDataType, IDBGetResult& outValue) = 0;
     virtual IDBError getAllRecords(const IDBResourceIdentifier& transactionIdentifier, const IDBGetAllRecordsData&, IDBGetAllResult& outValue) = 0;
     virtual IDBError getIndexRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, IndexedDB::IndexRecordType, const IDBKeyRangeData&, IDBGetResult& outValue) = 0;
     virtual IDBError getCount(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const IDBKeyRangeData&, uint64_t& outCount) = 0;
index 0a1652a..e633089 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "IDBCursorInfo.h"
 #include "IDBGetAllRecordsData.h"
+#include "IDBGetRecordData.h"
 #include "IDBGetResult.h"
 #include "IDBIndexInfo.h"
 #include "IDBIterateCursorData.h"
@@ -350,7 +351,7 @@ IDBError MemoryIDBBackingStore::addRecord(const IDBResourceIdentifier& transacti
     return objectStore->addRecord(*transaction, keyData, value);
 }
 
-IDBError MemoryIDBBackingStore::getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData& range, IDBGetResult& outValue)
+IDBError MemoryIDBBackingStore::getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData& range, IDBGetRecordDataType type, IDBGetResult& outValue)
 {
     LOG(IndexedDB, "MemoryIDBBackingStore::getRecord");
 
@@ -363,7 +364,15 @@ IDBError MemoryIDBBackingStore::getRecord(const IDBResourceIdentifier& transacti
     if (!objectStore)
         return { IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found") };
 
-    outValue = objectStore->valueForKeyRange(range);
+    switch (type) {
+    case IDBGetRecordDataType::KeyAndValue:
+        outValue = objectStore->valueForKeyRange(range);
+        break;
+    case IDBGetRecordDataType::KeyOnly:
+        outValue = objectStore->lowestKeyWithRecordInRange(range);
+        break;
+    }
+
     return { };
 }
 
index e85b805..37715ac 100644 (file)
@@ -61,7 +61,7 @@ public:
     IDBError keyExistsInObjectStore(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData&, bool& keyExists) final;
     IDBError deleteRange(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData&) final;
     IDBError addRecord(const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo&, const IDBKeyData&, const IDBValue&) final;
-    IDBError getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData&, IDBGetResult& outValue) final;
+    IDBError getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData&, IDBGetRecordDataType, IDBGetResult& outValue) final;
     IDBError getAllRecords(const IDBResourceIdentifier& transactionIdentifier, const IDBGetAllRecordsData&, IDBGetAllResult& outValue) final;
     IDBError getIndexRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, IndexedDB::IndexRecordType, const IDBKeyRangeData&, IDBGetResult& outValue) final;
     IDBError getCount(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const IDBKeyRangeData&, uint64_t& outCount) final;
index e61a0ee..883959e 100644 (file)
@@ -85,6 +85,7 @@ public:
 
     ThreadSafeDataBuffer valueForKey(const IDBKeyData&) const;
     ThreadSafeDataBuffer valueForKeyRange(const IDBKeyRangeData&) const;
+    IDBKeyData lowestKeyWithRecordInRange(const IDBKeyRangeData&) const;
     IDBGetResult indexValueForKeyRange(uint64_t indexIdentifier, IndexedDB::IndexRecordType, const IDBKeyRangeData&) const;
     uint64_t countForKeyRange(uint64_t indexIdentifier, const IDBKeyRangeData&) const;
 
@@ -106,7 +107,6 @@ public:
 private:
     MemoryObjectStore(const IDBObjectStoreInfo&);
 
-    IDBKeyData lowestKeyWithRecordInRange(const IDBKeyRangeData&) const;
     std::set<IDBKeyData>::iterator lowestIteratorInRange(const IDBKeyRangeData&, bool reverse) const;
 
     IDBError populateIndexWithExistingRecords(MemoryIndex&);
index fb6d378..0398a38 100644 (file)
@@ -33,6 +33,7 @@
 #include "IDBDatabaseException.h"
 #include "IDBGetAllRecordsData.h"
 #include "IDBGetAllResult.h"
+#include "IDBGetRecordData.h"
 #include "IDBGetResult.h"
 #include "IDBIterateCursorData.h"
 #include "IDBKeyData.h"
@@ -1785,7 +1786,7 @@ IDBError SQLiteIDBBackingStore::getBlobRecordsForObjectStoreRecord(int64_t objec
     return { };
 }
 
-IDBError SQLiteIDBBackingStore::getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID, const IDBKeyRangeData& keyRange, IDBGetResult& resultValue)
+IDBError SQLiteIDBBackingStore::getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID, const IDBKeyRangeData& keyRange, IDBGetRecordDataType type, IDBGetResult& resultValue)
 {
     LOG(IndexedDB, "SQLiteIDBBackingStore::getRecord - key range %s, object store %" PRIu64, keyRange.loggingString().utf8().data(), objectStoreID);
 
@@ -1824,17 +1825,39 @@ IDBError SQLiteIDBBackingStore::getRecord(const IDBResourceIdentifier& transacti
         static NeverDestroyed<ASCIILiteral> lowerClosedUpperOpen("SELECT value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;");
         static NeverDestroyed<ASCIILiteral> lowerClosedUpperClosed("SELECT value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;");
 
+        static NeverDestroyed<ASCIILiteral> lowerOpenUpperOpenKeyOnly("SELECT key FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;");
+        static NeverDestroyed<ASCIILiteral> lowerOpenUpperClosedKeyOnly("SELECT key FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;");
+        static NeverDestroyed<ASCIILiteral> lowerClosedUpperOpenKeyOnly("SELECT key FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;");
+        static NeverDestroyed<ASCIILiteral> lowerClosedUpperClosedKeyOnly("SELECT key FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;");
+
         SQLiteStatement* sql = nullptr;
-        if (keyRange.lowerOpen) {
-            if (keyRange.upperOpen)
-                sql = cachedStatement(SQL::GetValueRecordsLowerOpenUpperOpen, lowerOpenUpperOpen.get());
-            else
-                sql = cachedStatement(SQL::GetValueRecordsLowerOpenUpperClosed, lowerOpenUpperClosed.get());
-        } else {
-            if (keyRange.upperOpen)
-                sql = cachedStatement(SQL::GetValueRecordsLowerClosedUpperOpen, lowerClosedUpperOpen.get());
-            else
-                sql = cachedStatement(SQL::GetValueRecordsLowerClosedUpperClosed, lowerClosedUpperClosed.get());
+
+        switch (type) {
+        case IDBGetRecordDataType::KeyAndValue:
+            if (keyRange.lowerOpen) {
+                if (keyRange.upperOpen)
+                    sql = cachedStatement(SQL::GetValueRecordsLowerOpenUpperOpen, lowerOpenUpperOpen.get());
+                else
+                    sql = cachedStatement(SQL::GetValueRecordsLowerOpenUpperClosed, lowerOpenUpperClosed.get());
+            } else {
+                if (keyRange.upperOpen)
+                    sql = cachedStatement(SQL::GetValueRecordsLowerClosedUpperOpen, lowerClosedUpperOpen.get());
+                else
+                    sql = cachedStatement(SQL::GetValueRecordsLowerClosedUpperClosed, lowerClosedUpperClosed.get());
+            }
+            break;
+        case IDBGetRecordDataType::KeyOnly:
+            if (keyRange.lowerOpen) {
+                if (keyRange.upperOpen)
+                    sql = cachedStatement(SQL::GetKeyRecordsLowerOpenUpperOpen, lowerOpenUpperOpenKeyOnly.get());
+                else
+                    sql = cachedStatement(SQL::GetKeyRecordsLowerOpenUpperClosed, lowerOpenUpperClosedKeyOnly.get());
+            } else {
+                if (keyRange.upperOpen)
+                    sql = cachedStatement(SQL::GetKeyRecordsLowerClosedUpperOpen, lowerClosedUpperOpenKeyOnly.get());
+                else
+                    sql = cachedStatement(SQL::GetKeyRecordsLowerClosedUpperClosed, lowerClosedUpperClosedKeyOnly.get());
+            }
         }
 
         if (!sql
@@ -1861,7 +1884,25 @@ IDBError SQLiteIDBBackingStore::getRecord(const IDBResourceIdentifier& transacti
         sql->getColumnBlobAsVector(0, buffer);
         resultBuffer = ThreadSafeDataBuffer::adoptVector(buffer);
 
-        recordID = sql->getColumnInt64(1);
+        if (type == IDBGetRecordDataType::KeyAndValue)
+            recordID = sql->getColumnInt64(1);
+    }
+
+    if (type == IDBGetRecordDataType::KeyOnly) {
+        auto* vector = resultBuffer.data();
+        if (!vector) {
+            LOG_ERROR("Unable to deserialize key data from database for IDBObjectStore.getKey()");
+            return { IDBDatabaseException::UnknownError, ASCIILiteral("Error extracting key data from database executing IDBObjectStore.getKey()") };
+        }
+
+        IDBKeyData keyData;
+        if (!deserializeIDBKeyData(vector->data(), vector->size(), keyData)) {
+            LOG_ERROR("Unable to deserialize key data from database for IDBObjectStore.getKey()");
+            return { IDBDatabaseException::UnknownError, ASCIILiteral("Error extracting key data from database executing IDBObjectStore.getKey()") };
+        }
+
+        resultValue = { keyData };
+        return { };
     }
 
     ASSERT(recordID);
index e4f9672..2111d95 100644 (file)
@@ -66,7 +66,7 @@ public:
     IDBError keyExistsInObjectStore(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData&, bool& keyExists) final;
     IDBError deleteRange(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData&) final;
     IDBError addRecord(const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo&, const IDBKeyData&, const IDBValue&) final;
-    IDBError getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData&, IDBGetResult& outValue) final;
+    IDBError getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData&, IDBGetRecordDataType, IDBGetResult& outValue) final;
     IDBError getAllRecords(const IDBResourceIdentifier& transactionIdentifier, const IDBGetAllRecordsData&, IDBGetAllResult& outValue) final;
     IDBError getIndexRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, IndexedDB::IndexRecordType, const IDBKeyRangeData&, IDBGetResult& outValue) final;
     IDBError getCount(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const IDBKeyRangeData&, uint64_t& outCount) final;
@@ -159,6 +159,10 @@ private:
         GetValueRecordsLowerOpenUpperClosed,
         GetValueRecordsLowerClosedUpperOpen,
         GetValueRecordsLowerClosedUpperClosed,
+        GetKeyRecordsLowerOpenUpperOpen,
+        GetKeyRecordsLowerOpenUpperClosed,
+        GetKeyRecordsLowerClosedUpperOpen,
+        GetKeyRecordsLowerClosedUpperClosed,
         Count
     };
 
index cb04861..9910157 100644 (file)
@@ -1051,7 +1051,7 @@ void UniqueIDBDatabase::getRecord(const IDBRequestData& requestData, const IDBGe
     if (uint64_t indexIdentifier = requestData.indexIdentifier())
         postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetIndexRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), indexIdentifier, requestData.indexRecordType(), getRecordData.keyRangeData));
     else
-        postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), getRecordData.keyRangeData));
+        postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), getRecordData.keyRangeData, getRecordData.type));
 }
 
 void UniqueIDBDatabase::getAllRecords(const IDBRequestData& requestData, const IDBGetAllRecordsData& getAllRecordsData, GetAllResultsCallback callback)
@@ -1066,7 +1066,7 @@ void UniqueIDBDatabase::getAllRecords(const IDBRequestData& requestData, const I
     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetAllRecords, callbackID, requestData.transactionIdentifier(), getAllRecordsData));
 }
 
-void UniqueIDBDatabase::performGetRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData& keyRangeData)
+void UniqueIDBDatabase::performGetRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData& keyRangeData, IDBGetRecordDataType type)
 {
     ASSERT(!isMainThread());
     LOG(IndexedDB, "(db) UniqueIDBDatabase::performGetRecord");
@@ -1074,7 +1074,7 @@ void UniqueIDBDatabase::performGetRecord(uint64_t callbackIdentifier, const IDBR
     ASSERT(m_backingStore);
 
     IDBGetResult result;
-    IDBError error = m_backingStore->getRecord(transactionIdentifier, objectStoreIdentifier, keyRangeData, result);
+    IDBError error = m_backingStore->getRecord(transactionIdentifier, objectStoreIdentifier, keyRangeData, type, result);
 
     postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformGetRecord, callbackIdentifier, error, result));
 }
index 76aafc9..86eaba2 100644 (file)
@@ -57,6 +57,8 @@ class IDBGetAllResult;
 class IDBRequestData;
 class IDBTransactionInfo;
 
+enum class IDBGetRecordDataType;
+
 namespace IndexedDB {
 enum class IndexRecordType;
 }
@@ -156,7 +158,7 @@ private:
     void performDeleteIndex(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier);
     void performRenameIndex(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName);
     void performPutOrAdd(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData&, const IDBValue&, IndexedDB::ObjectStoreOverwriteMode);
-    void performGetRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData&);
+    void performGetRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData&, IDBGetRecordDataType);
     void performGetAllRecords(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBGetAllRecordsData&);
     void performGetIndexRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, IndexedDB::IndexRecordType, const IDBKeyRangeData&);
     void performGetCount(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const IDBKeyRangeData&);
index d19a26a..6884f2b 100644 (file)
@@ -34,7 +34,7 @@ namespace WebCore {
 
 IDBGetRecordData IDBGetRecordData::isolatedCopy() const
 {
-    return { keyRangeData.isolatedCopy() };
+    return { keyRangeData.isolatedCopy(), type };
 }
 
 } // namespace WebCore
index fecfa50..6182042 100644 (file)
 
 namespace WebCore {
 
+enum class IDBGetRecordDataType {
+    KeyOnly,
+    KeyAndValue,
+};
+
 struct IDBGetRecordData {
     IDBKeyRangeData keyRangeData;
+    IDBGetRecordDataType type;
 
     IDBGetRecordData isolatedCopy() const;
 
@@ -44,6 +50,7 @@ template<class Encoder>
 void IDBGetRecordData::encode(Encoder& encoder) const
 {
     encoder << keyRangeData;
+    encoder.encodeEnum(type);
 }
 
 template<class Decoder>
@@ -52,6 +59,9 @@ bool IDBGetRecordData::decode(Decoder& decoder, IDBGetRecordData& getRecordData)
     if (!decoder.decode(getRecordData.keyRangeData))
         return false;
 
+    if (!decoder.decodeEnum(getRecordData.type))
+        return false;
+
     return true;
 }