public static Schema project(Schema schema, Set<Integer> fieldIds) {
    Preconditions.checkNotNull(schema, "Schema cannot be null");

    Types.StructType result = project(schema.asStruct(), fieldIds);
    if (schema.asStruct().equals(result)) {
      return schema;
    } else if (result != null) {
      if (schema.getAliases() != null) {
        return new Schema(result.fields(), schema.getAliases());
      } else {
        return new Schema(result.fields());
      }
    }
    return new Schema(Collections.emptyList(), schema.getAliases());
  }
@Test
  public void testProjectMap() {
    // We can't partially project keys because it changes key equality
    Schema schema =
        new Schema(
            Lists.newArrayList(
                required(10, "a", Types.IntegerType.get()),
                required(11, "A", Types.IntegerType.get()),
                required(
                    12,
                    "map",
                    Types.MapType.ofRequired(
                        13,
                        14,
                        Types.StructType.of(
                            optional(100, "x", Types.IntegerType.get()),
                            optional(101, "y", Types.IntegerType.get())),
                        Types.StructType.of(
                            required(200, "z", Types.IntegerType.get()),
                            optional(
                                201,
                                "innerMap",
                                Types.MapType.ofOptional(
                                    202,
                                    203,
                                    Types.IntegerType.get(),
                                    Types.StructType.of(
                                        required(300, "foo", Types.IntegerType.get()),
                                        required(301, "bar", Types.IntegerType.get())))))))));

    assertThatThrownBy(() -> TypeUtil.project(schema, Sets.newHashSet(12)))
        .isInstanceOf(IllegalArgumentException.class)
        .hasMessageContaining("Cannot explicitly project List or Map types");

    assertThatThrownBy(() -> TypeUtil.project(schema, Sets.newHashSet(201)))
        .isInstanceOf(IllegalArgumentException.class)
        .hasMessageContaining("Cannot explicitly project List or Map types");

    Schema expectedTopLevel =
        new Schema(Lists.newArrayList(required(10, "a", Types.IntegerType.get())));
    Schema actualTopLevel = TypeUtil.project(schema, Sets.newHashSet(10));
    assertThat(actualTopLevel.asStruct()).isEqualTo(expectedTopLevel.asStruct());

    Schema expectedDepthOne =
        new Schema(
            Lists.newArrayList(
                required(10, "a", Types.IntegerType.get()),
                required(
                    12,
                    "map",
                    Types.MapType.ofRequired(
                        13,
                        14,
                        Types.StructType.of(
                            optional(100, "x", Types.IntegerType.get()),
                            optional(101, "y", Types.IntegerType.get())),
                        Types.StructType.of()))));
    Schema actualDepthOne = TypeUtil.project(schema, Sets.newHashSet(10, 13, 14, 100, 101));
    Schema actualDepthOneNoKeys = TypeUtil.project(schema, Sets.newHashSet(10, 13, 14));
    assertThat(actualDepthOne.asStruct()).isEqualTo(expectedDepthOne.asStruct());
    assertThat(actualDepthOneNoKeys.asStruct()).isEqualTo(expectedDepthOne.asStruct());

    Schema expectedDepthTwo =
        new Schema(
            Lists.newArrayList(
                required(10, "a", Types.IntegerType.get()),
                required(
                    12,
                    "map",
                    Types.MapType.ofRequired(
                        13,
                        14,
                        Types.StructType.of(
                            optional(100, "x", Types.IntegerType.get()),
                            optional(101, "y", Types.IntegerType.get())),
                        Types.StructType.of(
                            required(200, "z", Types.IntegerType.get()),
                            optional(
                                201,
                                "innerMap",
                                Types.MapType.ofOptional(
                                    202, 203, Types.IntegerType.get(), Types.StructType.of())))))));
    Schema actualDepthTwo =
        TypeUtil.project(schema, Sets.newHashSet(10, 13, 14, 100, 101, 200, 202, 203));
    assertThat(actualDepthTwo.asStruct()).isEqualTo(expectedDepthTwo.asStruct());
  }