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  }