blob: 15399ee5894609cfab4cdd8b03db5b72bc3df523 [file] [log] [blame]
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ Licensed to the Apache Software Foundation (ASF) under one
~ or more contributor license agreements. See the NOTICE file
~ distributed with this work for additional information
~ regarding copyright ownership. The ASF licenses this file
~ to you under the Apache License, Version 2.0 (the
~ "License"); you may not use this file except in compliance
~ with the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
package org.apache.sling.graphql.core.engine;
import graphql.schema.DataFetchingFieldSelectionSet;
import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.collections4.multimap.HashSetValuedHashMap;
import org.apache.sling.graphql.api.SelectedField;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Implement a wrapper for GraphQL SelectedField.
*
* ATTENTION: here we are assuming that fields added are unqiue by the Fully Qualified Name (FQN).
*
* This updated version is keeping duplicate fields by field's simple name. Use getFirstSubSelectedFieldByName() if
* you are sure that there is only one field with that simple name otherwise use hasDuplicateFieldByName() to determine
* if there are duplicates or use the fully qualified name (FQN) to find a field.
*/
public class SelectedFieldWrapper implements SelectedField {
private final String name;
private final String fullyQualifiedName;
private final String qualifiedName;
private final boolean conditional;
private final int level;
private final String alias;
private final String resultKey;
private final List<String> objectTypeNames;
private final MultiValuedMap<String, SelectedField> subFieldMap = new HashSetValuedHashMap<>();
private final Map<String, SelectedField> subFQNFieldMap = new HashMap<>();
private final List<SelectedField> subFields;
public SelectedFieldWrapper(graphql.schema.SelectedField selectedField) {
this.name = selectedField.getName();
this.qualifiedName = selectedField.getQualifiedName();
this.fullyQualifiedName = selectedField.getFullyQualifiedName();
this.objectTypeNames = selectedField.getObjectTypeNames() == null ? Collections.emptyList() : new ArrayList<>(selectedField.getObjectTypeNames());
this.conditional = selectedField.isConditional();
this.level = selectedField.getLevel();
this.alias = selectedField.getAlias();
this.resultKey = selectedField.getResultKey();
DataFetchingFieldSelectionSet selectionSet = selectedField.getSelectionSet();
if (selectionSet != null) {
selectionSet.getImmediateFields().forEach(sf -> {
SelectedFieldWrapper selectedChildField = new SelectedFieldWrapper(sf);
subFieldMap.put(sf.getName(), selectedChildField);
subFQNFieldMap.put(sf.getFullyQualifiedName(), selectedChildField);
});
}
// Fields are not taken from the FQN Map to avoid dropping fields with the same name
subFields = new ArrayList<>(subFQNFieldMap.values());
}
@Override
public String getName() {
return name;
}
@Override
public @Nullable String getQualifiedName() {
return qualifiedName;
}
@Override
public String getFullyQualifiedName() {
return fullyQualifiedName;
}
@Override
public boolean isConditional() {
return conditional;
}
@Override
public int getLevel() {
return level;
}
@Override
public String getAlias() {
return alias;
}
@Override
public String getResultKey() {
return resultKey;
}
@Override
@NotNull
public List<SelectedField> getSubSelectedFields() {
return subFields;
}
@Override
@NotNull
public Collection<SelectedField> getSubSelectedFieldByName(@NotNull String name) {
return subFieldMap.get(name);
}
@Override
@Nullable
public SelectedField getFirstSubSelectedFieldByName(@NotNull String name) {
Collection<SelectedField> fields = getSubSelectedFieldByName(name);
return fields.isEmpty() ? null : fields.iterator().next();
}
@Override
@Nullable
public SelectedField getSubSelectedFieldByFQN(@NotNull String fullyQualifiedName) {
return subFQNFieldMap.get(fullyQualifiedName);
}
@Override
public boolean hasDuplicateFieldByName(@NotNull String name) {
return subFieldMap.get(name).size() > 1;
}
@Override
public boolean hasSubSelectedFieldsByName(@NotNull String... name) {
return Arrays.stream(name).anyMatch(subFieldMap::containsKey);
}
@Override
public boolean hasSubSelectedFieldsByFQN(@NotNull String... fullyQualifiedName) {
return Arrays.stream(fullyQualifiedName).anyMatch(subFQNFieldMap::containsKey);
}
@Deprecated
@Override
public SelectedField getSubSelectedField(@NotNull String name) {
return name.indexOf('.') >= 0 ?
getSubSelectedFieldByFQN(name) :
getFirstSubSelectedFieldByName(name);
}
@Deprecated
@Override
public boolean hasSubSelectedFields(@NotNull String... name) {
return name[0].indexOf('.') >= 0 ?
Arrays.stream(name).anyMatch(subFQNFieldMap::containsKey) :
Arrays.stream(name).anyMatch(subFieldMap::containsKey);
}
@Deprecated
@Override
public boolean isInline() {
return false;
}
@Override
@NotNull
public List<String> getObjectTypeNames() {
return Collections.unmodifiableList(new ArrayList<String>(objectTypeNames));
}
}