Grails 2 - How to dynamically call multiple datasources - grails

I have two named data sources in my Grails app (Grails 2.0.3)...
dataSource_a {
// ...
}
dataSource_b {
// ...
}
I'd like the ability to dynamically change what datasource I'm accessing, based on some kind of parameter. I could do something like this...
def findPeople(datasource) {
if (datasource == 'a') {
return Person.a.list()
} else if (datasource == 'b') {
return Person.b.list()
}
}
What I was really hoping to be able to do, though, is something like this...
def findPeople(datasource) {
return Person."$datasource".list()
}
Unfortunately, I get an error when I try and do that. "Fatal error occurred apply query transformations: null 1 error".
Any thoughts on how to accomplish this? Or am I just stuck with if/switch blocks?

I figured it out, this is how you have to do it.
def findPeople(datasource) {
def p = People.class
p."${datasource}".list()
}
For some reason, if you call it like that, it works.

Related

Using Disjunction (logical or) in Grails Subqueries

In Grails 2.5.4, I am having issues using a disjunction in Subqueries. If I have a query like the following:
DomainObj.createCriteria().list {
def criteria = new DetachedCriteria(DomainObj2).build {
or {
eq('prop1', someVal)
eq('prop2', someVal)
eq('prop3', someVal)
}
projections {
distinct('id')
}
}
inList('prop', criteria)
}
The 'or' part of the query fails with a null pointer exception. The reason seems to be in AbstractHibernateCriterionAdapter the code is looking for a PersistentEntity for the DetachedCriteria which is never assigned.
The only workaround I have found is to switch the query to use more subqueries like this:
def criteria1 = new DetachedCriteria(DomainObj2).build {
eq('prop1', someVal)
projections {
distinct('id')
}
}
def criteria2 = new DetachedCriteria(DomainObj2).build {
eq('prop2', someVal)
projections {
distinct('id')
}
}
def criteria3 = new DetachedCriteria(DomainObj2).build {
eq('prop3', someVal)
projections {
distinct('id')
}
}
DomainObj.createCriteria().list {
or {
inList('prop', criteria1)
inList('prop', criteria2)
inList('prop', criteria3)
}
}
Which sidesteps the issue, and really isn't ideal. Any idea what is going wrong?
Update
So after looking around some more I found this issue on Github. What I am experiencing is a bug that was fixed in grails-data-mapping version 5.0.2. So for anyone that searches for this issue in the future it looks like the you either have to upgrade or use the crazy workaround highlighted above.
You could probably simplify your above working nest to:
private DetachedCriteria getCriteria(prop,val) {
return new DetachedCriteria(DomainObj2).build {
eq(prop,val)
projections {
distinct('id')
}
}
DomainObj.createCriteria().list {
or {
inList('prop', getCriteria('prop1','somVal'))
inList('prop', getCriteria('prop2','somVal'))
inList('prop', getCriteria('prop3','somVal'))
}
}
Personally I would probably either just do a findAll or just run an hql query, if it turns out you can't use the current method due to some limitation since am no expert on this matter itself.
//where d.domainObject2 is the binding of DomainObj2 within DomainObj
String query="select new map(d.id) from DomainObj d left join d.domainObject2 d2 where d2.field in (:someList)"
def input=[]
input.someList=[1,2,3] //The or segments
def results=DomainObj.executeQuery(query,[],[readOnly:true,timeout:15,max:-1])

How does grails pass arguments to controller methods?

In grails controller examples, I have seen save(Model modelInstance) and save(). I tried them both, both of them works. I imagine grails instantiates the modelInstance with the params. Is my assumption correct?
I also noticed in index(Integer max), does the param has to be named max? or any name would work as long as it is a number?
How does these passing of arguments work underneath?
If you write a controller like this...
class MyController {
def actionOne() {
// your code here
}
def actionTwo(int max) {
// your code here
}
def actionThree(SomeCommandObject co) {
// your code here
}
}
The Grails compiler will turn that in to something like this (not exactly this, but this describes effectively what is happening in a way that I think addresses your question)...
class MyController {
def actionOne() {
// Grails adds some code here to
// do some stuff that the framework needs
// your code here
}
// Grails generates this method...
def actionTwo() {
// the parameter doesn't have to be called
// "max", it could be anything.
int max = params.int('max')
actionTwo(max)
}
def actionTwo(int max) {
// Grails adds some code here to
// do some stuff that the framework needs
// your code here
}
// Grails generates this method...
def actionThree() {
def co = new SomeCommandObject()
bindData co, params
co.validate()
actionThree(co)
}
def actionThree(SomeCommandObject co) {
// Grails adds some code here to
// do some stuff that the framework needs
// your code here
}
}
There is other stuff going on to do things like impose allowedMethods checks, impose error handling, etc.
I hope that helps.

Reusing part of Grails criteria closure

I have a fairly large criteria closure in my Grails application, and I would like to reuse part of it in several places in my application. Rather than duplicating the section I need to reuse, I'd like to define this as a separate closure and reference it wherever it is needed, but I am struggling a bit with the syntax.
This is a simplified / cut down version, but essentially my criteria looks something like this:
def criteriaClosure = {
and {
// filtering criteria that I'd like to reuse in lots of places
or {
names.each { name ->
sqlRestriction(getFilteringSql(name), [someId])
}
}
if (isOrganisationChild(childDefaultGrailsDomainClass)) {
sqlRestriction(getFilteringSql(domain), [someArg])
}
// filtering criteria that's specific to this particular method
sqlRestriction(getSomeOtherSql(), [someOtherArg])
}
}
def criteria = domain.createCriteria()
def paginatedList = criteria.list([offset: offset, max: max], criteriaClosure)
I've tried defining the part of the closure I want to reuse as a variable, and referencing it in my criteria closure, however the restrictions it defines don't seem to be applied.
def reusableClosure = {
and {
or {
names.each { name ->
sqlRestriction(getFilteringSql(name), [someId])
}
}
if (isOrganisationChild(childDefaultGrailsDomainClass)) {
sqlRestriction(getFilteringSql(domain), [someArg])
}
}
}
def criteriaClosure = {
and {
reusableClosure() //this doesn't seem to work
sqlRestriction(getSomeOtherSql(), [someOtherArg])
}
}
I'm sure this must be a pretty straightforward thing to do, so apologies if it's a daft question. Any ideas?
I think you have to pass the delegate down to the reusableClosure, ie:
def criteriaClosure = {
and {
reusableClosure.delegate = delegate
reusableClosure()
sqlRestriction(getSomeOtherSql(), [someOtherArg])
}
}

How to make a query with usage of like operator over a string collection in GORM

Assume a domain class called User. User class looks like this:
class User {
List<String> values
}
The collection values contains strings like "http://example.com/x", "http://google.com/y", "http://google.com/z" and so on...
Let's say we want to build a query which gets all the users that have specific string in the collection values (e.g. "google.com"). Something like this:
def criteria = User.createCriteria()
def results = criteria.listDistinct () {
and {
user.values.each { like('someField', '%${it}%') }
}
}
Any ideas?
I have found the answer by experimentation. The solution is:
def criteria = User.createCriteria()
def results = criteria.listDistinct () {
and {
user.values.each { like('someField', '%'+it+'%') }
}
}
I am not sure what you are doing with your suggested answer.
I have never seen that usage of each in the criteria query before.
This question has been asked many times before but never given an answer.
The problem is that you are queriyng a String association, which is not a domain class. If you would make your own String domain class for example ondrej.String { String strValue } then you would be able to do :
User.withCriteria {
values { ilike("strValue", "...") }
}
The problem is not having access to the value of the String object. The value of the String class is called value, but it is a char array, so I do not believe the following will work:
User.withCriteria {
values { ilike("value", "...") }
}
You could try using :
User.withCriteria {
values { ilike("toString", "...") }
}
or something else instead of toString ... I do not have the possibility to test this right now.
Hope that helps
After a lot of trying and researching, I found this will work with Grails 2.4.0, I don't know about older versions.
Cat.withCriteria {
createAlias('nicknames', 'n')
ilike 'n.elements', '%kitty%'
}
The trick is to use 'n.elements'

How to access command objects from filter and is it possible at all?

I often write something like:
def myAction{ MyActionCommand cmd ->
if( cmd.hasErrors() ){
return render(status:HttpServletResponse.SC_BAD_REQUEST );
}else{
// actual action logic
}
So, I'd like to extract that common pattern into some reusable location. Filter looks like good candidate, but I can't find the way to get command object from the filter. Tryed something like this (in filters closure):
formValidation( controller:'*', action:'*' ){
before = { cmd ->
if( cmd.hasErrors() ){
response.sendError( HttpServletResponse.SC_BAD_REQUEST );
return false;
}else{
return true;
}
}
}
Intersted in grails 1.3.7 compatible solution. Is it possible at all?
No, it isn't possible to do what you are asking. Command Objects are not full framework artifacts like Controller, Service, etc, and so they do not get their validation logic added to them, unless they are a parameter to a Controller action. To that end a Command Object in a filter wouldn't have a .validate() or .hasErrors() method to check against.
As another option you could use the #Validateable annotation:
http://grails.org/doc/latest/guide/7.%20Validation.html#7.5%20Validation%20Non%20Domain%20and%20Command%20Object%20Classes
Move your Command Object to src/groovy as a regular Groovy class and annotate it with #Validateable. Then in your filter you can do:
def validObj = new MyValidateable(params)
if (!validObj.validate()) {
response.sendError( HttpServletResponse.SC_BAD_REQUEST );
return false;
} else {
return true;
}
Make sure you add the package name of your validateable class to the grails.validateable.packages List in Config.groovy.
What about creating a service like this:
class AutoValidateService {
def onValid(def cmd, Closure onValid) {
if( cmd.hasErrors() ){
return render(status:HttpServletResponse.SC_BAD_REQUEST );
}else{
onValid()
}
}
}
The use it like so:
class FooController {
AutoValidateService autoValidateService
def myAction{ MyActionCommand cmd ->
autoValidateService.onValid(cmd) {
// do something
}
}
}

Resources