orm_querym2m.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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. package orm
  15. import "reflect"
  16. // model to model struct
  17. type queryM2M struct {
  18. md interface{}
  19. mi *modelInfo
  20. fi *fieldInfo
  21. qs *querySet
  22. ind reflect.Value
  23. }
  24. // add models to origin models when creating queryM2M.
  25. // example:
  26. // m2m := orm.QueryM2M(post,"Tag")
  27. // m2m.Add(&Tag1{},&Tag2{})
  28. // for _,tag := range post.Tags{}
  29. //
  30. // make sure the relation is defined in post model struct tag.
  31. func (o *queryM2M) Add(mds ...interface{}) (int64, error) {
  32. fi := o.fi
  33. mi := fi.relThroughModelInfo
  34. mfi := fi.reverseFieldInfo
  35. rfi := fi.reverseFieldInfoTwo
  36. orm := o.qs.orm
  37. dbase := orm.alias.DbBaser
  38. var models []interface{}
  39. var otherValues []interface{}
  40. var otherNames []string
  41. for _, colname := range mi.fields.dbcols {
  42. if colname != mfi.column && colname != rfi.column && colname != fi.mi.fields.pk.column &&
  43. mi.fields.columns[colname] != mi.fields.pk {
  44. otherNames = append(otherNames, colname)
  45. }
  46. }
  47. for i, md := range mds {
  48. if reflect.Indirect(reflect.ValueOf(md)).Kind() != reflect.Struct && i > 0 {
  49. otherValues = append(otherValues, md)
  50. mds = append(mds[:i], mds[i+1:]...)
  51. }
  52. }
  53. for _, md := range mds {
  54. val := reflect.ValueOf(md)
  55. if val.Kind() == reflect.Slice || val.Kind() == reflect.Array {
  56. for i := 0; i < val.Len(); i++ {
  57. v := val.Index(i)
  58. if v.CanInterface() {
  59. models = append(models, v.Interface())
  60. }
  61. }
  62. } else {
  63. models = append(models, md)
  64. }
  65. }
  66. _, v1, exist := getExistPk(o.mi, o.ind)
  67. if exist == false {
  68. panic(ErrMissPK)
  69. }
  70. names := []string{mfi.column, rfi.column}
  71. values := make([]interface{}, 0, len(models)*2)
  72. for _, md := range models {
  73. ind := reflect.Indirect(reflect.ValueOf(md))
  74. var v2 interface{}
  75. if ind.Kind() != reflect.Struct {
  76. v2 = ind.Interface()
  77. } else {
  78. _, v2, exist = getExistPk(fi.relModelInfo, ind)
  79. if exist == false {
  80. panic(ErrMissPK)
  81. }
  82. }
  83. values = append(values, v1, v2)
  84. }
  85. names = append(names, otherNames...)
  86. values = append(values, otherValues...)
  87. return dbase.InsertValue(orm.db, mi, true, names, values)
  88. }
  89. // remove models following the origin model relationship
  90. func (o *queryM2M) Remove(mds ...interface{}) (int64, error) {
  91. fi := o.fi
  92. qs := o.qs.Filter(fi.reverseFieldInfo.name, o.md)
  93. nums, err := qs.Filter(fi.reverseFieldInfoTwo.name+ExprSep+"in", mds).Delete()
  94. if err != nil {
  95. return nums, err
  96. }
  97. return nums, nil
  98. }
  99. // check model is existed in relationship of origin model
  100. func (o *queryM2M) Exist(md interface{}) bool {
  101. fi := o.fi
  102. return o.qs.Filter(fi.reverseFieldInfo.name, o.md).
  103. Filter(fi.reverseFieldInfoTwo.name, md).Exist()
  104. }
  105. // clean all models in related of origin model
  106. func (o *queryM2M) Clear() (int64, error) {
  107. fi := o.fi
  108. return o.qs.Filter(fi.reverseFieldInfo.name, o.md).Delete()
  109. }
  110. // count all related models of origin model
  111. func (o *queryM2M) Count() (int64, error) {
  112. fi := o.fi
  113. return o.qs.Filter(fi.reverseFieldInfo.name, o.md).Count()
  114. }
  115. var _ QueryM2Mer = new(queryM2M)
  116. // create new M2M queryer.
  117. func newQueryM2M(md interface{}, o *orm, mi *modelInfo, fi *fieldInfo, ind reflect.Value) QueryM2Mer {
  118. qm2m := new(queryM2M)
  119. qm2m.md = md
  120. qm2m.mi = mi
  121. qm2m.fi = fi
  122. qm2m.ind = ind
  123. qm2m.qs = newQuerySet(o, fi.relThroughModelInfo).(*querySet)
  124. return qm2m
  125. }