This is an automated email from the ASF dual-hosted git repository.

zeroshade pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-go.git


The following commit(s) were added to refs/heads/main by this push:
     new cc92ce59 feat(view): view updates & MetadataBuilder stubs (#621)
cc92ce59 is described below

commit cc92ce59a54d0444ddfe21b8f15be65234b4a39a
Author: Tobias Pütz <[email protected]>
AuthorDate: Mon Nov 17 19:45:43 2025 +0100

    feat(view): view updates & MetadataBuilder stubs (#621)
    
    - view updates + deserialization
    - ViewMetadataBuilder stubs
---
 table/metadata.go        |   4 +
 table/updates.go         |   2 +-
 view/metadata_builder.go |  57 +++++++++++
 view/updates.go          | 251 +++++++++++++++++++++++++++++++++++++++++++++++
 view/updates_test.go     | 107 ++++++++++++++++++++
 5 files changed, 420 insertions(+), 1 deletion(-)

diff --git a/table/metadata.go b/table/metadata.go
index 01b8cc4c..88e6607f 100644
--- a/table/metadata.go
+++ b/table/metadata.go
@@ -153,6 +153,10 @@ type Metadata interface {
        PartitionStatistics() iter.Seq[PartitionStatisticsFile]
 }
 
+// MetadataBuilder is a struct used for building and updating Iceberg table 
metadata.
+//
+// It keeps track of applied changes in the `updates` field. This can be used 
to commit changes made to a table to the
+// catalog.
 type MetadataBuilder struct {
        base    Metadata
        updates []Update
diff --git a/table/updates.go b/table/updates.go
index c8eb1c5a..db31da01 100644
--- a/table/updates.go
+++ b/table/updates.go
@@ -113,7 +113,7 @@ func (u *Updates) UnmarshalJSON(data []byte) error {
                case UpdateRemoveSchemas:
                        upd = &removeSchemasUpdate{}
                default:
-                       return fmt.Errorf("unknown update action: %s", 
base.ActionName)
+                       return fmt.Errorf("%w: unknown update action: %s", 
iceberg.ErrInvalidArgument, base.ActionName)
                }
 
                if err := json.Unmarshal(raw, upd); err != nil {
diff --git a/view/metadata_builder.go b/view/metadata_builder.go
new file mode 100644
index 00000000..c87f7a9e
--- /dev/null
+++ b/view/metadata_builder.go
@@ -0,0 +1,57 @@
+// 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.
+
+package view
+
+import (
+       "github.com/apache/iceberg-go"
+)
+
+// MetadataBuilder is a struct used for building and updating Iceberg view 
metadata.
+type MetadataBuilder struct{}
+
+func (b *MetadataBuilder) AssignUUID(_ string) error {
+       return iceberg.ErrNotImplemented
+}
+
+func (b *MetadataBuilder) UpgradeFormatVersion(_ int) error {
+       return iceberg.ErrNotImplemented
+}
+
+func (b *MetadataBuilder) AddSchema(_ *iceberg.Schema) error {
+       return iceberg.ErrNotImplemented
+}
+
+func (b *MetadataBuilder) SetLocation(_ string) error {
+       return iceberg.ErrNotImplemented
+}
+
+func (b *MetadataBuilder) SetProperties(_ map[string]string) error {
+       return iceberg.ErrNotImplemented
+}
+
+func (b *MetadataBuilder) RemoveProperties(_ []string) error {
+       return iceberg.ErrNotImplemented
+}
+
+func (b *MetadataBuilder) AddVersion(_ *Version) error {
+       return iceberg.ErrNotImplemented
+}
+
+func (b *MetadataBuilder) SetCurrentVersionID(_ int64) error {
+       return iceberg.ErrNotImplemented
+}
diff --git a/view/updates.go b/view/updates.go
new file mode 100644
index 00000000..87566325
--- /dev/null
+++ b/view/updates.go
@@ -0,0 +1,251 @@
+// 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.
+
+package view
+
+import (
+       "encoding/json"
+       "fmt"
+
+       "github.com/apache/iceberg-go"
+)
+
+const (
+       UpdateActionAssignUUID            = "assign-uuid"
+       UpdateActionUpgradeFormatVersion  = "upgrade-format-version"
+       UpdateActionAddSchema             = "add-schema"
+       UpdateActionSetLocation           = "set-location"
+       UpdateActionSetProperties         = "set-properties"
+       UpdateActionRemoveProperties      = "remove-properties"
+       UpdateActionAddViewVersion        = "add-view-version"
+       UpdateActionSetCurrentViewVersion = "set-current-view-version"
+)
+
+// ViewUpdate represents a change to view metadata.
+type ViewUpdate interface {
+       // Action returns the name of the action that the update represents.
+       Action() string
+       // Apply applies the update to the given metadata builder.
+       Apply(*MetadataBuilder) error
+}
+
+type baseViewUpdate struct {
+       ActionName string `json:"action"`
+}
+
+func (u *baseViewUpdate) Action() string {
+       return u.ActionName
+}
+
+// ViewUpdates represents a list of view updates.
+type ViewUpdates []ViewUpdate
+
+func (u *ViewUpdates) UnmarshalJSON(data []byte) error {
+       var rawUpdates []json.RawMessage
+       if err := json.Unmarshal(data, &rawUpdates); err != nil {
+               return err
+       }
+
+       for _, raw := range rawUpdates {
+               var base baseViewUpdate
+               if err := json.Unmarshal(raw, &base); err != nil {
+                       return err
+               }
+
+               var upd ViewUpdate
+               switch base.ActionName {
+               case UpdateActionAssignUUID:
+                       upd = &AssignUUIDUpdate{}
+               case UpdateActionUpgradeFormatVersion:
+                       upd = &UpgradeFormatVersionUpdate{}
+               case UpdateActionAddSchema:
+                       upd = &AddSchemaUpdate{}
+               case UpdateActionSetLocation:
+                       upd = &SetLocationUpdate{}
+               case UpdateActionSetProperties:
+                       upd = &SetPropertiesUpdate{}
+               case UpdateActionRemoveProperties:
+                       upd = &RemovePropertiesUpdate{}
+               case UpdateActionAddViewVersion:
+                       upd = &AddViewVersionUpdate{}
+               case UpdateActionSetCurrentViewVersion:
+                       upd = &SetCurrentViewVersionUpdate{}
+               default:
+                       return fmt.Errorf("%w: unknown update action: %s", 
iceberg.ErrInvalidArgument, base.ActionName)
+               }
+
+               if err := json.Unmarshal(raw, upd); err != nil {
+                       return err
+               }
+               *u = append(*u, upd)
+       }
+
+       return nil
+}
+
+// AssignUUIDUpdate assigns a UUID to the view MetadataBuilder.
+type AssignUUIDUpdate struct {
+       baseViewUpdate
+       UUID string `json:"uuid"`
+}
+
+// Apply assigns the UUID to the view MetadataBuilder.
+func (u *AssignUUIDUpdate) Apply(b *MetadataBuilder) error {
+       return b.AssignUUID(u.UUID)
+}
+
+// NewAssignUUIDUpdate creates a new update that assigns a UUID to the view 
MetadataBuilder.
+func NewAssignUUIDUpdate(uuid string) *AssignUUIDUpdate {
+       return &AssignUUIDUpdate{
+               baseViewUpdate: baseViewUpdate{ActionName: 
UpdateActionAssignUUID},
+               UUID:           uuid,
+       }
+}
+
+// UpgradeFormatVersionUpdate upgrades the format version of the view 
MetadataBuilder to the given version.
+type UpgradeFormatVersionUpdate struct {
+       baseViewUpdate
+       FormatVersion int `json:"format-version"`
+}
+
+// Apply upgrades the format version of the view MetadataBuilder to the given 
version.
+func (u *UpgradeFormatVersionUpdate) Apply(b *MetadataBuilder) error {
+       return b.UpgradeFormatVersion(u.FormatVersion)
+}
+
+// NewUpgradeFormatVersionUpdate creates a new update that upgrades the format 
version.
+func NewUpgradeFormatVersionUpdate(version int) *UpgradeFormatVersionUpdate {
+       return &UpgradeFormatVersionUpdate{
+               baseViewUpdate: baseViewUpdate{ActionName: 
UpdateActionUpgradeFormatVersion},
+               FormatVersion:  version,
+       }
+}
+
+// AddSchemaUpdate adds a new schema to the view MetadataBuilder.
+type AddSchemaUpdate struct {
+       baseViewUpdate
+       Schema       *iceberg.Schema `json:"schema"`
+       LastColumnID *int            `json:"last-column-id,omitempty"`
+}
+
+func (u *AddSchemaUpdate) Apply(b *MetadataBuilder) error {
+       return b.AddSchema(u.Schema)
+}
+
+// NewAddSchemaUpdate creates a new update that adds a new schema.
+func NewAddSchemaUpdate(schema *iceberg.Schema) *AddSchemaUpdate {
+       return &AddSchemaUpdate{
+               baseViewUpdate: baseViewUpdate{ActionName: 
UpdateActionAddSchema},
+               Schema:         schema,
+       }
+}
+
+// SetLocationUpdate updates the view location in the MetadataBuilder.
+type SetLocationUpdate struct {
+       baseViewUpdate
+       Location string `json:"location"`
+}
+
+// Apply updates the view location of the MetadataBuilder.
+func (u *SetLocationUpdate) Apply(b *MetadataBuilder) error {
+       return b.SetLocation(u.Location)
+}
+
+// NewSetLocationUpdate creates a new update that updates the view location in 
the MetadataBuilder.
+func NewSetLocationUpdate(location string) *SetLocationUpdate {
+       return &SetLocationUpdate{
+               baseViewUpdate: baseViewUpdate{ActionName: 
UpdateActionSetLocation},
+               Location:       location,
+       }
+}
+
+// SetPropertiesUpdate sets view properties.
+type SetPropertiesUpdate struct {
+       baseViewUpdate
+       Updates map[string]string `json:"updates"`
+}
+
+// Apply sets view properties in the MetadataBuilder.
+func (u *SetPropertiesUpdate) Apply(b *MetadataBuilder) error {
+       return b.SetProperties(u.Updates)
+}
+
+// NewSetPropertiesUpdate creates a new update that sets view properties in 
the view MetadataBuilder.
+func NewSetPropertiesUpdate(updates map[string]string) *SetPropertiesUpdate {
+       return &SetPropertiesUpdate{
+               baseViewUpdate: baseViewUpdate{ActionName: 
UpdateActionSetProperties},
+               Updates:        updates,
+       }
+}
+
+// RemovePropertiesUpdate removes view properties in the view MetadataBuilder.
+type RemovePropertiesUpdate struct {
+       baseViewUpdate
+       Removals []string `json:"removals"`
+}
+
+// Apply removes view properties from the view MetadataBuilder.
+func (u *RemovePropertiesUpdate) Apply(b *MetadataBuilder) error {
+       return b.RemoveProperties(u.Removals)
+}
+
+// NewRemovePropertiesUpdate creates a new update that removes view properties 
from the view MetadataBuilder.
+func NewRemovePropertiesUpdate(removals []string) *RemovePropertiesUpdate {
+       return &RemovePropertiesUpdate{
+               baseViewUpdate: baseViewUpdate{ActionName: 
UpdateActionRemoveProperties},
+               Removals:       removals,
+       }
+}
+
+// AddViewVersionUpdate adds a new view version to the view MetadataBuilder.
+type AddViewVersionUpdate struct {
+       baseViewUpdate
+       ViewVersion *Version `json:"view-version"`
+}
+
+// Apply adds a new view version to the view MetadataBuilder.
+func (u *AddViewVersionUpdate) Apply(b *MetadataBuilder) error {
+       return b.AddVersion(u.ViewVersion)
+}
+
+// NewAddViewVersionUpdate creates a new update that adds a new view version 
to the view MetadataBuilder.
+func NewAddViewVersionUpdate(version *Version) *AddViewVersionUpdate {
+       return &AddViewVersionUpdate{
+               baseViewUpdate: baseViewUpdate{ActionName: 
UpdateActionAddViewVersion},
+               ViewVersion:    version,
+       }
+}
+
+// SetCurrentViewVersionUpdate sets the current view version of the view 
MetadataBuilder.
+// VersionID can be -1 to reference the last added version.
+type SetCurrentViewVersionUpdate struct {
+       baseViewUpdate
+       VersionID int64 `json:"version-id"`
+}
+
+// Apply sets the current view version of the view MetadataBuilder.
+func (u *SetCurrentViewVersionUpdate) Apply(b *MetadataBuilder) error {
+       return b.SetCurrentVersionID(u.VersionID)
+}
+
+// NewSetCurrentViewVersionUpdate creates a new update that sets the current 
view version of the view MetadataBuilder.
+func NewSetCurrentViewVersionUpdate(versionID int64) 
*SetCurrentViewVersionUpdate {
+       return &SetCurrentViewVersionUpdate{
+               baseViewUpdate: baseViewUpdate{ActionName: 
UpdateActionSetCurrentViewVersion},
+               VersionID:      versionID,
+       }
+}
diff --git a/view/updates_test.go b/view/updates_test.go
new file mode 100644
index 00000000..80a05ccc
--- /dev/null
+++ b/view/updates_test.go
@@ -0,0 +1,107 @@
+// 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.
+
+package view_test
+
+import (
+       "encoding/json"
+       "testing"
+
+       "github.com/apache/iceberg-go/view"
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+func TestViewUpdatesUnmarshalJSON(t *testing.T) {
+       jsonData := `[
+               {
+                       "action": "assign-uuid",
+                       "uuid": "550e8400-e29b-41d4-a716-446655440000"
+               },
+               {
+                       "action": "upgrade-format-version",
+                       "format-version": 2
+               },
+               {
+                       "action": "set-location",
+                       "location": "s3://bucket/warehouse/view"
+               },
+               {
+                       "action": "set-properties",
+                       "updates": {
+                               "key1": "value1",
+                               "key2": "value2"
+                       }
+               },
+               {
+                       "action": "remove-properties",
+                       "removals": ["old-key"]
+               }
+       ]`
+
+       var updates view.ViewUpdates
+       err := json.Unmarshal([]byte(jsonData), &updates)
+       require.NoError(t, err)
+       require.Len(t, updates, 5)
+
+       assignUUID, ok := updates[0].(*view.AssignUUIDUpdate)
+       require.True(t, ok)
+       assert.Equal(t, "assign-uuid", assignUUID.Action())
+       assert.Equal(t, "550e8400-e29b-41d4-a716-446655440000", assignUUID.UUID)
+
+       upgradeVersion, ok := updates[1].(*view.UpgradeFormatVersionUpdate)
+       require.True(t, ok)
+       assert.Equal(t, "upgrade-format-version", upgradeVersion.Action())
+       assert.Equal(t, 2, upgradeVersion.FormatVersion)
+
+       setLocation, ok := updates[2].(*view.SetLocationUpdate)
+       require.True(t, ok)
+       assert.Equal(t, "set-location", setLocation.Action())
+       assert.Equal(t, "s3://bucket/warehouse/view", setLocation.Location)
+
+       setProps, ok := updates[3].(*view.SetPropertiesUpdate)
+       require.True(t, ok)
+       assert.Equal(t, "set-properties", setProps.Action())
+       assert.Equal(t, map[string]string{"key1": "value1", "key2": "value2"}, 
setProps.Updates)
+
+       removeProps, ok := updates[4].(*view.RemovePropertiesUpdate)
+       require.True(t, ok)
+       assert.Equal(t, "remove-properties", removeProps.Action())
+       assert.Equal(t, []string{"old-key"}, removeProps.Removals)
+}
+
+func TestViewUpdatesUnmarshalJSONUnknownAction(t *testing.T) {
+       jsonData := `[
+               {
+                       "action": "unknown-action",
+                       "field": "value"
+               }
+       ]`
+
+       var updates view.ViewUpdates
+       err := json.Unmarshal([]byte(jsonData), &updates)
+       require.Error(t, err)
+       assert.Contains(t, err.Error(), "unknown update action: unknown-action")
+}
+
+func TestViewUpdatesUnmarshalJSONInvalidJSON(t *testing.T) {
+       jsonData := `invalid json`
+
+       var updates view.ViewUpdates
+       err := json.Unmarshal([]byte(jsonData), &updates)
+       require.Error(t, err)
+}

Reply via email to