Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NO TASK] Fix oneOf comparisons for both Booleans and Numbers (#14) #54

Conversation

simondale00
Copy link
Contributor

context

Fixes oneOf and notOneOf evaluation for Number and Boolean types.

description

The targeting rule documentation states that oneOf is evaluated by casting booleans and numbers to a string.

However, there was a recent update to the SDK that changed the implementation of stringValue(); The method now returns null when the EppoValue is either a number or boolean type.

The proposed change does the following:

  • Casts fields using toString() instead of stringValue() when evaluating oneOf or notOneOf
  • Changes the string representation of a number to better reflect the numbers intended type
    • Since double is used internally, an intended integer value of 2 will be cast to a string as 2.0.
    • This didn't seem intuitive, so I updated the toString() method to better represent the number type.

Copy link
Collaborator

@aarsilv aarsilv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch @simondale00! Apologies for the SDK deviating from the documented behavior. Love the test cases you made that will prevent such a regression in the future 💪

My one suggestion is to add a comment to toString() indicating it is used for IN and NOT IN comparisons, and changes should be made with caution. (As toString() typically is not used in business logic)

@@ -118,7 +118,19 @@ public String toString() {
case STRING:
return this.stringValue;
case NUMBER:
return this.doubleValue.toString();
// By default, `String.valueOf(<double>)` will include at least one decimal place.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉 Appreciate the comment including the documentation link!

@@ -153,9 +153,9 @@ private static boolean evaluateCondition(
return Compare.compareRegex(value.stringValue(),
Pattern.compile(condition.value.stringValue()));
case ONE_OF:
return Compare.isOneOf(value.stringValue(), condition.value.arrayValue());
return Compare.isOneOf(value.toString(), condition.value.arrayValue());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏

case NOT_ONE_OF:
return !Compare.isOneOf(value.stringValue(), condition.value.arrayValue());
return !Compare.isOneOf(value.toString(), condition.value.arrayValue());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏

@@ -71,6 +71,44 @@ public void addOneOfCondition(Rule rule) {
addConditionToRule(rule, condition);
}

public void addOneOfConditionWithIntegers(Rule rule) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙌

addConditionToRule(rule, condition);
}

public void addOneOfConditionWithDoubles(Rule rule) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙌

addConditionToRule(rule, condition);
}

public void addOneOfConditionWithBoolean(Rule rule) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙌

@simondale00
Copy link
Contributor Author

My one suggestion is to add a comment to toString() indicating it is used for IN and NOT IN comparisons, and changes should be made with caution.

Done! Thanks for the quick feedback.

(As toString() typically is not used in business logic)

I waffled on putting the change here for this exact reason. TBH I'd be just as happy to move this to a helper function.

Longer term it also may be worth exploring the behaviour of IN and NOT IN for number types. For example, the string representations of 2.0 and 2 would not be considered equivalent, despite the fact they are numerically equivalent. We haven't run into this specific problem, but I could see this being confusing to users that have less insight into the implementation.

@aarsilv
Copy link
Collaborator

aarsilv commented May 14, 2024

TBH I'd be just as happy to move this to a helper function.

I thought about this too but realized we'd just be re-implemting toString()

Longer term it also may be worth exploring the behaviour of IN and NOT IN for number types. For example, the string representations of 2.0 and 2 would not be considered equivalent, despite the fact they are numerically equivalent. We haven't run into this specific problem, but I could see this being confusing to users that have less insight into the implementation.

Agree. I think at some point we may want to consider making it loose comparisons (e.g., "4" == 4 == 4.0) as this would probably be more intuitive. However, for now, I figure sticking with the documentation of casting to string will be the least disruptive for now.

Thanks for iterating and adding the comment! Happy to merge, we just need to bump the version in pom.xml:

<version>2.4.3</version>

@aarsilv aarsilv merged commit c0b70f1 into Eppo-exp:main May 15, 2024
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants