private DimensionSelector makeDimensionSelectorUndecorated()

in processing/src/main/java/org/apache/druid/segment/RowBasedColumnSelectorFactory.java [170:410]


  private DimensionSelector makeDimensionSelectorUndecorated(DimensionSpec dimensionSpec)
  {
    final String dimension = dimensionSpec.getDimension();
    final ExtractionFn extractionFn = dimensionSpec.getExtractionFn();

    if (ColumnHolder.TIME_COLUMN_NAME.equals(dimensionSpec.getDimension())) {
      if (extractionFn == null) {
        throw new UnsupportedOperationException("time dimension must provide an extraction function");
      }

      final ToLongFunction<T> timestampFunction = adapter.timestampFunction();

      return new BaseSingleValueDimensionSelector()
      {
        private long currentId = RowIdSupplier.INIT;
        private String currentValue;

        @Override
        protected String getValue()
        {
          updateCurrentValue();
          return currentValue;
        }

        @Override
        public void inspectRuntimeShape(RuntimeShapeInspector inspector)
        {
          inspector.visit("row", rowSupplier);
          inspector.visit("extractionFn", extractionFn);
        }

        private void updateCurrentValue()
        {
          if (rowIdSupplier == null || rowIdSupplier.getRowId() != currentId) {
            currentValue = extractionFn.apply(timestampFunction.applyAsLong(rowSupplier.get()));

            if (rowIdSupplier != null) {
              currentId = rowIdSupplier.getRowId();
            }
          }
        }
      };
    } else {
      final Function<T, Object> dimFunction = adapter.columnFunction(dimension);

      return new DimensionSelector()
      {
        private long currentId = RowIdSupplier.INIT;
        private List<String> dimensionValues;

        private final RangeIndexedInts indexedInts = new RangeIndexedInts();

        @Override
        public IndexedInts getRow()
        {
          updateCurrentValues();
          indexedInts.setSize(dimensionValues.size());
          return indexedInts;
        }

        @Override
        public ValueMatcher makeValueMatcher(final @Nullable String value)
        {
          return new ValueMatcher()
          {
            @Override
            public boolean matches(boolean includeUnknown)
            {
              updateCurrentValues();

              if (dimensionValues.isEmpty()) {
                return includeUnknown || value == null;
              }

              for (String dimensionValue : dimensionValues) {
                if ((includeUnknown && dimensionValue == null) || Objects.equals(dimensionValue, value)) {
                  return true;
                }
              }
              return false;
            }

            @Override
            public void inspectRuntimeShape(RuntimeShapeInspector inspector)
            {
              inspector.visit("row", rowSupplier);
              inspector.visit("extractionFn", extractionFn);
            }
          };
        }

        @Override
        public ValueMatcher makeValueMatcher(final DruidPredicateFactory predicateFactory)
        {
          final DruidObjectPredicate<String> predicate = predicateFactory.makeStringPredicate();

          return new ValueMatcher()
          {
            @Override
            public boolean matches(boolean includeUnknown)
            {
              updateCurrentValues();

              if (dimensionValues.isEmpty()) {
                return predicate.apply(null).matches(includeUnknown);
              }

              for (String dimensionValue : dimensionValues) {
                if (predicate.apply(dimensionValue).matches(includeUnknown)) {
                  return true;
                }
              }
              return false;
            }

            @Override
            public void inspectRuntimeShape(RuntimeShapeInspector inspector)
            {
              inspector.visit("row", rowSupplier);
              inspector.visit("predicate", predicateFactory);
              inspector.visit("extractionFn", extractionFn);
            }
          };
        }

        @Override
        public int getValueCardinality()
        {
          return DimensionDictionarySelector.CARDINALITY_UNKNOWN;
        }

        @Override
        public String lookupName(int id)
        {
          updateCurrentValues();
          return dimensionValues.get(id);
        }

        @Override
        public boolean nameLookupPossibleInAdvance()
        {
          return false;
        }

        @Nullable
        @Override
        public IdLookup idLookup()
        {
          return null;
        }

        @Nullable
        @Override
        public Object getObject()
        {
          updateCurrentValues();

          if (dimensionValues.size() == 1) {
            return dimensionValues.get(0);
          }
          return dimensionValues;
        }

        @Override
        public Class classOfObject()
        {
          return Object.class;
        }

        @Override
        public void inspectRuntimeShape(RuntimeShapeInspector inspector)
        {
          inspector.visit("row", rowSupplier);
          inspector.visit("extractionFn", extractionFn);
        }

        private void updateCurrentValues()
        {
          if (rowIdSupplier == null || rowIdSupplier.getRowId() != currentId) {
            try {
              final Object rawValue = dimFunction.apply(rowSupplier.get());

              if (rawValue == null || rawValue instanceof String) {
                final String s = (String) rawValue;

                if (extractionFn == null) {
                  dimensionValues = Collections.singletonList(s);
                } else {
                  dimensionValues = Collections.singletonList(extractionFn.apply(s));
                }
              } else if (rawValue instanceof List) {
                //noinspection rawtypes
                final List<String> values = new ArrayList<>(((List) rawValue).size());

                //noinspection rawtypes
                for (final Object item : ((List) rawValue)) {
                  final String itemString;

                  if (useStringValueOfNullInLists) {
                    itemString = String.valueOf(item);
                  } else {
                    itemString = item == null ? null : String.valueOf(item);
                  }

                  // Behavior with null item is to convert it to string "null". This is not what most other areas of Druid
                  // would do when treating a null as a string, but it's consistent with Rows.objectToStrings, which is
                  // commonly used when retrieving strings from input-row-like objects.
                  if (extractionFn == null) {
                    values.add(itemString);
                  } else {
                    values.add(extractionFn.apply(itemString));
                  }
                }

                dimensionValues = values;
              } else {
                final List<String> nonExtractedValues = Rows.objectToStrings(rawValue);
                dimensionValues = new ArrayList<>(nonExtractedValues.size());

                for (final String value : nonExtractedValues) {
                  if (extractionFn == null) {
                    dimensionValues.add(value);
                  } else {
                    dimensionValues.add(extractionFn.apply(value));
                  }
                }
              }
            }
            catch (Throwable e) {
              currentId = RowIdSupplier.INIT;
              throw e;
            }

            if (rowIdSupplier != null) {
              currentId = rowIdSupplier.getRowId();
            }
          }
        }
      };
    }
  }