@@ -1292,6 +1292,11 @@ private static final class FieldPath {
12921292 private record Element (String fieldName , Integer arrayIndex ) {
12931293 private static final String EMPTY_STRING = "" ;
12941294
1295+ /**
1296+ * Creates a new FieldPath Element which corresponds to a regular part of a field path.
1297+ * @param fieldName name of the field to access, or a string to use for array indexing if running in CLASSIC access pattern.
1298+ * @return A field name element
1299+ */
12951300 static Element field (String fieldName ) {
12961301 Objects .requireNonNull (fieldName , "fieldName cannot be null" );
12971302 if (fieldName .isEmpty ()) {
@@ -1300,22 +1305,44 @@ static Element field(String fieldName) {
13001305 return new Element (fieldName , null );
13011306 }
13021307
1308+ /**
1309+ * Creates a new FieldPath Element which corresponds to an array index specified by the square bracket syntax available
1310+ * when using the {@link IngestPipelineFieldAccessPattern#FLEXIBLE} access pattern.
1311+ * @param arrayIndex array index specified in square brackets
1312+ * @return An array index element
1313+ */
13031314 static Element index (int arrayIndex ) {
13041315 if (arrayIndex < 0 ) {
13051316 throw new IndexOutOfBoundsException (arrayIndex );
13061317 }
13071318 return new Element (EMPTY_STRING , arrayIndex );
13081319 }
13091320
1321+ /**
1322+ * @return true if this element is for accessing a regular field
1323+ */
13101324 boolean isFieldName () {
13111325 return fieldName .isEmpty () == false && arrayIndex == null ;
13121326 }
13131327
1328+ /**
1329+ * @return true if this element is for an array index used for the FLEXIBLE access pattern
1330+ */
13141331 boolean isArrayIndex () {
1315- return fieldName .isEmpty () &&
1332+ return isFieldName () == false ;
1333+ }
1334+
1335+ @ Override
1336+ public String toString () {
1337+ return isFieldName () ? fieldName : "[" + arrayIndex + "]" ;
13161338 }
13171339 }
13181340
1341+ /**
1342+ * A compound cache key for tracking previously parsed field paths
1343+ * @param path The field path as given by the caller
1344+ * @param accessPattern The access pattern used to parse the field path
1345+ */
13191346 private record CacheKey (String path , IngestPipelineFieldAccessPattern accessPattern ) {}
13201347
13211348 private static final int MAX_SIZE = 512 ;
@@ -1370,6 +1397,20 @@ private static Element[] processPathParts(String fullPath, String[] pathParts, I
13701397 if (pathParts .length == 1 && pathParts [0 ].isEmpty ()) {
13711398 throw new IllegalArgumentException ("path [" + fullPath + "] is not valid" );
13721399 }
1400+ return switch (accessPattern ) {
1401+ case CLASSIC -> Arrays .stream (pathParts ).map (Element ::field ).toArray (Element []::new );
1402+ case FLEXIBLE -> parseFlexibleFields (fullPath , pathParts );
1403+ };
1404+ }
1405+
1406+ /**
1407+ * Parses path syntax that is specific to the {@link IngestPipelineFieldAccessPattern#FLEXIBLE} ingest doc access pattern. Supports
1408+ * syntax like square bracket array access, which is the only way to index arrays in flexible mode.
1409+ * @param fullPath The un-split path to use for error messages
1410+ * @param pathParts The tokenized field path to parse
1411+ * @return An array of Elements
1412+ */
1413+ private static Element [] parseFlexibleFields (String fullPath , String [] pathParts ) {
13731414 return Arrays .stream (pathParts )
13741415 .flatMap (pathPart -> {
13751416 int openBracket = pathPart .indexOf ('[' );
0 commit comments