diff --git a/db/merge.go b/db/merge.go index 5404e6c5..bd35e46a 100644 --- a/db/merge.go +++ b/db/merge.go @@ -263,13 +263,31 @@ func (d *document) mrgFld(ctx context.Context) (err error) { } // Sort the fields according to their - // priority and then loop over them in - // order processing them fully. + // priority so that fields which depend + // on another field can be processed + // after that field in a specific order. sort.Slice(fds, func(i, j int) bool { return fds[i].Priority < fds[j].Priority }) + // Loop through each field and check to + // see if it might be a specific type. + // This is because when updating records + // using json, there is no specific type + // for a 'datetime' and 'record'. + + d.current.Each(func(key string, val interface{}) (err error) { + if val, ok := conv.MightBe(val); ok { + d.current.Iff(val, key) + } + return nil + }) + + // Loop over each of the defined fields + // and process them fully, applying the + // VALUE and ASSERT clauses sequentially. + for _, fd := range fds { err = d.current.Walk(func(key string, val interface{}) (err error) { diff --git a/sql/ast.go b/sql/ast.go index 32ec5c93..530729c9 100644 --- a/sql/ast.go +++ b/sql/ast.go @@ -713,6 +713,15 @@ type Thing struct { ID interface{} } +func ParseThing(val string) *Thing { + r := strings.NewReader(val) + s := newScanner(r) + if t, _, v := s.scanThing(); t == THING { + return v.(*Thing) + } + return nil +} + func NewThing(TB string, ID interface{}) *Thing { switch val := ID.(type) { default: diff --git a/util/conv/conv.go b/util/conv/conv.go index 9848b0c2..2f395e99 100644 --- a/util/conv/conv.go +++ b/util/conv/conv.go @@ -54,6 +54,35 @@ func toBoolean(str string) (bool, error) { // -------------------------------------------------- +func MightBe(obj interface{}) (val interface{}, ok bool) { + switch now := obj.(type) { + case string: + if val, ok := MightBeDatetime(now); ok { + return val, ok + } + if val, ok := MightBeRecord(now); ok { + return val, ok + } + } + return obj, false +} + +func MightBeDatetime(obj string) (val interface{}, ok bool) { + if val, err := time.Parse(time.RFC3339, obj); err == nil { + return val, true + } + return nil, false +} + +func MightBeRecord(obj string) (val interface{}, ok bool) { + if val := sql.ParseThing(obj); val != nil { + return val, true + } + return nil, false +} + +// -------------------------------------------------- + func ConvertTo(t, k string, obj interface{}) (val interface{}, err error) { switch t { default: @@ -248,7 +277,8 @@ func ConvertToLongitude(obj interface{}) (val float64, err error) { } func ConvertToRecord(obj interface{}, tb string) (val *sql.Thing, err error) { - if now, ok := obj.(*sql.Thing); ok { + switch now := obj.(type) { + case *sql.Thing: switch tb { case now.TB: val = now @@ -257,7 +287,7 @@ func ConvertToRecord(obj interface{}, tb string) (val *sql.Thing, err error) { default: err = fmt.Errorf("Expected a record of type '%s', but found '%v'", tb, obj) } - } else { + default: switch tb { default: err = fmt.Errorf("Expected a record of type '%s', but found '%v'", tb, obj)