Skip to content
Open
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
Expand Up @@ -31,10 +31,14 @@
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import tech.jhipster.config.JHipsterConstants;
import tech.jhipster.config.JHipsterProperties;
import tech.jhipster.sample.config.sdc.CustomCouchbaseRepositoryFactoryBean;

@Configuration
@Profile("!" + JHipsterConstants.SPRING_PROFILE_CLOUD)
@EnableCouchbaseRepositories(basePackages = "tech.jhipster.sample.repository")
@EnableCouchbaseRepositories(
basePackages = "tech.jhipster.sample.repository",
repositoryFactoryBeanClass = CustomCouchbaseRepositoryFactoryBean.class
)
@EnableCouchbaseAuditing(auditorAwareRef = "springSecurityAuditorAware", dateTimeProviderRef = "")
public class DatabaseConfiguration extends AbstractCouchbaseConfiguration {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package tech.jhipster.sample.config.sdc;

import java.lang.reflect.Method;
import java.util.Optional;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
import org.springframework.data.couchbase.repository.query.CouchbaseQueryMethod;
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
import org.springframework.data.mapping.context.MappingContext;
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;

/**
* Created by mmonti on 2/1/21.
*/
public class CustomCouchbaseRepositoryFactory extends CouchbaseRepositoryFactory {

private MappingContext mappingContext;
private RepositoryOperationsMapping couchbaseOperationsMapping;

/**
* Create a new factory.
*
* @param couchbaseOperationsMapping the template for the underlying actions.
*/
public CustomCouchbaseRepositoryFactory(RepositoryOperationsMapping couchbaseOperationsMapping) {
super(couchbaseOperationsMapping);
this.couchbaseOperationsMapping = couchbaseOperationsMapping;
this.mappingContext = this.couchbaseOperationsMapping.getMappingContext();
}

@Override
protected Optional<QueryLookupStrategy> getQueryLookupStrategy(
QueryLookupStrategy.Key key,
QueryMethodEvaluationContextProvider contextProvider
) {
return Optional.of(new CustomCouchbaseQueryLookupStrategy(contextProvider));
}

private class CustomCouchbaseQueryLookupStrategy implements QueryLookupStrategy {

private final QueryMethodEvaluationContextProvider evaluationContextProvider;

public CustomCouchbaseQueryLookupStrategy(QueryMethodEvaluationContextProvider evaluationContextProvider) {
this.evaluationContextProvider = evaluationContextProvider;
}

@Override
public RepositoryQuery resolveQuery(
final Method method,
final RepositoryMetadata metadata,
final ProjectionFactory factory,
final NamedQueries namedQueries
) {
final CouchbaseOperations couchbaseOperations = couchbaseOperationsMapping.resolve(
metadata.getRepositoryInterface(),
metadata.getDomainType()
);

CouchbaseQueryMethod queryMethod = new CouchbaseQueryMethod(method, metadata, factory, mappingContext);
return new CustomCouchbaseRepositoryQuery(couchbaseOperations, queryMethod, namedQueries);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package tech.jhipster.sample.config.sdc;

import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactoryBean;

/**
* Created by mmonti on 2/1/21.
*/
public class CustomCouchbaseRepositoryFactoryBean extends CouchbaseRepositoryFactoryBean {

/**
* Creates a new {@link CouchbaseRepositoryFactoryBean} for the given repository interface.
*
* @param repositoryInterface must not be {@literal null}.
*/
public CustomCouchbaseRepositoryFactoryBean(Class repositoryInterface) {
super(repositoryInterface);
}

@Override
protected CouchbaseRepositoryFactory getFactoryInstance(RepositoryOperationsMapping operationsMapping) {
return new CustomCouchbaseRepositoryFactory(operationsMapping);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package tech.jhipster.sample.config.sdc;

import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.couchbase.repository.query.CouchbaseQueryMethod;
import org.springframework.data.couchbase.repository.query.CouchbaseRepositoryQuery;
import org.springframework.data.repository.core.NamedQueries;
import tech.jhipster.sample.config.sdc.n1ql.CustomN1qlRepositoryQueryExecutor;

/**
* Created by mmonti on 2/1/21.
*/
public class CustomCouchbaseRepositoryQuery extends CouchbaseRepositoryQuery {

private CouchbaseOperations couchbaseOperations;
private CouchbaseQueryMethod queryMethod;
private NamedQueries namedQueries;

public CustomCouchbaseRepositoryQuery(CouchbaseOperations operations, CouchbaseQueryMethod queryMethod, NamedQueries namedQueries) {
super(operations, queryMethod, namedQueries);
this.couchbaseOperations = operations;
this.queryMethod = queryMethod;
this.namedQueries = namedQueries;
}

@Override
public Object execute(final Object[] parameters) {
return new CustomN1qlRepositoryQueryExecutor(couchbaseOperations, queryMethod, namedQueries).execute(parameters);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package tech.jhipster.sample.config.sdc.n1ql;

import static org.springframework.data.couchbase.core.query.N1QLExpression.*;

import java.util.Iterator;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
import org.springframework.data.couchbase.core.query.Query;
import org.springframework.data.couchbase.core.query.QueryCriteria;
import org.springframework.data.domain.Sort;
import org.springframework.data.mapping.PersistentPropertyPath;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.QueryMethod;
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
import org.springframework.data.repository.query.parser.Part;
import org.springframework.data.repository.query.parser.PartTree;

public class CustomN1qlQueryCreator extends AbstractQueryCreator<Query, QueryCriteria> {

private final CouchbaseOperations couchbaseOperations;
private final ParameterAccessor accessor;
private final MappingContext<?, CouchbasePersistentProperty> context;
private final QueryMethod queryMethod;
private final CouchbaseConverter converter;

public CustomN1qlQueryCreator(
final CouchbaseOperations operations,
final PartTree tree,
final ParameterAccessor accessor,
QueryMethod queryMethod,
CouchbaseConverter converter
) {
super(tree, accessor);
this.accessor = accessor;
this.context = converter.getMappingContext();
this.queryMethod = queryMethod;
this.converter = converter;
this.couchbaseOperations = operations;
}

static Converter<? super CouchbasePersistentProperty, String> cvtr = source ->
new StringBuilder(source.getFieldName().length() + 2).append('`').append(source.getFieldName()).append('`').toString();

@Override
protected QueryCriteria create(final Part part, final Iterator<Object> iterator) {
PersistentPropertyPath<CouchbasePersistentProperty> path = context.getPersistentPropertyPath(part.getProperty());
CouchbasePersistentProperty property = path.getLeafProperty();
return from(part, property, QueryCriteria.where(addMetaIfIdProperty(path, property)), iterator);
}

@Override
protected QueryCriteria and(Part part, QueryCriteria base, Iterator<Object> iterator) {
if (base == null) {
return create(part, iterator);
}
PersistentPropertyPath<CouchbasePersistentProperty> path = context.getPersistentPropertyPath(part.getProperty());
CouchbasePersistentProperty property = path.getLeafProperty();
return from(part, property, base.and(addMetaIfIdProperty(path, property)), iterator);
}

private String addMetaIfIdProperty(
final PersistentPropertyPath<CouchbasePersistentProperty> path,
final CouchbasePersistentProperty property
) {
// To support findById on ReactiveFindByQueryOperationSupport.all()
// if (property.isIdProperty()) {
// return path(meta(i(couchbaseOperations.getBucketName())), path.toDotPath(cvtr)).toString();
// }
return path.toDotPath(cvtr);
}

@Override
protected QueryCriteria or(QueryCriteria base, QueryCriteria criteria) {
return base.or(criteria);
}

@Override
protected Query complete(QueryCriteria criteria, Sort sort) {
return (criteria == null ? new Query() : new Query().addCriteria(criteria)).with(sort);
}

private QueryCriteria from(
final Part part,
final CouchbasePersistentProperty property,
final QueryCriteria criteria,
final Iterator<Object> parameters
) {
final Part.Type type = part.getType();
/*
NEAR(new String[]{"IsNear", "Near"}),
*/
switch (type) {
case GREATER_THAN:
case AFTER:
return criteria.gt(parameters.next());
case GREATER_THAN_EQUAL:
return criteria.gte(parameters.next());
case LESS_THAN:
case BEFORE:
return criteria.lt(parameters.next());
case LESS_THAN_EQUAL:
return criteria.lte(parameters.next());
case SIMPLE_PROPERTY:
return criteria.eq(parameters.next());
case NEGATING_SIMPLE_PROPERTY:
return criteria.ne(parameters.next());
case CONTAINING:
return criteria.containing(parameters.next());
case NOT_CONTAINING:
return criteria.notContaining(parameters.next());
case STARTING_WITH:
return criteria.startingWith(parameters.next());
case ENDING_WITH:
return criteria.endingWith(parameters.next());
case LIKE:
return criteria.like(parameters.next());
case NOT_LIKE:
return criteria.notLike(parameters.next());
case WITHIN:
return criteria.within(parameters.next());
case IS_NULL:
return criteria.isNull(/*parameters.next()*/);
case IS_NOT_NULL:
return criteria.isNotNull(/*parameters.next()*/);
case IS_EMPTY:
return criteria.isNotValued(/*parameters.next()*/);
case IS_NOT_EMPTY:
return criteria.isValued(/*parameters.next()*/);
case EXISTS:
return criteria.isNotMissing(/*parameters.next()*/);
case REGEX:
return criteria.regex(parameters.next());
case BETWEEN:
return criteria.between(parameters.next(), parameters.next());
case IN:
return criteria.in(parameters.next());
case NOT_IN:
return criteria.notIn(parameters.next());
case TRUE:
return criteria.TRUE();
case FALSE:
return criteria.FALSE();
default:
throw new IllegalArgumentException("Unsupported keyword!");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package tech.jhipster.sample.config.sdc.n1ql;

import com.couchbase.client.java.query.QueryScanConsistency;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.couchbase.core.ExecutableFindByQueryOperation;
import org.springframework.data.couchbase.core.query.Query;
import org.springframework.data.couchbase.repository.query.CouchbaseQueryMethod;
import org.springframework.data.couchbase.repository.query.ReactiveN1qlRepositoryQueryExecutor;
import org.springframework.data.couchbase.repository.query.StringN1qlQueryCreator;
import org.springframework.data.repository.core.NamedQueries;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.ParametersParameterAccessor;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.parser.PartTree;

/**
* Created by mmonti on 2/1/21.
*/
public class CustomN1qlRepositoryQueryExecutor {

private final CouchbaseOperations operations;
private final CouchbaseQueryMethod queryMethod;
private final NamedQueries namedQueries;

public CustomN1qlRepositoryQueryExecutor(
final CouchbaseOperations operations,
final CouchbaseQueryMethod queryMethod,
final NamedQueries namedQueries
) {
this.operations = operations;
this.queryMethod = queryMethod;
this.namedQueries = namedQueries;
}

/**
* see also {@link ReactiveN1qlRepositoryQueryExecutor#execute(Object[] parameters) execute }
*
* @param parameters
* @return
*/
public Object execute(final Object[] parameters) {
final Class<?> domainClass = queryMethod.getResultProcessor().getReturnedType().getDomainType();
final ParameterAccessor accessor = new ParametersParameterAccessor(queryMethod.getParameters(), parameters);

// this is identical to ReactiveN1qlRespositoryQueryExecutor,
// except for the type of 'q', and the call to oneValue() vs one()
Query query;
ExecutableFindByQueryOperation.ExecutableFindByQuery q;
if (queryMethod.hasN1qlAnnotation()) {
query =
new StringN1qlQueryCreator(
accessor,
queryMethod,
operations.getConverter(),
operations.getBucketName(),
QueryMethodEvaluationContextProvider.DEFAULT,
namedQueries
)
.createQuery();
} else {
final PartTree tree = new PartTree(queryMethod.getName(), domainClass);
query = new CustomN1qlQueryCreator(operations, tree, accessor, queryMethod, operations.getConverter()).createQuery();
}
q =
(ExecutableFindByQueryOperation.ExecutableFindByQuery) operations
.findByQuery(domainClass)
.consistentWith(buildQueryScanConsistency())
.matching(query);
if (queryMethod.isCountQuery()) {
return q.count();
} else if (queryMethod.isCollectionQuery()) {
return q.all();
} else {
return q.oneValue();
}
}

private QueryScanConsistency buildQueryScanConsistency() {
QueryScanConsistency scanConsistency = QueryScanConsistency.NOT_BOUNDED;
if (queryMethod.hasConsistencyAnnotation()) {
scanConsistency = queryMethod.getConsistencyAnnotation().value();
} else if (queryMethod.hasScanConsistencyAnnotation()) {
scanConsistency = queryMethod.getScanConsistencyAnnotation().query();
}
return scanConsistency;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* Classes in this package are meant to extend Spring Data Couchbase and fix some of the issues encountered during
* integration.
*/
package tech.jhipster.sample.config.sdc;
Loading