Class FunctionKeyExpression

  • All Implemented Interfaces:
    AtomKeyExpression, KeyExpression, KeyExpressionWithChild, KeyExpressionWithChildren, PlanHashable
    Direct Known Subclasses:
    CollateFunctionKeyExpression

    @API(EXPERIMENTAL)
    public abstract class FunctionKeyExpression
    extends BaseKeyExpression
    implements AtomKeyExpression, KeyExpressionWithChild
    A FunctionKeyExpression is a KeyExpression that is dynamically loaded and defined by a String name and a Key.Expression that produces sets of arguments to which the function is to be evaluated. FunctionKeyExpressions provide a mechanism by which indexes can be defined on arbitrarily complex logic applied to a record being inserted. For example, assuming a function called "substr" that functions much like the java String.substring() method, you could create, say, a unique index with key of
         function("subsstr", concat(field("firstname"), value(0), value(2)))
     
    Which would prevent duplicate records in which the first two characters of the firstname are identical.

    Similarly, the function can be made to apply in a fan-out fashion, simply by providing a argument an expression that itself fans out into a set of arguments to substr. For example, given message definitions such as:

     message SubString {
       required string content = 1;
       required int32 start = 2;
       required int32 end = 3;
     }
    
     message SubStrings {
       repeated SubString substrings = 1;
     }
     
    In which we want to have the arguments to substr driven by data stored in the records themselves, you could define the index key expression as:
         function("substr", field("substrings", FanType.FanOut).nest(concatenateFields("content", "start", "end")))
     
    This would produce the result of performing substr(content, start, end) for each SubStringvalue in substrings.

    Actual implementations of FunctionKeyExpressions are discovered by polling all available FunctionKeyExpression.Registry implementations. A Registry returns a list of FunctionKeyExpression.Builders which, given a set of arguments, are capable of creating an implementation of a function.

    • Method Detail

      • create

        public static FunctionKeyExpression create​(@Nonnull
                                                   String name,
                                                   @Nonnull
                                                   KeyExpression arguments)
        Create a function.
        Parameters:
        name - the name of the function
        arguments - an expression that produces the arguments to the function
        Returns:
        the key expression that implements the function
        Throws:
        KeyExpression.InvalidExpressionException - if the function name provided does not have an available implementation, or the arguments provided are not suitable for the function
      • getMinArguments

        public abstract int getMinArguments()
        Get the the minimum number of arguments supported by this function.
        Returns:
        the minimum number of arguments supported by this function
      • getMaxArguments

        public abstract int getMaxArguments()
        Get the maximum number of arguments supported by this function.
        Returns:
        the maximum number of arguments supported by this function
      • evaluateMessage

        @Nonnull
        public <M extends MessageList<Key.Evaluated> evaluateMessage​(@Nullable
                                                                       FDBRecord<M> record,
                                                                       @Nullable
                                                                       Message message)
        Description copied from interface: KeyExpression
        Evaluate this expression against a record or a Protobuf message. The message might be the Protobuf form of a record or a piece of that record. If the key expression is meaningful against a subrecord, it should evaluate against the message. Otherwise, it should evaluate against the record and ignore what part of that record is being considered. There should not be any reason to call this method outside of the implementation of another evaluateMessage. Under ordinary circumstances, if record is null, then message will be null. Otherwise, message will be record.getRecord() or some submessage of that, possibly null if the corresponding field is missing.
        Specified by:
        evaluateMessage in interface KeyExpression
        Type Parameters:
        M - the type of record
        Parameters:
        record - the record
        message - the Protobuf message to evaluate against
        Returns:
        the evaluated keys for the given record
        See Also:
        KeyExpression.evaluate(com.apple.foundationdb.record.provider.foundationdb.FDBRecord<M>)
      • evaluateFunction

        @Nonnull
        public abstract <M extends MessageList<Key.Evaluated> evaluateFunction​(@Nullable
                                                                                 FDBRecord<M> record,
                                                                                 @Nullable
                                                                                 Message message,
                                                                                 @Nonnull
                                                                                 Key.Evaluated arguments)
        The evaluateFunction method implements the function execution. This method is invoked once per Key.Evaluated that was produced by the evaluation of the function's argument. Put another way, the function's argument expression is evaluated and is expected to produce a set of arguments. This method is invoked once for each of these and, itself, may produce a set of Key.Evaluated values that produce the final set of keys.

        Note that the record parameter might be null. Function implementors should treat this case the same way that they would treat a non-null record that has all of its non-repeated fields unset and all of its repeated fields empty. If the function result depends only on the value of arguments and not record directly, then the implementor can ignore the nullity of record.

        Type Parameters:
        M - the type of the records
        Parameters:
        record - the record against which this function will produce a key
        message - the Protobuf message against which this function will produce a key
        arguments - the set of arguments to be applied by the function against the record
        Returns:
        the list of keys for the given record
      • normalizeForPlanner

        @Nonnull
        public KeyExpression normalizeForPlanner​(@Nonnull
                                                 Source source,
                                                 @Nonnull
                                                 List<String> fieldNamePrefix)
        Description copied from interface: KeyExpression
        Normalize this key expression into another key expression that pushes all nesting and fan-out to ElementKeyExpressions at the leaves.

        By default, a key expression is a complicated nested structure that can be difficult to work with. This method pushes much of the complexity, including nested structures and fan-out of repeated fields, to special key expressions that track these relationship using the Source abstraction. This pre-processing makes planning nested and repeated structures much simpler.

        This normalization process requires tracking some state since the name of a nested field is available only at the relevant FieldKeyExpression, but that information is necessary to construct the ElementKeyExpression at the leaves of the sub-tree rooted at the NestingKeyExpression. This extra information is tracked in the fieldNamePrefix.

        Specified by:
        normalizeForPlanner in interface KeyExpression
        Parameters:
        source - the source representing the input stream of the key expression
        fieldNamePrefix - the (non-repeated) field names on the path from the most recent source to this part of the key expression
        Returns:
        a new key expression that has only ElementKeyExpressions at its leaves
      • hashCode

        public int hashCode()
        Overrides:
        hashCode in class Object
      • planHash

        public int planHash()
        Description copied from interface: PlanHashable
        Return a hash similar to hashCode, but with the additional guarantee that is is stable across JVMs.
        Specified by:
        planHash in interface PlanHashable
        Returns:
        a stable hash code