Skip to content

Commit

Permalink
prediction: add promise support (#1708)
Browse files Browse the repository at this point in the history
  • Loading branch information
callmehiphop authored and stephenplusplus committed Oct 17, 2016
1 parent 11b1100 commit d1c5fe3
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 34 deletions.
10 changes: 10 additions & 0 deletions packages/prediction/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ model.query('Hello', function(err, results) {
// ]
}
});

// Promises are also supported by omitting callbacks.
model.query('Hello').then(function(data) {
var results = data[0];
});

// It's also possible to integrate with third-party Promise libraries.
var prediction = require('@google-cloud/prediction')({
promise: require('bluebird')
});
```


Expand Down
2 changes: 1 addition & 1 deletion packages/prediction/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"prediction"
],
"dependencies": {
"@google-cloud/common": "^0.6.0",
"@google-cloud/common": "^0.7.0",
"JSONStream": "^1.0.7",
"arrify": "^1.0.0",
"extend": "^3.0.0",
Expand Down
74 changes: 53 additions & 21 deletions packages/prediction/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,14 @@ util.inherits(Prediction, common.Service);
* prediction.createModel('my-model', {
* data: modelDataCsv
* }, function(err, model, apiResponse) {});
*
* //-
* // If the callback is omitted, we'll return a Promise.
* //-
* prediction.createModel('my-model').then(function(data) {
* var model = data[0];
* var apiResponse = data[1];
* });
*/
Prediction.prototype.createModel = function(id, options, callback) {
var self = this;
Expand Down Expand Up @@ -219,25 +227,11 @@ Prediction.prototype.createModel = function(id, options, callback) {
* }, callback);
*
* //-
* // Get the models from your project as a readable object stream.
* // If the callback is omitted, we'll return a Promise.
* //-
* prediction.getModels()
* .on('error', console.error)
* .on('data', function(model) {
* // model is a Model object.
* })
* .on('end', function() {
* // All models retrieved.
* });
*
* //-
* // If you anticipate many results, you can end a stream early to prevent
* // unnecessary processing and API requests.
* //-
* prediction.getModels()
* .on('data', function(model) {
* this.end();
* });
* prediction.getModels().then(function(data) {
* var models = data[0];
* });
*/
Prediction.prototype.getModels = function(query, callback) {
var self = this;
Expand Down Expand Up @@ -274,6 +268,35 @@ Prediction.prototype.getModels = function(query, callback) {
});
};

/**
* Gets a list of {module:prediction/model} objects for the project as a
* readable object stream.
*
* @param {object=} query - Configuration object. See
* {module:prediction#getModels} for a complete list of options.
* @return {stream}
*
* @example
* prediction.getModelsStream()
* .on('error', console.error)
* .on('data', function(model) {
* // model is a Model object.
* })
* .on('end', function() {
* // All models retrieved.
* });
*
* //-
* // If you anticipate many results, you can end a stream early to prevent
* // unnecessary processing and API requests.
* //-
* prediction.getModelsStream()
* .on('data', function(model) {
* this.end();
* });
*/
Prediction.prototype.getModelsStream = common.paginator.streamify('getModels');

/**
* Create a model object representing a trained model.
*
Expand All @@ -295,10 +318,19 @@ Prediction.prototype.model = function(id) {

/*! Developer Documentation
*
* These methods can be used with either a callback or as a readable object
* stream. `streamRouter` is used to add this dual behavior.
* These methods can be auto-paginated.
*/
common.streamRouter.extend(Prediction, 'getModels');
common.paginator.extend(Prediction, 'getModels');

/*! Developer Documentation
*
* All async methods (except for streams) will return a Promise in the event
* that a callback is omitted.
*/
common.util.promisifyAll(Prediction, {
exclude: ['model']
});


Prediction.Model = Model;

Expand Down
77 changes: 76 additions & 1 deletion packages/prediction/src/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ function Model(prediction, id) {
* // The model was created successfully.
* }
* });
*
* //-
* // If the callback is omitted, we'll return a Promise.
* //-
* model.create().then(function(data) {
* var model = data[0];
* var apiResponse = data[1];
* });
*/
create: true,

Expand All @@ -75,6 +83,13 @@ function Model(prediction, id) {
*
* @example
* model.delete(function(err, apiResponse) {});
*
* //-
* // If the callback is omitted, we'll return a Promise.
* //-
* model.delete().then(function(data) {
* var apiResponse = data[0];
* });
*/
delete: true,

Expand All @@ -88,6 +103,13 @@ function Model(prediction, id) {
*
* @example
* model.exists(function(err, exists) {});
*
* //-
* // If the callback is omitted, we'll return a Promise.
* //-
* model.exists().then(function(data) {
* var exists = data[0];
* });
*/
exists: true,

Expand All @@ -107,6 +129,14 @@ function Model(prediction, id) {
* model.get(function(err, model, apiResponse) {
* // `model.metadata` has been populated.
* });
*
* //-
* // If the callback is omitted, we'll return a Promise.
* //-
* model.get().then(function(data) {
* var model = data[0];
* var apiResponse = data[1];
* });
*/
get: true,

Expand All @@ -122,6 +152,14 @@ function Model(prediction, id) {
*
* @example
* model.getMetadata(function(err, metadata, apiResponse) {});
*
* //-
* // If the callback is omitted, we'll return a Promise.
* //-
* model.getMetadata().then(function(data) {
* var metadata = data[0];
* var apiResponse = data[1];
* });
*/
getMetadata: true,

Expand All @@ -148,6 +186,13 @@ function Model(prediction, id) {
* };
*
* model.setMetadata(metadata, function(err, apiResponse) {});
*
* //-
* // If the callback is omitted, we'll return a Promise.
* //-
* model.setMetadata(metadata).then(function(data) {
* var apiResponse = data[0];
* });
*/
setMetadata: {
reqOpts: {
Expand Down Expand Up @@ -188,6 +233,14 @@ util.inherits(Model, common.ServiceObject);
* // `analysis.model` == {...}
* }
* });
*
* //-
* // If the callback is omitted, we'll return a Promise.
* //-
* model.analyze().then(function(data) {
* var analysis = data[0];
* var apiResponse = data[1];
* });
*/
Model.prototype.analyze = function(callback) {
this.request({
Expand Down Expand Up @@ -241,7 +294,7 @@ Model.prototype.createWriteStream = function(label) {
csvInstance: [[]]
}).split('[]');

var requestStream = self.request({
var requestStream = self.requestStream({
method: 'PUT',
uri: '',
headers: {
Expand Down Expand Up @@ -312,6 +365,14 @@ Model.prototype.createWriteStream = function(label) {
* // ]
* }
* });
*
* //-
* // If the callback is omitted, we'll return a Promise.
* //-
* model.query('Hello').then(function(data) {
* var results = data[0];
* var apiResponse = data[1];
* });
*/
Model.prototype.query = function(input, callback) {
this.request({
Expand Down Expand Up @@ -365,6 +426,13 @@ Model.prototype.query = function(input, callback) {
* // New data was inserted successfully.
* }
* });
*
* //-
* // If the callback is omitted, we'll return a Promise.
* //-
* model.train('english', 'Hello from Stephen!').then(function(data) {
* var apiResponse = data[0];
* });
*/
Model.prototype.train = function(label, input, callback) {
this.setMetadata({
Expand All @@ -373,4 +441,11 @@ Model.prototype.train = function(label, input, callback) {
}, callback);
};

/*! Developer Documentation
*
* All async methods (except for streams) will return a Promise in the event
* that a callback is omitted.
*/
common.util.promisifyAll(Model);

module.exports = Model;
2 changes: 1 addition & 1 deletion packages/prediction/system-test/prediction.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ describe('Prediction', function() {
});

it('should return models in stream mode', function(done) {
prediction.getModels({ maxResults: 1 })
prediction.getModelsStream({ maxResults: 1 })
.on('error', done)
.once('data', function() {
done();
Expand Down
29 changes: 24 additions & 5 deletions packages/prediction/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ function FakeService() {
nodeutil.inherits(FakeService, Service);

var extended = false;
var fakeStreamRouter = {
var fakePaginator = {
extend: function(Class, methods) {
if (Class.name !== 'Prediction') {
return;
Expand All @@ -46,12 +46,23 @@ var fakeStreamRouter = {
methods = arrify(methods);
assert.equal(Class.name, 'Prediction');
assert.deepEqual(methods, ['getModels']);
},
streamify: function(methodName) {
return methodName;
}
};


var promisified = false;
var fakeUtil = extend({}, util, {
makeAuthenticatedRequestFactory: util.noop
makeAuthenticatedRequestFactory: util.noop,
promisifyAll: function(Class, options) {
if (Class.name !== 'Prediction') {
return;
}

promisified = true;
assert.deepEqual(options.exclude, ['model']);
}
});

describe('Prediction', function() {
Expand All @@ -64,7 +75,7 @@ describe('Prediction', function() {
Prediction = proxyquire('../', {
'@google-cloud/common': {
Service: FakeService,
streamRouter: fakeStreamRouter,
paginator: fakePaginator,
util: fakeUtil
},
'./model.js': FakeModel,
Expand All @@ -79,7 +90,15 @@ describe('Prediction', function() {

describe('instantiation', function() {
it('should extend the correct methods', function() {
assert(extended); // See `fakeStreamRouter.extend`
assert(extended); // See `fakePaginator.extend`
});

it('should streamify the correct methods', function() {
assert.strictEqual(prediction.getModelsStream, 'getModels');
});

it('should promisify all the things', function() {
assert(promisified);
});

it('should normalize the arguments', function() {
Expand Down
Loading

0 comments on commit d1c5fe3

Please sign in to comment.