in zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/tools/lineage/ExpressionParentFinder.java [127:171]
public void visit(ResolvedGetStructField getStructField) {
ResolvedExpr structExpression = getStructField.getExpr();
StructType structExpressionType = structExpression.getType().asStruct();
int accessedFieldIndex = (int) getStructField.getFieldIdx();
String accessedFieldName = structExpressionType.getField(accessedFieldIndex).getName();
if (structExpression instanceof ResolvedMakeStruct) {
// If the user made a STRUCT and immediately accessed a field in it, only consider the
// parent
// columns of the corresponding field.
ResolvedMakeStruct makeStructExpression = (ResolvedMakeStruct) structExpression;
StructType makeStructExpressionType = makeStructExpression.getType().asStruct();
int numberOfFields = makeStructExpressionType.getFieldCount();
int fieldIndex =
IntStream.range(0, numberOfFields)
.filter(
index ->
makeStructExpressionType.getField(index).getName().equals(accessedFieldName))
.findFirst()
.orElseThrow(
() ->
new IllegalArgumentException(
"Field "
+ accessedFieldName
+ " does not exist in STRUCT of type: "
+ makeStructExpressionType));
ResolvedExpr fieldExpression = makeStructExpression.getFieldList().get(fieldIndex);
List<ResolvedColumn> parentColumns =
ExpressionParentFinder.findDirectParentsForExpression(fieldExpression);
parentColumns.forEach(result::push);
} else {
structExpression.accept(this);
ResolvedColumn structColumn = result.pop();
ResolvedColumn parentColumn =
new ResolvedColumn(
structColumn.getId(),
structColumn.getTableName(),
structColumn.getName() + "." + accessedFieldName,
getStructField.getType());
this.result.push(parentColumn);
}
}