Skip to content

Commit

Permalink
feat(segment_anding): feature parity fixes and new logic for and-ing
Browse files Browse the repository at this point in the history
  • Loading branch information
yquansah committed Jul 27, 2023
1 parent efa7054 commit aa80f34
Show file tree
Hide file tree
Showing 11 changed files with 953 additions and 898 deletions.
8 changes: 4 additions & 4 deletions config/migrations/sqlite3/11_segment_anding.up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ CREATE TABLE IF NOT EXISTS rule_segments (
INSERT INTO rule_segments (rule_id, namespace_key, segment_key) SELECT id AS rule_id, namespace_key, segment_key FROM rules;

-- Create temporary rules table
CREATE TABLE IF NOT EXISTS rules_new (
CREATE TABLE IF NOT EXISTS rules_temp (
id VARCHAR(255) PRIMARY KEY UNIQUE NOT NULL,
flag_key VARCHAR(255) NOT NULL,
rank INTEGER DEFAULT 1 NOT NULL,
segment_match_type INTEGER DEFAULT 0 NOT NULL,
rule_segment_operator INTEGER DEFAULT 0 NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
namespace_key VARCHAR(255) NOT NULL DEFAULT 'default' REFERENCES namespaces ON DELETE CASCADE,
FOREIGN KEY (namespace_key, flag_key) REFERENCES flags (namespace_key, key) ON DELETE CASCADE
);

INSERT INTO rules_new (id, flag_key, rank, created_at, updated_at, namespace_key) SELECT id, flag_key, rank, created_at, updated_at, namespace_key FROM rules;
INSERT INTO rules_temp (id, flag_key, rank, created_at, updated_at, namespace_key) SELECT id, flag_key, rank, created_at, updated_at, namespace_key FROM rules;

DROP TABLE rules;

ALTER TABLE rules_new RENAME TO rules;
ALTER TABLE rules_temp RENAME TO rules;
7 changes: 6 additions & 1 deletion internal/server/evaluation/evaluation.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,17 @@ func (s *Server) variant(ctx context.Context, flag *flipt.Flag, r *rpcevaluation

ver := &rpcevaluation.VariantEvaluationResponse{
Match: resp.Match,
SegmentKey: resp.SegmentKey,
Reason: reason,
VariantKey: resp.Value,
VariantAttachment: resp.Attachment,
}

if resp.SegmentKey != "" {
ver.SegmentKey = resp.SegmentKey
} else if len(resp.SegmentKeys) > 0 {
ver.SegmentKeys = resp.SegmentKeys
}

return ver, nil
}

Expand Down
13 changes: 7 additions & 6 deletions internal/server/evaluation/legacy_evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,23 +134,24 @@ func (e *Evaluator) Evaluate(ctx context.Context, flag *flipt.Flag, r *flipt.Eva
segmentKeys = append(segmentKeys, k)
}

switch rule.RuleMatchType {
case flipt.RuleSegmentMatchType_OR_TYPE:
switch rule.RuleSegmentOperator {
case flipt.RuleSegmentOperator_OR_SEGMENT_OPERATOR:
if segmentMatches < 1 {
e.logger.Debug("did not match ANY segments")
continue
}
case flipt.RuleSegmentMatchType_AND_TYPE:
case flipt.RuleSegmentOperator_AND_SEGMENT_OPERATOR:
if len(rule.Segments) != segmentMatches {
e.logger.Debug("did not match ALL segments")
continue
}
}

// otherwise, this is our matching rule, determine the flag variant to return
// based on the distributions
// For legacy reasons of supporting SegmentKey.
if len(rule.Segments) < 2 {
resp.SegmentKey = rule.Segments[segmentKeys[0]].SegmentKey
resp.SegmentKey = segmentKeys[0]
} else {
resp.SegmentKeys = segmentKeys
}

distributions, err := e.store.GetEvaluationDistributions(ctx, rule.ID)
Expand Down
29 changes: 18 additions & 11 deletions internal/storage/sql/common/evaluation.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package common
import (
"context"
"database/sql"
"fmt"

sq "github.com/Masterminds/squirrel"
"go.flipt.io/flipt/internal/storage"
Expand All @@ -20,6 +21,7 @@ func (s *Store) GetEvaluationRules(ctx context.Context, namespaceKey, flagKey st
r.flag_key,
rss.segment_key,
rss.segment_match_type,
r.rule_segment_operator,
r.rank,
rss.constraint_id,
rss.constraint_type,
Expand Down Expand Up @@ -63,12 +65,13 @@ func (s *Store) GetEvaluationRules(ctx context.Context, namespaceKey, flagKey st
for rows.Next() {
var (
intermediateStorageRule struct {
ID string
NamespaceKey string
FlagKey string
SegmentKey string
SegmentMatchType flipt.MatchType
Rank int32
ID string
NamespaceKey string
FlagKey string
SegmentKey string
SegmentMatchType flipt.MatchType
RuleSegmentOperator flipt.RuleSegmentOperator
Rank int32
}
optionalConstraint optionalConstraint
)
Expand All @@ -79,6 +82,7 @@ func (s *Store) GetEvaluationRules(ctx context.Context, namespaceKey, flagKey st
&intermediateStorageRule.FlagKey,
&intermediateStorageRule.SegmentKey,
&intermediateStorageRule.SegmentMatchType,
&intermediateStorageRule.RuleSegmentOperator,
&intermediateStorageRule.Rank,
&optionalConstraint.Id,
&optionalConstraint.Type,
Expand All @@ -88,6 +92,8 @@ func (s *Store) GetEvaluationRules(ctx context.Context, namespaceKey, flagKey st
return rules, err
}

fmt.Println("***RULE SEGMENT OPERATOR***: ", intermediateStorageRule.RuleSegmentOperator)

if existingRule, ok := uniqueRules[intermediateStorageRule.ID]; ok {
var constraint storage.EvaluationConstraint
if optionalConstraint.Id.Valid {
Expand Down Expand Up @@ -115,11 +121,12 @@ func (s *Store) GetEvaluationRules(ctx context.Context, namespaceKey, flagKey st
} else {
// haven't seen this rule before
newRule := &storage.EvaluationRule{
ID: intermediateStorageRule.ID,
NamespaceKey: intermediateStorageRule.NamespaceKey,
FlagKey: intermediateStorageRule.FlagKey,
Rank: intermediateStorageRule.Rank,
Segments: make(map[string]*storage.EvaluationSegment),
ID: intermediateStorageRule.ID,
NamespaceKey: intermediateStorageRule.NamespaceKey,
FlagKey: intermediateStorageRule.FlagKey,
Rank: intermediateStorageRule.Rank,
RuleSegmentOperator: intermediateStorageRule.RuleSegmentOperator,
Segments: make(map[string]*storage.EvaluationSegment),
}

newRule.Segments[intermediateStorageRule.SegmentKey] = &storage.EvaluationSegment{
Expand Down
29 changes: 18 additions & 11 deletions internal/storage/sql/common/rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ func (s *Store) GetRule(ctx context.Context, namespaceKey, id string) (*flipt.Ru

rule = &flipt.Rule{}

err = s.builder.Select("id, namespace_key, flag_key, \"rank\", created_at, updated_at").
err = s.builder.Select("id, namespace_key, flag_key, \"rank\", rule_segment_operator, created_at, updated_at").
From("rules").
Where(sq.And{sq.Eq{"id": id}, sq.Eq{"namespace_key": namespaceKey}}).
QueryRowContext(ctx).
Scan(&rule.Id, &rule.NamespaceKey, &rule.FlagKey, &rule.Rank, &createdAt, &updatedAt)
Scan(&rule.Id, &rule.NamespaceKey, &rule.FlagKey, &rule.Rank, &rule.RuleSegmentOperator, &createdAt, &updatedAt)
)

if err != nil {
Expand Down Expand Up @@ -346,7 +346,13 @@ func (s *Store) CountRules(ctx context.Context, namespaceKey, flagKey string) (u

// CreateRule creates a rule
func (s *Store) CreateRule(ctx context.Context, r *flipt.CreateRuleRequest) (frule *flipt.Rule, err error) {
segmentKeys := append(append([]string{}, r.SegmentKey), r.SegmentKeys...)
segmentKeys := make([]string, 0)

if len(r.SegmentKeys) > 0 {
segmentKeys = append(segmentKeys, r.SegmentKeys...)
} else if r.SegmentKey != "" {
segmentKeys = append(segmentKeys, r.SegmentKey)
}

if r.NamespaceKey == "" {
r.NamespaceKey = storage.DefaultNamespace
Expand All @@ -355,13 +361,13 @@ func (s *Store) CreateRule(ctx context.Context, r *flipt.CreateRuleRequest) (fru
var (
now = timestamppb.Now()
rule = &flipt.Rule{
Id: uuid.Must(uuid.NewV4()).String(),
NamespaceKey: r.NamespaceKey,
FlagKey: r.FlagKey,
Rank: r.Rank,
SegmentMatchType: r.SegmentMatchType,
CreatedAt: now,
UpdatedAt: now,
Id: uuid.Must(uuid.NewV4()).String(),
NamespaceKey: r.NamespaceKey,
FlagKey: r.FlagKey,
Rank: r.Rank,
RuleSegmentOperator: r.RuleSegmentOperator,
CreatedAt: now,
UpdatedAt: now,
}
)

Expand All @@ -373,12 +379,13 @@ func (s *Store) CreateRule(ctx context.Context, r *flipt.CreateRuleRequest) (fru
if _, err := s.builder.
Insert("rules").
RunWith(tx).
Columns("id", "namespace_key", "flag_key", "\"rank\"", "created_at", "updated_at").
Columns("id", "namespace_key", "flag_key", "\"rank\"", "rule_segment_operator", "created_at", "updated_at").
Values(
rule.Id,
rule.NamespaceKey,
rule.FlagKey,
rule.Rank,
rule.RuleSegmentOperator,
&fliptsql.Timestamp{Timestamp: rule.CreatedAt},
&fliptsql.Timestamp{Timestamp: rule.UpdatedAt},
).
Expand Down
18 changes: 9 additions & 9 deletions internal/storage/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ const (
// EvaluationRule represents a rule and constraints required for evaluating if a
// given flagKey matches a segment
type EvaluationRule struct {
ID string
NamespaceKey string
FlagKey string
SegmentKey string
SegmentMatchType flipt.MatchType
Segments map[string]*EvaluationSegment
Rank int32
RuleMatchType flipt.RuleSegmentMatchType
Constraints []EvaluationConstraint
ID string
NamespaceKey string
FlagKey string
SegmentKey string
SegmentMatchType flipt.MatchType
Segments map[string]*EvaluationSegment
Rank int32
RuleSegmentOperator flipt.RuleSegmentOperator
Constraints []EvaluationConstraint
}

type EvaluationSegment struct {
Expand Down
Loading

0 comments on commit aa80f34

Please sign in to comment.