public static Types.StructType selectNot(Types.StructType struct, Set<Integer> fieldIds) {
    Set<Integer> projectedIds = getIdsInternal(struct, false);
    projectedIds.removeAll(fieldIds);
    return project(struct, projectedIds);
  }
@Test
  public void testSelectNot() {
    Schema schema =
        new Schema(
            Lists.newArrayList(
                required(1, "id", Types.LongType.get()),
                required(
                    2,
                    "location",
                    Types.StructType.of(
                        required(3, "lat", Types.DoubleType.get()),
                        required(4, "long", Types.DoubleType.get())))));

    Schema expectedNoPrimitive =
        new Schema(
            Lists.newArrayList(
                required(
                    2,
                    "location",
                    Types.StructType.of(
                        required(3, "lat", Types.DoubleType.get()),
                        required(4, "long", Types.DoubleType.get())))));

    Schema actualNoPrimitve = TypeUtil.selectNot(schema, Sets.newHashSet(1));
    assertThat(actualNoPrimitve.asStruct()).isEqualTo(expectedNoPrimitive.asStruct());

    // Expected legacy behavior is to completely remove structs if their elements are removed
    Schema expectedNoStructElements = new Schema(required(1, "id", Types.LongType.get()));
    Schema actualNoStructElements = TypeUtil.selectNot(schema, Sets.newHashSet(3, 4));
    assertThat(actualNoStructElements.asStruct()).isEqualTo(expectedNoStructElements.asStruct());

    // Expected legacy behavior is to ignore selectNot on struct elements.
    Schema actualNoStruct = TypeUtil.selectNot(schema, Sets.newHashSet(2));
    assertThat(actualNoStruct.asStruct()).isEqualTo(schema.asStruct());
  }