From 11758046988cdb37ce4a4a39a50c09e2835cc10a Mon Sep 17 00:00:00 2001 From: Stephen Sawchuk Date: Mon, 9 Nov 2015 14:27:18 -0500 Subject: [PATCH] Implement Service & Service Object for BigQuery --- lib/bigquery/dataset.js | 238 ++++++++++++---------- lib/bigquery/index.js | 99 ++++------ lib/bigquery/job.js | 89 ++++++--- lib/bigquery/table.js | 203 ++++++++++++------- system-test/bigquery.js | 45 +---- test/bigquery/dataset.js | 412 +++++++++++++++++---------------------- test/bigquery/index.js | 222 ++++++++++++--------- test/bigquery/job.js | 104 ++++------ test/bigquery/table.js | 315 ++++++++++++------------------ 9 files changed, 836 insertions(+), 891 deletions(-) diff --git a/lib/bigquery/dataset.js b/lib/bigquery/dataset.js index 80d8ce9fde6..2f33adbdf98 100644 --- a/lib/bigquery/dataset.js +++ b/lib/bigquery/dataset.js @@ -22,12 +22,13 @@ var extend = require('extend'); var is = require('is'); +var nodeutil = require('util'); /** - * @type {module:bigquery/table} + * @type {module:common/serviceObject} * @private */ -var Table = require('./table.js'); +var ServiceObject = require('../common/service-object.js'); /** * @type {module:common/streamrouter} @@ -35,6 +36,12 @@ var Table = require('./table.js'); */ var streamRouter = require('../common/stream-router.js'); +/** + * @type {module:bigquery/table} + * @private + */ +var Table = require('./table.js'); + /*! Developer Documentation * * @param {module:bigquery} bigQuery - BigQuery instance. @@ -46,20 +53,121 @@ var streamRouter = require('../common/stream-router.js'); * * @alias module:bigquery/dataset * @constructor + * + * @example + * var gcloud = require('gcloud'); + * + * var bigquery = gcloud.bigquery({ + * keyFilename: '/path/to/keyfile.json', + * projectId: 'grape-spaceship-123' + * }); + * var dataset = bigquery.dataset('institutions'); */ function Dataset(bigQuery, id) { + var methods = { + /** + * Create a dataset. + * + * @example + * dataset.create(function(err, dataset, apiResponse) { + * if (!err) { + * // The dataset was created successfully. + * } + * }); + */ + create: true, + + /** + * Check if the dataset exists. + * + * @param {function} callback - The callback function. + * @param {?error} callback.err - An error returned while making this + * request. + * @param {boolean} callback.exists - Whether the dataset exists or not. + * + * @example + * dataset.exists(function(err, exists) {}); + */ + exists: true, + + /** + * Get a dataset if it exists. + * + * You may optionally use this to "get or create" an object by providing an + * object with `autoCreate` set to `true`. Any extra configuration that is + * normally required for the `create` method must be contained within this + * object as well. + * + * @param {options=} options - Configuration object. + * @param {boolean} options.autoCreate - Automatically create the object if + * it does not exist. Default: `false` + * + * @example + * dataset.get(function(err, dataset, apiResponse) { + * if (!err) { + * // `dataset.metadata` has been populated. + * } + * }); + */ + get: true, + + /** + * Get the metadata for the Dataset. + * + * @resource [Datasets: get API Documentation]{@link https://cloud.google.com/bigquery/docs/reference/v2/datasets/get} + * + * @param {function} callback - The callback function. + * @param {?error} callback.err - An error returned while making this + * request. + * @param {object} callback.metadata - The dataset's metadata. + * @param {object} callback.apiResponse - The full API response. + * + * @example + * dataset.getMetadata(function(err, metadata, apiResponse) {}); + */ + getMetadata: true, + + /** + * Sets the metadata of the Dataset object. + * + * @resource [Datasets: patch API Documentation]{@link https://cloud.google.com/bigquery/docs/reference/v2/datasets/patch} + * + * @param {object} metadata - Metadata to save on the Dataset. + * @param {function} callback - The callback function. + * @param {?error} callback.err - An error returned while making this + * request. + * @param {object} callback.apiResponse - The full API response. + * + * @example + * var metadata = { + * description: 'Info for every institution in the 2013 IPEDS universe' + * }; + * + * dataset.setMetadata(metadata, function(err, apiResponse) {}); + */ + setMetadata: true + }; + + ServiceObject.call(this, { + parent: bigQuery, + baseUrl: '/datasets', + id: id, + createMethod: bigQuery.createDataset.bind(bigQuery), + methods: methods + }); + this.bigQuery = bigQuery; - this.id = id; - this.metadata = {}; } +nodeutil.inherits(Dataset, ServiceObject); + /** * Create a table given a tableId or configuration object. * * @resource [Tables: insert API Documentation]{@link https://cloud.google.com/bigquery/docs/reference/v2/tables/insert} * - * @param {object} options - Table id or configuration object. - * @param {string} options.id - The id of the table. + * @param {string} id - Table id. + * @param {object=} options - Configuration object. * @param {string|object} options.schema - A comma-separated list of name:type * pairs. Valid types are "string", "integer", "float", "boolean", and * "timestamp". If the type is omitted, it is assumed to be "string". @@ -79,21 +187,21 @@ function Dataset(bigQuery, id) { * schema: 'UNITID,INSTNM,ADDR,CITY,STABBR,ZIP,FIPS,OBEREG,CHFNM,...' * }; * - * var bigquery = gcloud.bigquery({ - * projectId: 'grape-spaceship-123' - * }); - * var dataset = bigquery.dataset(); - * * dataset.createTable(tableConfig, function(err, table, apiResponse) {}); */ -Dataset.prototype.createTable = function(options, callback) { - var that = this; +Dataset.prototype.createTable = function(id, options, callback) { + var self = this; + + if (is.fn(options)) { + callback = options; + options = {}; + } extend(true, options, { tableReference: { datasetId: this.id, projectId: this.bigQuery.projectId, - tableId: options.id + tableId: id } }); @@ -101,15 +209,17 @@ Dataset.prototype.createTable = function(options, callback) { options.schema = Table.createSchemaFromString_(options.schema); } - delete options.id; - - this.makeReq_('POST', '/tables', null, options, function(err, resp) { + this.request({ + method: 'POST', + uri: '/tables', + json: options + }, function(err, resp) { if (err) { callback(err, null, resp); return; } - var table = that.table(resp.tableReference.tableId); + var table = self.table(resp.tableReference.tableId); table.metadata = resp; callback(null, table, resp); @@ -149,34 +259,11 @@ Dataset.prototype.delete = function(options, callback) { deleteContents: !!options.force }; - this.makeReq_('DELETE', '', query, null, callback); -}; - -/** - * Get the metadata for the Dataset. - * - * @resource [Datasets: get API Documentation]{@link https://cloud.google.com/bigquery/docs/reference/v2/datasets/get} - * - * @param {function} callback - The callback function. - * @param {?error} callback.err - An error returned while making this request - * @param {object} callback.metadata - The dataset's metadata. - * @param {object} callback.apiResponse - The full API response. - * - * @example - * dataset.getMetadata(function(err, metadata, apiResponse) {}); - */ -Dataset.prototype.getMetadata = function(callback) { - var that = this; - this.makeReq_('GET', '', null, null, function(err, resp) { - if (err) { - callback(err, null, resp); - return; - } - - that.metadata = resp; - - callback(null, that.metadata, resp); - }); + this.request({ + method: 'DELETE', + uri: '', + qs: query + }, callback); }; /** @@ -231,14 +318,16 @@ Dataset.prototype.getTables = function(query, callback) { query = query || {}; - this.makeReq_('GET', '/tables', query, null, function(err, resp) { + this.request({ + uri: '/tables', + qs: query + }, function(err, resp) { if (err) { callback(err, null, null, resp); return; } var nextQuery = null; - if (resp.nextPageToken) { nextQuery = extend({}, query, { pageToken: resp.nextPageToken @@ -277,39 +366,7 @@ Dataset.prototype.query = function(options, callback) { }; /** - * Sets the metadata of the Dataset object. - * - * @resource [Datasets: patch API Documentation]{@link https://cloud.google.com/bigquery/docs/reference/v2/datasets/patch} - * - * @param {object} metadata - Metadata to save on the Dataset. - * @param {function} callback - The callback function. - * @param {?error} callback.err - An error returned while making this request - * @param {object} callback.apiResponse - The full API response. - * - * @example - * var metadata = { - * description: 'Information for every institution in the 2013 IPEDS universe' - * }; - * - * dataset.setMetadata(metadata, function(err, apiResponse) {}); - */ -Dataset.prototype.setMetadata = function(metadata, callback) { - var that = this; - - this.makeReq_('PATCH', '', null, metadata, function(err, resp) { - if (err) { - callback(err, resp); - return; - } - - that.metadata = resp; - - callback(null, resp); - }); -}; - -/** - * Return a new instance of reference to an existing Table object. + * Create a Table object. * * @param {string} id - The ID of the table. * @return {module:bigquery/table} @@ -321,28 +378,11 @@ Dataset.prototype.table = function(id) { return new Table(this, id); }; -/** - * Pass through this request to BigQuery's request handler, first prepending the - * path with the dataset. - * - * @private - * - * @param {string} method - Action. - * @param {string} path - Request path. - * @param {*} query - Request query object. - * @param {*} body - Request body contents. - * @param {function} callback - The callback function. - */ -Dataset.prototype.makeReq_ = function(method, path, query, body, callback) { - path = '/datasets/' + this.id + path; - this.bigQuery.makeReq_(method, path, query, body, callback); -}; - /*! 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. */ -streamRouter.extend(Dataset, 'getTables'); +streamRouter.extend(Dataset, ['getTables']); module.exports = Dataset; diff --git a/lib/bigquery/index.js b/lib/bigquery/index.js index f6ff063e7f6..6a8cc5d5aba 100644 --- a/lib/bigquery/index.js +++ b/lib/bigquery/index.js @@ -22,6 +22,7 @@ var extend = require('extend'); var is = require('is'); +var nodeutil = require('util'); /** * @type {module:bigquery/dataset} @@ -35,6 +36,12 @@ var Dataset = require('./dataset.js'); */ var Job = require('./job.js'); +/** + * @type {module:common/service} + * @private + */ +var Service = require('../common/service.js'); + /** * @type {module:common/streamrouter} * @private @@ -53,20 +60,6 @@ var Table = require('./table.js'); */ var util = require('../common/util.js'); -/** - * @const {string} Base URL for the BigQuery API. - * @private - */ -var BIGQUERY_BASE_URL = 'https://www.googleapis.com/bigquery/v2/projects/'; - -/** - * Required scopes for Google Cloud BigQuery API. - * - * @const {array} - * @private - */ -var SCOPES = ['https://www.googleapis.com/auth/bigquery']; - /** * The examples below will demonstrate the different usage patterns your app may * need to support to retrieve a BigQuery object. @@ -100,16 +93,16 @@ function BigQuery(options) { return new BigQuery(options); } - this.makeAuthenticatedRequest_ = util.makeAuthenticatedRequestFactory({ - credentials: options.credentials, - keyFile: options.keyFilename, - scopes: SCOPES, - email: options.email - }); + var config = { + baseUrl: 'https://www.googleapis.com/bigquery/v2', + scopes: ['https://www.googleapis.com/auth/bigquery'] + }; - this.projectId = options.projectId; + Service.call(this, config, options); } +nodeutil.inherits(BigQuery, Service); + /** * Create a dataset. * @@ -133,7 +126,11 @@ BigQuery.prototype.createDataset = function(id, callback) { } }; - this.makeReq_('POST', '/datasets', null, body, function(err, resp) { + this.request({ + method: 'POST', + uri: '/datasets', + json: body + }, function(err, resp) { if (err) { callback(err, null, resp); return; @@ -147,7 +144,7 @@ BigQuery.prototype.createDataset = function(id, callback) { }; /** - * Create a reference to an existing dataset. + * Create a reference to a dataset. * * @param {string} id - ID of the dataset. * @return {module:bigquery/dataset} @@ -232,7 +229,10 @@ BigQuery.prototype.getDatasets = function(query, callback) { query = query || {}; - this.makeReq_('GET', '/datasets', query, null, function(err, resp) { + this.request({ + uri: '/datasets', + qs: query + }, function(err, resp) { if (err) { callback(err, null, null, resp); return; @@ -335,7 +335,10 @@ BigQuery.prototype.getJobs = function(options, callback) { options = options || {}; - this.makeReq_('GET', '/jobs', options, null, function(err, resp) { + this.request({ + uri: '/jobs', + qs: options + }, function(err, resp) { if (err) { callback(err, null, null, resp); return; @@ -360,7 +363,7 @@ BigQuery.prototype.getJobs = function(options, callback) { }; /** - * Create a reference to an existing Job. + * Create a reference to an existing job. * * @param {string} id - ID of the job. * @return {module:bigquery/job} @@ -460,11 +463,17 @@ BigQuery.prototype.query = function(options, callback) { if (job) { // Get results of the query. - var path = '/queries/' + job.id; - that.makeReq_('GET', path, requestQuery, null, responseHandler); + that.request({ + uri: '/queries/' + job.id, + qs: requestQuery + }, responseHandler); } else { // Create a job. - that.makeReq_('POST', '/queries', null, options, responseHandler); + that.request({ + method: 'POST', + uri: '/queries', + json: options + }, responseHandler); } function responseHandler(err, resp) { @@ -586,7 +595,11 @@ BigQuery.prototype.startQuery = function(options, callback) { } }; - this.makeReq_('POST', '/jobs', null, body, function(err, resp) { + this.request({ + method: 'POST', + uri: '/jobs', + json: body + }, function(err, resp) { if (err) { callback(err, null, resp); return; @@ -599,32 +612,6 @@ BigQuery.prototype.startQuery = function(options, callback) { }); }; -/** - * Make a new request object from the provided arguments and wrap the callback - * to intercept non-successful responses. - * - * @private - * - * @param {string} method - Action. - * @param {string} path - Request path. - * @param {*} query - Request query object. - * @param {*} body - Request body contents. - * @param {function} callback - The callback function. - */ -BigQuery.prototype.makeReq_ = function(method, path, query, body, callback) { - var reqOpts = { - method: method, - qs: query, - uri: BIGQUERY_BASE_URL + this.projectId + path - }; - - if (body) { - reqOpts.json = body; - } - - this.makeAuthenticatedRequest_(reqOpts, callback); -}; - /*! Developer Documentation * * These methods can be used with either a callback or as a readable object diff --git a/lib/bigquery/job.js b/lib/bigquery/job.js index ebf2f9f9afd..ba17e7bb796 100644 --- a/lib/bigquery/job.js +++ b/lib/bigquery/job.js @@ -21,6 +21,13 @@ 'use strict'; var is = require('is'); +var nodeutil = require('util'); + +/** + * @type {module:common/serviceObject} + * @private + */ +var ServiceObject = require('../common/service-object.js'); /*! Developer Documentation * @@ -51,42 +58,62 @@ var is = require('is'); * @constructor */ function Job(bigQuery, id) { - this.bigQuery = bigQuery; - this.id = id; - this.metadata = {}; -} + var methods = { + /** + * Check if the job exists. + * + * @param {function} callback - The callback function. + * @param {?error} callback.err - An error returned while making this + * request. + * @param {boolean} callback.exists - Whether the job exists or not. + * + * @example + * job.exists(function(err, exists) {}); + */ + exists: true, -/** - * Get the metadata of the job. This will mostly be useful for checking the - * status of a previously-run job. - * - * @resource [Jobs: get API Documentation]{@link https://cloud.google.com/bigquery/docs/reference/v2/jobs/get} - * - * @param {function} callback - The callback function. - * @param {?error} callback.err - An error returned while making this request - * @param {object} callback.metadata - The metadata of the job. - * @param {object} callback.apiResponse - The full API response. - * - * @example - * var job = bigquery.job('id'); - * job.getMetadata(function(err, metadata, apiResponse) {}); - */ -Job.prototype.getMetadata = function(callback) { - var that = this; + /** + * Get a job if it exists. + * + * @example + * job.get(function(err, job, apiResponse) { + * if (!err) { + * // `job.metadata` has been populated. + * } + * }); + */ + get: true, - var path = '/jobs/' + this.id; + /** + * Get the metadata of the job. This will mostly be useful for checking the + * status of a previously-run job. + * + * @resource [Jobs: get API Documentation]{@link https://cloud.google.com/bigquery/docs/reference/v2/jobs/get} + * + * @param {function} callback - The callback function. + * @param {?error} callback.err - An error returned while making this + * request. + * @param {object} callback.metadata - The metadata of the job. + * @param {object} callback.apiResponse - The full API response. + * + * @example + * var job = bigquery.job('id'); + * job.getMetadata(function(err, metadata, apiResponse) {}); + */ + getMetadata: true + }; - this.bigQuery.makeReq_('GET', path, null, null, function(err, resp) { - if (err) { - callback(err, null, resp); - return; - } + ServiceObject.call(this, { + parent: bigQuery, + baseUrl: '/jobs', + id: id, + methods: methods + }); - that.metadata = resp; + this.bigQuery = bigQuery; +} - callback(null, that.metadata, resp); - }); -}; +nodeutil.inherits(Job, ServiceObject); /** * Get the results of a job. diff --git a/lib/bigquery/table.js b/lib/bigquery/table.js index 2d4d9fc77d9..be0f1181c12 100644 --- a/lib/bigquery/table.js +++ b/lib/bigquery/table.js @@ -27,6 +27,7 @@ var extend = require('extend'); var format = require('string-format-obj'); var fs = require('fs'); var is = require('is'); +var nodeutil = require('util'); var path = require('path'); var streamEvents = require('stream-events'); @@ -34,7 +35,13 @@ var streamEvents = require('stream-events'); * @type {module:storage/file} * @private */ -var File = require('../storage/file'); +var File = require('../storage/file.js'); + +/** + * @type {module:common/serviceObject} + * @private + */ +var ServiceObject = require('../common/service-object.js'); /** * @type {module:common/streamrouter} @@ -46,7 +53,7 @@ var streamRouter = require('../common/stream-router.js'); * @type {module:common/util} * @private */ -var util = require('../common/util'); +var util = require('../common/util.js'); /*! Developer Documentation * @@ -72,12 +79,99 @@ var util = require('../common/util'); * var table = dataset.table('my-table'); */ function Table(dataset, id) { + var methods = { + /** + * Create a table. + * + * @param {object=} options - See {module:bigquery/dataset#createTable}. + * + * @example + * table.create(function(err, table, apiResponse) { + * if (!err) { + * // The table was created successfully. + * } + * }); + */ + create: true, + + /** + * Delete a table and all its data. + * + * @resource [Tables: delete API Documentation]{@link https://cloud.google.com/bigquery/docs/reference/v2/tables/delete} + * + * @param {function} callback - The callback function. + * @param {?error} callback.err - An error returned while making this + * request. + * @param {object} callback.apiResponse - The full API response. + * + * @example + * table.delete(function(err, apiResponse) {}); + */ + delete: true, + + /** + * Check if the table exists. + * + * @param {function} callback - The callback function. + * @param {?error} callback.err - An error returned while making this + * request. + * @param {boolean} callback.exists - Whether the table exists or not. + * + * @example + * table.exists(function(err, exists) {}); + */ + exists: true, + + /** + * Get a table if it exists. + * + * You may optionally use this to "get or create" an object by providing an + * object with `autoCreate` set to `true`. Any extra configuration that is + * normally required for the `create` method must be contained within this + * object as well. + * + * @param {options=} options - Configuration object. + * @param {boolean} options.autoCreate - Automatically create the object if + * it does not exist. Default: `false` + * + * @example + * table.get(function(err, table, apiResponse) { + * // `table.metadata` has been populated. + * }); + */ + get: true, + + /** + * Return the metadata associated with the Table. + * + * @resource [Tables: get API Documentation]{@link https://cloud.google.com/bigquery/docs/reference/v2/tables/get} + * + * @param {function} callback - The callback function. + * @param {?error} callback.err - An error returned while making this + * request. + * @param {object} callback.metadata - The metadata of the Table. + * @param {object} callback.apiResponse - The full API response. + * + * @example + * table.getMetadata(function(err, metadata, apiResponse) {}); + */ + getMetadata: true + }; + + ServiceObject.call(this, { + parent: dataset, + baseUrl: '/tables', + id: id, + createMethod: dataset.createTable.bind(dataset), + methods: methods + }); + this.bigQuery = dataset.bigQuery; this.dataset = dataset; - this.id = id; - this.metadata = {}; } +nodeutil.inherits(Table, ServiceObject); + /** * Convert a comma-separated name:type string to a table schema object. * @@ -190,7 +284,11 @@ Table.prototype.copy = function(destination, metadata, callback) { } }; - this.bigQuery.makeReq_('POST', '/jobs', null, body, function(err, resp) { + this.bigQuery.request({ + method: 'POST', + uri: '/jobs', + json: body, + }, function(err, resp) { if (err) { callback(err, null, resp); return; @@ -311,7 +409,7 @@ Table.prototype.createWriteStream = function(metadata) { dup.once('writing', function() { util.makeWritableStream(dup, { - makeAuthenticatedRequest: that.bigQuery.makeAuthenticatedRequest_, + makeAuthenticatedRequest: that.bigQuery.makeAuthenticatedRequest, metadata: { configuration: { load: metadata @@ -334,22 +432,6 @@ Table.prototype.createWriteStream = function(metadata) { return dup; }; -/** - * Delete a table and all its data. - * - * @resource [Tables: delete API Documentation]{@link https://cloud.google.com/bigquery/docs/reference/v2/tables/delete} - * - * @param {function} callback - The callback function. - * @param {?error} callback.err - An error returned while making this request - * @param {object} callback.apiResponse - The full API response. - * - * @example - * table.delete(function(err, apiResponse) {}); - */ -Table.prototype.delete = function(callback) { - this.makeReq_('DELETE', '', null, null, callback); -}; - /** * Export table to Google Cloud Storage. * @@ -462,7 +544,11 @@ Table.prototype.export = function(destination, options, callback) { } }; - this.bigQuery.makeReq_('POST', '/jobs', null, body, function(err, resp) { + this.bigQuery.request({ + method: 'POST', + uri: '/jobs', + json: body + }, function(err, resp) { if (err) { callback(err, null, resp); return; @@ -475,34 +561,6 @@ Table.prototype.export = function(destination, options, callback) { }); }; -/** - * Return the metadata associated with the Table. - * - * @resource [Tables: get API Documentation]{@link https://cloud.google.com/bigquery/docs/reference/v2/tables/get} - * - * @param {function} callback - The callback function. - * @param {?error} callback.err - An error returned while making this request - * @param {object} callback.metadata - The metadata of the Table. - * @param {object} callback.apiResponse - The full API response. - * - * @example - * table.getMetadata(function(err, metadata, apiResponse) {}); - */ -Table.prototype.getMetadata = function(callback) { - var that = this; - - this.makeReq_('GET', '', null, null, function(err, resp) { - if (err) { - callback(err, null, resp); - return; - } - - that.metadata = resp; - - callback(null, that.metadata, resp); - }); -}; - /** * Retrieves table data from a specified set of rows. The rows are returned to * your callback as an array of objects matching your table's schema. @@ -571,7 +629,10 @@ Table.prototype.getRows = function(options, callback) { callback = callback || util.noop; - this.makeReq_('GET', '/data', options, null, function(err, resp) { + this.request({ + uri: '/data', + qs: options + }, function(err, resp) { if (err) { onComplete(err, null, null, resp); return; @@ -735,7 +796,11 @@ Table.prototype.import = function(source, metadata, callback) { }) }); - this.bigQuery.makeReq_('POST', '/jobs', null, body, function(err, resp) { + this.bigQuery.request({ + method: 'POST', + uri: '/jobs', + json: body + }, function(err, resp) { if (err) { callback(err, null, resp); return; @@ -819,7 +884,11 @@ Table.prototype.insert = function(rows, callback) { }) }; - this.makeReq_('POST', '/insertAll', null, body, function(err, resp) { + this.request({ + method: 'POST', + uri: '/insertAll', + json: body + }, function(err, resp) { if (err) { callback(err, null, resp); return; @@ -875,6 +944,7 @@ Table.prototype.query = function(query, callback) { * description: 'A table for storing my recipes.', * schema: 'name:string, servings:integer, cookingTime:float, quick:boolean' * }; + * * table.setMetadata(metadata, function(err, metadata, apiResponse) {}); */ Table.prototype.setMetadata = function(metadata, callback) { @@ -889,7 +959,11 @@ Table.prototype.setMetadata = function(metadata, callback) { metadata.schema = Table.createSchemaFromString_(metadata.schema); } - this.makeReq_('PUT', '', null, metadata, function(err, resp) { + this.request({ + method: 'PUT', + uri: '', + json: metadata + }, function(err, resp) { if (err) { callback(err, resp); return; @@ -901,28 +975,11 @@ Table.prototype.setMetadata = function(metadata, callback) { }); }; -/** - * Pass through this request to BigQuery's request handler, first prepending the - * path with the dataset. - * - * @private - * - * @param {string} method - Action. - * @param {string} path - Request path. - * @param {*} query - Request query object. - * @param {*} body - Request body contents. - * @param {function} callback - The callback function. - */ -Table.prototype.makeReq_ = function(method, path, query, body, callback) { - path = '/tables/' + this.id + path; - this.dataset.makeReq_(method, path, query, body, callback); -}; - /*! 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. */ -streamRouter.extend(Table, 'getRows'); +streamRouter.extend(Table, ['getRows']); module.exports = Table; diff --git a/system-test/bigquery.js b/system-test/bigquery.js index bb0594cf268..0a89611c04c 100644 --- a/system-test/bigquery.js +++ b/system-test/bigquery.js @@ -31,9 +31,9 @@ var storage = gcloud.storage(); describe('BigQuery', function() { var DATASET_ID = ('gcloud_test_dataset_temp' + uuid.v1()).replace(/-/g, '_'); - var dataset; + var dataset = bigquery.dataset(DATASET_ID); var TABLE_ID = 'myKittens'; - var table; + var table = dataset.table(TABLE_ID); var BUCKET_NAME = 'gcloud-test-bucket-temp-' + uuid.v1(); var bucket; @@ -41,58 +41,25 @@ describe('BigQuery', function() { before(function(done) { async.series([ - function(next) { - // Delete the test dataset, if it exists. - bigquery.dataset(DATASET_ID).delete({ force: true }, function() { - next(); - }); - }, - // Create the test dataset. function(next) { - bigquery.createDataset(DATASET_ID, function(err, ds) { - if (err) { - next(err); - return; - } - - dataset = ds; - next(); - }); - }, - - // Delete the test table, if it exists. - function(next) { - dataset.table(TABLE_ID).delete(function() { - next(); - }); + dataset.create(next); }, // Create the test table. function(next) { - dataset.createTable({ - id: TABLE_ID, - schema: 'id:integer,breed,name,dob:timestamp' - }, function(err, t) { - if (err) { - next(err); - return; - } - - table = t; - next(); - }); + table.create({ schema: 'id:integer,breed,name,dob:timestamp' }, next); }, // Create a Bucket. function(next) { - storage.createBucket(BUCKET_NAME, function(err, b) { + storage.createBucket(BUCKET_NAME, function(err, bucket_) { if (err) { next(err); return; } - bucket = b; + bucket = bucket_; next(); }); } diff --git a/test/bigquery/dataset.js b/test/bigquery/dataset.js index 40af0bb74b8..51a27038a40 100644 --- a/test/bigquery/dataset.js +++ b/test/bigquery/dataset.js @@ -18,8 +18,12 @@ var arrify = require('arrify'); var assert = require('assert'); -var util = require('../../lib/common/util'); +var extend = require('extend'); var mockery = require('mockery'); +var nodeutil = require('util'); + +var ServiceObject = require('../../lib/common/service-object.js'); +var util = require('../../lib/common/util.js'); var extended = false; var fakeStreamRouter = { @@ -35,8 +39,18 @@ var fakeStreamRouter = { } }; +function FakeServiceObject() { + this.calledWith_ = arguments; + ServiceObject.apply(this, arguments); +} + +nodeutil.inherits(FakeServiceObject, ServiceObject); + describe('BigQuery/Dataset', function() { - var BIGQUERY = { projectId: 'my-project' }; + var BIGQUERY = { + projectId: 'my-project', + createDataset: util.noop + }; var DATASET_ID = 'kittens'; var Dataset; var Table; @@ -44,6 +58,7 @@ describe('BigQuery/Dataset', function() { before(function() { mockery.registerMock('../common/stream-router.js', fakeStreamRouter); + mockery.registerMock('../common/service-object.js', FakeServiceObject); mockery.enable({ useCleanCache: true, warnOnUnregistered: false @@ -66,6 +81,33 @@ describe('BigQuery/Dataset', function() { it('should extend the correct methods', function() { assert(extended); // See `fakeStreamRouter.extend` }); + + it('should inherit from ServiceObject', function(done) { + var bigQueryInstance = extend({}, BIGQUERY, { + createDataset: { + bind: function(context) { + assert.strictEqual(context, bigQueryInstance); + done(); + } + } + }); + + var ds = new Dataset(bigQueryInstance, DATASET_ID); + assert(ds instanceof ServiceObject); + + var calledWith = ds.calledWith_[0]; + + assert.strictEqual(calledWith.parent, bigQueryInstance); + assert.strictEqual(calledWith.baseUrl, '/datasets'); + assert.strictEqual(calledWith.id, DATASET_ID); + assert.deepEqual(calledWith.methods, { + create: true, + exists: true, + get: true, + getMetadata: true, + setMetadata: true + }); + }); }); describe('createTable', function() { @@ -80,45 +122,62 @@ describe('BigQuery/Dataset', function() { var SCHEMA_STRING = 'id:integer,breed,name,dob:timestamp'; var TABLE_ID = 'kittens'; + var API_RESPONSE = { + tableReference: { + tableId: TABLE_ID + } + }; + it('should create a table', function(done) { - ds.makeReq_ = function(method, path, query, body) { - assert.equal(method, 'POST'); - assert.equal(path, '/tables'); - assert.strictEqual(query, null); + var options = { + schema: SCHEMA_OBJECT + }; + + ds.request = function(reqOpts) { + assert.strictEqual(reqOpts.method, 'POST'); + assert.strictEqual(reqOpts.uri, '/tables'); + + var body = reqOpts.json; + assert.strictEqual(body, options); assert.deepEqual(body.schema, SCHEMA_OBJECT); assert.equal(body.tableReference.datasetId, DATASET_ID); assert.equal(body.tableReference.projectId, ds.bigQuery.projectId); assert.equal(body.tableReference.tableId, TABLE_ID); + done(); }; - ds.createTable({ id: TABLE_ID, schema: SCHEMA_OBJECT }, assert.ifError); + + ds.createTable(TABLE_ID, options, assert.ifError); }); it('should create a schema object from a string', function(done) { - ds.makeReq_ = function(method, path, query, body) { - assert.deepEqual(body.schema, SCHEMA_OBJECT); + ds.request = function(reqOpts) { + assert.deepEqual(reqOpts.json.schema, SCHEMA_OBJECT); done(); }; - ds.createTable({ id: TABLE_ID, schema: SCHEMA_STRING }, assert.ifError); + + ds.createTable(TABLE_ID, { schema: SCHEMA_STRING }, assert.ifError); }); it('should return an error to the callback', function(done) { var error = new Error('Error.'); - ds.makeReq_ = function(method, path, query, body, callback) { + + ds.request = function(reqOpts, callback) { callback(error); }; - ds.createTable({ id: TABLE_ID, schema: SCHEMA_OBJECT }, function(err) { - assert.equal(err, error); + + ds.createTable(TABLE_ID, { schema: SCHEMA_OBJECT }, function(err) { + assert.strictEqual(err, error); done(); }); }); it('should return a Table object', function(done) { - ds.makeReq_ = function(method, path, query, body, callback) { - callback(null, { tableReference: { tableId: TABLE_ID } }); + ds.request = function(reqOpts, callback) { + callback(null, API_RESPONSE); }; - var options = { id: TABLE_ID, schema: SCHEMA_OBJECT }; - ds.createTable(options, function(err, table) { + + ds.createTable(TABLE_ID, { schema: SCHEMA_OBJECT }, function(err, table) { assert.ifError(err); assert(table instanceof Table); done(); @@ -126,31 +185,32 @@ describe('BigQuery/Dataset', function() { }); it('should return an apiResponse', function(done) { - var resp = { tableReference: { tableId: TABLE_ID } }; - ds.makeReq_ = function(method, path, query, body, callback) { - callback(null, resp); + var opts = { id: TABLE_ID, schema: SCHEMA_OBJECT }; + + ds.request = function(reqOpts, callback) { + callback(null, API_RESPONSE); }; - var options = { id: TABLE_ID, schema: SCHEMA_OBJECT }; - ds.createTable(options, function(err, table, apiResponse) { + + ds.createTable(TABLE_ID, opts, function(err, table, apiResponse) { assert.ifError(err); - assert.deepEqual(apiResponse, resp); + assert.strictEqual(apiResponse, API_RESPONSE); done(); }); }); it('should assign metadata to the Table object', function(done) { - var metadata = { + var apiResponse = extend({ a: 'b', - c: 'd', - tableReference: { tableId: TABLE_ID } - }; - ds.makeReq_ = function(method, path, query, body, callback) { - callback(null, metadata); + c: 'd' + }, API_RESPONSE); + + ds.request = function(reqOpts, callback) { + callback(null, apiResponse); }; - var options = { id: TABLE_ID, schema: SCHEMA_OBJECT }; - ds.createTable(options, function(e, table) { - assert.ifError(e); - assert.deepEqual(table.metadata, metadata); + + ds.createTable(TABLE_ID, { schema: SCHEMA_OBJECT }, function(err, table) { + assert.ifError(err); + assert.strictEqual(table.metadata, apiResponse); done(); }); }); @@ -158,189 +218,153 @@ describe('BigQuery/Dataset', function() { describe('delete', function() { it('should delete the dataset via the api', function(done) { - ds.makeReq_ = function(method, path, query, body) { - assert.equal(method, 'DELETE'); - assert.equal(path, ''); - assert.deepEqual(query, { deleteContents: false }); - assert.strictEqual(body, null); + ds.request = function(reqOpts) { + assert.equal(reqOpts.method, 'DELETE'); + assert.equal(reqOpts.uri, ''); + assert.deepEqual(reqOpts.qs, { deleteContents: false }); done(); }; + ds.delete(assert.ifError); }); it('should allow a force delete', function(done) { - ds.makeReq_ = function(method, path, query) { - assert.deepEqual(query, { deleteContents: true }); + ds.request = function(reqOpts) { + assert.deepEqual(reqOpts.qs, { deleteContents: true }); done(); }; + ds.delete({ force: true }, assert.ifError); }); it('should execute callback when done', function(done) { - ds.makeReq_ = function(method, path, query, body, callback) { + ds.request = function(reqOpts, callback) { callback(); }; + ds.delete(done); }); it('should pass error to callback', function(done) { var error = new Error('Error.'); - ds.makeReq_ = function(method, path, query, body, callback) { + + ds.request = function(reqOpts, callback) { callback(error); }; + ds.delete(function(err) { - assert.equal(err, error); + assert.strictEqual(err, error); done(); }); }); it('should pass apiResponse to callback', function(done) { - var resp = { success: true }; - ds.makeReq_ = function(method, path, query, body, callback) { - callback(null, resp); - }; - ds.delete(function(err, apiResponse) { - assert.deepEqual(apiResponse, { success: true }); - done(); - }); - }); - }); + var apiResponse = {}; - describe('getMetadata', function() { - it('should get metadata from api', function(done) { - ds.makeReq_ = function(method, path, query, body) { - assert.equal(method, 'GET'); - assert.equal(path, ''); - assert.strictEqual(query, null); - assert.strictEqual(body, null); - done(); + ds.request = function(reqOpts, callback) { + callback(null, apiResponse); }; - ds.getMetadata(assert.ifError); - }); - it('should execute callback with error', function(done) { - var error = new Error('Error.'); - ds.makeReq_ = function(method, path, query, body, callback) { - callback(error); - }; - ds.getMetadata(function(err) { - assert.equal(err, error); + ds.delete(function(err, apiResponse_) { + assert.strictEqual(apiResponse_, apiResponse); done(); }); }); - - describe('metadata', function() { - var METADATA = { a: 'b', c: 'd' }; - - beforeEach(function() { - ds.makeReq_ = function(method, path, query, body, callback) { - callback(null, METADATA); - }; - }); - - it('should update metadata on Dataset object', function(done) { - ds.getMetadata(function(err) { - assert.ifError(err); - assert.deepEqual(ds.metadata, METADATA); - done(); - }); - }); - - it('should execute callback with metadata', function(done) { - ds.getMetadata(function(err, metadata) { - assert.ifError(err); - assert.deepEqual(metadata, METADATA); - done(); - }); - }); - - it('should execute callback with apiResponse', function(done) { - ds.getMetadata(function(err, metadata, apiResponse) { - assert.ifError(err); - assert.deepEqual(apiResponse, METADATA); - done(); - }); - }); - }); }); describe('getTables', function() { it('should get tables from the api', function(done) { - ds.makeReq_ = function(method, path, query, body) { - assert.equal(method, 'GET'); - assert.equal(path, '/tables'); - assert.deepEqual(query, {}); - assert.strictEqual(body, null); + ds.request = function(reqOpts) { + assert.equal(reqOpts.uri, '/tables'); + assert.deepEqual(reqOpts.qs, {}); done(); }; + ds.getTables(assert.ifError); }); - it('should accept query', function(done) { - var queryObject = { maxResults: 8, pageToken: 'token' }; - ds.makeReq_ = function(method, path, query) { - assert.deepEqual(query, queryObject); + it('should accept a query', function(done) { + var query = { + maxResults: 8, + pageToken: 'token' + }; + + ds.request = function(reqOpts) { + assert.strictEqual(reqOpts.qs, query); done(); }; - ds.getTables(queryObject, assert.ifError); + + ds.getTables(query, assert.ifError); }); it('should return error to callback', function(done) { var error = new Error('Error.'); - ds.makeReq_ = function(method, path, query, body, callback) { + + ds.request = function(reqOpts, callback) { callback(error); }; + ds.getTables(function(err) { - assert.equal(err, error); + assert.strictEqual(err, error); done(); }); }); - it('should return Table objects', function(done) { - ds.makeReq_ = function(method, path, query, body, callback) { - callback(null, { tables: [{ id: 'tableName' }] }); + describe('success', function() { + var apiResponse = { + tables: [ + { + a: 'b', + c: 'd', + id: 'tableName' + } + ] }; - ds.getTables(function(err, tables) { - assert.ifError(err); - assert(tables[0] instanceof Table); - done(); + + beforeEach(function() { + ds.request = function(reqOpts, callback) { + callback(null, apiResponse); + }; }); - }); - it('should return apiResponse', function(done) { - ds.makeReq_ = function(method, path, query, body, callback) { - callback(null, { tables: [{ id: 'tableName' }] }); - }; - ds.getTables(function(err, tables, nextQuery, apiResponse) { - assert.ifError(err); - assert.deepEqual(apiResponse, { tables: [{ id: 'tableName' }] }); - done(); + it('should return Table & apiResponse', function(done) { + ds.getTables(function(err, tables, nextQuery, apiResponse_) { + assert.ifError(err); + assert(tables[0] instanceof Table); + assert.strictEqual(apiResponse_, apiResponse); + done(); + }); }); - }); - it('should assign metadata to the Table objects', function(done) { - var tableObjects = [{ a: 'b', c: 'd', id: 'tableName' }]; - ds.makeReq_ = function(method, path, query, body, callback) { - callback(null, { tables: tableObjects }); - }; - ds.getTables(function(err, tables) { - assert.ifError(err); - assert(tables[0].metadata, tableObjects[0]); - done(); + it('should assign metadata to the Table objects', function(done) { + ds.getTables(function(err, tables) { + assert.ifError(err); + assert.strictEqual(tables[0].metadata, apiResponse.tables[0]); + done(); + }); }); - }); - it('should return token if more results exist', function(done) { - var token = 'token'; - ds.makeReq_ = function(method, path, query, body, callback) { - callback(null, { nextPageToken: token }); - }; - ds.getTables({ maxResults: 5 }, function(err, tables, nextQuery) { - assert.deepEqual(nextQuery, { - pageToken: token, + it('should return token if more results exist', function(done) { + var pageToken = 'token'; + + var query = { maxResults: 5 + }; + + var expectedNextQuery = { + maxResults: 5, + pageToken: pageToken + }; + + ds.request = function(reqOpts, callback) { + callback(null, { nextPageToken: pageToken }); + }; + + ds.getTables(query, function(err, tables, nextQuery) { + assert.ifError(err); + assert.deepEqual(nextQuery, expectedNextQuery); + done(); }); - done(); }); }); }); @@ -420,60 +444,6 @@ describe('BigQuery/Dataset', function() { }); }); - describe('setMetadata', function() { - var METADATA = { a: 'b', c: 'd' }; - - it('should send request to the api', function(done) { - ds.makeReq_ = function(method, path, query, body) { - assert.equal(method, 'PATCH'); - assert.equal(path, ''); - assert.strictEqual(query, null); - assert.deepEqual(body, METADATA); - done(); - }; - ds.setMetadata(METADATA, assert.ifError); - }); - - it('should execute callback with error & API response', function(done) { - var error = new Error('Error.'); - var apiResponse = {}; - - ds.makeReq_ = function(method, path, query, body, callback) { - callback(error, apiResponse); - }; - - ds.setMetadata(METADATA, function(err, apiResponse_) { - assert.strictEqual(err, error); - assert.strictEqual(apiResponse_, apiResponse); - done(); - }); - }); - - describe('metadata', function() { - beforeEach(function() { - ds.makeReq_ = function(method, path, query, body, callback) { - callback(null, METADATA); - }; - }); - - it('should update metadata on Dataset object', function(done) { - ds.setMetadata(METADATA, function(err) { - assert.ifError(err); - assert.deepEqual(ds.metadata, METADATA); - done(); - }); - }); - - it('should execute callback with apiResponse', function(done) { - ds.setMetadata(METADATA, function(err, apiResponse) { - assert.ifError(err); - assert.deepEqual(apiResponse, METADATA); - done(); - }); - }); - }); - }); - describe('table', function() { it('should return a Table object', function() { var tableId = 'tableId'; @@ -482,34 +452,4 @@ describe('BigQuery/Dataset', function() { assert.equal(table.id, tableId); }); }); - - describe('makeReq_', function() { - it('should prefix the path', function(done) { - var path = '/test-path'; - - ds.bigQuery.makeReq_ = function(method, p) { - assert.equal(p, '/datasets/' + ds.id + path); - done(); - }; - - ds.makeReq_('POST', path); - }); - - it('should pass through arguments', function(done) { - var method = 'POST'; - var query = { a: 'b', c: 'd', e: { f: 'g' } }; - var body = { a: 'b', c: 'd', e: { f: 'g' } }; - var callback = util.noop; - - ds.bigQuery.makeReq_ = function(m, p, q, b, c) { - assert.equal(m, method); - assert.deepEqual(q, query); - assert.deepEqual(b, body); - assert.equal(c, callback); - done(); - }; - - ds.makeReq_(method, '/path', query, body, callback); - }); - }); }); diff --git a/test/bigquery/index.js b/test/bigquery/index.js index 82f4cd81178..743ce56e46d 100644 --- a/test/bigquery/index.js +++ b/test/bigquery/index.js @@ -18,9 +18,12 @@ var arrify = require('arrify'); var assert = require('assert'); -var mockery = require('mockery'); var extend = require('extend'); -var util = require('../../lib/common/util'); +var mockery = require('mockery'); +var nodeutil = require('util'); + +var Service = require('../../lib/common/service.js'); +var util = require('../../lib/common/util.js'); var Table = require('../../lib/bigquery/table.js'); var fakeUtil = extend({}, util); @@ -50,6 +53,13 @@ var fakeStreamRouter = { } }; +function FakeService() { + this.calledWith_ = arguments; + Service.apply(this, arguments); +} + +nodeutil.inherits(FakeService, Service); + describe('BigQuery', function() { var JOB_ID = 'JOB_ID'; var PROJECT_ID = 'test-project'; @@ -59,13 +69,14 @@ describe('BigQuery', function() { before(function() { mockery.registerMock('./table.js', FakeTable); + mockery.registerMock('../common/service.js', FakeService); mockery.registerMock('../common/stream-router.js', fakeStreamRouter); mockery.registerMock('../common/util.js', fakeUtil); mockery.enable({ useCleanCache: true, warnOnUnregistered: false }); - BigQuery = require('../../lib/bigquery'); + BigQuery = require('../../lib/bigquery/index.js'); }); after(function() { @@ -100,31 +111,46 @@ describe('BigQuery', function() { fakeUtil.normalizeArguments = normalizeArguments; }); + + it('should inherit from Service', function() { + assert(bq instanceof Service); + + var calledWith = bq.calledWith_[0]; + + var baseUrl = 'https://www.googleapis.com/bigquery/v2'; + assert.strictEqual(calledWith.baseUrl, baseUrl); + assert.deepEqual(calledWith.scopes, [ + 'https://www.googleapis.com/auth/bigquery' + ]); + }); }); describe('createDataset', function() { var DATASET_ID = 'kittens'; it('should create a dataset', function(done) { - bq.makeReq_ = function(method, path, query, body) { - assert.equal(method, 'POST'); - assert.equal(path, '/datasets'); - assert.strictEqual(query, null); - assert.deepEqual(body, { + bq.request = function(reqOpts) { + assert.strictEqual(reqOpts.method, 'POST'); + assert.strictEqual(reqOpts.uri, '/datasets'); + assert.deepEqual(reqOpts.json, { datasetReference: { datasetId: DATASET_ID } }); + done(); }; + bq.createDataset(DATASET_ID, assert.ifError); }); it('should return an error to the callback', function(done) { var error = new Error('Error.'); - bq.makeReq_ = function(method, path, query, body, callback) { + + bq.request = function(reqOpts, callback) { callback(error); }; + bq.createDataset(DATASET_ID, function(err) { assert.equal(err, error); done(); @@ -132,9 +158,10 @@ describe('BigQuery', function() { }); it('should return a Dataset object', function(done) { - bq.makeReq_ = function(method, path, query, body, callback) { + bq.request = function(reqOpts, callback) { callback(null, {}); }; + bq.createDataset(DATASET_ID, function(err, dataset) { assert.ifError(err); assert.equal(dataset.constructor.name, 'Dataset'); @@ -144,9 +171,11 @@ describe('BigQuery', function() { it('should return an apiResponse', function(done) { var resp = { success: true }; - bq.makeReq_ = function(method, path, query, body, callback) { + + bq.request = function(reqOpts, callback) { callback(null, resp); }; + bq.createDataset(DATASET_ID, function(err, dataset, apiResponse) { assert.ifError(err); assert.deepEqual(apiResponse, resp); @@ -156,9 +185,11 @@ describe('BigQuery', function() { it('should assign metadata to the Dataset object', function(done) { var metadata = { a: 'b', c: 'd' }; - bq.makeReq_ = function(method, path, query, body, callback) { + + bq.request = function(reqOpts, callback) { callback(null, metadata); }; + bq.createDataset(DATASET_ID, function(err, dataset) { assert.ifError(err); assert.deepEqual(dataset.metadata, metadata); @@ -184,57 +215,64 @@ describe('BigQuery', function() { describe('getDatasets', function() { it('should get datasets from the api', function(done) { - bq.makeReq_ = function(method, path, query, body) { - assert.equal(method, 'GET'); - assert.equal(path, '/datasets'); - assert.deepEqual(query, {}); - assert.strictEqual(body, null); + bq.request = function(reqOpts) { + assert.strictEqual(reqOpts.uri, '/datasets'); + assert.deepEqual(reqOpts.qs, {}); + done(); }; + bq.getDatasets(assert.ifError); }); it('should accept query', function(done) { var queryObject = { all: true, maxResults: 8, pageToken: 'token' }; - bq.makeReq_ = function(method, path, query) { - assert.deepEqual(query, queryObject); + + bq.request = function(reqOpts) { + assert.strictEqual(reqOpts.qs, queryObject); done(); }; + bq.getDatasets(queryObject, assert.ifError); }); it('should return error to callback', function(done) { var error = new Error('Error.'); - bq.makeReq_ = function(method, path, query, body, callback) { + + bq.request = function(reqOpts, callback) { callback(error); }; + bq.getDatasets(function(err) { - assert.equal(err, error); + assert.strictEqual(err, error); done(); }); }); it('should return Dataset objects', function(done) { - bq.makeReq_ = function(method, path, query, body, callback) { + bq.request = function(reqOpts, callback) { callback(null, { datasets: [{ datasetReference: { datasetId: 'datasetName' } }] }); }; + bq.getDatasets(function(err, datasets) { assert.ifError(err); - assert.equal(datasets[0].constructor.name, 'Dataset'); + assert.strictEqual(datasets[0].constructor.name, 'Dataset'); done(); }); }); it('should return Dataset objects', function(done) { var resp = { success: true }; - bq.makeReq_ = function(method, path, query, body, callback) { + + bq.request = function(reqOpts, callback) { callback(null, resp); }; + bq.getDatasets(function(err, datasets, nextQuery, apiResponse) { assert.ifError(err); - assert.equal(apiResponse, resp); + assert.strictEqual(apiResponse, resp); done(); }); }); @@ -249,21 +287,25 @@ describe('BigQuery', function() { } } ]; - bq.makeReq_ = function(method, path, query, body, callback) { + + bq.request = function(reqOpts, callback) { callback(null, { datasets: datasetObjects }); }; + bq.getDatasets(function(err, datasets) { assert.ifError(err); - assert(datasets[0].metadata, datasetObjects[0]); + assert.strictEqual(datasets[0].metadata, datasetObjects[0]); done(); }); }); it('should return token if more results exist', function(done) { var token = 'token'; - bq.makeReq_ = function(method, path, query, body, callback) { + + bq.request = function(reqOpts, callback) { callback(null, { nextPageToken: token }); }; + bq.getDatasets(function(err, datasets, nextQuery) { assert.deepEqual(nextQuery, { pageToken: token @@ -275,13 +317,13 @@ describe('BigQuery', function() { describe('getJobs', function() { it('should get jobs from the api', function(done) { - bq.makeReq_ = function(method, path, query, body) { - assert.equal(method, 'GET'); - assert.equal(path, '/jobs'); - assert.deepEqual(query, {}); - assert.strictEqual(body, null); + bq.request = function(reqOpts) { + assert.equal(reqOpts.uri, '/jobs'); + assert.deepEqual(reqOpts.qs, {}); + done(); }; + bq.getJobs(assert.ifError); }); @@ -293,65 +335,77 @@ describe('BigQuery', function() { projection: 'full', stateFilter: 'done' }; - bq.makeReq_ = function(method, path, query) { - assert.deepEqual(query, queryObject); + + bq.request = function(reqOpts) { + assert.deepEqual(reqOpts.qs, queryObject); done(); }; + bq.getJobs(queryObject, assert.ifError); }); it('should return error to callback', function(done) { var error = new Error('Error.'); - bq.makeReq_ = function(method, path, query, body, callback) { + + bq.request = function(reqOpts, callback) { callback(error); }; + bq.getJobs(function(err) { - assert.equal(err, error); + assert.strictEqual(err, error); done(); }); }); it('should return Job objects', function(done) { - bq.makeReq_ = function(method, path, query, body, callback) { + bq.request = function(reqOpts, callback) { callback(null, { jobs: [{ id: JOB_ID }] }); }; + bq.getJobs(function(err, jobs) { assert.ifError(err); - assert.equal(jobs[0].constructor.name, 'Job'); + assert.strictEqual(jobs[0].constructor.name, 'Job'); done(); }); }); it('should return apiResponse', function(done) { var resp = { jobs: [{ id: JOB_ID }] }; - bq.makeReq_ = function(method, path, query, body, callback) { + + bq.request = function(reqOpts, callback) { callback(null, resp); }; + bq.getJobs(function(err, jobs, nextQuery, apiResponse) { assert.ifError(err); - assert.equal(resp, apiResponse); + assert.strictEqual(resp, apiResponse); done(); }); }); it('should assign metadata to the Job objects', function(done) { var jobObjects = [{ a: 'b', c: 'd', id: JOB_ID }]; - bq.makeReq_ = function(method, path, query, body, callback) { + + bq.request = function(reqOpts, callback) { callback(null, { jobs: jobObjects }); }; + bq.getJobs(function(err, jobs) { assert.ifError(err); - assert(jobs[0].metadata, jobObjects[0]); + assert.strictEqual(jobs[0].metadata, jobObjects[0]); done(); }); }); it('should return token if more results exist', function(done) { var token = 'token'; - bq.makeReq_ = function(method, path, query, body, callback) { + + bq.request = function(reqOpts, callback) { callback(null, { nextPageToken: token }); }; + bq.getJobs(function(err, jobs, nextQuery) { + assert.ifError(err); assert.deepEqual(nextQuery, { pageToken: token }); @@ -377,8 +431,8 @@ describe('BigQuery', function() { var QUERY_STRING = 'SELECT * FROM [dataset.table]'; it('should accept a string for a query', function(done) { - bq.makeReq_ = function(method, path, query, body) { - assert.equal(body.query, QUERY_STRING); + bq.request = function(reqOpts) { + assert.strictEqual(reqOpts.json.query, QUERY_STRING); done(); }; @@ -392,8 +446,8 @@ describe('BigQuery', function() { c: 'd' }; - bq.makeReq_ = function(method, path, query, body) { - assert.deepEqual(body, options); + bq.request = function(reqOpts) { + assert.strictEqual(reqOpts.json, options); done(); }; @@ -412,10 +466,9 @@ describe('BigQuery', function() { timeoutMs: 8 }; - bq.makeReq_ = function(method, path, query) { - assert.equal(method, 'GET'); - assert.equal(path, '/queries/' + JOB_ID); - assert.deepEqual(query, expectedRequestQuery); + bq.request = function(reqOpts) { + assert.strictEqual(reqOpts.uri, '/queries/' + JOB_ID); + assert.deepEqual(reqOpts.qs, expectedRequestQuery); done(); }; @@ -426,7 +479,7 @@ describe('BigQuery', function() { var options = {}; beforeEach(function() { - bq.makeReq_ = function(method, path, query, body, callback) { + bq.request = function(reqOpts, callback) { callback(null, { jobComplete: false, jobReference: { jobId: JOB_ID } @@ -468,7 +521,7 @@ describe('BigQuery', function() { var pageToken = 'token'; beforeEach(function() { - bq.makeReq_ = function(method, path, query, body, callback) { + bq.request = function(reqOpts, callback) { callback(null, { pageToken: pageToken, jobReference: { jobId: JOB_ID } @@ -506,7 +559,7 @@ describe('BigQuery', function() { done(); }; - bq.makeReq_ = function(method, path, query, body, callback) { + bq.request = function(reqOpts, callback) { callback(null, { jobReference: { jobId: JOB_ID }, rows: rows, @@ -520,7 +573,7 @@ describe('BigQuery', function() { it('should pass errors to the callback', function(done) { var error = new Error('Error.'); - bq.makeReq_ = function(method, path, query, body, callback) { + bq.request = function(reqOpts, callback) { callback(error); }; @@ -533,7 +586,7 @@ describe('BigQuery', function() { it('should return rows to the callback', function(done) { var ROWS = [{ a: 'b' }, { c: 'd' }]; - bq.makeReq_ = function(method, path, query, body, callback) { + bq.request = function(reqOpts, callback) { callback(null, { jobReference: { jobId: JOB_ID }, rows: [], @@ -571,7 +624,8 @@ describe('BigQuery', function() { beforeEach(function() { dataset = { bigQuery: bq, - id: 'dataset-id' + id: 'dataset-id', + createTable: util.noop }; }); @@ -585,8 +639,8 @@ describe('BigQuery', function() { }); it('should assign destination table to request body', function(done) { - bq.makeReq_ = function(method, path, query, body) { - assert.deepEqual(body.configuration.query.destinationTable, { + bq.request = function(reqOpts) { + assert.deepEqual(reqOpts.json.configuration.query.destinationTable, { datasetId: dataset.id, projectId: dataset.bigQuery.projectId, tableId: TABLE_ID @@ -602,7 +656,8 @@ describe('BigQuery', function() { }); it('should delete `destination` prop from request body', function(done) { - bq.makeReq_ = function(method, path, query, body) { + bq.request = function(reqOpts) { + var body = reqOpts.json; assert.strictEqual(body.configuration.query.destination, undefined); done(); }; @@ -617,8 +672,8 @@ describe('BigQuery', function() { it('should pass options to the request body', function(done) { var options = { a: 'b', c: 'd', query: 'query' }; - bq.makeReq_ = function(method, path, query, body) { - assert.deepEqual(body.configuration.query, options); + bq.request = function(reqOpts) { + assert.deepEqual(reqOpts.json.configuration.query, options); done(); }; @@ -626,11 +681,10 @@ describe('BigQuery', function() { }); it('should make the correct api request', function(done) { - bq.makeReq_ = function(method, path, query, body) { - assert.equal(method, 'POST'); - assert.equal(path, '/jobs'); - assert.strictEqual(query, null); - assert.deepEqual(body.configuration.query, { query: 'query' }); + bq.request = function(reqOpts) { + assert.equal(reqOpts.method, 'POST'); + assert.equal(reqOpts.uri, '/jobs'); + assert.deepEqual(reqOpts.json.configuration.query, { query: 'query' }); done(); }; @@ -640,7 +694,7 @@ describe('BigQuery', function() { it('should execute the callback with error', function(done) { var error = new Error('Error.'); - bq.makeReq_ = function(method, path, query, body, callback) { + bq.request = function(reqOpts, callback) { callback(error); }; @@ -653,7 +707,7 @@ describe('BigQuery', function() { it('should execute the callback with Job', function(done) { var jobsResource = { jobReference: { jobId: JOB_ID }, a: 'b', c: 'd' }; - bq.makeReq_ = function(method, path, query, body, callback) { + bq.request = function(reqOpts, callback) { callback(null, jobsResource); }; @@ -669,7 +723,7 @@ describe('BigQuery', function() { it('should execute the callback with apiResponse', function(done) { var jobsResource = { jobReference: { jobId: JOB_ID }, a: 'b', c: 'd' }; - bq.makeReq_ = function(method, path, query, body, callback) { + bq.request = function(reqOpts, callback) { callback(null, jobsResource); }; @@ -680,30 +734,4 @@ describe('BigQuery', function() { }); }); }); - - describe('makeReq_', function() { - var method = 'POST'; - var path = '/path'; - var query = { a: 'b', c: { d: 'e' } }; - var body = { hi: 'there' }; - - it('should make correct request', function(done) { - bq.makeAuthenticatedRequest_ = function(request) { - var basePath = 'https://www.googleapis.com/bigquery/v2/projects/'; - assert.equal(request.method, method); - assert.equal(request.uri, basePath + bq.projectId + path); - assert.deepEqual(request.qs, query); - assert.deepEqual(request.json, body); - done(); - }; - bq.makeReq_(method, path, query, body, assert.ifError); - }); - - it('should execute callback', function(done) { - bq.makeAuthenticatedRequest_ = function(request, callback) { - callback(); - }; - bq.makeReq_(method, path, query, body, done); - }); - }); }); diff --git a/test/bigquery/job.js b/test/bigquery/job.js index 1d02ca47485..902fbb80fce 100644 --- a/test/bigquery/job.js +++ b/test/bigquery/job.js @@ -17,17 +17,42 @@ 'use strict'; var assert = require('assert'); -var Job = require('../../lib/bigquery/job'); -var util = require('../../lib/common/util'); +var mockery = require('mockery'); +var nodeutil = require('util'); + +var ServiceObject = require('../../lib/common/service-object.js'); +var util = require('../../lib/common/util.js'); + +function FakeServiceObject() { + this.calledWith_ = arguments; + ServiceObject.apply(this, arguments); +} + +nodeutil.inherits(FakeServiceObject, ServiceObject); describe('BigQuery/Job', function() { var BIGQUERY = { - projectId: 'test-project', - makeReq_: util.noop + projectId: 'my-project' }; var JOB_ID = 'job_XYrk_3z'; + var Job; var job; + before(function() { + mockery.registerMock('../common/service-object.js', FakeServiceObject); + mockery.enable({ + useCleanCache: true, + warnOnUnregistered: false + }); + + Job = require('../../lib/bigquery/job.js'); + }); + + after(function() { + mockery.deregisterAll(); + mockery.disable(); + }); + beforeEach(function() { job = new Job(BIGQUERY, JOB_ID); }); @@ -37,69 +62,18 @@ describe('BigQuery/Job', function() { assert.deepEqual(job.bigQuery, BIGQUERY); }); - it('should assign the given id', function() { - assert.equal(job.id, JOB_ID); - }); + it('should inherit from ServiceObject', function() { + assert(job instanceof ServiceObject); - it('should assign empty metadata object', function() { - assert.equal(JSON.stringify(job.metadata), '{}'); - }); - }); - - describe('getMetadata', function() { - it('should get metadata from api', function(done) { - job.bigQuery.makeReq_ = function(method, path, query, body) { - assert.equal(method, 'GET'); - assert.equal(path, '/jobs/' + job.id); - assert.strictEqual(query, null); - assert.strictEqual(body, null); - done(); - }; - job.getMetadata(assert.ifError); - }); - - it('should execute callback with error', function(done) { - var error = new Error('Error.'); - job.bigQuery.makeReq_ = function(method, path, query, body, callback) { - callback(error); - }; - job.getMetadata(function(err) { - assert.equal(err, error); - done(); - }); - }); - - describe('metadata', function() { - var METADATA = { a: 'b', c: 'd' }; - - beforeEach(function() { - job.bigQuery.makeReq_ = function(method, path, query, body, callback) { - callback(null, METADATA); - }; - }); - - it('should update metadata on Dataset object', function(done) { - job.getMetadata(function(err) { - assert.ifError(err); - assert.deepEqual(job.metadata, METADATA); - done(); - }); - }); - - it('should execute callback with metadata', function(done) { - job.getMetadata(function(err, metadata) { - assert.ifError(err); - assert.deepEqual(metadata, METADATA); - done(); - }); - }); + var calledWith = job.calledWith_[0]; - it('should execute callback with apiResponse', function(done) { - job.getMetadata(function(err, metadata, apiResponse) { - assert.ifError(err); - assert.deepEqual(apiResponse, METADATA); - done(); - }); + assert.strictEqual(calledWith.parent, BIGQUERY); + assert.strictEqual(calledWith.baseUrl, '/jobs'); + assert.strictEqual(calledWith.id, JOB_ID); + assert.deepEqual(calledWith.methods, { + exists: true, + get: true, + getMetadata: true }); }); }); diff --git a/test/bigquery/table.js b/test/bigquery/table.js index 397e415488b..564d4ae4dae 100644 --- a/test/bigquery/table.js +++ b/test/bigquery/table.js @@ -20,12 +20,16 @@ var arrify = require('arrify'); var assert = require('assert'); var crypto = require('crypto'); var extend = require('extend'); -var File = require('../../lib/storage/file'); var mockery = require('mockery'); +var nodeutil = require('util'); var stream = require('stream'); -var util = require('../../lib/common/util'); + +var File = require('../../lib/storage/file.js'); +var ServiceObject = require('../../lib/common/service-object.js'); +var util = require('../../lib/common/util.js'); function FakeFile(a, b) { + this.request = util.noop; File.call(this, a, b); } @@ -51,15 +55,22 @@ var fakeStreamRouter = { } }; +function FakeServiceObject() { + this.calledWith_ = arguments; + ServiceObject.apply(this, arguments); +} + +nodeutil.inherits(FakeServiceObject, ServiceObject); + describe('BigQuery/Table', function() { var DATASET = { id: 'dataset-id', + createTable: util.noop, bigQuery: { - makeReq_: util.noop, + projectId: 'project-id', job: function(id) { return { id: id }; - }, - projectId: 'project-id' + } } }; @@ -79,15 +90,16 @@ describe('BigQuery/Table', function() { var tableOverrides = {}; before(function() { - mockery.registerMock('../storage/file', FakeFile); + mockery.registerMock('../storage/file.js', FakeFile); + mockery.registerMock('../common/service-object.js', FakeServiceObject); mockery.registerMock('../common/stream-router.js', fakeStreamRouter); - mockery.registerMock('../common/util', fakeUtil); + mockery.registerMock('../common/util.js', fakeUtil); mockery.enable({ useCleanCache: true, warnOnUnregistered: false }); - Table = require('../../lib/bigquery/table'); + Table = require('../../lib/bigquery/table.js'); var tableCached = extend(true, {}, Table); @@ -120,6 +132,33 @@ describe('BigQuery/Table', function() { it('should extend the correct methods', function() { assert(extended); // See `fakeStreamRouter.extend` }); + + it('should inherit from ServiceObject', function(done) { + var datasetInstance = extend({}, DATASET, { + createTable: { + bind: function(context) { + assert.strictEqual(context, datasetInstance); + done(); + } + } + }); + + var table = new Table(datasetInstance, TABLE_ID); + assert(table instanceof ServiceObject); + + var calledWith = table.calledWith_[0]; + + assert.strictEqual(calledWith.parent, datasetInstance); + assert.strictEqual(calledWith.baseUrl, '/tables'); + assert.strictEqual(calledWith.id, TABLE_ID); + assert.deepEqual(calledWith.methods, { + create: true, + delete: true, + exists: true, + get: true, + getMetadata: true + }); + }); }); describe('createSchemaFromString_', function() { @@ -179,11 +218,10 @@ describe('BigQuery/Table', function() { }); it('should send correct request to the API', function(done) { - table.bigQuery.makeReq_ = function(method, path, query, body) { - assert.equal(method, 'POST'); - assert.equal(path, '/jobs'); - assert.strictEqual(query, null); - assert.deepEqual(body, { + table.bigQuery.request = function(reqOpts) { + assert.equal(reqOpts.method, 'POST'); + assert.equal(reqOpts.uri, '/jobs'); + assert.deepEqual(reqOpts.json, { configuration: { copy: { a: 'b', @@ -201,6 +239,7 @@ describe('BigQuery/Table', function() { } } }); + done(); }; @@ -210,7 +249,7 @@ describe('BigQuery/Table', function() { it('should create and return a Job', function(done) { var jobId = 'job-id'; - table.bigQuery.makeReq_ = function(method, path, query, body, callback) { + table.bigQuery.request = function(reqOpts, callback) { callback(null, { jobReference: { jobId: jobId } }); }; @@ -224,7 +263,7 @@ describe('BigQuery/Table', function() { it('should assign metadata on the job', function(done) { var jobMetadata = { jobReference: { jobId: 'job-id' }, a: 'b', c: 'd' }; - table.bigQuery.makeReq_ = function(method, path, query, body, callback) { + table.bigQuery.request = function(reqOpts, callback) { callback(null, jobMetadata); }; @@ -236,7 +275,7 @@ describe('BigQuery/Table', function() { }); it('should accept just a destination and callback', function(done) { - table.bigQuery.makeReq_ = function(method, path, query, body, callback) { + table.bigQuery.request = function(reqOpts, callback) { callback(null, { jobReference: { jobId: 'job-id' } }); }; @@ -246,7 +285,7 @@ describe('BigQuery/Table', function() { it('should pass an error to the callback', function(done) { var error = new Error('Error.'); - table.bigQuery.makeReq_ = function(method, path, query, body, callback) { + table.bigQuery.request = function(reqOpts, callback) { callback(error); }; @@ -259,7 +298,7 @@ describe('BigQuery/Table', function() { it('should pass an apiResponse to the callback', function(done) { var jobMetadata = { jobReference: { jobId: 'job-id' }, a: 'b', c: 'd' }; - table.bigQuery.makeReq_ = function(method, path, query, body, callback) { + table.bigQuery.request = function(reqOpts, callback) { callback(null, jobMetadata); }; @@ -412,36 +451,10 @@ describe('BigQuery/Table', function() { }); }); - describe('delete', function() { - it('should send the correct API request to delete', function(done) { - table.makeReq_ = function(method, path, query, body, callback) { - assert.equal(method, 'DELETE'); - assert.equal(path, ''); - assert.strictEqual(query, null); - assert.strictEqual(body, null); - callback(); - }; - - table.delete(done); - }); - - it('should return apiResponse in callback', function(done) { - var resp = { success: true }; - table.makeReq_ = function(method, path, query, body, callback) { - callback(null, resp); - }; - - table.delete(function(err, apiResponse) { - assert.deepEqual(apiResponse, resp); - done(); - }); - }); - }); - describe('export', function() { var FILE = new FakeFile({ name: 'bucket-name', - makeReq_: util.noop + makeReq_: util.noop, }, 'file.json'); beforeEach(function() { @@ -451,15 +464,15 @@ describe('BigQuery/Table', function() { }); it('should send the correct API request', function(done) { - table.bigQuery.makeReq_ = function(method, path, query, body) { - assert.equal(method, 'POST'); - assert.equal(path, '/jobs'); - assert.strictEqual(query, null); - assert.deepEqual(body.configuration.extract.sourceTable, { + table.bigQuery.request = function(reqOpts) { + assert.equal(reqOpts.method, 'POST'); + assert.equal(reqOpts.uri, '/jobs'); + assert.deepEqual(reqOpts.json.configuration.extract.sourceTable, { datasetId: table.dataset.id, projectId: table.bigQuery.projectId, tableId: table.id }); + done(); }; @@ -467,7 +480,7 @@ describe('BigQuery/Table', function() { }); it('should accept just a destination and a callback', function(done) { - table.bigQuery.makeReq_ = function(method, path, query, body, callback) { + table.bigQuery.request = function(reqOpts, callback) { callback(null, { jobReference: { jobId: 'job-id' }}); }; @@ -475,8 +488,8 @@ describe('BigQuery/Table', function() { }); it('should parse out full gs:// urls from files', function(done) { - table.bigQuery.makeReq_ = function(method, path, query, body) { - assert.deepEqual(body.configuration.extract.destinationUris, [ + table.bigQuery.request = function(reqOpts) { + assert.deepEqual(reqOpts.json.configuration.extract.destinationUris, [ 'gs://' + FILE.bucket.name + '/' + FILE.name ]); done(); @@ -496,9 +509,9 @@ describe('BigQuery/Table', function() { }); it('should detect file format if a format is not provided', function(done) { - table.bigQuery.makeReq_ = function(method, path, query, body) { - var destinationFormat = body.configuration.extract.destinationFormat; - assert.equal(destinationFormat, 'NEWLINE_DELIMITED_JSON'); + table.bigQuery.request = function(reqOpts) { + var destFormat = reqOpts.json.configuration.extract.destinationFormat; + assert.equal(destFormat, 'NEWLINE_DELIMITED_JSON'); done(); }; @@ -506,9 +519,10 @@ describe('BigQuery/Table', function() { }); it('should assign the provided format if matched', function(done) { - table.bigQuery.makeReq_ = function(method, path, query, body) { - assert.equal(body.configuration.extract.destinationFormat, 'CSV'); - assert.strictEqual(body.configuration.extract.format, undefined); + table.bigQuery.request = function(reqOpts) { + var extract = reqOpts.json.configuration.extract; + assert.equal(extract.destinationFormat, 'CSV'); + assert.strictEqual(extract.format, undefined); done(); }; @@ -522,9 +536,9 @@ describe('BigQuery/Table', function() { }); it('should assign GZIP compression with gzip: true', function(done) { - table.bigQuery.makeReq_ = function(method, path, query, body) { - assert.equal(body.configuration.extract.compression, 'GZIP'); - assert.strictEqual(body.configuration.extract.gzip, undefined); + table.bigQuery.request = function(reqOpts) { + assert.equal(reqOpts.json.configuration.extract.compression, 'GZIP'); + assert.strictEqual(reqOpts.json.configuration.extract.gzip, undefined); done(); }; @@ -534,12 +548,12 @@ describe('BigQuery/Table', function() { it('should execute the callback with error', function(done) { var error = new Error('Error.'); - table.bigQuery.makeReq_ = function(method, path, query, body, callback) { + table.bigQuery.request = function(reqOpts, callback) { callback(error); }; table.export(FILE, function(err) { - assert.equal(err, error); + assert.strictEqual(err, error); done(); }); }); @@ -547,7 +561,7 @@ describe('BigQuery/Table', function() { it('should create a Job and returns it to the callback', function(done) { var jobMetadata = { jobReference: { jobId: 'job-id' }, a: 'b', c: 'd' }; - table.bigQuery.makeReq_ = function(method, path, query, body, callback) { + table.bigQuery.request = function(reqOpts, callback) { callback(null, jobMetadata); }; @@ -561,7 +575,7 @@ describe('BigQuery/Table', function() { it('should return apiResponse to callback', function(done) { var jobMetadata = { jobReference: { jobId: 'job-id' }, a: 'b', c: 'd' }; - table.bigQuery.makeReq_ = function(method, path, query, body, callback) { + table.bigQuery.request = function(reqOpts, callback) { callback(null, jobMetadata); }; @@ -573,67 +587,9 @@ describe('BigQuery/Table', function() { }); }); - describe('getMetadata', function() { - it('should get metadata from api', function(done) { - table.makeReq_ = function(method, path, query, body) { - assert.equal(method, 'GET'); - assert.equal(path, ''); - assert.strictEqual(query, null); - assert.strictEqual(body, null); - done(); - }; - table.getMetadata(assert.ifError); - }); - - it('should execute callback with error', function(done) { - var error = new Error('Error.'); - table.makeReq_ = function(method, path, query, body, callback) { - callback(error); - }; - table.getMetadata(function(err) { - assert.equal(err, error); - done(); - }); - }); - - describe('metadata', function() { - var METADATA = { a: 'b', c: 'd' }; - - beforeEach(function() { - table.makeReq_ = function(method, path, query, body, callback) { - callback(null, METADATA); - }; - }); - - it('should update metadata on Table object', function(done) { - table.getMetadata(function(err) { - assert.ifError(err); - assert.deepEqual(table.metadata, METADATA); - done(); - }); - }); - - it('should execute callback with metadata', function(done) { - table.getMetadata(function(err, metadata) { - assert.ifError(err); - assert.deepEqual(metadata, METADATA); - done(); - }); - }); - - it('should execute callback with apiResponse', function(done) { - table.getMetadata(function(err, metadata, apiResponse) { - assert.ifError(err); - assert.deepEqual(apiResponse, METADATA); - done(); - }); - }); - }); - }); - describe('getRows', function() { it('should accept just a callback', function(done) { - table.makeReq_ = function(method, path, query, body, callback) { + table.request = function(reqOpts, callback) { callback(null, {}); }; table.getRows(done); @@ -642,11 +598,9 @@ describe('BigQuery/Table', function() { it('should make correct API request', function(done) { var options = { a: 'b', c: 'd' }; - table.makeReq_ = function(method, path, query, body, callback) { - assert.equal(method, 'GET'); - assert.equal(path, '/data'); - assert.deepEqual(query, options); - assert.strictEqual(body, null); + table.request = function(reqOpts, callback) { + assert.strictEqual(reqOpts.uri, '/data'); + assert.strictEqual(reqOpts.qs, options); callback(null, {}); }; @@ -657,7 +611,7 @@ describe('BigQuery/Table', function() { var apiResponse = {}; var error = new Error('Error.'); - table.makeReq_ = function(method, path, query, body, callback) { + table.request = function(reqOpts, callback) { callback(error, apiResponse); }; @@ -677,7 +631,7 @@ describe('BigQuery/Table', function() { var schema = { fields: [{ name: 'name', type: 'string' }] }; beforeEach(function() { - table.makeReq_ = function(method, path, query, body, callback) { + table.request = function(reqOpts, callback) { // Respond with a row, so it grabs the schema. // Use setImmediate to let our getMetadata overwrite process. setImmediate(callback, null, { rows: rows }); @@ -730,7 +684,7 @@ describe('BigQuery/Table', function() { var schema = { fields: [{ name: 'name', type: 'string' }] }; table.metadata = { schema: schema }; - table.makeReq_ = function(method, path, query, body, callback) { + table.request = function(reqOpts, callback) { callback(null, { rows: rows }); }; @@ -746,7 +700,7 @@ describe('BigQuery/Table', function() { var schema = { fields: [{ name: 'name', type: 'string' }] }; table.metadata = { schema: schema }; - table.makeReq_ = function(method, path, query, body, callback) { + table.request = function(reqOpts, callback) { callback(null, { rows: rows }); }; @@ -764,7 +718,7 @@ describe('BigQuery/Table', function() { // Set a schema so it doesn't try to refresh the metadata. table.metadata = { schema: {} }; - table.makeReq_ = function(method, path, query, body, callback) { + table.request = function(reqOpts, callback) { callback(null, { pageToken: pageToken }); }; @@ -797,8 +751,8 @@ describe('BigQuery/Table', function() { return ws; }; - table.import(FILEPATH, function(error, job) { - assert.strictEqual(error, null); + table.import(FILEPATH, function(err, job) { + assert.strictEqual(err, null); assert.deepEqual(job, mockJob); done(); }); @@ -847,8 +801,8 @@ describe('BigQuery/Table', function() { }); it('should convert File objects to gs:// urls', function(done) { - table.bigQuery.makeReq_ = function(method, path, query, body) { - var sourceUri = body.configuration.load.sourceUris[0]; + table.bigQuery.request = function(reqOpts) { + var sourceUri = reqOpts.json.configuration.load.sourceUris[0]; assert.equal(sourceUri, 'gs://' + FILE.bucket.name + '/' + FILE.name); done(); }; @@ -857,8 +811,8 @@ describe('BigQuery/Table', function() { }); it('should infer the file format from a File object', function(done) { - table.bigQuery.makeReq_ = function(method, path, query, body) { - var sourceFormat = body.configuration.load.sourceFormat; + table.bigQuery.request = function(reqOpts) { + var sourceFormat = reqOpts.json.configuration.load.sourceFormat; assert.equal(sourceFormat, 'NEWLINE_DELIMITED_JSON'); done(); }; @@ -867,8 +821,8 @@ describe('BigQuery/Table', function() { }); it('should not override a provided format with a File', function(done) { - table.bigQuery.makeReq_ = function(method, path, query, body) { - var sourceFormat = body.configuration.load.sourceFormat; + table.bigQuery.request = function(reqOpts) { + var sourceFormat = reqOpts.json.configuration.load.sourceFormat; assert.equal(sourceFormat, 'CSV'); done(); }; @@ -879,7 +833,7 @@ describe('BigQuery/Table', function() { it('should execute the callback with error', function(done) { var error = new Error('Error.'); - table.bigQuery.makeReq_ = function(method, path, query, body, callback) { + table.bigQuery.request = function(reqOpts, callback) { callback(error); }; @@ -892,7 +846,7 @@ describe('BigQuery/Table', function() { it('should create a Job and return it to the callback', function(done) { var jobMetadata = { jobReference: { jobId: 'job-id' }, a: 'b', c: 'd' }; - table.bigQuery.makeReq_ = function(method, path, query, body, callback) { + table.bigQuery.request = function(reqOpts, callback) { callback(null, jobMetadata); }; @@ -906,7 +860,7 @@ describe('BigQuery/Table', function() { it('should return apiResponse to callback', function(done) { var jobMetadata = { jobReference: { jobId: 'job-id' }, a: 'b', c: 'd' }; - table.bigQuery.makeReq_ = function(method, path, query, body, callback) { + table.bigQuery.request = function(reqOpts, callback) { callback(null, jobMetadata); }; @@ -939,11 +893,10 @@ describe('BigQuery/Table', function() { }; it('should save data', function(done) { - table.makeReq_ = function(method, path, query, body) { - assert.equal(method, 'POST'); - assert.equal(path, '/insertAll'); - assert.strictEqual(query, null); - assert.deepEqual(body, dataApiFormat); + table.request = function(reqOpts) { + assert.equal(reqOpts.method, 'POST'); + assert.equal(reqOpts.uri, '/insertAll'); + assert.deepEqual(reqOpts.json, dataApiFormat); done(); }; @@ -953,7 +906,7 @@ describe('BigQuery/Table', function() { it('should execute callback with API response', function(done) { var apiResponse = { insertErrors: [] }; - table.makeReq_ = function(method, path, query, body, callback) { + table.request = function(reqOpts, callback) { callback(null, apiResponse); }; @@ -969,7 +922,7 @@ describe('BigQuery/Table', function() { var error = new Error('Error.'); var apiResponse = {}; - table.makeReq_ = function(method, path, query, body, callback) { + table.request = function(reqOpts, callback) { callback(error, apiResponse); }; @@ -985,7 +938,7 @@ describe('BigQuery/Table', function() { var row0Error = { message: 'Error.', reason: 'notFound' }; var row1Error = { message: 'Error.', reason: 'notFound' }; - table.makeReq_ = function(method, path, query, body, callback) { + table.request = function(reqOpts, callback) { callback(null, { insertErrors: [ { index: 0, errors: [row0Error] }, @@ -1023,28 +976,30 @@ describe('BigQuery/Table', function() { var METADATA = { a: 'b', c: 'd' }; it('should send request to the api', function(done) { - table.makeReq_ = function(method, path, query, body) { - assert.equal(method, 'PUT'); - assert.equal(path, ''); - assert.strictEqual(query, null); - assert.deepEqual(body, METADATA); + table.request = function(reqOpts) { + assert.strictEqual(reqOpts.method, 'PUT'); + assert.strictEqual(reqOpts.uri, ''); + assert.deepEqual(reqOpts.json, METADATA); done(); }; + table.setMetadata(METADATA, assert.ifError); }); it('should convert a name to a friendly name', function(done) { var name = 'a new name'; - table.makeReq_ = function(method, path, query, body) { - assert.equal(body.friendlyName, name); + + table.request = function(reqOpts) { + assert.equal(reqOpts.json.friendlyName, name); done(); }; + table.setMetadata({ name: name }, assert.ifError); }); it('should accept a schema', function(done) { - table.makeReq_ = function(method, path, query, body) { - assert.deepEqual(body.schema, { + table.request = function(reqOpts) { + assert.deepEqual(reqOpts.json.schema, { fields: [{ name: 'schema', type: 'string' }] }); done(); @@ -1056,7 +1011,7 @@ describe('BigQuery/Table', function() { var error = new Error('Error.'); var apiResponse = {}; - table.makeReq_ = function(method, path, query, body, callback) { + table.request = function(reqOpts, callback) { callback(error, apiResponse); }; @@ -1069,7 +1024,7 @@ describe('BigQuery/Table', function() { describe('metadata', function() { beforeEach(function() { - table.makeReq_ = function(method, path, query, body, callback) { + table.request = function(reqOpts, callback) { callback(null, METADATA); }; }); @@ -1099,34 +1054,4 @@ describe('BigQuery/Table', function() { }); }); }); - - describe('makeReq_', function() { - it('should prefix the path', function(done) { - var path = '/test-path'; - - table.dataset.makeReq_ = function(method, p) { - assert.equal(p, '/tables/' + table.id + path); - done(); - }; - - table.makeReq_('POST', path); - }); - - it('should pass through arguments', function(done) { - var method = 'POST'; - var query = { a: 'b', c: 'd', e: { f: 'g' } }; - var body = { a: 'b', c: 'd', e: { f: 'g' } }; - var callback = util.noop; - - table.dataset.makeReq_ = function(m, p, q, b, c) { - assert.equal(m, method); - assert.deepEqual(q, query); - assert.deepEqual(b, body); - assert.equal(c, callback); - done(); - }; - - table.makeReq_(method, '/path', query, body, callback); - }); - }); });