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 4ebe066d feat(metadata): remove schemas + validations & tests (#567)
4ebe066d is described below
commit 4ebe066d30e269e18b477d36947973104cc22999
Author: Tobias Pütz <[email protected]>
AuthorDate: Thu Sep 18 21:03:21 2025 +0200
feat(metadata): remove schemas + validations & tests (#567)
1. implement removeSchemas update
2. Add validation of sortOrders against schema
---
partitions.go | 2 +-
table/metadata.go | 71 ++++++++++++++--
table/metadata_builder_internal_test.go | 94 +++++++++++++++++++++-
table/metadata_internal_test.go | 46 ++++++++++-
table/sorting.go | 24 ++++++
table/testdata/TableMetadataV1NoValidSchema.json | 45 +++++++++++
.../TableMetadataV1SchemasWithoutCurrentId.json | 69 ++++++++++++++++
.../TableMetadataV2CurrentSchemaNotFound.json | 88 ++++++++++++++++++++
table/testdata/TableMetadataV2MissingSchemas.json | 71 ++++++++++++++++
table/updates.go | 8 +-
table/updates_test.go | 13 ---
11 files changed, 502 insertions(+), 29 deletions(-)
diff --git a/partitions.go b/partitions.go
index db66abd2..7bf5c0a2 100644
--- a/partitions.go
+++ b/partitions.go
@@ -96,7 +96,7 @@ type PartitionOption func(*PartitionSpec) error
// Otherwise, the existing spec id will be used.
// If a field in the spec is incompatible with the schema, an error will be
// returned.
-func (p *PartitionSpec) BindToSchema(schema *Schema, lastPartitionID *int,
newSpecID *int, isUnbound bool) (PartitionSpec, error) {
+func (p *PartitionSpec) BindToSchema(schema *Schema, lastPartitionID *int,
newSpecID *int) (PartitionSpec, error) {
opts := make([]PartitionOption, 0)
if newSpecID != nil {
opts = append(opts, WithSpecID(*newSpecID))
diff --git a/table/metadata.go b/table/metadata.go
index 568c9fd3..bae44694 100644
--- a/table/metadata.go
+++ b/table/metadata.go
@@ -286,8 +286,12 @@ func (b *MetadataBuilder) AddSchema(schema
*iceberg.Schema) error {
func (b *MetadataBuilder) AddPartitionSpec(spec *iceberg.PartitionSpec,
initial bool) error {
newSpecID := b.reuseOrCreateNewPartitionSpecID(*spec)
+ curSchema := b.CurrentSchema()
+ if curSchema == nil {
+ return errors.New("can't add sort order with no current schema")
+ }
- freshSpec, err := spec.BindToSchema(b.CurrentSchema(),
b.lastPartitionID, &newSpecID, false)
+ freshSpec, err := spec.BindToSchema(curSchema, b.lastPartitionID,
&newSpecID)
if err != nil {
return err
}
@@ -381,6 +385,15 @@ func (b *MetadataBuilder) RemoveSnapshots(snapshotIds
[]int64) error {
}
func (b *MetadataBuilder) AddSortOrder(sortOrder *SortOrder, initial bool)
error {
+ curSchema := b.CurrentSchema()
+ if curSchema == nil {
+ return errors.New("can't add sort order with no current schema")
+ }
+
+ if err := sortOrder.CheckCompatibility(curSchema); err != nil {
+ return fmt.Errorf("sort order %s is not compatible with current
schema: %w", sortOrder, err)
+ }
+
var sortOrders []SortOrder
if !initial {
sortOrders = append(sortOrders, b.sortOrderList...)
@@ -412,7 +425,8 @@ func (b *MetadataBuilder) RemoveProperties(keys []string)
error {
}
func (b *MetadataBuilder) SetCurrentSchemaID(currentSchemaID int) error {
- if currentSchemaID == -1 {
+ takeLast := currentSchemaID == -1
+ if takeLast {
if b.lastAddedSchemaID == nil {
return errors.New("can't set current schema to last
added schema, no schema has been added")
}
@@ -428,7 +442,11 @@ func (b *MetadataBuilder)
SetCurrentSchemaID(currentSchemaID int) error {
return fmt.Errorf("can't set current schema to schema with id
%d: %w", currentSchemaID, err)
}
- b.updates = append(b.updates,
NewSetCurrentSchemaUpdate(currentSchemaID))
+ if takeLast {
+ b.updates = append(b.updates, NewSetCurrentSchemaUpdate(-1))
+ } else {
+ b.updates = append(b.updates,
NewSetCurrentSchemaUpdate(currentSchemaID))
+ }
b.currentSchemaID = currentSchemaID
return nil
@@ -774,6 +792,7 @@ func (b *MetadataBuilder) Build() (Metadata, error) {
if err != nil {
return nil, err
}
+
if err := common.validate(); err != nil {
return nil, err
}
@@ -871,6 +890,33 @@ func (b *MetadataBuilder) RemovePartitionSpecs(ints []int)
error {
return nil
}
+func (b *MetadataBuilder) RemoveSchemas(ints []int) error {
+ if len(ints) == 0 {
+ return nil
+ }
+
+ if slices.Contains(ints, b.currentSchemaID) {
+ return fmt.Errorf("can't remove current schema with id %d",
b.currentSchemaID)
+ }
+
+ removed := make([]int, len(ints))
+ b.schemaList = slices.DeleteFunc(b.schemaList, func(s *iceberg.Schema)
bool {
+ if slices.Contains(ints, s.ID) {
+ removed = append(removed, s.ID)
+
+ return true
+ }
+
+ return false
+ })
+
+ if len(removed) != 0 {
+ b.updates = append(b.updates, NewRemoveSchemasUpdate(ints))
+ }
+
+ return nil
+}
+
// maxBy returns the maximum value of extract(e) for all e in elems.
// If elems is empty, returns 0.
func maxBy[S ~[]E, E any](elems S, extract func(e E) int) int {
@@ -1162,8 +1208,15 @@ func (c *commonMetadata) checkSortOrders() error {
for _, o := range c.SortOrderList {
if o.OrderID == c.DefaultSortOrderID {
+ if err := o.CheckCompatibility(c.CurrentSchema()); err
!= nil {
+ return fmt.Errorf("default sort order %d is not
compatible with current schema: %w", o.OrderID, err)
+ }
+
return nil
}
+ if o.OrderID == UnsortedSortOrderID && len(o.Fields) != 0 {
+ return fmt.Errorf("sort order ID %d is reserved for
unsorted order", UnsortedSortOrderID)
+ }
}
return fmt.Errorf("%w: default-sort-order-id %d can't be found in %+v",
@@ -1417,19 +1470,19 @@ func NewMetadataWithUUID(sc *iceberg.Schema, partitions
*iceberg.PartitionSpec,
return nil, err
}
- if err = builder.AddSortOrder(&reassignedIds.sortOrder, true); err !=
nil {
+ if err = builder.AddSchema(reassignedIds.schema); err != nil {
return nil, err
}
- if err = builder.SetDefaultSortOrderID(-1); err != nil {
+ if err = builder.SetCurrentSchemaID(-1); err != nil {
return nil, err
}
- if err = builder.AddSchema(reassignedIds.schema); err != nil {
+ if err = builder.AddSortOrder(&reassignedIds.sortOrder, true); err !=
nil {
return nil, err
}
- if err = builder.SetCurrentSchemaID(-1); err != nil {
+ if err = builder.SetDefaultSortOrderID(-1); err != nil {
return nil, err
}
@@ -1437,6 +1490,10 @@ func NewMetadataWithUUID(sc *iceberg.Schema, partitions
*iceberg.PartitionSpec,
return nil, err
}
+ if err = builder.SetDefaultSpecID(-1); err != nil {
+ return nil, err
+ }
+
if err = builder.SetLoc(location); err != nil {
return nil, err
}
diff --git a/table/metadata_builder_internal_test.go
b/table/metadata_builder_internal_test.go
index 0ff33869..0c733110 100644
--- a/table/metadata_builder_internal_test.go
+++ b/table/metadata_builder_internal_test.go
@@ -71,15 +71,18 @@ func builderWithoutChanges(formatVersion int)
MetadataBuilder {
if err = builder.SetFormatVersion(formatVersion); err != nil {
panic(err)
}
- if err = builder.AddSortOrder(&sortOrder, true); err != nil {
- panic(err)
- }
if err = builder.AddSchema(&tableSchema); err != nil {
panic(err)
}
if err = builder.SetCurrentSchemaID(-1); err != nil {
panic(err)
}
+ if err = builder.AddSortOrder(&sortOrder, true); err != nil {
+ panic(err)
+ }
+ if err = builder.SetDefaultSortOrderID(-1); err != nil {
+ panic(err)
+ }
if err = builder.AddPartitionSpec(&partitionSpec, true); err != nil {
panic(err)
}
@@ -331,6 +334,91 @@ func TestCannotAddDuplicateSnapshotID(t *testing.T) {
require.ErrorContains(t, builder.AddSnapshot(&snapshot), "can't add
snapshot with id 2, already exists")
}
+func TestAddIncompatibleCurrentSchemaFails(t *testing.T) {
+ builder := builderWithoutChanges(2)
+ addedSchema := iceberg.NewSchema(1)
+ err := builder.AddSchema(addedSchema)
+ require.NoError(t, err)
+ err = builder.SetCurrentSchemaID(1)
+ require.NoError(t, err)
+ _, err = builder.Build()
+ require.ErrorContains(t, err, "with source id 3 not found in schema")
+}
+
+func TestActiveSchemaCannotBeRemoved(t *testing.T) {
+ builder := builderWithoutChanges(2)
+ // Try to remove the current schema
+ require.ErrorContains(t, builder.RemoveSchemas([]int{0}), "can't remove
current schema with id 0")
+}
+
+func TestRemoveSchemas(t *testing.T) {
+ meta, err := getTestTableMetadata("TableMetadataV2Valid.json")
+ require.NoError(t, err)
+ require.Len(t, meta.Schemas(), 2, "expected 2 schemas in the metadata")
+ builder, err := MetadataBuilderFromBase(meta)
+ require.NoError(t, err)
+ err = builder.RemoveSchemas([]int{0})
+ require.NoError(t, err, "expected to remove schema with ID 1")
+ newMeta, err := builder.Build()
+ require.NoError(t, err)
+ require.Len(t, newMeta.Schemas(), 1, "expected 1 schema in the metadata
after removal")
+ require.Equal(t, 1, newMeta.CurrentSchema().ID, "expected current
schema to be 1")
+ require.Equal(t, 1, newMeta.(*metadataV2).CurrentSchemaID)
+ require.Len(t, builder.updates, 1, "expected one update for schema
removal")
+ require.Equal(t, builder.updates[0].Action(), UpdateRemoveSchemas)
+ require.Equal(t, builder.updates[0].(*removeSchemasUpdate).SchemaIDs,
[]int{0}, "expected schema ID 0 to be removed")
+}
+
+// Java: TestTableMetadata.testUpdateSchema
+func TestUpdateSchema(t *testing.T) {
+ // Test schema updates and evolution
+ schema1 := iceberg.NewSchema(
+ 0,
+ iceberg.NestedField{ID: 1, Name: "y", Type:
iceberg.PrimitiveTypes.Int64, Required: true, Doc: "comment"},
+ )
+
+ meta, err := NewMetadata(
+ schema1,
+ iceberg.UnpartitionedSpec,
+ UnsortedSortOrder,
+ "s3://bucket/test/location",
+ map[string]string{},
+ )
+ require.NoError(t, err)
+
+ require.Equal(t, 0, meta.CurrentSchema().ID)
+ require.Len(t, meta.Schemas(), 1)
+ require.Equal(t, 1, meta.LastColumnID())
+
+ // Update schema by adding a field
+ schema2 := iceberg.NewSchema(
+ 1,
+ iceberg.NestedField{ID: 1, Name: "y", Type:
iceberg.PrimitiveTypes.Int64, Required: true, Doc: "comment"},
+ iceberg.NestedField{ID: 2, Name: "x", Type:
iceberg.PrimitiveTypes.String, Required: true},
+ )
+
+ builder, err := MetadataBuilderFromBase(meta)
+ require.NoError(t, err)
+
+ err = builder.AddSchema(schema2)
+ require.NoError(t, err)
+
+ err = builder.SetCurrentSchemaID(-1) // Use last added
+ require.NoError(t, err)
+
+ updatedMeta, err := builder.Build()
+ require.NoError(t, err)
+
+ require.Equal(t, 1, updatedMeta.CurrentSchema().ID)
+ require.Len(t, updatedMeta.Schemas(), 2)
+ require.Equal(t, 2, updatedMeta.LastColumnID())
+
+ // Verify both schemas are preserved
+ schemas := updatedMeta.Schemas()
+ require.True(t, schemas[0].Equals(schema1))
+ require.True(t, schemas[1].Equals(schema2))
+}
+
func TestRemoveMainSnapshotRef(t *testing.T) {
meta, err := getTestTableMetadata("TableMetadataV2Valid.json")
require.NoError(t, err)
diff --git a/table/metadata_internal_test.go b/table/metadata_internal_test.go
index 87c3fd55..78bc5fe0 100644
--- a/table/metadata_internal_test.go
+++ b/table/metadata_internal_test.go
@@ -755,7 +755,9 @@ func TestMetadataV2Serialize(t *testing.T) {
func TestMetadataBuilderSetDefaultSpecIDLastPartition(t *testing.T) {
builder, err := NewMetadataBuilder()
assert.NoError(t, err)
-
+ schema := schema()
+ assert.NoError(t, builder.AddSchema(&schema))
+ assert.NoError(t, builder.SetCurrentSchemaID(-1))
partitionSpec := iceberg.NewPartitionSpecID(0)
assert.NoError(t, builder.AddPartitionSpec(&partitionSpec, false))
@@ -986,6 +988,48 @@ func TestDefaultPartitionSpec(t *testing.T) {
require.Equal(t, partitionSpec.ID(), defaultSpecID)
}
+func TestTableMetadataV1SchemasWithoutCurrentId(t *testing.T) {
+ meta, err :=
getTestTableMetadata("TableMetadataV1SchemasWithoutCurrentId.json")
+ require.NoError(t, err)
+ require.Equal(t, meta.(*metadataV1).Version(), 1)
+ require.Equal(t, meta.TableUUID(),
uuid.MustParse("d20125c8-7284-442c-9aea-15fee620737c"))
+ schema := meta.CurrentSchema()
+ require.Equal(t, len(schema.Fields()), 3)
+ require.Equal(t, schema.Fields()[0].Name, "x")
+ require.Equal(t, schema.Fields()[1].Name, "y")
+ require.Equal(t, schema.Fields()[2].Name, "z")
+}
+
+func TestTableMetadataV1NoValidSchema(t *testing.T) {
+ meta, err := getTestTableMetadata("TableMetadataV1NoValidSchema.json")
+ require.ErrorContains(t, err, "invalid metadata: current-schema-id -1
can't be found in any schema")
+ require.Nil(t, meta)
+}
+
+func TestTableMetadataV2SchemaNotFound(t *testing.T) {
+ meta, err :=
getTestTableMetadata("TableMetadataV2CurrentSchemaNotFound.json")
+ require.ErrorContains(t, err, "invalid metadata: current-schema-id 2
can't be found in any schema")
+ require.Nil(t, meta)
+}
+
+func TestTableMetadataV2MissingSchemas(t *testing.T) {
+ meta, err := getTestTableMetadata("TableMetadataV2MissingSchemas.json")
+ require.ErrorContains(t, err, "invalid metadata: current-schema-id -1
can't be found in any schema")
+ require.Nil(t, meta)
+}
+
+// Java: TestTableMetadata.testParseSchemaIdentifierFields
+func TestParseSchemaIdentifierFields(t *testing.T) {
+ meta, err := getTestTableMetadata("TableMetadataV2Valid.json")
+ require.NoError(t, err)
+ // Verify identifier fields
+ schemas := meta.Schemas()
+ require.Len(t, schemas, 2)
+
+ require.Empty(t, schemas[0].IdentifierFieldIDs)
+ require.Equal(t, []int{1, 2}, schemas[1].IdentifierFieldIDs)
+}
+
func getTestTableMetadata(fileName string) (Metadata, error) {
fCont, err := os.ReadFile(path.Join("testdata", fileName))
if err != nil {
diff --git a/table/sorting.go b/table/sorting.go
index 1ae9f053..d72ceb78 100644
--- a/table/sorting.go
+++ b/table/sorting.go
@@ -137,6 +137,30 @@ type SortOrder struct {
Fields []SortField `json:"fields"`
}
+func (s *SortOrder) CheckCompatibility(schema *iceberg.Schema) error {
+ if s == nil {
+ return nil
+ }
+
+ for _, field := range s.Fields {
+ f, ok := schema.FindFieldByID(field.SourceID)
+ if !ok {
+ return fmt.Errorf("sort field with source id %d not
found in schema", field.SourceID)
+ }
+
+ if _, ok := f.Type.(iceberg.PrimitiveType); !ok {
+ return fmt.Errorf("cannot sort by non-primitive source
field: %s", f.Type.Type())
+ }
+
+ // FIXME: field.Transform should be made required
+ if field.Transform != nil &&
!field.Transform.CanTransform(f.Type) {
+ return fmt.Errorf("invalid source type %s for transform
%s", f.Type.Type(), field.Transform)
+ }
+ }
+
+ return nil
+}
+
func (s SortOrder) Equals(rhs SortOrder) bool {
return s.OrderID == rhs.OrderID &&
slices.Equal(s.Fields, rhs.Fields)
diff --git a/table/testdata/TableMetadataV1NoValidSchema.json
b/table/testdata/TableMetadataV1NoValidSchema.json
new file mode 100644
index 00000000..b29c2fa3
--- /dev/null
+++ b/table/testdata/TableMetadataV1NoValidSchema.json
@@ -0,0 +1,45 @@
+{
+ "format-version": 1,
+ "table-uuid": "d20125c8-7284-442c-9aea-15fee620737c",
+ "location": "s3://bucket/test/location",
+ "last-updated-ms": 1602638573874,
+ "last-column-id": 3,
+ "schemas": [
+ {
+ "fields": [
+ {
+ "id": 1,
+ "name": "x",
+ "required": true,
+ "type": "long"
+ },
+ {
+ "id": 2,
+ "name": "y",
+ "required": true,
+ "type": "long",
+ "doc": "comment"
+ },
+ {
+ "id": 3,
+ "name": "z",
+ "required": true,
+ "type": "long"
+ }
+ ],
+ "schema-id": 0,
+ "type": "struct"
+ }
+ ],
+ "partition-spec": [
+ {
+ "name": "x",
+ "transform": "identity",
+ "source-id": 1,
+ "field-id": 1000
+ }
+ ],
+ "properties": {},
+ "current-snapshot-id": -1,
+ "snapshots": []
+}
\ No newline at end of file
diff --git a/table/testdata/TableMetadataV1SchemasWithoutCurrentId.json
b/table/testdata/TableMetadataV1SchemasWithoutCurrentId.json
new file mode 100644
index 00000000..7276c2a8
--- /dev/null
+++ b/table/testdata/TableMetadataV1SchemasWithoutCurrentId.json
@@ -0,0 +1,69 @@
+{
+ "format-version": 1,
+ "table-uuid": "d20125c8-7284-442c-9aea-15fee620737c",
+ "location": "s3://bucket/test/location",
+ "last-updated-ms": 1602638573874,
+ "last-column-id": 3,
+ "schemas": [
+ {
+ "fields": [
+ {
+ "id": 1,
+ "name": "x",
+ "required": true,
+ "type": "long"
+ },
+ {
+ "id": 2,
+ "name": "y",
+ "required": true,
+ "type": "long",
+ "doc": "comment"
+ },
+ {
+ "id": 3,
+ "name": "z",
+ "required": true,
+ "type": "long"
+ }
+ ],
+ "schema-id": 0,
+ "type": "struct"
+ }
+ ],
+ "schema": {
+ "type": "struct",
+ "fields": [
+ {
+ "id": 1,
+ "name": "x",
+ "required": true,
+ "type": "long"
+ },
+ {
+ "id": 2,
+ "name": "y",
+ "required": true,
+ "type": "long",
+ "doc": "comment"
+ },
+ {
+ "id": 3,
+ "name": "z",
+ "required": true,
+ "type": "long"
+ }
+ ]
+ },
+ "partition-spec": [
+ {
+ "name": "x",
+ "transform": "identity",
+ "source-id": 1,
+ "field-id": 1000
+ }
+ ],
+ "properties": {},
+ "current-snapshot-id": -1,
+ "snapshots": []
+}
\ No newline at end of file
diff --git a/table/testdata/TableMetadataV2CurrentSchemaNotFound.json
b/table/testdata/TableMetadataV2CurrentSchemaNotFound.json
new file mode 100644
index 00000000..d010785b
--- /dev/null
+++ b/table/testdata/TableMetadataV2CurrentSchemaNotFound.json
@@ -0,0 +1,88 @@
+{
+ "format-version": 2,
+ "table-uuid": "9c12d441-03fe-4693-9a96-a0705ddf69c1",
+ "location": "s3://bucket/test/location",
+ "last-sequence-number": 34,
+ "last-updated-ms": 1602638573590,
+ "last-column-id": 3,
+ "current-schema-id": 2,
+ "schemas": [
+ {
+ "type": "struct",
+ "schema-id": 0,
+ "fields": [
+ {
+ "id": 1,
+ "name": "x",
+ "required": true,
+ "type": "long"
+ }
+ ]
+ },
+ {
+ "type": "struct",
+ "schema-id": 1,
+ "fields": [
+ {
+ "id": 1,
+ "name": "x",
+ "required": true,
+ "type": "long"
+ },
+ {
+ "id": 2,
+ "name": "y",
+ "required": true,
+ "type": "long",
+ "doc": "comment"
+ },
+ {
+ "id": 3,
+ "name": "z",
+ "required": true,
+ "type": "long"
+ }
+ ]
+ }
+ ],
+ "default-spec-id": 0,
+ "partition-specs": [
+ {
+ "spec-id": 0,
+ "fields": [
+ {
+ "name": "x",
+ "transform": "identity",
+ "source-id": 1,
+ "field-id": 1000
+ }
+ ]
+ }
+ ],
+ "last-partition-id": 1000,
+ "default-sort-order-id": 3,
+ "sort-orders": [
+ {
+ "order-id": 3,
+ "fields": [
+ {
+ "transform": "identity",
+ "source-id": 2,
+ "direction": "asc",
+ "null-order": "nulls-first"
+ },
+ {
+ "transform": "bucket[4]",
+ "source-id": 3,
+ "direction": "desc",
+ "null-order": "nulls-last"
+ }
+ ]
+ }
+ ],
+ "properties": {},
+ "current-snapshot-id": -1,
+ "snapshots": [],
+ "snapshot-log": [],
+ "metadata-log": []
+}
\ No newline at end of file
diff --git a/table/testdata/TableMetadataV2MissingSchemas.json
b/table/testdata/TableMetadataV2MissingSchemas.json
new file mode 100644
index 00000000..3754354e
--- /dev/null
+++ b/table/testdata/TableMetadataV2MissingSchemas.json
@@ -0,0 +1,71 @@
+{
+ "format-version": 2,
+ "table-uuid": "9c12d441-03fe-4693-9a96-a0705ddf69c1",
+ "location": "s3://bucket/test/location",
+ "last-sequence-number": 34,
+ "last-updated-ms": 1602638573590,
+ "last-column-id": 3,
+ "schema": {
+ "type": "struct",
+ "fields": [
+ {
+ "id": 1,
+ "name": "x",
+ "required": true,
+ "type": "long"
+ },
+ {
+ "id": 2,
+ "name": "y",
+ "required": true,
+ "type": "long",
+ "doc": "comment"
+ },
+ {
+ "id": 3,
+ "name": "z",
+ "required": true,
+ "type": "long"
+ }
+ ]
+ },
+ "default-spec-id": 0,
+ "partition-specs": [
+ {
+ "spec-id": 0,
+ "fields": [
+ {
+ "name": "x",
+ "transform": "identity",
+ "source-id": 1,
+ "field-id": 1000
+ }
+ ]
+ }
+ ],
+ "default-sort-order-id": 3,
+ "sort-orders": [
+ {
+ "order-id": 3,
+ "fields": [
+ {
+ "transform": "identity",
+ "source-id": 2,
+ "direction": "asc",
+ "null-order": "nulls-first"
+ },
+ {
+ "transform": "bucket[4]",
+ "source-id": 3,
+ "direction": "desc",
+ "null-order": "nulls-last"
+ }
+ ]
+ }
+ ],
+ "properties": {},
+ "current-snapshot-id": -1,
+ "snapshots": [],
+ "snapshot-log": [],
+ "metadata-log": []
+}
\ No newline at end of file
diff --git a/table/updates.go b/table/updates.go
index dd867aab..996e1db4 100644
--- a/table/updates.go
+++ b/table/updates.go
@@ -541,18 +541,18 @@ func (u *removeSpecUpdate) Apply(builder
*MetadataBuilder) error {
type removeSchemasUpdate struct {
baseUpdate
- SchemaIds []int64 `json:"schema-ids"`
+ SchemaIDs []int `json:"schema-i-ds"`
}
// NewRemoveSchemasUpdate creates a new Update that removes a list of schemas
from
// the table metadata.
-func NewRemoveSchemasUpdate(schemaIds []int64) *removeSchemasUpdate {
+func NewRemoveSchemasUpdate(schemaIds []int) *removeSchemasUpdate {
return &removeSchemasUpdate{
baseUpdate: baseUpdate{ActionName: UpdateRemoveSchemas},
- SchemaIds: schemaIds,
+ SchemaIDs: schemaIds,
}
}
func (u *removeSchemasUpdate) Apply(builder *MetadataBuilder) error {
- return fmt.Errorf("%w: %s", iceberg.ErrNotImplemented,
UpdateRemoveSchemas)
+ return builder.RemoveSchemas(u.SchemaIDs)
}
diff --git a/table/updates_test.go b/table/updates_test.go
index c96a97c4..ade8a4da 100644
--- a/table/updates_test.go
+++ b/table/updates_test.go
@@ -19,7 +19,6 @@ package table
import (
"encoding/json"
- "errors"
"testing"
"github.com/apache/iceberg-go"
@@ -218,15 +217,3 @@ func TestUnmarshalUpdates(t *testing.T) {
})
}
}
-
-func TestRemoveSchemas(t *testing.T) {
- var builder *MetadataBuilder
- removeSchemas := removeSchemasUpdate{
- SchemaIds: []int64{},
- }
- t.Run("remove schemas should fail", func(t *testing.T) {
- if err := removeSchemas.Apply(builder); !errors.Is(err,
iceberg.ErrNotImplemented) {
- t.Fatalf("Expected unimplemented error, got %v", err)
- }
- })
-}