Add keyrange support for index cursors

This commit is contained in:
Ben Turner 2010-06-15 12:40:39 -07:00
parent 4a719c39a8
commit d1b409e700
6 changed files with 303 additions and 10 deletions

View File

@ -241,9 +241,26 @@ IDBIndexRequest::OpenCursor(nsIIDBKeyRange* aKeyRange,
return NS_ERROR_UNEXPECTED;
}
nsresult rv;
Key leftKey, rightKey;
PRUint16 keyRangeFlags = 0;
if (aKeyRange) {
NS_NOTYETIMPLEMENTED("Implement me!");
return NS_ERROR_NOT_IMPLEMENTED;
rv = aKeyRange->GetFlags(&keyRangeFlags);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIVariant> variant;
rv = aKeyRange->GetLeft(getter_AddRefs(variant));
NS_ENSURE_SUCCESS(rv, rv);
rv = IDBObjectStoreRequest::GetKeyFromVariant(variant, leftKey);
NS_ENSURE_SUCCESS(rv, rv);
rv = aKeyRange->GetRight(getter_AddRefs(variant));
NS_ENSURE_SUCCESS(rv, rv);
rv = IDBObjectStoreRequest::GetKeyFromVariant(variant, rightKey);
NS_ENSURE_SUCCESS(rv, rv);
}
if (aOptionalArgCount >= 2) {
@ -274,10 +291,10 @@ IDBIndexRequest::OpenCursor(nsIIDBKeyRange* aKeyRange,
nsRefPtr<OpenCursorHelper> helper =
new OpenCursorHelper(mObjectStore->Transaction(), request, this, mId,
mUnique, mAutoIncrement, Key(), Key(), 0, aDirection,
aPreload);
mUnique, mAutoIncrement, leftKey, rightKey,
keyRangeFlags, aDirection, aPreload);
nsresult rv = helper->DispatchToTransactionPool();
rv = helper->DispatchToTransactionPool();
NS_ENSURE_SUCCESS(rv, rv);
request.forget(_retval);
@ -516,6 +533,33 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
}
NS_NAMED_LITERAL_CSTRING(indexId, "index_id");
NS_NAMED_LITERAL_CSTRING(leftKeyName, "left_key");
NS_NAMED_LITERAL_CSTRING(rightKeyName, "right_key");
nsCAutoString keyRangeClause;
if (!mLeftKey.IsUnset()) {
keyRangeClause.AppendLiteral(" AND value");
if (mKeyRangeFlags & nsIIDBKeyRange::LEFT_OPEN) {
keyRangeClause.AppendLiteral(" > :");
}
else {
NS_ASSERTION(mKeyRangeFlags & nsIIDBKeyRange::LEFT_BOUND, "Bad flags!");
keyRangeClause.AppendLiteral(" >= :");
}
keyRangeClause.Append(leftKeyName);
}
if (!mRightKey.IsUnset()) {
keyRangeClause.AppendLiteral(" AND value");
if (mKeyRangeFlags & nsIIDBKeyRange::RIGHT_OPEN) {
keyRangeClause.AppendLiteral(" < :");
}
else {
NS_ASSERTION(mKeyRangeFlags & nsIIDBKeyRange::RIGHT_BOUND, "Bad flags!");
keyRangeClause.AppendLiteral(" <= :");
}
keyRangeClause.Append(rightKeyName);
}
nsCAutoString query("SELECT value, ");
query.Append(keyColumn);
@ -523,6 +567,7 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
query.Append(table);
query.AppendLiteral(" WHERE index_id = :");
query.Append(indexId);
query.Append(keyRangeClause);
query.AppendLiteral(" ORDER BY value ");
switch (mDirection) {
@ -551,6 +596,32 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
nsresult rv = stmt->BindInt64ByName(indexId, mId);
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
if (!mLeftKey.IsUnset()) {
if (mLeftKey.IsString()) {
rv = stmt->BindStringByName(leftKeyName, mLeftKey.StringValue());
}
else if (mLeftKey.IsInt()) {
rv = stmt->BindInt64ByName(leftKeyName, mLeftKey.IntValue());
}
else {
NS_NOTREACHED("Bad key!");
}
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
}
if (!mRightKey.IsUnset()) {
if (mRightKey.IsString()) {
rv = stmt->BindStringByName(rightKeyName, mRightKey.StringValue());
}
else if (mRightKey.IsInt()) {
rv = stmt->BindInt64ByName(rightKeyName, mRightKey.IntValue());
}
else {
NS_NOTREACHED("Bad key!");
}
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
}
PRBool hasResult;
while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
if (mData.Capacity() == mData.Length()) {
@ -620,5 +691,7 @@ OpenCursorHelper::GetSuccessResult(nsIWritableVariant* aResult)
aResult->SetAsISupports(static_cast<IDBRequest::Generator*>(cursor));
mIndex = nsnull;
return OK;
}

View File

@ -64,7 +64,7 @@ protected:
PRUint16 aFlags);
IDBKeyRange()
: mFlags(nsIIDBKeyRange::SINGLE)
: mFlags(0)
{ }
~IDBKeyRange() { }

View File

@ -181,7 +181,7 @@ public:
private:
// In-params.
const nsRefPtr<IDBObjectStoreRequest> mObjectStore;
nsRefPtr<IDBObjectStoreRequest> mObjectStore;
const Key mLeftKey;
const Key mRightKey;
const PRUint16 mKeyRangeFlags;
@ -1460,7 +1460,9 @@ AddHelper::UpdateIndexes(mozIStorageConnection* aConnection,
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->Execute();
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(rv)) {
return rv;
}
}
return NS_OK;
@ -1754,6 +1756,8 @@ OpenCursorHelper::GetSuccessResult(nsIWritableVariant* aResult)
aResult->SetAsISupports(static_cast<IDBRequest::Generator*>(cursor));
mObjectStore = nsnull;
return OK;
}

View File

@ -566,7 +566,8 @@ IndexedDatabaseRequest::MakeSingleKeyRange(nsIVariant* aValue,
}
nsRefPtr<IDBKeyRange> range =
IDBKeyRange::Create(aValue, aValue, PRUint16(nsIIDBKeyRange::SINGLE));
IDBKeyRange::Create(aValue, aValue, PRUint16(nsIIDBKeyRange::LEFT_BOUND |
nsIIDBKeyRange::RIGHT_BOUND));
NS_ASSERTION(range, "Out of memory?");
range.forget(_retval);

View File

@ -49,7 +49,6 @@ interface nsIVariant;
[scriptable, uuid(8e6b05f4-2358-420b-a6fd-03416543ed18)]
interface nsIIDBKeyRange : nsISupports
{
const unsigned short SINGLE = 0;
const unsigned short LEFT_OPEN = 1 << 1;
const unsigned short RIGHT_OPEN = 1 << 2;
const unsigned short LEFT_BOUND = 1 << 3;

View File

@ -232,6 +232,222 @@
is(keyIndex, -1, "Saw all the expected keys");
keyIndex = 1;
let keyRange = moz_indexedDB.makeBoundKeyRange("Bob", "Ron");
request = objectStore.index("name").openCursor(keyRange);
request.onerror = errorHandler;
request.onsuccess = function (event) {
let cursor = event.result;
if (cursor) {
is(cursor.key, objectStoreDataNameSort[keyIndex].value.name,
"Correct key");
is(cursor.value, objectStoreDataNameSort[keyIndex].key,
"Correct value");
cursor.continue();
keyIndex++;
}
else {
testGenerator.next();
}
}
yield;
is(keyIndex, 5, "Saw all the expected keys");
keyIndex = 2;
let keyRange = moz_indexedDB.makeBoundKeyRange("Bob", "Ron", true);
request = objectStore.index("name").openCursor(keyRange);
request.onerror = errorHandler;
request.onsuccess = function (event) {
let cursor = event.result;
if (cursor) {
is(cursor.key, objectStoreDataNameSort[keyIndex].value.name,
"Correct key");
is(cursor.value, objectStoreDataNameSort[keyIndex].key,
"Correct value");
cursor.continue();
keyIndex++;
}
else {
testGenerator.next();
}
}
yield;
is(keyIndex, 5, "Saw all the expected keys");
keyIndex = 1;
let keyRange = moz_indexedDB.makeBoundKeyRange("Bob", "Ron", false, true);
request = objectStore.index("name").openCursor(keyRange);
request.onerror = errorHandler;
request.onsuccess = function (event) {
let cursor = event.result;
if (cursor) {
is(cursor.key, objectStoreDataNameSort[keyIndex].value.name,
"Correct key");
is(cursor.value, objectStoreDataNameSort[keyIndex].key,
"Correct value");
cursor.continue();
keyIndex++;
}
else {
testGenerator.next();
}
}
yield;
is(keyIndex, 4, "Saw all the expected keys");
keyIndex = 2;
keyRange = moz_indexedDB.makeBoundKeyRange("Bob", "Ron", true, true);
request = objectStore.index("name").openCursor(keyRange);
request.onerror = errorHandler;
request.onsuccess = function (event) {
let cursor = event.result;
if (cursor) {
is(cursor.key, objectStoreDataNameSort[keyIndex].value.name,
"Correct key");
is(cursor.value, objectStoreDataNameSort[keyIndex].key,
"Correct value");
cursor.continue();
keyIndex++;
}
else {
testGenerator.next();
}
}
yield;
is(keyIndex, 4, "Saw all the expected keys");
keyIndex = 1;
keyRange = moz_indexedDB.makeLeftBoundKeyRange("Bob");
request = objectStore.index("name").openCursor(keyRange);
request.onerror = errorHandler;
request.onsuccess = function (event) {
let cursor = event.result;
if (cursor) {
is(cursor.key, objectStoreDataNameSort[keyIndex].value.name,
"Correct key");
is(cursor.value, objectStoreDataNameSort[keyIndex].key,
"Correct value");
cursor.continue();
keyIndex++;
}
else {
testGenerator.next();
}
}
yield;
is(keyIndex, objectStoreDataNameSort.length, "Saw all the expected keys");
keyIndex = 2;
keyRange = moz_indexedDB.makeLeftBoundKeyRange("Bob", true);
request = objectStore.index("name").openCursor(keyRange);
request.onerror = errorHandler;
request.onsuccess = function (event) {
let cursor = event.result;
if (cursor) {
is(cursor.key, objectStoreDataNameSort[keyIndex].value.name,
"Correct key");
is(cursor.value, objectStoreDataNameSort[keyIndex].key,
"Correct value");
cursor.continue();
keyIndex++;
}
else {
testGenerator.next();
}
}
yield;
is(keyIndex, objectStoreDataNameSort.length, "Saw all the expected keys");
keyIndex = 0;
keyRange = moz_indexedDB.makeRightBoundKeyRange("Joe");
request = objectStore.index("name").openCursor(keyRange);
request.onerror = errorHandler;
request.onsuccess = function (event) {
let cursor = event.result;
if (cursor) {
is(cursor.key, objectStoreDataNameSort[keyIndex].value.name,
"Correct key");
is(cursor.value, objectStoreDataNameSort[keyIndex].key,
"Correct value");
cursor.continue();
keyIndex++;
}
else {
testGenerator.next();
}
}
yield;
is(keyIndex, 3, "Saw all the expected keys");
keyIndex = 0;
keyRange = moz_indexedDB.makeRightBoundKeyRange("Joe", true);
request = objectStore.index("name").openCursor(keyRange);
request.onerror = errorHandler;
request.onsuccess = function (event) {
let cursor = event.result;
if (cursor) {
is(cursor.key, objectStoreDataNameSort[keyIndex].value.name,
"Correct key");
is(cursor.value, objectStoreDataNameSort[keyIndex].key,
"Correct value");
cursor.continue();
keyIndex++;
}
else {
testGenerator.next();
}
}
yield;
is(keyIndex, 2, "Saw all the expected keys");
keyIndex = 3;
keyRange = moz_indexedDB.makeSingleKeyRange("Pat");
request = objectStore.index("name").openCursor(keyRange);
request.onerror = errorHandler;
request.onsuccess = function (event) {
let cursor = event.result;
if (cursor) {
is(cursor.key, objectStoreDataNameSort[keyIndex].value.name,
"Correct key");
is(cursor.value, objectStoreDataNameSort[keyIndex].key,
"Correct value");
cursor.continue();
keyIndex++;
}
else {
testGenerator.next();
}
}
yield;
is(keyIndex, 4, "Saw all the expected keys");
finishTest();
yield;
}