"use strict";
/*!
* Copyright 2014 Google LLC.
*
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
const arrify = require("arrify");
/**
* Build a Query object.
*
* **Queries are built with {module:datastore#createQuery} and
* {@link Transaction#createQuery}.**
*
* @see [Datastore Queries]{@link http://goo.gl/Cag0r6}
*
* @class
* @param {Datastore|Transaction} scope The parent scope the query was created
* from.
* @param {string} [namespace] Namespace to query entities from.
* @param {string[]} kinds Kind to query.
*
* @example
* const {Datastore} = require('@google-cloud/datastore');
* const datastore = new Datastore();
* const query = datastore.createQuery('AnimalNamespace', 'Lion');
*/
class Query {
constructor(scope, namespaceOrKinds, kinds) {
let namespace = namespaceOrKinds;
if (!kinds) {
kinds = namespaceOrKinds;
namespace = null;
}
/**
* @name Query#scope
* @type {Datastore|Transaction}
*/
this.scope = scope;
/**
* @name Query#namespace
* @type {?string}
*/
this.namespace = namespace || null;
/**
* @name Query#kinds
* @type {string}
*/
this.kinds = kinds;
/**
* @name Query#filters
* @type {array}
*/
this.filters = [];
/**
* @name Query#orders
* @type {array}
*/
this.orders = [];
/**
* @name Query#groupByVal
* @type {array}
*/
this.groupByVal = [];
/**
* @name Query#selectVal
* @type {array}
*/
this.selectVal = [];
// pagination
/**
* @name Query#startVal
* @type {?number}
*/
this.startVal = null;
/**
* @name Query#endVal
* @type {?number}
*/
this.endVal = null;
/**
* @name Query#limitVal
* @type {number}
*/
this.limitVal = -1;
/**
* @name Query#offsetVal
* @type {number}
*/
this.offsetVal = -1;
}
/**
* Datastore allows querying on properties. Supported comparison operators
* are `=`, `<`, `>`, `<=`, and `>=`. "Not equal" and `IN` operators are
* currently not supported.
*
* *To filter by ancestors, see {module:datastore/query#hasAncestor}.*
*
* @see [Datastore Filters]{@link https://cloud.google.com/datastore/docs/concepts/queries#datastore-property-filter-nodejs}
*
* @param {string} property The field name.
* @param {string} [operator="="] Operator (=, <, >, <=, >=).
* @param {*} value Value to compare property to.
* @returns {Query}
*
* @example
* const {Datastore} = require('@google-cloud/datastore');
* const datastore = new Datastore();
* const query = datastore.createQuery('Company');
*
* //-
* // List all companies that are located in California.
* //-
* const caliQuery = query.filter('state', 'CA');
*
* //-
* // List all companies named Google that have less than 400 employees.
* //-
* const companyQuery = query
* .filter('name', 'Google')
* .filter('size', '<', 400);
*
* //-
* // To filter by key, use `__key__` for the property name. Filter on keys
* // stored as properties is not currently supported.
* //-
* const key = datastore.key(['Company', 'Google']);
* const keyQuery = query.filter('__key__', key);
*/
filter(property, operatorOrValue, value) {
let operator = operatorOrValue;
if (arguments.length === 2) {
value = operatorOrValue;
operator = '=';
}
this.filters.push({
name: property.trim(),
op: operator.trim(),
val: value,
});
return this;
}
/**
* Filter a query by ancestors.
*
* @see [Datastore Ancestor Filters]{@link https://cloud.google.com/datastore/docs/concepts/queries#datastore-ancestor-query-nodejs}
*
* @param {Key} key Key object to filter by.
* @returns {Query}
*
* @example
* const {Datastore} = require('@google-cloud/datastore');
* const datastore = new Datastore();
* const query = datastore.createQuery('MyKind');
* const ancestoryQuery = query.hasAncestor(datastore.key(['Parent', 123]));
*/
hasAncestor(key) {
this.filters.push({ name: '__key__', op: 'HAS_ANCESTOR', val: key });
return this;
}
/**
* Sort the results by a property name in ascending or descending order. By
* default, an ascending sort order will be used.
*
* @see [Datastore Sort Orders]{@link https://cloud.google.com/datastore/docs/concepts/queries#datastore-ascending-sort-nodejs}
*
* @param {string} property The property to order by.
* @param {object} [options] Options object.
* @param {boolean} [options.descending=false] Sort the results by a property
* name in descending order.
* @returns {Query}
*
* @example
* const {Datastore} = require('@google-cloud/datastore');
* const datastore = new Datastore();
* const companyQuery = datastore.createQuery('Company');
*
* // Sort by size ascendingly.
* const companiesAscending = companyQuery.order('size');
*
* // Sort by size descendingly.
* const companiesDescending = companyQuery.order('size', {
* descending: true
* });
*/
order(property, options) {
const sign = options && options.descending ? '-' : '+';
this.orders.push({ name: property, sign });
return this;
}
/**
* Group query results by a list of properties.
*
* @param {array} properties Properties to group by.
* @returns {Query}
*
* @example
* const {Datastore} = require('@google-cloud/datastore');
* const datastore = new Datastore();
* const companyQuery = datastore.createQuery('Company');
* const groupedQuery = companyQuery.groupBy(['name', 'size']);
*/
groupBy(fieldNames) {
this.groupByVal = arrify(fieldNames);
return this;
}
/**
* Retrieve only select properties from the matched entities.
*
* Queries that select a subset of properties are called Projection Queries.
*
* @see [Projection Queries]{@link https://cloud.google.com/datastore/docs/concepts/projectionqueries}
*
* @param {string|string[]} fieldNames Properties to return from the matched
* entities.
* @returns {Query}
*
* @example
* const {Datastore} = require('@google-cloud/datastore');
* const datastore = new Datastore();
* const companyQuery = datastore.createQuery('Company');
*
* // Only retrieve the name property.
* const selectQuery = companyQuery.select('name');
*
* // Only retrieve the name and size properties.
* const selectQuery = companyQuery.select(['name', 'size']);
*/
select(fieldNames) {
this.selectVal = arrify(fieldNames);
return this;
}
/**
* Set a starting cursor to a query.
*
* @see [Query Cursors]{@link https://cloud.google.com/datastore/docs/concepts/queries#cursors_limits_and_offsets}
*
* @param {string} cursorToken The starting cursor token.
* @returns {Query}
*
* @example
* const {Datastore} = require('@google-cloud/datastore');
* const datastore = new Datastore();
* const companyQuery = datastore.createQuery('Company');
*
* const cursorToken = 'X';
*
* // Retrieve results starting from cursorToken.
* const startQuery = companyQuery.start(cursorToken);
*/
start(start) {
this.startVal = start;
return this;
}
/**
* Set an ending cursor to a query.
*
* @see [Query Cursors]{@link https://cloud.google.com/datastore/docs/concepts/queries#Datastore_Query_cursors}
*
* @param {string} cursorToken The ending cursor token.
* @returns {Query}
*
* @example
* const {Datastore} = require('@google-cloud/datastore');
* const datastore = new Datastore();
* const companyQuery = datastore.createQuery('Company');
*
* const cursorToken = 'X';
*
* // Retrieve results limited to the extent of cursorToken.
* const endQuery = companyQuery.end(cursorToken);
*/
end(end) {
this.endVal = end;
return this;
}
/**
* Set a limit on a query.
*
* @see [Query Limits]{@link https://cloud.google.com/datastore/docs/concepts/queries#datastore-limit-nodejs}
*
* @param {number} n The number of results to limit the query to.
* @returns {Query}
*
* @example
* const {Datastore} = require('@google-cloud/datastore');
* const datastore = new Datastore();
* const companyQuery = datastore.createQuery('Company');
*
* // Limit the results to 10 entities.
* const limitQuery = companyQuery.limit(10);
*/
limit(n) {
this.limitVal = n;
return this;
}
/**
* Set an offset on a query.
*
* @see [Query Offsets]{@link https://cloud.google.com/datastore/docs/concepts/queries#datastore-limit-nodejs}
*
* @param {number} n The offset to start from after the start cursor.
* @returns {Query}
*
* @example
* const {Datastore} = require('@google-cloud/datastore');
* const datastore = new Datastore();
* const companyQuery = datastore.createQuery('Company');
*
* // Start from the 101st result.
* const offsetQuery = companyQuery.offset(100);
*/
offset(n) {
this.offsetVal = n;
return this;
}
/**
* Run the query.
*
* @param {object} [options] Optional configuration.
* @param {string} [options.consistency] Specify either `strong` or `eventual`.
* If not specified, default values are chosen by Datastore for the
* operation. Learn more about strong and eventual consistency
* [here](https://cloud.google.com/datastore/docs/articles/balancing-strong-and-eventual-consistency-with-google-cloud-datastore).
* @param {object} [options.gaxOptions] Request configuration options, outlined
* here: https://googleapis.github.io/gax-nodejs/global.html#CallOptions.
* @param {boolean | IntegerTypeCastOptions} [options.wrapNumbers=false]
* Wrap values of integerValue type in {@link Datastore#Int} objects.
* If a `boolean`, this will wrap values in {@link Datastore#Int} objects.
* If an `object`, this will return a value returned by
* `wrapNumbers.integerTypeCastFunction`.
* Please see {@link IntegerTypeCastOptions} for options descriptions.
* @param {function} [callback] The callback function. If omitted, a readable
* stream instance is returned.
* @param {?error} callback.err An error returned while making this request
* @param {object[]} callback.entities A list of entities.
* @param {object} callback.info An object useful for pagination.
* @param {?string} callback.info.endCursor Use this in a follow-up query to
* begin from where these results ended.
* @param {string} callback.info.moreResults Datastore responds with one of:
*
* - {@link Datastore#MORE_RESULTS_AFTER_LIMIT}: There *may* be more
* results after the specified limit.
* - {@link Datastore#MORE_RESULTS_AFTER_CURSOR}: There *may* be more
* results after the specified end cursor.
* - {@link Datastore#NO_MORE_RESULTS}: There are no more results.
*
* @example
* const {Datastore} = require('@google-cloud/datastore');
* const datastore = new Datastore();
* const query = datastore.createQuery('Company');
*
* query.run((err, entities, info) => {
* // entities = An array of records.
*
* // Access the Key object for an entity.
* const firstEntityKey = entities[0][datastore.KEY];
* });
*
* //-
* // A keys-only query returns just the keys of the result entities instead
* of
* // the entities themselves, at lower latency and cost.
* //-
* query.select('__key__');
*
* query.run((err, entities) => {
* const keys = entities.map((entity) => {
* return entity[datastore.KEY];
* });
* });
*
* //-
* // If the callback is omitted, we'll return a Promise.
* //-
* query.run().then((data) => {
* const entities = data[0];
* });
*/
run(optionsOrCallback, cb) {
const query = this;
const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
const runQuery = this.scope.runQuery.bind(this.scope);
return runQuery(query, options, callback);
}
/**
* Run the query as a readable object stream.
*
* @method Query#runStream
* @param {object} [options] Optional configuration. See
* {@link Query#run} for a complete list of options.
* @returns {stream}
*
* @example
* const {Datastore} = require('@google-cloud/datastore');
* const datastore = new Datastore();
* const query = datastore.createQuery('Company');
*
* query.runStream()
* .on('error', console.error)
* .on('data', function (entity) {
* // Access the Key object for this entity.
* const key = entity[datastore.KEY];
* })
* .on('info', (info) => {})
* .on('end', () => {
* // All entities retrieved.
* });
*
* //-
* // If you anticipate many results, you can end a stream early to prevent
* // unnecessary processing and API requests.
* //-
* query.runStream()
* .on('data', function (entity) {
* this.end();
* });
*/
runStream() {
const query = this;
// tslint:disable-next-line no-any
const args = [query].concat([].slice.call(arguments));
return this.scope.runQueryStream.apply(this.scope, args);
}
}
exports.Query = Query;
//# sourceMappingURL=query.js.map