How to verify if a field is an empty string with GORM? - grails

I have a GORM query and I need to make it avoid a field which may be a empty string for legacy system questions.
Currently, my query is:
def things = Thing.withCriteria{
resultTransformer CriteriaSpecification.ALIAS_TO_ENTITY_MAP
createAlias 'factor', 'f'
eq 'active', true
isNotNull 'title' // this field may be an empty string
isNotNull 'content' // this field also may be an empty string
// <-- and here I'd like to include sth like isEmpty 'title'
not {
inList 'f.id', factors
}
projections{
property 'id' , 'id'
property 'f.name' , 'name'
property 'title' , 'title'
property 'content' , 'content'
property 'f.id' , 'factorId'
}
}
I didn't find any solution in the docs, but I have a feeling that this solution should be with pure SQL. Is it possible? Any suggestion?

Have you tried adding this statement to the criteria?
ne title, ""
Grails criteria relies on hibernate Restrictions, so everything supported by this can also be used in grails criteria.
Otherwise you could also use sql restrictions (see Using SQL Restrictions section):
sqlRestriction "char_length(title) > 0"
Keep in mind that title here refers to the real column name in the database. If you want to have a more reliable code, you can include a static mapping for the field (column name) in the model :
static mapping = {
title column: 'title'
}
In this way you should avoid errors from db specific naming behaviour (if any).

Related

grails elasticsearch only indexed one instance out of many

I am using the elasticsearch grails plugin for the first time, and when I set the config bulkIndexOnStartup = true, it indexed several of the domain classes correctly, but for a couple of others it seemed to only index one instance out of many, even though I saw 99 distinct instances in the database.
When I tried to specifically index the instances by calling
elasticSearchService.index( anInstance )
it would just delete the old entry and add a new one, so at the end there was still only one instance in elasticsearch. Is there an "indexAllDistinct" setting somewhere? How does it decide to add a new entry or replace an existing entry?
I also noticed that on the instances that were indexed correctly, the _id fields all had numeric values, but on the incorrectly indexed instance, the _id field was "null".
EDIT: I found that the incorrectly indexed classes have the "id" mapping name set to a different field. How can I tell elasticsearch that the "id" has a different name for these classes?
For grails domain classes that map the default "id" to another name, I had to add a transient "id" for elasticsearch. For example:
class LogEntry {
Integer logId // replaces default id
...
static mapping = {
id name: 'logId', column: 'LOG_ID'
...
}
static transients = ['id'] // for elasticsearch
def getId(){
return logId
}
}

Grails Criteria query with a condition on data

I have a database table storing data for this Grails domain class using vanilla GORM:
class A {
String propOver // may be null
String propBase
}
I want to create a search query that searches against the propOver property if it contains a value, otherwise against the propBase property. Or, to word this differently, propOver overrides propBase when it exists.
I need something that works like this pseudo-code:
def results = A.createCriteria().list{
if propOver isn't null: // the heart of the problem
eq('propOver', search_input)
else
eq('propBase', search_input)
}
Is it even possible?
Please note that one (bad) solution would be to create a 3rd property that stores the propOver ?: propBase value, but it violates the DRY principle, and I'd prefer avoiding modifying the DB.
This will do?
A.createCriteria().list{
or {
eq 'propOver', search_input
and {
isNull 'propOver'
eq 'propBase', search_input
}
}
}

GORM criteria like query on string set

I have a domain as below:
class Event {
String name
Set tags
//.... other properties
static hasMany = [tags: String]
}
Now, I want to implement an query for search for Event using a list of String. The search should support a 'like' based search. i.e if an Event has tag like 'annual meeting', then string 'meeting' should give that event as result.
Can this be achieved using GORM criteria?
Due to https://hibernate.atlassian.net/browse/HHH-869 there is no way to query a collection of value types with Hibernate (which GORM uses)
You must use HQL instead.

findBy multiple attributes (findAllWhere)

I have an object from which I must filter certain attributes, some of which could also be "null". I have a Filter object and a Product object.
In the Filter object I have certain attributes reflecting the Product object which can be filled out or be left blank. Here a shortened view on the classes.
Product: String name, Boolean isEmpty, ...., belongsTo [Producer, Distributor]...
Filter: Boolean isEmpty, ... belongsTo [Producer, Distributor]...
With this filter I can search for all Products having certain attributes (empty, Producer, Distributor).
I have an export functionality where I can select the filter and it outputs the information based on that selection for the Products.
As all of these attributes can be null, but also contain a value, I first of thought to construct an own search query (combining strings etc) to construct an SQL-string and then using Product.findAll(string_query, string_params). But as this is quite tedious, I changed it now to someting like this:
if(filter.producer)
prods = Product.findAllWhere(producer:filter.producer)
if(filter.distributor)
prods = prods.findAll {it.distributor == filter.distributor}
if(filter.isEmpty!=null) //as it could be NULL but also false/true
prods = prods.findAll {it.isEmpty == filter.isEmpty}
But this becomes quite a larger task if I have 10-15 attributes to be filtered. I'm not very experienced with Grails or Groovy but I guess this can be solved easier, right?
I believe you'll find Grails Criteria queries to be a very nice way to accomplish tasks like this. See:
http://grails.org/doc/latest/guide/single.html#criteria
http://viaboxxsystems.de/the-grails-hibernatecriteriabuilder
Your sample might look something like this when expressed as a criteria query:
def prods = Product.createCriteria().list {
if(filter.producer) eq("producer", filter.producer)
if(filter.distributor) eq("distributor", filter.distributor)
if(filter.isEmpty != null) eq("isEmpty", filter.isEmpty)
}

grails findAll tag

How to use "SELECT id, name, part, description FROM user " in grails findAll tag.
I tried
User.findAll("SELECT id, name, part, description FROM user")
instead using
User.findAll("FROM user")
But shows errors.
What is the tag?
finadAll() returns a Collection of domain objects, so enumerating columns to select does not make sense; the queries it understands are not real SQL, and consist basically only of WHERE clauses. Since you don't seem to want to constrain the result set, this is probably all you need:
User.findAll()
It will return a collection of all User objects. If you need constraints, the syntax ist
User.findAll("from User as u where u.id=?", [userId])
Or, even simpler, you can use a dynamic finder:
User.findAllById(userId);
If you want to run report-style queries like this, use the executeQuery method:
def rows = User.executeQuery("SELECT id, name, part, description FROM User")
The return value will be a List of Object[] where each element in the object array is the type of the column, i.e. the 1st element will be a long, 2nd a String, etc.
Note that User has to be capitalized since you're referring to the Hibernate entity - this isn't a SQL query, it's HQL.
If you want to query for only certain fields, you can use a criteria query with a projection.
Example:
def userProperties = User.withCriteria {
projections {
property('id')
property('name')
property('part')
property('description')
}
}
This query will return an array of Strings (or whatever the database column type is mapped to) for each matching row, instead of a domain object.
It will return an ArrayList of objects you only have to access that objects values. For example:
def result = Code.findAll("from Code as c where c.user_code=?",[pass])
result[0].user_code
Where my Code class is something like this:
class Code {
String user_code
boolean flg_active
static constraints = {
user_code nullable:true, blank:true, size:0..Text.MID
flg_active nullable:true, blank:true, default:1
}
}

Resources