Sunday, March 28, 2010

Implementing findWhere() and findAllWhere() in ColdMVC

I posted this on the ColdMVC Google Group, but since the group isn't very active yet, I figured I'd post it here too for more visibility. Basically I'm looking for some feedback on implementing the findWhere() and findAllWhere() methods inside ColdMVC. For convenience sake, here's the post from the Google Group:

I haven't fully implemented the findWhere() and findAllWhere() methods for models because I haven't yet decided how it should be done in all circumstances. In Grails, it looks like this:

def book = Book.findWhere(title:"The Shining", author:"Stephen King")

This is easy enough to convert to ColdFusion, but I see 2 possible ways of achieving the same thing.

Option 1: Pass in multiple arguments, with each argument being a property on the model.

params.book = _Book.findWhere(title="The Shining", author="Stephen King");

Option 2: Pass in a single struct argument, with each key in the struct being a property on the model.

params.book = _Book.findWhere({title="The Shining", author="Stephen King"});

I think the first option more closely resembles Grails, which is nice. Plus it's a little cleaner. However, I think I prefer option 2 more when you start adding paging parameters (offset, max, sort, order) to findAllWhere(). For example:

params.books = _Book.findAllWhere({author="Stephen King"}, {max="10", sort="datePublished", order="desc"});

Having the constraint of only accepting 1 or 2 arguments would greatly simplify the code that generates the HQL, plus you no longer have to worry about naming conflicts between paging paramaters and model properties.

Also, I'd like some opinions on how to handle various operators (like, startsWith, endsWith, etc...). In Grails, you can use closures to generate the HQL like such:

def books = Book.createCriteria().list(max: 5, offset: 10) {
like("title","foo%")
}

Since closures aren't available in ColdFusion (yet), we need to figure out our own syntax. I think the most natural way of handling operators would be to make them available to the findWhere() and findAllWhere() methods. Here are a couple ways I see this working:

Option 1: Use an array where the first item is the operator and the second item is the value.

params.books = _Book.findAllWhere({
title = [ "like", "foo" ]
}, {
max="5",
offset="10"
});

Option 2: Use a struct with operator and value keys.

params.books = _Book.findAllWhere({
title = { operator="like", value="foo" }
}, {
max="5",
offset="10"
});

Option 3: Use a struct where the key is the operator and the value is... the value.

params.books = _Book.findAllWhere({
title = { like="foo" }
}, {
max="5",
offset="10"
});

I don't think any of the options would be that hard to implement, so it's really a matter of preference. I think right now I'm leaning towards option 1, although I wouldn't be against the other options either.

Any thoughts or comments are appreciated.

Also, here's a Grails reference if you're interested:
http://www.grails.org/DomainClass+Dynamic+Methods

2 comments:

Note: Only a member of this blog may post a comment.