Add double FIELD TYPE and improve type checking
This commit is contained in:
parent
543e864ed8
commit
4c8d5213dc
4 changed files with 101 additions and 24 deletions
|
@ -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{
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue