66from splitio .models .grammar .condition import ConditionType
77from splitio .models .grammar .matchers .misc import DependencyMatcher
88from splitio .models .grammar .matchers .keys import UserDefinedSegmentMatcher
9+ from splitio .models .grammar .matchers .rule_based_segment import RuleBasedSegmentMatcher
910from splitio .optional .loaders import asyncio
1011
1112CONTROL = 'control'
12- EvaluationContext = namedtuple ('EvaluationContext' , ['flags' , 'segment_memberships' ])
13+ EvaluationContext = namedtuple ('EvaluationContext' , ['flags' , 'segment_memberships' , 'segment_rbs_memberships' , 'segment_rbs_conditions' ])
1314
1415_LOGGER = logging .getLogger (__name__ )
1516
@@ -98,9 +99,10 @@ def _treatment_for_flag(self, flag, key, bucketing, attributes, ctx):
9899
99100class EvaluationDataFactory :
100101
101- def __init__ (self , split_storage , segment_storage ):
102+ def __init__ (self , split_storage , segment_storage , rbs_segment_storage ):
102103 self ._flag_storage = split_storage
103104 self ._segment_storage = segment_storage
105+ self ._rbs_segment_storage = rbs_segment_storage
104106
105107 def context_for (self , key , feature_names ):
106108 """
@@ -114,28 +116,50 @@ def context_for(self, key, feature_names):
114116 pending = set (feature_names )
115117 splits = {}
116118 pending_memberships = set ()
119+ pending_rbs_memberships = set ()
117120 while pending :
118121 fetched = self ._flag_storage .fetch_many (list (pending ))
119122 features = filter_missing (fetched )
120123 splits .update (features )
121124 pending = set ()
122125 for feature in features .values ():
123- cf , cs = get_dependencies (feature )
126+ cf , cs , crbs = get_dependencies (feature )
124127 pending .update (filter (lambda f : f not in splits , cf ))
125128 pending_memberships .update (cs )
126-
127- return EvaluationContext (splits , {
128- segment : self ._segment_storage .segment_contains (segment , key )
129- for segment in pending_memberships
130- })
131-
129+ pending_rbs_memberships .update (crbs )
130+
131+ rbs_segment_memberships = {}
132+ rbs_segment_conditions = {}
133+ key_membership = False
134+ segment_memberhsip = False
135+ for rbs_segment in pending_rbs_memberships :
136+ key_membership = key in self ._rbs_segment_storage .get (rbs_segment ).excluded .get_excluded_keys ()
137+ segment_memberhsip = False
138+ for segment_name in self ._rbs_segment_storage .get (rbs_segment ).excluded .get_excluded_segments ():
139+ if self ._segment_storage .segment_contains (segment_name , key ):
140+ segment_memberhsip = True
141+ break
142+
143+ rbs_segment_memberships .update ({rbs_segment : segment_memberhsip or key_membership })
144+ if not (segment_memberhsip or key_membership ):
145+ rbs_segment_conditions .update ({rbs_segment : [condition for condition in self ._rbs_segment_storage .get (rbs_segment ).conditions ]})
146+
147+ return EvaluationContext (
148+ splits ,
149+ { segment : self ._segment_storage .segment_contains (segment , key )
150+ for segment in pending_memberships
151+ },
152+ rbs_segment_memberships ,
153+ rbs_segment_conditions
154+ )
132155
133156class AsyncEvaluationDataFactory :
134157
135- def __init__ (self , split_storage , segment_storage ):
158+ def __init__ (self , split_storage , segment_storage , rbs_segment_storage ):
136159 self ._flag_storage = split_storage
137160 self ._segment_storage = segment_storage
138-
161+ self ._rbs_segment_storage = rbs_segment_storage
162+
139163 async def context_for (self , key , feature_names ):
140164 """
141165 Recursively iterate & fetch all data required to evaluate these flags.
@@ -148,23 +172,47 @@ async def context_for(self, key, feature_names):
148172 pending = set (feature_names )
149173 splits = {}
150174 pending_memberships = set ()
175+ pending_rbs_memberships = set ()
151176 while pending :
152177 fetched = await self ._flag_storage .fetch_many (list (pending ))
153178 features = filter_missing (fetched )
154179 splits .update (features )
155180 pending = set ()
156181 for feature in features .values ():
157- cf , cs = get_dependencies (feature )
182+ cf , cs , crbs = get_dependencies (feature )
158183 pending .update (filter (lambda f : f not in splits , cf ))
159184 pending_memberships .update (cs )
160-
185+ pending_rbs_memberships .update (crbs )
186+
161187 segment_names = list (pending_memberships )
162188 segment_memberships = await asyncio .gather (* [
163189 self ._segment_storage .segment_contains (segment , key )
164190 for segment in segment_names
165191 ])
166192
167- return EvaluationContext (splits , dict (zip (segment_names , segment_memberships )))
193+ rbs_segment_memberships = {}
194+ rbs_segment_conditions = {}
195+ key_membership = False
196+ segment_memberhsip = False
197+ for rbs_segment in pending_rbs_memberships :
198+ rbs_segment_obj = await self ._rbs_segment_storage .get (rbs_segment )
199+ key_membership = key in rbs_segment_obj .excluded .get_excluded_keys ()
200+ segment_memberhsip = False
201+ for segment_name in rbs_segment_obj .excluded .get_excluded_segments ():
202+ if await self ._segment_storage .segment_contains (segment_name , key ):
203+ segment_memberhsip = True
204+ break
205+
206+ rbs_segment_memberships .update ({rbs_segment : segment_memberhsip or key_membership })
207+ if not (segment_memberhsip or key_membership ):
208+ rbs_segment_conditions .update ({rbs_segment : [condition for condition in rbs_segment_obj .conditions ]})
209+
210+ return EvaluationContext (
211+ splits ,
212+ dict (zip (segment_names , segment_memberships )),
213+ rbs_segment_memberships ,
214+ rbs_segment_conditions
215+ )
168216
169217
170218def get_dependencies (feature ):
@@ -173,14 +221,17 @@ def get_dependencies(feature):
173221 """
174222 feature_names = []
175223 segment_names = []
224+ rbs_segment_names = []
176225 for condition in feature .conditions :
177226 for matcher in condition .matchers :
227+ if isinstance (matcher ,RuleBasedSegmentMatcher ):
228+ rbs_segment_names .append (matcher ._rbs_segment_name )
178229 if isinstance (matcher ,UserDefinedSegmentMatcher ):
179230 segment_names .append (matcher ._segment_name )
180231 elif isinstance (matcher , DependencyMatcher ):
181232 feature_names .append (matcher ._split_name )
182233
183- return feature_names , segment_names
234+ return feature_names , segment_names , rbs_segment_names
184235
185236def filter_missing (features ):
186237 return {k : v for (k , v ) in features .items () if v is not None }
0 commit comments