Skip to content

Commit 5034519

Browse files
authored
Add ViewUpdate to catalog (#690)
1 parent 52296eb commit 5034519

File tree

1 file changed

+261
-3
lines changed
  • crates/iceberg/src/catalog

1 file changed

+261
-3
lines changed

crates/iceberg/src/catalog/mod.rs

Lines changed: 261 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ use uuid::Uuid;
3030

3131
use crate::spec::{
3232
FormatVersion, Schema, SchemaId, Snapshot, SnapshotReference, SortOrder, TableMetadata,
33-
TableMetadataBuilder, UnboundPartitionSpec, ViewRepresentations,
33+
TableMetadataBuilder, UnboundPartitionSpec, ViewFormatVersion, ViewRepresentations,
34+
ViewVersion,
3435
};
3536
use crate::table::Table;
3637
use crate::{Error, ErrorKind, Result};
@@ -671,6 +672,64 @@ pub struct ViewCreation {
671672
pub summary: HashMap<String, String>,
672673
}
673674

675+
/// ViewUpdate represents an update to a view in the catalog.
676+
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
677+
#[serde(tag = "action", rename_all = "kebab-case")]
678+
pub enum ViewUpdate {
679+
/// Assign a new UUID to the view
680+
#[serde(rename_all = "kebab-case")]
681+
AssignUuid {
682+
/// The new UUID to assign.
683+
uuid: uuid::Uuid,
684+
},
685+
/// Upgrade view's format version
686+
#[serde(rename_all = "kebab-case")]
687+
UpgradeFormatVersion {
688+
/// Target format upgrade to.
689+
format_version: ViewFormatVersion,
690+
},
691+
/// Add a new schema to the view
692+
#[serde(rename_all = "kebab-case")]
693+
AddSchema {
694+
/// The schema to add.
695+
schema: Schema,
696+
/// The last column id of the view.
697+
last_column_id: Option<i32>,
698+
},
699+
/// Set view's current schema
700+
#[serde(rename_all = "kebab-case")]
701+
SetLocation {
702+
/// New location for view.
703+
location: String,
704+
},
705+
/// Set view's properties
706+
///
707+
/// Matching keys are updated, and non-matching keys are left unchanged.
708+
#[serde(rename_all = "kebab-case")]
709+
SetProperties {
710+
/// Properties to update for view.
711+
updates: HashMap<String, String>,
712+
},
713+
/// Remove view's properties
714+
#[serde(rename_all = "kebab-case")]
715+
RemoveProperties {
716+
/// Properties to remove
717+
removals: Vec<String>,
718+
},
719+
/// Add a new version to the view
720+
#[serde(rename_all = "kebab-case")]
721+
AddViewVersion {
722+
/// The view version to add.
723+
view_version: ViewVersion,
724+
},
725+
/// Set view's current version
726+
#[serde(rename_all = "kebab-case")]
727+
SetCurrentViewVersion {
728+
/// View version id to set as current, or -1 to set last added version
729+
view_version_id: i32,
730+
},
731+
}
732+
674733
#[cfg(test)]
675734
mod tests {
676735
use std::collections::HashMap;
@@ -680,10 +739,13 @@ mod tests {
680739
use serde::Serialize;
681740
use uuid::uuid;
682741

742+
use super::ViewUpdate;
683743
use crate::spec::{
684744
FormatVersion, NestedField, NullOrder, Operation, PrimitiveType, Schema, Snapshot,
685-
SnapshotReference, SnapshotRetention, SortDirection, SortField, SortOrder, Summary,
686-
TableMetadata, TableMetadataBuilder, Transform, Type, UnboundPartitionSpec,
745+
SnapshotReference, SnapshotRetention, SortDirection, SortField, SortOrder,
746+
SqlViewRepresentation, Summary, TableMetadata, TableMetadataBuilder, Transform, Type,
747+
UnboundPartitionSpec, ViewFormatVersion, ViewRepresentation, ViewRepresentations,
748+
ViewVersion,
687749
};
688750
use crate::{NamespaceIdent, TableCreation, TableIdent, TableRequirement, TableUpdate};
689751

@@ -1528,4 +1590,200 @@ mod tests {
15281590
.unwrap();
15291591
assert_eq!(updated_metadata.uuid(), uuid);
15301592
}
1593+
1594+
#[test]
1595+
fn test_view_assign_uuid() {
1596+
test_serde_json(
1597+
r#"
1598+
{
1599+
"action": "assign-uuid",
1600+
"uuid": "2cc52516-5e73-41f2-b139-545d41a4e151"
1601+
}
1602+
"#,
1603+
ViewUpdate::AssignUuid {
1604+
uuid: uuid!("2cc52516-5e73-41f2-b139-545d41a4e151"),
1605+
},
1606+
);
1607+
}
1608+
1609+
#[test]
1610+
fn test_view_upgrade_format_version() {
1611+
test_serde_json(
1612+
r#"
1613+
{
1614+
"action": "upgrade-format-version",
1615+
"format-version": 1
1616+
}
1617+
"#,
1618+
ViewUpdate::UpgradeFormatVersion {
1619+
format_version: ViewFormatVersion::V1,
1620+
},
1621+
);
1622+
}
1623+
1624+
#[test]
1625+
fn test_view_add_schema() {
1626+
let test_schema = Schema::builder()
1627+
.with_schema_id(1)
1628+
.with_identifier_field_ids(vec![2])
1629+
.with_fields(vec![
1630+
NestedField::optional(1, "foo", Type::Primitive(PrimitiveType::String)).into(),
1631+
NestedField::required(2, "bar", Type::Primitive(PrimitiveType::Int)).into(),
1632+
NestedField::optional(3, "baz", Type::Primitive(PrimitiveType::Boolean)).into(),
1633+
])
1634+
.build()
1635+
.unwrap();
1636+
test_serde_json(
1637+
r#"
1638+
{
1639+
"action": "add-schema",
1640+
"schema": {
1641+
"type": "struct",
1642+
"schema-id": 1,
1643+
"fields": [
1644+
{
1645+
"id": 1,
1646+
"name": "foo",
1647+
"required": false,
1648+
"type": "string"
1649+
},
1650+
{
1651+
"id": 2,
1652+
"name": "bar",
1653+
"required": true,
1654+
"type": "int"
1655+
},
1656+
{
1657+
"id": 3,
1658+
"name": "baz",
1659+
"required": false,
1660+
"type": "boolean"
1661+
}
1662+
],
1663+
"identifier-field-ids": [
1664+
2
1665+
]
1666+
},
1667+
"last-column-id": 3
1668+
}
1669+
"#,
1670+
ViewUpdate::AddSchema {
1671+
schema: test_schema.clone(),
1672+
last_column_id: Some(3),
1673+
},
1674+
);
1675+
}
1676+
1677+
#[test]
1678+
fn test_view_set_location() {
1679+
test_serde_json(
1680+
r#"
1681+
{
1682+
"action": "set-location",
1683+
"location": "s3://db/view"
1684+
}
1685+
"#,
1686+
ViewUpdate::SetLocation {
1687+
location: "s3://db/view".to_string(),
1688+
},
1689+
);
1690+
}
1691+
1692+
#[test]
1693+
fn test_view_set_properties() {
1694+
test_serde_json(
1695+
r#"
1696+
{
1697+
"action": "set-properties",
1698+
"updates": {
1699+
"prop1": "v1",
1700+
"prop2": "v2"
1701+
}
1702+
}
1703+
"#,
1704+
ViewUpdate::SetProperties {
1705+
updates: vec![
1706+
("prop1".to_string(), "v1".to_string()),
1707+
("prop2".to_string(), "v2".to_string()),
1708+
]
1709+
.into_iter()
1710+
.collect(),
1711+
},
1712+
);
1713+
}
1714+
1715+
#[test]
1716+
fn test_view_remove_properties() {
1717+
test_serde_json(
1718+
r#"
1719+
{
1720+
"action": "remove-properties",
1721+
"removals": [
1722+
"prop1",
1723+
"prop2"
1724+
]
1725+
}
1726+
"#,
1727+
ViewUpdate::RemoveProperties {
1728+
removals: vec!["prop1".to_string(), "prop2".to_string()],
1729+
},
1730+
);
1731+
}
1732+
1733+
#[test]
1734+
fn test_view_add_view_version() {
1735+
test_serde_json(
1736+
r#"
1737+
{
1738+
"action": "add-view-version",
1739+
"view-version": {
1740+
"version-id" : 1,
1741+
"timestamp-ms" : 1573518431292,
1742+
"schema-id" : 1,
1743+
"default-catalog" : "prod",
1744+
"default-namespace" : [ "default" ],
1745+
"summary" : {
1746+
"engine-name" : "Spark"
1747+
},
1748+
"representations" : [ {
1749+
"type" : "sql",
1750+
"sql" : "SELECT\n COUNT(1), CAST(event_ts AS DATE)\nFROM events\nGROUP BY 2",
1751+
"dialect" : "spark"
1752+
} ]
1753+
}
1754+
}
1755+
"#,
1756+
ViewUpdate::AddViewVersion {
1757+
view_version: ViewVersion::builder()
1758+
.with_version_id(1)
1759+
.with_timestamp_ms(1573518431292)
1760+
.with_schema_id(1)
1761+
.with_default_catalog(Some("prod".to_string()))
1762+
.with_default_namespace(NamespaceIdent::from_strs(vec!["default"]).unwrap())
1763+
.with_summary(
1764+
vec![("engine-name".to_string(), "Spark".to_string())]
1765+
.into_iter()
1766+
.collect(),
1767+
)
1768+
.with_representations(ViewRepresentations(vec![ViewRepresentation::Sql(SqlViewRepresentation {
1769+
sql: "SELECT\n COUNT(1), CAST(event_ts AS DATE)\nFROM events\nGROUP BY 2".to_string(),
1770+
dialect: "spark".to_string(),
1771+
})]))
1772+
.build(),
1773+
},
1774+
);
1775+
}
1776+
1777+
#[test]
1778+
fn test_view_set_current_view_version() {
1779+
test_serde_json(
1780+
r#"
1781+
{
1782+
"action": "set-current-view-version",
1783+
"view-version-id": 1
1784+
}
1785+
"#,
1786+
ViewUpdate::SetCurrentViewVersion { view_version_id: 1 },
1787+
);
1788+
}
15311789
}

0 commit comments

Comments
 (0)