2

Domain Fields:

startDate: Date
length: Integer
perpetuity: Boolean
expiryDate: Transient (startDate + length (in years))

Domain methods - These methods are used for filtering on a big filter form for a user to search for the 4 different expiration status'.

Date getExpiryDate() {
    if (this.startDate == null || this.length == null) {
        return null
    }

    Timestamp startDate = this.startDate;
    Calendar expirationDate = Calendar.getInstance()
    expirationDate.setTime(startDate)
    expirationDate.add(Calendar.YEAR, this.length)

    return expirationDate.getTime()
}

String getMechExpiredStatus() {
    String isExpiredString = 'Unspecified'
    Date expDate = getExpiryDate()
    if (expDate != null) {
        if (expDate < new Date()) {
            isExpiredString = 'Yes'
        } else {
            isExpiredString =  'No'
        }

    } else if (isPerpetual && startDate != null) {
        isExpiredString =  'Perpetual'
    }

    return isExpiredString
}

Building the results list

PagedResultList getMechanisms(offset, max, sortColumn, sortOrder, filters, idsOnly = false) {
    def criteria = Mechanism.createCriteria()
    def results = criteria.list(max: max, offset: offset) {
        if (idsOnly) {
            projections {
                property('id')
            }
        }

        if (filters && filters.idFilter) {
            eq('id', filters.idFilter);
        }
    ...
    }

    if (filters && filters.expiredFilter != null && filters.expiredFilter) {
        // Do Work
        // Tried getting results and removed invalid results that do not meet the 
        // expired filter selection
    }

return results

}

I cannot seem to find a way to write a createCriteria using the transient field 'expiryDate' nor using the getMechExpiredStatus method.

I've tried getting a list of items with the other filters and then removing the items that aren't valid for the expiration filter separately but the PagedResultList doesn't get updated properly; it just returns a current paged result list. I cannot find much help regarding the PagedResultList object either. Remove and Add returns a boolean for some reason. Apparently I do not understand the object very well.

If I remove the max and offset from the initial criteria list, the query takes a very long time to run.

Any ideas how I can accomplish this?

Vaesive
  • 105
  • 1
  • 11

2 Answers2

2

I solved the problem by just making the expiration status and date in a view and linked it to the domain object. Works great!

Vaesive
  • 105
  • 1
  • 11
1

You can not query against a transient property. Transient properties by definition are not present in your datasource and therefore can not be a part of the query executed by the datasource.

In order to accomplish what you are looking to do using a transient property you will need to create your own list of results without using the limit and offset features provided by your datasource, filter the results, and then apply the offset and limit yourself.

Since you haven't provided an example of what your query is I am left to make up my own for an example:

// this could be any type of query, using list for simplicity of the example
def databasePersons = Person.list()
// assumes anAdult is a boolean transient property of person
// calculated based on age
def filteredPersons = databasePersons.findAll{ it.isAnAdult() }

// get rid of the first X records, the offset
filteredPersons = filteredPersons.drop(offset)

// only take the next X remaining records, the max
filteredPersons = filteredPersons.take(max)
Joshua Moore
  • 24,706
  • 6
  • 50
  • 73
  • filteredPersons would return an ArrayList and it has to return a PagedResultList. I can't find a way to cast or convert them. I tried this code in the expiredFilter check: def allMechs = Mechanism.list() results = allMechs.findAll { it.getMechExpiredStatus() == filters.expiredFilter } results = expiredFilter.drop(offset) results = results.take(max) – Vaesive Aug 22 '14 at 17:16
  • Why must it return a PagedResultList? – Joshua Moore Aug 22 '14 at 17:20
  • Because we return the entire thing to a list object that page-ifys them into the max number of items per page. – Vaesive Aug 22 '14 at 18:04
  • Then use the public constructor to create one based on the list filteredPersons in my example. See: http://grails.org/doc/1.3.7/api/grails/orm/PagedResultList.html#PagedResultList%28java.util.List%29 ... **EDIT** Apparently that constructor was removed in later versions of Grails: http://grails.org/doc/2.2.x/api/grails/orm/PagedResultList.html – Joshua Moore Aug 22 '14 at 18:30
  • Without knowing how your "page-ifys" are truly being done I can't suggest anything further (such as returning a Map which implements the correct keys to appear to be a PagedResultList). If you are using the built in Grails pagination that's the route I would go. – Joshua Moore Aug 22 '14 at 18:34
  • I did try the example; my comment above shows the code I tried and I get a cannot cast ArrayList to PagedResultList exception. I'm thinking making a view of these fields and providing the view to the Domain would alleviate this issue. – Vaesive Aug 22 '14 at 18:35