DATACOUCH-504 - Reintroduce query index generation
This changeset reintroduces automatic n1ql index generation but through new annotations: QueryIndexed and CompositeQueryIndex (as well as CompositeQueryIndexes to supply more than one). They are translated into create index statements and executed at startup if configured in the config. Note that automatic index management is disabled by default but can be overidden with a simple flag on the config override. More features to come later.
This commit is contained in:
@@ -208,9 +208,19 @@ public abstract class AbstractCouchbaseConfiguration {
|
||||
mappingContext.setInitialEntitySet(getInitialEntitySet());
|
||||
mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
|
||||
mappingContext.setFieldNamingStrategy(fieldNamingStrategy());
|
||||
mappingContext.setAutoIndexCreation(autoIndexCreation());
|
||||
|
||||
return mappingContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure whether to automatically create indices for domain types by deriving the
|
||||
* from the entity or not.
|
||||
*/
|
||||
protected boolean autoIndexCreation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register custom Converters in a {@link CustomConversions} object if required. These {@link CustomConversions} will
|
||||
* be registered with the {@link #mappingCouchbaseConverter(CouchbaseMappingContext, CouchbaseCustomConversions)} )}
|
||||
|
||||
@@ -16,20 +16,33 @@
|
||||
|
||||
package org.springframework.data.couchbase.core;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.couchbase.CouchbaseClientFactory;
|
||||
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
|
||||
|
||||
import com.couchbase.client.java.Collection;
|
||||
import org.springframework.data.couchbase.core.index.CouchbasePersistentEntityIndexCreator;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
public class CouchbaseTemplate implements CouchbaseOperations {
|
||||
public class CouchbaseTemplate implements CouchbaseOperations, ApplicationContextAware {
|
||||
|
||||
private final CouchbaseClientFactory clientFactory;
|
||||
private final CouchbaseConverter converter;
|
||||
private final PersistenceExceptionTranslator exceptionTranslator;
|
||||
private final CouchbaseTemplateSupport templateSupport;
|
||||
private final MappingContext<? extends CouchbasePersistentEntity<?>, CouchbasePersistentProperty> mappingContext;
|
||||
private final ReactiveCouchbaseTemplate reactiveCouchbaseTemplate;
|
||||
private @Nullable CouchbasePersistentEntityIndexCreator indexCreator;
|
||||
|
||||
|
||||
public CouchbaseTemplate(final CouchbaseClientFactory clientFactory, final CouchbaseConverter converter) {
|
||||
this.clientFactory = clientFactory;
|
||||
@@ -37,6 +50,14 @@ public class CouchbaseTemplate implements CouchbaseOperations {
|
||||
this.exceptionTranslator = clientFactory.getExceptionTranslator();
|
||||
this.templateSupport = new CouchbaseTemplateSupport(converter);
|
||||
this.reactiveCouchbaseTemplate = new ReactiveCouchbaseTemplate(clientFactory, converter);
|
||||
|
||||
this.mappingContext = this.converter.getMappingContext();
|
||||
if (mappingContext instanceof CouchbaseMappingContext) {
|
||||
CouchbaseMappingContext cmc = (CouchbaseMappingContext) mappingContext;
|
||||
if (cmc.isAutoIndexCreation()) {
|
||||
indexCreator = new CouchbasePersistentEntityIndexCreator(cmc, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -138,4 +159,23 @@ public class CouchbaseTemplate implements CouchbaseOperations {
|
||||
return resolved == null ? ex : resolved;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
prepareIndexCreator(applicationContext);
|
||||
}
|
||||
|
||||
private void prepareIndexCreator(ApplicationContext context) {
|
||||
String[] indexCreators = context.getBeanNamesForType(CouchbasePersistentEntityIndexCreator.class);
|
||||
|
||||
for (String creator : indexCreators) {
|
||||
CouchbasePersistentEntityIndexCreator creatorBean = context.getBean(creator, CouchbasePersistentEntityIndexCreator.class);
|
||||
if (creatorBean.isIndexCreatorFor(mappingContext)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (context instanceof ConfigurableApplicationContext && indexCreator != null) {
|
||||
((ConfigurableApplicationContext) context).addApplicationListener(indexCreator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.springframework.data.couchbase.core.index;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target({ ElementType.TYPE })
|
||||
@Documented
|
||||
@Repeatable(CompositeQueryIndexes.class)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CompositeQueryIndex {
|
||||
|
||||
String[] fields();
|
||||
|
||||
String name() default "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.springframework.data.couchbase.core.index;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target({ ElementType.TYPE })
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CompositeQueryIndexes {
|
||||
|
||||
CompositeQueryIndex[] value();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.couchbase.core.index;
|
||||
|
||||
import com.couchbase.client.core.error.IndexExistsException;
|
||||
import com.couchbase.client.java.Cluster;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.data.couchbase.core.CouchbaseOperations;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.context.MappingContextEvent;
|
||||
import org.springframework.data.couchbase.core.index.CouchbasePersistentEntityIndexResolver.IndexDefinitionHolder;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class CouchbasePersistentEntityIndexCreator implements ApplicationListener<MappingContextEvent<?, ?>> {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CouchbasePersistentEntityIndexCreator.class);
|
||||
|
||||
private final Map<Class<?>, Boolean> classesSeen = new ConcurrentHashMap<>();
|
||||
private final CouchbaseMappingContext mappingContext;
|
||||
private final QueryIndexResolver indexResolver;
|
||||
private final CouchbaseOperations couchbaseOperations;
|
||||
|
||||
public CouchbasePersistentEntityIndexCreator(final CouchbaseMappingContext mappingContext,
|
||||
final CouchbaseOperations operations) {
|
||||
this.mappingContext = mappingContext;
|
||||
this.couchbaseOperations = operations;
|
||||
this.indexResolver = QueryIndexResolver.create(mappingContext, operations);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(final MappingContextEvent<?, ?> event) {
|
||||
if (!event.wasEmittedBy(mappingContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
PersistentEntity<?, ?> entity = event.getPersistentEntity();
|
||||
|
||||
// Double check type as Spring infrastructure does not consider nested generics
|
||||
if (entity instanceof CouchbasePersistentEntity) {
|
||||
checkForIndexes((CouchbasePersistentEntity<?>) entity);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkForIndexes(final CouchbasePersistentEntity<?> entity) {
|
||||
Class<?> type = entity.getType();
|
||||
|
||||
if (!classesSeen.containsKey(type)) {
|
||||
this.classesSeen.put(type, Boolean.TRUE);
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Analyzing class " + type + " for index information.");
|
||||
}
|
||||
|
||||
checkForAndCreateIndexes(entity);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkForAndCreateIndexes(final CouchbasePersistentEntity<?> entity) {
|
||||
if (entity.isAnnotationPresent(Document.class)) {
|
||||
|
||||
for (IndexDefinition indexDefinition : indexResolver.resolveIndexFor(entity.getTypeInformation())) {
|
||||
IndexDefinitionHolder indexToCreate = indexDefinition instanceof IndexDefinitionHolder
|
||||
? (IndexDefinitionHolder) indexDefinition
|
||||
: new IndexDefinitionHolder(indexDefinition.getIndexFields(), indexDefinition.getIndexName(), indexDefinition.getIndexPredicate());
|
||||
|
||||
createIndex(indexToCreate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createIndex(final IndexDefinitionHolder indexToCreate) {
|
||||
Cluster cluster = couchbaseOperations.getCouchbaseClientFactory().getCluster();
|
||||
|
||||
StringBuilder statement = new StringBuilder("CREATE INDEX ")
|
||||
.append(indexToCreate.getIndexName())
|
||||
.append(" ON `")
|
||||
.append(couchbaseOperations.getBucketName())
|
||||
.append("` (")
|
||||
.append(String.join(",", indexToCreate.getIndexFields()))
|
||||
.append(")");
|
||||
|
||||
if (indexToCreate.getIndexPredicate() != null && !indexToCreate.getIndexPredicate().isEmpty()) {
|
||||
statement.append(" WHERE ").append(indexToCreate.getIndexPredicate());
|
||||
}
|
||||
|
||||
try {
|
||||
cluster.query(statement.toString());
|
||||
} catch (IndexExistsException ex) {
|
||||
// ignored on purpose, rest is propagated
|
||||
LOGGER.debug("Index \"" + indexToCreate.getIndexName() + "\" already exists, ignoring.");
|
||||
} catch (Exception ex) {
|
||||
throw new DataIntegrityViolationException("Could not auto-create index with statement: "
|
||||
+ statement.toString(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the current index creator was registered for the given {@link MappingContext}.
|
||||
*/
|
||||
public boolean isIndexCreatorFor(final MappingContext<?, ?> context) {
|
||||
return this.mappingContext.equals(context);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.couchbase.core.index;
|
||||
|
||||
import org.springframework.data.couchbase.core.CouchbaseOperations;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
import org.springframework.data.couchbase.repository.support.MappingCouchbaseEntityInformation;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class CouchbasePersistentEntityIndexResolver implements QueryIndexResolver {
|
||||
|
||||
private final MappingContext<? extends CouchbasePersistentEntity<?>, CouchbasePersistentProperty> mappingContext;
|
||||
private final CouchbaseOperations operations;
|
||||
|
||||
public CouchbasePersistentEntityIndexResolver(
|
||||
final MappingContext<? extends CouchbasePersistentEntity<?>, CouchbasePersistentProperty> mappingContext,
|
||||
CouchbaseOperations operations) {
|
||||
this.mappingContext = mappingContext;
|
||||
this.operations = operations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<? extends IndexDefinitionHolder> resolveIndexFor(final TypeInformation<?> typeInformation) {
|
||||
return resolveIndexForEntity(mappingContext.getRequiredPersistentEntity(typeInformation));
|
||||
}
|
||||
|
||||
public List<IndexDefinitionHolder> resolveIndexForEntity(final CouchbasePersistentEntity<?> root) {
|
||||
Assert.notNull(root, "CouchbasePersistentEntity must not be null!");
|
||||
Document document = root.findAnnotation(Document.class);
|
||||
Assert.notNull(document, () -> String
|
||||
.format("Entity %s is not a collection root. Make sure to annotate it with @Document!", root.getName()));
|
||||
|
||||
List<IndexDefinitionHolder> indexInformation = new ArrayList<>();
|
||||
|
||||
root.doWithProperties((PropertyHandler<CouchbasePersistentProperty>) property -> this
|
||||
.potentiallyAddIndexForProperty(root, property, indexInformation));
|
||||
|
||||
return indexInformation;
|
||||
}
|
||||
|
||||
private void potentiallyAddIndexForProperty(final CouchbasePersistentEntity<?> root,
|
||||
final CouchbasePersistentProperty persistentProperty,
|
||||
final List<IndexDefinitionHolder> indexes) {
|
||||
List<IndexDefinitionHolder> indexDefinitions = createIndexDefinitionHolderForProperty(
|
||||
persistentProperty.getFieldName(), root, persistentProperty);
|
||||
if (!indexDefinitions.isEmpty()) {
|
||||
indexes.addAll(indexDefinitions);
|
||||
}
|
||||
}
|
||||
|
||||
private List<IndexDefinitionHolder> createIndexDefinitionHolderForProperty(final String dotPath,
|
||||
final CouchbasePersistentEntity<?> persistentEntity,
|
||||
final CouchbasePersistentProperty persistentProperty) {
|
||||
|
||||
List<IndexDefinitionHolder> indices = new ArrayList<>();
|
||||
|
||||
if (persistentProperty.isAnnotationPresent(QueryIndexed.class)) {
|
||||
indices.add(createFieldQueryIndexDefinition(persistentEntity, persistentProperty));
|
||||
}
|
||||
|
||||
if (persistentEntity.isAnnotationPresent(CompositeQueryIndex.class)
|
||||
|| persistentEntity.isAnnotationPresent(CompositeQueryIndexes.class)) {
|
||||
indices.addAll(createCompositeQueryIndexDefinitions(persistentEntity, persistentProperty));
|
||||
}
|
||||
|
||||
return indices;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected IndexDefinitionHolder createFieldQueryIndexDefinition(final CouchbasePersistentEntity<?> entity,
|
||||
final CouchbasePersistentProperty property) {
|
||||
QueryIndexed index = property.findAnnotation(QueryIndexed.class);
|
||||
if (index == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MappingCouchbaseEntityInformation<?, Object> entityInfo = new MappingCouchbaseEntityInformation<>(entity);
|
||||
|
||||
List<String> fields = new ArrayList<>();
|
||||
String fieldName = index.name().isEmpty() ? property.getFieldName() : index.name();
|
||||
fields.add(fieldName + (index.direction() == QueryIndexDirection.DESCENDING ? " DESC" : ""));
|
||||
|
||||
String indexName = "idx_" + StringUtils.uncapitalize(entity.getType().getSimpleName()) + "_" + fieldName;
|
||||
|
||||
return new IndexDefinitionHolder(fields, indexName, getPredicate(entityInfo));
|
||||
}
|
||||
|
||||
protected List<IndexDefinitionHolder> createCompositeQueryIndexDefinitions(final CouchbasePersistentEntity<?> entity,
|
||||
final CouchbasePersistentProperty property) {
|
||||
|
||||
List<CompositeQueryIndex> indexAnnotations = new ArrayList<>();
|
||||
|
||||
if (entity.isAnnotationPresent(CompositeQueryIndex.class)) {
|
||||
indexAnnotations.add(entity.findAnnotation(CompositeQueryIndex.class));
|
||||
}
|
||||
if (entity.isAnnotationPresent(CompositeQueryIndexes.class)) {
|
||||
indexAnnotations.addAll(Arrays.asList(entity.findAnnotation(CompositeQueryIndexes.class).value()));
|
||||
}
|
||||
|
||||
MappingCouchbaseEntityInformation<?, Object> entityInfo = new MappingCouchbaseEntityInformation<>(entity);
|
||||
|
||||
String predicate = getPredicate(entityInfo);
|
||||
|
||||
|
||||
return indexAnnotations
|
||||
.stream()
|
||||
.map(ann -> {
|
||||
List<String> fields = Arrays.asList(ann.fields());
|
||||
String fieldsIndexName = String
|
||||
.join("_", fields)
|
||||
.toLowerCase()
|
||||
.replace(" ", "")
|
||||
.replace("asc", "")
|
||||
.replace("desc", "");
|
||||
|
||||
String indexName = "idx_"
|
||||
+ StringUtils.uncapitalize(entity.getType().getSimpleName())
|
||||
+ "_"
|
||||
+ fieldsIndexName;
|
||||
return new IndexDefinitionHolder(fields, indexName, predicate);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private String getPredicate(final MappingCouchbaseEntityInformation<?, Object> entityInfo) {
|
||||
String typeKey = operations.getConverter().getTypeKey();
|
||||
String typeValue = entityInfo.getJavaType().getName();
|
||||
return "`" + typeKey + "` = \"" + typeValue + "\"";
|
||||
}
|
||||
|
||||
|
||||
public static class IndexDefinitionHolder implements IndexDefinition {
|
||||
|
||||
private final List<String> fields;
|
||||
private final String indexName;
|
||||
private final String indexPredicate;
|
||||
|
||||
public IndexDefinitionHolder(List<String> fields, String indexName, String indexPredicate) {
|
||||
this.fields = fields;
|
||||
this.indexName = indexName;
|
||||
this.indexPredicate = indexPredicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getIndexFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIndexName() {
|
||||
return indexName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIndexPredicate() {
|
||||
return indexPredicate;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2011-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.couchbase.core.index;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface IndexDefinition {
|
||||
|
||||
String getIndexName();
|
||||
|
||||
List<String> getIndexFields();
|
||||
|
||||
String getIndexPredicate();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.couchbase.core.index;
|
||||
|
||||
public enum QueryIndexDirection {
|
||||
ASCENDING, DESCENDING
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2014-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.couchbase.core.index;
|
||||
|
||||
import org.springframework.data.couchbase.core.CouchbaseOperations;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link QueryIndexResolver} finds those {@link IndexDefinition}s to be created for a given class.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
* @since 1.5
|
||||
*/
|
||||
public interface QueryIndexResolver {
|
||||
|
||||
/**
|
||||
* Creates a new {@link QueryIndexResolver} given {@link CouchbaseMappingContext}.
|
||||
*
|
||||
* @param mappingContext must not be {@literal null}.
|
||||
* @return the new {@link QueryIndexResolver}.
|
||||
* @since 2.2
|
||||
*/
|
||||
static QueryIndexResolver create(
|
||||
MappingContext<? extends CouchbasePersistentEntity<?>, CouchbasePersistentProperty> mappingContext,
|
||||
CouchbaseOperations operations) {
|
||||
Assert.notNull(mappingContext, "CouchbaseMappingContext must not be null!");
|
||||
return new CouchbasePersistentEntityIndexResolver(mappingContext, operations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and create {@link IndexDefinition}s for properties of given {@link TypeInformation}. {@link IndexDefinition}s
|
||||
* are created for properties and types with {@link QueryIndexed}.
|
||||
*
|
||||
* @param typeInformation
|
||||
* @return Empty {@link Iterable} in case no {@link IndexDefinition} could be resolved for type.
|
||||
*/
|
||||
Iterable<? extends IndexDefinition> resolveIndexFor(TypeInformation<?> typeInformation);
|
||||
|
||||
/**
|
||||
* Find and create {@link IndexDefinition}s for properties of given {@link TypeInformation}. {@link IndexDefinition}s
|
||||
* are created for properties and types with {@link QueryIndexed}.
|
||||
*
|
||||
* @param entityType
|
||||
* @return Empty {@link Iterable} in case no {@link IndexDefinition} could be resolved for type.
|
||||
* @see 2.2
|
||||
*/
|
||||
default Iterable<? extends IndexDefinition> resolveIndexFor(Class<?> entityType) {
|
||||
return resolveIndexFor(ClassTypeInformation.from(entityType));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.couchbase.core.index;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Mark a field to be indexed by the query engine.
|
||||
*/
|
||||
@Target({ ElementType.ANNOTATION_TYPE, ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface QueryIndexed {
|
||||
|
||||
QueryIndexDirection direction() default QueryIndexDirection.ASCENDING;
|
||||
|
||||
String name() default "";
|
||||
|
||||
}
|
||||
@@ -49,6 +49,8 @@ public class CouchbaseMappingContext
|
||||
*/
|
||||
private FieldNamingStrategy fieldNamingStrategy = DEFAULT_NAMING_STRATEGY;
|
||||
|
||||
private boolean autoIndexCreation = true;
|
||||
|
||||
/**
|
||||
* Configures the {@link FieldNamingStrategy} to be used to determine the field name if no manual mapping is applied.
|
||||
* Defaults to a strategy using the plain property name.
|
||||
@@ -101,4 +103,12 @@ public class CouchbaseMappingContext
|
||||
context = applicationContext;
|
||||
}
|
||||
|
||||
public boolean isAutoIndexCreation() {
|
||||
return autoIndexCreation;
|
||||
}
|
||||
|
||||
public void setAutoIndexCreation(boolean autoCreateIndexes) {
|
||||
this.autoIndexCreation = autoCreateIndexes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user