Developer's Notebook

 Dojo Developer's Notebook

Data Access Meetings

Meetings:
The Data Access community (dojo.data), tries to meet every week at the same time: 4:00PM-6:00PM EST and go over any outstanding issues for the current dojo.data specification. The meetings are held on IRC at: irc://irc.freenode.net in channel #dojo-meeting and are logged. Any dojo contributor is welcome to attend participate in the discussion.

Data Access Meeting (2006-08-29)

Data Access Meeting (2006-09-05)

[1:19 PM] brian_skinner: so, it's 1:20 -- no sign of chris yet -- should we go ahead without him?
[1:20 PM] slightlyoff: can we?
[1:20 PM] ttrenka: yeah, was about to ask the same q
[1:20 PM] slightlyoff: ttrenka: plotkit is PURDY
[1:20 PM] ttrenka: if you have ideas for visual improvements, now's the time
[1:21 PM] slightlyoff: ttrenka: uh, colors, some idea of scale (the interval numbers), and the interval markers in the background
[1:21 PM] ttrenka: ok
[1:21 PM] ttrenka: colors where?
[1:21 PM] brian_skinner: well, it would certainly be better to have him here -- but i'm not sure that we should block on it -- we're already months behind schedule on the data-store api stuff
[1:21 PM] slightlyoff: fair enough
[1:21 PM] brian_skinner: peller: any idea how to ping chris?
[1:21 PM] slightlyoff: ttrenka: the color scheme for plotkit is much nicer than our defaults
[1:22 PM] ttrenka: yeah, but that's easy to change.
[1:22 PM] ttrenka: right now you can specify the color of a series yourself
[1:22 PM] peller: brian_skinner: I'll go look for him... still don't have VPN on my Mac. Hang on
[1:22 PM] ttrenka: the demos don't
[1:22 PM] ttrenka: but I can definitely improve the plot area
[1:22 PM] slightlyoff: ttrenka: well, having a purdy defaults matters a LOT
[1:23 PM] ttrenka: the brown in the demos too are specified via CSS on the main widget div
[1:23 PM] ttrenka: it's not part of the actual widget.
[1:23 PM] ttrenka: (the overall background)
[1:23 PM] slightlyoff: ttrenka: oh, hrm, then purdy DEMOS matter a lot
[1:23 PM] ttrenka: ok
[1:23 PM] slightlyoff: 'cause that's what's gonna get copied
[1:23 PM] ttrenka: i'll come up with something today or tomorrow then
[1:23 PM] ttrenka: I thought the area demo was pretty :)
[1:24 PM] slightlyoff: ttrenka: yes, it is
[1:24 PM] ttrenka: but yes, I can change the color assignments a little and the plot area
[1:24 PM] brian_skinner: anybody have a chance to look over the proposed ReadStore? api?
[1:24 PM] brian_skinner: http://dojo.jot.com/dojo.data.api.ReadStore
[1:24 PM] ttrenka: not yet, unfortunately, going now
[1:24 PM] * slightlyoff goes
[1:25 PM] ttrenka: (http://archive.dojotoolkit.org/nightly/tests/widget/Chart/test_area.html, if you're interested brian)
[1:25 PM] brian_skinner: ttrenka: thanks, i'll go look
[1:25 PM] aszs: yes
[1:25 PM] aszs: its the same as the readstore on main api page, right?
[1:25 PM] slightlyoff: yeah, if that had background line markers, some interval numbers along the axes, and differen't color on the bg, it'd be awesome
[1:26 PM] |<-- peller has left freenode ()
[1:26 PM] ttrenka: slightlyoff: yeah, I'll play with it today.
[1:26 PM] brian_skinner: aszs: yes, the dojo.data.api page transcludes the dojo.data.api.ReadStore? page
[1:26 PM] aszs: ok
[1:27 PM] ttrenka: so brian--how is this any different from collections.Dictionary?
[1:27 PM] ttrenka: (just playing devil's advocate)
[1:27 PM] slightlyoff: brian_skinner: so does this store support any kind of query syntax?
[1:28 PM] brian_skinner: ttrenka: one second, let me answer slightlyoff first, since that's easier
[1:28 PM] brian_skinner: slightlyoff: yes
[1:28 PM] ttrenka: ok, np :)
[1:28 PM] brian_skinner: we've talked about two types of queries -- in-memory queries and server queries
[1:28 PM] slightlyoff: brian_skinner: which function takes it?
[1:28 PM] brian_skinner: this api just has server-queries
[1:28 PM] ttrenka: slightly: fetchArray
[1:28 PM] brian_skinner: right
[1:28 PM] slightlyoff: brian_skinner: but getValues is different?
[1:28 PM] aszs: wouldn't it better to return an iterator and not an array?
[1:28 PM] brian_skinner: i didn't try to address in-memory queries
[1:29 PM] slightlyoff: aszs: I think it might be
[1:29 PM] brian_skinner: aszs: there's a separate portion of the API that does return an iterator
[1:29 PM] aszs: where?
[1:29 PM] brian_skinner: but, i think for simple use cases, a simple array is convenient
[1:30 PM] ttrenka: aszs: you could use collections.Iterator on this array
[1:30 PM] aszs: well, you can get the array from the iterator
[1:30 PM] brian_skinner: my goal was to break the whole API up into little self-contained portions
[1:30 PM] aszs: using the iterator allows for deferred and asynchronous implementation
[1:30 PM] brian_skinner: a simple, minimalist data-store implementation can choose to implement only one or two portions of the API
[1:30 PM] slightlyoff: right, but refactoring to support iterator returns is gonna be harder later than it will be now
[1:30 PM] -->| peller (n=peller@209-6-218-233.c3-0.nwt-ubr2.sbo-nwt.ma.cable.rcn.com) has joined #dojo-meeting
[1:31 PM] brian_skinner: here's the full API page, which includes all the portions, including the iterator stuff:
[1:31 PM] brian_skinner: http://dojo.jot.com/dojo.data.api
[1:31 PM] ttrenka: thank you, I was just trying to find that
[1:31 PM] peller: brian_skinner: I pinged Chris, but he's logged in remotely and hasn't responded yet FYI
[1:31 PM] aszs: i don't see the need for both
[1:31 PM] brian_skinner: it has a fetchIterator() method that would take the same query syntax as the fetchArray() method
[1:32 PM] brian_skinner: peller: thanks!
[1:32 PM] aszs: the convence is minimal
[1:32 PM] ttrenka: brian, looking at dojo.data.api.AsyncReadStore?, which has some relevance here...
[1:33 PM] ttrenka: I know I wrote the iterator in Collections, but I think a forEach and a map mechanism in that iterator would be HUGE.
[1:33 PM] slightlyoff: ttrenka: you can add it = )
[1:33 PM] aszs: oops i'm wrong -- it thought the iterator interface had an toArray() method
[1:33 PM] brian_skinner: aszs: okay, if fetchArray() isn't popular, we could get rid of that and move fetchIterator() up into the most basic ReadStore? API
[1:33 PM] ttrenka: i can indeed
[1:33 PM] aszs: shouldn't it?
[1:34 PM] slightlyoff: aszs: dunno, should it?
[1:34 PM] slightlyoff: brian_skinner: I think that fetchArray() just gives makes it harder to think about the API as a whole
[1:34 PM] brian_skinner: aszs: we could add a toArray() method on the iterator
[1:34 PM] ttrenka: shouldn't that really be a part of the resultset though?
[1:34 PM] aszs: what's resultset?
[1:34 PM] ttrenka: the thing that is returned from fetch
[1:35 PM] aszs: how is a resultset difference from an iterator?
[1:35 PM] slightlyoff: that's what featchArray/fetchIterator does, right?
[1:35 PM] ttrenka: the wiki page has it as an array
[1:35 PM] ttrenka: right
[1:35 PM] aszs: i think widget should consume iterators as much as possible
[1:35 PM] ttrenka: but the difference is that an iterator iterates on the resultset
[1:35 PM] aszs: not resultsets
[1:35 PM] aszs: that makes them a lot more general
[1:35 PM] ttrenka: wait.
[1:35 PM] ttrenka: makes what a lot more general?
[1:36 PM] aszs: widgets
[1:36 PM] ttrenka: ok, you lost me
[1:37 PM] aszs: we could write widgets that use the dojo.data apis to display and modify data
[1:37 PM] ttrenka: ah, ok.
[1:37 PM] ttrenka: i would think you'd want the resultset and not an iterator for that
[1:37 PM] slightlyoff: ?
[1:37 PM] ttrenka: let the widget determine how it wants to iterate over a set
[1:37 PM] slightlyoff: I don't really see a difference
[1:37 PM] aszs: me neither
[1:37 PM] slightlyoff: ttrenka: why?
[1:37 PM] brian_skinner: ttrenka: how would a resultset differ from an iterator?
[1:37 PM] slightlyoff: ttrenka: what does that buy you?
[1:37 PM] ttrenka: a resultset could take a number of different forms
[1:38 PM] ttrenka: we could pass back an array
[1:38 PM] ttrenka: or a dictionary
[1:38 PM] ttrenka: or an xml nodelist
[1:38 PM] ttrenka: or whatever
[1:38 PM] aszs: is the resultset api described anywhere?
[1:38 PM] slightlyoff: uh, lets just say "you'll get one of these"
[1:38 PM] slightlyoff: I don't see much value in not just cutting down what can be returned
[1:38 PM] ttrenka: ...yeah, kind of wishing Chris was here now
[1:38 PM] brian_skinner: aszs: no -- nobody has posted a description of a resultset api
[1:38 PM] ttrenka: :(
[1:39 PM] brian_skinner: it's vapor-spec :-)
[1:39 PM] slightlyoff: haha
[1:39 PM] aszs: have considered subclasses of iterator interface such as a MutableIterator? or a DeferredIterator??
[1:39 PM] aszs: i think we are better off defining those than pushing that to the dojo.data apis
[1:40 PM] brian_skinner: aszs: the dojo.data.api.AsyncReadStore? write up includes some use of Deferred-style API
[1:40 PM] brian_skinner: http://dojo.jot.com/dojo.data.api
[1:41 PM] brian_skinner: the iterator object acts sort-of like a deferred
[1:41 PM] aszs: yes, i'm suggesting that would not be necessary if there was a DeferredIterator?
[1:41 PM] slightlyoff: aszs: not everyone is Twisted-clued
[1:42 PM] brian_skinner: aszs: right, i think we may both saying the same thing -- in the async use case we want the fetchIterator() method to return an interator that has deferred-style behavior
[1:42 PM] brian_skinner: right now dojo has no DeferredIterator?, so that's something we need to invent
[1:43 PM] slightlyoff: I'm for inventing DeferredIterator? if it'll simplify the dojo.data stuff
[1:43 PM] slightlyoff: or at least move more code out of it = )
[1:43 PM] brian_skinner: slightlyoff: that would be great
[1:43 PM] ttrenka: added forEach and map.
[1:43 PM] brian_skinner: ttrenka: where'd you add them?
[1:43 PM] aszs: ttrenka: ?
[1:44 PM] ttrenka: in the wiki
[1:44 PM] ttrenka: async read store
[1:44 PM] brian_skinner: thanks
[1:44 PM] ttrenka: np
[1:44 PM] slightlyoff: ttrenka: heh, I though you'd added them to dojo.collections.Iterator ;-)
[1:44 PM] aszs: ok, so basically that is DeferredIterator?
[1:44 PM] ttrenka: map has been there for a long time already
[1:44 PM] ttrenka: forEach has been added to selective collections
[1:45 PM] brian_skinner: aszs: yes, or at least it's an emerging spec for some sort of Deferred Iterator
[1:46 PM] aszs: so maybe fetchIterator needs an option flags or keyword parameter
[1:46 PM] brian_skinner: i tried to give some sense of what a DeferredIterator? might look like, but it seems like a hard problem, and I wasn't sure just what it needed to be able to do
[1:46 PM] brian_skinner: aszs: yup, maybe so -- what options?
[1:46 PM] ttrenka: yeah, that's an overall issue, I think
[1:47 PM] aszs: depends on the implementation, e.g. maxcount, async or not, etc.
[1:47 PM] brian_skinner: okay
[1:48 PM] aszs: so if there's a general purpose DeferredIterator? then there's no need for a separate data.api.AsyncReadStore?
[1:48 PM] brian_skinner: i was thinking it would be nice if people could write simple data store implementations without having to worry about async stuff -- like if you just want to make something like a read-only CSV store, or a JSON data simple-store
[1:48 PM] aszs: yes of course
[1:49 PM] aszs: the flag i was thinking about would be for user than didn't want to deal with async results
[1:50 PM] slightlyoff: aszs: not sure how it simplifies then
[1:50 PM] aszs: just like the parameter in xmlhttprequest.send()
[1:50 PM] brian_skinner: right, the data.api.AsyncReadStore? API only actually has one method, fetchIterator() -- everything else there is just examples of talking to the iterator itself
[1:50 PM] slightlyoff: ok
[1:50 PM] aszs: slightlyoff: not sure i follow?
[1:51 PM] slightlyoff: aszs: you're still in the business of presenting 2 "modes" to the developer
[1:52 PM] aszs: slightlyoff: yes, i don't see how to avoid that if we want to support async results
[1:52 PM] aszs: but still there's on less interface
[1:52 PM] slightlyoff: uh, deferred handles it by just immediately calling back
[1:53 PM] aszs: ko
[1:53 PM] aszs: oops
[1:53 PM] aszs: ok
[1:53 PM] brian_skinner: slightlyoff, aszs: do one of you (or both of you) feel like taking a stab at posting a spec and some examples for the DeferredIterator? API, as well as a spec and examples for how you call fetchIterator?
[1:54 PM] aszs: then the flag would a requirement... but do you think that some implementation would have reasons to choose sync or async?
[1:54 PM] ttrenka: in all honesty, shouldn't we just assume async?
[1:55 PM] aszs: oops again... i mean wouldn't be a requirement
[1:55 PM] slightlyoff: yes
[1:55 PM] slightlyoff: I'm all for assuming async
[1:55 PM] slightlyoff: sync is just a special case of async = )
[1:55 PM] aszs: me too
[1:55 PM] ttrenka: if it's synchronous then the callbacks will be fired immediately
[1:55 PM] ttrenka: right
[1:56 PM] slightlyoff: so yeah, one interface
[1:57 PM] slightlyoff: I think we're only going to help folks by providing different "slices" of the API if they can always work with the results the same way
[1:57 PM] ttrenka: to be honest, I'm not really sure what having a read store and a write store buys us either?
[1:57 PM] slightlyoff: ttrenka: can simplify the implementation for read-only things by not having to worry about the writing methods?
[1:57 PM] ttrenka: unless (brian) you're using this as interface definitions
[1:57 PM] aszs: ttrenka: yes, that why i proposing a MutableIterator?
[1:58 PM] ttrenka: k
[1:58 PM] brian_skinner: there are two things -- the iterface definitions and the data stores that implement those interfaces
[1:58 PM] slightlyoff: yep
[1:58 PM] brian_skinner: simple read-only data stores won't want to have to implement a write-api
[1:58 PM] brian_skinner: read-only is probably a very common use case
[1:58 PM] brian_skinner: with a much simpler api
[1:59 PM] ttrenka: ok. so everything on http://dojo.jot.com/WikiHome/dojo.data.api are basically interface definitions.
[1:59 PM] brian_skinner: yup
[1:59 PM] ttrenka: ok
[1:59 PM] ttrenka: I'm going to make that clear then
[1:59 PM] slightlyoff: yes
[1:59 PM] slightlyoff: = )
[1:59 PM] brian_skinner: yup, thanks ttrenka
[1:59 PM] ttrenka: ok, done
[2:00 PM] brian_skinner: i was thinking that it would be good to have actual source code in SVN just for the API definitions
[2:00 PM] brian_skinner: so that documentation would automatically get generated
[2:00 PM] brian_skinner: and because SVN is where people look for inof
[2:00 PM] brian_skinner: info
[2:01 PM] brian_skinner: but a data-store implementation would not have to actually dojo.require() any of the interface files
[2:01 PM] aszs: so is clear() equivalent to setValues with an empty array?
[2:02 PM] aszs: or removes the attribute entirely?
[2:03 PM] brian_skinner: aszs: i'm not sure -- that needs soime thought, the distinction between having an attribute with no values vs. not having the attribute
[2:03 PM] brian_skinner: maybe that's not a distinction worth making
[2:03 PM] brian_skinner: RDF doesn't make that distinction, does it?
[2:03 PM] aszs: if not then there should be a clear()
[2:03 PM] aszs: shouldn'
[2:03 PM] brian_skinner: we talked about that distinction in Chander once
[2:04 PM] aszs: i'm having trouble typing today ;)
[2:04 PM] brian_skinner: okay, so then yes, I think clear() is equivalent to setValues with an empty array
[2:04 PM] aszs: if it is i don't think we need a clear()
[2:04 PM] aszs: but RDF doesn't make that distinction
[2:05 PM] aszs: so does a dictionary a la javascript and python
[2:05 PM] aszs: oops
[2:05 PM] aszs: RDF does make that distinction
[2:05 PM] brian_skinner: really?
[2:05 PM] aszs: yes
[2:05 PM] brian_skinner: wanh
[2:05 PM] aszs: there no notion as undefined
[2:05 PM] aszs: or null
[2:06 PM] aszs: hmmm
[2:06 PM] slightlyoff: aszs: if it's just a wrapper for setValues([]), I don't see the harm = )
[2:06 PM] brian_skinner: having some convenience functions is convenient ;-)
[2:06 PM] brian_skinner: and may make for more readable code
[2:07 PM] aszs: slightlyoff: the expense is confusion and cognitive overhead vs. minimal convenivence imho
[2:07 PM] slightlyoff: aszs: not buying it here
[2:08 PM] ttrenka: neither am i
[2:08 PM] brian_skinner: how about we mark clear() as an open issue -- something we might want to remove from the API?
[2:08 PM] aszs: ok
[2:08 PM] slightlyoff: clear() is a pretty, um, clear semantic ;-)
[2:08 PM] ttrenka: i had a similar issue with the first version of FilteringTable, and ended up adding the clear method for clarity
[2:08 PM] brian_skinner: okay
[2:08 PM] ttrenka: (the issue wasn't me using it, it was others trying to)
[2:09 PM] aszs: ok,
[2:09 PM] aszs: so is setValues([]) eqiveant to set(attribute, undefined)?
[2:10 PM] brian_skinner: yes, i think so
[2:10 PM] brian_skinner: although, to be honest, i had never considered that someone might has undefined as a value for set()
[2:11 PM] brian_skinner: i had only thought about passing null
[2:11 PM] slightlyoff: I'm gonna have to run
[2:11 PM] aszs: so setValue(att, []); assert(typeof get(att) == 'undefined')
[2:11 PM] brian_skinner: slightlyoff: okay -- same time next week?
[2:12 PM] slightlyoff: yep
[2:12 PM] slightlyoff: that works for me
[2:12 PM] brian_skinner: slightlyoff: you feel like taking a stab at writing up a deferredIterator spec?
[2:12 PM] ttrenka: l8r
[2:12 PM] slightlyoff: brian_skinner: uh, sure, send me mail about it?
[2:12 PM] brian_skinner: slightlyoff: will do
[2:12 PM] slightlyoff: otherwise I'm garunteed to forget =
[2:12 PM] slightlyoff: thank you!
[2:13 PM] aszs: ok does getValues('non-existent-attribute') return []
[2:14 PM] brian_skinner: yes
[2:14 PM] brian_skinner: oh, wait
[2:14 PM] brian_skinner: no, i'm not sure
[2:15 PM] ttrenka: if it helps at all...
[2:15 PM] brian_skinner: i think maybe it should return null or throw an exception in that case
[2:15 PM] brian_skinner: i don't have a sense of what return value would be the most convenient for users
[2:15 PM] ttrenka: one of the standards I did with all of the collections was that if a method was supposed to return multiple values, it always returns an array--even if it's empty
[2:15 PM] ttrenka: whereas methods to get a single value would return null
[2:16 PM] brian_skinner: ttrenka: yes, that's what i had in mind with the get() and getValues() methods
[2:16 PM] ttrenka: yeah, it helps to be consistent
[2:16 PM] ttrenka: so then getValues() will return []
[2:16 PM] ttrenka: no matter what.
[2:17 PM] brian_skinner: but I think aszs is pointing out that if we do that, then we can't faithfully introspect on some notions in some data formats (like RDF)
[2:17 PM] aszs: i think there need to be a way to test for the existence of an attribute
[2:17 PM] |<-- slightlyoff has left freenode ()
[2:17 PM] brian_skinner: aszs: okay
[2:18 PM] aszs: checking for undefined doesn't see enough since the attribute could have that as its value
[2:18 PM] brian_skinner: we could add a hasAttribute() method
[2:18 PM] ttrenka: I would agree with the need for a test for an attribute for sure, but I don't think that should affect get
[2:18 PM] brian_skinner: ttrenka: okay
[2:18 PM] aszs: yes
[2:19 PM] brian_skinner: so hasAttribute() always returns a boolean, and getValues() always returns an array, and get() sometimes returns null?
[2:19 PM] aszs: and i would think clear(att); assert( hasAttribute(att) == false);
[2:19 PM] brian_skinner: aszs: +1
[2:19 PM] ttrenka: ok
[2:19 PM] ttrenka: oh jeez, I gotta run
[2:19 PM] aszs: get should return undefined
[2:19 PM] aszs: just like the wiki says now
[2:19 PM] brian_skinner: okay
[2:19 PM] aszs: it return null only if it was set to null
[2:20 PM] brian_skinner: yup
[2:20 PM] aszs: setValue(att, []); assert( hasAttribute(att) == false); ?
[2:20 PM] ttrenka: talk to you guys next week
[2:20 PM] aszs: bye
[2:20 PM] |<-- ttrenka has left freenode ()
[2:21 PM] brian_skinner: aszs: i'm not sure about that one -- what do you think is right?
[2:21 PM] aszs: i think so
[2:22 PM] aszs: supporting multiple values in RDF is tricky
[2:22 PM] aszs: since RDF doesn't support it
[2:22 PM] brian_skinner: :-)
[2:23 PM] aszs: how does ibm map undefined to their SQL datastore?
[2:24 PM] brian_skinner: i don't know
[2:24 PM] aszs: peller: do you know?
[2:24 PM] aszs: undefined in javascript is kind of lame
[2:24 PM] brian_skinner: it's been 15 years since i did stuff with SQL -- at the time there was a notion of null values, but not undefined
[2:24 PM] aszs: yes
[2:24 PM] peller: aszs: I'm really not a DB guy, sorry
[2:25 PM] aszs: undefined in javascript is lame introduce 4 valued logic!
[2:25 PM] aszs: python throw an exception where javascript returns undefined
[2:25 PM] aszs: i think that is better
[2:26 PM] aszs: maybe it should be an error to call "set(att, undefined)"
[2:26 PM] peller: aszs: I don't know that IBM does a lot with JS<>SQL. Most of the mappings are C or Java where you wouldn't have an undefined?
[2:26 PM] brian_skinner: well, we could change the data store API spec to require that conforming data store implementations never return undefined
[2:27 PM] brian_skinner: aszs: i'd be fine with saying that "set(att, undefined)" throws an exception
[2:27 PM] aszs: what does your JS SDO implementation do if undefined is set?
[2:28 PM] brian_skinner: aszs: what do you think about the whole notion of this modular API, with some data stores implementing portions of the API and some data stores implementing the whole API?
[2:28 PM] aszs: i'm all for that!
[2:28 PM] brian_skinner: :-)
[2:29 PM] brian_skinner: and what do you think about the breakdown as it appears now in http://dojo.jot.com/dojo.data.api ?
[2:30 PM] brian_skinner: some of the stuff near the bottom of the page is pretty speculative
[2:30 PM] aszs: look pretty good
[2:30 PM] brian_skinner: cool
[2:30 PM] aszs: not sure about TransactionalStore?
[2:31 PM] brian_skinner: then maybe we're pretty close to getting something that everybody might be game to sign off about
[2:31 PM] brian_skinner: at least for the first 5 or 6 parts of the API
[2:32 PM] brian_skinner: the Transactional stuff is important in OpenRecord -- but I think it could be implemented as a simple mixin that works with an simple ReadWrite? datastore
[2:32 PM] brian_skinner: with any simple ReadWrite? datastore
[2:32 PM] aszs: so
[2:33 PM] aszs: what does endTransaction() do
[2:33 PM] brian_skinner: it depends
[2:33 PM] aszs: how is it different from save() or rollback()
[2:33 PM] brian_skinner: let's say your code looks like this:
[2:34 PM] aszs: if we could just agree on ReadStore? and WriteStore? would that be enough?
[2:34 PM] aszs: for starters
[2:34 PM] brian_skinner: beginTrans(); store.set(foo, "bar", 1); beginTrans(); store.set(foo, "iggy", 1); endTrans(); endTrans();
[2:34 PM] brian_skinner: the first endTrans() does nothing
[2:35 PM] brian_skinner: the second endTrans() calls save()
[2:35 PM] brian_skinner: yes, if we can just agree on ReadStore? and WriteStore?, that would go a long way towards unblocking progress
[2:35 PM] aszs: who do you know implements nested transactions?
[2:35 PM] brian_skinner: ?
[2:36 PM] brian_skinner: um, I'm not sure
[2:36 PM] aszs: JDBC doesn't support that
[2:36 PM] aszs: it uses savepoint instead
[2:36 PM] aszs: because no SQL database support nested transactions
[2:36 PM] brian_skinner: I've definitely seen it somewhere
[2:36 PM] aszs: instead they support checkpoints or savepoints
[2:36 PM] aszs: yes they exist
[2:37 PM] aszs: but rarely
[2:37 PM] brian_skinner: i don't know how to write modular code without them
[2:37 PM] brian_skinner: class A has a method foo, and class B has a method bar, and foo calls bar
[2:37 PM] brian_skinner: bar should be written without knowledge of foo
[2:38 PM] brian_skinner: bar needs to do a beginTrans(); edit; endTrans();
[2:38 PM] brian_skinner: foo needs to do a beginTrans(); edit; B.bar(); edit; endTrans();
[2:38 PM] aszs: yes, i understand the attraction
[2:38 PM] brian_skinner: is there a better alternative?
[2:39 PM] brian_skinner: or just a different alternative?
[2:39 PM] aszs: but millions of lines of Java database code doesn't do that
[2:39 PM] brian_skinner: how do they do it?
[2:39 PM] aszs: JDBC doesn't have a begintransaction
[2:39 PM] aszs: aside, another problem is supporting autocommit
[2:39 PM] brian_skinner: do they get the same effect with checkpoints or savepoints?
[2:39 PM] aszs: yes and no
[2:40 PM] aszs: so JDBC just has commit() and rollback()
[2:40 PM] aszs: and an autocommit attribute
[2:41 PM] brian_skinner: an autocommit attribute?
[2:41 PM] aszs: so bar would have create a savepoint if what to be able to undo the work it did
[2:41 PM] aszs: yes
[2:41 PM] aszs: autocommit = true
[2:41 PM] aszs: means commit() and rollback() are no ops
[2:42 PM] aszs: every modification is commited immediately
[2:42 PM] aszs: if a database didn't support transactions autocommit is always true
[2:42 PM] brian_skinner: okay
[2:43 PM] aszs: nested transaction are relally hard to implement robustly and basically don't exist in the SQL world
[2:44 PM] brian_skinner: so if we want nested transactions for openrecord, we could have that code in the OpenRecord client code, rather than in the datastore implementation
[2:44 PM] aszs: yes...
[2:45 PM] aszs: and you might find it isn't necessary... what's wrong with rolling back the whole transaction if something goes wrong?
[2:46 PM] aszs: this kind of goes back to the discussion about having a save button
[2:46 PM] brian_skinner: i think you do want to roll back the whole transaction -- the nested transaction thing just makes it easy to mark where the whole transaction begins and ends
[2:47 PM] brian_skinner: if foo() calls bar(), then the whole transaction starts and ends in foo()
[2:47 PM] brian_skinner: if you call bar() directly, then the whole transaction starts and ends in bar()
[2:47 PM] brian_skinner: if foo() calls bar(), the begin and end calls in bar() become no-ops
[2:47 PM] aszs: in most database apis there is no begintransaction()
[2:48 PM] aszs: an new transaction starts immediate after commit() or rollback() is called
[2:48 PM] aszs: so you don't have to worry about begintransaction nesting
[2:49 PM] brian_skinner: right, but if foo() calls bar(), it's important that bar() not have a commit() statement that actually does anything
[2:49 PM] brian_skinner: you don't want to commit until foo is done
[2:49 PM] aszs: yes
[2:50 PM] aszs: yes bar() would never call commit()
[2:50 PM] brian_skinner: in the sort of nested transactions i'm talking about, this is all just done in client-side code -- there's no actual server database feature involved
[2:50 PM] aszs: yes
[2:50 PM] brian_skinner: the begin and end pairs just help the client code figure out when to actually commt
[2:50 PM] brian_skinner: commit()
[2:51 PM] brian_skinner: seems simple/harmless
[2:52 PM] brian_skinner: ...
[2:52 PM] aszs: so did i convince you that it should not be part of the data store api?
[2:52 PM] aszs: instead just add a rollback() alongside save() in the writestore
[2:52 PM] brian_skinner: i'm happy to leave it out of the datastore api
[2:52 PM] aszs: and implement the begin/end in the client?
[2:52 PM] aszs: cool
[2:53 PM] brian_skinner: i don't see the harm in offering it as an optional mixin, but we can talk about that later
[2:53 PM] brian_skinner: seems like the real thing to worry about now is the DeferredIterator? api, and the fetchIterator() api
[2:53 PM] brian_skinner: do you feel like taking a stab at those?
[2:53 PM] aszs: ok, but in that case rollback() still needs to be moved to WriteStore?()
[2:54 PM] aszs: ok
[2:54 PM] brian_skinner: aszs: okay, i'll move rollback() to WriteStore?()
[2:55 PM] brian_skinner: is rollback() the right name for that?
[2:55 PM] aszs: so i don't envision the RDF datastore implementing the Metamodel stuff
[2:55 PM] aszs: yes
[2:55 PM] brian_skinner: the pairing of save() and rollback() seems weird
[2:55 PM] brian_skinner: commit() and rollback() seem natural
[2:55 PM] brian_skinner: or save() and ___ ?
[2:55 PM] aszs: yes i agree
[2:55 PM] aszs: forget()?
[2:55 PM] aszs: discard()
[2:55 PM] brian_skinner: :-)
[2:56 PM] brian_skinner: cancel()
[2:56 PM] aszs: i like commit/rollback() if it ok to rename save()
[2:56 PM] brian_skinner: we can rename save()
[2:56 PM] aszs: oh yeah cancel() the obvious one
[2:57 PM] aszs: but maybe less precise in meaning
[2:57 PM] brian_skinner: okay, i'll use commit/rollback for now, and i'll put in a note about possible other names
[2:57 PM] aszs: sounds good
[2:57 PM] aszs: should we adjurn?
[2:57 PM] aszs: adjourn?
[2:57 PM] brian_skinner: more stuff to talk about today, or shoud adjourn?
[2:58 PM] brian_skinner: jinx
[2:58 PM] aszs: i concur
[2:58 PM] brian_skinner: next tuesday at 1:00?
[2:58 PM] aszs: ok
[2:58 PM] aszs: works for me
[2:58 PM] brian_skinner: cool -- thanks!
[2:58 PM] brian_skinner: bye peller!
[2:58 PM] aszs: i thinking we're making progress
[2:58 PM] aszs: ...
[2:58 PM] aszs: bye
[2:59 PM] brian_skinner: yup
[2:59 PM] brian_skinner: bye
[2:59 PM] <--| aszs has left #dojo-meeting

Data Access Meeting (2006-09-12)

Data Access Meeting (2006-09-19)

Data Access Meeting (2006-09-21)

 Resolutions

    * Brian to take code from dojo.data.Read/Result/Write pages and check those into SVN head
    * propose to move getByIdentity() and getIdentity() out of dojo.data.Read (maybe into dojo.data.Identity)
    * propose to add new methods add() and remove() to dojo.data.Write()

Transcript

[1:18 PM] brian_skinner: looks like it's just us two
[1:18 PM] jaxsphere: yep
[1:18 PM] brian_skinner: i didn't put together an agenda
[1:19 PM] jaxsphere: we had the one from last week
[1:19 PM] jaxsphere: err tues :)
[1:19 PM] brian_skinner: http://dojo.jot.com/2006-09-19
[1:19 PM] brian_skinner: plus the questions that Adam raised in his mail today
[1:21 PM] jaxsphere: It sounds like Adam has the api's in svn
[1:21 PM] jaxsphere: I'd like to get access to the same one's he's using
[1:21 PM] jaxsphere: maybe work this like the gfx team is doing
[1:21 PM] brian_skinner: he's working on an RDF implementation of the API
[1:21 PM] jaxsphere: can we get the current proposed API's posted to the contrib list
[1:22 PM] jaxsphere: as a zip
[1:22 PM] jaxsphere: we can update them there as issues are resolved
[1:22 PM] jaxsphere: I'd like to try implementing the xml ds behind these and see what other issues we hit
[1:23 PM] jaxsphere: but dont want code that's out of sync with what u guys are doing
[1:23 PM] jaxsphere: other option is just to put the api's into the datamodel branch in svn?
[1:24 PM] brian_skinner: i'm not actually doing any coding yet -- I wanted to start writing unit tests but haven't found the time -- so no risk of getting out of sync with me!
[1:24 PM] brian_skinner: i don't know that Adam is working in any SVN repository at all
[1:24 PM] brian_skinner: he may be working on his local hard drive
[1:24 PM] brian_skinner: or he may be working in his own SVN repository
[1:25 PM] jaxsphere: I'll send him a reply on contrib and see if he can post the api code to the list
[1:25 PM] brian_skinner: for his Raccoon/Rhizome project, rather than the Dojo SVN repository -- http://www.liminalzone.org/Rhizome
[1:26 PM] brian_skinner: i'd be happy to check the API files into the dojo/data/ directory in SVN head, if you don't think that would be premature
[1:26 PM] jaxsphere: i dont think it is at this point.  i think we need to validate via impls
[1:27 PM] brian_skinner: i know the APIs aren't quite stable, but we could make incremental changes in the SVN API files instead of the wiki API files
[1:27 PM] jaxsphere: until we actually write some code against them (like adam), i cant tell what additional issues there are going to be
[1:27 PM] brian_skinner: yup
[1:27 PM] brian_skinner: okay, i'll do a checkin this afternoon
[1:27 PM] jaxsphere: k
[1:27 PM] brian_skinner: should i just check in dojo.data.Read and dojo.data.Result, or should I also do dojo.data.Write?
[1:28 PM] jaxsphere: Write too
[1:28 PM] brian_skinner: okay, will do
[1:28 PM] jaxsphere: its private branch
[1:29 PM] jaxsphere: so the getByIdentity() function...\
[1:30 PM] jaxsphere: why would it invoke a query?
[1:30 PM] brian_skinner: I was thinking of checkin to head rather than private branch, and just marking the code as experimental -- that way API docs will get generated, and changes will automatically get posted to the dojo-checkins mailing list, and there's more visibility for other dojo developers
[1:30 PM] jaxsphere: i was assuming the string returned would be calculated from the item, source, values, etc.
[1:30 PM] jaxsphere: that's even better
[1:30 PM] brian_skinner: peachy, i'll do that
[1:31 PM] jaxsphere: we're not getting a whole lot of feedback from others outside the gang of 4 or 5... i think its time to try to make it concrete
[1:31 PM] brian_skinner: yup, agreed
[1:31 PM] jaxsphere: once there are ut's and examples, i'm sure we;ll get tons of input :)
[1:32 PM] brian_skinner: i'm planning to do a quick CSV implementation too -- just so that we have a concrete example -- something that can be wired up to different widgets
[1:32 PM] brian_skinner: i think adam was talking about getByIdentity(), not getIdentity()
[1:32 PM] jaxsphere: thats a really good one to start with
[1:32 PM] brian_skinner: getIdentity just returns a string
[1:33 PM] jaxsphere: right, ok
[1:33 PM] brian_skinner: but getByIdentity returns an item
[1:33 PM] jaxsphere: that returns an item, given a string from prev call to getIdentity()
[1:33 PM] brian_skinner: yup
[1:34 PM] brian_skinner: so, if the item happens to be in the cache, then it can return the item immediately
[1:34 PM] brian_skinner: but if not, then it might need to hit the server
[1:34 PM] jaxsphere: so the impl either needs to create a map index of identities so that items can be looked up, or if not not in the map try to pull from remote
[1:34 PM] jaxsphere: ok, gotcha
[1:34 PM] brian_skinner: yup
[1:35 PM] brian_skinner: should be straightforward to implement -- but the return value would be ugly
[1:35 PM] jaxsphere: yeah
[1:35 PM] jaxsphere: in a purely restful approach, each item would have an associated uri when retrieved remotely
[1:36 PM] jaxsphere: but that's not always the case
[1:36 PM] brian_skinner: always return a Deferred?  ...  sometimes return a Deferred?  ...  always return an item synchronously, even if it means waiting on the server response?
[1:36 PM] jaxsphere: perhaps identity functions should be an optional layer
[1:36 PM] brian_skinner: you mean, move getByIdentity() and getIdentity() out of dojo.data.Read, and into something like dojo.data.Identity?
[1:37 PM] jaxsphere: y
[1:38 PM] brian_skinner: that sounds okay to me -- we'd still have the same basic problem with the return values, but pushed out so that fewer people have to think about it
[1:38 PM] jaxsphere: right...kiss for common uc's
[1:39 PM] brian_skinner: okay, we can propose that at the next IRC meeting, or via the dojo-dev list
[1:39 PM] jaxsphere: one can build their own indexes off of the deffered, right :)
[1:39 PM] brian_skinner: i didn't follow that last idea -- can you explain?
[1:40 PM] jaxsphere: as items are recieved in the client, app code that's iterating can cache in a map
[1:40 PM] jaxsphere: however it wants
[1:40 PM] jaxsphere: but it would be up to the app to deal with identity
[1:41 PM] jaxsphere: just for grins, for CSV store, how would you implement getIdentity()?
[1:41 PM] brian_skinner: yup, but that seems a little scary -- the data provider implementation maintaining one cache-map thing, and the client app maintaining another
[1:41 PM] brian_skinner: makes MRU cache management that much harder
[1:42 PM] jaxsphere: y
[1:42 PM] brian_skinner: for CSV store, I was just going to use simple row numbers for getIdentity() -- '1', '2', '3'...
[1:42 PM] jaxsphere: would you offer a private function on the datastore to specify the key columns to use for identity?
[1:43 PM] brian_skinner: yup, a fancier CSV store could do that
[1:43 PM] jaxsphere: i think there's a set of these add'l identity related functions that will make sense to put with Identity.js
[1:43 PM] brian_skinner: but that seemed to start to get into metamodel/schema stuff, which we haven't really talked about API for
[1:44 PM] brian_skinner: yup, good point
[1:44 PM] jaxsphere: right, identity will prob require Read/Write/Meta api's
[1:44 PM] brian_skinner: another reason to push identity out fo dojo.data.Read
[1:44 PM] jaxsphere: yep
[1:46 PM] brian_skinner: i'm worried that even our simplest methods, get() and getValues() might actually need to trigger server access sometimes, just like getByIdentity() sometimes does
[1:46 PM] brian_skinner: if the user is navigating a complex object graph
[1:46 PM] jaxsphere: Let's hold this agenda item until weve each done a first pass prototoype on the current proposed apis:
[1:46 PM] jaxsphere: sign off on some APIs (or is it too early for this?)
[1:46 PM] jaxsphere:     * Read and Result
[1:46 PM] jaxsphere:     * Write
[1:46 PM] brian_skinner: okay
[1:47 PM] jaxsphere: what was the problem with Write api and saving single value?
[1:47 PM] jaxsphere: err adding
[1:47 PM] brian_skinner: example...
[1:47 PM] brian_skinner: books and authors
[1:48 PM] jaxsphere: child collections and references?
[1:48 PM] brian_skinner: an author can write many books -- a book can have a second author (more than one author)
[1:48 PM] brian_skinner: if TheStand is a book
[1:49 PM] brian_skinner: var authors = store.getValues(TheStand, "authors");
[1:49 PM] brian_skinner: then authors.length == 1
[1:49 PM] brian_skinner: authors[0] == StephenKing
[1:50 PM] brian_skinner: how do I add a second author?
[1:50 PM] |<-- DojoLog has left freenode (Read error: 104 (Connection reset by peer))
[1:50 PM] jaxsphere: and authors is an object with its own props
[1:50 PM] jaxsphere: or just string?
[1:50 PM] brian_skinner: authors is just a simple array
[1:50 PM] brian_skinner: StephenKing is an item
[1:51 PM] brian_skinner: var name = store.get(StephenKing, 'name')
[1:51 PM] jaxsphere: ok, add/remove on multivalued attributes (primitives)
[1:51 PM] brian_skinner: ?
[1:52 PM] jaxsphere: the authors is an array of strings, owned as part of the book item
[1:53 PM] brian_skinner: okay, that might be a good simpler case to start with
[1:53 PM] jaxsphere: or... is authors an array of references to Authors (owned by Book) and from the Authors you can get their names
[1:53 PM] brian_skinner: yes, that's the case I was thinking about
[1:53 PM] jaxsphere: from an author, you can add/remove booksAuthored
[1:53 PM] brian_skinner: yup
[1:54 PM] jaxsphere: a collection of Books (the opposite end of the relationship)
[1:54 PM] jaxsphere: Handling relationships like these require Meta package
[1:54 PM] brian_skinner: in RDF stores, and in OpenRecord, you can set up "inverse" attributes -- so that the values of booksAuthored and authorOf are automatically kept in synce
[1:54 PM] jaxsphere: Maybe a Relations module?
[1:55 PM] brian_skinner: but, ignoring the "inverse" thing for now
[1:55 PM] jaxsphere: well, handling inverse is very common
[1:55 PM] brian_skinner: let's just say some attribute has a more than one value -- how do you add a new value?
[1:55 PM] jaxsphere: on 1-many
[1:55 PM] jaxsphere: you need an add/remove op
[1:55 PM] brian_skinner: doesn't really matter if the values are literals or object references
[1:55 PM] -->| DojoLog (n=stats@reigndropsfall.net) has joined #dojo-meeting
[1:56 PM] jaxsphere: but its not just multi valued
[1:56 PM] jaxsphere: also, Employee.businessAddress->Address
[1:57 PM] brian_skinner: if the employee only has one businessAddress, then we already have API for that
[1:57 PM] jaxsphere: this is a "set" for a relationship between objs.  If the relationship is one of ownership, a backreference needs to be set
[1:57 PM] brian_skinner: yup
[1:57 PM] jaxsphere: but how do you know that it's a special ownership relationship without additional metadata
[1:58 PM] jaxsphere: eg. parent/child collection relationships
[1:59 PM] brian_skinner: the data provider implementation could do hande the backreference, even without a metadata API, if the data provider was hard-coded to know about that, or if it was reading metadata info from an RDBMS schema, even if that metadata wasn't exposed in any dojo.data API
[1:59 PM] jaxsphere: we need to add add90 and remove() ops to Write
[1:59 PM] jaxsphere: alonside set
[1:59 PM] brian_skinner: yup, i think we should maybe add add() and remove()
[2:00 PM] brian_skinner: but that raises a couple more questions...
[2:01 PM] brian_skinner: if there are multiple values, are those values ordered -- does add() just append the new value to the end of the list, or does add() allow you to specify where to put the new value in the list
[2:01 PM] brian_skinner: first author, second author, third author
[2:02 PM] jaxsphere: right, addFirst, addAfter,...
[2:03 PM] jaxsphere: now that i konw what the agenda bullet was about, i'll go back through the prototype...  Let's discuss this more next tues
[2:03 PM] brian_skinner: right, or maybe -- add({after: })
[2:03 PM] jaxsphere: add({at:0})
[2:03 PM] brian_skinner: yup
[2:04 PM] brian_skinner: okay, we'll put that on Tuesday's agenda
[2:04 PM] jaxsphere: i've got a hard stop today at 5
[2:04 PM] brian_skinner: okay
[2:04 PM] brian_skinner: isn't it past 5:00 now>?
[2:04 PM] jaxsphere: yep
[2:04 PM] jaxsphere: :)
[2:05 PM] brian_skinner: okay, see you tuesday :-)
[2:05 PM] jaxsphere: i'll try to do some coding this weekend
[2:05 PM] jaxsphere: sounds good, ttyl!
[2:05 PM] brian_skinner: i'll check in the APIs -- hopefully today
[2:05 PM] jaxsphere: k

Data Access Meeting (2006-09-26)

Data Access Meeting (2006-10-03)

 Agenda

    * dojo.data.Result API
         1. how do we want to handle GUIs that page or scroll through large result sets?
                o explicitly encourage data stores like the YahooStore example?
                o explicitly discourage or forbid that type of iteration?
                o other alternatives?
         2. clarify: run multiple foreachs run serially not in parallel?
                o [adamsz: serial]
                o [skinner: serial only]
                o [mitchell: serial (on the same result set instance)]
         3. what does inProgress() mean?
                o forEach() loop is in progress?
                o data is loading (query has been sent, forEach() not yet called)?
                o either of the above?
                o ~[adamsz: for clarity maybe instead we should have a state member;
                      + i think we need: initial, receiving, completed, error
                      + compare with:
                      + xmlhttprequest.readyState: 0 uninitialized, 1 open, 2 sent, 3 receiving, 4 loaded,
                      + deferred.fired: -1 initial, 0 success, 1 error
                      + ]~
                o [skinner: Having a state property seems like a good idea. Should the state property convey info about (a) progress loading data from the server (initial, receiving, completed), or (b) progress iterating through the forEach loop (initial, looping, completed), or (c) some combination of both? What's the name of the state property, and do we want some sort of getState() accessor method]
                o [mitchell: State member is good, for determining resultset state between store (local or remote) and JS client]
         4. signature for oncompleted callback?
                o [adamsz: oncompleted(iterator)]
                o [skinner: oncompleted(). We might consider passing an iterator to the callback method that the caller sets with setOnLoopCompleted(callback). We should not pass an iterator to the callback method that the caller sets with setOnFindCompleted(callback), since that doesn't work well with the style of access that we might want to do in paging/scrolling implementations like the YahooStore. Offering a synchronous-iterator creates a new implementation requirement that dictates that all results will be in memory at once. Synchronous looping is a nice feature to have, but we shouldn't impose the the all-results-in-memory requirement every time a find() is complete, as would be required if we automatically pass an iterator in to the oncompleted callback -- we should only impose the the all-results-in-memory requirement if the calling code explicitly asks for synchronous looping by calling a asIterator() or asArray() method. If we do have a asIterator() or asArray() method, I have a strong preference for asArray() instead of asIterator(), because looping through an array is something that every JavaScript textbook covers, whereas the iterator syntax is dojo-specific and less obvious.]
                o [mitchell: onCompleted(). We may also want to consider whether it makes sense to use "well known" topics for store or data events. Eg., dojo:data/store/yahoo1/recieving or dojo:data/store/yahoo1/valueChanged]

    * dojo.data.Read API
         1. get() returns undefined if attribute is present but has no values?
                o [mitchell: +1, undefined = not set]
         2. getValues() returns [] if attribute is present but has no values?
                o [adamsz: i think there should be no distinction between attribute existence and an attribute having no values. So getValues() should return undefined in this case. If an attribute was set to null it would return [null]. ]
                o [mitchell: agree with adam]
                o [skinner: I agree that there should be no distinction between attribute existence and an attribute having no values. I think that getValues() should return an empty array in this case, so that the calling code doesn't have to check to see whether or not an array was returned.]
         3. remove hasAttributeValue()?
                o [adamsz: no]
                o [mitchell: Not sure, isn't this the same as get() === undefined?]
         4. change getByIdentity() to findByIdentity(), as per suggestion in mail from Adam Souzis?
                o [mitchell: +1]
         5. findByIdentity() always synchronous?
                o [mitchell: ?]
         6. move getIdentity() and findByIdentity() out of dojo.data.Read (maybe into dojo.data.Identity)?
                o [adamsz: yes]
                o [mitchell: +1]
         7. have findByIdentity() return null if no item is found, rather than throwing an excpetion?
         8. find(query, {async:true}) vs. find(query, {sync:false})
                o just support 'async', or just 'sync', or both?
                o default to {async:false}?
                o [adamsz: just support 'sync' (match bind keyword)]
                o [adamsz: default to {sync:true}]
         9. semantics of isItem() more like isItemAvailable() (and, if so, rename it)?
                o should isItem(x) return true if x is an item Identity instead of an item?
                o should isItem(x) return true if x is an item that has been deleted? Prior to a save? After a save?
                o [adamsz: yes to all these]
                o [skinner: yes for deleted items. no if x is an item Identity, not an item. If isItem(x) returns true when x is an item Identity, that makes it impossible to use isItem() to figure out what a call to store.get() has just returned, and so you can't write GUI display code.]
                o [mitchell: How about isItem(any) for type-check, exists(item) for existence test?]

    * dojo.data.Write API
         1. save()
                o store.save({async: true})?
                o store.save({async: true, onComplete: callback});
                o always return a Deferred, or sometimes a boolean?
                o default to sync, not async?
                o [adamsz: save({sync:true}), always return Deferred (test result.fired for success) ]
         2. include methods add() and remove()
                o store.set(kermit, color, "green");
                o store.add(kermit, color, "blue");
                o store.add(kermit, color, "aqua", {at: 0});
                o store.add(kermit, color, "cyan", {after: "blue"});
                o store.remove(kermit, color, "green");
                o [adamsz: ok, but lets name them add/removeValue. And significance of order and whether duplicate values are allowed should be implementation dependent. also, clarify that removeValue removes all matching values if there are duplicates.]
                o [mitchell: +1, clarify that add with no optional 4th parm adds at end of value list, and at can be used for remove as well.]
         3. should isDirty() with no args returns whether the current transaction is dirty?
                o [adamsz: yes]
                o [skinner: Why not isDirty(store), as per the current documentation, rather than isDirty()? Or are you saying we should support isDirty() and isDirty(store), with different semantics?]
                o [mitchell: 0, could we move this to change-tracking interface?]
         4. should dojo.data.Write include (extend) dojo.data.Read?

    * add new code (where?, minor code style stuff first?)
         1. check in RemoteStore?
         2. check in mockXmlHttpRequest?
         3. move dojo.data.csv.Result out of .csv, for re-use?
                o [adamsz: yes, rename to something like SynchronousResult]
                o [mitchell: yes, assuming it's in sync with latest api]

    * wait to sign off on some APIs (Read/Result/Write) until after we have some lessons learned from trying initial implementations?
          o
                + [mitchell: yes]

Resolutions

dojo.data.Result API

    * A single result object may only have one forEach() loop running at a time. If your code calls result.forEach() while a loop is already running, that should be considered a bug in your code -- the result object may throw an exception. If you have two different result objects, it's okay to call forEach() on both objects at the same time and have the loops running in parallel.

dojo.data.Read API

    * store.get() returns undefined if the item does not have a value for the given attribute. Saying "the item does not have a value for that attribute" is identical to saying "the item does not have that attribute". It is an oxymoron to say "that attribute is present but has no values" or "the item has that attribute but does not have any attribute values"
    * store.getValues() returns [] if an item does not have attribute (when the item has no values for that attribute)
    * We will rename store.hasAttributeValue() to be store.containsValue(), and we will include containsValue() in dojo.data.Read
    * We will rename store.getByIdentity() to be store.findByIdentity()
    * store.findByIdentity() will always return either an item or null (it will never return a Deferred) Implementations of findByIdentity() may sometimes return an item from a local cache and may sometimes fetch an item from a remote server, in which case the call to findByIdentity() will block until the findByIdentity() implementation has the item to return.
    * We will move getIdentity() and findByIdentity() out of dojo.data.Read and into dojo.data.Identity.
    * store.findByIdentity() will return null if no item is found, rather than throwing an excpetion.
    * All implementations of store.find() should accept {sync:true} and {sync:false} as valid optional parameters. We'll standardize on "sync", not "async". If no {sync:} parameter is specified, the default is {sync:true}.

dojo.data.Write API

    * We will rename store.clear() to be store.unsetAttribute()
    * We will rename store.hasAttributeValue() to be store.containsValue()

Transcript

[1:00 PM] ttrenka: hey brian_skinner
[1:00 PM] ttrenka: i'm gonna lurk, if that's ok
[1:00 PM] brian_skinner: hey ttrenka
[1:00 PM] brian_skinner: yup, you bet
[1:01 PM] ttrenka: i'm at a point (finally) where I can start really debugging some major charting stuff, and I don't want to stop.
[1:01 PM] ttrenka: i'm pretty much with adam on most of the agenda, too.
[1:01 PM] ttrenka: so...no worries :)
[1:01 PM] brian_skinner: okay, sounds good
[1:01 PM] ttrenka: I'm working in a VM so if you want me, say my name
[1:01 PM] ttrenka: colloquy should warn me with a sound
[1:01 PM] brian_skinner: do you want to mark the agenda items where you differ from adam?
[1:02 PM] ttrenka: i don't think I differed from him at all
[1:02 PM] ttrenka: to be honest.
[1:02 PM] brian_skinner: okay
[1:04 PM] -->| aszs (n=chatzill@h-74-0-32-234.snfccasy.covad.net) has joined #dojo-meeting
[1:04 PM] aszs: hi
[1:04 PM] =-= jeffrey_afk is now known as JeffreyH
[1:04 PM] brian_skinner: hey aszs
[1:04 PM] brian_skinner: hey JeffreyH
[1:04 PM] JeffreyH: hello
[1:04 PM] -->| jaxsphere (n=chatzill@cpe-024-211-156-070.nc.res.rr.com) has joined #dojo-meeting
[1:04 PM] jaxsphere: hi all
[1:04 PM] brian_skinner: hey jaxsphere
[1:05 PM] brian_skinner: i think we have a quorum
[1:05 PM] jaxsphere: i just updated the issues list with positions on each
[1:05 PM] brian_skinner: ttrenka will be mostly lurking today, working on debugging his chart code
[1:05 PM] jaxsphere: k
[1:06 PM] jaxsphere: http://dojo.jot.com/2006-10-03
[1:06 PM] brian_skinner: i want to add one more agenda item, one sec
[1:07 PM] brian_skinner: okay
[1:07 PM] brian_skinner: sorry for the delay
[1:07 PM] jaxsphere: how about an agenda item to discuss the paging impl patches that were posted on the list
[1:08 PM] brian_skinner: running behind today
[1:08 PM] brian_skinner: jaxsphere: yup, that's what I just added :-)
[1:08 PM] jaxsphere: ;)
[1:08 PM] brian_skinner: if you reload the agenda you should see that as item #1
[1:08 PM] aszs: that #1 now, do you want to start?
[1:08 PM] aszs: there
[1:09 PM] aszs: or tackle the easier things first?
[1:09 PM] jaxsphere: let's weed out all the ones we agree on first :)
[1:09 PM] aszs: ok
[1:09 PM] brian_skinner: okay
[1:09 PM] aszs: #2
[1:09 PM] aszs: we all agree, right
[1:09 PM] brian_skinner: serial
[1:09 PM] brian_skinner: resolved
[1:10 PM] brian_skinner: wait, jaxsphere -- what do you mean by "on the same result set instance"
[1:10 PM] aszs: that different results may run in parallel?
[1:11 PM] aszs: i agree
[1:11 PM] jaxsphere: if multiple result sets executing async... oh, it will be serial
[1:11 PM] aszs: if i call find() twice with async = true
[1:11 PM] jaxsphere: y
[1:11 PM] aszs: they may execute in parallel
[1:11 PM] brian_skinner: multiple result sets potentially in parallel -- single result set always serial
[1:11 PM] aszs: yes
[1:11 PM] brian_skinner: sounds good
[1:12 PM] brian_skinner: next?
[1:12 PM] aszs: want to try #3?
[1:12 PM] jaxsphere: sure
[1:12 PM] brian_skinner: scary
[1:12 PM] jaxsphere: i dont think it should be state of iteration
[1:13 PM] jaxsphere: but state of io progress between client and store make sense
[1:13 PM] aszs: yes
[1:13 PM] brian_skinner: what do we anticipate the GUI code using this info for?
[1:13 PM] aszs: same way deferred.fired is used
[1:13 PM] jaxsphere: status indication
[1:14 PM] aszs: we could call it readState to match xmlhttprequest
[1:15 PM] brian_skinner: so for status indication, if you want to show the user a spinning "loading" icon until all the results show up in the UI, then what you really care about is the forEach() loop having completed, no the client/server io having completed
[1:15 PM] jaxsphere: you may want to show that the server is processing...
[1:15 PM] brian_skinner: and if you want to avoid starting a parallel forEach() loop, what you need to know about is whether the first forEach() loop has finished
[1:16 PM] brian_skinner: jaxsphere: yup, you might want that info too
[1:16 PM] brian_skinner: but i can't imagine a case where that's the *only* info you want
[1:17 PM] aszs: i think it should only be used for async results
[1:17 PM] aszs: sync results should always return in the either completed or error state
[1:17 PM] jaxsphere: so asyncReadState
[1:17 PM] jaxsphere: ?
[1:17 PM] brian_skinner: aszs: +1
[1:18 PM] aszs: i like readyState
[1:18 PM] brian_skinner: wait: +0
[1:18 PM] aszs: its will known
[1:18 PM] aszs: well known
[1:18 PM] jaxsphere: +1
[1:18 PM] jaxsphere: readyState
[1:18 PM] brian_skinner: the sync vs. async return value depends on whether we're only talking about server io vs. talking about looping
[1:18 PM] jaxsphere: only applies to async
[1:20 PM] aszs: yes
[1:20 PM] aszs: loops execute serially
[1:20 PM] aszs: we just agreed to that
[1:21 PM] brian_skinner: a single loop, forEach(foo), may call foo 100 times
[1:21 PM] brian_skinner: within foo, what is the value of the state?
[1:22 PM] brian_skinner: for example, if foo() calls a method, displayResultsInWindow()
[1:22 PM] brian_skinner: and displayResultsInWindow() wants to kick off another forEach() loop
[1:23 PM] brian_skinner: or wants to know when all the results have been looped over
[1:24 PM] brian_skinner: ...
[1:25 PM] brian_skinner: i don't mean to be slow, but i'm still not getting why the UI code cares about whether the client/server io is finished -- seems like the UI code cares much more about whether the loop is finished
[1:25 PM] aszs: let's drop state for now
[1:25 PM] brian_skinner: okay
[1:26 PM] brian_skinner: dojo.data.Read, agenda item #1
[1:26 PM] brian_skinner: ?
[1:26 PM] aszs: +1
[1:26 PM] jaxsphere: y
[1:26 PM] brian_skinner: +1
[1:26 PM] brian_skinner: resolved
[1:27 PM] aszs: item #2 -- i'm okay either way
[1:27 PM] aszs: either [] or undefined
[1:27 PM] brian_skinner: i vote for []
[1:27 PM] brian_skinner: easier for the client code
[1:27 PM] jaxsphere: client code will be simpler for [].  switching to +1
[1:28 PM] brian_skinner: resolved
[1:28 PM] brian_skinner: ?
[1:28 PM] aszs: item #3
[1:28 PM] jaxsphere: agree with brian on []
[1:28 PM] jaxsphere: Read:#3
[1:28 PM] aszs: i don't know if its totally necessary
[1:29 PM] brian_skinner: doesn't seem totally necessary -- doesn't seem like huge bloat either
[1:29 PM] jaxsphere: well, if get() and getValues() return undefined, then this seems unnecessary
[1:29 PM] brian_skinner: i'm fine either wa
[1:29 PM] brian_skinner: way
[1:29 PM] jaxsphere: how to tell the difference between empty list and unset for a multivalued attr?
[1:30 PM] aszs: if an attribute has multiple values hasAttributeWay tests if value is in the list, right?
[1:30 PM] brian_skinner: hasAttribute() or hasAttributeValue()?
[1:31 PM] brian_skinner: sorry, hasAttributeValue()
[1:31 PM] aszs: jaxsphere: your thinking of hasAttribute()
[1:31 PM] brian_skinner: yes, it tests to see if the value is in the list
[1:31 PM] aszs: hasAttribute() == false is the same as getValues() == []
[1:32 PM] brian_skinner: aszs: right
[1:32 PM] brian_skinner: but I think we should keep hasAttribute() anyway -- it makes the code easier to read
[1:32 PM] aszs: yes
[1:32 PM] jaxsphere: is there a way to unset an attribute value?
[1:33 PM] aszs: what do u mean?
[1:33 PM] jaxsphere: set value back to undefined (as if value never specified)_
[1:33 PM] brian_skinner: store.clear(kermit, "color")
[1:33 PM] aszs: or setValues(attr, [])
[1:33 PM] jaxsphere: oops, looking at Read
[1:34 PM] aszs: maybe clear() should be called clearAttribute?
[1:34 PM] aszs: clearer
[1:34 PM] aszs: or removeAttribute()
[1:34 PM] jaxsphere: or unset
[1:34 PM] aszs: y
[1:34 PM] aszs: unsetAttribute()
[1:34 PM] brian_skinner: i'm fine with any of those
[1:34 PM] jaxsphere: unsetAttribute() +1
[1:34 PM] aszs: +1
[1:34 PM] brian_skinner: resolved.
[1:35 PM] aszs: maybe rename hasAttributeValue() too?
[1:35 PM] brian_skinner: okay, to what?
[1:35 PM] jaxsphere: isValueSet()
[1:35 PM] aszs: hmm
[1:36 PM] aszs: something to emphasis "one of"
[1:36 PM] aszs: valueInAttribute?
[1:36 PM] aszs: containsValue()
[1:36 PM] jaxsphere: containsValue()
[1:36 PM] jaxsphere: :)
[1:37 PM] aszs: +1
[1:37 PM] brian_skinner: store.containsValue(kermit, "color", "green)
[1:37 PM] brian_skinner: okay
[1:37 PM] brian_skinner: resolved.
[1:37 PM] jaxsphere: y
[1:37 PM] aszs: move identity functions to another interface?
[1:37 PM] aszs: +1
[1:38 PM] jaxsphere: y
[1:38 PM] jaxsphere: +1
[1:38 PM] brian_skinner: so, that implies that we are keeping store.containsValue() in the API, yes?
[1:38 PM] brian_skinner: :-)
[1:38 PM] aszs: yes
[1:38 PM] brian_skinner: item #3 resolved
[1:39 PM] jaxsphere: how about #6, naming of identity interface?
[1:39 PM] jaxsphere: dojo.data.Identity+1
[1:39 PM] aszs: +1
[1:39 PM] brian_skinner: okay
[1:39 PM] aszs: should we skip the other identity questions now that there not in these Interfaces?
[1:40 PM] brian_skinner: so we just resolved #4 and #6?
[1:40 PM] brian_skinner: sorry, the scribe is having trouble keeping up :-)
[1:40 PM] aszs: #6 if you agree
[1:40 PM] aszs: +1 on #4
[1:40 PM] jaxsphere: +1 on #4
[1:40 PM] brian_skinner: yup, i'm fine with dojo.data.Identity
[1:41 PM] brian_skinner: and i'm fine wtih findByIdentity()
[1:41 PM] jaxsphere: can someone explain 5?
[1:41 PM] aszs: if findByIdentity might invoke a remote query
[1:41 PM] brian_skinner: findByIdentity() may need to make a call to the server to load the item
[1:41 PM] jaxsphere: immediate return
[1:41 PM] aszs: then should it be optionally async?
[1:42 PM] aszs: ok
[1:42 PM] jaxsphere: oh, if you have the identity of an item (from some prev iteration stored away), and you want to get back to that item...
[1:42 PM] brian_skinner: by "immediate return", do you mean return a Deferred?
[1:42 PM] jaxsphere: but item no longer in memort
[1:42 PM] brian_skinner: jaxsphere: yup
[1:42 PM] jaxsphere: Deferred
[1:43 PM] aszs: hmm,
[1:43 PM] aszs: not sure about that
[1:43 PM] brian_skinner: always return a Deferred?  even though 99% of the time the item will already be in memory?
[1:43 PM] aszs: maybe if you care about async just use find()
[1:43 PM] jaxsphere: ok with that
[1:43 PM] aszs: with the equivalant query
[1:43 PM] brian_skinner: aszs: that sounds good to me too
[1:44 PM] jaxsphere: keep key vals, rather than ident
[1:44 PM] brian_skinner: so findByIdentity() always returns an item
[1:44 PM] jaxsphere: and reexecute query
[1:44 PM] aszs: or null
[1:44 PM] brian_skinner: or null
[1:44 PM] jaxsphere: undefined...for item not in memory?
[1:44 PM] brian_skinner: and findByIdentity() may block, waiting for the server?
[1:44 PM] aszs: brian: yes
[1:45 PM] aszs: up to the implementation
[1:45 PM] brian_skinner: i'd vote for null rather than undefined, but no strong preference
[1:45 PM] brian_skinner: null seems easier to check for
[1:46 PM] jaxsphere: null
[1:46 PM] jaxsphere: ok
[1:46 PM] aszs: yes, lets leave undefined undefined
[1:46 PM] aszs: ;)
[1:46 PM] jaxsphere: ;)
[1:46 PM] brian_skinner: okay, resolved
[1:46 PM] aszs: looks we resolved 4 thru 7
[1:47 PM] brian_skinner: didn't we resolve 1 to 3 also?
[1:47 PM] aszs: yes
[1:47 PM] brian_skinner: okay
[1:47 PM] aszs: not 1
[1:47 PM] aszs: we skipped that
[1:48 PM] aszs: oops sorry
[1:48 PM] jaxsphere: find(query,{sync:false})
[1:48 PM] aszs: yes 1-3 in Read
[1:48 PM] aszs: +1
[1:48 PM] jaxsphere: +1
[1:48 PM] brian_skinner: right, resolved 1-7 in Read
[1:48 PM] aszs: the default for sync should be true?
[1:48 PM] brian_skinner: yes
[1:48 PM] jaxsphere: y
[1:49 PM] brian_skinner: okay, resolved
[1:49 PM] aszs: #9 -- i mistyped
[1:49 PM] brian_skinner: what did you mean to type?
[1:49 PM] aszs: i meant to say that i think isItem(x) should return false if delete
[1:50 PM] aszs: deleted
[1:50 PM] brian_skinner: okay, i'm fine with that too
[1:50 PM] brian_skinner: false if deleted but not saved?
[1:50 PM] jaxsphere: so is isItem both type check and existence check?
[1:51 PM] aszs: i think so but maybe implementation dependent
[1:51 PM] brian_skinner: what do you mean by an existence check?
[1:51 PM] jaxsphere: meaning does the item passed in exist
[1:51 PM] aszs: "there is no guarantee that isItem() will return true if the item has been deleted"
[1:51 PM] jaxsphere: (if it is an Item)
[1:51 PM] aszs: jaxsphere: yes both
[1:51 PM] brian_skinner: how would you ever have a handle to an item that doesn't exist?
[1:52 PM] jaxsphere: how about split to 2 ops? exists(item) and isItem(any)
[1:52 PM] aszs: in RemoteStore there's no way i can tell since my item reference is just a string
[1:52 PM] jaxsphere: exists(item | identity)
[1:53 PM] aszs: hmm, actually that not true
[1:53 PM] jaxsphere: you mean for the type check?
[1:53 PM] brian_skinner: so, exists(identity) may require a trip to the server, whereas isItem(item) is always knowable on the client?
[1:53 PM] aszs: sorry i mean my statement that in Remote store item is just a string is not true
[1:54 PM] jaxsphere: i think the exists(...) should move to Identity interface
[1:54 PM] aszs: the reason i suggested renaming it to isItemAvailable()
[1:55 PM] aszs: is to make it clear that this just test whether the object is a "usable" reference
[1:55 PM] brian_skinner: i think findByIdentity() may be enough -- we might not even need exists() -- but if we do have exists(), i agree that it should be in dojo.data.Identity
[1:55 PM] aszs: what exactly means is up to the implementation
[1:56 PM] jaxsphere: so isItem(something) should just be a type check
[1:56 PM] jaxsphere: no remote
[1:56 PM] aszs: yes
[1:56 PM] aszs: but more than a type check
[1:56 PM] brian_skinner: aszs: i understand that RemoteStore uses strings for both items and identities, but in general that may not be the case, and i think in general the APIs should try to make a firm distinction between the notion of an item and the notion of an identity
[1:56 PM] brian_skinner: all items, by definition, are available
[1:57 PM] brian_skinner: so isItem() is then just a type check
[1:57 PM] jaxsphere: isItem(getIdentity(item)) always === false
[1:57 PM] aszs: no more i think
[1:58 PM] aszs: consider:
[1:58 PM] aszs: store.get(item, 'attribute')
[1:58 PM] aszs: what if item is an Item type
[1:58 PM] aszs: but the item isn't part of the store
[1:58 PM] aszs: on the client
[1:58 PM] aszs: than get() throws an exception
[1:59 PM] aszs: according to the spec
[1:59 PM] aszs: to avoid that,
[1:59 PM] aszs: isItem() needs to test for availability in the store
[1:59 PM] brian_skinner: i see
[1:59 PM] brian_skinner: yes
[1:59 PM] brian_skinner: it's not just a type check
[1:59 PM] brian_skinner: it's a type check within the context of a store
[1:59 PM] brian_skinner: here's the case where I think isItem() is useful
[2:00 PM] brian_skinner: if you have a book
[2:00 PM] aszs: yes, that's why i think isItemAvailable() is more clear
[2:00 PM] brian_skinner: you have a book, theHobbit
[2:00 PM] brian_skinner: theHobbit is an item
[2:00 PM] brian_skinner: and you want to get the author
[2:00 PM] brian_skinner: so you do
[2:00 PM] brian_skinner: var author = store.get(theHobbit, "author")
[2:01 PM] brian_skinner: and you want to display the author's name
[2:01 PM] brian_skinner: dojo.debug(author)
[2:01 PM] brian_skinner: but you don't know whether author is a string, or a number, or an item
[2:01 PM] brian_skinner: so you need to do stuff like
[2:01 PM] jaxsphere: do you get a value, or an Item reference?
[2:01 PM] brian_skinner: dojo.lang.isString(author)
[2:01 PM] brian_skinner: store.isItem(author)
[2:01 PM] aszs: yes that's true
[2:01 PM] jaxsphere: isReference(author)
[2:02 PM] brian_skinner: and in that context, isItem() seems to make more sense than isItemAvailable()
[2:02 PM] aszs: if author is a reference, does store.get(author, 'attr') throw an exception?
[2:03 PM] brian_skinner: maybe I shouldn't have assumed this, but I always assumed that store.get(theHobbit, "author") would return an actual item, never an Identity or a reference or something
[2:03 PM] jaxsphere: we never specified how to deal with refs
[2:03 PM] aszs: you mean an item with all its attributes available?
[2:03 PM] brian_skinner: aszs: yes
[2:03 PM] aszs: we can't do that
[2:04 PM] aszs: that could suck in the whole store
[2:04 PM] aszs: on the server
[2:04 PM] brian_skinner: it could work like findByIdentity()
[2:05 PM] brian_skinner: it may trigger a small query that gets sent to the server, but it blocks until it gets a reply
[2:05 PM] aszs: you mean get() would invoke a query if the item is reference
[2:05 PM] aszs: hmm,
[2:05 PM] brian_skinner: get() *might* invoke a query if the item is a reference
[2:05 PM] aszs: i don't like that
[2:05 PM] jaxsphere: this gets into more complex get behavior than what we've spec'd so far.  Get will end up requiring identity interface
[2:06 PM] aszs: i rather it throw an exception
[2:06 PM] aszs: we could have both isItem and isItemAvailable()
[2:07 PM] aszs: btw, remotestore does have a notion of references
[2:07 PM] brian_skinner: okay, so do we want to say that store.get(theHobbit, "author") might return either an item or an Identity, depending on whether the tolkien item happens to have been loaded from the server already?
[2:07 PM] aszs: no
[2:08 PM] brian_skinner: okay, so what should store.get() do?
[2:08 PM] aszs: there should be two separate notions of items
[2:08 PM] aszs: should *not* be  i mean
[2:08 PM] brian_skinner: store.get() always returns an Identity?
[2:09 PM] aszs: what an Identity?
[2:09 PM] aszs: i don't think that should be in the Read api
[2:09 PM] aszs: get returns an item
[2:09 PM] brian_skinner: an Identity is the thing that you pass to findByIdentity()
[2:09 PM] brian_skinner: okay, so store.get() always returns an item?
[2:09 PM] aszs: but that's not in the Read API
[2:10 PM] aszs: yes, you can test whether the item is available or not
[2:11 PM] brian_skinner: okay, so then you're saying that you should never do store.get(kermit, "color") until you've first checked store.isItemAvailable(kermit)?
[2:11 PM] aszs: there a difference between an object reference and Identity
[2:11 PM] jaxsphere: apologize, but i have to go now
[2:11 PM] aszs: identity is a key
[2:11 PM] aszs: not all stores have keys
[2:11 PM] brian_skinner: jaxsphere: okay, thanks for coming!
[2:11 PM] aszs: no worries
[2:11 PM] aszs: yes, thanks
[2:12 PM] jaxsphere: good meeting today.  that was a good thing posting positions before hand
[2:12 PM] brian_skinner: yup, that was a good iea
[2:12 PM] brian_skinner: idea
[2:12 PM] jaxsphere: ttyl
[2:12 PM] brian_skinner: see ya
[2:12 PM] aszs: maybe we should table the identity/reference things for now
[2:12 PM] aszs: bye
[2:12 PM] <--| jaxsphere has left #dojo-meeting
[2:13 PM] brian_skinner: aszs: yes, maybe so, with jaxsphere and ttrenka both not here
[2:13 PM] aszs: yes, and a hard issue
[2:13 PM] brian_skinner: ...going away, back in 1 minute
[2:13 PM] aszs: ok
[2:15 PM] brian_skinner: sorry
[2:15 PM] brian_skinner: back again
[2:15 PM] aszs: hi
[2:16 PM] aszs: there's a whole bunch of issues with identity that i've been afraid to broach
[2:16 PM] aszs: hopefully we can avoid them in the
[2:16 PM] aszs: basic apis
[2:16 PM] aszs: for example, if the primary key of a table is say your SS #
[2:16 PM] brian_skinner: yup -- i've been nervous all along about the question of what exactly store.get(theHobbit, 'author') returns
[2:17 PM] aszs: and you call store.set(item, 'SS', another #)
[2:17 PM] aszs: did you just change the Identity of the item?
[2:17 PM] aszs: what if another item reference had that SS#
[2:17 PM] aszs: does it "switch over" to that record?
[2:17 PM] aszs: etc.
[2:18 PM] brian_skinner: if SS# is being used as a primary key, i think most datastore implementations would consider it an error to try to do store.set(item, 'SS', another #)
[2:18 PM] brian_skinner: seems like th store should throw an exception
[2:18 PM] brian_skinner: the store
[2:18 PM] aszs: yes
[2:19 PM] brian_skinner: the store should also throw an exception if you try to create a new item that has the same SSN as an existing item
[2:19 PM] aszs: that might only happen until save() though
[2:19 PM] brian_skinner: on save()?
[2:19 PM] aszs: the client doesn't know
[2:19 PM] brian_skinner: right
[2:19 PM] brian_skinner: bummer
[2:20 PM] aszs: anyways,
[2:20 PM] aszs: should we adjourn, maybe talk about open record a little?
[2:20 PM] brian_skinner: yup, that sounds good

Data Access Meeting (2006-10-10)

 Agenda

    * dojo.data.Read API
         1. how do we do "reference faulting" (or whatever the right term is) -- the situation where you have a giant data graph on the server, and you only have 10% loaded into data objects on the client, and when you ask a data object for some related object, it may just hand you back some other object that was already in memory, or it may initiate a request to the server to get the needed data?
         2. what does store.get(theHobbit, 'author') return?
                o an Identity
                o a reference (what's a reference?)
                o an item that is guarenteed to be available
                o an item that may or may not be available
                o a Deferred?
                o any of the above?
         3. semantics of isItem() more like isItemAvailable() (and, if so, rename it)?
                o should isItem(x) return true if x is an item Identity instead of an item?
                o should isItem(x) return true if x is an item that has been deleted? Prior to a save? After a save?
                o [adamsz: yes to all these]
                o [skinner: yes for deleted items. no if x is an item Identity, not an item. If isItem(x) returns true when x is an item Identity, that makes it impossible to use isItem() to figure out what a call to store.get() has just returned, and so you can't write GUI display code.]
                o [mitchell: How about isItem(any) for type-check, exists(item) for existence test?]

    * dojo.data.Result API
         1. how do we want to handle GUIs that page or scroll through large result sets?
                o explicitly encourage data stores like the YahooStore example?
                o explicitly discourage or forbid that type of iteration?
                o other alternatives?
         2. what does inProgress() mean?
                o forEach() loop is in progress?
                o data is loading (query has been sent, forEach() not yet called)?
                o either of the above?
                o ~[adamsz: for clarity maybe instead we should have a state member;
                      + i think we need: initial, receiving, completed, error
                      + compare with:
                      + xmlhttprequest.readyState: 0 uninitialized, 1 open, 2 sent, 3 receiving, 4 loaded,
                      + deferred.fired: -1 initial, 0 success, 1 error
                      + ]~
                o [skinner: Having a state property seems like a good idea. Should the state property convey info about (a) progress loading data from the server (initial, receiving, completed), or (b) progress iterating through the forEach loop (initial, looping, completed), or (c) some combination of both? What's the name of the state property, and do we want some sort of getState() accessor method]
                o [mitchell: State member is good, for determining resultset state between store (local or remote) and JS client]
         3. signature for oncompleted callback?
                o [adamsz: oncompleted(iterator)]
                o [skinner: oncompleted(). We might consider passing an iterator to the callback method that the caller sets with setOnLoopCompleted(callback). We should not pass an iterator to the callback method that the caller sets with setOnFindCompleted(callback), since that doesn't work well with the style of access that we might want to do in paging/scrolling implementations like the YahooStore. Offering a synchronous-iterator creates a new implementation requirement that dictates that all results will be in memory at once. Synchronous looping is a nice feature to have, but we shouldn't impose the the all-results-in-memory requirement every time a find() is complete, as would be required if we automatically pass an iterator in to the oncompleted callback -- we should only impose the the all-results-in-memory requirement if the calling code explicitly asks for synchronous looping by calling a asIterator() or asArray() method. If we do have a asIterator() or asArray() method, I have a strong preference for asArray() instead of asIterator(), because looping through an array is something that every JavaScript textbook covers, whereas the iterator syntax is dojo-specific and less obvious.]
                o [mitchell: onCompleted(). We may also want to consider whether it makes sense to use "well known" topics for store or data events. Eg., dojo:data/store/yahoo1/recieving or dojo:data/store/yahoo1/valueChanged]

    * dojo.data.Write API
         1. save()
                o store.save({sync: false})?
                o store.save({sync: false, onComplete: callback});
                o always return a Deferred, or sometimes a boolean?
                o default to sync, not async?
                o [adamsz: save({sync:true}), always return Deferred (test result.fired for success) ]
         2. include methods add() and remove()
                o store.set(kermit, color, "green");
                o store.add(kermit, color, "blue");
                o store.add(kermit, color, "aqua", {at: 0});
                o store.add(kermit, color, "cyan", {after: "blue"});
                o store.remove(kermit, color, "green");
                o [adamsz: ok, but lets name them add/removeValue. And significance of order and whether duplicate values are allowed should be implementation dependent. also, clarify that removeValue removes all matching values if there are duplicates.]
                o [mitchell: +1, clarify that add with no optional 4th parm adds at end of value list, and at can be used for remove as well.]
         3. should isDirty() with no args returns whether the current transaction is dirty?
                o [adamsz: yes]
                o [skinner: Why not isDirty(store), as per the current documentation, rather than isDirty()? Or are you saying we should support isDirty() and isDirty(store), with different semantics?]
                o [mitchell: 0, could we move this to change-tracking interface?]
         4. should dojo.data.Write include (extend) dojo.data.Read?

    * add new code (where?, minor code style stuff first?)
         1. check in RemoteStore?
         2. check in mockXmlHttpRequest?
         3. move dojo.data.csv.Result out of .csv, for re-use?
                o [adamsz: yes, rename to something like SynchronousResult]
                o [mitchell: yes, assuming it's in sync with latest api]

    * wait to sign off on some APIs (Read/Result/Write) until after we have some lessons learned from trying initial implementations?
          o [mitchell: yes]

Resolutions

    * none this week

Transcript

[1:01 PM] aszs: hi brian
[1:01 PM] brian_skinner: hi aszs
[1:01 PM] aszs: i have a (relatively) radical idea
[1:01 PM] brian_skinner: hi dmachi, tk, rcoup
[1:01 PM] brian_skinner: aszs: shoot
[1:02 PM] aszs: eliminate dojo.Result
[1:02 PM] brian_skinner: that's radical!
[1:02 PM] aszs: it fixes problems and makes things simpler
[1:02 PM] aszs: instead add
[1:02 PM] aszs: oncompleted, onnext, array, onerror keywords
[1:02 PM] aszs: to find()
[1:02 PM] aszs: var results=[];
[1:02 PM] aszs: var success = find("query", { array : results });
[1:03 PM] aszs: for simply synchronous query
[1:03 PM] brian_skinner: {array: results} is optional?
[1:03 PM] aszs: yes
[1:03 PM] aszs: instead use onnext
[1:03 PM] aszs: if u don't want all the results saved
[1:03 PM] brian_skinner: give me a second to look at the current apis and think about that
[1:03 PM] aszs: { onnext : myhandlerfunc }
[1:04 PM] aszs: i thought of this because of another problem with Result
[1:04 PM] aszs: what happens if the query is synchronous and there's an error
[1:04 PM] brian_skinner: yup, that's a problem
[1:05 PM] aszs: you don't set the onerror handler till after u get a result
[1:07 PM] brian_skinner: for the synchronous error case, couldn't you just call find() and get a result object back, where the result object knows that there was an error, and when you do result.setOnError(foo) then foo will get called?
[1:07 PM] aszs: yes
[1:07 PM] dmachi: hi everybody
[1:08 PM] aszs: but then you need to have a error handler just to find if there was one
[1:08 PM] brian_skinner: hi dmachi
[1:08 PM] brian_skinner: aszs: yup, it's a little clumsy
[1:08 PM] aszs: its not a big deal
[1:08 PM] aszs: its just how i came to this new idea
[1:08 PM] dmachi: aszs: you could do something like deferred does in that if you add a callback after the results have alreayd been recieved it just callsback with those immediately (same in case of errback)
[1:08 PM] aszs: dmachi: yes
[1:08 PM] dmachi: (maybe?)
[1:09 PM] brian_skinner: dmachi, aszs:  i got mail from chris -- he says he's not going to be able to make it today
[1:09 PM] dmachi: i wasn't really here either, this is just and idle channel and i got a little pop from my name being mentioned :)
[1:09 PM] brian_skinner: :)
[1:10 PM] brian_skinner: aszs: how would getLength() work?
[1:10 PM] aszs: yes
[1:10 PM] aszs: maybe result could be the length or -1 on error
[1:11 PM] brian_skinner: you mean...
[1:11 PM] aszs: if its async the length could be an arg for oncompleted
[1:11 PM] brian_skinner: var length = find(query, ...)
[1:11 PM] brian_skinner: right
[1:11 PM] aszs: yes
[1:11 PM] aszs: and if array is passed
[1:11 PM] aszs: just look at the array length
[1:11 PM] brian_skinner: right
[1:12 PM] aszs: then there's cancel
[1:12 PM] aszs: it could work like io.bind
[1:13 PM] aszs: pass abort kword
[1:13 PM] aszs: that gets set to an abort function
[1:13 PM] aszs: so abort and sync would be the same as io bind
[1:14 PM] aszs: so would error and completed
[1:14 PM] brian_skinner: i've never actually used dojo.io.bind -- i'll have to go look at it to understand about abort, error, completed
[1:15 PM] brian_skinner: so, just thinking out loud,
[1:15 PM] aszs: there just callback funcs
[1:15 PM] brian_skinner: for the sync case...
[1:15 PM] brian_skinner: var store = new dojo.data.csv.CsvStore({url:"movies.csv");
[1:15 PM] brian_skinner: var results = new Array();
[1:15 PM] brian_skinner: store.find(null, {array:results});
[1:15 PM] brian_skinner: it would be nicer to do this...
[1:15 PM] brian_skinner: var store = new dojo.data.csv.CsvStore({url:"movies.csv");
[1:15 PM] aszs: yes
[1:15 PM] brian_skinner: var results = store.find();
[1:16 PM] aszs: yes that'd be nicer but we can't do that
[1:16 PM] brian_skinner: if no oncompleted, onnext, array, onerror keywords are passed, then assume we just want a simple array
[1:16 PM] brian_skinner: and return an array
[1:16 PM] aszs: good idea
[1:16 PM] aszs: if array is null assum an error
[1:16 PM] brian_skinner: right
[1:17 PM] brian_skinner: or maybe it throws an exception if there's an error, i don't know
[1:17 PM] aszs: well this makes things *much*  simpler
[1:17 PM] brian_skinner: so, what does some simple async code look like?
[1:17 PM] brian_skinner: var store = new dojo.data.csv.CsvStore({url:"movies.csv");
[1:18 PM] aszs: find("query", { onnext=myforeachfunc } )
[1:18 PM] brian_skinner: store.find(someQuery, {oncompleted: foo, onnext: bar, onerror: iggy});
[1:18 PM] aszs: well in the simple case use just need onnext
[1:19 PM] brian_skinner: yes, right
[1:19 PM] aszs: and sync=false
[1:19 PM] brian_skinner: right
[1:19 PM] aszs: or array=result and oncompleted=foo
[1:19 PM] brian_skinner: store.find(someQuery, {sync: false, oncompleted: foo, onnext: bar, onerror: iggy});
[1:20 PM] aszs: or store.find(someQuery, {sync: false, oncompleted: foo, array: result);
[1:20 PM] brian_skinner: right
[1:21 PM] brian_skinner: just off the top of your head, is it easy for you to show me an example of what abort/cancel would look like?
[1:21 PM] aszs: let me look at my RemoteStore
[1:22 PM] aszs: i use bind's abort
[1:22 PM] aszs: to implement cancel
[1:22 PM] aszs: actually i'm wrong about io.bind
[1:24 PM] aszs: they implement it this way:
[1:24 PM] aszs: kwargs  = {}
[1:24 PM] aszs: io.bind( kwargs); //funct sets kwargs.abort here
[1:24 PM] aszs: var abortfunc = kwargs.abort
[1:24 PM] aszs: but the use sees this:
[1:24 PM] aszs:                     var request = dojo.io.bind( { ... });
[1:24 PM] aszs:                     result._abortFunc = request.abort;
[1:24 PM] aszs: the user i mean
[1:26 PM] aszs: i guess we could return minimal request object if its async
[1:26 PM] aszs: or do it the former way
[1:26 PM] brian_skinner: i'm confused -- so dojo.io.bind returns a request object, and that request object has an "abort" property which points to a function?
[1:26 PM] aszs: yes
[1:27 PM] brian_skinner: and you can call that function if you want to cancel the request?
[1:27 PM] aszs: yes
[1:27 PM] brian_skinner: okay
[1:27 PM] aszs: result.abort()
[1:28 PM] brian_skinner: or we could just return a *token* representing the request...
[1:28 PM] brian_skinner: var token = store.find(someQuery, {sync: false, oncompleted: foo, onnext: bar, onerror: iggy});
[1:28 PM] brian_skinner: and then...
[1:28 PM] brian_skinner: store.abort(token);
[1:28 PM] aszs: yes
[1:29 PM] aszs: but why?
[1:29 PM] brian_skinner: which isn't as object-oriented, but it means we don't even have to start any kind of conversation about what a request object is
[1:29 PM] brian_skinner: and we don't have to have a whole new file for dojo.data.Request API
[1:30 PM] aszs:  io.bind doesn't define what the result object is
[1:30 PM] aszs: just has one
[1:30 PM] brian_skinner: and it defines a little bit about how it behaves
[1:30 PM] brian_skinner: it conforms to some API
[1:30 PM] aszs: but there no dojo.io.Result
[1:30 PM] aszs: just uses duck typing
[1:30 PM] brian_skinner: right -- the API only appears in documentation
[1:31 PM] brian_skinner: http://manual.dojotoolkit.org/io.html
[1:32 PM] brian_skinner: ...
[1:32 PM] aszs: the doc says there *is* dojo.io.request
[1:32 PM] aszs: i didn't see that
[1:32 PM] brian_skinner: http://dojotoolkit.org/api/#dojo.io.Request
[1:33 PM] aszs: its not in the source code
[1:33 PM] aszs: not a real object
[1:33 PM] aszs: just a dictionary
[1:33 PM] brian_skinner: it must be in the source code somewhere, or it wouldn't appear in the automatically generated API docs
[1:33 PM] aszs: hmmm
[1:34 PM] brian_skinner: well, we can look into that more later
[1:34 PM] aszs: its in common.js
[1:34 PM] brian_skinner: in any case, we can do something like that for abort/cancel
[1:34 PM] aszs: doesn't look like BrowerIO uses that...
[1:34 PM] aszs: yes, in any case...
[1:35 PM] aszs: well, what do u think?
[1:35 PM] brian_skinner: okay, getting rid of the dojo.data.Result certainly has some appeal
[1:36 PM] brian_skinner: and I like the simple API for getting an array
[1:36 PM] brian_skinner: make simple things simple
[1:36 PM] brian_skinner: but I don't have a strong sense one way or the other about which API is better -- with dojo.data.Result or without
[1:37 PM] brian_skinner: it'd be great to get feedback from a few more people about the idea
[1:37 PM] brian_skinner: see what Chris and Tom think
[1:37 PM] aszs: ok
[1:37 PM] brian_skinner: i'm happy to follow whatever the consensus opinion is
[1:37 PM] brian_skinner: we could add it to our next agenda
[1:38 PM] brian_skinner: or you could write up some mail and send it to dojo-dev, if you feel like it
[1:38 PM] aszs: i could send an email or add a wiki page
[1:38 PM] aszs: which do u think is better?
[1:38 PM] brian_skinner: yup, or a wiki page
[1:38 PM] brian_skinner: my sense is that people read mail more than they read the wiki
[1:38 PM] aszs: ok
[1:39 PM] aszs: so what would be the arguments for keeping Result?
[1:39 PM] brian_skinner: inertia ;-)
[1:39 PM] brian_skinner: i don't know -- i don't think I have any good arguments
[1:40 PM] aszs: ok
[1:40 PM] aszs: to clarify: so if find is sync return an array unless onnext is specified?
[1:41 PM] aszs: or return an array always if sync?
[1:41 PM] brian_skinner: although, maybe we actually are talking about keeping it, in some minimal sense -- you do still get back a result object, and you can call result.abort(), and maybe you can get state info, like result.inProgress()
[1:41 PM] brian_skinner: find should default to sync
[1:41 PM] brian_skinner: so that makes the rule be something like this
[1:41 PM] aszs: yes
[1:42 PM] brian_skinner: return an array unless onnext and/or sync:false have been specified
[1:42 PM] brian_skinner: i'm not sure whether it's "and" or "or"
[1:43 PM] brian_skinner: i guess "or"
[1:43 PM] brian_skinner: although it would be weird to specify sync:false and not provide an onnext:foo
[1:43 PM] aszs: if sync false
[1:43 PM] aszs: we can't return an array
[1:43 PM] brian_skinner: right
[1:44 PM] aszs: unless we return an empty array
[1:44 PM] brian_skinner: and there probably isn't much value in doing that
[1:44 PM] aszs: so i guess its "or"
[1:44 PM] brian_skinner: okay
[1:45 PM] aszs: so we don't really need an array kwarg
[1:46 PM] brian_skinner: maybe not
[1:46 PM] brian_skinner: it'd be great to not need that
[1:46 PM] aszs: onnext : function(item) { result.push(item) }
[1:46 PM] aszs: if we don't want the user to have to write that
[1:46 PM] aszs: we could say if onnext's value is not an function
[1:47 PM] aszs: will call object.push(item) on it
[1:47 PM] aszs: instead of invoking it
[1:47 PM] aszs: then you could just go onnext : myArray
[1:47 PM] aszs: sync : false
[1:47 PM] aszs: xhr does something like
[1:47 PM] aszs: i think
[1:47 PM] brian_skinner: hmmm...  but that's kind of weird for large result sets
[1:48 PM] aszs: yes,
[1:48 PM] aszs: so user shouldn't do that
[1:48 PM] brian_skinner: if you know you're looking at 10,000 things -- conceptially you really don't want to "push" them onto an object
[1:48 PM] aszs: ok
[1:49 PM] aszs: we could just say onnext can be either a function or an array
[1:49 PM] brian_skinner: yes, that has some appeal
[1:49 PM] brian_skinner: but
[1:49 PM] aszs: is that better?
[1:49 PM] brian_skinner: seems like if you really want an array, then you're not going to want to see the array until after the whole loop has finished anyway
[1:49 PM] aszs: yes?
[1:50 PM] brian_skinner: so what you really want is something like this...
[1:50 PM] aszs: find( { sync: false, onnext : myarray, oncompleted: myfunc })
[1:50 PM] brian_skinner: maybe
[1:50 PM] brian_skinner: but that code would really look like this...
[1:51 PM] brian_skinner: var array = new Array();
[1:51 PM] brian_skinner: store.find( { sync: false, onnext : myarray, oncompleted: myfunc });
[1:51 PM] brian_skinner: ...
[1:51 PM] aszs: yes
[1:51 PM] brian_skinner: why should I have to create the array object?
[1:51 PM] brian_skinner: would it be better to do this...
[1:52 PM] brian_skinner: store.find( { sync:false, oncompleted: myfunc, array: true});
[1:52 PM] brian_skinner: or ...
[1:52 PM] aszs: yes
[1:52 PM] aszs: yr right
[1:53 PM] brian_skinner: store.find( { sync:false, onarrayloaded:myfunc});
[1:53 PM] aszs: and array is always true when sync = true
[1:53 PM] brian_skinner: yes
[1:53 PM] aszs: don't think we need a separate onarrayloaded
[1:53 PM] aszs: oncompleted(length, array)
[1:53 PM] aszs: array might be undefined if array : false
[1:54 PM] brian_skinner: yes
[1:54 PM] aszs: all this seems more elegant
[1:54 PM] aszs: and easier to implement stores
[1:55 PM] aszs: especially simple ones
[1:55 PM] brian_skinner: i was just thinking {onarrayloaded:myfunc} might be less confusing than {oncompleted: myfunc, array: true}, where there's some "invisible" interaction between the two parameters, myfunc and array:true, such that the params sent to myfunc are actually different depending on what array: was set to
[1:56 PM] brian_skinner: but, this is a pretty minor detail anyway
[1:56 PM] brian_skinner: ...
[1:56 PM] brian_skinner: so, should we talk about what "reference faulting", and what type of item/identity/reference you might get when you call store.get(theHobbit, "author")?
[1:56 PM] aszs: ok
[1:57 PM] brian_skinner: give me one minute...
[1:57 PM] aszs: ok... i was thinking the maybe the API doesn't distinguish
[1:57 PM] aszs: if item isn't loaded, then the store.get(item, 'foo')
[1:57 PM] aszs: would just remotely load the item if necessary
[1:58 PM] aszs: up to the implementation
[1:58 PM] brian_skinner: okay, i'm back
[1:58 PM] aszs: i mean doesn' t distinguish between items and references
[1:59 PM] brian_skinner: okay, so then store.get(item, 'foo') always returns an item (or a literal -- string, number, date, etc.)
[1:59 PM] aszs: yes
[1:59 PM] aszs: isItem(item) == true
[2:00 PM] aszs: if 'foo' returns an item
[2:00 PM] brian_skinner: and we don't make any distinction between "available items" and "not quite available items"?
[2:00 PM] aszs: hmm, i think so
[2:00 PM] aszs: isItem and isItemAvailable()
[2:00 PM] aszs: need both i think
[2:00 PM] brian_skinner: when would isItemAvailable() be false?
[2:01 PM] aszs: if it isn't loaded or has been deleted
[2:01 PM] brian_skinner: okay, let's ignore the deleted case for a second
[2:02 PM] brian_skinner: so, that API imposes a constraint on the implementations
[2:03 PM] brian_skinner: the implementation has to use the same "item" object to represent the item both before and after the item is loaded
[2:03 PM] aszs: why?
[2:03 PM] brian_skinner: var tolkein = store.get(theHobbit, "author")
[2:04 PM] brian_skinner: if (isItemAvailable(tolkein) { var name = store.get(tolkein, "name") }
[2:04 PM] aszs: isItem(item) { return item instanceof Item || item instanceof Reference; }
[2:04 PM] aszs: oh i see
[2:05 PM] brian_skinner: it's not a problem for any datastore that uses UUIDs or URLs or integers as "item" objects
[2:06 PM] brian_skinner: and also not a problem if you use a JSON-style anonymous object to represent items
[2:06 PM] aszs: well what if there's no isItemAvailable
[2:06 PM] brian_skinner: but i think it might be a problem for datastores that use XML DOM nodes to represent items
[2:06 PM] aszs: is that ok?
[2:07 PM] brian_skinner: if there's no isItemAvailable(), is that the same as saying that any item returned by store.get() is required to be available?
[2:08 PM] brian_skinner: which means store.get() may take a long time to execute, since it may go to the server?
[2:08 PM] aszs: yes or...
[2:08 PM] aszs: user catch exceptions
[2:09 PM] aszs: or change store.get() to return an error somehow
[2:09 PM] brian_skinner: you mean store.get(theHobbit, "author") could return/throw an error if theHobbit isn't an "available" item?
[2:10 PM] aszs: maybe.. ie if( store.get(the, 'authro') == ITEM_NOT_AVAILABLE) ....
[2:10 PM] aszs: or ITEM_DELETED
[2:11 PM] aszs: etc.
[2:11 PM] aszs: maybe some store would fetch automatically
[2:12 PM] aszs: or maybe that could be a flag when creating the store autofetch = true
[2:12 PM] brian_skinner: yup, that would work -- but that makes the GUI code painfully verbose -- you can't use the datastore without constantly doing if() statements to check that you really got a result back
[2:12 PM] brian_skinner: ah, I like autofetch=true
[2:12 PM] brian_skinner: and we could default to autofetch=true
[2:12 PM] brian_skinner: like defaulting to sync=true
[2:13 PM] aszs: so an arg for find? or a global flag for the store?
[2:13 PM] brian_skinner: i was thinking global flag for the store
[2:13 PM] aszs: yes, that seems better
[2:14 PM] brian_skinner: so, if autofetch=false
[2:14 PM] brian_skinner: how does that work
[2:14 PM] brian_skinner: what does the client code look like?
[2:14 PM] aszs: maybe just throws an exception
[2:14 PM] brian_skinner: if( store.get(the, 'authro') == ITEM_NOT_AVAILABLE) {
[2:14 PM] aszs: just like get is currently defined
[2:14 PM] === / Unknown command
[2:14 PM] === /what Unknown command
[2:14 PM] brian_skinner: }
[2:15 PM] aszs: then we don't need to spec it out?
[2:16 PM] brian_skinner: yup, maybe we don't need to spec it out -- I was just curious about what the code would look like in some typical example -- what does the client code do once it finds out that an item is not yet available?
[2:16 PM] aszs: call getByIdentity(item)
[2:16 PM] aszs: ?
[2:17 PM] aszs: or findById() that is
[2:17 PM] brian_skinner: but, getByIdentity() doesn't take an item as a parameter -- it only takes an Identity
[2:17 PM] brian_skinner: right, sorry, findById()
[2:17 PM] brian_skinner: findByIdentity()
[2:17 PM] aszs: well maybe it should be able to take either
[2:17 PM] aszs: don't see any harm in that
[2:17 PM] brian_skinner: so...
[2:18 PM] brian_skinner: var tolkein = store.get(theHobbit, "author")
[2:18 PM] brian_skinner: and then if items are being represented as XML DOM nodes, but tolkein hasn't been loaded?
[2:19 PM] aszs: raise an Error
[2:20 PM] aszs: i think get such continue to raise errors
[2:20 PM] brian_skinner: raise an Error if theHobbit hasn't been loaded, or raise an Error if tolkein hasn't been loaded?
[2:20 PM] aszs: theHobbit
[2:20 PM] brian_skinner: okay, i'm fine with that -- but what if tolkein hasn't been loaded?
[2:20 PM] aszs: what does that mean?
[2:21 PM] aszs: oh
[2:21 PM] aszs: you want to try to load before call get on it?
[2:22 PM] aszs: if (store.isItem(tolkien))  { tolkien = store.findById(tolkien); } //ensure its loaded
[2:22 PM] brian_skinner: should store.get(theHobbit, "author") block on a trip to the server to get tolkien?  or do we return (immediately) the Identity of tolkien, or a reference to tolkien?
[2:22 PM] aszs: no its should block
[2:22 PM] aszs: just like we agreeed last week that findbyid blocks
[2:23 PM] brian_skinner: right, so if we don't block, then what does store.get(theHobbit, "author") return
[2:23 PM] brian_skinner: either an Item or an Identity?
[2:23 PM] brian_skinner: so that you can do...
[2:23 PM] brian_skinner: if (store.isItem(tolkien)) { tolkien = store.findById(tolkien); } //ensure its loaded
[2:23 PM] aszs: no it should block
[2:23 PM] aszs: yes
[2:24 PM] brian_skinner: okay, that seems like an okay solution
[2:24 PM] aszs: yup
[2:25 PM] aszs: what to propose that on the wiki page?
[2:25 PM] brian_skinner: but then I think maybe findByIdentity() actually does belong in the dojo.data.Read API, rather than off in dojo.data.Identity, since we're now saying that another dojo.data.Read method (the get method) will sometimes return Identities
[2:26 PM] aszs: its not really returning identities
[2:26 PM] brian_skinner: it's not?
[2:26 PM] brian_skinner: var tolkein = store.get(theHobbit, "author")
[2:26 PM] brian_skinner: if (store.isItem(tolkien)) { tolkien = store.findById(tolkien); } //ensure its loaded
[2:26 PM] brian_skinner: ...
[2:27 PM] aszs: i think findById should work with items
[2:27 PM] aszs: too
[2:27 PM] brian_skinner: you mean, findByIdentity works with unavailable-items
[2:27 PM] aszs: it may or may not be an "Identity"
[2:27 PM] aszs: that up to the implementation
[2:28 PM] aszs: Identity isn't a dojo call
[2:28 PM] aszs: its just a mixin to the store
[2:28 PM] aszs: i mean...
[2:28 PM] aszs: tolkien isn't a dojo.Identity
[2:28 PM] aszs: there maybe some implementation defined Identity object that gets returned
[2:29 PM] aszs: but as long as isItem(tolkien) return true
[2:29 PM] aszs: it doesn't make a difference to the api
[2:31 PM] brian_skinner: hmm... i think my brain is starting to fade -- i'm not crazy about having both (a) the notion of items vs. identities and also (b) the notion of available items vs. not-yet-available items -- i'd rather have just one or the other, but i'm too fried to articulate options/problems
[2:32 PM] aszs: ok
[2:32 PM] aszs: let's wait till next week
[2:33 PM] brian_skinner: okay, sorry i'm not sharper todya
[2:33 PM] brian_skinner: today
[2:33 PM] aszs: no problem
[2:33 PM] brian_skinner: so, other stuff for now?
[2:33 PM] brian_skinner: or adjourn until next week?
[2:33 PM] aszs: i think we're good for today
[2:33 PM] aszs: yes
[2:34 PM] brian_skinner: okay, col
[2:34 PM] brian_skinner: cool
[2:34 PM] aszs: i'll write an email about the REsult
[2:34 PM] aszs: changes
[2:34 PM] brian_skinner: sounds good, thanks

Data Access Meeting (2006-10-17)

 Agenda

    * Adam Souzis's idea from last week
          o see: http://article.gmane.org/gmane.comp.web.dojo.devel/4257
          o getting rid of result.forEach() and most of the rest of dojo.data.Result
          o different ways to call store.find():
                + var array = store.find(someQuery); // make simple things simple -- sync case
                + store.find(someQuery, {sync:false, oncompleted:fooFunc, onnext:barFunc, onerror:iggyFunc}); // calls onnext(item) for each item
                + store.find(someQuery, {sync:false, oncompleted:myfunc, array:true}); // calls myfunc(array) after all items are ready
          o or, some naming alternatives:
                + store.find(someQuery, {onnext:bar});
                + store.find(someQuery, {oneach:bar}); // "oneach" instead of "onnext"
                + store.find(someQuery, {forEach:bar}); // "forEach" instead of "onnext"
                + store.find(someQuery, {onnext:bar, onlast:foo}); // "onlast" instead of "oncompleted"
          o and another possible parameter, if you want to pass a object that the callback methods will be called on:
                + store.find(someQuery, {sync:false, oncompleted:obj.fooFunc, onnext:obj.barFunc, onerror:obj.iggyFunc, context:obj});

    * dojo.data.Read API
         1. how do we do "reference faulting" (or whatever the right term is) -- the situation where you have a giant data graph on the server, and you only have 10% loaded into data objects on the client, and when you ask a data object for some related object, it may just hand you back some other object that was already in memory, or it may initiate a request to the server to get the needed data?
         2. what does store.get(theHobbit, 'author') return?
                o an Identity
                o a reference (what's a reference?)
                o an item that is guarenteed to be available
                o an item that may or may not be available
                o a Deferred?
                o any of the above?
         3. semantics of isItem() more like isItemAvailable() (and, if so, rename it)?
                o should isItem(x) return true if x is an item Identity instead of an item?
                o should isItem(x) return true if x is an item that has been deleted? Prior to a save? After a save?
                o [adamsz: yes to all these]
                o [skinner: yes for deleted items. no if x is an item Identity, not an item. If isItem(x) returns true when x is an item Identity, that makes it impossible to use isItem() to figure out what a call to store.get() has just returned, and so you can't write GUI display code.]
                o [mitchell: How about isItem(any) for type-check, exists(item) for existence test?]

    * dojo.data.Result API
         1. how do we want to handle GUIs that page or scroll through large result sets?
                o explicitly encourage data stores like the YahooStore example?
                o explicitly discourage or forbid that type of iteration?
                o other alternatives?
         2. what does inProgress() mean?
                o forEach() loop is in progress?
                o data is loading (query has been sent, forEach() not yet called)?
                o either of the above?
                o ~[adamsz: for clarity maybe instead we should have a state member;
                      + i think we need: initial, receiving, completed, error
                      + compare with:
                      + xmlhttprequest.readyState: 0 uninitialized, 1 open, 2 sent, 3 receiving, 4 loaded,
                      + deferred.fired: -1 initial, 0 success, 1 error
                      + ]~
                o [skinner: Having a state property seems like a good idea. Should the state property convey info about (a) progress loading data from the server (initial, receiving, completed), or (b) progress iterating through the forEach loop (initial, looping, completed), or (c) some combination of both? What's the name of the state property, and do we want some sort of getState() accessor method]
                o [mitchell: State member is good, for determining resultset state between store (local or remote) and JS client]
         3. signature for oncompleted callback?
                o [adamsz: oncompleted(iterator)]
                o [skinner: oncompleted(). We might consider passing an iterator to the callback method that the caller sets with setOnLoopCompleted(callback). We should not pass an iterator to the callback method that the caller sets with setOnFindCompleted(callback), since that doesn't work well with the style of access that we might want to do in paging/scrolling implementations like the YahooStore. Offering a synchronous-iterator creates a new implementation requirement that dictates that all results will be in memory at once. Synchronous looping is a nice feature to have, but we shouldn't impose the the all-results-in-memory requirement every time a find() is complete, as would be required if we automatically pass an iterator in to the oncompleted callback -- we should only impose the the all-results-in-memory requirement if the calling code explicitly asks for synchronous looping by calling a asIterator() or asArray() method. If we do have a asIterator() or asArray() method, I have a strong preference for asArray() instead of asIterator(), because looping through an array is something that every JavaScript textbook covers, whereas the iterator syntax is dojo-specific and less obvious.]
   &