in nifi-commons/nifi-record-path/src/main/java/org/apache/nifi/record/path/paths/RecordPathCompiler.java [125:475]
public static RecordPathSegment buildPath(final Tree tree, final RecordPathSegment parent, final boolean absolute) {
switch (tree.getType()) {
case ROOT_REFERENCE: {
return new RootPath();
}
case CHILD_REFERENCE: {
if (tree.getChildCount() == 0) {
return new RootPath();
}
final Tree childTree = tree.getChild(0);
if (childTree == null) {
return new RootPath();
}
final int childTreeType = childTree.getType();
if (childTreeType == FIELD_NAME) {
final String childName = childTree.getChild(0).getText();
return new ChildFieldPath(childName, parent, absolute);
} else if (childTreeType == WILDCARD) {
return new WildcardChildPath(parent, absolute);
} else {
throw new RecordPathException("Expected field name following '/' Token but found " + childTree);
}
}
case ARRAY_INDEX: {
final Tree indexListTree = tree.getChild(0);
if (indexListTree.getType() == NUMBER_LIST) {
if (indexListTree.getChildCount() == 1 && indexListTree.getChild(0).getType() == NUMBER) {
final Tree indexTree = indexListTree.getChild(0);
final int index = Integer.parseInt(indexTree.getText());
return new ArrayIndexPath(index, parent, absolute);
}
final List<NumericRange> indexList = new ArrayList<>();
for (int i = 0; i < indexListTree.getChildCount(); i++) {
final Tree indexTree = indexListTree.getChild(i);
if (indexTree.getType() == NUMBER) {
final int index = Integer.valueOf(indexTree.getText());
indexList.add(new NumericRange(index, index));
} else if (indexTree.getType() == NUMBER_RANGE) {
final int min = Integer.valueOf(indexTree.getChild(0).getText());
final int max = Integer.valueOf(indexTree.getChild(1).getText());
indexList.add(new NumericRange(min, max));
} else {
throw new RecordPathException("Expected Number or Range following '[' Token but found " + indexTree);
}
}
return new MultiArrayIndexPath(indexList, parent, absolute);
} else {
throw new RecordPathException("Expected Number or Range following '[' Token but found " + indexListTree);
}
}
case MAP_KEY: {
final Tree keyTree = tree.getChild(0);
if (keyTree.getType() == STRING_LIST) {
if (keyTree.getChildCount() == 1) {
return new SingularMapKeyPath(keyTree.getChild(0).getText(), parent, absolute);
}
final List<String> keys = new ArrayList<>(keyTree.getChildCount());
for (int i = 0; i < keyTree.getChildCount(); i++) {
keys.add(keyTree.getChild(i).getText());
}
return new MultiMapKeyPath(keys, parent, absolute);
} else {
throw new RecordPathException("Expected Map Key following '[' Token but found " + keyTree);
}
}
case WILDCARD: {
return new WildcardIndexPath(parent, absolute);
}
case DESCENDANT_REFERENCE: {
final Tree childTree = tree.getChild(0);
final int childTreeType = childTree.getType();
if (childTreeType == FIELD_NAME) {
final String descendantName = childTree.getChild(0).getText();
return new DescendantFieldPath(descendantName, parent, absolute);
} else if (childTreeType == WILDCARD) {
return new WildcardDescendantPath(parent, absolute);
} else {
throw new RecordPathException("Expected field name following '//' Token but found " + childTree);
}
}
case PARENT_REFERENCE: {
return new ParentPath(parent, absolute);
}
case CURRENT_FIELD: {
return new CurrentFieldPath(parent, absolute);
}
case STRING_LITERAL: {
return new LiteralValuePath(parent, tree.getText(), absolute);
}
case NUMBER: {
return new LiteralValuePath(parent, Integer.parseInt(tree.getText()), absolute);
}
case PREDICATE: {
final Tree operatorTree = tree.getChild(0);
final RecordPathFilter filter = createFilter(operatorTree, parent, absolute);
return new PredicatePath(parent, filter, absolute);
}
case RELATIVE_PATH: {
return compile(tree, parent, absolute);
}
case PATH: {
return compile(tree, new RootPath(), absolute);
}
case FUNCTION: {
final String functionName = tree.getChild(0).getText();
final Tree argumentListTree = tree.getChild(1);
switch (functionName) {
case "substring": {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 3, functionName, absolute);
return new Substring(args[0], args[1], args[2], absolute);
}
case "substringAfter": {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
return new SubstringAfter(args[0], args[1], absolute);
}
case "substringAfterLast": {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
return new SubstringAfterLast(args[0], args[1], absolute);
}
case "substringBefore": {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
return new SubstringBefore(args[0], args[1], absolute);
}
case "substringBeforeLast": {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
return new SubstringBeforeLast(args[0], args[1], absolute);
}
case "replace": {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 3, functionName, absolute);
return new Replace(args[0], args[1], args[2], absolute);
}
case "replaceRegex": {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 3, functionName, absolute);
return new ReplaceRegex(args[0], args[1], args[2], absolute);
}
case "replaceNull": {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
return new ReplaceNull(args[0], args[1], absolute);
}
case "concat": {
final int numArgs = argumentListTree.getChildCount();
final RecordPathSegment[] argPaths = new RecordPathSegment[numArgs];
for (int i = 0; i < numArgs; i++) {
argPaths[i] = buildPath(argumentListTree.getChild(i), null, absolute);
}
return new Concat(argPaths, absolute);
}
case "arrayOf": {
final int numArgs = argumentListTree.getChildCount();
final RecordPathSegment[] argPaths = new RecordPathSegment[numArgs];
for (int i = 0; i < numArgs; i++) {
argPaths[i] = buildPath(argumentListTree.getChild(i), null, absolute);
}
return new ArrayOf(argPaths, absolute);
}
case "mapOf": {
final int numArgs = argumentListTree.getChildCount();
if (numArgs % 2 != 0) {
throw new RecordPathException("The mapOf function requires an even number of arguments");
}
final RecordPathSegment[] argPaths = new RecordPathSegment[numArgs];
for (int i = 0; i < numArgs; i++) {
argPaths[i] = buildPath(argumentListTree.getChild(i), null, absolute);
}
return new MapOf(argPaths, absolute);
}
case "recordOf": {
final int numArgs = argumentListTree.getChildCount();
if (numArgs % 2 != 0) {
throw new RecordPathException("The recordOf function requires an even number of arguments");
}
final RecordPathSegment[] argPaths = new RecordPathSegment[numArgs];
for (int i = 0; i < numArgs; i++) {
argPaths[i] = buildPath(argumentListTree.getChild(i), null, absolute);
}
return new RecordOf(argPaths, absolute);
}
case "toLowerCase": {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 1, functionName, absolute);
return new ToLowerCase(args[0], absolute);
}
case "toUpperCase": {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 1, functionName, absolute);
return new ToUpperCase(args[0], absolute);
}
case "trim": {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 1, functionName, absolute);
return new TrimString(args[0], absolute);
}
case "fieldName": {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 1, functionName, absolute);
return new FieldName(args[0], absolute);
}
case "toDate": {
final int numArgs = argumentListTree.getChildCount();
if (numArgs == 2) {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
return new ToDate(args[0], args[1], absolute);
} else {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 3, functionName, absolute);
return new ToDate(args[0], args[1], args[2], absolute);
}
}
case "toString": {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
return new ToString(args[0], args[1], absolute);
}
case "toBytes": {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
return new ToBytes(args[0], args[1], absolute);
}
case "format": {
final int numArgs = argumentListTree.getChildCount();
if (numArgs == 2) {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
return new Format(args[0], args[1], absolute);
} else {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 3, functionName, absolute);
return new Format(args[0], args[1], args[2], absolute);
}
}
case "base64Encode": {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 1, functionName, absolute);
return new Base64Encode(args[0], absolute);
}
case "base64Decode": {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 1, functionName, absolute);
return new Base64Decode(args[0], absolute);
}
case "escapeJson": {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 1, functionName, absolute);
return new EscapeJson(args[0], absolute);
}
case "unescapeJson": {
final int numArgs = argumentListTree.getChildCount();
final RecordPathSegment[] args = getArgPaths(argumentListTree, numArgs, functionName, absolute);
final RecordPathSegment convertToRecord = numArgs > 1 ? args[1] : null;
final RecordPathSegment recursiveConversion = numArgs > 2 ? args[2] : null;
return new UnescapeJson(args[0], convertToRecord, recursiveConversion, absolute);
}
case "hash": {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
return new Hash(args[0], args[1], absolute);
}
case "padLeft": {
final int numArgs = argumentListTree.getChildCount();
if (numArgs == 2) {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
return new PadLeft(args[0], args[1], absolute);
} else {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 3, functionName, absolute);
return new PadLeft(args[0], args[1], args[2], absolute);
}
}
case "padRight": {
final int numArgs = argumentListTree.getChildCount();
if (numArgs == 2) {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
return new PadRight(args[0], args[1], absolute);
} else {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 3, functionName, absolute);
return new PadRight(args[0], args[1], args[2], absolute);
}
}
case "uuid5": {
final int numArgs = argumentListTree.getChildCount();
if (numArgs == 2) {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
return new UUID5(args[0], args[1], absolute);
} else {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 1, functionName, absolute);
return new UUID5(args[0], null, absolute);
}
}
case "coalesce": {
final int numArgs = argumentListTree.getChildCount();
final RecordPathSegment[] argPaths = new RecordPathSegment[numArgs];
for (int i = 0; i < numArgs; i++) {
argPaths[i] = buildPath(argumentListTree.getChild(i), null, absolute);
}
return new Coalesce(argPaths, absolute);
}
case "count": {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 1, functionName, absolute);
return new Count(args[0], absolute);
}
case "join": {
final int numArgs = argumentListTree.getChildCount();
if (numArgs < 2) {
throw new RecordPathException("Invalid number of arguments: " + functionName + " function takes 2 or more arguments but got " + numArgs);
}
final RecordPathSegment[] joinPaths = new RecordPathSegment[numArgs - 1];
for (int i = 0; i < numArgs - 1; i++) {
joinPaths[i] = buildPath(argumentListTree.getChild(i + 1), null, absolute);
}
final RecordPathSegment delimiterPath = buildPath(argumentListTree.getChild(0), null, absolute);
return new Join(delimiterPath, joinPaths, absolute);
}
case "anchored": {
final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
return new Anchored(args[0], args[1], absolute);
}
case "not":
case "contains":
case "containsRegex":
case "endsWith":
case "startsWith":
case "isBlank":
case "isEmpty":
case "matchesRegex": {
final RecordPathFilter filter = createFilter(tree, null, absolute);
return new FilterFunction(functionName, filter, absolute);
}
default: {
throw new RecordPathException("Invalid function call: The '" + functionName + "' function does not exist or can only "
+ "be used within a predicate, not as a standalone function");
}
}
}
}
throw new RecordPathException("Encountered unexpected token " + tree);
}