use of com.yahoo.elide.core.type.Type in project elide by yahoo.
the class GraphQLConversionUtils method attributeToQueryObject.
/**
* Helper function which converts an attribute of an entity to a GraphQL Query Type.
* @param parentClass The parent entity class (Can either be an elide entity or not).
* @param attributeClass The attribute class.
* @param attribute The name of the attribute.
* @param fetcher The data fetcher to associated with the newly created GraphQL Query Type
*
* @return A GraphQL Query Type (either newly created or singleton instance for class) or
* null if the underlying type cannot be converted.
*/
protected GraphQLOutputType attributeToQueryObject(Type<?> parentClass, Type<?> attributeClass, String attribute, DataFetcher fetcher, EntityDictionary dictionary) {
/* Determine if we've already processed this item. */
if (outputConversions.containsKey(attributeClass)) {
return outputConversions.get(attributeClass);
}
if (enumConversions.containsKey(attributeClass)) {
return enumConversions.get(attributeClass);
}
/* We don't support Class */
if (ClassType.CLASS_TYPE.isAssignableFrom(attributeClass)) {
return null;
}
/* If the attribute is a map */
if (ClassType.MAP_TYPE.isAssignableFrom(attributeClass)) {
/* Extract the key and value types */
Type<?> keyType = dictionary.getParameterizedType(parentClass, attribute, 0);
Type<?> valueType = dictionary.getParameterizedType(parentClass, attribute, 1);
return classToQueryMap(keyType, valueType, fetcher);
/* If the attribute is a collection */
} else if (ClassType.COLLECTION_TYPE.isAssignableFrom(attributeClass)) {
/* Extract the collection type */
Type<?> listType = dictionary.getParameterizedType(parentClass, attribute, 0);
// If this is a collection of a boxed type scalar, we want to unwrap it properly
return new GraphQLList(fetchScalarOrObjectOutput(listType, fetcher));
}
return fetchScalarOrObjectOutput(attributeClass, fetcher);
}
use of com.yahoo.elide.core.type.Type in project elide by yahoo.
the class MultiplexManager method populateEntityDictionary.
@Override
public void populateEntityDictionary(EntityDictionary dictionary) {
this.dictionary = dictionary;
for (DataStore dataStore : dataStores) {
EntityDictionary subordinateDictionary = new EntityDictionary(dictionary.getCheckMappings(), dictionary.getRoleChecks(), dictionary.getInjector(), dictionary.getSerdeLookup(), dictionary.getEntitiesToExclude(), dictionary.getScanner());
dataStore.populateEntityDictionary(subordinateDictionary);
for (EntityBinding binding : subordinateDictionary.getBindings(false)) {
// route class to this database manager
this.dataStoreMap.put(binding.entityClass, dataStore);
// bind to multiplex dictionary
dictionary.bindEntity(binding);
}
for (Map.Entry<Type<?>, Function<RequestScope, PermissionExecutor>> entry : subordinateDictionary.getEntityPermissionExecutor().entrySet()) {
dictionary.bindPermissionExecutor(entry.getKey(), entry.getValue());
}
}
}
use of com.yahoo.elide.core.type.Type in project elide by yahoo.
the class ModelBuilder method build.
/**
* Builds a GraphQL schema.
* @return The built schema.
*/
public GraphQLSchema build() {
Set<Type<?>> allClasses = entityDictionary.getBoundClassesByVersion(apiVersion);
if (allClasses.isEmpty()) {
throw new IllegalArgumentException("None of the provided classes are exported by Elide");
}
Set<Type<?>> rootClasses = allClasses.stream().filter(entityDictionary::isRoot).collect(Collectors.toSet());
/*
* Walk the object graph (avoiding cycles) and construct the GraphQL input object types.
*/
entityDictionary.walkEntityGraph(rootClasses, this::buildInputObjectStub);
/* Construct root object */
GraphQLObjectType.Builder root = newObject().name(OBJECT_QUERY);
for (Type<?> clazz : rootClasses) {
String entityName = entityDictionary.getJsonAliasFor(clazz);
root.field(newFieldDefinition().name(entityName).description(EntityDictionary.getEntityDescription(clazz)).argument(relationshipOpArg).argument(idArgument).argument(filterArgument).argument(sortArgument).argument(pageFirstArgument).argument(pageOffsetArgument).argument(buildInputObjectArgument(clazz, true)).arguments(generator.entityArgumentToQueryObject(clazz, entityDictionary)).type(buildConnectionObject(clazz)));
}
GraphQLObjectType queryRoot = root.build();
GraphQLObjectType mutationRoot = root.name(OBJECT_MUTATION).build();
objectTypes.add(queryRoot);
objectTypes.add(mutationRoot);
/*
* Walk the object graph (avoiding cycles) and construct the GraphQL output object types.
*/
entityDictionary.walkEntityGraph(rootClasses, this::buildConnectionObject);
GraphQLCodeRegistry.Builder codeRegistry = GraphQLCodeRegistry.newCodeRegistry();
objectTypes.addAll(generator.getObjectTypes());
for (GraphQLObjectType objectType : objectTypes) {
String objectName = objectType.getName();
for (GraphQLFieldDefinition fieldDefinition : objectType.getFieldDefinitions()) {
codeRegistry.dataFetcher(FieldCoordinates.coordinates(objectName, fieldDefinition.getName()), dataFetcher);
}
}
/* Construct the schema */
GraphQLSchema schema = GraphQLSchema.newSchema().query(queryRoot).mutation(mutationRoot).codeRegistry(codeRegistry.build()).additionalTypes(new HashSet<>(CollectionUtils.union(connectionObjectRegistry.values(), inputObjectRegistry.values()))).build();
return schema;
}
use of com.yahoo.elide.core.type.Type in project elide by yahoo.
the class PersistentResourceFetcher method fetchRelationship.
/**
* Fetches a relationship for a top-level entity.
*
* @param parentResource Parent object
* @param relationship constructed relationship object with entityProjection
* @param ids List of ids
* @return persistence resource object(s)
*/
public static ConnectionContainer fetchRelationship(PersistentResource<?> parentResource, @NotNull Relationship relationship, Optional<List<String>> ids) {
EntityDictionary dictionary = parentResource.getRequestScope().getDictionary();
Type relationshipClass = dictionary.getParameterizedType(parentResource.getObject(), relationship.getName());
String relationshipType = dictionary.getJsonAliasFor(relationshipClass);
Set<PersistentResource> relationResources;
if (ids.isPresent()) {
relationResources = parentResource.getRelation(ids.get(), relationship).toList(LinkedHashSet::new).blockingGet();
} else {
relationResources = parentResource.getRelationCheckedFiltered(relationship).toList(LinkedHashSet::new).blockingGet();
}
return new ConnectionContainer(relationResources, Optional.ofNullable(relationship.getProjection().getPagination()), relationshipType);
}
use of com.yahoo.elide.core.type.Type in project elide by yahoo.
the class PersistentResource method loadRecords.
/**
* Load a collection from the datastore.
*
* @param projection the projection to load
* @param requestScope the request scope
* @param ids a list of object identifiers to optionally load. Can be empty.
* @return a filtered collection of resources loaded from the datastore.
*/
public static Observable<PersistentResource> loadRecords(EntityProjection projection, List<String> ids, RequestScope requestScope) {
Type<?> loadClass = projection.getType();
Pagination pagination = projection.getPagination();
Sorting sorting = projection.getSorting();
FilterExpression filterExpression = projection.getFilterExpression();
EntityDictionary dictionary = requestScope.getDictionary();
DataStoreTransaction tx = requestScope.getTransaction();
if (shouldSkipCollection(loadClass, ReadPermission.class, requestScope, projection.getRequestedFields())) {
if (ids.isEmpty()) {
return Observable.empty();
}
throw new InvalidObjectIdentifierException(ids.toString(), dictionary.getJsonAliasFor(loadClass));
}
Set<String> requestedFields = projection.getRequestedFields();
if (pagination != null && !pagination.isDefaultInstance() && !CanPaginateVisitor.canPaginate(loadClass, dictionary, requestScope, requestedFields)) {
throw new BadRequestException(String.format("Cannot paginate %s", dictionary.getJsonAliasFor(loadClass)));
}
Set<PersistentResource> newResources = new LinkedHashSet<>();
if (!ids.isEmpty()) {
String typeAlias = dictionary.getJsonAliasFor(loadClass);
newResources = requestScope.getNewPersistentResources().stream().filter(resource -> typeAlias.equals(resource.getTypeName()) && ids.contains(resource.getUUID().orElse(""))).collect(Collectors.toSet());
FilterExpression idExpression = buildIdFilterExpression(ids, loadClass, dictionary, requestScope);
// Combine filters if necessary
filterExpression = Optional.ofNullable(filterExpression).map(fe -> (FilterExpression) new AndFilterExpression(idExpression, fe)).orElse(idExpression);
}
Optional<FilterExpression> permissionFilter = getPermissionFilterExpression(loadClass, requestScope, requestedFields);
if (permissionFilter.isPresent()) {
if (filterExpression != null) {
filterExpression = new AndFilterExpression(filterExpression, permissionFilter.get());
} else {
filterExpression = permissionFilter.get();
}
}
EntityProjection modifiedProjection = projection.copyOf().filterExpression(filterExpression).sorting(sorting).pagination(pagination).build();
Observable<PersistentResource> existingResources = filter(ReadPermission.class, Optional.ofNullable(modifiedProjection.getFilterExpression()), projection.getRequestedFields(), Observable.fromIterable(new PersistentResourceSet(tx.loadObjects(modifiedProjection, requestScope), requestScope)));
// TODO: Sort again in memory now that two sets are glommed together?
Observable<PersistentResource> allResources = Observable.fromIterable(newResources).mergeWith(existingResources);
Set<String> foundIds = new HashSet<>();
allResources = allResources.doOnNext((resource) -> {
String id = (String) resource.getUUID().orElseGet(resource::getId);
if (ids.contains(id)) {
foundIds.add(id);
}
});
allResources = allResources.doOnComplete(() -> {
Set<String> missedIds = Sets.difference(new HashSet<>(ids), foundIds);
if (!missedIds.isEmpty()) {
throw new InvalidObjectIdentifierException(missedIds.toString(), dictionary.getJsonAliasFor(loadClass));
}
});
return allResources;
}
Aggregations