-
Notifications
You must be signed in to change notification settings - Fork 21
feat!: Context Values support, getEvaluationResult
#184
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
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces support for context values and adds a new getEvaluationResult
API while removing legacy engine APIs. The changes involve a breaking refactor from Java 8 to Java 11 and introduces JSONPath-enabled context value evaluation.
Key changes:
- Introduces
EvaluationResult getEvaluationResult(EvaluationContext context)
API replacing old model-based APIs - Adds JSONPath support for context value evaluation and removes model-based segment evaluation
- Drops Java 8 support in favor of Java 11 minimum requirement
Reviewed Changes
Copilot reviewed 58 out of 58 changed files in this pull request and generated 5 comments.
Show a summary per file
File | Description |
---|---|
pom.xml | Updates Java version from 8 to 11, adds JsonPath dependency and code generation plugin |
src/main/java/com/flagsmith/flagengine/Engine.java | Replaces model-based feature evaluation with context-based evaluation using new API |
src/main/java/com/flagsmith/flagengine/segments/SegmentEvaluator.java | Refactors from model-based to context-based segment evaluation with JSONPath support |
src/main/java/com/flagsmith/mappers/EngineMappers.java | New mapper utility for converting JSON documents to engine contexts |
src/main/java/com/flagsmith/interfaces/IOfflineHandler.java | Breaking change: replaces EnvironmentModel with EvaluationContext |
src/test/java/com/flagsmith/flagengine/unit/segments/SegmentModelTest.java | Updates test to use new context-based evaluation instead of model-based |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
src/test/java/com/flagsmith/flagengine/unit/segments/SegmentModelTest.java
Show resolved
Hide resolved
|
||
@ParameterizedTest | ||
@MethodSource("identitiesInSegmentsPercentageSplit") | ||
public void testIdentityInSegmentPercentageSplitUsesDjangoId(Integer djangoId, String identifier, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Non blocking comments, since engine tests pass. These comments may or may not require attention.
P.S. Reviewing this on the iPad was frustratingly difficult, as is reading this Java codebase sometimes. I’m sorry for the somewhat poor review compared to my standards.
.filter(String.class::isInstance) | ||
.map(Object::toString) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is .map
here for typing? It looks redundant given the .filter
above.
if (!(contextValue instanceof Boolean) && contextValue != null) { | ||
contextValue = String.valueOf(contextValue); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why booleans are left out of the party here. 😞 Will .contains
below compare "true" == true
/ "false" == false
? Sorry I don't follow. Our whole boolean thing is already a bit of a party pooper.
Double divisor = Double.parseDouble(parts[0]); | ||
Double remainder = Double.parseDouble(parts[1]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to worry divisor
and remainder
could be non-numeric strings?
|| Boolean.FALSE.toString().equalsIgnoreCase(((String) str)); | ||
|| Boolean.TRUE.toString().equalsIgnoreCase((String.valueOf(str))) | ||
|| Boolean.FALSE.toString().equalsIgnoreCase((String.valueOf(str))) | ||
|| "1".equals(String.valueOf(str)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This final proposition here looks like cheating some specific test to pass. 😆
I admit I'm even more confused now. Sorry this may be correct as is and I just don't follow the "true" and "false" strings on steroids above.
(I don't mean to insult your code, or the previous author's)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(maybe lowkey I do but I don't mean any disrespect)
|
||
return segment; | ||
}).collect(Collectors.toList()); | ||
}).filter(Objects::nonNull).collect(Collectors.toList()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this to support typing?
} | ||
|
||
@Override | ||
public int hashCode() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | ||
|
||
@Override | ||
public boolean equals(Object other) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
metadata = MapperFactory.getMapper() | ||
.convertValue(flagResult.getMetadata(), FeatureMetadata.class); | ||
|
||
if (metadata == null || metadata.getFlagsmithId() == null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we expect metadata not to exist in a FlagResult
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I second that, as it's used internally and we seem to have an agreement on using them, I could see it required.
if (traits != null && !traits.isEmpty()) { | ||
for (Map.Entry<String, Object> entry : traits.entrySet()) { | ||
Object traitValue = entry.getValue(); | ||
// Handle TraitConfig-like objects (maps with "value" key) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just wondering: do we cover this in engine test data?
* @param environmentModel the environment model | ||
* @return the evaluation context | ||
*/ | ||
public static EvaluationContext mapEnvironmentToContext( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this a separate function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me overall. I share Evandro's confusion surrounding boolean management - some clarification could help, also to have other implementations ISO.
I added a comment on the modulo evaluator
return false; | ||
|
||
case MODULO: | ||
if (contextValue instanceof Number && conditionValue instanceof String) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we want to try parsing context value in case it's a numerical string ?
Contributes to #179.
In this PR, we:
EvaluationResult getEvaluationResult(EvaluationContext context)
and remove all of the old engine APIs.EngineMappers
class for engine-API data interop.EnvironmentModel
class, used byIOfflineHandler
, is no longer part ofcom.flagsmith.flagengine
package. Methods carrying the engine business logic and sub-models/fields not relevant to the SDK are removed.