Windows Azure Node.js SDK

I am wondering how to get continuation tokens using the Windows Azure Node.js SDK? For example using the SDK I now do this to retrieve data from a table:

var tableService = azure.createTableService();

tableService.getTable('UsersUserFacebookActions', function (error) {
    if (error === null) {
        var query = azure.TableQuery
            .select()
            .from('UsersUserFacebookActions')
            .where('PartitionKey eq ?', userID)
            .and('Kind eq ?', 'User')
            .and('Deleted eq ?', 'false');

        tableService.queryEntities(query, function (error, userEntities) {
            if (error === null && userEntities.length > 0) {
                // check to see if access token needs extending
                extendAccessToken(userEntities[0], function (user) {
                    callback({
                        PartitionKey: user.PartitionKey,
                        RowKey: user.RowKey,
                        Kind: user.Kind,
                        EmailAddress: user.EmailAddress,
                        AccessToken: user.AccessToken,
                        TokenExpiration: user.TokenExpiration,
                        JoinDate: user.JoinDate,
                        ChannelCount: user.ChannelCount,
                        FollowCount: user.FollowCount,
                        ChannelCountString: accounting.formatNumber(user.ChannelCount),
                        FollowCountString: accounting.formatNumber(user.FollowCount),
                        Deleted: user.Deleted,
                        DeleteDate: user.DeleteDate
                    }); 
                });
            }
            else callback();
        });
    }
    else callback();
});

However I've hunted through the examples and documentation including this site:

https://www.windowsazure.com/en-us/develop/nodejs/

but haven't come across anything mentioning continuation tokens.

Any help or advice would be appreciated.

According to the source (line 481) a 'queryEntitiesResultContinuation' property will be added to your results if a continuation token is present:

https://github.com/WindowsAzure/azure-sdk-for-node/blob/master/lib/services/table/tableservice.js

This has a function called 'getNextPage' which takes a callback:

https://github.com/WindowsAzure/azure-sdk-for-node/blob/master/lib/services/table/models/queryentitiesresultcontinuation.js

You should probably create a separate function to handle the results of your query. This function would iterate over the entities, and then check to see if 'queryEntitiesResultContinuation' is set. If so, call the function, passing your new function as the callback.

I've not actually tried it, and I can't find any code samples!

UPDATE

Here is a code sample for handling continuation tokens with node:

var tableService = require("azure").createTableService();

function queryWithContinuation(query, cb) {
    tableService.queryEntities(query, function(error, entities, continuationToken){
        if (continuationToken.nextPartitionKey) { 
            nextPage(entities, continuationToken, cb);
        } else {
            cb(entities);                    
        }
    });
}

// used to recursively retrieve the results
function nextPage(entities, continuationToken, cb){
    continuationToken.getNextPage(function(error, results, newContinuationToken){
        entities = entities.concat(results);
        if (newContinuationToken.nextPartitionKey){
            nextPage(entities, newContinuationToken, cb);
        } else {
            cb(entities);
        }
    });
}

// example usage
var query = azure.TableQuery.select().from('really-big-table');
queryWithContinuation(query, function(results){
    console.log(results);
});

I am not familiar with node.js. But even if the client library doesn’t support continuation token, we can still manually issue HTTP requests. The document on http://nodejs.org/api/https.html#https_https_get_options_callback tells us how to issue HTTP requests from node.js, and the document on http://msdn.microsoft.com/en-us/library/windowsazure/dd135718 tells us how to use continuation token using HTTP requests. Combine them, and the scenario will work. Richard may provide more information on how to use the Windows Azure node.js client library, which may make the process easier.

Best Regards,

Ming Xu.

In case of use to anyone I've written a helper module to traverse the continuation token.

See https://github.com/freakyfriday/azure-storage-extension

//Usage

//create azure table service 
var tableService = azure.createTableService("AZURE_STORAGE_ACCOUNT","AZURE_STORAGE_ACCESS_KEY");

//query 
var myQuery = new azure.TableQuery().where(whereClause);

//get data automatically retrieving data where there is a continuation token 
tableService.queryEntitiesContinuation('Table', myQuery, null, function (error, result) { 
var allResults = result.entries; });

//module (place in separate file)
var azure = require('azure-storage');

azure.TableService.prototype.queryEntitiesContinuation = function (tableName, query, maxContinuationCount, callback) {

var tableService = this;
var data = new Array();
var countinuationCount = 0;
var operation = function (tableName, query, continuationToken) {
    tableService.queryEntities(tableName, query, continuationToken, function (error, result) {

        if (!error) {
            if (result.continuationToken) {

                result.entries.forEach(function (entry) {
                    data.push(entry);
                });

                if (maxContinuationCount === null || countinuationCount < maxContinuationCount) {
                    ++countinuationCount;
                    //update top
                    if (query._top !== null) {
                        query._top = query._top - data.length;
                        if (query._top !== 0) {
                            operation(tableName, query, result.continuationToken);
                        } else {
                            callback(error, result);
                        }
                    } else {
                        operation(tableName, query, result.continuationToken);
                    }
                } else {
                    callback(error, result);
                }

                
            } else {

                data.forEach(function (entry) {
                    result.entries.push(entry)
                });

                callback(error, result);
            }
        } else {

            result.entries.push(data);
            callback(error, result);
        }
    });
};

operation(tableName, query, null);
};

module.exports = azure;