public static RET getFieldValue()

in core/src/main/java/com/jetbrains/youtrackdb/internal/core/record/impl/EntityHelper.java [124:569]


  public static <RET> RET getFieldValue(
      DatabaseSessionEmbedded session, Object value, final String iFieldName,
      @Nonnull final CommandContext iContext) {
    if (value == null) {
      return null;
    }

    final var fieldNameLength = iFieldName.length();
    if (fieldNameLength == 0) {
      return (RET) value;
    }

    var currentRecord = value instanceof Identifiable ? (Identifiable) value : null;

    var beginPos = iFieldName.charAt(0) == '.' ? 1 : 0;
    var nextSeparatorPos = iFieldName.charAt(0) == '.' ? 1 : 0;
    var firstInChain = true;
    do {
      var nextSeparator = ' ';
      for (; nextSeparatorPos < fieldNameLength; ++nextSeparatorPos) {
        nextSeparator = iFieldName.charAt(nextSeparatorPos);
        if (nextSeparator == '.' || nextSeparator == '[') {
          break;
        }
      }

      final String fieldName;
      if (nextSeparatorPos < fieldNameLength) {
        fieldName = iFieldName.substring(beginPos, nextSeparatorPos);
      } else {
        nextSeparator = ' ';
        if (beginPos > 0) {
          fieldName = iFieldName.substring(beginPos);
        } else {
          fieldName = iFieldName;
        }
      }

      if (nextSeparator == '[') {
        if (!fieldName.isEmpty()) {
          if (currentRecord != null) {
            value = getIdentifiableValue(session, currentRecord, fieldName);
          } else if (value instanceof Map<?, ?>) {
            value = getMapEntry(session, (Map<String, ?>) value, fieldName);
          } else if (MultiValue.isMultiValue(value)) {
            final HashSet<Object> temp = new LinkedHashSet<Object>();
            for (var o : MultiValue.getMultiValueIterable(value)) {
              if (o instanceof Identifiable) {
                var r = getFieldValue(session, o, iFieldName);
                if (r != null) {
                  MultiValue.add(temp, r);
                }
              }
            }
            value = temp;
          }
        }

        if (value == null) {
          return null;
        } else if (value instanceof Identifiable) {
          currentRecord = (Identifiable) value;
        }

        // final int end = iFieldName.indexOf(']', nextSeparatorPos);
        final var end = findClosingBracketPosition(iFieldName, nextSeparatorPos);
        if (end == -1) {
          throw new IllegalArgumentException("Missed closed ']'");
        }

        var indexPart = iFieldName.substring(nextSeparatorPos + 1, end);
        if (indexPart.isEmpty()) {
          return null;
        }

        nextSeparatorPos = end;

        if (value instanceof CommandContext) {
          value = ((CommandContext) value).getVariables();
        }

        if (value instanceof Identifiable) {
          final DBRecord record;
          if (currentRecord instanceof Identifiable) {
            var transaction = session.getActiveTransaction();
            record = transaction.load(currentRecord);
          } else {
            record = null;
          }

          final var index = getIndexPart(iContext, indexPart);
          final var indexAsString = index != null ? index.toString() : null;

          final var indexParts =
              StringSerializerHelper.smartSplit(
                  indexAsString, ',', StringSerializerHelper.DEFAULT_IGNORE_CHARS);
          final var indexRanges =
              StringSerializerHelper.smartSplit(indexAsString, '-', ' ');
          final var indexCondition =
              StringSerializerHelper.smartSplit(indexAsString, '=', ' ');

          if (indexParts.size() == 1 && indexCondition.size() == 1 && indexRanges.size() == 1)
          // SINGLE VALUE
          {
            value = ((EntityImpl) record).getProperty(indexAsString);
          } else if (indexParts.size() > 1) {
            // MULTI VALUE
            final var values = new Object[indexParts.size()];
            for (var i = 0; i < indexParts.size(); ++i) {
              final var iFieldName1 = IOUtils.getStringContent(indexParts.get(i));
              values[i] = ((EntityImpl) record).getProperty(iFieldName1);
            }
            value = values;
          } else if (indexRanges.size() > 1) {

            // MULTI VALUES RANGE
            var from = indexRanges.get(0);
            var to = indexRanges.get(1);

            final var entity = (EntityImpl) record;

            final var fieldNames = entity.propertyNames();
            final var rangeFrom = from != null && !from.isEmpty() ? Integer.parseInt(from) : 0;
            final var rangeTo =
                to != null && !to.isEmpty()
                    ? Math.min(Integer.parseInt(to), fieldNames.length - 1)
                    : fieldNames.length - 1;

            final var values = new Object[rangeTo - rangeFrom + 1];

            for (var i = rangeFrom; i <= rangeTo; ++i) {
              values[i - rangeFrom] = entity.getProperty(fieldNames[i]);
            }

            value = values;

          } else if (!indexCondition.isEmpty()) {
            // CONDITION
            final var conditionFieldName = indexCondition.get(0);
            var conditionFieldValue =
                RecordSerializerStringAbstract.getTypeValue(session, indexCondition.get(1));

            if (conditionFieldValue instanceof String) {
              conditionFieldValue = IOUtils.getStringContent(conditionFieldValue);
            }

            final var fieldValue = getFieldValue(session, currentRecord, conditionFieldName);

            if (conditionFieldValue != null && fieldValue != null) {
              var type = PropertyTypeInternal.getTypeByValue(fieldValue);
              conditionFieldValue = type.convert(conditionFieldValue, null,
                  null, session);
            }

            if (fieldValue == null && !conditionFieldValue.equals("null")
                || fieldValue != null && !fieldValue.equals(conditionFieldValue)) {
              value = null;
            }
          }
        } else if (value instanceof Map<?, ?> || value instanceof Result) {
          final var index = getIndexPart(iContext, indexPart);
          final var indexAsString = index != null ? index.toString() : null;

          final var indexParts =
              StringSerializerHelper.smartSplit(
                  indexAsString, ',', StringSerializerHelper.DEFAULT_IGNORE_CHARS);
          final var indexRanges =
              StringSerializerHelper.smartSplit(indexAsString, '-', ' ');
          final var indexCondition =
              StringSerializerHelper.smartSplit(indexAsString, '=', ' ');

          if (indexParts.size() == 1 && indexCondition.size() == 1 && indexRanges.size() == 1)
          // SINGLE VALUE
          {
            if (value instanceof Map<?, ?> map) {
              value = map.get(index.toString());
            } else {
              var result = (Result) value;
              value = result.getProperty(indexAsString);
            }
          } else if (indexParts.size() > 1) {
            // MULTI VALUE
            final var values = new Object[indexParts.size()];
            if (value instanceof Map<?, ?> map) {
              for (var i = 0; i < indexParts.size(); ++i) {
                values[i] = map.get(IOUtils.getStringContent(indexParts.get(i)));
              }
            } else {
              var result = (Result) value;
              for (var i = 0; i < indexParts.size(); ++i) {
                values[i] = result.getProperty(IOUtils.getStringContent(indexParts.get(i)));
              }
            }
            value = values;
          } else if (indexRanges.size() > 1) {

            // MULTI VALUES RANGE
            var from = indexRanges.get(0);
            var to = indexRanges.get(1);

            final ArrayList<String> fieldNames;
            if (value instanceof Map<?, ?> map) {
              fieldNames = new ArrayList<>(((Map<String, Object>) map).keySet());
            } else {
              var result = (Result) value;
              fieldNames = new ArrayList<>(result.getPropertyNames());
            }
            final var rangeFrom = from != null && !from.isEmpty() ? Integer.parseInt(from) : 0;
            final var rangeTo =
                to != null && !to.isEmpty()
                    ? Math.min(Integer.parseInt(to), fieldNames.size() - 1)
                    : fieldNames.size() - 1;

            final var values = new Object[rangeTo - rangeFrom + 1];

            if (value instanceof Map<?, ?> map) {
              for (var i = rangeFrom; i <= rangeTo; ++i) {
                values[i - rangeFrom] = map.get(fieldNames.get(i));
              }
            } else {
              var result = (Result) value;

              for (var i = rangeFrom; i <= rangeTo; ++i) {
                values[i - rangeFrom] = result.getProperty(fieldNames.get(i));
              }
            }

            value = values;

          } else if (!indexCondition.isEmpty()) {
            // CONDITION
            final var conditionFieldName = indexCondition.get(0);
            var conditionFieldValue =
                RecordSerializerStringAbstract.getTypeValue(session, indexCondition.get(1));

            if (conditionFieldValue instanceof String) {
              conditionFieldValue = IOUtils.getStringContent(conditionFieldValue);
            }

            Object fieldValue = null;

            if (value instanceof Map<?, ?> map) {
              value = map.get(conditionFieldName);
            } else {
              var result = (Result) value;
              fieldValue = result.getProperty(conditionFieldName);
            }

            if (conditionFieldValue != null && fieldValue != null) {
              var type = PropertyTypeInternal.getTypeByValue(fieldValue);
              conditionFieldValue = type.convert(conditionFieldValue, null,
                  null, session);
            }

            if (fieldValue == null && !conditionFieldValue.equals("null")
                || fieldValue != null && !fieldValue.equals(conditionFieldValue)) {
              value = null;
            }
          }

        } else if (MultiValue.isMultiValue(value)) {
          // MULTI VALUE
          final var index = getIndexPart(iContext, indexPart);
          final var indexAsString = index != null ? index.toString() : null;

          final var indexParts = StringSerializerHelper.smartSplit(indexAsString, ',');
          final var indexRanges = StringSerializerHelper.smartSplit(indexAsString, '-');
          if (isFieldName(indexAsString)) {
            // SINGLE VALUE
            if (Character.isDigit(indexAsString.charAt(0))) {
              value = MultiValue.getValue(value, Integer.parseInt(indexAsString));
            } else
            // FILTER BY FIELD
            {
              value = getFieldValue(session, value, indexAsString, iContext);
            }

          } else if (isListOfNumbers(indexParts)) {

            // MULTI VALUES
            final var values = new Object[indexParts.size()];
            for (var i = 0; i < indexParts.size(); ++i) {
              values[i] = MultiValue.getValue(value, Integer.parseInt(indexParts.get(i)));
            }
            if (indexParts.size() > 1) {
              value = values;
            } else {
              value = values[0];
            }

          } else if (isListOfNumbers(indexRanges)) {

            // MULTI VALUES RANGE
            var from = indexRanges.get(0);
            var to = indexRanges.get(1);

            final var rangeFrom = from != null && !from.isEmpty() ? Integer.parseInt(from) : 0;
            final int rangeTo;
            if (to != null && !to.isEmpty()) {
              rangeTo = Math.min(Integer.parseInt(to), (int) MultiValue.getSize(value) - 1);
            } else {
              rangeTo = (int) MultiValue.getSize(value) - 1;
            }

            var arraySize = rangeTo - rangeFrom + 1;
            if (arraySize < 0) {
              arraySize = 0;
            }
            final var values = new Object[arraySize];
            for (var i = rangeFrom; i <= rangeTo; ++i) {
              values[i - rangeFrom] = MultiValue.getValue(value, i);
            }
            value = values;

          } else {
            // CONDITION
            var pred = new SQLPredicate(iContext, indexAsString);
            final HashSet<Object> values = new LinkedHashSet<Object>();

            for (var v : MultiValue.getMultiValueIterable(value)) {
              if (v instanceof Identifiable identifiable) {
                var transaction = session.getActiveTransaction();
                var entity = transaction.loadEntity(identifiable);
                var result =
                    pred.evaluate(entity, (EntityImpl) entity, iContext);
                if (Boolean.TRUE.equals(result)) {
                  values.add(v);
                }
              } else if (v instanceof Map) {
                var entity = (EntityImpl) session.newEmbeddedEntity();
                entity.updateFromMap((Map<String, ?>) v);
                var result = pred.evaluate(entity, entity, iContext);
                if (Boolean.TRUE.equals(result)) {
                  values.add(v);
                }
              }
            }

            if (values.isEmpty())
            // RETURNS NULL
            {
              value = values;
            } else if (values.size() == 1)
            // RETURNS THE SINGLE ODOCUMENT
            {
              value = values.iterator().next();
            } else
            // RETURNS THE FILTERED COLLECTION
            {
              value = values;
            }
          }
        }
      } else {
        if (fieldName.isEmpty()) {
          // NO FIELD NAME: THIS IS THE CASE OF NOT USEFUL . AFTER A ] OR .
          beginPos = ++nextSeparatorPos;
          continue;
        }

        if (fieldName.charAt(0) == '$') {
          value = iContext.getVariable(fieldName);
        } else if (fieldName.contains("(")) {
          var executedMethod = false;
          if (!firstInChain && fieldName.endsWith("()")) {
            var method =
                SQLEngine.getMethod(fieldName.substring(0, fieldName.length() - 2));
            if (method != null) {
              var transaction = session.getActiveTransaction();
              value = method.execute(value,
                  currentRecord != null ? transaction.loadEntity(currentRecord) : null, iContext,
                  value,
                  new Object[]{});
              executedMethod = true;
            }
          }
          if (!executedMethod) {
            value = evaluateFunction(value, fieldName, iContext);
          }
        } else {
          final var indexCondition =
              StringSerializerHelper.smartSplit(fieldName, '=', ' ');

          if (indexCondition.size() == 2) {
            final var conditionFieldName = indexCondition.get(0);
            var conditionFieldValue =
                RecordSerializerStringAbstract.getTypeValue(session, indexCondition.get(1));

            if (conditionFieldValue instanceof String) {
              conditionFieldValue = IOUtils.getStringContent(conditionFieldValue);
            }

            value = filterItem(session, conditionFieldName, conditionFieldValue, value);

          } else if (currentRecord != null) {
            // GET THE LINKED OBJECT IF ANY
            value = getIdentifiableValue(session, currentRecord, fieldName);
          } else if (value instanceof Map<?, ?>) {
            value = getMapEntry(session, (Map<String, ?>) value, fieldName);
          } else if (value instanceof Result result) {
            value = getResultEntry(session, result, fieldName);
          } else if (MultiValue.isMultiValue(value)) {
            final Set<Object> values = new LinkedHashSet<Object>();
            for (var v : MultiValue.getMultiValueIterable(value)) {
              final Object item;

              if (v instanceof Identifiable) {
                item = getIdentifiableValue(session, (Identifiable) v, fieldName);
              } else if (v instanceof Map) {
                item = ((Map<?, ?>) v).get(fieldName);
              } else {
                item = null;
              }

              if (item != null) {
                if (item instanceof Collection<?>) {
                  values.addAll((Collection<?>) item);
                } else {
                  values.add(item);
                }
              }
            }

            if (values.isEmpty()) {
              value = null;
            } else {
              value = values;
            }
          } else {
            return null;
          }
        }
      }

      if (value instanceof Identifiable) {
        currentRecord = (Identifiable) value;
      } else {
        currentRecord = null;
      }

      beginPos = ++nextSeparatorPos;
      firstInChain = false;
    } while (nextSeparatorPos < fieldNameLength && value != null);

    return (RET) value;
  }