Skip to content

DATAMONGO-362 - initial support for Specification #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.springframework.data.mongodb.domain;

import com.mysema.query.types.Path;
import com.mysema.query.types.Predicate;

public class Join<T> {


private QueryDslMongodbPredicate<T> queryDslMongodbPredicate;
private Path<?> ref;
private Path<?> target;
private Predicate[] predicate;

<K> Join(Path<K> ref,
Path<K> target,QueryDslMongodbPredicate<T> queryDslMongodbPredicate) {
this.queryDslMongodbPredicate = queryDslMongodbPredicate;
this.ref = ref;
this.target = target;
}


/**
* Apply {@link Predicate} on query to filter {@link T} documents based on joined DBRef properties.
*
* @param conditions
* @return
*/
public QueryDslMongodbPredicate<T> on(Predicate... conditions) {
predicate = conditions;
return this.queryDslMongodbPredicate;
}

@SuppressWarnings("unchecked")
<K> Path<K> getRef() {
return (Path<K>) ref;
}

@SuppressWarnings("unchecked")
<K> Path<K> getTarget() {
return (Path<K>) target;
}

Predicate[] getPredicate() {
return predicate;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.springframework.data.mongodb.domain;

import com.mysema.query.types.ExpressionUtils;
import com.mysema.query.types.Predicate;

public class PredicateBuilder<T> {

private QueryDslMongodbPredicate<T> queryDslMongodbPredicate;

/**
* Apply {@link Predicate}s (if any) on query to filter on {@link T} document properties
*
* @param predicate
* @return
*/
public QueryDslMongodbPredicate<T> where(Predicate... predicate) {
queryDslMongodbPredicate = new QueryDslMongodbPredicate<T>(this);
queryDslMongodbPredicate.predicate = ExpressionUtils.allOf(predicate);
return queryDslMongodbPredicate;
}

/**
* Create a conjunction of the given expressions
*
* @param first
* @param second
* @return
*/
public QueryDslMongodbPredicate<T> and(QueryDslMongodbPredicate<T> first,QueryDslMongodbPredicate<T> second) {
queryDslMongodbPredicate = new QueryDslMongodbPredicate<T>(this);
for (Join<?> join : first.joins) {
queryDslMongodbPredicate.join(join.getRef(), join.getTarget()).on(join.getPredicate());
}
for (Join<?> join : second.joins) {
queryDslMongodbPredicate.join(join.getRef(), join.getTarget()).on(join.getPredicate());
}
queryDslMongodbPredicate.predicate = ExpressionUtils.allOf(new Predicate[]{first.predicate,second.predicate});
return queryDslMongodbPredicate;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.springframework.data.mongodb.domain;

import java.util.ArrayList;
import java.util.List;

import org.springframework.data.mongodb.core.mapping.DBRef;

import com.mysema.query.mongodb.MongodbQuery;
import com.mysema.query.types.Path;
import com.mysema.query.types.Predicate;

public class QueryDslMongodbPredicate<T> {
PredicateBuilder<T> predicateBuilder;

QueryDslMongodbPredicate(PredicateBuilder<T> predicateBuilder) {
this.predicateBuilder = predicateBuilder;
}

Predicate predicate;
List<Join<?>> joins = new ArrayList<Join<?>>();

private <K> Join<T> addJoin(Path<K> ref, Path<K> target){
Join<T> join = new Join<T>(ref, target,this);
joins.add(join);
return join;
}

/**
* Create a pathway to {@link DBRef} properties on {@link T} document
*
* @param ref
* @param target
* @return
*/
public <K> Join<T> join(Path<K> ref, Path<K> target) {
return addJoin(ref, target);
}

public void applyPredicate(MongodbQuery<T> mongodbQuery) {
for (Join<?> join : joins) {
mongodbQuery.join(join.getRef(), join.getTarget()).on(join.getPredicate());
}
if(predicate != null){
mongodbQuery.where(predicate);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.springframework.data.mongodb.domain;




public interface Specification<T> {

/**
* Build WHERE clause based on related Document.
*
* @param predicateBuilder
*/
QueryDslMongodbPredicate<T> buildPredicate(PredicateBuilder<T> predicateBuilder);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.springframework.data.mongodb.domain;

public class Specifications<T> implements Specification<T> {

private Specification<T> specification;

public Specifications(Specification<T> specification) {
this.specification = specification;
}

public static <T> Specifications<T> where(Specification<T> specification) {
return new Specifications<T>(specification);
}
public Specifications<T> and(final Specification<T> spec) {
return new Specifications<T>(new Specification<T>() {
public QueryDslMongodbPredicate<T> buildPredicate(PredicateBuilder<T> predicateBuilder) {
return predicateBuilder.and(specification.buildPredicate(predicateBuilder), spec.buildPredicate(predicateBuilder));
}
});
}

public QueryDslMongodbPredicate<T> buildPredicate(PredicateBuilder<T> predicateBuilder) {
return specification.buildPredicate(predicateBuilder);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.springframework.data.mongodb.repository;

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.domain.Specification;


/**
* Interface to allow execution of {@link Specification}s based on the QueryDSL DbRef predicate.
*
* @author Patryk Wasik
*/
public interface QueryDslMongoSpecificationExecutor<T> {

/**
* Returns a single entity matching the given {@link Specification}.
*
* @param spec
* @return
*/
T findOne(Specification<T> spec);

/**
* Returns all entities matching the given {@link Specification}.
*
* @param spec
* @return
*/
List<T> findAll(Specification<T> spec);

/**
* Returns a {@link Page} of entities matching the given {@link Specification}.
*
* @param spec
* @param pageable
* @return
*/
Page<T> findAll(Specification<T> spec, Pageable pageable);

/**
* Returns all entities matching the given {@link Specification} and {@link Sort}.
*
* @param spec
* @param sort
* @return
*/
List<T> findAll(Specification<T> spec, Sort sort);

/**
* Returns the number of instances that the given {@link Specification} will return.
*
* @param spec the {@link Specification} to count instances for
* @return the number of instances
*/
long count(Specification<T> spec);
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.domain.PredicateBuilder;
import org.springframework.data.mongodb.domain.Specification;
import org.springframework.data.mongodb.repository.QueryDslMongoSpecificationExecutor;
import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
import org.springframework.data.querydsl.EntityPathResolver;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
Expand All @@ -45,7 +48,7 @@
* @author Oliver Gierke
*/
public class QueryDslMongoRepository<T, ID extends Serializable> extends SimpleMongoRepository<T, ID> implements
QueryDslPredicateExecutor<T> {
QueryDslPredicateExecutor<T>, QueryDslMongoSpecificationExecutor<T> {

private final PathBuilder<T> builder;

Expand Down Expand Up @@ -187,4 +190,57 @@ private OrderSpecifier<?> toOrder(Order order) {
return new OrderSpecifier(order.isAscending() ? com.mysema.query.types.Order.ASC
: com.mysema.query.types.Order.DESC, property);
}

/* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.QueryDslMongoSpecificationExecutor#findOne(org.springframework.data.mongodb.domain.Specification)
*/
public T findOne(Specification<T> spec) {
return createQueryFor(spec).uniqueResult();
}

/* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.QueryDslMongoSpecificationExecutor#findAll(org.springframework.data.mongodb.domain.Specification)
*/
public List<T> findAll(Specification<T> spec) {
return createQueryFor(spec).list();
}

/* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.QueryDslMongoSpecificationExecutor#findAll(org.springframework.data.mongodb.domain.Specification, org.springframework.data.domain.Pageable)
*/
public Page<T> findAll(Specification<T> spec, Pageable pageable) {
MongodbQuery<T> countQuery = createQueryFor(spec);
MongodbQuery<T> query = createQueryFor(spec);
return new PageImpl<T>(applyPagination(query, pageable).list(),pageable,countQuery.count());
}

/* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.QueryDslMongoSpecificationExecutor#findAll(org.springframework.data.mongodb.domain.Specification, org.springframework.data.domain.Sort)
*/
public List<T> findAll(Specification<T> spec, Sort sort) {
MongodbQuery<T> query = createQueryFor(spec);
return applySorting(query, sort).list();
}

/* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.QueryDslMongoSpecificationExecutor#count(org.springframework.data.mongodb.domain.Specification)
*/
public long count(Specification<T> spec) {
return createQueryFor(spec).count();
}

/**
* Creates a {@link MongodbQuery} for the given {@link Specification}.
*
* @param predicate
* @return
*/
private MongodbQuery<T> createQueryFor(Specification<T> specification) {

Class<T> domainType = getEntityInformation().getJavaType();

MongodbQuery<T> query = new SpringDataMongodbQuery<T>(getMongoOperations(), domainType);
specification.buildPredicate(new PredicateBuilder<T>()).applyPredicate(query);
return query;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.springframework.data.mongodb.repository;

import java.math.BigInteger;

import org.springframework.data.mongodb.core.mapping.Document;

@Document
public class Boss {

BigInteger id;
String name;

}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ public enum Sex {

@DBRef
User creator;

@DBRef
Boss boss;

public Person() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
*
* @author Oliver Gierke
*/
public interface PersonRepository extends MongoRepository<Person, String>, QueryDslPredicateExecutor<Person> {
public interface PersonRepository extends MongoRepository<Person, String>, QueryDslPredicateExecutor<Person>, QueryDslMongoSpecificationExecutor<Person> {

/**
* Returns all {@link Person}s with the given lastname.
Expand Down
Loading