Is it possible to add 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” - it’s effective to prepare some things and run a similar query in the database, and then do something with the results. The only part where the methods differ is the request that 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 would be to go to the first line of closure as a method parameter. how

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

I tried this, but the "request" is ignored. I tried query (), but then the query sentence is executed where defined, so this does not work either. I suppose I could just pass the whole closure as a parameter, but that seems wrong - the request may also get complicated in the future.

Anyone have any better ideas?

+4
source share
3 answers

You use DSL criteria, which may differ from normal groovy closures.

To do what you ask, you can use the method described here -

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

and put your request in a private method.

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

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

Look at

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

example -

+3
source

Not sure about building Grails Criteria, but with other builders you can do something like:

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

And call it through:

 def f = { criteria -> criteria.eq( 'browser', Browser.get( 1 ) ) } doStats( f ) 

If not, you are probably best looking at named queries as tomas says

+2
source

I found the leftShift statement useful for creating a closure from two separate ones. What you can do is:

 Closure a = { /*...*/ } Closure b = { /*...*/ } Closure c = a << b 

Take a look at this example:

 def criteria = { projection Projections.distinct(Projections.property('id')) and { eq 'owner.id', userDetails.id if (filter.groupId) { eq 'group.id', filter.groupId } } } List<Long> ids = Contact.createCriteria().list(criteria << { maxResults filter.max firstResult filter.offset }) Integer totalCount = Contact.createCriteria().count(criteria) 

Here you can see that I am creating criteria to enumerate ant counting GORM objects. The criterion for both cases is almost the same, but for listing purposes I also need to include the restriction and offset from the command object.

+2
source

Source: https://habr.com/ru/post/1335842/


All Articles