Skip to content

Commit 2405567

Browse files
feat: Support non-fractional Integers as targeting key
1 parent 04fa28b commit 2405567

File tree

1 file changed

+63
-12
lines changed

1 file changed

+63
-12
lines changed

confidence-resolver/src/lib.rs

Lines changed: 63 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -635,15 +635,23 @@ impl<'a, H: Host> AccountResolver<'a, H> {
635635
Ok(())
636636
}
637637

638-
fn get_targeting_key(&self, targeting_key: &str) -> Result<Option<&str>, String> {
638+
fn get_targeting_key(&self, targeting_key: &str) -> Result<Option<String>, String> {
639639
let unit_value = self.get_attribute_value(targeting_key);
640640
match &unit_value.kind {
641641
None => Ok(None),
642642
Some(Kind::NullValue(_)) => Ok(None),
643-
Some(Kind::StringValue(string_unit)) => Ok(Some(string_unit)),
643+
Some(Kind::StringValue(string_unit)) => Ok(Some(string_unit.clone())),
644+
Some(Kind::NumberValue(num_value)) => {
645+
if num_value.is_finite() && num_value.fract() == 0.0 {
646+
Ok(Some(format!("{:.0}", num_value)))
647+
} else {
648+
Err("TargetingKeyError".to_string())
649+
}
650+
}
644651
_ => Err("TargetingKeyError".to_string()),
645652
}
646653
}
654+
647655
pub fn resolve_flag_name(&'a self, flag_name: &str) -> Option<ResolvedValue<'a>> {
648656
self.state
649657
.flags
@@ -675,15 +683,13 @@ impl<'a, H: Host> AccountResolver<'a, H> {
675683
} else {
676684
TARGETING_KEY
677685
};
678-
let unit_value = self.get_attribute_value(targeting_key);
679-
let unit = match &unit_value.kind {
680-
None => continue,
681-
Some(Kind::NullValue(_)) => continue,
682-
Some(Kind::StringValue(string_unit)) => string_unit,
683-
_ => return resolved_value.error(ResolveReason::TargetingKeyError),
686+
let unit: String = match self.get_targeting_key(targeting_key) {
687+
Ok(Some(u)) => u,
688+
Ok(None) => continue,
689+
Err(_) => return resolved_value.error(ResolveReason::TargetingKeyError),
684690
};
685691

686-
if !self.segment_match(segment, unit) {
692+
if !self.segment_match(segment, &unit) {
687693
// ResolveReason::SEGMENT_NOT_MATCH
688694
continue;
689695
}
@@ -712,7 +718,7 @@ impl<'a, H: Host> AccountResolver<'a, H> {
712718
resolved_value.attribute_fallthrough_rule(
713719
rule,
714720
&assignment.assignment_id,
715-
unit,
721+
&unit,
716722
);
717723
continue;
718724
}
@@ -721,7 +727,7 @@ impl<'a, H: Host> AccountResolver<'a, H> {
721727
rule,
722728
segment,
723729
&assignment.assignment_id,
724-
unit,
730+
&unit,
725731
)
726732
}
727733
rule::assignment::Assignment::Variant(
@@ -739,7 +745,7 @@ impl<'a, H: Host> AccountResolver<'a, H> {
739745
segment,
740746
variant,
741747
&assignment.assignment_id,
742-
unit,
748+
&unit,
743749
);
744750
}
745751
};
@@ -1591,6 +1597,51 @@ mod tests {
15911597
}
15921598
}
15931599

1600+
#[test]
1601+
fn test_targeting_key_integer_supported() {
1602+
let state =
1603+
ResolverState::from_proto(EXAMPLE_STATE.to_owned().into(), "confidence-demo-june");
1604+
1605+
// Using integer for visitor_id should be treated as string and work
1606+
let context_json = r#"{"visitor_id": 26}"#;
1607+
let resolver: AccountResolver<'_, L> = state
1608+
.get_resolver_with_json_context(SECRET, context_json, &ENCRYPTION_KEY)
1609+
.unwrap();
1610+
1611+
let flag = resolver
1612+
.state
1613+
.flags
1614+
.get("flags/fallthrough-test-2")
1615+
.unwrap();
1616+
let resolved_value = resolver.resolve_flag(flag);
1617+
1618+
assert_eq!(resolved_value.reason as i32, ResolveReason::Match as i32);
1619+
let assignment_match = resolved_value.assignment_match.unwrap();
1620+
assert_eq!(assignment_match.targeting_key, "26");
1621+
}
1622+
1623+
#[test]
1624+
fn test_targeting_key_fractional_rejected() {
1625+
let state =
1626+
ResolverState::from_proto(EXAMPLE_STATE.to_owned().into(), "confidence-demo-june");
1627+
1628+
// Fractional number for visitor_id should be rejected
1629+
let context_json = r#"{"visitor_id": 26.5}"#;
1630+
let resolver: AccountResolver<'_, L> = state
1631+
.get_resolver_with_json_context(SECRET, context_json, &ENCRYPTION_KEY)
1632+
.unwrap();
1633+
1634+
let flag = resolver
1635+
.state
1636+
.flags
1637+
.get("flags/fallthrough-test-2")
1638+
.unwrap();
1639+
let resolved_value = resolver.resolve_flag(flag);
1640+
1641+
assert_eq!(resolved_value.reason as i32, ResolveReason::TargetingKeyError as i32);
1642+
assert!(resolved_value.assignment_match.is_none());
1643+
}
1644+
15941645
// eq rules
15951646

15961647
#[test]

0 commit comments

Comments
 (0)