blob: 580f422ca2f88ab83584bfd7afcc7fef6b805dde [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package types contains user-defined types for use in the tests for the arrow package
package types
import (
"encoding/binary"
"fmt"
"reflect"
"github.com/apache/arrow/go/v6/arrow"
"github.com/apache/arrow/go/v6/arrow/array"
"golang.org/x/xerrors"
)
// UUIDArray is a simple array which is a FixedSizeBinary(16)
type UUIDArray struct {
array.ExtensionArrayBase
}
// UUIDType is a simple extension type that represents a FixedSizeBinary(16)
// to be used for representing UUIDs
type UUIDType struct {
arrow.ExtensionBase
}
// NewUUIDType is a convenience function to create an instance of UuidType
// with the correct storage type
func NewUUIDType() *UUIDType {
return &UUIDType{
ExtensionBase: arrow.ExtensionBase{
Storage: &arrow.FixedSizeBinaryType{ByteWidth: 16}}}
}
// ArrayType returns TypeOf(UuidArray) for constructing uuid arrays
func (UUIDType) ArrayType() reflect.Type { return reflect.TypeOf(UUIDArray{}) }
func (UUIDType) ExtensionName() string { return "uuid" }
// Serialize returns "uuid-serialized" for testing proper metadata passing
func (UUIDType) Serialize() string { return "uuid-serialized" }
// Deserialize expects storageType to be FixedSizeBinaryType{ByteWidth: 16} and the data to be
// "uuid-serialized" in order to correctly create a UuidType for testing deserialize.
func (UUIDType) Deserialize(storageType arrow.DataType, data string) (arrow.ExtensionType, error) {
if string(data) != "uuid-serialized" {
return nil, xerrors.Errorf("type identifier did not match: '%s'", string(data))
}
if !arrow.TypeEqual(storageType, &arrow.FixedSizeBinaryType{ByteWidth: 16}) {
return nil, xerrors.Errorf("invalid storage type for UuidType: %s", storageType.Name())
}
return NewUUIDType(), nil
}
// UuidTypes are equal if both are named "uuid"
func (u UUIDType) ExtensionEquals(other arrow.ExtensionType) bool {
return u.ExtensionName() == other.ExtensionName()
}
// Parametric1Array is a simple int32 array for use with the Parametric1Type
// in testing a parameterized user-defined extension type.
type Parametric1Array struct {
array.ExtensionArrayBase
}
// Parametric2Array is another simple int32 array for use with the Parametric2Type
// also for testing a parameterized user-defined extension type that utilizes
// the parameter for defining different types based on the param.
type Parametric2Array struct {
array.ExtensionArrayBase
}
// A type where ExtensionName is always the same
type Parametric1Type struct {
arrow.ExtensionBase
param int32
}
func NewParametric1Type(p int32) *Parametric1Type {
ret := &Parametric1Type{param: p}
ret.ExtensionBase.Storage = arrow.PrimitiveTypes.Int32
return ret
}
func (p *Parametric1Type) String() string { return "extension<" + p.ExtensionName() + ">" }
// ExtensionEquals returns true if other is a *Parametric1Type and has the same param
func (p *Parametric1Type) ExtensionEquals(other arrow.ExtensionType) bool {
o, ok := other.(*Parametric1Type)
if !ok {
return false
}
return p.param == o.param
}
// ExtensionName is always "parametric-type-1"
func (Parametric1Type) ExtensionName() string { return "parametric-type-1" }
// ArrayType returns the TypeOf(Parametric1Array{})
func (Parametric1Type) ArrayType() reflect.Type { return reflect.TypeOf(Parametric1Array{}) }
// Serialize returns the param as 4 little endian bytes
func (p *Parametric1Type) Serialize() string {
var buf [4]byte
binary.LittleEndian.PutUint32(buf[:], uint32(p.param))
return string(buf[:])
}
// Deserialize requires storage to be an int32 type and data should be a 4 byte little endian int32 value
func (Parametric1Type) Deserialize(storage arrow.DataType, data string) (arrow.ExtensionType, error) {
if len(data) != 4 {
return nil, xerrors.Errorf("parametric1type: invalid serialized data size: %d", len(data))
}
if storage.ID() != arrow.INT32 {
return nil, xerrors.New("parametric1type: must have int32 as underlying storage type")
}
return &Parametric1Type{arrow.ExtensionBase{Storage: arrow.PrimitiveTypes.Int32}, int32(binary.LittleEndian.Uint32([]byte(data)))}, nil
}
// a parametric type where the extension name is different for each
// parameter, and must be registered separately
type Parametric2Type struct {
arrow.ExtensionBase
param int32
}
func NewParametric2Type(p int32) *Parametric2Type {
ret := &Parametric2Type{param: p}
ret.ExtensionBase.Storage = arrow.PrimitiveTypes.Int32
return ret
}
func (p *Parametric2Type) String() string { return "extension<" + p.ExtensionName() + ">" }
// ExtensionEquals returns true if other is a *Parametric2Type and has the same param
func (p *Parametric2Type) ExtensionEquals(other arrow.ExtensionType) bool {
o, ok := other.(*Parametric2Type)
if !ok {
return false
}
return p.param == o.param
}
// ExtensionName incorporates the param in the name requiring different instances of
// Parametric2Type to be registered separately if they have different params. this is
// used for testing registration of different types with the same struct type.
func (p *Parametric2Type) ExtensionName() string {
return fmt.Sprintf("parametric-type-2<param=%d>", p.param)
}
// ArrayType returns TypeOf(Parametric2Array{})
func (Parametric2Type) ArrayType() reflect.Type { return reflect.TypeOf(Parametric2Array{}) }
// Serialize returns the param as a 4 byte little endian slice
func (p *Parametric2Type) Serialize() string {
var buf [4]byte
binary.LittleEndian.PutUint32(buf[:], uint32(p.param))
return string(buf[:])
}
// Deserialize expects storage to be int32 type and data must be a 4 byte little endian slice.
func (Parametric2Type) Deserialize(storage arrow.DataType, data string) (arrow.ExtensionType, error) {
if len(data) != 4 {
return nil, xerrors.Errorf("parametric1type: invalid serialized data size: %d", len(data))
}
if storage.ID() != arrow.INT32 {
return nil, xerrors.New("parametric1type: must have int32 as underlying storage type")
}
return &Parametric2Type{arrow.ExtensionBase{Storage: arrow.PrimitiveTypes.Int32}, int32(binary.LittleEndian.Uint32([]byte(data)))}, nil
}
// ExtStructArray is a struct array type for testing an extension type with non-primitive storage
type ExtStructArray struct {
array.ExtensionArrayBase
}
// ExtStructType is an extension type with a non-primitive storage type containing a struct
// with fields {a: int64, b: float64}
type ExtStructType struct {
arrow.ExtensionBase
}
func NewExtStructType() *ExtStructType {
return &ExtStructType{
ExtensionBase: arrow.ExtensionBase{Storage: arrow.StructOf(
arrow.Field{Name: "a", Type: arrow.PrimitiveTypes.Int64},
arrow.Field{Name: "b", Type: arrow.PrimitiveTypes.Float64},
)},
}
}
func (p *ExtStructType) String() string { return "extension<" + p.ExtensionName() + ">" }
// ExtensionName is always "ext-struct-type"
func (ExtStructType) ExtensionName() string { return "ext-struct-type" }
// ExtensionEquals returns true if other is a *ExtStructType
func (ExtStructType) ExtensionEquals(other arrow.ExtensionType) bool {
_, ok := other.(*ExtStructType)
return ok
}
// ArrayType returns TypeOf(ExtStructType{})
func (ExtStructType) ArrayType() reflect.Type { return reflect.TypeOf(ExtStructArray{}) }
// Serialize just returns "ext-struct-type-unique-code" to test metadata passing in IPC
func (ExtStructType) Serialize() string { return "ext-struct-type-unique-code" }
// Deserialize ignores the passed in storage datatype and only checks the serialized data byte slice
// returning the correct type if it matches "ext-struct-type-unique-code".
func (ExtStructType) Deserialize(_ arrow.DataType, serialized string) (arrow.ExtensionType, error) {
if string(serialized) != "ext-struct-type-unique-code" {
return nil, xerrors.New("type identifier did not match")
}
return NewExtStructType(), nil
}
var (
_ arrow.ExtensionType = (*UUIDType)(nil)
_ arrow.ExtensionType = (*Parametric1Type)(nil)
_ arrow.ExtensionType = (*Parametric2Type)(nil)
_ arrow.ExtensionType = (*ExtStructType)(nil)
_ array.ExtensionArray = (*UUIDArray)(nil)
_ array.ExtensionArray = (*Parametric1Array)(nil)
_ array.ExtensionArray = (*Parametric2Array)(nil)
_ array.ExtensionArray = (*ExtStructArray)(nil)
)