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);
Comparator<Record<?>> comparator = intValue.asComparator(); // <1>
ToIntFunction<Record<?>> incremented = intValue.increment(); // <2>
1 | A numeric open range predicate. Ranges are available for all comparable cell types. |
2 | An integer extracting function that returns a specialized builder type, that is also a primitive int bearing function. |
3 | An integer extracting function that outputs the value incremented (+1). |
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.
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, 42); // <2>
UpdateOperation.CellUpdateOperation<Long, Integer>
increment = UpdateOperation.write(defnA, defnA.intValueOr(0).increment()); // <3>
UpdateOperation.CellUpdateOperation<Long, Integer>
copy = UpdateOperation.write(defnB, 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.