From ff46f155917a5b274422d4b2e3ac463c1736a8bf Mon Sep 17 00:00:00 2001 From: Anshul Data Date: Wed, 28 Aug 2024 18:01:16 +0530 Subject: [PATCH] Support for Parameterized type * Separate AnyType. This will be helpful in match method * Added support for ParameterizedFixedChar/VarChar/FixedBinary/Decimal * Added parser support for Parameterized/PrecisionTimestamp/PrecisionTimestampTz --- extensions/simple_extension.go | 15 +++ types/any_type.go | 58 +++++++++++ types/any_type_test.go | 33 +++++++ types/parameterized_decimal_type.go | 55 +++++++++++ types/parameterized_types.go | 114 ++++++++++++++++++++++ types/parameterized_types_test.go | 66 +++++++++++++ types/parser/type_parser.go | 145 +++++++++++++++++++++++----- types/parser/type_parser_test.go | 8 ++ types/precison_timestamp_types.go | 13 +++ types/types.go | 56 ++++++----- 10 files changed, 517 insertions(+), 46 deletions(-) create mode 100644 types/any_type.go create mode 100644 types/any_type_test.go create mode 100644 types/parameterized_decimal_type.go create mode 100644 types/parameterized_types.go create mode 100644 types/parameterized_types_test.go diff --git a/extensions/simple_extension.go b/extensions/simple_extension.go index b191ea1..d629c1e 100644 --- a/extensions/simple_extension.go +++ b/extensions/simple_extension.go @@ -3,11 +3,13 @@ package extensions import ( + "errors" "fmt" "reflect" "strings" substraitgo "github.com/substrait-io/substrait-go" + "github.com/substrait-io/substrait-go/types" "github.com/substrait-io/substrait-go/types/parser" ) @@ -57,6 +59,7 @@ type TypeVariation struct { type Argument interface { toTypeString() string + ArgType() (types.Type, error) } type EnumArg struct { @@ -69,6 +72,10 @@ func (EnumArg) toTypeString() string { return "req" } +func (EnumArg) ArgType() (types.Type, error) { + return nil, errors.New("unimplemented") +} + type ValueArg struct { Name string `yaml:",omitempty"` Description string `yaml:",omitempty"` @@ -80,6 +87,10 @@ func (v ValueArg) toTypeString() string { return v.Value.Expr.(*parser.Type).ShortType() } +func (v ValueArg) ArgType() (types.Type, error) { + return v.Value.Expr.(*parser.Type).Type() +} + type TypeArg struct { Name string `yaml:",omitempty"` Description string `yaml:",omitempty"` @@ -88,6 +99,10 @@ type TypeArg struct { func (TypeArg) toTypeString() string { return "type" } +func (TypeArg) ArgType() (types.Type, error) { + return nil, errors.New("unimplemented") +} + type ArgumentList []Argument func (a *ArgumentList) UnmarshalYAML(fn func(interface{}) error) error { diff --git a/types/any_type.go b/types/any_type.go new file mode 100644 index 0000000..7d7f2e8 --- /dev/null +++ b/types/any_type.go @@ -0,0 +1,58 @@ +package types + +import ( + "fmt" + + "github.com/substrait-io/substrait-go/proto" +) + +// AnyType to represent AnyType, this type is to indicate "any" type of argument +// This type is not used in function invocation. It is only used in function definition +type AnyType struct { + Name string + Nullability Nullability +} + +func (*AnyType) isRootRef() {} +func (m *AnyType) WithNullability(nullability Nullability) Type { + m.Nullability = nullability + return m +} +func (m *AnyType) GetType() Type { return m } +func (m *AnyType) GetNullability() Nullability { + return m.Nullability +} +func (*AnyType) GetTypeVariationReference() uint32 { + panic("not allowed") +} +func (*AnyType) Equals(rhs Type) bool { + // equal to every other type + return true +} + +func (*AnyType) ToProtoFuncArg() *proto.FunctionArgument { + panic("not allowed") +} + +func (*AnyType) ToProto() *proto.Type { + panic("not allowed") +} + +func (t *AnyType) ShortString() string { return t.Name } +func (t *AnyType) String() string { + return fmt.Sprintf("%s%s", t.Name, strNullable(t)) +} + +// Below methods are for parser Def interface + +func (*AnyType) Optional() bool { + panic("not allowed") +} + +func (m *AnyType) ShortType() string { + return "any" +} + +func (m *AnyType) Type() (Type, error) { + return m, nil +} diff --git a/types/any_type_test.go b/types/any_type_test.go new file mode 100644 index 0000000..8362617 --- /dev/null +++ b/types/any_type_test.go @@ -0,0 +1,33 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + "github.com/substrait-io/substrait-go/types" +) + +func TestAnyType(t *testing.T) { + for _, td := range []struct { + testName string + argName string + nullability types.Nullability + expectedString string + }{ + {"any", "any", types.NullabilityNullable, "any?"}, + {"anyrequired", "any", types.NullabilityRequired, "any"}, + {"anyOtherName", "any1", types.NullabilityNullable, "any1?"}, + {"T name", "T", types.NullabilityNullable, "T?"}, + } { + t.Run(td.testName, func(t *testing.T) { + arg := &types.AnyType{ + Name: td.argName, + Nullability: td.nullability, + } + require.Equal(t, td.expectedString, arg.String()) + require.Equal(t, td.nullability, arg.GetNullability()) + require.Equal(t, td.argName, arg.ShortString()) + require.Equal(t, "any", arg.ShortType()) + }) + } +} diff --git a/types/parameterized_decimal_type.go b/types/parameterized_decimal_type.go new file mode 100644 index 0000000..7bcc128 --- /dev/null +++ b/types/parameterized_decimal_type.go @@ -0,0 +1,55 @@ +package types + +import ( + "fmt" + + "github.com/substrait-io/substrait-go/proto" +) + +type ParameterizedDecimal struct { + Nullability Nullability + TypeVariationRef uint32 + Precision IntegerParam + Scale IntegerParam +} + +func (*ParameterizedDecimal) isRootRef() {} +func (m *ParameterizedDecimal) WithNullability(n Nullability) Type { + m.Nullability = n + return m +} + +func (m *ParameterizedDecimal) GetType() Type { return m } +func (m *ParameterizedDecimal) GetNullability() Nullability { return m.Nullability } +func (m *ParameterizedDecimal) GetTypeVariationReference() uint32 { + return m.TypeVariationRef +} +func (m *ParameterizedDecimal) Equals(rhs Type) bool { + if o, ok := rhs.(*ParameterizedDecimal); ok { + return *o == *m + } + return false +} + +func (*ParameterizedDecimal) ToProtoFuncArg() *proto.FunctionArgument { + // parameterized type are never on wire so to proto is not supported + panic("not supported") +} + +func (m *ParameterizedDecimal) ShortString() string { + t := &DecimalType{} + return t.ShortString() +} + +func (m *ParameterizedDecimal) String() string { + return fmt.Sprintf("%s%s%s", m.BaseString(), strNullable(m), m.ParameterString()) +} + +func (m *ParameterizedDecimal) ParameterString() string { + return fmt.Sprintf("<%s,%s>", m.Precision.String(), m.Scale.String()) +} + +func (m *ParameterizedDecimal) BaseString() string { + t := &DecimalType{} + return t.BaseString() +} diff --git a/types/parameterized_types.go b/types/parameterized_types.go new file mode 100644 index 0000000..b271ccd --- /dev/null +++ b/types/parameterized_types.go @@ -0,0 +1,114 @@ +package types + +import ( + "fmt" + + "github.com/substrait-io/substrait-go/proto" +) + +type IntegerParam struct { + Name string +} + +func (m IntegerParam) Equals(o IntegerParam) bool { + return m == o +} + +func (p IntegerParam) ToProto() *proto.ParameterizedType_IntegerParameter { + panic("not implemented") +} + +func (m *IntegerParam) String() string { + return m.Name +} + +type ParameterizedSingleIntegerType interface { + Type + WithIntegerOption(param IntegerParam) ParameterizedSingleIntegerType +} + +type ParameterizedTypeSingleIntegerParam[T VarCharType | FixedCharType | FixedBinaryType | PrecisionTimestampType | PrecisionTimestampTzType] struct { + Nullability Nullability + TypeVariationRef uint32 + IntegerOption IntegerParam +} + +func (m *ParameterizedTypeSingleIntegerParam[T]) WithIntegerOption(integerOption IntegerParam) ParameterizedSingleIntegerType { + m.IntegerOption = integerOption + return m +} + +func (*ParameterizedTypeSingleIntegerParam[T]) isRootRef() {} +func (m *ParameterizedTypeSingleIntegerParam[T]) WithNullability(n Nullability) Type { + m.Nullability = n + return m +} + +func (m *ParameterizedTypeSingleIntegerParam[T]) GetType() Type { return m } +func (m *ParameterizedTypeSingleIntegerParam[T]) GetNullability() Nullability { return m.Nullability } +func (m *ParameterizedTypeSingleIntegerParam[T]) GetTypeVariationReference() uint32 { + return m.TypeVariationRef +} +func (m *ParameterizedTypeSingleIntegerParam[T]) Equals(rhs Type) bool { + if o, ok := rhs.(*ParameterizedTypeSingleIntegerParam[T]); ok { + return *o == *m + } + return false +} + +func (*ParameterizedTypeSingleIntegerParam[T]) ToProtoFuncArg() *proto.FunctionArgument { + // parameterized type are never on wire so to proto is not supported + panic("not supported") +} + +func (m *ParameterizedTypeSingleIntegerParam[T]) ShortString() string { + switch any(m).(type) { + case *ParameterizedVarCharType: + t := &VarCharType{} + return t.ShortString() + case *ParameterizedFixedCharType: + t := &FixedCharType{} + return t.ShortString() + case *ParameterizedFixedBinaryType: + t := &FixedBinaryType{} + return t.ShortString() + case *ParameterizedPrecisionTimestampType: + t := &PrecisionTimestampType{} + return t.ShortString() + case *ParameterizedPrecisionTimestampTzType: + t := &PrecisionTimestampTzType{} + return t.ShortString() + default: + panic("unknown type") + } +} + +func (m *ParameterizedTypeSingleIntegerParam[T]) String() string { + return fmt.Sprintf("%s%s%s", m.BaseString(), strNullable(m), m.ParameterString()) +} + +func (m *ParameterizedTypeSingleIntegerParam[T]) ParameterString() string { + return fmt.Sprintf("<%s>", m.IntegerOption.String()) +} + +func (m *ParameterizedTypeSingleIntegerParam[T]) BaseString() string { + switch any(m).(type) { + case *ParameterizedVarCharType: + t := &VarCharType{} + return t.BaseString() + case *ParameterizedFixedCharType: + t := &FixedCharType{} + return t.BaseString() + case *ParameterizedFixedBinaryType: + t := &FixedBinaryType{} + return t.BaseString() + case *ParameterizedPrecisionTimestampType: + t := &PrecisionTimestampType{} + return t.BaseString() + case *ParameterizedPrecisionTimestampTzType: + t := &PrecisionTimestampTzType{} + return t.BaseString() + default: + panic("unknown type") + } +} diff --git a/types/parameterized_types_test.go b/types/parameterized_types_test.go new file mode 100644 index 0000000..eba0f86 --- /dev/null +++ b/types/parameterized_types_test.go @@ -0,0 +1,66 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + "github.com/substrait-io/substrait-go/types" +) + +func TestParameterizedVarCharType(t *testing.T) { + for _, td := range []struct { + name string + typ types.ParameterizedSingleIntegerType + nullability types.Nullability + integerOption types.IntegerParam + expectedString string + expectedBaseString string + expectedShortString string + }{ + {"nullable varchar", &types.ParameterizedVarCharType{}, types.NullabilityNullable, types.IntegerParam{Name: "L1"}, "varchar?", "varchar", "vchar"}, + {"non nullable varchar", &types.ParameterizedVarCharType{}, types.NullabilityRequired, types.IntegerParam{Name: "L1"}, "varchar", "varchar", "vchar"}, + {"nullable fixChar", &types.ParameterizedFixedCharType{}, types.NullabilityNullable, types.IntegerParam{Name: "L1"}, "char?", "char", "fchar"}, + {"non nullable fixChar", &types.ParameterizedFixedCharType{}, types.NullabilityRequired, types.IntegerParam{Name: "L1"}, "char", "char", "fchar"}, + {"nullable fixBinary", &types.ParameterizedFixedBinaryType{}, types.NullabilityNullable, types.IntegerParam{Name: "L1"}, "fixedbinary?", "fixedbinary", "fbin"}, + {"non nullable fixBinary", &types.ParameterizedFixedBinaryType{}, types.NullabilityRequired, types.IntegerParam{Name: "L1"}, "fixedbinary", "fixedbinary", "fbin"}, + {"nullable precisionTimeStamp", &types.ParameterizedPrecisionTimestampType{}, types.NullabilityNullable, types.IntegerParam{Name: "L1"}, "precision_timestamp?", "precision_timestamp", "prets"}, + {"non nullable precisionTimeStamp", &types.ParameterizedPrecisionTimestampType{}, types.NullabilityRequired, types.IntegerParam{Name: "L1"}, "precision_timestamp", "precision_timestamp", "prets"}, + {"nullable precisionTimeStampTz", &types.ParameterizedPrecisionTimestampTzType{}, types.NullabilityNullable, types.IntegerParam{Name: "L1"}, "precision_timestamp_tz?", "precision_timestamp_tz", "pretstz"}, + {"non nullable precisionTimeStampTz", &types.ParameterizedPrecisionTimestampTzType{}, types.NullabilityRequired, types.IntegerParam{Name: "L1"}, "precision_timestamp_tz", "precision_timestamp_tz", "pretstz"}, + } { + t.Run(td.name, func(t *testing.T) { + pt := td.typ.WithIntegerOption(td.integerOption).WithNullability(td.nullability) + require.Equal(t, td.expectedString, pt.String()) + parameterizeType, ok := pt.(types.ParameterizedType) + require.True(t, ok) + require.Equal(t, td.expectedBaseString, parameterizeType.BaseString()) + require.Equal(t, td.expectedShortString, pt.ShortString()) + require.True(t, pt.Equals(pt)) + }) + } +} + +func TestParameterizedDecimalType(t *testing.T) { + for _, td := range []struct { + name string + precision string + scale string + nullability types.Nullability + expectedString string + expectedBaseString string + expectedShortString string + }{ + {"nullable decimal", "P", "S", types.NullabilityNullable, "decimal?", "decimal", "dec"}, + {"non nullable decimal", "P", "S", types.NullabilityRequired, "decimal", "decimal", "dec"}, + } { + t.Run(td.name, func(t *testing.T) { + precision := types.IntegerParam{Name: td.precision} + scale := types.IntegerParam{Name: td.scale} + pt := &types.ParameterizedDecimalType{Precision: precision, Scale: scale, Nullability: td.nullability} + require.Equal(t, td.expectedString, pt.String()) + require.Equal(t, td.expectedBaseString, pt.BaseString()) + require.Equal(t, td.expectedShortString, pt.ShortString()) + require.True(t, pt.Equals(pt)) + }) + } +} diff --git a/types/parser/type_parser.go b/types/parser/type_parser.go index ae5e4a2..6a3b0b9 100644 --- a/types/parser/type_parser.go +++ b/types/parser/type_parser.go @@ -3,6 +3,7 @@ package parser import ( + "errors" "io" "strconv" "strings" @@ -21,6 +22,14 @@ type TypeExpression struct { func (t TypeExpression) String() string { return t.Expr.String() } +func (t TypeExpression) Type() (types.Type, error) { + typeDef, ok := t.Expr.(Def) + if !ok { + return nil, errors.New("type expression doesn't represent type") + } + return typeDef.Type() +} + func (t TypeExpression) MarshalYAML() (interface{}, error) { return t.Expr.String(), nil } @@ -104,7 +113,7 @@ func (t *typename) Capture(values []string) error { } type nonParamType struct { - TypeName typename `parser:"@(AnyType | Template | IntType | Boolean | FPType | Temporal | BinaryType)"` + TypeName typename `parser:"@(IntType | Boolean | FPType | Temporal | BinaryType)"` Nullability bool `parser:"@'?'?"` // Variation int `parser:"'[' @\d+ ']'?"` } @@ -120,10 +129,6 @@ func (t *nonParamType) String() string { } func (t *nonParamType) ShortType() string { - if strings.HasPrefix(string(t.TypeName), "any") { - return "any" - } - return types.GetShortTypeName(types.TypeName(t.TypeName)) } @@ -188,6 +193,10 @@ func (p *lengthType) ShortType() string { switch p.TypeName { case "fixedchar", "varchar", "fixedbinary": return types.GetShortTypeName(types.TypeName(p.TypeName)) + case "precision_timestamp": + return "prets" + case "precision_timestamp_tz": + return "pretstz" } return "" } @@ -200,16 +209,62 @@ func (p *lengthType) Optional() bool { return false } func (p *lengthType) Type() (types.Type, error) { var n types.Nullability - lit, ok := p.NumericParam.Expr.(*IntegerLiteral) - if !ok { + + var typ types.Type + var err error + switch t := p.NumericParam.Expr.(type) { + case *IntegerLiteral: + typ, err = getFixedTypeFromConcreteParam(p.TypeName, t) + case *ParamName: + typ, err = getParameterizedTypeSingleParam(p.TypeName, t) + default: return nil, substraitgo.ErrNotImplemented } + if err != nil { + return nil, err + } + return typ.WithNullability(n), nil +} - typ, err := types.FixedTypeNameToType(types.TypeName(p.TypeName)) +func getFixedTypeFromConcreteParam(name string, param *IntegerLiteral) (types.Type, error) { + typeName := types.TypeName(name) + switch typeName { + case types.TypeNamePrecisionTimestamp: + precision, err := types.ProtoToTimePrecision(param.Value) + if err != nil { + return nil, err + } + return types.NewPrecisionTimestampType(precision), nil + case types.TypeNamePrecisionTimestampTz: + precision, err := types.ProtoToTimePrecision(param.Value) + if err != nil { + return nil, err + } + return types.NewPrecisionTimestampTzType(precision), nil + } + typ, err := types.FixedTypeNameToType(typeName) if err != nil { return nil, err } - return typ.WithLength(lit.Value).WithNullability(n), nil + return typ.WithLength(param.Value), nil +} + +func getParameterizedTypeSingleParam(typeName string, param *ParamName) (types.Type, error) { + intParam := types.IntegerParam{Name: param.Name} + switch types.TypeName(typeName) { + case types.TypeNameVarChar: + return &types.ParameterizedVarCharType{IntegerOption: intParam}, nil + case types.TypeNameFixedChar: + return &types.ParameterizedFixedCharType{IntegerOption: intParam}, nil + case types.TypeNameFixedBinary: + return &types.ParameterizedFixedBinaryType{IntegerOption: intParam}, nil + case types.TypeNamePrecisionTimestamp: + return &types.ParameterizedPrecisionTimestampType{IntegerOption: intParam}, nil + case types.TypeNamePrecisionTimestampTz: + return &types.ParameterizedPrecisionTimestampTzType{IntegerOption: intParam}, nil + default: + return nil, substraitgo.ErrNotImplemented + } } type decimalType struct { @@ -232,21 +287,28 @@ func (d *decimalType) Optional() bool { return d.Nullability } func (d *decimalType) Type() (types.Type, error) { var n types.Nullability - p, ok := d.Precision.Expr.(*IntegerLiteral) - if !ok { - return nil, substraitgo.ErrNotImplemented + pi, ok1 := d.Precision.Expr.(*IntegerLiteral) + si, ok2 := d.Scale.Expr.(*IntegerLiteral) + if ok1 && ok2 { + // concrete decimal param + return &types.DecimalType{ + Nullability: n, + Precision: pi.Value, + Scale: si.Value, + }, nil } - s, ok := d.Scale.Expr.(*IntegerLiteral) - if !ok { - return nil, substraitgo.ErrNotImplemented + ps, ok1 := d.Precision.Expr.(*ParamName) + ss, ok2 := d.Scale.Expr.(*ParamName) + if ok1 && ok2 { + // parameterized decimal param + return &types.ParameterizedDecimalType{ + Nullability: n, + Precision: types.IntegerParam{Name: ps.Name}, + Scale: types.IntegerParam{Name: ss.Name}, + }, nil } - - return &types.DecimalType{ - Nullability: n, - Precision: p.Value, - Scale: s.Value, - }, nil + return nil, substraitgo.ErrNotImplemented } type structType struct { @@ -352,6 +414,43 @@ func (m *mapType) Type() (types.Type, error) { }, nil } +// parser token for any +type anyType struct { + TypeName typename `parser:"@(AnyType|Template)"` + Nullability bool `parser:"@'?'?"` +} + +func (anyType) Optional() bool { return false } + +func (t anyType) String() string { + opt := string(t.TypeName) + if t.Nullability { + opt += "?" + } + return opt +} + +func (t anyType) ShortType() string { + if strings.HasPrefix(string(t.TypeName), "any") { + return "any" + } + return string(t.TypeName) +} + +func (t anyType) Type() (types.Type, error) { + var n types.Nullability + if t.Nullability { + n = types.NullabilityNullable + } else { + n = types.NullabilityRequired + } + typeName := string(t.TypeName) + if strings.HasPrefix(typeName, "any") { + return &types.AnyType{Name: "any", Nullability: n}, nil + } + return &types.AnyType{Name: typeName, Nullability: n}, nil +} + var ( def = lexer.MustSimple([]lexer.SimpleRule{ {Name: "whitespace", Pattern: `[ \t]+`}, @@ -362,7 +461,7 @@ var ( {Name: "FPType", Pattern: `fp(32|64)`}, {Name: "Temporal", Pattern: `timestamp(_tz)?|date|time|interval_day|interval_year`}, {Name: "BinaryType", Pattern: `string|binary|uuid`}, - {Name: "LengthType", Pattern: `fixedchar|varchar|fixedbinary`}, + {Name: "LengthType", Pattern: `fixedchar|varchar|fixedbinary|precision_timestamp_tz|precision_timestamp`}, {Name: "Int", Pattern: `[-+]?\d+`}, {Name: "ParamType", Pattern: `(?i)(struct|list|decimal|map)`}, {Name: "Identifier", Pattern: `[a-zA-Z_$][a-zA-Z_$0-9]*`}, @@ -389,7 +488,7 @@ func (p *Parser) ParseBytes(expr []byte) (*TypeExpression, error) { func New() (*Parser, error) { parser, err := participle.Build[TypeExpression]( participle.Union[Expression](&Type{}, &IntegerLiteral{}, &ParamName{}), - participle.Union[Def](&nonParamType{}, &mapType{}, &listType{}, &structType{}, &lengthType{}, &decimalType{}), + participle.Union[Def](&anyType{}, &nonParamType{}, &mapType{}, &listType{}, &structType{}, &lengthType{}, &decimalType{}), participle.CaseInsensitive("Boolean", "ParamType", "IntType", "FPType", "Temporal", "BinaryType", "LengthType"), participle.Lexer(def), participle.UseLookahead(3), diff --git a/types/parser/type_parser_test.go b/types/parser/type_parser_test.go index 0abc300..20390d4 100644 --- a/types/parser/type_parser_test.go +++ b/types/parser/type_parser_test.go @@ -29,6 +29,14 @@ func TestParser(t *testing.T) { {"struct", "struct", "struct", &types.StructType{Types: []types.Type{&types.Int16Type{Nullability: types.NullabilityNullable}, &types.Int32Type{Nullability: types.NullabilityRequired}}, Nullability: types.NullabilityRequired}}, {"map>", "map>", "map", &types.MapType{Key: &types.BooleanType{Nullability: types.NullabilityNullable}, Value: &types.StructType{Types: []types.Type{&types.Int16Type{Nullability: types.NullabilityNullable}, &types.Int32Type{Nullability: types.NullabilityNullable}, &types.Int64Type{Nullability: types.NullabilityNullable}}, Nullability: types.NullabilityNullable}, Nullability: types.NullabilityRequired}}, {"map?>", "map?>", "map", &types.MapType{Key: &types.BooleanType{Nullability: types.NullabilityNullable}, Value: &types.StructType{Types: []types.Type{&types.Int16Type{Nullability: types.NullabilityNullable}, &types.Int32Type{Nullability: types.NullabilityNullable}, &types.Int64Type{Nullability: types.NullabilityNullable}}, Nullability: types.NullabilityNullable}, Nullability: types.NullabilityNullable}}, + {"precision_timestamp<5>", "precision_timestamp<5>", "prets", &types.PrecisionTimestampType{Precision: types.PrecisionEMinus5Seconds}}, + {"precision_timestamp_tz<5>", "precision_timestamp_tz<5>", "pretstz", &types.PrecisionTimestampTzType{PrecisionTimestampType: types.PrecisionTimestampType{Precision: types.PrecisionEMinus5Seconds}}}, + {"varchar", "varchar", "vchar", &types.ParameterizedVarCharType{IntegerOption: types.IntegerParam{Name: "L1"}}}, + {"fixedchar", "fixedchar", "fchar", &types.ParameterizedFixedCharType{IntegerOption: types.IntegerParam{Name: "L1"}}}, + {"fixedbinary", "fixedbinary", "fbin", &types.ParameterizedFixedBinaryType{IntegerOption: types.IntegerParam{Name: "L1"}}}, + {"precision_timestamp", "precision_timestamp", "prets", &types.ParameterizedPrecisionTimestampType{IntegerOption: types.IntegerParam{Name: "L1"}}}, + {"precision_timestamp_tz", "precision_timestamp_tz", "pretstz", &types.ParameterizedPrecisionTimestampTzType{IntegerOption: types.IntegerParam{Name: "L1"}}}, + {"decimal", "decimal", "dec", &types.ParameterizedDecimalType{Precision: types.IntegerParam{Name: "P"}, Scale: types.IntegerParam{Name: "S"}}}, } p, err := parser.New() diff --git a/types/precison_timestamp_types.go b/types/precison_timestamp_types.go index e27dd0c..e88d656 100644 --- a/types/precison_timestamp_types.go +++ b/types/precison_timestamp_types.go @@ -2,6 +2,7 @@ package types import ( "fmt" + "reflect" "github.com/substrait-io/substrait-go/proto" ) @@ -97,6 +98,14 @@ func (m *PrecisionTimestampType) String() string { m.Precision.ToProtoVal()) } +func (m *PrecisionTimestampType) ParameterString() string { + return fmt.Sprintf("%d", m.Precision.ToProtoVal()) +} + +func (m *PrecisionTimestampType) BaseString() string { + return typeNames[reflect.TypeOf(m)] +} + // PrecisionTimestampTzType this is used to represent a type of Precision timestamp with TimeZone type PrecisionTimestampTzType struct { PrecisionTimestampType @@ -145,3 +154,7 @@ func (m *PrecisionTimestampTzType) Equals(rhs Type) bool { return false } func (*PrecisionTimestampTzType) ShortString() string { return "pretstz" } + +func (m *PrecisionTimestampTzType) BaseString() string { + return typeNames[reflect.TypeOf(m)] +} diff --git a/types/types.go b/types/types.go index a837860..447a586 100644 --- a/types/types.go +++ b/types/types.go @@ -44,10 +44,12 @@ const ( TypeNameIntervalDay TypeName = "interval_day" TypeNameUUID TypeName = "uuid" - TypeNameFixedBinary TypeName = "fixedbinary" - TypeNameFixedChar TypeName = "fixedchar" - TypeNameVarChar TypeName = "varchar" - TypeNameDecimal TypeName = "decimal" + TypeNameFixedBinary TypeName = "fixedbinary" + TypeNameFixedChar TypeName = "fixedchar" + TypeNameVarChar TypeName = "varchar" + TypeNameDecimal TypeName = "decimal" + TypeNamePrecisionTimestamp TypeName = "precision_timestamp" + TypeNamePrecisionTimestampTz TypeName = "precision_timestamp_tz" ) var simpleTypeNameMap = map[TypeName]Type{ @@ -523,6 +525,8 @@ var typeNames = map[reflect.Type]string{ reflect.TypeOf(&FixedBinary{}): "fixedbinary", reflect.TypeOf(&emptyFixedChar): "char", reflect.TypeOf(&VarChar{}): "varchar", + reflect.TypeOf(&PrecisionTimestampType{}): "precision_timestamp", + reflect.TypeOf(&PrecisionTimestampTzType{}): "precision_timestamp_tz", } var shortNames = map[reflect.Type]string{ @@ -604,25 +608,31 @@ func (s *PrimitiveType[T]) String() string { // create type aliases to the generic structs type ( - BooleanType = PrimitiveType[bool] - Int8Type = PrimitiveType[int8] - Int16Type = PrimitiveType[int16] - Int32Type = PrimitiveType[int32] - Int64Type = PrimitiveType[int64] - Float32Type = PrimitiveType[float32] - Float64Type = PrimitiveType[float64] - StringType = PrimitiveType[string] - BinaryType = PrimitiveType[[]byte] - TimestampType = PrimitiveType[Timestamp] - DateType = PrimitiveType[Date] - TimeType = PrimitiveType[Time] - TimestampTzType = PrimitiveType[TimestampTz] - IntervalYearType = PrimitiveType[IntervalYearToMonth] - IntervalDayType = PrimitiveType[IntervalDayToSecond] - UUIDType = PrimitiveType[UUID] - FixedCharType = FixedLenType[FixedChar] - VarCharType = FixedLenType[VarChar] - FixedBinaryType = FixedLenType[FixedBinary] + BooleanType = PrimitiveType[bool] + Int8Type = PrimitiveType[int8] + Int16Type = PrimitiveType[int16] + Int32Type = PrimitiveType[int32] + Int64Type = PrimitiveType[int64] + Float32Type = PrimitiveType[float32] + Float64Type = PrimitiveType[float64] + StringType = PrimitiveType[string] + BinaryType = PrimitiveType[[]byte] + TimestampType = PrimitiveType[Timestamp] + DateType = PrimitiveType[Date] + TimeType = PrimitiveType[Time] + TimestampTzType = PrimitiveType[TimestampTz] + IntervalYearType = PrimitiveType[IntervalYearToMonth] + IntervalDayType = PrimitiveType[IntervalDayToSecond] + UUIDType = PrimitiveType[UUID] + FixedCharType = FixedLenType[FixedChar] + VarCharType = FixedLenType[VarChar] + FixedBinaryType = FixedLenType[FixedBinary] + ParameterizedVarCharType = ParameterizedTypeSingleIntegerParam[VarCharType] + ParameterizedFixedCharType = ParameterizedTypeSingleIntegerParam[FixedCharType] + ParameterizedFixedBinaryType = ParameterizedTypeSingleIntegerParam[FixedBinaryType] + ParameterizedPrecisionTimestampType = ParameterizedTypeSingleIntegerParam[PrecisionTimestampType] + ParameterizedPrecisionTimestampTzType = ParameterizedTypeSingleIntegerParam[PrecisionTimestampTzType] + ParameterizedDecimalType = ParameterizedDecimal ) // FixedLenType is any of the types which also need to track their specific