import { CompoundPredicate } from './CompoundPredicate' import { IncludesPredicate } from './IncludesPredicate' import { AllPredicateCompoundOperators, PredicateCompoundOperator, PredicateInterface, PredicateOperator, SureValue, PredicateJsonForm, AllPredicateOperators, RawPredicateInArrayForm, SureValueNonObjectTypesAsStrings, StringKey, PredicateTarget, } from './Interface' import { NotPredicate } from './NotPredicate' import { Predicate } from './Predicate' export function predicateFromArguments( keypath: StringKey | undefined, operator: PredicateOperator, value: SureValue | PredicateJsonForm, ): PredicateInterface { if (AllPredicateCompoundOperators.includes(operator as PredicateCompoundOperator)) { return compoundPredicateFromArguments(operator, value as unknown as PredicateJsonForm[]) } else if (operator === 'not') { return new NotPredicate(predicateFromJson(value as PredicateJsonForm)) } else if (operator === 'includes' && keypath) { if (isSureValue(value)) { return new Predicate(keypath, operator, value) } else { return new IncludesPredicate(keypath, predicateFromJson(value as PredicateJsonForm)) } } else if (keypath) { return new Predicate(keypath, operator, value as SureValue) } throw Error('Invalid predicate arguments') } export function compoundPredicateFromArguments( operator: PredicateOperator, value: PredicateJsonForm[], ): PredicateInterface { const subPredicates = value.map((jsonPredicate) => { return predicateFromJson(jsonPredicate) }) return new CompoundPredicate(operator as PredicateCompoundOperator, subPredicates) } export function notPredicateFromArguments(value: PredicateJsonForm): PredicateInterface { const subPredicate = predicateFromJson(value) return new NotPredicate(subPredicate) } export function includesPredicateFromArguments( keypath: StringKey, value: PredicateJsonForm, ): PredicateInterface { const subPredicate = predicateFromJson(value) return new IncludesPredicate(keypath, subPredicate) } export function predicateFromJson(values: PredicateJsonForm): PredicateInterface { if (Array.isArray(values)) { throw Error('Invalid predicateFromJson value') } return predicateFromArguments( values.keypath as StringKey, values.operator, isValuePredicateInArrayForm(values.value) ? predicateDSLArrayToJsonPredicate(values.value) : (values.value as PredicateJsonForm), ) } export function predicateFromDSLString(dsl: string): PredicateInterface { try { const components = JSON.parse(dsl.substring(1, dsl.length)) as string[] components.shift() const predicateJson = predicateDSLArrayToJsonPredicate(components as RawPredicateInArrayForm) return predicateFromJson(predicateJson) } catch (e) { throw Error(`Invalid smart view syntax ${JSON.stringify(e)}`) } } function isValuePredicateInArrayForm( value: SureValue | PredicateJsonForm | PredicateJsonForm[] | RawPredicateInArrayForm, ): value is RawPredicateInArrayForm { return Array.isArray(value) && AllPredicateOperators.includes(value[1] as PredicateOperator) } function isSureValue(value: unknown): value is SureValue { if (SureValueNonObjectTypesAsStrings.includes(typeof value)) { return true } if (Array.isArray(value)) { return !isValuePredicateInArrayForm(value) } return false } function predicateDSLArrayToJsonPredicate(predicateArray: RawPredicateInArrayForm): PredicateJsonForm { const predicateValue = predicateArray[2] as | SureValue | SureValue[] | RawPredicateInArrayForm | RawPredicateInArrayForm[] let resolvedPredicateValue: PredicateJsonForm | SureValue | PredicateJsonForm[] if (Array.isArray(predicateValue)) { const level1CondensedValue = predicateValue as SureValue[] | RawPredicateInArrayForm | RawPredicateInArrayForm[] if (Array.isArray(level1CondensedValue[0])) { const level2CondensedValue = level1CondensedValue as RawPredicateInArrayForm[] resolvedPredicateValue = level2CondensedValue.map((subPredicate) => predicateDSLArrayToJsonPredicate(subPredicate), ) } else if (isValuePredicateInArrayForm(predicateValue[1])) { const level2CondensedValue = level1CondensedValue as RawPredicateInArrayForm resolvedPredicateValue = predicateDSLArrayToJsonPredicate(level2CondensedValue) } else { const level2CondensedValue = predicateValue as SureValue resolvedPredicateValue = level2CondensedValue } } else { const level1CondensedValue = predicateValue as SureValue resolvedPredicateValue = level1CondensedValue } return { keypath: predicateArray[0], operator: predicateArray[1] as PredicateOperator, value: resolvedPredicateValue, } }