Search code examples
grailsgroovygrails-orm

Can I append a closure to another in Groovy?


I have two very similar methods in Grails, something like "calculate statistics by os" and "calculate statistics by browser" - effectively both prepare some things, then run a similar query on the DB, then do things with the results. The only part where the methods differ is the query they run in the middle of my method -

def summary = c.list {
    eq('browser', Browser.get(1)) // OR eq('os', OS.get(1))
    between('date', dates.start, dates.end)
}

It occurred to me that the ideal way to refactor it would be to pass in the first line of the closure as a method parameter. Like

doStats (Closure query) {
    ...
    def summary = c.list {
        query
        between('date', dates.start, dates.end)
    }
}

I tried this but "query" gets ignored. I tried query() instead but then the query clause is executed where defined, so this doesn't work either. I suppose I could just pass the whole closure as a parameter but that seems wrong - the query might also get more complicated in future.

Anyone have any better ideas?


Solution

  • You're using the criteria DSL which might be different than plain groovy closures.

    To do what you're asking, you can use the method described here -

    http://mrhaki.blogspot.com/2010/06/grails-goodness-refactoring-criteria.html

    and put your query in to private method.

    The more elegant solution for this is to use named queries in grails -

    http://grails.org/doc/latest/ref/Domain%20Classes/namedQueries.html

    Look at the

      recentPublicationsWithBookInTitle {
           // calls to other named queries…
           recentPublications()
           publicationsWithBookInTitle()
      }
    

    example -