Conversation
lcmartinez
left a comment
There was a problem hiding this comment.
This will be a great improvement to the library, thank you!
My comments/questions were mainly around testing/docs/readability. The approach seems sound to me, though.
| * Similar to {@link #addFilter} but removes all existing filters for {@code fieldName} first. | ||
| * | ||
| * @param fieldName | ||
| * Name as seen in the query; not multi-value proxies ("id", not "ids") |
There was a problem hiding this comment.
I see that our other addFilter (and similar) methods' docstrings don't include @param docs for the other params besides fieldName, but feels like it would be useful to briefly describe what filterEntryConditionCreator represents and does here, since it's a bit more complex.
| * @param fieldName | ||
| * Name as seen in the query; not multi-value proxies ("id", not "ids") | ||
| */ | ||
| public void addFilterEntryConditionCreatorExclusively(String fieldName, |
There was a problem hiding this comment.
Seems like there should be test coverage for this in ParsedQueryTest.
| } | ||
| } | ||
| return removed; | ||
| return combinedFilterEntry.removeAllFiltersFor(fieldName); |
There was a problem hiding this comment.
Looks like this cleans up a lot. Nice.
| @Target({ | ||
| ElementType.FIELD, ElementType.METHOD | ||
| }) | ||
| public @interface Aggregated { |
There was a problem hiding this comment.
It would be helpful to use this in one of the test model/entity classes to demonstrate how it's intended to be used.
There was a problem hiding this comment.
I actually ended up removing this in favor of updating FilterBy
There was a problem hiding this comment.
Ok cool, ok, so no need for this file anymore.
| for (JoinCondition joinCondition : joinConditions) { | ||
| if (joinCondition.isLeftJoin()) { | ||
| ((SelectJoinStep<?>) select).leftOuterJoin(joinCondition.getTable()).on(joinCondition.getCondition()); | ||
| ((SelectJoinStep<?>) select).leftJoin(joinCondition.getTable()).on(joinCondition.getCondition()); |
There was a problem hiding this comment.
Just to verify my understanding.. leftJoin is equivalent to leftOuterJoin right?
There was a problem hiding this comment.
leftOuterJoin is a convenience method for leftJoin. Seemed odd that we were inconsistent in some places so I cleaned this up.
| .getQueryName() | ||
| .equals(fieldName)); | ||
| boolean removedFromChildren = conditionCreators.stream() | ||
| .filter(cc -> cc instanceof CombinedFilterEntry) |
There was a problem hiding this comment.
It looks like you're doing this instanceof logic a lot to identify leaf nodes vs. combinations... would it be cleaner to add an isCombinedCondition helper (and/or isLeafCondition, or something like that) to FilterEntryConditionCreator that does the instanceof checks?
There was a problem hiding this comment.
I've removed most of these. I'll think about this some more but my knee jerk is that it seems odd to have helpers defined in the interface / higher level classes for checking if the instances are of a specific subclass type.
There was a problem hiding this comment.
Could be an actual interface method (i.e. not actually implemented in FilterEntryConditionCreator), where the implementation in CombinedFilterEntry simply returns false (not a leaf node) and the one in BoundFilterEntry returns true (is a leaf node).
There was a problem hiding this comment.
Ahh sorry, I missed your follow up here. Yea that doesn't seem so bad. I guess I'm not sure what it would buy though in the implementation. Every instanceOf check I do is right before a cast and I wouldn't feel comfortable casting without that anyways.
| return removedFromThis || removedFromChildren; | ||
| } | ||
|
|
||
| public Optional<BoundFilterEntry<T>> getFirstFilterForFieldName(String fieldName) { |
There was a problem hiding this comment.
I'm not sure I totally understand what a "first" filter means in this kind of tree structure, or what it's used for. It looks like it'll first look through all top-level "leaf" filters and then dive into the combined filters... Will that find the "first"?
What about using getFlattenedBoundFilterEntries for this?
There was a problem hiding this comment.
Yea this is a part of the API that was a little odd to maintain in the new structure. I think getFlattenedBoundFilterEntries should be fine actually.
| return maybeBfe; | ||
| } | ||
|
|
||
| public List<BoundFilterEntry<T>> getAllFiltersForFieldName(String fieldName) { |
There was a problem hiding this comment.
Again, what about using getFlattenedBoundFilterEntries() for this?
| .get(filterName))).findFirst(); | ||
| Optional<BoundFilterEntry<T>> filterEntryOptional = filterTable.rowKeySet().stream().filter(f -> Objects.equals(f | ||
| .getFieldName(), finalFieldName) && Objects.equals(f.getFilter(), UriParamParser.BY_NAME | ||
| .get(filterName))).findFirst(); |
| // Use reserved words instead of simple look-up to throw exception on disallowed fields | ||
| if (!filterEntryOptional.isPresent() || (!RESERVED_WORDS.contains(filterEntryOptional.get().getQueryName()) && !filterTable.contains(filterEntryOptional.get(), filterName))) { | ||
| if (!filterEntryOptional.isPresent() || (!RESERVED_WORDS.contains(filterEntryOptional.get().getQueryName()) && !filterTable | ||
| .contains(filterEntryOptional.get(), filterName))) { |
boulter
left a comment
There was a problem hiding this comment.
I'm not sure I grok all the details here as I haven't worked much in this repo, but I left a few comments. Is there an example of what the query string would look like that this would be able to parse?
| public ParsedQuery( | ||
| T boundQuerySpec, | ||
| Class<T> queryType, | ||
| List<BoundFilterEntry<T>> boundFilterEntries, |
There was a problem hiding this comment.
this is a breaking change, right?
There was a problem hiding this comment.
Nice catch, I'll fix
| .filter(cc -> cc instanceof CombinedFilterEntry) | ||
| .map(cc -> ((CombinedFilterEntry<T>) cc)) | ||
| .collect(Collectors.toList()); | ||
| for (CombinedFilterEntry<T> combinedFilterEntry : combinedFilterEntries) { |
There was a problem hiding this comment.
why collect to a list just to iterate over that list? You could just use map and findAny.
| import com.hubspot.httpql.FieldFactory; | ||
| import com.hubspot.httpql.QuerySpec; | ||
|
|
||
| public class CombinedFilterEntry<T extends QuerySpec> implements FilterEntryConditionCreator<T> { |
There was a problem hiding this comment.
Maybe this is just a FilterEntryClause or BooleanFilterEntryClause? Combined doesn't really give any more information about what it combines. Or maybe use "expression" or "term" if we're creating boolean syntax trees?
There was a problem hiding this comment.
I like the symmetry of the combined term with the CombinedCondition in jooq, which is really the plumbing of httpQL. Agree that FilterEntry doesn't make much sense so I went with CombinedConditionCreator instead
|
@boulter this isn't a change to actual parsing yet, there's a few more steps required for that. This is a step in that direction that will allow for modifying or augmenting |
| private final Class<T> queryType; | ||
|
|
||
| private final List<BoundFilterEntry<T>> boundFilterEntries; | ||
| private final CombinedConditionCreator<T> combinedFilterEntry; |
There was a problem hiding this comment.
should probably rename the variable here to match the new classname
| @Target({ | ||
| ElementType.FIELD, ElementType.METHOD | ||
| }) | ||
| public @interface Aggregated { |
There was a problem hiding this comment.
Ok cool, ok, so no need for this file anymore.
|
|
||
| String as() default ""; | ||
|
|
||
| Class<?> typeOverride() default void.class; |
There was a problem hiding this comment.
I'm actually not sure I understand what this annotation param does. Could you add it to the docstring above and to the tests?
| boundFilterEntries.add(boundColumn); | ||
| } | ||
|
|
||
| CombinedConditionCreator<T> combinedFilterEntry = new CombinedConditionCreator<>(Operator.AND, Lists.newArrayList(boundFilterEntries)); |
There was a problem hiding this comment.
Again you might want to rename the variable here to match the new class name.
|
Updated, thanks for the review all! Looking to merge this in the morning. |
Step 1 towards #4
Represents replaces the List on ParsedQuery with a CombinedFilterEntry. Which has an Operator (AND, OR) and itself has a List (which BoundFilterEntries now extend). This allows us to have nested complex where conditions as opposed to the previous simple ANDed list.
Other improvements