Fold decimal(scale) into kafka.source-type

This commit is contained in:
Travis Turner 2023-02-28 11:37:42 -06:00
parent 634553d3c3
commit 6107ddef47
No known key found for this signature in database
GPG key ID: 3FB5CF5C97A37B30
3 changed files with 68 additions and 18 deletions

View file

@ -381,9 +381,14 @@ func (cmd *Command) setupConfig() error {
return errors.Wrap(err, "cleaning config")
}
flds, err := kafka.ConfigToFields(cfg)
if err != nil {
return errors.Wrap(err, "getting fields from config")
}
cmd.kafkaRunner = kafka.NewRunner(
cleanCfg,
batch.NewSQLBatcher(cmd, kafka.ConfigToFields(cfg)),
batch.NewSQLBatcher(cmd, flds),
cmd.Stderr,
)
}

View file

@ -10,7 +10,7 @@ import (
)
type Config struct {
Hosts []string `mapstructure:"hosts" help: "Kafka hosts."`
Hosts []string `mapstructure:"hosts" help:"Kafka hosts."`
Group string `mapstructure:"group" help:"Kafka group."`
Topics []string `mapstructure:"topics" help:"Kafka topics to read from."`
@ -38,15 +38,9 @@ type ConfigForIDK struct {
type Field struct {
Name string `mapstructure:"name"`
Type string `mapstructure:"type"`
SourceType string `mapstructure:"source-type"`
SourcePath []string `mapstructure:"source-path"`
PrimaryKey bool `mapstructure:"primary-key"`
Options FieldOptions `mapstructure:"options"`
}
type FieldOptions struct {
Scale int64 `mapstructure:"scale"`
}
// ValidateConfig validates the config is usable.
@ -104,7 +98,7 @@ func ConvertConfig(c Config) (ConfigForIDK, error) {
foundPK = true
}
typ, err := dax.BaseTypeFromString(fld.Type)
typ, quals, err := dax.SplitFieldType(fld.SourceType)
if err != nil {
return out, errors.Wrap(err, "getting base type")
}
@ -123,7 +117,10 @@ func ConvertConfig(c Config) (ConfigForIDK, error) {
case dax.BaseTypeInt:
// We don't have to handle min/max because we don't create the table.
case dax.BaseTypeDecimal:
rawFld.Config = []byte(fmt.Sprintf(`{"scale":%d}`, fld.Options.Scale))
if len(quals) != 1 {
return out, errors.Errorf("expected decimal scale")
}
rawFld.Config = []byte(fmt.Sprintf(`{"scale":%d}`, quals[0]))
case dax.BaseTypeID:
rawFld.Config = []byte("{\"mutex\":true}")
case dax.BaseTypeIDSet:
@ -149,7 +146,7 @@ func ConvertConfig(c Config) (ConfigForIDK, error) {
// ConfigToFields returns a list of *dax.Field based on the IDField and Fields
// in the Config.
func ConfigToFields(c Config) []*dax.Field {
func ConfigToFields(c Config) ([]*dax.Field, error) {
// We don't know if a primary key will be found, so we can't set the
// capacity to `len(c.Fields)-1`.
out := make([]*dax.Field, 0, len(c.Fields))
@ -158,15 +155,27 @@ func ConfigToFields(c Config) []*dax.Field {
if fld.PrimaryKey {
continue
}
typ, quals, err := dax.SplitFieldType(fld.SourceType)
if err != nil {
return nil, errors.Wrap(err, "splitting field type")
}
dfld := &dax.Field{
Name: dax.FieldName(fld.Name),
Type: dax.BaseType(fld.Type),
Options: dax.FieldOptions{
Scale: fld.Options.Scale,
},
Type: typ,
}
switch typ {
case dax.BaseTypeDecimal:
if len(quals) != 1 {
return nil, errors.Errorf("expected decimal scale")
}
scale, ok := quals[0].(int64)
if !ok {
return nil, errors.Errorf("invalid decimal scale: %v", quals[0])
}
dfld.Options.Scale = scale
}
out = append(out, dfld)
}
return out
return out, nil
}

View file

@ -693,6 +693,42 @@ func BaseTypeFromString(s string) (BaseType, error) {
}
}
// SplitFieldType splits a string into a BaseType and, when applicable, a slice
// of qualifiers for that type. For example, the string `decimal(2)` would be
// split into BaseType `decimal` and []interface{}{int64(2)}.
func SplitFieldType(s string) (BaseType, []interface{}, error) {
var base string
var paren string
parts := strings.Split(s, "(")
base = parts[0]
if len(parts) > 1 {
parenParts := strings.Split(parts[1], ")")
if len(parenParts) != 2 {
return "", nil, errors.Errorf("invalid type qualifier: %s", s)
}
paren = parenParts[0]
}
baseType, err := BaseTypeFromString(base)
if err != nil {
return "", nil, err
}
// Handle the string found in parenthesis.
args := []interface{}{}
switch baseType {
case BaseTypeDecimal:
scale, err := strconv.ParseInt(paren, 10, 64)
if err != nil {
return "", nil, errors.Wrapf(err, "parsing int from string: %s", paren)
}
args = append(args, scale)
}
return baseType, args, nil
}
// Field represents a field and its configuration.
type Field struct {
Name FieldName `json:"name"`
@ -707,7 +743,7 @@ func (f *Field) String() string {
return string(f.Name)
}
// Definition returns the field name along with its parenthetical (when
// Definition returns the field type along with its parenthetical (when
// applicable).
func (f *Field) Definition() string {
switch f.Type {