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 Summary
Modifier and TypeMethodDescriptionstatic PredicateFolds conjuncts back into a single predicate as a left-deepAndPredicatechain — the inverse ofconjuncts(com.darkcollective.relix.ast.Predicate).Splitspinto its top-level conjuncts.equalityLiteralFor(Predicate p, String column) Returns the literal thatcolumnis pinned to, ifpis an equality between that column and a constant.static booleanReturns whetheropis a reference tocolumn, comparing case-insensitively and ignoring any relation qualifier — soUsers.id,id, andIDall match"id".static booleanReturns whetheropis a compile-time constant literal.
-
Method Details
-
conjuncts
Splitspinto its top-level conjuncts.Descends only through
AndPredicate; every other node — including anORorNOTthat 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
Folds conjuncts back into a single predicate as a left-deepAndPredicatechain — the inverse ofconjuncts(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- ifconjunctsis empty
-
isLiteral
Returns whetheropis 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:
trueif the operand is a literal constant
-
isColumn
Returns whetheropis a reference tocolumn, comparing case-insensitively and ignoring any relation qualifier — soUsers.id,id, andIDall match"id".- Parameters:
op- the operand to test; must not be nullcolumn- the bare column name to match; must not be null- Returns:
trueif the operand references that column
-
equalityLiteralFor
Returns the literal thatcolumnis pinned to, ifpis an equality between that column and a constant.Accepts either argument order, so both
id = 5and5 = idyield the literal5. Any other predicate — a different operator, a different column, or a comparison against something computed — yieldsOptional.empty().- Parameters:
p- the predicate to inspect; must not be nullcolumn- the bare column name of interest; must not be null- Returns:
- the literal the column equals, or empty
-