Version 13, changed by brian 03/20/2007. Show version history
Agenda Item 1
Callback argument signatures for fetch():Request and Result:
- onItem(item, request)
- onBegin(size, request) // -1 if no size info available
- onError(err, request)
- onComplete(
null, request) // null if onItem callback was provided - onComplete(arrayOfItems,
request) // if no onItem callback provided
- we will delete the dojo.data.core.Result.js file, and any references to it
- we will create a dojo.data.core.Request.js file
- the fetch() Request will be a similar concept to the dojo.io.bind request
- dojo.data.core.Request is an API, not a concrete class
- dojo.data.core.Request is a place to hang documentation for the doc tool
- the fetch method on dojo.data.core.Read will return an object that conforms to the Request API
- the Request API defines a single function: abort()
Agenda Item 2:
2.1: we will add support for the ? single character pattern match
2.2: we will not add support for numeric pattern matching
Agenda Item 3:
- we will change the name of set() to be setValue()
- save() will not return a Deferred -- save() will have no return value at all
- save() will take three optional arguments: onComplete, onError, and scope
- store.save({scope:foo, onComplete:callback, onError:errback});
- save() implies that datastores implement some sort of change tracking (Or be stupid if it wants and always save everything regardless! :)
- we will not have a saveItem() method
Agenda Item 4:
- we will continue to have a dojo.data.core.Notification API, separate from the dojo.data.core.Write API
- the Notification API will include three methods
- onNew
- onDelete
- onSet
- if a read-write datastore implements the Notification API, it will call this.onNew() immediately after it's own newItem() method gets called, it will call this.onDelete() after it's deleteItem() method gets called, and it will call this.onSet() after any call to setValue(), setValues(), or unsetAttribute()
- a read-only datastore may also choose to implement the Notification API -- for example, if the datastore uses server-polling or Comet to get updates from the server, then the datastore can pass those updates on to the UI through the notification API
- the UI code can watch for notifications by using dojo.event.connect to connect to the onNew, onDelete, and onSet methods
- The dojo.data APIs have no dependency on the dojo toolkit. A project that uses only YUI or some other javascript toolkit can still include a datastore that conforms to the dojo.data APIs. If the app is not using dojo, the UI code cannot use dojo.event.connect to connect to the notification methods, but the app can still use closure replacement to do the same thing
- method arguments:
- onNew(newItem)
- onDelete(oldItem)
- onSet(item, attribute (or attribute name), oldValue (or undefined, or array of values), newValue (or undefined, or array of values))
- if onSet is called as a result of a setValues() call, then newValue will probably be an array
- if onSet is called as a result of a setValue() call, then newValue will not be an array
- if onSet is called as a result of an unsetAttribute() call, then newValue will be undefined
- if onSet is called for an attribute that had never before been set, then oldValue will be undefined
- etc.
jaredj: Since last Thursday other items at work have been occupying my time. I have not been able to spend much time on the implementation conversion to option 6 for the base API set (Result.js, Read.js, SimpleBaseStore?.js, JsonItemStore?, etc. Will hopefully have time this week.
One thing I would like to propose we add here is the support for the ? single character pattern match in addition to the basic * pattern match. There are three reasons I'd like to add this with community agreement as a standard option on the API:
- It should be less code in the simple pattern generator to support this than to ignore it (about two lines less, I believe). So, we get it virtually for free by deleting two lines in the Filter helper that many datastores can use.
- There is a definite way this can be mapped to relational stores like SQL. In SQL, as * is to %, ? is to _. So, there should be an easy translation to backend stores that use DB queries.
- One of the widget contributors would like to see this added (Douglas Hays).
Item 2.2:
Support for non-string (numeric) pattern matching. While going through this, I realized another likely common fuzzy search people may wish to do involves numbers, such as X >=5. This can come into play where you want to search for all items that have a last modified date greater than some value, for example. How should this be done, if any?
One way is to have the ability to specify a numeric comparator, in addition to the basic string comparators such as:
'=<some number>'
'>=<some number>'
'<=<some number>'
'><some number>'
'<<some number>'
'!=<some number>'
Another is not to have this on the standard API at all to keep it simpler and let individual datastores implement this however they wish to implement it. Chris M is in favor of leaving it up to the datastores and keep the required API of the datastore as small and simple as possible.
CCM: More specifically, we should not be introducing expressions other than simple wildcarding for string values into param values for find(). We stated in previous design discussions that the actual query language used in datastores is the responsibility of the datastore and must be hidden from the client of the find() api. The find() function is only provided to allow parameters to be provided for substitution into underlying datastore query language expressions. Exposing expressions through the api goes directly against design decision to shield the client from the language.
skinner: I'm inclined to agree with CCM. We're already on the slippary slope, now that we've added the * for string pattern matching, but maybe we should resist going any further down the slope. If we add numeric patters (like population > 5), then it's easy to argue we might also want boolean patterns (like airBags = true), and date patterns (like purchaseDate > 2007-02-21). And once we go too far that direction, we end up touching on other issues, like date formatting standardization, and combining patterns with AND and OR.
* ISSUE -
* Should the async save take a callback, like this:
* store.save({sync: false, onComplete: callback});
* Or should the async save return a Deferred, like this:
* var deferred = store.save({sync: false});
* deferred.addCallbacks(successCallback, errorCallback);
* Or should save() return boolean, like this:
* var success = store.save();
This needs to be decided on.
JaredJ: For symmetry of the read/write APIs, my vote would be for the store.save({sync: false, onComplete: callback}); Use callbacks, the same as you do for the find API. It also allows you to easily specify other callbacl, such as onError. I don't see what functionality a 'Deferred' object gives you that could not be done with using the callbacks method.
skinner: It would be good if the dojo.data APIs did not have any dependency on dojo.Deferred. If we can keep the APIs independent of any dependency on the dojo toolkit then people who don't use dojo can still conform to the APIs, and then we can play nicely with other toolkits. That's something that came up as a design goal at Dojo Developer Day in January. So, +1 for just using callbacks, like onError.
skinner: We've decided that find() and fetch() only operate in async mode, and that we don't allow a "sync" argument for doing sync:true or sync:false. I think we should say the same thing for save() -- save() should not take a "sync" argument, and we should never return a boolean success value.
var item = store.newItem(...);
store.setValue(item, "anAttribute", aValue);
...
store.saveItem(item);
may look more intuitive, compared to:
var item = store.newItem(...);
store.setValue(item, "anAttribute", aValue);
...
store.save();
where the caller may not 100% sure on what will be saved, especially when multiple and complicated calls to newItem(), setValue() and deleteItem() are involved.
saveItem() also allows a data store to skip the task to find out what to save by examining records of "new", "modified", and "deleted" items.