Skip to content

Commit 9d8e2d6

Browse files
authored
fix: SEGMENT_RULES_CONDITIONS_EXPLICIT_ORDERING_ENABLED does not affect rules (#5866)
1 parent 3018bec commit 9d8e2d6

5 files changed

Lines changed: 38 additions & 22 deletions

File tree

api/integrations/launch_darkly/services.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ def _create_segment_rule_for_segment(
352352
f" skipping for segment: {segment.name}",
353353
)
354354

355-
return parent_rule # type: ignore[no-any-return]
355+
return parent_rule
356356

357357

358358
def _create_feature_segment_from_clauses(

api/segments/models.py

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,26 @@
3232

3333
from .managers import LiveSegmentManager, SegmentManager
3434

35+
ModelT = typing.TypeVar("ModelT", bound=models.Model)
36+
3537
logger = logging.getLogger(__name__)
3638

3739

40+
class ConfiguredOrderManager(SoftDeleteExportableManager, models.Manager[ModelT]):
41+
def get_queryset(
42+
self,
43+
) -> models.QuerySet[ModelT]:
44+
# Effectively `<ModelT>.Meta.ordering = ("id",) if ... else ()`,
45+
# but avoid the weirdness of a setting-dependant migration
46+
# and having to reload everything in tests
47+
qs: models.QuerySet[ModelT]
48+
if settings.SEGMENT_RULES_CONDITIONS_EXPLICIT_ORDERING_ENABLED:
49+
qs = super().get_queryset().order_by("id")
50+
else:
51+
qs = super().get_queryset()
52+
return qs
53+
54+
3855
class Segment(
3956
LifecycleModelMixin, # type: ignore[misc]
4057
SoftDeleteExportableModel,
@@ -168,7 +185,8 @@ def copy_rules_and_conditions_from(self, source_segment: "Segment") -> None:
168185
cloned_rule.pk = None
169186
cloned_rule.uuid = uuid.uuid4()
170187
cloned_rule.segment = self if rule.segment else None
171-
cloned_rule.rule = rule_to_cloned_rule_map.get(rule.rule)
188+
if rule.rule in rule_to_cloned_rule_map:
189+
cloned_rule.rule = rule_to_cloned_rule_map[rule.rule]
172190
cloned_rule.save()
173191
rule_to_cloned_rule_map[rule] = cloned_rule
174192

@@ -217,6 +235,10 @@ class SegmentRule(
217235

218236
history_record_class_path = "segments.models.HistoricalSegmentRule"
219237

238+
objects: typing.ClassVar[ConfiguredOrderManager["SegmentRule"]] = (
239+
ConfiguredOrderManager()
240+
)
241+
220242
def __str__(self): # type: ignore[no-untyped-def]
221243
return "%s rule for %s" % (
222244
self.type,
@@ -241,21 +263,6 @@ def get_skip_create_audit_log(self) -> bool:
241263
return True
242264

243265

244-
class ConditionManager(SoftDeleteExportableManager):
245-
def get_queryset(
246-
self,
247-
) -> models.QuerySet["Condition"]:
248-
# Effectively `Condition.Meta.ordering = ("id",) if ... else ()`,
249-
# but avoid the weirdness of a setting-dependant migration
250-
# and having to reload everything in tests
251-
qs: models.QuerySet["Condition"]
252-
if settings.SEGMENT_RULES_CONDITIONS_EXPLICIT_ORDERING_ENABLED:
253-
qs = super().get_queryset().order_by("id")
254-
else:
255-
qs = super().get_queryset()
256-
return qs
257-
258-
259266
class Condition(
260267
SoftDeleteExportableModel,
261268
abstract_base_auditable_model_factory(["uuid"]), # type: ignore[misc]
@@ -299,7 +306,9 @@ class Condition(
299306
created_at = models.DateTimeField(null=True, auto_now_add=True)
300307
updated_at = models.DateTimeField(null=True, auto_now=True)
301308

302-
objects: typing.ClassVar[ConditionManager] = ConditionManager()
309+
objects: typing.ClassVar[ConfiguredOrderManager["Condition"]] = (
310+
ConfiguredOrderManager()
311+
)
303312

304313
def __str__(self) -> str:
305314
return "Condition for %s: %s %s %s" % (

api/tests/unit/environments/identities/test_unit_identities_views.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,9 @@ def test_identities_endpoint_returns_value_for_segment_if_rule_type_percentage_s
603603
)
604604
Condition.objects.create(
605605
operator=PERCENTAGE_SPLIT,
606-
value=(identity_percentage_value + (1 - identity_percentage_value) / 2) * 100.0,
606+
value=int(
607+
(identity_percentage_value + (1 - identity_percentage_value) / 2) * 100.0
608+
),
607609
rule=segment_rule,
608610
)
609611
feature_segment = FeatureSegment.objects.create(
@@ -654,7 +656,7 @@ def test_identities_endpoint_returns_default_value_if_rule_type_percentage_split
654656
)
655657
Condition.objects.create(
656658
operator=PERCENTAGE_SPLIT,
657-
value=identity_percentage_value / 2,
659+
value=int(identity_percentage_value / 2),
658660
rule=segment_rule,
659661
)
660662
feature_segment = FeatureSegment.objects.create(

api/tests/unit/segments/test_unit_segments_views.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -707,8 +707,9 @@ def test_update_segment_add_new_condition(
707707
assert response.status_code == status.HTTP_200_OK
708708

709709
assert nested_rule.conditions.count() == 2
710-
assert nested_rule.conditions.last().property == new_condition_property
711-
assert nested_rule.conditions.last().value == new_condition_value
710+
assert (expected_new_condition := nested_rule.conditions.last())
711+
assert expected_new_condition.property == new_condition_property
712+
assert expected_new_condition.value == new_condition_value
712713

713714

714715
def test_update_segment_versioned_segment(

infrastructure/aws/staging/ecs-task-definition-web.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,10 @@
217217
"name": "PROMETHEUS_ENABLED",
218218
"value": "True"
219219
},
220+
{
221+
"name": "SEGMENT_RULES_CONDITIONS_EXPLICIT_ORDERING_ENABLED",
222+
"value": "True"
223+
},
220224
{
221225
"name": "FLAGSMITH_ON_FLAGSMITH_SERVER_OFFLINE_MODE",
222226
"value": "False"

0 commit comments

Comments
 (0)