Skip to content

Instantly share code, notes, and snippets.

@lancejpollard
Created April 30, 2012 14:34
Show Gist options
  • Select an option

  • Save lancejpollard/2558833 to your computer and use it in GitHub Desktop.

Select an option

Save lancejpollard/2558833 to your computer and use it in GitHub Desktop.
Tower.js Discussion - What should App.User.all() return?

Since querying a model requires a callback, you normally write it like this:

App.User.where(email: /^[aA]/).all (error, users) =>
  for user in users
    # ...

That's fine, since it's async. But in the console, and on the client for "bindable collections" or "bindable scopes", you don't really want to be using the callback approach. In the console, it'd be much easier if it just auto-logged the result using some global callback handler. And Ember.js {{#each}} blocks are dynamic, so it will just be updated whenever an item is added to a collection.

So, the question is, what should the following return:

result = App.User.where(email: /^[aA]/).all()
  1. Tower.Model.Scope
  2. Tower.Model.Cursor
  3. Array

I am going with Tower.Model.Cursor. Tower.Model.Scope is just an "api layer" to the cursor, but the cursor does all the dirty work for actually querying/modifying the dataset. So, it seems like the best candidate for Ember.js: you just add a record to the matching cursor (test cursor's query criteria against the model) and views will update. An array could also work, but it would be blank [] in mongodb, until an instant later once it is populated.

Also, what should the first and last scopes return?

first = App.User.where(email: /^[aA]/).first()
last  = App.User.where(email: /^[aA]/).last()

Imagine this... On your homepage you have a "featured product" or "top deal" or something. There's only one. So the logical thing to do is bind it to App.Product.where(featured: true).desc('createdAt').first() or something. But what happens when you add a new featured product? The new one should replace the old one automatically.

One approach is to have first and last return a Tower.Model "proxy" or something. This way you can replace it's record property with a new one. But this starts to look like a Tower.Model.Cursor with limit: 1. So, I think this should also return a cursor.

Again, all of these methods will have the callback signature (error, record[s]), but what it returns is different, tailored for Ember and the console/debugging.

What are your thoughts?

@contentfree
Copy link

Intuitively, returning an enumerable collection of Users from all() makes sense. And returning an actual User from first()/last() makes the most sense to me. Yeah, I get that this is async... but it's truly a hassle. Same if you had @user.company (@user.get('company')?) … I expect a Company in return …

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment