Version 12, changed by jaredj 04/04/2007. Show version history
Continue to move forwardon a check-in this week to try and meet M1 milestone.
The following descisions came out of this meeting:
- All Abstract APIs that are for documentation move to: dojo.data.api. This includes: Read.js, Write.js, Notification.js, Identity.js, and Request.js
- All baseline store implementations go into: dojo.data
- All ultility functions and mixins go into: dojo.data.util
- SimpleBaseStore? is to be converted to a mixin and moved to dojo.data.util, instead of being an abstract class.
There was a lot of discussion on this topic but no real descision made. There were two main approaches outlined to consider and are listed below. These need to be further discussed and alternatives examined:
JavaScript attribute accessor notation:Assume the following item structure:
var marge = {name:{first:"Marge", last:"Simpson"}};
var homer = store.newItem({name:{first:"Homer", last:"Simpson"}, spouse:marge});
var lisa = store.newItem({name:"Lisa", parents:{mom:marge, dad:homer}});
Then the following would be expected from accessor notation:var spouseFirstName = store.getValue(homer,"spouse.name.first");
// spouseFirstName should be: "Marge"var spouseLastName = store.getValue(homer,"spouse.name.last");
// spouseLastName should be: "Simpson"var spouse = store.getValue(homer,"spouse");Pros:
// spouseLastName should be: object [Object] (unless it implements toString() or the like)
- Simple to understand
- Assumes all items either return an atomic value, or the result of a toString() type conversion.
Attribute aliasing:Cons:
- Unclear if you traverse items or not in this example.
- Always returning a stringlike value as the result could get confusing/frustrating. What do you do if you *want* the object it returns instead of a string?
- How do you handle non-javascript based items, such as an XML Dom node?
var marge = {name:{first:"Marge", last:"Simpson"}};
var homer = store.newItem({name:{first:"Homer", last:"Simpson"}, spouse:marge});
var lisa = store.newItem({name:"Lisa", parents:{mom:marge, dad:homer}});
The store should set up a mapping of complex object structures to perhaps simpler attribute names. For example, spouse.name.first could be mapped to: spouseFirstName, and the lookup is:var spouseFirstName = store.getValue(homer,"spouseFirstName");
// spouseFirstName should be: "Marge"
Jaredj: I don't precisely see how this is any easier than the dot notation, other than it keeps you from seeing the actual item object structure.
Agreed that newITem() keywordArgs should generaly be of a simple name/attribute pairing where the names are the toplevel attribute names of the items and the values are the toplevel values of those items. Documentation should be explicit on that. This sort of behavior
This item is to address something Adam Peller raised while discussing how to get the code committed in. The issue is around the API specification files, which are the large part of dojo.data.core. The purpose of Read.js, Write.js, etc, are to define out the API a store must conform to in order to implement a feature. These are currently implemented as classes created by dojo.declare(). This really seems unnecessary as no one will ever generally subclass these files as what would be the point? They just provide 'unimplemented' methods which must be over-ridden to work anyway, so subclassing them just forces stores to import them, which wastes download space.
So, the question put to the Dojo organizxation is, how should these files be defined such that API doc tools can provide the API docs easily but doesn't so something inefficient like make a require on dojo.declare? Should they be done as simple Javascript objects defined as: dojo.data.core.Read = {}; Should they not be capitalized? Basically, input from the senior Dojo devs is needed here to d the right thing for dojo. JaredJ has been following the pattern that has existed for these files (dojo.declare() creations), but has also commented on this seeming odd. Before we go further and commit items in, we should decide definitively how an API specification file for Dojo should be written so developers can easily get the API docs as well as understand what they must implement. Does anything else in Dojo do this?skinner: I don't have any answers for most of those questions, but for what it's worth, at one point we talked about putting the API interface files in an "api" directory, which I think might be an improvement:
dojo.data.api.Read
dojo.data.api.Write
From Contributors discussion:From Jesse Kubnert:skinner: Some questions, to try to understand how our path-based access would work...I'd personally really like to see this appear somewhere. It could be that it only gets used as a ui binding kind of construct but I've found it very intuitive / nice to have around ...Unless there are better / simpler ways of doing something like it with say FilteringTable (or whatever the next incarnation becomes) .From Brian Skinner in reply to the above:
On 3/28/07, Tom Trenka <ttrenka@gmail.com> wrote:
> One other thing I might mention is that collections.Store right now supports
> a basic pathing feature, so that things in a hierarchical store *can* be
> used, including methods that take no parameters:
>
> field="someObject.someProperty "
> field="someObject.someMethod().someOtherMethod().someProperty">
> ...in this way, it supports both calculated expressions as well as the
> display of nested properties. I don't remember seeing a plan for this in
> the read API, though I seem to remember it being discussed. Is there any
> plans for this sort of field retrieval at all?
>
> trtWe don't yet have a plan for that sort of retrieval.
We've talked about that sort of feature many times now, but its been controversial and we've always deferred the discussion. In particular, we've talked about adding a new datastore accessor method that could parse some sort of limited XPath expression or JavaScript dot-path notation.
I'd like to avoid using any string-based path description, like "book.author.name", or "book/author/name". Using path expressions like that would mean that we need to start reserving special characters (like . or / ), which would then cause problems for any datastore that connects to a datasource which already uses those characters in its attribute names.
Comment from JaredJ: If we reserve characters off, then it is just a matter for DS users to escape said characters in some fashion so that they are not parsed as a path. This is not uncommon behavior, just look at the general escapes already used for things like JSON. I'm not sure this is such a big issue in that respect.
In particular, I'm concerned about RDF datastores. We already have a dojo.data.RdfStore, which we started using in OpenRecord last fall. And OpenLink Software has written a preliminary dojo.data adapter for their Virtuoso server. In RDF, attributes are identified by URLs. For example, the "title" of a web page would use the title attribute, which has the id "http://purl.org/dc/elements/1.1/title".
As an alternative, I've suggested using an array of attributes as the argument to any new path-based accessor method, like this: var = store.getValueFromPath(book, ['author', 'name']);(1) If we have this feature, is the plan that it will be consistent across datastores -- it will work the same way for an XML datastore and a JSON datastore?
jaredj: From my perspective I think it would need to be consistent, otherwise it is useless to exploit in a generic fashion in widgets.
ttrenka: +1 on consistent
skinner: +1 on consistent
(2) Are we talking about "sub-attributes", where you have attributes that have sub-parts? For example, say you have a single data item that represents a person, with attributes like:{height:'1.65 meters', weight:'61 kg', name:{first:'Jaime', last:'Sommers'}}then you could get the person's last name by doing:var lastName = store.getValueFromPath(person, 'name.last');(3) Or are we talking about "traversing items", where you traverse a series of items by getting the attribute values of each item along the way? For example, think of a bookstore database, with data items representing books and authors. Given a single item representing an author, you could ask for a list of of the titles of the related book items:var titles = store.getValuesFromPath(stephenKing, 'books.title')ttrenka: "I'd say that we are not traversing items"
(4) Or, are we talking about support for both "sub-attributes" and "traversing items", with a single unified API?
(5) If the attribute 'name' has sub-attributes 'first' and 'last', when you do store.getValue(person, 'name'), is the return value an item?var lastName = store.getValueFromPath(person, 'name.last');(6) Can "sub-attributes" contain item references as well as literals? For example:
var something = store.getValue(person, 'name');
??? = store.isItem(something);var marge = "Marge Simpson";(7) Can "sub-attributes" contain nested sub-sub-attributes, and so on?
var homer = store.newItem({name:{first:"Homer", last:"Simpson"}, spouse:marge});
var lisa = store.newItem({name:"Lisa", parents:{mom:marge, dad:homer}});
(8) If we want our simple JsonItemStore to support "sub-attributes", how will that change the file format that it reads? For example, we currently have files that look like this:{ identifier: 'key',What would that file look like if Homer's name had sub-attributes for 'first' and 'last'? In the file format, how do we distinguish between name:{first:'Homer'} and spouse:{reference:'marge'}? What happens if you have a sub-attribute named "reference"?
items: [
{ key:'homer', name:'Homer Simpson', spouse:{reference:'marge'}},
{ key:'marge', name:'Marge Simpson', spouse:{reference:'homer'}},
]}
(9) If we allow for "traversing items", does the API we're defining require that the datastore be able to traverse across any arbitrary set of items and attributes, or is the datastore only required to successful traverse across items that are already loaded into local memory? For example, drilling down within a single XML file, versus navigating through a huge server-side data graph (such as a social network on a web service like LinkedIn).
(10) Is each datastore required to provide its own implementation for this feature, or is there a single standard implementation that automatically works across all datastores, by building on top of the getValue() and getValues() methods? If we do have a single standard implementation, does that code live in an abstract superclass that all datastores inherit from, or does the code live in a generic mixin file (like the dojo.data.core.nestedTransaction mixin, which adds beginTransaction and endTransaction methods to any datastore that supports the Write API)?
(11) Do we want to provide a method that allows you to get (a) just a single result value or (b) just a list of result values? Or two separate methods, one that always returns single values and one that always returns lists?
(12) Are we talking about just simple paths, like "foo.bar.iggy" and/or "foo/bar/iggy"? Or are we talking about additional XPath style features, like:"/foo"(13) Are we talking about also supporting method calls via the path syntax? For example:
"foo/bar[2]"
"foo/bar/text()""foobar.someMethod()"jesse:
My only experience with these kinds of expressions are when they've been embedded as html attributes, so for instance we might have a situation like:
<table id="datagrid">
<thead>
<th data="person.name">Name</th>
<th data="person.dob" format="date">Date of Birth</th>
</thead>
</table>The grid would then just have a single string to throw at a data provider with no knowledge of the actual structure. You could get into function invocation semantics like checking for getDob/setDob getName/setName if the property paths weren't resolvable.
Of course things could get really silly really quickly, so it might be easier to start with supporting the most basic subset of property paths + get/set function detections. Another project I'm also currently working on does all of this and much much more, so it could be referenced as an example of how things could "get silly" wrt the expression syntax allowed. (which we probably don't want to do, as I've got the benefit of being able to do bytecode jit compilation of my expressions) http://www.ognl.org/2.6.9/Documentation/html/LanguageGuide/index.html .
The Grid widget needs a defined behavior here, such as the names of the attributes of an item are the parameters of an anonymus object for the newItem call. Right now I do not believe this is documented as what should be expected. Should it be, or is this a poor assumption on my part?skinner: In the dojo.data.core.Write API doc for newItem() we say "Sets the attributes of the new item based on the keywordArgs provided", and the documentation has an example that shows it being used like this:var kermit = store.newItem({name: "Kermit", color:[blue, green]});I think that in any datastore, newItem() should take a single optional keywordArgs argument, with attribute names and values. We might need to clarify that in the Write API documentation.
jaredj: I think we do need to update the documentation, then. It's unclear that it should be just attribute name/value pairs passed in; in effect an anonymous construction of the item. This question came up from the work Bill was doing on grid, and how some prototype stores (such as an XmlStore?), were not following that pattern.