I'm working on building a createCriteria
dynamically. So far, so good:
obj
is the domain object(s) I want back
rulesList
is a list of maps which hold the field to be searched on, the operator to use, and the value to search against
def c = obj.createCriteria()
l = c.list (max: irows, offset: offset) {
switch(obj){ //constrain results to those relevant to the user
case Vehicle:
eq("garage", usersGarage)
break
case Garage:
users {
idEq(user.id)
}
break
}
rulesList.each { rule ->
switch(rule['op']){
case 'eq':
eq("${rule['field']}", rule['value'])
break
case 'ne':
ne("${rule['field']}", rule['value'])
break
case 'gt':
gt("${rule['field']}", rule['value'])
break;
case 'ge':
ge("${rule['field']}", rule['value'])
break
case 'lt':
lt("${rule['field']}", rule['value'])
break
case 'le':
le("${rule['field']}", rule['value'])
break
case 'bw':
ilike("${rule['field']}", "${rule['value']}%")
break
case 'bn':
not{ilike("${rule['field']}", "${rule['value']}%")}
break
case 'ew':
ilike("${rule['field']}", "%${rule['value']}")
break
case 'en':
not{ilike("${rule['field']}", "%${rule['value']}")}
break
case 'cn':
ilike("${rule['field']}", "%${rule['value']}%")
break
case 'nc':
not{ilike("${rule['field']}", "%${rule['value']}%")}
break
}
}
}
}
The above code works fine and is only a little verbose-looking with the switch statements. But what if I want to add functionality to choose to match ANY of the rules or ALL of them? I would need to conditionally put the rules in an or{}
. I can't do something like
if(groupOp == 'or'){
or{
}
before I go through the rulesList and then
if(groupOp == 'or'){
}
}
afterward. All I can think to do is to repeat the code for each condition:
if(groupOp == 'or'){
or{
rulesList.each { rule ->
switch(rule['op']){
...
}
}
}
}
else{
rulesList.each { rule ->
switch(rule['op']){
...
}
}
Now the code is looking quite sloppy and repetitive. Suppose I want to search on a property of a property of the domain object? (Ex: I want to return vehicles whose tires are a certain brand; vehicle.tires.brand, or vehicles whose drivers match a name; vehicle.driver.name). Would I have to do something like:
switch(rule['op']){
case 'eq':
switch(thePropertiesProperty){
case Garage:
garage{
eq("${rule['field']}", rule['value'])
}
break
case Driver:
driver{
eq("${rule['field']}", rule['value'])
}
break
}
break
case 'ne':
...
}