wirybeaver commented on code in PR #2933:
URL: https://github.com/apache/iceberg-rust/pull/2933#discussion_r3997432918


##########
crates/iceberg/src/spec/datatypes.rs:
##########
@@ -408,6 +590,25 @@ impl fmt::Display for PrimitiveType {
             PrimitiveType::Uuid => write!(f, "uuid"),
             PrimitiveType::Fixed(size) => write!(f, "fixed({size})"),
             PrimitiveType::Binary => write!(f, "binary"),
+            PrimitiveType::Geometry(geometry) => match geometry.crs() {
+                Some(crs) => write!(f, "geometry({crs})"),
+                None => write!(f, "geometry"),
+            },
+            PrimitiveType::Geography(geography) => {
+                let algorithm = geography.algorithm();
+                match (geography.crs(), algorithm) {
+                    (None, EdgeInterpolationAlgorithm::Spherical) => write!(f, 
"geography"),
+                    (Some(crs), EdgeInterpolationAlgorithm::Spherical) => {
+                        write!(f, "geography({crs})")
+                    }
+                    (crs, algorithm) => write!(
+                        f,
+                        "geography({}, {})",
+                        crs.unwrap_or(DEFAULT_GEOSPATIAL_CRS),
+                        edge_interpolation_algorithm_as_str(algorithm)
+                    ),
+                }
+            }

Review Comment:
   Done in 07727701. Geography display now always includes both the canonical 
CRS and edge algorithm, matching iceberg-java, including `spherical`.



##########
crates/iceberg/src/spec/datatypes.rs:
##########
@@ -1042,6 +1243,56 @@ mod tests {
         )
     }
 
+    #[test]
+    fn primitive_type_geospatial() {
+        let cases = vec![
+            (
+                r#""geometry""#,
+                PrimitiveType::Geometry(GeometryType::default()),
+                "geometry",
+            ),
+            (
+                r#""geometry ( EPSG:3857 )""#,
+                
PrimitiveType::Geometry(GeometryType::new(Some("EPSG:3857".to_string())).unwrap()),
+                "geometry(EPSG:3857)",
+            ),
+            (
+                r#""geography""#,
+                PrimitiveType::Geography(GeographyType::default()),
+                "geography",
+            ),
+            (
+                r#""geography ( OGC:CRS27 , karney )""#,
+                PrimitiveType::Geography(
+                    GeographyType::new(
+                        Some("OGC:CRS27".to_string()),
+                        EdgeInterpolationAlgorithm::Karney,
+                    )
+                    .unwrap(),
+                ),
+                "geography(OGC:CRS27, karney)",
+            ),
+        ];
+
+        for (json, expected, display) in cases {
+            let actual: PrimitiveType = serde_json::from_str(json).unwrap();
+            assert_eq!(actual, expected);
+            assert_eq!(actual.to_string(), display);
+            assert_eq!(
+                serde_json::to_string(&actual).unwrap(),
+                format!(r#""{display}""#)
+            );

Review Comment:
   Done in 07727701. Added the requested assertion messages.



##########
crates/iceberg/public-api.txt:
##########
@@ -1463,6 +1463,29 @@ impl serde_core::ser::Serialize for 
iceberg::spec::DataFileFormat where Self: co
 pub fn iceberg::spec::DataFileFormat::serialize<__S>(&self, serializer: __S) 
-> core::result::Result<<__S as serde_core::ser::Serializer>::Ok, <__S as 
serde_core::ser::Serializer>::Error> where __S: serde_core::ser::Serializer
 impl<'de> serde_core::de::Deserialize<'de> for iceberg::spec::DataFileFormat 
where Self: core::str::traits::FromStr, <Self as 
core::str::traits::FromStr>::Err: core::fmt::Display
 pub fn iceberg::spec::DataFileFormat::deserialize<__D>(deserializer: __D) -> 
core::result::Result<Self, <__D as serde_core::de::Deserializer>::Error> where 
__D: serde_core::de::Deserializer<'de>
+pub enum iceberg::spec::EdgeInterpolationAlgorithm
+pub iceberg::spec::EdgeInterpolationAlgorithm::Andoyer
+pub iceberg::spec::EdgeInterpolationAlgorithm::Karney
+pub iceberg::spec::EdgeInterpolationAlgorithm::Spherical
+pub iceberg::spec::EdgeInterpolationAlgorithm::Thomas
+pub iceberg::spec::EdgeInterpolationAlgorithm::Vincenty
+impl core::clone::Clone for iceberg::spec::EdgeInterpolationAlgorithm
+pub fn iceberg::spec::EdgeInterpolationAlgorithm::clone(&self) -> 
iceberg::spec::EdgeInterpolationAlgorithm
+impl core::cmp::Eq for iceberg::spec::EdgeInterpolationAlgorithm
+impl core::cmp::PartialEq for iceberg::spec::EdgeInterpolationAlgorithm
+pub fn iceberg::spec::EdgeInterpolationAlgorithm::eq(&self, other: 
&iceberg::spec::EdgeInterpolationAlgorithm) -> bool
+impl core::default::Default for iceberg::spec::EdgeInterpolationAlgorithm
+pub fn iceberg::spec::EdgeInterpolationAlgorithm::default() -> 
iceberg::spec::EdgeInterpolationAlgorithm
+impl core::fmt::Debug for iceberg::spec::EdgeInterpolationAlgorithm
+pub fn iceberg::spec::EdgeInterpolationAlgorithm::fmt(&self, f: &mut 
core::fmt::Formatter<'_>) -> core::fmt::Result
+impl core::hash::Hash for iceberg::spec::EdgeInterpolationAlgorithm
+pub fn iceberg::spec::EdgeInterpolationAlgorithm::hash<__H: 
core::hash::Hasher>(&self, state: &mut __H)
+impl core::marker::Copy for iceberg::spec::EdgeInterpolationAlgorithm
+impl core::marker::StructuralPartialEq for 
iceberg::spec::EdgeInterpolationAlgorithm
+impl serde_core::ser::Serialize for iceberg::spec::EdgeInterpolationAlgorithm
+pub fn iceberg::spec::EdgeInterpolationAlgorithm::serialize<__S>(&self, 
__serializer: __S) -> core::result::Result<<__S as 
serde_core::ser::Serializer>::Ok, <__S as serde_core::ser::Serializer>::Error> 
where __S: serde_core::ser::Serializer
+impl<'de> serde_core::de::Deserialize<'de> for 
iceberg::spec::EdgeInterpolationAlgorithm
+pub fn 
iceberg::spec::EdgeInterpolationAlgorithm::deserialize<__D>(__deserializer: 
__D) -> core::result::Result<Self, <__D as 
serde_core::de::Deserializer>::Error> where __D: 
serde_core::de::Deserializer<'de>

Review Comment:
   I kept these in the existing flat `spec` namespace because they are 
constituents of the public primitive type model, consistent with the other spec 
datatypes. Moving the geospatial API into a new module is a broader public API 
organization decision; I will leave this thread open for maintainer consensus.



##########
crates/iceberg/src/spec/datatypes.rs:
##########
@@ -324,6 +499,10 @@ impl<'de> Deserialize<'de> for PrimitiveType {
             deserialize_decimal(s.into_deserializer())
         } else if s.starts_with("fixed") {
             deserialize_fixed(s.into_deserializer())
+        } else if s.starts_with("geometry") {
+            parse_geometry(&s).map_err(D::Error::custom)
+        } else if s.starts_with("geography") {
+            parse_geography(&s).map_err(D::Error::custom)

Review Comment:
   The difference is intentional: fixed binary and decimal are represented 
directly by Arrow `DataType`, while GeoArrow WKB identity and CRS/edge metadata 
live on the enclosing `Field` as extension metadata. The field conversion 
applies that metadata after the storage type visitor returns.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to