66import dev .vortex .api .Expression ;
77import dev .vortex .api .Expression .BinaryOp ;
88import dev .vortex .api .Expression .TimeUnit ;
9+ import java .math .BigDecimal ;
10+ import java .math .BigInteger ;
11+ import java .util .ArrayList ;
12+ import java .util .Arrays ;
13+ import java .util .List ;
14+ import java .util .Map ;
15+ import java .util .Optional ;
916import org .apache .spark .sql .connector .expressions .Literal ;
1017import org .apache .spark .sql .connector .expressions .NamedReference ;
1118import org .apache .spark .sql .connector .expressions .filter .AlwaysFalse ;
3340import org .apache .spark .sql .types .TimestampType ;
3441import org .apache .spark .unsafe .types .UTF8String ;
3542
36- import java .math .BigDecimal ;
37- import java .math .BigInteger ;
38- import java .util .ArrayList ;
39- import java .util .Arrays ;
40- import java .util .List ;
41- import java .util .Map ;
42- import java .util .Optional ;
43-
4443/**
4544 * Translates {@link Predicate Spark V2 predicates} into Vortex {@link Expression}s for predicate pushdown.
4645 *
5049 */
5150final class SparkPredicateToVortexExpression {
5251
53- private SparkPredicateToVortexExpression () {
54- }
52+ private SparkPredicateToVortexExpression () {}
5553
5654 /**
5755 * Returns true if the given Spark predicate can be translated to a Vortex expression and every named reference
5856 * resolves to a real field path under {@code dataColumnTypes}.
5957 *
6058 * <p>{@code dataColumnTypes} maps each pushable top-level column name to its top-level Spark {@link DataType};
61- * partition columns and columns the scan does not project should not appear in the map. For nested references
62- * (for example {@code info.email}) the validator walks the named reference part by part, descending into
59+ * partition columns and columns the scan does not project should not appear in the map. For nested references (for
60+ * example {@code info.email}) the validator walks the named reference part by part, descending into
6361 * {@link StructType} fields so that {@code info} must be a struct that contains an {@code email} field.
6462 *
6563 * <p>This is the cheap check used in {@code SupportsPushDownV2Filters.pushPredicates} to decide which predicates
@@ -77,8 +75,7 @@ static boolean isPushable(Predicate predicate, Map<String, DataType> dataColumnT
7775
7876 /**
7977 * Walks {@code parts} against {@code dataColumnTypes}, descending through {@link StructType} fields for
80- * dot-separated nested references. Returns true only when every part resolves to an actual field in the
81- * schema.
78+ * dot-separated nested references. Returns true only when every part resolves to an actual field in the schema.
8279 */
8380 private static boolean resolveFieldPath (String [] parts , Map <String , DataType > dataColumnTypes ) {
8481 if (parts .length == 0 ) {
@@ -102,7 +99,9 @@ private static boolean resolveFieldPath(String[] parts, Map<String, DataType> da
10299 }
103100
104101 private static Optional <StructField > findField (StructType struct , String name ) {
105- return Arrays .stream (struct .fields ()).filter (structField -> structField .name ().equals (name )).findFirst ();
102+ return Arrays .stream (struct .fields ())
103+ .filter (structField -> structField .name ().equals (name ))
104+ .findFirst ();
106105 }
107106
108107 private static boolean isStructurallyPushable (Predicate predicate ) {
@@ -135,7 +134,7 @@ private static boolean isStructurallyPushable(Predicate predicate) {
135134 yield true ;
136135 }
137136 case "STARTS_WITH" , "ENDS_WITH" , "CONTAINS" ->
138- children .length == 2 && isPushableFieldRef (children [0 ]) && isPushableStringLiteral (children [1 ]);
137+ children .length == 2 && isPushableFieldRef (children [0 ]) && isPushableStringLiteral (children [1 ]);
139138 // `BOOLEAN_EXPRESSION` wraps a bare boolean-valued child. We only handle the case
140139 // where the child itself is a field reference (e.g. `WHERE bool_col`).
141140 case "BOOLEAN_EXPRESSION" -> children .length == 1 && isPushableFieldRef (children [0 ]);
@@ -178,12 +177,12 @@ static Optional<Expression> convert(Predicate predicate) {
178177 case "=" , "<>" , "!=" , ">" , ">=" , "<" , "<=" -> convertComparison (predicate .name (), children );
179178 case "IS_NULL" -> children .length == 1 ? columnOf (children [0 ]).map (Expression ::isNull ) : Optional .empty ();
180179 case "IS_NOT_NULL" ->
181- children .length == 1 ? columnOf (children [0 ]).map (Expression ::isNotNull ) : Optional .empty ();
180+ children .length == 1 ? columnOf (children [0 ]).map (Expression ::isNotNull ) : Optional .empty ();
182181 case "IN" -> convertIn (children );
183182 case "STARTS_WITH" ->
184- convertStringMatch (children , /* leadingWildcard= */ false , /* trailingWildcard= */ true );
183+ convertStringMatch (children , /* leadingWildcard= */ false , /* trailingWildcard= */ true );
185184 case "ENDS_WITH" ->
186- convertStringMatch (children , /* leadingWildcard= */ true , /* trailingWildcard= */ false );
185+ convertStringMatch (children , /* leadingWildcard= */ true , /* trailingWildcard= */ false );
187186 case "CONTAINS" -> convertStringMatch (children , /* leadingWildcard= */ true , /* trailingWildcard= */ true );
188187 case "BOOLEAN_EXPRESSION" -> children .length == 1 ? columnOf (children [0 ]) : Optional .empty ();
189188 default -> Optional .empty ();
@@ -327,9 +326,7 @@ private static boolean isFieldRefExpr(org.apache.spark.sql.connector.expressions
327326 return expr instanceof NamedReference ;
328327 }
329328
330- /**
331- * Returns the Vortex column expression for a Spark named reference, walking nested struct fields.
332- */
329+ /** Returns the Vortex column expression for a Spark named reference, walking nested struct fields. */
333330 private static Optional <Expression > columnOf (org .apache .spark .sql .connector .expressions .Expression expr ) {
334331 if (!(expr instanceof NamedReference )) {
335332 return Optional .empty ();
@@ -501,9 +498,7 @@ private static Optional<Expression> convertLiteral(Object value, DataType dataTy
501498 return Optional .empty ();
502499 }
503500
504- /**
505- * Extract the unscaled integer value of a Spark decimal literal at the supplied {@code scale}.
506- */
501+ /** Extract the unscaled integer value of a Spark decimal literal at the supplied {@code scale}. */
507502 private static BigInteger unscaledValueOf (Object value , int scale ) {
508503 BigDecimal decimal ;
509504 if (value instanceof Decimal ) {
0 commit comments