static SearchArgument convert(Expression expr, TypeDescription readSchema) {
    Map<Integer, String> idToColumnName =
        ORCSchemaUtil.idToOrcName(ORCSchemaUtil.convert(readSchema));
    SearchArgument.Builder builder = SearchArgumentFactory.newBuilder();
    ExpressionVisitors.visit(expr, new ExpressionToSearchArgument(builder, idToColumnName))
        .invoke();
    return builder.build();
  }
@Test
  public void testEvolvedSchema() {
    Schema fileSchema =
        new Schema(
            required(1, "int", Types.IntegerType.get()),
            optional(2, "long_to_be_dropped", Types.LongType.get()));

    Schema evolvedSchema =
        new Schema(
            required(1, "int_renamed", Types.IntegerType.get()),
            optional(3, "float_added", Types.FloatType.get()));

    TypeDescription readSchema =
        ORCSchemaUtil.buildOrcProjection(evolvedSchema, ORCSchemaUtil.convert(fileSchema));

    Expression expr = equal("int_renamed", 1);
    Expression boundFilter = Binder.bind(evolvedSchema.asStruct(), expr, true);
    SearchArgument expected =
        SearchArgumentFactory.newBuilder().equals("`int`", Type.LONG, 1L).build();

    SearchArgument actual = ExpressionToSearchArgument.convert(boundFilter, readSchema);
    assertThat(actual.toString()).isEqualTo(expected.toString());

    // for columns not in the file, buildOrcProjection will append field names with _r<ID>
    // this will be passed down to ORC, but ORC will handle such cases and return a TruthValue
    // during evaluation
    expr = equal("float_added", 1);
    boundFilter = Binder.bind(evolvedSchema.asStruct(), expr, true);
    expected =
        SearchArgumentFactory.newBuilder().equals("`float_added_r3`", Type.FLOAT, 1.0).build();

    actual = ExpressionToSearchArgument.convert(boundFilter, readSchema);
    assertThat(actual.toString()).isEqualTo(expected.toString());
  }