diff --git a/datastore/entity.js b/datastore/entity.js new file mode 100644 index 00000000000..97fd009ce21 --- /dev/null +++ b/datastore/entity.js @@ -0,0 +1,415 @@ +'use strict'; + +var gcloud = require('gcloud'); + +// This mock is used in the documentation snippets. +var datastore = { + delete: function() {}, + get: function() {}, + insert: function() {}, + update: function() {}, + upsert: function() {}, + save: function() {} +}; + +function Entity(projectId) { + this.datastore = gcloud.datastore({ + projectId: projectId + }); + + // 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(); +} + +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; +}; + +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; +}; + +Entity.prototype.getTask = function() { + // [START basic_entity] + var task = { + type: 'Personal', + done: false, + priority: 4, + description: 'Learn Cloud Datastore' + }; + // [END basic_entity] + + return task; +}; + +Entity.prototype.testIncompleteKey = function(callback) { + this.datastore.save({ + key: this.incompleteKey, + data: {} + }, callback); +}; + +Entity.prototype.testNamedKey = function(callback) { + this.datastore.save({ + key: this.namedKey, + data: {} + }, callback); +}; + +Entity.prototype.testKeyWithParent = function(callback) { + this.datastore.save({ + key: this.keyWithParent, + data: {} + }, callback); +}; + +Entity.prototype.testKeyWithMultiLevelParent = function(callback) { + this.datastore.save({ + key: this.keyWithMultiLevelParent, + data: {} + }, callback); +}; + +Entity.prototype.testEntityWithParent = function(callback) { + var taskKey = this.keyWithParent; + + // [START entity_with_parent] + var task = { + key: taskKey, + data: { + type: '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 = { + type: 'Personal', + created: new Date(), + done: false, + priority: 4, + percent_complete: 10.0, + description: 'Learn Cloud Datastore' + }; + // [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); +}; + +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] + + this.datastore.upsert({ + key: taskKey, + data: task + }, callback); +}; + +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.insert({ + key: taskKey, + data: task + }, callback); +}; + +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 = { + // type: 'Personal', + // done: false, + // priority: 4, + // description: 'Learn Cloud Datastore' + // }; + } + }); + // [End lookup] + + this.datastore.insert({ + key: taskKey, + data: {} + }, function(err) { + if (err) { + callback(err); + return; + } + + self.datastore.get(taskKey, callback); + }); +}; + +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.insert({ + key: taskKey, + data: {} + }, function(err) { + if (err) { + callback(err); + return; + } + + self.datastore.update({ + 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.insert({ + key: taskKey, + data: {} + }, function(err) { + if (err) { + callback(err); + return; + } + + self.datastore.delete(taskKey, callback); + }); +}; + +Entity.prototype.testBatchUpsert = function(callback) { + datastore.key = this.datastore.key; + + // [START batch_upsert] + var taskKey1 = datastore.key(['Task', 1]); + var taskKey2 = datastore.key(['Task', 2]); + + var task1 = { + type: 'Personal', + done: false, + priority: 4, + description: 'Learn Cloud Datastore' + }; + + var task2 = { + type: 'Work', + done: false, + priority: 8, + description: 'Integrate Cloud Datastore' + }; + + 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, entities) { + if (!err) { + // entities[0].data = { + // type: 'Personal', + // done: false, + // priority: 4, + // description: 'Learn Cloud Datastore' + // }; + + // entities[1].data = { + // type: 'Work', + // // ... + // }; + } + }); + // [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); +}; + +module.exports = Entity; diff --git a/datastore/index.js b/datastore/index.js new file mode 100644 index 00000000000..06c694b8656 --- /dev/null +++ b/datastore/index.js @@ -0,0 +1,60 @@ +'use strict'; + +var gcloud = require('gcloud'); + +// This mock is used in the documentation snippets. +var datastore = { + insert: function() {} +}; + +function Index(projectId) { + this.datastore = gcloud.datastore({ + projectId: projectId + }); +} + +Index.prototype.testUnindexedPropertyQuery = function(callback) { + var datastore = this.datastore; + + // [START unindexed_property_query] + var query = datastore.createQuery('Task') + .filter('description =', 'A task description.'); + // [END unindexed_property_query] + + this.datastore.runQuery(query, callback); +}; + +Index.prototype.testExplodingProperties = function(callback) { + datastore.key = this.datastore.key; + + // [START exploding_properties] + var task = { + key: datastore.key('Task'), + data: { + tags: [ + 'fun', + 'programming', + 'learn' + ], + collaborators: [ + 'alice', + 'bob', + 'charlie' + ], + created: new Date() + } + }; + + datastore.insert(task, function(err) { + if (!err) { + // Task inserted successfully. + } + }); + // [END exploding_properties] + + delete datastore.key; + + this.datastore.insert(task, callback); +}; + +module.exports = Index; \ No newline at end of file diff --git a/datastore/query.js b/datastore/query.js new file mode 100644 index 00000000000..bd24ff7452f --- /dev/null +++ b/datastore/query.js @@ -0,0 +1,388 @@ +'use strict'; + +var gcloud = require('gcloud'); + +// This mock is used in the documentation snippets. +var datastore = { + key: function() {}, + runQuery: function() {} +}; + +function Query(projectId) { + this.datastore = gcloud.datastore({ + projectId: projectId + }); + + this.basicQuery = this.getBasicQuery(); + this.projectionQuery = this.getProjectionQuery(); + this.ancestorQuery = this.getAncestorQuery(); +} + +Query.prototype.getBasicQuery = function() { + var datastore = this.datastore; + + // [START basic_query] + var query = datastore.createQuery('Task') + .filter('done =', false) + .filter('priority >=', 4) + .order('-priority'); + // [END basic_query] + + return query; +}; + +Query.prototype.getProjectionQuery = function() { + var datastore = this.datastore; + + // [START projection_query] + var query = datastore.createQuery('Task') + .select('priority') + .select('percent_complete'); + // [END projection_query] + + return query; +}; + +Query.prototype.getAncestorQuery = function() { + var datastore = this.datastore; + + // [START anscestor_query] + // SELECT * FROM Task WHERE __key__ HAS ANCESTOR ("TaskList", "default") + var ancestorKey = datastore.key(['TaskList', 'default']); + + var query = datastore.createQuery('Task') + .hasAncestor(ancestorKey); + // [END anscestor_query] + + return query; +}; + +Query.prototype.testRunQuery = function(callback) { + var query = this.basicQuery; + + // jshint unused:false + // [START run_query] + datastore.runQuery(query, function(err, entities) { + if (!err) { + // Entities found. + } + }); + // [END run_query] + + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testPropertyFilter = function(callback) { + var datastore = this.datastore; + + // [START property_filter] + var query = datastore.createQuery('Task') + .filter('done =', false); + // [END property_filter] + + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testCompositeFilter = function(callback) { + var datastore = this.datastore; + + // [START composite_filter] + var query = datastore.createQuery('Task') + .filter('done =', false) + .filter('priority =', 4); + // [END composite_filter] + + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testKeyFilter = function(callback) { + var datastore = this.datastore; + + // [START key_filter] + var query = datastore.createQuery('Task') + .filter('__key__ =', datastore.key(['Task', 'someTask'])); + // [END key_filter] + + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testAscendingSort = function(callback) { + var datastore = this.datastore; + + // [START ascending_sort] + var query = datastore.createQuery('Task') + .order('created'); + // [END ascending_sort] + + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testDescendingSort = function(callback) { + var datastore = this.datastore; + + // [START descending_sort] + var query = datastore.createQuery('Task') + .order('-created'); + // [END descending_sort] + + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testMultiSort = function(callback) { + var datastore = this.datastore; + + // [START multi_sort] + var query = datastore.createQuery('Task') + .order('-priority') + .order('created'); + // [END multi_sort] + + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testKindlessQuery = function(callback) { + var datastore = this.datastore; + var lastSeenKey = this.datastore.key(['Task', Date.now()]); + + // [START kindless_query] + var query = datastore.createQuery() + .filter('__key__ =', lastSeenKey); + // [END kindless_query] + + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testRunQueryProjection = function(callback) { + var query = this.projectionQuery; + + // jshint unused:false + // [START run_query_projection] + datastore.runQuery(query, function(err, entities) { + if (!err) { + // Entities found. + } + }); + // [END run_query_projection] + + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testKeysOnlyQuery = function(callback) { + var datastore = this.datastore; + + // [START keys_only_query] + var query = datastore.createQuery() + .select('__key__'); + // [END keys_only_query] + + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testDistinctQuery = function(callback) { + var datastore = this.datastore; + + // [START distinct_query] + var query = datastore.createQuery('Task') + .groupBy(['type', 'priority']) + .order('type') + .order('priority'); + // [END distinct_query] + + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testDistinctOnQuery = function(callback) { + var datastore = this.datastore; + + // [START distinct_on_query] + var query = datastore.createQuery('Task') + .groupBy('type') + .order('type') + .order('priority'); + // [END distinct_on_query] + + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testArrayValueInequalityRange = function(callback) { + var datastore = this.datastore; + + // [START array_value_inequality_range] + var query = datastore.createQuery('Task') + .filter('tag >', 'learn') + .filter('tag <', 'math'); + // [END array_value_inequality_range] + + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testArrayValueEquality = function(callback) { + var datastore = this.datastore; + + // [START array_value_equality_range] + var query = datastore.createQuery('Task') + .filter('tag =', 'fun') + .filter('tag =', 'programming'); + // [END array_value_equality_range] + + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testInequalityRange = function(callback) { + var datastore = this.datastore; + + // [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] + + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testInequalityInvalid = function(callback) { + var datastore = this.datastore; + + // [START inequality_invalid] + var query = datastore.createQuery('Task') + .filter('priority >', 3) + .filter('created >', new Date('1990-01-01T00:00:00z')); + // [END inequality_invalid] + + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testEqualAndInequalityRange = function(callback) { + var datastore = this.datastore; + + // [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] + + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testInequalitySort = function(callback) { + var datastore = this.datastore; + + // [START inequality_sort] + var query = datastore.createQuery('Task') + .filter('priority >', 3) + .order('priority') + .order('created'); + // [END inequality_sort] + + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testInequalitySortInvalidNotSame = function(callback) { + var datastore = this.datastore; + + // [START inequality_sort_invalid_not_same] + var query = datastore.createQuery('Task') + .filter('priority >', 3) + .order('created'); + // [END inequality_sort_invalid_not_same] + + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testInequalitySortInvalidNotFirst = function(callback) { + var datastore = this.datastore; + + // [START inequality_sort_invalid_not_first] + var query = datastore.createQuery('Task') + .filter('priority >', 3) + .order('created') + .order('priority'); + // [END inequality_sort_invalid_not_first] + + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testLimit = function(callback) { + var datastore = this.datastore; + + // [START limit] + var query = datastore.createQuery('Task') + .limit(5); + // [END limit] + + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testCursorPaging = function(callback) { + var pageSize = 1; + + datastore.createQuery = this.datastore.createQuery; + + // [START cursor_paging] + var query = datastore.createQuery('Task') + // Pagination is enabled by default in gcloud-node. To switch it off: + .autoPaginate(false) + .limit(pageSize); + + function onQueryResults(err, results, nextQuery) { + if (err) { + // An error occurred while running the query. + return; + } + + // If there are more results to retrieve, the cursor will have automatically + // been set on `nextQuery`. + if (nextQuery) { + datastore.runQuery(nextQuery, onQueryResults); + } + } + + datastore.runQuery(query, onQueryResults); + // [END cursor_paging] + + delete datastore.createQuery; + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testEventualConsistentQuery = function(callback) { + var query = this.ancestorQuery; + + // jshint unused:false + // [START eventual_consistent_query] + datastore.runQuery(query, function(err, entities) { + if (!err) { + // Entities found. + } + }); + // [END eventual_consistent_query] + + this.datastore.runQuery(query, callback); +}; + +Query.prototype.testIndex1Query1 = function() { + // [START index1_query1] + // GQL is not supported in gcloud-node. + // [END index1_query1] +}; + +Query.prototype.testIndex1Query2 = function() { + // [START index1_query2] + // GQL is not supported in gcloud-node. + // [END index1_query2] +}; + +Query.prototype.testIndex2Query1 = function() { + // [START index2_query1] + // GQL is not supported in gcloud-node. + // [END index2_query1] +}; + +Query.prototype.testIndex2Query2 = function() { + // [START index2_query2] + // GQL is not supported in gcloud-node. + // [END index2_query1] +}; + +module.exports = Query; diff --git a/package.json b/package.json index 1b8c0f1b05f..daee0902b5d 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "license": "Apache 2", "private": true, "dependencies": { + "gcloud": "stephenplusplus/gcloud-node#spp--datastore-v1beta3", "googleapis": "~2.1.3" }, "devDependencies": { diff --git a/test/datastore/index.yaml b/test/datastore/index.yaml new file mode 100644 index 00000000000..764f62508a7 --- /dev/null +++ b/test/datastore/index.yaml @@ -0,0 +1,36 @@ +indexes: +- kind: Task + properties: + - name: done + - name: priority + direction: desc +- kind: Task + properties: + - name: priority + - name: percent_complete +- kind: Task + properties: + - name: type + - name: priority +- kind: Task + properties: + - name: priority + - name: created +- kind: Task + properties: + - name: done + - name: created +- kind: Task + properties: + - name: type + - name: priority + direction: desc +- kind: Task + properties: + - name: type + - name: created +- kind: Task + properties: + - name: priority + direction: desc + - name: created \ No newline at end of file diff --git a/test/datastore/testEntity.js b/test/datastore/testEntity.js new file mode 100644 index 00000000000..689d59155c3 --- /dev/null +++ b/test/datastore/testEntity.js @@ -0,0 +1,104 @@ +'use strict'; + +var Entity = require('../../datastore/entity'); +var entity; + +before(function() { + entity = new Entity(process.env.TEST_PROJECT_ID); +}); + +describe('incomplete key', function() { + it('saves with an incomplete key', function(done) { + entity.testIncompleteKey(done); + }); +}); + +describe('testNamedKey', function() { + it('saves with a named key', function(done) { + entity.testNamedKey(done); + }); +}); + +describe('testKeyWithParent', function() { + it('saves a key with a parent', function(done) { + entity.testKeyWithParent(done); + }); +}); + +describe('testKeyWithMultiLevelParent', function() { + it('saves a key with multiple parents', function(done) { + entity.testKeyWithMultiLevelParent(done); + }); +}); + +describe('testEntityWithParent', function() { + it('saves an entity with a parent', function(done) { + entity.testEntityWithParent(done); + }); +}); + +describe('testProperties', function() { + it('saves an entity with properties', function(done) { + entity.testProperties(done); + }); +}); + +describe('testArrayValue', function() { + it('saves an entity with arrays', function(done) { + entity.testArrayValue(done); + }); +}); + +describe('testBasicEntity', function() { + it('saves a basic entity', function(done) { + entity.testBasicEntity(done); + }); +}); + +describe('testUpsert', function() { + it('saves with an upsert', function(done) { + entity.testUpsert(done); + }); +}); + +describe('testInsert', function() { + it('saves with an insert', function(done) { + entity.testInsert(done); + }); +}); + +describe('testLookup', function() { + it('performs a lookup', function(done) { + entity.testLookup(done); + }); +}); + +describe('testUpdate', function() { + it('saves with an update', function(done) { + entity.testUpdate(done); + }); +}); + +describe('testDelete', function() { + it('deletes an entity', function(done) { + entity.testDelete(done); + }); +}); + +describe('testBatchUpsert', function() { + it('performs a batch upsert', function(done) { + entity.testBatchUpsert(done); + }); +}); + +describe('testBatchLookup', function() { + it('performs a batch lookup', function(done) { + entity.testBatchLookup(done); + }); +}); + +describe('testBatchDelete', function() { + it('performs a batch delete', function(done) { + entity.testBatchDelete(done); + }); +}); diff --git a/test/datastore/testIndexes.js b/test/datastore/testIndexes.js new file mode 100644 index 00000000000..cb833d5fef7 --- /dev/null +++ b/test/datastore/testIndexes.js @@ -0,0 +1,20 @@ +'use strict'; + +var Index = require('../../datastore/index'); +var index; + +before(function() { + index = new Index(process.env.TEST_PROJECT_ID); +}); + +describe('unindexed properties', function() { + it('performs a query with a filter on an unindexed property', function(done) { + index.testUnindexedPropertyQuery(done); + }); +}); + +describe('exploding properties', function() { + it('inserts arrays of data', function(done) { + index.testExplodingProperties(done); + }); +}); diff --git a/test/datastore/testQuery.js b/test/datastore/testQuery.js new file mode 100644 index 00000000000..58404c07725 --- /dev/null +++ b/test/datastore/testQuery.js @@ -0,0 +1,159 @@ +'use strict'; + +var assert = require('assert'); + +var Query = require('../../datastore/query'); +var query; + +before(function() { + query = new Query(process.env.TEST_PROJECT_ID); +}); + +describe('basic query', function() { + it('performs a basic query', function(done) { + query.testRunQuery(done); + }); +}); + +describe('property filter', function() { + it('performs a query with a property filter', function(done) { + query.testPropertyFilter(done); + }); +}); + +describe('composite filter', function() { + it('performs a query with a composite filter', function(done) { + query.testCompositeFilter(done); + }); +}); + +describe('key filter', function() { + it('performs a query with a key filter', function(done) { + query.testKeyFilter(done); + }); +}); + +describe('ascending sort', function() { + it('performs a query with ascending sort', function(done) { + query.testAscendingSort(done); + }); +}); + +describe('descending sort', function() { + it('performs a query with descending sort', function(done) { + query.testDescendingSort(done); + }); +}); + +describe('multi sort', function() { + it('performs a query with multi sort', function(done) { + query.testMultiSort(done); + }); +}); + +describe('kindless query', function() { + it('performs a kindless query', function(done) { + query.testKindlessQuery(done); + }); +}); + +describe('projection query', function() { + it('performs a projection query', function(done) { + query.testRunQueryProjection(done); + }); +}); + +describe('keys only query', function() { + it('performs a keys only query', function(done) { + query.testKeysOnlyQuery(done); + }); +}); + +describe('distinct query', function() { + it('performs a distinct query', function(done) { + query.testDistinctQuery(done); + }); +}); + +describe('distinct on query', function() { + it('performs a distinct on query', function(done) { + query.testDistinctOnQuery(done); + }); +}); + +describe('array value inequality range', function() { + it('performs an array value inequality query', function(done) { + query.testArrayValueInequalityRange(done); + }); +}); + +describe('array value equality', function() { + it('performs an array value equality query', function(done) { + query.testArrayValueEquality(done); + }); +}); + +describe('inequality range', function() { + it('performs an inequality range query', function(done) { + query.testInequalityRange(done); + }); +}); + +describe('inequality invalid', function() { + it('returns an error from an invalid query', function(done) { + query.testInequalityInvalid(function(err) { + assert.notStrictEqual(err, null); + done(); + }); + }); +}); + +describe('equal and inequality range', function() { + it('performs an equal and inequality range query', function(done) { + query.testEqualAndInequalityRange(done); + }); +}); + +describe('inequality sort', function() { + it('performs an equality sort query', function(done) { + query.testInequalitySort(done); + }); +}); + +describe('inequality sort invalid', function() { + it('returns an error when not sorted on filtered property', function(done) { + query.testInequalitySortInvalidNotSame(function(err) { + assert.notStrictEqual(err, null); + done(); + }); + }); + + it('returns an error when not sorted on first filter prop', function(done) { + query.testInequalitySortInvalidNotFirst(function(err) { + assert.notStrictEqual(err, null); + done(); + }); + }); +}); + +describe('limit query', function() { + it('performs a query with a limit', function(done) { + query.testLimit(done); + }); +}); + +describe('cursor paging', function() { + it('allows manual pagination through results', function(done) { + query.testCursorPaging(function(err, results, nextQuery) { + assert.ifError(err); + assert.notStrictEqual(nextQuery, null); + done(); + }); + }); +}); + +describe('eventually consistent query', function() { + it('performs an ancestor query', function(done) { + query.testEventualConsistentQuery(done); + }); +});