Commit 0b93da5f authored by hans@chromium.org's avatar hans@chromium.org
Browse files

2011-01-19 Hans Wennborg <hans@chromium.org>

        Reviewed by Jeremy Orlow.

        IndexedDB: Support auto-increment keys
        https://bugs.webkit.org/show_bug.cgi?id=52576

        Add layout test for auto increment keys.
        Update previous test not to consider auto increment an error.

        * storage/indexeddb/create-object-store-options-expected.txt:
        * storage/indexeddb/create-object-store-options.html:
        * storage/indexeddb/objectstore-autoincrement-expected.txt: Added.
        * storage/indexeddb/objectstore-autoincrement.html: Added.
2011-01-19  Hans Wennborg  <hans@chromium.org>

        Reviewed by Jeremy Orlow.

        IndexedDB: Support auto-increment keys
        https://bugs.webkit.org/show_bug.cgi?id=52576

        Add support for auto-increment keys.

        Test: storage/indexeddb/objectstore-autoincrement.html

        * storage/IDBDatabase.cpp:
        (WebCore::IDBDatabase::createObjectStore):
        * storage/IDBObjectStoreBackendImpl.cpp:
        (WebCore::genAutoIncrementKey):
        (WebCore::IDBObjectStoreBackendImpl::putInternal):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@76126 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 24c1fe69
2011-01-19 Hans Wennborg <hans@chromium.org>
Reviewed by Jeremy Orlow.
IndexedDB: Support auto-increment keys
https://bugs.webkit.org/show_bug.cgi?id=52576
Add layout test for auto increment keys.
Update previous test not to consider auto increment an error.
* storage/indexeddb/create-object-store-options-expected.txt:
* storage/indexeddb/create-object-store-options.html:
* storage/indexeddb/objectstore-autoincrement-expected.txt: Added.
* storage/indexeddb/objectstore-autoincrement.html: Added.
2011-01-19 Csaba Osztrogonác <ossy@webkit.org>
 
Unreviewed.
......
......@@ -17,8 +17,6 @@ Deleted all object stores.
db.createObjectStore('a', {keyPath: 'a'})
db.createObjectStore('b')
db.createObjectStore('c', {autoIncrement: true});
PASS Exception thrown
PASS code is webkitIDBDatabaseException.UNKNOWN_ERR
trans = db.transaction({mode: webkitIDBTransaction.READ_WRITE})
PASS trans.mode is webkitIDBTransaction.READ_WRITE
trans.objectStore('a').put({'a': 0})
......
......@@ -44,16 +44,8 @@ function cleaned()
evalAndLog("db.createObjectStore('a', {keyPath: 'a'})");
evalAndLog("db.createObjectStore('b')");
try {
// FIXME: This should work in the future.
debug("db.createObjectStore('c', {autoIncrement: true});");
db.createObjectStore('c', {autoIncrement: true});
testFailed('createObjectStore with autoIncrement = true should throw');
} catch (err) {
testPassed("Exception thrown");
code = err.code;
shouldBe("code", "webkitIDBDatabaseException.UNKNOWN_ERR");
}
debug("db.createObjectStore('c', {autoIncrement: true});");
db.createObjectStore('c', {autoIncrement: true});
trans = evalAndLog("trans = db.transaction({mode: webkitIDBTransaction.READ_WRITE})");
shouldBe("trans.mode", "webkitIDBTransaction.READ_WRITE");
......
Test IndexedDB's IDBObjectStore auto-increment feature.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
webkitIndexedDB.open('Address Book')
PASS 'onsuccess' in result is true
PASS 'onerror' in result is true
PASS 'readyState' in result is true
An event should fire shortly...
openSuccess():
Success event fired:
PASS 'result' in event is true
PASS 'code' in event is false
PASS 'message' in event is false
PASS 'source' in event is true
PASS event.source != null is true
PASS 'onsuccess' in event.target is true
PASS 'onerror' in event.target is true
PASS 'readyState' in event.target is true
PASS event.target.readyState is event.target.DONE
db = event.result
db.setVersion('new version')
PASS 'onsuccess' in result is true
PASS 'onerror' in result is true
PASS 'readyState' in result is true
An event should fire shortly...
setVersionSuccess():
Success event fired:
PASS 'result' in event is true
PASS 'code' in event is false
PASS 'message' in event is false
PASS 'source' in event is true
PASS event.source != null is true
PASS 'onsuccess' in event.target is true
PASS 'onerror' in event.target is true
PASS 'readyState' in event.target is true
PASS event.target.readyState is event.target.DONE
trans = event.result
PASS trans !== null is true
Deleted all object stores.
createObjectStore():
store = db.createObjectStore('StoreWithKeyPath', {keyPath: 'id', autoIncrement: true})
db.createObjectStore('StoreWithAutoIncrement', {autoIncrement: true})
db.createObjectStore('PlainOldStore', {autoIncrement: false})
storeNames = db.objectStoreNames
PASS store.name is "StoreWithKeyPath"
PASS store.keyPath is 'id'
PASS storeNames.contains('StoreWithKeyPath') is true
PASS storeNames.contains('StoreWithAutoIncrement') is true
PASS storeNames.contains('PlainOldStore') is true
PASS storeNames.length is 3
setVersionCompleted():
trans = db.transaction({mode: webkitIDBTransaction.READ_WRITE})
store = trans.objectStore('StoreWithKeyPath')
Insert in object store with key gen and key path
store.add({name: 'Lincoln', number: '7012'})
addLincolnError():
Error event fired:
PASS 'result' in event is false
PASS 'code' in event is true
PASS 'message' in event is true
PASS 'source' in event is true
PASS event.source != null is true
PASS 'onsuccess' in event.target is true
PASS 'onerror' in event.target is true
PASS 'readyState' in event.target is true
PASS event.target.readyState is event.target.DONE
PASS event.code is webkitIDBDatabaseException.UNKNOWN_ERR
store = trans.objectStore('StoreWithAutoIncrement')
Insert into object store with key gen using explicit key
store.add({name: 'Lincoln'}, 1)
addWithExplicitKeyError():
Error event fired:
PASS 'result' in event is false
PASS 'code' in event is true
PASS 'message' in event is true
PASS 'source' in event is true
PASS event.source != null is true
PASS 'onsuccess' in event.target is true
PASS 'onerror' in event.target is true
PASS 'readyState' in event.target is true
PASS event.target.readyState is event.target.DONE
PASS event.code is webkitIDBDatabaseException.DATA_ERR
Insert into object store with key gen and no key path
store.add({name: 'Lincoln', number: '7012'})
addLincolnSuccess():
Success event fired:
PASS 'result' in event is true
PASS 'code' in event is false
PASS 'message' in event is false
PASS 'source' in event is true
PASS event.source != null is true
PASS 'onsuccess' in event.target is true
PASS 'onerror' in event.target is true
PASS 'readyState' in event.target is true
PASS event.target.readyState is event.target.DONE
PASS event.result is 1
store.get(1)
getLincolnSuccess():
Success event fired:
PASS 'result' in event is true
PASS 'code' in event is false
PASS 'message' in event is false
PASS 'source' in event is true
PASS event.source != null is true
PASS 'onsuccess' in event.target is true
PASS 'onerror' in event.target is true
PASS 'readyState' in event.target is true
PASS event.target.readyState is event.target.DONE
PASS event.result.name is "Lincoln"
PASS event.result.number is "7012"
store.put({name: 'Abraham', number: '2107'})
putAbrahamSuccess():
Success event fired:
PASS 'result' in event is true
PASS 'code' in event is false
PASS 'message' in event is false
PASS 'source' in event is true
PASS event.source != null is true
PASS 'onsuccess' in event.target is true
PASS 'onerror' in event.target is true
PASS 'readyState' in event.target is true
PASS event.target.readyState is event.target.DONE
PASS event.result is 2
store.get(2)
getAbrahamSuccess():
Success event fired:
PASS 'result' in event is true
PASS 'code' in event is false
PASS 'message' in event is false
PASS 'source' in event is true
PASS event.source != null is true
PASS 'onsuccess' in event.target is true
PASS 'onerror' in event.target is true
PASS 'readyState' in event.target is true
PASS event.target.readyState is event.target.DONE
PASS event.result.name is "Abraham"
PASS event.result.number is "2107"
store = trans.objectStore('PlainOldStore')
Try adding with no key to object store without auto increment.
store.add({name: 'Adam'})
addAdamError():
Error event fired:
PASS 'result' in event is false
PASS 'code' in event is true
PASS 'message' in event is true
PASS 'source' in event is true
PASS event.source != null is true
PASS 'onsuccess' in event.target is true
PASS 'onerror' in event.target is true
PASS 'readyState' in event.target is true
PASS event.target.readyState is event.target.DONE
PASS event.code is webkitIDBDatabaseException.DATA_ERR
store.add({name: 'Adam'}, 1)
addAdamSuccess():
Success event fired:
PASS 'result' in event is true
PASS 'code' in event is false
PASS 'message' in event is false
PASS 'source' in event is true
PASS event.source != null is true
PASS 'onsuccess' in event.target is true
PASS 'onerror' in event.target is true
PASS 'readyState' in event.target is true
PASS event.target.readyState is event.target.DONE
PASS event.result is 1
PASS successfullyParsed is true
TEST COMPLETE
<html>
<head>
<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
<script src="../../fast/js/resources/js-test-pre.js"></script>
<script src="../../fast/js/resources/js-test-post-function.js"></script>
<script src="resources/shared.js"></script>
</head>
<body>
<p id="description"></p>
<div id="console"></div>
<script>
description("Test IndexedDB's IDBObjectStore auto-increment feature.");
if (window.layoutTestController)
layoutTestController.waitUntilDone();
function test()
{
result = evalAndLog("webkitIndexedDB.open('Address Book')");
verifyResult(result);
result.onsuccess = openSuccess;
result.onerror = unexpectedErrorCallback;
}
function openSuccess()
{
debug("openSuccess():");
verifySuccessEvent(event);
window.db = evalAndLog("db = event.result");
result = evalAndLog("db.setVersion('new version')");
verifyResult(result);
result.onsuccess = setVersionSuccess;
result.onerror = unexpectedErrorCallback;
}
function setVersionSuccess()
{
debug("setVersionSuccess():");
verifySuccessEvent(event);
window.trans = evalAndLog("trans = event.result");
shouldBeTrue("trans !== null");
trans.onabort = unexpectedAbortCallback;
trans.oncomplete = setVersionCompleted;
deleteAllObjectStores(db, createObjectStore);
}
function createObjectStore()
{
debug("createObjectStore():");
window.store = evalAndLog("store = db.createObjectStore('StoreWithKeyPath', {keyPath: 'id', autoIncrement: true})");
evalAndLog("db.createObjectStore('StoreWithAutoIncrement', {autoIncrement: true})");
evalAndLog("db.createObjectStore('PlainOldStore', {autoIncrement: false})");
var storeNames = evalAndLog("storeNames = db.objectStoreNames");
shouldBeEqualToString("store.name", "StoreWithKeyPath");
shouldBe("store.keyPath", "'id'");
shouldBe("storeNames.contains('StoreWithKeyPath')", "true");
shouldBe("storeNames.contains('StoreWithAutoIncrement')", "true");
shouldBe("storeNames.contains('PlainOldStore')", "true");
shouldBe("storeNames.length", "3");
// Let the setVersion transaction complete.
}
function setVersionCompleted()
{
debug("setVersionCompleted():");
window.trans = evalAndLog("trans = db.transaction({mode: webkitIDBTransaction.READ_WRITE})");
trans.onabort = unexpectedAbortCallback;
trans.oncomplete = done;
window.store = evalAndLog("store = trans.objectStore('StoreWithKeyPath')");
debug("Insert in object store with key gen and key path");
result = evalAndLog("store.add({name: 'Lincoln', number: '7012'})");
result.onsuccess = unexpectedSuccessCallback;
result.onerror = addLincolnError;
}
function addLincolnError()
{
debug("addLincolnError():");
verifyErrorEvent(event);
// FIXME: This should be implemented, but we make it an error for now.
shouldBe("event.code", "webkitIDBDatabaseException.UNKNOWN_ERR");
window.store = evalAndLog("store = trans.objectStore('StoreWithAutoIncrement')");
debug("Insert into object store with key gen using explicit key");
result = evalAndLog("store.add({name: 'Lincoln'}, 1)");
result.onsuccess = unexpectedSuccessCallback;
result.onerror = addWithExplicitKeyError;
}
function addWithExplicitKeyError()
{
debug("addWithExplicitKeyError():");
verifyErrorEvent(event);
shouldBe("event.code", "webkitIDBDatabaseException.DATA_ERR");
debug("Insert into object store with key gen and no key path");
result = evalAndLog("store.add({name: 'Lincoln', number: '7012'})");
result.onsuccess = addLincolnSuccess;
result.onerror = unexpectedErrorCallback;
}
function addLincolnSuccess()
{
debug("addLincolnSuccess():");
verifySuccessEvent(event);
shouldBe("event.result", "1");
result = evalAndLog("store.get(1)");
result.onsuccess = getLincolnSuccess;
result.onerror = unexpectedErrorCallback;
}
function getLincolnSuccess()
{
debug("getLincolnSuccess():");
verifySuccessEvent(event);
shouldBeEqualToString("event.result.name", "Lincoln");
shouldBeEqualToString("event.result.number", "7012");
result = evalAndLog("store.put({name: 'Abraham', number: '2107'})");
result.onsuccess = putAbrahamSuccess;
result.onerror = unexpectedErrorCallback;
}
function putAbrahamSuccess()
{
debug("putAbrahamSuccess():");
verifySuccessEvent(event);
shouldBe("event.result", "2");
result = evalAndLog("store.get(2)");
result.onsuccess = getAbrahamSuccess;
result.onerror = unexpectedErrorCallback;
}
function getAbrahamSuccess()
{
debug("getAbrahamSuccess():");
verifySuccessEvent(event);
shouldBeEqualToString("event.result.name", "Abraham");
shouldBeEqualToString("event.result.number", "2107");
window.store = evalAndLog("store = trans.objectStore('PlainOldStore')");
debug("Try adding with no key to object store without auto increment.");
result = evalAndLog("store.add({name: 'Adam'})");
result.onsuccess = unexpectedSuccessCallback;
result.onerror = addAdamError;
}
function addAdamError()
{
debug("addAdamError():");
verifyErrorEvent(event);
shouldBe("event.code", "webkitIDBDatabaseException.DATA_ERR");
result = evalAndLog("store.add({name: 'Adam'}, 1)");
result.onsuccess = addAdamSuccess;
result.onerror = unexpectedErrorCallback;
}
function addAdamSuccess()
{
debug("addAdamSuccess():");
verifySuccessEvent(event);
shouldBe("event.result", "1");
}
test();
var successfullyParsed = true;
</script>
</body>
</html>
2011-01-19 Hans Wennborg <hans@chromium.org>
Reviewed by Jeremy Orlow.
IndexedDB: Support auto-increment keys
https://bugs.webkit.org/show_bug.cgi?id=52576
Add support for auto-increment keys.
Test: storage/indexeddb/objectstore-autoincrement.html
* storage/IDBDatabase.cpp:
(WebCore::IDBDatabase::createObjectStore):
* storage/IDBObjectStoreBackendImpl.cpp:
(WebCore::genAutoIncrementKey):
(WebCore::IDBObjectStoreBackendImpl::putInternal):
2011-01-19 Csaba Osztrogonác <ossy@webkit.org>
 
Reviewed by Laszlo Gombos and Tor Arne Vestbø.
......@@ -73,12 +73,6 @@ PassRefPtr<IDBObjectStore> IDBDatabase::createObjectStore(const String& name, co
options.getKeyBool("autoIncrement", autoIncrement);
// FIXME: Look up evictable and pass that on as well.
if (autoIncrement) {
// FIXME: Implement support for auto increment.
ec = IDBDatabaseException::UNKNOWN_ERR;
return 0;
}
RefPtr<IDBObjectStoreBackendInterface> objectStore = m_backend->createObjectStore(name, keyPath, autoIncrement, m_setVersionTransaction.get(), ec);
if (!objectStore) {
ASSERT(ec);
......
......@@ -59,6 +59,7 @@ IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(IDBSQLiteDatabase* database
, m_name(name)
, m_keyPath(keyPath)
, m_autoIncrement(autoIncrement)
, m_autoIncrementNumber(-1)
{
loadIndexes();
}
......@@ -69,6 +70,7 @@ IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(IDBSQLiteDatabase* database
, m_name(name)
, m_keyPath(keyPath)
, m_autoIncrement(autoIncrement)
, m_autoIncrementNumber(-1)
{
}
......@@ -113,7 +115,7 @@ void IDBObjectStoreBackendImpl::getInternal(ScriptExecutionContext*, PassRefPtr<
}
ASSERT((key->type() == IDBKey::StringType) != query.isColumnNull(0));
// FIXME: Implement date.
ASSERT((key->type() == IDBKey::DateType) != query.isColumnNull(1));
ASSERT((key->type() == IDBKey::NumberType) != query.isColumnNull(2));
callbacks->onSuccess(SerializedScriptValue::createFromWire(query.getColumnText(3)));
......@@ -200,22 +202,36 @@ void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr<
RefPtr<SerializedScriptValue> value = prpValue;
RefPtr<IDBKey> key = prpKey;
// FIXME: Support auto-increment.
if (!objectStore->m_keyPath.isNull() && key) {
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "A key was supplied for an objectStore that has a keyPath."));
return;
}
if (objectStore->autoIncrement() && key) {
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "A key was supplied for an objectStore that is using auto increment."));
return;
}
if (!objectStore->m_keyPath.isNull()) {
if (key) {
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "A key was supplied for an objectStore that has a keyPath."));
if (objectStore->autoIncrement()) {
key = objectStore->genAutoIncrementKey();
if (!objectStore->m_keyPath.isNull()) {
// FIXME: Inject the generated key into the object.
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Adding data to object stores with auto increment and in-line keys not yet supported."));
return;
}
} else if (!objectStore->m_keyPath.isNull()) {
key = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
if (!key) {
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "The key could not be fetched from the keyPath."));
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "The key could not be fetched from the keyPath."));
return;
}
} else if (!key) {
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "No key supplied."));
return;
}
if (key->type() == IDBKey::NullType) {
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "NULL key is not allowed."));
return;
......@@ -511,6 +527,27 @@ void IDBObjectStoreBackendImpl::addIndexToMap(ScriptExecutionContext*, PassRefPt
objectStore->m_indexes.set(indexPtr->name(), indexPtr);
}
PassRefPtr<IDBKey> IDBObjectStoreBackendImpl::genAutoIncrementKey()
{
if (m_autoIncrementNumber > 0)
return IDBKey::createNumber(m_autoIncrementNumber++);
String sql = "SELECT max(keyNumber) + 1 FROM ObjectStoreData WHERE objectStoreId = ? AND keyString IS NULL AND keyDate IS NULL";
SQLiteStatement query(sqliteDatabase(), sql);
bool ok = query.prepare() == SQLResultOk;
ASSERT_UNUSED(ok, ok);
query.bindInt64(1, id());
if (query.step() != SQLResultRow || query.isColumnNull(0))
m_autoIncrementNumber = 1;
else
m_autoIncrementNumber = static_cast<int>(query.getColumnDouble(0));
return IDBKey::createNumber(m_autoIncrementNumber++);
}
} // namespace WebCore
......
......@@ -82,6 +82,7 @@ private:
void loadIndexes();
SQLiteDatabase& sqliteDatabase() const;
PassRefPtr<IDBKey> genAutoIncrementKey();
static void getInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>);
static void putInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key, bool addOnly, PassRefPtr<IDBCallbacks>, PassRefPtr<IDBTransactionBackendInterface>);
......@@ -103,6 +104,7 @@ private:
typedef HashMap<String, RefPtr<IDBIndexBackendImpl> > IndexMap;
IndexMap m_indexes;
int m_autoIncrementNumber;
};
} // namespace WebCore
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment