Terracotta 10.11 | TCStore API Developer Guide | Reference | Functional DSL
 
Functional DSL
The functional DSL exists to allow users to express arguments passed to TCStore operations in a form that is both portable between clients and servers (over the network), and whose underlying behavior can be introspected and understood by the TCStore software. DSL expressions are the preferred form for all functional arguments passed to TCStore.
Cell Operations
Functional operations on cells and their associated values can be created via references to the associated cell definition objects.

BoolCellDefinition definition = defineBool("cell");
Predicate<Record<?>> exists = definition.exists(); // <1>
Predicate<Record<?>> isTrue = definition.isTrue(); // <2>
1
A cell existence predicate. The predicate returns true if the passed record contains a cell of this definition. This is available for all definition types.
2
A boolean cell value predicate. The predicate returns true if the passed record contains a cell of this definition with a true value (this means an absence of the cell results in a false value).
The types returned from the DSL are fluent builders so you can derive functions from existing functions.

StringCellDefinition definition = defineString("cell");
BuildableComparableOptionalFunction<Record<?>, String>
value = definition.value(); // <1>

Predicate<Record<?>> isFoo = value.is("foo"); // <2>
Predicate<Record<?>> isAfterBar = value.isGreaterThan("bar"); // <3>
1
A cell value extraction function. This is a subtype of Function<Record<?>, Optional<String>> but can also be built upon.
2
A value equality predicate. The predicate returns true if the passed record contains a cell of this definition whose value is "foo".
3
An open range predicate. The predicate returns true if the passed records contains a cell of this definition whose value is strictly greater than "bar".
The available build methods are specialized to the type of the cell in question. Numerically typed cells can be used to do numeric manipulations.
IntCellDefinition definition = defineInt("cell");

BuildableToIntFunction<Record<?>> intValue = definition.intValueOr(0); // <1>
BuildablePredicate<Record<?>> isGreaterThanOrEqualTo4 =
intValue.isGreaterThanOrEqualTo(4); // <2>
ToIntFunction<Record<?>> incremented = intValue.increment(); // <3>
Comparator<Record<?>> comparator = intValue.asComparator(); // <4>
1
An integer extracting function that returns a specialized builder type, that is also a primitive int bearing function.
2
A numeric open range predicate. Ranges are available for all comparable cell types.
3
An integer extracting function that outputs the value incremented (+1).
4
A comparator over extracted values.
Cell derived expressions will be frequently used as:
*Predicates for streams and CRUD operations.
*Mappers for streams and read operations.
*Input for functional update operations.
Complex Data Types (CDTs)
LIST and MAP typed cells have additional DSL concepts. Lists and Maps are not scalar values, they contain multitudes. This affects their interaction with the DSL in a couple of ways. First, they have three common DSL predicates that generate scalar values and thus integrate directly with the existing DSL: isEmpty(), notEmpty(), size().
For example, this fragment shows conditional filtering on a LIST cell.
ListCellDefinition listDef=...
...stream().filter(listDef.value().size().greaterThan(10)).
The LIST cell definition's value() family of methods use the BuildableListFunction hierarchy and add contains() to test if the list contains a specified TypedValue. The MAP cell definition's value() family of methods add containsKey() and containsValue().
Complex Data Type Content Selection
Querying inside CDTs requires using the find() method on all CDTs. This is accessible in the DSL via the corresponding find() family of functions on LIST or MAP cell definitions, or Record.find() if you wish to query on the entire Record.
These find() methods return variants of BuildableTypedValueSelectionFunction. This hierarchy allows further refinement of the resulting Selection via types, etc.
If at any point the DSL is used to restrict the subset to a typed scalar value, then that builder can be used with any of the existing DSL to construct possibly portable filters.
Update Operations
Update operation instances are used to express mutation used in either single-key update operations, or against stream contents via a MutableRecordStream operation. Update operations are created via static accessor methods on the UpdateOperation class
IntCellDefinition defnA = defineInt("cell-a");
IntCellDefinition defnB = defineInt("cell-b");

UpdateOperation<Long> install =
UpdateOperation.install(defnA.newCell(42), defnB.newCell(42)); // 1

UpdateOperation.CellUpdateOperation<Long, Integer> write =
UpdateOperation.write(defnA).value(42); // 2

UpdateOperation.CellUpdateOperation<Long, Integer> increment = // 3
UpdateOperation.write(defnA)
.intResultOf(defnA.intValueOr(0).increment());

UpdateOperation.CellUpdateOperation<Long, Integer> copy =
UpdateOperation.write(defnB).intResultOf(defnA.intValueOr(42));

UpdateOperation<Long> aggregate =
UpdateOperation.allOf(increment, copy); // 4
1
Install a specific list of cells. An install operation replaces all existing cells.
2
Write an individual cell. This will overwrite an existing cell or create a new one as necessary.
3
Write an individual cell with a value given by executing the given function against the current record.
4
Perform a list of individual cell updates as a single unit.
Update Output
Update operations output a pair of values representing the state before and after the mutation application. This is either in the form of a pair of values passed to a bi-function or as a tuple of records.

BiFunction<Record<?>, Record<?>, Integer> inputBiFunction =
UpdateOperation.input(defnA.valueOr(42)); // <1>
BiFunction<Record<?>, Record<?>, Integer> outputBiFunction =
UpdateOperation.output(defnA.valueOr(42)); // <2>

Function<Tuple<Record<?>, ?>, Integer> inputTupleFunction =
Tuple.<Record<?>>first().andThen(defnA.valueOr(42)); // <3>
Function<Tuple<?, Record<?>>, Integer> outputTupleFunction =
Tuple.<Record<?>>second().andThen(defnA.valueOr(42)); // <4>
1
Extract the input value of cell-a from the resultant bi-function's two arguments.
2
Extract the output value of cell-a from the resultant bi-function's two arguments.
3
Extract the value of cell-a from the first value of the resultant function's tuple argument.
4
Extract the value of cell-a from the second value of the resultant function's tuple argument.
Both tuple and bi-function forms follow the convention that input records are the first argument or tuple member, and output records are the second argument or tuple member.
Collectors
To support stream collection operations a mirror of the JDK java.util.stream.Collectors class that creates collectors transparent to TCStore at com.terracottatech.store.function.Collectors.