Re: [IndexedDB] Proposal for async API changes

On 5/18/2010 7:20 AM, Jeremy Orlow wrote:
>> 1. Once a database has been opened (a database connection has been
>> established) read access to meta-data, such as objectStore and index
>> names, is synchronous. Changes to such meta data, such as creating
>> objectStores and indexes, is still asynchronous.
> I believe this is already how it's specced.  The IDBDatabase interface
> already gives you synchronous access to all of this.
Mostly that is the same, with the exception of getting an object store 
or index which is now synchronous.

>> 9. IDBKeyRanges are created using functions on IndexedDatabaseRequest.
>> We couldn't figure out how the old API allowed you to create a range
>> object without first having a range object.
> In the spec, I see the following in examples:
> var range = new IDBKeyRange.bound(2, 4);
> and
> var range = IDBKeyRange.leftBound(key);
>
> I'm not particularly happy with hanging functions off of
> IndexedDatabaseRequest for this.  Can it work something like what I listed
> above?  If not, maybe we can find a better place to put them?  Or just
> create multiple openCursor functions for each case?
I think one concern with the above syntax is that it's adding another 
object to the global scope.  I recall Ben Turner and I discussing the 
possibility of hanging it off of indexedDB, so:
var range = new indexedDB.KeyRange.bound(2, 4);

My concern with making multiple openCursor functions is that there is 
more API complexity there.  With that said, I don't have any strong 
opinions here either way.

>> 10. You are allowed to have multiple transactions per database
>> connection. However if they use overlapping tables, only the first one
>> will receive events until it is finished (with the usual exceptions of
>> allowing multiple readers of the same table).
> Can you please clarify what you mean here?  This seems like simply an
> implementation detail to me, so maybe I'm missing something?
What this is trying to say is that you can have an object store being 
used in more than one transaction, but they cannot access it at the same 
time.  However, I think it's best for Jonas to chime in here because 
this doesn't quite seem right to me like it did yesterday.

> 5)  You have two IDBTransactionRequest.onaborts.  I think one is supposed to
> be an ontimeout.
Whoops, I thought we fixed that before he sent this out :)

> 6)  What is the default limit for the getAll functions?  Should we make it 0
> (and define any<=0 amount to mean infinity)?
I believe we intended the default to be infinity (as in, if you don't 
specify, you get it all).

> 7)  I expect "add or modify" to be more used than the add or the modify
> methods.  As such, I wonder if it makes sense to optimize the naming for
> that.  For example, addOrModify=>set, add=>add/insert,
> modify=>modify/update/replace maybe?
We had a lot of internal debate over this very thing.  The problem we 
kept running into was that set could easily be read as doing just 
updating so it wouldn't be clear that you can also insert a new record 
there (without reading the spec or some tutorial).  The benefit with 
addOrModify is that it is very explicit in what it does.  We don't like 
how long it is, but we couldn't come up with a shorter name that doesn't 
have a fair amount of ambiguity.

> 8)   We can't leave deciding whether a cursor is pre-loaded up to UAs
> since people will code for their favorite UA and then access
> IDBCursorPreloadedRequest.count when some other UA does it as a
> non-preloaded request.  Even in the same UA this will cause problems when
> users have different datasets than developers are testing with.
I think that you might have been confused by our wording there.  Sorry 
about that!  IDBCursorPreloadedRequest is what you get if you pass 
sync=true into openCursor or openObjectCursor.  Basically, sync cursors 
will give you a count, whereas async ones will not.

> interface IBDCursorRequest : IDBCursor {
>    readonly attribute any key;
>
>    readonly attribute any value;
>
>    *readonly attribute unsigned long long estimatedCount;*
>
>   * // Returns null if the cursor was updated synchronously.  Otherwise*
> *  // will return an IDBRequest object whose result will be set to this*
> *  // cursor on success.  Until onsuccess is called, any access of key*
> *  // or value will raise an exception.  The first request MUST cause*
> *  // an asynchronous request but the behavior of subsequent calls is*
> *  // up to the UA.*
> *  IDBRequest continue(in optional any key /* null */);*
>
>    // Success fires IDBTransactionEvent, result == key
>    IDBRequest update(in any value);
>
>    // Success fires IDBTransactionEvent, result == null
>    IDBRequest remove();
> };
>
> I'm not super happy with this interface, but I think it's a lot better for a
> few reasons:
> 1) It's not all or nothing.  Even if a result can't be 100% loaded into
> memory, it doesn't mean that we'll have to deal with the overhead of every
> fetch causing an asynchronous firing of an event.

> 2) There's an estimated count even if it's not pre-loaded (which has been
> requested in other threads).
Were there use cases in those other threads?  We couldn't come up with a 
case that would have been useful.

> 3) Because the first continue call will always be asynchronous, people using
> this interface cannot get away with assuming results are always returned
> synchronously, so the problems I mentioned in (8) are pretty much gone.
Not sure this matters (see my clarification).

Cheers,

Shawn

Received on Tuesday, 18 May 2010 17:32:15 UTC