github.com/ecodeclub/eorm@v0.0.2-0.20231001112437-dae71da914d0/sharding_builder.go (about) 1 // Copyright 2021 ecodeclub 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 eorm 16 17 import ( 18 "context" 19 20 "github.com/ecodeclub/ekit/slice" 21 "github.com/ecodeclub/eorm/internal/errs" 22 operator "github.com/ecodeclub/eorm/internal/operator" 23 "github.com/ecodeclub/eorm/internal/sharding" 24 ) 25 26 type shardingBuilder struct { 27 builder 28 } 29 30 func (b *shardingBuilder) findDst(ctx context.Context, predicates ...Predicate) (sharding.Response, error) { 31 // 通过遍历 pre 查找目标 shardingkey 32 if len(predicates) > 0 { 33 pre := predicates[0] 34 for i := 1; i < len(predicates)-1; i++ { 35 pre = pre.And(predicates[i]) 36 } 37 return b.findDstByPredicate(ctx, pre) 38 } 39 res := sharding.Response{ 40 Dsts: b.meta.ShardingAlgorithm.Broadcast(ctx), 41 } 42 return res, nil 43 } 44 45 func (b *shardingBuilder) findDstByPredicate(ctx context.Context, pre Predicate) (sharding.Response, error) { 46 switch pre.op { 47 case opAnd: 48 left, err := b.findDstByPredicate(ctx, pre.left.(Predicate)) 49 if err != nil { 50 return sharding.EmptyResp, err 51 } 52 right, err := b.findDstByPredicate(ctx, pre.right.(Predicate)) 53 if err != nil { 54 return sharding.EmptyResp, err 55 } 56 return b.mergeAnd(left, right), nil 57 case opOr: 58 left, err := b.findDstByPredicate(ctx, pre.left.(Predicate)) 59 if err != nil { 60 return sharding.EmptyResp, err 61 } 62 right, err := b.findDstByPredicate(ctx, pre.right.(Predicate)) 63 if err != nil { 64 return sharding.EmptyResp, err 65 } 66 return b.mergeOR(left, right), nil 67 case opIn: 68 col := pre.left.(Column) 69 right := pre.right.(values) 70 var results []sharding.Response 71 for _, val := range right.data { 72 res, err := b.meta.ShardingAlgorithm.Sharding(ctx, 73 sharding.Request{Op: opEQ, SkValues: map[string]any{col.name: val}}) 74 if err != nil { 75 return sharding.EmptyResp, err 76 } 77 results = append(results, res) 78 } 79 return b.mergeIN(results), nil 80 case opNot: 81 nPre, err := b.negatePredicate(pre.right.(Predicate)) 82 if err != nil { 83 return sharding.EmptyResp, err 84 } 85 return b.findDstByPredicate(ctx, nPre) 86 case opNotIN: 87 return b.meta.ShardingAlgorithm.Sharding(ctx, 88 sharding.Request{Op: opNotIN, SkValues: map[string]any{}}) 89 case opEQ, opGT, opLT, opGTEQ, opLTEQ, opNEQ: 90 col, isCol := pre.left.(Column) 91 right, isVals := pre.right.(valueExpr) 92 if !isCol || !isVals { 93 return sharding.EmptyResp, errs.ErrUnsupportedTooComplexQuery 94 } 95 return b.meta.ShardingAlgorithm.Sharding(ctx, 96 sharding.Request{Op: pre.op, SkValues: map[string]any{col.name: right.val}}) 97 default: 98 return sharding.EmptyResp, errs.NewUnsupportedOperatorError(pre.op.Text) 99 } 100 } 101 102 func (b *shardingBuilder) negatePredicate(pre Predicate) (Predicate, error) { 103 switch pre.op { 104 case opAnd: 105 left, err := b.negatePredicate(pre.left.(Predicate)) 106 if err != nil { 107 return emptyPredicate, err 108 } 109 right, err := b.negatePredicate(pre.right.(Predicate)) 110 if err != nil { 111 return emptyPredicate, err 112 } 113 return Predicate{ 114 left: left, op: opOr, right: right, 115 }, nil 116 case opOr: 117 left, err := b.negatePredicate(pre.left.(Predicate)) 118 if err != nil { 119 return emptyPredicate, err 120 } 121 right, err := b.negatePredicate(pre.right.(Predicate)) 122 if err != nil { 123 return emptyPredicate, err 124 } 125 return Predicate{ 126 left: left, op: opAnd, right: right, 127 }, nil 128 default: 129 nOp, err := operator.NegateOp(pre.op) 130 if err != nil { 131 return emptyPredicate, err 132 } 133 return Predicate{left: pre.left, op: nOp, right: pre.right}, nil 134 } 135 } 136 137 // mergeAnd 两个分片结果的交集 138 func (*shardingBuilder) mergeAnd(left, right sharding.Response) sharding.Response { 139 dsts := slice.IntersectSetFunc[sharding.Dst](left.Dsts, right.Dsts, func(src, dst sharding.Dst) bool { 140 return src.Equals(dst) 141 }) 142 return sharding.Response{Dsts: dsts} 143 } 144 145 // mergeOR 两个分片结果的并集 146 func (*shardingBuilder) mergeOR(left, right sharding.Response) sharding.Response { 147 dsts := slice.UnionSetFunc[sharding.Dst](left.Dsts, right.Dsts, func(src, dst sharding.Dst) bool { 148 return src.Equals(dst) 149 }) 150 return sharding.Response{Dsts: dsts} 151 } 152 153 // mergeIN 多个分片结果的并集 154 func (*shardingBuilder) mergeIN(vals []sharding.Response) sharding.Response { 155 var dsts []sharding.Dst 156 for _, val := range vals { 157 dsts = slice.UnionSetFunc[sharding.Dst](dsts, val.Dsts, func(src, dst sharding.Dst) bool { 158 return src.Equals(dst) 159 }) 160 } 161 return sharding.Response{Dsts: dsts} 162 }