mattermost-community-enterp.../vendor/github.com/splitio/go-split-commons/v7/engine/grammar/condition.go
Claude ec1f89217a Merge: Complete Mattermost Server with Community Enterprise
Full Mattermost server source with integrated Community Enterprise features.
Includes vendor directory for offline/air-gapped builds.

Structure:
- enterprise-impl/: Enterprise feature implementations
- enterprise-community/: Init files that register implementations
- enterprise/: Bridge imports (community_imports.go)
- vendor/: All dependencies for offline builds

Build (online):
  go build ./cmd/mattermost

Build (offline/air-gapped):
  go build -mod=vendor ./cmd/mattermost

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 23:59:07 +09:00

143 lines
4.0 KiB
Go

package grammar
import (
"github.com/splitio/go-split-commons/v7/dtos"
"github.com/splitio/go-split-commons/v7/engine/grammar/datatypes"
"github.com/splitio/go-toolkit/v5/logging"
)
// Condition struct with added logic that wraps around a DTO
type Condition struct {
matchers []MatcherInterface
combiner string
partitions []Partition
label string
conditionType string
}
// NewCondition instantiates a new Condition struct with appropriate wrappers around dtos and returns it.
func NewCondition(cond *dtos.ConditionDTO, logger logging.LoggerInterface, ruleBuilder RuleBuilder) (*Condition, error) {
partitions := make([]Partition, 0)
for _, part := range cond.Partitions {
partitions = append(partitions, Partition{PartitionData: part})
}
matcherObjs, err := processMatchers(cond.MatcherGroup.Matchers, logger, ruleBuilder)
if err != nil {
// At this point the only error forwarded is UnsupportedMatcherError
return nil, err
}
return &Condition{
combiner: cond.MatcherGroup.Combiner,
matchers: matcherObjs,
partitions: partitions,
label: cond.Label,
conditionType: cond.ConditionType,
}, nil
}
func NewRBCondition(cond *dtos.RuleBasedConditionDTO, logger logging.LoggerInterface, ruleBuilder RuleBuilder) (*Condition, error) {
partitions := make([]Partition, 0)
matcherObjs, err := processMatchers(cond.MatcherGroup.Matchers, logger, ruleBuilder)
if err != nil {
// At this point the only error forwarded is UnsupportedMatcherError
return nil, err
}
return &Condition{
combiner: cond.MatcherGroup.Combiner,
matchers: matcherObjs,
partitions: partitions,
conditionType: cond.ConditionType,
}, nil
}
func processMatchers(condMatchers []dtos.MatcherDTO, logger logging.LoggerInterface, ruleBuilder RuleBuilder) ([]MatcherInterface, error) {
matcherObjs := make([]MatcherInterface, 0)
for _, matcher := range condMatchers {
m, err := ruleBuilder.BuildMatcher(&matcher)
if err == nil {
matcherObjs = append(matcherObjs, m)
} else {
logger.Debug("error in BuildMatcher, reason: ", err.Error())
if _, ok := err.(datatypes.UnsupportedMatcherError); ok {
return nil, err
}
}
}
return matcherObjs, nil
}
// Partition struct with added logic that wraps around a DTO
type Partition struct {
PartitionData dtos.PartitionDTO
}
// ConditionType returns validated condition type. Whitelist by default
func (c *Condition) ConditionType() string {
switch c.conditionType {
case ConditionTypeRollout:
return ConditionTypeRollout
case ConditionTypeWhitelist:
return ConditionTypeWhitelist
default:
return ConditionTypeWhitelist
}
}
func (c *Condition) Combiner() string {
return c.combiner
}
// Label returns the condition's label
func (c *Condition) Label() string {
return c.label
}
// Matches returns true if the condition matches for a specific key and/or set of attributes
func (c *Condition) Matches(key string, bucketingKey *string, attributes map[string]interface{}) bool {
partial := make([]bool, len(c.matchers))
for i, matcher := range c.matchers {
partial[i] = matcher.Match(key, attributes, bucketingKey)
if matcher.Negate() {
partial[i] = !partial[i]
}
}
return applyCombiner(partial, c.combiner)
}
// CalculateTreatment calulates the treatment for a specific condition based on the bucket
func (c *Condition) CalculateTreatment(bucket int) *string {
accum := 0
for _, partition := range c.partitions {
accum += partition.PartitionData.Size
if bucket <= accum {
return &partition.PartitionData.Treatment
}
}
return nil
}
func BuildCondition(conditionType string, label string, partitions []Partition, matchers []MatcherInterface, combiner string) *Condition {
return &Condition{
conditionType: conditionType,
label: label,
partitions: partitions,
matchers: matchers,
combiner: combiner,
}
}
func applyCombiner(results []bool, combiner string) bool {
temp := true
switch combiner {
case "AND":
for _, result := range results {
temp = temp && result
}
default:
return false
}
return temp
}