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;
}