From dbb186aaa724396cb3d6501707b1148a195b961a Mon Sep 17 00:00:00 2001 From: Jason Dobry Date: Mon, 7 Nov 2016 10:06:00 -0800 Subject: [PATCH] Fixes #48 Fixes #234 Fixes #250 Addressed comments. --- README.md | 47 +- datastore/README.md | 29 +- datastore/concepts.js | 2150 ++++++++++------------ datastore/error.js | 67 +- datastore/package.json | 11 +- datastore/quickstart.js | 16 +- datastore/system-test/concepts.test.js | 401 ++-- datastore/system-test/error.test.js | 45 +- datastore/system-test/quickstart.test.js | 51 +- datastore/system-test/tasks.test.js | 106 +- datastore/system-test/util.js | 30 - datastore/tasks.js | 222 +-- datastore/test/concepts.test.js | 18 - datastore/test/error.test.js | 18 - datastore/test/quickstart.test.js | 50 - datastore/test/tasks.test.js | 18 - language/package.json | 2 +- 17 files changed, 1440 insertions(+), 1841 deletions(-) delete mode 100644 datastore/system-test/util.js mode change 100755 => 100644 datastore/tasks.js delete mode 100644 datastore/test/concepts.test.js delete mode 100644 datastore/test/error.test.js delete mode 100644 datastore/test/quickstart.test.js delete mode 100644 datastore/test/tasks.test.js diff --git a/README.md b/README.md index ea192d8b3f..97fd745519 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,8 @@ on Google Cloud Platform. [slack_badge]: https://img.shields.io/badge/slack-nodejs%20on%20gcp-E01563.svg [slack_link]: https://gcp-slack.appspot.com/ -[build_badge]: https://img.shields.io/travis/GoogleCloudPlatform/nodejs-docs-samples.svg?style=flat -[build_link]: https://travis-ci.org/GoogleCloudPlatform/nodejs-docs-samples +[build_badge]: https://img.shields.io/circleci/project/github/GoogleCloudPlatform/nodejs-docs-samples/master.svg?style=flat +[build_link]: https://circleci.com/gh/GoogleCloudPlatform/nodejs-docs-samples [cov_badge]: https://img.shields.io/codecov/c/github/GoogleCloudPlatform/nodejs-docs-samples/master.svg?style=flat [cov_link]: https://codecov.io/github/GoogleCloudPlatform/nodejs-docs-samples?branch=master [cloud]: https://cloud.google.com/ @@ -32,22 +32,22 @@ on Google Cloud Platform. * [Google Container Engine](#google-container-engine) * [Google Cloud Functions (Alpha)](#google-cloud-functions-alpha) * [**Storage and Databases**](#storage-and-databases) - * [Google Cloud Datastore (Beta)](#google-cloud-datastore-beta) + * [Google Cloud Datastore](#google-cloud-datastore) * [Google Cloud Storage](#google-cloud-storage) * [**Big Data**](#big-data) * [Google BigQuery](#google-bigquery) * [Google Cloud Pub/Sub](#google-cloud-pubsub) * [**Machine Learning**](#machine-learning) - * [Google Cloud Natural Language API (Beta)](#google-cloud-natural-language-api-beta) + * [Google Cloud Natural Language API](#google-cloud-natural-language-api) * [Google Cloud Prediction API](#google-cloud-prediction-api) * [Google Cloud Speech API (Beta)](#google-cloud-speech-api-beta) * [Google Translate API](#google-translate-api) * [Google Cloud Vision API](#google-cloud-vision-api) * [**Management Tools**](#management-tools) - * [Stackdriver Debugger (Beta)](#stackdriver-debugger-beta) - * [Stackdriver Logging (Beta)](#stackdriver-logging-beta) - * [Stackdriver Monitoring (Beta)](#stackdriver-monitoring-beta) - * [Stackdriver Trace (Beta)](#stackdriver-trace-beta) + * [Stackdriver Debugger](#stackdriver-debugger) + * [Stackdriver Logging](#stackdriver-logging) + * [Stackdriver Monitoring](#stackdriver-monitoring) + * [Stackdriver Trace](#stackdriver-trace) * [**Networking**](#management-tools) * [Google Cloud DNS](#google-cloud-dns) * [Other sample applications](#other-sample-applications) @@ -151,21 +151,6 @@ on Google Cloud Platform. ### How to run the tests 1. Read the [Contributing Guide][contrib]. -1. Set the `TEST_BUCKET_NAME` environment variable to the name of a test Google -Cloud Storage bucket: - - Linux: - - export TEST_BUCKET_NAME=your-bucket-name - - Windows: - - set TEST_BUCKET_NAME=your-bucket-name - - Windows (PowerShell): - - $env:TEST_BUCKET_NAME="your-bucket-name" - 1. In a terminal, start Redis: redis-server @@ -198,14 +183,14 @@ Cloud Storage bucket: ### Google Cloud Platform logoGoogle Cloud Node.js client library -The idiomatic client for Google Cloud Platform services. +The recommended, idiomatic client for Google Cloud Platform services. * [Documentation](https://googlecloudplatform.github.io/gcloud-node/) * [Source code](https://github.com/GoogleCloudPlatform/gcloud-node) ### Google logoGoogle API Node.js client library -Node.js client library for Google APIs. +An older Node.js client library for making REST requests to Google APIs. * [Documentation](http://google.github.io/google-api-nodejs-client/) * [Source code](https://github.com/google/google-api-nodejs-client) @@ -261,7 +246,7 @@ View the [Cloud Functions Node.js samples][functions_samples]. ### Storage and Databases -#### Google Cloud Datastore (Beta) +#### Google Cloud Datastore [Cloud Datastore][datastore_docs] is a NoSQL document database built for automatic scaling, high performance, and ease of application development. @@ -305,7 +290,7 @@ View the [Cloud Pub/Sub Node.js samples][pubsub_samples]. ### Machine Learning -#### Google Cloud Natural Language API (Beta) +#### Google Cloud Natural Language API [Cloud Natural Language API][language_docs] provides natural language understanding technologies to developers, including sentiment analysis, entity @@ -361,7 +346,7 @@ View the [Cloud Vision API Node.js samples][vision_samples]. ### Management Tools -#### Stackdriver Debugger (Beta) +#### Stackdriver Debugger [Stackdriver Debugger][debugger_docs] makes it easier to view the application state without adding logging statements. @@ -371,7 +356,7 @@ View the [Stackdriver Debugger Node.js sample][debugger_sample]. [debugger_docs]: https://cloud.google.com/debugger/docs/ [debugger_sample]: debugger -#### Stackdriver Logging (Beta) +#### Stackdriver Logging [Stackdriver Logging][logging_docs] allows you to store, search, analyze, monitor, and alert on log data and events from Google Cloud Platform and Amazon @@ -382,7 +367,7 @@ View the [Stackdriver Logging Node.js samples][logging_samples]. [logging_docs]: https://cloud.google.com/logging/docs/ [logging_samples]: logging -#### Stackdriver Monitoring (Beta) +#### Stackdriver Monitoring [Stackdriver Monitoring][monitoring_docs] collects metrics, events, and metadata from Google Cloud Platform, Amazon Web Services (AWS), hosted uptime probes, @@ -394,7 +379,7 @@ View the [Stackdriver Monitoring Node.js samples][monitoring_samples]. [monitoring_docs]: https://cloud.google.com/monitoring/docs/ [monitoring_samples]: monitoring -#### Stackdriver Trace (Beta) +#### Stackdriver Trace [Stackdriver Trace][trace_docs] is a distributed tracing system for Google Cloud Platform that collects latency data from App Engine applications and displays it diff --git a/datastore/README.md b/datastore/README.md index 5c34edc732..f7500f62ee 100644 --- a/datastore/README.md +++ b/datastore/README.md @@ -33,15 +33,26 @@ View the [documentation][tasks_docs] or the [source code][tasks_code]. __Run the sample:__ -Usage: `node tasks [args]...` - -Print usage: - - node tasks - -Example: - - node tasks list +Usage: `node tasks.js [args]...` + +``` +Commands: + new Adds a task with a description . + done Marks the specified task as done. + list Lists all tasks ordered by creation time. + delete Deletes a task. + +Options: + --help Show help [boolean] + +Examples: + node tasks.js new "Buy milk" Adds a task with description "Buy milk". + node tasks.js done 12345 Marks task 12345 as Done. + node tasks.js list Lists all tasks ordered by creation time + node tasks.js delete 12345 Deletes task 12345. + +For more information, see https://cloud.google.com/datastore/docs +``` [tasks_docs]: https://cloud.google.com/datastore/docs/datastore-api-tutorial [tasks_code]: tasks.js diff --git a/datastore/concepts.js b/datastore/concepts.js index 658f8cb578..ccf1f79a06 100644 --- a/datastore/concepts.js +++ b/datastore/concepts.js @@ -1,1352 +1,1244 @@ -// Copyright 2015, Google, Inc. -// 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. +/** + * Copyright 2016, Google, Inc. + * 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 asyncUtil = require('async'); +const assert = require('power-assert'); // By default, the client will authenticate using the service account file // specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable and use // the project specified by the GCLOUD_PROJECT environment variable. See // https://googlecloudplatform.github.io/gcloud-node/#/docs/google-cloud/latest/guides/authentication -var Datastore = require('@google-cloud/datastore'); +const Datastore = require('@google-cloud/datastore'); -module.exports = { - Entity: Entity, - Index: Index, - Metadata: Metadata, - Query: Query, - Transaction: Transaction -}; +function makeStub () { + return sinon.stub().returns(Promise.resolve([])); +} // This mock is used in the documentation snippets. -var datastore = { - delete: function () {}, - get: function () {}, - insert: function () {}, - key: function () {}, - update: function () {}, - upsert: function () {}, - runQuery: function () {}, - save: function () {} +let datastore = { + delete: makeStub(), + get: makeStub(), + insert: makeStub(), + key: makeStub(), + update: makeStub(), + upsert: makeStub(), + runQuery: sinon.stub().returns(Promise.resolve([[]])), + save: makeStub() }; -function Entity (projectId) { - var options = { - projectId: projectId - }; - - this.datastore = Datastore(options); - - // To create the keys, we have to use this instance of Datastore. - datastore.key = this.datastore.key; - - this.incompleteKey = this.getIncompleteKey(); - this.namedKey = this.getNamedKey(); - this.keyWithParent = this.getKeyWithParent(); - this.keyWithMultiLevelParent = this.getKeyWithMultiLevelParent(); +class TestHelper { + constructor (projectId) { + const options = { + projectId: projectId + }; + this.datastore = Datastore(options); + } } -Entity.prototype.getIncompleteKey = function () { - // [START incomplete_key] - var taskKey = datastore.key('Task'); - // [END incomplete_key] - - return taskKey; -}; - -Entity.prototype.getNamedKey = function () { - // [START named_key] - var taskKey = datastore.key([ - 'Task', - 'sampleTask' - ]); - // [END named_key] - - return taskKey; -}; +class Entity extends TestHelper { + constructor (projectId) { + super(projectId); + // To create the keys, we have to use this instance of Datastore. + datastore.key = this.datastore.key; -Entity.prototype.getKeyWithParent = function () { - // [START key_with_parent] - var taskKey = datastore.key([ - 'TaskList', - 'default', - 'Task', - 'sampleTask' - ]); - // [END key_with_parent] - - return taskKey; -}; - -Entity.prototype.getKeyWithMultiLevelParent = function () { - // [START key_with_multilevel_parent] - var taskKey = datastore.key([ - 'User', - 'alice', - 'TaskList', - 'default', - 'Task', - 'sampleTask' - ]); - // [END key_with_multilevel_parent] - - return taskKey; -}; + this.incompleteKey = this.getIncompleteKey(); + this.namedKey = this.getNamedKey(); + this.keyWithParent = this.getKeyWithParent(); + this.keyWithMultiLevelParent = this.getKeyWithMultiLevelParent(); + } -Entity.prototype.getTask = function () { - // [START basic_entity] - var task = { - category: 'Personal', - done: false, - priority: 4, - description: 'Learn Cloud Datastore' - }; - // [END basic_entity] - - return task; -}; + getIncompleteKey () { + // [START incomplete_key] + const taskKey = datastore.key('Task'); + // [END incomplete_key] -Entity.prototype.testIncompleteKey = function (callback) { - this.datastore.save({ - key: this.incompleteKey, - data: {} - }, callback); -}; + return taskKey; + } -Entity.prototype.testNamedKey = function (callback) { - this.datastore.save({ - key: this.namedKey, - data: {} - }, callback); -}; + getNamedKey () { + // [START named_key] + const taskKey = datastore.key([ + 'Task', + 'sampleTask' + ]); + // [END named_key] -Entity.prototype.testKeyWithParent = function (callback) { - this.datastore.save({ - key: this.keyWithParent, - data: {} - }, callback); -}; + return taskKey; + } -Entity.prototype.testKeyWithMultiLevelParent = function (callback) { - this.datastore.save({ - key: this.keyWithMultiLevelParent, - data: {} - }, callback); -}; + getKeyWithParent () { + // [START key_with_parent] + const taskKey = datastore.key([ + 'TaskList', + 'default', + 'Task', + 'sampleTask' + ]); + // [END key_with_parent] + + return taskKey; + } -Entity.prototype.testEntityWithParent = function (callback) { - var taskKey = this.keyWithParent; + getKeyWithMultiLevelParent () { + // [START key_with_multilevel_parent] + const taskKey = datastore.key([ + 'User', + 'alice', + 'TaskList', + 'default', + 'Task', + 'sampleTask' + ]); + // [END key_with_multilevel_parent] + + return taskKey; + } - // [START entity_with_parent] - var task = { - key: taskKey, - data: { + getTask () { + // [START basic_entity] + const task = { category: 'Personal', done: false, priority: 4, description: 'Learn Cloud Datastore' - } - }; - // [END entity_with_parent] - - this.datastore.save(task, callback); -}; - -Entity.prototype.testProperties = function (callback) { - // jshint camelcase:false - // [START properties] - var task = [ - { - name: 'category', - value: 'Personal' - }, - { - name: 'created', - value: new Date() - }, - { - name: 'done', - value: false - }, - { - name: 'priority', - value: 4 - }, - { - name: 'percent_complete', - value: 10.0 - }, - { - name: 'description', - value: 'Learn Cloud Datastore', - excludeFromIndexes: true - } - ]; - // [END properties] - - this.datastore.save({ - key: this.incompleteKey, - data: task - }, callback); -}; - -Entity.prototype.testArrayValue = function (callback) { - // [START array_value] - var task = { - tags: [ - 'fun', - 'programming' - ], - collaborators: [ - 'alice', - 'bob' - ] - }; - // [END array_value] - - this.datastore.save({ - key: this.incompleteKey, - data: task - }, callback); -}; - -Entity.prototype.testBasicEntity = function (callback) { - this.datastore.save({ - key: this.getIncompleteKey(), - data: this.getTask() - }, callback); -}; + }; + // [END basic_entity] -Entity.prototype.testUpsert = function (callback) { - var taskKey = this.getIncompleteKey(); - var task = this.getTask(); - - // [START upsert] - datastore.upsert({ - key: taskKey, - data: task - }, function (err) { - if (!err) { - // Task inserted successfully. - } - }); - // [END upsert] + return task; + } - this.datastore.upsert({ - key: this.datastore.key(['Task', 1]), - data: task - }, callback); -}; + testIncompleteKey () { + return this.datastore.save({ + key: this.incompleteKey, + data: {} + }); + } -Entity.prototype.testInsert = function (callback) { - var taskKey = this.getIncompleteKey(); - var task = this.getTask(); - - // [START insert] - datastore.insert({ - key: taskKey, - data: task - }, function (err) { - if (!err) { - // Task inserted successfully. - } - }); - // [END insert] - - this.datastore.save({ - method: 'insert', - key: taskKey, - data: task - }, callback); -}; + testNamedKey () { + return this.datastore.save({ + key: this.namedKey, + data: {} + }); + } -Entity.prototype.testLookup = function (callback) { - var self = this; - var taskKey = this.getIncompleteKey(); - - // jshint unused:false - // [START lookup] - datastore.get(taskKey, function (err, entity) { - if (!err) { - // Task found. - - // entity.data = { - // category: 'Personal', - // done: false, - // priority: 4, - // description: 'Learn Cloud Datastore' - // }; - } - }); - // [END lookup] - - this.datastore.save({ - method: 'insert', - key: taskKey, - data: {} - }, function (err) { - if (err) { - callback(err); - return; - } + testKeyWithParent () { + return this.datastore.save({ + key: this.keyWithParent, + data: {} + }); + } - self.datastore.get(taskKey, callback); - }); -}; + testKeyWithMultiLevelParent () { + return this.datastore.save({ + key: this.keyWithMultiLevelParent, + data: {} + }); + } -Entity.prototype.testUpdate = function (callback) { - var self = this; - var taskKey = this.getIncompleteKey(); - var task = this.getTask(); - - // [START update] - datastore.update({ - key: taskKey, - data: task - }, function (err) { - if (!err) { - // Task updated successfully. - } - }); - // [END update] - - this.datastore.save({ - method: 'insert', - key: taskKey, - data: {} - }, function (err) { - if (err) { - callback(err); - return; - } + testEntityWithParent () { + const taskKey = this.keyWithParent; - self.datastore.update({ + // [START entity_with_parent] + const task = { key: taskKey, - data: task - }, callback); - }); -}; - -Entity.prototype.testDelete = function (callback) { - var self = this; - var taskKey = this.getIncompleteKey(); - - // [START delete] - datastore.delete(taskKey, function (err) { - if (!err) { - // Task deleted successfully. - } - }); - // [END delete] - - this.datastore.save({ - method: 'insert', - key: taskKey, - data: {} - }, function (err) { - if (err) { - callback(err); - return; - } - - self.datastore.delete(taskKey, callback); - }); -}; - -Entity.prototype.testBatchUpsert = function (callback) { - var taskKey1 = this.datastore.key(['Task', 1]); - var taskKey2 = this.datastore.key(['Task', 2]); - - var task1 = { - category: 'Personal', - done: false, - priority: 4, - description: 'Learn Cloud Datastore' - }; - - var task2 = { - category: 'Work', - done: false, - priority: 8, - description: 'Integrate Cloud Datastore' - }; - - // [START batch_upsert] - datastore.upsert([ - { - key: taskKey1, - data: task1 - }, - { - key: taskKey2, - data: task2 - } - ], function (err) { - if (!err) { - // Tasks inserted successfully. - } - }); - // [END batch_upsert] - - this.datastore.upsert([ - { - key: taskKey1, - data: task1 - }, - { - key: taskKey2, - data: task2 - } - ], callback); -}; - -Entity.prototype.testBatchLookup = function (callback) { - var taskKey1 = this.datastore.key(['Task', 1]); - var taskKey2 = this.datastore.key(['Task', 2]); - - // jshint unused:false - // [START batch_lookup] - datastore.get([ - taskKey1, - taskKey2 - ], function (err, tasks) { - if (!err) { - // Tasks retrieved successfully. - } - }); - // [END batch_lookup] - - this.datastore.get([ - taskKey1, - taskKey2 - ], callback); -}; - -Entity.prototype.testBatchDelete = function (callback) { - var taskKey1 = this.datastore.key(['Task', 1]); - var taskKey2 = this.datastore.key(['Task', 2]); - - // [START batch_delete] - datastore.delete([ - taskKey1, - taskKey2 - ], function (err) { - if (!err) { - // Tasks deleted successfully. - } - }); - // [END batch_delete] - - this.datastore.delete([ - taskKey1, - taskKey2 - ], callback); -}; - -function Index (projectId) { - var options = { - projectId: projectId - }; - - this.datastore = Datastore(options); -} - -Index.prototype.testUnindexedPropertyQuery = function (callback) { - var datastore = this.datastore; + data: { + category: 'Personal', + done: false, + priority: 4, + description: 'Learn Cloud Datastore' + } + }; + // [END entity_with_parent] - // [START unindexed_property_query] - var query = datastore.createQuery('Task') - .filter('description', '=', 'A task description.'); - // [END unindexed_property_query] + return this.datastore.save(task); + } - this.datastore.runQuery(query, callback); -}; + testProperties () { + // [START properties] + const task = [ + { + name: 'category', + value: 'Personal' + }, + { + name: 'created', + value: new Date() + }, + { + name: 'done', + value: false + }, + { + name: 'priority', + value: 4 + }, + { + name: 'percent_complete', + value: 10.0 + }, + { + name: 'description', + value: 'Learn Cloud Datastore', + excludeFromIndexes: true + } + ]; + // [END properties] -Index.prototype.testExplodingProperties = function (callback) { - var original = datastore.key; - datastore.key = this.datastore.key; + return this.datastore.save({ + key: this.incompleteKey, + data: task + }); + } - // [START exploding_properties] - var task = { - method: 'insert', - key: datastore.key('Task'), - data: { + testArrayValue () { + // [START array_value] + const task = { tags: [ 'fun', - 'programming', - 'learn' + 'programming' ], collaborators: [ 'alice', - 'bob', - 'charlie' - ], - created: new Date() - } - }; - // [END exploding_properties] - - datastore.key = original; - - this.datastore.save(task, callback); -}; + 'bob' + ] + }; + // [END array_value] -function Metadata (projectId) { - var options = { - projectId: projectId - }; + return this.datastore.save({ + key: this.incompleteKey, + data: task + }); + } - this.datastore = Datastore(options); -} + testBasicEntity () { + return this.datastore.save({ + key: this.getIncompleteKey(), + data: this.getTask() + }); + } -Metadata.prototype.testNamespaceRunQuery = function (callback) { - var self = this; + testUpsert () { + const taskKey = this.getIncompleteKey(); + const task = this.getTask(); - datastore.createQuery = this.datastore.createQuery; - datastore.key = this.datastore.key; + // [START upsert] + const entity = { + key: taskKey, + data: task + }; - var startNamespace = 'Animals'; - var endNamespace = 'Zoos'; + datastore.upsert(entity) + .then(() => { + // Task inserted successfully. + }); + // [END upsert] - this.datastore.save([ - { - key: datastore.key({ - namespace: 'Animals', - path: ['Ant', 1] - }), - data: {} - } - ], function (err) { - if (err) { - callback(err); - return; - } + return this.datastore.upsert({ + key: this.datastore.key(['Task', 1]), + data: task + }); + } - // jshint unused:false - // [START namespace_run_query] - var query = datastore.createQuery('__namespace__') - .select('__key__') - .filter('__key__', '>=', datastore.key(['__namespace__', startNamespace])) - .filter('__key__', '<', datastore.key(['__namespace__', endNamespace])); + testInsert () { + const taskKey = this.getIncompleteKey(); + const task = this.getTask(); - datastore.runQuery(query, function (err, entities) { - if (err) { - // An error occurred while running the query. - return; - } + // [START insert] + const entity = { + key: taskKey, + data: task + }; - var namespaces = entities.map(function (entity) { - return entity.key.path.pop(); + datastore.insert(entity) + .then(() => { + // Task inserted successfully. }); - console.log('namespaces', namespaces); - }); - // [END namespace_run_query] + // [END insert] - self.datastore.runQuery(query, callback); - }); -}; + return this.datastore.save({ + method: 'insert', + key: taskKey, + data: task + }); + } -Metadata.prototype.testKindRunQuery = function (callback) { - datastore.createQuery = this.datastore.createQuery; + testLookup () { + const taskKey = this.getIncompleteKey(); + + // [START lookup] + datastore.get(taskKey) + .then((results) => { + // Task found. + const entity = results[0]; + + // entity = { + // category: 'Personal', + // done: false, + // priority: 4, + // description: 'Learn Cloud Datastore' + // }; + console.log(entity); + }); + // [END lookup] - // jshint unused:false - // [START kind_run_query] - var query = datastore.createQuery('__kind__') - .select('__key__'); + return this.datastore.save({ + method: 'insert', + key: taskKey, + data: {} + }).then(() => this.datastore.get(taskKey)); + } - datastore.runQuery(query, function (err, entities) { - if (err) { - // An error occurred while running the query. - return; - } + testUpdate () { + const taskKey = this.getIncompleteKey(); + const task = this.getTask(); - var kinds = entities.map(function (entity) { - return entity.key.path.pop(); - }); - console.log('kinds', kinds); - }); - // [END kind_run_query] + // [START update] + const entity = { + key: taskKey, + data: task + }; - this.datastore.runQuery(query, callback); -}; + datastore.update(entity) + .then(() => { + // Task updated successfully. + }); + // [END update] -Metadata.prototype.testPropertyRunQuery = function (callback) { - datastore.createQuery = this.datastore.createQuery; + return this.datastore.save({ + method: 'insert', + key: taskKey, + data: {} + }).then(() => this.datastore.update({ key: taskKey, data: task })); + } - // [START property_run_query] - var query = datastore.createQuery('__property__') - .select('__key__'); + testDelete () { + const taskKey = this.getIncompleteKey(); - datastore.runQuery(query, function (err, entities) { - if (err) { - // An error occurred while running the query. - return; - } + // [START delete] + datastore.delete(taskKey) + .then(() => { + // Task deleted successfully. + }); + // [END delete] - var propertiesByKind = {}; + return this.datastore.save({ + method: 'insert', + key: taskKey, + data: {} + }).then(() => this.datastore.delete(taskKey)); + } - entities.forEach(function (entity) { - var kind = entity.key.path[1]; - var propertyName = entity.key.path[3]; + testBatchUpsert () { + const taskKey1 = this.datastore.key(['Task', 1]); + const taskKey2 = this.datastore.key(['Task', 2]); - propertiesByKind[kind] = propertiesByKind[kind] || []; - propertiesByKind[kind].push(propertyName); - }); - }); - // [END property_run_query] + const task1 = { + category: 'Personal', + done: false, + priority: 4, + description: 'Learn Cloud Datastore' + }; - this.datastore.runQuery(query, callback); -}; + const task2 = { + category: 'Work', + done: false, + priority: 8, + description: 'Integrate Cloud Datastore' + }; -Metadata.prototype.testPropertyByKindRunQuery = function (callback) { - var datastore = this.datastore; + // [START batch_upsert] + const entities = [ + { + key: taskKey1, + data: task1 + }, + { + key: taskKey2, + data: task2 + } + ]; - // jshint camelcase:false - // [START property_by_kind_run_query] - var ancestorKey = datastore.key(['__kind__', 'Task']); + datastore.upsert(entities) + .then(() => { + // Tasks inserted successfully. + }); + // [END batch_upsert] + + return this.datastore.upsert([ + { + key: taskKey1, + data: task1 + }, + { + key: taskKey2, + data: task2 + } + ]); + } - var query = datastore.createQuery('__property__') - .hasAncestor(ancestorKey); + testBatchLookup () { + const taskKey1 = this.datastore.key(['Task', 1]); + const taskKey2 = this.datastore.key(['Task', 2]); - datastore.runQuery(query, function (err, entities) { - if (err) { - // An error occurred while running the query. - return; - } + // [START batch_lookup] + const keys = [taskKey1, taskKey2]; - var representationsByProperty = {}; + datastore.get(keys) + .then((results) => { + // Tasks retrieved successfully. + const tasks = results[0]; - entities.forEach(function (entity) { - var propertyName = entity.key.path.pop(); - var propertyType = entity.data.property_representation; + console.log(tasks); + }); + // [END batch_lookup] - representationsByProperty[propertyName] = propertyType; - }); - }); - // [END property_by_kind_run_query] + return this.datastore.get([taskKey1, taskKey2]); + } - this.datastore.runQuery(query, callback); -}; + testBatchDelete () { + const taskKey1 = this.datastore.key(['Task', 1]); + const taskKey2 = this.datastore.key(['Task', 2]); -function Query (projectId) { - var options = { - projectId: projectId - }; + // [START batch_delete] + const keys = [taskKey1, taskKey2]; - this.datastore = Datastore(options); + datastore.delete(keys) + .then(() => { + // Tasks deleted successfully. + }); + // [END batch_delete] - this.basicQuery = this.getBasicQuery(); - this.projectionQuery = this.getProjectionQuery(); - this.ancestorQuery = this.getAncestorQuery(); + return this.datastore.delete([taskKey1, taskKey2]); + } } -Query.prototype.getBasicQuery = function () { - var datastore = this.datastore; +class Index extends TestHelper { + testUnindexedPropertyQuery () { + const datastore = this.datastore; - // [START basic_query] - var query = datastore.createQuery('Task') - .filter('done', '=', false) - .filter('priority', '>=', 4) - .order('priority', { - descending: true - }); - // [END basic_query] + // [START unindexed_property_query] + const query = datastore.createQuery('Task') + .filter('description', '=', 'A task description.'); + // [END unindexed_property_query] - return query; -}; + return this.datastore.runQuery(query); + } + + testExplodingProperties () { + const original = datastore.key; + datastore.key = this.datastore.key; -Query.prototype.getProjectionQuery = function () { - var datastore = this.datastore; + // [START exploding_properties] + const task = { + method: 'insert', + key: datastore.key('Task'), + data: { + tags: [ + 'fun', + 'programming', + 'learn' + ], + collaborators: [ + 'alice', + 'bob', + 'charlie' + ], + created: new Date() + } + }; + // [END exploding_properties] - // [START projection_query] - var query = datastore.createQuery('Task') - .select(['priority', 'percent_complete']); - // [END projection_query] + datastore.key = original; - return query; -}; + return this.datastore.save(task) + .then(() => { + assert(task.key); + assert(task.key.id); + }); + } +} -Query.prototype.getAncestorQuery = function () { - var datastore = this.datastore; +class Metadata extends TestHelper { + testNamespaceRunQuery () { + const datastore = this.datastore; - // [START ancestor_query] - var ancestorKey = datastore.key(['TaskList', 'default']); + const startNamespace = 'Animals'; + const endNamespace = 'Zoos'; - var query = datastore.createQuery('Task') - .hasAncestor(ancestorKey); - // [END ancestor_query] + return datastore.save({ + key: datastore.key({ + namespace: 'Animals', + path: ['Ant', 1] + }), + data: {} + }) + .then(() => { + // [START namespace_run_query] + function runNamespaceQuery (startNamespace, endNamespace) { + const startKey = datastore.key(['__namespace__', startNamespace]); + const endKey = datastore.key(['__namespace__', endNamespace]); + + const query = datastore.createQuery('__namespace__') + .select('__key__') + .filter('__key__', '>=', startKey) + .filter('__key__', '<', endKey); + + return datastore.runQuery(query) + .then((results) => { + const entities = results[0]; + const namespaces = entities.map((entity) => entity[datastore.KEY].name); + + console.log('Namespaces:'); + namespaces.forEach((namespace) => console.log(namespace)); + + return namespaces; + }); + } + // [END namespace_run_query] - return query; -}; + return runNamespaceQuery(startNamespace, endNamespace); + }) + .then((namespaces) => { + assert.deepEqual(namespaces, ['Animals']); + }); + } -Query.prototype.testRunQuery = function (callback) { - var query = this.basicQuery; + testKindRunQuery () { + const datastore = this.datastore; - // jshint unused:false - // [START run_query] - datastore.runQuery(query, function (err, tasks) { - if (!err) { - // Task entities found. - } - }); - // [END run_query] + // [START kind_run_query] + function runKindQuery () { + const query = datastore.createQuery('__kind__') + .select('__key__'); - this.datastore.runQuery(query, callback); -}; + return datastore.runQuery(query) + .then((results) => { + const entities = results[0]; + const kinds = entities.map((entity) => entity[datastore.KEY].name); -Query.prototype.testPropertyFilter = function (callback) { - var datastore = this.datastore; + console.log('Kinds:'); + kinds.forEach((kind) => console.log(kind)); - // [START property_filter] - var query = datastore.createQuery('Task') - .filter('done', '=', false); - // [END property_filter] + return kinds; + }); + } + // [END kind_run_query] - this.datastore.runQuery(query, callback); -}; + return runKindQuery() + .then((kinds) => { + assert.equal(kinds.includes('Account'), true); + }); + } -Query.prototype.testCompositeFilter = function (callback) { - var datastore = this.datastore; + testPropertyRunQuery () { + const datastore = this.datastore; - // [START composite_filter] - var query = datastore.createQuery('Task') - .filter('done', '=', false) - .filter('priority', '=', 4); - // [END composite_filter] + // [START property_run_query] + function runPropertyQuery () { + const query = datastore.createQuery('__property__') + .select('__key__'); - this.datastore.runQuery(query, callback); -}; + return datastore.runQuery(query) + .then((results) => { + const entities = results[0]; + const propertiesByKind = {}; -Query.prototype.testKeyFilter = function (callback) { - var datastore = this.datastore; + entities.forEach((entity) => { + const key = entity[datastore.KEY]; + const kind = key.path[1]; + const property = key.path[3]; - // [START key_filter] - var query = datastore.createQuery('Task') - .filter('__key__', '>', datastore.key(['Task', 'someTask'])); - // [END key_filter] + propertiesByKind[kind] = propertiesByKind[kind] || []; + propertiesByKind[kind].push(property); + }); - this.datastore.runQuery(query, callback); -}; + console.log('Properties by Kind:'); + for (let key in propertiesByKind) { + console.log(key, propertiesByKind[key]); + } -Query.prototype.testAscendingSort = function (callback) { - var datastore = this.datastore; + return propertiesByKind; + }); + } + // [END property_run_query] - // [START ascending_sort] - var query = datastore.createQuery('Task') - .order('created'); - // [END ascending_sort] + return runPropertyQuery() + .then((propertiesByKind) => { + assert.deepEqual(propertiesByKind.Account, ['balance']); + }); + } - this.datastore.runQuery(query, callback); -}; + testPropertyByKindRunQuery () { + const datastore = this.datastore; -Query.prototype.testDescendingSort = function (callback) { - var datastore = this.datastore; + // [START property_by_kind_run_query] + function runPropertyByKindQuery () { + const ancestorKey = datastore.key(['__kind__', 'Account']); - // [START descending_sort] - var query = datastore.createQuery('Task') - .order('created', { - descending: true - }); - // [END descending_sort] + const query = datastore.createQuery('__property__') + .hasAncestor(ancestorKey); - this.datastore.runQuery(query, callback); -}; + return datastore.runQuery(query) + .then((results) => { + const entities = results[0]; -Query.prototype.testMultiSort = function (callback) { - var datastore = this.datastore; + const representationsByProperty = {}; - // [START multi_sort] - var query = datastore.createQuery('Task') - .order('priority', { - descending: true - }) - .order('created'); - // [END multi_sort] + entities.forEach((entity) => { + const key = entity[datastore.KEY]; + const propertyName = key.name; + const propertyType = entity.property_representation; - this.datastore.runQuery(query, callback); -}; + representationsByProperty[propertyName] = propertyType; + }); -Query.prototype.testKindlessQuery = function (callback) { - var datastore = this.datastore; - var lastSeenKey = this.datastore.key(['Task', Date.now()]); + console.log('Task property representations:'); + for (let key in representationsByProperty) { + console.log(key, representationsByProperty[key]); + } - // [START kindless_query] - var query = datastore.createQuery() - .filter('__key__', '>', lastSeenKey) - .limit(1); - // [END kindless_query] + return representationsByProperty; + }); + } + // [END property_by_kind_run_query] - this.datastore.runQuery(query, callback); -}; + return runPropertyByKindQuery() + .then((propertiesByKind) => { + assert.deepEqual(propertiesByKind, { + balance: ['INT64'] + }); + }); + } +} -Query.prototype.testRunQueryProjection = function (callback) { - var self = this; - var query = this.projectionQuery; +class Query extends TestHelper { + constructor (projectId) { + super(projectId); - // Overwrite the mock to actually run the query. - datastore.runQuery = function (query, queryCallback) { - // Restore the mock. - datastore.runQuery = function () {}; + this.basicQuery = this.getBasicQuery(); + this.projectionQuery = this.getProjectionQuery(); + this.ancestorQuery = this.getAncestorQuery(); + } - self.datastore.runQuery(query, function (err) { - if (err) { - return callback(err); - } + getBasicQuery () { + const datastore = this.datastore; - queryCallback.apply(null, arguments); + // [START basic_query] + const query = datastore.createQuery('Task') + .filter('done', '=', false) + .filter('priority', '>=', 4) + .order('priority', { + descending: true + }); + // [END basic_query] - if (priorities.length === 0 || percentCompletes.length === 0) { - callback(new Error('Projection lists did not build up.')); - } else { - callback(); - } - }); - }; + return query; + } - // jshint unused:false, camelcase:false - // [START run_query_projection] - var priorities = []; - var percentCompletes = []; + getProjectionQuery () { + const datastore = this.datastore; - datastore.runQuery(query, function (err, tasks) { - if (err) { - // An error occurred while running the query. - return; - } + // [START projection_query] + const query = datastore.createQuery('Task') + .select(['priority', 'percent_complete']); + // [END projection_query] - tasks.forEach(function (task) { - priorities.push(task.data.priority); - percentCompletes.push(task.data.percent_complete); - }); - }); - // [END run_query_projection] -}; + return query; + } -Query.prototype.testKeysOnlyQuery = function (callback) { - var datastore = this.datastore; + getAncestorQuery () { + const datastore = this.datastore; - // [START keys_only_query] - var query = datastore.createQuery() - .select('__key__') - .limit(1); - // [END keys_only_query] + // [START ancestor_query] + const ancestorKey = datastore.key(['TaskList', 'default']); - this.datastore.runQuery(query, callback); -}; + const query = datastore.createQuery('Task') + .hasAncestor(ancestorKey); + // [END ancestor_query] -Query.prototype.testDistinctQuery = function (callback) { - var datastore = this.datastore; + return query; + } - // [START distinct_query] - var query = datastore.createQuery('Task') - .groupBy(['category', 'priority']) - .order('category') - .order('priority'); - // [END distinct_query] + testRunQuery () { + const query = this.basicQuery; - this.datastore.runQuery(query, callback); -}; + // [START run_query] + datastore.runQuery(query) + .then((results) => { + // Task entities found. + const tasks = results[0]; -Query.prototype.testDistinctOnQuery = function (callback) { - var datastore = this.datastore; + console.log('Tasks:'); + tasks.forEach((task) => console.log(task)); + }); + // [END run_query] - // [START distinct_on_query] - var query = datastore.createQuery('Task') - .groupBy('category') - .order('category') - .order('priority'); - // [END distinct_on_query] + return this.datastore.runQuery(query); + } - this.datastore.runQuery(query, callback); -}; + testPropertyFilter () { + const datastore = this.datastore; -Query.prototype.testArrayValueInequalityRange = function (callback) { - var datastore = this.datastore; + // [START property_filter] + const query = datastore.createQuery('Task') + .filter('done', '=', false); + // [END property_filter] - // [START array_value_inequality_range] - var query = datastore.createQuery('Task') - .filter('tag', '>', 'learn') - .filter('tag', '<', 'math'); - // [END array_value_inequality_range] + return this.datastore.runQuery(query); + } - this.datastore.runQuery(query, callback); -}; + testCompositeFilter () { + const datastore = this.datastore; -Query.prototype.testArrayValueEquality = function (callback) { - var datastore = this.datastore; + // [START composite_filter] + const query = datastore.createQuery('Task') + .filter('done', '=', false) + .filter('priority', '=', 4); + // [END composite_filter] - // [START array_value_equality] - var query = datastore.createQuery('Task') - .filter('tag', '=', 'fun') - .filter('tag', '=', 'programming'); - // [END array_value_equality] + return this.datastore.runQuery(query); + } - this.datastore.runQuery(query, callback); -}; + testKeyFilter () { + const datastore = this.datastore; -Query.prototype.testInequalityRange = function (callback) { - var datastore = this.datastore; + // [START key_filter] + const query = datastore.createQuery('Task') + .filter('__key__', '>', datastore.key(['Task', 'someTask'])); + // [END key_filter] - // [START inequality_range] - var query = datastore.createQuery('Task') - .filter('created', '>', new Date('1990-01-01T00:00:00z')) - .filter('created', '<', new Date('2000-12-31T23:59:59z')); - // [END inequality_range] + return this.datastore.runQuery(query); + } - this.datastore.runQuery(query, callback); -}; + testAscendingSort () { + const datastore = this.datastore; -Query.prototype.testInequalityInvalid = function (callback) { - var datastore = this.datastore; + // [START ascending_sort] + const query = datastore.createQuery('Task') + .order('created'); + // [END ascending_sort] - // [START inequality_invalid] - var query = datastore.createQuery('Task') - .filter('priority', '>', 3) - .filter('created', '>', new Date('1990-01-01T00:00:00z')); - // [END inequality_invalid] + return this.datastore.runQuery(query); + } - this.datastore.runQuery(query, callback); -}; + testDescendingSort () { + const datastore = this.datastore; -Query.prototype.testEqualAndInequalityRange = function (callback) { - var datastore = this.datastore; + // [START descending_sort] + const query = datastore.createQuery('Task') + .order('created', { + descending: true + }); + // [END descending_sort] - // [START equal_and_inequality_range] - var query = datastore.createQuery('Task') - .filter('priority', '=', 4) - .filter('done', '=', false) - .filter('created', '>', new Date('1990-01-01T00:00:00z')) - .filter('created', '<', new Date('2000-12-31T23:59:59z')); - // [END equal_and_inequality_range] + return this.datastore.runQuery(query); + } - this.datastore.runQuery(query, callback); -}; + testMultiSort () { + const datastore = this.datastore; -Query.prototype.testInequalitySort = function (callback) { - var datastore = this.datastore; + // [START multi_sort] + const query = datastore.createQuery('Task') + .order('priority', { + descending: true + }) + .order('created'); + // [END multi_sort] - // [START inequality_sort] - var query = datastore.createQuery('Task') - .filter('priority', '>', 3) - .order('priority') - .order('created'); - // [END inequality_sort] + return this.datastore.runQuery(query); + } - this.datastore.runQuery(query, callback); -}; + testKindlessQuery () { + const datastore = this.datastore; + const lastSeenKey = this.datastore.key(['Task', Date.now()]); -Query.prototype.testInequalitySortInvalidNotSame = function (callback) { - var datastore = this.datastore; + // [START kindless_query] + const query = datastore.createQuery() + .filter('__key__', '>', lastSeenKey) + .limit(1); + // [END kindless_query] - // [START inequality_sort_invalid_not_same] - var query = datastore.createQuery('Task') - .filter('priority', '>', 3) - .order('created'); - // [END inequality_sort_invalid_not_same] + return this.datastore.runQuery(query); + } - this.datastore.runQuery(query, callback); -}; + testRunQueryProjection () { + const datastore = this.datastore; + const query = this.projectionQuery; -Query.prototype.testInequalitySortInvalidNotFirst = function (callback) { - var datastore = this.datastore; + // [START run_query_projection] + function runProjectionQuery () { + const priorities = []; + const percentCompletes = []; - // [START inequality_sort_invalid_not_first] - var query = datastore.createQuery('Task') - .filter('priority', '>', 3) - .order('created') - .order('priority'); - // [END inequality_sort_invalid_not_first] + return datastore.runQuery(query) + .then((results) => { + const tasks = results[0]; - this.datastore.runQuery(query, callback); -}; + tasks.forEach((task) => { + priorities.push(task.priority); + percentCompletes.push(task.percent_complete); + }); -Query.prototype.testLimit = function (callback) { - var datastore = this.datastore; + return { + priorities: priorities, + percentCompletes: percentCompletes + }; + }); + } + // [END run_query_projection] - // [START limit] - var query = datastore.createQuery('Task') - .limit(5); - // [END limit] + return runProjectionQuery(); + } - this.datastore.runQuery(query, callback); -}; + testKeysOnlyQuery () { + const datastore = this.datastore; -Query.prototype.testCursorPaging = function (callback) { - var pageSize = 1; - var pageCursor = ''; + // [START keys_only_query] + const query = datastore.createQuery() + .select('__key__') + .limit(1); + // [END keys_only_query] - datastore.createQuery = this.datastore.createQuery; + return this.datastore.runQuery(query); + } - // [START cursor_paging] - // By default, gcloud-node will automatically paginate through all of the - // results that match a query. However, this sample implements manual - // pagination using limits and cursor tokens. - var query = datastore.createQuery('Task') - .limit(pageSize) - .start(pageCursor); + testDistinctQuery () { + const datastore = this.datastore; - this.datastore.runQuery(query, function (err, results, info) { - if (err) { - // An error occurred while running the query. - return; - } + // [START distinct_query] + const query = datastore.createQuery('Task') + .groupBy(['category', 'priority']) + .order('category') + .order('priority'); + // [END distinct_query] - var nextPageCursor; + return this.datastore.runQuery(query); + } - if (info.moreResults !== Datastore.NO_MORE_RESULTS) { - // If there are more results to retrieve, the end cursor is - // automatically set on `info`. To get this value directly, access - // the `endCursor` property. - nextPageCursor = info.endCursor; - } else { - // No more results exist. - } - console.log('nextPageCursor', nextPageCursor); - }); - // [END cursor_paging] - - delete datastore.createQuery; - this.datastore.runQuery(query, function (err, results, info) { - if (err) { - callback(err); - return; - } + testDistinctOnQuery () { + const datastore = this.datastore; - if (!info || !info.endCursor) { - callback(new Error('An `info` with an `endCursor` is not present.')); - } else { - callback(); - } - }); -}; + // [START distinct_on_query] + const query = datastore.createQuery('Task') + .groupBy('category') + .order('category') + .order('priority'); + // [END distinct_on_query] -Query.prototype.testEventualConsistentQuery = function () { - // [START eventual_consistent_query] - // Read consistency cannot be specified in gcloud-node. - // [END eventual_consistent_query] -}; + return this.datastore.runQuery(query); + } -// [START transactional_update] -function transferFunds (fromKey, toKey, amount, callback) { - var transaction = datastore.transaction(); + testArrayValueInequalityRange () { + const datastore = this.datastore; - transaction.run(function (err) { - if (err) { - return callback(err); - } + // [START array_value_inequality_range] + const query = datastore.createQuery('Task') + .filter('tag', '>', 'learn') + .filter('tag', '<', 'math'); + // [END array_value_inequality_range] - transaction.get([ - fromKey, - toKey - ], function (err, accounts) { - if (err) { - return transaction.rollback(function (_err) { - return callback(_err || err); - }); - } + return this.datastore.runQuery(query); + } - accounts[0].data.balance -= amount; - accounts[1].data.balance += amount; + testArrayValueEquality () { + const datastore = this.datastore; - transaction.save(accounts); + // [START array_value_equality] + const query = datastore.createQuery('Task') + .filter('tag', '=', 'fun') + .filter('tag', '=', 'programming'); + // [END array_value_equality] - transaction.commit(function (err) { - if (err) { - return callback(err); - } + return this.datastore.runQuery(query); + } - // The transaction completed successfully. - callback(); - }); - }); - }); -} -// [END transactional_update] + testInequalityRange () { + const datastore = this.datastore; -function Transaction (projectId) { - var options = { - projectId: projectId - }; + // [START inequality_range] + const query = datastore.createQuery('Task') + .filter('created', '>', new Date('1990-01-01T00:00:00z')) + .filter('created', '<', new Date('2000-12-31T23:59:59z')); + // [END inequality_range] - this.datastore = Datastore(options); + return this.datastore.runQuery(query); + } - this.fromKey = this.datastore.key(['Bank', 1, 'Account', 1]); - this.toKey = this.datastore.key(['Bank', 1, 'Account', 2]); + testInequalityInvalid () { + const datastore = this.datastore; - this.originalBalance = 100; - this.amountToTransfer = 10; -} + // [START inequality_invalid] + const query = datastore.createQuery('Task') + .filter('priority', '>', 3) + .filter('created', '>', new Date('1990-01-01T00:00:00z')); + // [END inequality_invalid] -Transaction.prototype.restoreBankAccountBalances = function (config, callback) { - var saveArray = config.keys.map(function (key) { - return { - key: key, - data: { - balance: config.balance - } - }; - }); + return this.datastore.runQuery(query); + } - this.datastore.save(saveArray, callback); -}; + testEqualAndInequalityRange () { + const datastore = this.datastore; -Transaction.prototype.testTransactionalUpdate = function (callback) { - var self = this; - - var fromKey = this.fromKey; - var toKey = this.toKey; - var originalBalance = this.originalBalance; - var amountToTransfer = this.amountToTransfer; - - this.restoreBankAccountBalances({ - keys: [fromKey, toKey], - balance: originalBalance - }, function (err) { - if (err) { - callback(err); - return; - } + // [START equal_and_inequality_range] + const query = datastore.createQuery('Task') + .filter('priority', '=', 4) + .filter('done', '=', false) + .filter('created', '>', new Date('1990-01-01T00:00:00z')) + .filter('created', '<', new Date('2000-12-31T23:59:59z')); + // [END equal_and_inequality_range] - // Overwrite so the real Datastore instance is used in `transferFunds`. - var datastoreMock = datastore; - datastore = self.datastore; + return this.datastore.runQuery(query); + } - transferFunds(fromKey, toKey, amountToTransfer, function (err) { - // Restore `datastore` to the mock API. - datastore = datastoreMock; + testInequalitySort () { + const datastore = this.datastore; - if (err) { - callback(err); - return; - } + // [START inequality_sort] + const query = datastore.createQuery('Task') + .filter('priority', '>', 3) + .order('priority') + .order('created'); + // [END inequality_sort] - self.datastore.get([ - fromKey, - toKey - ], function (err, accounts) { - if (err) { - callback(err); - return; - } + return this.datastore.runQuery(query); + } - var transactionWasSuccessful = - accounts[0].data.balance === originalBalance - amountToTransfer && - accounts[1].data.balance === originalBalance + amountToTransfer; + testInequalitySortInvalidNotSame () { + const datastore = this.datastore; - if (!transactionWasSuccessful) { - callback(new Error('Accounts were not updated successfully.')); - } else { - callback(); - } - }); - }); - }); -}; + // [START inequality_sort_invalid_not_same] + const query = datastore.createQuery('Task') + .filter('priority', '>', 3) + .order('created'); + // [END inequality_sort_invalid_not_same] -Transaction.prototype.testTransactionalRetry = function (callback) { - // Overwrite so the real Datastore instance is used in `transferFunds`. - var datastoreMock = datastore; - datastore = this.datastore; - - var originalCallback = callback; - callback = function () { - // Restore `datastore` to the mock API. - datastore = datastoreMock; - originalCallback.apply(null, arguments); - }; - - var fromKey = this.fromKey; - var toKey = this.toKey; - - this.restoreBankAccountBalances({ - keys: [fromKey, toKey], - balance: this.originalBalance - }, function (err) { - if (err) { - callback(err); - return; - } + return this.datastore.runQuery(query); + } - // [START transactional_retry] - var async = require('async'); + testInequalitySortInvalidNotFirst () { + const datastore = this.datastore; - function attemptTransfer (callback) { - transferFunds(fromKey, toKey, 10, callback); - } + // [START inequality_sort_invalid_not_first] + const query = datastore.createQuery('Task') + .filter('priority', '>', 3) + .order('created') + .order('priority'); + // [END inequality_sort_invalid_not_first] - async.retry(5, attemptTransfer, callback); - // [END transactional_retry] - }); -}; + return this.datastore.runQuery(query); + } -Transaction.prototype.testTransactionalGetOrCreate = function (callback) { - var taskKey = this.datastore.key(['Task', Date.now()]); + testLimit () { + const datastore = this.datastore; - // Overwrite so the real Datastore instance is used in `transferFunds`. - var datastoreMock = datastore; - datastore = this.datastore; + // [START limit] + const query = datastore.createQuery('Task') + .limit(5); + // [END limit] - var originalCallback = callback; - callback = function () { - // Restore `datastore` to the mock API. - datastore = datastoreMock; - originalCallback.apply(null, arguments); - }; + return this.datastore.runQuery(query); + } - // [START transactional_get_or_create] - function getOrCreate (taskKey, taskData, callback) { - var taskEntity = { - key: taskKey, - data: taskData - }; + testCursorPaging () { + const datastore = this.datastore; + const pageSize = 1; - var transaction = datastore.transaction(); + // [START cursor_paging] + // By default, google-cloud-node will automatically paginate through all of + // the results that match a query. However, this sample implements manual + // pagination using limits and cursor tokens. + function runPageQuery (pageCursor) { + let query = datastore.createQuery('Task') + .limit(pageSize); - transaction.run(function (err) { - if (err) { - return callback(err); + if (pageCursor) { + query = query.start(pageCursor); } - transaction.get(taskKey, function (err, task) { - if (err) { - // An error occurred while getting the values. - return transaction.rollback(function (_err) { - return callback(_err || err); - }); - } + return datastore.runQuery(query) + .then((results) => { + const entities = results[0]; + const info = results[1]; + + if (info.moreResults !== Datastore.NO_MORE_RESULTS) { + // If there are more results to retrieve, the end cursor is + // automatically set on `info`. To get this value directly, access + // the `endCursor` property. + return runPageQuery(info.endCursor) + .then((results) => { + // Concatenate entities + results[0] = entities.concat(results[0]); + return results; + }); + } - if (task) { - // The task entity already exists. - transaction.rollback(callback); - } else { - // Create the task entity. - transaction.save(taskEntity); - transaction.commit(function (err) { - if (err) { - return callback(err); - } - // The transaction completed successfully. - callback(null, taskEntity); - }); + return [entities, info]; + }); + } + // [END cursor_paging] + + return runPageQuery() + .then((results) => { + const entities = results[0]; + assert.equal(Array.isArray(entities), true); + const info = results[1]; + if (!info || !info.endCursor) { + throw new Error('An `info` with an `endCursor` is not present.'); } }); - }); } - // [END transactional_get_or_create] - - asyncUtil.series([ - // Create: - testWithCreateBehavior, - // Then try to get it: - testWithGetBehavior - ], callback); - - function testWithCreateBehavior (callback) { - getOrCreate(taskKey, {}, function (err, task) { - if (err) { - callback(err); - return; - } - if (!task) { - return callback(new Error('Entity was not created successfully.')); - } - callback(); - }); + testEventualConsistentQuery () { + // [START eventual_consistent_query] + // Read consistency cannot be specified in google-cloud-node. + // [END eventual_consistent_query] } +} - function testWithGetBehavior (callback) { - getOrCreate(taskKey, {}, function (err, task) { - if (err) { - callback(err); - return; - } +// [START transactional_update] +function transferFunds (fromKey, toKey, amount) { + const transaction = datastore.transaction(); + + return transaction.run() + .then(() => Promise.all([transaction.get(fromKey), transaction.get(toKey)])) + .then((results) => { + const accounts = results + .map((result) => result[0]); + + accounts[0].balance -= amount; + accounts[1].balance += amount; + + transaction.save([ + { + key: fromKey, + data: accounts[0] + }, + { + key: toKey, + data: accounts[1] + } + ]); - if (!task) { - return callback(new Error('Entity was not retrieved successfully.')); - } - callback(); + return transaction.commit(); + }) + .catch(() => transaction.rollback()); +} +// [END transactional_update] + +class Transaction extends TestHelper { + constructor (projectId) { + super(projectId); + this.fromKey = this.datastore.key(['Bank', 1, 'Account', 1]); + this.toKey = this.datastore.key(['Bank', 1, 'Account', 2]); + + this.originalBalance = 100; + this.amountToTransfer = 10; + } + + restoreBankAccountBalances (config) { + const entities = config.keys.map((key) => { + return { + key: key, + data: { + balance: config.balance + } + }; }); + + return this.datastore.save(entities); } -}; -Transaction.prototype.testSingleEntityGroupReadOnly = function (callback) { - // Overwrite so the real Datastore instance is used in `transferFunds`. - var datastoreMock = datastore; - datastore = this.datastore; + testTransactionalUpdate () { + const fromKey = this.fromKey; + const toKey = this.toKey; + const originalBalance = this.originalBalance; + const amountToTransfer = this.amountToTransfer; + const datastoreMock = datastore; - var originalCallback = callback; - callback = function () { - // Restore `datastore` to the mock API. - datastore = datastoreMock; - originalCallback.apply(null, arguments); - }; + // Overwrite so the real Datastore instance is used in `transferFunds`. + datastore = this.datastore; - // [START transactional_single_entity_group_read_only] - function getTaskListEntities (callback) { - var taskListEntities; + return this.restoreBankAccountBalances({ + keys: [fromKey, toKey], + balance: originalBalance + }) + .then(() => transferFunds(fromKey, toKey, amountToTransfer)) + .then(() => Promise.all([this.datastore.get(fromKey), this.datastore.get(toKey)])) + .then((results) => { + const accounts = results.map((result) => result[0]); + // Restore `datastore` to the mock API. + datastore = datastoreMock; + assert.equal(accounts[0].balance, originalBalance - amountToTransfer); + assert.equal(accounts[1].balance, originalBalance + amountToTransfer); + }) + .catch((err) => { + // Restore `datastore` to the mock API. + datastore = datastoreMock; + return Promise.reject(err); + }); + } - var transaction = datastore.transaction(); + testTransactionalRetry () { + // Overwrite so the real Datastore instance is used in `transferFunds`. + const datastoreMock = datastore; + datastore = this.datastore; - transaction.run(function (err) { - if (err) { - return callback(err); - } + const fromKey = this.fromKey; + const toKey = this.toKey; - var taskListKey = datastore.key(['TaskList', 'default']); + return this.restoreBankAccountBalances({ + keys: [fromKey, toKey], + balance: this.originalBalance + }) + .then(() => { + // [START transactional_retry] + function transferFundsWithRetry () { + const maxTries = 5; + let currentAttempt = 1; + let delay = 100; + + function tryRequest () { + return transferFunds(fromKey, toKey, 10) + .catch((err) => { + if (currentAttempt <= maxTries) { + // Use exponential backoff + return new Promise((resolve, reject) => { + setTimeout(() => { + currentAttempt++; + delay *= 2; + tryRequest().then(resolve, reject); + }, delay); + }); + } + return Promise.reject(err); + }); + } - datastore.get(taskListKey, function (err) { - if (err) { - return transaction.rollback(function (_err) { - return callback(_err || err); - }); + return tryRequest(1, 5); } + // [END transactional_retry] + return transferFundsWithRetry(); + }) + .then(() => { + // Restore `datastore` to the mock API. + datastore = datastoreMock; + }) + .catch(() => { + // Restore `datastore` to the mock API. + datastore = datastoreMock; + }); + } - var query = datastore.createQuery('Task') - .hasAncestor(taskListKey); + testTransactionalGetOrCreate () { + const taskKey = this.datastore.key(['Task', Date.now()]); - datastore.runQuery(query, function (err, entities) { - if (err) { - // An error occurred while running the query. - return transaction.rollback(function (_err) { - return callback(_err || err); - }); + // Overwrite so the real Datastore instance is used in `transferFunds`. + const datastoreMock = datastore; + datastore = this.datastore; + + // [START transactional_get_or_create] + function getOrCreate (taskKey, taskData) { + const taskEntity = { + key: taskKey, + data: taskData + }; + + const transaction = datastore.transaction(); + + return transaction.run() + .then(() => transaction.get(taskKey)) + .then((results) => { + const task = results[0]; + if (task) { + // The task entity already exists. + return transaction.rollback(); + } else { + // Create the task entity. + transaction.save(taskEntity); + return transaction.commit(); } - - taskListEntities = entities; - transaction.commit(function (err) { - if (err) { - return callback(err); - } - - // The transaction completed successfully. - callback(null, taskListEntities); - }); - }); + }) + .then(() => taskEntity) + .catch(() => transaction.rollback()); + } + // [END transactional_get_or_create] + + return getOrCreate(taskKey, {}) + .then((task) => { + assert(task, 'Should have a task.'); + return getOrCreate(taskKey, {}); + }) + .then((task) => { + assert(task, 'Should have a task.'); + // Restore `datastore` to the mock API. + datastore = datastoreMock; + }) + .catch((err) => { + // Restore `datastore` to the mock API. + datastore = datastoreMock; + return Promise.reject(err); }); - }); } - // [END transactional_single_entity_group_read_only] - getTaskListEntities(function (err, entities) { - if (err) { - callback(err); - return; + testSingleEntityGroupReadOnly () { + // Overwrite so the real Datastore instance is used in `transferFunds`. + const datastoreMock = datastore; + datastore = this.datastore; + + // [START transactional_single_entity_group_read_only] + function getTaskListEntities () { + let taskList, taskListEntities; + + const transaction = datastore.transaction(); + const taskListKey = datastore.key(['TaskList', 'default']); + + return transaction.run() + .then(() => datastore.get(taskListKey)) + .then((results) => { + taskList = results[0]; + const query = datastore.createQuery('Task') + .hasAncestor(taskListKey); + return datastore.runQuery(query); + }) + .then((results) => { + taskListEntities = results[0]; + return transaction.commit(); + }) + .then(() => [taskList, taskListEntities]) + .catch(() => transaction.rollback()); } + // [END transactional_single_entity_group_read_only] + + return getTaskListEntities() + .then((results) => { + // Restore `datastore` to the mock API. + datastore = datastoreMock; + assert.equal(results.length, 2); + assert.equal(Array.isArray(results[1]), true); + }, (err) => { + // Restore `datastore` to the mock API. + datastore = datastoreMock; + return Promise.reject(err); + }); + } +} - if (!entities) { - return callback(new Error('Entities were not retrieved successfully.')); - } - callback(); - }); +module.exports = { + Entity: Entity, + Index: Index, + Metadata: Metadata, + Query: Query, + Transaction: Transaction }; diff --git a/datastore/error.js b/datastore/error.js index 4ed1c93c94..a9434e4845 100644 --- a/datastore/error.js +++ b/datastore/error.js @@ -1,34 +1,37 @@ -// Copyright 2016, Google, Inc. -// 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. +/** + * Copyright 2016, Google, Inc. + * 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'; -// By default, the client will authenticate using the service account file -// specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable and use -// the project specified by the GCLOUD_PROJECT environment variable. See -// https://googlecloudplatform.github.io/gcloud-node/#/docs/google-cloud/latest/guides/authentication -var Datastore = require('@google-cloud/datastore'); - -// Instantiate a datastore client -var datastore = Datastore(); +const Datastore = require('@google-cloud/datastore'); // [START error] -function runQuery (cb) { - var query = datastore.createQuery(['Company']).start('badrequest'); - - datastore.runQuery(query, function (err, entities) { - // Check for an error - if (err) { +function runQuery () { + // Instantiates a client + const datastore = Datastore(); + + const query = datastore.createQuery(['Company']).start('badrequest'); + + return datastore.runQuery(query) + .then((results) => { + const entities = results[0]; + console.log('Entities:'); + entities.forEach((entity) => console.log(entity)); + return entities; + }) + .catch((err) => { console.log(err.errors); // [...] console.log(err.code); // 400 console.log(err.message); // "Bad Request" @@ -38,21 +41,17 @@ function runQuery (cb) { // For example, treat permission error like no entities were found if (err.code === 403) { - return cb(null, []); + return []; } // Forward the error to the caller - return cb(err); - } - - // We're good - return cb(null, entities); - }); + return Promise.reject(err); + }); } // [END error] exports.runQuery = runQuery; if (module === require.main) { - runQuery(console.log); + exports.runQuery(); } diff --git a/datastore/package.json b/datastore/package.json index 009de7d153..837c76e9a5 100644 --- a/datastore/package.json +++ b/datastore/package.json @@ -5,16 +5,11 @@ "license": "Apache Version 2.0", "author": "Google Inc.", "scripts": { - "test": "mocha -R spec -t 120000 --require intelli-espower-loader ../test/_setup.js test/*.test.js", - "system-test": "mocha -R spec -t 120000 --require intelli-espower-loader ../system-test/_setup.js system-test/*.test.js" + "test": "cd ..; npm run st -- datastore/system-test/*.test.js" }, "dependencies": { - "@google-cloud/datastore": "^0.1.1", - "async": "^2.0.1", - "yargs": "^5.0.0" - }, - "devDependencies": { - "mocha": "^3.0.2" + "@google-cloud/datastore": "^0.5.0", + "yargs": "^6.4.0" }, "engines": { "node": ">=4.3.2" diff --git a/datastore/quickstart.js b/datastore/quickstart.js index 7925508374..2e07f62457 100644 --- a/datastore/quickstart.js +++ b/datastore/quickstart.js @@ -23,7 +23,7 @@ const Datastore = require('@google-cloud/datastore'); const projectId = 'YOUR_PROJECT_ID'; // Instantiates a client -const datastoreClient = Datastore({ +const datastore = Datastore({ projectId: projectId }); @@ -32,7 +32,7 @@ const kind = 'Task'; // The name/ID for the new entity const name = 'sampletask1'; // The Cloud Datastore key for the new entity -const taskKey = datastoreClient.key([kind, name]); +const taskKey = datastore.key([kind, name]); // Prepares the new entity const task = { @@ -43,12 +43,8 @@ const task = { }; // Saves the entity -datastoreClient.save(task, (err) => { - if (err) { - console.error(err); - return; - } - - console.log(`Saved ${task.key.name}: ${task.data.description}`); -}); +datastore.save(task) + .then(() => { + console.log(`Saved ${task.key.name}: ${task.data.description}`); + }); // [END datastore_quickstart] diff --git a/datastore/system-test/concepts.test.js b/datastore/system-test/concepts.test.js index 74bb3b143b..2365dae13c 100644 --- a/datastore/system-test/concepts.test.js +++ b/datastore/system-test/concepts.test.js @@ -1,36 +1,40 @@ -// Copyright 2015, Google, Inc. -// 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. +/** + * Copyright 2016, Google, Inc. + * 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 testUtil = require('./util'); -var concepts = require('../concepts'); -var transaction; -var metadata; -var index; -var query; -var entity; - -var Transaction = concepts.Transaction; -var Metadata = concepts.Metadata; -var Index = concepts.Index; -var Entity = concepts.Entity; -var Query = concepts.Query; +'use strict'; -describe('datastore:concepts', function () { - before(function () { - var projectId = process.env.GCLOUD_PROJECT || 'nodejs-docs-samples'; +const assert = require(`power-assert`); +const concepts = require(`../concepts`); + +let transaction; +let metadata; +let index; +let query; +let entity; + +const Transaction = concepts.Transaction; +const Metadata = concepts.Metadata; +const Index = concepts.Index; +const Entity = concepts.Entity; +const Query = concepts.Query; + +describe(`datastore:concepts`, () => { + before(() => { + const projectId = process.env.GCLOUD_PROJECT; + assert.equal(!!projectId, true, `You must set the GCLOUD_PROJECT env var!`); transaction = new Transaction(projectId); metadata = new Metadata(projectId); index = new Index(projectId); @@ -38,245 +42,108 @@ describe('datastore:concepts', function () { query = new Query(projectId); }); - after(function (done) { - var datastore = transaction.datastore; - var query = datastore.createQuery('Task'); - - testUtil.deleteEntities(datastore, query, done); - }); - - // Transactions - - it('performs a transactional update', function (done) { - transaction.testTransactionalUpdate(done); - }); - - it('performs retries if necessary', function (done) { - transaction.testTransactionalRetry(done); - }); - - it('performs a get or create', function (done) { - transaction.testTransactionalGetOrCreate(done); - }); - - it('gets a snapshot of task list entities', function (done) { - transaction.testSingleEntityGroupReadOnly(done); - }); - - // Metadata - - it('performs a namespace query', function (done) { - metadata.testNamespaceRunQuery(done); - }); - - it('performs a kind query', function (done) { - metadata.testKindRunQuery(done); - }); - - it('performs a property query', function (done) { - metadata.testPropertyRunQuery(done); - }); - - it('performs a property by kind query', function (done) { - metadata.testPropertyByKindRunQuery(done); - }); - - // Indexes - - it( - 'performs a query with a filter on an unindexed property', - function (done) { - index.testUnindexedPropertyQuery(done); - } - ); - - it('inserts arrays of data', function (done) { - index.testExplodingProperties(done); - }); - - // Queries - - it('performs a basic query', function (done) { - query.testRunQuery(done); - }); - - it('performs a query with a property filter', function (done) { - query.testPropertyFilter(done); - }); - - it('performs a query with a composite filter', function (done) { - query.testCompositeFilter(done); - }); - - it('performs a query with a key filter', function (done) { - query.testKeyFilter(done); - }); - - it('performs a query with ascending sort', function (done) { - query.testAscendingSort(done); - }); - - it('performs a query with descending sort', function (done) { - query.testDescendingSort(done); - }); - - it('performs a query with multi sort', function (done) { - query.testMultiSort(done); - }); - - it('performs a kindless query', function (done) { - query.testKindlessQuery(done); - }); - - it('performs a projection query', function (done) { - entity.testProperties(function (err, tasks) { - console.log(err, tasks); - assert.ifError(err); - setTimeout(function () { - query.testRunQueryProjection(done); - }, 1000); + after(() => { + const datastore = transaction.datastore; + const query = datastore.createQuery(`Task`).select(`__key__`); + return datastore.runQuery(query) + .then((results) => datastore.delete(results[0].map((entity) => entity[datastore.KEY]))); + }); + + describe(`Transactions`, () => { + it(`performs a transactional update`, () => transaction.testTransactionalUpdate()); + it(`performs retries if necessary`, () => transaction.testTransactionalRetry()); + it(`performs a get or create`, () => transaction.testTransactionalGetOrCreate()); + it(`gets a snapshot of task list entities`, () => transaction.testSingleEntityGroupReadOnly()); + }); + + describe(`Metadata`, () => { + it(`performs a namespace query`, () => metadata.testNamespaceRunQuery()); + it(`performs a kind query`, () => metadata.testKindRunQuery()); + it(`performs a property query`, () => metadata.testPropertyRunQuery()); + it(`performs a property by kind query`, () => metadata.testPropertyByKindRunQuery()); + }); + + describe(`Indexes`, () => { + it(`performs a query with a filter on an unindexed property`, () => index.testUnindexedPropertyQuery()); + it(`inserts arrays of data`, () => index.testExplodingProperties()); + }); + + describe(`Queries`, () => { + it(`performs a basic query`, () => query.testRunQuery()); + it(`performs a query with a property filter`, () => query.testPropertyFilter()); + it(`performs a query with a composite filter`, () => query.testCompositeFilter()); + it(`performs a query with a key filter`, () => query.testKeyFilter()); + it(`performs a query with ascending sort`, () => query.testAscendingSort()); + it(`performs a query with descending sort`, () => query.testDescendingSort()); + it(`performs a query with multi sort`, () => query.testMultiSort()); + it(`performs a kindless query`, () => query.testKindlessQuery()); + it('performs a projection query', () => { + return entity.testProperties() + .then(() => { + return new Promise((resolve, reject) => { + setTimeout(function () { + query.testRunQueryProjection().then(resolve, reject); + }, 1000); + }); + }) + .then((results) => { + assert.deepEqual(results, { + priorities: [4], + percentCompletes: [10] + }); + }); }); - }); - - it('performs a keys only query', function (done) { - query.testKeysOnlyQuery(done); - }); - - it('performs a distinct query', function (done) { - query.testDistinctQuery(done); - }); - - it('performs a distinct on query', function (done) { - query.testDistinctOnQuery(done); - }); - - it('performs an array value inequality query', function (done) { - query.testArrayValueInequalityRange(done); - }); - - it('performs an array value equality query', function (done) { - query.testArrayValueEquality(done); - }); - - it('performs an inequality range query', function (done) { - query.testInequalityRange(done); - }); - - it('returns an error from an invalid query', function (done) { - query.testInequalityInvalid(function (err) { - assert(err); - done(); + it(`performs a keys only query`, () => query.testKeysOnlyQuery()); + it(`performs a distinct query`, () => query.testDistinctQuery()); + it(`performs a distinct on query`, () => query.testDistinctOnQuery()); + it(`performs an array value inequality query`, () => query.testArrayValueInequalityRange()); + it(`performs an array value equality query`, () => query.testArrayValueEquality()); + it(`performs an inequality range query`, () => query.testInequalityRange()); + it(`returns an error from an invalid query`, () => { + return query.testInequalityInvalid() + .then(() => assert.fail(), (err) => assert(err)); }); - }); - - it('performs an equal and inequality range query', function (done) { - query.testEqualAndInequalityRange(done); - }); - - it('performs an equality sort query', function (done) { - query.testInequalitySort(done); - }); - - it( - 'returns an error when not sorted on filtered property', - function (done) { - query.testInequalitySortInvalidNotSame(function (err) { - assert(err); - done(); - }); - } - ); - - it( - 'returns an error when not sorted on first filter prop', - function (done) { - query.testInequalitySortInvalidNotFirst(function (err) { - assert(err); - done(); - }); - } - ); - - it('performs a query with a limit', function (done) { - query.testLimit(done); - }); - - it('allows manual pagination through results', function (done) { - entity.testBatchUpsert(function (err) { - assert.ifError(err); - setTimeout(function () { - query.testCursorPaging(done); - }, 1000); + it(`performs an equal and inequality range query`, () => query.testEqualAndInequalityRange()); + it(`performs an equality sort query`, () => query.testInequalitySort()); + it(`returns an error when not sorted on filtered property`, () => { + return query.testInequalitySortInvalidNotSame() + .then(() => assert.fail(), (err) => assert(err)); }); - }); - - it.skip('performs an ancestor query', function (done) { - query.testEventualConsistentQuery(done); - }); - - // Entities - - it('saves with an incomplete key', function (done) { - entity.testIncompleteKey(done); - }); - - it('saves with a named key', function (done) { - entity.testNamedKey(done); - }); - - it('saves a key with a parent', function (done) { - entity.testKeyWithParent(done); - }); - - it('saves a key with multiple parents', function (done) { - entity.testKeyWithMultiLevelParent(done); - }); - - it('saves an entity with a parent', function (done) { - entity.testEntityWithParent(done); - }); - - it('saves an entity with properties', function (done) { - entity.testProperties(done); - }); - - it('saves an entity with arrays', function (done) { - entity.testArrayValue(done); - }); - - it('saves a basic entity', function (done) { - entity.testBasicEntity(done); - }); - - it('saves with an upsert', function (done) { - entity.testUpsert(done); - }); - - it('saves with an insert', function (done) { - entity.testInsert(done); - }); - - it('performs a lookup', function (done) { - entity.testLookup(done); - }); - - it('saves with an update', function (done) { - entity.testUpdate(done); - }); - - it('deletes an entity', function (done) { - entity.testDelete(done); - }); - - it('performs a batch upsert', function (done) { - entity.testBatchUpsert(done); - }); - - it('performs a batch lookup', function (done) { - entity.testBatchLookup(done); - }); - - it('performs a batch delete', function (done) { - entity.testBatchDelete(done); + it(`returns an error when not sorted on first filter prop`, () => { + return query.testInequalitySortInvalidNotFirst() + .then(() => assert.fail(), (err) => assert(err)); + }); + it(`performs a query with a limit`, () => query.testLimit()); + it(`allows manual pagination through results`, () => { + return entity.testBatchUpsert() + .then(() => { + return new Promise((resolve, reject) => { + setTimeout(() => { + query.testCursorPaging() + .then(resolve, reject); + }, 1000); + }); + }); + }); + it(`performs an ancestor query`, () => query.testEventualConsistentQuery()); + }); + + describe(`Entities`, () => { + it(`saves with an incomplete key`, () => entity.testIncompleteKey()); + it(`saves with a named key`, () => entity.testNamedKey()); + it(`saves a key with a parent`, () => entity.testKeyWithParent()); + it(`saves a key with multiple parents`, () => entity.testKeyWithMultiLevelParent()); + it(`saves an entity with a parent`, () => entity.testEntityWithParent()); + it(`saves an entity with properties`, () => entity.testProperties()); + it(`saves an entity with arrays`, () => entity.testArrayValue()); + it(`saves a basic entity`, () => entity.testBasicEntity()); + it(`saves with an upsert`, () => entity.testUpsert()); + it(`saves with an insert`, () => entity.testInsert()); + it(`performs a lookup`, () => entity.testLookup()); + it(`saves with an update`, () => entity.testUpdate()); + it(`deletes an entity`, () => entity.testDelete()); + it(`performs a batch upsert`, () => entity.testBatchUpsert()); + it(`performs a batch lookup`, () => entity.testBatchLookup()); + it(`performs a batch delete`, () => entity.testBatchDelete()); }); }); diff --git a/datastore/system-test/error.test.js b/datastore/system-test/error.test.js index ef304b6086..578ec64c87 100644 --- a/datastore/system-test/error.test.js +++ b/datastore/system-test/error.test.js @@ -1,26 +1,31 @@ -// Copyright 2015-2016, Google, Inc. -// 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. +/** + * Copyright 2016, Google, Inc. + * 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 error = require('../error'); +const error = require('../error'); -describe('datastore:error', function () { - it('should have an error', function (done) { - error.runQuery(function (err) { - assert(err); - assert.equal(err.code, 400); - done(); - }); +describe(`datastore:error`, () => { + it(`should have an error`, () => { + return error.runQuery() + .then(() => { + assert.fail(`should have failed!`); + }) + .catch((err) => { + assert(err); + assert.equal(err.code, 400); + }); }); }); diff --git a/datastore/system-test/quickstart.test.js b/datastore/system-test/quickstart.test.js index b385261116..38522bb4ea 100644 --- a/datastore/system-test/quickstart.test.js +++ b/datastore/system-test/quickstart.test.js @@ -17,47 +17,42 @@ const proxyquire = require(`proxyquire`).noPreserveCache(); const datastore = proxyquire(`@google-cloud/datastore`, {})(); +const entity = { description: `Buy milk` }; const kind = `Task`; const name = `sampletask1`; -const key = datastore.key(kind, name); +const key = datastore.key([kind, name]); describe(`datastore:quickstart`, () => { - let datastoreMock, DatastoreMock; - - after((done) => { - datastore.delete(key, () => { - // Ignore any error, the entity might not have been created - done(); - }); - }); + before(() => datastore.delete(key).catch(() => {})); + after(() => datastore.delete(key).catch(() => {})); it(`should get a task from Datastore`, (done) => { - datastoreMock = { - key (...args) { - return datastore.key(...args); - }, + const datastoreMock = { + key: (...args) => datastore.key(...args), - save (_task, _callback) { + save: (_task) => { assert.equal(_task.key.kind, kind); assert.equal(_task.key.name, name); - assert.deepEqual(_task.data, { - description: `Buy milk` - }); - assert.equal(typeof _callback, 'function'); - - datastore.save(_task, (err) => { - _callback(err); - assert.ifError(err); - assert.equal(console.log.calledOnce, true); - assert.deepEqual(console.log.firstCall.args, [`Saved ${_task.key.name}: ${_task.data.description}`]); - done(); - }); + assert.deepEqual(_task.data, entity); + + return datastore.save(_task) + .then(() => { + setTimeout(() => { + datastore.get(key) + .then((results) => { + const task = results[0]; + assert.deepEqual(task, entity); + assert.equal(console.log.calledWith(`Saved ${name}: ${entity.description}`), true); + done(); + }) + .catch(done); + }, 200); + }, done); } }; - DatastoreMock = sinon.stub().returns(datastoreMock); proxyquire(`../quickstart`, { - '@google-cloud/datastore': DatastoreMock + '@google-cloud/datastore': sinon.stub().returns(datastoreMock) }); }); }); diff --git a/datastore/system-test/tasks.test.js b/datastore/system-test/tasks.test.js index 3d7e94e2a4..1d4913a999 100644 --- a/datastore/system-test/tasks.test.js +++ b/datastore/system-test/tasks.test.js @@ -1,62 +1,68 @@ -// Copyright 2015-2016, Google, Inc. -// 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. +/** + * Copyright 2016, Google, Inc. + * 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 async = require('async'); -var tasks = require('../tasks'); -var taskIds = []; - -describe('datastore:tasks', function () { - after(function (done) { - async.parallel(taskIds.map(function (taskId) { - return function (cb) { - tasks.deleteEntity(taskId, cb); - }; - }), done); - }); +const path = require(`path`); +const datastore = require(`@google-cloud/datastore`)(); +const run = require(`../../utils`).run; - it('should add a task', function (done) { - getTaskId(done); - }); +const cmd = `node tasks.js`; +const cwd = path.join(__dirname, `..`); + +describe(`datastore:tasks`, () => { + const description = `description`; + let key; - it('should mark a task as done', function (done) { - getTaskId(function (err, taskId) { - assert.ifError(err); - tasks.updateEntity(taskId, done); - }); + after(() => datastore.delete(key).catch(() => {})); + + it(`should add a task`, () => { + const expected = /^Task (\d+) created successfully.$/; + const parts = run(`${cmd} new "${description}"`, cwd).match(expected); + assert.equal(expected.test(parts[0]), true); + return datastore.get(datastore.key([`Task`, parseInt(parts[1], 10)])) + .then((results) => { + const task = results[0]; + key = task[datastore.KEY]; + assert.equal(task.description, description); + }); }); - it('should list tasks', function (done) { - tasks.retrieveEntities(done); + it(`should mark a task as done`, () => { + const expected = `Task ${key.id} updated successfully.`; + assert.equal(run(`${cmd} done ${key.id}`, cwd), expected); + return datastore.get(key) + .then((results) => { + assert.equal(results[0].done, true); + }); }); - it('should delete a task', function (done) { - getTaskId(function (err, taskId) { - assert.ifError(err); - tasks.deleteEntity(taskId, done); - }); + it(`should list tasks`, (done) => { + setTimeout(() => { + const output = run(`${cmd} list`, cwd); + assert.equal(output.includes(key.id), true); + done(); + }, 5000); }); - function getTaskId (callback) { - tasks.addEntity('description', function (err, taskKey) { - if (err) { - return callback(err); - } - - var taskId = taskKey.path.pop(); - taskIds.push(taskId); - callback(null, taskId); - }); - } + it(`should delete a task`, () => { + const expected = `Task ${key.id} deleted successfully.`; + assert.equal(run(`${cmd} delete ${key.id}`, cwd), expected); + return datastore.get(key) + .then((results) => { + assert.equal(results[0], undefined); + }); + }); }); diff --git a/datastore/system-test/util.js b/datastore/system-test/util.js deleted file mode 100644 index 1c47393b60..0000000000 --- a/datastore/system-test/util.js +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2015, Google, Inc. -// 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'; - -module.exports = { - deleteEntities: function (datastore, query, callback) { - datastore.runQuery(query, function (err, entities) { - if (err) { - return callback(err); - } - - var keys = entities.map(function (entity) { - return entity.key; - }); - - datastore.delete(keys, callback); - }); - } -}; diff --git a/datastore/tasks.js b/datastore/tasks.js old mode 100755 new mode 100644 index 7d8230778f..d60016a94e --- a/datastore/tasks.js +++ b/datastore/tasks.js @@ -1,15 +1,17 @@ -// Copyright 2015-2016, Google, Inc. -// 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. +/** + * Copyright 2016, Google, Inc. + * 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'; @@ -17,11 +19,11 @@ // By default, the client will authenticate using the service account file // specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable and use // the project specified by the GCLOUD_PROJECT environment variable. See -// https://googlecloudplatform.github.io/gcloud-node/#/docs/google-cloud/latest/guides/authentication -var Datastore = require('@google-cloud/datastore'); +// https://googlecloudplatform.github.io/google-cloud-node/#/docs/datastore/latest/guides/authentication +const Datastore = require('@google-cloud/datastore'); -// Instantiate a datastore client -var datastore = Datastore(); +// Instantiates a client +const datastore = Datastore(); // [END build_service] /* @@ -46,7 +48,7 @@ npm install 5. With the gcloud SDK, be sure you are authenticated: ```sh -gcloud auth login +gcloud beta auth application-default login ``` 6. At a command prompt, run the following, where `` is the ID of @@ -62,10 +64,9 @@ node tasks */ // [START add_entity] -function addTask (description, callback) { - var taskKey = datastore.key('Task'); - - datastore.save({ +function addTask (description) { + const taskKey = datastore.key('Task'); + const entity = { key: taskKey, data: [ { @@ -82,129 +83,110 @@ function addTask (description, callback) { value: false } ] - }, function (err) { - if (err) { - return callback(err); - } - - var taskId = taskKey.path.pop(); - console.log('Task %d created successfully.', taskId); - return callback(null, taskKey); - }); + }; + + return datastore.save(entity) + .then(() => { + console.log(`Task ${taskKey.id} created successfully.`); + return taskKey; + }); } // [END add_entity] // [START update_entity] -function markDone (taskId, callback) { - var transaction = datastore.transaction(); - - transaction.run(function (err) { - if (err) { - return callback(err); - } - - var taskKey = datastore.key([ - 'Task', - taskId - ]); - - transaction.get(taskKey, function (err, task) { - if (err) { - // An error occurred while getting the task - return transaction.rollback(function (_err) { - return callback(err || _err); - }); - } - - task.data.done = true; - - transaction.save(task); - - // Commit the transaction - transaction.commit(function (err) { - if (err) { - return callback(err); - } +function markDone (taskId) { + const transaction = datastore.transaction(); + const taskKey = datastore.key([ + 'Task', + taskId + ]); - // The transaction completed successfully. - console.log('Task %d updated successfully.', taskId); - return callback(null); + return transaction.run() + .then(() => transaction.get(taskKey)) + .then((results) => { + const task = results[0]; + task.done = true; + transaction.save({ + key: taskKey, + data: task }); - }); - }); + return transaction.commit(); + }) + .then(() => { + // The transaction completed successfully. + console.log(`Task ${taskId} updated successfully.`); + }) + .catch(() => transaction.rollback()); } // [END update_entity] // [START retrieve_entities] -function listTasks (callback) { - var query = datastore.createQuery('Task') +function listTasks () { + const query = datastore.createQuery('Task') .order('created'); - datastore.runQuery(query, function (err, tasks) { - if (err) { - return callback(err); - } + return datastore.runQuery(query) + .then((results) => { + const tasks = results[0]; - console.log('Found %d task(s)!', tasks.length); - return callback(null, tasks); - }); + console.log('Tasks:'); + tasks.forEach((task) => { + const taskKey = task[datastore.KEY]; + console.log(taskKey.id, task); + }); + + return tasks; + }); } // [END retrieve_entities] // [START delete_entity] -function deleteTask (taskId, callback) { - var taskKey = datastore.key([ +function deleteTask (taskId) { + const taskKey = datastore.key([ 'Task', taskId ]); - datastore.delete(taskKey, function (err) { - if (err) { - return callback(err); - } - - console.log('Task %d deleted successfully.', taskId); - return callback(null); - }); + return datastore.delete(taskKey) + .then(() => { + console.log(`Task ${taskId} deleted successfully.`); + }); } // [END delete_entity] -var cli = require('yargs'); -var makeHandler = require('../utils').makeHandler; - -var program = module.exports = { - addEntity: addTask, - updateEntity: markDone, - retrieveEntities: listTasks, - deleteEntity: deleteTask, - main: function (args) { - // Run the command-line program - cli.help().strict().parse(args).argv; - } -}; - -cli +require(`yargs`) .demand(1) - .command('new ', 'Adds a task with a description .', {}, function (options) { - addTask(options.description, makeHandler()); - }) - .command('done ', 'Marks the specified task as done.', {}, function (options) { - markDone(options.taskId, makeHandler()); - }) - .command('list', 'Lists all tasks ordered by creation time.', {}, function (options) { - listTasks(makeHandler()); - }) - .command('delete ', 'Deletes a task.', {}, function (options) { - deleteTask(options.taskId, makeHandler()); - }) - .example('node $0 new "Buy milk"', 'Adds a task with description "Buy milk".') - .example('node $0 done 12345', 'Marks task 12345 as Done.') - .example('node $0 list', 'Lists all tasks ordered by creation time') - .example('node $0 delete 12345', 'Deletes task 12345.') + .command( + `new `, + `Adds a task with a description .`, + {}, + (opts) => addTask(opts.description) + ) + .command( + `done `, + `Marks the specified task as done.`, + {}, + (opts) => markDone(opts.taskId) + ) + .command( + `list`, + `Lists all tasks ordered by creation time.`, + {}, + listTasks + ) + .command( + `delete `, + `Deletes a task.`, + {}, + (opts) => deleteTask(opts.taskId) + ) + .example(`node $0 new "Buy milk"`, `Adds a task with description "Buy milk".`) + .example(`node $0 done 12345`, `Marks task 12345 as Done.`) + .example(`node $0 list`, `Lists all tasks ordered by creation time`) + .example(`node $0 delete 12345`, `Deletes task 12345.`) .wrap(120) .recommendCommands() - .epilogue('For more information, see https://cloud.google.com/datastore/docs'); - -if (module === require.main) { - program.main(process.argv.slice(2)); -} + .epilogue(`For more information, see https://cloud.google.com/datastore/docs`) + .help() + .strict() + .argv; diff --git a/datastore/test/concepts.test.js b/datastore/test/concepts.test.js deleted file mode 100644 index 8deb451a29..0000000000 --- a/datastore/test/concepts.test.js +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2016, Google, Inc. -// 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'; - -describe('datastore:concepts', function () { - it('should be tested'); -}); diff --git a/datastore/test/error.test.js b/datastore/test/error.test.js deleted file mode 100644 index 6396d45d5f..0000000000 --- a/datastore/test/error.test.js +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2016, Google, Inc. -// 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'; - -describe('datastore:error', function () { - it('should be tested'); -}); diff --git a/datastore/test/quickstart.test.js b/datastore/test/quickstart.test.js deleted file mode 100644 index 1d37c24007..0000000000 --- a/datastore/test/quickstart.test.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright 2016, Google, Inc. - * 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'; - -const proxyquire = require(`proxyquire`).noPreserveCache(); - -describe(`datastore:quickstart`, () => { - let datastoreMock, DatastoreMock; - const error = new Error(`error`); - const mockKey = {}; - - before(() => { - datastoreMock = { - save: sinon.stub().yields(error), - key: sinon.stub().returns(mockKey) - }; - DatastoreMock = sinon.stub().returns(datastoreMock); - }); - - it(`should handle error`, () => { - proxyquire(`../quickstart`, { - '@google-cloud/datastore': DatastoreMock - }); - - assert.equal(DatastoreMock.calledOnce, true); - assert.deepEqual(DatastoreMock.firstCall.args, [{ projectId: 'YOUR_PROJECT_ID' }]); - assert.equal(datastoreMock.save.calledOnce, true); - assert.deepEqual(datastoreMock.save.firstCall.args.slice(0, -1), [{ - key: mockKey, - data: { - description: 'Buy milk' - } - }]); - assert.equal(console.error.calledOnce, true); - assert.deepEqual(console.error.firstCall.args, [error]); - }); -}); diff --git a/datastore/test/tasks.test.js b/datastore/test/tasks.test.js deleted file mode 100644 index 2353d821f9..0000000000 --- a/datastore/test/tasks.test.js +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2016, Google, Inc. -// 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'; - -describe('datastore:tasks', function () { - it('should be tested'); -}); diff --git a/language/package.json b/language/package.json index f95e29b9fd..30d16f2d7a 100644 --- a/language/package.json +++ b/language/package.json @@ -5,7 +5,7 @@ "license": "Apache Version 2.0", "author": "Google Inc.", "scripts": { - "test": "cd ..; npm run st -- language/system-test/*" + "test": "cd ..; npm run st -- language/system-test/*.test.js" }, "dependencies": { "@google-cloud/language": "^0.6.0",