package iceberg
import (
"encoding/json"
"fmt"
"strings"
"golang.org/x/exp/slices"
)
const (
partitionDataIDStart = 1000
InitialPartitionSpecID = 0
)
var UnpartitionedSpec = &PartitionSpec {id : 0 }
type PartitionField struct {
SourceID int `json:"source-id"`
FieldID int `json:"field-id,omitempty"`
Name string `json:"name"`
Transform Transform `json:"transform"`
}
func (p *PartitionField ) String () string {
return fmt .Sprintf ("%d: %s: %s(%d)" , p .FieldID , p .Name , p .Transform , p .SourceID )
}
func (p *PartitionField ) UnmarshalJSON (b []byte ) error {
type Alias PartitionField
aux := struct {
TransformString string `json:"transform"`
*Alias
}{
Alias : (*Alias )(p ),
}
err := json .Unmarshal (b , &aux )
if err != nil {
return err
}
if p .Transform , err = ParseTransform (aux .TransformString ); err != nil {
return err
}
return nil
}
type PartitionSpec struct {
id int
fields []PartitionField
sourceIdToFields map [int ][]PartitionField
}
func NewPartitionSpec (fields ...PartitionField ) PartitionSpec {
return NewPartitionSpecID (InitialPartitionSpecID , fields ...)
}
func NewPartitionSpecID (id int , fields ...PartitionField ) PartitionSpec {
ret := PartitionSpec {id : id , fields : fields }
ret .initialize ()
return ret
}
func (ps *PartitionSpec ) CompatibleWith (other *PartitionSpec ) bool {
if ps == other {
return true
}
if len (ps .fields ) != len (other .fields ) {
return false
}
return slices .EqualFunc (ps .fields , other .fields , func (left , right PartitionField ) bool {
return left .SourceID == right .SourceID && left .Name == right .Name &&
left .Transform == right .Transform
})
}
func (ps *PartitionSpec ) Equals (other PartitionSpec ) bool {
return ps .id == other .id && slices .Equal (ps .fields , other .fields )
}
func (ps PartitionSpec ) MarshalJSON () ([]byte , error ) {
if ps .fields == nil {
ps .fields = []PartitionField {}
}
return json .Marshal (struct {
ID int `json:"spec-id"`
Fields []PartitionField `json:"fields"`
}{ps .id , ps .fields })
}
func (ps *PartitionSpec ) UnmarshalJSON (b []byte ) error {
aux := struct {
ID int `json:"spec-id"`
Fields []PartitionField `json:"fields"`
}{ID : ps .id , Fields : ps .fields }
if err := json .Unmarshal (b , &aux ); err != nil {
return err
}
ps .id , ps .fields = aux .ID , aux .Fields
ps .initialize ()
return nil
}
func (ps *PartitionSpec ) initialize () {
ps .sourceIdToFields = make (map [int ][]PartitionField )
for _ , f := range ps .fields {
ps .sourceIdToFields [f .SourceID ] =
append (ps .sourceIdToFields [f .SourceID ], f )
}
}
func (ps *PartitionSpec ) ID () int { return ps .id }
func (ps *PartitionSpec ) NumFields () int { return len (ps .fields ) }
func (ps *PartitionSpec ) Field (i int ) PartitionField { return ps .fields [i ] }
func (ps *PartitionSpec ) IsUnpartitioned () bool {
if len (ps .fields ) == 0 {
return true
}
for _ , f := range ps .fields {
if _ , ok := f .Transform .(VoidTransform ); !ok {
return false
}
}
return true
}
func (ps *PartitionSpec ) FieldsBySourceID (fieldID int ) []PartitionField {
return slices .Clone (ps .sourceIdToFields [fieldID ])
}
func (ps PartitionSpec ) String () string {
var b strings .Builder
b .WriteByte ('[' )
for i , f := range ps .fields {
if i == 0 {
b .WriteString ("\n" )
}
b .WriteString ("\t" )
b .WriteString (f .String ())
b .WriteString ("\n" )
}
b .WriteByte (']' )
return b .String ()
}
func (ps *PartitionSpec ) LastAssignedFieldID () int {
if len (ps .fields ) == 0 {
return partitionDataIDStart - 1
}
id := ps .fields [0 ].FieldID
for _ , f := range ps .fields [1 :] {
if f .FieldID > id {
id = f .FieldID
}
}
return id
}
func (ps *PartitionSpec ) PartitionType (schema *Schema ) *StructType {
nestedFields := []NestedField {}
for _ , field := range ps .fields {
sourceType , ok := schema .FindTypeByID (field .SourceID )
if !ok {
continue
}
resultType := field .Transform .ResultType (sourceType )
nestedFields = append (nestedFields , NestedField {
ID : field .FieldID ,
Name : field .Name ,
Type : resultType ,
Required : false ,
})
}
return &StructType {FieldList : nestedFields }
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .