Skip to content

Commit b223c24

Browse files
committed
adding tests and arrow and substrait passthroughs
Signed-off-by: happydave1 <dzhao2004@gmail.com>
1 parent 3d99104 commit b223c24

5 files changed

Lines changed: 115 additions & 0 deletions

File tree

schema.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,8 @@ type SchemaVisitorPerPrimitiveType[T any] interface {
567567
VisitBinary() T
568568
VisitUUID() T
569569
VisitUnknown() T
570+
VisitGeometry(GeometryType) T
571+
VisitGeography(GeographyType) T
570572
}
571573

572574
// Visit accepts a visitor and performs a post-order traversal of the given schema.

table/arrow_utils.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,22 @@ func (c convertToArrow) VisitUnknown() arrow.Field {
630630
}
631631
}
632632

633+
func (c convertToArrow) VisitGeometry(iceberg.GeometryType) arrow.Field {
634+
// Passthrough binary for now, adding geoarrow-go support later
635+
if c.useLargeTypes {
636+
return arrow.Field{Type: arrow.BinaryTypes.LargeBinary}
637+
}
638+
return arrow.Field{Type: arrow.BinaryTypes.Binary}
639+
}
640+
641+
func (c convertToArrow) VisitGeography(iceberg.GeographyType) arrow.Field {
642+
// Passthrough binary for now, adding geoarrow-go support later
643+
if c.useLargeTypes {
644+
return arrow.Field{Type: arrow.BinaryTypes.LargeBinary}
645+
}
646+
return arrow.Field{Type: arrow.BinaryTypes.Binary}
647+
}
648+
633649
var _ iceberg.SchemaVisitorPerPrimitiveType[arrow.Field] = convertToArrow{}
634650

635651
// SchemaToArrowSchema converts an Iceberg schema to an Arrow schema. If the metadata parameter

table/substrait/substrait.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,10 @@ func (convertToSubstrait) VisitUnknown() types.Type {
169169
// Returning nil indicates this type cannot be converted to Substrait
170170
return nil
171171
}
172+
func (convertToSubstrait) VisitGeometry(iceberg.GeometryType) types.Type { return &types.BinaryType{} }
173+
func (convertToSubstrait) VisitGeography(iceberg.GeographyType) types.Type {
174+
return &types.BinaryType{}
175+
}
172176

173177
var _ iceberg.SchemaVisitorPerPrimitiveType[types.Type] = (*convertToSubstrait)(nil)
174178

table/update_schema_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,31 @@ func TestAddColumn(t *testing.T) {
344344
}},
345345
}, newSchema.Fields())
346346
})
347+
348+
t.Run("test update schema with add geometry and geography columns", func(t *testing.T) {
349+
table := New([]string{"id"}, testMetadata, "", nil, nil)
350+
txn := table.NewTransaction()
351+
352+
geog, err := iceberg.GeographyTypeOf("srid:4269", iceberg.EdgeAlgorithmKarney)
353+
assert.NoError(t, err)
354+
355+
newSchema, err := NewUpdateSchema(txn, true, true).
356+
AddColumn([]string{"geom"}, iceberg.GeometryType{}, "", false, nil).
357+
AddColumn([]string{"geog"}, geog, "", false, nil).
358+
Apply()
359+
assert.NoError(t, err)
360+
assert.NotNil(t, newSchema)
361+
362+
geomField, ok := newSchema.FindFieldByName("geom")
363+
assert.True(t, ok)
364+
assert.Equal(t, 12, geomField.ID)
365+
assert.Equal(t, iceberg.GeometryType{}, geomField.Type)
366+
367+
geogField, ok := newSchema.FindFieldByName("geog")
368+
assert.True(t, ok)
369+
assert.Equal(t, 13, geogField.ID)
370+
assert.True(t, geogField.Type.Equals(geog))
371+
})
347372
}
348373

349374
func TestApplyChanges(t *testing.T) {
@@ -861,6 +886,31 @@ func TestErrorHandling(t *testing.T) {
861886
assert.Contains(t, err.Error(), "cannot change column nullability from optional to required")
862887
})
863888

889+
t.Run("test update geography CRS and edge algorithm without allowIncompatibleChanges", func(t *testing.T) {
890+
currentGeog, err := iceberg.GeographyTypeOf("srid:4269", iceberg.EdgeAlgorithmKarney)
891+
assert.NoError(t, err)
892+
targetGeog, err := iceberg.GeographyTypeOf("srid:4326", iceberg.EdgeAlgorithmSpherical)
893+
assert.NoError(t, err)
894+
895+
geoSchema := iceberg.NewSchema(1,
896+
iceberg.NestedField{ID: 1, Name: "id", Type: iceberg.PrimitiveTypes.Int32, Required: true},
897+
iceberg.NestedField{ID: 2, Name: "geog", Type: currentGeog, Required: false},
898+
)
899+
geoMeta, err := NewMetadata(geoSchema, nil, UnsortedSortOrder, "", iceberg.Properties{
900+
PropertyFormatVersion: "3",
901+
})
902+
assert.NoError(t, err)
903+
904+
table := New([]string{"geo"}, geoMeta, "", nil, nil)
905+
txn := table.NewTransaction()
906+
907+
_, err = NewUpdateSchema(txn, true, false).UpdateColumn([]string{"geog"}, ColumnUpdate{
908+
FieldType: iceberg.Optional[iceberg.Type]{Valid: true, Val: targetGeog},
909+
}).Apply()
910+
assert.Error(t, err)
911+
assert.Contains(t, err.Error(), "cannot promote geography(srid:4269, karney) to geography(srid:4326, spherical)")
912+
})
913+
864914
t.Run("test add required field without default value", func(t *testing.T) {
865915
table := New([]string{"id"}, testMetadata, "", nil, nil)
866916
txn := table.NewTransaction()

table/update_spec_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,49 @@ func TestUpdateSpecAddField(t *testing.T) {
204204
assert.NotNil(t, newSpec)
205205
assert.Equal(t, "street_void_1001", newSpec.FieldsBySourceID(5)[0].Name)
206206
})
207+
208+
t.Run("reject geometry source for identity partition transform", func(t *testing.T) {
209+
geoSchema := iceberg.NewSchema(1,
210+
iceberg.NestedField{ID: 1, Name: "id", Required: true, Type: iceberg.PrimitiveTypes.Int64},
211+
iceberg.NestedField{ID: 2, Name: "geom", Required: false, Type: iceberg.GeometryType{}},
212+
)
213+
metadata, err := table.NewMetadata(geoSchema, iceberg.UnpartitionedSpec, table.UnsortedSortOrder, "", nil)
214+
assert.NoError(t, err)
215+
216+
tbl := table.New([]string{"geo_geometry"}, metadata, "", nil, nil)
217+
specUpdate := table.NewUpdateSpec(tbl.NewTransaction(), true)
218+
219+
updates, reqs, err := specUpdate.
220+
AddField("geom", iceberg.IdentityTransform{}, "geom_identity").
221+
BuildUpdates()
222+
assert.Error(t, err)
223+
assert.Nil(t, updates)
224+
assert.Nil(t, reqs)
225+
})
226+
227+
t.Run("reject geography source for identity partition transform", func(t *testing.T) {
228+
geog, err := iceberg.GeographyTypeOf("srid:4269", iceberg.EdgeAlgorithmKarney)
229+
assert.NoError(t, err)
230+
231+
geoSchema := iceberg.NewSchema(1,
232+
iceberg.NestedField{ID: 1, Name: "id", Required: true, Type: iceberg.PrimitiveTypes.Int64},
233+
iceberg.NestedField{ID: 2, Name: "geog", Required: false, Type: geog},
234+
)
235+
metadata, err := table.NewMetadata(geoSchema, iceberg.UnpartitionedSpec, table.UnsortedSortOrder, "", nil)
236+
assert.NoError(t, err)
237+
238+
tbl := table.New([]string{"geo_geography"}, metadata, "", nil, nil)
239+
specUpdate := table.NewUpdateSpec(tbl.NewTransaction(), true)
240+
241+
updates, reqs, err := specUpdate.
242+
AddField("geog", iceberg.IdentityTransform{}, "geog_identity").
243+
BuildUpdates()
244+
assert.Error(t, err)
245+
assert.ErrorContains(t, err, "cannot transform")
246+
assert.ErrorContains(t, err, "geog")
247+
assert.Nil(t, updates)
248+
assert.Nil(t, reqs)
249+
})
207250
}
208251

209252
func TestUpdateSpecAddIdentityField(t *testing.T) {

0 commit comments

Comments
 (0)