1

I'm executing a query on RDBMS and getting the result as a String. The String looks something like this:

val DBASE = "my_database"
val FREQ = "monthly"
val queryResult: String = sqlContext.read.jdbc(...).collect.map(...).first
// queryResult = Database is $$${DBASE} and frequency is $$${FREQ}

Next I'm replacing $$$ with $, so I'm left with something like:

queryResult = "Database is ${DBASE} and frequency is ${FREQ}"

How to use String Interpolation on DBASE and FREQ? I have tried:

val substituted = f"${queryResult}"

and

val substituted = s"${queryResult}"

But the variables are not getting replaced. Is there something else I can do apart from using the following :

queryResult.replaceAll("\\$\\{DBASE\\}", DBASE).replaceAll(...)

3 Answers 3

5

One option is to let scripting do your templating:

     ________ ___   / /  ___  
    / __/ __// _ | / /  / _ | 
  __\ \/ /__/ __ |/ /__/ __ | 
 /____/\___/_/ |_/____/_/ | | 
                          |/  version 2.12.6

scala> import javax.script._
import javax.script._

scala> val se = new ScriptEngineManager().getEngineByName("scala")
se: javax.script.ScriptEngine = scala.tools.nsc.interpreter.Scripted@6549ce71

scala> val b = se.createBindings
b: javax.script.Bindings = javax.script.SimpleBindings@2648aa1b

scala> b.put("DBASE", "my_db")
res0: Object = null

scala> b.put("FREQ", "monthly")
res1: Object = null

scala> se.eval("""s"Db is $DBASE, freq is $FREQ"""", b)
res2: Object = Db is my_db, freq is monthly

The bound objects aren't well-typed, but you can cast or what have you and do more computation:

scala> se.eval("""s"Db is $DBASE, freq is ${FREQ.toString * 2}"""", b)
res4: Object = Db is my_db, freq is monthlymonthly
Sign up to request clarification or add additional context in comments.

Comments

2

Scala's string interpolation

s"Database is ${DBASE} and frequency is ${FREQ}"

is essentially just fancy syntax for a method call on StringContext. It desugars to something like

StringContext("Database is ", " and frequency is ",  "").s(DBASE, FREQ)

While you could theoretically split the string "Database is ${DBASE} and frequency is ${FREQ}" into pieces that are appropriate for StringContext, and then look up the variables DBASE and FREQ somewhere, it seems that it is much easier to replaceAll occurrences of $$${DBASE} and $$${FREQ} right away.

3 Comments

It's just that string is almost 50,000 characters ( a parameterized SQL query that I need to execute ) so I don't think it'll be very feasible to split and use StringContext. Guess I'll use replaceAll then.
@philantrovert I'm not sure why you are trying to manually plug in parameters into queries that are returned by other queries... Seems like a strange stringly-typed design. Is there no way to use some kind of prepared statement instead?
No, the query needs to be passed to hive.
0

I think it is not possible dynamically to interpolate a string as it happens during compile time itself.

1) String interpolation happens at compile time, so the compiler does not generally have enough information to interpolate s(queryResult). It expects a string literal, according to https://docs.scala-lang.org/sips/string-interpolation.html.

2) Under Advanced Usage in the documentation, it is explained that an expression of the form id"Hello $name ." is translated at compile time to new StringContext("Hello", "."). id(name).

So you can create something like

StringContext("Database is ", " and frequency is ",  "").s(DBASE, FREQ)

which will substitute the syntactic suger. Hope that helps.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.