import { isString } from 'datalib/src/util' ; import { ExtendedChannel } from 'vega-lite/build/src/channel' ; import { Data } from 'vega-lite/build/src/data' ; import { Mark } from 'vega-lite/build/src/mark' ; import { FacetedUnitSpec , TopLevel } from 'vega-lite/build/src/spec' ; import { StackOffset , StackProperties } from 'vega-lite/build/src/stack' ; import * as TYPE from 'vega-lite/build/src/type' ; import { QueryConfig } from './config' ; import { getGroupByKey } from './nest' ; import { ENCODING_NESTED_PROPS , ENCODING_TOPLEVEL_PROPS , isEncodingNestedParent , isEncodingNestedProp , Property , } from './property' ; import { AutoCountQuery , EncodingQuery , isAutoCountQuery , isDisabledAutoCountQuery , isFieldQuery , toEncoding , } from './query/encoding' ; import { ExtendedGroupBy , parseGroupBy } from './query/groupby' ; import { spec as specShorthand } from './query/shorthand' ; import { getStackChannel , getStackOffset , getVlStack , isAggregate , SpecQuery } from './query/spec' ; import { RankingScore } from './ranking/ranking' ; import { ResultTree } from './result' ; import { Schema } from './schema' ; import { Dict , duplicate , extend } from './util' ; import { getDefaultEnumValues , getDefaultName , initWildcard , isWildcard , SHORT_WILDCARD , Wildcard } from './wildcard' ; import { WildcardIndex } from './wildcardindex' ; /**
 * Internal class for specQuery that provides helper for the enumeration process.
 */ export class SpecQueryModel { private _spec : SpecQuery ; /** channel => EncodingQuery */ private _channelFieldCount : Dict < number > ; private _wildcardIndex : WildcardIndex ; private _assignedWildcardIndex : Dict < any > ; private _schema : Schema ; private _opt : QueryConfig ; private _rankingScore : Dict < RankingScore > = { } ; return public static build ( specQ , schema , opt ) { const wildcardIndex = new WildcardIndex ( ) ; if ( isWildcard ( specQ . mark ) ) { const name = getDefaultName ( Property . MARK ) ; specQ . mark = initWildcard ( specQ . mark , name , opt . enum . mark ) ; wildcardIndex . setMark ( specQ . mark ) ; } specQ . encodings . forEach ( ( encQ , index ) => { if ( isAutoCountQuery ( encQ ) ) { console . warn ( 'A field with autoCount should not be included as autoCount meant to be an internal object.' ) ; encQ . type = TYPE . QUANTITATIVE ; } if ( isFieldQuery ( encQ ) && encQ . type === undefined ) { encQ . type = SHORT_WILDCARD ; } ENCODING_TOPLEVEL_PROPS . forEach ( ( prop ) => { if ( isWildcard ( encQ [ prop ] ) ) { const defaultWildcardName = getDefaultName ( prop ) + index ; const defaultEnumValues = getDefaultEnumValues ( prop , schema , opt ) ; const wildcard = ( encQ [ prop ] = initWildcard ( encQ [ prop ] , defaultWildcardName , defaultEnumValues ) ) ; wildcardIndex . setEncodingProperty ( index , prop , wildcard ) ; } } ) ; ENCODING_NESTED_PROPS . forEach ( ( prop ) => { const propObj = encQ [ prop . parent ] ; if ( propObj ) { const child = prop . child ; if ( isWildcard ( propObj [ child ] ) ) { const defaultWildcardName = getDefaultName ( prop ) + index ; const defaultEnumValues = getDefaultEnumValues ( prop , schema , opt ) ; const wildcard = ( propObj [ child ] = initWildcard ( propObj [ child ] , defaultWildcardName , defaultEnumValues ) ) ; wildcardIndex . setEncodingProperty ( index , prop , wildcard ) ; } } } ) ; } ) ; if ( opt . autoAddCount ) { const channel = { name : getDefaultName ( Property . CHANNEL ) + specQ . encodings . length , enum : getDefaultEnumValues ( Property . CHANNEL , schema , opt ) , } ; const autoCount = { name : getDefaultName ( Property . AUTOCOUNT ) + specQ . encodings . length , enum : [ false , true ] , } ; const countEncQ = { channel , autoCount , type : TYPE . QUANTITATIVE , } ; specQ . encodings . push ( countEncQ ) ; const index = specQ . encodings . length - 1 ; wildcardIndex . setEncodingProperty ( index , Property . CHANNEL , channel ) ; wildcardIndex . setEncodingProperty ( index , Property . AUTOCOUNT , autoCount ) ; } return new SpecQueryModel ( specQ , wildcardIndex , schema , opt , { } ) ; } constructor ( spec , wildcardIndex , schema , opt , wildcardAssignment ) { this . _spec = spec ; this . _channelFieldCount = spec . encodings . reduce ( ( m , encQ ) => { if ( ! isWildcard ( encQ . channel ) && ( ! isAutoCountQuery ( encQ ) || encQ . autoCount !== false ) ) { m [ `${ encQ . channel }` ] = 1 ; } return m ; } , { } as Dict < number > ) ; this . _wildcardIndex = wildcardIndex ; this . _assignedWildcardIndex = wildcardAssignment ; this . _opt = opt ; this . _schema = schema ; } public get wildcardIndex ( ) { return this . _wildcardIndex ; } public get schema ( ) { return this . _schema ; } public get specQuery ( ) { return this . _spec ; } public duplicate ( ) { return new SpecQueryModel ( duplicate ( this . _spec ) , this . _wildcardIndex , this . _schema , this . _opt , duplicate ( this . _assignedWildcardIndex ) ) ; } public setMark ( mark ) { const name = this . _wildcardIndex . mark . name ; this . _assignedWildcardIndex [ name ] = this . _spec . mark = mark ; } public resetMark ( ) { const wildcard = ( this . _spec . mark = this . _wildcardIndex . mark ) ; delete this . _assignedWildcardIndex [ wildcard . name ] ; } public getMark ( ) { return this . _spec . mark ; } public getEncodingProperty ( index , prop ) { const encQ = this . _spec . encodings [ index ] ; if ( isEncodingNestedProp ( prop ) ) { return encQ [ prop . parent ] [ prop . child ] ; } return encQ [ prop ] ; } public setEncodingProperty ( index , prop , value , wildcard ) { const encQ = this . _spec . encodings [ index ] ; if ( prop === Property . CHANNEL && encQ . channel && ! isWildcard ( encQ . channel ) ) { this . _channelFieldCount [ encQ . channel as ExtendedChannel ] -- ; } if ( isEncodingNestedProp ( prop ) ) { encQ [ prop . parent ] [ prop . child ] = value ; } else if ( isEncodingNestedParent ( prop ) && value === true ) { encQ [ prop ] = extend ( { } , encQ [ prop ] , { enum : undefined , name : undefined } ) ; } else { encQ [ prop ] = value ; } this . _assignedWildcardIndex [ wildcard . name ] = value ; if ( prop === Property . CHANNEL ) { this . _channelFieldCount [ value ] = ( this . _channelFieldCount [ value ] || 0 ) + 1 ; } } public resetEncodingProperty ( index , prop , wildcard ) { const encQ = this . _spec . encodings [ index ] ; if ( prop === Property . CHANNEL ) { this . _channelFieldCount [ encQ . channel as ExtendedChannel ] -- ; } if ( isEncodingNestedProp ( prop ) ) { encQ [ prop . parent ] [ prop . child ] = wildcard ; } else { encQ [ prop ] = wildcard ; } delete this . _assignedWildcardIndex [ wildcard . name ] ; } public channelUsed ( channel ) { return this . _channelFieldCount [ channel ] > 0 ; } public channelEncodingField ( channel ) { const encodingQuery = this . getEncodingQueryByChannel ( channel ) ; return isFieldQuery ( encodingQuery ) ; } public getEncodings ( ) { return this . _spec . encodings . filter ( ( encQ ) => ! isDisabledAutoCountQuery ( encQ ) ) ; } public getEncodingQueryByChannel ( channel ) { for ( const specEncoding of this . _spec . encodings ) { if ( specEncoding . channel === channel ) { return specEncoding ; } } return undefined ; } public getEncodingQueryByIndex ( i ) { return this . _spec . encodings [ i ] ; } public isAggregate ( ) { return isAggregate ( this . _spec ) ; } return public getVlStack ( ) { return getVlStack ( this . _spec ) ; } return public getStackOffset ( ) { return getStackOffset ( this . _spec ) ; } return public getStackChannel ( ) { return getStackChannel ( this . _spec ) ; } public toShorthand ( groupBy ? ) { if ( groupBy ) { if ( isString ( groupBy ) ) { return getGroupByKey ( this . specQuery , groupBy ) ; } const parsedGroupBy = parseGroupBy ( groupBy ) ; return specShorthand ( this . _spec , parsedGroupBy . include , parsedGroupBy . replacer ) ; } return specShorthand ( this . _spec ) ; } return public toSpec ( data ? ) { if ( isWildcard ( this . _spec . mark ) ) return null ; const spec = { } ; data = data || this . _spec . data ; if ( data ) { spec . data = data ; } if ( this . _spec . transform ) { spec . transform = this . _spec . transform ; } spec . mark = this . _spec . mark as Mark ; spec . encoding = toEncoding ( this . specQuery . encodings , { schema : this . _schema , wildcardMode : 'null' } ) ; if ( this . _spec . width ) { spec . width = this . _spec . width ; } if ( this . _spec . height ) { spec . height = this . _spec . height ; } if ( this . _spec . background ) { spec . background = this . _spec . background ; } if ( this . _spec . padding ) { spec . padding = this . _spec . padding ; } if ( this . _spec . title ) { spec . title = this . _spec . title ; } if ( spec . encoding === null ) { return null ; } if ( this . _spec . config || this . _opt . defaultSpecConfig ) spec . config = extend ( { } , this . _opt . defaultSpecConfig , this . _spec . config ) ; return spec ; } public getRankingScore ( rankingName ) { return this . _rankingScore [ rankingName ] ; } public setRankingScore ( rankingName , score ) { this . _rankingScore [ rankingName ] = score ; } } export type SpecQueryModelGroup = ResultTree < SpecQueryModel > ;