W3C home > Mailing lists > Public > public-webapps@w3.org > April to June 2010

Re: [IndexedDB] KeyPaths and missing properties.

From: Jonas Sicking <jonas@sicking.cc>
Date: Wed, 19 May 2010 17:24:11 -0700
Message-ID: <AANLkTimbC9pTMRdNGoLo_kygnKuosgRIPOgH_DCtDxtq@mail.gmail.com>
To: Jeremy Orlow <jorlow@chromium.org>
Cc: Webapps WG <public-webapps@w3.org>
On Wed, May 19, 2010 at 4:58 PM, Jeremy Orlow <jorlow@chromium.org> wrote:
> On Wed, May 19, 2010 at 9:38 PM, Jonas Sicking <jonas@sicking.cc> wrote:
>>
>> On Wed, May 19, 2010 at 2:36 AM, Jeremy Orlow <jorlow@chromium.org> wrote:
>> > Interesting you'd bring this up.  Andrei and I were just looking at
>> > indexes
>> > as specced and wondered whether it still makes sense to allow indexes to
>> > not
>> > have a keyPath.
>>
>> I think so. Consider for example a objectStore that contains entries like:
>>
>> { name: "Elvis Presley", born: "1935-1-8", death: "1977-8-16" }
>>
>> But index on how old the person was when he/she died. I guess you
>> could require that people store a property containing the age, however
>> it seems unfortunate to require modifying the stored data.
>>
>> Worse, you might have entries like:
>>
>> { id: 5, givenName: "Benny", otherNames: ["Göran", "Bror"],
>> familyName: "Andersson", age: 63, interest: "Music" }
>>
>> in order to search for people, you might want to search for a name, no
>> matter if that is a given name, a family name, or second name.
>> Currently you can accomplish this by inserting 4 entries into an
>> index, all pointing to the same entry in the objectStore. I can't
>> think of a sane way to accomplish this using only keyPath.
>
> I think the main use case here is the need to allow an unknown quantity of
> entries in the index to one entry in the objectStore.  What if we allowed
> keyEntry's to be any javascript expression and allow them to return arrays
> of indexible data.  In this case, the expression would return an array of
> otherNames + the givenName + the familyName.  The keyPath already is
> essentially just a javascript expression, so this doesn't seem like too big
> of a leap.
> This would also support your age upon death use case.  (Though I think
> requiring the developer to store that age if they want it indexed isn't too
> bad of an answer either.)
> Thoughts?

I think it's an interesting idea, and one that came up when we were
talking to developers way back before IndexedDB spec was started.
However then we more discussed it in the sense that libraries would be
using the technique, rather than that the API would use it.

The problem with using a javascript expression is how do you provide
it? If you're allowed to pass in a function, that also means that
you're pulling in the full scope of that function. This obviously
doesn't work since the index generally outlives the scope and is used
in other browsing sessions and other tabs.

So you'd have to pass in the javascript expression as a string. This
certainly works but is more than a little ugly. It also complicates
the implementation a good bit since it now has to include a javascript
engine. Not a huge issue given that all browsers has one anyway, but
feels a bit iffy.

I still think it's an interesting idea, though I'm not sold on it.
Especially for the first version of the spec.

>> >  And, if so, whether we should tie insertion into the
>> > objectStore to insertion to the index. The main reason to make such
>> > changes
>> > would be to enforce a notion of database consistency.
>>
>> You mean so that you would have to pass in index keys to the
>> insert/modify functions? In other words, require at an API level that
>> indexes were always up to date?
>>
>> This is an interesting idea. I can't really say I feel strongly one
>> way or another. I guess it depends on what the API would look like.
>> The nice thing about what we have now is that the API is pretty
>> simple.
>
> One possible way to implement it: add/modify/addOrModify could have an
> optional parameter that takes an associative array.  For example, {age: 63,
> interest: "music"} if you were indexing on age and interest.
> That said, I think I like my above proposal better.

"age" and "interest" being index names? Definitely an interesting idea.

>> > On Wed, May 19, 2010 at 3:06 AM, Jonas Sicking <jonas@sicking.cc> wrote:
>> >>
>> >> Hi IndexedDB fans!
>> >>
>> >> So another issue that's come up here. This question is orthogonal to
>> >> the other discussed issues and applies equally to both the existing
>> >> API, and the mozilla proposed API, so I figured it was safe to raise
>> >> right away.
>> >>
>> >> What should happen if you insert a object into an objectStore which
>> >> has an index attached to it, but the property defined by the keyPath
>> >> in the index does not exist? Consider a database with an objectStore
>> >> called "people" with keyPath "name". The objectStore has an
>> >> auto-populated index named "phone numbers" with keyPath "phone". The
>> >> objectStore is initially empty.
>> >>
>> >> What should happen if you attempt to store an object with value {
>> >> name: "Benny", email: "benny@sweden.com" } ?
>> >>
>> >> There are three possible behaviors I can think of:
>> >>
>> >> 1. The storing operation should fail and an error event should be
>> >> fired.
>> >> 2. The storing operation should succeed, but no records should be
>> >> added to the "phone" index.
>> >> 3. The storing operation should succeed and a record should be added
>> >> to the "phone" index using null as key.
>> >>
>> >> Which one is correct behavior? What if the "phone numbers" index is
>> >> flagged as unique?
>> >>
>> >> I definitely think there is a use case for allowing records to be
>> >> stored even if there are indexes on missing properties. Consider for
>> >> example a objectStore containing people where not everyone has a known
>> >> phone number. It still seems useful to be able to search based on
>> >> phone number in this objectStore. To satisfy this use case either
>> >> solution 2 or 3 would work. 3 would additionally allow searching for
>> >> everyone without a phone number, though I'm not sure how important
>> >> that is. On the other hand 2 would be more space effective in that
>> >> only relevant records would be stored.
>> >>
>> >> Possibly we'll want to add a 'required' flag to the createIndex
>> >> function specifying if the index should cause behavior 1 or behavior
>> >> 2. So far I'm not a big fan of 3, but I'm all ears for input.
>> >
>> > If we went with (1) then it seems as though developers could simply
>> > insert
>> > items with .phone=null to get around the limitation.
>>
>> People doing that doesn't seem to really change anything. The question
>> would just turn into "what should we do if the key is absent, null or
>> undefined". The same 1, 2, 3 answers still seem like possible answers.
>>
>> > 3 seems like it'd be error prone and somewhat confusing.
>> > If we decide there should be a 1:1 mapping then it seems we're choosing
>> > between 1 and 3.  And if not, then I think 2 is the clear answer.
>>
>> I'm still not sure what the "a 1:1 mapping" means, so not really
>> following your logic here.
>
> Does it make sense now?  Either way, I guess I'm leaning towards 2 at this
> point since there do seem to be valid use cases for multiple (or 0) entries
> in one index pointing to one objectStore entry.

Still not quite following you, but since I agree that 2 would be the
way to go maybe we can leave it at that :)

>> Consider the following. An objectStore with keyPath "id" and a key
>> generator enabled, and the last generated key had the value 6. If I
>> call
>>
>> objectStore.put({ name: "Benny" });
>>
>> then that would store an object like
>>
>> { name: "Benny", id: 7 }
>>
>> in the objectStore. The question is, what should happen if I instead had
>> called:
>>
>> myObjectStore.put(["Benny"]);
>>
>> The spec now says to create a structured clone of the value (i.e. the
>> array), and then set its .id property. This is perfectly valid in
>> javascript. I.e. JS allows you to do:
>>
>> a = ["Benny"];
>> a.id = 7;
>>
>> This results in an array object of length 1, but which has a .id
>> property set to 7. It would be possible to store such an object in the
>> database and have it accessible if you do
>>
>> myObjectStore.get(7);
>>
>> However since the structured clone algorithm is used when reading the
>> value from the database, you'd still just get back a normal array with
>> no .id property.
>>
>> In general the whole situation seem complex and surprising, and so I
>> don't think we should allow it.
>
> Oh, interesting!  Do you know why the structured clone algorithm is specced
> that way?
> Anyway, I'd agree that disallowing it is probably the right answer.

Hmm.. it turns out I'm wrong. It does not in fact drop id property.
Ugh, that complicates serializing arrays quite a bit :(

I still think it's surprising to add properties to arrays, and so I'd
prefer to treat arrays like primitives and other non-plain-objects and
make it an error.

/ Jonas
Received on Thursday, 20 May 2010 00:25:04 GMT

This archive was generated by hypermail 2.3.1 : Tuesday, 26 March 2013 18:49:38 GMT