diff --git a/package.json b/package.json index 2257e49ab..813c8eedb 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "system-test": "mocha build/system-test --timeout 600000", "fix": "gts fix && eslint '**/*.js' --fix", "clean": "gts clean", - "compile": "tsc -p . && cp -r src/v1/ build/src/v1/ && cp -r protos build/ && cp test/*.js build/test", + "compile": "tsc -p . && cp -r src/v1 build/src && cp -r protos build && cp test/*.js build/test", "prepare": "npm run compile", "pretest": "npm run compile" }, diff --git a/src/entity.ts b/src/entity.ts index e8abc9b9b..e89d572cf 100644 --- a/src/entity.ts +++ b/src/entity.ts @@ -17,15 +17,20 @@ import * as arrify from 'arrify'; import * as extend from 'extend'; import * as is from 'is'; +import {Query, QueryProto} from './query'; // tslint:disable-next-line no-namespace export namespace entity { + export interface InvalidKeyErrorOptions { + code: string; + } + export class InvalidKeyError extends Error { - constructor(opts) { + constructor(opts: InvalidKeyErrorOptions) { const errorMessages = { MISSING_KIND: 'A key should contain at least a kind.', MISSING_ANCESTOR_ID: 'Ancestor keys require an id or name.', - }; + } as {[index: string]: string}; super(errorMessages[opts.code]); this.name = 'InvalidKey'; } @@ -69,7 +74,7 @@ export namespace entity { * @param {*} value * @returns {boolean} */ - export function isDsDouble(value) { + export function isDsDouble(value?: {}) { return value instanceof entity.Double; } @@ -102,7 +107,7 @@ export namespace entity { * @param {*} value * @returns {boolean} */ - export function isDsInt(value) { + export function isDsInt(value?: {}) { return value instanceof entity.Int; } @@ -151,10 +156,15 @@ export namespace entity { * @param {*} value * @returns {boolean} */ - export function isDsGeoPoint(value) { + export function isDsGeoPoint(value?: {}) { return value instanceof entity.GeoPoint; } + export interface KeyOptions { + namespace?: string; + path: Array; + } + /** * Build a Datastore Key object. * @@ -172,14 +182,14 @@ export namespace entity { * }); */ export class Key { - namespace: string; + namespace?: string; id?: string; name?: string; kind: string; parent?: Key; - path; + path!: Array; - constructor(options) { + constructor(options: KeyOptions) { /** * @name Key#namespace * @type {string} @@ -192,13 +202,13 @@ export namespace entity { const identifier = options.path.pop(); if (is.number(identifier) || isDsInt(identifier)) { - this.id = identifier.value || identifier; + this.id = ((identifier as {} as Int).value || identifier) as string; } else if (is.string(identifier)) { - this.name = identifier; + this.name = identifier as string; } } - this.kind = options.path.pop(); + this.kind = options.path.pop() as string; if (options.path.length > 0) { this.parent = new Key(options); @@ -229,7 +239,7 @@ export namespace entity { * @param {*} value * @returns {boolean} */ - export function isDsKey(value) { + export function isDsKey(value?: {}) { return value instanceof entity.Key; } @@ -256,8 +266,8 @@ export namespace entity { * }); * // */ - export function decodeValueProto(valueProto) { - const valueType = valueProto.valueType; + export function decodeValueProto(valueProto: ValueProto) { + const valueType = valueProto.valueType!; const value = valueProto[valueType]; switch (valueType) { @@ -311,9 +321,9 @@ export namespace entity { * // stringValue: 'Hi' * // } */ - export function encodeValue(value) { - // tslint:disable-next-line no-any - const valueProto: any = {}; + // tslint:disable-next-line no-any + export function encodeValue(value?: any): ValueProto { + const valueProto: ValueProto = {}; if (is.boolean(value)) { valueProto.booleanValue = value; @@ -325,7 +335,7 @@ export namespace entity { return valueProto; } - if (is.number(value)) { + if (typeof value === 'number') { if (value % 1 === 0) { value = new entity.Int(value); } else { @@ -334,17 +344,17 @@ export namespace entity { } if (isDsInt(value)) { - valueProto.integerValue = value.value; + valueProto.integerValue = (value as Int).value; return valueProto; } if (isDsDouble(value)) { - valueProto.doubleValue = value.value; + valueProto.doubleValue = (value as Double).value; return valueProto; } if (isDsGeoPoint(value)) { - valueProto.geoPointValue = value.value; + valueProto.geoPointValue = (value as GeoPoint).value; return valueProto; } @@ -369,7 +379,7 @@ export namespace entity { return valueProto; } - if (is.array(value)) { + if (Array.isArray(value)) { valueProto.arrayValue = { values: value.map(entity.encodeValue), }; @@ -428,9 +438,10 @@ export namespace entity { * // name: 'Stephen' * // } */ - export function entityFromEntityProto(entityProto) { - const entityObject = {}; - + // tslint:disable-next-line no-any + export function entityFromEntityProto(entityProto: EntityProto): any { + // tslint:disable-next-line no-any + const entityObject: any = {}; const properties = entityProto.properties || {}; // tslint:disable-next-line forin @@ -472,11 +483,11 @@ export namespace entity { * // } * // } */ - export function entityToEntityProto(entityObject) { + export function entityToEntityProto(entityObject: Entity): EntityProto { const properties = entityObject.data; const excludeFromIndexes = entityObject.excludeFromIndexes; - const entityProto = { + const entityProto: EntityProto = { key: null, properties: Object.keys(properties) @@ -485,7 +496,8 @@ export namespace entity { encoded[key] = entity.encodeValue(properties[key]); return encoded; }, - {}), + // tslint:disable-next-line no-any + {} as any), }; if (excludeFromIndexes && excludeFromIndexes.length > 0) { @@ -496,7 +508,7 @@ export namespace entity { return entityProto; - function excludePathFromEntity(entity, path) { + function excludePathFromEntity(entity: EntityProto, path: string) { const arrayIndex = path.indexOf('[]'); const entityIndex = path.indexOf('.'); @@ -531,7 +543,7 @@ export namespace entity { const delimiter = firstPathPartIsArray ? '[]' : '.'; const splitPath = path.split(delimiter); - const firstPathPart = splitPath.shift(); + const firstPathPart = splitPath.shift()!; const remainderPath = splitPath.join(delimiter).replace(/^(\.|\[\])/, ''); if (!(entity.properties && entity.properties[firstPathPart])) { @@ -543,7 +555,8 @@ export namespace entity { // check also if the property in question is actually an array value. entity.properties[firstPathPart].arrayValue) { const array = entity.properties[firstPathPart].arrayValue; - array.values.forEach(value => { + // tslint:disable-next-line no-any + array.values.forEach((value: any) => { if (remainderPath === '') { // We want to exclude *this* array property, which is // equivalent with excluding all its values @@ -589,10 +602,10 @@ export namespace entity { * // * }); */ - export function formatArray(results) { + export function formatArray(results: ResponseResult[]) { return results.map(result => { const ent = entity.entityFromEntityProto(result.entity); - ent[entity.KEY_SYMBOL] = entity.keyFromKeyProto(result.entity.key); + ent[entity.KEY_SYMBOL] = entity.keyFromKeyProto(result.entity.key!); return ent; }); } @@ -608,8 +621,8 @@ export namespace entity { * isKeyComplete(new Key(['Company', 'Google'])); // true * isKeyComplete(new Key('Company')); // false */ - export function isKeyComplete(key) { - const lastPathElement = entity.keyToKeyProto(key).path.pop(); + export function isKeyComplete(key: Key) { + const lastPathElement = entity.keyToKeyProto(key).path.pop()!; return !!(lastPathElement.id || lastPathElement.name); } @@ -634,7 +647,7 @@ export namespace entity { * ] * }); */ - export function keyFromKeyProto(keyProto) { + export function keyFromKeyProto(keyProto: KeyProto): Key { // tslint:disable-next-line no-any const keyOptions: any = { path: [], @@ -647,7 +660,7 @@ export namespace entity { keyProto.path.forEach((path, index) => { keyOptions.path.push(path.kind); - let id = path[path.idType]; + let id = path[path.idType!]; if (path.idType === 'id') { id = new entity.Int(id); @@ -683,7 +696,7 @@ export namespace entity { * // ] * // } */ - export function keyToKeyProto(key) { + export function keyToKeyProto(key: Key): KeyProto { if (is.undefined(key.kind)) { throw new InvalidKeyError({ code: 'MISSING_KIND', @@ -691,7 +704,7 @@ export namespace entity { } // tslint:disable-next-line no-any - const keyProto: any = { + const keyProto: KeyProto = { path: [], }; @@ -727,7 +740,7 @@ export namespace entity { keyProto.path.unshift(pathElement); // tslint:disable-next-line no-conditional-assignment - } while ((key = key.parent) && ++numKeysWalked); + } while ((key = key.parent!) && ++numKeysWalked); return keyProto; } @@ -765,7 +778,7 @@ export namespace entity { * // groupBy: [] * // } */ - export function queryToQueryProto(query) { + export function queryToQueryProto(query: Query): QueryProto { const OP_TO_OPERATOR = { '=': 'EQUAL', '>': 'GREATER_THAN', @@ -780,8 +793,7 @@ export namespace entity { '+': 'ASCENDING', }; - // tslint:disable-next-line no-any - const queryProto: any = { + const queryProto: QueryProto = { distinctOn: query.groupByVal.map(groupBy => { return { name: groupBy, @@ -863,3 +875,36 @@ export namespace entity { return queryProto; } } + +export interface ValueProto { + // tslint:disable-next-line no-any + [index: string]: any; + valueType?: string; + values?: ValueProto[]; + // tslint:disable-next-line no-any + value?: any; +} + +export interface EntityProto { + key: KeyProto|null; + // tslint:disable-next-line no-any + properties: any; + excludeFromIndexes?: boolean; +} + +// tslint:disable-next-line no-any +export type Entity = any; + +export interface KeyProto { + path: Array<{ + // tslint:disable-next-line no-any + [index: string]: any; id: string; name: string; + kind?: string; + idType?: string; + }>; + partitionId?: {namespaceId: {}}; +} + +export interface ResponseResult { + entity: EntityProto; +} diff --git a/src/index.ts b/src/index.ts index 6acf4e6be..37c17ba10 100644 --- a/src/index.ts +++ b/src/index.ts @@ -37,8 +37,9 @@ */ import * as arrify from 'arrify'; -import {GoogleAuth} from 'google-auth-library'; +import {GoogleAuth, GoogleAuthOptions} from 'google-auth-library'; import {GrpcClient, GrpcClientOptions} from 'google-gax'; +import {ChannelCredentials} from 'grpc'; import * as is from 'is'; import {entity} from './entity'; @@ -48,6 +49,9 @@ import {Transaction} from './transaction'; const {grpc} = new GrpcClient({} as GrpcClientOptions); +// tslint:disable-next-line: no-any +export type PathType = any; + // Import the clients for each version supported by this package. const gapic = Object.freeze({ v1: require('./v1'), @@ -381,16 +385,16 @@ const gapic = Object.freeze({ * }); */ class Datastore extends DatastoreRequest { - clients_; - namespace; + clients_: Map; + namespace?: string; projectId: string; defaultBaseUrl_: string; - options; + options: DatastoreOptions; baseUrl_?: string; port_?: number; customEndpoint_?: boolean; auth: GoogleAuth; - constructor(options?) { + constructor(options?: DatastoreOptions) { super(); options = options || {}; this.clients_ = new Map(); @@ -443,11 +447,11 @@ class Datastore extends DatastoreRequest { * const datastore = new Datastore(); * const threeDouble = datastore.double(3.0); */ - static double(value) { + static double(value: number) { return new entity.Double(value); } - double(value) { + double(value: number) { return Datastore.double(value); } @@ -463,11 +467,11 @@ class Datastore extends DatastoreRequest { * datastore.isDouble(0.42); // false * datastore.isDouble(datastore.double(0.42)); // true */ - static isDouble(value) { + static isDouble(value?: {}) { return entity.isDsDouble(value); } - isDouble(value) { + isDouble(value?: {}) { return Datastore.isDouble(value); } @@ -489,11 +493,11 @@ class Datastore extends DatastoreRequest { * * const geoPoint = datastore.geoPoint(coordinates); */ - static geoPoint(coordinates) { + static geoPoint(coordinates: entity.Coordinates) { return new entity.GeoPoint(coordinates); } - geoPoint(coordinates) { + geoPoint(coordinates: entity.Coordinates) { return Datastore.geoPoint(coordinates); } @@ -514,11 +518,11 @@ class Datastore extends DatastoreRequest { * datastore.isGeoPoint(coordinates); // false * datastore.isGeoPoint(datastore.geoPoint(coordinates)); // true */ - static isGeoPoint(value) { + static isGeoPoint(value?: {}) { return entity.isDsGeoPoint(value); } - isGeoPoint(value) { + isGeoPoint(value?: {}) { return Datastore.isGeoPoint(value); } @@ -544,11 +548,11 @@ class Datastore extends DatastoreRequest { * datastore.int('100000000000001234') * ]); */ - static int(value) { + static int(value: number|string) { return new entity.Int(value); } - int(value) { + int(value: number|string) { return Datastore.int(value); } @@ -564,11 +568,11 @@ class Datastore extends DatastoreRequest { * datastore.isInt(42); // false * datastore.isInt(datastore.int(42)); // true */ - static isInt(value) { + static isInt(value?: {}) { return entity.isDsInt(value); } - isInt(value) { + isInt(value?: {}) { return Datastore.isInt(value); } @@ -643,7 +647,7 @@ class Datastore extends DatastoreRequest { createQuery(namespace: string, kind?: string) { if (arguments.length < 2) { kind = namespace; - namespace = this.namespace; + namespace = this.namespace!; } return new Query(this, namespace, arrify(kind)); } @@ -697,12 +701,15 @@ class Datastore extends DatastoreRequest { * path: ['Company', 123] * }); */ - key(options) { + key(options: entity.KeyOptions): entity.Key; + key(path: PathType[]): entity.Key; + key(path: string): entity.Key; + key(options: string|entity.KeyOptions|PathType[]): entity.Key { options = is.object(options) ? options : { namespace: this.namespace, path: arrify(options), }; - return new entity.Key(options); + return new entity.Key(options as entity.KeyOptions); } /** @@ -717,10 +724,10 @@ class Datastore extends DatastoreRequest { * datastore.isKey({path: ['Company', 123]}); // false * datastore.isKey(datastore.key(['Company', 123])); // true */ - static isKey(value) { + static isKey(value?: {}) { return entity.isDsKey(value); } - isKey(value) { + isKey(value?: {}) { return Datastore.isKey(value); } @@ -738,7 +745,7 @@ class Datastore extends DatastoreRequest { * const datastore = new Datastore(); * const transaction = datastore.transaction(); */ - transaction(options?) { + transaction(options?: TransactionOptions) { return new Transaction(this, options); } @@ -751,7 +758,7 @@ class Datastore extends DatastoreRequest { * * @param {string} customApiEndpoint Custom API endpoint. */ - determineBaseUrl_(customApiEndpoint) { + determineBaseUrl_(customApiEndpoint?: string) { let baseUrl = this.defaultBaseUrl_; const leadingProtocol = new RegExp('^https*://'); const trailingSlashes = new RegExp('/*$'); @@ -851,3 +858,14 @@ export {Datastore}; * Reference to {@link v1.DatastoreClient}. */ module.exports.v1 = gapic.v1; + +export interface TransactionOptions { + id?: string; + readOnly?: boolean; +} + +export interface DatastoreOptions extends GoogleAuthOptions { + namespace?: string; + apiEndpoint?: string; + sslCreds?: ChannelCredentials; +} diff --git a/src/query.ts b/src/query.ts index 2429f89cc..fbb94279d 100644 --- a/src/query.ts +++ b/src/query.ts @@ -15,6 +15,29 @@ */ import * as arrify from 'arrify'; +import {Key} from 'readline'; + +import {Datastore} from '.'; +import {Entity} from './entity'; +import {Transaction} from './transaction'; + +export type Operator = '='|'<'|'>'|'<='|'>='|'HAS_ANCESTOR'; + +export interface OrderOptions { + descending?: boolean; +} + +export interface Order { + name: string; + sign: '-'|'+'; +} + +export interface Filter { + name: string; + // tslint:disable-next-line no-any + val: any; + op: Operator; +} /** * Build a Query object. @@ -28,7 +51,7 @@ import * as arrify from 'arrify'; * @param {Datastore|Transaction} scope The parent scope the query was created * from. * @param {string} [namespace] Namespace to query entities from. - * @param {string} kind Kind to query. + * @param {string[]} kinds Kind to query. * * @example * const {Datastore} = require('@google-cloud/datastore'); @@ -36,20 +59,27 @@ import * as arrify from 'arrify'; * const query = datastore.createQuery('AnimalNamespace', 'Lion'); */ class Query { - scope; - namespace?: string; - kinds; - filters; - orders; - groupByVal; - selectVal; - startVal; - endVal; - limitVal; - offsetVal; - constructor(scope?, namespace?, kinds?) { + scope?: Datastore|Transaction; + namespace?: string|null; + kinds: string[]; + filters: Filter[]; + orders: Order[]; + groupByVal: Array<{}>; + selectVal: Array<{}>; + startVal: string|Buffer|null; + endVal: string|Buffer|null; + limitVal: number; + offsetVal: number; + + constructor(scope?: Datastore|Transaction, kinds?: string[]); + constructor( + scope?: Datastore|Transaction, namespace?: string, kinds?: string[]); + constructor( + scope?: Datastore|Transaction, namespaceOrKinds?: string|string[], + kinds?: string[]) { + let namespace = namespaceOrKinds as string | null; if (!kinds) { - kinds = namespace; + kinds = namespaceOrKinds as string[]; namespace = null; } @@ -152,15 +182,18 @@ class Query { * const key = datastore.key(['Company', 'Google']); * const keyQuery = query.filter('__key__', key); */ - filter(property: string, operator, value?) { + filter(property: string, value: {}): Query; + filter(property: string, operator: Operator, value: {}): Query; + filter(property: string, operatorOrValue: Operator, value?: {}): Query { + let operator = operatorOrValue as Operator; if (arguments.length === 2) { - value = operator; + value = operatorOrValue as {}; operator = '='; } this.filters.push({ name: property.trim(), - op: operator.trim(), + op: operator.trim() as Operator, val: value, }); return this; @@ -180,7 +213,7 @@ class Query { * const query = datastore.createQuery('MyKind'); * const ancestoryQuery = query.hasAncestor(datastore.key(['Parent', 123])); */ - hasAncestor(key) { + hasAncestor(key: Key) { this.filters.push({name: '__key__', op: 'HAS_ANCESTOR', val: key}); return this; } @@ -210,7 +243,7 @@ class Query { * descending: true * }); */ - order(property: string, options?) { + order(property: string, options?: OrderOptions) { const sign = options && options.descending ? '-' : '+'; this.orders.push({name: property, sign}); return this; @@ -228,7 +261,7 @@ class Query { * const companyQuery = datastore.createQuery('Company'); * const groupedQuery = companyQuery.groupBy(['name', 'size']); */ - groupBy(fieldNames) { + groupBy(fieldNames: string|string[]) { this.groupByVal = arrify(fieldNames); return this; } @@ -255,7 +288,7 @@ class Query { * // Only retrieve the name and size properties. * const selectQuery = companyQuery.select(['name', 'size']); */ - select(fieldNames) { + select(fieldNames: string|string[]) { this.selectVal = arrify(fieldNames); return this; } @@ -278,7 +311,7 @@ class Query { * // Retrieve results starting from cursorToken. * const startQuery = companyQuery.start(cursorToken); */ - start(start) { + start(start: string|Buffer) { this.startVal = start; return this; } @@ -301,7 +334,7 @@ class Query { * // Retrieve results limited to the extent of cursorToken. * const endQuery = companyQuery.end(cursorToken); */ - end(end) { + end(end: string|Buffer) { this.endVal = end; return this; } @@ -322,7 +355,7 @@ class Query { * // Limit the results to 10 entities. * const limitQuery = companyQuery.limit(10); */ - limit(n) { + limit(n: number) { this.limitVal = n; return this; } @@ -343,7 +376,7 @@ class Query { * // Start from the 101st result. * const offsetQuery = companyQuery.offset(100); */ - offset(n) { + offset(n: number) { this.offsetVal = n; return this; } @@ -403,10 +436,18 @@ class Query { * const entities = data[0]; * }); */ - run(...argy) { - const query = this; - const args = [query].concat(argy); - return this.scope.runQuery.apply(this.scope, args); + run(options?: RunQueryOptions): Promise; + run(options: RunQueryOptions, callback: RunQueryCallback): void; + run(callback: RunQueryCallback): void; + run(optionsOrCallback?: RunQueryOptions|RunQueryCallback, + cb?: RunQueryCallback): void|Promise { + const query = this as Query; + const options = + typeof optionsOrCallback === 'object' ? optionsOrCallback : {}; + const callback = + typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!; + const runQuery = this.scope!.runQuery.bind(this.scope); + return (runQuery as Function)(query, options, callback); } /** @@ -444,14 +485,43 @@ class Query { */ runStream() { const query = this; - const args = [query].concat([].slice.call(arguments)); - return this.scope.runQueryStream.apply(this.scope, args); + // tslint:disable-next-line no-any + const args: any = [query].concat([].slice.call(arguments)); + return this.scope!.runQueryStream.apply(this.scope, args); } } +export interface QueryProto { + startCursor?: string|Buffer; + distinctOn: {}; + kind: {}; + order: {}; + projection: {}; + endCursor?: string|Buffer; + limit?: {}; + offset?: number; + filter?: {}; +} + /** * Reference to the {@link Query} class. * @name module:@google-cloud/datastore.Query * @see Query */ export {Query}; + +export interface RunQueryOptions { + consistency?: 'strong'|'eventual'; +} + +export interface RunQueryCallback { + (err: Error|null, entities?: Entity[], info?: RunQueryInfo): void; +} + +export type RunQueryResponse = [Entity[], RunQueryInfo]; + +export interface RunQueryInfo { + endCursor?: string; + moreResults?: 'MORE_RESULTS_AFTER_LIMIT'|'MORE_RESULTS_AFTER_CURSOR'| + 'NO_MORE_RESULTS'; +} diff --git a/src/request.ts b/src/request.ts index fe4bf7ab7..c878e5722 100644 --- a/src/request.ts +++ b/src/request.ts @@ -30,8 +30,8 @@ const gapic = Object.freeze({ v1: require('./v1'), }); -import {entity} from './entity'; -import {Query} from './query'; +import {entity, Entity} from './entity'; +import {Query, RunQueryInfo, RunQueryOptions, RunQueryResponse, RunQueryCallback} from './query'; import {Datastore} from '.'; export interface EntityDataObj { @@ -585,16 +585,19 @@ class DatastoreRequest { * const entities = data[0]; * }); */ - runQuery(query, options?): Promise>>; - runQuery(query, options?, callback?): void|Promise>> { - if (is.fn(options)) { - callback = options; - options = {}; - } - - options = options || {}; - - let info; + runQuery(query: Query, options?: RunQueryOptions): Promise; + runQuery(query: Query, options: RunQueryOptions, callback: RunQueryCallback): + void; + runQuery(query: Query, callback: RunQueryCallback): void; + runQuery( + query: Query, optionsOrCallback?: RunQueryOptions|RunQueryCallback, + cb?: RunQueryCallback): void|Promise { + const options = + typeof optionsOrCallback === 'object' ? optionsOrCallback : {}; + const callback = + typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!; + + let info: RunQueryInfo; this.runQueryStream(query, options) .on('error', callback) @@ -602,7 +605,7 @@ class DatastoreRequest { info_ => { info = info_; }) - .pipe(concat(results => { + .pipe(concat((results: Entity[]) => { callback(null, results, info); })); } @@ -638,7 +641,7 @@ class DatastoreRequest { * this.end(); * }); */ - runQueryStream(query, options?) { + runQueryStream(query: Query, options?) { options = options || {}; query = extend(true, new Query(), query); @@ -686,7 +689,8 @@ class DatastoreRequest { info.endCursor = resp.batch.endCursor.toString('base64'); } - let entities = []; + // tslint:disable-next-line no-any + let entities: any[] = []; if (resp.batch.entityResults) { entities = entity.formatArray(resp.batch.entityResults); @@ -1162,7 +1166,7 @@ class DatastoreRequest { 'google-cloud-resource-prefix': `projects/${projectId}`, }, }); - gaxClient[method](reqOpts, gaxOpts, callback); + gaxClient![method](reqOpts, gaxOpts, callback); }); } } diff --git a/src/transaction.ts b/src/transaction.ts index c38419c49..ce8418fa4 100644 --- a/src/transaction.ts +++ b/src/transaction.ts @@ -18,6 +18,7 @@ import {promisifyAll} from '@google-cloud/promisify'; import * as arrify from 'arrify'; import * as is from 'is'; +import {Datastore} from '.'; import {entity} from './entity'; import {DatastoreRequest} from './request'; @@ -41,12 +42,12 @@ import {DatastoreRequest} from './request'; */ class Transaction extends DatastoreRequest { projectId: string; - namespace: string; + namespace?: string; readOnly: boolean; request; modifiedEntities_; skipCommit?: boolean; - constructor(datastore, options) { + constructor(datastore: Datastore, options) { super(); /** * @name Transaction#datastore diff --git a/system-test/datastore.ts b/system-test/datastore.ts index 5dd666a3e..4ec29f84b 100644 --- a/system-test/datastore.ts +++ b/system-test/datastore.ts @@ -19,7 +19,7 @@ import {Datastore} from '../src'; import {entity} from '../src/entity'; describe('Datastore', () => { - const testKinds: Array<{}> = []; + const testKinds: string[] = []; const datastore = new Datastore(); // Override the Key method so we can track what keys are created during the // tests. They are then deleted in the `after` hook. @@ -373,8 +373,8 @@ describe('Datastore', () => { datastore.runQuery(query, (err, results) => { assert.ifError(err); - assert.strictEqual(results[0].fullName, 'Full name'); - assert.deepStrictEqual(results[0].linkedTo, personKey); + assert.strictEqual(results![0].fullName, 'Full name'); + assert.deepStrictEqual(results![0].linkedTo, personKey); datastore.delete(personKey, done); }); }); @@ -547,15 +547,15 @@ describe('Datastore', () => { datastore.runQuery(q, (err, firstEntities, info) => { assert.ifError(err); - assert.strictEqual(firstEntities.length, 5); + assert.strictEqual(firstEntities!.length, 5); const secondQ = datastore.createQuery('Character') .hasAncestor(ancestor) - .start(info.endCursor); + .start(info!.endCursor!); datastore.runQuery(secondQ, (err, secondEntities) => { assert.ifError(err); - assert.strictEqual(secondEntities.length, 3); + assert.strictEqual(secondEntities!.length, 3); done(); }); }); @@ -569,7 +569,7 @@ describe('Datastore', () => { datastore.runQuery(q, (err, results) => { assert.ifError(err); - assert.strictEqual(results.length, limit); + assert.strictEqual(results!.length, limit); done(); }); }); @@ -615,7 +615,7 @@ describe('Datastore', () => { datastore.runQuery(q, (err, entities) => { assert.ifError(err); - assert.strictEqual(entities.length, 6); + assert.strictEqual(entities!.length, 6); done(); }); }); @@ -628,7 +628,7 @@ describe('Datastore', () => { datastore.runQuery(q, (err, entities) => { assert.ifError(err); - assert.strictEqual(entities.length, 6); + assert.strictEqual(entities!.length, 6); done(); }); }); @@ -638,7 +638,7 @@ describe('Datastore', () => { datastore.runQuery(q, (err, entities) => { assert.ifError(err); - assert.strictEqual(entities.length, characters.length); + assert.strictEqual(entities!.length, characters.length); done(); }); }); @@ -652,7 +652,7 @@ describe('Datastore', () => { datastore.runQuery(q, (err, entities) => { assert.ifError(err); - assert.strictEqual(entities.length, 1); + assert.strictEqual(entities!.length, 1); done(); }); }); @@ -665,8 +665,8 @@ describe('Datastore', () => { datastore.runQuery(q, (err, entities) => { assert.ifError(err); - assert.strictEqual(entities[0].name, characters[0].name); - assert.strictEqual(entities[7].name, characters[3].name); + assert.strictEqual(entities![0].name, characters[0].name); + assert.strictEqual(entities![7].name, characters[3].name); done(); }); @@ -681,12 +681,12 @@ describe('Datastore', () => { datastore.runQuery(q, (err, entities) => { assert.ifError(err); - assert.deepStrictEqual(entities[0], { + assert.deepStrictEqual(entities![0], { name: 'Arya', family: 'Stark', }); - assert.deepStrictEqual(entities[8], { + assert.deepStrictEqual(entities![8], { name: 'Sansa', family: 'Stark', }); @@ -705,20 +705,20 @@ describe('Datastore', () => { datastore.runQuery(q, (err, entities, info) => { assert.ifError(err); - assert.strictEqual(entities.length, 3); - assert.strictEqual(entities[0].name, 'Robb'); - assert.strictEqual(entities[2].name, 'Catelyn'); + assert.strictEqual(entities!.length, 3); + assert.strictEqual(entities![0].name, 'Robb'); + assert.strictEqual(entities![2].name, 'Catelyn'); const secondQ = datastore.createQuery('Character') .hasAncestor(ancestor) .order('appearances') - .start(info.endCursor); + .start(info!.endCursor!); datastore.runQuery(secondQ, (err, secondEntities) => { assert.ifError(err); - assert.strictEqual(secondEntities.length, 3); - assert.strictEqual(secondEntities[0].name, 'Sansa'); - assert.strictEqual(secondEntities[2].name, 'Arya'); + assert.strictEqual(secondEntities!.length, 3); + assert.strictEqual(secondEntities![0].name, 'Sansa'); + assert.strictEqual(secondEntities![2].name, 'Arya'); done(); }); }); @@ -737,14 +737,14 @@ describe('Datastore', () => { const secondQ = datastore.createQuery('Character') .hasAncestor(ancestor) .order('appearances') - .start(info.endCursor); + .start(info!.endCursor!); datastore.runQuery(secondQ, (err, secondEntities) => { assert.ifError(err); - assert.strictEqual(secondEntities.length, 4); - assert.strictEqual(secondEntities[0].name, 'Catelyn'); - assert.strictEqual(secondEntities[3].name, 'Arya'); + assert.strictEqual(secondEntities!.length, 4); + assert.strictEqual(secondEntities![0].name, 'Catelyn'); + assert.strictEqual(secondEntities![3].name, 'Arya'); done(); }); @@ -758,7 +758,7 @@ describe('Datastore', () => { datastore.runQuery(q, (err, entities) => { assert.ifError(err); - assert.strictEqual(entities.length, characters.length - 1); + assert.strictEqual(entities!.length, characters.length - 1); done(); }); }); @@ -886,7 +886,7 @@ describe('Datastore', () => { transaction.rollback(done); return; } - assert(entities.length > 0); + assert(entities!.length > 0); transaction.commit(done); }); }); diff --git a/test/query.ts b/test/query.ts index 7afa84e42..8c72b4036 100644 --- a/test/query.ts +++ b/test/query.ts @@ -285,14 +285,12 @@ describe('Query', () => { describe('run', () => { it('should call the parent instance runQuery correctly', (done) => { - const args = [0, 1, 2]; + const args = [{}, () => {}]; query.scope.runQuery = function() { assert.strictEqual(this, query.scope); assert.strictEqual(arguments[0], query); assert.strictEqual(arguments[1], args[0]); - assert.strictEqual(arguments[2], args[1]); - assert.strictEqual(arguments[3], args[2]); done(); }; diff --git a/test/request.ts b/test/request.ts index 315ac11b4..8f037f394 100644 --- a/test/request.ts +++ b/test/request.ts @@ -23,8 +23,8 @@ import * as proxyquire from 'proxyquire'; import * as sinon from 'sinon'; import * as through from 'through2'; -import {entity} from '../src/entity.js'; -import {Query} from '../src/query.js'; +import {entity, KeyProto} from '../src/entity.js'; +import {Query, QueryProto} from '../src/query.js'; let promisified = false; const fakePfy = Object.assign({}, pfy, { @@ -144,7 +144,7 @@ describe('Request', () => { }); it('should make the correct request', done => { - const keyProto = {}; + const keyProto = {} as KeyProto; sandbox.stub(entity, 'isKeyComplete'); sandbox.stub(entity, 'keyToKeyProto').callsFake(key => { assert.strictEqual(key, INCOMPLETE_KEY); @@ -258,6 +258,7 @@ describe('Request', () => { sandbox.stub(entity, 'keyToKeyProto').callsFake(key_ => { assert.strictEqual(key_, key); done(); + return {} as KeyProto; }); request.createReadStream(key).on('error', done); @@ -391,7 +392,8 @@ describe('Request', () => { ], }; - const expectedResult = entity.formatArray(apiResponse.found)[0]; + // tslint:disable-next-line no-any + const expectedResult = entity.formatArray(apiResponse.found as any)[0]; const apiResponseWithMultiEntities = extend(true, {}, apiResponse); const entities = apiResponseWithMultiEntities.found; @@ -688,6 +690,7 @@ describe('Request', () => { assert.notStrictEqual(query_, query); assert.deepStrictEqual(query_, query); done(); + return {} as QueryProto; }); request.runQueryStream(query).on('error', done).emit('reading'); @@ -695,7 +698,7 @@ describe('Request', () => { it('should make correct request when the stream is ready', done => { const query = {namespace: 'namespace'}; - const queryProto = {}; + const queryProto = {} as QueryProto; sandbox.stub(entity, 'queryToQueryProto').returns(queryProto); @@ -828,7 +831,7 @@ describe('Request', () => { limit: { value: query.limitVal, }, - }; + } as {} as QueryProto; let timesRequestCalled = 0; let startCalled = false; @@ -943,7 +946,7 @@ describe('Request', () => { callback(null, {batch}); }; - sandbox.stub(entity, 'queryToQueryProto').returns({}); + sandbox.stub(entity, 'queryToQueryProto').returns({} as QueryProto); const limitStub = sandbox.stub(FakeQuery.prototype, 'limit'); request.runQueryStream(query) @@ -1061,7 +1064,7 @@ describe('Request', () => { assert.ifError(err); const spy = request.runQueryStream.getCall(0); - assert.deepStrictEqual(spy.args[1], {}); + assert.deepStrictEqual(spy.args[0], {}); done(); }); });