@Override public Object loadObject(Class<?> entityClass, Serializable id, Optional<FilterExpression> filterExpression, RequestScope scope) { Class idType = dictionary.getIdType(entityClass); String idField = dictionary.getIdFieldName(entityClass); FilterExpression idFilter = new InPredicate( new Path.PathElement(entityClass, idType, idField), id ); FilterExpression joinedFilterExpression = filterExpression .map(fe -> (FilterExpression) new AndFilterExpression(idFilter, fe)) .orElse(idFilter); Iterable<Object> results = loadObjects(entityClass, Optional.of(joinedFilterExpression), Optional.empty(), Optional.empty(), scope); Iterator<Object> it = results == null ? null : results.iterator(); if (it != null && it.hasNext()) { return it.next(); } return null; }
String fieldName = pathElement.getFieldName(); Class<?> typeClass = dictionary.lookupEntityClass(pathElement.getType()); String typeAlias = FilterPredicate.getTypeAlias(typeClass); if (! dictionary.isRelation(pathElement.getType(), fieldName)) { return joinClause.toString();
for (String valueParams : paramValues) { for (String valueParam : valueParams.split(",")) { values.add(CoerceUtil.coerce(valueParam, last.getFieldType()));
FilterPredicate idExpression = new InPredicate(new PathElement(parentType, idType, idField), idVal); new PathElement(parentType, relationship.getChildType(), relationship.getRelationshipName())); FilterExpression scoped = filterExpression .map(fe -> fe.accept(visitor))
String fieldName = keyParts[i + 1]; Class fieldClass = types[i + 1]; Path.PathElement pathElement = new Path.PathElement(typeClass, fieldClass, fieldName);
String fieldName = keyParts[i + 1]; Class fieldClass = types[i + 1]; Path.PathElement pathElement = new Path.PathElement(typeClass, fieldClass, fieldName);
new Path.PathElement(Book.class, Publisher.class, PUBLISHER), new Path.PathElement(Publisher.class, String.class, NAME) );
Path.PathElement idPath = new Path.PathElement(entityClass, idType, idField); if (id != null) { idExpression = new InPredicate(idPath, id);
new Path.PathElement(Book.class, Publisher.class, PUBLISHER), new Path.PathElement(Publisher.class, String.class, "name") );
for (String valueParams : paramValues) { for (String valueParam : valueParams.split(",")) { values.add(CoerceUtil.coerce(valueParam, last.getFieldType()));
Path.PathElement idPath = new Path.PathElement(entityClass, idType, idField); if (id != null) { idExpression = new InPredicate(idPath, id);
Path.PathElement idPath = new Path.PathElement(entityClass, idType, idField); if (id != null) { idExpression = new InPredicate(idPath, id);
new Path.PathElement(Author.class, Book.class, BOOKS), new Path.PathElement(Book.class, Chapter.class, "chapters"), new Path.PathElement(Chapter.class, String.class, TITLE) ); new Path.PathElement(Author.class, Book.class, BOOKS), new Path.PathElement(Book.class, Publisher.class, PUBLISHER), new Path.PathElement(Publisher.class, String.class, "name") );
new Path.PathElement(Book.class, Publisher.class, PUBLISHER), new Path.PathElement(Publisher.class, String.class, NAME) );
@Test public void testRootFetchWithJoinFilter() { List<Path.PathElement> chapterTitlePath = Arrays.asList( new Path.PathElement(Author.class, Book.class, BOOKS), new Path.PathElement(Book.class, Chapter.class, "chapters"), new Path.PathElement(Chapter.class, String.class, TITLE) ); new Path.PathElement(Author.class, Book.class, BOOKS), new Path.PathElement(Book.class, Publisher.class, PUBLISHER), new Path.PathElement(Publisher.class, String.class, "name") );
@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); }
/** * Get the comparator for sorting. * * @param path Path to field for sorting * @param order Order to sort * @param requestScope Request scope * @return Comparator for sorting */ private Comparator<Object> getComparator(Path path, Sorting.SortOrder order, RequestScope requestScope) { return (left, right) -> { Object leftCompare = left; Object rightCompare = right; // Drill down into path to find value for comparison for (Path.PathElement pathElement : path.getPathElements()) { leftCompare = PersistentResource.getValue(leftCompare, pathElement.getFieldName(), requestScope); rightCompare = PersistentResource.getValue(rightCompare, pathElement.getFieldName(), requestScope); } // Make sure value is comparable and perform comparison if (leftCompare instanceof Comparable) { int result = ((Comparable<Object>) leftCompare).compareTo(rightCompare); if (order == Sorting.SortOrder.asc) { return result; } return -result; } throw new IllegalStateException("Trying to comparing non-comparable types!"); }; }
@Test public void testFilterJoinClause() { List<Path.PathElement> chapterTitlePath = Arrays.asList( new Path.PathElement(Author.class, Book.class, BOOKS), new Path.PathElement(Book.class, Chapter.class, "chapters"), new Path.PathElement(Chapter.class, String.class, TITLE) ); FilterPredicate titlePredicate = new InPredicate( new Path(chapterTitlePath), ABC, DEF); FilterPredicate titlePredicateDuplicate = new InPredicate( new Path(chapterTitlePath), ABC, DEF); List<Path.PathElement> publisherNamePath = Arrays.asList( new Path.PathElement(Author.class, Book.class, BOOKS), new Path.PathElement(Book.class, Publisher.class, PUBLISHER), new Path.PathElement(Publisher.class, String.class, NAME) ); FilterPredicate publisherNamePredicate = new InPredicate( new Path(publisherNamePath), "Pub1"); OrFilterExpression orExpression = new OrFilterExpression(titlePredicate, publisherNamePredicate); AndFilterExpression andExpression = new AndFilterExpression(orExpression, titlePredicateDuplicate); String actual = getJoinClauseFromFilters(andExpression); String expected = " LEFT JOIN example_Author.books example_Author_books " + "LEFT JOIN example_Author_books.chapters example_Book_chapters " + "LEFT JOIN example_Author_books.publisher example_Book_publisher "; Assert.assertEquals(actual, expected); }
@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; }
private FilterExpression equalityExpression(String argument, Path path, List<Object> values) { boolean startsWith = argument.startsWith("*"); boolean endsWith = argument.endsWith("*"); if (startsWith && endsWith && argument.length() > 2) { String value = argument.substring(1, argument.length() - 1); return new FilterPredicate(path, caseSensitivityStrategy.mapOperator(Operator.INFIX), Collections.singletonList(value)); } if (startsWith && argument.length() > 1) { String value = argument.substring(1, argument.length()); return new FilterPredicate(path, caseSensitivityStrategy.mapOperator(Operator.POSTFIX), Collections.singletonList(value)); } if (endsWith && argument.length() > 1) { String value = argument.substring(0, argument.length() - 1); return new FilterPredicate(path, caseSensitivityStrategy.mapOperator(Operator.PREFIX), Collections.singletonList(value)); } Boolean isStringLike = path.lastElement() .map(e -> e.getFieldType().isAssignableFrom(String.class)) .orElse(false); if (isStringLike) { return new FilterPredicate(path, caseSensitivityStrategy.mapOperator(Operator.IN), values); } return new InPredicate(path, values); }