Skip to content

Commit

Permalink
Restructure enumSpecIndex for encodings (#161)
Browse files Browse the repository at this point in the history
- Add `encodingIndicesByProperty` and `encodings`
- Remove each properties from the top-level of `enumSpecIndex` as it's getting too messy.
- Bump to 0.3.1
  • Loading branch information
kanitw authored and FelixCodes committed Aug 1, 2016
1 parent b284747 commit 46c0f4e
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 113 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "compassql",
"version": "0.3.0",
"version": "0.3.1",
"description": "CompassQL visualization query language",
"main": "compassql.js",
"directories": {
Expand Down
17 changes: 9 additions & 8 deletions src/constraint/encoding.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import {Channel, getSupportedRole} from 'vega-lite/src/channel';
import {ScaleType} from 'vega-lite/src/scale';
import {Type} from 'vega-lite/src/type';

import {AbstractConstraint, AbstractConstraintModel} from './base';

import {QueryConfig} from '../config';
import {EnumSpecIndexTuple, SpecQueryModel} from '../model';
import {SpecQueryModel} from '../model';
import {getNestedEncodingProperty, Property} from '../property';
import {scaleType, EncodingQuery, isDimension, isMeasure, ScaleQuery} from '../query/encoding';
import {isEnumSpec} from '../enumspec';
import {isEnumSpec, EnumSpec} from '../enumspec';
import {PrimitiveType, Schema} from '../schema';
import {contains, every} from '../util';
import {ScaleType} from 'vega-lite/src/scale';

import {AbstractConstraint, AbstractConstraintModel} from './base';
import {scaleType, EncodingQuery, isDimension, isMeasure, ScaleQuery} from '../query/encoding';

/**
* Collection of constraints for a single encoding mapping.
Expand Down Expand Up @@ -263,12 +264,12 @@ export const ENCODING_CONSTRAINTS_BY_PROPERTY: {[prop: string]: EncodingConstrai
/**
* Check all encoding constraints for a particular property and index tuple
*/
export function checkEncoding(prop: Property, indexTuple: EnumSpecIndexTuple<any>,
export function checkEncoding(prop: Property, enumSpec: EnumSpec<any>, index: number,
specM: SpecQueryModel, schema: Schema, opt: QueryConfig): string {

// Check encoding constraint
const encodingConstraints = ENCODING_CONSTRAINTS_BY_PROPERTY[prop] || [];
const encQ = specM.getEncodingQueryByIndex(indexTuple.index);
const encQ = specM.getEncodingQueryByIndex(index);

for (let i = 0; i < encodingConstraints.length; i++) {
const c = encodingConstraints[i];
Expand All @@ -281,7 +282,7 @@ export function checkEncoding(prop: Property, indexTuple: EnumSpecIndexTuple<any
let violatedConstraint = '(enc) ' + c.name();
/* istanbul ignore if */
if (opt.verbose) {
console.log(violatedConstraint + ' failed with ' + specM.toShorthand() + ' for ' + indexTuple.enumSpec.name);
console.log(violatedConstraint + ' failed with ' + specM.toShorthand() + ' for ' + enumSpec.name);
}
return violatedConstraint;
}
Expand Down
15 changes: 8 additions & 7 deletions src/constraint/spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ import {Type} from 'vega-lite/src/type';
import {AbstractConstraint, AbstractConstraintModel} from './base';

import {QueryConfig} from '../config';
import {SpecQueryModel, EnumSpecIndexTuple} from '../model';
import {isEnumSpec, EnumSpec} from '../enumspec';
import {SpecQueryModel} from '../model';
import {getNestedEncodingProperty, Property, isEncodingProperty} from '../property';
import {Schema} from '../schema';
import {isEnumSpec} from '../enumspec';
import {scaleType, EncodingQuery, isMeasure, ScaleQuery} from '../query/encoding';
import {contains, every, some} from '../util';

import {scaleType, EncodingQuery, isMeasure, ScaleQuery} from '../query/encoding';

export interface SpecConstraintChecker {
(specM: SpecQueryModel, schema: Schema, opt: QueryConfig): boolean;
}
Expand Down Expand Up @@ -171,8 +172,8 @@ export const SPEC_CONSTRAINTS: SpecConstraintModel[] = [
throw new Error('Unsupported Type');
});
} else {
const neverHaveAutoCount = every(specM.enumSpecIndex.autoCount, (indexTuple: EnumSpecIndexTuple<boolean>) => {
return !isEnumSpec(specM.getEncodingQueryByIndex(indexTuple.index).autoCount);
const neverHaveAutoCount = every(specM.enumSpecIndex.encodingIndicesByProperty['autoCount'], (index: number) => {
return !isEnumSpec(specM.getEncodingQueryByIndex(index).autoCount);
});
if (neverHaveAutoCount) {
// If the query surely does not have autoCount
Expand Down Expand Up @@ -582,7 +583,7 @@ export const SPEC_CONSTRAINTS_BY_PROPERTY: {[prop: string]: SpecConstraintModel[
/**
* Check all encoding constraints for a particular property and index tuple
*/
export function checkSpec(prop: Property, indexTuple: EnumSpecIndexTuple<any>,
export function checkSpec(prop: Property, enumSpec: EnumSpec<any>,
specM: SpecQueryModel, schema: Schema, opt: QueryConfig): string {

// Check encoding constraint
Expand All @@ -599,7 +600,7 @@ export function checkSpec(prop: Property, indexTuple: EnumSpecIndexTuple<any>,
let violatedConstraint = '(spec) ' + c.name();
/* istanbul ignore if */
if (opt.verbose) {
console.log(violatedConstraint + ' failed with ' + specM.toShorthand() + ' for ' + indexTuple.enumSpec.name);
console.log(violatedConstraint + ' failed with ' + specM.toShorthand() + ' for ' + enumSpec.name);
}
return violatedConstraint;
}
Expand Down
23 changes: 12 additions & 11 deletions src/enumerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {Mark} from 'vega-lite/src/mark';
import {QueryConfig} from './config';
import {checkEncoding} from './constraint/encoding';
import {checkSpec} from './constraint/spec';
import {EnumSpecIndex, EnumSpecIndexTuple, SpecQueryModel} from './model';
import {EnumSpecIndex, SpecQueryModel} from './model';
import {Property, ENCODING_PROPERTIES, NESTED_ENCODING_PROPERTIES} from './property';
import {EnumSpec} from './enumspec';
import {Schema} from './schema';
Expand Down Expand Up @@ -60,17 +60,18 @@ export function EncodingPropertyGeneratorFactory(prop: Property): EnumeratorFact

return (answerSet: SpecQueryModel[], specM: SpecQueryModel) => {
// index of encoding mappings that require enumeration
const indexTuples: EnumSpecIndexTuple<any>[] = enumSpecIndex[prop];
const indices = enumSpecIndex.encodingIndicesByProperty[prop];

function enumerate(jobIndex: number) {
if (jobIndex === indexTuples.length) {
if (jobIndex === indices.length) {
// emit and terminate
answerSet.push(specM.duplicate());
return;
}
const indexTuple = indexTuples[jobIndex];
const encQ = specM.getEncodingQueryByIndex(indexTuple.index);
const propEnumSpec = specM.getEncodingProperty(indexTuple.index, prop);
const index = indices[jobIndex];
const enumSpec: EnumSpec<any> = enumSpecIndex.encodings[index][prop];
const encQ = specM.getEncodingQueryByIndex(index);
const propEnumSpec = specM.getEncodingProperty(index, prop);

if (
// TODO: encQ.exclude
Expand All @@ -84,21 +85,21 @@ export function EncodingPropertyGeneratorFactory(prop: Property): EnumeratorFact
) { // TODO: encQ.excluded
enumerate(jobIndex + 1);
} else {
propEnumSpec.values.forEach((propVal) => {
enumSpec.values.forEach((propVal) => {
if (propVal === null) {
// our duplicate() method use JSON.stringify, parse and thus can accidentally
// convert undefined in an array into null
propVal = undefined;
}
specM.setEncodingProperty(indexTuple.index, prop, propVal, indexTuple.enumSpec);
specM.setEncodingProperty(index, prop, propVal, enumSpec);

// Check encoding constraint
const violatedEncodingConstraint = checkEncoding(prop, indexTuple, specM, schema, opt);
const violatedEncodingConstraint = checkEncoding(prop, enumSpec, index, specM, schema, opt);
if (violatedEncodingConstraint) {
return; // do not keep searching
}
// Check spec constraint
const violatedSpecConstraint = checkSpec(prop, indexTuple, specM, schema, opt);
const violatedSpecConstraint = checkSpec(prop, enumSpec, specM, schema, opt);
if (violatedSpecConstraint) {
return; // do not keep searching
}
Expand All @@ -107,7 +108,7 @@ export function EncodingPropertyGeneratorFactory(prop: Property): EnumeratorFact
});

// Reset to avoid side effect
specM.resetEncodingProperty(indexTuple.index, prop, indexTuple.enumSpec);
specM.resetEncodingProperty(index, prop, enumSpec);
}
}

Expand Down
6 changes: 5 additions & 1 deletion src/enumspec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ export interface EnumSpec<T> {
values?: T[];
}

export interface ExtendedEnumSpec<T> extends EnumSpec<T> {
[prop: string]: any;
}

export function isEnumSpec(prop: any) {
return prop === SHORT_ENUM_SPEC || (prop !== undefined && (!!prop.values || !!prop.name) && !isArray(prop));
}

export function initEnumSpec(prop: any, defaultName: string, defaultEnumValues: any[]): EnumSpec<any> & any {
export function initEnumSpec(prop: any, defaultName: string, defaultEnumValues: any[]): ExtendedEnumSpec<any> {
return extend({}, {
name: defaultName,
values: defaultEnumValues
Expand Down
4 changes: 2 additions & 2 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} from './model';
import {SpecQueryModel, hasPropertyIndex} from './model';
import {SpecQuery} from './query/spec';
import {Schema} from './schema';

Expand All @@ -15,7 +15,7 @@ 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 (enumSpecIndex[prop]) {
if (hasPropertyIndex(enumSpecIndex, prop)) {
// update answerset
const reducer = ENUMERATOR_INDEX[prop](enumSpecIndex, schema, opt);
answerSet = answerSet.reduce(reducer, []);
Expand Down
Loading

0 comments on commit 46c0f4e

Please sign in to comment.