Last active
March 17, 2023 04:38
-
-
Save yurikilian/cc096e3384904001d4273de69ed4ea4c to your computer and use it in GitHub Desktop.
Soft Delete Mongo Repository
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import br.com.radharsomeluz.inventory.configuration.SoftDeletionMongoRepository; | |
import br.com.radharsomeluz.inventory.configuration.SoftDeletionRepositoryFactoryBean; | |
import org.springframework.boot.SpringApplication; | |
import org.springframework.boot.autoconfigure.SpringBootApplication; | |
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; | |
import springfox.documentation.swagger2.annotations.EnableSwagger2; | |
@SpringBootApplication | |
@EnableSwagger2 | |
@EnableMongoRepositories( | |
repositoryBaseClass = SoftDeletionMongoRepository.class, | |
repositoryFactoryBeanClass = SoftDeletionRepositoryFactoryBean.class) | |
public class ApiApplication { | |
public static void main(String[] args) { | |
SpringApplication.run(ApiApplication.class, args); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.springframework.data.mongodb.core.MongoOperations; | |
import org.springframework.data.mongodb.core.query.Query; | |
import org.springframework.data.mongodb.repository.query.ConvertingParameterAccessor; | |
import org.springframework.data.mongodb.repository.query.MongoQueryMethod; | |
import org.springframework.data.mongodb.repository.query.PartTreeMongoQuery; | |
import static org.springframework.data.mongodb.core.query.Criteria.where; | |
public class SoftDeletionMongoQuery extends PartTreeMongoQuery { | |
public SoftDeletionMongoQuery(MongoQueryMethod method, MongoOperations mongoOperations) { | |
super(method, mongoOperations); | |
} | |
@Override | |
protected Query createQuery(ConvertingParameterAccessor accessor) { | |
Query query = super.createQuery(accessor); | |
query.addCriteria(where("deleted").is(false)); | |
return query; | |
} | |
@Override | |
protected Query createCountQuery(ConvertingParameterAccessor accessor) { | |
Query countQuery = super.createCountQuery(accessor); | |
countQuery.addCriteria(where("deleted").is(false)); | |
return countQuery; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.springframework.data.domain.*; | |
import org.springframework.data.mongodb.core.MongoOperations; | |
import org.springframework.data.mongodb.core.query.Criteria; | |
import org.springframework.data.mongodb.core.query.Query; | |
import org.springframework.data.mongodb.core.query.Update; | |
import org.springframework.data.mongodb.repository.MongoRepository; | |
import org.springframework.data.mongodb.repository.query.MongoEntityInformation; | |
import org.springframework.data.repository.support.PageableExecutionUtils; | |
import org.springframework.data.util.StreamUtils; | |
import org.springframework.data.util.Streamable; | |
import org.springframework.lang.Nullable; | |
import org.springframework.util.Assert; | |
import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.List; | |
import java.util.Optional; | |
import java.util.stream.Collectors; | |
import static org.springframework.data.mongodb.core.query.Criteria.where; | |
public class SoftDeletionMongoRepository<T, ID> implements MongoRepository<T, ID> { | |
private static final String SOFT_DELETION_KEY = "deleted"; | |
private final MongoOperations mongoOperations; | |
private final MongoEntityInformation<T, ID> entityInformation; | |
public SoftDeletionMongoRepository( | |
MongoEntityInformation<T, ID> metadata, MongoOperations mongoOperations) { | |
Assert.notNull(metadata, "MongoEntityInformation must not be null!"); | |
Assert.notNull(mongoOperations, "MongoOperations must not be null!"); | |
this.entityInformation = metadata; | |
this.mongoOperations = mongoOperations; | |
} | |
@Override | |
public <S extends T> S save(S entity) { | |
Assert.notNull(entity, "Entity must not be null!"); | |
if (entityInformation.isNew(entity)) { | |
return mongoOperations.insert(entity, entityInformation.getCollectionName()); | |
} | |
return mongoOperations.save(entity, entityInformation.getCollectionName()); | |
} | |
@Override | |
public <S extends T> List<S> saveAll(Iterable<S> entities) { | |
Assert.notNull(entities, "The given Iterable of entities not be null!"); | |
Streamable<S> source = Streamable.of(entities); | |
boolean allNew = source.stream().allMatch(entityInformation::isNew); | |
if (allNew) { | |
List<S> result = source.stream().collect(Collectors.toList()); | |
return new ArrayList<>(mongoOperations.insert(result, entityInformation.getCollectionName())); | |
} | |
return source.stream().map(this::save).collect(Collectors.toList()); | |
} | |
@Override | |
public Optional<T> findById(ID id) { | |
Assert.notNull(id, "The given id must not be null!"); | |
return Optional.ofNullable( | |
mongoOperations.findOne( | |
getIdQuery(id), | |
entityInformation.getJavaType(), | |
entityInformation.getCollectionName())); | |
} | |
@Override | |
public boolean existsById(ID id) { | |
Assert.notNull(id, "The given id must not be null!"); | |
return mongoOperations.exists( | |
getIdQuery(id).addCriteria(where(SOFT_DELETION_KEY).is(false)), | |
entityInformation.getJavaType(), | |
entityInformation.getCollectionName()); | |
} | |
@Override | |
public long count() { | |
Query query = new Query(); | |
query.addCriteria(where(SOFT_DELETION_KEY).is(false)); | |
return mongoOperations.count(query, entityInformation.getCollectionName()); | |
} | |
@Override | |
public void deleteById(ID id) { | |
Assert.notNull(id, "The given id must not be null!"); | |
mongoOperations.updateFirst( | |
getIdQuery(id), | |
new Update().set(SOFT_DELETION_KEY, true), | |
entityInformation.getJavaType(), | |
entityInformation.getCollectionName()); | |
} | |
@Override | |
public void delete(T entity) { | |
Assert.notNull(entity, "The given entity must not be null!"); | |
deleteById(entityInformation.getRequiredId(entity)); | |
} | |
@Override | |
public void deleteAll(Iterable<? extends T> entities) { | |
Assert.notNull(entities, "The given Iterable of entities not be null!"); | |
entities.forEach(this::delete); | |
} | |
@Override | |
public void deleteAll() { | |
Update update = new Update(); | |
update.set(SOFT_DELETION_KEY, true); | |
mongoOperations.updateMulti( | |
new Query(), | |
update, | |
entityInformation.getJavaType(), | |
entityInformation.getCollectionName()); | |
} | |
@Override | |
public List<T> findAll() { | |
return findAll(new Query()); | |
} | |
@Override | |
public Iterable<T> findAllById(Iterable<ID> ids) { | |
return findAll( | |
new Query( | |
new Criteria(entityInformation.getIdAttribute()) | |
.in(Streamable.of(ids).stream().collect(StreamUtils.toUnmodifiableList())))); | |
} | |
@Override | |
public Page<T> findAll(Pageable pageable) { | |
Assert.notNull(pageable, "Pageable must not be null!"); | |
long count = count(); | |
List<T> list = findAll(new Query().with(pageable)); | |
return new PageImpl<>(list, pageable, count); | |
} | |
@Override | |
public List<T> findAll(Sort sort) { | |
Assert.notNull(sort, "Sort must not be null!"); | |
return findAll(new Query().with(sort)); | |
} | |
@Override | |
public <S extends T> S insert(S entity) { | |
Assert.notNull(entity, "Entity must not be null!"); | |
return mongoOperations.insert(entity, entityInformation.getCollectionName()); | |
} | |
@Override | |
public <S extends T> List<S> insert(Iterable<S> entities) { | |
Assert.notNull(entities, "The given Iterable of entities not be null!"); | |
List<S> list = Streamable.of(entities).stream().collect(StreamUtils.toUnmodifiableList()); | |
if (list.isEmpty()) { | |
return list; | |
} | |
return new ArrayList<>(mongoOperations.insertAll(list)); | |
} | |
@Override | |
public <S extends T> Page<S> findAll(final Example<S> example, Pageable pageable) { | |
Assert.notNull(example, "Sample must not be null!"); | |
Assert.notNull(pageable, "Pageable must not be null!"); | |
Query q = new Query(new Criteria().alike(example)).with(pageable); | |
q.addCriteria(where(SOFT_DELETION_KEY).is(true)); | |
List<S> list = | |
mongoOperations.find(q, example.getProbeType(), entityInformation.getCollectionName()); | |
return PageableExecutionUtils.getPage( | |
list, | |
pageable, | |
() -> | |
mongoOperations.count( | |
q, example.getProbeType(), entityInformation.getCollectionName())); | |
} | |
@Override | |
public <S extends T> List<S> findAll(Example<S> example, Sort sort) { | |
Assert.notNull(example, "Sample must not be null!"); | |
Assert.notNull(sort, "Sort must not be null!"); | |
Query q = new Query(new Criteria().alike(example)).with(sort); | |
q.addCriteria(where(SOFT_DELETION_KEY).is(true)); | |
return mongoOperations.find(q, example.getProbeType(), entityInformation.getCollectionName()); | |
} | |
@Override | |
public <S extends T> List<S> findAll(Example<S> example) { | |
return findAll(example, Sort.unsorted()); | |
} | |
@Override | |
public <S extends T> Optional<S> findOne(Example<S> example) { | |
Assert.notNull(example, "Sample must not be null!"); | |
Query q = new Query(new Criteria().alike(example)); | |
q.addCriteria(where(SOFT_DELETION_KEY).is(true)); | |
return Optional.ofNullable( | |
mongoOperations.findOne(q, example.getProbeType(), entityInformation.getCollectionName())); | |
} | |
@Override | |
public <S extends T> long count(Example<S> example) { | |
Assert.notNull(example, "Sample must not be null!"); | |
Query q = new Query(new Criteria().alike(example)); | |
q.addCriteria(where(SOFT_DELETION_KEY).is(true)); | |
return mongoOperations.count(q, example.getProbeType(), entityInformation.getCollectionName()); | |
} | |
@Override | |
public <S extends T> boolean exists(Example<S> example) { | |
Assert.notNull(example, "Sample must not be null!"); | |
Query q = new Query(new Criteria().alike(example)); | |
q.addCriteria(where(SOFT_DELETION_KEY).is(true)); | |
return mongoOperations.exists(q, example.getProbeType(), entityInformation.getCollectionName()); | |
} | |
private Query getIdQuery(Object id) { | |
return new Query(getIdCriteria(id)); | |
} | |
private Criteria getIdCriteria(Object id) { | |
return where(entityInformation.getIdAttribute()).is(id).and(SOFT_DELETION_KEY).is(false); | |
} | |
private List<T> findAll(@Nullable Query query) { | |
if (query == null) { | |
return Collections.emptyList(); | |
} | |
query.addCriteria(where(SOFT_DELETION_KEY).is(false)); | |
return mongoOperations.find( | |
query, entityInformation.getJavaType(), entityInformation.getCollectionName()); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.springframework.data.mapping.context.MappingContext; | |
import org.springframework.data.mongodb.core.MongoOperations; | |
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; | |
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; | |
import org.springframework.data.mongodb.repository.query.MongoQueryMethod; | |
import org.springframework.data.mongodb.repository.query.StringBasedMongoQuery; | |
import org.springframework.data.mongodb.repository.support.MongoRepositoryFactory; | |
import org.springframework.data.projection.ProjectionFactory; | |
import org.springframework.data.repository.core.NamedQueries; | |
import org.springframework.data.repository.core.RepositoryMetadata; | |
import org.springframework.data.repository.query.QueryLookupStrategy; | |
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider; | |
import org.springframework.data.repository.query.RepositoryQuery; | |
import org.springframework.expression.spel.standard.SpelExpressionParser; | |
import java.lang.reflect.Method; | |
import java.util.Optional; | |
public class SoftDeletionMongoRepositoryFactory extends MongoRepositoryFactory { | |
private static final SpelExpressionParser EXPRESSION_PARSER = new SpelExpressionParser(); | |
private final MongoOperations operations; | |
public SoftDeletionMongoRepositoryFactory(MongoOperations mongoOperations) { | |
super(mongoOperations); | |
this.operations = mongoOperations; | |
} | |
@Override | |
protected Optional<QueryLookupStrategy> getQueryLookupStrategy( | |
QueryLookupStrategy.Key key, QueryMethodEvaluationContextProvider evaluationContextProvider) { | |
return Optional.of( | |
new MongoQueryLookupStrategy( | |
operations, evaluationContextProvider, operations.getConverter().getMappingContext())); | |
} | |
private static class MongoQueryLookupStrategy implements QueryLookupStrategy { | |
private final MongoOperations operations; | |
private final QueryMethodEvaluationContextProvider evaluationContextProvider; | |
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext; | |
public MongoQueryLookupStrategy( | |
MongoOperations operations, | |
QueryMethodEvaluationContextProvider evaluationContextProvider, | |
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> | |
mappingContext) { | |
this.operations = operations; | |
this.evaluationContextProvider = evaluationContextProvider; | |
this.mappingContext = mappingContext; | |
} | |
@Override | |
public RepositoryQuery resolveQuery( | |
Method method, | |
RepositoryMetadata metadata, | |
ProjectionFactory factory, | |
NamedQueries namedQueries) { | |
MongoQueryMethod queryMethod = | |
new MongoQueryMethod(method, metadata, factory, mappingContext); | |
String namedQueryName = queryMethod.getNamedQueryName(); | |
if (namedQueries.hasQuery(namedQueryName)) { | |
String namedQuery = namedQueries.getQuery(namedQueryName); | |
return new StringBasedMongoQuery( | |
namedQuery, queryMethod, operations, EXPRESSION_PARSER, evaluationContextProvider); | |
} else if (queryMethod.hasAnnotatedQuery()) { | |
return new StringBasedMongoQuery( | |
queryMethod, operations, EXPRESSION_PARSER, evaluationContextProvider); | |
} else { | |
return new SoftDeletionMongoQuery(queryMethod, operations); | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.springframework.data.mapping.context.MappingContext; | |
import org.springframework.data.mongodb.core.MongoOperations; | |
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; | |
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; | |
import org.springframework.data.mongodb.repository.query.MongoQueryMethod; | |
import org.springframework.data.mongodb.repository.query.StringBasedMongoQuery; | |
import org.springframework.data.mongodb.repository.support.MongoRepositoryFactory; | |
import org.springframework.data.projection.ProjectionFactory; | |
import org.springframework.data.repository.core.NamedQueries; | |
import org.springframework.data.repository.core.RepositoryMetadata; | |
import org.springframework.data.repository.query.QueryLookupStrategy; | |
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider; | |
import org.springframework.data.repository.query.RepositoryQuery; | |
import org.springframework.expression.spel.standard.SpelExpressionParser; | |
import java.lang.reflect.Method; | |
import java.util.Optional; | |
public class SoftDeletionMongoRepositoryFactory extends MongoRepositoryFactory { | |
private static final SpelExpressionParser EXPRESSION_PARSER = new SpelExpressionParser(); | |
private final MongoOperations operations; | |
public SoftDeletionMongoRepositoryFactory(MongoOperations mongoOperations) { | |
super(mongoOperations); | |
this.operations = mongoOperations; | |
} | |
@Override | |
protected Optional<QueryLookupStrategy> getQueryLookupStrategy( | |
QueryLookupStrategy.Key key, QueryMethodEvaluationContextProvider evaluationContextProvider) { | |
return Optional.of( | |
new MongoQueryLookupStrategy( | |
operations, evaluationContextProvider, operations.getConverter().getMappingContext())); | |
} | |
private static class MongoQueryLookupStrategy implements QueryLookupStrategy { | |
private final MongoOperations operations; | |
private final QueryMethodEvaluationContextProvider evaluationContextProvider; | |
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext; | |
public MongoQueryLookupStrategy( | |
MongoOperations operations, | |
QueryMethodEvaluationContextProvider evaluationContextProvider, | |
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> | |
mappingContext) { | |
this.operations = operations; | |
this.evaluationContextProvider = evaluationContextProvider; | |
this.mappingContext = mappingContext; | |
} | |
@Override | |
public RepositoryQuery resolveQuery( | |
Method method, | |
RepositoryMetadata metadata, | |
ProjectionFactory factory, | |
NamedQueries namedQueries) { | |
MongoQueryMethod queryMethod = | |
new MongoQueryMethod(method, metadata, factory, mappingContext); | |
String namedQueryName = queryMethod.getNamedQueryName(); | |
if (namedQueries.hasQuery(namedQueryName)) { | |
String namedQuery = namedQueries.getQuery(namedQueryName); | |
return new StringBasedMongoQuery( | |
namedQuery, queryMethod, operations, EXPRESSION_PARSER, evaluationContextProvider); | |
} else if (queryMethod.hasAnnotatedQuery()) { | |
return new StringBasedMongoQuery( | |
queryMethod, operations, EXPRESSION_PARSER, evaluationContextProvider); | |
} else { | |
return new SoftDeletionMongoQuery(queryMethod, operations); | |
} | |
} | |
} | |
} |
hello @YasserOn, for a certain reason your MongontityInformation is not getting injected by the application.
Did you add the constructor for the SoftDeletionMongoRepository or add the component scan for the org.springframework.data.mongodb.repository package at a @componentscan annotation on your Application class?
best regards,
Yuri
Hi I had the same problem, I solved it by correcting the SoftDeletionRepositoryFactoryBean.java class, which apparently has the same code as SoftDeletionMongoRepositoryFactory.java
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello author, I use it , springboot startup error message is as follows
Description:
Parameter 0 of constructor in com.ddll.log.common.core.SoftDeletionMongoRepository required a bean of type 'org.springframework.data.mongodb.repository.query.MongoEntityInformation' that could not be found.
Action:
Consider defining a bean of type 'org.springframework.data.mongodb.repository.query.MongoEntityInformation' in your configuration.
How to solve