public static Optional<SpanWithinQueryBuilder> fromXContent(QueryParseContext parseContext)
      throws IOException {
    XContentParser parser = parseContext.parser();

    float boost = AbstractQueryBuilder.DEFAULT_BOOST;
    String queryName = null;
    SpanQueryBuilder big = null;
    SpanQueryBuilder little = null;

    String currentFieldName = null;
    XContentParser.Token token;
    while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
      if (token == XContentParser.Token.FIELD_NAME) {
        currentFieldName = parser.currentName();
      } else if (token == XContentParser.Token.START_OBJECT) {
        if (parseContext.getParseFieldMatcher().match(currentFieldName, BIG_FIELD)) {
          Optional<QueryBuilder> query = parseContext.parseInnerQueryBuilder();
          if (query.isPresent() == false || query.get() instanceof SpanQueryBuilder == false) {
            throw new ParsingException(
                parser.getTokenLocation(), "span_within [big] must be of type span query");
          }
          big = (SpanQueryBuilder) query.get();
        } else if (parseContext.getParseFieldMatcher().match(currentFieldName, LITTLE_FIELD)) {
          Optional<QueryBuilder> query = parseContext.parseInnerQueryBuilder();
          if (query.isPresent() == false || query.get() instanceof SpanQueryBuilder == false) {
            throw new ParsingException(
                parser.getTokenLocation(), "span_within [little] must be of type span query");
          }
          little = (SpanQueryBuilder) query.get();
        } else {
          throw new ParsingException(
              parser.getTokenLocation(),
              "[span_within] query does not support [" + currentFieldName + "]");
        }
      } else if (parseContext
          .getParseFieldMatcher()
          .match(currentFieldName, AbstractQueryBuilder.BOOST_FIELD)) {
        boost = parser.floatValue();
      } else if (parseContext
          .getParseFieldMatcher()
          .match(currentFieldName, AbstractQueryBuilder.NAME_FIELD)) {
        queryName = parser.text();
      } else {
        throw new ParsingException(
            parser.getTokenLocation(),
            "[span_within] query does not support [" + currentFieldName + "]");
      }
    }

    if (big == null) {
      throw new ParsingException(parser.getTokenLocation(), "span_within must include [big]");
    }
    if (little == null) {
      throw new ParsingException(parser.getTokenLocation(), "span_within must include [little]");
    }

    SpanWithinQueryBuilder query = new SpanWithinQueryBuilder(big, little);
    query.boost(boost).queryName(queryName);
    return Optional.of(query);
  }
  public static FieldMaskingSpanQueryBuilder fromXContent(QueryParseContext parseContext)
      throws IOException {
    XContentParser parser = parseContext.parser();

    float boost = AbstractQueryBuilder.DEFAULT_BOOST;

    SpanQueryBuilder inner = null;
    String field = null;
    String queryName = null;

    String currentFieldName = null;
    XContentParser.Token token;
    while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
      if (token == XContentParser.Token.FIELD_NAME) {
        currentFieldName = parser.currentName();
      } else if (token == XContentParser.Token.START_OBJECT) {
        if (parseContext.getParseFieldMatcher().match(currentFieldName, QUERY_FIELD)) {
          QueryBuilder query = parseContext.parseInnerQueryBuilder();
          if (!(query instanceof SpanQueryBuilder)) {
            throw new ParsingException(
                parser.getTokenLocation(), "[field_masking_span] query must be of type span query");
          }
          inner = (SpanQueryBuilder) query;
        } else {
          throw new ParsingException(
              parser.getTokenLocation(),
              "[field_masking_span] query does not support [" + currentFieldName + "]");
        }
      } else {
        if (parseContext
            .getParseFieldMatcher()
            .match(currentFieldName, AbstractQueryBuilder.BOOST_FIELD)) {
          boost = parser.floatValue();
        } else if (parseContext.getParseFieldMatcher().match(currentFieldName, FIELD_FIELD)) {
          field = parser.text();
        } else if (parseContext
            .getParseFieldMatcher()
            .match(currentFieldName, AbstractQueryBuilder.NAME_FIELD)) {
          queryName = parser.text();
        } else {
          throw new ParsingException(
              parser.getTokenLocation(),
              "[field_masking_span] query does not support [" + currentFieldName + "]");
        }
      }
    }
    if (inner == null) {
      throw new ParsingException(
          parser.getTokenLocation(), "field_masking_span must have [query] span query clause");
    }
    if (field == null) {
      throw new ParsingException(
          parser.getTokenLocation(), "field_masking_span must have [field] set for it");
    }

    FieldMaskingSpanQueryBuilder queryBuilder = new FieldMaskingSpanQueryBuilder(inner, field);
    queryBuilder.boost(boost);
    queryBuilder.queryName(queryName);
    return queryBuilder;
  }
  /** we resolve empty inner clauses by representing this whole query as empty optional upstream */
  public void testFromJsonEmptyQueryBody() throws IOException {
    String query =
        "{\n"
            + "  \"has_parent\" : {\n"
            + "    \"query\" : { },\n"
            + "    \"parent_type\" : \"blog\""
            + "   }"
            + "}";
    XContentParser parser = XContentFactory.xContent(query).createParser(query);
    QueryParseContext context = createParseContext(parser, ParseFieldMatcher.EMPTY);
    Optional<QueryBuilder> innerQueryBuilder = context.parseInnerQueryBuilder();
    assertTrue(innerQueryBuilder.isPresent() == false);

    checkWarningHeaders("query malformed, empty clause found at [3:17]");

    parser = XContentFactory.xContent(query).createParser(query);
    QueryParseContext otherContext = createParseContext(parser, ParseFieldMatcher.STRICT);
    IllegalArgumentException ex =
        expectThrows(IllegalArgumentException.class, () -> otherContext.parseInnerQueryBuilder());
    assertThat(ex.getMessage(), equalTo("query malformed, empty clause found at [3:17]"));
    checkWarningHeaders("query malformed, empty clause found at [3:17]");
  }
  @Override
  protected QueryBuilder doRewrite(QueryRewriteContext context) throws IOException {
    try (XContentParser qSourceParser =
        XContentFactory.xContent(source).createParser(context.getXContentRegistry(), source)) {
      QueryParseContext parseContext = context.newParseContext(qSourceParser);

      final QueryBuilder queryBuilder = parseContext.parseInnerQueryBuilder();
      if (boost() != DEFAULT_BOOST || queryName() != null) {
        final BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.must(queryBuilder);
        return boolQueryBuilder;
      }
      return queryBuilder;
    }
  }
  @Override
  public NotQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException {
    XContentParser parser = parseContext.parser();

    QueryBuilder query = null;
    boolean queryFound = false;

    String queryName = null;
    String currentFieldName = null;
    float boost = AbstractQueryBuilder.DEFAULT_BOOST;
    XContentParser.Token token;
    while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
      if (token == XContentParser.Token.FIELD_NAME) {
        currentFieldName = parser.currentName();
      } else if (parseContext.isDeprecatedSetting(currentFieldName)) {
        // skip
      } else if (token == XContentParser.Token.START_OBJECT) {
        if (parseContext.parseFieldMatcher().match(currentFieldName, QUERY_FIELD)) {
          query = parseContext.parseInnerQueryBuilder();
          queryFound = true;
        } else {
          queryFound = true;
          // its the filter, and the name is the field
          query = parseContext.parseInnerQueryBuilderByName(currentFieldName);
        }
      } else if (token.isValue()) {
        if ("_name".equals(currentFieldName)) {
          queryName = parser.text();
        } else if ("boost".equals(currentFieldName)) {
          boost = parser.floatValue();
        } else {
          throw new ParsingException(
              parser.getTokenLocation(), "[not] query does not support [" + currentFieldName + "]");
        }
      }
    }

    if (!queryFound) {
      throw new ParsingException(
          parser.getTokenLocation(), "query is required when using `not` query");
    }

    NotQueryBuilder notQueryBuilder = new NotQueryBuilder(query);
    notQueryBuilder.queryName(queryName);
    notQueryBuilder.boost(boost);
    return notQueryBuilder;
  }
  public static SpanNearQueryBuilder fromXContent(QueryParseContext parseContext)
      throws IOException {
    XContentParser parser = parseContext.parser();

    float boost = AbstractQueryBuilder.DEFAULT_BOOST;
    Integer slop = null;
    boolean inOrder = SpanNearQueryBuilder.DEFAULT_IN_ORDER;
    String queryName = null;

    List<SpanQueryBuilder> clauses = new ArrayList<>();

    String currentFieldName = null;
    XContentParser.Token token;
    while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
      if (token == XContentParser.Token.FIELD_NAME) {
        currentFieldName = parser.currentName();
      } else if (token == XContentParser.Token.START_ARRAY) {
        if (parseContext.getParseFieldMatcher().match(currentFieldName, CLAUSES_FIELD)) {
          while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
            QueryBuilder query = parseContext.parseInnerQueryBuilder();
            if (!(query instanceof SpanQueryBuilder)) {
              throw new ParsingException(
                  parser.getTokenLocation(), "spanNear [clauses] must be of type span query");
            }
            clauses.add((SpanQueryBuilder) query);
          }
        } else {
          throw new ParsingException(
              parser.getTokenLocation(),
              "[span_near] query does not support [" + currentFieldName + "]");
        }
      } else if (token.isValue()) {
        if (parseContext.getParseFieldMatcher().match(currentFieldName, IN_ORDER_FIELD)) {
          inOrder = parser.booleanValue();
        } else if (parseContext
            .getParseFieldMatcher()
            .match(currentFieldName, COLLECT_PAYLOADS_FIELD)) {
          // Deprecated in 3.0.0
        } else if (parseContext.getParseFieldMatcher().match(currentFieldName, SLOP_FIELD)) {
          slop = parser.intValue();
        } else if (parseContext
            .getParseFieldMatcher()
            .match(currentFieldName, AbstractQueryBuilder.BOOST_FIELD)) {
          boost = parser.floatValue();
        } else if (parseContext
            .getParseFieldMatcher()
            .match(currentFieldName, AbstractQueryBuilder.NAME_FIELD)) {
          queryName = parser.text();
        } else {
          throw new ParsingException(
              parser.getTokenLocation(),
              "[span_near] query does not support [" + currentFieldName + "]");
        }
      } else {
        throw new ParsingException(
            parser.getTokenLocation(),
            "[span_near] query does not support [" + currentFieldName + "]");
      }
    }

    if (clauses.isEmpty()) {
      throw new ParsingException(parser.getTokenLocation(), "span_near must include [clauses]");
    }

    if (slop == null) {
      throw new ParsingException(parser.getTokenLocation(), "span_near must include [slop]");
    }

    SpanNearQueryBuilder queryBuilder = new SpanNearQueryBuilder(clauses.get(0), slop);
    for (int i = 1; i < clauses.size(); i++) {
      queryBuilder.clause(clauses.get(i));
    }
    queryBuilder.inOrder(inOrder);
    queryBuilder.boost(boost);
    queryBuilder.queryName(queryName);
    return queryBuilder;
  }
  public static Optional<HasParentQueryBuilder> fromXContent(QueryParseContext parseContext)
      throws IOException {
    XContentParser parser = parseContext.parser();
    float boost = AbstractQueryBuilder.DEFAULT_BOOST;
    String parentType = null;
    boolean score = false;
    String queryName = null;
    InnerHitBuilder innerHits = null;
    boolean ignoreUnmapped = DEFAULT_IGNORE_UNMAPPED;

    String currentFieldName = null;
    XContentParser.Token token;
    Optional<QueryBuilder> iqb = Optional.empty();
    while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
      if (token == XContentParser.Token.FIELD_NAME) {
        currentFieldName = parser.currentName();
      } else if (token == XContentParser.Token.START_OBJECT) {
        if (parseContext.getParseFieldMatcher().match(currentFieldName, QUERY_FIELD)) {
          iqb = parseContext.parseInnerQueryBuilder();
        } else if (parseContext.getParseFieldMatcher().match(currentFieldName, INNER_HITS_FIELD)) {
          innerHits = InnerHitBuilder.fromXContent(parseContext);
        } else {
          throw new ParsingException(
              parser.getTokenLocation(),
              "[has_parent] query does not support [" + currentFieldName + "]");
        }
      } else if (token.isValue()) {
        if (parseContext.getParseFieldMatcher().match(currentFieldName, TYPE_FIELD)) {
          parentType = parser.text();
        } else if (parseContext.getParseFieldMatcher().match(currentFieldName, SCORE_MODE_FIELD)) {
          String scoreModeValue = parser.text();
          if ("score".equals(scoreModeValue)) {
            score = true;
          } else if ("none".equals(scoreModeValue)) {
            score = false;
          } else {
            throw new ParsingException(
                parser.getTokenLocation(),
                "[has_parent] query does not support ["
                    + scoreModeValue
                    + "] as an option for score_mode");
          }
        } else if (parseContext.getParseFieldMatcher().match(currentFieldName, SCORE_FIELD)) {
          score = parser.booleanValue();
        } else if (parseContext
            .getParseFieldMatcher()
            .match(currentFieldName, IGNORE_UNMAPPED_FIELD)) {
          ignoreUnmapped = parser.booleanValue();
        } else if (parseContext
            .getParseFieldMatcher()
            .match(currentFieldName, AbstractQueryBuilder.BOOST_FIELD)) {
          boost = parser.floatValue();
        } else if (parseContext
            .getParseFieldMatcher()
            .match(currentFieldName, AbstractQueryBuilder.NAME_FIELD)) {
          queryName = parser.text();
        } else {
          throw new ParsingException(
              parser.getTokenLocation(),
              "[has_parent] query does not support [" + currentFieldName + "]");
        }
      }
    }
    if (iqb.isPresent() == false) {
      // if inner query is empty, bubble this up to caller so they can decide how to deal with it
      return Optional.empty();
    }
    HasParentQueryBuilder queryBuilder =
        new HasParentQueryBuilder(parentType, iqb.get(), score)
            .ignoreUnmapped(ignoreUnmapped)
            .queryName(queryName)
            .boost(boost);
    if (innerHits != null) {
      queryBuilder.innerHit(innerHits);
    }
    return Optional.of(queryBuilder);
  }