From 2fbac9316ce77951cef178a15218932afd21af6e Mon Sep 17 00:00:00 2001
From: Ryan Seys
Date: Fri, 19 Sep 2014 02:39:07 -0400
Subject: [PATCH 1/8] Refactor Transaction and Dataset
---
lib/datastore/dataset.js | 127 +----------
lib/datastore/datastore_request.js | 330 +++++++++++++++++++++++++++++
lib/datastore/transaction.js | 312 +--------------------------
test/datastore/dataset.js | 28 +--
test/datastore/transaction.js | 8 +-
5 files changed, 366 insertions(+), 439 deletions(-)
create mode 100644 lib/datastore/datastore_request.js
diff --git a/lib/datastore/dataset.js b/lib/datastore/dataset.js
index 35290fc1367..2f1a53c075f 100644
--- a/lib/datastore/dataset.js
+++ b/lib/datastore/dataset.js
@@ -55,6 +55,7 @@ var Transaction = require('./transaction.js');
* @private
*/
var util = require('../common/util.js');
+var nodeutil = require('util');
/**
* Scopes for Google Datastore access.
@@ -66,6 +67,8 @@ var SCOPES = [
'https://www.googleapis.com/auth/userinfo.email'
];
+var DatastoreRequester = require('./datastore_request.js');
+
/**
* Interact with a dataset from the
* [Google Cloud Datastore]{@link https://developers.google.com/datastore/}.
@@ -101,11 +104,13 @@ function Dataset(options) {
keyFilename: options.keyFilename,
scopes: SCOPES
});
+
this.projectId = options.projectId;
this.namespace = options.namespace;
- this.transaction = this.createTransaction_();
}
+nodeutil.inherits(Dataset, DatastoreRequester);
+
/**
* Helper to create a Key object, scoped to the dataset's namespace by default.
*
@@ -166,117 +171,6 @@ Dataset.prototype.createQuery = function(namespace, kinds) {
return new Query(namespace, util.arrayize(kinds));
};
-/**
- * Retrieve the entities identified with the specified key(s) in the current
- * transaction. Get operations require a valid key to retrieve the
- * key-identified entity from Datastore.
- *
- * @borrows {module:datastore/transaction#get} as get
- *
- * @param {Key|Key[]} key - Datastore key object(s).
- * @param {function} callback - The callback function.
- *
- * @example
- * dataset.get([
- * dataset.key(['Company', 123]),
- * dataset.key(['Product', 'Computer'])
- * ], function(err, entities) {});
- */
-Dataset.prototype.get = function(key, callback) {
- this.transaction.get(key, callback);
-};
-
-/**
- * Insert or update the specified object(s) in the current transaction. If a
- * key is incomplete, its associated object is inserted and its generated
- * identifier is returned to the callback.
- *
- * @borrows {module:datastore/transaction#save} as save
- *
- * @param {object|object[]} entities - Datastore key object(s).
- * @param {Key} entities.key - Datastore key object.
- * @param {object} entities.data - Data to save with the provided key.
- * @param {function} callback - The callback function.
- *
- * @example
- * // Save a single entity.
- * dataset.save({
- * key: dataset.key('Company'),
- * data: {
- * rating: '10'
- * }
- * }, function(err, key) {
- * // Because we gave an incomplete key as an argument, `key` will be
- * // populated with the complete, generated key.
- * });
- *
- * // Save multiple entities at once.
- * dataset.save([
- * {
- * key: dataset.key(['Company', 123]),
- * data: {
- * HQ: 'Dallas, TX'
- * }
- * },
- * {
- * key: dataset.key(['Product', 'Computer']),
- * data: {
- * vendor: 'Dell'
- * }
- * }
- * ], function(err, keys) {});
- */
-Dataset.prototype.save = function(key, obj, callback) {
- this.transaction.save(key, obj, callback);
-};
-
-/**
- * Delete all entities identified with the specified key(s) in the current
- * transaction.
- *
- * @param {Key|Key[]} key - Datastore key object(s).
- * @param {function} callback - The callback function.
- *
- * @borrows {module:datastore/transaction#delete} as delete
- *
- * @example
- * // Delete a single entity.
- * dataset.delete(dataset.key(['Company', 123]), function(err) {});
- *
- * // Delete multiple entities at once.
- * dataset.delete([
- * dataset.key(['Company', 123]),
- * dataset.key(['Product', 'Computer'])
- * ], function(err) {});
- */
-Dataset.prototype.delete = function(key, callback) {
- this.transaction.delete(key, callback);
-};
-
-/**
- * Datastore allows you to query entities by kind, filter them by property
- * filters, and sort them by a property name. Projection and pagination are also
- * supported. If more results are available, a query to retrieve the next page
- * is provided to the callback function.
- *
- * @borrows {module:datastore/transaction#runQuery} as runQuery
- *
- * @param {module:datastore/query} query - Query object.
- * @param {function} callback - The callback function.
- *
- * @example
- * // Retrieve 5 companies.
- * dataset.runQuery(queryObject, function(err, entities, nextQuery) {
- * // `nextQuery` is not null if there are more results.
- * if (nextQuery) {
- * dataset.runQuery(nextQuery, function(err, entities, nextQuery) {});
- * }
- * });
- */
-Dataset.prototype.runQuery = function(q, callback) {
- this.transaction.runQuery(q, callback);
-};
-
/**
* Run a function in the context of a new transaction. Transactions allow you to
* perform multiple operations, committing your changes atomically.
@@ -342,7 +236,8 @@ Dataset.prototype.allocateIds = function(incompleteKey, n, callback) {
for (var i = 0; i < n; i++) {
incompleteKeys.push(entity.keyToKeyProto(incompleteKey));
}
- this.transaction.makeReq(
+
+ this.createRequest(
'allocateIds',
new pb.AllocateIdsRequest({ key: incompleteKeys }),
pb.AllocateIdsResponse, function(err, resp) {
@@ -358,12 +253,6 @@ Dataset.prototype.allocateIds = function(incompleteKey, n, callback) {
});
};
-/**
- * Create a new Transaction object using the existing connection and dataset.
- *
- * @return {module:datastore/transaction}
- * @private
- */
Dataset.prototype.createTransaction_ = function() {
return new Transaction(this.connection, this.projectId);
};
diff --git a/lib/datastore/datastore_request.js b/lib/datastore/datastore_request.js
new file mode 100644
index 00000000000..0a34ca46559
--- /dev/null
+++ b/lib/datastore/datastore_request.js
@@ -0,0 +1,330 @@
+/*!
+ * Copyright 2014 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+var https = require('https');
+
+/** @type module:datastore/entity */
+var entity = require('./entity.js');
+
+/** @type module:datastore/pb */
+var pb = require('./pb.js');
+
+/** @type module:common/util */
+var util = require('../common/util.js');
+
+/** @const {string} Host to send with API requests. */
+var GOOGLE_APIS_HOST = 'www.googleapis.com';
+
+/** @const {string} Non-transaction mode key. */
+var MODE_NON_TRANSACTIONAL = 'NON_TRANSACTIONAL';
+
+/** @const {string} Transaction mode key. */
+var MODE_TRANSACTIONAL = 'TRANSACTIONAL';
+
+
+/**
+ * @type module:common/util
+ * @private
+ */
+var util = require('../common/util.js');
+
+function DatastoreRequester() {}
+
+/**
+ * Retrieve the entities identified with the specified key(s) in the current
+ * transaction. Get operations require a valid key to retrieve the
+ * key-identified entity from Datastore.
+ *
+ * @param {Key|Key[]} key - Datastore key object(s).
+ * @param {function} callback - The callback function.
+ *
+ * @example
+ * // These examples work with both a Transaction object and a Dataset object.
+ *
+ * // Get a single entity.
+ * transaction.get(dataset.key(['Company', 123]), function(err, entity) {});
+ *
+ * // Get multiple entities at once.
+ * transaction.get([
+ * dataset.key(['Company', 123]),
+ * dataset.key(['Product', 'Computer'])
+ * ], function(err, entities) {});
+ */
+DatastoreRequester.prototype.get = function(keys, callback) {
+ var isMultipleRequest = Array.isArray(keys);
+ keys = isMultipleRequest ? keys : [keys];
+ callback = callback || util.noop;
+ var req = new pb.LookupRequest({
+ key: keys.map(entity.keyToKeyProto)
+ });
+ var res = pb.LookupResponse;
+ if (this.id) {
+ req.transaction = this.id;
+ }
+ this.createRequest('lookup', req, res, function(err, resp) {
+ if (err) {
+ callback(err);
+ return;
+ }
+ var found = entity.formatArray(resp.found);
+ if (isMultipleRequest && resp.deferred && resp.deferred.length) {
+ // There may be more results. Call `.get` again, and append the results.
+ this.get(
+ resp.deferred.map(entity.keyFromKeyProto), function (err, entities) {
+ if (err) {
+ callback(err);
+ return;
+ }
+ if (resp) {
+ found = (found || []).concat(entities);
+ }
+ callback(null, found);
+ });
+ return;
+ }
+ callback(null, isMultipleRequest ? found : found[0]);
+ }.bind(this));
+};
+
+/**
+ * Insert or update the specified object(s) in the current transaction. If a
+ * key is incomplete, its associated object is inserted and its generated
+ * identifier is returned to the callback.
+ *
+ * @param {object|object[]} entities - Datastore key object(s).
+ * @param {Key} entities.key - Datastore key object.
+ * @param {object} entities.data - Data to save with the provided key.
+ * @param {function} callback - The callback function.
+ *
+ * @example
+ * // These examples work with both a Transaction object and a Dataset object.
+ *
+ * // Save a single entity.
+ * transaction.save({
+ * key: dataset.key('Company'),
+ * data: {
+ * rating: '10'
+ * }
+ * }, function(err, key) {
+ * // Because we gave an incomplete key as an argument, `key` will be
+ * // populated with the complete, generated key.
+ * });
+ *
+ * // Save multiple entities at once.
+ * transaction.save([
+ * {
+ * key: dataset.key(['Company', 123]),
+ * data: {
+ * HQ: 'Dallas, TX'
+ * }
+ * },
+ * {
+ * key: dataset.key(['Product', 'Computer']),
+ * data: {
+ * vendor: 'Dell'
+ * }
+ * }
+ * ], function(err, keys) {});
+ */
+DatastoreRequester.prototype.save = function(entities, callback) {
+ var isMultipleRequest = Array.isArray(entities);
+ entities = isMultipleRequest ? entities : [entities];
+ var insertIndexes = [];
+ var keys = entities.map(function(entityObject) {
+ return entityObject.key;
+ });
+ var req = {
+ mode: MODE_NON_TRANSACTIONAL,
+ mutation: entities.reduce(function(acc, entityObject, index) {
+ var ent = entity.entityToEntityProto(entityObject.data);
+ ent.key = entity.keyToKeyProto(entityObject.key);
+ if (entity.isKeyComplete(entityObject.key)) {
+ acc.upsert.push(ent);
+ } else {
+ insertIndexes.push(index);
+ acc.insert_auto_id.push(ent);
+ }
+ return acc;
+ }.bind(this), { upsert: [], insert_auto_id: [] })
+ };
+ if (this.id) {
+ req.transaction = this.id;
+ req.mode = MODE_TRANSACTIONAL;
+ }
+ req = new pb.CommitRequest(req);
+ var res = pb.CommitResponse;
+ this.createRequest('commit', req, res, function(err, resp) {
+ if (err || !resp) {
+ callback(err);
+ return;
+ }
+ var autoInserted = (resp.mutation_result.insert_auto_id_key || []);
+ autoInserted.forEach(function(key, index) {
+ keys[insertIndexes[index]] = entity.keyFromKeyProto(key);
+ });
+ callback(null, isMultipleRequest ? keys : keys[0]);
+ });
+};
+
+/**
+ * Delete all entities identified with the specified key(s) in the current
+ * transaction.
+ *
+ * @param {Key|Key[]} key - Datastore key object(s).
+ * @param {function} callback - The callback function.
+ *
+ * @example
+ * // These examples work with both a Transaction object and a Dataset object.
+ *
+ * // Delete a single entity.
+ * transaction.delete(dataset.key(['Company', 123]), function(err) {});
+ *
+ * // Delete multiple entities at once.
+ * transaction.delete([
+ * dataset.key(['Company', 123]),
+ * dataset.key(['Product', 'Computer'])
+ * ], function(err) {});
+ */
+DatastoreRequester.prototype.delete = function(keys, callback) {
+ var isMultipleRequest = Array.isArray(keys);
+ keys = isMultipleRequest ? keys : [keys];
+ callback = callback || util.noop;
+
+ var req = {
+ mode: MODE_NON_TRANSACTIONAL,
+ mutation: {
+ delete: keys.map(entity.keyToKeyProto)
+ }
+ };
+ if (this.id) {
+ req.transaction = this.id;
+ req.mode = MODE_TRANSACTIONAL;
+ }
+ req = new pb.CommitRequest(req);
+ var res = pb.CommitResponse;
+ this.createRequest('commit', req, res, callback);
+};
+
+/**
+ * Datastore allows you to query entities by kind, filter them by property
+ * filters, and sort them by a property name. Projection and pagination are also
+ * supported. If more results are available, a query to retrieve the next page
+ * is provided to the callback function.
+ *
+ * @param {module:datastore/query} query - Query object.
+ * @param {function} callback - The callback function.
+ *
+ * @example
+ * // Retrieve 5 companies.
+ * transaction.runQuery(queryObject, function(err, entities, nextQuery) {
+ * // `nextQuery` is not null if there are more results.
+ * if (nextQuery) {
+ * transaction.runQuery(nextQuery, function(err, entities, nextQuery) {});
+ * }
+ * });
+ */
+
+DatastoreRequester.prototype.runQuery = function(q, callback) {
+ callback = callback || util.noop;
+ var req = {
+ read_options: {},
+ query: entity.queryToQueryProto(q)
+ };
+
+ if(this.id) {
+ req.read_options.transaction = this.id;
+ }
+ if (q.namespace) {
+ req.partition_id = {
+ namespace: q.namespace
+ };
+ }
+ req = new pb.RunQueryRequest(req);
+ var res = pb.RunQueryResponse;
+
+ this.createRequest('runQuery', req, res, function(err, resp) {
+ if (err || !resp.batch || !resp.batch.entity_result) {
+ callback(err);
+ return;
+ }
+ var nextQuery = null;
+ if (resp.batch.end_cursor) {
+ var cursor = resp.batch.end_cursor.toBase64();
+ if (cursor !== q.startVal) {
+ nextQuery = q.start(cursor).offset(0);
+ }
+ }
+ callback(null, entity.formatArray(resp.batch.entity_result), nextQuery);
+ });
+};
+
+
+/**
+ * Make a request to the API endpoint.
+ *
+ * @param {string} method - Transaction action (allocateIds, commit, etc.).
+ * @param {object} req - Request configuration object.
+ * @param {function} callbcak - The callback function.
+ *
+ * @example
+ * var deleteRequest = {
+ * MODE: 'NON_TRANSACTIONAL',
+ * mutation: {
+ * delete: [] // datastore key objects.
+ * }
+ * };
+ * transaction.makeReq('commit', deleteRequest, function(err) {});
+ */
+DatastoreRequester.prototype.createRequest =
+ function(method, req, respType, cb) {
+ // TODO: Handle non-HTTP 200 cases.
+ cb = cb || util.noop;
+ this.connection.createAuthorizedReq({
+ method: 'POST',
+ host: GOOGLE_APIS_HOST,
+ path: '/datastore/v1beta2/datasets/' + this.projectId + '/' + method,
+ headers: {
+ 'content-type': 'application/x-protobuf'
+ }
+ }, function(err, request) {
+ if (err) {
+ cb(err);
+ return;
+ }
+ var remoteStream = https.request(request, function(resp) {
+ var buffer = new Buffer('');
+ resp.on('data', function(chunk) {
+ buffer = Buffer.concat([buffer, chunk]);
+ });
+ resp.on('end', function() {
+ util.handleResp(null, resp, buffer.toString(), function(err) {
+ if (err) {
+ cb(err);
+ return;
+ }
+ cb(null, respType.decode(buffer));
+ });
+ });
+ });
+ remoteStream.on('error', cb);
+ remoteStream.write(req.toBuffer());
+ remoteStream.end();
+ });
+};
+
+module.exports = DatastoreRequester;
diff --git a/lib/datastore/transaction.js b/lib/datastore/transaction.js
index db9db825a9d..b20f21ba30a 100644
--- a/lib/datastore/transaction.js
+++ b/lib/datastore/transaction.js
@@ -21,25 +21,15 @@
'use strict';
-var https = require('https');
-
-/** @type module:datastore/entity */
-var entity = require('./entity.js');
-
/** @type module:datastore/pb */
var pb = require('./pb.js');
/** @type module:common/util */
var util = require('../common/util.js');
-/** @const {string} Host to send with API requests. */
-var GOOGLE_APIS_HOST = 'www.googleapis.com';
-
-/** @const {string} Non-transaction mode key. */
-var MODE_NON_TRANSACTIONAL = 'NON_TRANSACTIONAL';
+var nodeutil = require('util');
-/** @const {string} Transaction mode key. */
-var MODE_TRANSACTIONAL = 'TRANSACTIONAL';
+var DatastoreRequester = require('./datastore_request.js');
/**
* Build a Transaction object. Transactions will generally be built for you by
@@ -53,7 +43,7 @@ var MODE_TRANSACTIONAL = 'TRANSACTIONAL';
*
* @param {module:common/connection.Connection} conn - An authorized connection
* to Google Cloud Datastore.
- * @param {string} datasetId - Dataset ID. This is your project ID from the
+ * @param {string} projectId - Dataset ID. This is your project ID from the
* Google Developers Console.
*
* @example
@@ -61,15 +51,17 @@ var MODE_TRANSACTIONAL = 'TRANSACTIONAL';
* var myConnection = new Connection({});
* var transaction = new Transaction(myConnection, 'my-project-id');
*/
-function Transaction(conn, datasetId) {
+function Transaction(conn, projectId) {
this.conn = conn;
- this.datasetId = datasetId;
+ this.projectId = projectId;
// the default transaction has no id.
// if id is not set, run operations non-transactional.
this.id = null;
this.isFinalized = false;
}
+nodeutil.inherits(Transaction, DatastoreRequester);
+
/**
* Begin a remote transaction and identify the current transaction instance with
* the remote transaction's ID.
@@ -94,7 +86,7 @@ Transaction.prototype.begin = function(callback) {
var that = this;
var req = new pb.BeginTransactionRequest();
var res = pb.BeginTransactionResponse;
- this.makeReq('beginTransaction', req, res, function(err, resp) {
+ this.createRequest('beginTransaction', req, res, function(err, resp) {
if (err) {
callback(err);
return;
@@ -123,7 +115,7 @@ Transaction.prototype.rollback = function(callback) {
var that = this;
var req = new pb.RollbackRequest({ transaction: this.id });
var res = pb.RollbackResponse;
- this.makeReq('rollback', req, res, function(err) {
+ this.createRequest('rollback', req, res, function(err) {
if (err) {
callback(err);
return;
@@ -152,7 +144,7 @@ Transaction.prototype.commit = function(callback) {
var that = this;
var req = new pb.CommitRequest({ transaction: this.id });
var res = pb.CommitResponse;
- this.makeReq('commit', req, res, function(err) {
+ this.createRequest('commit', req, res, function(err) {
if (err) {
callback(err);
return;
@@ -184,238 +176,6 @@ Transaction.prototype.finalize = function(callback) {
setImmediate(callback);
};
-/**
- * Retrieve the entities identified with the specified key(s) in the current
- * transaction. Get operations require a valid key to retrieve the
- * key-identified entity from Datastore.
- *
- * @param {Key|Key[]} key - Datastore key object(s).
- * @param {function} callback - The callback function.
- *
- * @example
- * // These examples work with both a Transaction object and a Dataset object.
- *
- * // Get a single entity.
- * transaction.get(dataset.key(['Company', 123]), function(err, entity) {});
- *
- * // Get multiple entities at once.
- * transaction.get([
- * dataset.key(['Company', 123]),
- * dataset.key(['Product', 'Computer'])
- * ], function(err, entities) {});
- */
-Transaction.prototype.get = function(keys, callback) {
- var isMultipleRequest = Array.isArray(keys);
- keys = isMultipleRequest ? keys : [keys];
- callback = callback || util.noop;
- var req = new pb.LookupRequest({
- key: keys.map(entity.keyToKeyProto)
- });
- var res = pb.LookupResponse;
- if (this.id) {
- req.transaction = this.id;
- }
- this.makeReq('lookup', req, res, function(err, resp) {
- if (err) {
- callback(err);
- return;
- }
- var found = entity.formatArray(resp.found);
- if (isMultipleRequest && resp.deferred && resp.deferred.length) {
- // There may be more results. Call `.get` again, and append the results.
- this.get(
- resp.deferred.map(entity.keyFromKeyProto), function (err, entities) {
- if (err) {
- callback(err);
- return;
- }
- if (resp) {
- found = (found || []).concat(entities);
- }
- callback(null, found);
- });
- return;
- }
- callback(null, isMultipleRequest ? found : found[0]);
- }.bind(this));
-};
-
-/**
- * Insert or update the specified object(s) in the current transaction. If a
- * key is incomplete, its associated object is inserted and its generated
- * identifier is returned to the callback.
- *
- * @param {object|object[]} entities - Datastore key object(s).
- * @param {Key} entities.key - Datastore key object.
- * @param {object} entities.data - Data to save with the provided key.
- * @param {function} callback - The callback function.
- *
- * @example
- * // These examples work with both a Transaction object and a Dataset object.
- *
- * // Save a single entity.
- * transaction.save({
- * key: dataset.key('Company'),
- * data: {
- * rating: '10'
- * }
- * }, function(err, key) {
- * // Because we gave an incomplete key as an argument, `key` will be
- * // populated with the complete, generated key.
- * });
- *
- * // Save multiple entities at once.
- * transaction.save([
- * {
- * key: dataset.key(['Company', 123]),
- * data: {
- * HQ: 'Dallas, TX'
- * }
- * },
- * {
- * key: dataset.key(['Product', 'Computer']),
- * data: {
- * vendor: 'Dell'
- * }
- * }
- * ], function(err, keys) {});
- */
-Transaction.prototype.save = function(entities, callback) {
- var isMultipleRequest = Array.isArray(entities);
- entities = isMultipleRequest ? entities : [entities];
- var insertIndexes = [];
- var keys = entities.map(function(entityObject) {
- return entityObject.key;
- });
- var req = {
- mode: MODE_NON_TRANSACTIONAL,
- mutation: entities.reduce(function(acc, entityObject, index) {
- var ent = entity.entityToEntityProto(entityObject.data);
- ent.key = entity.keyToKeyProto(entityObject.key);
- if (entity.isKeyComplete(entityObject.key)) {
- acc.upsert.push(ent);
- } else {
- insertIndexes.push(index);
- acc.insert_auto_id.push(ent);
- }
- return acc;
- }.bind(this), { upsert: [], insert_auto_id: [] })
- };
- if (this.id) {
- req.transaction = this.id;
- req.mode = MODE_TRANSACTIONAL;
- }
- req = new pb.CommitRequest(req);
- var res = pb.CommitResponse;
- this.makeReq('commit', req, res, function(err, resp) {
- if (err || !resp) {
- callback(err);
- return;
- }
- if (this.id) {
- this.isFinalized = true;
- }
- var autoInserted = (resp.mutation_result.insert_auto_id_key || []);
- autoInserted.forEach(function(key, index) {
- keys[insertIndexes[index]] = entity.keyFromKeyProto(key);
- });
- callback(null, isMultipleRequest ? keys : keys[0]);
- }.bind(this));
-};
-
-/**
- * Delete all entities identified with the specified key(s) in the current
- * transaction.
- *
- * @param {Key|Key[]} key - Datastore key object(s).
- * @param {function} callback - The callback function.
- *
- * @example
- * // These examples work with both a Transaction object and a Dataset object.
- *
- * // Delete a single entity.
- * transaction.delete(dataset.key(['Company', 123]), function(err) {});
- *
- * // Delete multiple entities at once.
- * transaction.delete([
- * dataset.key(['Company', 123]),
- * dataset.key(['Product', 'Computer'])
- * ], function(err) {});
- */
-Transaction.prototype.delete = function(keys, callback) {
- var isMultipleRequest = Array.isArray(keys);
- keys = isMultipleRequest ? keys : [keys];
- callback = callback || util.noop;
-
- var req = {
- mode: MODE_NON_TRANSACTIONAL,
- mutation: {
- delete: keys.map(entity.keyToKeyProto)
- }
- };
- if (this.id) {
- req.transaction = this.id;
- req.mode = MODE_TRANSACTIONAL;
- }
- req = new pb.CommitRequest(req);
- var res = pb.CommitResponse;
- this.makeReq('commit', req, res, function(err, response) {
- if (this.id) {
- this.isFinalized = true;
- }
- callback(err, response);
- }.bind(this));
-};
-
-/**
- * Datastore allows you to query entities by kind, filter them by property
- * filters, and sort them by a property name. Projection and pagination are also
- * supported. If more results are available, a query to retrieve the next page
- * is provided to the callback function.
- *
- * @param {module:datastore/query} query - Query object.
- * @param {function} callback - The callback function.
- *
- * @example
- * // Retrieve 5 companies.
- * transaction.runQuery(queryObject, function(err, entities, nextQuery) {
- * // `nextQuery` is not null if there are more results.
- * if (nextQuery) {
- * transaction.runQuery(nextQuery, function(err, entities, nextQuery) {});
- * }
- * });
- */
-Transaction.prototype.runQuery = function(q, callback) {
- callback = callback || util.noop;
- var req = {
- read_options: {
- transaction: this.id
- },
- query: entity.queryToQueryProto(q)
- };
- if (q.namespace) {
- req.partition_id = {
- namespace: q.namespace
- };
- }
- req = new pb.RunQueryRequest(req);
- var res = pb.RunQueryResponse;
- this.makeReq('runQuery', req, res, function(err, resp) {
- if (err || !resp.batch || !resp.batch.entity_result) {
- callback(err);
- return;
- }
- var nextQuery = null;
- if (resp.batch.end_cursor) {
- var cursor = resp.batch.end_cursor.toBase64();
- if (cursor !== q.startVal) {
- nextQuery = q.start(cursor).offset(0);
- }
- }
- callback(null, entity.formatArray(resp.batch.entity_result), nextQuery);
- });
-};
-
/**
* mapQuery
*
@@ -425,56 +185,4 @@ Transaction.prototype.mapQuery = function() {
throw new Error('not yet implemented');
};
-/**
- * Make a request to the API endpoint.
- *
- * @param {string} method - Transaction action (allocateIds, commit, etc.).
- * @param {object} req - Request configuration object.
- * @param {function} callbcak - The callback function.
- *
- * @example
- * var deleteRequest = {
- * MODE: 'NON_TRANSACTIONAL',
- * mutation: {
- * delete: [] // datastore key objects.
- * }
- * };
- * transaction.makeReq('commit', deleteRequest, function(err) {});
- */
-Transaction.prototype.makeReq = function(method, req, respType, callback) {
- // TODO: Handle non-HTTP 200 cases.
- callback = callback || util.noop;
- this.conn.createAuthorizedReq({
- method: 'POST',
- host: GOOGLE_APIS_HOST,
- path: '/datastore/v1beta2/datasets/' + this.datasetId + '/' + method,
- headers: {
- 'content-type': 'application/x-protobuf'
- }
- }, function(err, request) {
- if (err) {
- callback(err);
- return;
- }
- var remoteStream = https.request(request, function(resp) {
- var buffer = new Buffer('');
- resp.on('data', function(chunk) {
- buffer = Buffer.concat([buffer, chunk]);
- });
- resp.on('end', function() {
- util.handleResp(null, resp, buffer.toString(), function(err) {
- if (err) {
- callback(err);
- return;
- }
- callback(null, respType.decode(buffer));
- });
- });
- });
- remoteStream.on('error', callback);
- remoteStream.write(req.toBuffer());
- remoteStream.end();
- });
-};
-
module.exports = Transaction;
diff --git a/test/datastore/dataset.js b/test/datastore/dataset.js
index 7b8695f45af..9296ee02d3f 100644
--- a/test/datastore/dataset.js
+++ b/test/datastore/dataset.js
@@ -94,7 +94,7 @@ describe('Dataset', function() {
it('should get by key', function(done) {
var ds = datastore.dataset({ projectId: 'test' });
- ds.transaction.makeReq = function(method, proto, typ, callback) {
+ ds.createRequest = function(method, proto, typ, callback) {
assert.equal(method, 'lookup');
assert.equal(proto.key.length, 1);
callback(null, mockRespGet);
@@ -111,7 +111,7 @@ describe('Dataset', function() {
it('should multi get by keys', function(done) {
var ds = datastore.dataset({ projectId: 'test' });
- ds.transaction.makeReq = function(method, proto, typ, callback) {
+ ds.createRequest = function(method, proto, typ, callback) {
assert.equal(method, 'lookup');
assert.equal(proto.key.length, 1);
callback(null, mockRespGet);
@@ -133,7 +133,7 @@ describe('Dataset', function() {
var key = ds.key(['Kind', 5732568548769792]);
var key2 = ds.key(['Kind', 5732568548769792]);
var lookupCount = 0;
- ds.transaction.makeReq = function(method, proto, typ, callback) {
+ ds.createRequest = function(method, proto, typ, callback) {
lookupCount++;
assert.equal(method, 'lookup');
if (mockRespGet.deferred.length) {
@@ -153,7 +153,7 @@ describe('Dataset', function() {
it('should delete by key', function(done) {
var ds = datastore.dataset({ projectId: 'test' });
- ds.transaction.makeReq = function(method, proto, typ, callback) {
+ ds.createRequest = function(method, proto, typ, callback) {
assert.equal(method, 'commit');
assert.equal(!!proto.mutation.delete, true);
callback();
@@ -163,7 +163,7 @@ describe('Dataset', function() {
it('should multi delete by keys', function(done) {
var ds = datastore.dataset({ projectId: 'test' });
- ds.transaction.makeReq = function(method, proto, typ, callback) {
+ ds.createRequest = function(method, proto, typ, callback) {
assert.equal(method, 'commit');
assert.equal(proto.mutation.delete.length, 2);
callback();
@@ -176,7 +176,7 @@ describe('Dataset', function() {
it('should save with incomplete key', function(done) {
var ds = datastore.dataset({ projectId: 'test' });
- ds.transaction.makeReq = function(method, proto, typ, callback) {
+ ds.createRequest = function(method, proto, typ, callback) {
assert.equal(method, 'commit');
assert.equal(proto.mutation.insert_auto_id.length, 1);
callback();
@@ -187,7 +187,7 @@ describe('Dataset', function() {
it('should save with keys', function(done) {
var ds = datastore.dataset({ projectId: 'test' });
- ds.transaction.makeReq = function(method, proto, typ, callback) {
+ ds.createRequest = function(method, proto, typ, callback) {
assert.equal(method, 'commit');
assert.equal(proto.mutation.upsert.length, 2);
assert.equal(proto.mutation.upsert[0].property[0].name, 'k');
@@ -203,7 +203,7 @@ describe('Dataset', function() {
it('should produce proper allocate IDs req protos', function(done) {
var ds = datastore.dataset({ projectId: 'test' });
- ds.transaction.makeReq = function(method, proto, typ, callback) {
+ ds.createRequest = function(method, proto, typ, callback) {
assert.equal(method, 'allocateIds');
assert.equal(proto.key.length, 1);
assert.deepEqual(proto.key[0], {
@@ -237,7 +237,7 @@ describe('Dataset', function() {
ds = datastore.dataset({ projectId: 'test' });
ds.createTransaction_ = function() {
transaction = new Transaction();
- transaction.makeReq = function(method, proto, typ, callback) {
+ transaction.createRequest = function(method, proto, typ, callback) {
assert.equal(method, 'beginTransaction');
callback(null, { transaction: '' });
};
@@ -257,7 +257,7 @@ describe('Dataset', function() {
it('should commit the transaction when done', function() {
ds.runInTransaction(function(t, done) {
- transaction.makeReq = function(method) {
+ transaction.createRequest = function(method) {
assert.equal(method, 'commit');
};
done();
@@ -325,7 +325,7 @@ describe('Dataset', function() {
describe('errors', function() {
it('should handle upstream errors', function() {
var upstreamError = new Error('upstream error.');
- ds.transaction.makeReq = function(method, proto, typ, callback) {
+ ds.createRequest = function(method, proto, typ, callback) {
assert.equal(method, 'runQuery');
callback(upstreamError);
};
@@ -336,7 +336,7 @@ describe('Dataset', function() {
});
it('should handle missing results error', function() {
- ds.transaction.makeReq = function(method, proto, typ, callback) {
+ ds.createRequest = function(method, proto, typ, callback) {
assert.equal(method, 'runQuery');
callback('simulated-error', mockResponse.withoutResults);
};
@@ -348,7 +348,7 @@ describe('Dataset', function() {
});
it('should execute callback with results', function() {
- ds.transaction.makeReq = function(method, proto, typ, callback) {
+ ds.createRequest = function(method, proto, typ, callback) {
assert.equal(method, 'runQuery');
callback(null, mockResponse.withResults);
};
@@ -365,7 +365,7 @@ describe('Dataset', function() {
});
it('should return a new query if results remain', function() {
- ds.transaction.makeReq = function(method, proto, typ, callback) {
+ ds.createRequest = function(method, proto, typ, callback) {
assert.equal(method, 'runQuery');
callback(null, mockResponse.withResultsAndEndCursor);
};
diff --git a/test/datastore/transaction.js b/test/datastore/transaction.js
index c273c7a1e1d..4c36f4f388e 100644
--- a/test/datastore/transaction.js
+++ b/test/datastore/transaction.js
@@ -31,7 +31,7 @@ describe('Transaction', function() {
});
it('should begin', function(done) {
- transaction.makeReq = function(method, proto, respType, callback) {
+ transaction.createRequest = function(method, proto, respType, callback) {
assert.equal(method, 'beginTransaction');
callback(null, 'some-id');
};
@@ -40,7 +40,7 @@ describe('Transaction', function() {
it('should rollback', function(done) {
transaction.id = 'some-id';
- transaction.makeReq = function(method, proto, respType, callback) {
+ transaction.createRequest = function(method, proto, respType, callback) {
assert.equal(method, 'rollback');
assert.equal(
proto.transaction.toBase64(),
@@ -55,7 +55,7 @@ describe('Transaction', function() {
it('should commit', function(done) {
transaction.id = 'some-id';
- transaction.makeReq = function(method, proto, respType, callback) {
+ transaction.createRequest = function(method, proto, respType, callback) {
assert.equal(method, 'commit');
assert.equal(
proto.transaction.toBase64(),
@@ -69,7 +69,7 @@ describe('Transaction', function() {
});
it('should be committed if not rolled back', function(done) {
- transaction.makeReq = function(method) {
+ transaction.createRequest = function(method) {
assert.equal(method, 'commit');
done();
};
From 06eca8677cf0828155f5464864d403d9dfa7599e Mon Sep 17 00:00:00 2001
From: Ryan Seys
Date: Sat, 27 Sep 2014 14:56:05 -0400
Subject: [PATCH 2/8] Fix this.connection
---
lib/datastore/transaction.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/datastore/transaction.js b/lib/datastore/transaction.js
index b20f21ba30a..4b1d4318950 100644
--- a/lib/datastore/transaction.js
+++ b/lib/datastore/transaction.js
@@ -52,7 +52,7 @@ var DatastoreRequester = require('./datastore_request.js');
* var transaction = new Transaction(myConnection, 'my-project-id');
*/
function Transaction(conn, projectId) {
- this.conn = conn;
+ this.connection = conn;
this.projectId = projectId;
// the default transaction has no id.
// if id is not set, run operations non-transactional.
From 6bb7c61282a705f67cf514d31431308486e2af61 Mon Sep 17 00:00:00 2001
From: Ryan Seys
Date: Sat, 27 Sep 2014 16:35:13 -0400
Subject: [PATCH 3/8] DatastoreRequester --> DatastoreRequest
---
lib/datastore/dataset.js | 4 ++--
lib/datastore/datastore_request.js | 16 +++++++++-------
lib/datastore/transaction.js | 4 ++--
3 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/lib/datastore/dataset.js b/lib/datastore/dataset.js
index 2f1a53c075f..da2feb0717f 100644
--- a/lib/datastore/dataset.js
+++ b/lib/datastore/dataset.js
@@ -67,7 +67,7 @@ var SCOPES = [
'https://www.googleapis.com/auth/userinfo.email'
];
-var DatastoreRequester = require('./datastore_request.js');
+var DatastoreRequest = require('./datastore_request.js');
/**
* Interact with a dataset from the
@@ -109,7 +109,7 @@ function Dataset(options) {
this.namespace = options.namespace;
}
-nodeutil.inherits(Dataset, DatastoreRequester);
+nodeutil.inherits(Dataset, DatastoreRequest);
/**
* Helper to create a Key object, scoped to the dataset's namespace by default.
diff --git a/lib/datastore/datastore_request.js b/lib/datastore/datastore_request.js
index 0a34ca46559..d45122eca6c 100644
--- a/lib/datastore/datastore_request.js
+++ b/lib/datastore/datastore_request.js
@@ -43,7 +43,9 @@ var MODE_TRANSACTIONAL = 'TRANSACTIONAL';
*/
var util = require('../common/util.js');
-function DatastoreRequester() {}
+function DatastoreRequest() {
+
+}
/**
* Retrieve the entities identified with the specified key(s) in the current
@@ -65,7 +67,7 @@ function DatastoreRequester() {}
* dataset.key(['Product', 'Computer'])
* ], function(err, entities) {});
*/
-DatastoreRequester.prototype.get = function(keys, callback) {
+DatastoreRequest.prototype.get = function(keys, callback) {
var isMultipleRequest = Array.isArray(keys);
keys = isMultipleRequest ? keys : [keys];
callback = callback || util.noop;
@@ -141,7 +143,7 @@ DatastoreRequester.prototype.get = function(keys, callback) {
* }
* ], function(err, keys) {});
*/
-DatastoreRequester.prototype.save = function(entities, callback) {
+DatastoreRequest.prototype.save = function(entities, callback) {
var isMultipleRequest = Array.isArray(entities);
entities = isMultipleRequest ? entities : [entities];
var insertIndexes = [];
@@ -200,7 +202,7 @@ DatastoreRequester.prototype.save = function(entities, callback) {
* dataset.key(['Product', 'Computer'])
* ], function(err) {});
*/
-DatastoreRequester.prototype.delete = function(keys, callback) {
+DatastoreRequest.prototype.delete = function(keys, callback) {
var isMultipleRequest = Array.isArray(keys);
keys = isMultipleRequest ? keys : [keys];
callback = callback || util.noop;
@@ -239,7 +241,7 @@ DatastoreRequester.prototype.delete = function(keys, callback) {
* });
*/
-DatastoreRequester.prototype.runQuery = function(q, callback) {
+DatastoreRequest.prototype.runQuery = function(q, callback) {
callback = callback || util.noop;
var req = {
read_options: {},
@@ -290,7 +292,7 @@ DatastoreRequester.prototype.runQuery = function(q, callback) {
* };
* transaction.makeReq('commit', deleteRequest, function(err) {});
*/
-DatastoreRequester.prototype.createRequest =
+DatastoreRequest.prototype.createRequest =
function(method, req, respType, cb) {
// TODO: Handle non-HTTP 200 cases.
cb = cb || util.noop;
@@ -327,4 +329,4 @@ DatastoreRequester.prototype.createRequest =
});
};
-module.exports = DatastoreRequester;
+module.exports = DatastoreRequest;
diff --git a/lib/datastore/transaction.js b/lib/datastore/transaction.js
index 4b1d4318950..a1c74d9a64d 100644
--- a/lib/datastore/transaction.js
+++ b/lib/datastore/transaction.js
@@ -29,7 +29,7 @@ var util = require('../common/util.js');
var nodeutil = require('util');
-var DatastoreRequester = require('./datastore_request.js');
+var DatastoreRequest = require('./datastore_request.js');
/**
* Build a Transaction object. Transactions will generally be built for you by
@@ -60,7 +60,7 @@ function Transaction(conn, projectId) {
this.isFinalized = false;
}
-nodeutil.inherits(Transaction, DatastoreRequester);
+nodeutil.inherits(Transaction, DatastoreRequest);
/**
* Begin a remote transaction and identify the current transaction instance with
From 52fc5bc90df42b938c94112c9082a5dad9177437 Mon Sep 17 00:00:00 2001
From: Ryan Seys
Date: Sat, 27 Sep 2014 21:17:02 -0400
Subject: [PATCH 4/8] Rename datastore_request to request and fix various
cosmetic errors
---
lib/datastore/dataset.js | 17 ++++++++++++++---
.../{datastore_request.js => request.js} | 12 ++++++++----
lib/datastore/transaction.js | 10 +++++++---
3 files changed, 29 insertions(+), 10 deletions(-)
rename lib/datastore/{datastore_request.js => request.js} (99%)
diff --git a/lib/datastore/dataset.js b/lib/datastore/dataset.js
index da2feb0717f..f5c0edab5f2 100644
--- a/lib/datastore/dataset.js
+++ b/lib/datastore/dataset.js
@@ -20,6 +20,8 @@
'use strict';
+var nodeutil = require('util');
+
/**
* @type module:common/connection
* @private
@@ -55,7 +57,12 @@ var Transaction = require('./transaction.js');
* @private
*/
var util = require('../common/util.js');
-var nodeutil = require('util');
+
+/**
+ * @type module:datastore/request
+ * @private
+ */
+var DatastoreRequest = require('./request');
/**
* Scopes for Google Datastore access.
@@ -67,8 +74,6 @@ var SCOPES = [
'https://www.googleapis.com/auth/userinfo.email'
];
-var DatastoreRequest = require('./datastore_request.js');
-
/**
* Interact with a dataset from the
* [Google Cloud Datastore]{@link https://developers.google.com/datastore/}.
@@ -253,6 +258,12 @@ Dataset.prototype.allocateIds = function(incompleteKey, n, callback) {
});
};
+/**
+ * Create a new Transaction object using the existing connection and dataset.
+ *
+ * @return {module:datastore/transaction}
+ * @private
+ */
Dataset.prototype.createTransaction_ = function() {
return new Transaction(this.connection, this.projectId);
};
diff --git a/lib/datastore/datastore_request.js b/lib/datastore/request.js
similarity index 99%
rename from lib/datastore/datastore_request.js
rename to lib/datastore/request.js
index d45122eca6c..f2df763dd49 100644
--- a/lib/datastore/datastore_request.js
+++ b/lib/datastore/request.js
@@ -14,6 +14,11 @@
* limitations under the License.
*/
+/**
+ * @private
+ * @module datastore/request
+ */
+
'use strict';
var https = require('https');
@@ -43,9 +48,7 @@ var MODE_TRANSACTIONAL = 'TRANSACTIONAL';
*/
var util = require('../common/util.js');
-function DatastoreRequest() {
-
-}
+function DatastoreRequest() {}
/**
* Retrieve the entities identified with the specified key(s) in the current
@@ -251,11 +254,13 @@ DatastoreRequest.prototype.runQuery = function(q, callback) {
if(this.id) {
req.read_options.transaction = this.id;
}
+
if (q.namespace) {
req.partition_id = {
namespace: q.namespace
};
}
+
req = new pb.RunQueryRequest(req);
var res = pb.RunQueryResponse;
@@ -275,7 +280,6 @@ DatastoreRequest.prototype.runQuery = function(q, callback) {
});
};
-
/**
* Make a request to the API endpoint.
*
diff --git a/lib/datastore/transaction.js b/lib/datastore/transaction.js
index a1c74d9a64d..874a70ad4b1 100644
--- a/lib/datastore/transaction.js
+++ b/lib/datastore/transaction.js
@@ -21,15 +21,19 @@
'use strict';
+var nodeutil = require('util');
+
/** @type module:datastore/pb */
var pb = require('./pb.js');
/** @type module:common/util */
var util = require('../common/util.js');
-var nodeutil = require('util');
-
-var DatastoreRequest = require('./datastore_request.js');
+/**
+ * @type module:datastore/request
+ * @private
+ */
+var DatastoreRequest = require('./request');
/**
* Build a Transaction object. Transactions will generally be built for you by
From b0800de39c8df757e84c5f0ff0c1065796b07345 Mon Sep 17 00:00:00 2001
From: Ryan Seys
Date: Sat, 27 Sep 2014 21:50:45 -0400
Subject: [PATCH 5/8] Linting galore in datastore
---
lib/datastore/dataset.js | 12 +++++++++---
lib/datastore/request.js | 22 ++++++++++------------
lib/datastore/transaction.js | 11 ++++++-----
3 files changed, 25 insertions(+), 20 deletions(-)
diff --git a/lib/datastore/dataset.js b/lib/datastore/dataset.js
index f5c0edab5f2..ca3db99efea 100644
--- a/lib/datastore/dataset.js
+++ b/lib/datastore/dataset.js
@@ -62,7 +62,7 @@ var util = require('../common/util.js');
* @type module:datastore/request
* @private
*/
-var DatastoreRequest = require('./request');
+var DatastoreRequest = require('./request.js');
/**
* Scopes for Google Datastore access.
@@ -81,7 +81,7 @@ var SCOPES = [
* @constructor
* @alias module:datastore/dataset
*
- * @param {object=} options
+ * @param {object=} options options object
* @param {string=} options.projectId - Dataset ID. This is your project ID from
* the Google Developers Console.
* @param {string=} options.keyFilename - Full path to the JSON key downloaded
@@ -145,6 +145,8 @@ nodeutil.inherits(Dataset, DatastoreRequest);
* namespace: 'My-NS',
* path: ['Company', 123]
* });
+ *
+ * @return {Key} A newly created Key from the options given.
*/
Dataset.prototype.key = function(options) {
options = util.is(options, 'object') ? options : {
@@ -254,7 +256,7 @@ Dataset.prototype.allocateIds = function(incompleteKey, n, callback) {
(resp.key || []).forEach(function(k) {
keys.push(entity.keyFromKeyProto(k));
});
- callback(null ,keys);
+ callback(null, keys);
});
};
@@ -268,4 +270,8 @@ Dataset.prototype.createTransaction_ = function() {
return new Transaction(this.connection, this.projectId);
};
+/**
+ * Exports Dataset
+ * @type {Dataset}
+ */
module.exports = Dataset;
diff --git a/lib/datastore/request.js b/lib/datastore/request.js
index f2df763dd49..2f5acb7a5c1 100644
--- a/lib/datastore/request.js
+++ b/lib/datastore/request.js
@@ -41,13 +41,6 @@ var MODE_NON_TRANSACTIONAL = 'NON_TRANSACTIONAL';
/** @const {string} Transaction mode key. */
var MODE_TRANSACTIONAL = 'TRANSACTIONAL';
-
-/**
- * @type module:common/util
- * @private
- */
-var util = require('../common/util.js');
-
function DatastoreRequest() {}
/**
@@ -55,7 +48,7 @@ function DatastoreRequest() {}
* transaction. Get operations require a valid key to retrieve the
* key-identified entity from Datastore.
*
- * @param {Key|Key[]} key - Datastore key object(s).
+ * @param {Key|Key[]} keys - Datastore key object(s).
* @param {function} callback - The callback function.
*
* @example
@@ -90,7 +83,7 @@ DatastoreRequest.prototype.get = function(keys, callback) {
if (isMultipleRequest && resp.deferred && resp.deferred.length) {
// There may be more results. Call `.get` again, and append the results.
this.get(
- resp.deferred.map(entity.keyFromKeyProto), function (err, entities) {
+ resp.deferred.map(entity.keyFromKeyProto), function(err, entities) {
if (err) {
callback(err);
return;
@@ -231,7 +224,7 @@ DatastoreRequest.prototype.delete = function(keys, callback) {
* supported. If more results are available, a query to retrieve the next page
* is provided to the callback function.
*
- * @param {module:datastore/query} query - Query object.
+ * @param {module:datastore/query} q - Query object.
* @param {function} callback - The callback function.
*
* @example
@@ -251,7 +244,7 @@ DatastoreRequest.prototype.runQuery = function(q, callback) {
query: entity.queryToQueryProto(q)
};
- if(this.id) {
+ if (this.id) {
req.read_options.transaction = this.id;
}
@@ -285,7 +278,8 @@ DatastoreRequest.prototype.runQuery = function(q, callback) {
*
* @param {string} method - Transaction action (allocateIds, commit, etc.).
* @param {object} req - Request configuration object.
- * @param {function} callbcak - The callback function.
+ * @param {object} respType - Response type.s
+ * @param {function} cb - The callback function.
*
* @example
* var deleteRequest = {
@@ -333,4 +327,8 @@ DatastoreRequest.prototype.createRequest =
});
};
+/**
+ * Exports DatastoreRequest
+ * @type {DatastoreRequest}
+ */
module.exports = DatastoreRequest;
diff --git a/lib/datastore/transaction.js b/lib/datastore/transaction.js
index 874a70ad4b1..637ce9a7a57 100644
--- a/lib/datastore/transaction.js
+++ b/lib/datastore/transaction.js
@@ -29,11 +29,8 @@ var pb = require('./pb.js');
/** @type module:common/util */
var util = require('../common/util.js');
-/**
- * @type module:datastore/request
- * @private
- */
-var DatastoreRequest = require('./request');
+/** @type module:datastore/request */
+var DatastoreRequest = require('./request.js');
/**
* Build a Transaction object. Transactions will generally be built for you by
@@ -189,4 +186,8 @@ Transaction.prototype.mapQuery = function() {
throw new Error('not yet implemented');
};
+/**
+ * Exports Transaction
+ * @type {Transaction}
+ */
module.exports = Transaction;
From 6ac220e0e1e82ea3e00e118ed1376aeae1f3585a Mon Sep 17 00:00:00 2001
From: Ryan Seys
Date: Mon, 29 Sep 2014 10:54:45 -0400
Subject: [PATCH 6/8] Update documentation for DatastoreRequest
---
lib/datastore/dataset.js | 6 +-----
lib/datastore/request.js | 18 ++++++++++++++----
lib/datastore/transaction.js | 4 ----
3 files changed, 15 insertions(+), 13 deletions(-)
diff --git a/lib/datastore/dataset.js b/lib/datastore/dataset.js
index ca3db99efea..1397388dd7c 100644
--- a/lib/datastore/dataset.js
+++ b/lib/datastore/dataset.js
@@ -81,7 +81,7 @@ var SCOPES = [
* @constructor
* @alias module:datastore/dataset
*
- * @param {object=} options options object
+ * @param {object=} options - Configuration object.
* @param {string=} options.projectId - Dataset ID. This is your project ID from
* the Google Developers Console.
* @param {string=} options.keyFilename - Full path to the JSON key downloaded
@@ -270,8 +270,4 @@ Dataset.prototype.createTransaction_ = function() {
return new Transaction(this.connection, this.projectId);
};
-/**
- * Exports Dataset
- * @type {Dataset}
- */
module.exports = Dataset;
diff --git a/lib/datastore/request.js b/lib/datastore/request.js
index 2f5acb7a5c1..332ec0854fc 100644
--- a/lib/datastore/request.js
+++ b/lib/datastore/request.js
@@ -41,6 +41,20 @@ var MODE_NON_TRANSACTIONAL = 'NON_TRANSACTIONAL';
/** @const {string} Transaction mode key. */
var MODE_TRANSACTIONAL = 'TRANSACTIONAL';
+/**
+ * Handles request logic for Datastore.
+ *
+ * Creates requests to the Dataset endpoint. Designed to be inherited by
+ * datastore.Dataset and datastore.Transaction objects.
+ *
+ * @constructor
+ * @alias module:datastore/request
+ *
+ * @example
+ * // Inherit in Dataset and Transaction
+ * require('util').inherits(Dataset, DatastoreRequest);
+ * require('util').inherits(Transaction, DatastoreRequest);
+ */
function DatastoreRequest() {}
/**
@@ -327,8 +341,4 @@ DatastoreRequest.prototype.createRequest =
});
};
-/**
- * Exports DatastoreRequest
- * @type {DatastoreRequest}
- */
module.exports = DatastoreRequest;
diff --git a/lib/datastore/transaction.js b/lib/datastore/transaction.js
index 637ce9a7a57..f4bba30c651 100644
--- a/lib/datastore/transaction.js
+++ b/lib/datastore/transaction.js
@@ -186,8 +186,4 @@ Transaction.prototype.mapQuery = function() {
throw new Error('not yet implemented');
};
-/**
- * Exports Transaction
- * @type {Transaction}
- */
module.exports = Transaction;
From 5d85faea4f240bceb34b11c9422e4a87299ed24f Mon Sep 17 00:00:00 2001
From: Stephen Sawchuk
Date: Tue, 30 Sep 2014 09:51:35 -0400
Subject: [PATCH 7/8] include transaction in the docs.
---
docs/components/docs/docs-directives.js | 12 +
docs/components/docs/docs-services.js | 24 +
docs/components/docs/docs-values.js | 54 ++
docs/components/docs/docs.html | 22 +-
docs/components/docs/docs.js | 229 ++---
docs/index.html | 4 +
docs/lib/semver.js | 1098 +++++++++++++++++++++++
lib/datastore/dataset.js | 56 +-
lib/datastore/request.js | 117 ++-
lib/datastore/transaction.js | 56 +-
package.json | 2 +-
test/datastore/dataset.js | 28 +-
test/datastore/transaction.js | 8 +-
13 files changed, 1479 insertions(+), 231 deletions(-)
create mode 100644 docs/components/docs/docs-directives.js
create mode 100644 docs/components/docs/docs-services.js
create mode 100644 docs/components/docs/docs-values.js
create mode 100644 docs/lib/semver.js
diff --git a/docs/components/docs/docs-directives.js b/docs/components/docs/docs-directives.js
new file mode 100644
index 00000000000..0295fb30f33
--- /dev/null
+++ b/docs/components/docs/docs-directives.js
@@ -0,0 +1,12 @@
+angular.module('gcloud.docs')
+ .directive('docsExample', function($compile) {
+ 'use strict';
+
+ return {
+ link: function(scope, element, attr) {
+ scope.$watch(attr.ngBindHtml, function() {
+ $compile(element.contents())(scope);
+ }, true);
+ }
+ };
+ });
diff --git a/docs/components/docs/docs-services.js b/docs/components/docs/docs-services.js
new file mode 100644
index 00000000000..e4dd9847722
--- /dev/null
+++ b/docs/components/docs/docs-services.js
@@ -0,0 +1,24 @@
+angular.module('gcloud.docs')
+ .factory('getLinks', function(pages) {
+ 'use strict';
+
+ return function(version) {
+ var baseUrl = '#/docs/' + version;
+ var VERSIONS = pages.VERSIONS;
+ var versions;
+ var match;
+ if (!version || version === 'master') {
+ versions = Object.keys(VERSIONS);
+ match = versions[versions.length - 1];
+ } else {
+ match = Object.keys(VERSIONS).filter(semver.satisfies.bind(null, version))[0];
+ }
+ return VERSIONS[match]
+ .map(function(module) {
+ if (pages[module]._url) {
+ pages[module].url = pages[module]._url.replace('{baseUrl}', baseUrl);
+ }
+ return pages[module];
+ });
+ };
+ });
diff --git a/docs/components/docs/docs-values.js b/docs/components/docs/docs-values.js
new file mode 100644
index 00000000000..fc3f9952daa
--- /dev/null
+++ b/docs/components/docs/docs-values.js
@@ -0,0 +1,54 @@
+angular.module('gcloud.docs')
+ .value('pages', {
+ gcloud: {
+ title: 'gcloud',
+ _url: '{baseUrl}'
+ },
+
+ datastore: {
+ title: 'Datastore',
+ _url: '{baseUrl}/datastore',
+ pages: [
+ {
+ title: 'Dataset',
+ url: '/dataset'
+ },
+ {
+ title: 'Query',
+ url: '/query'
+ }
+ ]
+ },
+
+ datastoreWithTransaction: {
+ title: 'Datastore',
+ _url: '{baseUrl}/datastore',
+ pages: [
+ {
+ title: 'Dataset',
+ url: '/dataset'
+ },
+ {
+ title: 'Transaction',
+ url: '/transaction'
+ },
+ {
+ title: 'Query',
+ url: '/query'
+ }
+ ]
+ },
+
+ storage: {
+ title: 'Storage',
+ _url: '{baseUrl}/storage'
+ },
+
+ VERSIONS: {
+ // Give a version with/without a comparator, anything semver:
+ // https://github.com/npm/node-semver#versions
+ // List should be in ascending order.
+ '<=0.7.1': ['gcloud', 'datastore', 'storage'],
+ '>0.7.1': ['gcloud', 'datastoreWithTransaction', 'storage']
+ }
+ });
diff --git a/docs/components/docs/docs.html b/docs/components/docs/docs.html
index be0e1e0d3f5..eb6ead22cab 100644
--- a/docs/components/docs/docs.html
+++ b/docs/components/docs/docs.html
@@ -45,13 +45,13 @@
However, if you're running your app elsewhere, you will need to provide this information.
- // App Engine and Compute Engine
- var gcloud = require('gcloud');
+// App Engine and Compute Engine
+var gcloud = require('gcloud');
- // Elsewhere
- var gcloud = require('gcloud')({
- keyFilename: '/path/to/keyfile.json'
- });
+// Elsewhere
+var gcloud = require('gcloud')({
+ keyFilename: '/path/to/keyfile.json'
+});
In any environment, you are free to provide these and other default properties, which eventually will be passed to the gcloud
sub-modules (Datastore, Storage, etc.).
@@ -98,8 +98,7 @@
ng-if="method.name[0].toUpperCase() !== method.name[0]">
#
+ ng-href="{{activeUrl + '?method=' + method.name}}">#
{{method.name}}
@@ -118,9 +117,8 @@ Parameters
Returns
Example
-
+
@@ -135,7 +133,7 @@ Example
-
+
diff --git a/docs/components/docs/docs.js b/docs/components/docs/docs.js
index da018a44842..98d3dc89ca7 100644
--- a/docs/components/docs/docs.js
+++ b/docs/components/docs/docs.js
@@ -4,14 +4,41 @@ angular
'use strict';
function filterDocJson($sce, version) {
- // Transform JSON response to remove extraneous objects, such as copyright
- // notices & use strict directives.
+ // Transform JSON response to remove extraneous objects.
function formatHtml(str) {
return str
.replace(/\s+/g, ' ')
.replace(/ /g, ' ')
.replace(/`([^`]*)`/g, '$1
');
}
+ function formatComments(str) {
+ var matched = 0;
+ var paragraphComments = /\/\/-+((\n|\r|.)*?(\/\/-))/g;
+
+ if (!paragraphComments.test(str)) {
+ return '\n' + str + '
';
+ }
+
+ str = str.replace(paragraphComments, function(match, block) {
+ return '' +
+ (++matched > 1 ? '' : '') +
+ '' +
+ formatHtml(detectLinks(detectModules(
+ block.trim()
+ .replace(/\/\/-*\s*/g, '\n')
+ .replace(/\n\n/g, '\n')
+ .replace(/(\w)\n(\w)/g, '$1 $2')
+ .replace(/\n\n/g, '
')
+ ))) +
+ '
' +
+ '';
+ });
+
+ str = str.replace(/(
]*>)\n+/g, '$1\n');
+ str = str.replace(/\n<\/div>/g, '
');
+
+ return str;
+ }
function detectLinks(str) {
var regex = {
withCode: /{@linkcode
([^<]*)<\/a>/g,
@@ -42,13 +69,23 @@ angular
};
var a = document.createElement('a');
return str.replace(regex.see, function(match, module) {
- a.href = '#/docs/' + version + '/' + module;
+ var path = module;
+ if (path.indexOf('#') > -1) {
+ path = path.split('#').map(function(part, index, parts) {
+ if (index < parts.length - 1) {
+ return part + '/';
+ } else {
+ return '?method=' + part;
+ }
+ }).join('');
+ }
+ a.href = '#/docs/' + version + '/' + path;
a.innerText = module;
return a.outerHTML;
});
}
function reduceModules(acc, type, index, types) {
- var CUSTOM_TYPES = ['query', 'dataset'];
+ var CUSTOM_TYPES = ['query', 'dataset', 'transaction'];
if (CUSTOM_TYPES.indexOf(type.toLowerCase()) > -1) {
if (types[index - 1]) {
type = types[index - 1] + '/' + type;
@@ -70,6 +107,9 @@ angular
constructor: obj.tags.some(function(tag) {
return tag.type === 'constructor';
}),
+ mixes: obj.tags.filter(function(tag) {
+ return tag.type === 'mixes';
+ }),
description: $sce.trustAsHtml(
formatHtml(detectLinks(detectModules(obj.description.full)))),
params: obj.tags.filter(function(tag) {
@@ -88,13 +128,13 @@ angular
})
.map(function(tag) {
return $sce.trustAsHtml(
- tag.types.reduceRight(reduceModules, [])[0])
+ tag.types.reduceRight(reduceModules, [])[0]);
})[0],
example: obj.tags.filter(function(tag) {
- return tag.type === 'example'
+ return tag.type === 'example';
})
.map(function(tag) {
- return tag.string;
+ return $sce.trustAsHtml(formatComments(tag.string));
})[0]
};
})
@@ -104,24 +144,77 @@ angular
};
}
- function setMethod($location, methodName, version) {
- return function(methods) {
- var methodExists = methods.some(function(methodObj) {
- return methodName === methodObj.name;
+ function getMixIns($sce, $q, $http, version, baseUrl) {
+ return function(data) {
+ var methodWithMixIns = data.filter(function(method) {
+ return method.mixes;
+ })[0];
+ if (!methodWithMixIns) {
+ return data;
+ }
+ return $q
+ .all(getMixInMethods(methodWithMixIns))
+ .then(combineMixInMethods(data));
+ };
+ function getMixInMethods(method) {
+ return method.mixes.map(function (module) {
+ module = module.string.trim().replace('module:', '');
+ return $http.get(baseUrl + '/' + module + '.json')
+ .then(filterDocJson($sce, version))
+ .then(function(mixInData) {
+ return mixInData.filter(function(method) {
+ return !method.constructor;
+ });
+ });
});
- if (methodExists) {
- methods.singleMethod = methodName;
- return methods;
- } else {
- $location.path('/docs/' + version + '/' + module + '/' + cl);
+ }
+ function combineMixInMethods(data) {
+ return function(mixInData) {
+ return mixInData
+ .reduce(function(acc, mixInMethods) {
+ return acc = acc.concat(mixInMethods);
+ }, data)
+ .sort(function(a, b) {
+ return a.name > b.name;
+ });
+ };
+ }
+ }
+
+ function setSingleMethod(method) {
+ return function(methods) {
+ if (method && methods.some(function(methodObj) {
+ return methodObj.name === method;
+ })) {
+ methods.singleMethod = method;
}
+ return methods;
};
}
- var MODULE_TO_CLASSES = {
- datastore: ['dataset', 'query'],
- storage: []
- };
+ function getMethods($http, $route, $sce, $q, $location) {
+ var version = $route.current.params.version;
+ var module = $route.current.params.module;
+ var cl = $route.current.params.class;
+ var path = ['json', version];
+ if (!module && !cl) {
+ path.push('index.json');
+ } else if (module && !cl) {
+ path.push(module);
+ path.push('index.json');
+ } else if (module && cl) {
+ path.push(module);
+ path.push(cl + '.json');
+ }
+ return $http.get(path.join('/'))
+ .then(filterDocJson($sce, version))
+ .then(getMixIns($sce, $q, $http, version, 'json/' + version))
+ .then(setSingleMethod($location.search().method));
+ }
+
+ function getLinks($route, getLinks) {
+ return getLinks($route.current.params.version);
+ }
$routeProvider
.when('/docs', {
@@ -134,72 +227,23 @@ angular
.when('/docs/:version', {
controller: 'DocsCtrl',
templateUrl: 'components/docs/docs.html',
- resolve: {
- methods: function($http, $route, $sce) {
- var version = $route.current.params.version;
- return $http.get('json/' + version + '/index.json')
- .then(filterDocJson($sce, version))
- .then(function(methods) {
- // Prevent displaying permalinks.
- // ** Can remove when PubSub api is documented **
- methods.noPermalink = true;
- return methods;
- });
- }
- }
+ resolve: { methods: getMethods, links: getLinks }
})
.when('/docs/:version/:module', {
controller: 'DocsCtrl',
templateUrl: 'components/docs/docs.html',
- resolve: {
- methods: function($http, $route, $sce) {
- var version = $route.current.params.version;
- var module = $route.current.params.module;
- return $http.get('json/' + version + '/' + module + '/index.json')
- .then(filterDocJson($sce, version));
- }
- }
+ resolve: { methods: getMethods, links: getLinks }
})
.when('/docs/:version/:module/:class', {
controller: 'DocsCtrl',
templateUrl: 'components/docs/docs.html',
- resolve: {
- methods: function($q, $http, $route, $sce, $location) {
- var version = $route.current.params.version;
- var module = $route.current.params.module;
- var cl = $route.current.params.class;
- if (MODULE_TO_CLASSES[module].length > 0) {
- return $http
- .get('json/' + version + '/' + module + '/' + cl + '.json')
- .then(filterDocJson($sce, version));
- } else {
- // This is not a class, this is the name of a method.
- var method = cl;
- return $http.get('json/' + version + '/' +module + '/index.json')
- .then(filterDocJson($sce, version))
- .then(setMethod($location, method, version));
- }
- }
- }
- })
- .when('/docs/:version/:module/:class/:method', {
- controller: 'DocsCtrl',
- templateUrl: 'components/docs/docs.html',
- resolve: {
- methods: function($q, $http, $route, $sce, $location) {
- var version = $route.current.params.version;
- var module = $route.current.params.module;
- var cl = $route.current.params.class;
- var method = $route.current.params.method;
- return $http.get('json/' + version + '/' + module + '/' + cl + '.json')
- .then(filterDocJson($sce, version))
- .then(setMethod($location, method, version));
- }
- }
+ resolve: { methods: getMethods, links: getLinks }
});
})
.run(function($location, $route, $rootScope, versions) {
+ 'use strict';
+
$rootScope.$on('$routeChangeStart', function(event, route) {
var url = $location.path();
if (url.indexOf('/docs/') === -1 || (!route.params || !route.params.version)) {
@@ -217,7 +261,7 @@ angular
});
})
- .controller('DocsCtrl', function($location, $scope, $routeParams, methods, $http, versions) {
+ .controller('DocsCtrl', function($location, $scope, $routeParams, methods, $http, links, versions) {
'use strict';
$scope.isActiveUrl = function(url) {
@@ -236,44 +280,17 @@ angular
$scope.showReference = true;
$scope.activeUrl = '#' + $location.path();
$scope.singleMethod = methods.singleMethod;
- $scope.noPermalink = methods.singleMethod || methods.noPermalink;
- $scope.methods = methods;
$scope.module = $routeParams.module;
+ $scope.methods = methods;
$scope.version = $routeParams.version;
$scope.isLatestVersion = $scope.version == versions[0];
$scope.versions = versions;
- var baseUrl = '#/docs/' + $scope.version;
- /*
- TODO(silvano): future versions will introduce new pages, so the list below will have
- to be generated according to the specific version
- */
- $scope.pages = [
- {
- title: 'gcloud',
- url: baseUrl
- },
- {
- title: 'Datastore',
- url: baseUrl + '/datastore',
- pages: [
- {
- title: 'Dataset',
- url: '/dataset'
- },
- {
- title: 'Query',
- url: '/query'
- }
- ]
- },
- {
- title: 'Storage',
- url: baseUrl + '/storage'
- }
- ];
+ $scope.links = links;
})
.controller('HistoryCtrl', function($scope, versions) {
+ 'use strict';
+
$scope.pageTitle = 'Node.js Docs Versions';
$scope.showHistory = true;
$scope.versions = versions;
diff --git a/docs/index.html b/docs/index.html
index daeec618fc7..60740144fad 100755
--- a/docs/index.html
+++ b/docs/index.html
@@ -26,8 +26,12 @@
+
+
+
+