github.com/astaxie/beego@v1.12.3/orm/orm_querym2m.go (about) 1 // Copyright 2014 beego Author. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package orm 16 17 import "reflect" 18 19 // model to model struct 20 type queryM2M struct { 21 md interface{} 22 mi *modelInfo 23 fi *fieldInfo 24 qs *querySet 25 ind reflect.Value 26 } 27 28 // add models to origin models when creating queryM2M. 29 // example: 30 // m2m := orm.QueryM2M(post,"Tag") 31 // m2m.Add(&Tag1{},&Tag2{}) 32 // for _,tag := range post.Tags{} 33 // 34 // make sure the relation is defined in post model struct tag. 35 func (o *queryM2M) Add(mds ...interface{}) (int64, error) { 36 fi := o.fi 37 mi := fi.relThroughModelInfo 38 mfi := fi.reverseFieldInfo 39 rfi := fi.reverseFieldInfoTwo 40 41 orm := o.qs.orm 42 dbase := orm.alias.DbBaser 43 44 var models []interface{} 45 var otherValues []interface{} 46 var otherNames []string 47 48 for _, colname := range mi.fields.dbcols { 49 if colname != mfi.column && colname != rfi.column && colname != fi.mi.fields.pk.column && 50 mi.fields.columns[colname] != mi.fields.pk { 51 otherNames = append(otherNames, colname) 52 } 53 } 54 for i, md := range mds { 55 if reflect.Indirect(reflect.ValueOf(md)).Kind() != reflect.Struct && i > 0 { 56 otherValues = append(otherValues, md) 57 mds = append(mds[:i], mds[i+1:]...) 58 } 59 } 60 for _, md := range mds { 61 val := reflect.ValueOf(md) 62 if val.Kind() == reflect.Slice || val.Kind() == reflect.Array { 63 for i := 0; i < val.Len(); i++ { 64 v := val.Index(i) 65 if v.CanInterface() { 66 models = append(models, v.Interface()) 67 } 68 } 69 } else { 70 models = append(models, md) 71 } 72 } 73 74 _, v1, exist := getExistPk(o.mi, o.ind) 75 if !exist { 76 panic(ErrMissPK) 77 } 78 79 names := []string{mfi.column, rfi.column} 80 81 values := make([]interface{}, 0, len(models)*2) 82 for _, md := range models { 83 84 ind := reflect.Indirect(reflect.ValueOf(md)) 85 var v2 interface{} 86 if ind.Kind() != reflect.Struct { 87 v2 = ind.Interface() 88 } else { 89 _, v2, exist = getExistPk(fi.relModelInfo, ind) 90 if !exist { 91 panic(ErrMissPK) 92 } 93 } 94 values = append(values, v1, v2) 95 96 } 97 names = append(names, otherNames...) 98 values = append(values, otherValues...) 99 return dbase.InsertValue(orm.db, mi, true, names, values) 100 } 101 102 // remove models following the origin model relationship 103 func (o *queryM2M) Remove(mds ...interface{}) (int64, error) { 104 fi := o.fi 105 qs := o.qs.Filter(fi.reverseFieldInfo.name, o.md) 106 107 return qs.Filter(fi.reverseFieldInfoTwo.name+ExprSep+"in", mds).Delete() 108 } 109 110 // check model is existed in relationship of origin model 111 func (o *queryM2M) Exist(md interface{}) bool { 112 fi := o.fi 113 return o.qs.Filter(fi.reverseFieldInfo.name, o.md). 114 Filter(fi.reverseFieldInfoTwo.name, md).Exist() 115 } 116 117 // clean all models in related of origin model 118 func (o *queryM2M) Clear() (int64, error) { 119 fi := o.fi 120 return o.qs.Filter(fi.reverseFieldInfo.name, o.md).Delete() 121 } 122 123 // count all related models of origin model 124 func (o *queryM2M) Count() (int64, error) { 125 fi := o.fi 126 return o.qs.Filter(fi.reverseFieldInfo.name, o.md).Count() 127 } 128 129 var _ QueryM2Mer = new(queryM2M) 130 131 // create new M2M queryer. 132 func newQueryM2M(md interface{}, o *orm, mi *modelInfo, fi *fieldInfo, ind reflect.Value) QueryM2Mer { 133 qm2m := new(queryM2M) 134 qm2m.md = md 135 qm2m.mi = mi 136 qm2m.fi = fi 137 qm2m.ind = ind 138 qm2m.qs = newQuerySet(o, fi.relThroughModelInfo).(*querySet) 139 return qm2m 140 }