Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add openCursor(key, primaryKey) and continuePrimaryKey #14

Open
2 of 4 tasks
inexorabletash opened this issue May 19, 2015 · 16 comments
Open
2 of 4 tasks

Add openCursor(key, primaryKey) and continuePrimaryKey #14

inexorabletash opened this issue May 19, 2015 · 16 comments

Comments

@inexorabletash
Copy link
Member

https://www.w3.org/Bugs/Public/show_bug.cgi?id=20257

partial interface IDBIndex {
  IDBRequest openCursor(optional any query, optional IDBCursorDirection direction, IDBIndexOpenCursorOptions options);
  IDBRequest openKeyCursor(optional any query, optional IDBCursorDirection direction, IDBIndexOpenCursorOptions options);
}

dictionary IDBIndexOpenCursorOptions {
  any key;
  any primaryKey;
}

partial interface IDBCursor {
  void continuePrimaryKey(optional any key, optional any primaryKey);
}

If primaryKey is specified in options but key is not, throw.

  • cursor iteration operation
  • continuePrimaryKey()
  • IDBIndex.openCursor()
  • IDBIndex.openKeyCursor()
@inexorabletash
Copy link
Member Author

Need to specify what happens if you call continuePrimaryKey() on a cursor where the source is an object store. Throw?

I'm updating the experimental impl in Blink to throw InvalidAccessError in this case, pending further discussion.

@inexorabletash
Copy link
Member Author

What should the behavior of continuePrimaryKey() be with "prevunique" iteration? Given this index:

  • r1 = key: 'a', primary key: 1
  • r2 = key: 'a', primary key: 2
  • r3 = key: 'b', primary key: 1

If direction is "prevunique" and the cursor is at r3, continue('a') is specified to end up at r1 (the first record with matching key).

Cases:

  • If direction is "prevunique" and the cursor is at r3, continue('a', 1) should end up at... ?
    • r1 is obvious
  • If direction is "prevunique" and the cursor is at r3, continue('a', 2) should end up at... ?
    • r2 seems to make the most sense here, but r1 would be consistent too.
  • If direction is "prevunique" and the cursor is at r3, continue('a', 3) should end up at... ?
    • to me, r2 seems sensible here, but my intuition may be wonky

@inexorabletash
Copy link
Member Author

Heh, http://crbug.com/497454

@inexorabletash
Copy link
Member Author

Initial work in a4e4d2b

@inexorabletash
Copy link
Member Author

Another option is to throw if continuePrimaryKey() is used with "nextunique" or "prevunique" since the behavior is a bit odd.

@yathit
Copy link

yathit commented Jun 16, 2015

@inexorabletash +1 throw InvalidAccessError

@inexorabletash
Copy link
Member Author

@yathit do you mean for the object store source case, or for "nextunique" / "prevunique", or both?

@yathit
Copy link

yathit commented Jun 16, 2015

@inexorabletash both cases.

@inexorabletash
Copy link
Member Author

sgtm!

@inexorabletash
Copy link
Member Author

In the openCursor() case, is the lower-bound of the key range implicitly the index key if primaryKey is specified (and thus it's an error if a open lower bound is specified), or should the range and starting position be decoupled and require both the key and primaryKey to be explicit specified e.g. openCursor(null, null, {key: x, primaryKey: y}) ?

@yathit
Copy link

yathit commented Jun 20, 2015

Agree. IDBIndexOpenCursorOptions should be a complete cursor position.

dictionary IDBIndexOpenCursorOptions {
  IDBKey key, // nullable, default to lower-bound
  IDBKey primaryKey; // nullable, default to first
}

Using openCursor becomes easier. Let the keyRange unchanged and open with different starting position, without requiring keyRange to be met with cursor position.

@inexorabletash
Copy link
Member Author

Should we throw if primaryKey is specified but key is not? (I vote yes.)

Should we define any special behavior if options are used on a unique index? (I vote no.)

@inexorabletash
Copy link
Member Author

For posterity, here's how you'd write a fallback if these methods didn't exist:

  var options = {key: 2, primaryKey: 2};

  var req = idx.openCursor(null, 'next', options);
  req.onsuccess = function() {
    var cursor = req.result;
    if (!cursor) return;

    if (indexedDB.cmp(cursor.key, options.key) < 0 ||
      (indexedDB.cmp(cursor.key, options.key) === 0 &&
        indexedDB.cmp(cursor.primaryKey, options.primaryKey) < 0)) {

          // if you have continuePrimaryKey but not openCursor(..., options) for some reason
          if (cursor.continuePrimaryKey) {
            cursor.continuePrimaryKey(options.key, options.primaryKey);
            return;
          }

          // If index key is too low we can jump directly to that.
          if (indexedDB.cmp(cursor.key, options.key) < 0) {
            cursor.continue();
            return;
          }

          // Otherwise we're stuck iterating until we hit the right primary key.
          cursor.continue();
          return;
    }

    // The cursor is positioned at appropriate record - use it!
    cursor.continue();
  };

@pwnall
Copy link

pwnall commented Mar 9, 2017

Should this issue be closed? I'm pretty sure Chrome, Firefox and Safari are shipping this.

@inexorabletash
Copy link
Member Author

openCursor() with primaryKey specified is still a proposal - no-one implements that.

Currently you need to open the cursor against key then maybe call continuePrimaryKey() to advance it to the right primaryKey on the first iteration.

@pwnall
Copy link

pwnall commented Mar 9, 2017

Thanks for explaining! I missed that first part.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants