public FilterPredicate negate() { Operator newOp = operator.negate(); return new FilterPredicate(this.path, newOp, this.values); }
private Serializable extractId(FilterExpression filterExpression, String idFieldName, Class<?> relationClass) { Collection<FilterPredicate> predicates = filterExpression.accept(new PredicateExtractionVisitor()); return predicates.stream() .filter(p -> p.getEntityType() == relationClass && p.getOperator() == Operator.IN) .filter(p -> p.getValues().size() == 1) .filter(p -> p.getField().equals(idFieldName)) .findFirst() .map(p -> (Serializable) p.getValues().get(0)) .orElse(null); } }
/** * Applies a filter predicate to the object in question. * * @param object object returned from datastore * @param filterPredicate A predicate from filterExpressionCheck * @param requestScope Request scope object * @return true if the object pass evaluation against Predicate. */ public boolean applyPredicateToObject(T object, FilterPredicate filterPredicate, RequestScope requestScope) { try { String fieldPath = filterPredicate.getFieldPath(); com.yahoo.elide.core.RequestScope scope = coreScope(requestScope); Predicate fn = filterPredicate.getOperator().contextualize(fieldPath, filterPredicate.getValues(), scope); return fn.test(object); } catch (Exception e) { log.error("Failed to apply predicate {}", filterPredicate, e); return false; } }
/** * Compute the parameter value/name pairings. * @return the filter parameters for this predicate */ public List<FilterParameter> getParameters() { String baseName = String.format("%s_%s_", getFieldPath().replace(PERIOD, UNDERSCORE), Integer.toHexString(hashCode())); return IntStream.range(0, values.size()) .mapToObj(idx -> new FilterParameter(String.format("%s%d", baseName, idx), values.get(idx))) .collect(Collectors.toList()); }
String fieldPath = filterPredicate.getFieldPath(); fieldPath = filterPredicate.getAlias() + "." + filterPredicate.getField(); List<FilterParameter> params = filterPredicate.getParameters(); String firstParam = params.size() > 0 ? params.get(0).getPlaceholder() : null; switch (filterPredicate.getOperator()) { case IN: Preconditions.checkState(!filterPredicate.getValues().isEmpty()); return String.format("%s IN (%s)", fieldPath, params.stream() .map(FilterParameter::getPlaceholder) Preconditions.checkState(!filterPredicate.getValues().isEmpty()); return String.format("lower(%s) IN (%s)", fieldPath, params.stream() .map(LOWERED_PARAMETER) Preconditions.checkState(!filterPredicate.getValues().isEmpty()); return String.format("%s NOT IN (%s)", fieldPath, params.stream() .map(FilterParameter::getPlaceholder) Preconditions.checkState(!filterPredicate.getValues().isEmpty()); return String.format("lower(%s) NOT IN (%s)", fieldPath, params.stream() .map(LOWERED_PARAMETER) throw new InvalidPredicateException("Operator not implemented: " + filterPredicate.getOperator());
/** * Given a collection of filter predicates and a Hibernate query, populates the named parameters in the * Hibernate query. * * @param query The HQL query * @param predicates The predicates to extract named parameter values from */ protected void supplyFilterQueryParameters(Query query, Collection<FilterPredicate> predicates) { for (FilterPredicate filterPredicate : predicates) { if (filterPredicate.getOperator().isParameterized()) { boolean shouldEscape = filterPredicate.isMatchingOperator(); filterPredicate.getParameters().forEach(param -> { query.setParameter(param.getName(), shouldEscape ? param.escapeMatching() : param.getValue()); }); } } }
@Override public Map<String, FilterExpression> parseTypedExpression(String path, MultivaluedMap<String, String> filterParams) throws ParseException { Map<String, FilterExpression> expressionMap = new HashMap<>(); List<FilterPredicate> filterPredicates = extractPredicates(filterParams); for (FilterPredicate filterPredicate : filterPredicates) { if (FilterPredicate.toManyInPath(dictionary, filterPredicate.getPath())) { throw new ParseException("Invalid toMany join: " + 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; }
Path path = buildPath(entityType, relationship); if (FilterPredicate.toManyInPath(dictionary, path) && !allowNestedToManyAssociations) { throw new RSQLParseException(String.format("Invalid association %s", relationship)); return new FilterPredicate(path, OPERATOR_MAP.get(op), values);
/** * Returns an alias that uniquely identifies the last collection of entities in the path. * @return An alias for the path. */ public String getAlias() { List<PathElement> elements = path.getPathElements(); PathElement last = elements.get(elements.size() - 1); if (elements.size() == 1) { return getTypeAlias(last.getType()); } PathElement previous = elements.get(elements.size() - 2); return getTypeAlias(previous.getType()) + UNDERSCORE + previous.getFieldName(); }
for (Path.PathElement pathElement : predicate.getPath().getPathElements()) { String fieldName = pathElement.getFieldName(); Class<?> typeClass = dictionary.lookupEntityClass(pathElement.getType()); String typeAlias = FilterPredicate.getTypeAlias(typeClass);
private Operator operator(FilterExpression expression) { return expression instanceof FilterPredicate ? ((FilterPredicate) expression).getOperator() : null; }
@Override public Predicate apply(RequestScope dictionary) { return operator.contextualize(getFieldPath(), values, dictionary); }
@Override public FilterExpression parseGlobalExpression(String path, MultivaluedMap<String, String> filterParams) throws ParseException { List<FilterPredicate> filterPredicates; filterPredicates = extractPredicates(filterParams); /* 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) { Class 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 (joinedExpression == null) { joinedExpression = filterPredicate; } else { joinedExpression = new AndFilterExpression(joinedExpression, filterPredicate); } } return joinedExpression; }
@Test public void testHQLQueryVisitor() throws Exception { List<Path.PathElement> p1Path = Arrays.asList( new Path.PathElement(Book.class, Author.class, "authors"), new Path.PathElement(Author.class, String.class, "name") ); FilterPredicate p1 = new InPredicate(new Path(p1Path), "foo", "bar"); List<Path.PathElement> p2Path = Arrays.asList( new Path.PathElement(Book.class, String.class, "name") ); FilterPredicate p2 = new InPredicate(new Path(p2Path), "blah"); List<Path.PathElement> p3Path = Arrays.asList( new Path.PathElement(Book.class, String.class, "genre") ); FilterPredicate p3 = new InPredicate(new Path(p3Path), "scifi"); OrFilterExpression or = new OrFilterExpression(p2, p3); AndFilterExpression and = new AndFilterExpression(or, p1); NotFilterExpression not = new NotFilterExpression(and); HQLFilterOperation filterOp = new HQLFilterOperation(); String query = filterOp.apply(not, false); String p1Params = p1.getParameters().stream() .map(FilterPredicate.FilterParameter::getPlaceholder).collect(Collectors.joining(", ")); String p2Params = p2.getParameters().stream() .map(FilterPredicate.FilterParameter::getPlaceholder).collect(Collectors.joining(", ")); String p3Params = p3.getParameters().stream() .map(FilterPredicate.FilterParameter::getPlaceholder).collect(Collectors.joining(", ")); String expected = "WHERE NOT (((name IN (" + p2Params + ") OR genre IN (" + p3Params + ")) " + "AND authors.name IN (" + p1Params + ")))"; Assert.assertEquals(query, expected); }
@Override public Map<String, FilterExpression> parseTypedExpression(String path, MultivaluedMap<String, String> filterParams) throws ParseException { Map<String, FilterExpression> expressionMap = new HashMap<>(); List<FilterPredicate> filterPredicates = extractPredicates(filterParams); for (FilterPredicate filterPredicate : filterPredicates) { if (FilterPredicate.toManyInPath(dictionary, filterPredicate.getPath())) { throw new ParseException("Invalid toMany join: " + 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; }
Path path = buildPath(entityType, relationship); if (FilterPredicate.toManyInPath(dictionary, path) && !allowNestedToManyAssociations) { throw new RSQLParseException(String.format("Invalid association %s", relationship)); return new FilterPredicate(path, OPERATOR_MAP.get(op), values);
/** * Returns an alias that uniquely identifies the last collection of entities in the path. * @return An alias for the path. */ public String getAlias() { List<PathElement> elements = path.getPathElements(); PathElement last = elements.get(elements.size() - 1); if (elements.size() == 1) { return getTypeAlias(last.getType()); } PathElement previous = elements.get(elements.size() - 2); return getTypeAlias(previous.getType()) + UNDERSCORE + previous.getFieldName(); }
private Operator operator(FilterExpression expression) { return expression instanceof FilterPredicate ? ((FilterPredicate) expression).getOperator() : null; }
/** * Compute the parameter value/name pairings. * @return the filter parameters for this predicate */ public List<FilterParameter> getParameters() { String baseName = String.format("%s_%s_", getFieldPath().replace(PERIOD, UNDERSCORE), Integer.toHexString(hashCode())); return IntStream.range(0, values.size()) .mapToObj(idx -> new FilterParameter(String.format("%s%d", baseName, idx), values.get(idx))) .collect(Collectors.toList()); }
@Override public Predicate apply(RequestScope dictionary) { return operator.contextualize(getFieldPath(), values, dictionary); }