mattermost-community-enterp.../vendor/github.com/splitio/go-split-commons/v7/engine/grammar/rulebuilder.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

403 lines
12 KiB
Go

package grammar
import (
"errors"
"fmt"
"golang.org/x/exp/slices"
"github.com/splitio/go-split-commons/v7/dtos"
"github.com/splitio/go-split-commons/v7/engine/grammar/datatypes"
"github.com/splitio/go-split-commons/v7/storage"
"github.com/splitio/go-toolkit/v5/logging"
)
type dependencyEvaluator interface {
EvaluateDependency(key string, bucketingKey *string, feature string, attributes map[string]interface{}) string
}
type RuleBuilder struct {
segmentStorage storage.SegmentStorageConsumer
ruleBasedSegmentStorage storage.RuleBasedSegmentStorageConsumer
largeSegmentStorage storage.LargeSegmentStorageConsumer
ffAcceptedMatchers []string
rbAcceptedMatchers []string
logger logging.LoggerInterface
dependencyEvaluator dependencyEvaluator
}
func NewRuleBuilder(segmentStorage storage.SegmentStorageConsumer, ruleBasedSegmentStorage storage.RuleBasedSegmentStorageConsumer, largeSegmentStorage storage.LargeSegmentStorageConsumer, ffAcceptedMatchers []string, rbAcceptedMatchers []string, logger logging.LoggerInterface, dedependencyEvaluator dependencyEvaluator) RuleBuilder {
return RuleBuilder{
segmentStorage: segmentStorage,
ruleBasedSegmentStorage: ruleBasedSegmentStorage,
largeSegmentStorage: largeSegmentStorage,
ffAcceptedMatchers: ffAcceptedMatchers,
rbAcceptedMatchers: rbAcceptedMatchers,
logger: logger,
dependencyEvaluator: dedependencyEvaluator,
}
}
func (r RuleBuilder) BuildMatcher(dto *dtos.MatcherDTO) (MatcherInterface, error) {
if !slices.Contains(r.ffAcceptedMatchers, dto.MatcherType) {
return nil, datatypes.UnsupportedMatcherError{
Message: fmt.Sprintf("Unable to create matcher for matcher type: %s", dto.MatcherType),
}
}
var matcher MatcherInterface
var attributeName *string
if dto.KeySelector != nil {
attributeName = dto.KeySelector.Attribute
}
switch dto.MatcherType {
case MatcherTypeAllKeys:
r.logger.Debug(fmt.Sprintf("Building AllKeysMatcher with negate=%t", dto.Negate))
matcher = NewAllKeysMatcher(dto.Negate)
case MatcherTypeEqualTo:
if dto.UnaryNumeric == nil {
return nil, errors.New("UnaryNumeric is required for EQUAL_TO matcher type")
}
r.logger.Debug(fmt.Sprintf(
"Building EqualToMatcher with negate=%t, value=%d, type=%s, attributeName=%v",
dto.Negate, dto.UnaryNumeric.Value, dto.UnaryNumeric.DataType, attributeName,
))
matcher = NewEqualToMatcher(
dto.Negate,
dto.UnaryNumeric.Value,
dto.UnaryNumeric.DataType,
attributeName,
)
case MatcherTypeInSegment:
if dto.UserDefinedSegment == nil {
return nil, errors.New("UserDefinedSegment is required for IN_SEGMENT matcher type")
}
r.logger.Debug(fmt.Sprintf(
"Building InSegmentMatcher with negate=%t, segmentName=%s, attributeName=%v",
dto.Negate, dto.UserDefinedSegment.SegmentName, attributeName,
))
matcher = NewInSegmentMatcher(
dto.Negate,
dto.UserDefinedSegment.SegmentName,
attributeName,
r.segmentStorage,
)
case MatcherTypeWhitelist:
if dto.Whitelist == nil {
return nil, errors.New("Whitelist is required for WHITELIST matcher type")
}
r.logger.Debug(fmt.Sprintf(
"Building WhitelistMatcher with negate=%t, whitelist=%v, attributeName=%v",
dto.Negate, dto.Whitelist.Whitelist, attributeName,
))
matcher = NewWhitelistMatcher(
dto.Negate,
dto.Whitelist.Whitelist,
attributeName,
)
case MatcherTypeGreaterThanOrEqualTo:
if dto.UnaryNumeric == nil {
return nil, errors.New("UnaryNumeric is required for GREATER_THAN_OR_EQUAL_TO matcher type")
}
r.logger.Debug(fmt.Sprintf(
"Building GreaterThanOrEqualToMatcher with negate=%t, value=%d, type=%s, attributeName=%v",
dto.Negate, dto.UnaryNumeric.Value, dto.UnaryNumeric.DataType, attributeName,
))
matcher = NewGreaterThanOrEqualToMatcher(
dto.Negate,
dto.UnaryNumeric.Value,
dto.UnaryNumeric.DataType,
attributeName,
)
case MatcherTypeLessThanOrEqualTo:
if dto.UnaryNumeric == nil {
return nil, errors.New("UnaryNumeric is required for LESS_THAN_OR_EQUAL_TO matcher type")
}
r.logger.Debug(fmt.Sprintf(
"Building LessThanOrEqualToMatcher with negate=%t, value=%d, type=%s, attributeName=%v",
dto.Negate, dto.UnaryNumeric.Value, dto.UnaryNumeric.DataType, attributeName,
))
matcher = NewLessThanOrEqualToMatcher(
dto.Negate,
dto.UnaryNumeric.Value,
dto.UnaryNumeric.DataType,
attributeName,
)
case MatcherTypeBetween:
if dto.Between == nil {
return nil, errors.New("Between is required for BETWEEN matcher type")
}
r.logger.Debug(fmt.Sprintf(
"Building BetweenMatcher with negate=%t, start=%d, end=%d, type=%s, attributeName=%v",
dto.Negate, dto.Between.Start, dto.Between.End, dto.Between.DataType, attributeName,
))
matcher = NewBetweenMatcher(
dto.Negate,
dto.Between.Start,
dto.Between.End,
dto.Between.DataType,
attributeName,
)
case MatcherTypeEqualToSet:
if dto.Whitelist == nil {
return nil, errors.New("Whitelist is required for EQUAL_TO_SET matcher type")
}
r.logger.Debug(fmt.Sprintf(
"Building EqualToSetMatcher with negate=%t, set=%v, attributeName=%v",
dto.Negate, dto.Whitelist.Whitelist, attributeName,
))
matcher = NewEqualToSetMatcher(
dto.Negate,
dto.Whitelist.Whitelist,
attributeName,
)
case MatcherTypePartOfSet:
if dto.Whitelist == nil {
return nil, errors.New("Whitelist is required for PART_OF_SET matcher type")
}
r.logger.Debug(fmt.Sprintf(
"Building PartOfSetMatcher with negate=%t, set=%v, attributeName=%v",
dto.Negate, dto.Whitelist.Whitelist, attributeName,
))
matcher = NewPartOfSetMatcher(
dto.Negate,
dto.Whitelist.Whitelist,
attributeName,
)
case MatcherTypeContainsAllOfSet:
if dto.Whitelist == nil {
return nil, errors.New("Whitelist is required for CONTAINS_ALL_OF_SET matcher type")
}
r.logger.Debug(fmt.Sprintf(
"Building AllOfSetMatcher with negate=%t, set=%v, attributeName=%v",
dto.Negate, dto.Whitelist.Whitelist, attributeName,
))
matcher = NewContainsAllOfSetMatcher(
dto.Negate,
dto.Whitelist.Whitelist,
attributeName,
)
case MatcherTypeContainsAnyOfSet:
if dto.Whitelist == nil {
return nil, errors.New("Whitelist is required for CONTAINS_ANY_OF_SET matcher type")
}
r.logger.Debug(fmt.Sprintf(
"Building AnyOfSetMatcher with negate=%t, set=%v, attributeName=%v",
dto.Negate, dto.Whitelist.Whitelist, attributeName,
))
matcher = NewContainsAnyOfSetMatcher(
dto.Negate,
dto.Whitelist.Whitelist,
attributeName,
)
case MatcherTypeStartsWith:
if dto.Whitelist == nil {
return nil, errors.New("Whitelist is required for STARTS_WITH matcher type")
}
r.logger.Debug(fmt.Sprintf(
"Building StartsWithMatcher with negate=%t, set=%v, attributeName=%v",
dto.Negate, dto.Whitelist.Whitelist, attributeName,
))
matcher = NewStartsWithMatcher(
dto.Negate,
dto.Whitelist.Whitelist,
attributeName,
)
case MatcherTypeEndsWith:
if dto.Whitelist == nil {
return nil, errors.New("Whitelist is required for ENDS_WITH matcher type")
}
r.logger.Debug(fmt.Sprintf(
"Building EndsWithMatcher with negate=%t, set=%v, attributeName=%v",
dto.Negate, dto.Whitelist.Whitelist, attributeName,
))
matcher = NewEndsWithMatcher(
dto.Negate,
dto.Whitelist.Whitelist,
attributeName,
)
case MatcherTypeContainsString:
if dto.Whitelist == nil {
return nil, errors.New("Whitelist is required for CONTAINS_STRING matcher type")
}
r.logger.Debug(fmt.Sprintf(
"Building ContainsStringMatcher with negate=%t, set=%v, attributeName=%v",
dto.Negate, dto.Whitelist.Whitelist, attributeName,
))
matcher = NewContainsStringMatcher(
dto.Negate,
dto.Whitelist.Whitelist,
attributeName,
)
case MatcherTypeInSplitTreatment:
if dto.Dependency == nil {
return nil, errors.New("Dependency is required for IN_SPLIT_TREATMENT matcher type")
}
r.logger.Debug(fmt.Sprintf(
"Building DependencyMatcher with negate=%t, feature=%s, treatments=%v, attributeName=%v",
dto.Negate, dto.Dependency.Split, dto.Dependency.Treatments, attributeName,
))
matcher = NewDependencyMatcher(
dto.Negate,
dto.Dependency.Split,
dto.Dependency.Treatments,
r.dependencyEvaluator,
)
case MatcherTypeEqualToBoolean:
if dto.Boolean == nil {
return nil, errors.New("Boolean is required for EQUAL_TO_BOOLEAN matcher type")
}
r.logger.Debug(fmt.Sprintf(
"Building BooleanMatcher with negate=%t, value=%t, attributeName=%v",
dto.Negate, *dto.Boolean, attributeName,
))
matcher = NewBooleanMatcher(
dto.Negate,
dto.Boolean,
attributeName,
)
case MatcherTypeMatchesString:
if dto.String == nil {
return nil, errors.New("String is required for MATCHES_STRING matcher type")
}
r.logger.Debug(fmt.Sprintf(
"Building RegexMatcher with negate=%t, regex=%s, attributeName=%v",
dto.Negate, *dto.String, attributeName,
))
matcher = NewRegexMatcher(
dto.Negate,
*dto.String,
attributeName,
)
case MatcherEqualToSemver:
if dto.String == nil {
return nil, ErrInvalidEqualSemver
}
r.logger.Debug(fmt.Sprintf(
"Building EqualToSemverMatcher with negate=%t, regex=%s, attributeName=%v",
dto.Negate, *dto.String, attributeName,
))
matcher = NewEqualToSemverMatcher(
*dto.String,
dto.Negate,
attributeName,
r.logger,
)
case MatcherTypeGreaterThanOrEqualToSemver:
if dto.String == nil {
return nil, ErrInvalidGTOESemver
}
r.logger.Debug(fmt.Sprintf(
"Building GreaterThanOrEqualToSemverMatcher with negate=%t, semver=%s, attributeName=%v",
dto.Negate, *dto.String, attributeName,
))
matcher = NewGreaterThanOrEqualToSemverMatcher(
dto.Negate,
*dto.String,
attributeName,
r.logger,
)
case MatcherTypeLessThanOrEqualToSemver:
if dto.String == nil {
return nil, ErrInvalidLTOESemver
}
r.logger.Debug(fmt.Sprintf(
"Building LessThanOrEqualToSemverMatcher with negate=%t, regex=%s, attributeName=%v",
dto.Negate, *dto.String, attributeName,
))
matcher = NewLessThanOrEqualToSemverMatcher(
*dto.String,
dto.Negate,
attributeName,
r.logger,
)
case MatcherTypeBetweenSemver:
if dto.BetweenString.Start == nil || dto.BetweenString.End == nil {
return nil, ErrInvalidLBetweenSemver
}
r.logger.Debug(fmt.Sprintf(
"Building BetweenSemverMatcher with negate=%t, regexStart=%s, regexEnd=%s, attributeName=%v",
dto.Negate, *dto.BetweenString.Start, *dto.BetweenString.End, attributeName,
))
matcher = NewBetweenSemverMatcher(
*dto.BetweenString.Start,
*dto.BetweenString.End,
dto.Negate,
attributeName,
r.logger,
)
case MatcherTypeInListSemver:
if dto.Whitelist == nil {
return nil, ErrInvalidLInListSemver
}
r.logger.Debug(fmt.Sprintf(
"Building ErrInvalidLInListSemver with negate=%t, regex=%v, attributeName=%v",
dto.Negate, dto.Whitelist.Whitelist, attributeName,
))
matcher = NewInListSemverMatcher(
dto.Whitelist.Whitelist,
dto.Negate,
attributeName,
r.logger,
)
case MatcherTypeInLargeSegment:
if dto.UserDefinedLargeSegment == nil {
return nil, errors.New("UserDefinedLargeSegment is required for IN_LARGE_SEGMENT matcher type")
}
r.logger.Debug(fmt.Sprintf(
"Building InLargeSegmentMatcher with negate=%t, largeSegmentName=%s, attributeName=%v",
dto.Negate, dto.UserDefinedLargeSegment.LargeSegmentName, attributeName,
))
matcher = NewInLargeSegmentMatcher(
dto.Negate,
dto.UserDefinedLargeSegment.LargeSegmentName,
attributeName,
r.largeSegmentStorage,
)
case MatcherTypeInRuleBasedSegment:
if dto.UserDefinedSegment == nil {
return nil, errors.New("UserDefinedSegment is required for IN_RULE_BASED_SEGMENT matcher type")
}
r.logger.Debug(fmt.Sprintf(
"Building InRuleBasedSegmentMatcher with negate=%t, ruleBasedSegmentName=%s, attributeName=%v",
dto.Negate, dto.UserDefinedSegment.SegmentName, attributeName,
))
matcher = NewInRuleBasedSegmentMatcher(
dto.Negate,
dto.UserDefinedSegment.SegmentName,
attributeName,
r,
)
default:
return nil, datatypes.UnsupportedMatcherError{
Message: fmt.Sprintf("Unable to create matcher for matcher type: %s", dto.MatcherType),
}
}
matcher.base().logger = r.logger
return matcher, nil
}
func (r RuleBuilder) BuildPrerequistesMatchers(prerequistes []dtos.Prerequisite) *PrerequisitesMatcher {
return NewPrerequisitesMatcher(prerequistes, r.dependencyEvaluator)
}