use of com.yahoo.elide.jsonapi.models.Relationship in project elide by yahoo.
the class PersistentResourceTest method testTransferPermissionSuccessOnUpdateSingularRelationship.
@Test
public void testTransferPermissionSuccessOnUpdateSingularRelationship() {
example.User userModel = new example.User();
userModel.setId(1);
NoShareEntity noShare = new NoShareEntity();
/* The noshare already exists so no exception should be thrown */
userModel.setNoShare(noShare);
List<Resource> idList = new ArrayList<>();
idList.add(new ResourceIdentifier("noshare", "1").castToResource());
Relationship ids = new Relationship(null, new Data<>(idList));
when(tx.getToOneRelation(any(), eq(userModel), any(), any())).thenReturn(noShare);
when(tx.loadObject(any(), eq(1L), any())).thenReturn(noShare);
RequestScope goodScope = buildRequestScope(tx, goodUser);
PersistentResource<example.User> userResource = new PersistentResource<>(userModel, goodScope.getUUIDFor(userModel), goodScope);
boolean returnVal = userResource.updateRelation("noShare", ids.toPersistentResources(goodScope));
assertFalse(returnVal);
assertEquals(noShare, userModel.getNoShare());
}
use of com.yahoo.elide.jsonapi.models.Relationship 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.jsonapi.models.Relationship 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;
}
use of com.yahoo.elide.jsonapi.models.Relationship in project elide by yahoo.
the class CollectionTerminalState method createObject.
private PersistentResource createObject(RequestScope requestScope) throws ForbiddenAccessException, InvalidObjectIdentifierException {
JsonApiDocument doc = requestScope.getJsonApiDocument();
JsonApiMapper mapper = requestScope.getMapper();
if (doc.getData() == null) {
throw new InvalidEntityBodyException("Invalid JSON-API document: " + doc);
}
Data<Resource> data = doc.getData();
Collection<Resource> resources = data.get();
Resource resource = (resources.size() == 1) ? IterableUtils.first(resources) : null;
if (resource == null) {
try {
throw new InvalidEntityBodyException(mapper.writeJsonApiDocument(doc));
} catch (JsonProcessingException e) {
throw new InternalServerErrorException(e);
}
}
String id = resource.getId();
Type<?> newObjectClass = requestScope.getDictionary().getEntityClass(resource.getType(), requestScope.getApiVersion());
if (newObjectClass == null) {
throw new UnknownEntityException("Entity " + resource.getType() + " not found");
}
if (!entityClass.isAssignableFrom(newObjectClass)) {
throw new InvalidValueException("Cannot assign value of type: " + resource.getType() + " to type: " + entityClass);
}
PersistentResource pResource = PersistentResource.createObject(parent.orElse(null), relationName.orElse(null), newObjectClass, requestScope, Optional.ofNullable(id));
Map<String, Object> attributes = resource.getAttributes();
if (attributes != null) {
for (Map.Entry<String, Object> entry : attributes.entrySet()) {
String fieldName = entry.getKey();
Object val = entry.getValue();
pResource.updateAttribute(fieldName, val);
}
}
Map<String, Relationship> relationships = resource.getRelationships();
if (relationships != null) {
for (Map.Entry<String, Relationship> entry : relationships.entrySet()) {
String fieldName = entry.getKey();
Relationship relationship = entry.getValue();
Set<PersistentResource> resourceSet = (relationship == null) ? null : relationship.toPersistentResources(requestScope);
pResource.updateRelation(fieldName, resourceSet);
}
}
return pResource;
}
use of com.yahoo.elide.jsonapi.models.Relationship in project elide by yahoo.
the class RelationshipTerminalState method handleGet.
@Override
public Supplier<Pair<Integer, JsonNode>> handleGet(StateContext state) {
JsonApiDocument doc = new JsonApiDocument();
RequestScope requestScope = state.getRequestScope();
JsonApiMapper mapper = requestScope.getMapper();
MultivaluedMap<String, String> queryParams = requestScope.getQueryParams();
Map<String, Relationship> relationships = record.toResource(parentProjection).getRelationships();
if (relationships != null && relationships.containsKey(relationshipName)) {
Relationship relationship = relationships.get(relationshipName);
// Handle valid relationship
// Set data
Data<Resource> data = relationship.getData();
doc.setData(data);
// Run include processor
DocumentProcessor includedProcessor = new IncludedProcessor();
includedProcessor.execute(doc, record, queryParams);
return () -> Pair.of(HttpStatus.SC_OK, mapper.toJsonObject(doc));
}
// Handle no data for relationship
if (relationshipType.isToMany()) {
doc.setData(new Data<>(new ArrayList<>()));
} else if (relationshipType.isToOne()) {
doc.setData(new Data<>((Resource) null));
} else {
throw new IllegalStateException("Failed to GET a relationship; relationship is neither toMany nor toOne");
}
return () -> Pair.of(HttpStatus.SC_OK, mapper.toJsonObject(doc));
}
Aggregations