laskoviymishka commented on code in PR #1313:
URL: https://github.com/apache/iceberg-go/pull/1313#discussion_r3490763459


##########
table/sorting.go:
##########
@@ -271,6 +303,9 @@ func NewSortOrder(orderID int, fields []SortField) 
(SortOrder, error) {
                fields = []SortField{}
        }
        for idx, field := range fields {
+               if err := validateSortSourceIDs(field.SourceIDs); err != nil {

Review Comment:
   This changes the error a caller sees for `SortField{SourceIDs: nil, 
Transform: nil}` from `ErrInvalidTransform` to `ErrInvalidSortSourceID`, since 
the source-id check now runs first. `NewSortOrder` is public with named 
sentinels, so anyone doing `errors.Is(err, ErrInvalidTransform)` on 
programmatic construction quietly breaks — worth documenting the new validation 
order in the godoc, or reordering so transform stays first.
   
   While here: `fmt.Errorf("%w: sort field at index %d", err, idx)` wraps an 
already-wrapped `err`, so the message reads "invalid sort source ID: source-ids 
must not be empty: sort field at index 0" with the index trailing. The 
transform line right below it puts the sentinel first in a self-contained 
message — I'd flatten this to match.



##########
table/sorting.go:
##########
@@ -180,6 +190,28 @@ func (s *SortField) UnmarshalJSON(b []byte) error {
        return nil
 }
 
+func validateSortSourceID(id int) error {
+       if id <= 0 {

Review Comment:
   I'd drop the `id <= 0` guard from the parse path — it's stricter than the 
spec. The spec doesn't reserve source-id 0 for sort fields (only order-id 0, 
for unsorted), and Java's `SortOrderParser`, iceberg-rust, and PyIceberg all 
accept it with no range check.
   
   Since this fires in `UnmarshalJSON`, a table another client wrote with 
source-id 0 becomes unreadable here — we'd fail to load the metadata at all. If 
we want to reject nonsensical *writes*, the place for it is 
`CheckCompatibility` or `MarshalJSON`, not the reader. wdyt?



##########
table/sorting.go:
##########
@@ -133,10 +134,13 @@ func (s *SortField) UnmarshalJSON(b []byte) error {
                return fmt.Errorf("%w: failed to unmarshal sort field", err)
        }
 
-       if _, ok := raw["source-id"]; ok {
-               if _, ok := raw["source-ids"]; ok {
-                       return errors.New("sort field cannot contain both 
source-id and source-ids")
-               }
+       _, hasSourceID := raw["source-id"]
+       _, hasSourceIDs := raw["source-ids"]
+       if hasSourceID && hasSourceIDs {
+               return errors.New("sort field cannot contain both source-id and 
source-ids")
+       }
+       if !hasSourceID && !hasSourceIDs {
+               return fmt.Errorf("%w: sort field must contain source-id or 
source-ids", ErrInvalidSortSourceID)

Review Comment:
   V3 marks both `source-id` and `source-ids` as `optional` in the sort field 
JSON, so a reader hard-failing when both are absent isn't spec-compliant — the 
"single-arg writes source-id, multi-arg writes source-ids" rule is a writer 
obligation, not a reader parse-rejection rule.
   
   Same interop risk as the zero-check: a V3 writer that omits both (a future 
extension, or a quirk in another client) makes the whole table unreadable here. 
I'd let `SourceIDs` stay empty through the parse and let `CheckCompatibility` 
reject it downstream. Keep the `hasSourceID && hasSourceIDs` rejection though — 
that one's genuinely malformed.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to