11# frozen_string_literal: true
22
3+ require_relative 'mappers/environment'
4+ require_relative 'mappers/identity'
5+ require_relative 'mappers/segments'
6+
37module Flagsmith
48 module Engine
59 module Evaluation
10+ # Mappers for converting between models and evaluation contexts
611 module Mappers
712 STRONGEST_PRIORITY = Float ::INFINITY
813 WEAKEST_PRIORITY = -Float ::INFINITY
@@ -12,12 +17,8 @@ module Mappers
1217 # @param override_traits [Array<Flagsmith::Engine::Identities::Trait>, nil] Optional override traits
1318 # @return [Hash] Evaluation context with environment, features, segments, and optionally identity
1419 def self . get_evaluation_context ( environment , identity = nil , override_traits = nil )
15- environment_context = map_environment_model_to_evaluation_context ( environment )
16- identity_context = identity ? map_identity_model_to_identity_context ( identity , override_traits ) : nil
17-
18- context = environment_context . dup
19- context [ :identity ] = identity_context if identity_context
20-
20+ context = map_environment_model_to_evaluation_context ( environment )
21+ context [ :identity ] = map_identity_model_to_identity_context ( identity , override_traits ) if identity
2122 context
2223 end
2324
@@ -26,85 +27,15 @@ def self.get_evaluation_context(environment, identity = nil, override_traits = n
2627 # @param environment [Flagsmith::Engine::Environment] The environment model
2728 # @return [Hash] Context with :environment, :features, and :segments keys
2829 def self . map_environment_model_to_evaluation_context ( environment )
29- environment_context = {
30- key : environment . api_key ,
31- name : environment . project . name
30+ context = {
31+ environment : Environment . build_environment_context ( environment ) ,
32+ features : Environment . build_features_context ( environment . feature_states ) ,
33+ segments : Segments . build_segments_context ( environment . project . segments )
3234 }
3335
34- # Map feature states to features hash
35- features = { }
36- environment . feature_states . each do |fs |
37- # Map multivariate values if present
38- variants = nil
39- if fs . multivariate_feature_state_values &.any?
40- variants = fs . multivariate_feature_state_values . map do |mv |
41- {
42- value : mv . multivariate_feature_option . value ,
43- weight : mv . percentage_allocation ,
44- priority : mv . id || uuid_to_big_int ( mv . mv_fs_value_uuid )
45- }
46- end
47- end
48-
49- feature_hash = {
50- key : fs . django_id &.to_s || fs . uuid ,
51- feature_key : fs . feature . id . to_s ,
52- name : fs . feature . name ,
53- enabled : fs . enabled ,
54- value : fs . get_value
55- }
56-
57- feature_hash [ :variants ] = variants if variants
58- priority = fs . feature_segment &.priority
59- feature_hash [ :priority ] = priority unless priority . nil?
60- feature_hash [ :metadata ] = { flagsmith_id : fs . feature . id }
61-
62- features [ fs . feature . name ] = feature_hash
63- end
64-
65- # Map segments from project
66- segments = { }
67- environment . project . segments . each do |segment |
68- overrides = segment . feature_states . map do |fs |
69- override_hash = {
70- key : fs . django_id &.to_s || fs . uuid ,
71- feature_key : fs . feature . id . to_s ,
72- name : fs . feature . name ,
73- enabled : fs . enabled ,
74- value : fs . get_value
75- }
76- override_hash [ :priority ] = fs . feature_segment . priority if fs . feature_segment &.priority
77- override_hash [ :metadata ] = { flagsmith_id : fs . feature . id }
78- override_hash
79- end
36+ context [ :segments ] . merge! ( Identity . map_overrides_to_segments ( environment . identity_overrides ) ) if environment . identity_overrides &.any?
8037
81- segments [ segment . id . to_s ] = {
82- key : segment . id . to_s ,
83- name : segment . name ,
84- rules : segment . rules . map { |rule | map_segment_rule_model_to_rule ( rule ) } ,
85- overrides : overrides ,
86- metadata : {
87- source : 'API' ,
88- flagsmith_id : segment . id
89- }
90- }
91- end
92-
93- # Map identity overrides to segments
94- if environment . identity_overrides &.any?
95- identity_override_segments = map_identity_overrides_to_segments ( environment . identity_overrides )
96- segments . merge! ( identity_override_segments )
97- end
98-
99- {
100- environment : environment_context ,
101- features : features ,
102- segments : segments
103- }
104- end
105-
106- def self . uuid_to_big_int ( uuid )
107- uuid . gsub ( '-' , '' ) . to_i ( 16 )
38+ context
10839 end
10940
11041 # Maps identity model to identity context
@@ -113,108 +44,23 @@ def self.uuid_to_big_int(uuid)
11344 # @param override_traits [Array<Flagsmith::Engine::Identities::Trait>, nil] Optional override traits
11445 # @return [Hash] Identity context with :identifier, :key, and :traits
11546 def self . map_identity_model_to_identity_context ( identity , override_traits = nil )
116- # Use override traits if provided, otherwise use identity's traits
117- traits = override_traits || identity . identity_traits
118-
119- # Map traits to a hash with trait key => trait value
120- traits_hash = { }
121- traits . each do |trait |
122- traits_hash [ trait . trait_key ] = trait . trait_value
123- end
124-
125- {
126- identifier : identity . identifier ,
127- key : identity . django_id &.to_s || identity . composite_key ,
128- traits : traits_hash
129- }
47+ Identity . build_environment_context ( identity , override_traits )
13048 end
13149
13250 # Maps segment rule model to rule hash
13351 #
13452 # @param rule [Flagsmith::Engine::Segments::Rule] The segment rule model
13553 # @return [Hash] Mapped rule with :type, :conditions, and :rules
13654 def self . map_segment_rule_model_to_rule ( rule )
137- result = {
138- type : rule . type
139- }
140-
141- # Map conditions if present
142- result [ :conditions ] = ( rule . conditions || [ ] ) . map do |condition |
143- { property : condition . property , operator : condition . operator , value : condition . value }
144- end
145-
146- result [ :rules ] = if rule . rules &.any?
147- rule . rules . map { |nested_rule | map_segment_rule_model_to_rule ( nested_rule ) }
148- else
149- [ ]
150- end
151-
152- result
55+ Segments . map_rule ( rule )
15356 end
15457
15558 # Maps identity overrides to segments
15659 #
15760 # @param identity_overrides [Array<Flagsmith::Engine::Identity>] Array of identity override models
15861 # @return [Hash] Segments hash for identity overrides
15962 def self . map_identity_overrides_to_segments ( identity_overrides )
160- segments = { }
161- features_to_identifiers = { }
162-
163- identity_overrides . each do |identity |
164- next if identity . identity_features . nil? || identity . identity_features . none?
165-
166- # Sort features by name for consistent hashing
167- sorted_features = identity . identity_features . to_a . sort_by { |fs | fs . feature . name }
168-
169- # Create override keys for hashing
170- overrides_key = sorted_features . map do |fs |
171- {
172- feature_key : fs . feature . id . to_s ,
173- name : fs . feature . name ,
174- enabled : fs . enabled ,
175- value : fs . get_value ,
176- priority : STRONGEST_PRIORITY ,
177- metadata : {
178- flagsmith_id : fs . feature . id
179- }
180- }
181- end
182-
183- # Create hash of the overrides to group identities with same overrides
184- overrides_hash = overrides_key . hash
185-
186- features_to_identifiers [ overrides_hash ] ||= { identifiers : [ ] , overrides : overrides_key }
187- features_to_identifiers [ overrides_hash ] [ :identifiers ] << identity . identifier
188- end
189-
190- # Create segments for each unique set of overrides
191- features_to_identifiers . each do |overrides_hash , data |
192- segment_key = "identity_override_#{ overrides_hash } "
193-
194- segments [ segment_key ] = {
195- key : segment_key ,
196- name : 'identity_override' ,
197- rules : [
198- {
199- type : 'ALL' ,
200- conditions : [
201- {
202- property : '$.identity.identifier' ,
203- operator : 'IN' ,
204- value : data [ :identifiers ]
205- }
206- ] ,
207- rules : [ ]
208- }
209- ] ,
210- metadata : {
211- source : 'identity_override'
212- } ,
213- overrides : data [ :overrides ]
214- }
215- end
216-
217- segments
63+ Identity . map_overrides_to_segments ( identity_overrides )
21864 end
21965 end
22066 end
0 commit comments