Skip to content
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

DATAJPA-954 - Delete by Predicate feature #184

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,43 @@
package org.springframework.data.jpa.repository.support;

import com.querydsl.core.types.EntityPath;
import com.querydsl.jpa.EclipseLinkTemplates;
import com.querydsl.jpa.HQLTemplates;
import com.querydsl.jpa.OpenJPATemplates;
import com.querydsl.jpa.impl.JPADeleteClause;
import org.springframework.data.jpa.provider.PersistenceProvider;

import javax.persistence.EntityManager;

/**
* Helper instance to ease access to DeleteClause JPA query API.
*
* @author Nikita Mishchenko
*/
public class DeleteQuerydsl {

private final EntityManager em;
private final PersistenceProvider provider;
private final EntityPath<?> path;

public DeleteQuerydsl(EntityManager em, EntityPath<?> path) {
this.em = em;
this.provider = PersistenceProvider.fromEntityManager(em);
this.path = path;
}

public JPADeleteClause createQuery() {
switch (provider) {
case ECLIPSELINK:
return new JPADeleteClause(em, path, EclipseLinkTemplates.DEFAULT);
case HIBERNATE:
return new JPADeleteClause(em, path, HQLTemplates.DEFAULT);
case OPEN_JPA:
return new JPADeleteClause(em, path, OpenJPATemplates.DEFAULT);
case GENERIC_JPA:
default:
return new JPADeleteClause(em, path);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.springframework.data.querydsl.EntityPathResolver;
import org.springframework.data.querydsl.QSort;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
import org.springframework.data.querydsl.QueryDslPredicateModifyingExecutor;
import org.springframework.data.querydsl.SimpleEntityPathResolver;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.data.repository.support.PageableExecutionUtils.TotalSupplier;
Expand All @@ -38,29 +39,32 @@
import com.querydsl.core.types.dsl.PathBuilder;
import com.querydsl.jpa.JPQLQuery;
import com.querydsl.jpa.impl.AbstractJPAQuery;
import com.querydsl.jpa.impl.JPADeleteClause;
import org.springframework.transaction.annotation.Transactional;

/**
* QueryDsl specific extension of {@link SimpleJpaRepository} which adds implementation for
* {@link QueryDslPredicateExecutor}.
*
*
* @author Oliver Gierke
* @author Thomas Darimont
* @author Mark Paluch
* @author Jocelyn Ntakpe
*/
public class QueryDslJpaRepository<T, ID extends Serializable> extends SimpleJpaRepository<T, ID>
implements QueryDslPredicateExecutor<T> {
implements QueryDslPredicateExecutor<T>, QueryDslPredicateModifyingExecutor {

private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE;

private final EntityPath<T> path;
private final PathBuilder<T> builder;
private final Querydsl querydsl;
private final DeleteQuerydsl deleteQuerydsl;

/**
* Creates a new {@link QueryDslJpaRepository} from the given domain class and {@link EntityManager}. This will use
* the {@link SimpleEntityPathResolver} to translate the given domain class into an {@link EntityPath}.
*
*
* @param entityInformation must not be {@literal null}.
* @param entityManager must not be {@literal null}.
*/
Expand All @@ -71,7 +75,7 @@ public QueryDslJpaRepository(JpaEntityInformation<T, ID> entityInformation, Enti
/**
* Creates a new {@link QueryDslJpaRepository} from the given domain class and {@link EntityManager} and uses the
* given {@link EntityPathResolver} to translate the domain class into an {@link EntityPath}.
*
*
* @param entityInformation must not be {@literal null}.
* @param entityManager must not be {@literal null}.
* @param resolver must not be {@literal null}.
Expand All @@ -84,6 +88,7 @@ public QueryDslJpaRepository(JpaEntityInformation<T, ID> entityInformation, Enti
this.path = resolver.createPath(entityInformation.getJavaType());
this.builder = new PathBuilder<T>(path.getType(), path.getMetadata());
this.querydsl = new Querydsl(entityManager, builder);
this.deleteQuerydsl = new DeleteQuerydsl(entityManager, path);
}

/*
Expand Down Expand Up @@ -113,7 +118,7 @@ public List<T> findAll(Predicate predicate, OrderSpecifier<?>... orders) {
return executeSorted(createQuery(predicate).select(path), orders);
}

/*
/*
* (non-Javadoc)
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.mysema.query.types.Predicate, org.springframework.data.domain.Sort)
*/
Expand All @@ -122,7 +127,7 @@ public List<T> findAll(Predicate predicate, Sort sort) {
return executeSorted(createQuery(predicate).select(path), sort);
}

/*
/*
* (non-Javadoc)
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.mysema.query.types.OrderSpecifier[])
*/
Expand Down Expand Up @@ -150,6 +155,16 @@ public long get() {
});
}

/*
* (non-Javadoc)
* @see org.springframework.data.querydsl.QueryDslPredicateModifyingExecutor#delete(com.mysema.query.types.Predicate)
*/
@Transactional
@Override
public long delete(Predicate... predicate) {
return createDeleteClause(predicate).execute();
}

/*
* (non-Javadoc)
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#count(com.mysema.query.types.Predicate)
Expand All @@ -159,7 +174,7 @@ public long count(Predicate predicate) {
return createQuery(predicate).fetchCount();
}

/*
/*
* (non-Javadoc)
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#exists(com.mysema.query.types.Predicate)
*/
Expand All @@ -170,7 +185,7 @@ public boolean exists(Predicate predicate) {

/**
* Creates a new {@link JPQLQuery} for the given {@link Predicate}.
*
*
* @param predicate
* @return the Querydsl {@link JPQLQuery}.
*/
Expand All @@ -193,7 +208,29 @@ protected JPQLQuery<?> createQuery(Predicate... predicate) {
return query;
}

/**
/**
* Creates a new {@link JPADeleteClause} for the given {@link Predicate}.
*
* @param predicate
* @return the Querydsl {@link JPADeleteClause}.
*/
protected JPADeleteClause createDeleteClause(Predicate... predicate) {
JPADeleteClause deleteClause = deleteQuerydsl.createQuery().where(predicate);
CrudMethodMetadata metadata = getRepositoryMethodMetadata();

if (metadata == null) {
return deleteClause;
}

LockModeType type = metadata.getLockModeType();
deleteClause = type == null ? deleteClause : deleteClause.setLockMode(type);


return deleteClause;
}


/**
* Creates a new {@link JPQLQuery} count query for the given {@link Predicate}.
*
* @param predicate, can be {@literal null}.
Expand All @@ -205,7 +242,7 @@ protected JPQLQuery<?> createCountQuery(Predicate predicate) {

/**
* Executes the given {@link JPQLQuery} after applying the given {@link OrderSpecifier}s.
*
*
* @param query must not be {@literal null}.
* @param orders must not be {@literal null}.
* @return
Expand All @@ -216,7 +253,7 @@ private List<T> executeSorted(JPQLQuery<T> query, OrderSpecifier<?>... orders) {

/**
* Executes the given {@link JPQLQuery} after applying the given {@link Sort}.
*
*
* @param query must not be {@literal null}.
* @param sort must not be {@literal null}.
* @return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,23 @@ public void executesPredicatesCorrectly() throws Exception {
assertThat(result, hasItems(carter, dave));
}

@Test
public void executesDeletePredicatesCorrectly() throws Exception {

BooleanExpression isCalledDave = user.firstname.eq("Dave");
BooleanExpression isBeauford = user.lastname.eq("Beauford");

List<User> result = repository.findAll(isCalledDave.or(isBeauford));

assertThat(result.size(), is(2));

repository.delete(isCalledDave);

result = repository.findAll(isCalledDave.or(isBeauford));

assertThat(result.size(), is(1));
}

@Test
public void executesStringBasedPredicatesCorrectly() throws Exception {

Expand Down