public CloseableIterator<T> readData(KeyedTableScanTask keyedTableScanTask) {
    MixedDeleteFilter<T> mixedDeleteFilter =
        createMixedDeleteFilter(
            keyedTableScanTask,
            tableSchema,
            projectedSchema,
            primaryKeySpec,
            sourceNodes,
            structLikeCollections);
    Schema newProjectedSchema = mixedDeleteFilter.requiredSchema();

    CloseableIterable<T> dataIterable =
        mixedDeleteFilter.filter(
            CloseableIterable.concat(
                CloseableIterable.transform(
                    CloseableIterable.withNoopClose(keyedTableScanTask.dataTasks()),
                    fileScanTask -> {
                      switch (fileScanTask.file().format()) {
                        case PARQUET:
                          return newParquetIterable(
                              fileScanTask,
                              newProjectedSchema,
                              DataReaderCommon.getIdToConstant(
                                  fileScanTask, newProjectedSchema, convertConstant));
                        case ORC:
                          return newOrcIterable(
                              fileScanTask,
                              newProjectedSchema,
                              DataReaderCommon.getIdToConstant(
                                  fileScanTask, newProjectedSchema, convertConstant));
                        default:
                          throw new UnsupportedOperationException(
                              "Cannot read unknown format: " + fileScanTask.file().format());
                      }
                    })));
    return dataIterable.iterator();
  }
Abstract implementation of mixed-format data reader consuming {@link KeyedTableScanTask}, return
records after filtering with {@link MixedDeleteFilter}.

@param <T> to indicate the record data type.
amoro-format-iceberg/src/main/java/org/apache/amoro/io/reader/AbstractKeyedDataReader.java