Skip to content
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

Allow or filtering in source #12

Merged
merged 7 commits into from
Oct 5, 2018

Conversation

nbelisle11
Copy link
Contributor

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

  • Updating to latest basepom as we were way behind
  • Sorted poms as I was getting errors in the sortpom-maven-plugin for not sorted poms
  • Fixed deprecation warnings on Jackson and Throwables.propagte

Copy link

@lcmartinez lcmartinez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like there should be test coverage for this in ParsedQueryTest.

}
}
return removed;
return combinedFilterEntry.removeAllFiltersFor(fieldName);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this cleans up a lot. Nice.

@Target({
ElementType.FIELD, ElementType.METHOD
})
public @interface Aggregated {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be helpful to use this in one of the test model/entity classes to demonstrate how it's intended to be used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually ended up removing this in favor of updating FilterBy

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok cool, ok, so no need for this file anymore.

@@ -277,7 +277,7 @@ public String getFieldName(String name) {
select = selectFrom.from(table);
for (JoinCondition joinCondition : joinConditions) {
if (joinCondition.isLeftJoin()) {
((SelectJoinStep<?>) select).leftOuterJoin(joinCondition.getTable()).on(joinCondition.getCondition());
((SelectJoinStep<?>) select).leftJoin(joinCondition.getTable()).on(joinCondition.getCondition());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to verify my understanding.. leftJoin is equivalent to leftOuterJoin right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird wrapping here again.


// 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))) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And again 😄

Copy link
Contributor

@boulter boulter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

@@ -45,7 +43,7 @@
public ParsedQuery(
T boundQuerySpec,
Class<T> queryType,
List<BoundFilterEntry<T>> boundFilterEntries,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a breaking change, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch, I'll fix

.filter(cc -> cc instanceof CombinedFilterEntry)
.map(cc -> ((CombinedFilterEntry<T>) cc))
.collect(Collectors.toList());
for (CombinedFilterEntry<T> combinedFilterEntry : combinedFilterEntries) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@nbelisle11
Copy link
Contributor Author

@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 ParsedQuerys with more complex where conditions with nested OR clauses

@@ -30,7 +29,8 @@

private final Class<T> queryType;

private final List<BoundFilterEntry<T>> boundFilterEntries;
private final CombinedConditionCreator<T> combinedFilterEntry;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should probably rename the variable here to match the new classname

@Target({
ElementType.FIELD, ElementType.METHOD
})
public @interface Aggregated {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok cool, ok, so no need for this file anymore.

@@ -25,4 +25,6 @@
Class<? extends Filter>[] value();

String as() default "";

Class<?> typeOverride() default void.class;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm actually not sure I understand what this annotation param does. Could you add it to the docstring above and to the tests?

@@ -181,18 +191,20 @@ protected void buildOrderableFields(final Map<String, BeanPropertyDefinition> fi
boundFilterEntries.add(boundColumn);
}

CombinedConditionCreator<T> combinedFilterEntry = new CombinedConditionCreator<>(Operator.AND, Lists.newArrayList(boundFilterEntries));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again you might want to rename the variable here to match the new class name.

@nbelisle11
Copy link
Contributor Author

Updated, thanks for the review all! Looking to merge this in the morning.

@nbelisle11 nbelisle11 merged commit 0b0b65b into HubSpot:master Oct 5, 2018
@nbelisle11 nbelisle11 deleted the allowOrFilteringInSource branch October 5, 2018 14:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants