-
Notifications
You must be signed in to change notification settings - Fork 6
Choice rule payload validation #189
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
Conversation
|
update:
|
|
wip: pre-compiling operations |
a0d0c26 to
0993b77
Compare
|
update:
This is a lot more involved but a lot more strict/stringent update:
|
0993b77 to
07a1411
Compare
|
rubocop: command line and web have different opinions on whether a regex is freezable. one complains no matter what code I use here. un-wip: this seems to work |
fdab00e to
e1bce92
Compare
|
update:
update:
|
|
Can you add specs around these new classes? wondering if would catch the invalid namespace thing I found. |
e1bce92 to
4ff6108
Compare
|
update:
I commented out every line there, and the specs fail. So every one of those classes are tested |
|
Discussion: e.g.: |
| values = COMPARE_RULE.match(key) | ||
| return [key, DATA_RULES[values[2]], !!values[3]] if values |
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 think this would read better if the match was decomposed or perhaps if named captures were used instead of using values[2], values[3], etc.
Some other quetsions
- where is the prefix used (the
(String|Numeric|Boolean|Timestamp)part)? It seems to be ignored here. - The caller does
compare_key, klass = klass_params(payload), but this method returns 3 items, so is that a bug? Where did the 3rd param go with the path, and why isn't it being used?
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.
the current pattern for the states/command objects to parse the payload themselves.
Here, we need to parse the string to
The old code ignored the first part, so I continued to ignore it. I can see doing type checks or conversions.
returning 2 vs 3 is probably a bug. thanks
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.
- yes, we ignore the type prefix part and don't currently do data type conversion. (not sure if that is needed)
- changed this code. think all set.
Maybe, but this all feels overly complicated to me personally. I don't see why each of these can't be a simple method (or even just the original code the way it was). Just curious what problem you were trying to solve. I could see creating the classes to encapsulate a |
856fce4 to
1ceb8f4
Compare
|
sorry - this is for previous commit update:
|
|
update
|
49a5ec5 to
e5455a3
Compare
|
update:
update:
un-WIP: this is working, no more dependencies. want to either merge or just drop |
| class Data < Floe::Workflow::ChoiceRule | ||
| TYPES = ["String", "Numeric", "Boolean", "Timestamp", "Present", "Null"].freeze | ||
| COMPARES = ["Equals", "LessThan", "GreaterThan", "LessThanEquals", "GreaterThanEquals", "Matches"].freeze | ||
| OPERATIONS = TYPES.each_with_object({}) { |dt, a| a[dt] = :"is_#{dt.downcase}?" } \ |
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.
Line continuation is not needed
| OPERATIONS = TYPES.each_with_object({}) { |dt, a| a[dt] = :"is_#{dt.downcase}?" } \ | |
| OPERATIONS = TYPES.each_with_object({}) { |dt, a| a[dt] = :"is_#{dt.downcase}?" } |
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.
strange, thought I did this a while back. must have rebased it out of here.
It is back
| attr_reader :variable, :compare_key, :operation, :type, :compare_predicate, :path | ||
| attr_reader :variable, :compare_key, :operator, :type, :compare_predicate, :path |
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 is changing the "public" api - not a big deal if it's internal, but is anything else using this?
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.
we've been pretty lax on public and private api for these models.
Every attribute here is internal to this class only.
In a separate PR, do we want to circle through and mark private/public?
Would it buy us anything, or will it just make debugging more difficult?
Come to think of it, I think only Workflow and Context have a public api.
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.
No it's fine, I just wanted to make sure that was accounted for or not.
|
This PR got renamed? Having trouble following the history here. |
e5455a3 to
afab6ce
Compare
|
This was a PR with a ton of stuff. almost all of the stuff had been extracted (as you can see from the punch list at the top) Originally, the type checks ( I am not a fan of the non-grep style of update:
|
afab6ce to
b783324
Compare
| elsif (match_value = TYPE_CHECK.match(key)) | ||
| @compare_key = key | ||
| _operator, type = match_value.captures | ||
| _is, @operator = match_value.captures |
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.
If we don't need the Is, you can also just not capture it in the first place. i.e.
- TYPE_CHECK = /^(Is)(#{TYPES.join("|")})$/
+ TYPE_CHECK = /^Is(#{TYPES.join("|")})$/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.
@Fryguy Yes, totally agree that the Is does not need to be captured, and it is probably more resource intensive.
I like the parallelism:
- operations has
(String)(Equals),(String)(GreaterThan)(Path). - type check has
(Is)(String)
Where we have a type (i.e.: String) and a verb (e.g.: Is, Equals, GreaterThan).
| OPERATIONS = TYPES.each_with_object({}) { |dt, a| a[dt] = :"is_#{dt.downcase}?" } \ | ||
| .merge(COMPARES.each_with_object({}) { |op, a| a[op] = :"op_#{op.downcase}?" }).freeze | ||
| # e.g.: (Is)(String), (Is)(Present) | ||
| TYPE_CHECK = /^(Is)(#{TYPES.join("|")})$/ |
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 just noticed this now, so not for this PR, but instead of TYPES.join(|), you should probably use Regex.union(TYPES). Same goes for the OPERATION constant
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.
irb(main):006> /Is(#{['a', 'b'].join("|")})/
=> /Is(a|b)/
irb(main):008> /Is(#{Regexp.union(['a', 'b'])})/
=> /Is((?-mix:a|b))/Are these the same thing?
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 have a separate PR all set for this
|
I'm fine with the PR rename now that the scope has been narrowed - it was just confusing because the opening PR had this list of dependent PRs that seemed unrelated. |
|
@Fryguy I think there is a question that asks, do we want to even do this? A while ago, we used to have hashes that were manually created: I liked that simple lookup. Currently, those are arrays not hashes and we manually generate the methods on the fly. This PR suggests auto generating a hash, but maybe that is just overkill/un-necessary. Do we think a static hash makes this any more sense/grepable/readable? Or is there another way to make this more accessible? (Just put the operation comment at the beginning of every op_gt? kind of method?). Performance wise, allocation difference will be negligible. Not sure the best way to benchmark this - but doesn't seem worth the work to gauge this. |
38a20cf to
fe8a2db
Compare
fe8a2db to
a5d6f21
Compare
|
update
|
- No longer access workflow#payload out side of Workflow (ManageIQ#321) - Cache choice rule operations (ManageIQ#189) - Fix `Context#==` to compare contents (ManageIQ#317) - Declare active support dependency (ManageIQ#316)
Added - Declare active support dependency (#316) - Add Context equality comparison (#317) - Choice rule payload validation (#189) Changed - In ChoiceRule use Regexp.union (#323) - Remove special case for choice rule IsPresent (#322) - Rename data operation parameters (#324) - Refactor workflow state check to not use payload (#326) Fixed - Fix missing parameters in item_batcher_spec (#325)
alt to #187
Depend upon:
[WIP] Catch and display path errors #246Overview
Remove un-necessary string allocations. and symbol lookups
Most of the changes have already been pulled out and merged.
So if we don't like this, then that is fine.
Leaving this for legacy reasons
Overview
Choice does not quite behave the same as the AWS States Language reference implementation.
If you specify a
Paththat points to nothing or the wrong type, aws raises aStates.Runtime. In truth, the type checking is not the most consistent, but the missing path is always raised.Changes:
Nextpoints to a valid state.Variableand compare key values are the correct data type.Variableor compare key path values not not found or the wrong data type. It used to throw ruby exceptions."IsPresent": trueto detect values present rather than not null."Is*"comparisons now supporttrueandfalsevalues.Choicewith noDefaultprovided.