How to extract a list from params in controller - grails

I have a list of lists passed in from view like this:
[lists:[["e","q"],["t","w"]], action:save, controller:newReport]
in my controller
def lists = params.lists;
the lists will be a string which has value of "[["e","q"],["t","w"]]"
how should I iterate through the list to get each sublist?

Use JSON.parse:
groovy:000> lists = JSON.parse("[['e', 'q'], ['w', 'q']]")
===> [["e","q"],["w","q"]]
groovy:000> lists.each { list -> println list }
[e, q]
[w, q]
===> [["e","q"],["w","q"]]
groovy:000> lists[0].each { entry -> println entry }
e
q
===> ["e","q"]
This is much more secure than a GroovyShell. That way you don't have to think about how to secure it or how to use a regex to parse the string.

Grails have a good type conversion that you can use in params.
Have you tried params.list('lists')?
EDIT:
Tried now here, in your case you can evaluate the expression to transform in a list:
params.lists = '[["e","q"],["t","w"]]'
def listValues = new GroovyShell().evaluate(params.lists)
listValues.each { list ->
println list
println list.class.canonicalName
}
EDIT2: This may be dangerous if the user send another content that's not expected. You can secure your GroovyShell as explained in this post.

Related

Neo4j Cypher: String Build with Unwind and Array

Im using an unwind query in neo4j, with a nodejs driver (https://github.com/philippkueng/node-neo4j)
What I am trying to do is include an array of objects in the unwind query.
It currently works if I hard code the string as shown below, but i'm trying to have the array inserted dynamically.
UNWIND [{Label:'User',Lang:'English'},{Label:'Usuario',Lang:'Español'},{Label:'用户',Lang:'中文_简体'}] as ll
Regardless of the query I use, after testing, the above works, but if I do something like the following it doesn't:
var MyList = [{Label:'User',Lang:'English'},{Label:'Usuario',Lang:'Español'},{Label:'用户',Lang:'中文_简体'}];
"UNWIND "+ MyList " + as ll"
The problem is that when you do "UNWIND " + MyList you convert MyList to string, and it will be something like [object Object],[object Object],.... My first idea was to use JSON.stringify but that produces a JSON, which is not ok in cypher syntax (it is { "Label": ... } instead of { Label: ... }). The solution is to use parameters:
var queryString = 'UNWIND {list} as ll // continue query';
var queryParams = { list: MyList };
db.cypherQuery(queryString, queryParams, function(err, res) {
// handle response
});
Ideally you would use the ll identifier in your query.
However by seeing you have a property named Label, I remind you that currently it is not possible to add labels dynamically.
A possible query you might do is :
UNWIND MyList AS ll
CREATE (user:User) SET user.lang = {ll}.Lang
Chris

Need help improving how objects are saved from params in my app

So, I have a form that collects a bunch of radio selections and checkboxes and I need to build a series of objects based on what gets returned, which might look like this:
[thingid:1, 13:30,14:33, 11:26, 12:78, action:save, controller:userThing]
One object is created from the thingid, and the integer value pairs are ids of 2 other objects that are used to create n additional objects, so right now I'm looping through the params with an each() and filtering the non integer pairs with a long if expression, and then saving the object I need :
params.each {
key, value ->
if (key=="submit" | key=="action" | key=="thingid" | key=="controller"){}else{
def prop = ThingProperty.find(){
id == key
}
def level = ThingLevel.find(){
id == value
}
new UserThingScore(userthing: userthing,thingproperty: prop ,thinglevel: level).save(flush:true)
}
}
It works, in that it creates all the necessary objects correctly, but this just seems ridiculous to me, and I know there must be a better way... is there someway I can group form elements so they get returned like this?:
[thingid:1, integerpairs:[13:30,14:33, 11:26, 12:78],action:save,controller:userThing]
An alternative might be:
def userThingList = params.keySet().grep( Integer ).collect { it ->
new UserThingScore( userthing: userthing,
thingproperty: ThingProperty.get( it ),
thinglevel: ThingLevel.get( params[ it ] ) )
}
userThingList*.save()

Grails data binding to command object with maps - convert key to number

I have a Grails command object with a list of maps. The map key is intended to be a numeric domain object ID.
class MyCommand {
def grid = [].withDefault { [:] }
}
Data binding to the list/map is working in general because of the dynamic list expansion.
However, in the POST, the map keys are being bound as Strings and I want them to be Longs, as they are when the form is initially populated. I want foo[123] in my map, not foo['123'].
Alternatively I would be satisfied if the [] operators found the correct value given a numeric ID key to look up. In other words, if I could get foo[123] to return the same value as foo['123'], that would work too.
Any way to get this to work the way I want to? Maybe strongly type the map?
Or a better approach?
You can inject the property into the map to convert a String key to Long. For example:
def myMap = [:] << ['1': "name"] << ['Test': "bobo"]
def result = myMap.inject([:]){map, v ->
def newKey = v.key.isNumber() ? v.key.toLong() : v.key
map[newKey] = v.value
map
}
assert myMap['1'] == 'name'
assert result[1L] == 'name'
assert result['Test'] == 'bobo'

How would I find the text of a node that has a specific value for an attribute in groovy?

I'm using XMLSlurper. My code is below (but does not work). The problem is that it fails when it hits a node that does not have the attribute "id". How do I account for this?
//Parse XML
def page = new XmlSlurper(false,false).parseText(xml)
//Now save the value of the proper node to a property (this fails)
properties[ "finalValue" ] = page.find {
it.attributes().find { it.key.equalsIgnoreCase( 'id' ) }.value == "myNode"
};
I just need to account for nodes without "id" attribute so it doesn't fail. How do I do that?
You could alternatively use the GPath notation, and check if "#id" is empty first.
The following code snippet finds the last element (since the id attribute is "B" and the value is also "bizz", it prints out "bizz" and "B").
def xml = new XmlSlurper().parseText("<foo><bar>bizz</bar><bar id='A'>bazz</bar><bar id='B'>bizz</bar></foo>")
def x = xml.children().find{!it.#id.isEmpty() && it.text()=="bizz"}
println x
println x.#id
Apprently I can get it to work when I simply use depthFirst. So:
properties[ "finalValue" ] = page.depthFirst().find {
it.attributes().find { it.key.equalsIgnoreCase( 'id' ) }.value == "myNode"
};

help with oauthService and linkedin

I am trying to iterate over a list of parameters, in a grails controller. when I have a list, longer than one element, like this:
[D4L2DYJlSw, 8OXQWKDDvX]
the following code works fine:
def recipientId = params.email
recipientId.each { test->
System.print(test + "\n")
}
The output being:
A4L2DYJlSw
8OXQWKDDvX
But, if the list only has one item, the output is not the only item, but each letter in the list. for example, if my params list is :
A4L2DYJlSwD
using the same code as above, the output becomes:
A
4
L
2
D
Y
J
l
S
w
can anyone tell me what's going on and what I am doing wrong?
thanks
jason
I run at the same problem a while ago! My solution for that it was
def gameId = params.gameId
def selectedGameList = gameId.class.isArray() ? Game.getAll(gameId as List) : Game.get(gameId);
because in my case I was getting 1 or more game Ids as parameters!
What you can do is the same:
def recipientId = params.email
if(recipientId.class.isArray()){
// smtg
}else{
// smtg
}
Because what is happening here is, as soon as you call '.each' groovy transform that object in a list! and 'String AS LIST' in groovy means char_array of that string!
My guess would be (from what I've seen with groovy elsewhere) is that it is trying to figure out what the type for recipientId should be since you haven't given it one (and it's thus dynamic).
In your first example, groovy decided what got passed to the .each{} closure was a List<String>. The second example, as there is only one String, groovy decides the type should be String and .each{} knows how to iterate over a String too - it just converts it to a char[].
You could simply make recipientId a List<String> I think in this case.
You can also try like this:
def recipientId = params.email instanceof List ? params.email : [params.email]
recipientId.each { test-> System.print(test + "\n") }
It will handle both the cases ..
Grails provides a built-in way to guarantee that a specific parameter is a list, even when only one was submitted. This is actually the preferred way to get a list of items when the number of items may be 0, 1, or more:
def recipientId = params.list("email")
recipientId.each { test->
System.print(test + "\n")
}
The params object will wrap a single item as a list, or return the list if there is more than one.

Resources