| # Licensed to the Apache Software Foundation (ASF) under one | |
| # or more contributor license agreements. See the NOTICE file | |
| # distributed with this work for additional information | |
| # regarding copyright ownership. The ASF licenses this file | |
| # to you under the Apache License, Version 2.0 (the | |
| # "License"); you may not use this file except in compliance | |
| # with the License. You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, | |
| # software distributed under the License is distributed on an | |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| # KIND, either express or implied. See the License for the | |
| # specific language governing permissions and limitations | |
| # under the License. | |
| from abc import ABC, abstractmethod | |
| class Instant(ABC): | |
| """Table rollback instant. | |
| Supports polymorphic JSON serialization via to_dict/from_dict | |
| Serialization format: | |
| SnapshotInstant: {"type": "snapshot", "snapshotId": 123} | |
| TagInstant: {"type": "tag", "tagName": "test_tag"} | |
| """ | |
| FIELD_TYPE = "type" | |
| TYPE_SNAPSHOT = "snapshot" | |
| TYPE_TAG = "tag" | |
| @staticmethod | |
| def snapshot(snapshot_id): | |
| """Create a SnapshotInstant. | |
| Args: | |
| snapshot_id: The snapshot ID to rollback to. | |
| Returns: | |
| A SnapshotInstant instance. | |
| """ | |
| return SnapshotInstant(snapshot_id) | |
| @staticmethod | |
| def tag(tag_name): | |
| """Create a TagInstant. | |
| Args: | |
| tag_name: The tag name to rollback to. | |
| Returns: | |
| A TagInstant instance. | |
| """ | |
| return TagInstant(tag_name) | |
| @abstractmethod | |
| def to_dict(self): | |
| """Serialize this Instant to a dictionary for JSON output.""" | |
| @staticmethod | |
| def from_dict(data): | |
| """Deserialize an Instant from a dictionary. | |
| Args: | |
| data: A dictionary with a 'type' field indicating the instant type. | |
| Returns: | |
| A SnapshotInstant or TagInstant instance. | |
| Raises: | |
| ValueError: If the type field is missing or unknown. | |
| """ | |
| instant_type = data.get(Instant.FIELD_TYPE) | |
| if instant_type == Instant.TYPE_SNAPSHOT: | |
| return SnapshotInstant(data[SnapshotInstant.FIELD_SNAPSHOT_ID]) | |
| elif instant_type == Instant.TYPE_TAG: | |
| return TagInstant(data[TagInstant.FIELD_TAG_NAME]) | |
| else: | |
| raise ValueError("Unknown instant type: {}".format(instant_type)) | |
| class SnapshotInstant(Instant): | |
| """Snapshot instant for table rollback.""" | |
| FIELD_SNAPSHOT_ID = "snapshotId" | |
| def __init__(self, snapshot_id): | |
| self.snapshot_id = snapshot_id | |
| def to_dict(self): | |
| return { | |
| Instant.FIELD_TYPE: Instant.TYPE_SNAPSHOT, | |
| self.FIELD_SNAPSHOT_ID: self.snapshot_id, | |
| } | |
| def __eq__(self, other): | |
| if not isinstance(other, SnapshotInstant): | |
| return False | |
| return self.snapshot_id == other.snapshot_id | |
| def __hash__(self): | |
| return hash(self.snapshot_id) | |
| def __repr__(self): | |
| return "SnapshotInstant(snapshot_id={})".format(self.snapshot_id) | |
| class TagInstant(Instant): | |
| """Tag instant for table rollback.""" | |
| FIELD_TAG_NAME = "tagName" | |
| def __init__(self, tag_name): | |
| self.tag_name = tag_name | |
| def to_dict(self): | |
| return { | |
| Instant.FIELD_TYPE: Instant.TYPE_TAG, | |
| self.FIELD_TAG_NAME: self.tag_name, | |
| } | |
| def __eq__(self, other): | |
| if not isinstance(other, TagInstant): | |
| return False | |
| return self.tag_name == other.tag_name | |
| def __hash__(self): | |
| return hash(self.tag_name) | |
| def __repr__(self): | |
| return "TagInstant(tag_name={})".format(self.tag_name) |