Grails Plugin Searchable - default wildcard search - grails

Is there a way to automatically wrap all searches with a wildcard?
e.g.:
Book.search("*${params.q}*", params)

I'm not familiar with .search (are you using a plugin?). However, for a wildcard search in models, I typically create a method inside the domain model class. In your example,
In the Book model class:
class Book {
String title
String author
int year
static List wildSearch(par, val) {
def foundList = this.executeQuery("select b FROM Book b WHERE ${par} like \'%${val}%\'")
return foundList
}
}
In your controller:
def searchBook = {
def b1 = new Book(title: "Farewell To Arms", author: "Ernest Hemingway").save()
def b2 = new Book(title: "The Brother's Karamazov", author: "Anton Chekov").save()
def b3 = new Book(title: "Brothers in Arms", author: "Cherry Dalton").save()
// If you search for "Arms", This returns b1 and b3
def found = Book.wildSearch("title", params.title)
}
Example URL:
http://localhost:8080/mytest/mycontroller/searchBooks?title=Arms

Related

Grails GORM : SELECT AS

I'm trying to get all the Users that are born today with GORM but I'm failing to write this query in Grails:
SELECT
DAY(dateOfBirth) AS 'day',
MONTH(dateOfBirth) AS 'month'
FROM Users
WHERE day = '...' AND month = '...';
... will be replaced with today's values.
Minimal User Domain class
class User {
Date dateOfBirth
...
}
Minimal UserService class
#Transactional
class UserService {
def getTodayBirthdays() {
def bornTodayQuery = User.where{
/* I'm thinking here I must
* select the DAY and MONTH from the DB
* and compare it with the today ones.
*/
}
User usersBornToday = bornTodayQuery.findAll()
usersBornToday
}
}
Any ideas how can I do an alias (SELECT field AS alias) with GORM?
I'm using:
Grails 2.4.4
Thanks!
You could use a where query in your service:
#Transactional(readOnly = true)
def listBirthday(int _month, int _day) {
// Calendar.JANUARY equals to zero!
def m = _month + 1
// Run a where query on the users
User.where {
month(dateOfBirth) == m && day(dateOfBirth) == _day
}
}
#Transactional(readOnly = true)
def listBirthdayToday() {
def cal = Calendar.getInstance()
listBirthday(cal.get(cal.MONTH), cal.get(cal.DAY_OF_MONTH))
}
In addition to month and day there are some other functions, here is the documentation (look for "Other Functions")
Any ideas how can I do an alias (SELECT field AS alias) with GORM?
(SELECT field AS _alias)
Putting an underscore (_) as prefix to alias worked for me with grails-2.5.6
I have not found it in documentation but using trail and error method.

Why does overriding putAt result in MissingPropertyException?

I've been trying to take advantage of operator overloading in Groovy by defining a custom putAt method in my POGO like this:
class Book {
Map additionalInfo = [:]
def putAt(key, value) {
additionalInfo[key] = value
}
}
So that I can do something like, book['notes'] = 'I like this one.' (let's say this makes sense). However, I've been getting:
groovy.lang.MissingPropertyException: No such property: notes for class: Book
at BookSpec.Set property using putAt(BookSpec.groovy:40)
My class is part of a Grails application so I'm not sure if Grails has something to do with the problem. Can anyone enlighten me on this?
The signature should be
def putAt(String key, value)
Instead of doing putAt and then override the operator, there is an easy/better way by adding the propertyMissing methods.
Here is the link for more explanation.
class Foo {
def storage = [:]
def propertyMissing(String name, value) { storage[name] = value }
def propertyMissing(String name) { storage[name] }
}
def f = new Foo()
f.foo = "bar"
assertEquals "bar", f.foo

How can I get a set of field values in groovy?

class Book {
String title
}
def book = new Book(title: 'title1')
def book = new Book(title: 'title2')
def book = new Book(title: 'title3')
How can I get the set of titles? Something like titleSet = ['title1', 'title2', 'title3']
I thought maybe something like def titleSet = Book.findTitles(); would work but I can't find anything like that.
I know I could do:
def books = Book.list()
def titleSet
for(def book : books)
titleSet.add(book.title)
But I'm looking for a groovier way.
This goes through all the books for their title and creates a Set instead of a List.
Book.all.title as Set
UPDATE
The above will fetch all Book instances which might be heavy if you only need title. You can also try using criteria or HQL to get only list of titles.
def titleSet = Book.createCriteria().listDistinct {
projections {
property('title')
}
}
Try
Set titleSet = books*.title
Or
Set titleSet = books.collect { it.title }

Dynamic namedQueries

Is their a dynamic namedquery on grails? Im not sure if its the right term but, I mean a namedquery that can be true to all.
Something like:
namedQueries = {
dynamicQuery{ term, name, value ->
term(name, value)
}
}
Then it can be called maybe like but not exactly:
def testClass = TestClass.dynamicQuery('eq', 'lastname', 'Bill').list()
and so you call it too like:
def testClass = TestClass.dynamicQuery('gt', 'id', 12).list()
This one might not work but is their something similar in grails?
UPDATE
The idea is that so I can chained it as many as I want like:
def testClass = TestClass.dynamicQuery('gt', 'id', 12).dynamicQuery('eq', 'stat', 11).list()
This is so that I dont have to create many namedqueries. I was hoping I can create one and use it multiple times.
Grails' createCriteria method generates Grails HibernateCriteriaBuilder instance, within which you can call invokeMethod method to dynamically create query criteria, which usually is defined by the standard DSL.
Here is a example in some controller:
private String dynamicCriteriaTest(String term, name, value) {
def c = TestClass.createCriteria()
def param = []
param << name
param << value
def result = c.list{
c.invokeMethod(term, param as Object[])
}
return result.toString()
}
def test() {
render dynamicCriteriaTest('eq','lastname','Bill')
}
That will get something you want.
update
If you want to call this method multiple times, pass the criteria parameters in an a List then execute the query:
private List dynamicCriteriaTest(List param) {
def c = TestClass.createCriteria()
def paramList = param.collate(3) //split the parameters into groups
def result = c.list{
paramList.each { paramInstance ->
def command = paramInstance[0]
paramInstance.remove(0)
c.invokeMethod(command, paramInstance as Object[])
}
}
return result
}
def test() {
ArrayList param = new ArrayList()
//the 1st criteria
param << 'gt'
param << 'id'
param << (long)12 //you have to check the Grails [HibernateCriteriaBuilder] API to make sure the parameter passed to `invokeMethod` is in the right type (e.g. **long** in this case)
//the 2nd one
param << 'eq'
param << 'stat'
param << (long)11
//even more
param << 'like'
param << 'description'
param << 'some text%'
render dynamicCriteriaTest(param)
}
In Grails you have NamedQueries and also Where Queries. The example you give can possibly be implemented by using a namedqueries and placing this in a abstract domain class. Your domain classes should extend this abstract domain.

Grails error: No such property: it for class:

Below is my code.
Here I am getting an error which is 'No such property: it for class: emp.EmployeeController'.
I think I am doing something wrong here.
Any advice??
def list ={
def id=params.id
def results
String employee="SELECT empName, empDate, empNo from employee where empId='id'"
String referrer="SELECT empName, empDate, empNo from referer where empId='id'"
def employeeInstanceList = new ArrayList<Employee>()
Sql sql = new Sql(dataSource)
def joining=null
joining = sql.rows( "select joining from employee_dates")
if (joining!=null)
results = sql.eachRow(employee)
employeeInstanceList=getCalculatedEmployeeData(results)
/*{
def employee = new Employee()
employee.setempName it.empName
employee.setEmpNo it.empNo
employee.setEmpDate it.EmpDate
employeeInstanceList.add employee
}*/
else
results = sql.rows (currentDaySql)
employeeInstanceList=getCalculatedEmployeeData(results)
/*{
def employee = new Employee()
employee.setempName it.empName
employee.setEmpNo it.empNo
employee.setEmpDate it.EmpDate
employeeInstanceList.add employee }*/
}
[employeeInstanceList: [employeeInstanceList: employeeInstanceTotal: Employee.count()]
}
def getCalculatedImpactData(def results){
def employee = new Employee()
employee.setempName it.empName
employee.setEmpNo it.empNo
employee.setEmpDate it.EmpDate
employeeInstanceList.add employee }*/
return [employeeInstanceList: employeeInstanceList]
}
Thanks,
Meghana
i would second leebutts answer... but just a pointer, the usage of the it keyword is usually confined to closures... so instead of doing this in java:
List l = [];
for (Iterator i = l.iterator(); i.hasNext(); ) {
...do something adressing List l at position i...
}
you could do this in groovy / grails:
list.each { it ->
...do something with each object in the list (it)...
}
but you should really read up on groovy closures at http://groovy.codehaus.org/Closures
There is so much wrong with that code, I don't know where to start...
But to avoid getting more down votes I have tried :)
I tried to copy your code into an IDE and try and work out what you are trying to achieve but couldn't.
This is as close as I could get it:
def list = {
def id = parmas.id
def results
String employee = "SELECT empName, empDate, empNo from employe"
def employeeInstanceList
Sql sql = new Sql(dataSource)
def joining = sql.rows("select joining from employee_dates")
if (joining != null) {
results = sql.eachRow(employee)
employeeInstanceList = getCalculatedEmployeeData(results)
}
else {
results = sql.rows(currentDaySql)
employeeInstanceList = getCalculatedEmployeeData(results)
}
[employeeInstanceList: employeeInstanceList, employeeInstanceTotal: Employee.count()]
}
def getCalculatedImpactData(def results) {
def employeeInstanceList = new ArrayList<Employee>()
results.each { it ->
def employee = new Employee()
employee.empName = it.empName
employee.empNo = it.empNo
employee.empDate = it.EmpDate
employeeInstanceList.add(employee)
}
return employeeInstanceList
}
but it is still referring to a variable currentDaySql which doesn't exist and I'm not sure what you're trying to do with the 'joining' result.
You really need to read up on Groovy basics.
The block of code where the error occurs is probably:
def getCalculatedImpactData(def results){
def employee = new Employee()
employee.setempName it.empName
employee.setEmpNo it.empNo
employee.setEmpDate it.EmpDate
employeeInstanceList.add employee
return [employeeInstanceList: employeeInstanceList]
}
it is not defined anywhere (hint: the compilation error told you this). Like Sebastian said, it is typically used in closures; what you've defined here is a function. Presumably you wanted to use results (or something) instead of it here.
I'm assuming that some of the things in your code (e.g. comment opening/closing) weren't in there and were added between when you saw the error and when you posted the code. Otherwise you'd get other errors.

Resources