Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

go - Persisting custom set data type using GORM golang

I have created a custom Set Data type in go, which i am using to define one to many relationships. For example in my Schema, i have the following struct definition

type Doctor struct {
  firstName string
  lastName string
  capabilities commons.Set
 }

Here capabilities is a set of strings which have the following values chat, audio, video, with this setup i am trying to persist the above struct into MySQL using the GORM library, but when i do this i get the following error

panic: invalid sql type Set (interface) for mysql

goroutine 6 [running]:
catalog/vendor/github.com/jinzhu/gorm.(*mysql).DataTypeOf(0xc00027e8a0, 0xc00024d680, 0x8, 0x8)
    /home/kumard/go/src/catalog/vendor/github.com/jinzhu/gorm/dialect_mysql.go:123 +0xce9
catalog/vendor/github.com/jinzhu/gorm.(*Scope).createTable(0xc000169400, 0xc14e60)

I know that i have to implement certain methods in order to achieve this, but i am not able to figure out which method/callback to implement here.

ThreadUnsafeSet Definition:

type threadUnsafeSet map[interface{}]struct{}    

type OrderedPair struct {
    First interface{}
    Second interface{}
}    

func newThreadUnsafeSet() threadUnsafeSet {
    return make(threadUnsafeSet)
}    

func (pair *OrderedPair) Equal(other OrderedPair) bool {
    return pair.First == other.First && pair.Second == other.Second
}    

func (set *threadUnsafeSet) Add(i interface{}) bool {
    _, found := (*set)[i]
    if found {
        return false
    }
    (*set)[i] = struct{}{}
    return true
}    

func (set *threadUnsafeSet) Contains(i ...interface{}) bool {
    for _, val := range i {
        if _, ok := (*set)[val]; !ok {
            return false
        }
    }
    return true
}    

func (set *threadUnsafeSet) Cardinality() int {
    return len(*set)
}    

func (set *threadUnsafeSet) Equal(other Set) bool {
    _ = other.(*threadUnsafeSet)
    if set.Cardinality() != other.Cardinality() {
        return false
    }
    for elem := range *set {
        if !other.Contains(elem){
            return false
        }
    }
    return true
}    

func (set *threadUnsafeSet) IsSubSet(other Set) bool {
    _ = other.(*threadUnsafeSet)
    if set.Cardinality() > other.Cardinality() {
        return false
    }
    for elem := range *set {
        if !other.Contains(elem) {
            return false
        }
    }
    return true
}    

func (set *threadUnsafeSet) IsProperSubSet(other Set) bool {
    return set.IsSubSet(other) && !set.Equal(other)
}    

func (set *threadUnsafeSet) IsSuperSet(other Set) bool {
    return other.IsSubSet(set)
}    

func (set *threadUnsafeSet) IsProperSuperSet(other Set) bool {
    return set.IsSuperSet(other) && !set.Equal(other)
}    

func (set *threadUnsafeSet) Union(other Set) Set {
    o := other.(*threadUnsafeSet)
    result := newThreadUnsafeSet()
    for elem := range *set {
        result.Add(elem)
    }
    for elem := range *o {
        result.Add(elem)
    }
    return &result
}    


func (set *threadUnsafeSet) Intersect(other Set) Set {
    o := other.(*threadUnsafeSet)    

    intersection := newThreadUnsafeSet()    

    if set.Cardinality() < other.Cardinality() {
        for elem := range *set {
            if other.Contains(elem) {
                intersection.Add(elem)
            }
        }
    } else {
        for elem := range *o {
            if set.Contains(elem) {
                intersection.Add(elem)
            }
        }
    }
    return &intersection
}    

func (set *threadUnsafeSet) Difference(other Set) Set {
    _ = other.(*threadUnsafeSet)
    difference := newThreadUnsafeSet()
    for elem := range *set {
        if !other.Contains(elem) {
            difference.Add(elem)
        }
    }
    return &difference
}    

func (set *threadUnsafeSet) SymmetricDifference(other Set) Set {
    _ = other.(*threadUnsafeSet)
    aDiff := set.Difference(other)
    bDiff := other.Difference(set)
    return aDiff.Difference(bDiff)
}    

func (set *threadUnsafeSet) Clear(){
    *set = newThreadUnsafeSet()
}    

func (set *threadUnsafeSet) Remove(i interface{}) {
    delete(*set, i)
}    

func (set *threadUnsafeSet) Each(cb func(interface{}) bool) {
    for elem := range *set {
        if cb(elem) {
            break
        }
    }
}    

func (set *threadUnsafeSet) Iter() <-chan interface{} {
    ch := make(chan interface{})
    go func() {
        for elem := range *set {
            ch <- elem
        }
        close(ch)
    }()
    return ch
}    

func (set *threadUnsafeSet) Iterator() *commons.Iterator {
    iterator, ch, stopCh := commons.NewIterator()
    go func (){
        L:
            for elem := range *set {
                select {
                    case <-stopCh: {
                        break L
                    }
                    case ch <- elem:
                }
                close(ch)
            }
    }()
    return iterator
}    

func (set *threadUnsafeSet) Clone() Set {
    clonedSet := newThreadUnsafeSet()
    for elem := range *set {
        clonedSet.Add(elem)
    }
    return &clonedSet
}    

func (set *threadUnsafeSet) String() string {
    items := make([]string, 0, len(*set))    

    for elem := range *set {
        items = append(items, fmt.Sprintf("%v", elem))
    }
    return fmt.Sprintf("Set{%s}", strings.Join(items, ","))
}    

func (pair OrderedPair) String() string {
    return fmt.Sprintf("(%v, %v)", pair.First, pair.Second)
}    

func (set *threadUnsafeSet) Pop() interface{} {
    for item := range *set {
        delete (*set, item)
        return item
    }
    return nil
}    

func (set *threadUnsafeSet) PowerSet() Set {
    powSet := NewThreadUnsafeSet()
    nullSet := newThreadUnsafeSet()
    powSet.Add(&nullSet)    

    for _, v := range i {
        switch t := v.(type) {
        case []interface{}, map[string]interface{}:
            continue
        default:
            set.Add(t)
        }
    }
    return nil
}    

func (set *threadUnsafeSet) FindAny() fi.Optional {
    for elem := range *set {
        return fi.MakeNullable(elem)
    }
    return fi.MakeNullable(nil)
}    

func (set *threadUnsafeSet) FindFirst(predicate func(interface{}) bool) fi.Optional {
    for elem := range *set {
        if predicate(elem) {
            return fi.MakeNullable(elem)
        }
    }
    return fi.MakeNullable(nil)
}    

func (set *threadUnsafeSet) RemoveAll(elementsToRemove ... interface{}) {
    for _, elem := range elementsToRemove {
        if set.Contains(elem) {
            set.Remove(elem)
        }
    }
}
    for es := range *set {
        u := newThreadUnsafeSet()
        j := powSet.Iter()
        for err := range j {
            p := newThreadUnsafeSet()
            if reflect.TypeOf(err).Name() == "" {
                k := err.(*threadUnsafeSet)
                for ek := range *(k){
                    p.Add(ek)
                }
            }else {
                p.Add(err)
            }
            p.Add(es)
            u.Add(&p)
        }
        powSet = powSet.Union(&u)
    }
    return powSet
}    

func (set *threadUnsafeSet) CartesianProduct(other Set) Set {
    o := other.(*threadUnsafeSet)
    cartProduct := NewThreadUnsafeSet()
    for i := range *set {
        for j := range *o {
            elem := OrderedPair{First: i, Second: j}
            cartProduct.Add(elem)
        }
    }
    return cartProduct
}    

func (set *threadUnsafeSet) ToSlice() []interface{}{
    keys := make([]interface{}, 0, set.Cardinality())
    for elem := range *set {
        keys = append(keys, elem)
    }
    return keys
}    

func (set *threadUnsafeSet) MarshalJSON() ([]byte, error) {
    items := make([]string, 0, set.Cardinality())    

    for elem := range *set {
        b, err := json.Marshal(elem)
        if err != nil {
            return nil, err
        }
        items = append(items, string(b))
    }
    return []byte(fmt.Sprintf("[%s]", strings.Join(items, ","))), nil
}    

func (set *threadUnsafeSet) UnMarshalJSON(b []byte) error {
    var i []interface{}    

    d := json.NewDecoder(bytes.NewReader(b))
    d.UseNumber()
    err := d.Decode(&i)
    if err != nil {
        return err
    }

Set Interface definition

type Set interface {
    Add(i interface{}) bool    

    Cardinality() int    

    Clear()    

    Clone() Set    

    Contains(i ...interface{}) bool    

    Difference(other Set) Set    

    Equal(other Set) bool    

    Intersect(other Set) Set    

    IsProperSubSet(other Set) bool    

    IsSubSet(other Set) bool    

    IsSuperSet(other Set) bool    

    Each(func(interface{}) bool)    

    Iter() <-chan interface{}    

    Iterator() *commons.Iterator    

    Remove(i interface{})    

    String() string    

    SymmetricDifference(other Set) Set    

    Union(other Set) Set    

    Pop() interface{}    

    PowerSet() Set    

    CartesianProduct(other Set) Set    

    ToSlice() []interface{}    

    FindAny() fi.Optional    

    FindFirst(predicate func(interface{}) bool) fi.Optional    

    RemoveAll(...interface{})
}    

// NewSet creates and returns a reference to an empty set.  Operations
// on the resulting set are thread-safe.
func NewSet(s ...interface{}) Set {
    set := newThreadSafeSet()
    for _, item := range s {
        set.Add(item)
    }
    return &set
}    

// NewSetWith creates and returns a new set with the given elements.
// Operations on the resulting set are thread-safe.
func NewSetWith(elts ...interface{}) Set {
    return NewSetFromSlice(elts)
}    

// NewSetFromSlice creates and returns a reference to a set from an
// existing slice.  Operations on the resulting set are thread-safe.
func NewSetFromSlice(s []interface{}) Set {
    a := NewSet(s...)
    return a
}    

// NewThreadUnsafeSet creates and returns a reference to an empty set.
// Operations on the resulting set are not thread-safe.
func NewThreadUnsafeSet() Set {
    set := newThreadUnsafeSet()
    return &set
}    

// NewThreadUnsafeSetFromSlice creates and returns a reference to a
// set from an existing slice.  Operations on the resulting set are
// not thread-safe.
func NewThreadUnsafeSetFromSlice(s []interface{}) Set {
    a := NewThreadUnsafeSet()
    for _, item := range s {
        a.Add(item)
    }
    return a
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...