6
6
from splitio .models .grammar .condition import ConditionType
7
7
from splitio .models .grammar .matchers .misc import DependencyMatcher
8
8
from splitio .models .grammar .matchers .keys import UserDefinedSegmentMatcher
9
+ from splitio .models .grammar .matchers .rule_based_segment import RuleBasedSegmentMatcher
9
10
from splitio .optional .loaders import asyncio
10
11
11
12
CONTROL = 'control'
12
- EvaluationContext = namedtuple ('EvaluationContext' , ['flags' , 'segment_memberships' ])
13
+ EvaluationContext = namedtuple ('EvaluationContext' , ['flags' , 'segment_memberships' , 'segment_rbs_memberships' , 'segment_rbs_conditions' ])
13
14
14
15
_LOGGER = logging .getLogger (__name__ )
15
16
@@ -98,9 +99,10 @@ def _treatment_for_flag(self, flag, key, bucketing, attributes, ctx):
98
99
99
100
class EvaluationDataFactory :
100
101
101
- def __init__ (self , split_storage , segment_storage ):
102
+ def __init__ (self , split_storage , segment_storage , rbs_segment_storage ):
102
103
self ._flag_storage = split_storage
103
104
self ._segment_storage = segment_storage
105
+ self ._rbs_segment_storage = rbs_segment_storage
104
106
105
107
def context_for (self , key , feature_names ):
106
108
"""
@@ -114,28 +116,50 @@ def context_for(self, key, feature_names):
114
116
pending = set (feature_names )
115
117
splits = {}
116
118
pending_memberships = set ()
119
+ pending_rbs_memberships = set ()
117
120
while pending :
118
121
fetched = self ._flag_storage .fetch_many (list (pending ))
119
122
features = filter_missing (fetched )
120
123
splits .update (features )
121
124
pending = set ()
122
125
for feature in features .values ():
123
- cf , cs = get_dependencies (feature )
126
+ cf , cs , crbs = get_dependencies (feature )
124
127
pending .update (filter (lambda f : f not in splits , cf ))
125
128
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
+ )
132
155
133
156
class AsyncEvaluationDataFactory :
134
157
135
- def __init__ (self , split_storage , segment_storage ):
158
+ def __init__ (self , split_storage , segment_storage , rbs_segment_storage ):
136
159
self ._flag_storage = split_storage
137
160
self ._segment_storage = segment_storage
138
-
161
+ self ._rbs_segment_storage = rbs_segment_storage
162
+
139
163
async def context_for (self , key , feature_names ):
140
164
"""
141
165
Recursively iterate & fetch all data required to evaluate these flags.
@@ -148,23 +172,47 @@ async def context_for(self, key, feature_names):
148
172
pending = set (feature_names )
149
173
splits = {}
150
174
pending_memberships = set ()
175
+ pending_rbs_memberships = set ()
151
176
while pending :
152
177
fetched = await self ._flag_storage .fetch_many (list (pending ))
153
178
features = filter_missing (fetched )
154
179
splits .update (features )
155
180
pending = set ()
156
181
for feature in features .values ():
157
- cf , cs = get_dependencies (feature )
182
+ cf , cs , crbs = get_dependencies (feature )
158
183
pending .update (filter (lambda f : f not in splits , cf ))
159
184
pending_memberships .update (cs )
160
-
185
+ pending_rbs_memberships .update (crbs )
186
+
161
187
segment_names = list (pending_memberships )
162
188
segment_memberships = await asyncio .gather (* [
163
189
self ._segment_storage .segment_contains (segment , key )
164
190
for segment in segment_names
165
191
])
166
192
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
+ )
168
216
169
217
170
218
def get_dependencies (feature ):
@@ -173,14 +221,17 @@ def get_dependencies(feature):
173
221
"""
174
222
feature_names = []
175
223
segment_names = []
224
+ rbs_segment_names = []
176
225
for condition in feature .conditions :
177
226
for matcher in condition .matchers :
227
+ if isinstance (matcher ,RuleBasedSegmentMatcher ):
228
+ rbs_segment_names .append (matcher ._rbs_segment_name )
178
229
if isinstance (matcher ,UserDefinedSegmentMatcher ):
179
230
segment_names .append (matcher ._segment_name )
180
231
elif isinstance (matcher , DependencyMatcher ):
181
232
feature_names .append (matcher ._split_name )
182
233
183
- return feature_names , segment_names
234
+ return feature_names , segment_names , rbs_segment_names
184
235
185
236
def filter_missing (features ):
186
237
return {k : v for (k , v ) in features .items () if v is not None }
0 commit comments