package table
import (
"context"
"encoding/json"
"errors"
"fmt"
"strconv"
"github.com/polarsignals/iceberg-go"
"github.com/thanos-io/objstore"
"golang.org/x/exp/maps"
)
type Operation string
const (
OpAppend Operation = "append"
OpReplace Operation = "replace"
OpOverwrite Operation = "overwrite"
OpDelete Operation = "delete"
)
var (
ErrInvalidOperation = errors .New ("invalid operation value" )
ErrMissingOperation = errors .New ("missing operation key" )
)
func ValidOperation (s string ) (Operation , error ) {
switch s {
case "append" , "replace" , "overwrite" , "delete" :
return Operation (s ), nil
}
return "" , fmt .Errorf ("%w: found '%s'" , ErrInvalidOperation , s )
}
const operationKey = "operation"
type Summary struct {
Operation Operation
Properties map [string ]string
}
func (s *Summary ) String () string {
out := string (s .Operation )
if s .Properties != nil {
data , _ := json .Marshal (s .Properties )
out += ", " + string (data )
}
return out
}
func (s *Summary ) Equals (other *Summary ) bool {
if s == other {
return true
}
if s != nil && other == nil {
return false
}
if s .Operation != other .Operation {
return false
}
if len (s .Properties ) == 0 && len (other .Properties ) == 0 {
return true
}
return maps .Equal (s .Properties , other .Properties )
}
func (s *Summary ) UnmarshalJSON (b []byte ) (err error ) {
alias := map [string ]string {}
if err = json .Unmarshal (b , &alias ); err != nil {
return
}
op , ok := alias [operationKey ]
if !ok {
return ErrMissingOperation
}
if s .Operation , err = ValidOperation (op ); err != nil {
return
}
delete (alias , operationKey )
s .Properties = alias
return nil
}
func (s *Summary ) MarshalJSON () ([]byte , error ) {
props := maps .Clone (s .Properties )
if s .Operation != "" {
if props == nil {
props = make (map [string ]string )
}
props [operationKey ] = string (s .Operation )
}
return json .Marshal (props )
}
type Snapshot struct {
SnapshotID int64 `json:"snapshot-id"`
ParentSnapshotID *int64 `json:"parent-snapshot-id,omitempty"`
SequenceNumber int64 `json:"sequence-number"`
TimestampMs int64 `json:"timestamp-ms"`
ManifestList string `json:"manifest-list,omitempty"`
Summary *Summary `json:"summary,omitempty"`
SchemaID *int `json:"schema-id,omitempty"`
}
func (s Snapshot ) String () string {
var (
op , parent , schema string
)
if s .Summary != nil {
op = s .Summary .String () + ": "
}
if s .ParentSnapshotID != nil {
parent = ", parent_id=" + strconv .FormatInt (*s .ParentSnapshotID , 10 )
}
if s .SchemaID != nil {
schema = ", schema_id=" + strconv .Itoa (*s .SchemaID )
}
return fmt .Sprintf ("%sid=%d%s%s, sequence_number=%d, timestamp_ms=%d, manifest_list=%s" ,
op , s .SnapshotID , parent , schema , s .SequenceNumber , s .TimestampMs , s .ManifestList )
}
func (s Snapshot ) Equals (other Snapshot ) bool {
switch {
case s .ParentSnapshotID == nil && other .ParentSnapshotID != nil :
fallthrough
case s .ParentSnapshotID != nil && other .ParentSnapshotID == nil :
fallthrough
case s .SchemaID == nil && other .SchemaID != nil :
fallthrough
case s .SchemaID != nil && other .SchemaID == nil :
return false
}
return s .SnapshotID == other .SnapshotID &&
((s .ParentSnapshotID == other .ParentSnapshotID ) || (*s .ParentSnapshotID == *other .ParentSnapshotID )) &&
((s .SchemaID == other .SchemaID ) || (*s .SchemaID == *other .SchemaID )) &&
s .SequenceNumber == other .SequenceNumber &&
s .TimestampMs == other .TimestampMs &&
s .ManifestList == other .ManifestList &&
s .Summary .Equals (other .Summary )
}
func (s Snapshot ) Manifests (bucket objstore .Bucket ) ([]iceberg .ManifestFile , error ) {
if s .ManifestList != "" {
f , err := bucket .Get (context .TODO (), s .ManifestList )
if err != nil {
return nil , fmt .Errorf ("could not open manifest file: %w" , err )
}
defer f .Close ()
return iceberg .ReadManifestList (f )
}
return nil , nil
}
type MetadataLogEntry struct {
MetadataFile string `json:"metadata-file"`
TimestampMs int64 `json:"timestamp-ms"`
}
type SnapshotLogEntry struct {
SnapshotID int64 `json:"snapshot-id"`
TimestampMs int64 `json:"timestamp-ms"`
}
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 .