Re: IndexedDB >> Proposed API Change: cursor.advance BACKWARD when direction is "prev"

On Fri, May 23, 2014 at 6:24 PM, marc fawzi <marc.fawzi@gmail.com> wrote:

> Here is a jsfiddle showing how .advance behaves when the range is
> restricted by .only
>
> Create new e.g. 7 items with names like "marc" and tags like "w1 w3 w5 w2"
> (random selection of tags with some tags appearing across multiple records
> (per the attached image)
>
> Enter "w2" or "w5" in the box next to 'get by tag' and click 'get by tag'
>
> You'll see the first 2 matching items, with primary keys 7 and 6
>
> Click 'get by tag' again and you'll see the next 2 matching items, with
> primary keys 4 and 2
>
> Click 'get by tag' again and you'll see the next and last matching item,
> with primary key 1
>
> Notice the way I advance the cursor each time in order to re-continue the
> search from where I left off in the previous invocation is by using the
> number of items already found
>
> http://jsfiddle.net/marcfawzi/y5ELj/
>
>
Thanks for sharing this example.


> It's the correct behavior but it would be easier imo if we have .find()
> for what .continue() and .continue(key) does and use .continue() to mean
> .advance(1) and .continue(n) to mean .advance(n)
>
> But I could be totally wrong. Just a harmless feedback at this point.
>
>
It's a reasonable suggestion. Unfortunately, we already have multiple
shipping implementations and code in the wild depending on the API as
specified, and this would be a breaking change. It's useful feedback if we
add new cursor/iteration APIs in the future, though - the current choice of
"continue" and "advance" vs. e.g. "find" or "seek" is pretty arbitrary and
can be a source of confusion.

Thanks again for following up with examples to ensure we understood your
feedback!


> :)
>
>
> On Fri, May 23, 2014 at 1:07 PM, marc fawzi <marc.fawzi@gmail.com> wrote:
>
>> <<
>> Thanks for following up! At least two IDB implementers were worried that
>> you'd found some browser bugs we couldn't reproduce.
>> >>
>> Yup. I had to figure this stuff out as the API is very low level (which
>> is why it can also be used in very powerful ways and also potentially very
>> confusing for the uninitiated)
>>
>> <<Assuming the store has [1,2,3,4,5,6,7,8,9] and the cursor's range is
>> not restricted, if the cursor's key=7 and direction='prev' then I would
>> expect after advance(2) that key=5. If you're seeing key=2 can you post a
>> sample somewhere (e.g. jsfiddle.com?)>>
>>
>> In the case I have say 7 items [1,2,3,4,5,6,7] and the cursor's range is
>> restricted by IDBKeyRange.only(val, "prev") ... so if the matching (or in
>> range) items are at 7, 6, 4, 2, 1 then I can obtain them individually or in
>> contiguous ranges by advancing the cursor on each consecutive invocation of
>> my search routine, like so: on first invocation advance(1) from 7 to 6, on
>> second invocation advance(2) from 7 to 4, on third invocation advance(3)
>> from 7 to 2 and on fourth invocation advance(4) from 7 to 1. I could also
>> use advance to advance by 1 within each invocation until no matching items
>> are found but only up to 2 times an invocation (for a store with 700 or
>> 70000 items we can advance by 1 about 200 times per invocation, but that's
>> arbitrary)
>>
>>  I can definitely post a jsfiddle if you believe the above is not in
>> accordance with the spec.
>>
>> As to continue(n) or continue(any string), i would make that
>> .find(something)
>>
>>
>>
>> On Fri, May 23, 2014 at 10:41 AM, Joshua Bell <jsbell@google.com> wrote:
>>
>>> On Fri, May 23, 2014 at 9:40 AM, marc fawzi <marc.fawzi@gmail.com>wrote:
>>>
>>>> I thought .continue/advance was similar to the 'continue' statement in
>>>> a for loop in that everything below the statement will be ignored and the
>>>> loop would start again from the next index. So my console logging was
>>>> giving confusing results. I figured it out and it works fine now.
>>>>
>>>
>>> Thanks for following up! At least two IDB implementers were worried that
>>> you'd found some browser bugs we couldn't reproduce.
>>>
>>>
>>>>  For sanity's sake, I've resorted to adding a 'return'  in my code in
>>>> the .success callback after every .advance and .continue so the execution
>>>> flow is easier to follow. It's very confusing, from execution flow
>>>> perspective, for execution to continue past .continue/.advance while at
>>>> once looping asynchronously. I understand it's two different instances of
>>>> the .success callback but it was entirely not clear to me from reading the
>>>> docs on MDN (for example) that .advance / .continue are async.
>>>>
>>>
>>> Long term, we expect JS to evolve better ways of expressing async calls
>>> and using async results. Promises are a first step, and hopefully the
>>> language also grows some syntax for them. IDB should jump on that train
>>> somehow.
>>>
>>>
>>>> Also, the description of .advance in browser vendor's documentation,
>>>> e.g. on MDN, says "Advance the cursor position forward by two places" for
>>>> cursor.advance(2) but what they should really say is "advance the cursor
>>>> position forward by two results." For example, let's say cursor first
>>>> landed on an item with primary key = 7, and you issue the statement
>>>> cursor.advance(2), I would expect it to go to the item with primary key 5
>>>> (for cursor direction = "prev") but instead it goes to the item with
>>>> primary key 2 because that's the 2nd match for the range argument from the
>>>> cursor's current position
>>>>
>>>
>>> What "range argument" are you referring to?
>>>
>>> Assuming the store has [1,2,3,4,5,6,7,8,9] and the cursor's range is not
>>> restricted, if the cursor's key=7 and direction='prev' then I would expect
>>> after advance(2) that key=5. If you're seeing key=2 can you post a sample
>>> somewhere (e.g. jsfiddle.com?)
>>>
>>>
>>>> , which means that .advance(n) would be far more clear semantically
>>>> speaking if it was simply done as .continue(n)  ... I guess if there is an
>>>> understanding that the cursor is always at a matching item and that it
>>>> could only continue/advance to the next/prev matching item, not literal
>>>> 'positions' in the table (i.e. sequentially through the list of all items)
>>>> then there would be no confusion but the very concept of a cursor is
>>>> foreign to most front end developers, and that's where the confusion comes
>>>> from for many.
>>>>
>>>> My inclination as a front end developer, so far removed from database
>>>> terminology, would be
>>>>
>>>> 1) to deprecate .advance in favor of .continue(n) and
>>>>
>>>
>>> continue(n) already has meaning - it jumps ahead to the key with value n
>>>
>>>
>>>>
>>>> 2) if it makes sense (you have to say why it may not) have
>>>> .continue()/.continue(n) cause the return of the execution flow similar to
>>>> 'continue' in a for loop.
>>>>
>>>
>>> The API can't change the language - you return from functions via return
>>> or throw. Further, there are reasons you may want to do further processing
>>> after calling continue() - e.g. there may be multiple cursors (e.g. in a
>>> join operation) or for better performance you can call continue() as early
>>> as possible so that the database can do its work while you're processing
>>> the previous result.
>>>
>>>
>>>
>>>>
>>>> What do you think?
>>>>
>>>>
>>>>
>>>> On Wed, May 21, 2014 at 10:42 AM, Joshua Bell <jsbell@google.com>wrote:
>>>>
>>>>>
>>>>>
>>>>>
>>>>> On Wed, May 21, 2014 at 7:32 AM, Arthur Barstow <art.barstow@gmail.com
>>>>> > wrote:
>>>>>
>>>>>> [ Bcc www-tag ; Marc - please use public-webapps for IDB discussions ]
>>>>>>
>>>>>> On 5/20/14 7:46 PM, marc fawzi wrote:
>>>>>>
>>>>>>> Hi everyone,
>>>>>>>
>>>>>>> I've been using IndexedDB for a week or so and I've noticed that
>>>>>>> cursor.advance(n) will always move n items forward regardless of cursor
>>>>>>> direction. In other words, when the cursor direction is set to "prev" as
>>>>>>> in: range = IDBKeyRange.only(someValue, "prev") and primary key is
>>>>>>> auto-incremented, the cursor, upon cursor.advance(n), will actually advance
>>>>>>> n items in the opposite direction to the cursor.continue() operation.
>>>>>>
>>>>>>
>>>>> That runs contrary to the spec. Both continue() and advance()
>>>>> reference the "steps for iterating a cursor" which picks up the direction
>>>>> from the cursor object; neither entry point alters the steps to affect the
>>>>> direction.
>>>>>
>>>>> When you say "you've noticed", are you observing a particular
>>>>> browser's implementation or are you interpreting the spec? I did a quick
>>>>> test and Chrome, Firefox, and IE all appear to behave as I expected when
>>>>> intermixing continue() and advance() calls with direction 'prev' - the
>>>>> cursor always moves in the same direction regardless of which call is used.
>>>>>
>>>>> Can you share sample code that demonstrates the problem, and indicate
>>>>> which browser(s) you've tested?
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>>  This is not only an issue of "broken symmetry" but it presents an
>>>>>>> obstacle to doing things like: keeping a record of the primaryKey of the
>>>>>>> last found item (after calling cursor.continue for say 200 times) and, long
>>>>>>> after the transaction has ended, call our search function again and, upon
>>>>>>> finding the same item it found first last time, advance the cursor to the
>>>>>>> previously recorded primary key and call cursor.continue 200 times, from
>>>>>>> that offset, and repeat whenever you need to fetch the next 200 matching
>>>>>>> items. Such algorithm works in the forward direction (from oldest to newest
>>>>>>> item) because cursor.advance(n) can be used to position the cursor forward
>>>>>>> at the previously recorded primary key (of last found item) but it does not
>>>>>>> work in the backward direction (from newest to oldest item) because there
>>>>>>> is no way to make the cursor advance backward. It only advances forward,
>>>>>>> regardless of its own set direction.
>>>>>>>
>>>>>>> This example is very rough and arbitrary. But it appears to me that
>>>>>>> the cursor.advance needs to obey the cursor's own direction setting. It's
>>>>>>> almost like having a car that only moves forward (and can't u-turn) and in
>>>>>>> order to move backward you have to reverse the road. That's bonkers.
>>>>>>>
>>>>>>> What's up with that?
>>>>>>>
>>>>>>> How naive or terribly misguided am I being?
>>>>>>>
>>>>>>> Thanks in advance.
>>>>>>>
>>>>>>> Marc
>>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>

Received on Tuesday, 27 May 2014 16:21:47 UTC