Modify groovy method call with if statement - if-statement

I want to have a method call where if !row[connected].equals("")
then
Event(id: "event_${row[eventid]}", externalId: "event_${row[eventid]}", connected: row[connected]){
but if row[connected].equals("")
then
Event(id: "event_${row[eventid]}", externalId: "event_${row[eventid]}"){
I don't want to copy the code twice in an if else statement because there is a ton of code inside the brace of the Event method
Can i do this simply with dollar signs for example so that the call will still work?

Method calls with named arguments in Groovy are simply passing a Map to the method, so you could say
def eventParams = [
id: "event_${row[eventid]}", externalId: "event_${row[eventid]}"
]
if(row[connected]) { // empty string is Groovy-false, non-empty is true
eventParams.connected = row[connected]
}
Event(eventParams)

Or a cheeky one-liner:
Event( [ id : "event_${row[eventid]}",
externalId: "event_${row[eventid]}" ] <<
row[connected] == '' ? [:] : [ connected: row[connected] ] )

Related

Build Elasticsearch query dynamically by extracting fields to be matched from the Lambda event in AWS Elasticsearch service

I want to write a query to match indexed fields in Elasticsearch. I am using AWS Elasticsearch service and writing the query as an AWS Lambda function. This lambda function is executed when an event occurs, searches for a fields sent in the event, matches the fields with the indexed documents and returns the matched documents.
However, we don't know the fields or the number of fields to be searched ahead of time. So I want to be able to extract the fields from the event in the lambda function and construct the query dynamically to match the fields with the indexed documents.
The event is as follows:
{
"headers": {
"Host": "***"
},
"queryStringParameters": {
"fieldA": "abc",
"fieldB": "def"
}
}
The lambda function is as follows. This function expects two fields and matches them.
def search(event, context):
fields = list(event['queryStringParameters'].keys())
firstField = fields[0]
secondField = fields[1]
values = list(event['queryStringParameters'].values())
firstValue = values[0]
secondValue = values[1]
query = {
"query": {
"bool" : {
"must" :[
{"match" : { firstField : firstValue }},
{"match" : { secondField : secondValue }}
]
}
}
}
How can I rewrite my query so it dynamically accepts the fields and the number of fields that the event sends (not known ahead of time)?
Not sure what your exact requirements are but you could go with the following:
def search(event, context):
query = {
"query": {
"bool": {
"query_string": {
"query": " OR ".join([
"(%s:'%s')" % (k, v) for (k, v) in event["queryStringParameters"].items()
])
}
}
}
}
print(query)
which'd result in a proper query_string_query:
{
"query":{
"bool":{
"query_string":{
"query":"(fieldB:'def') OR (fieldA:'abc')"
}
}
}
}
You could interchange the OR with an AND. Also keep in mind that when the values are wrapped in quotes, ES will enforce exact matches. Leave them out in case you're after a contains behavior (i.e. a match query).

How to exclude substring in Elasticsearch regexp

I'm trying to write an elasticsearch regexp that excludes elements that have a key that contains a substring, let's say in the title of books.
The elasticsearch docs suggest that a substring can be excluded with the following snippet:
#&~(foo.+) # anything except string beginning with "foo"
However, in my case, I've tried to create such a filter and failed.
{
query: {
constant_score: {
filter: {
bool: {
filter: query_filters,
},
},
},
},
size: 1_000,
}
def query_filters
[
{ regexp: { title: "#&~(red)" } },
# goal: exclude titles that start with "Red"
]
end
I've used other regexp in the same query filter that have worked, so I don't think there's a bug in the way the regexp is being passed to ES.
Any ideas? Thanks in advance!
Update:
I found a workaround: I can add a must_not clause to the filter.
{
query: {
constant_score: {
filter: {
bool: {
filter: query_filters,
must_not: must_not_filters,
},
},
},
},
size: 1_000,
}
def must_not_filters
[ { regexp: { title: "red.*" } } ]
end
Still curious if there's another idea for the original regex though

Strongloop Looback Where Or filter in REST syntax

I need to query where descr like 'xxx' or short_descr like 'xxx'
I know how to do it using:
{"where": {
"or": [
{"description": {"like": "xxx"}},
{"short_description": {"like": "xxx"}}
}
}
}
but need to add query params in REST syntax.
I'm trying:
params['filter[where][or]'] = JSON.stringify([
{ "description": { "like": "xxx" } },
{ "short_description": { "like": "xxx" } }
])
with The or operator has invalid clauses result.
Here is an example (I used 'desc' instead of 'description'):
http://localhost:3000/api/cats?filter[where][or][0][desc][like]=foo&filter[where][or][1][short_desc][like]=goo
So the important parts are this:
First, you need to give an index to each part of the OR clause. Note the first one is 0, then 1.
Secondly - um... I thought I had more, but that's pretty much it.
More information on WHERE filters: https://docs.strongloop.com/display/LB/Where+filter

groovy: create a list of values with all strings

I am trying to iterate through a map and create a new map value. The below is the input
def map = [[name: 'hello', email: ['on', 'off'] ], [ name: 'bye', email: ['abc', 'xyz']]]
I want the resulting data to be like:
[hello: ['on', 'off'], bye: ['abc', 'xyz']]
The code I have right now -
result = [:]
map.each { key ->
result[random] = key.email.each {random ->
"$random"
}
}
return result
The above code returns
[hello: [on, off], bye: [abc, xyz]]
As you can see from above, the quotes from on, off and abc, xyz have disappeared, which is causing problems for me when i am trying to do checks on the list value [on, off]
It should not matter. If you see the result in Groovy console, they are still String.
Below should be sufficient:
map.collectEntries {
[ it.name, it.email ]
}
If you still need the single quotes to create a GString instead of a String, then below tweak would be required:
map.collectEntries {
[ it.name, it.email.collect { "'$it'" } ]
}
I personally do not see any reasoning behind doing the later way. BTW, map is not a Map, it is a List, you can rename it to avoid unnecessary confusions.
You could convert it to a json object and then everything will have quotes
This does it. There should/may be a groovier way though.
def listOfMaps = [[name: 'hello', email: ['on', 'off'] ], [ name: 'bye', email: ['abc', 'xyz']]]
def result = [:]
listOfMaps.each { map ->
def list = map.collect { k, v ->
v
}
result[list[0]] = ["'${list[1][0]}'", "'${list[1][1]}'"]
}
println result

How can I get rid of "no such property" when testing a class that accesses Item.constraints.xyz?

The following constellation in a unit test returns: No such property: title for class: myproject.Item Possible solutions: title
ItemController.groovy
def add = {
[itemInstance: new Item(), titleMin: Item.constraints.title.size.min() ]
}
ItemControllerSpec.groovy
mockDomain Item
def result = controller.add()
How can I mock out that constraints line?
Note: I just want the test to run instead of failing due to that line.
Via metaClass. In setUp(), write something like:
Item.metaClass.'static'.constraints = [ title: [ size: [ min: {5}, max: {30} ] ] ]
If your test class extends GrailUnitTestCase, call mockForConstraintsTests(Item) before the test executes. If you can't extend this class, try invoking grails.test.MockUtils.prepareForConstraintsTests(Item) before the test executes.