use of com.yahoo.elide.core.filter.expression.AndFilterExpression in project elide by yahoo.
the class SplitFilterExpressionVisitorTest method testVisitOrExpression.
@Test
public void testVisitOrExpression() {
// pure-W OR pure-W
OrFilterExpression filterExpression = new OrFilterExpression(WHERE_PREDICATE, WHERE_PREDICATE);
assertEquals("(playerStats.overallRating IN [foo] OR playerStats.overallRating IN [foo])", splitFilterExpressionVisitor.visitOrExpression(filterExpression).getWhereExpression().toString());
assertNull(splitFilterExpressionVisitor.visitOrExpression(filterExpression).getHavingExpression());
// H1 OR W1
OrFilterExpression or = new OrFilterExpression(HAVING_PREDICATE, WHERE_PREDICATE);
assertNull(splitFilterExpressionVisitor.visitOrExpression(or).getWhereExpression());
assertEquals("(playerStats.highScore GT [99] OR playerStats.overallRating IN [foo])", splitFilterExpressionVisitor.visitOrExpression(or).getHavingExpression().toString());
// (W1 AND H1) OR W2
AndFilterExpression and = new AndFilterExpression(WHERE_PREDICATE, HAVING_PREDICATE);
or = new OrFilterExpression(and, WHERE_PREDICATE);
assertNull(splitFilterExpressionVisitor.visitOrExpression(or).getWhereExpression());
assertEquals("((playerStats.overallRating IN [foo] AND playerStats.highScore GT [99]) OR playerStats.overallRating IN [foo])", splitFilterExpressionVisitor.visitOrExpression(or).getHavingExpression().toString());
}
use of com.yahoo.elide.core.filter.expression.AndFilterExpression 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.filter.expression.AndFilterExpression in project elide by yahoo.
the class DataStoreTransaction method loadObject.
/**
* Loads an object by ID. The reason we support both load by ID and load by filter is that
* some legacy stores are optimized to load by ID.
*
* @param entityProjection the collection to load.
* @param id - the ID of the object to load.
* @param scope - the current request scope
* @param <T> The model type being loaded.
* It is optional for the data store to attempt evaluation.
* @return the loaded object if it exists AND any provided security filters pass.
*/
default <T> T loadObject(EntityProjection entityProjection, Serializable id, RequestScope scope) {
Type<?> entityClass = entityProjection.getType();
FilterExpression filterExpression = entityProjection.getFilterExpression();
EntityDictionary dictionary = scope.getDictionary();
Type idType = dictionary.getIdType(entityClass);
String idField = dictionary.getIdFieldName(entityClass);
FilterExpression idFilter = new InPredicate(new Path.PathElement(entityClass, idType, idField), id);
FilterExpression joinedFilterExpression = (filterExpression != null) ? new AndFilterExpression(idFilter, filterExpression) : idFilter;
Iterable<T> results = loadObjects(entityProjection.copyOf().filterExpression(joinedFilterExpression).build(), scope);
Iterator<T> it = results == null ? null : results.iterator();
if (it != null && it.hasNext()) {
T obj = it.next();
if (!it.hasNext()) {
return obj;
}
// Multiple objects with the same ID.
throw new InvalidObjectIdentifierException(id.toString(), dictionary.getJsonAliasFor(entityClass));
}
return null;
}
use of com.yahoo.elide.core.filter.expression.AndFilterExpression in project elide by yahoo.
the class DefaultFilterDialect method parseGlobalExpression.
@Override
public FilterExpression parseGlobalExpression(String path, MultivaluedMap<String, String> filterParams, String apiVersion) throws ParseException {
List<FilterPredicate> filterPredicates;
filterPredicates = extractPredicates(filterParams, apiVersion);
/* Extract the first collection in the URL */
String normalizedPath = JsonApiParser.normalizePath(path);
String[] pathComponents = normalizedPath.split("/");
String firstPathComponent = "";
if (pathComponents.length > 0) {
firstPathComponent = pathComponents[0];
}
/* Comma separated filter parameters are joined with logical AND. */
FilterExpression joinedExpression = null;
for (FilterPredicate filterPredicate : filterPredicates) {
Type firstClass = filterPredicate.getPath().getPathElements().get(0).getType();
/* The first type in the predicate must match the first collection in the URL */
if (!dictionary.getJsonAliasFor(firstClass).equals(firstPathComponent)) {
throw new ParseException(String.format("Invalid predicate: %s", filterPredicate));
}
if ((filterPredicate.getOperator().equals(Operator.HASMEMBER) || filterPredicate.getOperator().equals(Operator.HASNOMEMBER)) && !FilterPredicate.isLastPathElementAssignableFrom(dictionary, filterPredicate.getPath(), COLLECTION_TYPE)) {
throw new ParseException("Invalid Path: Last Path Element has to be a collection type");
}
if (joinedExpression == null) {
joinedExpression = filterPredicate;
} else {
joinedExpression = new AndFilterExpression(joinedExpression, filterPredicate);
}
}
return joinedExpression;
}
use of com.yahoo.elide.core.filter.expression.AndFilterExpression in project elide by yahoo.
the class DefaultFilterDialect method parseTypedExpression.
@Override
public Map<String, FilterExpression> parseTypedExpression(String path, MultivaluedMap<String, String> filterParams, String apiVersion) throws ParseException {
Map<String, FilterExpression> expressionMap = new HashMap<>();
List<FilterPredicate> filterPredicates = extractPredicates(filterParams, apiVersion);
for (FilterPredicate filterPredicate : filterPredicates) {
validateFilterPredicate(filterPredicate);
String entityType = dictionary.getJsonAliasFor(filterPredicate.getEntityType());
FilterExpression filterExpression = expressionMap.get(entityType);
if (filterExpression != null) {
expressionMap.put(entityType, new AndFilterExpression(filterExpression, filterPredicate));
} else {
expressionMap.put(entityType, filterPredicate);
}
}
return expressionMap;
}
Aggregations