Skip to content

Commit ab4f69a

Browse files
View Spec implementation (#331)
* Add support for ViewSpec * Fix typos * Fix typos * clippy is always right * Add tests * Remove new_view_version test function * Remove append_version * View Representations Struct * ViewRepresentation case insensitive * Add fallible methods for ViewRepresentationsBuilder * Add tests for fallibe ViewRepresentationsBuilder methods * Introduce ViewVersionId as i32 * Iterator for &'a ViewRepresentations * Improve comments Co-authored-by: Renjie Liu <[email protected]> * Add test_view_metadata_v1_file_valid * Fix view_version iter * Remove ViewRepresentationsBuilder * Fix comment * Timestamp error handling * Fallible Timestamp Conversion from Millis * Fix Initial view Version = 1 * Cleanup * Hide ViewMetadata iter() type * timestamp_ms_to_utc -> error.rs * TableMetadata timestamp conversion -> utility function * Improve error context * timestamp_ms_to_utc: LocalResult::None -> DataInvalid * Fix obsolete comment * ViewRepresentation::SqlViewRepresentation -> ::Sql * Fix broken clippy from rebase --------- Co-authored-by: Renjie Liu <[email protected]>
1 parent aeeaa11 commit ab4f69a

15 files changed

+1474
-14
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ tempfile = "3.8"
8585
tokio = { version = "1", default-features = false }
8686
typed-builder = "^0.19"
8787
url = "2"
88-
uuid = "1.6.1"
88+
urlencoding = "2"
89+
uuid = { version = "1.6.1", features = ["v7"] }
8990
volo-thrift = "0.10"
9091
hive_metastore = "0.1.0"
9192
tera = "1"

crates/catalog/rest/src/catalog.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,7 +1321,7 @@ mod tests {
13211321
);
13221322
assert_eq!(
13231323
Utc.timestamp_millis_opt(1646787054459).unwrap(),
1324-
table.metadata().last_updated_ms()
1324+
table.metadata().last_updated_timestamp().unwrap()
13251325
);
13261326
assert_eq!(
13271327
vec![&Arc::new(
@@ -1511,7 +1511,11 @@ mod tests {
15111511
);
15121512
assert_eq!(
15131513
1657810967051,
1514-
table.metadata().last_updated_ms().timestamp_millis()
1514+
table
1515+
.metadata()
1516+
.last_updated_timestamp()
1517+
.unwrap()
1518+
.timestamp_millis()
15151519
);
15161520
assert_eq!(
15171521
vec![&Arc::new(
@@ -1682,7 +1686,11 @@ mod tests {
16821686
);
16831687
assert_eq!(
16841688
1657810967051,
1685-
table.metadata().last_updated_ms().timestamp_millis()
1689+
table
1690+
.metadata()
1691+
.last_updated_timestamp()
1692+
.unwrap()
1693+
.timestamp_millis()
16861694
);
16871695
assert_eq!(
16881696
vec![&Arc::new(

crates/iceberg/src/catalog/mod.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use uuid::Uuid;
2929

3030
use crate::spec::{
3131
FormatVersion, Schema, Snapshot, SnapshotReference, SortOrder, TableMetadataBuilder,
32-
UnboundPartitionSpec,
32+
UnboundPartitionSpec, ViewRepresentations,
3333
};
3434
use crate::table::Table;
3535
use crate::{Error, ErrorKind, Result};
@@ -439,6 +439,31 @@ impl TableUpdate {
439439
}
440440
}
441441

442+
/// ViewCreation represents the creation of a view in the catalog.
443+
#[derive(Debug, TypedBuilder)]
444+
pub struct ViewCreation {
445+
/// The name of the view.
446+
pub name: String,
447+
/// The view's base location; used to create metadata file locations
448+
pub location: String,
449+
/// Representations for the view.
450+
pub representations: ViewRepresentations,
451+
/// The schema of the view.
452+
pub schema: Schema,
453+
/// The properties of the view.
454+
#[builder(default)]
455+
pub properties: HashMap<String, String>,
456+
/// The default namespace to use when a reference in the SELECT is a single identifier
457+
pub default_namespace: NamespaceIdent,
458+
/// Default catalog to use when a reference in the SELECT does not contain a catalog
459+
#[builder(default)]
460+
pub default_catalog: Option<String>,
461+
/// A string to string map of summary metadata about the version
462+
/// Typical keys are "engine-name" and "engine-version"
463+
#[builder(default)]
464+
pub summary: HashMap<String, String>,
465+
}
466+
442467
#[cfg(test)]
443468
mod tests {
444469
use std::collections::HashMap;

crates/iceberg/src/error.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ use std::backtrace::{Backtrace, BacktraceStatus};
1919
use std::fmt;
2020
use std::fmt::{Debug, Display, Formatter};
2121

22+
use chrono::{DateTime, TimeZone as _, Utc};
23+
2224
/// Result that is a wrapper of `Result<T, iceberg::Error>`
2325
pub type Result<T> = std::result::Result<T, Error>;
2426

@@ -331,6 +333,28 @@ define_from_err!(
331333

332334
define_from_err!(std::io::Error, ErrorKind::Unexpected, "IO Operation failed");
333335

336+
/// Converts a timestamp in milliseconds to `DateTime<Utc>`, handling errors.
337+
///
338+
/// # Arguments
339+
///
340+
/// * `timestamp_ms` - The timestamp in milliseconds to convert.
341+
///
342+
/// # Returns
343+
///
344+
/// This function returns a `Result<DateTime<Utc>, Error>` which is `Ok` with the `DateTime<Utc>` if the conversion is successful,
345+
/// or an `Err` with an appropriate error if the timestamp is ambiguous or invalid.
346+
pub(crate) fn timestamp_ms_to_utc(timestamp_ms: i64) -> Result<DateTime<Utc>> {
347+
match Utc.timestamp_millis_opt(timestamp_ms) {
348+
chrono::LocalResult::Single(t) => Ok(t),
349+
chrono::LocalResult::Ambiguous(_, _) => Err(Error::new(
350+
ErrorKind::Unexpected,
351+
"Ambiguous timestamp with two possible results",
352+
)),
353+
chrono::LocalResult::None => Err(Error::new(ErrorKind::DataInvalid, "Invalid timestamp")),
354+
}
355+
.map_err(|e| e.with_context("timestamp value", timestamp_ms.to_string()))
356+
}
357+
334358
/// Helper macro to check arguments.
335359
///
336360
///

crates/iceberg/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ mod catalog;
2929

3030
pub use catalog::{
3131
Catalog, Namespace, NamespaceIdent, TableCommit, TableCreation, TableIdent, TableRequirement,
32-
TableUpdate,
32+
TableUpdate, ViewCreation,
3333
};
3434

3535
pub mod table;

crates/iceberg/src/spec/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ mod sort;
2727
mod table_metadata;
2828
mod transform;
2929
mod values;
30+
mod view_metadata;
31+
mod view_version;
3032

3133
pub use datatypes::*;
3234
pub use manifest::*;
@@ -38,3 +40,5 @@ pub use sort::*;
3840
pub use table_metadata::*;
3941
pub use transform::*;
4042
pub use values::*;
43+
pub use view_metadata::*;
44+
pub use view_version::*;

crates/iceberg/src/spec/table_metadata.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use std::fmt::{Display, Formatter};
2424
use std::sync::Arc;
2525

2626
use _serde::TableMetadataEnum;
27-
use chrono::{DateTime, TimeZone, Utc};
27+
use chrono::{DateTime, Utc};
2828
use serde::{Deserialize, Serialize};
2929
use serde_repr::{Deserialize_repr, Serialize_repr};
3030
use uuid::Uuid;
@@ -33,7 +33,7 @@ use super::snapshot::{Snapshot, SnapshotReference, SnapshotRetention};
3333
use super::{
3434
PartitionSpec, PartitionSpecRef, SchemaId, SchemaRef, SnapshotRef, SortOrder, SortOrderRef,
3535
};
36-
use crate::error::Result;
36+
use crate::error::{timestamp_ms_to_utc, Result};
3737
use crate::{Error, ErrorKind, TableCreation};
3838

3939
static MAIN_BRANCH: &str = "main";
@@ -143,8 +143,14 @@ impl TableMetadata {
143143

144144
/// Returns last updated time.
145145
#[inline]
146-
pub fn last_updated_ms(&self) -> DateTime<Utc> {
147-
Utc.timestamp_millis_opt(self.last_updated_ms).unwrap()
146+
pub fn last_updated_timestamp(&self) -> Result<DateTime<Utc>> {
147+
timestamp_ms_to_utc(self.last_updated_ms)
148+
}
149+
150+
/// Returns last updated time in milliseconds.
151+
#[inline]
152+
pub fn last_updated_ms(&self) -> i64 {
153+
self.last_updated_ms
148154
}
149155

150156
/// Returns schemas
@@ -328,7 +334,7 @@ impl TableMetadataBuilder {
328334

329335
let table_metadata = TableMetadata {
330336
format_version: FormatVersion::V2,
331-
table_uuid: Uuid::new_v4(),
337+
table_uuid: Uuid::now_v7(),
332338
location: location.ok_or_else(|| {
333339
Error::new(
334340
ErrorKind::DataInvalid,
@@ -472,7 +478,7 @@ pub(super) mod _serde {
472478

473479
/// Helper to serialize and deserialize the format version.
474480
#[derive(Debug, PartialEq, Eq)]
475-
pub(super) struct VersionNumber<const V: u8>;
481+
pub(crate) struct VersionNumber<const V: u8>;
476482

477483
impl Serialize for TableMetadata {
478484
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -903,8 +909,14 @@ pub struct SnapshotLog {
903909

904910
impl SnapshotLog {
905911
/// Returns the last updated timestamp as a DateTime<Utc> with millisecond precision
906-
pub fn timestamp(self) -> DateTime<Utc> {
907-
Utc.timestamp_millis_opt(self.timestamp_ms).unwrap()
912+
pub fn timestamp(self) -> Result<DateTime<Utc>> {
913+
timestamp_ms_to_utc(self.timestamp_ms)
914+
}
915+
916+
/// Returns the timestamp in milliseconds
917+
#[inline]
918+
pub fn timestamp_ms(&self) -> i64 {
919+
self.timestamp_ms
908920
}
909921
}
910922

0 commit comments

Comments
 (0)