How to create conditional query in grails « Intelligrape Groovy & Grails Blogs

Posts Tagged ‘ How to create conditional query in grails ’

Grails Data Binding & criteria reuse

Posted by on July 1st, 2011

Data Binding in grails is something that I love alot. In most of the cases we look at the Binding with respect to some domain class but binding can be one of the best candidate for searching and filtration.
In my recent project we had a domain Class Article and the user could filter articles on different criteria. The page looks something like following

We had 3-4 such pages but with some extra states (Enum property) of article. So for doing this we created two CO classes, one for basic search properties like max, offset, order and sort and other for article related fields. So the CO goes like following

class SearchCO {
  Integer max = 10
  Integer offset = 0
  String sort = "id"
  String order = "asc"

  def searchCriteria = {
    order(sort, order)
  }
}

class ArticleSearchCO extends SearchCO {
  List<ArticleType> types  // This is Enum
  List<Long> styleIds
  List<Long> categoryIds
  String topic
  def searchCriteria = {
     and {
      if (topic) {
        ilike("topic", "%${topic}%")
      }

      if (categoryIds) {
        subCategory {
              inList("id", categoryIds)
          }
      }

      if (styleIds) {
        writingStyle {
             inList("id", styleIds)
         }
      }

      if (types) {
            inList("type", types)
        }
    }
    super.searchCriteria
  }
}

In our controller side we got the fully populated object that can be used for searching the different articles based on searching. So our controller side code was something like

def findWork = {ArticleSearchCO co ->
    List<Article> articles = authorService.findWork(co)
    render(template:"articles",model:[articles:articles,totalCount:articles.totalCount])
}

def currentWork = {ArticleSearchCO co ->
    List<Article> articles = authorService.currentWork(co)
    render(template:"articles",model:[articles:articles,totalCount:articles.totalCount])
}

As I already have the searching closures in my CO so the code in my service was something like

public List<Article> findWork(ArticleSearchCO co) {
    def articleCriteria = Article.createCriteria()
    Closure searchCriteria = co.searchCriteria
    searchCriteria.delegate = articleCriteria
    List<Article> articles = articleCriteria.list([max: co.max, offset: co.offset]) {
      eq("status", ArticleStatus.Unassigned)
      searchCriteria()
    }
    return articles
  }

In the same way for currentWork method I just changed the status i.e; ArticleStatus.InProgress. Thats how I handled the searching, filtering, pagination which was all Ajax. I tried to make my code as DRY as possible . There are still few things that I dont like about it one is so many if statements and other is delegating the searching criteria in each method. I think now with the support of namedQuery I can optimize the method.

Hope it helps
Uday Pratap Singh
uday@intelligrape.com
https://twitter.com/meudaypratap
http://in.linkedin.com/in/meudaypratap