|
Subject: Naturalizing Dojo Data Newsgroups: gmane.comp.web.dojo.devel Date: 2008-04-09 18:57:42 GMT (33 weeks, 6 days, 12 hours and 10 minutes ago)
The dojox.lang.observable (and dojox.data.JSData) modules were written for
the purpose of providing more natural and aesthetic APIs and data access.
There may be a number of possible uses, however, I wanted to make some
specific notes about naturalizing dojo data access. I think our primary
intent is that we can access and modify properties/attributes using regular
javascript syntax rather than without having to call store.{g,s}etValue.
Rather than writing:
var name = store.getValue(item,"name");
store.setValue(item,"foo","bar");
we write:
var name = item.name;
name.foo = "bar";
Unfortunately, with the vbscript/lettable hack as used in observable, we
can't capture:
item.subItem = {name:"my object"}; // objects won't work in vb's setters
However, even with native getters and setters, we can't capture all actions
like:
delete item.old; // delete removes the getter/setter without calling
anything
item.newProp = "value"; // property didn't exist before
Prior to working at SitePen, I developed a whole client side framework (part
of the Persevere project) that really could detect all JavaScript
modifications and perform the appropriate lookups or persistence. However,
this framework required JavaScript compilation in order to work (basically
it compiled all property accesses and modifications to internal calls).
However, I don't think anyone wants the cost of compilation in order to
improve dojo data API. ES4 may also provide the means for capturing almost
all modifications, by using catch-all getters/setters and I think there is a
delete meta function that may be interceptable, as well. But ES4 is a ways
off still.
Unfortunately, today this means we must develop a set of rules for
developers if they want to use normal property access with dojo data items
as provided by the dojox.data.JSData (observable) data store converter:
1. You may use JavaScript's property syntax for modifying or accessing an
existing property.
2. If you want to delete a property, you must use unsetAttribute, rather
than JS's delete operator.
3. If you want to add a new property, you must use store.setValue.
(Because of vbscript limitations, these rules also must be observed):
4. If you want to access a property that has (or may have) an object value,
you must use store.getValue
5. If you want to modify a property that has had an object value or will
have an object value, you must use store.setValue
So using an item from a store with the observable/JSData module would look
like:
name = item.name; // rule 1
subItem = store.getValue(item,"subItem"); // get an object rule 4
subName = subItem.name; // rule 1
item.name = "new name"; // rule 1
store.unsetAttribute(item,"oldProp"); // rule 2
store.setValue(item,"newProp","value"); // rule 3
store.save();
It is worth noting that accessing and modifying existing properties with
primitive values is probably the predominant use case. The observable module
does provide the means for covering this use case. Also, once native support
is available for getters and setters in IE, developers would only need to
abide by the first three rules.
I have been developing a JsonRestStore data store that accesses and saves
data through RESTian endpoints (Amazon S3, CouchDB, and Persevere so far).
This has been built intentionally with the idea of allowing developers to do
direct property access with a minimal set of rules. There are few techniques
I utilized to make items more directly usable:
1. All references are resolved on intake, rather than on access
2. Any lazy references (references to data that hasn't been loaded yet from
the RESTian endpoint), are represented as dojo.Deferred objects
3. Public API for "_setDirty" (right now, I call it "changing").
Therefore developers can use the following rules for directly accessing item
properties:
1. Prior to any modifications to an item, you must call store.changing(item)
2. Any property may be directly accessed, however if it is a lazy property,
you can have it automatically resolved by calling getValue, or if you access
it directly, you will get a Deferred object. You can add a callback, and
receive the resolved value.
The last example would look like:
name = item.name;
subItem = item.subItem;
subName = store.getValue(subItem,"name"); // let's assume this is a lazy
property
store.changing(item);
item.name = "new name";
delete item.oldProp; // we can use the JS delete operator
item.newProp = value; // we can set new properties as well
store.save();
In terms of ease of use and simplicity, I think this approach may actually
be relatively palatable. This approach also doesn't incur the big
performance penalty of getters/setters (as documented in the previous
emails). Additionaly, when native getters/setters arrive, they can
selectively be applied to lazy properties (for minimal performance hit), and
developers would only need to observer rule #1 in order to directly access
and modify properties. Of course this is viable due to the way JsonRestStore
was developed, it can't be retroactively applied to other data stores
(unless someone does some recoding).
So briefly, the observable/JSdata module can take existing data stores and
make properties accessible with JavaScript for the majority case, existing
primitive values. However, it is slow and has a somewhat more complicated
set of rules for different forms of access. Alternately, data stores can be
developed that have a simpler set of rules and provide faster data access.
Thanks,
Kris
|
|
|