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

datastore: pagination changes #1295

Merged
merged 9 commits into from
May 13, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions lib/common/stream-router.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,18 +94,14 @@ streamRouter.parseArguments_ = function(args) {
if (is.number(query.maxResults)) {
// `maxResults` is used API-wide.
maxResults = query.maxResults;
} else if (is.number(query.limitVal)) {
// `limitVal` is part of a Datastore query.
maxResults = query.limitVal;
} else if (is.number(query.pageSize)) {
// `pageSize` is Pub/Sub's `maxResults`.
maxResults = query.pageSize;
}

if (callback &&
(maxResults !== -1 || // The user specified a limit.
query.autoPaginate === false ||
query.autoPaginateVal === false)) {
query.autoPaginate === false)) {
autoPaginate = false;
}
}
Expand Down Expand Up @@ -159,8 +155,8 @@ streamRouter.router_ = function(parsedArguments, originalMethod) {
* This method simply calls the nextQuery recursively, emitting results to a
* stream. The stream ends when `nextQuery` is null.
*
* `maxResults` and `limitVal` (from Datastore) will act as a cap for how many
* results are fetched and emitted to the stream.
* `maxResults` will act as a cap for how many results are fetched and emitted
* to the stream.
*
* @param {object=|string=} parsedArguments.query - Query object. This is most
* commonly an object, but to make the API more simple, it can also be a
Expand Down
75 changes: 66 additions & 9 deletions lib/datastore/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,19 +192,43 @@ var util = require('../common/util.js');
* //-
* // <h3>Paginating Records</h3>
* //
* // By default, all records are returned at once. To control pagination, you
* // can disable this on your query with {module:datastore/query#autoPaginate}.
* // Imagine building a website that allows a user to sift through hundreds of
* // their contacts. You'll likely want to only display a subset of these at
* // once, so you set a limit.
* //-
* query.autoPaginate(false);
* var express = require('express');
* var app = express();
*
* datastore.runQuery(query, function(err, entities, nextQuery) {
* // entities = [...];
* var NUM_RESULTS_PER_PAGE = 15;
*
* if (nextQuery) {
* // Run `datastore.runQuery` again with the prepared query to retrieve the
* // next set of results.
* datastore.runQuery(nextQuery, function(err, entities, nextQuery) {});
* app.get('/contacts', function(req, res) {
* var query = datastore.createQuery('Contacts')
* .limit(NUM_RESULTS_PER_PAGE);
*
* if (req.query.nextPageCursor) {
* query.start(req.query.nextPageCursor);
* }
*
* datastore.runQuery(query, function(err, entities, info) {
* if (err) {
* // Error handling omitted...
* return;
* }
*
* // Respond to the front end with the contacts and the cursoring token
* // from the query we just ran.
* var frontEndResponse = {
* contacts: entities
* };
*
* var moreResultsMayExist = info.moreResults !== datastore.NO_MORE_RESULTS;
*
* if (moreResultsMayExist) {
* frontEndResponse.nextPageCursor = info.endCursor;
* }
*
* res.render('contacts', frontEndResponse);
* });
* });
*
* //-
Expand Down Expand Up @@ -374,6 +398,39 @@ Datastore.int = function(value) {
return new entity.Int(value);
};

/**
* This is one of three values which may be returned from
* {module:datastore#runQuery}, {module:transaction#runQuery}, and
* {module:datastore/query#run} as `info.moreResults`.
*
* There *may* be more results after the specified end cursor.
*
* @type {string}
*/
Datastore.MORE_RESULTS_AFTER_CURSOR = 'MORE_RESULTS_AFTER_CURSOR';

/**
* This is one of three values which may be returned from
* {module:datastore#runQuery}, {module:transaction#runQuery}, and
* {module:datastore/query#run} as `info.moreResults`.
*
* There *may* be more results after the specified limit.
*
* @type {string}
*/
Datastore.MORE_RESULTS_AFTER_LIMIT = 'MORE_RESULTS_AFTER_LIMIT';

/**
* This is one of three values which may be returned from
* {module:datastore#runQuery}, {module:transaction#runQuery}, and
* {module:datastore/query#run} as `info.moreResults`.
*
* There are no more results left to query for.
*
* @type {string}
*/
Datastore.NO_MORE_RESULTS = 'NO_MORE_RESULTS';

This comment was marked as spam.

This comment was marked as spam.


/**
* Create a query for the specified kind. See {module:datastore/query} for all
* of the available methods.
Expand Down
64 changes: 14 additions & 50 deletions lib/datastore/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,41 +67,12 @@ function Query(scope, namespace, kinds) {
this.selectVal = [];

// pagination
this.autoPaginateVal = true;
this.startVal = null;
this.endVal = null;
this.limitVal = -1;
this.offsetVal = -1;
}

/**
* @param {boolean=} autoPaginateVal - Have pagination handled automatically.
* Default: true.
* @return {module:datastore/query}
*
* @example
* //-
* // Retrieve a list of people related to "Dave", with auto-pagination
* // disabled.
* //-
* var query = datastore.createQuery('Person')
* .hasAncestor(datastore.key(['Person', 'Dave']))
* .autoPaginate(false);
*
* function callback(err, entities, nextQuery, apiResponse) {
* if (nextQuery) {
* // More results might exist, so we'll manually fetch them.
* datastore.runQuery(nextQuery, callback);
* }
* }
*
* datastore.runQuery(query, callback);
*/
Query.prototype.autoPaginate = function(autoPaginateVal) {
this.autoPaginateVal = autoPaginateVal !== false;
return this;
};

/**
* Datastore allows querying on properties. Supported comparison operators
* are `=`, `<`, `>`, `<=`, and `>=`. "Not equal" and `IN` operators are
Expand Down Expand Up @@ -316,35 +287,28 @@ Query.prototype.offset = function(n) {
* stream instance is returned.
* @param {?error} callback.err - An error returned while making this request
* @param {object[]} callback.entities - A list of entities.
* @param {?object} callback.nextQuery - If present, query with this object to
* check for more results.
* @param {object} callback.apiResponse - The full API response.
*
* @example
* query.run(function(err, entities) {});
* @param {object} callback.info - An object useful for pagination.
* @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:

This comment was marked as spam.

This comment was marked as spam.

*
* //-
* // To control how many API requests are made and page through the results
* // manually, call `autoPaginate(false)` on your query.
* //-
* query.autoPaginate(false);
* - {module:datastore#MORE_RESULTS_AFTER_LIMIT}: There *may* be more
* results after the specified limit.
* - {module:datastore#MORE_RESULTS_AFTER_CURSOR}: There *may* be more
* results after the specified end cursor.
* - {module:datastore#NO_MORE_RESULTS}: There are no more results.
*
* function callback(err, entities, nextQuery, apiResponse) {
* if (nextQuery) {
* // More results might exist.
* nextQuery.run(callback);
* }
* }
*
* query.run(callback);
* @example
* query.run(function(err, entities, info) {});
*
* //-
* // If you omit the callback, `run` will automatically call subsequent queries
* // until no results remain. Entity objects will be pushed as they are found.
* // If you omit the callback, you will get the matching entities in a readable
* // object stream.
* //-
* query.run()
* .on('error', console.error)
* .on('data', function (entity) {})
* .on('info', function(info) {})

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

* .on('end', function() {
* // All entities retrieved.
* });
Expand Down
Loading