Skip to content

Commit fb31c9c

Browse files
committed
support JSON-encoded IN condition values
1 parent 7fb2748 commit fb31c9c

File tree

3 files changed

+36
-4
lines changed

3 files changed

+36
-4
lines changed

flag_engine/context/mappers.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import json
12
import typing
23
from collections import defaultdict
34

@@ -122,7 +123,7 @@ def _map_identity_overrides_to_segment_contexts(
122123
{
123124
"property": "$.identity.identifier",
124125
"operator": "IN",
125-
"value": ",".join(identifiers),
126+
"value": json.dumps(identifiers),
126127
}
127128
],
128129
}

flag_engine/segments/evaluator.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import json
12
import operator
23
import re
34
import typing
@@ -322,12 +323,22 @@ def _evaluate_in(
322323
segment_value: typing.Optional[str], context_value: ContextValue
323324
) -> bool:
324325
if segment_value:
325-
if isinstance(context_value, str):
326-
return context_value in segment_value.split(",")
326+
try:
327+
in_values = json.loads(segment_value)
328+
# Only accept JSON lists.
329+
# Ideally, we should use something like pydantic.TypeAdapter[list[str]],
330+
# but we aim to ditch the pydantic dependency in the future.
331+
if not isinstance(in_values, list):
332+
raise ValueError
333+
in_values = [str(value) for value in in_values]
334+
except ValueError:
335+
in_values = segment_value.split(",")
336+
# Guard against comparing boolean values to numeric strings.
327337
if isinstance(context_value, int) and not any(
328338
context_value is x for x in (False, True)
329339
):
330-
return str(context_value) in segment_value.split(",")
340+
context_value = str(context_value)
341+
return context_value in in_values
331342
return False
332343

333344

tests/unit/segments/test_segments_evaluator.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,26 @@ def test_context_in_segment_is_set_and_is_not_set(
480480
(constants.IN, 1, "1", True),
481481
(constants.IN, 1, None, False),
482482
(constants.IN, 1, None, False),
483+
(constants.IN, "foo", "", False),
484+
(constants.IN, "foo", "foo,bar", True),
485+
(constants.IN, "bar", "foo,bar", True),
486+
(constants.IN, "foo", "foo", True),
487+
(constants.IN, 1, "1,2,3,4", True),
488+
(constants.IN, 1, "", False),
489+
(constants.IN, 1, "1", True),
490+
(constants.IN, 1, None, False),
491+
(constants.IN, 1, None, False),
492+
(constants.IN, "foo", "[]", False),
493+
(constants.IN, "foo", '["foo","bar"]', True),
494+
(constants.IN, "bar", '["foo","bar"]', True),
495+
(constants.IN, "foo", '["foo"]', True),
496+
(constants.IN, 1, "[1,2,3,4]", True),
497+
(constants.IN, 1, '["1","2","3","4"]', True),
498+
(constants.IN, 1, "[]", False),
499+
(constants.IN, 1, "[1]", True),
500+
(constants.IN, 1, '["1"]', True),
501+
(constants.IN, 1, None, False),
502+
(constants.IN, 1, None, False),
483503
),
484504
)
485505
def test_segment_condition_matches_context_value(

0 commit comments

Comments
 (0)