Implement mostRecent search type for rules historical condition#1138
Conversation
8c9fc24 to
5fed783
Compare
| let semaphore = DispatchSemaphore(value: 0) | ||
|
|
||
| runtime.getHistoricalEvents(requestEvents, enforceOrder: searchType == .ordered) { results in | ||
| defer { semaphore.signal() } |
There was a problem hiding this comment.
This is unrelated to the mostRecent support, but I refactored the individual semaphore signals to use a defer instead in getHistoricalEventCount
Wondering if we should avoid making changes to what's not broken? (same question for the new params.count >= 3 to avoid index out of bounds errors (although based on the current code should be impossible))
There was a problem hiding this comment.
i'm with you on the "don't fix what's not broken" change. thoughts on both suggestions though:
- the defer looks like it's in the right spot and shouldn't change any functionality (our tests should confirm this!)
- i'm totally fine with a param count check on 205 - it doesn't change anything functionally but could serve as a fast fail if we don't have at least those 3 parameters we need.
similar to the comment made earlier in the review, i'm thinking that by using a switch statement inside of this callback we'd add some clarity to someone reading the code. what do you think about the idea of a little refactor?
There was a problem hiding this comment.
Doing the switch refactor really drove home the point that .mostRecent was being silently handled by the else case in the existing logic...
For this refactor, I made the following changes:
- Added an early exit for the unsupported
.mostRecenttype to return the error value of -1 (since 0 is a valid and specific meaning for that search type) - Converted the nested if/else's into a switch handling all cases without a default
- No
default, so that any future cases will cause a compiler error and need to be explicitly handled (much unlike how adding.mostRecenthad unnoticed potential side effects (although impossible with the current logic) - It does require a bit of redundancy to include the
mostRecenthere in the switch cases too, but I thought that the benefit of the compiler error point above outweighed this
- No
- The database error check has been turned into a guard instead
Please let me know what you think!
| init?(_ optionalValue: String?) { | ||
| guard let value = optionalValue, let enumValue = EventHistorySearchType(rawValue: value) else { | ||
| return nil | ||
| } | ||
| self = enumValue | ||
| } |
There was a problem hiding this comment.
nit: talk me into this.
it feels unnecessary, as the rawValue initializer is effectively doing the same thing
There was a problem hiding this comment.
As we discussed offline:
- Removed this custom init which was basically adding a lot of unnecessary infrastructure just to handle unwrapping a String
- Updated the search type to be even Swiftier 🤩 by using
flatMapon the definition’ssearchType, defaulting to.anywhen the value is either missing or fails to initialize a validEventHistorySearchType
| let historyOperand: Operand<Int> | ||
| if searchType == .mostRecent { | ||
| historyOperand = Operand<Int>(function: getMostRecentHistoricalEvent, parameters: params) | ||
| } else { | ||
| // .any or .ordered | ||
| historyOperand = Operand<Int>(function: getHistoricalEventCount, parameters: params) | ||
| } |
There was a problem hiding this comment.
we're handling 3 different kinds of search types at this point - a more robust solution here would be to use a switch statement. it also makes it more clear to the reader (via code) how each case is handled, rather than depending on comments
There was a problem hiding this comment.
Thanks, thats a great point - updated to switch instead
| let semaphore = DispatchSemaphore(value: 0) | ||
|
|
||
| runtime.getHistoricalEvents(requestEvents, enforceOrder: searchType == .ordered) { results in | ||
| defer { semaphore.signal() } |
There was a problem hiding this comment.
i'm with you on the "don't fix what's not broken" change. thoughts on both suggestions though:
- the defer looks like it's in the right spot and shouldn't change any functionality (our tests should confirm this!)
- i'm totally fine with a param count check on 205 - it doesn't change anything functionally but could serve as a fast fail if we don't have at least those 3 parameters we need.
similar to the comment made earlier in the review, i'm thinking that by using a switch statement inside of this callback we'd add some clarity to someone reading the code. what do you think about the idea of a little refactor?
| return returnValue | ||
| } | ||
|
|
||
| /// Returns the index of the most recent historical event based on occurrence date. |
There was a problem hiding this comment.
Thank you! Updated
| runtime.getHistoricalEvents(requestEvents, enforceOrder: false) { eventResults in | ||
| defer { semaphore.signal() } | ||
|
|
||
| for (index, result) in eventResults.enumerated() { |
…emove default value logging Replace search type operand handling with switch Refactor getHistoricalEventCount with switch instead of nested if else and add early exit guard for unsupported type Fix doc error
timkimadobe
left a comment
There was a problem hiding this comment.
Thanks so much for the review @sbenedicadb! Updated based on feedback
| init?(_ optionalValue: String?) { | ||
| guard let value = optionalValue, let enumValue = EventHistorySearchType(rawValue: value) else { | ||
| return nil | ||
| } | ||
| self = enumValue | ||
| } |
There was a problem hiding this comment.
As we discussed offline:
- Removed this custom init which was basically adding a lot of unnecessary infrastructure just to handle unwrapping a String
- Updated the search type to be even Swiftier 🤩 by using
flatMapon the definition’ssearchType, defaulting to.anywhen the value is either missing or fails to initialize a validEventHistorySearchType
| let historyOperand: Operand<Int> | ||
| if searchType == .mostRecent { | ||
| historyOperand = Operand<Int>(function: getMostRecentHistoricalEvent, parameters: params) | ||
| } else { | ||
| // .any or .ordered | ||
| historyOperand = Operand<Int>(function: getHistoricalEventCount, parameters: params) | ||
| } |
There was a problem hiding this comment.
Thanks, thats a great point - updated to switch instead
| let semaphore = DispatchSemaphore(value: 0) | ||
|
|
||
| runtime.getHistoricalEvents(requestEvents, enforceOrder: searchType == .ordered) { results in | ||
| defer { semaphore.signal() } |
There was a problem hiding this comment.
Doing the switch refactor really drove home the point that .mostRecent was being silently handled by the else case in the existing logic...
For this refactor, I made the following changes:
- Added an early exit for the unsupported
.mostRecenttype to return the error value of -1 (since 0 is a valid and specific meaning for that search type) - Converted the nested if/else's into a switch handling all cases without a default
- No
default, so that any future cases will cause a compiler error and need to be explicitly handled (much unlike how adding.mostRecenthad unnoticed potential side effects (although impossible with the current logic) - It does require a bit of redundancy to include the
mostRecenthere in the switch cases too, but I thought that the benefit of the compiler error point above outweighed this
- No
- The database error check has been turned into a guard instead
Please let me know what you think!
| return returnValue | ||
| } | ||
|
|
||
| /// Returns the index of the most recent historical event based on occurrence date. |
There was a problem hiding this comment.
Thank you! Updated
| let runtime = params[0] as? ExtensionRuntime, | ||
| let requestEvents = params[1] as? [EventHistoryRequest], | ||
| let searchType = params[2] as? EventHistorySearchType else { | ||
| return 0 |
There was a problem hiding this comment.
Also why does missing input values return 0? Isn't this an error case? Should getMostRecentHistoricalEvent not be returning -1 like it currently is in it's equivalent validation?
87934f4
into
adobe:feature/historical-consequence
Description
This PR implements the
mostRecentsearch type for rules historical condition, to support the requalification workflow.The
mostRecentsearch type is defined as follows:A new Operand function called
getMostRecentHistoricalEventhas been created to perform the most recent search, which requires as inputs:runtime: ExtensionRuntime- to call getHistoricalEventsrequestEvents: [EventHistoryRequest]- to know which events to compare to return most recentFor each event provided in the condition, it searches event history and returns the index of the event with the newest occurrence, or -1 if none exist or a database error was encountered.
getHistoricalEventCountimplementationAlso adds new warnings for early exit or fallback paths in the related
extractHistoricalConditionmethodAlternative implementations
Considered potentially concurrently dispatching the
getHistoricalEventsrequests. Doesn't make sense for two reasons:Related Issue
Motivation and Context
How Has This Been Tested?
Screenshots (if appropriate):
Types of changes
Checklist: