Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically creating a query based on params being passed to a controller

In my task management application, users should be able to filter tasks based on : assignedTo, priority, status and/or dueDate

I am not sure on how to create a dynamic query in that it will build a query based on the available parameters.

For example :

If I have a URL such as : task/index?assignedTo=1&status=2

I can build a query based on only these two parameters. The method I am used to is the

Task.findAllByAssignedToAndStatus(
   User.get(params.assignedTo),
   TaskStatus.get(params.status)
)

I obviously dont want to implement a DRY method by writing out each findAllBy query for every possible URL parameter combination.

Is there a good way to do this in grails?

like image 361
andy mccullough Avatar asked Apr 11 '13 11:04

andy mccullough


3 Answers

We have implemented filter functionality on the domain classes to do this. In short you add small snippets of namedQueries to your domain class.

Example:

class Employee {

    String firstname
    String lastname
    Integer age

    static constraints = {
    }

    static namedQueries = {
        filteronFirstname { String inFirstname ->
            if (inFirstname&& inFirstname?.size() > 0) {
                ilike 'firstname', "%${inFirstname}%"
            }
        }

        filteronLastname { String inLastname ->
            if (inLastname && inLastname?.size() > 0) {
                ilike 'lastname', "%${inLastname}%"
            }
        }

        filteronAgeOlderThen { String ageOlderThen ->
            if (age && age ?.size() > 0) {
                gt 'age', ageOlderThen as Integer
            }
        }

    }
}

This enable fine grained filter capabilities so you can build 1 list method that uses all filter methods and depending on what the user gives as input the namedqueries are joined together.

Employee.filteronFirstname("John").
filterOnLastname("Doe").
filteronAgeOlderThen("10").
list(params)
like image 91
Marco Avatar answered Oct 13 '22 00:10

Marco


I managed to get this working using createCriteria as follows :

I am using the value 0 for any of the params if the user selects 'All' for that particular filter, therefore it will be omitted from the where clause, ie no eq() statement for that parameter.

A snippet of the code:

else
    {       
        def assignedTo = Integer.parseInt(taskParams.assignedTo)
        def priority = Integer.parseInt(taskParams.priority)
        def status = Integer.parseInt(taskParams.status)

        tasks = Task.createCriteria().list {            

            eq("project", Project.get(taskParams.PId))

            if(assignedTo > 0)
                eq("assignedTo", User.get(assignedTo))

            if(priority > 0)
                eq("priority", TaskPriority.get(priority))

            if(status > 0)
                eq("status", TaskStatus.get(status))                
        }           
    }
    return tasks
}
like image 24
andy mccullough Avatar answered Oct 12 '22 23:10

andy mccullough


I would consider the Searchable Plugin for this (http://grails.org/plugin/searchable). It is easy to specify which properties of Task should be searchable.

like image 29
zoran119 Avatar answered Oct 13 '22 00:10

zoran119