c-thiel commented on code in PR #491: URL: https://github.com/apache/iceberg-rust/pull/491#discussion_r1713990348
########## crates/iceberg/src/spec/partition.rs: ########## @@ -136,6 +145,427 @@ impl UnboundPartitionSpec { } } +impl From<PartitionField> for UnboundPartitionField { + fn from(field: PartitionField) -> Self { + UnboundPartitionField { + source_id: field.source_id, + partition_id: Some(field.field_id), + name: field.name, + transform: field.transform, + } + } +} + +impl From<PartitionSpec> for UnboundPartitionSpec { + fn from(spec: PartitionSpec) -> Self { + UnboundPartitionSpec { + spec_id: Some(spec.spec_id), + fields: spec.fields.into_iter().map(Into::into).collect(), + } + } +} + +/// Create a new UnboundPartitionSpec +#[derive(Debug, Default)] +pub struct UnboundPartitionSpecBuilder { + spec_id: Option<i32>, + fields: Vec<UnboundPartitionField>, +} + +impl UnboundPartitionSpecBuilder { + /// Create a new partition spec builder with the given schema. + pub fn new() -> Self { + Self { + spec_id: None, + fields: vec![], + } + } + + /// Set the spec id for the partition spec. + pub fn with_spec_id(mut self, spec_id: i32) -> Self { + self.spec_id = Some(spec_id); + self + } + + /// Add a new partition field to the partition spec from an unbound partition field. + pub fn add_partition_field( + self, + source_id: i32, + target_name: impl ToString, + transformation: Transform, + ) -> Result<Self> { + let field = UnboundPartitionField { + source_id, + partition_id: None, + name: target_name.to_string(), + transform: transformation, + }; + self.add_partition_field_internal(field) + } + + /// Add multiple partition fields to the partition spec. + pub fn add_partition_fields( + self, + fields: impl IntoIterator<Item = UnboundPartitionField>, + ) -> Result<Self> { + let mut builder = self; + for field in fields { + builder = builder.add_partition_field_internal(field)?; + } + Ok(builder) + } + + fn add_partition_field_internal(mut self, field: UnboundPartitionField) -> Result<Self> { + self.check_name_set_and_unique(&field.name)?; + self.check_for_redundant_partitions(field.source_id, &field.transform)?; + if let Some(partition_id) = field.partition_id { + self.check_partition_id_unique(partition_id)?; + } + self.fields.push(field); + Ok(self) + } + + /// Build the unbound partition spec. + pub fn build(self) -> UnboundPartitionSpec { + UnboundPartitionSpec { + spec_id: self.spec_id, + fields: self.fields, + } + } +} + +/// Create valid partition specs for a given schema. +#[derive(Debug)] +pub struct PartitionSpecBuilder<'a> { + spec_id: Option<i32>, + last_assigned_field_id: i32, + fields: Vec<UnboundPartitionField>, + schema: &'a Schema, +} + +impl<'a> PartitionSpecBuilder<'a> { + pub(crate) const UNPARTITIONED_LAST_ASSIGNED_ID: i32 = 999; + // Default partition spec id is only used for building `PartitionSpec`. + // When building unbound partition specs, the spec id is not set by default. + pub(crate) const DEFAULT_PARTITION_SPEC_ID: i32 = 0; + + /// Create a new partition spec builder with the given schema. + pub fn new(schema: &'a Schema) -> Self { + Self { + spec_id: None, + fields: vec![], + last_assigned_field_id: Self::UNPARTITIONED_LAST_ASSIGNED_ID, + schema, + } + } + + /// Create a new partition spec builder from an existing unbound partition spec. + pub fn new_from_unbound(unbound: UnboundPartitionSpec, schema: &'a Schema) -> Result<Self> { Review Comment: `bind` sounds to me more like the combination of "new().build()" - I would expect to get a final result. However, I added a `bind` method to `UnboundPartitionSpec` which does exactly this: ```rust /// Bind this unbound partition spec to a schema. pub fn bind(self, schema: &Schema) -> Result<PartitionSpec> { PartitionSpecBuilder::new_from_unbound(self, schema)?.build() } ``` -- 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: issues-unsubscr...@iceberg.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org --------------------------------------------------------------------- To unsubscribe, e-mail: issues-unsubscr...@iceberg.apache.org For additional commands, e-mail: issues-h...@iceberg.apache.org