Documentation
¶
Overview ¶
Package evaluate provides local flag evaluation logic for the Flagmint Go SDK. It ports the flag-evaluator.ts logic from the JS SDK, enabling server-side applications to evaluate flags without a network round-trip.
Index ¶
- Variables
- func CoerceBool(v any) (bool, error)
- func CoerceFloat64(v any) (float64, error)
- func CoerceString(v any) (string, error)
- func HashPercent(input string) int
- func InRollout(key string, percentage float64) booldeprecated
- func MatchAll(rules []Condition, attrs map[string]any) bool
- func StableHash(s string) uint32deprecated
- func StringHash(s string) uint32
- func VariantForKey(key string, variants []string) stringdeprecated
- type Condition
- type Evaluator
- type FlagConfig
- type FlagType
- type LogicalOperator
- type Operator
- type Rollout
- type RolloutKind
- type Segment
- type TargetingRule
- type VariantWeight
- type Variation
Constants ¶
This section is empty.
Variables ¶
var ( // ErrMissingRolloutKey is returned when a rollout requires a stable user // key (kind+key or user_id) but none is present in the context. ErrMissingRolloutKey = errors.New("rollout requires stable user key (kind+key or user_id)") // ErrPercentageNonBoolean is returned when a percentage rollout is applied // to a non-boolean flag. Use variant rollout for multi-value flags. ErrPercentageNonBoolean = errors.New("percentage rollout is boolean-only; use variant rollout for multi-value flags") // ErrGradualNonBoolean is returned when a gradual rollout is applied to a // non-boolean flag. ErrGradualNonBoolean = errors.New("gradual rollout is boolean-only; use variant rollout for multi-value flags") // ErrMissingSegment is returned when a targeting rule references a segment // ID that is not present in FlagConfig.SegmentsByID. ErrMissingSegment = errors.New("targeting rule references unknown segment") // ErrMissingVariation is returned when a targeting rule or off-variation // ID references a variation that is not present in FlagConfig.VariationsByID. ErrMissingVariation = errors.New("targeting rule references unknown variation") // ErrMissingRollout is returned when a targeting rule references a rollout // ID that is not present in FlagConfig.Rollouts. ErrMissingRollout = errors.New("targeting rule references unknown rollout") // ErrInvalidVariantWeights is returned when variant rollout weights do not // sum to 100. ErrInvalidVariantWeights = errors.New("variant weights must sum to 100") )
Sentinel errors returned by the local evaluator. All evaluation errors are non-fatal; the caller should return the flag's fallback value and log the error rather than propagating it.
Functions ¶
func CoerceFloat64 ¶
CoerceFloat64 coerces v to a float64.
func HashPercent ¶
HashPercent returns a stable bucket value in [0, 99] for rollout bucketing. Two callers with the same input always receive the same bucket.
func InRollout
deprecated
InRollout returns true when the 0-based hash bucket for key falls within the [0, percentage) range (percentage expressed as 0–100).
Deprecated: uses FNV-1a (StableHash). New callers should use the Evaluator with a RolloutPercentage strategy, which uses StringHash for cross-SDK parity.
func MatchAll ¶
MatchAll returns true when every condition in rules matches attrs. Kept for backward compatibility; new code should use evaluateConditions.
func StableHash
deprecated
func StringHash ¶
StringHash produces a 32-bit hash identical to the npm `string-hash` package (djb2 variant). This is the hash used for rollout bucketing to guarantee cross-SDK consistency: a user bucketed at 30% in the JS SDK must land in the same bucket in the Go SDK.
func VariantForKey
deprecated
VariantForKey maps key to one of the provided variant names using a stable hash. The variants slice must be non-empty.
Deprecated: uses FNV-1a (StableHash). New callers should use the Evaluator with a RolloutVariant strategy, which uses StringHash for cross-SDK parity.
Types ¶
type Condition ¶
type Condition struct {
Attribute string `json:"attribute"`
Operator Operator `json:"operator"`
Value any `json:"value"`
}
Condition is a single attribute comparison in a targeting rule.
type Evaluator ¶
type Evaluator struct {
// contains filtered or unexported fields
}
Evaluator evaluates feature flags locally against FlagConfig objects. It is safe for concurrent use by multiple goroutines.
func NewEvaluator ¶
func NewEvaluator() *Evaluator
NewEvaluator returns a new Evaluator using the default slog logger.
func NewEvaluatorWithLogger ¶
NewEvaluatorWithLogger returns a new Evaluator with the provided logger.
func (*Evaluator) Evaluate ¶
Evaluate evaluates config against the pre-flattened context map flatCtx and returns the resulting flag value. flatCtx should be produced by calling EvaluationContext.Flatten() before passing here.
On any evaluation error (missing segment, bad config, etc.) the method returns the coerced default value and the error so the caller can log it. Evaluation never panics.
type FlagConfig ¶
type FlagConfig struct {
Key string `json:"key"`
Type FlagType `json:"type"`
IsActive bool `json:"is_active"`
DefaultValue any `json:"default_value"`
OffVariationID *string `json:"off_variation_id,omitempty"`
TargetingRules []TargetingRule `json:"targeting_rules,omitempty"`
Variations []Variation `json:"variations,omitempty"`
// Rollouts maps rollout ID → Rollout for targeting-rule lookups.
Rollouts map[string]*Rollout `json:"rollouts,omitempty"`
// VariationsByID is populated by HydrateVariations; not serialised.
VariationsByID map[string]Variation `json:"-"`
// SegmentsByID must be populated before calling Evaluate when any
// targeting rule has kind="segment". Not serialised.
SegmentsByID map[string]*Segment `json:"-"`
}
FlagConfig is the full flag configuration used for local evaluation. Deserialize from the server payload, then call HydrateVariations before passing to Evaluator.Evaluate.
func (*FlagConfig) HydrateVariations ¶
func (fc *FlagConfig) HydrateVariations()
HydrateVariations populates VariationsByID from the Variations slice. Call this once after deserialising a FlagConfig from JSON.
type LogicalOperator ¶
type LogicalOperator string
LogicalOperator determines how conditions are combined.
const ( LogicalAND LogicalOperator = "AND" LogicalOR LogicalOperator = "OR" LogicalNOT LogicalOperator = "NOT" )
type Operator ¶
type Operator string
Operator is a comparison operator used in targeting-rule conditions.
const ( OpEquals Operator = "eq" OpNotEquals Operator = "neq" OpContains Operator = "contains" OpNotContains Operator = "not_contains" OpGreaterThan Operator = "gt" OpLessThan Operator = "lt" OpIn Operator = "in" // OpNin is the "not in" operator. Values is expected to be []any. OpNin Operator = "nin" OpStartsWith Operator = "startsWith" OpEndsWith Operator = "endsWith" // OpExists is true when the attribute is present in the context and not nil. OpExists Operator = "exists" // OpNotExists is true when the attribute is absent from the context or nil. OpNotExists Operator = "not_exists" )
type Rollout ¶
type Rollout struct {
ID string `json:"id,omitempty"`
Strategy RolloutKind `json:"strategy"`
Percentage float64 `json:"percentage,omitempty"`
Salt string `json:"salt"`
Variants []VariantWeight `json:"variants,omitempty"`
TargetPercentage float64 `json:"target_percentage,omitempty"`
Increment float64 `json:"increment,omitempty"`
IntervalHours float64 `json:"interval_hours,omitempty"`
StartAt *time.Time `json:"start_at,omitempty"`
}
Rollout defines how flag values are distributed across users.
type RolloutKind ¶
type RolloutKind string
RolloutKind enumerates the supported rollout strategies.
const ( // RolloutOff disables the rollout; the flag returns its default value. RolloutOff RolloutKind = "off" // RolloutPercentage enables a flag for a stable percentage of users (boolean-only). RolloutPercentage RolloutKind = "percentage" // RolloutVariant distributes traffic across named variations using weighted buckets. RolloutVariant RolloutKind = "variant" // RolloutGradual slowly ramps a boolean flag from 0% to TargetPercentage over time. RolloutGradual RolloutKind = "gradual" )
type Segment ¶
type Segment struct {
ID string `json:"id"`
Rules []Condition `json:"rules"`
LogicalOp LogicalOperator `json:"logical_op"`
// Force, when true, causes the segment to always match regardless of conditions.
Force bool `json:"force"`
}
Segment is a reusable group of conditions evaluated as a unit.
type TargetingRule ¶
type TargetingRule struct {
ID string `json:"id"`
Kind string `json:"kind"` // "segment" | "custom"
OrderIndex int `json:"order_index"`
SegmentID string `json:"segment_id,omitempty"`
Conditions []Condition `json:"conditions,omitempty"`
LogicalOp LogicalOperator `json:"logical_op,omitempty"`
VariationID *string `json:"variation_id,omitempty"`
RolloutID *string `json:"rollout_id,omitempty"`
}
TargetingRule is a single rule in the targeting chain. Rules are evaluated in ascending OrderIndex order; the first match wins.
type VariantWeight ¶
type VariantWeight struct {
VariationID string `json:"variation_id"`
Weight float64 `json:"weight"`
}
VariantWeight pairs a variation with its traffic allocation weight (0–100).