使用GORM golang持久化自定义集数据类型
我在go中创建了一个自定义的使用GORM golang持久化自定义集数据类型,go,go-gorm,Go,Go Gorm,我在go中创建了一个自定义的Set数据类型,用于定义一对多关系。例如,在我的模式中,我有以下结构定义 type Doctor struct { firstName string lastName string capabilities commons.Set } 这里的capabilities是一组字符串,具有以下值chat、audio、video,通过此设置,我试图使用GORM库将上述结构持久化到MySQL,但当我这样做时,我得到以下错误 panic: invalid sql
Set
数据类型,用于定义一对多关系。例如,在我的模式中,我有以下结构定义
type Doctor struct {
firstName string
lastName string
capabilities commons.Set
}
这里的capabilities
是一组字符串,具有以下值chat、audio、video
,通过此设置,我试图使用GORM
库将上述结构持久化到MySQL
,但当我这样做时,我得到以下错误
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)
我知道我必须实现某些方法才能实现这一点,但我无法确定在这里实现哪个方法/回调
ThreadUnsafeSet定义:
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
}
type threadUnsafeSet映射[interface{}]struct{}
类型OrderedPair结构{
第一接口{}
第二接口{}
}
func newThreadUnsafeSet()threadUnsafeSet{
退货品牌(螺纹未固定)
}
func(对*有序对)等于(其他有序对)布尔{
返回pair.First==other.First&&pair.Second==other.Second
}
func(set*threadUnsafeSet)Add(i接口{})bool{
_,发现:=(*set)[i]
如果找到{
返回错误
}
(*set)[i]=struct{}{}
返回真值
}
func(set*threadUnsafeSet)包含(i…接口{})bool{
对于u,val:=范围i{
如果,确定:=(*设置)[val];!确定{
返回错误
}
}
返回真值
}
func(set*threadUnsafeSet)基数()int{
返回长度(*套)
}
func(集合*threadUnsafeSet)相等(其他集合)布尔{
_=其他。(*threadUnsafeSet)
如果set.Cardinality()!=其他.Cardinality(){
返回错误
}
对于元素:=范围*集{
if!other.Contains(elem){
返回错误
}
}
返回真值
}
func(集合*threadUnsafeSet)IsubSet(其他集合)布尔{
_=其他。(*threadUnsafeSet)
如果set.Cardinality()>other.Cardinality(){
返回错误
}
对于元素:=范围*集{
if!other.Contains(elem){
返回错误
}
}
返回真值
}
func(集合*threadUnsafeSet)ISPropertSubset(其他集合)布尔{
返回set.IsSubSet(其他)和&!set.Equal(其他)
}
func(集合*threadUnsafeSet)IsSuperSet(其他集合)布尔{
返回其他.IsSubSet(集合)
}
func(集合*threadUnsafeSet)ISPropertSuperSet(其他集合)布尔{
返回set.IsSuperSet(其他)和&!set.Equal(其他)
}
func(集合*threadUnsafeSet)并集(其他集合)集合{
o:=其他。(*threadUnsafeSet)
结果:=newThreadUnsafeSet()
对于元素:=范围*集{
结果。添加(元素)
}
对于元素:=范围*o{
结果。添加(元素)
}
返回和结果
}
func(集合*threadUnsafeSet)相交(其他集合)集合{
o:=其他。(*threadUnsafeSet)
交集:=newThreadUnsafeSet()
如果set.Cardinality()
func (data *CustomType) Value() (driver.Value, error) {
...
}
func (data *CustomType) Scan(value interface{}) error {
...
}
例如:
假设UserAccess是map[interface{}]struct{}
type
type UserAccess map[interface{}]struct{}
func (data *UserAccess) Value() (driver.Value, error) {
return data.ConvertJSONToString(), nil
}
func (data *UserAccess) Scan(value interface{}) error {
*data = data.ConvertStringToJson(valueString)
}
这里的ConvertStringToJson
和ConvertJSONToString
用于将自定义数据类型值转换为与数据库兼容的类型,如json字符串。@AbinashGhosh threadUnsafeSet是Set接口的实现
type UserAccess map[interface{}]struct{}
func (data *UserAccess) Value() (driver.Value, error) {
return data.ConvertJSONToString(), nil
}
func (data *UserAccess) Scan(value interface{}) error {
*data = data.ConvertStringToJson(valueString)
}