Escape dot from GString - sql

I would like to learn how to escape dot in GString so groovy (1.8) does not treat it as a part of an variable inside sql.execute. I have the following code:
Map<String, String> dbSettings = [schemaName:"testSchema"];
String myDbPrefix = dbSetting.schemaName + ".";
sql.execute "DELETE FROM ${myDbPrefix}myTable"
And I got this error:
Ignoring groovy.lang.MissingPropertyException: No such property: myTable for class: java.lang.String
Clearly indicating that . was interpreted as part of variable ${myDbPrefix}.

Does escaping the embedded variable help?
  sql.execute "DELETE FROM ${Sql.expand myDbPrefix}myTable"

I got hit by this problem today. GStrings get handled by a special way in GroovySQL. It's mentioned in the javadoc. It does automatic parameter binding.
Each value in the GString will become a parameter (?) which gets set as a JDBC prepared statement parameter.
What a surprise!
I'm going to fix the problem in my application by subclassing the Sql class and overriding the GString handling with plain ".toString()" .
Documented in Groovy wiki:
GString Use Cases - GSQL Another use case for GString is GSQL where
parameters can be passed into SQL statements using this same mechanism
which makes for a neat way to integrate Groovy with other languages
like SQL. GroovySql then converts the expressions to ? and uses a JDBC
PreparedStatement and passes the values in, preserving their types.
If you explicitly want to coerce the GString to a String you can use
the toString() method. Groovy can also automatically coerce GStrings
into Strings for you.

Related

Syntax error when using Spring #ConditionalOnExpression in Kotlin

I import in a Kotlin configuration class the
org.springframework.boot.autoconfigure.condition.ConditionalOnExpression
but I get the error message of An annotation argument must be a compile-time constant from IntelliJ when I use the annotation with Spring expression language on a bean definition
#ConditionalOnExpression("${xxx.enabled:true} or ${yyy.enabled:true}")
The xxx.enabled and yyy.enabled are configured in a yml file.
What could be the problem? Thanks.
In Kotlin, the $ operator is used for string interpolation. When your annotation contains #ConditionalOnExpression("${xxx.enabled:true} or ${yyy.enabled:true}") it tries to interpolate whatever is in the curly braces into your string - this makes the string not a compile-time constant. You need to escape the $ to tell the Kotlin compiler not to treat that as an interpolated String. Spring will inject the values into the annotation at run time.
#ConditionalOnExpression("\${xxx.enabled:true} or \${yyy.enabled:true}")

How do I replace multiple characters in a String?

How do I replace multiple characters in a String?
Like Java's replaceAll(regex:replacement:) function.
str.replaceAll("[$,.]", "") //java code
This answer is very close but I want to change more than one character at the same time.
[$,.] is regex, which is the expected input for Java's replaceAll() method. Kotlin, however, has a class called Regex, and string.replace() is overloaded to take either a String or a Regex argument.
So you have to call .toRegex() explicitly, otherwise it thinks you want to replace the String literal [$,.]. It's also worth mentioning that $ in Kotlin is used with String templates, meaning in regular strings you have to escape it using a backslash. Kotlin supports raw Strings (marked by three " instead of one) which don't need to have these escaped, meaning you can do this:
str = str.replace("""[$,.]""".toRegex(), "")
In general, you need a Regex object. Aside using toRegex() (which may or may not be syntactical sugar), you can also create a Regex object by using the constructor for the class:
str = str.replace(Regex("""[$,.]"""), "")
Both these signal that your string is regex, and makes sure the right replace() is used.
If you're happy to work with regular expressions, then refer to the accepted answer here. If you're curious as to how you can achieve this without regular expressions, continue reading.
You can use the String.filterNot(predicate:) and Set.contains(element:) functions to define a String.removeAll extension function as follows:
/**
* #param charactersToRemove The characters to remove from the receiving String.
* #return A copy of the receiving String with the characters in `charactersToRemove` removed.
*/
fun String.removeAll(charactersToRemove: Set<Char>): String {
return filterNot { charactersToRemove.contains(it) }
}
You would call on this function as follows: myString.removeAll(setOf('$', '.'))

Why does this Kotlin method have enclosing backticks?

What are the backticks used for in the snippet below?
Why add them around the fun is(amount:Int ):Boolean { ... }?
verifier.`is`(amount)
It's because is is a reserved keyword in Kotlin. Since Kotlin is supposed to be interoperable with Java and is is a valid method (identifier) name in Java, the backticks are used to escape the method so that it can be used as a method without confusing it as a keyword. Without it it will not work because it would be invalid syntax.
This is highlighted in the Kotlin documentation:
Escaping for Java identifiers that are keywords in Kotlin
Some of the Kotlin keywords are valid identifiers in Java: in, object, is, etc. If a Java library uses a Kotlin keyword for a method, you can still call the method escaping it with the backtick (`) character
foo.`is`(bar)
Useful for tests
Backticks are very useful in tests for long function names:
#Test
fun `adding 3 and 4 should be equal to 7`() {
assertEquals(calculator.add(3, 4), 7)
}
This makes the function names more readable. We can add spaces and other special characters in the function names. However, remember to use it only in tests, it's against the Kotlin coding conventions of the regular code.
It allows you to call a Java method whose name is a Kotlin keyword. It won't work if you leave out the backticks.
The backtick are a "workaround" to allow you to call methods that have a name representing a Kotlin keyword.
See kotlinlang:
Some of the Kotlin keywords are valid identifiers in Java: in, object, is, etc. If a Java library uses a Kotlin keyword for a method, you can still call the method escaping it with the backtick (`) character
is in list of Kotlin reserved words
To use Kotlin reserved word (such as is or object) for function/class name you should wrap it to backticks
Some of the Kotlin keywords are valid identifiers in Java: in, object, is, etc. If a Java library uses a Kotlin keyword for a method, you can still call the method escaping it with the backtick (`) character
https://kotlinlang.org/docs/reference/java-interop.html

String template to set the default value of PARAMETER

Is it possible, in ABAP, to evaluate string templates dynamically?
Normally, you will have some string template in code that will be checked by the compiler. (The variables in the curly brackets are checked by the compiler at compile time).
However, is it possible to have a string evaluated at runtime?
So, instead of:
data(val) = |System ID: { sy-sysid }|.
I would like the string to be interpolated to come from elsewhere, for example:
parameter: p_file type string lower case default '/mnt/{ sy-sysid }/file.txt'.
In this case, I would like to have the value of p_file to be evaluated at runtime to substitute the variable (sy-sysid) with the runtime value.
You could, of course, program your own substitution by finding all occurrences of variables with curly brackets with a regex expression, then evaluate the variable values with ASSIGN and substitute them back into the string, but I am looking for a built-in way to do this.
Sorry, this is maybe a stupid example, but hopefully you understand what I mean. (If not, please let me know in the comments and I will try and clarify).
The problem in your snippet is not with string template but with PARAMETER behavior. It does not allow dynamics in DEFAULT clause.
To achieve what you want you should use INITIALIZATION and set path value in runtime:
parameter: p_file type string lower case.
INITIALIZATION.
p_file = | /mnt/{ sy-sysid }/file.txt |.
Unfortunately, the example you gave, does not make any sense to me. ABAP String templates are evaluated at run-time and type-checked at compile-time.
In your example, it is always the run-time value of SY-SYSID that will be written to the variable.
I guess what you want to do is circumvent compile-time checks for expressions inside a string template.
Please try to give us your actual use case, so maybe we find an even better solution to your problem.
However, here is what I think could help you:
Personally, I do not recommend to write code like the one below, because it is extremely error-prone likely to mislead other programmers and because there is very likely a better solution.
Given that you know the name of a variable at run-time, try this:
".. say LV_VARNAME is a charlike variable that contains a
" variable name at runtime.
"NOTE that the variable LV_VARNAME must be visible in the scope of the
"following code.
FIELD-SYMBOLS: <my_var> TYPE any.
ASSIGN (lv_varname) TO <my_var>.
DATA(lv_str) = |The value is { <my_var> }|.

Pass Java List to SQL query Grails

i have a populated list:
def someList=... (string values)
and I want to pass this into a SQL statement to restrict which columns the query selects.
db.rows("select ${someList} from arch_application")
However, I get this error when I try to do so:
There is a ? parameter in the select list. This is not allowed.
Anyone have an ideas? Thanks!
When you pass a GString to Sql.rows, it gets parsed differently than normal in groovy. In particular, it creates a PreparedStatement with replaceable parameters for ${} substitutions. In your case this is probably not what you want. Try forcing the GString to a Java string:
db.rows("select ${someList.join(',')} from arch_application" as String)