sq/libsq/core/kind/kind.go
Neil O'Toole ad23d5c116
Auto-detect CSV headers (#188)
* wip: initial header detection

* wip: refactored csv driver

* wip: Fixes to kind.Detector

* typo

* Refactor pkg csv files

* Update to changelog

* workflow: now running codacy and codeql on cron, not on push/pr
2023-04-09 08:44:27 -06:00

155 lines
2.7 KiB
Go

// Package kind encapsulates the notion of data "kind": that is, it
// is an abstraction over data types across implementations.
package kind
import (
"strings"
"github.com/neilotoole/sq/libsq/core/errz"
)
const (
// Unknown indicates an unknown kind.
Unknown Kind = iota
// Null indicates a NULL kind.
Null
// Text indicates a text kind.
Text
// Int indicates an integer kind.
Int
// Float indicates a float kind.
Float
// Decimal indicates a decimal kind.
Decimal
// Bool indicates a boolean kind.
Bool
// Bytes indicates a bytes or blob kind.
Bytes
// Datetime indicates a date-time kind.
Datetime
// Date indicates a date-only kind. For example "2022-12-31".
Date
// Time indicates a time-only kind.
Time
)
// Kind models a generic data kind, which ultimately maps
// to some more specific implementation data type,
// such as a SQL VARCHAR or JSON boolean.
type Kind int
// String returns a log/debug-friendly representation.
func (k Kind) String() string {
t, err := k.MarshalText()
if err != nil {
return "<err>"
}
return string(t)
}
// MarshalJSON implements json.Marshaler.
func (k Kind) MarshalJSON() ([]byte, error) {
t, err := k.MarshalText()
if err != nil {
return nil, err
}
return []byte(`"` + string(t) + `"`), nil
}
// MarshalText implements encoding.TextMarshaler.
func (k Kind) MarshalText() ([]byte, error) {
var name string
switch k {
case Unknown:
name = "unknown"
case Null:
name = "null"
case Text:
name = "text"
case Int:
name = "int"
case Float:
name = "float"
case Decimal:
name = "decimal"
case Bool:
name = "bool"
case Datetime:
name = "datetime"
case Date:
name = "date"
case Time:
name = "time"
case Bytes:
name = "bytes"
default:
return nil, errz.Errorf("invalid data kind '%d'", k)
}
return []byte(name), nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (k *Kind) UnmarshalText(text []byte) error {
kind, err := parse(string(text))
if err != nil {
return err
}
*k = kind
return nil
}
// parse parses text and returns the appropriate kind, or
// an error.
func parse(text string) (Kind, error) {
switch strings.ToLower(text) {
default:
return Unknown, errz.Errorf("unrecognized kind name {%s}", text)
case "unknown":
return Unknown, nil
case "text":
return Text, nil
case "int":
return Int, nil
case "float":
return Float, nil
case "decimal":
return Decimal, nil
case "bool":
return Bool, nil
case "datetime":
return Datetime, nil
case "date":
return Date, nil
case "time":
return Time, nil
case "bytes":
return Bytes, nil
case "null":
return Null, nil
}
}
func containsKind(needle Kind, haystack ...Kind) bool {
for _, k := range haystack {
if k == needle {
return true
}
}
return false
}