-
Notifications
You must be signed in to change notification settings - Fork 587
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
Initial support for CompositeFilter class #3290
Conversation
firebase-firestore/src/main/java/com/google/firebase/firestore/Query.java
Show resolved
Hide resolved
firebase-firestore/src/main/java/com/google/firebase/firestore/Query.java
Outdated
Show resolved
Hide resolved
Coverage Report 1Affected ProductsNo changes between base commit (275b3eb) and merge commit (3a4eee8).Test Logs
Notes |
Size Report 1Affected Products
Test Logs
Notes |
|
||
/** @hide */ | ||
@RestrictTo(RestrictTo.Scope.LIBRARY) | ||
class FieldFilterData extends Filter { |
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.
s/FieldFilterData/Filter.UnaryFilter ?
We don't use non-public classes: https://engdoc.corp.google.com/eng/doc/devguide/java/style/index.md?cl=head#s3.4.1-one-top-level-class. You can make this an inner class instead.
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.
Using an inner class now.
I don't want to use UnaryFilter as it could get confused with
firebase-android-sdk/firebase-firestore/src/proto/google/firestore/v1/query.proto
Lines 168 to 170 in ac3276c
// A filter with a single operand. | |
message UnaryFilter { | |
// A unary operator. |
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.
There is also already a FieldFilter class. Between two FieldFilters and two UnaryFilters, I would pick two UnaryFilters as the naming UnaryFilter vs CompositeFilter offers clear and obvious distinctions.
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.
Pinging this once more as I find the current naming a bit hard to follow. It is not obvious to me that a CompositeFilter is not a FieldFilter.
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.
Done
firebase-firestore/src/main/java/com/google/firebase/firestore/Filter.java
Outdated
Show resolved
Hide resolved
private final FieldFilter.Operator operator; | ||
private final Object value; | ||
|
||
public FieldFilterData(@NonNull FieldPath field, FieldFilter.Operator operator, Object value) { |
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 am not 100% certain but it seems like we don't use @NonNull
in non-public methods, so I would drop it here and below. NonNull is assumed to be the default.
While we are at it "value" is nullable though.
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.
Done
@@ -387,15 +388,17 @@ public Query whereNotIn(@NonNull FieldPath fieldPath, @NonNull List<? extends Ob | |||
} | |||
|
|||
/** | |||
* Parses the given value object and creates a new {@code FieldFilter} with the given field, | |||
* operator, and value. Also performs validation on the filter before retuning it. | |||
* Takes a {@code FieldFilterData} object, parses the value object and returns a new {@code |
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.
* Takes a {@code FieldFilterData} object, parses the value object and returns a new {@code | |
* Takes a {@link FieldFilterData} object, parses the value object and returns a new {@code |
That way, we can click on it and it gets renamed if we use IDE refactoring.
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.
Done
* @return The created {@code FieldFilter}. | ||
*/ | ||
private FieldFilter parseFieldFilter(@NonNull FieldPath fieldPath, Operator op, Object value) { | ||
@NonNull | ||
private FieldFilter parseFieldFilterData(@NonNull FieldFilterData fieldFilterData) { |
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.
Again, I think we can drop NonNull here, even though we are a bit inconsistent with the replaced method.
s/parseFieldFilterData/parseUnaryFilter
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.
Dropped NonNull. Don't think using UnaryFilter is a good idea.
public abstract List<FieldFilter> getAllFieldFilters(); | ||
|
||
/** Returns the field of the first filter that's an inequality, or null if none. */ | ||
public abstract FieldPath inequalityField(); |
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.
Please prefix with "get" (and possibly future-proof it by making it getFirstInequalityField
)
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.
Done
|
||
/** | ||
* Performs a depth-first search to find and return the first FieldFilter in the composite filter | ||
* that satisfies the condition. Returns null if none of the FieldFilters satisfy the condition. |
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.
* that satisfies the condition. Returns null if none of the FieldFilters satisfy the condition. | |
* that satisfies the condition. Returns {@code null} if none of the FieldFilters satisfy the condition. |
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.
Done
* Performs a depth-first search to find and return the first FieldFilter in the composite filter | ||
* that satisfies the condition. Returns null if none of the FieldFilters satisfy the condition. | ||
*/ | ||
private FieldFilter firstFieldFilterWhere(Function<FieldFilter, Boolean> condition) { |
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.
private FieldFilter firstFieldFilterWhere(Function<FieldFilter, Boolean> condition) { | |
@Nullable private FieldFilter firstFieldFilterWhere(Function<FieldFilter, Boolean> condition) { |
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.
Also, just because I can't help myself and to give you something to ignore: What about "findFirstMatchingFilter"? This method name could use a verb.
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.
lol. Done.
StringBuilder builder = new StringBuilder(); | ||
for (Filter filter : filters) { | ||
if (builder.length() == 0) { | ||
builder.append(isConjunction() ? "and(" : "or("); | ||
} else { | ||
builder.append(","); | ||
} | ||
builder.append(filter.getCanonicalId()); | ||
} | ||
builder.append(")"); |
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.
You can use TextUtils.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.
Done
@Override | ||
public List<FieldFilter> getAllFieldFilters() { | ||
// This is already a field filter, so we return a list of size one. | ||
return Arrays.asList(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.
return Arrays.asList(this); | |
return Collections.singletonList(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.
Done
/retest |
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.
Some more minor comments. Thanks for the update.
|
||
/** @hide */ | ||
@RestrictTo(RestrictTo.Scope.LIBRARY) | ||
class FieldFilterData extends Filter { |
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.
There is also already a FieldFilter class. Between two FieldFilters and two UnaryFilters, I would pick two UnaryFilters as the naming UnaryFilter vs CompositeFilter offers clear and obvious distinctions.
public FieldPath getField() { | ||
return field; | ||
} | ||
static class FieldFilter extends Filter { |
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 not public and thus should not need the annotation. Same below.
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.
oops. Done.
return filter; | ||
} | ||
|
||
/** | ||
* Takes a {@link Filter.CompositeFilter} object, parses each of its subfilters, and a new {@link |
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.
Word missing before "a new". The return type in the comment is also not correct.
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.
Done
/** | ||
* Takes a {@link Filter.CompositeFilter} object, parses each of its subfilters, and a new {@link | ||
* CompositeFilter} that is constructed using the parsed values. Returns null if the given | ||
* Filter.CompositeFilter does not contain any subfilters. Returns a {@link FieldFilter} if the |
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.
Method no longer returns null.
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.
Done
query.filter(parseFieldFilter(filter.getField(), filter.getOperator(), filter.getValue())), | ||
firestore); | ||
com.google.firebase.firestore.core.Filter parsedFilter = parseFilter(filter); | ||
if (parsedFilter.getFlattenedFilters().isEmpty()) { |
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.
Would it be more efficient to call getFilters() here?
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, it would be. Good suggestion. Done.
* returns the first one that is, or null if none are. | ||
*/ | ||
@Nullable | ||
private Operator findFilterOperator( |
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.
s/findFilterOperator/findFilterByOperarator or findFilterWithOperator?
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.
Done
|
||
@Override | ||
public List<FieldFilter> getFlattenedFilters() { | ||
List<FieldFilter> result = new ArrayList<>(); |
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.
Would it make sense to memoize this result?
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 good suggestion. As of now we only invoke this once when validating the composite filter. If the next PRs add more invocations of this method, I think it's worth memoizing. I'll keep that in mind for future PRs.
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.
Please add TODO, otherwise we will never look at this code again.
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.
Done
@Override | ||
public String toString() { | ||
return getCanonicalId(); | ||
} |
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 probably also need equals() and hashCode()
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.
Also coming in next PRs.
public abstract List<FieldFilter> getFlattenedFilters(); | ||
|
||
/** Returns the field of the first filter that's an inequality, or null if none. */ | ||
public abstract FieldPath getFirstInequalityField(); |
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.
Add @Nullable
.
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.
Done.
/retest |
1 similar comment
/retest |
} | ||
|
||
/** | ||
* Returns the first inequality filter contained within this composite filter. Returns null if it |
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.
s/null/{@code null}
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.
Done
|
||
@Override | ||
public List<FieldFilter> getFlattenedFilters() { | ||
List<FieldFilter> result = new ArrayList<>(); |
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.
Please add TODO, otherwise we will never look at this code again.
/retest |
No description provided.