Add double FIELD TYPE and improve type checking

This commit is contained in:
Tobie Morgan Hitchcock 2016-10-20 14:14:10 +01:00
parent 543e864ed8
commit 4c8d5213dc
4 changed files with 101 additions and 24 deletions

View file

@ -1413,11 +1413,11 @@ func Test_Parse_Queries_Define(t *testing.T) {
}, },
{ {
sql: `DEFINE FIELD temp ON person TYPE`, sql: `DEFINE FIELD temp ON person TYPE`,
err: "Found `` but expected `any, url, uuid, color, email, phone, array, object, domain, string, number, custom, boolean, datetime, latitude, longitude`", err: "Found `` but expected `any, url, uuid, color, email, phone, array, object, domain, string, number, double, custom, boolean, datetime, latitude, longitude`",
}, },
{ {
sql: `DEFINE FIELD temp ON person TYPE something`, sql: `DEFINE FIELD temp ON person TYPE something`,
err: "Found `something` but expected `any, url, uuid, color, email, phone, array, object, domain, string, number, custom, boolean, datetime, latitude, longitude`", err: "Found `something` but expected `any, url, uuid, color, email, phone, array, object, domain, string, number, double, custom, boolean, datetime, latitude, longitude`",
}, },
{ {
sql: `DEFINE FIELD temp ON person TYPE any`, sql: `DEFINE FIELD temp ON person TYPE any`,
@ -1483,6 +1483,14 @@ func Test_Parse_Queries_Define(t *testing.T) {
Type: "number", Type: "number",
}}}, }}},
}, },
{
sql: `DEFINE FIELD temp ON person TYPE double`,
res: &Query{Statements: []Statement{&DefineFieldStatement{
Name: "temp",
What: []string{"person"},
Type: "double",
}}},
},
{ {
sql: `DEFINE FIELD temp ON person TYPE custom`, sql: `DEFINE FIELD temp ON person TYPE custom`,
res: &Query{Statements: []Statement{&DefineFieldStatement{ res: &Query{Statements: []Statement{&DefineFieldStatement{

View file

@ -16,7 +16,7 @@ package sql
func (p *parser) parseType() (exp string, err error) { func (p *parser) parseType() (exp string, err error) {
allowed := []string{"any", "url", "uuid", "color", "email", "phone", "array", "object", "domain", "string", "number", "custom", "boolean", "datetime", "latitude", "longitude"} allowed := []string{"any", "url", "uuid", "color", "email", "phone", "array", "object", "domain", "string", "number", "double", "custom", "boolean", "datetime", "latitude", "longitude"}
_, lit, err := p.shouldBe(IDENT, CUSTOM) _, lit, err := p.shouldBe(IDENT, CUSTOM)
if err != nil { if err != nil {

View file

@ -16,13 +16,40 @@ package conv
import ( import (
"fmt" "fmt"
"strconv"
"time" "time"
"github.com/asaskevich/govalidator" "github.com/asaskevich/govalidator"
) )
func toNumber(str string) (int64, error) {
val, err := strconv.ParseFloat(str, 64)
if err != nil {
val = 0.0
}
return int64(val), err
}
func toDouble(str string) (float64, error) {
val, err := strconv.ParseFloat(str, 64)
if err != nil {
val = 0.0
}
return float64(val), err
}
func toBoolean(str string) (bool, error) {
val, err := strconv.ParseBool(str)
if err != nil {
val = false
}
return bool(val), err
}
// --------------------------------------------------
func ConvertToUrl(obj interface{}) (val string, err error) { func ConvertToUrl(obj interface{}) (val string, err error) {
val = govalidator.ToString(obj) val = fmt.Sprintf("%v", obj)
if !govalidator.IsURL(val) { if !govalidator.IsURL(val) {
err = fmt.Errorf("Not a valid url") err = fmt.Errorf("Not a valid url")
} }
@ -30,7 +57,7 @@ func ConvertToUrl(obj interface{}) (val string, err error) {
} }
func ConvertToUuid(obj interface{}) (val string, err error) { func ConvertToUuid(obj interface{}) (val string, err error) {
val = govalidator.ToString(obj) val = fmt.Sprintf("%v", obj)
if !govalidator.IsUUID(val) { if !govalidator.IsUUID(val) {
err = fmt.Errorf("Not a valid uuid") err = fmt.Errorf("Not a valid uuid")
} }
@ -38,7 +65,7 @@ func ConvertToUuid(obj interface{}) (val string, err error) {
} }
func ConvertToEmail(obj interface{}) (val string, err error) { func ConvertToEmail(obj interface{}) (val string, err error) {
val = govalidator.ToString(obj) val = fmt.Sprintf("%v", obj)
if !govalidator.IsEmail(val) { if !govalidator.IsEmail(val) {
err = fmt.Errorf("Not a valid email") err = fmt.Errorf("Not a valid email")
} }
@ -46,7 +73,7 @@ func ConvertToEmail(obj interface{}) (val string, err error) {
} }
func ConvertToPhone(obj interface{}) (val string, err error) { func ConvertToPhone(obj interface{}) (val string, err error) {
val = govalidator.ToString(obj) val = fmt.Sprintf("%v", obj)
if !govalidator.Matches(val, `^[\s\d\+\-\(\)]+$`) { if !govalidator.Matches(val, `^[\s\d\+\-\(\)]+$`) {
err = fmt.Errorf("Not a valid phone") err = fmt.Errorf("Not a valid phone")
} }
@ -54,7 +81,7 @@ func ConvertToPhone(obj interface{}) (val string, err error) {
} }
func ConvertToColor(obj interface{}) (val string, err error) { func ConvertToColor(obj interface{}) (val string, err error) {
val = govalidator.ToString(obj) val = fmt.Sprintf("%v", obj)
if !govalidator.IsHexcolor(val) && !govalidator.IsRGBcolor(val) { if !govalidator.IsHexcolor(val) && !govalidator.IsRGBcolor(val) {
err = fmt.Errorf("Not a valid color") err = fmt.Errorf("Not a valid color")
} }
@ -80,7 +107,7 @@ func ConvertToObject(obj interface{}) (val map[string]interface{}, err error) {
} }
func ConvertToDomain(obj interface{}) (val string, err error) { func ConvertToDomain(obj interface{}) (val string, err error) {
val = govalidator.ToString(obj) val = fmt.Sprintf("%v", obj)
if !govalidator.IsDNSName(val) { if !govalidator.IsDNSName(val) {
err = fmt.Errorf("Not a valid domain name") err = fmt.Errorf("Not a valid domain name")
} }
@ -88,7 +115,7 @@ func ConvertToDomain(obj interface{}) (val string, err error) {
} }
func ConvertToBase64(obj interface{}) (val string, err error) { func ConvertToBase64(obj interface{}) (val string, err error) {
val = govalidator.ToString(obj) val = fmt.Sprintf("%v", obj)
if !govalidator.IsBase64(val) { if !govalidator.IsBase64(val) {
err = fmt.Errorf("Not valid base64 data") err = fmt.Errorf("Not valid base64 data")
} }
@ -96,24 +123,55 @@ func ConvertToBase64(obj interface{}) (val string, err error) {
} }
func ConvertToString(obj interface{}) (val string, err error) { func ConvertToString(obj interface{}) (val string, err error) {
if now, ok := obj.(string); ok { switch now := obj.(type) {
case string:
return now, err return now, err
case []interface{}:
return val, fmt.Errorf("Not valid string")
case map[string]interface{}:
return val, fmt.Errorf("Not valid string")
default:
return fmt.Sprintf("%v", obj), err
} }
return govalidator.ToString(obj), err
} }
func ConvertToNumber(obj interface{}) (val float64, err error) { func ConvertToNumber(obj interface{}) (val int64, err error) {
if now, ok := obj.(float64); ok { switch now := obj.(type) {
return now, err case int64:
return int64(now), err
case float64:
return int64(now), err
case string:
return toNumber(now)
default:
return toNumber(fmt.Sprintf("%v", obj))
}
}
func ConvertToDouble(obj interface{}) (val float64, err error) {
switch now := obj.(type) {
case int64:
return float64(now), err
case float64:
return float64(now), err
case string:
return toDouble(now)
default:
return toDouble(fmt.Sprintf("%v", obj))
} }
return govalidator.ToFloat(govalidator.ToString(obj))
} }
func ConvertToBoolean(obj interface{}) (val bool, err error) { func ConvertToBoolean(obj interface{}) (val bool, err error) {
if now, ok := obj.(bool); ok { switch now := obj.(type) {
return now, err case int64:
return now > 0, err
case float64:
return now > 0, err
case string:
return toBoolean(now)
default:
return toBoolean(fmt.Sprintf("%v", obj))
} }
return govalidator.ToBoolean(govalidator.ToString(obj))
} }
func ConvertToDatetime(obj interface{}) (val time.Time, err error) { func ConvertToDatetime(obj interface{}) (val time.Time, err error) {
@ -126,7 +184,7 @@ func ConvertToDatetime(obj interface{}) (val time.Time, err error) {
} }
func ConvertToLatitude(obj interface{}) (val float64, err error) { func ConvertToLatitude(obj interface{}) (val float64, err error) {
str := govalidator.ToString(obj) str := fmt.Sprintf("%v", obj)
if !govalidator.IsLatitude(str) { if !govalidator.IsLatitude(str) {
err = fmt.Errorf("Not a valid latitude") err = fmt.Errorf("Not a valid latitude")
} }
@ -134,8 +192,8 @@ func ConvertToLatitude(obj interface{}) (val float64, err error) {
} }
func ConvertToLongitude(obj interface{}) (val float64, err error) { func ConvertToLongitude(obj interface{}) (val float64, err error) {
str := govalidator.ToString(obj) str := fmt.Sprintf("%v", obj)
if !govalidator.IsLatitude(str) { if !govalidator.IsLongitude(str) {
err = fmt.Errorf("Not a valid longitude") err = fmt.Errorf("Not a valid longitude")
} }
return govalidator.ToFloat(str) return govalidator.ToFloat(str)
@ -145,10 +203,10 @@ func ConvertToOneOf(obj interface{}, pos ...interface{}) (val interface{}, err e
for _, now := range pos { for _, now := range pos {
if num, ok := obj.(int64); ok { if num, ok := obj.(int64); ok {
if float64(num) == now { if float64(num) == now {
return obj, nil return obj, err
} }
} else if obj == now { } else if obj == now {
return obj, nil return obj, err
} }
} }
return nil, fmt.Errorf("Not a valid option") return nil, fmt.Errorf("Not a valid option")

View file

@ -237,6 +237,17 @@ func each(fld *sql.DefineFieldStatement, initial *data.Doc, current *data.Doc) (
} }
} }
case "double":
if val, err := conv.ConvertToDouble(c); err == nil {
current.Set(val, fld.Name)
} else {
if fld.Validate {
return fmt.Errorf("Field '%v' needs to be a double", fld.Name)
} else {
current.Iff(i, fld.Name)
}
}
case "boolean": case "boolean":
if val, err := conv.ConvertToBoolean(c); err == nil { if val, err := conv.ConvertToBoolean(c); err == nil {
current.Set(val, fld.Name) current.Set(val, fld.Name)