import { parseGeoDistance , parseGeoPoint , } from '@terascope/utils' ; import { GeoPoint , xLuceneFieldType , xLuceneTypeConfig , } from '@terascope/types' ; import * as i from './interfaces' ; import * as utils from './utils' ; const inferredFieldTypes = Object . freeze ( { [ xLuceneFieldType . String ] : true , } ) ; export function makeContext ( arg ) { let typeConfig ; ( { typeConfig = { } } = arg ) ; if ( ! typeConfig ) { throw new Error ( 'xLucene Parser given invalid context' ) ; } function validateScopedChars ( chars ) { chars . forEach ( ( char , ind ) => { if ( char === '.' && chars [ ind + 1 ] === '.' ) { throw new Error ( `Invalid scoped variable "@${ chars . join ( '' ) }", char "." cannot be next to another "." char` ) ; } } ) ; } /**
    * Propagate the default field on a field group expression
    */ function propagateDefaultField ( node , field ) { if ( ! node ) return ; if ( utils . isRange ( node ) ) { node . field ??= field ; const fieldType = getFieldType ( node . field ) ; if ( fieldType ) node . field_type = fieldType ; coerceTermType ( node . left , node . field ) ; if ( node . right ) coerceTermType ( node . right , node . field ) ; return ; } if ( utils . isTermType ( node ) ) { node . field ??= field ; coerceTermType ( node , node . field ) ; return ; } if ( utils . isNegation ( node ) ) { propagateDefaultField ( node . node , field ) ; return ; } if ( utils . isGroupLike ( node ) ) { for ( const conj of node . flow ) { propagateDefaultField ( conj , field ) ; } return ; } if ( utils . isConjunction ( node ) ) { for ( const conj of node . nodes ) { propagateDefaultField ( conj , field ) ; } } } function getFieldType ( field ) { if ( ! field ) return ; return typeConfig [ field ] ; } function isInferredTermType ( field ) { const fieldType = getFieldType ( field ) ; if ( ! fieldType ) return false ; return inferredFieldTypes [ fieldType ] === true ; } function parseInferredTermType ( field , value ) { const fieldType = getFieldType ( field ) ; const term = { type : i . NodeType . Term , field_type : fieldType , } ; if ( fieldType === xLuceneFieldType . String ) { term . quoted = false ; term . value = { type : 'value' , value : String ( value ) , } ; return term ; } utils . logger . warn ( `Unsupported field inferred field type ${ fieldType } for field ${ field }` ) ; term . value = { type : 'value' , value } ; return term ; } function coerceTermType ( node , _field ? ) { if ( ! node ) return ; const field = node . field || _field ; if ( ! field ) return ; let fieldType = getFieldType ( field ) ; if ( fieldType === xLuceneFieldType . AnalyzedString ) { node . analyzed = true ; } if ( ! node . analyzed && utils . isTermType ( node ) && ! typeConfig [ field ] && field . includes ( '.' ) ) { const parentField = field . split ( '.' ) . slice ( 0 , - 1 ) [ 0 ] ; const parentType = typeConfig [ parentField ] ; if ( parentType && parentType !== xLuceneFieldType . Object ) { fieldType = parentType ; node . analyzed = true ; } } if ( fieldType && node . value ?. type === 'value' ) { _coerceTermValue ( node , field , fieldType ) ; } if ( fieldType ) node . field_type = fieldType ; } function _coerceTermValue ( node , field , fieldType ) { const value = node . value . value as any ; utils . logger . trace ( `coercing field "${ field }":${ value } type of ${ node . field_type } to ${ fieldType }` ) ; if ( node . type === i . NodeType . Term && fieldType === xLuceneFieldType . IPRange ) { Object . assign ( node , utils . createIPRangeFromTerm ( node , value ) ) ; return ; } if ( node . field_type !== fieldType ) { const coerceFn = utils . makeCoerceFn ( fieldType ) ; if ( fieldType === xLuceneFieldType . String ) { node . quoted ??= false ; node . restricted = false ; } else { if ( 'quoted' in node ) delete node . quoted ; if ( 'restricted' in node ) delete node . restricted ; } node . value = { type : 'value' , value : coerceFn ( value ) , } ; } } function throwOnOldGeoUsage ( term , field ) { function formatPoint ( point ) { return `"${ point . lat },${ point . lon }"` ; } if ( term . type === 'geo-bounding-box' ) { const example = `${ field }:geoBox(bottom_right:${ formatPoint ( term . bottom_right ) }, top_left:${ formatPoint ( term . top_left ) })` ; throw new Error ( `Invalid geo bounding box syntax, please use "${ example }" syntax instead` ) ; } const example = `${ field }:geoDistance(point:${ formatPoint ( term as any ) }, distance:${ term . distance })` ; throw new Error ( `Invalid geo distance syntax, please use "${ example }" syntax instead` ) ; } return { logger : utils . logger , parseGeoPoint , parseGeoDistance , coerceTermType , parseInferredTermType , isInferredTermType , propagateDefaultField , getFieldType , throwOnOldGeoUsage , validateScopedChars } ; }