-
Notifications
You must be signed in to change notification settings - Fork 641
datastore: pagination changes #1295
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
|
This seems like a reasonable approach to me. Wouldn't this fit it with all the existing pagination + streaming infrastructure if we return a In the case of other |
Yes, we can do that, but I would still remove
I think I'm still seeing the value in returning var q = datastore.createQuery('Character')
.hasAncestor(ancestor)
.limit(5);
datastore.runQuery(q, function(err, firstEntities, nextQuery) {
// ... get the next results ...
datastore.runQuery(nextQuery, // ...to: var q = datastore.createQuery('Character')
.hasAncestor(ancestor)
.limit(5);
datastore.runQuery(q, function(err, firstEntities, nextQuery) {
// ... get the next results ...
q.start(info.endCursor).limit(q.limitVal - firstEntities.length);
datastore.runQuery(q, ...If the user only needs to know the start cursor of the next query for returning to the FE: var q = datastore.createQuery('Character')
.hasAncestor(ancestor)
.limit(5);
datastore.runQuery(q, function(err, firstEntities, nextQuery) {
hypotheticalHttpResponse.send({ startCursor: nextQuery.startVal });There's always the option of getting it from the raw response as well: datastore.runQuery(q, function(err, firstEntities, nextQuery, apiResponse) {
hypotheticalHttpResponse.send({ startCursor: apiResponse.batch.endCursor }); |
|
I'm confused about that test change: If we always continue the query when the backend returns |
|
Doesn't it get "MORE_RESULTS_AFTER_LIMIT"? |
|
Sorry if I misunderstood. The test checks that we only get 5 results first, then after the second query, we get the remaining. I was just duplicating the logic that we do (currently) when preparing the nextQuery: nextQuery.limit(limit - resp.batch.entityResults.length); |
|
Yes in that test |
|
So it's basically just a weird way of saying "remove the limit" then, right? The previous test didn't do that because it was done by |
|
I don't think so in this case. If you want to use this for paging, you would always set the same limit ("I want pages of size 50"). The logic for updating the limit and offset should only happen inside the clients and only when Clearing the limit after the first query is more like saying "I want the first 50 results, then after that I want all the results.". I don't think the client should make this easy -- if a user wants all the results, they should just not set a limit and ask for all the results. |
|
My mistake. It's just a fluke in this test case that it works. Ignoring the part where we always run |
|
That logic makes sense. I think though that it gets confusing that basically your first query handles an offset, but then we generate more queries that don't. I think we shouldn't try to handle so much in the client and just expose the cursors -- The user can make their own decision about how to treat the first page and 2-n pages differently. |
Can you elaborate on that? |
|
It makes sense in the case of |
|
Thanks. So at this point, you prefer this: var q = datastore.createQuery('Character')
.hasAncestor(ancestor)
.limit(5);
datastore.runQuery(q, function(err, firstEntities, info) {
// ... get the next results ...
var nextQuery = datastore.createQuery('Character')
.hasAncestor(ancestor)
.start(info.endCursor);
datastore.runQuery(q, ...I'm also a fan of forcing users to be explicit, but I do like providing sane defaults and making things as easy as possible. Isn't it a relatively safe assumption that if a user asked for 50, that they expect the "nextQuery" would be prepared to get the next 50? The user will always have the choice of creating a new query or simply overriding the limit if it's wrong. |
|
Possibly, but we are also assuming that they don't want an offset either. Since we are expecting them to not actually call this in the same context (given the httpresponse to the user and back), they'll likely need to recreate the query anyways. I would consider making it easy to issue the same query multiple times in the same request a non-goal of the client. It will encourage users to try managing batching themselves. Instead we should let the server handle it's own resource management. It will also make it easier to switch to a streaming setup in the future without changing how the customer interacts with the client. In particular, if we have a streaming RPC it would be less efficient to fetch entities in multiple batches as we'll have to create and tear down these connections, rather than streaming as many results as we can. |
|
Alright, I'll go forward with the info object and manual stream override of |
c787f53 to
7ed6f9d
Compare
|
@pcostell ptal! |
lib/datastore/index.js
Outdated
| * }; | ||
| * | ||
| * if (info.moreResults !== 'NO_MORE_RESULTS') { | ||
| * frontEndResponse.startCursor = info.endCursor; |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
7ed6f9d to
7528e09
Compare
|
@pcostell feel free to take another look. I believe I've covered everything we're going for. |
|
LGTM |
lib/datastore/index.js
Outdated
| * contacts: entities | ||
| * }; | ||
| * | ||
| * if (info.moreResults !== 'NO_MORE_RESULTS') { |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
|
@callmehiphop updated with the constant. |
d920615 to
d190a72
Compare
| return new entity.Int(value); | ||
| }; | ||
|
|
||
| Datastore.NO_MORE_RESULTS = 'NO_MORE_RESULTS'; |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
|
Added the other constants! |
lib/datastore/query.js
Outdated
| * @param {?string} callback.info.endCursor - Use this in a follow-up query to | ||
| * begin from where these results ended. | ||
| * @param {string} callback.info.moreResults - Datastore responds with one of: | ||
| * - `MORE_RESULTS_AFTER_LIMIT`: There *may* be more results after the |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
test/docs.js
Outdated
|
|
||
| function FakeExpress() { | ||
| return { | ||
| get: function() {} |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
* datastore: the changes * manually run runQuery as a stream * add tests * add early stream exit test conditions * move NO_MORE_RESULTS to constant * add other moreResults constants * link constants to constant docs * mock express * fakeexpress mock
* implementing mocha retries * feat: fixing formatting for implementing mocha retries * feat: adding mocha retries to sample tests * changing # of retries * redoing # of retries * changing retry logic * changing function syntax for timeouts * changing async syntax for timeouts * changing timeout on tests * remove timeouts
Fixes #1293
RE: #1260
RE: #1260 (comment)
To Dos
Changes:
autoPaginateis goneapiResponsefromrunandrunQueryis goneNOT_FINISHEDnextQueryobject, we return aninfoobject, which containsmoreResultsendCursor(if provided by Datastore)