@Override
 public Query apply(Function parent, Function inner, Context context) throws IOException {
   FunctionLiteralPair outerPair = new FunctionLiteralPair(parent);
   if (!outerPair.isValid()) {
     return null;
   }
   Query query = getQuery(inner, context);
   if (query == null) return null;
   Boolean negate = !(Boolean) outerPair.input().value();
   if (negate) {
     BooleanQuery booleanQuery = new BooleanQuery();
     booleanQuery.add(query, BooleanClause.Occur.MUST_NOT);
     return booleanQuery;
   } else {
     return query;
   }
 }
      /**
       * @param parent the outer function. E.g. in the case of
       *     <pre>where distance(p1, POINT (10 20)) > 20</pre>
       *     this would be
       *     <pre>gt( \<inner function\>,  20)</pre>
       *
       * @param inner has to be the distance function
       */
      @Override
      public Query apply(Function parent, Function inner, Context context) {
        assert inner.info().ident().name().equals(DistanceFunction.NAME);

        RefLiteralPair distanceRefLiteral = new RefLiteralPair(inner);
        if (!distanceRefLiteral.isValid()) {
          // can't use distance filter without literal, fallback to genericFunction
          return null;
        }
        FunctionLiteralPair functionLiteralPair = new FunctionLiteralPair(parent);
        if (!functionLiteralPair.isValid()) {
          // must be something like eq(distance(..), non-literal) - fallback to genericFunction
          return null;
        }
        Double distance = DataTypes.DOUBLE.value(functionLiteralPair.input().value());

        String fieldName = distanceRefLiteral.reference().info().ident().columnIdent().fqn();
        FieldMapper mapper = getGeoPointFieldMapper(fieldName, context.mapperService);
        GeoPointFieldMapper geoMapper = ((GeoPointFieldMapper) mapper);
        IndexGeoPointFieldData fieldData = context.fieldDataService.getForField(mapper);

        Input geoPointInput = distanceRefLiteral.input();
        Double[] pointValue = (Double[]) geoPointInput.value();
        double lat = pointValue[1];
        double lon = pointValue[0];

        String parentName = functionLiteralPair.functionName();

        Double from = null;
        Double to = null;
        boolean includeLower = false;
        boolean includeUpper = false;

        switch (parentName) {
          case EqOperator.NAME:
            includeLower = true;
            includeUpper = true;
            from = distance;
            to = distance;
            break;
          case LteOperator.NAME:
            includeUpper = true;
            to = distance;
            break;
          case LtOperator.NAME:
            to = distance;
            break;
          case GteOperator.NAME:
            from = distance;
            includeLower = true;
            break;
          case GtOperator.NAME:
            from = distance;
            break;
          default:
            // invalid operator? give up
            return null;
        }
        GeoPoint geoPoint = new GeoPoint(lat, lon);
        Filter filter =
            new GeoDistanceRangeFilter(
                geoPoint,
                from,
                to,
                includeLower,
                includeUpper,
                GEO_DISTANCE,
                geoMapper,
                fieldData,
                optimizeBox);
        return new FilteredQuery(
            Queries.newMatchAllQuery(), context.indexCache.filter().cache(filter));
      }