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