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  }