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-terraform.git
The following commit(s) were added to refs/heads/main by this push:
new 44d2417 Adds support for partition spec + sort order (#23)
44d2417 is described below
commit 44d241743da55a90dc2575afb13db903ba4116c3
Author: Alex Stephen <[email protected]>
AuthorDate: Tue Mar 24 09:18:16 2026 -0700
Adds support for partition spec + sort order (#23)
* Partition spec and sort ID
* PR changes
---
go.mod | 1 +
go.sum | 2 +
internal/provider/resource_table.go | 228 ++++++++++++++++++++++++++++++-
internal/provider/resource_table_test.go | 160 ++++++++++++++++++++++
internal/provider/table_schema.go | 107 +++++++++++++++
5 files changed, 496 insertions(+), 2 deletions(-)
diff --git a/go.mod b/go.mod
index 5851bc2..e6520a6 100644
--- a/go.mod
+++ b/go.mod
@@ -20,6 +20,7 @@ go 1.25.1
require (
github.com/apache/iceberg-go v0.4.1-0.20260201105728-7cfbf238ee7f
github.com/hashicorp/terraform-plugin-framework v1.17.0
+ github.com/hashicorp/terraform-plugin-framework-validators v0.17.0
github.com/hashicorp/terraform-plugin-go v0.29.0
github.com/hashicorp/terraform-plugin-log v0.10.0
github.com/hashicorp/terraform-plugin-testing v1.14.0
diff --git a/go.sum b/go.sum
index 5d48a01..cf0f2d7 100644
--- a/go.sum
+++ b/go.sum
@@ -361,6 +361,8 @@ github.com/hashicorp/terraform-json v0.27.2
h1:BwGuzM6iUPqf9JYM/Z4AF1OJ5VVJEEzoK
github.com/hashicorp/terraform-json v0.27.2/go.mod
h1:GzPLJ1PLdUG5xL6xn1OXWIjteQRT2CNT9o/6A9mi9hE=
github.com/hashicorp/terraform-plugin-framework v1.17.0
h1:JdX50CFrYcYFY31gkmitAEAzLKoBgsK+iaJjDC8OexY=
github.com/hashicorp/terraform-plugin-framework v1.17.0/go.mod
h1:4OUXKdHNosX+ys6rLgVlgklfxN3WHR5VHSOABeS/BM0=
+github.com/hashicorp/terraform-plugin-framework-validators v0.17.0
h1:0uYQcqqgW3BMyyve07WJgpKorXST3zkpzvrOnf3mpbg=
+github.com/hashicorp/terraform-plugin-framework-validators v0.17.0/go.mod
h1:VwdfgE/5Zxm43flraNa0VjcvKQOGVrcO4X8peIri0T0=
github.com/hashicorp/terraform-plugin-go v0.29.0
h1:1nXKl/nSpaYIUBU1IG/EsDOX0vv+9JxAltQyDMpq5mU=
github.com/hashicorp/terraform-plugin-go v0.29.0/go.mod
h1:vYZbIyvxyy0FWSmDHChCqKvI40cFTDGSb3D8D70i9GM=
github.com/hashicorp/terraform-plugin-log v0.10.0
h1:eu2kW6/QBVdN4P3Ju2WiB2W3ObjkAsyfBsL3Wh1fj3g=
diff --git a/internal/provider/resource_table.go
b/internal/provider/resource_table.go
index b22971b..b06e068 100644
--- a/internal/provider/resource_table.go
+++ b/internal/provider/resource_table.go
@@ -28,6 +28,8 @@ import (
rscschema
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/schema/validator"
+
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/hashicorp/terraform-plugin-log/tflog"
@@ -46,6 +48,8 @@ type icebergTableResourceModel struct {
Namespace types.List `tfsdk:"namespace"`
Name types.String `tfsdk:"name"`
Schema types.Object `tfsdk:"schema"`
+ PartitionSpec types.Object `tfsdk:"partition_spec"`
+ SortOrder types.Object `tfsdk:"sort_order"`
UserProperties types.Map `tfsdk:"user_properties"`
ServerProperties types.Map `tfsdk:"server_properties"`
}
@@ -96,6 +100,76 @@ func (r *icebergTableResource) Schema(_ context.Context, _
resource.SchemaReques
},
},
},
+ "partition_spec": rscschema.SingleNestedAttribute{
+ Description: "The partition spec of the table.",
+ Optional: true,
+ Computed: true,
+ Attributes: map[string]rscschema.Attribute{
+ "fields": rscschema.ListNestedAttribute{
+ Description: "The fields of the
partition spec.",
+ Required: true,
+ NestedObject:
rscschema.NestedAttributeObject{
+ Attributes:
map[string]rscschema.Attribute{
+ "source_ids":
rscschema.ListAttribute{
+
Description: "The source field IDs.",
+
Required: true,
+
ElementType: types.Int64Type,
+ },
+ "field_id":
rscschema.Int64Attribute{
+
Description: "The partition field ID.",
+
Optional: true,
+
Computed: true,
+ },
+ "name":
rscschema.StringAttribute{
+
Description: "The partition field name.",
+
Required: true,
+ },
+ "transform":
rscschema.StringAttribute{
+
Description: "The partition transform.",
+
Required: true,
+ },
+ },
+ },
+ },
+ },
+ },
+ "sort_order": rscschema.SingleNestedAttribute{
+ Description: "The sort order of the table.",
+ Optional: true,
+ Computed: true,
+ Attributes: map[string]rscschema.Attribute{
+ "fields": rscschema.ListNestedAttribute{
+ Description: "The fields of the
sort order.",
+ Required: true,
+ NestedObject:
rscschema.NestedAttributeObject{
+ Attributes:
map[string]rscschema.Attribute{
+ "source_id":
rscschema.Int64Attribute{
+
Description: "The source field ID.",
+
Required: true,
+ },
+ "transform":
rscschema.StringAttribute{
+
Description: "The sort transform.",
+
Required: true,
+ },
+ "direction":
rscschema.StringAttribute{
+
Description: "The sort direction (asc or desc).",
+
Required: true,
+
Validators: []validator.String{
+
stringvalidator.OneOf("asc", "desc"),
+ },
+ },
+ "null_order":
rscschema.StringAttribute{
+
Description: "The null order (nulls-first or nulls-last).",
+
Required: true,
+
Validators: []validator.String{
+
stringvalidator.OneOf("nulls-first", "nulls-last"),
+ },
+ },
+ },
+ },
+ },
+ },
+ },
"user_properties": rscschema.MapAttribute{
Description: "User-defined properties for the
table.",
Optional: true,
@@ -301,8 +375,41 @@ func (r *icebergTableResource) Create(ctx context.Context,
req resource.CreateRe
}
}
- // TODO: Add PartitionSpec support
- tbl, err := r.catalog.CreateTable(ctx, tableIdent, tblSchema,
catalog.WithProperties(userProps))
+ createOpts := []catalog.CreateTableOpt{
+ catalog.WithProperties(userProps),
+ }
+
+ if !data.PartitionSpec.IsNull() && !data.PartitionSpec.IsUnknown() {
+ var spec icebergTablePartitionSpec
+ diags = data.PartitionSpec.As(ctx, &spec,
basetypes.ObjectAsOptions{})
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+ icebergSpec, err := spec.ToIceberg()
+ if err != nil {
+ resp.Diagnostics.AddError("failed to convert partition
spec", err.Error())
+ return
+ }
+ createOpts = append(createOpts,
catalog.WithPartitionSpec(icebergSpec))
+ }
+
+ if !data.SortOrder.IsNull() && !data.SortOrder.IsUnknown() {
+ var order icebergTableSortOrder
+ diags = data.SortOrder.As(ctx, &order,
basetypes.ObjectAsOptions{})
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+ icebergOrder, err := order.ToIceberg()
+ if err != nil {
+ resp.Diagnostics.AddError("failed to convert sort
order", err.Error())
+ return
+ }
+ createOpts = append(createOpts,
catalog.WithSortOrder(icebergOrder))
+ }
+
+ tbl, err := r.catalog.CreateTable(ctx, tableIdent, tblSchema,
createOpts...)
if err != nil {
resp.Diagnostics.AddError("failed to create table", err.Error())
return
@@ -406,6 +513,8 @@ func (r *icebergTableResource) Update(ctx context.Context,
req resource.UpdateRe
updates = append(updates, r.calculatePropertyUpdates(ctx, &plan,
&state, &resp.Diagnostics)...)
updates = append(updates, r.calculateSchemaUpdates(ctx, &plan, &state,
&resp.Diagnostics)...)
+ updates = append(updates, r.calculatePartitionUpdates(ctx, &plan, tbl,
&resp.Diagnostics)...)
+ updates = append(updates, r.calculateSortOrderUpdates(ctx, &plan, tbl,
&resp.Diagnostics)...)
if resp.Diagnostics.HasError() {
return
@@ -507,6 +616,91 @@ func (r *icebergTableResource) calculateSchemaUpdates(ctx
context.Context, plan,
return nil
}
+func (r *icebergTableResource) calculatePartitionUpdates(ctx context.Context,
plan *icebergTableResourceModel, tbl *table.Table, diags *diag.Diagnostics)
[]table.Update {
+ spec := tbl.Spec()
+ if plan.PartitionSpec.IsUnknown() {
+ if spec.NumFields() > 0 {
+ // Create a new unpartitioned spec and set it as default
+ unpartitionedSpec := iceberg.NewPartitionSpec()
+ return []table.Update{
+
table.NewAddPartitionSpecUpdate(&unpartitionedSpec, false),
+ table.NewSetDefaultSpecUpdate(-1),
+ }
+ }
+ return nil
+ }
+
+ if plan.PartitionSpec.IsNull() {
+ return nil
+ }
+
+ var planSpec icebergTablePartitionSpec
+ d := plan.PartitionSpec.As(ctx, &planSpec, basetypes.ObjectAsOptions{})
+ diags.Append(d...)
+
+ if diags.HasError() {
+ return nil
+ }
+
+ newIcebergSpec, err := planSpec.ToIceberg()
+ if err != nil {
+ diags.AddError("failed to convert partition spec", err.Error())
+ return nil
+ }
+
+ // Compare with current spec
+ if !spec.CompatibleWith(newIcebergSpec) {
+ return []table.Update{
+ table.NewAddPartitionSpecUpdate(newIcebergSpec, false),
+ table.NewSetDefaultSpecUpdate(-1),
+ }
+ }
+
+ return nil
+}
+
+func (r *icebergTableResource) calculateSortOrderUpdates(ctx context.Context,
plan *icebergTableResourceModel, tbl *table.Table, diags *diag.Diagnostics)
[]table.Update {
+ if plan.SortOrder.IsUnknown() {
+ if tbl.SortOrder().OrderID() != 0 {
+ // Create a new unsorted order and set it as default
+ unsortedOrder := table.UnsortedSortOrder
+ return []table.Update{
+ table.NewAddSortOrderUpdate(&unsortedOrder),
+ table.NewSetDefaultSortOrderUpdate(0),
+ }
+ }
+ return nil
+ }
+
+ if plan.SortOrder.IsNull() {
+ return nil
+ }
+
+ var planOrder icebergTableSortOrder
+ d := plan.SortOrder.As(ctx, &planOrder, basetypes.ObjectAsOptions{})
+ diags.Append(d...)
+
+ if diags.HasError() {
+ return nil
+ }
+
+ newIcebergOrder, err := planOrder.ToIceberg()
+ if err != nil {
+ diags.AddError("failed to convert sort order", err.Error())
+ return nil
+ }
+
+ // Compare with current sort order
+ if !tbl.SortOrder().Equals(newIcebergOrder) {
+ return []table.Update{
+ table.NewAddSortOrderUpdate(&newIcebergOrder),
+ table.NewSetDefaultSortOrderUpdate(-1),
+ }
+ }
+
+ return nil
+}
+
func (r *icebergTableResource) syncTableToModel(ctx context.Context, tbl
*table.Table, model *icebergTableResourceModel, diags *diag.Diagnostics) {
// Update ServerProperties
serverProperties, d := types.MapValueFrom(ctx, types.StringType,
tbl.Properties())
@@ -530,6 +724,36 @@ func (r *icebergTableResource) syncTableToModel(ctx
context.Context, tbl *table.
return
}
+ // Update PartitionSpec
+ icebergSpec := tbl.Spec()
+ if icebergSpec.NumFields() > 0 {
+ var updatedSpec icebergTablePartitionSpec
+ if err := updatedSpec.FromIceberg(icebergSpec); err != nil {
+ diags.AddError("failed to convert iceberg partition
spec to terraform partition spec", err.Error())
+ return
+ }
+ var d3 diag.Diagnostics
+ model.PartitionSpec, d3 = types.ObjectValueFrom(ctx,
icebergTablePartitionSpec{}.AttrTypes(), updatedSpec)
+ diags.Append(d3...)
+ } else {
+ model.PartitionSpec =
types.ObjectNull(icebergTablePartitionSpec{}.AttrTypes())
+ }
+
+ // Update SortOrder
+ icebergOrder := tbl.SortOrder()
+ if icebergOrder.Len() > 0 {
+ var updatedOrder icebergTableSortOrder
+ if err := updatedOrder.FromIceberg(icebergOrder); err != nil {
+ diags.AddError("failed to convert iceberg sort order to
terraform sort order", err.Error())
+ return
+ }
+ var d4 diag.Diagnostics
+ model.SortOrder, d4 = types.ObjectValueFrom(ctx,
icebergTableSortOrder{}.AttrTypes(), updatedOrder)
+ diags.Append(d4...)
+ } else {
+ model.SortOrder =
types.ObjectNull(icebergTableSortOrder{}.AttrTypes())
+ }
+
// Update UserProperties to match reality for tracked keys
if !model.UserProperties.IsNull() {
planProps := make(map[string]string)
diff --git a/internal/provider/resource_table_test.go
b/internal/provider/resource_table_test.go
index a7c4868..be73c65 100644
--- a/internal/provider/resource_table_test.go
+++ b/internal/provider/resource_table_test.go
@@ -17,6 +17,7 @@ package provider
import (
"fmt"
"os"
+ "regexp"
"testing"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
@@ -376,3 +377,162 @@ resource "iceberg_table" "full" {
}
`, tableName)
}
+
+func TestAccIcebergTablePartitionSpecAndSortOrder(t *testing.T) {
+ catalogURI := os.Getenv("ICEBERG_CATALOG_URI")
+ if catalogURI == "" {
+ catalogURI = "http://localhost:8181"
+ }
+
+ providerCfg := fmt.Sprintf(providerConfig, catalogURI)
+ tableName := "partition_sort_test_table"
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config:
testAccIcebergTablePartitionSortConfig(providerCfg, tableName, "bucket[16]",
"asc"),
+ Check: resource.ComposeTestCheckFunc(
+
resource.TestCheckResourceAttr("iceberg_table.test", "name", tableName),
+
resource.TestCheckResourceAttr("iceberg_table.test", "partition_spec.fields.#",
"1"),
+
resource.TestCheckResourceAttr("iceberg_table.test",
"partition_spec.fields.0.source_ids.0", "1"),
+
resource.TestCheckResourceAttr("iceberg_table.test",
"partition_spec.fields.0.field_id", "1000"),
+
resource.TestCheckResourceAttr("iceberg_table.test",
"partition_spec.fields.0.name", "id_bucket"),
+
resource.TestCheckResourceAttr("iceberg_table.test",
"partition_spec.fields.0.transform", "bucket[16]"),
+
+
resource.TestCheckResourceAttr("iceberg_table.test", "sort_order.fields.#",
"1"),
+
resource.TestCheckResourceAttr("iceberg_table.test",
"sort_order.fields.0.source_id", "1"),
+
resource.TestCheckResourceAttr("iceberg_table.test",
"sort_order.fields.0.transform", "identity"),
+
resource.TestCheckResourceAttr("iceberg_table.test",
"sort_order.fields.0.direction", "asc"),
+
resource.TestCheckResourceAttr("iceberg_table.test",
"sort_order.fields.0.null_order", "nulls-first"),
+ ),
+ },
+ {
+ Config:
testAccIcebergTablePartitionSortConfig(providerCfg, tableName, "bucket[32]",
"desc"),
+ Check: resource.ComposeTestCheckFunc(
+
resource.TestCheckResourceAttr("iceberg_table.test", "name", tableName),
+
resource.TestCheckResourceAttr("iceberg_table.test", "partition_spec.fields.#",
"1"),
+
resource.TestCheckResourceAttr("iceberg_table.test",
"partition_spec.fields.0.transform", "bucket[32]"),
+
resource.TestCheckResourceAttr("iceberg_table.test", "sort_order.fields.#",
"1"),
+
resource.TestCheckResourceAttr("iceberg_table.test",
"sort_order.fields.0.direction", "desc"),
+ ),
+ },
+ {
+ Config:
testAccIcebergTablePartitionSortConfig(providerCfg, tableName, "bucket[32]",
"invalid"),
+ ExpectError: regexp.MustCompile(`(?s)Attribute
sort_order\.fields\[0\]\.direction value must be one of:.*"asc".*"desc".*got:
"invalid"`),
+ },
+ {
+ Config:
testAccIcebergTableInvalidNullOrderConfig(providerCfg, tableName),
+ ExpectError: regexp.MustCompile(`(?s)Attribute
sort_order\.fields\[0\]\.null_order value must be one
of:.*"nulls-first".*"nulls-last".*got: "invalid"`),
+ },
+ {
+ Config:
testAccIcebergTableNoPartitionSortConfig(providerCfg, tableName),
+ Check: resource.ComposeTestCheckFunc(
+
resource.TestCheckResourceAttr("iceberg_table.test", "name", tableName),
+
resource.TestCheckResourceAttr("iceberg_table.test", "partition_spec.fields.#",
"0"),
+
resource.TestCheckResourceAttr("iceberg_table.test", "sort_order.fields.#",
"0"),
+ ),
+ },
+ },
+ })
+}
+
+func testAccIcebergTableNoPartitionSortConfig(providerCfg string, tableName
string) string {
+ return providerCfg + fmt.Sprintf(`
+resource "iceberg_namespace" "db3" {
+ name = ["db3"]
+}
+
+resource "iceberg_table" "test" {
+ namespace = iceberg_namespace.db3.name
+ name = "%s"
+ schema = {
+ fields = [
+ {
+ id = 1
+ name = "id"
+ type = "long"
+ required = true
+ }
+ ]
+ }
+}
+`, tableName)
+}
+
+func testAccIcebergTableInvalidNullOrderConfig(providerCfg string, tableName
string) string {
+ return providerCfg + fmt.Sprintf(`
+resource "iceberg_namespace" "db3" {
+ name = ["db3"]
+}
+
+resource "iceberg_table" "test" {
+ namespace = iceberg_namespace.db3.name
+ name = "%s"
+ schema = {
+ fields = [
+ {
+ id = 1
+ name = "id"
+ type = "long"
+ required = true
+ }
+ ]
+ }
+ sort_order = {
+ fields = [
+ {
+ source_id = 1
+ transform = "identity"
+ direction = "asc"
+ null_order = "invalid"
+ }
+ ]
+ }
+}
+`, tableName)
+}
+
+func testAccIcebergTablePartitionSortConfig(providerCfg string, tableName
string, partitionTransform string, sortDirection string) string {
+ return providerCfg + fmt.Sprintf(`
+resource "iceberg_namespace" "db3" {
+ name = ["db3"]
+}
+
+resource "iceberg_table" "test" {
+ namespace = iceberg_namespace.db3.name
+ name = "%s"
+ schema = {
+ fields = [
+ {
+ id = 1
+ name = "id"
+ type = "long"
+ required = true
+ }
+ ]
+ }
+ partition_spec = {
+ fields = [
+ {
+ source_ids = [1]
+ field_id = 1000
+ name = "id_bucket"
+ transform = "%s"
+ }
+ ]
+ }
+ sort_order = {
+ fields = [
+ {
+ source_id = 1
+ transform = "identity"
+ direction = "%s"
+ null_order = "nulls-first"
+ }
+ ]
+ }
+}
+`, tableName, partitionTransform, sortDirection)
+}
diff --git a/internal/provider/table_schema.go
b/internal/provider/table_schema.go
index 85e7da4..d47e853 100644
--- a/internal/provider/table_schema.go
+++ b/internal/provider/table_schema.go
@@ -20,6 +20,7 @@ import (
"strings"
"github.com/apache/iceberg-go"
+ "github.com/apache/iceberg-go/table"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/types"
)
@@ -95,6 +96,112 @@ func (s *icebergTableSchema) FromIceberg(icebergSchema
*iceberg.Schema) error {
return json.Unmarshal(b, s)
}
+type icebergTablePartitionSpec struct {
+ Fields []icebergTablePartitionField `tfsdk:"fields" json:"fields"`
+}
+
+func (s icebergTablePartitionSpec) AttrTypes() map[string]attr.Type {
+ return map[string]attr.Type{
+ "fields": types.ListType{
+ ElemType: types.ObjectType{
+ AttrTypes:
icebergTablePartitionField{}.AttrTypes(),
+ },
+ },
+ }
+}
+
+func (s *icebergTablePartitionSpec) ToIceberg() (*iceberg.PartitionSpec,
error) {
+ b, err := json.Marshal(s)
+ if err != nil {
+ return nil, err
+ }
+ var icebergSpec iceberg.PartitionSpec
+ if err := json.Unmarshal(b, &icebergSpec); err != nil {
+ return nil, err
+ }
+ return &icebergSpec, nil
+}
+
+func (s *icebergTablePartitionSpec) FromIceberg(icebergSpec
iceberg.PartitionSpec) error {
+ s.Fields = make([]icebergTablePartitionField, 0,
icebergSpec.NumFields())
+ for field := range icebergSpec.Fields() {
+ fieldID := int64(field.FieldID)
+ s.Fields = append(s.Fields, icebergTablePartitionField{
+ SourceIDs: []int64{int64(field.SourceID)},
+ FieldID: &fieldID,
+ Name: field.Name,
+ Transform: field.Transform.String(),
+ })
+ }
+ return nil
+}
+
+type icebergTablePartitionField struct {
+ SourceIDs []int64 `tfsdk:"source_ids" json:"source-ids"`
+ FieldID *int64 `tfsdk:"field_id" json:"field-id,omitempty"`
+ Name string `tfsdk:"name" json:"name"`
+ Transform string `tfsdk:"transform" json:"transform"`
+}
+
+func (icebergTablePartitionField) AttrTypes() map[string]attr.Type {
+ return map[string]attr.Type{
+ "source_ids": types.ListType{ElemType: types.Int64Type},
+ "field_id": types.Int64Type,
+ "name": types.StringType,
+ "transform": types.StringType,
+ }
+}
+
+type icebergTableSortOrder struct {
+ Fields []icebergTableSortField `tfsdk:"fields" json:"fields"`
+}
+
+func (s icebergTableSortOrder) AttrTypes() map[string]attr.Type {
+ return map[string]attr.Type{
+ "fields": types.ListType{
+ ElemType: types.ObjectType{
+ AttrTypes: icebergTableSortField{}.AttrTypes(),
+ },
+ },
+ }
+}
+
+func (s *icebergTableSortOrder) ToIceberg() (table.SortOrder, error) {
+ b, err := json.Marshal(s)
+ if err != nil {
+ return table.SortOrder{}, err
+ }
+ var icebergOrder table.SortOrder
+ if err := json.Unmarshal(b, &icebergOrder); err != nil {
+ return table.SortOrder{}, err
+ }
+ return icebergOrder, nil
+}
+
+func (s *icebergTableSortOrder) FromIceberg(icebergOrder table.SortOrder)
error {
+ b, err := json.Marshal(icebergOrder)
+ if err != nil {
+ return err
+ }
+ return json.Unmarshal(b, s)
+}
+
+type icebergTableSortField struct {
+ SourceID int64 `tfsdk:"source_id" json:"source-id"`
+ Transform string `tfsdk:"transform" json:"transform"`
+ Direction string `tfsdk:"direction" json:"direction"`
+ NullOrder string `tfsdk:"null_order" json:"null-order"`
+}
+
+func (icebergTableSortField) AttrTypes() map[string]attr.Type {
+ return map[string]attr.Type{
+ "source_id": types.Int64Type,
+ "transform": types.StringType,
+ "direction": types.StringType,
+ "null_order": types.StringType,
+ }
+}
+
type icebergTableSchemaField struct {
ID types.Int64 `tfsdk:"id"
json:"id"`
Name string `tfsdk:"name"
json:"name"`