DATAREDIS-425 - Support distinct indexName

This commit adds support for distinguishing between
the property path that is being indexed and the
name of the index that should be used.

This is useful when you do not want the property
path and index name to be the same. For example,
if you want to use Spel expressions, it may not be
possible to use the path as the name of the index.

Original PR #160
This commit is contained in:
Rob Winch
2015-12-14 17:13:53 -06:00
committed by Christoph Strobl
parent bd7728e6ad
commit 40c2582302
8 changed files with 160 additions and 38 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-2016 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.
@@ -32,6 +32,7 @@ import org.springframework.util.CollectionUtils;
* allows to remove the root key from all indexes in case of deletion.
*
* @author Christoph Strobl
* @author Rob Winch
* @since 1.7
*/
class IndexWriter {
@@ -113,7 +114,7 @@ class IndexWriter {
}
/**
* Remove given key from all indexes matching {@link IndexedData#getPath()}:
* Remove given key from all indexes matching {@link IndexedData#getIndexName()}:
*
* @param key
* @param indexedData
@@ -121,7 +122,8 @@ class IndexWriter {
protected void removeKeyFromExistingIndexes(byte[] key, IndexedData indexedData) {
Assert.notNull(indexedData, "IndexedData must not be null!");
Set<byte[]> existingKeys = connection.keys(toBytes(indexedData.getKeySpace() + ":" + indexedData.getPath() + ":*"));
Set<byte[]> existingKeys = connection.keys(toBytes(indexedData.getKeySpace() + ":" + indexedData.getIndexName()
+ ":*"));
if (!CollectionUtils.isEmpty(existingKeys)) {
for (byte[] existingKey : existingKeys) {
@@ -138,7 +140,7 @@ class IndexWriter {
}
/**
* Adds a given key to the index for {@link IndexedData#getPath()}.
* Adds a given key to the index for {@link IndexedData#getIndexName()}.
*
* @param key must not be {@literal null}.
* @param indexedData must not be {@literal null}.
@@ -156,7 +158,7 @@ class IndexWriter {
return;
}
byte[] indexKey = toBytes(indexedData.getKeySpace() + ":" + indexedData.getPath() + ":");
byte[] indexKey = toBytes(indexedData.getKeySpace() + ":" + indexedData.getIndexName() + ":");
indexKey = ByteUtils.concat(indexKey, toBytes(value));
connection.sAdd(indexKey, key);

View File

@@ -37,7 +37,7 @@ import org.springframework.util.Assert;
/**
* {@link IndexResolver} implementation considering properties annotated with {@link Indexed} or paths set up in
* {@link IndexConfiguration}.
*
*
* @author Christoph Strobl
* @since 1.7
*/
@@ -55,7 +55,7 @@ public class IndexResolverImpl implements IndexResolver {
/**
* Creates new {@link IndexResolverImpl} with given {@link IndexConfiguration}.
*
*
* @param mapppingContext must not be {@literal null}.
*/
public IndexResolverImpl(RedisMappingContext mappingContext) {
@@ -166,7 +166,11 @@ public class IndexResolverImpl implements IndexResolver {
String path = normalizeIndexPath(propertyPath, property);
if (indexConfiguration.hasIndexFor(keyspace, path)) {
return new SimpleIndexedPropertyValue(keyspace, path, value);
// FIXME it seems there is a mis-match between IndexConfiguration
// resolving many RedisIndexSetting objects to resolving a single
// IndexData in this method.
RedisIndexSetting indexSetting = indexConfiguration.getIndexDefinitionsFor(keyspace, path).iterator().next();
return new SimpleIndexedPropertyValue(keyspace, indexSetting.getIndexName(), value);
}
else if (property != null && property.isAnnotationPresent(Indexed.class)) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-2016 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.
@@ -17,22 +17,23 @@ package org.springframework.data.redis.core.convert;
/**
* {@link IndexedData} represents a secondary index for a property path in a given keyspace.
*
*
* @author Christoph Strobl
* @author Rob Winch
* @since 1.7
*/
public interface IndexedData {
/**
* Get the {@link String} representation of the dot path to the referenced property.
*
* Get the {@link String} representation of the index name.
*
* @return never {@literal null}.
*/
String getPath();
String getIndexName();
/**
* Get the associated keyspace the index resides in.
*
*
* @return
*/
String getKeySpace();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-2016 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.
@@ -19,33 +19,34 @@ import org.springframework.util.ObjectUtils;
/**
* {@link IndexedData} implementation indicating storage of data within a Redis Set.
*
*
* @author Christoph Strobl
* @author Rob Winch
* @since 1.7
*/
public class SimpleIndexedPropertyValue implements IndexedData {
private final String keyspace;
private final String path;
private final String indexName;
private final Object value;
/**
* Creates new {@link SimpleIndexedPropertyValue}.
*
*
* @param keyspace must not be {@literal null}.
* @param path must not be {@literal null}.
* @param indexName must not be {@literal null}.
* @param value can be {@literal null}.
*/
public SimpleIndexedPropertyValue(String keyspace, String path, Object value) {
public SimpleIndexedPropertyValue(String keyspace, String indexName, Object value) {
this.keyspace = keyspace;
this.path = path;
this.indexName = indexName;
this.value = value;
}
/**
* Get the value to index.
*
*
* @return can be {@literal null}.
*/
public Object getValue() {
@@ -54,11 +55,11 @@ public class SimpleIndexedPropertyValue implements IndexedData {
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.convert.IndexedData#getPath()
* @see org.springframework.data.redis.core.convert.IndexedData#getIndexName()
*/
@Override
public String getPath() {
return path;
public String getIndexName() {
return indexName;
}
/*
@@ -79,7 +80,7 @@ public class SimpleIndexedPropertyValue implements IndexedData {
int result = 1;
result += ObjectUtils.nullSafeHashCode(keyspace);
result += ObjectUtils.nullSafeHashCode(path);
result += ObjectUtils.nullSafeHashCode(indexName);
result += ObjectUtils.nullSafeHashCode(value);
return result;
}
@@ -105,7 +106,7 @@ public class SimpleIndexedPropertyValue implements IndexedData {
if (!ObjectUtils.nullSafeEquals(this.keyspace, that.keyspace)) {
return false;
}
if (!ObjectUtils.nullSafeEquals(this.path, that.path)) {
if (!ObjectUtils.nullSafeEquals(this.indexName, that.indexName)) {
return false;
}
return ObjectUtils.nullSafeEquals(this.value, that.value);
@@ -117,7 +118,7 @@ public class SimpleIndexedPropertyValue implements IndexedData {
*/
@Override
public String toString() {
return "SimpleIndexedPropertyValue [keyspace=" + keyspace + ", path=" + path + ", value=" + value + "]";
return "SimpleIndexedPropertyValue [keyspace=" + keyspace + ", indexName=" + indexName + ", value=" + value + "]";
}
}

View File

@@ -28,8 +28,9 @@ import org.springframework.util.ObjectUtils;
/**
* {@link IndexConfiguration} allows programmatic setup of indexes. This is suitable for cases where there is no option
* to use the equivalent {@link Indexed} annotation.
*
*
* @author Christoph Strobl
* @author Rob Winch
* @since 1.7
*/
public class IndexConfiguration {
@@ -40,6 +41,7 @@ public class IndexConfiguration {
* Creates new empty {@link IndexConfiguration}.
*/
public IndexConfiguration() {
this.definitions = new CopyOnWriteArraySet<RedisIndexSetting>();
for (RedisIndexSetting initial : initialConfiguration()) {
addIndexDefinition(initial);
@@ -48,7 +50,7 @@ public class IndexConfiguration {
/**
* Checks if an index is defined for a given keyspace and property path.
*
*
* @param keyspace
* @param path
* @return true if index is defined.
@@ -66,7 +68,7 @@ public class IndexConfiguration {
/**
* Get the list of {@link RedisIndexSetting} for a given keyspace and property path.
*
*
* @param keyspace
* @param path
* @return never {@literal null}.
@@ -86,7 +88,7 @@ public class IndexConfiguration {
/**
* Add given {@link RedisIndexSetting}.
*
*
* @param indexDefinition must not be {@literal null}.
*/
public void addIndexDefinition(RedisIndexSetting indexDefinition) {
@@ -108,7 +110,7 @@ public class IndexConfiguration {
/**
* Customization hook.
*
*
* @return must not return {@literal null}.
*/
protected Iterable<RedisIndexSetting> initialConfiguration() {
@@ -117,12 +119,14 @@ public class IndexConfiguration {
/**
* @author Christoph Strobl
* @author Rob Winch
* @since 1.7
*/
public static class RedisIndexSetting {
private final Serializable keyspace;
private final String path;
private final String indexName;
private final IndexType type;
public RedisIndexSetting(Serializable keyspace, String path) {
@@ -130,12 +134,20 @@ public class IndexConfiguration {
}
public RedisIndexSetting(Serializable keyspace, String path, IndexType type) {
this(keyspace, path, path, type);
}
public RedisIndexSetting(Serializable keyspace, String path, String indexName, IndexType type) {
this.keyspace = keyspace;
this.path = path;
this.indexName = indexName;
this.type = type == null ? IndexType.SIMPLE : type;
}
public String getIndexName() {
return indexName;
}
public Serializable getKeyspace() {
return keyspace;
}
@@ -153,6 +165,7 @@ public class IndexConfiguration {
int result = ObjectUtils.nullSafeHashCode(keyspace);
result += ObjectUtils.nullSafeHashCode(path);
result += ObjectUtils.nullSafeHashCode(indexName);
result += ObjectUtils.nullSafeHashCode(type);
return result;
}
@@ -178,6 +191,9 @@ public class IndexConfiguration {
if (!ObjectUtils.nullSafeEquals(this.path, that.path)) {
return false;
}
if (!ObjectUtils.nullSafeEquals(this.indexName, that.indexName)) {
return false;
}
if (!ObjectUtils.nullSafeEquals(this.type, that.type)) {
return false;
}