Class SearchOperator

java.lang.Object
org.apache.juneau.commons.beanquery.SearchOperator

public final class SearchOperator extends Object
The immutable definition of a single $-search operator — its $-name, arity, the value types it applies to, and its popup help text.

A custom operator always carries its own help text; the help text of a built-in (SearchOperatorSet.standard()) operator is owned by the browser runtime, so help() is null for built-ins. A custom operator additionally may carry a SearchPredicate the in-memory context calls when it hits that $-name — Juneau never invents one. Anything else a downstream module (for example a SQL renderer) needs to attach lives in the typed extension slot: it is keyed by the extension's own Class, so this module (commons) never needs to depend on that module's types (design §5.3).

Instances are built with SearchOperator.Builder: create(String, String) starts a new custom operator, and copy() starts a modified copy of an existing one (built-in or custom).

Combinators vs. leaves

$and/$or/$not are combinators: their children are sub-expressions, not literal value arguments, and they apply to every type. Every other operator is a leaf whose arguments are literal values and whose applicability is a fixed type set (an empty type set means "applies to all types").

Example (custom operator, with a typed extension):

SearchOperator op = SearchOperator.create("$near", "Fuzzy match. Example: $near(jhon)") .types(SearchType.TEXT) .predicate((cell, args) -> fuzzy(cell, args.get(0))) .extension(MySqlRenderer.class, myRenderer) .build(); // A later consumer that knows about MySqlRenderer retrieves it back, type-safe, with no cast. Optional<MySqlRenderer> renderer = op.extension(MySqlRenderer.class);

Since:
10.0.0
  • Method Details

    • create

      public static SearchOperator.Builder create(String name, String helpText)
      Starts a new custom (application-defined) leaf operator.

      Defaults: arity 1..* (one or more arguments), applies to all value types (an empty type set), no predicate, no extensions. Narrow it with SearchOperator.Builder.minArgs(int)/SearchOperator.Builder.maxArgs(int)/ SearchOperator.Builder.types(SearchType...) and attach an evaluator with SearchOperator.Builder.predicate(SearchPredicate) (in-memory) and/or a typed SearchOperator.Builder.extension(Class, Object) (for example, a SQL renderer).

      Parameters:
      name - The operator name, including the leading $ (e.g. "$near"). Must not be null or blank and must start with $.
      helpText - The popup help text: what the operator accepts and a short example. Must not be null or blank.
      Returns:
      A new SearchOperator.Builder pre-filled with name/helpText and the defaults above.
      Throws:
      IllegalArgumentException - If name is not a valid $-name or helpText is blank.
    • copy

      Starts a SearchOperator.Builder pre-filled with this operator's current state, for building a modified copy.

      The returned builder is fully independent of this instance: mutating it (or the SearchOperator it eventually builds) never affects this instance.

      Renaming is only legal for a copy of a custom operator. Both evaluation engines dispatch a built-in purely by its name() — the in-memory engine's leaf switch and SqlDialect#builtinRenderer(String) alike — so changing the name on a copy of a custom operator (one with its own predicate/ extension) is fine and gives it a fresh identity, but doing the same to a copy of a built-in operator throws IllegalArgumentException from build(). A built-in's copy may still have its help text changed freely; only its name is fixed.

      Returns:
      A new builder seeded from this operator.
    • name

      public String name()
      The operator name, including the leading $ (e.g. "$eq").
      Returns:
      The operator name.
    • help

      public String help()
      The human-readable help text for this operator, shown in the column-search popup.

      Built-in operators return null: their help text is owned by juneau-search.js, which the popup falls back to. Custom operators always return non-blank text, because SearchOperator.Builder.build() rejects a custom operator without it.

      Example:

      SearchOperator near = SearchOperator.create("$near", "Within N units. Example: $near(5)").build(); near.help(); // "Within N units. Example: $near(5)" SearchOperatorSet.standard().get("$eq").help(); // null

      Returns:
      The help text, or null for a built-in operator.
    • isCustom

      public boolean isCustom()
      Whether this is an application-defined custom operator (vs. a built-in).
      Returns:
      true if custom.
    • isCombinator

      public boolean isCombinator()
      Whether this is a combinator ($and/$or/$not) whose children are sub-expressions.
      Returns:
      true if a combinator.
    • minArgs

      public int minArgs()
      The minimum argument count (inclusive).
      Returns:
      The minimum arity.
    • maxArgs

      public int maxArgs()
      The maximum argument count (inclusive), or -1 for unbounded.
      Returns:
      The maximum arity, or -1.
    • predicate

      The in-memory evaluator for a custom operator, if one was supplied.
      Returns:
      The predicate, or null for built-ins and for customs with no predicate.
    • types

      public Set<SearchType> types()
      The value types this operator applies to (combinators apply to all types regardless of this set).
      Returns:
      An unmodifiable view of the applicable types; empty means "applies to all types".
    • appliesTo

      public boolean appliesTo(SearchType type)
      Whether this operator applies to the specified value type.
      Parameters:
      type - The column value type. Can be null.
      Returns:
      true if this operator is offered for that type (combinators, and operators with an empty type set, apply to every type).
    • acceptsArgCount

      public boolean acceptsArgCount(int count)
      Whether the specified argument count satisfies this operator's arity.
      Parameters:
      count - The number of arguments supplied.
      Returns:
      true if count is within [minArgs, maxArgs] (upper bound ignored when unbounded).
    • typedArgs

      public boolean typedArgs()
      Whether this operator's SQL renderer should be given typed values rather than literal strings. Never affects the in-memory predicate, which always receives literal strings.
      Returns:
      true if typed (see SearchOperator.Builder.typedArgs(boolean)).
    • extension

      public <X> Optional<X> extension(Class<X> type)
      Looks up a typed extension previously attached with SearchOperator.Builder.extension(Class, Object).

      This is how a downstream module (for example juneau-beanquery-sql's SQL renderer) attaches its own metadata to a custom operator without this module (commons) ever depending on that module's types: the extension is keyed by its own Class, so retrieval is type-safe with no cast (design §5.3).

      Type Parameters:
      X - The extension type.
      Parameters:
      type - The extension's class, used as the lookup key. Must not be null.
      Returns:
      The extension, or Optional.empty() if none was attached under that type.
    • equals

      public boolean equals(Object o)
      Overrides:
      equals in class Object
    • hashCode

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

      public String toString()
      Overrides:
      toString in class Object