Skip to content

Commit

Permalink
Merge pull request #82 from intuit/optimize-svc-metadata
Browse files Browse the repository at this point in the history
optimize service metadata implementation
  • Loading branch information
bhavinshah7 authored Jun 1, 2022
2 parents 05db9ca + 19005b7 commit e12d906
Show file tree
Hide file tree
Showing 12 changed files with 300 additions and 180 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import com.intuit.graphql.graphQL.FieldDefinition;
import com.intuit.graphql.graphQL.TypeDefinition;
import com.intuit.graphql.orchestrator.ServiceProvider;
import com.intuit.graphql.orchestrator.schema.ServiceMetadata;
import graphql.language.Field;
import graphql.schema.FieldCoordinates;
import java.util.HashMap;
Expand All @@ -25,19 +24,23 @@
@Getter
public class FederationMetadata {

private final ServiceMetadata serviceMetadata;
private final ServiceProvider serviceProvider;

/** entities owned by the service */
/**
* entities owned by the service
*/
private final Map<String, EntityMetadata> entitiesByTypename = new HashMap<>();

/** entities extended by the service */
/**
* entities extended by the service
*/
private final Map<String, EntityExtensionMetadata> extensionsByTypename = new HashMap<>();

private final Map<FieldCoordinates, Set<Field>> requiresFieldSetByCoordinate = new HashMap<>();

public FederationMetadata(ServiceMetadata serviceMetadata) {
Objects.requireNonNull(serviceMetadata);
this.serviceMetadata = serviceMetadata;
public FederationMetadata(ServiceProvider serviceProvider) {
Objects.requireNonNull(serviceProvider);
this.serviceProvider = serviceProvider;
}

public boolean isFieldExternal(FieldCoordinates fieldCoordinates) {
Expand Down Expand Up @@ -72,10 +75,15 @@ public Set<Field> getRequireFields(FieldCoordinates fieldCoordinates) {
@Builder
@Getter
public static class EntityMetadata {
@NonNull private final String typeName;
@NonNull private final List<KeyDirectiveMetadata> keyDirectives;
@NonNull private final Set<String> fields;
@NonNull private final FederationMetadata federationMetadata;

@NonNull
private final String typeName;
@NonNull
private final List<KeyDirectiveMetadata> keyDirectives;
@NonNull
private final Set<String> fields;
@NonNull
private final FederationMetadata federationMetadata;

public static Set<String> getFieldsFrom(TypeDefinition entityDefinition) {
Set<String> output = new HashSet<>(); // make sure HashSet is used
Expand All @@ -89,10 +97,15 @@ public static Set<String> getFieldsFrom(TypeDefinition entityDefinition) {
@Builder
@Getter
public static class EntityExtensionMetadata {
@NonNull private final String typeName;
@NonNull private final List<KeyDirectiveMetadata> keyDirectives;
@NonNull private final Map<String, Set<Field>> requiredFieldsByFieldName;
@NonNull private final FederationMetadata federationMetadata;

@NonNull
private final String typeName;
@NonNull
private final List<KeyDirectiveMetadata> keyDirectives;
@NonNull
private final Map<String, Set<Field>> requiredFieldsByFieldName;
@NonNull
private final FederationMetadata federationMetadata;
// TODO @provides

private EntityMetadata baseEntityMetadata;
Expand All @@ -112,13 +125,12 @@ public void setBaseEntityMetadata(EntityMetadata baseEntityMetadata) {
}

public ServiceProvider getServiceProvider() {
return this.federationMetadata.getServiceMetadata().getServiceProvider();
return this.federationMetadata.getServiceProvider();
}

public ServiceProvider getBaseServiceProvider() {
return this.baseEntityMetadata
.getFederationMetadata()
.getServiceMetadata()
.getServiceProvider();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package com.intuit.graphql.orchestrator.schema;

import static java.util.Objects.requireNonNull;

import com.intuit.graphql.orchestrator.ServiceProvider;
import com.intuit.graphql.orchestrator.federation.metadata.FederationMetadata;
import com.intuit.graphql.orchestrator.schema.transform.FieldResolverContext;
import graphql.schema.FieldCoordinates;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import lombok.Getter;

@Getter
public class ServiceMetadataImpl implements ServiceMetadata {

private final Map<String, TypeMetadata> typeMetadataMap;
private final ServiceProvider serviceProvider;
private final FederationMetadata federationMetadata;
private final boolean hasInterfaceOrUnion;
private final boolean hasFieldResolverDefinition;

private ServiceMetadataImpl(Builder builder) {
typeMetadataMap = builder.typeMetadataMap;
serviceProvider = requireNonNull(builder.serviceProvider);
federationMetadata = builder.federationMetadata;
hasInterfaceOrUnion = builder.hasInterfaceOrUnion;
hasFieldResolverDefinition = builder.hasFieldResolverDefinition;
}

public static Builder newBuilder() {
return new Builder();
}

public static Builder newBuilder(ServiceMetadataImpl copy) {
Builder builder = new Builder();
builder.typeMetadataMap = copy.getTypeMetadataMap();
builder.serviceProvider = copy.getServiceProvider();
builder.federationMetadata = copy.getFederationMetadata();
builder.hasInterfaceOrUnion = copy.isHasInterfaceOrUnion();
builder.hasFieldResolverDefinition = copy.isHasFieldResolverDefinition();
return builder;
}

@Override
public boolean hasType(String typeName) {
return this.typeMetadataMap.containsKey(typeName);
}

@Override
public boolean requiresTypenameInjection() {
return this.hasInterfaceOrUnion;
}

@Override
public boolean hasFieldResolverDirective() {
return this.hasFieldResolverDefinition;
}

@Override
public boolean isFederationService() {
return this.serviceProvider.isFederationProvider();
}

@Override
public boolean shouldRemoveExternalFields() {
return this.hasFieldResolverDirective() || this.isFederationService();
}


@Override
public ServiceProvider getServiceProvider() {
return this.serviceProvider;
}

@Override
public FieldResolverContext getFieldResolverContext(FieldCoordinates fieldCoordinates) {
return Optional.ofNullable(this.typeMetadataMap.get(fieldCoordinates.getTypeName()))
.map(typeMetadata -> typeMetadata.getFieldResolverContext(fieldCoordinates.getFieldName()))
.orElse(null);
}

@Override
public boolean isOwnedByEntityExtension(FieldCoordinates fieldCoordinates) {
return this.serviceProvider.isFederationProvider() && federationMetadata.isFieldExternal(fieldCoordinates);
}


@Override
public boolean isEntity(String typename) {
return this.isFederationService() && this.federationMetadata.isEntity(typename);
}

@Override
public FederationMetadata getFederationServiceMetadata() {
return federationMetadata;
}


public static final class Builder {

private Map<String, TypeMetadata> typeMetadataMap = new HashMap<>();
private ServiceProvider serviceProvider;
private FederationMetadata federationMetadata;
private boolean hasInterfaceOrUnion;
private boolean hasFieldResolverDefinition;

private Builder() {
}

public Builder typeMetadataMap(Map<String, TypeMetadata> val) {
typeMetadataMap = val;
return this;
}

public Builder serviceProvider(ServiceProvider val) {
serviceProvider = val;
return this;
}

public Builder federationMetadata(FederationMetadata val) {
federationMetadata = val;
return this;
}

public Builder hasInterfaceOrUnion(boolean val) {
hasInterfaceOrUnion = val;
return this;
}

public Builder hasFieldResolverDefinition(boolean val) {
hasFieldResolverDefinition = val;
return this;
}

public ServiceMetadataImpl build() {
return new ServiceMetadataImpl(this);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package com.intuit.graphql.orchestrator.schema.fold;

import static com.intuit.graphql.orchestrator.schema.fold.FieldMergeValidations.checkMergeEligibility;
import static com.intuit.graphql.orchestrator.utils.DescriptionUtils.mergeDescriptions;
import static com.intuit.graphql.orchestrator.xtext.DataFetcherContext.STATIC_DATAFETCHER_CONTEXT;
import static com.intuit.graphql.orchestrator.xtext.GraphQLFactoryDelegate.createObjectType;
import static com.intuit.graphql.utils.XtextTypeUtils.unwrapAll;

import com.intuit.graphql.graphQL.EnumTypeDefinition;
import com.intuit.graphql.graphQL.EnumValueDefinition;
import com.intuit.graphql.graphQL.FieldDefinition;
Expand All @@ -19,9 +25,6 @@
import com.intuit.graphql.orchestrator.xtext.FieldContext;
import com.intuit.graphql.orchestrator.xtext.XtextGraph;
import com.intuit.graphql.utils.XtextTypeUtils;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.util.EcoreUtil;

import java.util.Collection;
import java.util.EnumMap;
import java.util.HashMap;
Expand All @@ -30,12 +33,8 @@
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import static com.intuit.graphql.orchestrator.schema.fold.FieldMergeValidations.checkMergeEligibility;
import static com.intuit.graphql.orchestrator.utils.DescriptionUtils.mergeDescriptions;
import static com.intuit.graphql.orchestrator.xtext.DataFetcherContext.STATIC_DATAFETCHER_CONTEXT;
import static com.intuit.graphql.orchestrator.xtext.GraphQLFactoryDelegate.createObjectType;
import static com.intuit.graphql.utils.XtextTypeUtils.unwrapAll;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.util.EcoreUtil;

public class XtextGraphFolder implements Foldable<XtextGraph> {

Expand Down Expand Up @@ -69,18 +68,21 @@ private XtextGraph merge(XtextGraph accumulator, XtextGraph current) {
merge(accumulator.getOperationType(op), current.getOperationType(op), current.getServiceProvider()));
}

if(current.isFederationService()) {
if (current.getServiceProvider().isFederationProvider()) {
current.getValueTypesByName().values()
.forEach(incomingSharedType -> {
TypeDefinition preexistingTypeDefinition = accumulator.getType(incomingSharedType.getName());
if(incomingSharedType instanceof EnumTypeDefinition) {
mergeSharedValueType((EnumTypeDefinition) preexistingTypeDefinition, (EnumTypeDefinition) incomingSharedType, current.getServiceProvider());
} else if(incomingSharedType instanceof ObjectTypeDefinition) {
mergeSharedValueType((ObjectTypeDefinition) preexistingTypeDefinition, (ObjectTypeDefinition) incomingSharedType, current.getServiceProvider());
} else if(incomingSharedType instanceof InterfaceTypeDefinition) {
mergeSharedValueType((InterfaceTypeDefinition) preexistingTypeDefinition, (InterfaceTypeDefinition) incomingSharedType, current.getServiceProvider());
}
});
.forEach(incomingSharedType -> {
TypeDefinition preexistingTypeDefinition = accumulator.getType(incomingSharedType.getName());
if (incomingSharedType instanceof EnumTypeDefinition) {
mergeSharedValueType((EnumTypeDefinition) preexistingTypeDefinition,
(EnumTypeDefinition) incomingSharedType, current.getServiceProvider());
} else if (incomingSharedType instanceof ObjectTypeDefinition) {
mergeSharedValueType((ObjectTypeDefinition) preexistingTypeDefinition,
(ObjectTypeDefinition) incomingSharedType, current.getServiceProvider());
} else if (incomingSharedType instanceof InterfaceTypeDefinition) {
mergeSharedValueType((InterfaceTypeDefinition) preexistingTypeDefinition,
(InterfaceTypeDefinition) incomingSharedType, current.getServiceProvider());
}
});
}

resolveTypeConflicts(accumulator.getTypes(), current.getTypes(), current);
Expand Down Expand Up @@ -118,7 +120,8 @@ private void resolveTypeConflicts(final Map<String, TypeDefinition> existing,
TypeDefinition existingType = existing.get(typeName);
if (Objects.nonNull(existingType) && !nestedTypes.containsKey(existingType.getName())) {
TypeDefinition conflictingType = current.get(typeName);
XtextTypeConflictResolver.INSTANCE.resolve(conflictingType, existingType, currentGraph.getServiceProvider().isFederationProvider());
XtextTypeConflictResolver.INSTANCE
.resolve(conflictingType, existingType, currentGraph.getServiceProvider().isFederationProvider());
}
}
}
Expand Down Expand Up @@ -170,7 +173,7 @@ private ObjectTypeDefinition merge(ObjectTypeDefinition current, ObjectTypeDefin
* @return merged object
*/
private TypeDefinition mergeSharedValueType(EnumTypeDefinition current, EnumTypeDefinition newComer,
ServiceProvider newComerServiceProvider) {
ServiceProvider newComerServiceProvider) {
//nothing to merge
if (current == null || !newComerServiceProvider.isFederationProvider()) {
return current;
Expand All @@ -194,15 +197,15 @@ private TypeDefinition mergeSharedValueType(EnumTypeDefinition current, EnumType
}

private TypeDefinition mergeSharedValueType(ObjectTypeDefinition current, ObjectTypeDefinition newComer,
ServiceProvider newComerServiceProvider) {
ServiceProvider newComerServiceProvider) {
if (current == null || !newComerServiceProvider.isFederationProvider()) {
return current;
}

newComer.getFieldDefinition().forEach(newField -> {
Optional<FieldDefinition> currentField = current.getFieldDefinition().stream()
.filter(fieldName -> newField.getName().equals(fieldName.getName()))
.findFirst();
.filter(fieldName -> newField.getName().equals(fieldName.getName()))
.findFirst();

if (!currentField.isPresent()) {
addNewFieldToObject(current, newField, newComerServiceProvider);
Expand All @@ -217,15 +220,15 @@ private TypeDefinition mergeSharedValueType(ObjectTypeDefinition current, Object
}

private TypeDefinition mergeSharedValueType(InterfaceTypeDefinition current, InterfaceTypeDefinition newComer,
ServiceProvider newComerServiceProvider) {
ServiceProvider newComerServiceProvider) {
if (current == null || !newComerServiceProvider.isFederationProvider()) {
return current;
}

newComer.getFieldDefinition().forEach(newField -> {
Optional<FieldDefinition> currentField = current.getFieldDefinition().stream()
.filter(fieldName -> newField.getName().equals(fieldName.getName()))
.findFirst();
.filter(fieldName -> newField.getName().equals(fieldName.getName()))
.findFirst();

if (!currentField.isPresent()) {
addNewFieldToObject(current, newField, newComerServiceProvider);
Expand Down Expand Up @@ -281,13 +284,13 @@ private void addNewFieldToObject(ObjectTypeDefinition objectTypeDefinition, Fiel


private void addNewFieldToObject(EnumTypeDefinition enumTypeDefinition, EnumValueDefinition valueDefinition,
ServiceProvider serviceProvider) {
ServiceProvider serviceProvider) {
addFieldContextToRegistry(enumTypeDefinition.getName(), valueDefinition.getEnumValue(), serviceProvider);
enumTypeDefinition.getEnumValueDefinition().add(EcoreUtil.copy(valueDefinition));
}

private void addNewFieldToObject(InterfaceTypeDefinition interfaceTypeDefinition, FieldDefinition fieldDefinition,
ServiceProvider serviceProvider) {
ServiceProvider serviceProvider) {
addFieldContextToRegistry(interfaceTypeDefinition.getName(), fieldDefinition.getName(), serviceProvider);
interfaceTypeDefinition.getFieldDefinition().add(EcoreUtil.copy(fieldDefinition));
}
Expand All @@ -297,7 +300,7 @@ private void addFieldContextToRegistry(String parentName, String definitionName,
final FieldContext fieldContext = new FieldContext(parentName, definitionName);

accCodeRegistry.put(fieldContext, DataFetcherContext.newBuilder().namespace(serviceProvider.getNameSpace())
.serviceType(serviceProvider.getSeviceType()).build());
.serviceType(serviceProvider.getSeviceType()).build());
}

/**
Expand Down
Loading

0 comments on commit e12d906

Please sign in to comment.