Welcome, guest ( Login )

WikiHome » dojo.data » Dojo Data Meetings » 2007-03-15

2007-03-15

Version 6, changed by jaredj 03/20/2007.   Show version history

Agenda Item 1:  Close on discussion from last meeting with regard to callbacks and behavior.

  • lack of parallel structure between onBegin and onCompleted (present tense vs. past tense) -- should it be onComplete instead, or onEnd?
    • skinner: i thought we settled on "onComplete" in our last meeting (2007-03-13)
    • jaredj: I believe we did to some extent, but there was ambiguity on which callbacks we were even going to support.  So I left this item here as a reminder to revisit it.
  • instead of "saveResult", would it be better to have "onCompleteArray"?
    • proposal 1: Eliminate the saveResult argument entirely. Automatically pass an array of the result items to the onComplete callback whenever there is not an onItem callback.
    • proposal 2: Eliminate the saveResult argument entirely. Have two separate onComplete callbacks, one that gets passed the array of items and one that doesn't. Name them something like onComplete and onCompleteWithArray (or whatever).
Use Case Link examples to help solidify the diection:
Use Cases:
Read Examples
Find and Fetch Options

Conclusion from meeting (After MUCH discussion), go with Option 6:

Option 6: store.fetch()

example

Simple case (streaming, no paging):
1 | var store = new dojo.data.CsvStore({url:"movies.csv"});
2 | store.fetch({onItem:displayItem});

Simple case (all items as one chunk):
1 | var store = new dojo.data.CsvStore({url:"movies.csv"});
2 | store.fetch({onComplete:displayAll});

Simple case (Paged chunks):
1 | var store = new dojo.data.CsvStore({url:"movies.csv"});
2 | store.fetch({count:20, onComplete:displayPage}); // Return the first 20 items. If start not defined, assumed started at 0.
...
40 | store.fetch({start:20, count:20, onComplete:displayPage}); // Grab the next twenty items.

Semi-complex case (paging, with query, sorting, etc, specified.):
1 | var store = new dojo.data.LargeRdbmsStore({url:"jdbc:odbc:foobar"});
2 | var fetchArgs = {
3 | query: {type:"employees", name:"Hillary *"}, // string matching
4 | sort: [{attribute:"department", descending:true}],
5 | start: 0,
6 | count: 20,
7 | scope: displayer,
8 | onBegin: showThrobber,
9 | onItem: displayItem,
10 | onComplete: stopThrobber,
11 | onError: handleFetchError,
12 | };
13 | store.fetch(fetchArgs);
...| ...
40 | // and then when the user presses the "Next Page" button...
41 | fetchArgs.start += 20;
42 | store.fetch(fetchArgs); // get the next 20 items


pros

  1. "simple things simple, and complex things possible"
  2. Creates fewer method to document, fewer methods to test, and fewer methods for a user to learn, because there's now no store.find() or result.fetch().
  3. Under the covers, a datastore can still use database cursors, and does not need to run the same query twice. This option is just as performant as other options, but now that performance improvement is an implementation detail, not something exposed in the API.
  4. The semantics are consistent across use cases.
  5. Makes it possible to write a general-purpose, off-the-shelf dojo.data.Result class that can easily be re-used by anyone who is implementing a new datastore.
  6. Allows the guts of the fetch() method to be implemented in the datastore object rather than the result object, since the datastore object has all the smarts and knows how to do efficient caching, range queries, etc.

cons

  1. does not feel familiar to people who are used to working with databases

opinions

  • brian likes it
  • alex at first said "gives me the willies because then you've got users juggling location in the result set", but now says he's okay with it
  • jared's reviewer says: "For Options 4-6, we don't like having the fetch on the store since logically this is an operation that's associated with query result rather than the store itself to which multiple queries can be directed."
  • jared has said he's okay with it, and i think has said that chris is game to sign off on it as well


The below is relegated to the next meeting:


Agenda Item 2:  Additions to filtering capability to simple filtering API (Filtering api as discussed from 2007-03-06):


Item 1:
One thing I would like to propose we add here is the support for the ? single character pattern match in addition to the basic * pattern match.  There are three reasons I'd like to add this with community agreement as a standard option on the API:
  • It should be less code in the simple pattern generator to support this than to ignore it (about two lines less, I believe).  So, we get it virtually for free by deleting two lines in the Filter helper that many datastores can use.
  • There is a definite way this can be mapped to relational stores like SQL.  In SQL, as * is to %, ? is to _.   So, there should be an easy translation to backend stores that use DB queries.
  • One of the widget contributors would like to see this added (Douglas Hays). 

Item 2:
Support for non-string (numeric) pattern matching.  While going through this, I realized another likely common fuzzy search people may wish to do involves numbers, such as X >=5.  This can come into play where you want to search for all items that have a last modified date greater than some value, for example.   How should this be done, if any?  

One way is to have the ability to specify a numeric comparator, in addition to the basic string comparators such as:
'=<some number>'
'>=<some number>'
'<=<some number>'
'><some number>'
'<<some number>'
'!=<some number>'
Another is not to have this on the standard API at all to keep it simpler and let individual datastores implement this however they wish to implement it.   Chris M is in favor of leaving it up to the datastores and keep the required API of the datastore as small and simple as possible.

CCM: More specifically, we should not be introducing expressions other than simple wildcarding for string values into param values for find().  We stated in previous design discussions that the actual query language used in datastores is the responsibility of the datastore and must be hidden from the client of the find() api. The find() function is only provided to allow parameters to be provided for substitution into underlying datastore query language expressions.  Exposing expressions through the api goes directly against design decision to shield the client from the language. 

skinner: I'm inclined to agree with CCM. We're already on the slippary slope, now that we've added the * for string pattern matching, but maybe we should resist going any further down the slope. If we add numeric patters (like population > 5), then it's easy to argue we might also want boolean patterns (like airBags = true), and date patterns (like purchaseDate > 2007-02-21). And once we go too far that direction, we end up touching on other issues, like date formatting standardization, and combining patterns with AND and OR.

Agenda Item 3:  The Write API

  • 'Write' defines a method to set an item attribute value as set(), while Read.get() has been renamed to Read.getValue(). Shouldn't Write.set() be also renamed to setValue() for symmetric set of APIs? (skinner: yes, let's change it to setValue())
  • What should save() method take as a parameter? what should save() return? (especially, to support async.).  Currently in the API docs it states:
         * ISSUE -
         *   Should the async save take a callback, like this:
         *     store.save({sync: false, onComplete: callback});
         *   Or should the async save return a Deferred, like this:
         *     var deferred = store.save({sync: false});
         *     deferred.addCallbacks(successCallback, errorCallback);
         *   Or should save() return boolean, like this:
         *     var success = store.save();

This needs to be decided on. 

    JaredJ:  For symmetry of the read/write APIs, my vote would be for the store.save({sync: false, onComplete: callback});  Use callbacks, the same as you do for the find API.  It also allows you to easily specify other callbacl, such as onError.  I don't see what functionality a 'Deferred' object gives you that could not be done with using the callbacks method.

    skinner: It would be good if the dojo.data APIs did not have any dependency on dojo.Deferred. If we can keep the APIs independent of any dependency on the dojo toolkit then people who don't use dojo can still conform to the APIs, and then we can play nicely with other toolkits. That's something that came up as a design goal at Dojo Developer Day in January. So, +1 for just using callbacks, like onError.

    skinner: We've decided that find() and fetch() only operate in async mode, and that we don't allow a "sync" argument for doing sync:true or sync:false. I think we should say the same thing for save() -- save() should not take a "sync" argument, and we should never return a boolean success value.
  •  From looking at the APIs as they are today, Write.save() seems to assume that a data store tracks changes to items to be wrote back to the server on save().   Is this the intention?  (skinner: Yes, we also have write.revert and write.isDirty, which implies that the data store must track changes.)
  • An explicit method to just save a single item would be convenient to have, such as: 
var item = store.newItem(...);
store.setValue(item, "anAttribute", aValue);
...
store.saveItem(item);

may look more intuitive, compared to:

var item = store.newItem(...);
store.setValue(item, "anAttribute", aValue);
...
store.save();

where the caller may not 100% sure on what will be saved, especially when multiple and complicated calls to newItem(), setValue() and deleteItem() are involved.

saveItem() also allows a data store to skip the task to find out what to save by examining records of "new", "modified", and "deleted" items.



Minutes:
[20:01] <brian_skinner> hi
[20:02] <jared_j> brian_skinner: Hello there. Don't think Chris will make it, at least not until after 5. He got puleld aside to do some major presentation work for a VP here.
[20:02] <brian_skinner> okay
[20:02] <jared_j> Thanks for putting together those examples, they do erally help visualize/work through it.
[20:02] <jared_j> Are we going to get Alex today, do you think?
[20:02] <brian_skinner> i don't know
[20:03] <jared_j> I've also asked some peope internally to look at your options proposed as well.
[20:03] <brian_skinner> cool, thanks
[20:03] <jared_j> To get feedback from people who will be writing stores to it.
[20:03] <jared_j> Or using it.
[20:03] <brian_skinner> yup, real world users -- always a good source of feedback :-)
[20:03] <jared_j> And you sound tired. (Or at least that's what I'm reading into your text).
[20:03] <brian_skinner> i am tired
[20:04] <brian_skinner> i've got too much going on right now
[20:04] <brian_skinner> visitors from out of town, taxes, packing, moving, dojo, other projects...
[20:04] <jared_j> Ugh.
[20:04] <jared_j> After reading over it, my, and Chris' personal opinion on the examples is ... we like option 6 just for the sheer simplicity it presents (and what you can still do.) Unforunately, one of the replies internally didn't like 4-6.
[20:05] <brian_skinner> okay
[20:05] <jared_j> The reason being: We don't like having the fetch on the store since logically this is an operation that's associated with query result rather than the store itself to which multiple queries can be directed.
[20:05] <jared_j> To quote them
[20:05] <jared_j> They're relational DB folks, by the way.
[20:05] <brian_skinner> jared_j: i think that matches what bill's reaction was
[20:05] <jared_j> So they're used to the get result, fetch() on it.
[20:06] <jared_j> If I remember right, yes, I think it was as well.
[20:07] <jared_j> Which is a shame becase the more i think on it, having it as one function simplifies the API as well as simplifies the store in a lot of respects.
[20:07] <brian_skinner> seems like that reaction might be a common one then -- so that's a real disadvantage in going with option 6
[20:07] <brian_skinner> yup
[20:07] <jared_j> Splitting it does add a level of complication, such as how do you really do the fetch. The store has to provide some sort of hook there.
[20:07] <jared_j> If you add it to read.js, then it loosk odd.
[20:08] <jared_j> If you make it 'private', I feel like we're almost saying it's an undocumented api you have to do anyway.
[20:08] <brian_skinner> option 6 is my favorite too -- Adam Souzis first took us in the direction of option 6 back last fall, and at first i didn't think it was a good idea, but now i've grown to like it
[20:08] <jared_j> I'd like to see what Alex thinks on it too, admittedly.
[20:09] <jared_j> Option 6 also almost makes Result.js obsoluete/unneeded too. I only see aue for it for say, an abort or whatnot.
[20:09] <brian_skinner> yup
[20:09] <jared_j> My love of the KIS principle really likes option 6.
[20:09] <brian_skinner> in the replies that you got internally, which option was the favorite?
[20:09] <jared_j> Nto to mention I could redo JsonItemStore that way in like a day or less, I bet.
[20:10] <jared_j> I haven't really gotten a favorite yet. I'v only gotten one reply out of the fw I've asked so far.
[20:10] <jared_j> HEre's what I got verbatim from that reply...
[20:10] <jared_j> As the comments already note, (relational) database people are comfortable and understand option 1. We agree!
[20:10] <jared_j> Option 2 seems odd, given that you already have the Result, what's the benefit. Pretending that the "smarts" are on the store is confusing since it's the Result that actually has the state. We're not sure what a general-purpose Result implementation would look like since there are so many flavors of datastore, and would suggest that this could be refactored later if it makes sense when...
[20:10] <jared_j> ...there are more implementations to analyze.
[20:11] <jared_j> For both Option 2 and Option 3, how functions get factored between the store and the result should be an implementor's decision and should not be reflected into the API.
[20:11] <jared_j> For Options 4-6, we don't like having the fetch on the store since logically this is an operation that's associated with query result rather than the store itself to which multiple queries can be directed.
[20:11] <jared_j> I don't necessarily agree with 'For both Option 2 and Option 3,...' because it does matter, because some relation has to be defined so people know how to write a store that works.
[20:12] <jared_j> But anyway, that's all I've gotten from folks here so far.
[20:12] <brian_skinner> that all sounds reasonable
[20:12] <jared_j> Yes, but they didn't say that they really liked one over the other, alas.
[20:12] <brian_skinner> i agree that options 4-5 definitely don't have an object-oriented feel
[20:13] <jared_j> No, they don't.
[20:13] <brian_skinner> if we don't end up doing #6, what's your second choice?
[20:13] <jared_j> Me? Hm.
[20:14] <jared_j> Probably option 3. We should at least make it noted that _fetch() is Datastore private and for use as a hook point for the store into access into the DS cache or whatever.
[20:14] <brian_skinner> i know you may not be a typical user, but you've thought this through more than our typical users have, and you've been thinking about it from the point of view of both the user and the datastore author
[20:15] <jared_j> Yeah, I'm not a typical user, I'm on both sides of the fence. :)
[20:16] <jared_j> I also have to think that if we make writing a datastore too hard, no one wil use the API anyway, so I have to consider what is simple to implement. (For good or bad as that may be)
[20:16] <jared_j> Which one, other than 6, d o you prefer?
[20:17] <brian_skinner> i'm not sure -- give me a second to look at them
[20:17] <jared_j> Ok
[20:19] <brian_skinner> i guess option 5 would be my next choice, then option 4
[20:19] <jared_j> Keeping fetch on the store.
[20:19] <jared_j> Not the result.
[20:19] <brian_skinner> i think my preferences run in straight order: 6, 5, 4, 3, 2, 1
[20:20] <jared_j> Heh.
[20:20] <jared_j> If we did do that, then what callbacks would find really need? If it by itself never returns any items ... I guess all it would need is onError, wouldn't it?
[20:21] <brian_skinner> sorry, i got lost -- if did which one?
[20:21] <jared_j> 5
[20:22] <brian_skinner> yes, i think just onError
[20:22] <brian_skinner> and scope
[20:22] <jared_j> The concern I'd have with 5 is just that which has been re-iterated, it doesn't meet with what DB type folks expect.
[20:22] <jared_j> Yeah, scope for what cscope onError is called at.
[20:23] <brian_skinner> yup, i wish i had some clever idea about how to address that concern -- how to make an option that does feel right to the DB crowd
[20:23] <jared_j> And if we're not going to meet their wishes, I'd rather just do 6 over 5.
[20:23] <brian_skinner> have you read the wisdom of crowds?
[20:23] <jared_j> I think Alex may have issue with 5 because it's more 'handle passing', with the result as a handle.
[20:24] <jared_j> But I can't say for sure on that.
[20:24] <brian_skinner> i don't have a good understand of what alex thinks on this stuff
[20:24] <brian_skinner> understanding
[20:24] <jared_j> I don't either, other than he really didn't seem to like the idea of passing around handles, as he put it 'willy nilly'.
[20:25] <brian_skinner> should i send him mail and see if he's free now?
[20:25] <brian_skinner> what should we do about today's meeting? is there stuff that you and i should go over, or should we wait for chris, or should we reschedule for a day when we can get alex and bill and others?
[20:25] <jared_j> Please do. We have time. Chris will hopefulyl be here at 5.
[20:25] <jared_j> I don't think just us two can make the final call. Well, I guess we could, but.
[20:25] <brian_skinner> okay, will do
[20:25] <brian_skinner> but that would end in tears ;-)
[20:25] <jared_j> Exactly.
[20:28] <jared_j> Who in the dojo community in general would be good to get to look and vote on options? Trenka, I assume. Bill and Alex. Any others?
[20:29] * slightlyoff (n=alex@204.14.154.182) has joined #dojo-meeting
[20:29] * ChanServ sets mode +o slightlyoff
[20:29] <slightlyoff> hey all, sorry I'm late
[20:30] * Deffender (n=Chip@204.14.154.182) has joined #dojo-meeting
[20:30] <jared_j> Welcome, slightlyoff, sorry to drag you back into this. We would like your opinions on the options Brian proposed. have you had a chance to look at them at all?
[20:30] <slightlyoff> jared_j: I did give them a once-over
[20:30] <slightlyoff> jared_j: can you give me 5 minutes to re-acquiant myself w/ them?
[20:30] <brian_skinner> hey slightlyoff -- good to see you, i was just sending you mail
[20:30] <jared_j> Certainly.
[20:31] <slightlyoff> so brian_skinner, is the proposed syntactic sugar to remove find() going to be a static method on all Store objects?
[20:32] <brian_skinner> jared_j: to answer your question from a few minutes ago: yes, i think Bill and Trenka are the two other people who are the most interested in where this goes
[20:33] <jared_j> slightlyoff: And t let you know, Chris and I have been querying around here to get input from epople who would write to, and use these apis to see what their opinions were.
[20:33] <slightlyoff> jared_j: and the consensus from the RDBMS world is.... ?
[20:34] <brian_skinner> slightlyoff: sorry, i didn't follow that question -- are you looking at the DojoDataReadExamples or the DojoDataFindAndFetch page?
[20:34] <slightlyoff> brian_skinner: ReadExamples
[20:34] <slightlyoff> http://dojo.jot.com/DojoDataReadExamples
[20:34] <slightlyoff> specifically option 2.1
[20:35] <jared_j> slightlyofF: The one response we got back so far (On FindandFetch options) likes 1, in that it followws what they're used to. They don't like 6, because to quote them: we don't like having the fetch on the store since logically this is an operation that's associated with query result rather than the store itself to which multiple queries can be directed.
[20:35] <brian_skinner> got it -- so in that proposal find() would just be optional
[20:36] <brian_skinner> that option 2.1 corresponds to option 5 in the longer page: http://dojo.jot.com/WikiHome/DojoDataFindAndFetch
[20:37] <brian_skinner> slightlyoff: and i think that response that jared got in house matches the reaction we got from bill
[20:38] <slightlyoff> jared_j: so I'm actually not opposed to what was proposed in 2.1, w/ the caveat that my non-opposition is based on it not being confusing for users
[20:39] <jared_j> Having fetch() on the store?
[20:39] <jared_j> Not the result itself?
[20:39] <slightlyoff> jared_j: well, some syntactic sugar that folds them in some common-case scenario
[20:40] <slightlyoff> jared_j: but my potential objections to it (and what I voiced 2 weeks ago) center on potential confusion
[20:40] <jared_j> With the RDBS folks, I assume.
[20:40] <brian_skinner> slightlyoff: i'm not sure i know what you mean by "well, some syntactic sugar that folds them in some common-case scenario"
[20:40] <slightlyoff> brian_skinner: trying to find the analogy in the larger doc, one sec
[20:41] <jared_j> brian_skinner: Oh good, I wasn't the only one wondering. I thought I was being daft. :)
[20:41] <brian_skinner> slightlyoff: take your time -- the docs are long now
[20:43] <slightlyoff> so I hate option 4
[20:43] <brian_skinner> :-)
[20:43] <slightlyoff> = )
[20:43] <brian_skinner> good clear feedback
[20:44] <jared_j> Because of passing of a result handle?
[20:44] <slightlyoff> jared_j: yes
[20:44] <slightlyoff> option 6 gives me the willies because then you've got users juggling location in the result set
[20:45] <jared_j> Well, does option 6 even really have a result object at all?
[20:45] <slightlyoff> no, which also seems strange = )
[20:45] <jared_j> You have a set of params you keep calling against and adjusting. Not necessarily the resultset itself.
[20:45] <slightlyoff> which means having them manage the offset is even dumber
[20:47] <slightlyoff> option 5 feels like an API we would have ratified in Dojo 0.3.x days
[20:47] <slightlyoff> which means it's got things to recommend it, but will be hard to introduce
[20:48] <slightlyoff> I don't mind option 2 or option 1
[20:48] <jared_j> But 2 has the possible pass by handle into store.
[20:50] <slightlyoff> yeah, I dislike that...if the store is going to have a fetch() method, it needs to assume it's a new result from a new (blank) find() and just fetch
[20:50] <brian_skinner> i've just been adding to the page, to make notes about people's opinions about the different options
[20:50] <slightlyoff> being smarter than that is unwarranted, IMO
[20:50] <jared_j> brian_skinner: On option 1, do we really need count at all?
[20:50] <jared_j> In find()
[20:50] <slightlyoff> and we should direct folks to the broken up find()/fetch() for advanced use in secnario 2
[20:51] <jared_j> If we did allow a fetch() on the store, the result itself could make use of that to call back into the store.
[20:51] <brian_skinner> jared_j: we had described count as optional before, which i think means we don't really need it
[20:51] <jared_j> But then having two fetches, to me, seems confusing. :)
[20:51] <brian_skinner> but it may be something that database people use
[20:52] <brian_skinner> if we have two fetches, they should just be synonyms, or else it will be a pain
[20:53] <brian_skinner> both for user and implementor
[20:53] <jared_j> Would that then allow result to use the store defined fetch? Or would the store still need to plug a fetch()onto result?
[20:54] <brian_skinner> in my mind, for option 2, the result.fetch() implementation would always just be a simple two line method that calls store.fetch
[20:54] <slightlyoff> I'm w/ brian_skinner on that
[20:55] <slightlyoff> brian_skinner: exactly
[20:55] <jared_j> brain_skinner: Same here. That's why I wanted to clarify. :)
[20:55] <jared_j> So the basic result object just calls the store fetch
[20:55] <slightlyoff> jared_j: making it smarter creates a janky semantic disconnect which belies it's use as a shortcut (as opposed to a more-important thing)
[20:55] <slightlyoff> jared_j: it would be:
[20:56] <slightlyoff> fetch: function(){ var r = this.find(); return r.fetch.apply(r, arguments); }
[20:56] <slightlyoff> that should be the whole method
[20:57] <jared_j> The store's fetch function, you mean?
[20:58] <brian_skinner> i was thinking something different
[20:58] <jared_j> The result object still has to have some what to get into the store to locate items. Or so I thought. For things like paging where we dont' even have the dataa yet.
[20:58] <brian_skinner> i was thinking that the result object has this:
[20:58] <jared_j> brian_skinner: So was I. I was thinkingthe opposite.
[20:59] <slightlyoff> jared_j: yes, that would be the store's fetch
[20:59] <brian_skinner> function fetch(keywordArgs) { keywordArgs.from = this; return store.fetch(keywordArgs); }
[20:59] <jared_j> brian_skinner: that's more along the lines of what I was thinking.
[21:00] <slightlyoff> hrm, OK, etither way is fine by me
[21:00] <brian_skinner> that way you don't do a new find() for every fetch
[21:01] <slightlyoff> brian_skinner: oh, I wouldn't expect that we would if you're calling it from the result object
[21:01] <slightlyoff> brian_skinner: my code above was "fetch from the store object", but the point is well taken
[21:01] <brian_skinner> i see
[21:02] <brian_skinner> yes, in that case the two approaches amount to the same thing -- one just delegates to the other
[21:02] <brian_skinner> if i'm not misunderstanding
[21:02] <jared_j> I was thinking in general result delegates to the store.
[21:03] <jared_j> That way result itself doesn't have to maintain much state.
[21:03] <jared_j> Or are folks thinking otherwise?
[21:03] <brian_skinner> i think that way would make the implementation easier -- result delegates to store
[21:04] <brian_skinner> makes caching easier, etc.
[21:04] <slightlyoff> sounds great to me
[21:04] <jared_j> Right. All caching in store.
[21:04] <jared_j> Less point of failure.
[21:06] <slightlyoff> ok, so what's left to decide?
[21:06] <brian_skinner> jared_j: i've added an opinions section to each of the options on the wiki page, with some entries with opinions from me and alex -- should i add in the opinions you got from the in house reviewer, or should those be private?
[21:06] <jared_j> Feel free to add them.
[21:07] <jared_j> With regards to the fetch() api on the store itself, should we denote that it should not be generally used?
[21:07] <jared_j> And go through result?
[21:07] <jared_j> for fetching?
[21:08] <brian_skinner> slightlyoff: we need to pick one of the six options, but maybe we want to wait until we've heard from more people? and then we need to decide about the saveResult thing, and depending which option we pick, there are other little sub-decisions
[21:08] <jared_j> I'm just concerned about potential confusion with having two fetch() functions and if we should doc it specifically one way.
[21:09] <brian_skinner> jared_j: if we're planning to discourage store.fetch(), then shouldn't we go with option 3?
[21:09] <slightlyoff> brian_skinner: frankly, whatever decision we make is going to be wrong to some set of users. We're happy-ish w/ the discussed modifications to #1 and #2
[21:09] <jared_j> Well, if people want to use the store fetch as a bypass, that's fine.
[21:09] <jared_j> Since the result is just going to call it anyway. End result would be the same
[21:09] <slightlyoff> which is the use case that I thought brian_skinner was arguing for?
[21:09] <brian_skinner> slightlyoff: i'm not very happy with #1 and #2
[21:10] <brian_skinner> slightlyoff: #6
[21:11] <slightlyoff> brian_skinner: which of them do you like?
[21:11] <brian_skinner> #6
[21:12] <brian_skinner> and my second choice would be #5, and then on down from there: 4, 3, 2, 1
[21:12] <slightlyoff> brian_skinner: yes, but if we were to compromise on letting users have a result object to call fetch() on as well, would that be OK w/ you?
[21:12] <slightlyoff> passing result around is stupid
[21:13] <slightlyoff> so no to 4 & 5
[21:13] <slightlyoff> (sorry, I just can't get behind that)
[21:14] <slightlyoff> it offends my sensibilities to get something from a method that I have to hold but can't *do* anything with
[21:15] <jared_j> slightlyoff: You must really hate Win32 API programming then. ;)
[21:15] <slightlyoff> 3 just doesn't make sense in light of your preference for 6
[21:15] <brian_skinner> i'm definitely game to compromise. I don't want to stand in the way of progress. But i'd like to feel like it was a something that people had thought through. As it is now, we're talking about nixing #6 even though it only has a single 'con' argument
[21:16] <brian_skinner> and the con argument is about gut reaction, rather than any practical disadvantage
[21:16] <jared_j> The RDBS folks don't like 6. We have confirmation of that.
[21:16] <jared_j> Well, at least one set doesn't.
[21:16] <brian_skinner> yup, point taken
[21:16] <slightlyoff> brian_skinner: I'm not opposed to it, with the caveat that we allow there to be a find() method whose result can also expose a fetch
[21:17] <slightlyoff> brian_skinner: and it's not because I like that better
[21:17] <slightlyoff> brian_skinner: I like #6
[21:17] <brian_skinner> slightlyoff: what does that buy us, except more complexity?
[21:18] <slightlyoff> brian_skinner: is there a case to be made that there should be some smarts at all in the Result object?
[21:18] <slightlyoff> brian_skinner: if not, you've got my vote on 6
[21:18] <slightlyoff> brian_skinner: it's easy to introduce
[21:18] <slightlyoff> and I don't mind 1 for the same reason
[21:18] <brian_skinner> in my opinion, if we try to put any smarts in the result object we'll end up regretting it
[21:18] <slightlyoff> my objections are actually not related to how capable the APIs are...just how hard they are to talk about
[21:20] <brian_skinner> yup, being able to easily explain them is important
[21:20] <jared_j> What should Result allow you to do, then?
[21:20] <jared_j> If there are no smarts?
[21:20] <jared_j> Just abort a fetch()?
[21:20] <slightlyoff> jared_j: apparently, nothing = )
[21:20] <brian_skinner> i think we just need a result.abort()
[21:21] <slightlyoff> brian_skinner: wouldn't store.abort() do the same then?
[21:21] <jared_j> slightloff: How does the store know which fetch out of many that may be calling into it, to abort?
[21:21] <brian_skinner> yes, i suppose store.abort() would work, if you passed in the same fetchArgs
[21:21] <jared_j> In that case.
[21:22] <slightlyoff> well, I'm down w/ whatever fetch() returns having an abort() method
[21:22] <brian_skinner> or you could have store.fetch() return a token...
[21:22] <slightlyoff> what else should it be able to do?
[21:22] <brian_skinner> var token = store.fetch(...)
[21:22] <brian_skinner> store.abort(token)
[21:22] <slightlyoff> brian_skinner: again, things you get that you can't do anything with are dumb
[21:22] <brian_skinner> well, they
[21:23] <brian_skinner> well, they're not object-orientied, but you can still do things with them
[21:23] <jared_j> It's effectively an index, I guess.
[21:23] <brian_skinner> we moved away from having an object-oriented API back 8 months ago, when we put the getValue() method on store rather than item
[21:23] <slightlyoff> but there's no difference! Just return an object that holds the index and a method to call store.abort(this.index)!!!!
[21:24] <brian_skinner> which we had to do in order to satisfy the performance features we wanted
[21:24] <slightlyoff> brian_skinner: I'm not even advocating for classes here...just not castration
[21:25] <slightlyoff> whatever...there's no serious over head here, but we can benchmark and whatnot if you like
[21:25] <slightlyoff> what's left to decide?
[21:25] <brian_skinner> easy there, i'm not arguing against having a result.abort()
[21:25] <slightlyoff> brian_skinner: *phew*
[21:25] <slightlyoff> thanks
[21:25] <brian_skinner> you're the one who proposed store.abort()
[21:26] <slightlyoff> brian_skinner: fair enough
[21:26] <slightlyoff> brian_skinner: ok, what else, if anything, needs to be on the result?
[21:26] <brian_skinner> well, one other possible thing
[21:27] <jared_j> Would it be even remotely useful to have an isComplete flag on it stating when the operation is done?
[21:27] <brian_skinner> there's this question about whether you want to be able to find out how many items you could get back from a query
[21:27] <brian_skinner> jared_j: when what operation is done?
[21:28] <brian_skinner> when all the items have been iterated over, after the last onItem call?
[21:28] <jared_j> The fetch operation itself. Right
[21:28] <jared_j> Not sure it's useful or not.
[21:28] <jared_j> With an onComplete callback, probably isn't.
[21:29] <brian_skinner> i can't think of when you would use it, given that we have onComplete
[21:29] <brian_skinner> but the thing about wanting to know the number of available items concerns me
[21:30] <brian_skinner> like, if you need to know how big to make the scrollbar, for a table that will let you scroll through 1,200 items
[21:30] <jared_j> Well, it depends on how you ge the items
[21:30] <jared_j> One at a time, by pages, or all at once.
[21:30] <jared_j> But I see your point.
[21:31] <brian_skinner> i think it's really only an issue in the paging case
[21:31] <brian_skinner> in any other case you could just use onComplete to get an array, and look at array.length
[21:32] <brian_skinner> or onBegin could get passed the total length
[21:32] <jared_j> So, that does imply there could be an option/value that gives you total number of hits.
[21:32] <slightlyoff> that seems smart
[21:32] <jared_j> If you even know it at onBegin...
[21:32] <jared_j> But that's a store impl problem. :)
[21:32] <slightlyoff> jared_j: -1 if we don't?
[21:32] <brian_skinner> actually, i guess onBegin could get passed the total length even in the paging case
[21:32] <jared_j> Yeah, -1 of we have no idea.
[21:33] <jared_j> Otherwise a number denoting how many total items we have to work with. That would make sense.
[21:34] <brian_skinner> so, then to pop back up to alex's question -- what else, if anything, needs to be on the result? -- i think the answer is nothing
[21:35] <jared_j> So, then should we summarize where we think we're at?
[21:35] <brian_skinner> jared_j: that sounds good
[21:36] <brian_skinner> can you take a stab at that -- i'm not sure i can do it
[21:36] <jared_j> Sure, working on it...
[21:37] <jared_j> brian_skinner: It sounds like to me people are leaning to option #6, regardless of the RDBS concerns. Result is just a small object that lets you abort a current lookup, nothing else. onBegin passes the number of items found, onComplete passes an array of items if and only if onItem wasn't se, onError passes an error. find() goes away in favor of the more flexible fetch() call (as per #6)..
[21:38] <jared_j> saveResult can also go away, I would think, since you can get it in the callbacks. it just clutters the api. (Since you can use onItem, onComplete to determine if you want it in a big array or not)
[21:38] <jared_j> And on, if # of items is indetermanent, onBegin gets passed a -1.
[21:39] <jared_j> Does that seem to generally cover it?
[21:39] * Deffender (n=Chip@204.14.154.182) has left #dojo-meeting
[21:39] <brian_skinner> that all sounds good to me
[21:40] <jared_j> And if we're all in agreement, should we post a summary to the community and get their vote? Or we just make the call here and do it?
[21:40] <slightlyoff> I think we need to just recommend something, implement it, and move on
[21:41] <slightlyoff> the rest of the community has entrusted this group w/ the task...lets just get it done
[21:41] <jared_j> slightlyoff: I'm in agreement with you on that. We won't please everyone, regardless. I'm just new here and don't want to step on toes. :)
[21:41] <slightlyoff> besides, I'll give you feedback when we move this into core = )
[21:41] <brian_skinner> likewise, i'm worried that i've already stepped on too many toes!
[21:41] <slightlyoff> nothing goes into core w/o it making me happy = )
[21:42] * jared_j expects lots of: This sucks! ;)
[21:42] <slightlyoff> brian_skinner: nope, I think you advocated your point of view articulately and it's an idiomatic JS API for data access
[21:42] <slightlyoff> jared_j: I think we won't get that from JS devs
[21:43] <slightlyoff> jared_j: from their perspective, it's a magical wonderland of data access in 4 lines of code or less
[21:43] <jared_j> True enough.
[21:43] <slightlyoff> jared_j: so was find().fetch(), but as I noted before, my worries are all about how easy the API is to introduce
[21:44] <slightlyoff> jared_j: so folks who don't really know how deep the rabbit hole goes should be happy w/ this
[21:44] <slightlyoff> jared_j: and folks who do...well...they didn't *really* need us to do this for them...
[21:44] <jared_j> I personally think #6 is simple enough to use and not overly complicated.
[21:44] <slightlyoff> sold!
[21:44] <slightlyoff> ;-)
[21:45] <jared_j> And frankly, easier to implement in stores than maintaining state between a result and store. ;)
[21:45] <jared_j> So making a store to plug in ought to be somewhat easier.
[21:45] <brian_skinner> should we move on to the next agenda item? or, if not, i have a quick question for slightlyoff about the unit test stuff
[21:46] <slightlyoff> brian_skinner: shoot
[21:46] <jared_j> Go ahead and ask. I need to call and see if I'm expected to meet my GF for dinner soon...
[21:46] <slightlyoff> jared_j: those all sounds like solid reasons for going this way
[21:47] <brian_skinner> slightlyoff: i read through the unit test system doc page: http://redesign.dojotoolkit.org/node/159
[21:47] <slightlyoff> yep
[21:47] <brian_skinner> i'm feeling dense about the async case
[21:47] <brian_skinner> let me give a quick example
[21:47] <slightlyoff> ok
[21:48] <brian_skinner> pretend i'm testing a normal sync function, called math.add()
[21:48] <brian_skinner> so i make a test that looks like this, yes?
[21:48] <brian_skinner> function testTwoPlusTwo() {
[21:48] <brian_skinner> var four = math.add("2 + 2");
[21:48] <brian_skinner> tests.isTrue(four == 4);
[21:48] <brian_skinner> }
[21:48] <brian_skinner> and i'm done
[21:48] <slightlyoff> yep
[21:48] <brian_skinner> okay, so now say that math.add is an async method
[21:48] <slightlyoff> that's the whole shooting match
[21:49] <brian_skinner> so i do
[21:49] <brian_skinner> math.add("2 + 2", callback)
[21:49] <brian_skinner> and callback will be passed 4
[21:49] <slightlyoff> ok
[21:49] <brian_skinner> how do i write the unit test
[21:50] <slightlyoff> so you need to register the async handler in a full fixture
[21:50] <slightlyoff> instead of just the one-off function
[21:50] <slightlyoff> so:
[21:52] <slightlyoff> { name: "testTwoPlusTwo", runTest: function(){ var d = new tests.Deferred(); math.add("2+2", function(res){ d.callback(2==2); }); return d; } }
[21:52] <slightlyoff> it's not nearly as clean or as nice to use
[21:52] <slightlyoff> and I'm still struggling w/ how to make that process easier
[21:53] <slightlyoff> like a "generateCallback" method that will let you use isTrue, etc., in your callback functions instead of handling the error/success tests so manually
[21:53] <brian_skinner> okay, give me a second to digest that
[21:54] <brian_skinner> shoud that be...
[21:54] <brian_skinner> d.callback(res==4)
[21:54] <brian_skinner> rather than
[21:54] <brian_skinner> d.callback(2==2);
[21:54] <slightlyoff> yeah, that = )
[21:54] <slightlyoff> actually, I can do that easily
[21:55] <slightlyoff> give me a couple of minutes
[21:55] <slightlyoff> the code would then be:
[21:56] <slightlyoff> { name: "testTwoPlusTwo", runTest: function(){ var d = new tests.Deferred(); math.add("2+2", d.getTestCallback(function(res){ tests.isTrue(res == 4); })); return d; } }
[21:56] * slightlyoff finds pastebin to format it
[21:57] <slightlyoff> actually, you were right
[21:57] <slightlyoff> don't need the full fixture
[21:57] <slightlyoff> I forgot I got around that by detecting the deferred return = )
[21:58] <brian_skinner> so then just...
[21:58] <brian_skinner> function testTwoPlusTwo() {
[21:58] <brian_skinner> var d = new tests.Deferred();
[21:58] <brian_skinner> math.add("2+2", d.getTestCallback(
[21:58] <brian_skinner> function(res){ tests.isTrue(res == 4); });
[21:58] <brian_skinner> return d;
[21:58] <brian_skinner> }
[21:58] <brian_skinner> ?
[21:59] <slightlyoff> http://scsys.co.uk:8002/6918
[21:59] <slightlyoff> yep, exactly
[21:59] * slightlyoff code getTestCallback method
[21:59] <brian_skinner> peachy
[21:59] <brian_skinner> thanks!
[21:59] <slightlyoff> does it make sense?
[21:59] <brian_skinner> yup, it's good
[22:00] <jared_j> I'm going to head out. Thanks for a productive meeting, everyone. And oh... slightlyoff: I pulled down the 0.4 branch this morning to try editor2. Wit the fixes that wentt in, works much beter now.
[22:00] <brian_skinner> it's a little confusing at first -- but any solution for async testing is going to be slightly hard to get used to
[22:00] <brian_skinner> thanks jared_j!
[22:00] <slightlyoff> jared_j: awesome
[22:00] <slightlyoff> jared_j: thanks again
[22:01] <slightlyoff> brian_skinner: yeah, and if you've got ideas on how to make it easier, that would be great
[22:01] <jared_j> Also thanks for asking about async tests. I need that to try out converting data unit tests to the new test framework. :)
[22:01] * jared_j (i=chatzill@nat/ibm/x-63be4b93e124c951) Quit ("Chatzilla 0.9.77 [Firefox 1.5.0.10/2007021601]")
[22:02] <brian_skinner> thanks for the new test harness slightlyoff -- i'm very much looking forward to it
[22:02] <slightlyoff> brian_skinner: sorry it's late =
[22:02] <brian_skinner> okay, i'm headed off too, unless there's anything else you wanted me for
[22:02] <slightlyoff> brian_skinner: nope, really productive meeting today
[22:02] <slightlyoff> again, my apologies for being so tardy
[22:02] <brian_skinner> no problem -- i'm glad you made it
[22:03] <slightlyoff> brian_skinner: I'm excited that data is nearly nailed down
[22:03] <brian_skinner> yup
[22:03] <brian_skinner> high time!
[22:03] <slightlyoff> and just in time = )
[22:03] <slightlyoff> ok, thanks again
[22:03] <slightlyoff> later!
[22:03] * slightlyoff (n=alex@204.14.154.182) has left #dojo-meeting
[22:03] <brian_skinner> have a good weekend
[22:03] * brian_skinner (n=brian_sk@adsl-68-122-193-57.dsl.pltn13.pacbell.net) Quit ("Chatzilla 0.9.77 [Firefox 1.5.0.10/2007021601]")

Attachments (0)

  File By Size Attached Ver.