API: Restore the type of the identity transform (#6242)

* API: Restore the type of the identity transform

This caused some regression for the Iceberg 1.1.0 release:

```
2022-11-21T12:05:46.6549795Z [ERROR] io.trino.plugin.iceberg.TestIcebergSystemTables.testManifestsTable  Time elapsed: 0.701 s  <<< FAILURE!
2022-11-21T12:05:46.6550853Z java.lang.AssertionError:
2022-11-21T12:05:46.6551986Z [Rows for query [SELECT added_data_files_count, existing_rows_count, added_rows_count, deleted_data_files_count, deleted_rows_count, partitions FROM test_schema."test_table$manifests"]]
2022-11-21T12:05:46.6553075Z Expecting:
2022-11-21T12:05:46.6553593Z   <(2, 0, 3, 0, 0, [[false, false, 18148, 18149]]), (2, 0, 3, 0, 0, [[false, false, 18147, 18148]])>
2022-11-21T12:05:46.6553980Z to contain exactly in any order:
2022-11-21T12:05:46.6554557Z   <[(2, 0, 3, 0, 0, [[false, false, 2019-09-08, 2019-09-09]]),
2022-11-21T12:05:46.6554992Z     (2, 0, 3, 0, 0, [[false, false, 2019-09-09, 2019-09-10]])]>
2022-11-21T12:05:46.6555273Z elements not found:
2022-11-21T12:05:46.6555804Z   <(2, 0, 3, 0, 0, [[false, false, 2019-09-08, 2019-09-09]]), (2, 0, 3, 0, 0, [[false, false, 2019-09-09, 2019-09-10]])>
2022-11-21T12:05:46.6556132Z and elements not expected:
2022-11-21T12:05:46.6556488Z   <(2, 0, 3, 0, 0, [[false, false, 18148, 18149]]), (2, 0, 3, 0, 0, [[false, false, 18147, 18148]])>
```

The system tables (manifests in this example above), would return
the days since epoch instead of a date.

* Restore equals

* Bind SortOrder as well

* Add todo
diff --git a/api/src/main/java/org/apache/iceberg/SortOrder.java b/api/src/main/java/org/apache/iceberg/SortOrder.java
index 43da605..d35dc36 100644
--- a/api/src/main/java/org/apache/iceberg/SortOrder.java
+++ b/api/src/main/java/org/apache/iceberg/SortOrder.java
@@ -284,7 +284,7 @@
 
     private Transform<?, ?> toTransform(BoundTerm<?> term) {
       if (term instanceof BoundReference) {
-        return Transforms.identity();
+        return Transforms.identity(term.type());
       } else if (term instanceof BoundTransform) {
         return ((BoundTransform<?, ?>) term).transform();
       } else {
diff --git a/api/src/main/java/org/apache/iceberg/UnboundSortOrder.java b/api/src/main/java/org/apache/iceberg/UnboundSortOrder.java
index c9d7d0b..ce9f6b1 100644
--- a/api/src/main/java/org/apache/iceberg/UnboundSortOrder.java
+++ b/api/src/main/java/org/apache/iceberg/UnboundSortOrder.java
@@ -23,6 +23,7 @@
 import org.apache.iceberg.relocated.com.google.common.collect.Lists;
 import org.apache.iceberg.transforms.Transform;
 import org.apache.iceberg.transforms.Transforms;
+import org.apache.iceberg.types.Type;
 
 public class UnboundSortOrder {
   private static final UnboundSortOrder UNSORTED_ORDER =
@@ -40,7 +41,14 @@
     SortOrder.Builder builder = SortOrder.builderFor(schema).withOrderId(orderId);
 
     for (UnboundSortField field : fields) {
-      builder.addSortField(field.transform, field.sourceId, field.direction, field.nullOrder);
+      Type sourceType = schema.findType(field.sourceId);
+      Transform<?, ?> transform;
+      if (sourceType != null) {
+        transform = Transforms.fromString(sourceType, field.transform.toString());
+      } else {
+        transform = field.transform;
+      }
+      builder.addSortField(transform, field.sourceId, field.direction, field.nullOrder);
     }
 
     return builder.build();
diff --git a/api/src/main/java/org/apache/iceberg/transforms/Identity.java b/api/src/main/java/org/apache/iceberg/transforms/Identity.java
index 365abdf..d4e5e53 100644
--- a/api/src/main/java/org/apache/iceberg/transforms/Identity.java
+++ b/api/src/main/java/org/apache/iceberg/transforms/Identity.java
@@ -29,6 +29,18 @@
 class Identity<T> implements Transform<T, T> {
   private static final Identity<?> INSTANCE = new Identity<>();
 
+  private final Type type;
+
+  /**
+   * Instantiates a new Identity Transform
+   *
+   * @deprecated use {@link #get()} instead; will be removed in 2.0.0
+   */
+  @Deprecated
+  public static <I> Identity<I> get(Type type) {
+    return new Identity<>(type);
+  }
+
   @SuppressWarnings("unchecked")
   public static <I> Identity<I> get() {
     return (Identity<I>) INSTANCE;
@@ -48,7 +60,13 @@
     }
   }
 
-  private Identity() {}
+  private Identity() {
+    this(null);
+  }
+
+  private Identity(Type type) {
+    this.type = type;
+  }
 
   @Override
   public T apply(T value) {
@@ -56,6 +74,7 @@
   }
 
   @Override
+  @SuppressWarnings("checkstyle:HiddenField")
   public SerializableFunction<T, T> bind(Type type) {
     Preconditions.checkArgument(canTransform(type), "Cannot bind to unsupported type: %s", type);
     return Apply.get();
@@ -66,6 +85,24 @@
     return maybePrimitive.isPrimitiveType();
   }
 
+  /**
+   * Returns a human-readable String representation of a transformed value.
+   *
+   * <p>null values will return "null"
+   *
+   * @param value a transformed value
+   * @return a human-readable String representation of the value
+   * @deprecated use {@link #toHumanString(Type, Object)} instead; will be removed in 2.0.0
+   */
+  @Deprecated
+  @Override
+  public String toHumanString(T value) {
+    if (this.type != null) {
+      return toHumanString(this.type, value);
+    }
+    return Transform.super.toHumanString(value);
+  }
+
   @Override
   public Type getResultType(Type sourceType) {
     return sourceType;
@@ -106,6 +143,23 @@
   }
 
   @Override
+  public boolean equals(Object o) {
+    // Can be removed with 2.0.0 deprecation of get(Type)
+    if (this == o) {
+      return true;
+    } else if (o instanceof Identity) {
+      return true;
+    }
+    return false;
+  }
+
+  @Override
+  public int hashCode() {
+    // Can be removed with 2.0.0 deprecation of get(Type)
+    return 0;
+  }
+
+  @Override
   public String toString() {
     return "identity";
   }
diff --git a/api/src/main/java/org/apache/iceberg/transforms/Transforms.java b/api/src/main/java/org/apache/iceberg/transforms/Transforms.java
index 59ac30c..a1ce33d 100644
--- a/api/src/main/java/org/apache/iceberg/transforms/Transforms.java
+++ b/api/src/main/java/org/apache/iceberg/transforms/Transforms.java
@@ -81,7 +81,7 @@
     }
 
     if (transform.equalsIgnoreCase("identity")) {
-      return Identity.get();
+      return Identity.get(type);
     }
 
     try {
@@ -111,7 +111,7 @@
    */
   @Deprecated
   public static <T> Transform<T, T> identity(Type type) {
-    return Identity.get();
+    return Identity.get(type);
   }
 
   /**
diff --git a/api/src/test/java/org/apache/iceberg/transforms/TestIdentity.java b/api/src/test/java/org/apache/iceberg/transforms/TestIdentity.java
index a14b7c8..3925a67 100644
--- a/api/src/test/java/org/apache/iceberg/transforms/TestIdentity.java
+++ b/api/src/test/java/org/apache/iceberg/transforms/TestIdentity.java
@@ -70,6 +70,18 @@
   }
 
   @Test
+  public void testDateHumanStringDeprecated() {
+    Types.DateType date = Types.DateType.get();
+    Transform<Integer, Integer> identity = Transforms.identity(date);
+
+    String dateString = "2017-12-01";
+    Literal<Integer> dateLit = Literal.of(dateString).to(date);
+
+    Assert.assertEquals(
+        "Should produce identical date", dateString, identity.toHumanString(dateLit.value()));
+  }
+
+  @Test
   public void testTimeHumanString() {
     Types.TimeType time = Types.TimeType.get();
     Transform<Long, Long> identity = Transforms.identity();