Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: sprinkle some types about #291

Merged
merged 2 commits into from
Jan 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down
131 changes: 88 additions & 43 deletions src/entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
}
Expand Down Expand Up @@ -69,7 +74,7 @@ export namespace entity {
* @param {*} value
* @returns {boolean}
*/
export function isDsDouble(value) {
export function isDsDouble(value?: {}) {
return value instanceof entity.Double;
}

Expand Down Expand Up @@ -102,7 +107,7 @@ export namespace entity {
* @param {*} value
* @returns {boolean}
*/
export function isDsInt(value) {
export function isDsInt(value?: {}) {
return value instanceof entity.Int;
}

Expand Down Expand Up @@ -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<string|number>;
}

/**
* Build a Datastore Key object.
*
Expand All @@ -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<string|number>;

constructor(options) {
constructor(options: KeyOptions) {
/**
* @name Key#namespace
* @type {string}
Expand All @@ -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);
Expand Down Expand Up @@ -229,7 +239,7 @@ export namespace entity {
* @param {*} value
* @returns {boolean}
*/
export function isDsKey(value) {
export function isDsKey(value?: {}) {
return value instanceof entity.Key;
}

Expand All @@ -256,8 +266,8 @@ export namespace entity {
* });
* // <Buffer 68 65 6c 6c 6f>
*/
export function decodeValueProto(valueProto) {
const valueType = valueProto.valueType;
export function decodeValueProto(valueProto: ValueProto) {
const valueType = valueProto.valueType!;
const value = valueProto[valueType];

switch (valueType) {
Expand Down Expand Up @@ -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;
Expand All @@ -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 {
Expand All @@ -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;
}

Expand All @@ -369,7 +379,7 @@ export namespace entity {
return valueProto;
}

if (is.array(value)) {
if (Array.isArray(value)) {
valueProto.arrayValue = {
values: value.map(entity.encodeValue),
};
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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) {
Expand All @@ -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('.');

Expand Down Expand Up @@ -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])) {
Expand All @@ -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
Expand Down Expand Up @@ -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;
});
}
Expand All @@ -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);
}

Expand All @@ -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: [],
Expand All @@ -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);
Expand Down Expand Up @@ -683,15 +696,15 @@ export namespace entity {
* // ]
* // }
*/
export function keyToKeyProto(key) {
export function keyToKeyProto(key: Key): KeyProto {
if (is.undefined(key.kind)) {
throw new InvalidKeyError({
code: 'MISSING_KIND',
});
}

// tslint:disable-next-line no-any
const keyProto: any = {
const keyProto: KeyProto = {
path: [],
};

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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',
Expand All @@ -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,
Expand Down Expand Up @@ -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;
}
Loading