Groovy variables in query strings

Using your own Groovy variables, closures, and classes in Deephaven query strings is one of Deephaven's most powerful features. This guide covers three common kinds of Groovy variables: scalars, strings, and lists or arrays. It starts with the rules that decide which variables a query string can see and what column types they produce.

Rules for Groovy variables in query strings

Query strings find Groovy variables through Deephaven's query scope. In a Groovy session, the query scope is the script session's variable binding, which holds the variables a script assigns without def or a type.

The first four rules below decide which variables a query string can see:

  • A variable assigned without def or a type is in the binding, so a query string can use it by name. This includes a top-level assignment such as a = 4. It also includes an assignment inside a closure, such as { -> z = 5 }, once the closure runs.
  • A variable declared with def or a type, such as def a = 4 or int a = 4, is local to the script and isn't in the binding. Neither is a variable declared inside a method or closure. A query string that uses one fails with a "Cannot find variable or class" error. To fix it, add the variable with QueryScope.addParam, as Local (function) scope shows.
  • A variable with the same name as a column of the table is hidden, even when it's in the binding. The query string reads the column instead, with no error. See Columns take precedence over variables.
  • A variable named i, ii, or k is hidden too. Those names are built-in variables for row position and row key, so the query string always reads the built-in. The name not is reserved as well. Give your variable a different name.

The last two rules decide what column types those variables produce:

  • A column's type comes from the variable's Groovy type:
    • A boxed number becomes a primitive. An Integer gives an int column, and a Double gives a double column.
    • A Boolean gives a java.lang.Boolean column.
    • A decimal literal such as 3.14 is a java.math.BigDecimal in Groovy, not a double. It gives a BigDecimal column unless you cast it. See Scalars.
  • Indexing into a Groovy list returns Object, so cast the element to the type you want. Indexing into a Java primitive array, such as int[], keeps the element type. See Lists and arrays.

Every example on this page assigns its variables at the top level, without def or a type, so they are all in the binding.

Scalars

Scalars are single values, such as numbers or booleans. A query string uses a scalar by its variable name, with no special syntax. The following example uses Groovy variables in query strings to create new columns in a table:

The meta table, sourceMeta, shows each column's type:

  • A is an int.
  • B and C are java.math.BigDecimal. Groovy reads every decimal literal as a BigDecimal, including one with an exponent such as -1.91e7.
  • D is a java.lang.Boolean.

To get a double column instead of a BigDecimal one, do one of these:

  • Cast the variable in the query string: "B = (double)b". See type casts.
  • Give the literal a d suffix: b = 3.14d.

Strings

Like scalars, a Groovy string goes into a query string by its variable name, with no special syntax. The following example creates a table with two string columns:

The meta table, sourceMeta, shows that both columns are java.lang.String.

A string that interpolates a value, such as "Hello ${name}", is a Groovy GString, not a java.lang.String. In a query string, it makes a GStringImpl column. A match filter that compares it with a String column finds no rows, and it raises no error. To avoid this, call toString when you assign the string, for example greeting = "Hello ${name}".toString(). See Strings for more.

Lists and arrays

You can also use Groovy lists and Java arrays in query strings. A Groovy list literal such as [1, 2, 3] is a java.util.ArrayList:

The sourceListMeta table shows that ListColumn holds the whole list as a single java.util.ArrayList object.

You can also extract individual elements in a query string. For a list, myList[0] becomes myList.get(0), which returns Object. Use type casts to get the column type you want:

With the casts, FirstElement, SecondElement, and ThirdElement are all int columns.

To use a Java primitive array instead, convert the list with as, for example myArray = [1, 2, 3] as int[]. Don't declare it as int[] myArray = [1, 2, 3]. A typed declaration isn't in the binding, so a query string can't see it.

In the following example, ArrayColumn holds the whole int[]. Indexing into a primitive array keeps the element type, so FirstElement is an int with no cast: