Search in sources :

Example 1 with Path

use of com.yahoo.elide.core.Path in project elide by yahoo.

the class DefaultFilterDialect method getPath.

/**
 * Parses [ author, books, publisher, name ] into [(author, books), (book, publisher), (publisher, name)].
 *
 * @param keyParts [ author, books, publisher, name ]
 * @param apiVersion The client requested version.
 * @return [(author, books), (book, publisher), (publisher, name)]
 * @throws ParseException if the filter cannot be parsed
 */
private Path getPath(final String[] keyParts, String apiVersion) throws ParseException {
    if (keyParts == null || keyParts.length <= 0) {
        throw new ParseException("Invalid filter expression");
    }
    List<Path.PathElement> path = new ArrayList<>();
    Type<?>[] types = new Type[keyParts.length];
    String type = keyParts[0];
    types[0] = dictionary.getEntityClass(type, apiVersion);
    if (types[0] == null) {
        throw new ParseException("Unknown entity in filter: " + type);
    }
    /* Extract all the paths for the associations */
    for (int i = 1; i < keyParts.length; ++i) {
        final String field = keyParts[i];
        final Type<?> entityClass = types[i - 1];
        final Type<?> fieldType = ("id".equals(field.toLowerCase(Locale.ENGLISH))) ? dictionary.getIdType(entityClass) : dictionary.getParameterizedType(entityClass, field);
        if (fieldType == null) {
            throw new ParseException("Unknown field in filter: " + field);
        }
        types[i] = fieldType;
    }
    /* Build all the Predicate path elements */
    for (int i = 0; i < types.length - 1; ++i) {
        Type typeClass = types[i];
        String fieldName = keyParts[i + 1];
        Type fieldClass = types[i + 1];
        Path.PathElement pathElement = new Path.PathElement(typeClass, fieldClass, fieldName);
        path.add(pathElement);
    }
    return new Path(path);
}
Also used : Path(com.yahoo.elide.core.Path) Type(com.yahoo.elide.core.type.Type) ArrayList(java.util.ArrayList) ParseException(com.yahoo.elide.core.filter.dialect.ParseException)

Example 2 with Path

use of com.yahoo.elide.core.Path in project elide by yahoo.

the class EntityProjectionMakerTest method testRelationshipsAndIncludeWithFilterAndSort.

@Test
public void testRelationshipsAndIncludeWithFilterAndSort() {
    MultivaluedMap<String, String> queryParams = new MultivaluedHashMap<>();
    queryParams.add("include", "authors");
    queryParams.add("filter[author]", "name=='Foo'");
    queryParams.add("filter[publisher]", "name=='Foo'");
    queryParams.add("sort", "name");
    String path = "/book/1/relationships/publisher";
    Sorting sorting = SortingImpl.parseSortRule("name", ClassType.of(Publisher.class), dictionary);
    RequestScope scope = new TestRequestScope(dictionary, path, queryParams);
    EntityProjectionMaker maker = new EntityProjectionMaker(dictionary, scope);
    EntityProjection expected = EntityProjection.builder().type(Book.class).relationship("publisher", EntityProjection.builder().type(Publisher.class).filterExpression(new InPredicate(new Path(Publisher.class, dictionary, "name"), "Foo")).sorting(sorting).pagination(PaginationImpl.getDefaultPagination(ClassType.of(Publisher.class))).build()).relationship("authors", EntityProjection.builder().attribute(Attribute.builder().name("name").type(String.class).build()).attribute(Attribute.builder().name("type").type(Author.AuthorType.class).build()).attribute(Attribute.builder().name("homeAddress").type(Address.class).build()).attribute(Attribute.builder().name("vacationHomes").type(Set.class).build()).attribute(Attribute.builder().name("stuff").type(Map.class).build()).attribute(Attribute.builder().name("awards").type(Collection.class).build()).filterExpression(new InPredicate(new Path(Author.class, dictionary, "name"), "Foo")).relationship("books", EntityProjection.builder().type(Book.class).build()).type(Author.class).build()).relationship("editor", EntityProjection.builder().type(Editor.class).build()).build();
    EntityProjection actual = maker.parsePath(path);
    projectionEquals(expected, actual);
}
Also used : TestRequestScope(com.yahoo.elide.core.TestRequestScope) Path(com.yahoo.elide.core.Path) EntityProjection(com.yahoo.elide.core.request.EntityProjection) Set(java.util.Set) Publisher(example.Publisher) InPredicate(com.yahoo.elide.core.filter.predicates.InPredicate) RequestScope(com.yahoo.elide.core.RequestScope) TestRequestScope(com.yahoo.elide.core.TestRequestScope) Sorting(com.yahoo.elide.core.request.Sorting) MultivaluedHashMap(javax.ws.rs.core.MultivaluedHashMap) Book(example.Book) Collection(java.util.Collection) Editor(example.Editor) Test(org.junit.jupiter.api.Test)

Example 3 with Path

use of com.yahoo.elide.core.Path in project elide by yahoo.

the class EntityProjectionMakerTest method testRootCollectionWithGlobalFilter.

@Test
public void testRootCollectionWithGlobalFilter() {
    MultivaluedMap<String, String> queryParams = new MultivaluedHashMap<>();
    queryParams.add("filter", "genre=='Science Fiction'");
    String path = "/book";
    RequestScope scope = new TestRequestScope(dictionary, path, queryParams);
    FilterExpression expression = new InPredicate(new Path(Book.class, dictionary, "genre"), "Science Fiction");
    EntityProjectionMaker maker = new EntityProjectionMaker(dictionary, scope);
    EntityProjection expected = EntityProjection.builder().type(Book.class).attribute(Attribute.builder().name("language").type(String.class).build()).attribute(Attribute.builder().name("genre").type(String.class).build()).attribute(Attribute.builder().name("title").type(String.class).build()).attribute(Attribute.builder().name("awards").type(Collection.class).build()).attribute(Attribute.builder().name("publishDate").type(long.class).build()).attribute(Attribute.builder().name("authorTypes").type(Collection.class).build()).attribute(Attribute.builder().name("price").type(Price.class).build()).filterExpression(expression).relationship("publisher", EntityProjection.builder().type(Publisher.class).build()).relationship("editor", EntityProjection.builder().type(Editor.class).build()).relationship("authors", EntityProjection.builder().type(Author.class).build()).pagination(PaginationImpl.getDefaultPagination(ClassType.of(Book.class))).build();
    EntityProjection actual = maker.parsePath(path);
    projectionEquals(expected, actual);
}
Also used : TestRequestScope(com.yahoo.elide.core.TestRequestScope) Path(com.yahoo.elide.core.Path) EntityProjection(com.yahoo.elide.core.request.EntityProjection) InPredicate(com.yahoo.elide.core.filter.predicates.InPredicate) RequestScope(com.yahoo.elide.core.RequestScope) TestRequestScope(com.yahoo.elide.core.TestRequestScope) MultivaluedHashMap(javax.ws.rs.core.MultivaluedHashMap) Book(example.Book) Collection(java.util.Collection) FilterExpression(com.yahoo.elide.core.filter.expression.FilterExpression) Editor(example.Editor) Test(org.junit.jupiter.api.Test)

Example 4 with Path

use of com.yahoo.elide.core.Path in project elide by yahoo.

the class SortingImpl method getValidSortingRules.

/**
 * Given the sorting rules validate sorting rules against the entities bound to the entityClass.
 * @param entityClass  The root class for sorting (eg. /book?sort=-title this would be package.Book)
 * @param attributes  The attributes that are being requested for the sorted model
 * @param dictionary The elide entity dictionary
 * @param <T> The entityClass
 * @return The valid sorting rules - validated through the entity dictionary, or empty dictionary
 * @throws InvalidValueException when sorting values are not valid for the jpa entity
 */
private <T> Map<Path, SortOrder> getValidSortingRules(final Type<T> entityClass, final Set<Attribute> attributes, final EntityDictionary dictionary) throws InvalidValueException {
    Map<Path, SortOrder> returnMap = new LinkedHashMap<>();
    for (Map.Entry<String, SortOrder> entry : replaceIdRule(dictionary.getIdFieldName(entityClass)).entrySet()) {
        String dotSeparatedPath = entry.getKey();
        SortOrder order = entry.getValue();
        Path path;
        if (dotSeparatedPath.contains(".")) {
            // Creating a path validates that the dot separated path is valid.
            path = new Path(entityClass, dictionary, dotSeparatedPath);
        } else {
            Attribute attribute = attributes.stream().filter(attr -> attr.getName().equals(dotSeparatedPath) || attr.getAlias().equals(dotSeparatedPath)).findFirst().orElse(null);
            if (attribute == null) {
                path = new Path(entityClass, dictionary, dotSeparatedPath);
            } else {
                path = new Path(entityClass, dictionary, attribute.getName(), attribute.getAlias(), attribute.getArguments());
            }
        }
        if (!isValidSortRulePath(path, dictionary)) {
            throw new InvalidValueException("Cannot sort across a to-many relationship: " + path.getFieldPath());
        }
        returnMap.put(path, order);
    }
    return returnMap;
}
Also used : Path(com.yahoo.elide.core.Path) InvalidValueException(com.yahoo.elide.core.exceptions.InvalidValueException) Attribute(com.yahoo.elide.core.request.Attribute) ToString(lombok.ToString) LinkedHashMap(java.util.LinkedHashMap) MultivaluedMap(javax.ws.rs.core.MultivaluedMap) Map(java.util.Map) LinkedHashMap(java.util.LinkedHashMap)

Example 5 with Path

use of com.yahoo.elide.core.Path in project elide by yahoo.

the class DefaultQueryValidator method validateHavingClause.

@Override
public void validateHavingClause(Query query) {
    FilterExpression havingClause = query.getHavingFilter();
    if (havingClause == null) {
        return;
    }
    havingClause.accept(new PredicateExtractionVisitor()).forEach(predicate -> {
        Path path = predicate.getPath();
        if (path.getPathElements().size() > 1) {
            throw new InvalidOperationException("Relationship traversal not supported for analytic queries.");
        }
        validatePredicate(query, predicate);
        extractFilterProjections(query, havingClause).stream().forEach(projection -> {
            Predicate<ColumnProjection> filterByNameAndArgs = (column) -> (column.getAlias().equals(projection.getAlias()) || column.getName().equals(projection.getName())) && column.getArguments().equals(projection.getArguments());
            // Query by (alias or name) and arguments.   The filter may or may not be using the alias.
            if (query.getColumnProjection(filterByNameAndArgs) == null) {
                Predicate<ColumnProjection> filterByName = (column) -> (column.getAlias().equals(projection.getAlias()) || column.getName().equals(projection.getName()));
                // The column wasn't projected at all.
                if (query.getColumnProjection(filterByName) == null) {
                    throw new InvalidOperationException(String.format("Post aggregation filtering on '%s' requires the field to be projected in the response", projection.getAlias()));
                // The column was projected but arguments didn't match.
                } else {
                    throw new InvalidOperationException(String.format("Post aggregation filtering on '%s' requires the field to be projected " + "in the response with matching arguments", projection.getAlias()));
                }
            }
        });
    });
}
Also used : Path(com.yahoo.elide.core.Path) PredicateExtractionVisitor(com.yahoo.elide.core.filter.expression.PredicateExtractionVisitor) FilterPredicate(com.yahoo.elide.core.filter.predicates.FilterPredicate) Path(com.yahoo.elide.core.Path) Queryable.extractFilterProjections(com.yahoo.elide.datastores.aggregation.query.Queryable.extractFilterProjections) Argument(com.yahoo.elide.core.request.Argument) HashSet(java.util.HashSet) InvalidOperationException(com.yahoo.elide.core.exceptions.InvalidOperationException) Map(java.util.Map) Column(com.yahoo.elide.datastores.aggregation.metadata.models.Column) ColumnProjection(com.yahoo.elide.datastores.aggregation.query.ColumnProjection) FilterExpression(com.yahoo.elide.core.filter.expression.FilterExpression) LinkedHashSet(java.util.LinkedHashSet) Sorting(com.yahoo.elide.core.request.Sorting) Predicate(java.util.function.Predicate) ValueType(com.yahoo.elide.datastores.aggregation.metadata.enums.ValueType) ArgumentDefinition(com.yahoo.elide.datastores.aggregation.metadata.models.ArgumentDefinition) Set(java.util.Set) Collectors(java.util.stream.Collectors) EntityDictionary(com.yahoo.elide.core.dictionary.EntityDictionary) Query(com.yahoo.elide.datastores.aggregation.query.Query) List(java.util.List) Stream(java.util.stream.Stream) SQLTable(com.yahoo.elide.datastores.aggregation.queryengines.sql.metadata.SQLTable) Type(com.yahoo.elide.core.type.Type) Operator(com.yahoo.elide.core.filter.Operator) Optional(java.util.Optional) ColumnProjection(com.yahoo.elide.datastores.aggregation.query.ColumnProjection) PredicateExtractionVisitor(com.yahoo.elide.core.filter.expression.PredicateExtractionVisitor) InvalidOperationException(com.yahoo.elide.core.exceptions.InvalidOperationException) FilterExpression(com.yahoo.elide.core.filter.expression.FilterExpression)

Aggregations

Path (com.yahoo.elide.core.Path)88 Test (org.junit.jupiter.api.Test)67 FilterPredicate (com.yahoo.elide.core.filter.predicates.FilterPredicate)51 FilterExpression (com.yahoo.elide.core.filter.expression.FilterExpression)41 AndFilterExpression (com.yahoo.elide.core.filter.expression.AndFilterExpression)35 Query (com.yahoo.elide.datastores.aggregation.query.Query)35 OrFilterExpression (com.yahoo.elide.core.filter.expression.OrFilterExpression)34 SQLUnitTest (com.yahoo.elide.datastores.aggregation.framework.SQLUnitTest)33 SQLTable (com.yahoo.elide.datastores.aggregation.queryengines.sql.metadata.SQLTable)31 InPredicate (com.yahoo.elide.core.filter.predicates.InPredicate)29 Book (example.Book)29 Day (com.yahoo.elide.datastores.aggregation.timegrains.Day)22 Date (java.util.Date)19 Argument (com.yahoo.elide.core.request.Argument)14 EntityProjection (com.yahoo.elide.core.request.EntityProjection)14 GameRevenue (example.GameRevenue)14 HashSet (java.util.HashSet)14 Author (example.Author)12 Publisher (example.Publisher)9 Sorting (com.yahoo.elide.core.request.Sorting)8