Open-API: Refactor TableRequirements#7710
Conversation
I believe the constraints are not defined in the right way.
After generating code I got:
```python
class TableRequirement(BaseModel):
type: Literal[
'assert-create',
'assert-table-uuid',
'assert-ref-snapshot-id',
'assert-last-assigned-field-id',
'assert-current-schema-id',
'assert-last-assigned-partition-id',
'assert-default-spec-id',
'assert-default-sort-order-id',
]
ref: Optional[str] = None
uuid: Optional[str] = None
snapshot_id: Optional[int] = Field(None, alias='snapshot-id')
last_assigned_field_id: Optional[int] = Field(None, alias='last-assigned-field-id')
current_schema_id: Optional[int] = Field(None, alias='current-schema-id')
last_assigned_partition_id: Optional[int] = Field(
None, alias='last-assigned-partition-id'
)
default_spec_id: Optional[int] = Field(None, alias='default-spec-id')
default_sort_order_id: Optional[int] = Field(None, alias='default-sort-order-id')
```
Which encapulates all the requirements. After the refactor in this
PR, we'll end up with:
```python
class AssertCreate(BaseModel):
type: Literal['assert-create']
class AssertTableUUID(BaseModel):
type: Literal['assert-table-uuid']
uuid: str
class AssertRefSnapshotId(BaseModel):
type: Literal['assert-ref-snapshot-id']
ref: str
snapshot_id: int = Field(..., alias='snapshot-id')
class AssertLastAssignedFieldId(BaseModel):
type: Literal['assert-last-assigned-field-id']
last_assigned_partition_id: int = Field(..., alias='last-assigned-partition-id')
class AssertCurrentSchemaId(BaseModel):
type: Literal['assert-current-schema-id']
current_schema_id: int = Field(..., alias='current-schema-id')
class AssertLastAssignedPartitionId(BaseModel):
type: Literal['assert-last-assigned-partition-id']
last_assigned_partition_id: int = Field(..., alias='last-assigned-partition-id')
class AssertDefaultSpecId(BaseModel):
type: Literal['assert-default-spec-id']
default_spec_id: int = Field(..., alias='default-spec-id')
class AssertDefaultSortOrderId(BaseModel):
type: Literal['assert-default-sort-order-id']
default_sort_order_id: int = Field(..., alias='default-sort-order-id')
class TableRequirement(BaseModel):
__root__: Union[
AssertCreate,
AssertTableUUID,
AssertRefSnapshotId,
AssertLastAssignedFieldId,
AssertCurrentSchemaId,
AssertLastAssignedPartitionId,
AssertDefaultSpecId,
AssertDefaultSortOrderId,
] = Field(..., discriminator='type')
```
Which makes sense to me.
Co-authored-by: Eduard Tudenhoefner <etudenhoefner@gmail.com>
…ator-iceberg into fd-fix-open-api-requirements
|
Alright, now I have it right: class TableRequirement(BaseModel):
type: str
class AssertCreate(TableRequirement):
"""
The table must not already exist; used for create transactions
"""
type: Literal['assert-create']
class AssertTableUUID(TableRequirement):
"""
The table UUID must match the requirement's `uuid`
"""
type: Literal['assert-table-uuid']
uuid: str
class AssertRefSnapshotId(TableRequirement):
"""
The table branch or tag identified by the requirement's `ref` must reference the requirement's `snapshot-id`; if `snapshot-id` is `null` or missing, the ref must not already exist
"""
type: Literal['assert-ref-snapshot-id']
ref: str
snapshot_id: int = Field(..., alias='snapshot-id')
class AssertLastAssignedFieldId(TableRequirement):
"""
The table's last assigned column id must match the requirement's `last-assigned-field-id`
"""
type: Literal['assert-last-assigned-field-id']
last_assigned_field_id: int = Field(..., alias='last-assigned-field-id')
class AssertCurrentSchemaId(TableRequirement):
"""
The table's current schema id must match the requirement's `current-schema-id`
"""
type: Literal['assert-current-schema-id']
current_schema_id: int = Field(..., alias='current-schema-id')
class AssertLastAssignedPartitionId(TableRequirement):
"""
The table's last assigned partition id must match the requirement's `last-assigned-partition-id`
"""
type: Literal['assert-last-assigned-partition-id']
last_assigned_partition_id: int = Field(..., alias='last-assigned-partition-id')
class AssertDefaultSpecId(TableRequirement):
"""
The table's default spec id must match the requirement's `default-spec-id`
"""
type: Literal['assert-default-spec-id']
default_spec_id: int = Field(..., alias='default-spec-id')
class AssertDefaultSortOrderId(TableRequirement):
"""
The table's default sort order id must match the requirement's `default-sort-order-id`
"""
type: Literal['assert-default-sort-order-id']
default_sort_order_id: int = Field(..., alias='default-sort-order-id')The inheritance tree now checks out. |
It is not super clear from the current structure: https://github.com/apache/iceberg/blob/main/open-api/rest-catalog-open-api.py#L304-L329 This is because I had to deconstruct the object. It would be great to get apache/iceberg#7710 in
It is not super clear from the current structure: https://github.com/apache/iceberg/blob/main/open-api/rest-catalog-open-api.py#L304-L329 This is because I had to deconstruct the object. It would be great to get apache/iceberg#7710 in
It is not super clear from the current structure: https://github.com/apache/iceberg/blob/main/open-api/rest-catalog-open-api.py#L304-L329 This is because I had to deconstruct the object. It would be great to get apache/iceberg#7710 in
| - $ref: '#/components/schemas/SetPropertiesUpdate' | ||
| - $ref: '#/components/schemas/RemovePropertiesUpdate' | ||
|
|
||
| TableRequirement: |
There was a problem hiding this comment.
Nit: Should TableRequirement be defined first?
There was a problem hiding this comment.
Yes, I don't recall this isn't the case.
rdblue
left a comment
There was a problem hiding this comment.
This looks good to me. I like using the discriminator. We should probably refactor other areas to have that structure.
|
Sorry for the late review. This looks great. Thanks @Fokko! I didn't merge this in case it conflicts with the other linked PR. Feel free to merge in the order that makes the most sense. |
|
Hi, Have you tested this refactoring with code generated for Go? type TableRequirement struct {
Type string `json:"type"`
}and (for example) type AssertTableUUID struct {
TableRequirement
Type string `json:"type"`
Uuid string `json:"uuid"`
}There are couple of problems with that:
In summary, Go generated code does not produce equivalent to what it's shown for Python. |
|
@Fokko not sure if you'll see the above comment since the pr has been merged, thus an explicit call-out. |
Noticed this when working on #6323
I believe the requirements are not defined in the right way. After generating code I got:
Which encapsulates all the requirements. After the refactor in this PR, we'll end up with:
Which makes sense to me.
See below for the final version.