in core/src/main/java/com/jetbrains/youtrackdb/internal/core/index/CompositeIndexDefinition.java [622:803]
private record CompositeWrapperMap(FrontendTransaction transaction,
Object2IntOpenHashMap<CompositeKey> underlying,
List<IndexDefinition> indexDefinitions, Object[] params,
int multiValueIndex, boolean isNullValuesIgnored) implements
Object2IntMap<Object> {
@Override
public int size() {
return underlying.size();
}
@Override
public boolean isEmpty() {
return underlying.isEmpty();
}
@Override
public boolean containsKey(Object key) {
final var compositeKey = convertToCompositeKeyFast(transaction, key);
if (compositeKey == null) {
return false;
}
return underlying.containsKey(compositeKey);
}
@Override
public void defaultReturnValue(int i) {
underlying.defaultReturnValue(i);
}
@Override
public int defaultReturnValue() {
return underlying.defaultReturnValue();
}
@Override
public ObjectSet<Entry<Object>> object2IntEntrySet() {
throw new UnsupportedOperationException();
}
@Override
public boolean containsValue(int i) {
return underlying.containsValue(i);
}
@Override
public int getInt(Object o) {
var key = convertToCompositeKeyFast(transaction, o);
if (key == null) {
return defaultReturnValue();
}
return underlying.getInt(key);
}
@Override
public int put(Object key, int value) {
final var result = convertToCompositeKeyFast(transaction, key);
if (result != null) {
if (result instanceof CompositeKey compositeKey) {
return underlying.put(compositeKey, value);
} else if (result instanceof Stream<?> compositeKeyStream) {
compositeKeyStream.forEach(
compositeKey -> underlying.put((CompositeKey) compositeKey, value));
} else {
throw new IllegalStateException("Unexpected result type: " + result.getClass());
}
}
return value;
}
@Override
public int removeInt(Object key) {
var compositeKey = convertToCompositeKeyFast(transaction, key);
if (compositeKey == null) {
return defaultReturnValue();
}
return underlying.removeInt(compositeKey);
}
@Override
public void clear() {
underlying.clear();
}
@Nonnull
@Override
public ObjectSet<Object> keySet() {
throw new UnsupportedOperationException();
}
@Override
public void putAll(@Nonnull Map<?, ? extends Integer> m) {
throw new UnsupportedOperationException();
}
@Override
@Nonnull
public IntCollection values() {
return underlying.values();
}
@Nullable
private Object convertToCompositeKeyFast(FrontendTransaction transaction, Object key) {
final var compositeKey = new CompositeKey();
var paramsIndex = 0;
for (var i = 0; i < indexDefinitions.size(); i++) {
final var indexDefinition = indexDefinitions.get(i);
if (i != multiValueIndex) {
var keyValue = indexDefinition.createValue(transaction, params[paramsIndex]);
if (keyValue == null && isNullValuesIgnored) {
return null;
}
if (keyValue instanceof Collection<?> collection) {
if (collection.isEmpty() && isNullValuesIgnored) {
return null;
}
if (collection.isEmpty()) {
compositeKey.addKey(null);
} else if (collection.size() == 1) {
compositeKey.addKey(collection.iterator().next());
} else {
return convertToCompositeKeySlow(transaction, i, paramsIndex, compositeKey, key);
}
} else {
compositeKey.addKey(keyValue);
}
paramsIndex++;
} else {
compositeKey.addKey(
((IndexDefinitionMultiValue) indexDefinition).createSingleValue(transaction, key));
}
}
return compositeKey;
}
@Nullable
Stream<CompositeKey> convertToCompositeKeySlow(FrontendTransaction transaction,
int currentIndexDefinition, int paramasIndex, CompositeKey startCompositeKey,
Object key) {
var stream = Stream.of(startCompositeKey);
for (var i = currentIndexDefinition; i < indexDefinitions.size(); i++) {
var indexDefinition = indexDefinitions.get(i);
if (i != multiValueIndex) {
final var keyValue = indexDefinition.createValue(transaction, params[paramasIndex]);
if (keyValue == null && isNullValuesIgnored) {
return null;
}
// for empty collections we add null key in index
if (keyValue instanceof Collection<?> collection) {
if (collection.isEmpty()) {
if (isNullValuesIgnored) {
return null;
} else {
stream = stream.peek(compositeKey -> compositeKey.addKey(null));
}
} else {
stream = stream.flatMap(compositeKey -> addKey(compositeKey, collection));
}
} else {
stream = stream.peek(compositeKey -> compositeKey.addKey(keyValue));
}
paramasIndex++;
} else {
var singleKey =
((IndexDefinitionMultiValue) indexDefinition).createSingleValue(transaction, key);
stream = stream.peek(compositeKey -> compositeKey.addKey(singleKey));
}
}
return stream;
}
}