-
Notifications
You must be signed in to change notification settings - Fork 39
Runtime rules engine #54
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
Open
joshua-koehler
wants to merge
28
commits into
mixpanel:master
Choose a base branch
from
joshua-koehler:runtime-rules-engine
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
1bee4e4
add runtime eval rule; deprecate legacy one
joshua-koehler 5a322de
succint test harness
joshua-koehler 0361a6e
test should fail, but doesn't
joshua-koehler f5b2303
runtime rules engine basic exact match ❌
joshua-koehler 1cb4b98
add plumbing of method that doesn't work
joshua-koehler 6f981b7
try json logic - doesn't work yet
joshua-koehler 4bda0c3
simple exact match rule ✅
joshua-koehler d89a959
don't convert in a getter
joshua-koehler a0aebb3
case insensitive params ❌
joshua-koehler 9c3a9e6
wrap third-party lib, use util classes
joshua-koehler db94845
case-insensitive params ✅
joshua-koehler bea8b88
case insensitive rule ❌
joshua-koehler f175961
complex rule case insensitive ❌
joshua-koehler 507862a
simple case insensitive rule ✅
joshua-koehler a8ba289
evaluate complex rule case insensitive ✅
joshua-koehler 337e1b7
Add more tests for parity with other sdks ✅
joshua-koehler 5e585ac
log to stdout when running tests 💡
joshua-koehler 0bf760c
correct logging; remove TODO
joshua-koehler d74ddee
roll our own Map.of() for Java 8 support
joshua-koehler ebed7ff
Update src/main/java/com/mixpanel/mixpanelapi/featureflags/util/JsonL…
joshua-koehler eb9b950
Update src/main/java/com/mixpanel/mixpanelapi/featureflags/util/JsonC…
joshua-koehler 7157550
Update src/main/java/com/mixpanel/mixpanelapi/featureflags/provider/L…
joshua-koehler ce3117e
Update src/main/java/com/mixpanel/mixpanelapi/featureflags/model/Roll…
joshua-koehler 1e35fc7
docs; handle array inputs; memory management;
joshua-koehler 12334ff
Merge branch 'runtime-rules-engine' of github.com:joshua-koehler/mixp…
joshua-koehler a4fff2b
final var in supplier
joshua-koehler cbbe908
add test util (forgot the git add file)
joshua-koehler a817ed8
add case-insensitive util tests
joshua-koehler File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
60 changes: 60 additions & 0 deletions
60
src/main/java/com/mixpanel/mixpanelapi/featureflags/util/JsonCaseDesensitizer.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| package com.mixpanel.mixpanelapi.featureflags.util; | ||
|
|
||
| import java.util.Map; | ||
|
|
||
| /** | ||
| * Implements case-insensitive comparison for runtime evaluation rule definitions and runtime parameters. | ||
| */ | ||
| public class JsonCaseDesensitizer { | ||
| public static Object lowercaseLeafNodes(Object object) { | ||
| if (object == null) { | ||
| return null; | ||
| } | ||
| else if (object instanceof String){ | ||
| return ((String) object).toLowerCase(); | ||
| } else if (object instanceof org.json.JSONObject) { | ||
| org.json.JSONObject jsonObject = (org.json.JSONObject) object; | ||
| org.json.JSONObject result = new org.json.JSONObject(); | ||
| for (String key : jsonObject.keySet()) { | ||
| result.put(key, lowercaseLeafNodes(jsonObject.get(key))); | ||
| } | ||
| return result; | ||
| } else if (object instanceof org.json.JSONArray) { | ||
| org.json.JSONArray jsonArray = (org.json.JSONArray) object; | ||
| org.json.JSONArray result = new org.json.JSONArray(); | ||
| for (int i = 0; i < jsonArray.length(); i++) { | ||
| result.put(lowercaseLeafNodes(jsonArray.get(i))); | ||
| } | ||
| return result; | ||
| } else { | ||
| return object; | ||
| } | ||
| } | ||
| public static Object lowercaseAllNodes(Object object) { | ||
| if (object == null) { | ||
| return null; | ||
| } | ||
| else if (object instanceof String){ | ||
| return ((String) object).toLowerCase(); | ||
| } else if (object instanceof Map) { | ||
| Map<?, ?> map = (Map<?, ?>) object; | ||
| Map<Object, Object> result = new java.util.HashMap<>(); | ||
| for (Map.Entry<?, ?> entry : map.entrySet()) { | ||
| Object lowerKey = entry.getKey() instanceof String | ||
| ? ((String) entry.getKey()).toLowerCase() | ||
| : entry.getKey(); | ||
| result.put(lowerKey, lowercaseAllNodes(entry.getValue())); | ||
| } | ||
| return result; | ||
| } else if( object instanceof Iterable) { | ||
| Iterable<?> iterable = (Iterable<?>) object; | ||
| java.util.List<Object> result = new java.util.ArrayList<>(); | ||
| for (Object item : iterable) { | ||
| result.add(lowercaseAllNodes(item)); | ||
| } | ||
| return result; | ||
| } else { | ||
| return object; | ||
| } | ||
| } | ||
| } |
34 changes: 34 additions & 0 deletions
34
src/main/java/com/mixpanel/mixpanelapi/featureflags/util/JsonLogicEngine.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| package com.mixpanel.mixpanelapi.featureflags.util; | ||
|
|
||
| import java.util.HashMap; | ||
| import java.util.Map; | ||
| import java.util.logging.Level; | ||
|
|
||
| import org.json.JSONObject; | ||
|
|
||
| import io.github.jamsesso.jsonlogic.JsonLogic; | ||
|
|
||
| /** | ||
| * Wrapper for third-party library to evaluate JsonLogic DML rules. | ||
| */ | ||
| public class JsonLogicEngine { | ||
| private static final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(JsonLogicEngine.class.getName()); | ||
|
|
||
| private static final JsonLogic jsonLogic = new JsonLogic(); | ||
|
|
||
| public static boolean evaluate(JSONObject rule, Map<String, Object> data) { | ||
| if (data == null) { | ||
| data = new HashMap<>(); | ||
| } | ||
| Map<String, Object> lowercasedData = (Map<String, Object>) JsonCaseDesensitizer.lowercaseAllNodes(data); | ||
| try { | ||
| String ruleJson = JsonCaseDesensitizer.lowercaseLeafNodes(rule).toString(); | ||
| logger.log(Level.FINE, () -> "Evaluating JsonLogic rule: " + ruleJson + " with data: " + lowercasedData.toString()); | ||
| Object result = jsonLogic.apply(ruleJson, lowercasedData); | ||
| return JsonLogic.truthy(result); | ||
| } catch (Exception e) { | ||
| logger.log(Level.WARNING, "Error evaluating runtime rule", e); | ||
| return false; | ||
| } | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.