Re: IDBObjectStore/IDBIndex.exists(key)

2014-06-21 Thread ben turner
I think this sounds like a fine idea.

-Ben Turner


On Sat, Jun 21, 2014 at 5:39 PM, Jonas Sicking jo...@sicking.cc wrote:

 Hi all,

 I found an old email with notes about features that we might want to put
 in v2.

 Almost all of them was recently brought up in the recent threads about
 IDBv2. However there was one thing on the list that I haven't seen brought
 up.

 It might be a nice perf improvement to add support for a
 IDBObjectStore/IDBIndex.exists(key) function.

 This would require less IO and less object creation than simply using
 .get(). It is probably particularly useful when doing a filtering join
 operation between two indexes/object stores. But it is probably useful
 other times too.

 Is this something that others think would be useful?

 / Jonas



Re: [indexeddb] Do we need to support keyPaths with an empty string?

2012-01-20 Thread ben turner
Mozilla is fine with removing the special |keyPath:| behavior.
Please note that this will also mean that step 1 of the algorithm here

  
http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#dfn-steps-for-extracting-a-key-from-a-value-using-a-key-path

will need to change.

We do want to continue to allow set behavior without specifying the
key twice, though, so we would propose adding an additional option to
createObjectStore to accomplish this:

  // Old way:
  var set = db.createObjectStore(mySet, { keyPath: });
  set.put(keyValue);

  // New way:
  var set = db.createObjectStore(mySet, { isSet: true });
  set.put(keyValue);

(We are not in love with isSet, better names are highly encouraged!)

What do you all think? This would allow us to continue to support nice
set behavior without making the empty string magic.

-Ben



Re: [indexeddb] Do we need to support keyPaths with an empty string?

2012-01-18 Thread ben turner
On Wed, Jan 18, 2012 at 1:16 PM, Israel Hilerio isra...@microsoft.com wrote:

 We did some testing in FF and Chrome and found different behaviors:

Hi Israel,

Which version of Firefox did you test with?

Thanks,
Ben



Re: [indexeddb] Do we need to support keyPaths with an empty string?

2012-01-18 Thread ben turner
On Wed, Jan 18, 2012 at 1:40 PM, Israel Hilerio isra...@microsoft.com wrote:
 We tested on Firefox 8.0.1

Ah, ok. We made lots of big changes to key handling that will be in 11
I think. If you're curious I would recommend retesting with an aurora
build from https://www.mozilla.org/en-US/firefox/aurora.

Thanks for the info!
-Ben



Re: [IndexedDB] Passing an empty array to IDBDatabase.transaction

2011-10-10 Thread ben turner
So it sounds like everyone agrees that accepting an empty array is not
desired... Can we just make that case throw an exception rather than
generating an empty transaction (which will then throw when it is
used)?

-Ben Turner



Re: [indexeddb] IDBTransaction.oncomplete event type equals commit

2011-06-23 Thread ben turner
I think complete should be the correct type string.

-Ben Turner



Re: What changes to Web Messaging spec are proposed? [Was: Re: Using ArrayBuffer as payload for binary data to/from Web Workers]

2011-06-08 Thread ben turner
I agree with Kenneth.

-Ben Turner

On Wed, Jun 8, 2011 at 2:33 PM, Kenneth Russell k...@google.com wrote:
 I prefer continuing to use an array for several reasons: simpler
 syntax, better type checking at the Web IDL level, and fewer
 ECMAScript-specific semantics.

 -Ken

 On Wed, Jun 8, 2011 at 2:29 PM, David Levin le...@chromium.org wrote:


 On Wed, Jun 8, 2011 at 2:24 PM, Kenneth Russell k...@google.com wrote:

 My understanding is that we have reached a proposal which respecifies
 the ports argument to postMessage as an array of objects to
 transfer, in such a way that we:

 Array or object? (by object I mean: {transfer: [arrayBuffer1], ports:
 [port]})


  - Maintain 100% backward compatibility
  - Enhance the ability to pass MessagePorts, so that the object graph
 can refer to them as well
  - Allow more object types to participate in transfer of ownership in the
 future

 To the best of my knowledge there are no active points of
 disagreement. I think we are only waiting for general consensus from
 all interested parties that this is the desired step to take.

 If it is, I would be happy to draft proposed edits to the associated
 specs; there are several, and the edits may be somewhat involved. I'd
 also be happy to share the work with Ian or anyone else.

 I don't know the various processes for web specs, but the Web
 Messaging spec will definitely need to be updated if we decide to move
 in this direction.

 -Ken

 On Wed, Jun 8, 2011 at 4:30 AM, Arthur Barstow art.bars...@nokia.com
 wrote:
  Now that the responses on this thread have slowed, I would appreciate if
  the
  participants would please summarize where they think we are on this
  issue,
  e.g. the points of agreement and disagreement, how to move forward, etc.
 
  Also, coming back to the question in the subject (and I apologize if my
  premature subject change caused any confusion or problems), since we
  have an
  open CfC (ends June 9 [1]) to publish a Candidate Recommendation of Web
  Messaging, is the Messaging spec going to need to change to address the
  issues raised in this thread?
 
  -Art Barstow
 
  [1]
  http://lists.w3.org/Archives/Public/public-webapps/2011AprJun/0797.html
 





Re: What changes to Web Messaging spec are proposed? [Was: Re: Using ArrayBuffer as payload for binary data to/from Web Workers]

2011-06-02 Thread ben turner
On Thu, Jun 2, 2011 at 9:58 AM, Travis Leithead
travis.leith...@microsoft.com wrote:

 This plan requires all objects that want to opt-in to a new 
 transfer-of-ownership (or really
 any special custom behavior for postMessage) to 1) participate in the special 
 inheritance
 interface and 2) be isolated from the primary object graph being passed to 
 the first
 parameter.

I interpreted the proposal differently... This is what I envisioned:

  var bufferToTransfer = /* make ArrayBuffer */;
  var bufferToCopy = /* make ArrayBuffer */;
  var worker = /* make Worker */;
  var message = { buf1: bufferToTransfer, buf2: bufferToCopy };
  worker.postMessage(message, [bufferToTransfer]);

We'd keep the structure exactly the same, it's just that when we clone
'message' we compare each object value to one of the ones passed in
the transfer array. If the objects match (===) then we'd transfer it
rather than copy it.

Does that sound like what you were hoping for?

-Ben Turner



Re: Indexed Database API

2011-03-04 Thread ben turner
Firefox does lazily deserialize cursor values, so the slowdown you're
noticing is most likely due to us preserving the order of request
callbacks by queuing every continue() call in line with the rest of
the transaction. Jonas had proposed a faster, high performance cursor
that did not respect this ordering, maybe that's all that you'd need.

However, a few thoughts:

1. How do you know Page 5 even exists? We haven't exposed a count()
function yet...
2. I think we should expose a count() function!
3. Maybe we should expose a getAt(long index, enum direction);
function on indexes and objectStores?

-Ben

On Fri, Mar 4, 2011 at 12:11 PM, Olli Pettay olli.pet...@helsinki.fi wrote:
 On 03/02/2011 09:02 AM, Ben Dilts wrote:

 Why is there no mechanism for paging results, a la SQL's limit?  If I
 want entries in positions 140-159 from an index, I have to call
 continue() on a cursor 139 times, which in turn unserializes 139 objects
 from my store that I don't care about, which in FF4 is making a lookup
 in IndexedDB sometimes take many seconds for even a few records.

 Sounds like there is something to optimize in the implementation.
 Have you filed a bug https://bugzilla.mozilla.org/enter_bug.cgi?product=Core
 component DOM ?
 If not, please do so and attach a *minimal* testcase.


 Thanks,


 -Olli


  It

 makes no sense--am I just missing something in the spec?


 Ben Dilts





Re: [IndexedDB] More questions about IDBRequests always firing (WAS: Reason for aborting transactions)

2011-02-17 Thread ben turner
 Also, what should we do when you enqueue a setVersion transaction and then
 close the database handle?  Maybe an ABORT_ERR there too?

 Yeah, that'd make sense to me. Just like if you enque any other
 transaction and then close the db handle.

We don't abort transactions that are already in progress when you call
db.close()... We just set a flag and prevent further transactions from
being created.

-Ben



Re: [Bug 11348] New: [IndexedDB] Overhaul of the event model

2011-02-11 Thread ben turner
It looks like I was wrong. Our current impl throws NOT_ALLOWED_ERR for
getting errorCode *and* result before readyState is set to DONE.

And now that I think about it I think I like that best. If we returned
NO_ERR from errorCode before DONE then it seems to imply that the
request succeeded when the reality is we don't yet know. Checking
errorCode before DONE is most likely a bug in the page script just as
calling result before DONE, so I'm happy with throwing here.

Sound ok?

-Ben



Re: [Bug 11348] New: [IndexedDB] Overhaul of the event model

2011-02-10 Thread ben turner
 I think generally avoiding throwing exceptions is a good thing. So for
 .errorCode I would say returning unidentified or 0 is the way to go.

I would say we should add a code to IDBDatabaseException, NO_ERR = 0.
Or else indicate somehow that 0 is reserved for no exception. Then
return that from errorCode.

 But it does seem like a
 pretty bad bug if you do access these properties before having a
 result. So maybe exception is in fact better here.

Definitely agreed. People will want to know that they're checking a
result too early.

-Ben



Re: [IndexedDB] Reason for aborting transactions

2011-02-09 Thread ben turner
Hm, Jeremy is right, If you want to look just at the transaction and
see why it aborted you can't rely on errorCode. Ick.

The only thing I'd change then is the abortMessage property. It's
easier to tell why your transaction aborted with the error code, and
I'd hate people doing string comparisons instead of checking the error
code. And what about localization?

-Ben



Re: [IndexedDB] Reason for aborting transactions

2011-02-09 Thread ben turner
 Normal exceptions have error messages that are not consistient across
 implementations and are not localized.  What's the difference?

These messages aren't part of any exception though, it's just some
property on a transaction object. (None of our DOM exceptions, IDB or
otherwise, have message properties btw, they're only converted to some
message if they make it to the error console).

 For stuff like internal errors, they seem especially important.

You're thinking of having multiple messages for the INTERAL_ERROR_ABORT code?

-Ben



Re: [IndexedDB] Reason for aborting transactions

2011-02-09 Thread ben turner
 (It's somewhat frustrating when they come back localized, but bearable.)

Sounds like what you really want is more specific error codes, not
really messages, right?

-Ben



Re: [IndexedDB] Reason for aborting transactions

2011-02-08 Thread ben turner
Why not just expand our list of error codes to have multiple ABORT_
variants for each situation, and then always fire the abort event
with a slightly different errorCode?

That seems far simpler IMO.

-Ben

On Tue, Feb 8, 2011 at 2:21 AM, Jonas Sicking jo...@sicking.cc wrote:
 On Mon, Feb 7, 2011 at 8:05 PM, Jeremy Orlow jor...@chromium.org wrote:
 On Mon, Feb 7, 2011 at 7:36 PM, Jonas Sicking jo...@sicking.cc wrote:

 On Fri, Jan 28, 2011 at 4:33 PM, Jeremy Orlow jor...@chromium.org wrote:
  We do that as well.
  What's the best way to do it API wise?  Do we need to add an
  IDBTransactionError object with error codes and such?

 I don't actually know. I can't think of a precedence. Usually you use
 different error codes for different errors, but here we want to
 distinguish a particular type of error (aborts) into several sub
 categories.

 I don't see how that's any different than what we're doing with the onerror
 error codes though?

 Hmm.. true.

 To make this more complicated, I actually think we're going to end up
 having to change a lot of error handling when things are all said and
 done. Error handling right now is sort of a mess since DOM exceptions
 are vastly different from JavaScript exceptions. Also DOM exceptions
 have a messy situation of error codes overlapping making it very easy
 to confuse a IDBDatabaseException with a DOMException with an
 overlapping error code.

 For details, see

 http://lists.w3.org/Archives/Public/public-script-coord/2010OctDec/0112.html

 So my gut feeling is that we'll have to revamp exceptions quite a bit
 before we unprefix our implementation. This is very unfortunate, but
 shouldn't be as big deal of a deal as many other changes as most of
 the time people don't have error handling code. Or at least not error
 handling code that differentiates the various errors.

 Unfortunately we can't make any changes to the spec here until WebIDL
 prescribes what the new exceptions should look like :(

 So to loop back to your original question, I think that the best way
 to expose the different types of aborts is by adding a .reason (or
 better named) property which returns a string or enum which describes
 the reason for the abort.

 Could we just add .abortCode, .abortReason, and constants for each code to
 IDBTransaction?

 Why both? How are they different. I'd just go with the former to align
 with error codes.

 And maybe revisit in the future?

 Yes. I think we need to wait for webidl to solidify a bit here before
 we do anything.

 / Jonas





Re: [IndexedDB] Reason for aborting transactions

2011-02-08 Thread ben turner
 I think that's what Ben was suggesting.

Yes. We already have ABORT_ERR, no reason we can't subdivide that
since it's being overloaded. In fact I think it makes perfect sense.

 Add the following to IDBTransaction:

I'm really not a fan of making IDBTransaction more complicated. We
already have a generic tell me when something goes wrong, and why
mechanism via errorCode and onError/onAbort. Why add another one? If
the name is confusing we could rename it to exceptionCode perhaps?

   readonly attribute abortMessage;

We dropped errorMessage already, let's not add abortMessage.

 And just set the message/code right before firing an abort event.

And what happens when someone calls .abortCode before the transaction
has finished? Or if the transaction succeeded? Or if the transaction
failed for some other reason? I think we'd probably want the same
behavior as calling .errorCode, so again I think we should just roll
the specific abort reasons into error codes and stick with our
existing mechanism.

-Ben



Re: [IndexedDB] setVersion blocked on uncollected garbage IDBDatabases

2011-02-08 Thread ben turner
I'm actually fine with keeping the setVersion from proceeding until
the old database is collected. First, this is probably a bug in the
web page, and the page should be fixed. Second, the new database that
is waiting for setVersion to proceed will get an onblocked event, so
the page should know that something is wrong.

I really don't think this is that big of a deal, and certainly not
worth changing the opt-in vs. opt-out behavior that we've settled on.

-Ben



Re: IndexedDB: updates through cursors on indexes that change the key

2011-02-01 Thread ben turner
Has anyone heard of or proposed any kind of use case where it would be
valuable to change the primary key of an object in the object store
(outside, or inside, a cursor)?

-Ben Turner



Re: IndexedDB: updates through cursors on indexes that change the key

2011-02-01 Thread ben turner
No, that idea was rejected a while ago. IndexedDB cursors are live, so
any change made during the cursor are visible to the cursor as well as
later queries.

-Ben Turner

On Tue, Feb 1, 2011 at 4:35 PM, Keean Schupke ke...@fry-it.com wrote:
 Surely the cursor should be atomic, representing the instant in time the
 query executed. Any updates or deletes etc would not be visible to the
 cursor, only to later queries. Then you can allow any modifications
 including to keys and indexes.

 Cheers,
 Keean

 On 2 Feb 2011 00:05, Jeremy Orlow jor...@chromium.org wrote:

 On Tue, Feb 1, 2011 at 2:56 PM, Jonas Sicking jo...@sicking.cc wrote:


 On Tue, Feb 1, 2011 at 11:44 AM, Jeremy Orlow jor...@chromium.org wrote:
  On Tue, Feb 1, 2...

 Good points (against having it remove the original key if it changes).
 After some more thought: The original idea behind cursor.delete() and
 cursor.update() was that they would basically just be aliases for
 objectStore.delete() and objectStore.put().  Maybe calling .update() with a
 changed primary key should simply have the same behavior as .put().  Thus
 the value corresponding to the original key would be left unmodified and the
 new key would then correspond to the new value.
 I can't think of any examples where the current behavior would get in
 someone's way though.  So I guess maybe we should just leave it as is.  But
 I still hate the idea of it being subtly different from being a straight up
 alias to put.
 J



Re: [Bug 11348] New: [IndexedDB] Overhaul of the event model

2011-01-27 Thread ben turner
 The call to .continue() returns a IDBRequest (same one as was
 originally returned from .openCursor()).

No... continue() returns void as currently spec'd and implemented in FF.

-Ben



Re: [Bug 11348] New: [IndexedDB] Overhaul of the event model

2011-01-27 Thread ben turner
 Lastly, let's say you're doing cursor.continue() on an index cursor, how can
 you get a handle to the objectStore?  I believe you can't.

We gave IDBCursor a source property too, that either points to the
objectStore or index depending on who called openCursor.

-Ben



Re: [IndexedDB] Events and requests

2011-01-10 Thread ben turner
FWIW Jonas' proposed changes have been implemented and will be
included in Firefox 4 Beta 9, due out in a few days.

-Ben

On Fri, Dec 10, 2010 at 12:47 PM, Jonas Sicking jo...@sicking.cc wrote:
 I've been reaching out to get feedback, but no success yet. Will re-poke.

 / Jonas

 On Fri, Dec 10, 2010 at 4:33 AM, Jeremy Orlow jor...@chromium.org wrote:
 Any additional thoughts on this?  If no one else cares, then we can go with
 Jonas' proposal (and we should file a bug).
 J

 On Thu, Nov 11, 2010 at 12:06 PM, Jeremy Orlow jor...@chromium.org wrote:

 On Tue, Nov 9, 2010 at 11:35 AM, Jonas Sicking jo...@sicking.cc wrote:

 Hi All,

 One of the things we briefly discussed at the summit was that we
 should make IDBErrorEvents have a .transaction. This since we are
 allowing you to place new requests from within error handlers, but we
 currently provide no way to get from an error handler to any useful
 objects. Instead developers will have to use closures to get to the
 transaction or other object stores.

 Another thing that is somewhat strange is that we only make the result
 available through the success event. There is no way after that to get
 it from the request. So instead we use special event interfaces with
 supply access to source, transaction and result.

 Compare this to how XMLHttpRequests work. Here the result and error
 code is available on the request object itself. The 'load' event,
 which is equivalent to our 'success' event didn't supply any
 information until we recently added progress event support. But still
 it only supplies information about the progress, not the actual value
 itself.

 One thing we could do is to move

 .source
 .transaction
 .result
 .error

 to IDBRequest. Then make success and error events be simple events
 which only implement the Event interface. I.e. we could get rid of the
 IDBEvent, IDBSuccessEvent, IDBTransactionEvent and IDBErrorEvent
 interfaces.

 We'd still have to keep IDBVersionChangeEvent, but it can inherit
 Event directly.

 The request created from IDBFactory.open would return a IDBRequest
 where .transaction and .source is null. We already fire a IDBEvent
 where .source is null (actually, the spec currently doesn't define
 what the source should be I see now).


 The only major downside with this setup that I can see is that the
 current syntax:

 db.transaction([foo]).objectStore(foo).get(mykey).onsuccess =
 function(e) {
  alert(e.result);
 }

 would turn into the slightly more verbose

 db.transaction([foo]).objectStore(foo).get(mykey).onsuccess =
 function(e) {
  alert(e.target.result);
 }

 (And note that with the error handling that we have discussed, the
 above code snippets are actually plausible (apart from the alert() of
 course)).

 The upside that I can see is that we behave more like XMLHttpRequest.
 It seems that people currently follow a coding pattern where they
 place a request and at some later point hand the request to another
 piece of code. At that point the code can either get the result from
 the .result property, or install a onload handler and wait for the
 result if it isn't yet available.

 However I only have anecdotal evidence that this is a common coding
 pattern, so not much to go on.

 Here's a counter proposal:  Let's add .transaction, .source, and .result
 to IDBEvent and just specify them to be null when there is no transaction,
 source, and/or result.  We then remove readyState from IDBResult as it
 serves no purpose.
 What I'm proposing would result in an API that's much more similar to what
 we have at the moment, but would be a bit different than XHR.  It is
 definitely good to have similar patterns for developers to follow, but I
 feel as thought the model of IndexedDB is already pretty different from XHR.
  For example, method calls are supplied parameters and return an IDBRequest
 object vs you using new to create the XHR object and then making method
 calls to set it up and then making a method call to start it.  In fact, if
 you think about it, there's really not that much XHR and IndexedDB have in
 common except that they use event handlers.
 As for your proposal, let me think about it for a bit and forward it on to
 some people I know who are playing with IndexedDB already.
 J






Re: [IndexedDB] .value of no-duplicate cursors

2010-11-11 Thread ben turner
On Thu, Nov 11, 2010 at 8:07 AM, Jonas Sicking jo...@sicking.cc wrote:
 The reason I specced it they way I did, with the lowest key always
 being used, is that this way a NEXT_NO_DUPLICATE and a
 PREV_NO_DUPLICATE cursor iterate the same entries. It seems unexpected
 that reversing direction would return different results?

I agree.

-Ben



Re: [Bug 11270] New: Interaction between in-line keys and key generators

2010-11-10 Thread ben turner
 Actually, we could go even further and disallow paths entirely, and
 just allow a property name. That is what the firefox implementation
 currently does. That also sidesteps the issue of missing parents.

I'm not convinced that people are going to bury their key several
levels deep on the documents they store. +1 for this.

-Ben



Re: [IndexedDB] setVersion with multiple IDBDatabase objects

2010-09-28 Thread ben turner
Yes, let's have it tied to the instance on which setVersion() was called.

As Shawn pointed out that is consistent with the behavior that
database instances from different windows will observe. As Jeremy
pointed out that is consistent with the way object stores and indexes
are tied to a transaction instance. Also, the |event.source| will be
db1 in the given example, so it seems natural to allow changes only to
the database we pass in the event and no other.

-Ben

On Tue, Sep 28, 2010 at 8:00 AM, Jeremy Orlow jor...@chromium.org wrote:
 I guess I should have mentioned that I too am in favor of it being tied to
 an instance.  I think this matches the model we use elsewhere in terms of
 transactions being tied to specific objectStore and index instances.
 J

 On Tue, Sep 28, 2010 at 3:47 PM, Shawn Wilsher sdwi...@mozilla.com wrote:

 On 9/28/2010 7:42 AM, Jeremy Orlow wrote:

 What do we want to do if the user calls window.indexedDB.open(myDB,
 some
 description) twice and stores the result as db1 and db2, calls
 db1.setVersion(), and then in the success handler does
 db2.createObjectStore?  In other words, is the setVersion transaction
 tied
 to the database instance that setVersion was called on, or is it
 available
 to any instance/object that points to that particular database for that
 particular origin in that particular page/worker?

 While I can see an argument either way, I think I'd prefer it to be tied
 to the instance.  I like this because then it works the same as it does
 being in different windows.  I don't have a strong opinion on this though.

 Cheers,

 Shawn






Re: [IndexedDB] A versionchangeblocked event

2010-09-24 Thread ben turner
The strategy we decided on was to send a 'versionchange' event to
every database that isn't closed first. Then we loop again and if
there are any left that are not closed we fire the blocked event.
Since we expect pages to call close() inside their 'versionchange'
handler we shouldn't be firing the blocked event unless it's really
necessary.

-Ben

On Fri, Sep 24, 2010 at 3:17 AM, Jeremy Orlow jor...@chromium.org wrote:
 Are we really sure this is needed?
 I was just writing up a bug for this and started to wonder if we needed any
 event when there no longer is a block.  I then realized that once you're
 unblocked the onsuccess should fire immediately, so there's no need.  But
 wait...isn't this true of normal blocking as well?  Basically either the
 onsuccess will fire immediately or onblocked will.  So couldn't an app just
 assume it's blocked until it receives a onsuccess message?  The worst case
 is that the web app blinks up some message to the user to close other
 windows, but it seems like that could happen even with an onblocked event
 being added.  Am I missing something here?
 J
 On Thu, Sep 23, 2010 at 9:57 PM, ben turner bent.mozi...@gmail.com wrote:

 I'm voting for 1! I'd hate to give all the other requests a property
 that only setVersion requests will use.

 -Ben

 On Thu, Sep 23, 2010 at 9:48 AM, Jonas Sicking jo...@sicking.cc wrote:
  On Thu, Sep 23, 2010 at 2:43 AM, Jeremy Orlow jor...@chromium.org
  wrote:
  On Wed, Sep 22, 2010 at 9:07 PM, ben turner bent.mozi...@gmail.com
  wrote:
 
  Hi folks,
 
  While implementing the latest setVersion changes Jonas and I decided
  that it would be really useful to be able to signal to the caller that
  other web pages are open and using the database (thus preventing a
  setVersion transaction from running).
 
  Consider a web page open in two windows, one minimized or otherwise
  obscured and the other in the foreground. If the background window is
  running a transaction then the foreground window will not be able to
  immediately begin a setVersion transaction when it makes that request.
  The spec currently informs the background page that it should close
  all its databases, but it would be even more useful to inform the
  foreground page that it is currently blocked. That way the foreground
  page could display some kind of notification (Hey, you! Go close your
  other tabs if you want us to upgrade the database!) that would aid
  the process. We are also relying on page authors to correctly call
  close() on their databases in response to the versionchanged event
  and I don't believe that they will always follow through.
 
  Jonas and I thought of three possibilities:
 
  1. Make setVersion return a special kind of request that had an
  onblocked event handler. The caller could then add a handler just as
  they do for success and error conditions.
  2. Make all IDBRequests have an onblocked handler, but just never
  call it in other situations.
  3. Fire a versionchangeblocked event at the database.
 
  What do you guys think? Any preferences? I don't really like 2, and
  I've preemptively implemented 3, but I'm not in love with 1 or 3
  either.
 
  This exact thing came up when we originally talked about setVersion.  I
  thought Jonas proposed and we decided on 1 (though I'm not against
  3)..?
   Did this just not make it into the spec?
 
  I think that 1 and 2 are the best solutions and I too thought that
  that was what we had decided on. I don't really see the advantage with
  3 since it means that you have to register event handlers on two
  separate objects, and potentially worry about colliding with other
  pieces of code doing version upgrades (though the latter problem seems
  somewhat far fetched).
 
  IMHO 2 seems simpler but I don't really care between 1 and 2. I'll
  note that there is lots of precedence in the HTML5 spec of adding
  attribute handlers on objects even though they don't necessarily fire
  on the given object. This was done to keep down the number of
  interfaces and thus keep things simpler.
 
  But if people prefer 1 I'm game for that too.
 
  / Jonas
 





Re: [IndexedDB] A versionchangeblocked event

2010-09-23 Thread ben turner
I'm voting for 1! I'd hate to give all the other requests a property
that only setVersion requests will use.

-Ben

On Thu, Sep 23, 2010 at 9:48 AM, Jonas Sicking jo...@sicking.cc wrote:
 On Thu, Sep 23, 2010 at 2:43 AM, Jeremy Orlow jor...@chromium.org wrote:
 On Wed, Sep 22, 2010 at 9:07 PM, ben turner bent.mozi...@gmail.com wrote:

 Hi folks,

 While implementing the latest setVersion changes Jonas and I decided
 that it would be really useful to be able to signal to the caller that
 other web pages are open and using the database (thus preventing a
 setVersion transaction from running).

 Consider a web page open in two windows, one minimized or otherwise
 obscured and the other in the foreground. If the background window is
 running a transaction then the foreground window will not be able to
 immediately begin a setVersion transaction when it makes that request.
 The spec currently informs the background page that it should close
 all its databases, but it would be even more useful to inform the
 foreground page that it is currently blocked. That way the foreground
 page could display some kind of notification (Hey, you! Go close your
 other tabs if you want us to upgrade the database!) that would aid
 the process. We are also relying on page authors to correctly call
 close() on their databases in response to the versionchanged event
 and I don't believe that they will always follow through.

 Jonas and I thought of three possibilities:

 1. Make setVersion return a special kind of request that had an
 onblocked event handler. The caller could then add a handler just as
 they do for success and error conditions.
 2. Make all IDBRequests have an onblocked handler, but just never
 call it in other situations.
 3. Fire a versionchangeblocked event at the database.

 What do you guys think? Any preferences? I don't really like 2, and
 I've preemptively implemented 3, but I'm not in love with 1 or 3
 either.

 This exact thing came up when we originally talked about setVersion.  I
 thought Jonas proposed and we decided on 1 (though I'm not against 3)..?
  Did this just not make it into the spec?

 I think that 1 and 2 are the best solutions and I too thought that
 that was what we had decided on. I don't really see the advantage with
 3 since it means that you have to register event handlers on two
 separate objects, and potentially worry about colliding with other
 pieces of code doing version upgrades (though the latter problem seems
 somewhat far fetched).

 IMHO 2 seems simpler but I don't really care between 1 and 2. I'll
 note that there is lots of precedence in the HTML5 spec of adding
 attribute handlers on objects even though they don't necessarily fire
 on the given object. This was done to keep down the number of
 interfaces and thus keep things simpler.

 But if people prefer 1 I'm game for that too.

 / Jonas




[IndexedDB] Simultaneous setVersion from multiple pages

2010-09-22 Thread ben turner
Hi folks,

While implementing the latest setVersion changes I came across this problem:

Let's say that a site is open in two different windows and each
decides to do a setVersion request at the same time. Only one of them
can win, obviously, and the other must end up calling close() on
itself or the setVersion transaction will never run (and all database
activity will basically hang at that point).

Jonas and I decided that this situation should result in the losing
database's request having its error handler called with DEADLOCK_ERR.
Does that sound reasonable to everyone?

-Ben



[IndexedDB] Accept simple strings in IDBDatabase.transaction()

2010-09-22 Thread ben turner
Hi folks,

The spec currently says that IDBDatabase.transaction() takes an array
of object store names as its first parameter. While I think this is
fine I'd like to propose that we loosen that restriction and allow a
simple string to name one object store as well. Thus this code:

  var transaction = database.transaction([foo]);

could, additionally, be written as:

  var transaction = database.transaction(foo);

I of course would like the array syntax to continue to be valid for
one or more object store names.

What do you guys think?

-Ben



[IndexedDB] A versionchangeblocked event

2010-09-22 Thread ben turner
Hi folks,

While implementing the latest setVersion changes Jonas and I decided
that it would be really useful to be able to signal to the caller that
other web pages are open and using the database (thus preventing a
setVersion transaction from running).

Consider a web page open in two windows, one minimized or otherwise
obscured and the other in the foreground. If the background window is
running a transaction then the foreground window will not be able to
immediately begin a setVersion transaction when it makes that request.
The spec currently informs the background page that it should close
all its databases, but it would be even more useful to inform the
foreground page that it is currently blocked. That way the foreground
page could display some kind of notification (Hey, you! Go close your
other tabs if you want us to upgrade the database!) that would aid
the process. We are also relying on page authors to correctly call
close() on their databases in response to the versionchanged event
and I don't believe that they will always follow through.

Jonas and I thought of three possibilities:

1. Make setVersion return a special kind of request that had an
onblocked event handler. The caller could then add a handler just as
they do for success and error conditions.
2. Make all IDBRequests have an onblocked handler, but just never
call it in other situations.
3. Fire a versionchangeblocked event at the database.

What do you guys think? Any preferences? I don't really like 2, and
I've preemptively implemented 3, but I'm not in love with 1 or 3
either.

-Ben



[IndexedDB] Let's remove IDBDatabase.objectStore()

2010-08-23 Thread ben turner
Hi folks,

We originally included IDBDatabase.objectStore() as a convenience
function because we figured that everyone would hate typing
|myDatabase.transaction('myObjectStore').objectStore('myObjectStore')|.
Unfortunately I think we should remove it - too many developers have
used the function without realizing that the returned object was tied
to a particular transaction. Any objections?

-Ben



Re: [Bug 10400] New: [IndexedDB] IDBCursor.continue should return an IDBRequest

2010-08-19 Thread ben turner
Sorry, I replied on the bug rather than to the list. Here's what I said:

Hm, I think the wording in the spec is bad, but I believe this bug is invalid.
The way we envisioned this for the async api is that calling continue() always
returns true (to match sync api, but it's really pointless) and the original
event listener is called again. There is no new request object. So it works
like this:

  var request = objectStore.openCursor();
  request.onsuccess = function (event) {
var cursor = event.result;
if (cursor) {
  // Do something...
  alert(cursor.value);
  // And again...
  cursor.continue();
}
else {
  // No more values...
}
  }

This way you don't have to define multiple request objects and event listeners.

For the sync api, I think it should work very similarly:

  var cursor = objectStore.openCursor();
  if (cursor) {
do {
  // Do something..
  alert(cursor.value);
} while (cursor.continue());
  }



Re: [IndexedDB] question about description argument of IDBFactory::open()

2010-08-11 Thread ben turner
I am fine with removing it.

-Ben



[IndexedDB] Need a method to clear an object store

2010-08-03 Thread ben turner
Hi folks,

Currently there are only two ways to clear an object store of all
data: (i) remove the object store and recreate it, or (ii) open a
cursor and call remove for all entries. I propose a third, simpler
approach:

interface IDBObjectStore
{
  ...
  void clear();
  ...
};

Any thoughts?

-Ben



Re: [IndexedDB] Need a method to clear an object store

2010-08-03 Thread ben turner
On Tue, Aug 3, 2010 at 12:20 PM, Jonas Sicking jo...@sicking.cc wrote:
 I think there is a bug in the above proposal though. clear() should
 return a IDBRequest. However the .result of the request should likely
 be null.

Yes, definitely. My fingers were too fast for my brain.

-Ben



Re: [IndexedDB] Current editor's draft

2010-07-14 Thread ben turner
On Wed, Jul 14, 2010 at 3:10 AM, Jeremy Orlow jor...@chromium.org wrote:
 For example, with dynamic transactions you can get into live-lock
 situations.

I'm particularly opposed to dynamic transactions for just this reason.
We would clearly have to throw an exception or call the error callback
if we detect livelock. I doubt that most web authors would recognize
the potential hazard, and even if they did I think it would be
extremely difficult for a web author to test such a scenario or write
code to handle it properly. The hardware running the web app and the
browser's transaction scheduling algorithm would of course affect the
frequency of these collisions making proper tests even more difficult.

 If we do leave them in, it
 should definitely be in its own method to make it quite clear that the
 semantics are more complex.

I completely agree.

So, as I've said, I'm very opposed to leaving dynamic transactions in
the spec. However, one thing we could do if everyone really wanted
this feature I guess is to set a limit of only a single dynamic
transaction per database at a time. That would remove the livelock
hazard but it may diminish the utility of the feature enough to be
useless.



Re: [IndexedDB] .value of no-duplicate cursors

2010-07-02 Thread ben turner
I think I would be happy just removing the _NO_DUPLICATE directions.
As Jeremy noted it is quite easy to emulate and it would then be up to
the webapp author whether she wanted the first or last duplicate
value.

-Ben

On Wed, Jun 30, 2010 at 11:56 PM, Jonas Sicking jo...@sicking.cc wrote:
 On Wed, Jun 30, 2010 at 10:42 PM, Jeremy Orlow jor...@chromium.org wrote:
 On Thu, Jul 1, 2010 at 12:07 PM, Jonas Sicking jo...@sicking.cc wrote:

 Hi All,

 This was one issue we ran into while implementing IndexedDB. In the
 code examples I'll use the mozilla proposed asynchronous APIs, but the
 issue applies equally to the spec as it is now, as well as the
 synchronous APIs.

 Consider an objectStore containing the following objects:

 { id: 1, name: foo, flags: [hi, low] }
 { id: 2, name: foo, flags: [apple, orange] }
 { id: 3, name: foo, flags: [hello, world] }
 { id: 4, name: bar, flags: [fahrvergnügen] }

 And an index keyed on the name property. What should the following code
 alert?

 results = [];
 db.objectStore(myObjectStore).index(nameIndex).openCursor(null,
 IDBCursor.NEXT_NO_DUPLICATE).onsuccess = function(e) {
  cursor = e.result;
  if (!cursor) {
    alert(results.length);
    alert(results);
  }
  results.push(cursor.value);
  cursor.continue();
 };

 It's clear that the first alert would display '2', as there are 2
 distinct 'name' values in the objectStore. However it's not clear what
 the second alert would show. I.e. what would cursor.value be on each
 'success' event firing?

 We could define that it is one of the rows matching the distinct
 value. In that case either 1,4, 2,4 or 3,4 would be valid values
 for the second alert. If we choose that solution then ideally we
 should define which one and make it consistent in all implementations.

 Alternatively we could say that .value is null for all *_NO_DUPLICATE
 cursors.

 The question equally applies if the above code used openObjectCursor
 rather than openCursor. However if we define that .value is null for
 *_NO_DUPLICATE cursors, then openObjectCursor with *_NO_DUPLICATE
 doesn't make much sense in that it returns the same thing as
 openCursor with *_NO_DUPLICATE.

 I don't personally don't care much which solution we use. I'm unclear
 on what the exact use cases are for *_NO_DUPLICATE cursors.

 This is a very good point.  What are the use cases?  After all, you can
 easily emulate such a cursor yourself.  Unless there are some compelling use
 cases, I'd be happy to just get rid of it.

 Same here. Though I suspect there are use cases as SQL has a similar
 feature (SELECT DISTINCT).

 However if
 we do say that .value should represent a particular row, then I think
 we should define which row is returned.

 Agreed that it should be deterministic.  I'm fine with null, the first
 value, or the last value.  If we do null, then I think calling
 openObjectCursor with *_NO_DUPLICATE should be an error.

 Agreed. We just have to define what first and/or last means. Two
 alternatives are insertion order or order in objectStore. I prefer the
 latter as to avoid introducing insertion order as a concept.

 Hmm.. come to think of it, we likely have to define an order anyway.
 So that it is deterministic what the order of the example index is
 defined when iterated with a normal cursor. I filed a bug on getting
 that defiend:

 http://www.w3.org/Bugs/Public/show_bug.cgi?id=10058

 / Jonas






Re: [IndexedDB] .value of no-duplicate cursors

2010-07-02 Thread ben turner
I think I would be happy just removing the _NO_DUPLICATE directions.
As Jeremy noted it is quite easy to emulate and it would then be up to
the webapp author whether she wanted the first or last duplicate
value.

-Ben

On Wed, Jun 30, 2010 at 11:56 PM, Jonas Sicking jo...@sicking.cc wrote:
 On Wed, Jun 30, 2010 at 10:42 PM, Jeremy Orlow jor...@chromium.org wrote:
 On Thu, Jul 1, 2010 at 12:07 PM, Jonas Sicking jo...@sicking.cc wrote:

 Hi All,

 This was one issue we ran into while implementing IndexedDB. In the
 code examples I'll use the mozilla proposed asynchronous APIs, but the
 issue applies equally to the spec as it is now, as well as the
 synchronous APIs.

 Consider an objectStore containing the following objects:

 { id: 1, name: foo, flags: [hi, low] }
 { id: 2, name: foo, flags: [apple, orange] }
 { id: 3, name: foo, flags: [hello, world] }
 { id: 4, name: bar, flags: [fahrvergnügen] }

 And an index keyed on the name property. What should the following code
 alert?

 results = [];
 db.objectStore(myObjectStore).index(nameIndex).openCursor(null,
 IDBCursor.NEXT_NO_DUPLICATE).onsuccess = function(e) {
  cursor = e.result;
  if (!cursor) {
    alert(results.length);
    alert(results);
  }
  results.push(cursor.value);
  cursor.continue();
 };

 It's clear that the first alert would display '2', as there are 2
 distinct 'name' values in the objectStore. However it's not clear what
 the second alert would show. I.e. what would cursor.value be on each
 'success' event firing?

 We could define that it is one of the rows matching the distinct
 value. In that case either 1,4, 2,4 or 3,4 would be valid values
 for the second alert. If we choose that solution then ideally we
 should define which one and make it consistent in all implementations.

 Alternatively we could say that .value is null for all *_NO_DUPLICATE
 cursors.

 The question equally applies if the above code used openObjectCursor
 rather than openCursor. However if we define that .value is null for
 *_NO_DUPLICATE cursors, then openObjectCursor with *_NO_DUPLICATE
 doesn't make much sense in that it returns the same thing as
 openCursor with *_NO_DUPLICATE.

 I don't personally don't care much which solution we use. I'm unclear
 on what the exact use cases are for *_NO_DUPLICATE cursors.

 This is a very good point.  What are the use cases?  After all, you can
 easily emulate such a cursor yourself.  Unless there are some compelling use
 cases, I'd be happy to just get rid of it.

 Same here. Though I suspect there are use cases as SQL has a similar
 feature (SELECT DISTINCT).

 However if
 we do say that .value should represent a particular row, then I think
 we should define which row is returned.

 Agreed that it should be deterministic.  I'm fine with null, the first
 value, or the last value.  If we do null, then I think calling
 openObjectCursor with *_NO_DUPLICATE should be an error.

 Agreed. We just have to define what first and/or last means. Two
 alternatives are insertion order or order in objectStore. I prefer the
 latter as to avoid introducing insertion order as a concept.

 Hmm.. come to think of it, we likely have to define an order anyway.
 So that it is deterministic what the order of the example index is
 defined when iterated with a normal cursor. I filed a bug on getting
 that defiend:

 http://www.w3.org/Bugs/Public/show_bug.cgi?id=10058

 / Jonas






Re: [IndexedDB] Should .add/.put/.update throw when called in read-only transaction?

2010-07-02 Thread ben turner
I would also point out that throwing exceptions at the call site makes
debugging much easier in my opinion. Our error events currently don't
include information like filename and line number where the failing
request was generated (though I think we should add that eventually).
Exceptions are much easier to track down, diagnose, and fix.

-Ben

On Thu, Jul 1, 2010 at 2:03 AM, Jonas Sicking jo...@sicking.cc wrote:
 On Wed, Jun 30, 2010 at 8:16 PM, Jeremy Orlow jor...@chromium.org wrote:
 I've thought about this more and have some additional doubts inline.
 On Thu, Jul 1, 2010 at 11:55 AM, Jonas Sicking jo...@sicking.cc wrote:

 On Wed, Jun 30, 2010 at 6:42 PM, Jeremy Orlow jor...@chromium.org wrote:
  On Thu, Jul 1, 2010 at 11:17 AM, Jonas Sicking jo...@sicking.cc wrote:
 
  Hi All,
 
  Currently the IndexedDB specification is silent on what should happen
  if IDBObjectStore.add, IDBObjectStore.put, IDBObjectStore.remove,
  IDBCursor.update or IDBCursor.remove() is called from a READ_ONLY
  transaction. There are two possible ways we can handle this:
 
  1. We can throw an exception.
  2. We can return a IDBRequest object and asynchronously fire a 'error'
  event on this object.
 
  The advantage of 1 is that we pretty much know that this was an error
  due to a bug in the web page,

 I don't see why this is compelling.  Many of the other errors that you still
 propose we fire via the callback are due to bugs in the page.


  and we can always know this
  synchronously without having to consult the database.

 So?  Just because we can doesn't mean we should.


  Throwing an
  error means that all the existing infrastructure for error handling
  with automatically kick in. For example any higher-level try/catch
  constructs will have an opportunity to catch the error.
  Implementations generally report uncaught exceptions to an error log..
  The browser will fire an 'error' event on the window which the page
  can use for further logging. Firing an error event on the other hand
  does not allow the browser to automatically log the error in a console
  as the page hasn't yet gotten a chance to handle it.

 Sure, but this doesn't help the majority of error conditions in IndexedDB.
  It also ignores the cost of handling errors in 2 different ways.

 I'm arguing that people generally won't want to check for all types of
 errors, such as writing in a READ_ONLY transaction. Compare to the
 Node.appendChild function which throws for a number of conditions, yet
 I've never seen anyone put a try around it and check for
 HIERARCHY_REQUEST_ERR.

 Additionally, anything you do can likely in theory throw exceptions.
 For example if you specify the wrong number of arguments or call a
 function that doesn't exist, this will result in an exception. However
 you rarely see people wrap try around calls to try to handle this
 type of bugs.

 Another example is the line:

 db.objectStore(myObjectStore).get(53)

 can result in errors both being thrown and being reported as an error
 event. If the objectStore myObjectStore doesn't exist, then the
 .objectStore() call will return null and the js engine will throw due
 to trying to call a function on a null value.

 Error checking is mostly useful when there are ways you can actually
 handle the error. I think generally if someone calls .put during a
 READ_ONLY transaction, they simply have a bug in their program and
 there is little they can do in terms of handling that, short of
 simply logging it.

  The advantage of 2 is that this is consistent with other error
  conditions, such as writing duplicate keys, disk errors during writing
  the database to disk, internal errors in the database, etc.

 The other problem is that users then need 2 sets of error handling routines
 for each call.  Given how difficult it is to get web developers to do any
 error checking, requiring 2 types of checks seems like a big downside.

 Actually, this is somewhat faulty math. With exceptions you can put a
 try/catch high up in a call stack to catch errors from multiple
 different locations. This will catch all errors thrown from all
 function calls inside the try. Compare that to error events, which has
 to be manually installed at every single request site. From this point
 of view, the more errors we move to being reported as exceptions, the
 more easily we're making it for developers to catch more errors.

 Javascript has a error reporting mechanism, exceptions. We should try
 to make good use of it.

  While consistency, and only needing to check for errors one way, is
  certainly good arguments, I would argue that people won't need to
  check for calling-add-on-read-only-transactions. For properly written
  code it's not an error that will occur, and thus there is no need to
  check for it. In fact, you probably are generally better off letting
  the exception bubble all the way up and get logged or caught by
  generic error handlers.

 These are awfully bold assumptions.  Simply not catching 

Re: [IndexedDB] Should .add/.put/.update throw when called in read-only transaction?

2010-07-02 Thread ben turner
I would also point out that throwing exceptions at the call site makes
debugging much easier in my opinion. Our error events currently don't
include information like filename and line number where the failing
request was generated (though I think we should add that eventually).
Exceptions are much easier to track down, diagnose, and fix.

-Ben

On Thu, Jul 1, 2010 at 2:03 AM, Jonas Sicking jo...@sicking.cc wrote:
 On Wed, Jun 30, 2010 at 8:16 PM, Jeremy Orlow jor...@chromium.org wrote:
 I've thought about this more and have some additional doubts inline.
 On Thu, Jul 1, 2010 at 11:55 AM, Jonas Sicking jo...@sicking.cc wrote:

 On Wed, Jun 30, 2010 at 6:42 PM, Jeremy Orlow jor...@chromium.org wrote:
  On Thu, Jul 1, 2010 at 11:17 AM, Jonas Sicking jo...@sicking.cc wrote:
 
  Hi All,
 
  Currently the IndexedDB specification is silent on what should happen
  if IDBObjectStore.add, IDBObjectStore.put, IDBObjectStore.remove,
  IDBCursor.update or IDBCursor.remove() is called from a READ_ONLY
  transaction. There are two possible ways we can handle this:
 
  1. We can throw an exception.
  2. We can return a IDBRequest object and asynchronously fire a 'error'
  event on this object.
 
  The advantage of 1 is that we pretty much know that this was an error
  due to a bug in the web page,

 I don't see why this is compelling.  Many of the other errors that you still
 propose we fire via the callback are due to bugs in the page.


  and we can always know this
  synchronously without having to consult the database.

 So?  Just because we can doesn't mean we should.


  Throwing an
  error means that all the existing infrastructure for error handling
  with automatically kick in. For example any higher-level try/catch
  constructs will have an opportunity to catch the error.
  Implementations generally report uncaught exceptions to an error log..
  The browser will fire an 'error' event on the window which the page
  can use for further logging. Firing an error event on the other hand
  does not allow the browser to automatically log the error in a console
  as the page hasn't yet gotten a chance to handle it.

 Sure, but this doesn't help the majority of error conditions in IndexedDB.
  It also ignores the cost of handling errors in 2 different ways.

 I'm arguing that people generally won't want to check for all types of
 errors, such as writing in a READ_ONLY transaction. Compare to the
 Node.appendChild function which throws for a number of conditions, yet
 I've never seen anyone put a try around it and check for
 HIERARCHY_REQUEST_ERR.

 Additionally, anything you do can likely in theory throw exceptions.
 For example if you specify the wrong number of arguments or call a
 function that doesn't exist, this will result in an exception. However
 you rarely see people wrap try around calls to try to handle this
 type of bugs.

 Another example is the line:

 db.objectStore(myObjectStore).get(53)

 can result in errors both being thrown and being reported as an error
 event. If the objectStore myObjectStore doesn't exist, then the
 .objectStore() call will return null and the js engine will throw due
 to trying to call a function on a null value.

 Error checking is mostly useful when there are ways you can actually
 handle the error. I think generally if someone calls .put during a
 READ_ONLY transaction, they simply have a bug in their program and
 there is little they can do in terms of handling that, short of
 simply logging it.

  The advantage of 2 is that this is consistent with other error
  conditions, such as writing duplicate keys, disk errors during writing
  the database to disk, internal errors in the database, etc.

 The other problem is that users then need 2 sets of error handling routines
 for each call.  Given how difficult it is to get web developers to do any
 error checking, requiring 2 types of checks seems like a big downside.

 Actually, this is somewhat faulty math. With exceptions you can put a
 try/catch high up in a call stack to catch errors from multiple
 different locations. This will catch all errors thrown from all
 function calls inside the try. Compare that to error events, which has
 to be manually installed at every single request site. From this point
 of view, the more errors we move to being reported as exceptions, the
 more easily we're making it for developers to catch more errors.

 Javascript has a error reporting mechanism, exceptions. We should try
 to make good use of it.

  While consistency, and only needing to check for errors one way, is
  certainly good arguments, I would argue that people won't need to
  check for calling-add-on-read-only-transactions. For properly written
  code it's not an error that will occur, and thus there is no need to
  check for it. In fact, you probably are generally better off letting
  the exception bubble all the way up and get logged or caught by
  generic error handlers.

 These are awfully bold assumptions.  Simply not catching 

[IndexedDB] Asynchronous inline key generation for autoIncrement'ing objectStores

2010-05-11 Thread ben turner
Hi folks,

We've hit a bit of a snag implementing put() for autoIncrement'ing
objectStores when using inline keys. Consider this:

Spec text from 
http://dev.w3.org/2006/webapi/WebSimpleDB/#dfn-steps-for-storing-a-record-into-an-object-store

  5. If key is not defined or null, then perform the following steps.
1. Using store's key generator, produce the next key and store it as key.
2. If store uses in-line keys, then store key as the property
value for object at store's key path.

Sample code from http://dev.w3.org/2006/webapi/WebSimpleDB/#object-store-sync

  var db = indexedDB.open('AddressBook', 'Address Book');
  if (db.version !== '1') {
 var olddb = indexedDB.open('AddressBook', 'Address Book');
 olddb.createObjectStore('Contact', 'id', true);
 olddb.setVersion('1');
  }
  var store = db.openObjectStore('Contact');
  var lincoln = {name: 'Lincoln', number: '7012'};
  var contact = store.put(lincoln);
  // contact.id === 1

The spec and sample code clearly say that the object passed to put()
will be updated so that the object's keyPath property will contain the
newly generated key. This won't work for the async API as we have to
hit the database before we can know which key will be assigned to the
new record.

We propose that the object passed to put() *not* be modified when
using the async API, and we further propose that the keyPath property
be set on the structured clone before storing into the database so
that a subsequent get() call would return a copy of the object with
the keyPath property correctly set. The key assigned to the object
will of course continue to be returned as the result of the success
event fired in response to the put() request.

What do you guys think?

-Ben



Re: [IndexedDB] Asynchronous inline key generation for autoIncrement'ing objectStores

2010-05-11 Thread ben turner
On Tue, May 11, 2010 at 11:10 AM, Jeremy Orlow jor...@chromium.org wrote:

 I agree this is a problem and I largely agree with your solution.  My only
 concern is performance of cloning data which will (in most cases) not even
 be used.  I wonder if the result of put should (instead of being the
 structured clone + the generated number) simply be the generated key.  When
 the keys are not auto-generated, it'd be undefined.  In the rare case the
 person wants to get the rest of the object back, they can subsequently do a
 get.

Hm, sorry if I was unclear. I think we're in total agreement. The
result of put() as currently spec'd for the async API is the key
value, not the object+key. I agree that we should keep that, and if
the user needs the object+key then they can do a subsequent get().

-Ben



Re: [IndexedDB] Asynchronous inline key generation for autoIncrement'ing objectStores

2010-05-11 Thread ben turner
On Tue, May 11, 2010 at 11:10 AM, Jeremy Orlow jor...@chromium.org wrote:
 No matter what, I think we shouldn't have the semantics of the sync and
 async APIs differ in such a subtle way: if the async API returns a clone +
 the generated number as its result, then the sync API should as well (vs.
 modifying the object passed in).

Oops, I didn't respond to this. I agree that we should change the sync
API to return the key value only and let the user do with it what they
will.

-Ben



[IndexedDB] Changes to IDBRequest and specification of the success and error events

2010-05-06 Thread ben turner
Hi folks,

We've been playing around with the async API and have made some
changes to the IDBRequest interface that we'd like feedback on and
hopefully inclusion in the spec. Here's what we have now:

  interface IDBRequest : EventTarget {
void abort();

const unsigned short INITIAL = 0;
const unsigned short LOADING = 1;
const unsigned short DONE = 2;
readonly attribute unsigned short readyState;

attribute Function onsuccess;

attribute Function onerror;
  };

  interface IDBEvent : Event {
readonly attribute Any source;
  };

  interface IDBSuccessEvent : IDBEvent {
readonly attribute Any result;
  };

  interface IDBErrorEvent : IDBEvent {
readonly attribute unsigned short code;

readonly attribute DOMString message;
  };

First, the obvious stuff. We've moved the error and result property
from the request to their respective events. Having everything on the
event makes it much easier to write callback functions, in my opinion.
Example in a sec. We've also made the success and error event keep a
source property that can be used to get back to the object that
generated the request. This may be a bit confusing but the example
will help. Here we go:

The following code uses the old API to put two values into an object
store and then alert the two keys that were created. We're assuming
that the object store Data exists and is an autoIncrementing store.

  var request = indexedDB.open(MyDB, My Cool Database);
  request.onsuccess = function(event) {
// request.result is an IDBDatabaseRequest
var request2 = request.result.openObjectStore(Data);
request2.onsuccess = function(event) {
  // request2.result is an IDBObjectStoreRequest
  var objectStore = request2.result;
  var request3 = objectStore.put(foo);
  request3.onsuccess = function(event) {
// request3.result is a key value
var key1 = request3.result;
var request4 = objectStore.put(bar);
request4.onsuccess = function(event) {
  // request4.result is a key value
  var key2 = request4.result;
  alert(All done, keys are  + key1 +  and  + key2);
};
request4.onerror = function(event) {
  alert(request4.error.message);
};
  };
  request3.onerror = function(event) {
alert(request3.error.message);
  };
};
request2.onerror = function(event) {
  alert(request2.error.message);
};
  };
  request.onerror = function(event) {
alert(request.error.message);
  };

From that sample you can see that the error functions are almost
identical but they have to keep track of the proper request that
created them in order to get the right error message.

The success functions also have to keep track of the request that
created them to know what the result property contains. Note also that
we have to save objectStore in request2.onsuccess in order to do an
additional put into the object store in request3.onsuccess. Keeping
track of all of this is really tedious and error prone.

With the changes outlined above, this code can be condensed to the following:

  function errorHandler(event) {
// event.source is different each time here but can be used to
figure out which operation failed
// event.code holds the error code
alert(event.message);
  }
  var request = indexedDB.open(MyDB, My Cool Database);
  request.onerror = errorHandler;
  request.onsuccess = function(event) {
// event.source is an IndexedDatabaseRequest
// event.result is an IDBDatabaseRequest
request = event.result.openObjectStore(Data);
request.onerror = errorHandler;
request.onsuccess = function(event) {
  // event.source is an IDBDatabaseRequest
  // event.result is an IDBObjectStoreRequest
  request = event.result.put(foo);
  request.onerror = errorHandler;
  request.onsuccess = function(event) {
// event.source is an IDBObjectStoreRequest
// event.result is a key value
var key1 = event.result;
request = event.source.put(bar);
request.onerror = errorHandler;
request.onsuccess = function(event) {
  // event.source is an IDBObjectStoreRequest
  // event.result is a key value
  var key2 = event.result;
  alert(All done, keys are  + key1 +  and  + key2);
};
  };
};
  };

We haven't done much to compress the length of the script here, but
you'll notice that each success handler is relatively self contained
and doesn't really need to use closures to perform further operations.
There's also no need to remember keep track of whether or not you want
request3 or request2 or request5000. The error handler is much easier
to reuse as well.

So, what do you guys think?

-Ben




Re: [IndexedDB] Interaction between transactions and objects that allow multiple operations

2010-05-06 Thread ben turner
Hey folks,

I'm working with Shawn on the Firefox implementation. Here's our idea
as of now, would you all please comment about things you like or
dislike? Hopefully this follows the gist of the comments shared
already.

  interface IndexedDatabaseRequest {
IDBRequest open(in DOMString name,
in DOMString description,
in optional boolean modifyDatabase);
  };

  interface IDBDatabaseRequest : IDBDatabase {
IDBRequest openTransaction(in optional DOMStringList storeNames,
   in optional unsigned long timeout);
  };

  interface IDBTransactionRequest : IDBTransaction {
IDBRequest abort();

IDBRequest commit();

IDBRequest createObjectStore(in DOMString name,
 in DOMString keyPath,
 in optional boolean autoIncrement);

IDBRequest openObjectStore(in DOMString name,
   in optional unsigned short mode);

IDBRequest createIndex(in DOMString name,
   in DOMString storeName,
   in DOMString keyPath,
   in optional boolean unique);

IDBRequest openIndex(in DOMString name);

IDBRequest removeObjectStore(in DOMString storeName);

IDBRequest removeIndex(in DOMString indexName);

IDBRequest setVersion(in DOMString version);
  };

We've made some additional changes to IDBRequest and actually
specified the success/error events, but they're not really relevant
here and I'll post about them later.

Note that if we go this route then the mode parameter of the
openObjectStore method becomes nearly meaningless since transactions
are currently supposed to exclusively lock the stores and indexes they
access.

As Shawn has said previously we're looking to make the async API as
close to the synchronous API as possible (never allowing anything to
block, of course) to avoid tons of nested functions that will make web
developers' lives harder. To that end we're wondering how much of the
IDBTransactionRequest interface (as written above) can be made
synchronous-like. For instance, we could simply wait to fire the
success callback until we've read some metadata back from the database
file. Then we could make openObjectStore simply return an
IDBObjectStoreRequest instead of another IDBRequest as we would
already know if the object store exists. It would be even simpler if
the caller used the storeNames parameter in the openTransaction call
since we wouldn't call the success callback unless those stores
existed. We could do similar cheats for the other methods.

What do you guys think?

-Ben

On Thu, May 6, 2010 at 3:17 AM, Jeremy Orlow jor...@chromium.org wrote:
 On Thu, May 6, 2010 at 9:14 AM, Nikunj Mehta nik...@o-micron.com wrote:

 On May 4, 2010, at 7:17 PM, Pablo Castro wrote:

  The interaction between transactions and objects that allow multiple
  operations is giving us trouble. I need to elaborate a little to explain 
  the
  problem.
 
  You can perform operations in IndexedDB with or without an explicitly
  started transaction. When no transaction is present, you get an implicit 
  one
  that is there for the duration of the operation and is committed and the 
  end
  (or rolled-back if an error occurs).

 To provide context to those who might be missing it, an explicit
 transaction is active in an IndexedDB Database as long as it has not been
 explicitly committed or aborted. An implicit transaction's life time is
 under the control of the implementation and spans no more than the operation
 requested.

 
  There are a number of operations in IndexedDB that are a single step.
  For example, store.put() occurs either entirely in the current transaction
  (if the user started one explicitly) or in an implicit transaction if there
  isn't one active at the time the operation starts. The interaction between
  the operation and transactions is straightforward in this case.
 
  On the other hand, other operations in IndexedDB return an object that
  then allows multiple operations on it. For example, when you open a cursor
  over a store, you can then move to the next row, update a row, delete a 
  row,
  etc. The question is, what is the interaction between these operations and
  transactions? Are all interactions with a given cursor supposed to happen
  within the transaction that was active (implicit or explicit) when the
  cursor was opened? Or should each interaction happen in its own transaction
  (unless there is a long-lived active transaction, of course)?

 The transactional context of a series of operations is the transaction
 that was created in the database. Each and every operation from that point
 on till one of the following happens is performed in that transaction:

 1. The transaction is committed
 2. The transaction is aborted
 3. The database object goes out of scope.

 
  We have a few options:
  a) make multi-step objects bound to the 

Re: [IndexedDB] Interaction between transactions and objects that allow multiple operations

2010-05-06 Thread ben turner
Hey folks,

I'm working with Shawn on the Firefox implementation. Here's our idea
as of now, would you all please comment about things you like or
dislike? Hopefully this follows the gist of the comments shared
already.

 interface IndexedDatabaseRequest {
   IDBRequest open(in DOMString name,
   in DOMString description,
   in optional boolean modifyDatabase);
 };

 interface IDBDatabaseRequest : IDBDatabase {
   IDBRequest openTransaction(in optional DOMStringList storeNames,
  in optional unsigned long timeout);
 };

 interface IDBTransactionRequest : IDBTransaction {
   IDBRequest abort();

   IDBRequest commit();

   IDBRequest createObjectStore(in DOMString name,
in DOMString keyPath,
in optional boolean autoIncrement);

   IDBRequest openObjectStore(in DOMString name,
  in optional unsigned short mode);

   IDBRequest createIndex(in DOMString name,
  in DOMString storeName,
  in DOMString keyPath,
  in optional boolean unique);

   IDBRequest openIndex(in DOMString name);

   IDBRequest removeObjectStore(in DOMString storeName);

   IDBRequest removeIndex(in DOMString indexName);

   IDBRequest setVersion(in DOMString version);
 };

We've made some additional changes to IDBRequest and actually
specified the success/error events, but they're not really relevant
here and I'll post about them later.

Note that if we go this route then the mode parameter of the
openObjectStore method becomes nearly meaningless since transactions
are currently supposed to exclusively lock the stores and indexes they
access.

As Shawn has said previously we're looking to make the async API as
close to the synchronous API as possible (never allowing anything to
block, of course) to avoid tons of nested functions that will make web
developers' lives harder. To that end we're wondering how much of the
IDBTransactionRequest interface (as written above) can be made
synchronous-like. For instance, we could simply wait to fire the
success callback until we've read some metadata back from the database
file. Then we could make openObjectStore simply return an
IDBObjectStoreRequest instead of another IDBRequest as we would
already know if the object store exists. It would be even simpler if
the caller used the storeNames parameter in the openTransaction call
since we wouldn't call the success callback unless those stores
existed. We could do similar cheats for the other methods.

What do you guys think?

-Ben