use crate::basic::LogicalType;
use crate::errors::ParquetError;
use crate::schema::types::Type;
use arrow_schema::Field;
pub(crate) fn try_add_extension_type(
arrow_field: Field,
parquet_type: &Type,
) -> Result<Field, ParquetError> {
let Some(parquet_logical_type) = parquet_type.get_basic_info().logical_type_ref() else {
return Ok(arrow_field);
};
Ok(match parquet_logical_type {
#[cfg(feature = "variant_experimental")]
LogicalType::Variant { .. } => {
let mut arrow_field = arrow_field;
arrow_field.try_with_extension_type(parquet_variant_compute::VariantType)?;
arrow_field
}
#[cfg(feature = "arrow_canonical_extension_types")]
LogicalType::Uuid => {
let mut arrow_field = arrow_field;
arrow_field.try_with_extension_type(arrow_schema::extension::Uuid)?;
arrow_field
}
#[cfg(feature = "arrow_canonical_extension_types")]
LogicalType::Json => {
let mut arrow_field = arrow_field;
arrow_field.try_with_extension_type(arrow_schema::extension::Json::default())?;
arrow_field
}
#[cfg(feature = "geospatial")]
LogicalType::Geometry { crs } => {
let md = parquet_geospatial::WkbMetadata::new(crs.as_deref(), None);
let mut arrow_field = arrow_field;
arrow_field.try_with_extension_type(parquet_geospatial::WkbType::new(Some(md)))?;
arrow_field
}
#[cfg(feature = "geospatial")]
LogicalType::Geography { crs, algorithm } => {
let algorithm = algorithm.map(|a| a.try_as_edges()).transpose()?;
let md = parquet_geospatial::WkbMetadata::new(crs.as_deref(), algorithm);
let mut arrow_field = arrow_field;
arrow_field.try_with_extension_type(parquet_geospatial::WkbType::new(Some(md)))?;
arrow_field
}
_ => arrow_field,
})
}
pub(crate) fn has_extension_type(parquet_type: &Type) -> bool {
let Some(parquet_logical_type) = parquet_type.get_basic_info().logical_type_ref() else {
return false;
};
match parquet_logical_type {
#[cfg(feature = "variant_experimental")]
LogicalType::Variant { .. } => true,
#[cfg(feature = "arrow_canonical_extension_types")]
LogicalType::Uuid => true,
#[cfg(feature = "arrow_canonical_extension_types")]
LogicalType::Json => true,
#[cfg(feature = "geospatial")]
LogicalType::Geometry { .. } => true,
#[cfg(feature = "geospatial")]
LogicalType::Geography { .. } => true,
_ => false,
}
}
#[cfg(feature = "variant_experimental")]
pub(crate) fn logical_type_for_struct(field: &Field) -> Option<LogicalType> {
use arrow_schema::extension::ExtensionType;
use parquet_variant_compute::VariantType;
if field.extension_type_name()? != VariantType::NAME {
return None;
}
match field.try_extension_type::<VariantType>() {
Ok(VariantType) => Some(LogicalType::Variant {
specification_version: None,
}),
Err(_e) => None,
}
}
#[cfg(not(feature = "variant_experimental"))]
pub(crate) fn logical_type_for_struct(_field: &Field) -> Option<LogicalType> {
None
}
#[cfg(feature = "arrow_canonical_extension_types")]
pub(crate) fn logical_type_for_fixed_size_binary(field: &Field) -> Option<LogicalType> {
use arrow_schema::extension::Uuid;
field
.try_extension_type::<Uuid>()
.ok()
.map(|_| LogicalType::Uuid)
}
#[cfg(not(feature = "arrow_canonical_extension_types"))]
pub(crate) fn logical_type_for_fixed_size_binary(_field: &Field) -> Option<LogicalType> {
None
}
#[cfg(feature = "arrow_canonical_extension_types")]
pub(crate) fn logical_type_for_string(field: &Field) -> Option<LogicalType> {
use arrow_schema::extension::Json;
field
.try_extension_type::<Json>()
.map_or(Some(LogicalType::String), |_| Some(LogicalType::Json))
}
#[cfg(not(feature = "arrow_canonical_extension_types"))]
pub(crate) fn logical_type_for_string(_field: &Field) -> Option<LogicalType> {
Some(LogicalType::String)
}
#[cfg(feature = "geospatial")]
pub(crate) fn logical_type_for_binary(field: &Field) -> Option<LogicalType> {
use arrow_schema::extension::ExtensionType;
use parquet_geospatial::WkbType;
use parquet_geospatial::WkbTypeHint;
match field.extension_type_name() {
Some(n) if n == WkbType::NAME => match field.try_extension_type::<WkbType>() {
Ok(wkb_type) => match wkb_type.metadata().type_hint() {
WkbTypeHint::Geometry => Some(LogicalType::Geometry {
crs: wkb_type.metadata().crs.as_ref().map(|c| c.to_string()),
}),
WkbTypeHint::Geography => Some(LogicalType::Geography {
crs: wkb_type.metadata().crs.as_ref().map(|c| c.to_string()),
algorithm: wkb_type.metadata().algorithm.map(|a| a.into()),
}),
},
Err(_e) => None,
},
_ => None,
}
}
#[cfg(not(feature = "geospatial"))]
pub(crate) fn logical_type_for_binary(_field: &Field) -> Option<LogicalType> {
None
}
#[cfg(feature = "geospatial")]
pub(crate) fn logical_type_for_binary_view(field: &Field) -> Option<LogicalType> {
logical_type_for_binary(field)
}
#[cfg(not(feature = "geospatial"))]
pub(crate) fn logical_type_for_binary_view(_field: &Field) -> Option<LogicalType> {
None
}