Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions dtos/configmapper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package dtos

// ConvertConfigToSplit converts a ConfigDTO to a SplitDTO
func ConvertConfigToSplit(config ConfigDTO) SplitDTO {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you need to extract variants element as well, see comment below

// Apply defaults
trafficTypeName := config.TrafficTypeName
if trafficTypeName == "" {
trafficTypeName = "user"
}

status := config.Status
if status == "" {
status = "ACTIVE"
}

defaultTreatment := config.DefaultTreatment
if defaultTreatment == "" {
defaultTreatment = "default"
}

// Handle conditions - create default if empty
conditions := config.Conditions
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

based on the last structure, the conditions are under targeting element
[
{
"name": "SomeConfig1",
"variants": [
{
"name": "v1",
"definition": {
"prop1": true,
"prop2": 123
}
},
{
"name": "v2",
"definition": {
"prop1": false,
"prop2": 456
}
}
],
"targeting": {
"conditions": [
{
"variant": "v1",
"label": "main condition",
"matchers": [
{
"type": "IS_EQUAL_TO",
"data": {
"type": "NUMBER",
"number": 42
},
"attribute": "age"
},
{
"type": "WHITELIST",
"data": {
"strings": [
"a",
"b",
"c"
]
},
"attribute": "favoriteCharacter"
}
]
}
]
}
}
]

if len(conditions) == 0 {
conditions = []ConditionDTO{
{
ConditionType: "ROLLOUT",
Label: "default rule",
MatcherGroup: MatcherGroupDTO{
Combiner: "AND",
Matchers: []MatcherDTO{
{
MatcherType: "ALL_KEYS",
Negate: false,
},
},
},
Partitions: []PartitionDTO{
{
Treatment: defaultTreatment,
Size: 100,
},
},
},
}
}

return SplitDTO{
Name: config.Name,
Killed: config.Killed,
ChangeNumber: config.ChangeNumber,
Configurations: config.Configurations,
DefaultTreatment: defaultTreatment,
TrafficTypeName: trafficTypeName,
Status: status,
Algo: 2,
Seed: config.Seed,
TrafficAllocation: config.TrafficAllocation,
TrafficAllocationSeed: config.TrafficAllocationSeed,
Conditions: conditions,
}
}
89 changes: 89 additions & 0 deletions dtos/configs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package dtos

import "encoding/json"

// ConfigDTO represents a configuration definition fetched from the /configs endpoint
type ConfigDTO struct {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, missing variants and targeting elements

Name string `json:"name"`
Status string `json:"status"`
Killed bool `json:"killed"`
TrafficTypeName string `json:"trafficTypeName"`
DefaultTreatment string `json:"defaultTreatment"`
ChangeNumber int64 `json:"changeNumber"`
TrafficAllocation int `json:"trafficAllocation"`
TrafficAllocationSeed int64 `json:"trafficAllocationSeed"`
Seed int64 `json:"seed"`
Configurations map[string]string `json:"configurations"`
Conditions []ConditionDTO `json:"conditions"`
}

// ConfigsDataDTO represents the configs data wrapper in the response
type ConfigsDataDTO struct {
Since int64 `json:"s"`
Till int64 `json:"t"`
Configs []ConfigDTO `json:"d"`
}

// ConfigsResponseDTO represents the response from the /configs endpoint
type ConfigsResponseDTO struct {
Configs ConfigsDataDTO `json:"configs"`
RBS []RuleBasedSegmentDTO `json:"rbs"`
}

// FFResponseConfigs implements FFResponse interface for configs endpoint responses
type FFResponseConfigs struct {
configsResponse ConfigsResponseDTO
}

// NewFFResponseConfigs creates a new FFResponseConfigs instance from JSON data
func NewFFResponseConfigs(data []byte) (FFResponse, error) {
var configsResponse ConfigsResponseDTO
err := json.Unmarshal(data, &configsResponse)
if err != nil {
return nil, err
}
return &FFResponseConfigs{
configsResponse: configsResponse,
}, nil
}

// NeedsAnotherFetch checks if another fetch is needed based on the since and till values
func (f *FFResponseConfigs) NeedsAnotherFetch() bool {
return f.configsResponse.Configs.Since == f.configsResponse.Configs.Till
}

// RuleBasedSegments returns the list of rule-based segments from the response
func (f *FFResponseConfigs) RuleBasedSegments() []RuleBasedSegmentDTO {
return f.configsResponse.RBS
}

// FeatureFlags returns the list of feature flags (splits) converted from configs
func (f *FFResponseConfigs) FeatureFlags() []SplitDTO {
splits := make([]SplitDTO, 0, len(f.configsResponse.Configs.Configs))
for _, config := range f.configsResponse.Configs.Configs {
splits = append(splits, ConvertConfigToSplit(config))
}
return splits
}

// FFTill returns the till value for feature flags
func (f *FFResponseConfigs) FFTill() int64 {
return f.configsResponse.Configs.Till
}

// RBTill returns the till value for rule-based segments
func (f *FFResponseConfigs) RBTill() int64 {
return f.configsResponse.Configs.Till
}

// FFSince returns the since value for feature flags
func (f *FFResponseConfigs) FFSince() int64 {
return f.configsResponse.Configs.Since
}

// RBSince returns the since value for rule-based segments
func (f *FFResponseConfigs) RBSince() int64 {
return f.configsResponse.Configs.Since
}

var _ FFResponse = (*FFResponseConfigs)(nil)
Loading
Loading