Skip to content

Commit dd58ac1

Browse files
grihaborFokko
andauthored
Implement update for remove-snapshot-ref action (#1598)
Part of #1561 Closes #822 --------- Co-authored-by: Fokko Driesprong <[email protected]>
1 parent 829b7dc commit dd58ac1

File tree

4 files changed

+103
-0
lines changed

4 files changed

+103
-0
lines changed

pyiceberg/table/update/__init__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,22 @@ def _(update: SetSnapshotRefUpdate, base_metadata: TableMetadata, context: _Tabl
466466
return base_metadata.model_copy(update=metadata_updates)
467467

468468

469+
@_apply_table_update.register(RemoveSnapshotRefUpdate)
470+
def _(update: RemoveSnapshotRefUpdate, base_metadata: TableMetadata, context: _TableMetadataUpdateContext) -> TableMetadata:
471+
if update.ref_name not in base_metadata.refs:
472+
return base_metadata
473+
474+
existing_ref = base_metadata.refs[update.ref_name]
475+
if base_metadata.snapshot_by_id(existing_ref.snapshot_id) is None:
476+
raise ValueError(f"Cannot remove {update.ref_name} ref with unknown snapshot {existing_ref.snapshot_id}")
477+
478+
current_snapshot_id = None if update.ref_name == MAIN_BRANCH else base_metadata.current_snapshot_id
479+
480+
metadata_refs = {ref_name: ref for ref_name, ref in base_metadata.refs.items() if ref_name != update.ref_name}
481+
context.add_update(update)
482+
return base_metadata.model_copy(update={"refs": metadata_refs, "current_snapshot_id": current_snapshot_id})
483+
484+
469485
@_apply_table_update.register(AddSortOrderUpdate)
470486
def _(update: AddSortOrderUpdate, base_metadata: TableMetadata, context: _TableMetadataUpdateContext) -> TableMetadata:
471487
context.add_update(update)

pyiceberg/table/update/snapshot.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
from pyiceberg.table.update import (
6666
AddSnapshotUpdate,
6767
AssertRefSnapshotId,
68+
RemoveSnapshotRefUpdate,
6869
SetSnapshotRefUpdate,
6970
TableRequirement,
7071
TableUpdate,
@@ -746,6 +747,28 @@ def _commit(self) -> UpdatesAndRequirements:
746747
"""Apply the pending changes and commit."""
747748
return self._updates, self._requirements
748749

750+
def _remove_ref_snapshot(self, ref_name: str) -> ManageSnapshots:
751+
"""Remove a snapshot ref.
752+
753+
Args:
754+
ref_name: branch / tag name to remove
755+
Stages the updates and requirements for the remove-snapshot-ref.
756+
Returns
757+
This method for chaining
758+
"""
759+
updates = (RemoveSnapshotRefUpdate(ref_name=ref_name),)
760+
requirements = (
761+
AssertRefSnapshotId(
762+
snapshot_id=self._transaction.table_metadata.refs[ref_name].snapshot_id
763+
if ref_name in self._transaction.table_metadata.refs
764+
else None,
765+
ref=ref_name,
766+
),
767+
)
768+
self._updates += updates
769+
self._requirements += requirements
770+
return self
771+
749772
def create_tag(self, snapshot_id: int, tag_name: str, max_ref_age_ms: Optional[int] = None) -> ManageSnapshots:
750773
"""
751774
Create a new tag pointing to the given snapshot id.
@@ -768,6 +791,17 @@ def create_tag(self, snapshot_id: int, tag_name: str, max_ref_age_ms: Optional[i
768791
self._requirements += requirement
769792
return self
770793

794+
def remove_tag(self, tag_name: str) -> ManageSnapshots:
795+
"""
796+
Remove a tag.
797+
798+
Args:
799+
tag_name (str): name of tag to remove
800+
Returns:
801+
This for method chaining
802+
"""
803+
return self._remove_ref_snapshot(ref_name=tag_name)
804+
771805
def create_branch(
772806
self,
773807
snapshot_id: int,
@@ -799,3 +833,14 @@ def create_branch(
799833
self._updates += update
800834
self._requirements += requirement
801835
return self
836+
837+
def remove_branch(self, branch_name: str) -> ManageSnapshots:
838+
"""
839+
Remove a branch.
840+
841+
Args:
842+
branch_name (str): name of branch to remove
843+
Returns:
844+
This for method chaining
845+
"""
846+
return self._remove_ref_snapshot(ref_name=branch_name)

tests/integration/test_snapshot_operations.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,35 @@ def test_create_branch(catalog: Catalog) -> None:
4040
branch_snapshot_id = tbl.history()[-2].snapshot_id
4141
tbl.manage_snapshots().create_branch(snapshot_id=branch_snapshot_id, branch_name="branch123").commit()
4242
assert tbl.metadata.refs["branch123"] == SnapshotRef(snapshot_id=branch_snapshot_id, snapshot_ref_type="branch")
43+
44+
45+
@pytest.mark.integration
46+
@pytest.mark.parametrize("catalog", [pytest.lazy_fixture("session_catalog_hive"), pytest.lazy_fixture("session_catalog")])
47+
def test_remove_tag(catalog: Catalog) -> None:
48+
identifier = "default.test_table_snapshot_operations"
49+
tbl = catalog.load_table(identifier)
50+
assert len(tbl.history()) > 3
51+
# first, create the tag to remove
52+
tag_name = "tag_to_remove"
53+
tag_snapshot_id = tbl.history()[-3].snapshot_id
54+
tbl.manage_snapshots().create_tag(snapshot_id=tag_snapshot_id, tag_name=tag_name).commit()
55+
assert tbl.metadata.refs[tag_name] == SnapshotRef(snapshot_id=tag_snapshot_id, snapshot_ref_type="tag")
56+
# now, remove the tag
57+
tbl.manage_snapshots().remove_tag(tag_name=tag_name).commit()
58+
assert tbl.metadata.refs.get(tag_name, None) is None
59+
60+
61+
@pytest.mark.integration
62+
@pytest.mark.parametrize("catalog", [pytest.lazy_fixture("session_catalog_hive"), pytest.lazy_fixture("session_catalog")])
63+
def test_remove_branch(catalog: Catalog) -> None:
64+
identifier = "default.test_table_snapshot_operations"
65+
tbl = catalog.load_table(identifier)
66+
assert len(tbl.history()) > 2
67+
# first, create the branch to remove
68+
branch_name = "branch_to_remove"
69+
branch_snapshot_id = tbl.history()[-2].snapshot_id
70+
tbl.manage_snapshots().create_branch(snapshot_id=branch_snapshot_id, branch_name=branch_name).commit()
71+
assert tbl.metadata.refs[branch_name] == SnapshotRef(snapshot_id=branch_snapshot_id, snapshot_ref_type="branch")
72+
# now, remove the branch
73+
tbl.manage_snapshots().remove_branch(branch_name=branch_name).commit()
74+
assert tbl.metadata.refs.get(branch_name, None) is None

tests/table/test_init.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
AssertRefSnapshotId,
7979
AssertTableUUID,
8080
RemovePropertiesUpdate,
81+
RemoveSnapshotRefUpdate,
8182
RemoveStatisticsUpdate,
8283
SetDefaultSortOrderUpdate,
8384
SetPropertiesUpdate,
@@ -793,6 +794,15 @@ def test_update_metadata_set_snapshot_ref(table_v2: Table) -> None:
793794
)
794795

795796

797+
def test_update_remove_snapshots(table_v2: Table) -> None:
798+
# assert fixture data to easily understand the test assumptions
799+
assert len(table_v2.metadata.refs) == 2
800+
update = RemoveSnapshotRefUpdate(ref_name="test")
801+
new_metadata = update_table_metadata(table_v2.metadata, (update,))
802+
assert len(new_metadata.refs) == 1
803+
assert new_metadata.refs["main"].snapshot_id == 3055729675574597004
804+
805+
796806
def test_update_metadata_add_update_sort_order(table_v2: Table) -> None:
797807
new_sort_order = SortOrder(order_id=table_v2.sort_order().order_id + 1)
798808
new_metadata = update_table_metadata(

0 commit comments

Comments
 (0)