Lets say, i have a "Book" class with field "availableOn"(as shown below).
class Book {
String availableOn;
}
The fields holds values
"All days" or
String representation of a date. For example "13/06/2012"
How can i get all Books that are available within next two days? The below code would throw an exception ("java.util.Date cannot be cast to java.lang.String")
def books = c.list(){
between('availableOn', new Date(), new Date() + 2)
}
PS : Am working on a legacy DB, and so am not suppose to change the schema :(
I think there are 2 problems which the between statement will have:
availableOn cannot be converted to a Date for comparison when its value is All days
Even when availableOn has a date value in it, it is not converted to a Date for the comparison
I'd try something along the lines of this:
def now = new Date()
def books = Book.findAllByAvailableNotEqual("All days").findAll { book ->
Date.parse('dd/MM/yyyy', book.availableOn) > now && Date.parse('dd/MM/yyyy', book.availableOn) < now+2
}
Clearly, this can be done in a nicer way (adding some methods to the domain class for example), but this should illustrate my idea...
I don't have a criteria based solution, but you can try something like this:
Book.executeQuery(
"select book from Book book where book.availableOn = :availableOn or to_date(book.availableOn, :format) between (:startDate, :endDate) ",
[availableOn:"All days", format: "dd/MM/yyyy", startDate: startDate, endDate:endDate])
The problem with my solution is that this query becomes DB dependent. to_date is an Oracle function. You may want to alter this to fit your database
You can use format on a date to get desired string format of it.
new Date().format('dd/MM/yyyy')
And your criteria would get modified to
def books = c.list(){
def todayDateStr = new Date().format('dd/MM/yyyy')
def twoDaysAfterTodayDateStr = (new Date()+2).format('dd/MM/yyyy')
or{
between('availableOn', todayDateStr, twoDaysAfterTodayDateStr)
eq 'availableOn', 'All Days'
}
}
Test if the str comparison works, otherwise other ways has to be used. Sending from phone, excuse my typos.
UPDATE
The above would fail in peculiar cases when dates are like "01/01/2013" and "07/11/2011".
Alternatively, you can use sqlRestriction but in that case it gets tightly coupled with the underlying database. Something like this can be done if Oracle db is used:
def books = c.list(){
def todayDateStr = new Date().format('dd/MM/yyyy')
def twoDaysAfterTodayDateStr = (new Date()+2).format('dd/MM/yyyy')
or{
sqlRestriction "to_date(available_on, 'DD/MM/YYYY') between to_date(todayDateStr, 'DD/MM/YYYY') and to_date(twoDaysAfterTodayDateStr, 'DD/MM/YYYY')"
eq 'availableOn', 'All Days'
}
}
Related
This code just displays the values inside the array model.request_reports
To get the most recent, I have to loop through and compare the current
report.updated_at with the last saved report.update_at value. One thing to find
out is what class the update_at field is and how to compare them against each other. The class is ActiveSupport::TimeZone
I need to keep track of the array index of the report that has the most recent updated_at as I loop so that I can access it after the loop.
The problem is, I don't know how to do this:
msg = ""
reports_arr = model.request_reports
reports_arr.each do |report|
updated_at = report.updated_at
if updated_at
msg = msg + "#{updated_at} --- "
msg = msg + "#{updated_at.class}---"
end
end
msg
To add to #meagar comment. You should be using the DB to do sorts on tables.
With that said we need to know what DB you are using as the exact command differs for each.
Mongo w/ Mongoid would be Model.order_by(:updated_at => 'desc').first
My loop had to go through the array and check by greatest date value because in the system Im using, it automatically sorts the reports array by the field "due_at" which is not the reports most recent updated record. Code below works for me.
msg = ""
reports_arr = model.request_reports
last_modified_report = model.last_modified_report
recent = nil
recent_report = nil
reports_arr.each_with_index do |report,index|
updated_at = report.updated_at
if index == 0
recent = updated_at
recent_report = report
end
if updated_at > recent
recent = updated_at
recent_report = report
end
last_modified_report = recent_report
end
msg = msg + "#{recent}---"
msg = msg + "#{recent_report}---"
msg = msg + "#{last_modified_report}"
model.last_modified_report = last_modified_report
model.save(validate: false)
msg
The OP's answer is only good if you absolutely cannot query the database for the info you want directly. I assume you only want the index so you can find the most recent one?
Even if automatic sorting is on one column, your query for the data can have it sorted on a different column.
model.request_reports.order_by(:updated_at => 'desc').first
If you have a default scope that's messing with your query, you can ask for an unscoped list, although I doubt a default ordering would cause any trouble.
model.unscoped.order_by(:updated_at => 'desc').first
You can string together queries that are already written: that can be useful even if request_reports is a query or scope you have somewhere.
It will be way less expensive than getting everything, and looping through it - you are always better off finding a way to get just the info you need in a db query if you can.
My controller action is
def jasper () {
def emp = Employee.findAll()
chain(controller:'jasper', action:'index', model:[data:emp],params:params)
}
and in my jrxml file i have following fields: name, lastname, gender, phone
I want to write a query that would have data only of name and lastname but with same jrxml file then my action would be
def jasper () {
def emp = Employee.executeQuery("select a.name a.lastname from Employee a ")
chain(controller:'jasper', action:'index', model:[data:emp],params:params)
}
This do not print only name and lastname in my report rather gives NoSuchMethodException. How to do this?
I don't think that the second query result could be a replacement of the first since the structure of the result is completely different.
In the first case you will get a List<Employee>, while in the second case you get an List<Object[]>.
You could rework your Jasper report to expect List<Object[]> and use select a.name, a.lastname, a.gender, a.phone from Employee a for the first scenario. In this case, you could safeguard the report agains the possible null values so that the report works well with the second, more limited result set.
I need to translate a message key using a Hashmap using the Grails standard internationalization method.
I receive an Enum and a map with the binding, which are going to be replaced in the text.
The Enum indicates, which key is going to be recovered. The bindings have the values to replace on the translation.
messageSource.getMessage("mail.layout.subject.${templateName}",ARGS,"",locale)
The problem is that I need to pass the map to the args like an array, not like a map, but I don't know the order of the args.
My question is, if there are any ways to create a tranlation key like:
mail.layout.subject.ENUM1=Blablabl {name} bablablabl {age}
Instead of
mail.layout.subject.ENUM1=Blablabl {0} bablablabl {1}
Finally I did it with brute force. May be is not the best answer but I coudln't find any one better.
Basically I get the translation with te message resources and then I work with it finding my custom expresions.
def messageSource = grailsApplication.getMainContext().getBean('messageSource')
def subject = messageSource.getMessage("mail.layout.subject.NOTIFICATION",null,"",locale)
An example of subject resource
mail.layout.subject.NOTIFICATION=The user {friend.name} is friend of {user}
An example bindings:
def bindings = [friend:[name:"Jhon",surname:"Smith"],user:"David"]
With this senteces I replace my expresions with the value of the bindings
Pattern pattern = Pattern.compile("\\{[^}]+\\}")
def res = subject.replaceAll(pattern,{
def expresion = it[1..it.size()-2] // removes brackets
def fields = expresion.split("\\.");
def res = bindings
fields.each{
println(it)
res = res."${it}"
}
return res
})
After the proces the subject becomes like: "The user Jhon is friend of David"
The example use a HashMap of HashMaps, but it also works with object because grails/groovy handles the object like HashMaps and viceversa
This is much cleaner. :)
import groovy.text.SimpleTemplateEngine
def text = 'Dear "$firstname $lastname",So nice to meet you in ${city.name}.See you in ${month},${signed}'
def binding = ["firstname":"Sam", "lastname":"Pullara", "city":["name":"San Francisco", "id":"28"], "month":"December", "signed":"Groovy-Dev"]
def engine = new SimpleTemplateEngine()
template = engine.createTemplate(text).make(binding)
I noticed that invoking service method with simple select makes MyDomain.class Date field update in DB (clears time). However enclosing the method with #Transactional(readOnly = true) doesn't update the date value.
Why the value is saved into DB?
Here is the service method
#Transactional(readOnly = true)
Date getDate()
{
Date date = null
date = MyDomain.executeQuery("select min(s.startDate) from MyDomain s where ....)[0]
print "Result: " + date
}
The object will only get updated in the database if it is somehow changed after it brought into the hibernate session (selected) and before the the session is closed (usually at the end of the method). Take a look at your object, and see how it might be modified in some way that you did not intend.
I have a database table TableA, which has a column 'theDate' for which the datatype in the database is DATE.
When I save a java.util.Date to 'theDate' through GORM it appears to save just the date value when I look at the data in the table by just executing select * from TableA.
However, when I run a query such as:
select * from TableA where theDate = :myDate
No results are found, but if I run something like;
select * from TableA where theDate <= :myDate
I do get results.
So it's like the Time is relevant.
My question is how do I save a Date and query for a Date ignoring the Time completely and just matching on an exact Date only?
Thanks.
note: I have also tried using sql.Date and util.Calendar but to no success.
clearTime()
You can use clearTime() before saving and before comparing to zero out the time fields:
// zero the time when saving
new MyDomain(theDate: new Date().clearTime()).save()
// zero the target time before comparing
def now = new Date().clearTime()
MyDomain.findAll('SELECT * FROM MyDomain WHERE theDate = :myDate', [myDate: now])
joda-time plugin
An alternative would be to install the joda-time plugin and use the LocalDate type (which only holds date information, no times) instead of Date. For what it's worth, I don't think I've worked on a project with dates without using the Joda plugin. It's completely worth it.
If you have date saved without clearing you could retrieve it using range, as Jordan H. wrote but in more simple way.
def getResults(Date date) {
def from = date.clearTime()
def to = from + 1
def results = MyDomain.findAll("from MyDomain where dateCreated between :start and :stop" ,[start:from,stop:to])
}
Your question may be a duplicate. See Convert datetime in to date. But if anyone has more recent information, that would be great.
If that doesn't help, you can hack it the way I might, with a BETWEEN restriction, e.g.
def today = new Date()
def ymdFmt = new java.text.SimpleDateFormat("yyyy-MM-dd")
def dateYmd = ymdFmt.format(today)
def dateTimeFormat = new java.text.SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
def startDate = dateTimeFormat.parse("${dateYmd} 00:00:00");
def endDate = dateTimeFormat.parse("${dateYmd} 23:59:59");
MyDomain.findAll("from MyDomain where dateCreated between ? and ?", [startDate, endDate])
It's definitely not pretty, but it may get you where you're going.
I figured it out.
I used DateGroovyMethods.clearTime to clear the time value before saving.
You can use the DB type date not datetime , in the filed type