private void add()

in solr/core/src/java/org/apache/solr/search/SolrReturnFields.java [242:468]


  private void add(
      String fl,
      Deque<DeferredRenameEntry> deferred,
      DocTransformers augmenters,
      SolrQueryRequest req) {
    if (fl == null) {
      return;
    }
    try {
      StrParser sp = new StrParser(fl);

      for (; ; ) {
        sp.opt(',');
        sp.eatws();
        if (sp.pos >= sp.end) break;

        int start = sp.pos;

        // short circuit test for a really simple field name
        String key = null;
        String field = getFieldName(sp);
        char ch = sp.ch();

        if (field != null) {
          if (sp.opt(':')) {
            // this was a key, not a field name
            key = field;
            field = null;
            sp.eatws();
            start = sp.pos;
          } else {
            if (Character.isWhitespace(ch) || ch == ',' || ch == 0) {
              addField(field, key, augmenters, false);
              continue;
            }
            // an invalid field name... reset the position pointer to retry
            sp.pos = start;
            field = null;
          }
        }

        if (key != null) {
          // we read "key : "
          field = sp.getId(null);
          ch = sp.ch();
          if (field != null && (Character.isWhitespace(ch) || ch == ',' || ch == 0)) {
            deferred.addFirst(
                new DeferredRenameEntry(
                    key,
                    new ModifiableSolrParams().set(SOURCE_FIELD_ARGNAME, field),
                    req,
                    RENAME_FIELD_TRANSFORMER_FACTORY));
            // NOTE: treat as pseudoField below because `fields` will be modified on deferred
            // invocation
            addField(field, key, augmenters, true);
            continue;
          }
          // an invalid field name... reset the position pointer to retry
          sp.pos = start;
          field = null;
        }

        if (field == null) {
          // We didn't find a simple name, so let's see if it's a globbed field name.
          // Globbing only works with field names of the recommended form (roughly like java
          // identifiers)

          field = sp.getGlobbedId(null);
          ch = sp.ch();
          if (field != null && (Character.isWhitespace(ch) || ch == ',' || ch == 0)) {
            // "*" looks and acts like a glob, but we give it special treatment
            if ("*".equals(field)) {
              _wantsAllFields = true;
            } else {
              globs.add(field);
            }
            continue;
          }

          // an invalid glob
          sp.pos = start;
        }

        String funcStr = sp.val.substring(start);

        // Is it an augmenter of the form [augmenter_name foo=1 bar=myfield]?
        // This is identical to localParams syntax except it uses [] instead of {!}

        if (funcStr.startsWith("[")) {
          ModifiableSolrParams augmenterParams = new ModifiableSolrParams();
          int end =
              QueryParsing.parseLocalParams(funcStr, 0, augmenterParams, req.getParams(), "[", ']');
          sp.pos += end;

          // [foo] is short for [type=foo] in localParams syntax
          String augmenterName = augmenterParams.get("type");
          augmenterParams.remove("type");
          String disp = key;
          if (disp == null) {
            disp = '[' + augmenterName + ']';
          }

          TransformerFactory factory = req.getCore().getTransformerFactory(augmenterName);
          if (factory instanceof TransformerFactory.FieldRenamer) {
            // NOTE: `deferred` is a Deque because some TransformerFactories (e.g.,
            // `GeoTransformerFactory`) can subtly modify the representation of the associated value
            // (i.e., it's not just a straight rename). This subverts the "update source field"
            // phase of `FieldRenamer.create(...)`. We _know_ however that "simple" field renames
            // don't do any value modification whatsoever, so those are added to the beginning of
            // the `deferred` Deque so that they will be processed first, and all other
            // `FieldRenamers` are added (here) to the front or back of the Deque, depending on the
            // return value of `mayModifyValue()`.
            final DeferredRenameEntry deferredEntry =
                new DeferredRenameEntry(
                    disp, augmenterParams, req, (TransformerFactory.FieldRenamer) factory);
            if (((TransformerFactory.FieldRenamer) factory).mayModifyValue()) {
              deferred.addLast(deferredEntry);
            } else {
              deferred.addFirst(deferredEntry);
            }
          } else if (factory != null) {
            DocTransformer t = factory.create(disp, augmenterParams, req);
            if (t != null) {
              if (!_wantsAllFields) {
                String[] extra = t.getExtraRequestFields();
                if (extra != null) {
                  for (String f : extra) {
                    fields.add(f); // also request this field from IndexSearcher
                  }
                }
              }
              augmenters.addTransformer(t);
            }
          } else {
            // throw new SolrException(ErrorCode.BAD_REQUEST, "Unknown DocTransformer:
            // "+augmenterName);
          }
          addField(field, disp, augmenters, true);
          continue;
        }

        // let's try it as a function instead
        QParser parser = QParser.getParser(funcStr, FunctionQParserPlugin.NAME, req);
        Query q = null;
        ValueSource vs = null;

        try {
          if (parser instanceof FunctionQParser fparser) {
            fparser.setParseMultipleSources(false);
            fparser.setParseToEnd(false);

            q = fparser.getQuery();

            if (fparser.localParams != null) {
              if (fparser.valFollowedParams) {
                // need to find the end of the function query via the string parser
                int leftOver = fparser.sp.end - fparser.sp.pos;
                sp.pos = sp.end - leftOver; // reset our parser to the same amount of leftover
              } else {
                // the value was via the "v" param in localParams, so we need to find
                // the end of the local params themselves to pick up where we left off
                sp.pos = start + fparser.localParamsEnd;
              }
            } else {
              // need to find the end of the function query via the string parser
              int leftOver = fparser.sp.end - fparser.sp.pos;
              sp.pos = sp.end - leftOver; // reset our parser to the same amount of leftover
            }
          } else {
            // A QParser that's not for function queries.
            // It must have been specified via local params.
            q = parser.getQuery();

            assert parser.getLocalParams() != null;
            sp.pos = start + parser.localParamsEnd;
          }
          funcStr = sp.val.substring(start, sp.pos);

          if (q instanceof FunctionQuery) {
            vs = ((FunctionQuery) q).getValueSource();
          } else {
            vs = new QueryValueSource(q, 0.0f);
          }

          if (key == null) {
            SolrParams localParams = parser.getLocalParams();
            if (localParams != null) {
              key = localParams.get("key");
            }
          }

          if (key == null) {
            key = funcStr;
          }
          addField(funcStr, key, augmenters, true);
          augmenters.addTransformer(new ValueSourceAugmenter(key, parser, vs));
        } catch (SyntaxError e) {
          // try again, simple rules for a field name with no whitespace
          sp.pos = start;
          field = sp.getSimpleString();

          if (req.getSchema().getFieldOrNull(field) != null) {
            // OK, it was an oddly named field
            addField(field, key, augmenters, false);
            if (key != null) {
              deferred.addFirst(
                  new DeferredRenameEntry(
                      key,
                      new ModifiableSolrParams().set(SOURCE_FIELD_ARGNAME, field),
                      req,
                      RENAME_FIELD_TRANSFORMER_FACTORY));
            }
          } else {
            throw new SolrException(
                SolrException.ErrorCode.BAD_REQUEST,
                "Error parsing fieldname: " + e.getMessage(),
                e);
          }
        }

        // end try as function

      } // end for(;;)
    } catch (SyntaxError e) {
      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Error parsing fieldname", e);
    }
  }