I have a list that need to be sorted by 3 different fields. If it were a query I could do something like:
and {
invoiceTicketDetail {
order('date', 'asc')
order('xrefCode', 'asc')
}
order('lineType')
}
But I already have the list like the following:
List<InvoiceDetail> invoiceDetailList = invoiceHeader.invoiceDetails.findAll {it.deleted==Boolean.FALSE && it.amount!=0} as List
How can I order to get the same result from the first one? The thing is we have two different ways to display the information. One to print on screen and one to generate a report. Both of them must show the information in the same sort.
You can do like this in your criteria:
{
order('date,xrefCode,lineType','asc')
}
or write query:
Clazz.find("from Clazz order by date,xrefCode,lineType asc")
Clazz is your domain
You can sort by multiple conditions (fields, properties, etc) by...
Comparing the first property
If the first property comparison results in 0 (which means they're equal) continue to the next property. Otherwise, consider the two items sorted.
Here's a closure that can be curry'ed with a list of property names and then passed to Iterable.sort(boolean, Closure) or Iterable.toSorted(Closure).
def sortByProperties = { List propertyNames, Object a, Object b ->
propertyNames
.collect { a[it] <=> b[it] }
.find { it != 0 }
}
Example
Here's how to use the closure.
def date1 = new Date() + 3
def date2 = new Date() - 2
def list = [
[date: date1, xrefCode: 2, lineType: 'b'],
[date: date2, xrefCode: 2, lineType: 'c'],
[date: date2, xrefCode: 1, lineType: 'c'],
[date: date1, xrefCode: 2, lineType: 'a']
]
def sortByProperties = { List propertyNames, Object a, Object b ->
propertyNames
.collect { a[it] <=> b[it] }
.find { it != 0 }
}
// This form requires Groovy >= 2.4
def sortedList = list.toSorted(sortByProperties.curry(['date', 'xrefCode', 'lineType']))
// An alternative.
def sortedList = list.sort(false, sortByProperties.curry(['date', 'xrefCode', 'lineType']))
The output looks like this.
[
[date:Tue Oct 06 20:13:13 EDT 2015, xrefCode:1, lineType:c],
[date:Tue Oct 06 20:13:13 EDT 2015, xrefCode:2, lineType:c],
[date:Sun Oct 11 20:13:13 EDT 2015, xrefCode:2, lineType:a],
[date:Sun Oct 11 20:13:13 EDT 2015, xrefCode:2, lineType:b]
]
Well,
What I've done to solve this problem:
Created my own comparator and when I got the list I called something like:
Collections.sort(list, new MyComparator());
Before displaying in the screen and before generating the report.
That solved my problem.
Related
In my jenkins job, I have a choice parameter containing 4 values (val1, val2, val3, val4).
Is it possible to set dynamically the choice parameter value based on a recurrent temporal event?
More precisely, I would like to change dynamically this value every Monday of the year.
For example:
Monday March 16 => it takes val1
Monday March 23 => it takes val2
Monday March 30 => it takes val3
Monday April 6 => it takes val4
Monday April 13 => it takes val1
and so on.
So, your question basically boils down to two:
How can I programmatically determine which value to select, based on current date?
Having that figured out, how can I cause that value to be the default in the choice parameter of the pipeline?
Considering you're doing fine by yourself with #1 (may include getting the week number and taking the remainder of that divided by 4), let's tackle the second question.
To modify the choices parameter based on the result of some arbitrary Groovy script, you may want to run a scripted pipeline before your declarative one, something like this:
def use_as_default = getValToUseAsDefault() // val1 on March 16, etc.
def list_of_vals = []
list_of_vals += use_as_default // first in the list will get to be selected
if (! ("val1" in list_of_vals) ) { list_of_vals += "val1"}
if (! ("val2" in list_of_vals) ) { list_of_vals += "val2"}
if (! ("val3" in list_of_vals) ) { list_of_vals += "val3"}
if (! ("val4" in list_of_vals) ) { list_of_vals += "val4"}
list_of_vals = Arrays.asList(list_of_vals)
pipeline
{
agent any
parameters
{
choice(name: 'VALS', choices: list_of_vals, description: 'Choose value')
}
...
}
def getValToUseAsDefault() {
// left as exercise to OP
return "val1"
}
I am working on news function. News model contains publishing date....
Is there a way to filter my record from db on the base of Publishing Date's day name such as in controller action:
var data1 = db.News.Where(x => x.PublishingDate >= DateTime.Now
&& x.PublishingDate.Day == (int)DayOfWeek.Sunday);
ViewBag.SundayNews = data1;
Or if there is another way around or any reference.
Try this solution: http://c-sharp-snippets.blogspot.ru/2011/12/getting-dayofweek-in-linq-to-entities.html
var firstSunday = new DateTime(1753, 1, 7);
var filtered = from e in dbContext.Entities
where EntityFunctions.DiffDays(firstSunday, e.SomeDate) % 7 == (int)DayOfWeek.Monday
select e;
firstSunday stores the minimal value for MS SQL DATETIME type.
I need a way to find these in grails:
1) I have two dates say start and end.
2) User selects two dates in the browser say them userStartDate and userEndDate.
I have all these values, but I need to write a query that do find that both start and end falls between userStartDate and userEndDate.
For example, March 2nd and March 3rd falls between March 1st and March 4th. Given that :
March 2nd and March 3rd are userStartDate and userEndDate dates respectively
March 1st and March 4th are start and end respectively. (they are domain objects).
I have this code which works for between cases i.e start is in between userStartDate and userEndDate like so :
test = Holiday.createCriteria().list {
and {
user {
eq('username',username)
}
or {
between('start',userStartDate,userEndDate)
between('end',userStartDate,userEndDate)
}
}
}
As according to my question, how can attach that part into my code?
Thanks in advance.
Assuming that you already do a check that userStartDate is before userEndDate (validated when the user selects) and that start is before end in the database (validated when inserting), the criteria query should look something like this:
test = Holiday.createCriteria().list {
user { eq('username',username) }
lt('start', userStartDate)
gt('end', userEndDate)
}
This checks that start is less than (i.e. before) userStartDate and that end is greater than (i.e. after) userEndDate. There is also no need to wrap in an and block since all clauses are implicitly and-ed.
Date provides before and after methods (http://docs.oracle.com/javase/6/docs/api/)
if(start.after(userStartDate) && start.before(userEndDate))
{
//start is between userStartDate && userEndDate
}
The simplest way to figure out if one date is between two others is using a Range object
def start = new Date()
def end = new Date() + 10
// make a date range
def dateRange = start..end
// test if some dates are within the range
def inRange = new Date() + 5
def outsideRange = new Date() + 50
assert inRange in dateRange
assert !(outsideRange in dateRange)
However, you mentioned that you want to compare dates in a query, so a Groovy solution may not be optimal. Here's an example for checking if someone's birthday is between 2 dates using a criteria query
def start = new Date()
def end = new Date() + 10
def results = User.withCriteria {
between('birthday', start, end)
}
I'm new to Grails development.
I have a domain class like this :
class DaySchedule {
Date Todaysdate
String startTime;
String endTime;
String task
int priority
boolean completed
static belongsTo = [ schedule : Schedule ]
}
I have bootstrapped with some test data's. Now I want to do a query, with following condition :
I need to pick each task (which are stored in bootstrap.groovy) which are belongs to a particularTodaysdate.
For example if I have these statements in my BootStrap.groovy :
//other codes
def daySchedule3 = new DaySchedule(Todaysdate:new Date(),
startTime:"6pm",endTime:"10pm",
task:"ReaD git...",completed:false)
def daySchedule4 = new DaySchedule(Todaysdate:new Date()+1,
startTime:"10am",endTime:"12pm",
task:"Read MySQL....",completed:false)
Now clearly the task, ReaD git... belongs to a day (which is today as I have passed new Date() into it).
To find these I came up with a partial solution like this:
def allTasks = DaySchedule.findAllByTaskIsNotNull()
def dates = allTasks.collect { it.Todaysdate }
def tasks = dates.collect {
def queryParameter = new DaySchedule(Todaysdate:it)
def todaysWork = DaySchedule.findAll(queryParameter)
todaysWork.task
}
I have a problem with this code. I couldn't use collectEntries method on the dates and tasks so that I convert it into map of a particular date(i.e dates) with values as tasks. (which is what I tried for!)
Now I'm left lone. I couldn't not able to find a way to guess for which dates the tasks belongs to.
Any other solutions for it?
Thanks in advance.
It sounds like you're trying to get a map with a key of the date, and a value of the task name, for all of the domain objects DaySchedule. You may want to try Collection.groupBy. For example:
def allTasks = DaySchedule.findAllByTaskIsNotNull()
def tasksByDate = [:] // start with empty map
tasksByDate.putAll(
allTasks.groupBy { task ->
// group by just the date portion, ignoring time
// clone since clearTime modifies original
task.todaysDate.clone().clearTime()
}.collect { date, daySchedule ->
// change from map of date -> daySchedule to map of date -> task
[date, daySchedule.task] as MapEntry
}
)
I think you have a design problem somewhere... it would be easier to have something like :
class Task {
Date startTime;
Date endTime;
String description
int priority
boolean completed
static belongsTo = [ schedule : Schedule ]
String toString() {
return "${description} : from ${startTime} to ${endTime}"
}
}
Then, you can list all the dates for which you have tasks in them like this :
java.text.DateFormat df = java.text.DateFormat.getDateInstance(DateFormat.LONG, Locale.US);
def days = Task.list().collect {
df.format(it.startTime);
}.unique()
So now the "days" variable contains an array of strings of unique days present in your database with tasks associated.
If you want to list the tasks by day, you can then do :
days.each { dayString ->
def date = df.parse(dayString)
def dayTasks = Task.findAllByStartTimeBetween(date, date+1)
println "Tasks for ${dayString}"
dayTasks.each {
println " - ${it}"
}
}
I have one scenario to sort the values based domain class property. This property may acept all numeric and alphanumeric values in the format XXX-1.
def res= Book.listOrderByName()
or
def res = Book.findAll("from Book order by name")
Giving the same result and result is displaying first numbers latter alphanumeric values.
My problem is :
these values are sorted before -.
for example i have AB-1,AB-2,...AB-12.
The result is displayed as AB-1,AB-10.AB-11,AB-2,AB-3,..AB-9
I have result like:
[18001,18002,2,300,3901,42,9,AB-1,AB-10,AB-2,AB-21,AB-9]
It should display the value as:
[2,9,42,300,3901,18001,18002,AB-1,AB-2,AB-9,AB-10,AB-21]
Run this in the Groovy console:
List sort(list) {
list.sort {a, b ->
a.class == b.class ? a <=> b : a instanceof Integer ? -1 : 1
}
}
// Test the sort function
def list = [18001,18002,2,300,3901,42,9,'AB-1','AB-10','AB-2','AB-21','AB-9']
assert sort(list) == [2, 9, 42, 300, 3901, 18001, 18002, 'AB-1', 'AB-10', 'AB-2', 'AB-21', 'AB-9']