java.lang.Object
com.darkcollective.relix.ast.internal.Predicates

public final class Predicates extends Object
Utilities for taking a Predicate tree apart and putting it back together.

Splitting a filter into its top-level conjuncts, deciding which of them a rewrite may move, and re-conjoining the remainder is the shape of nearly every selection-pushdown rule. These helpers live here — beside the AST they operate on — so that the passes performing those rewrites share one definition rather than each carrying a private copy.

That sharing is not cosmetic. The copies had already drifted: one isLiteral predated the temporal types and still recognised only NUMBER/STRING/BOOLEAN, so a rewrite keyed on it silently skipped temporal literals.

Note that a conjunct-splitter which also validates — rejecting OR/NOT rather than treating them as opaque leaves — is a different operation and deliberately not folded in here.

  • Method Details

    • conjuncts

      public static List<Predicate> conjuncts(Predicate p)
      Splits p into its top-level conjuncts.

      Descends only through AndPredicate; every other node — including an OR or NOT that may itself contain conjunctions — is an opaque leaf. a ∧ (b ∧ c) yields [a, b, c]; a predicate that is not a conjunction at all yields itself.

      Parameters:
      p - the predicate to split; must not be null
      Returns:
      its top-level conjuncts, in left-to-right order; never empty
    • conjoin

      public static Predicate conjoin(List<Predicate> conjuncts)
      Folds conjuncts back into a single predicate as a left-deep AndPredicate chain — the inverse of conjuncts(com.darkcollective.relix.ast.Predicate).

      Each combining node takes its location from the right-hand conjunct, so a diagnostic points at the conjunct being added rather than the whole chain.

      Parameters:
      conjuncts - the conjuncts to combine; must not be null or empty
      Returns:
      the conjunction, or the sole element when there is only one
      Throws:
      IllegalArgumentException - if conjuncts is empty
    • isLiteral

      public static boolean isLiteral(Operand op)
      Returns whether op is a compile-time constant literal.

      True for every literal operand form the language has, including the temporal literals. False for anything computed — an attribute reference, an arithmetic expression, a function call, or a set/struct/array construction.

      Parameters:
      op - the operand to classify; must not be null
      Returns:
      true if the operand is a literal constant
    • isColumn

      public static boolean isColumn(Operand op, String column)
      Returns whether op is a reference to column, comparing case-insensitively and ignoring any relation qualifier — so Users.id, id, and ID all match "id".
      Parameters:
      op - the operand to test; must not be null
      column - the bare column name to match; must not be null
      Returns:
      true if the operand references that column
    • equalityLiteralFor

      public static Optional<Operand> equalityLiteralFor(Predicate p, String column)
      Returns the literal that column is pinned to, if p is an equality between that column and a constant.

      Accepts either argument order, so both id = 5 and 5 = id yield the literal 5. Any other predicate — a different operator, a different column, or a comparison against something computed — yields Optional.empty().

      Parameters:
      p - the predicate to inspect; must not be null
      column - the bare column name of interest; must not be null
      Returns:
      the literal the column equals, or empty