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
feat(firestore): implement limitToLast #2420
Conversation
Change-Id: Iac088306a1cc846bc27ab43aae0761c6d5350de1
Change-Id: Ib9d54c0f80af0368f8a4bd8ab77228e05cdd2bcf
Change-Id: Ib94fa125d7f3ec4bf1667228cc4ceccf726c3923
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.
@tritone or @codyoss Can either of you review this for the go implementation.
A query with limitToLast(n)
defined on it, should:
- invert any ordering defined on the query
- Send the query to the backend
- Read the
n
results into memory - Return a query result to the user with the results read back in 3 reversed
Due to the fact that this feature is dependency on buffering to memory, streaming results are not supported.
firestore/query.go
Outdated
@@ -569,8 +579,48 @@ func trunc32(i int) int32 { | |||
return int32(i) | |||
} | |||
|
|||
// Get returns an array of query's resulting documents. | |||
func (q Query) Get(ctx context.Context) ([]*DocumentSnapshot, error) { |
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.
To be consistent with Query.Documents , I wonder if this should be called GetAll
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 thought about that. The thing is that in other languages it's called just get()
. And GetAll()
is a method of an iterator, so it gives all the docs once instead of streaming/iterating them - that makes sense for an iterator, but I'm not sure about Query
. Anyway, I'm just explaining, if you think it should be renamed, I'll rename.
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.
Looks like pretty much all other get methods in cloud.google.com/go/firestore which return a slice are called GetAll, whereas Get() is used for a single Transaction or DocumentRef. From that perspective I think GetAll makes more sense.
Also, I feel like the fact that this method is being added to the surface for the library is a bigger change than what's implied by the title of the PR. Could you change the title to reflect this? I also think it would be good to add an example of how this would be used to examples_test.go for the docs.
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.
One more thing-- looking at this a little more closely I see that the following are now equivalent for a non-limitToLast query q
:
q.Get()
q.Documents().GetAll()
Do we have an opinion about which is preferred?
And really, is it necessary to have this duplication? (I guess the answer is yes with the current design because DocumentIterator doesn't have access to the Query fields. But in theory we could just add an unexported field there and pass it along I think-- this would mean that to do a limitToLast query you would also call q.Documents().GetAll()
, though it would mean that other DocumentIterator methods would then need to error if limitToLast were set to true).
Would be curious on your thoughts @BenWhitehead @codyoss
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 there isn't a semantic difference to how those methods execute, I suspect it's fine to have a single method. And if there is a uniform way for users to keep doing what they're used to doing to read results it's probably better to stick with that, than it is to try and have this implementation be uniform with the other languages.
The complexity with limitToLast
is that it has to buffer the up to n
results and flip the order in memory before return to the application. So, as long as that property can be ensured whichever way is fine with me.
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 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.
NP. As you mentioned before, I've added an unexported Query
field into DocumentIterator
and moved all the implementation into DocumentIterator.GetAll()
. Seems to me we're no more in need of an example (as there are no new methods added), and a separate test.
firestore/query.go
Outdated
|
||
q.limitToLast = false | ||
} | ||
docs, err := q.Documents(ctx).GetAll() |
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.
Should all this logic just happen within this method? @tritone Thoughts?
If we did this the err returned from calling Documents()
could instead be used to Documents.Next
.
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 I'm reading this correctly-- we will have flipped q.limitToLast to false before calling q.Documents, so there shouldn't be an error from q.Documents unless one is set by newQueryDocumentIterator, correct? It would just be equivalent to having L624-626 up here. Seems clearer in some ways to decouple these methods but I'm not super opinionated on this.
Change-Id: I7f8d59c20623d56a700c356e5c72e342e4f8a616
Change-Id: I8ecf940714704f30b7bc06181e466e84e1292495
Friendly ping |
I'll defer to @tritone for the rest of the review. I think I mentioned everything that I saw. |
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.
Apologies for the delay. I have a few comments and questions about the surface design here-- would appreciate thoughts.
return q | ||
} | ||
|
||
// LimitToLast returns a new Query that specifies the maximum number of last |
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.
Will this the meaning of this first / last results distinction be obvious to users of Firestore? @BenWhitehead
firestore/query.go
Outdated
@@ -569,8 +579,48 @@ func trunc32(i int) int32 { | |||
return int32(i) | |||
} | |||
|
|||
// Get returns an array of query's resulting documents. | |||
func (q Query) Get(ctx context.Context) ([]*DocumentSnapshot, error) { |
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.
Looks like pretty much all other get methods in cloud.google.com/go/firestore which return a slice are called GetAll, whereas Get() is used for a single Transaction or DocumentRef. From that perspective I think GetAll makes more sense.
Also, I feel like the fact that this method is being added to the surface for the library is a bigger change than what's implied by the title of the PR. Could you change the title to reflect this? I also think it would be good to add an example of how this would be used to examples_test.go for the docs.
firestore/query.go
Outdated
|
||
q.limitToLast = false | ||
} | ||
docs, err := q.Documents(ctx).GetAll() |
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 I'm reading this correctly-- we will have flipped q.limitToLast to false before calling q.Documents, so there shouldn't be an error from q.Documents unless one is set by newQueryDocumentIterator, correct? It would just be equivalent to having L624-626 up here. Seems clearer in some ways to decouple these methods but I'm not super opinionated on this.
firestore/query.go
Outdated
@@ -569,8 +579,48 @@ func trunc32(i int) int32 { | |||
return int32(i) | |||
} | |||
|
|||
// Get returns an array of query's resulting documents. | |||
func (q Query) Get(ctx context.Context) ([]*DocumentSnapshot, error) { |
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.
One more thing-- looking at this a little more closely I see that the following are now equivalent for a non-limitToLast query q
:
q.Get()
q.Documents().GetAll()
Do we have an opinion about which is preferred?
And really, is it necessary to have this duplication? (I guess the answer is yes with the current design because DocumentIterator doesn't have access to the Query fields. But in theory we could just add an unexported field there and pass it along I think-- this would mean that to do a limitToLast query you would also call q.Documents().GetAll()
, though it would mean that other DocumentIterator methods would then need to error if limitToLast were set to true).
Would be curious on your thoughts @BenWhitehead @codyoss
Change-Id: I58783a8cb39f5215e518cbe98772a07dc5c32691
Change-Id: I4427d9b1b48ec8549b1ead25e2b80d91b80fefb9
Change-Id: I0e9eaa202ed642e5aa38991b9e32a2020bcff2a5
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 implementation looks a lot cleaner, thanks @IlyaFaer ! A couple remaining questions I had.
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.
LGTM. @BenWhitehead @codyoss please take a final look before I merge?
LGTM |
Got verbal sign off from @BenWhitehead , so I'm going to go ahead and merge this. |
Your PR has attempted to merge for 3 hours. Please check that all required checks have passed, you have an automerge label, and that all your reviewers have approved the PR |
Support "limit to last" feature. This allows a query which will return only the final N results. See https://firebase.google.com/docs/reference/js/firebase.database.Query#limittolast
Closes #2419