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

Convert EnumSpecIndex into a class #165

Merged
merged 9 commits into from
Aug 2, 2016
3 changes: 2 additions & 1 deletion src/enumerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import {Mark} from 'vega-lite/src/mark';
import {QueryConfig} from './config';
import {checkEncoding} from './constraint/encoding';
import {checkSpec} from './constraint/spec';
import {EnumSpecIndex, SpecQueryModel} from './model';
import {EnumSpecIndex} from './enumspecindex';
import {SpecQueryModel} from './model';
import {Property, ENCODING_PROPERTIES, NESTED_ENCODING_PROPERTIES} from './property';
import {EnumSpec} from './enumspec';
import {Schema} from './schema';
Expand Down
137 changes: 137 additions & 0 deletions src/enumspecindex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import {AggregateOp} from 'vega-lite/src/aggregate';
import {Channel} from 'vega-lite/src/channel';
import {Mark} from 'vega-lite/src/mark';
import {ScaleType} from 'vega-lite/src/scale';
import {TimeUnit} from 'vega-lite/src/timeunit';
import {Type} from 'vega-lite/src/type';

import {EnumSpec} from './enumspec';
import {Property, isEncodingProperty} from './property';
import {Dict, keys} from './util';


export interface EncodingEnumSpecIndex {
/** Enum spec for channel enumeration. */
channel?: EnumSpec<Channel>;

/** Enum spec for aggregate enumeration. */
aggregate?: EnumSpec<AggregateOp>;

/** Enum spec for autoCount enumeration. */
autoCount?: EnumSpec<AggregateOp>;

/** Enum spec for bin enumeration. */
bin?: EnumSpec<boolean>;

/** Enum spec for bin.maxbins enumeration */
maxbin?: EnumSpec<number>;

/** Enum spec for scale enumeration. */
scale?: EnumSpec<boolean>;

/** Enum spec for scale.bandSize enumeration */
scaleBandSize?: EnumSpec<number>;

/** Enum spec for scale.clamp enumeration */
scaleClamp?: EnumSpec<boolean>;

/** Enum spec for scale.domain enumeration */
scaleDomain?: EnumSpec<string | string[] | number[]>;

/** Enum spec for scale.exponent enumeration */
scaleExponent?: EnumSpec<number>;

/** Enum spec for scale.nice enumeration */
scaleNice?: EnumSpec<boolean>;

/** Enum spec for scale.range enumeration */
scaleRange?: EnumSpec<string | string[] | number[]>;

/** Enum spec for scale.round enumeration */
scaleRound?: EnumSpec<boolean>;

/** Enum spec for scale.type enumeration */
scaleType?: EnumSpec<ScaleType>;

/** Enum spec for scale.useRawDomain enumeration */
scaleUseRawDomain?: EnumSpec<boolean>;

/** Enum spec for scale.zero enumeration */
scaleZero?: EnumSpec<boolean>;

/** Enum spec for timeUnit enumeration. */
timeUnit?: EnumSpec<TimeUnit>;

/** Enum spec for field enumeration. */
field?: EnumSpec<string>;

/** Enum spec for type enumeration. */
type?: EnumSpec<Type>;
}

export interface EncodingsEnumSpecIndex {
[index: number]: EncodingEnumSpecIndex;
}

export class EnumSpecIndex {
private _mark: EnumSpec<Mark>;
// TODO: transform

/**
* Dictionary mapping encoding index to an encoding enum spec index.
*/

private _encodings: EncodingsEnumSpecIndex;
private _encodingIndicesByProperty: Dict<number[]>;

constructor() {
this._mark = undefined;
this._encodings = {};
this._encodingIndicesByProperty = {};
}

public setEncodingProperty(index: number, prop: Property, enumSpec: EnumSpec<any>) {
const encodingsIndex = this._encodings;

// Init encoding index and set prop
const encIndex = encodingsIndex[index] = encodingsIndex[index] || {};
encIndex[prop] = enumSpec;

// Initialize indicesByProperty[prop] and add index
const encodingIndicesByProperty = this._encodingIndicesByProperty;
(encodingIndicesByProperty[prop] = encodingIndicesByProperty[prop] || []).push(index);

return this;
}

public hasProperty(prop: Property) {
if (isEncodingProperty(prop)) {
return !!this.encodingIndicesByProperty[prop];
} if (prop === Property.MARK) {
return !!this.mark;
}
/* istanbul ignore next */
throw new Error('Unimplemented for property ' + prop);
}

public isEmpty() {
return !this.mark && keys(this.encodingIndicesByProperty).length === 0;
}

public setMark(mark) {
this._mark = mark;
return this;
}

public get mark() {
return this._mark;
}

public get encodings() {
return this._encodings;
}

public get encodingIndicesByProperty() {
return this._encodingIndicesByProperty;
}
}
6 changes: 3 additions & 3 deletions src/generate.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {ENUMERATOR_INDEX} from '../src/enumerator';

import {QueryConfig, DEFAULT_QUERY_CONFIG} from './config';
import {SpecQueryModel, hasPropertyIndex} from './model';
import {SpecQueryModel} from './model';
import {SpecQuery} from './query/spec';
import {Schema} from './schema';

Expand All @@ -14,8 +14,8 @@ export function generate(specQ: SpecQuery, schema: Schema, opt: QueryConfig = DE

let answerSet = [specM]; // Initialize Answer Set with only the input spec query.
opt.propertyPrecedence.forEach((prop) => {
// If the original specQuery contains enumSpec for this prop type
if (hasPropertyIndex(enumSpecIndex, prop)) {
// If the original specQuery contains enumSpec for this prop
if (enumSpecIndex.hasProperty(prop)) {
// update answerset
const reducer = ENUMERATOR_INDEX[prop](enumSpecIndex, schema, opt);
answerSet = answerSet.reduce(reducer, []);
Expand Down
122 changes: 7 additions & 115 deletions src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,115 +4,20 @@ import {Data} from 'vega-lite/src/data';
import {Encoding} from 'vega-lite/src/encoding';
import {FieldDef} from 'vega-lite/src/fielddef';
import {Mark} from 'vega-lite/src/mark';
import {ScaleType} from 'vega-lite/src/scale';
import {TimeUnit} from 'vega-lite/src/timeunit';
import {Type} from 'vega-lite/src/type';
import {ExtendedUnitSpec} from 'vega-lite/src/spec';



import {QueryConfig} from './config';
import {Property, ENCODING_PROPERTIES, NESTED_ENCODING_PROPERTIES, hasNestedProperty, getNestedEncodingProperty} from './property';
import {EnumSpec, SHORT_ENUM_SPEC, initEnumSpec, isEnumSpec} from './enumspec';
import {isEncodingProperty} from './property';
import {EnumSpecIndex} from './enumspecindex';
import {SpecQuery, isAggregate, stack} from './query/spec';
import {isDimension, isMeasure, EncodingQuery} from './query/encoding';
import {spec as specShorthand} from './query/shorthand';
import {RankingScore} from './ranking/ranking';
import {Schema} from './schema';
import {Dict, duplicate, extend} from './util';

export interface EncodingsEnumSpecIndex {
[index: number]: EncodingEnumSpecIndex;
}

export interface EncodingEnumSpecIndex {
/** Enum spec for channel enumeration. */
channel?: EnumSpec<Channel>;

/** Enum spec for aggregate enumeration. */
aggregate?: EnumSpec<AggregateOp>;

/** Enum spec for autoCount enumeration. */
autoCount?: EnumSpec<AggregateOp>;

/** Enum spec for bin enumeration. */
bin?: EnumSpec<boolean>;

/** Enum spec for bin.maxbins enumeration */
maxbin?: EnumSpec<number>;

/** Enum spec for scale enumeration. */
scale?: EnumSpec<boolean>;

/** Enum spec for scale.bandSize enumeration */
scaleBandSize?: EnumSpec<number>;

/** Enum spec for scale.clamp enumeration */
scaleClamp?: EnumSpec<boolean>;

/** Enum spec for scale.domain enumeration */
scaleDomain?: EnumSpec<string | string[] | number[]>;

/** Enum spec for scale.exponent enumeration */
scaleExponent?: EnumSpec<number>;

/** Enum spec for scale.nice enumeration */
scaleNice?: EnumSpec<boolean>;

/** Enum spec for scale.range enumeration */
scaleRange?: EnumSpec<string | string[] | number[]>;

/** Enum spec for scale.round enumeration */
scaleRound?: EnumSpec<boolean>;

/** Enum spec for scale.type enumeration */
scaleType?: EnumSpec<ScaleType>;

/** Enum spec for scale.useRawDomain enumeration */
scaleUseRawDomain?: EnumSpec<boolean>;

/** Enum spec for scale.zero enumeration */
scaleZero?: EnumSpec<boolean>;

/** Enum spec for timeUnit enumeration. */
timeUnit?: EnumSpec<TimeUnit>;

/** Enum spec for field enumeration. */
field?: EnumSpec<string>;

/** Enum spec for type enumeration. */
type?: EnumSpec<Type>;
}

/**
* Object that stores different types of EnumSpecIndexTuple
*/
export interface EnumSpecIndex {
/** Index tuple for the mark (if mark requires enumeration). */
// TODO: replace with just EnumSpec<Mark>.
mark?: EnumSpec<Mark>;

// TODO: transform

/**
* Dictionary mapping encoding index to an encoding enum spec index.
*/
encodings: EncodingsEnumSpecIndex;

encodingIndicesByProperty: Dict<number[]>;
}

export function hasPropertyIndex(enumSpecIndex: EnumSpecIndex, prop: Property) {
if (isEncodingProperty(prop)) {
return !!enumSpecIndex.encodingIndicesByProperty[prop];
} if (prop === Property.MARK) {
return !!enumSpecIndex.mark;
}
/* istanbul ignore next */
throw new Error('Unimplemented for property ' + prop);
}

export function getDefaultName(prop: Property) {
switch (prop) {
case Property.MARK:
Expand Down Expand Up @@ -216,18 +121,6 @@ export function getDefaultEnumValues(prop: Property, schema: Schema, opt: QueryC
throw new Error('No default enumValues for ' + prop);
}

function setEnumSpecIndex(enumSpecIndex: EnumSpecIndex, index: number, prop: Property, enumSpec: EnumSpec<any>) {
const encodingsIndex = enumSpecIndex.encodings;

// Init encoding index and set prop
const encIndex = encodingsIndex[index] = encodingsIndex[index] || {};
encIndex[prop] = enumSpec;

// Initialize indicesByProperty[prop] and add index
const encodingIndicesByProperty = enumSpecIndex.encodingIndicesByProperty;
(encodingIndicesByProperty[prop] = encodingIndicesByProperty[prop] || []).push(index);
}

/**
* Internal class for specQuery that provides helper for the enumeration process.
*/
Expand All @@ -252,13 +145,12 @@ export class SpecQueryModel {
* @return a SpecQueryModel that wraps the specQuery and the enumSpecIndex.
*/
public static build(specQ: SpecQuery, schema: Schema, opt: QueryConfig): SpecQueryModel {
let enumSpecIndex: EnumSpecIndex = {encodings: {}, encodingIndicesByProperty: {}};

let enumSpecIndex: EnumSpecIndex = new EnumSpecIndex();
// mark
if (isEnumSpec(specQ.mark)) {
const name = getDefaultName(Property.MARK);
specQ.mark = initEnumSpec(specQ.mark, name, opt.marks);
enumSpecIndex.mark = specQ.mark;
enumSpecIndex.setMark(specQ.mark);
}

// TODO: transform
Expand Down Expand Up @@ -286,7 +178,7 @@ export class SpecQueryModel {
const enumSpec = encQ[prop] = initEnumSpec(encQ[prop], defaultEnumSpecName, defaultEnumValues);

// Add index of the encoding mapping to the property's enum spec index.
setEnumSpecIndex(enumSpecIndex, index, prop, enumSpec);
enumSpecIndex.setEncodingProperty(index, prop, enumSpec);
}
});

Expand All @@ -303,7 +195,7 @@ export class SpecQueryModel {
const enumSpec = propObj[child] = initEnumSpec(propObj[child], defaultEnumSpecName, defaultEnumValues);

// Add index of the encoding mapping to the property's enum spec index.
setEnumSpecIndex(enumSpecIndex, index, prop, enumSpec);
enumSpecIndex.setEncodingProperty(index, prop, enumSpec);
}
}
});
Expand All @@ -328,8 +220,8 @@ export class SpecQueryModel {
const index = specQ.encodings.length - 1;

// Add index of the encoding mapping to the property's enum spec index.
setEnumSpecIndex(enumSpecIndex, index, Property.CHANNEL, countEncQ.channel);
setEnumSpecIndex(enumSpecIndex, index, Property.AUTOCOUNT, countEncQ.autoCount);
enumSpecIndex.setEncodingProperty(index, Property.CHANNEL, countEncQ.channel);
enumSpecIndex.setEncodingProperty(index, Property.AUTOCOUNT, countEncQ.autoCount);
}

return new SpecQueryModel(specQ, enumSpecIndex, schema, opt, {});
Expand Down
Loading