limit select on certain Domain Class Items - grails

My Domain Classes simplified look like this:
class ScheduleTimeExp{
Data date
}
class ScheduleAction{
ScheduleTimeExp scheduleTimeExp
}
I have a select box in my gsp:
<g:select id="scheduleTimeExp" name="scheduleTimeExp.id" from="${tao.marketing.ScheduleTimeExp.list()}" optionKey="id" required="" value="${tao.marketing.ScheduleAction?.scheduleTimeExp?.id}" class="many-to-one"/>
Rather that letting the user select from all ScheduleTimeExp
from="${tao.marketing.ScheduleTimeExp.list()}"
I would like to show only those ScheduleTimeExp where a relation between ScheduleTimeExp and ScheduleAction does not exist for any other ScheduleAction. In other words only those time expressions which have not yet been selected in another ScheduleAction.

To enforce logic from presentation separation, you want to fill the list inside controller action:
def dataSource
def someAction() {
final Sql sql = new Sql( dataSource )
def scheduleTimeExps = sql.rows( 'select ste.id, ste.date from Schedule_Time_Exp ste where ste.id not in (select sa.Schedule_Time_Exp_id from Schedule_Action sa)' ).collect{ it as ScheduleTimeExp }
[ ..., scheduleTimeExps:scheduleTimeExps ]
}
Note: make sure the case and naming of the tables and columns are correct
and then in gsp:
<g:select .. from="${scheduleTimeExps}"/>

Related

join a table in two columns due to polymorphic relation

I have the following structure:
Buro->hasOne->Address->hasOne->City->hasOne->State
Buro->hasOne->Category
and
Order->hasOne->Address->hasOne->City->hasOne->State
Order->hasOne->Category
and
Category->hasMany->Orders and Category->hasMany->Buros
I have a "One-To-Many" polymorphic relation between addresses in one side and Buro/Orders in the other side. There is just One address for a buro and just one adddress for an order, therefor I couls use [0] to get the first the first and only one element in a collection.
Address class
class Address extends Model
{
...
public function addressable()
{
return $this->morphTo();
}
...
}
Büro class
class Buro extends Model
{
....
public function addressable()
{
return $this->morphMany('App\Address', 'addressable');
}
...
}
Order class
class order extends Model
{
....
public function addressable()
{
return $this->morphMany('App\Address', 'addressable');
}
...
}
Now I am building a form in the frontend with a SELECT field in order to select just from the Buros that operate in the same State where the order was placed.
Using ELOQUENT I did this:
$all_bueros = Buero::where('category_id', $order->category_id)
->where('title', $order->client->addressable[0]->city->state->title) // <- Look at this "title" column name
->pluck('title', 'id')->all();
The problem here is that the "Title" column name is not in "Buros" table but three tables away. Exactly in: buros.addresses.city.state.title
I have tried these syntaxes but no one worked:
->where('buros.addresses.city.state.title', $order->client->addressable[0]->city->state->title) // as object notation
and
->where('buros->addressable[0]->cities->state->title', $order->client->addressable[0]->city->state->title) // using the relation
I used the query builder but there is even more messy:
$buros = DB::table('buros')
->join('categories', 'categories.id', '=', $order->category_id)
->join('addresses', 'addresses.addressable_id', '=', $order->id, 'AND','addresses', 'addresses.addressable_type', '=', 'buros') //two points to join the table
->join('cities', 'addresses.city_id', '=', 'cities.id')
->join('states', 'cities.states', '=', 'states.id')
->select('buros.title', 'buros.id')
->where('states.title', '=', $order->client->addressable[0]->city->states->title)
->get();
My problem is how to join a table in two points since there is a polymorphic relation. Because I need to join the Address Table in the "Buro-column" (addressable_type) and in the Buro-id column (addressable_id)
Any help will be appretiate

Grails HasMany on Long

I have an class with an hasMany on a Long:
class Test {
static hasMany = [longList:Long]
}
I want to filter on longList with Criteria:
Test.createCriteria().list{
'in'('longList',[Long.valueOf('1')])
}
I get an SQLException: No value specified for parameter 1.
The SQL looks like this:
select * from test this_ where this_.id in (?)
i tried things like:
createAlias('labours', 'l')
eq('l',Long.valueOf(filter.labourId)) )
or
eq('labours.value', Long.valueOf(filter.labourId))
But i can't get it working.
For a workaround i would make another domain Class:
class Test {
statis hasMany=[longList:TestLongList]
}
class TestLongList{
Long longListItem
static belongsto = [test:Test]
}
This should be working but i must always create an TestLongList Instance if I create an Test Object, so the code would turn from:
test.addToLongList(Long.valueOf('22'))
to
TestLongList tll = new TestLongList
tll.test= test
tll.longListitem = Long.valueOf('22')
tll.save()
test.addToLongList(tll)
Is there a way to stay with the Long-List without HQL?
You have to rewrite the criteria to look like this:
Test.createCriteria().list{
createAlias('longList', 'l')
'in' ('l.elements', [1L])
}
This boils down to the property name under which Hibernate stores collection (elements).

How can we get GroovyfirstRowResult to just list values, and not the column headers and without flower braces when shown in .gsp view?

In the groovy Controller Code I call the function:
def wiki =
{
def currentNode = params.nodePath
def conceptName = nodeService.retrieveConceptName (currentNode);
render (template:'wiki', model:[conceptName : conceptName])
}
In the service class I define the function retrieveConceptName:
def retrieveConceptName(currentNode)
{
groovy.sql.Sql sql = new groovy.sql.Sql(dataSource);
def row= sql.firstRow(" SELECT cname FROM Person WHERE FULLNAME= ?",[currentNode]);
return row;
}
In my output(wiki template(gsp view)) I get flowerbrackets along with field header , How to get only value of column and not the flower braces or field header?
You haven't shown the GSP code that displays the row, but I guess it looks like either ${it} or ${row}. If so, replace it with either
${it.cname} or ${row.cname}

Grails controller not getting current value of a dropdown in a controller

I have a dropdown (g:select) in my view that displays a list from a domain class. I want to println whatever value that is in it whenever a save button is clicked. Below is the script in the view
<g:select params="[tablename: storehouseInstance?.tablename]" name="tablename" from="${Warehouse.list()}" optionKey="id" optionValue="${Warehouse.list()}" value="tablename"
noSelection="['':'Choose Table']"
onchange="${remoteFunction (
controller: 'warehouse',
action: 'updateSelect',
params: "'warehouse.id=' + this.value + storehouseInstance?.tablename" ,
param: "this.value",
update: [success:'fieldSelection'] //update: 'fieldselection'
)}"/>
And in my controller i have:
def save() {
println("params are "+ params)
println("Saving table name: " + params.tablename)
}
I am getting tablename to be '1' instead of the value that should be something like 'MYTESTVALUE'
Any help please.
Assuming the warehouse's name property is name, try this instead:
<g:select params="[tablename: storehouseInstance?.tablename]"
name="tablename"
from="${Warehouse.list()}"
optionKey="name" // I changed this line
optionValue="name" // I changed this line too
value="tablename"
noSelection="['':'Choose Table']"
onchange="${remoteFunction (
controller: 'warehouse',
action: 'updateSelect',
params: "'warehouse.id=' + this.value + storehouseInstance?.tablename" ,
param: "this.value",
update: [success:'fieldSelection']
)}"/>
In a g:select the parameter that is sent to the server is defined by optionKey and the value that is displayed in the dropdown is defined by optionValue
Aside
From an MVC purity point-of-view, you shouldn't be doing queries in GSPs, e.g. Warehouse.list(). Instead you should retrieve the data you need in a service/contoller and pass it via the model to the view (GSP).

Grails using query in g:select with service

Fairly new to the Grails model, and having a little trouble getting around using a service for my database transactions.
Service:
class ReportService {
def dataSource
def listDatatypeValues(Datatype dt) {
def sql = new Sql(dataSource)
def list = sql.rows (dt.statement)
return list
}
}
Controller:
def run(Long id) {
def reportInstance = Report.get(id)
def listPromptValues = populatePrompts(reportInstance)
if (!reportInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'report.label', default: 'Report'), id])
return
}
[reportInstance: reportInstance, listPromptValues: listPromptValues]
}
def populatePrompts(Report rp){
//for a prompt in the report, go out and get it's values
rp.prompts.each {
List list = reportService.listDatatypeValues(it.datatype)
}
}
View snippet:
<g:if test="${reportInstance?.prompts}">
<li class="fieldcontain">
<g:each var="prompt" in="${reportInstance.prompts}">
<g:if test="${prompt.datatype.type == 'DropDown'}">
<g:select id="prompt.name" from="${listPromptValues}" name="prompt.name" value="" noSelection="['':'']"/>
</g:if>
</g:each>
</li>
</g:if>
We have a report object, that contains prompts, which in turn contain a datatype. For any given report, when it is pulled up on the UI, it will give the report details, and then list the prompt value for a give prompt. The problem is the current setup is listing the object reference as the prompt value and not the list of values returned from the service.
And example would be Report 1 has 2 prompts, Starting Term Code and Ending Term Code. Both of them use Term Code as the datatype since it is the same SQL query, and the list returned from listDataTypeValues would be a list of 70+ term codes that are stored in the database.
Any thoughts or direction?
I tried following along with this but I can't get it to work.
Thanks!
Your populatePrompts function isn't returning a meaningful value. If you iterate with collectMany instead of each the value of the expression will be the concatenation of all the results from your queries. Try something like this:
def populatePrompts(Report rp){
rp.prompts.collectMany {
reportService.listDatatypeValues(it.datatype)
} //.unique()
}
You may also want to call unique on the result to avoid duplicates in your g:select input.

Resources