github.com/fraugster/parquet-go@v0.12.0/floor/interfaces/marshaller.go (about)

     1  package interfaces
     2  
     3  import "github.com/fraugster/parquet-go/parquetschema"
     4  
     5  // Marshaller is the interface necessary for objects to be
     6  // marshalled when passed to the (*Writer).WriteRecord method.
     7  type Marshaller interface {
     8  	MarshalParquet(obj MarshalObject) error
     9  }
    10  
    11  // MarshalObject is the interface a Marshaller needs to marshall its data
    12  // to.
    13  type MarshalObject interface {
    14  	AddField(field string) MarshalElement
    15  
    16  	GetData() map[string]interface{}
    17  }
    18  
    19  // MarshalElement describes the interface to set the value of an element in a Marshaller
    20  // implementation.
    21  type MarshalElement interface {
    22  	Group() MarshalObject
    23  	SetInt32(i int32)
    24  	SetInt64(i int64)
    25  	SetInt96(i [12]byte)
    26  	SetFloat32(f float32)
    27  	SetFloat64(f float64)
    28  	SetBool(b bool)
    29  	SetByteArray(data []byte)
    30  	List() MarshalList
    31  	Map() MarshalMap
    32  }
    33  
    34  // MarshalList describes the interface to add a list of values in a Marshaller
    35  // implementation.
    36  type MarshalList interface {
    37  	Add() MarshalElement
    38  }
    39  
    40  // MarshalMap describes the interface to add a map of keys and values in a Marshaller
    41  // implementation.
    42  type MarshalMap interface {
    43  	Add() MarshalMapElement
    44  }
    45  
    46  // MarshalMapElement describes the interfaces to set an individual pair of keys and
    47  // values in a Marshaller implementation.
    48  type MarshalMapElement interface {
    49  	Key() MarshalElement
    50  	Value() MarshalElement
    51  }
    52  
    53  type object struct {
    54  	data   map[string]interface{}
    55  	schema *parquetschema.SchemaDefinition
    56  }
    57  
    58  func (o *object) GetData() map[string]interface{} {
    59  	return o.data
    60  }
    61  
    62  func (o *object) AddField(field string) MarshalElement {
    63  	return &element{data: o.data, f: field, schema: o.schema.SubSchema(field)}
    64  }
    65  
    66  type element struct {
    67  	data   map[string]interface{}
    68  	f      string
    69  	schema *parquetschema.SchemaDefinition
    70  }
    71  
    72  func (e *element) SetInt32(i int32) {
    73  	e.data[e.f] = i
    74  }
    75  
    76  func (e *element) SetInt64(i int64) {
    77  	e.data[e.f] = i
    78  }
    79  
    80  func (e *element) SetInt96(i [12]byte) {
    81  	e.data[e.f] = i
    82  }
    83  
    84  func (e *element) SetFloat32(f float32) {
    85  	e.data[e.f] = f
    86  }
    87  
    88  func (e *element) SetFloat64(f float64) {
    89  	e.data[e.f] = f
    90  }
    91  
    92  func (e *element) SetBool(b bool) {
    93  	e.data[e.f] = b
    94  }
    95  
    96  func (e *element) SetByteArray(data []byte) {
    97  	e.data[e.f] = data
    98  }
    99  
   100  func (e *element) List() MarshalList {
   101  	listName := "list"
   102  	elemName := "element"
   103  	bagSchema := e.schema.SubSchema("bag")
   104  	if bagSchema != nil {
   105  		listName = "bag"
   106  		elemName = "array_element"
   107  	}
   108  	return &list{parentData: e.data, parentField: e.f, listName: listName, elemName: elemName, schema: e.schema.SubSchema(listName).SubSchema(elemName)}
   109  }
   110  
   111  func (e *element) Map() MarshalMap {
   112  	data := map[string]interface{}{"key_value": []map[string]interface{}{}}
   113  	e.data[e.f] = data
   114  	return &marshMap{data: data, schema: e.schema}
   115  }
   116  
   117  func (e *element) Group() MarshalObject {
   118  	obj := map[string]interface{}{}
   119  	e.data[e.f] = obj
   120  	return &object{data: obj}
   121  }
   122  
   123  type list struct {
   124  	parentData  map[string]interface{}
   125  	parentField string
   126  	data        map[string]interface{}
   127  	schema      *parquetschema.SchemaDefinition
   128  	listName    string
   129  	elemName    string
   130  }
   131  
   132  func (l *list) Add() MarshalElement {
   133  	if l.data == nil {
   134  		l.data = map[string]interface{}{l.listName: []map[string]interface{}{}}
   135  		// we need to delay adding map to parent data field until Add() is called first time, otherwise
   136  		// this code will fail on an empty m.Foobar:
   137  		//
   138  		// 	list := obj.AddField("foobar").List()
   139  		// 	for _, elem := range m.Foobar {
   140  		// 		list.Add().SetByteArray([]byte(elem))
   141  		// 	}
   142  		l.parentData[l.parentField] = l.data
   143  	}
   144  	listData := l.data[l.listName].([]map[string]interface{})
   145  	elemData := map[string]interface{}{}
   146  	l.data[l.listName] = append(listData, elemData)
   147  	e := &element{data: elemData, f: l.elemName, schema: l.schema}
   148  	return e
   149  }
   150  
   151  type marshMap struct {
   152  	data   map[string]interface{}
   153  	schema *parquetschema.SchemaDefinition
   154  }
   155  
   156  func (l *marshMap) Add() MarshalMapElement {
   157  	kvData := l.data["key_value"].([]map[string]interface{})
   158  	elemData := map[string]interface{}{}
   159  	l.data["key_value"] = append(kvData, elemData)
   160  	me := &mapElement{data: elemData, schema: l.schema.SubSchema("key_value")}
   161  	return me
   162  }
   163  
   164  type mapElement struct {
   165  	data   map[string]interface{}
   166  	schema *parquetschema.SchemaDefinition
   167  }
   168  
   169  func (m *mapElement) Key() MarshalElement {
   170  	return &element{data: m.data, f: "key", schema: m.schema.SubSchema("key")}
   171  }
   172  
   173  func (m *mapElement) Value() MarshalElement {
   174  	return &element{data: m.data, f: "value", schema: m.schema.SubSchema("value")}
   175  }
   176  
   177  // NewMarshallObject creates a new marshaller object
   178  func NewMarshallObject(data map[string]interface{}) MarshalObject {
   179  	if data == nil {
   180  		data = make(map[string]interface{})
   181  	}
   182  	return &object{
   183  		data: data,
   184  	}
   185  }
   186  
   187  // NewMarshallObjectWithSchema creates a new marshaller object with a particular schema.
   188  func NewMarshallObjectWithSchema(data map[string]interface{}, schemaDef *parquetschema.SchemaDefinition) MarshalObject {
   189  	if data == nil {
   190  		data = make(map[string]interface{})
   191  	}
   192  	return &object{
   193  		data:   data,
   194  		schema: schemaDef,
   195  	}
   196  }
   197  
   198  // NewMarshalElement creates new marshall element object
   199  func NewMarshalElement(data map[string]interface{}, name string) MarshalElement {
   200  	if data == nil {
   201  		data = make(map[string]interface{})
   202  	}
   203  	return &element{
   204  		data: data,
   205  		f:    name,
   206  	}
   207  }