use of com.yahoo.elide.core.type.Type in project elide by yahoo.
the class RootCollectionFetchQueryBuilder method build.
/**
* Constructs a query that fetches a root collection.
*
* @return the constructed query
*/
@Override
public Query build() {
Type<?> entityClass = this.entityProjection.getType();
String entityName = entityClass.getCanonicalName();
String entityAlias = getTypeAlias(entityClass);
Query query;
FilterExpression filterExpression = entityProjection.getFilterExpression();
if (filterExpression != null) {
PredicateExtractionVisitor extractor = new PredicateExtractionVisitor();
Collection<FilterPredicate> predicates = filterExpression.accept(extractor);
// Build the WHERE clause
String filterClause = WHERE + new FilterTranslator(dictionary).apply(filterExpression, USE_ALIAS);
// Build the JOIN clause
String joinClause = getJoinClauseFromFilters(filterExpression) + getJoinClauseFromSort(entityProjection.getSorting()) + extractToOneMergeJoins(entityClass, entityAlias);
boolean requiresDistinct = entityProjection.getPagination() != null && containsOneToMany(filterExpression);
boolean sortOverRelationship = entityProjection.getSorting() != null && entityProjection.getSorting().getSortingPaths().keySet().stream().anyMatch(path -> path.getPathElements().size() > 1);
if (requiresDistinct && sortOverRelationship) {
// SQL does not support distinct and order by on columns which are not selected
throw new InvalidValueException("Combination of pagination, sorting over relationship and" + " filtering over toMany relationships unsupported");
}
query = session.createQuery(SELECT + (requiresDistinct ? DISTINCT : "") + entityAlias + FROM + entityName + AS + entityAlias + SPACE + joinClause + SPACE + filterClause + SPACE + getSortClause(entityProjection.getSorting()));
// Fill in the query parameters
supplyFilterQueryParameters(query, predicates);
} else {
query = session.createQuery(SELECT + entityAlias + FROM + entityName + AS + entityAlias + SPACE + getJoinClauseFromSort(entityProjection.getSorting()) + extractToOneMergeJoins(entityClass, entityAlias) + SPACE + getSortClause(entityProjection.getSorting()));
}
addPaginationToQuery(query);
return query;
}
use of com.yahoo.elide.core.type.Type in project elide by yahoo.
the class SubscriptionModelBuilder 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<?>> subscriptionClasses = allClasses.stream().filter((cls) -> entityDictionary.getAnnotation(cls, Subscription.class) != null).collect(Collectors.toSet());
/* Construct root object */
GraphQLObjectType.Builder root = newObject().name("Subscription");
for (Type<?> clazz : subscriptionClasses) {
Subscription subscription = entityDictionary.getAnnotation(clazz, Subscription.class);
if (subscription == null) {
continue;
}
GraphQLObjectType subscriptionType = buildQueryObject(clazz);
String entityName = entityDictionary.getJsonAliasFor(clazz);
GraphQLFieldDefinition.Builder rootFieldDefinitionBuilder = newFieldDefinition().name(entityName).description(EntityDictionary.getEntityDescription(clazz)).argument(filterArgument).type(subscriptionType);
if (subscription.operations() != null && subscription.operations().length > 0) {
GraphQLEnumType.Builder topicTypeBuilder = newEnum().name(nameUtils.toTopicName(clazz));
for (Subscription.Operation operation : subscription.operations()) {
TopicType topicType = TopicType.fromOperation(operation);
topicTypeBuilder.value(topicType.name(), topicType);
}
topicTypeBuilder.definition(EnumTypeDefinition.newEnumTypeDefinition().build());
rootFieldDefinitionBuilder.argument(GraphQLArgument.newArgument().name(TOPIC_ARGUMENT).type(topicTypeBuilder.build()).build());
}
root.field(rootFieldDefinitionBuilder.build());
}
GraphQLObjectType queryRoot = root.build();
for (Type<?> relationshipType : relationshipTypes) {
this.buildQueryObject(relationshipType);
}
// Attach the client provided dataFetcher to all of the GraphQL subscription objects.
GraphQLCodeRegistry.Builder codeRegistry = GraphQLCodeRegistry.newCodeRegistry();
Set<GraphQLObjectType> objectsThatNeedAFetcher = new HashSet<>(queryObjectRegistry.values());
objectsThatNeedAFetcher.addAll(generator.getObjectTypes());
objectsThatNeedAFetcher.add(queryRoot);
for (GraphQLObjectType objectType : objectsThatNeedAFetcher) {
String objectName = objectType.getName();
for (GraphQLFieldDefinition fieldDefinition : objectType.getFieldDefinitions()) {
codeRegistry.dataFetcher(FieldCoordinates.coordinates(objectName, fieldDefinition.getName()), dataFetcher);
}
}
/* Construct the schema */
GraphQLSchema schema = GraphQLSchema.newSchema().subscription(queryRoot).query(queryRoot).codeRegistry(codeRegistry.build()).additionalTypes(Sets.newHashSet(queryObjectRegistry.values())).build();
return schema;
}
use of com.yahoo.elide.core.type.Type in project elide by yahoo.
the class JsonApiModelResolver method resolve.
@Override
public Model resolve(java.lang.reflect.Type type, ModelConverterContext context, Iterator<ModelConverter> next) {
if (!(type instanceof Class || type instanceof SimpleType || type instanceof Type)) {
return super.resolve(type, context, next);
}
Type<?> clazzType = null;
/*
* If an Elide entity is an attribute somewhere in a model, the ModelResolver will
* end up wrapping this as a SimpleType (rather than trying to resolve the entity class directly).
*/
if (type instanceof SimpleType) {
type = ((SimpleType) type).getRawClass();
clazzType = ClassType.of((Class<?>) type);
} else if (type instanceof Type) {
clazzType = (Type<?>) type;
} else if (type instanceof Class) {
clazzType = ClassType.of((Class<?>) type);
}
/* Not an entity managed by Elide, let Swagger convert it */
String typeAlias;
try {
typeAlias = dictionary.getJsonAliasFor(clazzType);
} catch (IllegalArgumentException e) {
return super.resolve(type, context, next);
}
Resource entitySchema = new Resource();
entitySchema.description(getModelDescription(clazzType));
entitySchema.setSecurityDescription(getClassPermissions(clazzType));
/* Populate the attributes */
List<String> attributeNames = dictionary.getAttributes(clazzType);
for (String attributeName : attributeNames) {
Type<?> attributeType = dictionary.getType(clazzType, attributeName);
Property attribute = processAttribute(clazzType, attributeName, attributeType, context, next);
entitySchema.addAttribute(attributeName, attribute);
}
/* Populate the relationships */
List<String> relationshipNames = dictionary.getRelationships(clazzType);
for (String relationshipName : relationshipNames) {
Type<?> relationshipType = dictionary.getParameterizedType(clazzType, relationshipName);
Relationship relationship = processRelationship(clazzType, relationshipName, relationshipType);
if (relationship != null) {
entitySchema.addRelationship(relationshipName, relationship);
}
}
entitySchema.name(typeAlias);
return entitySchema;
}
use of com.yahoo.elide.core.type.Type in project elide by yahoo.
the class PersistentResource method getRelation.
/**
* Load a relation from the PersistentResource.
*
* @param relationship the relation
* @param ids a list of object identifiers to optionally load. Can be empty.
* @return PersistentResource relation
*/
public Observable<PersistentResource> getRelation(List<String> ids, com.yahoo.elide.core.request.Relationship relationship) {
FilterExpression filterExpression = Optional.ofNullable(relationship.getProjection().getFilterExpression()).orElse(null);
assertPropertyExists(relationship.getName());
Type<?> entityType = dictionary.getParameterizedType(getResourceType(), relationship.getName());
Set<PersistentResource> newResources = new LinkedHashSet<>();
/* If this is a bulk edit request and the ID we are fetching for is newly created... */
if (!ids.isEmpty()) {
// Fetch our set of new resources that we know about since we can't find them in the datastore
newResources = requestScope.getNewPersistentResources().stream().filter(resource -> entityType.isAssignableFrom(resource.getResourceType()) && ids.contains(resource.getUUID().orElse(""))).collect(Collectors.toSet());
FilterExpression idExpression = buildIdFilterExpression(ids, entityType, dictionary, requestScope);
// Combine filters if necessary
filterExpression = Optional.ofNullable(relationship.getProjection().getFilterExpression()).map(fe -> (FilterExpression) new AndFilterExpression(idExpression, fe)).orElse(idExpression);
}
// TODO: Filter on new resources?
// TODO: Update pagination to subtract the number of new resources created?
Observable<PersistentResource> existingResources = filter(ReadPermission.class, Optional.ofNullable(filterExpression), relationship.getProjection().getRequestedFields(), getRelation(relationship.copyOf().projection(relationship.getProjection().copyOf().filterExpression(filterExpression).build()).build(), true));
// 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(), relationship.getName());
}
});
return allResources;
}
use of com.yahoo.elide.core.type.Type in project elide by yahoo.
the class PersistentResource method createObject.
/**
* Create a resource in the database.
*
* @param parent - The immediate ancestor in the lineage or null if this is a root.
* @param parentRelationship - The name of the parent relationship traversed to create this object.
* @param entityClass the entity class
* @param requestScope the request scope
* @param uuid the (optional) uuid
* @param <T> object type
* @return persistent resource
*/
public static <T> PersistentResource<T> createObject(PersistentResource<?> parent, String parentRelationship, Type<T> entityClass, RequestScope requestScope, Optional<String> uuid) {
T obj = requestScope.getTransaction().createNewObject(entityClass, requestScope);
String id = uuid.orElse(null);
PersistentResource<T> newResource = new PersistentResource<>(obj, parent, parentRelationship, id, requestScope);
// The ID must be assigned before we add it to the new resources set. Persistent resource
// hashcode and equals are only based on the ID/UUID & type.
assignId(newResource, id);
// Keep track of new resources for non-transferable resources
requestScope.getNewPersistentResources().add(newResource);
checkPermission(CreatePermission.class, newResource);
newResource.auditClass(Audit.Action.CREATE, new ChangeSpec(newResource, null, null, newResource.getObject()));
requestScope.publishLifecycleEvent(newResource, CREATE);
requestScope.setUUIDForObject(newResource.type, id, newResource.getObject());
// Initialize null ToMany collections
requestScope.getDictionary().getRelationships(entityClass).stream().filter(relationName -> newResource.getRelationshipType(relationName).isToMany() && newResource.getValueUnchecked(relationName) == null).forEach(relationName -> newResource.setValue(relationName, new LinkedHashSet<>()));
newResource.markDirty();
return newResource;
}
Aggregations