Re: [IndexedDB] KeyPaths and missing properties.

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.

>  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.

> So I guess the
> fundamental question here is whether there should be a 1:1 mapping between
> entries in an objectStore's indexes and the objectStore itself.

I'm not sure what you mean by "a 1:1 mapping"? Do you mean that there
are the same number of entries in the index as there are in the
objectStore?

> 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.

>> There is a similar issue if an objectStore uses in-line keys. Consider
>> a database with a objectStore called "people" with keyPath "name" and
>> no key generator. What if someone inserts an object with the value {
>> email: "benny@sweden.com" }? I would think that this should be an
>> error, but it doesn't appear that any of the steps in "Object Store
>> Storage steps" says to create an error.
>
> This is probably just an omission in the spec.  If so, someone should file
> an issue on it.

Agreed. I'll file a bug.

>> Finally, there is the issue of what should happen if someone tries to
>> insert a number as a value into an objectStore with a keyPath and a
>> key generator. Consider the objectStore "albums" with keyPath "id" and
>> a key generator enabled. What should happen if someone tries to insert
>> the value 9 into this table? If an object was inserted, then this
>> would result in that objects 'id' property being set to the next
>> generated value from the generator, however it doesn't really make
>> sense to set a property on a number. Same question obviously applies
>> if the stored value is a boolean, a string, or any other primitive JS
>> type, or types such as regexps and File objects. I think that in all
>> these cases the operation should fail.
>
> Agreed.

I'll file a bug.

>> The question also applies if the stored value is an array. Technically
>> Javascript allows setting values on arrays, however the structured
>> clone algorithm drops these values, and so it seems to add needless
>> complexity for the implementation if the only time you need to
>> serialize/deserialize arrays with non-integer properties is in this
>> one case. Additionally, the id would be lost when the value is read as
>> that is done using the structured clone algorithm too.
>
> Hm.  I'm having trouble following this case.  Any chance you could explain
> it further?

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.

/ Jonas

Received on Wednesday, 19 May 2010 20:39:03 UTC