private static StructType buildPartitionProjectionType(
      String typeName, Collection<PartitionSpec> specs, Set<Integer> projectedFieldIds) {

    // we currently don't know the output type of unknown transforms
    List<Transform<?, ?>> unknownTransforms = collectUnknownTransforms(specs);
    ValidationException.check(
        unknownTransforms.isEmpty(),
        "Cannot build %s type, unknown transforms: %s",
        typeName,
        unknownTransforms);

    Map<Integer, PartitionField> fieldMap = Maps.newHashMap();
    Map<Integer, Type> typeMap = Maps.newHashMap();
    Map<Integer, String> nameMap = Maps.newHashMap();

    // sort specs by ID in descending order to pick up the most recent field names
    List<PartitionSpec> sortedSpecs =
        specs.stream()
            .sorted(Comparator.comparingLong(PartitionSpec::specId).reversed())
            .collect(Collectors.toList());

    for (PartitionSpec spec : sortedSpecs) {
      for (PartitionField field : spec.fields()) {
        int fieldId = field.fieldId();

        if (!projectedFieldIds.contains(fieldId)) {
          continue;
        }

        NestedField structField = spec.partitionType().field(fieldId);
        PartitionField existingField = fieldMap.get(fieldId);

        if (existingField == null) {
          fieldMap.put(fieldId, field);
          typeMap.put(fieldId, structField.type());
          nameMap.put(fieldId, structField.name());

        } else {
          // verify the fields are compatible as they may conflict in v1 tables
          ValidationException.check(
              equivalentIgnoringNames(field, existingField),
              "Conflicting partition fields: ['%s', '%s']",
              field,
              existingField);

          // use the correct type for dropped partitions in v1 tables
          if (isVoidTransform(existingField) && !isVoidTransform(field)) {
            fieldMap.put(fieldId, field);
            typeMap.put(fieldId, structField.type());
          }
        }
      }
    }

    List<NestedField> sortedStructFields =
        fieldMap.keySet().stream()
            .sorted(Comparator.naturalOrder())
            .map(
                fieldId ->
                    NestedField.optional(fieldId, nameMap.get(fieldId), typeMap.get(fieldId)))
            .collect(Collectors.toList());
    return StructType.of(sortedStructFields);
  }
Checks if any of the specs in a table is partitioned.

@param table the table to check.
@return {@code true} if the table is partitioned, {@code false} otherwise.
iceberg/patched-iceberg-core/src/main/java/org/apache/iceberg/Partitioning.java