-
Notifications
You must be signed in to change notification settings - Fork 626
[WIP] Expose query constrains on the public Query class #178
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
Hi @rosariopfernandes. Thanks for your PR. I'm waiting for a firebase member to verify that this patch is reasonable to test. If it is, they should reply with I understand the commands that are listed here. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
@rosariopfernandes thanks for doing this so quickly! I know this is just a skeleton but I think one of the issues is that it now makes these classes part of the API:
So as @mikelehen said we'd have to find some way to serialize these into Strings or Integers or something before they could be exposed. |
@samtstern Thanks for kick-starting the discussion. I've pushed some changes to not expose the As for This is what the public Filter class would look like:
The same idea would apply for |
@rosariopfernandes Sorry for the silence on this. We had some discussion internally and agree that it would be useful to expose query constraints, but we'll want to be very deliberate about the additional API and it'll need to go through our internal API review process, which could take some time and back/forth. So if you want to push this forward, I'd say go for it with the following guidance:
Anyway, feel free to keep working on this PR (or you could write up a rough proposal in a comment if that's easier to start with), and let us know when it's in shape for us to look at again. Thanks! |
@mikelehen Thank you for your reply, I totally understand the delay. I'll proceed as instructed :) |
@mikelehen Sorry for the delay here... I duplicated the Filter class to avoid exposing the I think this is ready for review. |
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.
Sorry for the delay on this, and thanks again for putting it together!
I think this is generally very much like what we want, but I've flagged a number of things that I think need to be tweaked. There are also some things that we need to discuss more internally, which I've flagged with "note to self:" and you can ignore those for now.
If you're up for making the changes I suggest, that would be great. If you're not sure about anything, feel free to punt for the moment.
In any case, the next big step here will be for me to take what you've done, come up with JavaScript and iOS equivalent APIs, and then write it all up in a doc that then gets reviewed internally. I'll add this to my TODO list, but I can't promise when I'll get to it, so there may be more delays. I apologize in advance.
firebase-firestore/src/main/java/com/google/firebase/firestore/Filter.java
Outdated
Show resolved
Hide resolved
firebase-firestore/src/main/java/com/google/firebase/firestore/Filter.java
Outdated
Show resolved
Hide resolved
|
||
@PublicApi | ||
public String getFieldPath() { | ||
return filter.getField().canonicalString(); |
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.
Returning the field path as a String
here using .canonicalString()
exposes the underlying backend representation of field paths which we don't currently expose in our API, specifically:
- Escaped field paths. i.e. If you do a query on
FieldPath.of("emails", "[email protected]")
then the string returned here will be something like"emails.`test@example\.com`"
(since we have to escape.
when it's contained within a field). - A query on
FieldPath.documentId()
will show up as"__name__"
here.
I need to discuss this with the team, but I think my suggestion would be to:
- Return
FieldPath
here instead ofString
- Add a
getSegments()
method toFieldPath
that returns a String[] containing the path segments. - Add a
isDocumentId()
method that returns a bool indicating whether the FieldPath is equal toFieldPath.documentId()
.
} | ||
|
||
@PublicApi | ||
public List<OrderBy> getExplicitOrderBy() { |
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.
Implicit vs explicit order-by is an internal implementation detail. So I think you can rename this to just getOrderBy().
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 reason why I had named it getExplicitOrderBy()
was to avoid conflicts with the existing getOrderBy()
, which is only used internally. So in order to differentiate the two:
getOrderBy()
becamegetInternalOrderBy()
getExplicityOrderBy()
becamegetOrderBy()
@@ -45,19 +50,28 @@ public Direction getDirection() { | |||
return direction; | |||
} | |||
|
|||
@NonNull | |||
@PublicApi | |||
public Query.Direction getSortDirection() { |
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'd drop "Sort" and just make this getDirection()
} | ||
|
||
@PublicApi | ||
public @Nullable String getStartAt() { |
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 getStartAt() / getEndAt() need to return Object
, like getFieldValue()
on Filter
does, so that you could pass the value back into .startAt(...)
to reconstruct the query... But we also need to be able to distinguish the lack of a startAt from the null
startAt. So we may need .hasStartAt()
that returns bool and .getStartAt()
that returns the Object
value of the startAt (and probably throws an exception if there is no startAt).
@PublicApi | ||
public Object getFieldValue() { | ||
if (isRelationFilter()) { | ||
return ((RelationFilter) filter).getValue().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.
This probably needs a bit of extra work to handle DocumentReference round-tripping. A public DocumentReference
will get parsed into a core.ReferenceValue
, but the result of calling .value()
on that is a DocumentKey
, not a DocumentReference
so we need to detect that and re-wrap it in a DocumentReference
(here and also in getStartAt(), getEndAt()).
} | ||
|
||
@PublicApi | ||
public List<com.google.firebase.firestore.Filter> getFilters() { |
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.
Note to self: Since we're exposing filters as Filter
objects, should we have a Query.addFilter(...)
method in order to re-construct the query? Else, you'd need to do a switch
on the operator and then call the appropriate Query.where...()
method to match the operator which would be tedious.
@@ -70,14 +71,22 @@ public String canonicalString() { | |||
return builder.toString(); | |||
} | |||
|
|||
public String getFieldValue() { |
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.
Per my comment on getStartAt() / getEndAt(), this should probably go away (we don't want / need the field value as a string).
@@ -900,6 +899,47 @@ private ListenerRegistration addSnapshotListenerInternal( | |||
firestore.getClient(), queryListener, activity, wrappedListener); | |||
} | |||
|
|||
@PublicApi | |||
public String getPath() { |
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.
Note to self: We need to figure out how we want to expose Collection Group queries (#233) in general.
FYI- After some internal discussion we do think it probably makes sense to additionally:
One additional question that came up was whether we should also be thinking about implementing Parcelable on these classes. Though that may not actually be feasible since a |
FWIW this PR would be really useful in situations like this PR I just got on FirebaseUI: The developer over there has basically re-implemented That's interesting that That said I think |
@samtstern Thanks! Yeah, the problem is essentially that |
all these changes were made according to feedback on the PR: - Rename Query.getExplicitOrderBy() to Query.getOrderBy() - Rename Filter.getFieldOperator() to getOperator() - Remove isNaNFilter() and isNullFilter() - Remove Bound.getFieldValue()
@mikelehen Apologies for the delay here, haven't had much time to work on this. I'll be pushing some commits to address your feedback from time to time, and I'll let you know when it's ready for another review. Your patience is appreciated. |
This PR is 4+ years old and my use case for this feature is no longer feasible (it relied on the Cloud Functions Spark plan). |
DO NOT MERGE
As discussed in #176, this is a skeleton PR (for discussion) that adds the API surface area.
cc:
@mikelehen
@samtstern
@wilhuff