Skip to content

Commit bd4f0d3

Browse files
Rob Winchchristophstrobl
authored andcommitted
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
1 parent af5bc62 commit bd4f0d3

File tree

8 files changed

+160
-38
lines changed

8 files changed

+160
-38
lines changed

src/main/java/org/springframework/data/redis/core/IndexWriter.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015 the original author or authors.
2+
* Copyright 2015-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@
3232
* allows to remove the root key from all indexes in case of deletion.
3333
*
3434
* @author Christoph Strobl
35+
* @author Rob Winch
3536
* @since 1.7
3637
*/
3738
class IndexWriter {
@@ -113,15 +114,16 @@ private void removeKeyFromExistingIndexes(byte[] key, Iterable<IndexedData> inde
113114
}
114115

115116
/**
116-
* Remove given key from all indexes matching {@link IndexedData#getPath()}:
117+
* Remove given key from all indexes matching {@link IndexedData#getIndexName()}:
117118
*
118119
* @param key
119120
* @param indexedData
120121
*/
121122
protected void removeKeyFromExistingIndexes(byte[] key, IndexedData indexedData) {
122123

123124
Assert.notNull(indexedData, "IndexedData must not be null!");
124-
Set<byte[]> existingKeys = connection.keys(toBytes(indexedData.getKeySpace() + ":" + indexedData.getPath() + ":*"));
125+
Set<byte[]> existingKeys = connection.keys(toBytes(indexedData.getKeySpace() + ":" + indexedData.getIndexName()
126+
+ ":*"));
125127

126128
if (!CollectionUtils.isEmpty(existingKeys)) {
127129
for (byte[] existingKey : existingKeys) {
@@ -138,7 +140,7 @@ private void addKeyToIndexes(byte[] key, Iterable<IndexedData> indexValues) {
138140
}
139141

140142
/**
141-
* Adds a given key to the index for {@link IndexedData#getPath()}.
143+
* Adds a given key to the index for {@link IndexedData#getIndexName()}.
142144
*
143145
* @param key must not be {@literal null}.
144146
* @param indexedData must not be {@literal null}.
@@ -156,7 +158,7 @@ protected void addKeyToIndex(byte[] key, IndexedData indexedData) {
156158
return;
157159
}
158160

159-
byte[] indexKey = toBytes(indexedData.getKeySpace() + ":" + indexedData.getPath() + ":");
161+
byte[] indexKey = toBytes(indexedData.getKeySpace() + ":" + indexedData.getIndexName() + ":");
160162
indexKey = ByteUtils.concat(indexKey, toBytes(value));
161163
connection.sAdd(indexKey, key);
162164

src/main/java/org/springframework/data/redis/core/convert/IndexResolverImpl.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
/**
3838
* {@link IndexResolver} implementation considering properties annotated with {@link Indexed} or paths set up in
3939
* {@link IndexConfiguration}.
40-
*
40+
*
4141
* @author Christoph Strobl
4242
* @since 1.7
4343
*/
@@ -55,7 +55,7 @@ public IndexResolverImpl() {
5555

5656
/**
5757
* Creates new {@link IndexResolverImpl} with given {@link IndexConfiguration}.
58-
*
58+
*
5959
* @param mapppingContext must not be {@literal null}.
6060
*/
6161
public IndexResolverImpl(RedisMappingContext mappingContext) {
@@ -166,7 +166,11 @@ protected IndexedData resolveIndex(String keyspace, String propertyPath, Persist
166166
String path = normalizeIndexPath(propertyPath, property);
167167

168168
if (indexConfiguration.hasIndexFor(keyspace, path)) {
169-
return new SimpleIndexedPropertyValue(keyspace, path, value);
169+
// FIXME it seems there is a mis-match between IndexConfiguration
170+
// resolving many RedisIndexSetting objects to resolving a single
171+
// IndexData in this method.
172+
RedisIndexSetting indexSetting = indexConfiguration.getIndexDefinitionsFor(keyspace, path).iterator().next();
173+
return new SimpleIndexedPropertyValue(keyspace, indexSetting.getIndexName(), value);
170174
}
171175

172176
else if (property != null && property.isAnnotationPresent(Indexed.class)) {

src/main/java/org/springframework/data/redis/core/convert/IndexedData.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015 the original author or authors.
2+
* Copyright 2015-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,22 +17,23 @@
1717

1818
/**
1919
* {@link IndexedData} represents a secondary index for a property path in a given keyspace.
20-
*
20+
*
2121
* @author Christoph Strobl
22+
* @author Rob Winch
2223
* @since 1.7
2324
*/
2425
public interface IndexedData {
2526

2627
/**
27-
* Get the {@link String} representation of the dot path to the referenced property.
28-
*
28+
* Get the {@link String} representation of the index name.
29+
*
2930
* @return never {@literal null}.
3031
*/
31-
String getPath();
32+
String getIndexName();
3233

3334
/**
3435
* Get the associated keyspace the index resides in.
35-
*
36+
*
3637
* @return
3738
*/
3839
String getKeySpace();

src/main/java/org/springframework/data/redis/core/convert/SimpleIndexedPropertyValue.java

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015 the original author or authors.
2+
* Copyright 2015-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,33 +19,34 @@
1919

2020
/**
2121
* {@link IndexedData} implementation indicating storage of data within a Redis Set.
22-
*
22+
*
2323
* @author Christoph Strobl
24+
* @author Rob Winch
2425
* @since 1.7
2526
*/
2627
public class SimpleIndexedPropertyValue implements IndexedData {
2728

2829
private final String keyspace;
29-
private final String path;
30+
private final String indexName;
3031
private final Object value;
3132

3233
/**
3334
* Creates new {@link SimpleIndexedPropertyValue}.
34-
*
35+
*
3536
* @param keyspace must not be {@literal null}.
36-
* @param path must not be {@literal null}.
37+
* @param indexName must not be {@literal null}.
3738
* @param value can be {@literal null}.
3839
*/
39-
public SimpleIndexedPropertyValue(String keyspace, String path, Object value) {
40+
public SimpleIndexedPropertyValue(String keyspace, String indexName, Object value) {
4041

4142
this.keyspace = keyspace;
42-
this.path = path;
43+
this.indexName = indexName;
4344
this.value = value;
4445
}
4546

4647
/**
4748
* Get the value to index.
48-
*
49+
*
4950
* @return can be {@literal null}.
5051
*/
5152
public Object getValue() {
@@ -54,11 +55,11 @@ public Object getValue() {
5455

5556
/*
5657
* (non-Javadoc)
57-
* @see org.springframework.data.redis.core.convert.IndexedData#getPath()
58+
* @see org.springframework.data.redis.core.convert.IndexedData#getIndexName()
5859
*/
5960
@Override
60-
public String getPath() {
61-
return path;
61+
public String getIndexName() {
62+
return indexName;
6263
}
6364

6465
/*
@@ -79,7 +80,7 @@ public int hashCode() {
7980

8081
int result = 1;
8182
result += ObjectUtils.nullSafeHashCode(keyspace);
82-
result += ObjectUtils.nullSafeHashCode(path);
83+
result += ObjectUtils.nullSafeHashCode(indexName);
8384
result += ObjectUtils.nullSafeHashCode(value);
8485
return result;
8586
}
@@ -105,7 +106,7 @@ public boolean equals(Object obj) {
105106
if (!ObjectUtils.nullSafeEquals(this.keyspace, that.keyspace)) {
106107
return false;
107108
}
108-
if (!ObjectUtils.nullSafeEquals(this.path, that.path)) {
109+
if (!ObjectUtils.nullSafeEquals(this.indexName, that.indexName)) {
109110
return false;
110111
}
111112
return ObjectUtils.nullSafeEquals(this.value, that.value);
@@ -117,7 +118,7 @@ public boolean equals(Object obj) {
117118
*/
118119
@Override
119120
public String toString() {
120-
return "SimpleIndexedPropertyValue [keyspace=" + keyspace + ", path=" + path + ", value=" + value + "]";
121+
return "SimpleIndexedPropertyValue [keyspace=" + keyspace + ", indexName=" + indexName + ", value=" + value + "]";
121122
}
122123

123124
}

src/main/java/org/springframework/data/redis/core/index/IndexConfiguration.java

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@
2828
/**
2929
* {@link IndexConfiguration} allows programmatic setup of indexes. This is suitable for cases where there is no option
3030
* to use the equivalent {@link Indexed} annotation.
31-
*
31+
*
3232
* @author Christoph Strobl
33+
* @author Rob Winch
3334
* @since 1.7
3435
*/
3536
public class IndexConfiguration {
@@ -40,6 +41,7 @@ public class IndexConfiguration {
4041
* Creates new empty {@link IndexConfiguration}.
4142
*/
4243
public IndexConfiguration() {
44+
4345
this.definitions = new CopyOnWriteArraySet<RedisIndexSetting>();
4446
for (RedisIndexSetting initial : initialConfiguration()) {
4547
addIndexDefinition(initial);
@@ -48,7 +50,7 @@ public IndexConfiguration() {
4850

4951
/**
5052
* Checks if an index is defined for a given keyspace and property path.
51-
*
53+
*
5254
* @param keyspace
5355
* @param path
5456
* @return true if index is defined.
@@ -66,7 +68,7 @@ public boolean hasIndexFor(Serializable keyspace, String path) {
6668

6769
/**
6870
* Get the list of {@link RedisIndexSetting} for a given keyspace and property path.
69-
*
71+
*
7072
* @param keyspace
7173
* @param path
7274
* @return never {@literal null}.
@@ -86,7 +88,7 @@ public List<RedisIndexSetting> getIndexDefinitionsFor(Serializable keyspace, Str
8688

8789
/**
8890
* Add given {@link RedisIndexSetting}.
89-
*
91+
*
9092
* @param indexDefinition must not be {@literal null}.
9193
*/
9294
public void addIndexDefinition(RedisIndexSetting indexDefinition) {
@@ -108,7 +110,7 @@ private RedisIndexSetting getIndexDefinition(Serializable keyspace, String path,
108110

109111
/**
110112
* Customization hook.
111-
*
113+
*
112114
* @return must not return {@literal null}.
113115
*/
114116
protected Iterable<RedisIndexSetting> initialConfiguration() {
@@ -117,25 +119,35 @@ protected Iterable<RedisIndexSetting> initialConfiguration() {
117119

118120
/**
119121
* @author Christoph Strobl
122+
* @author Rob Winch
120123
* @since 1.7
121124
*/
122125
public static class RedisIndexSetting {
123126

124127
private final Serializable keyspace;
125128
private final String path;
129+
private final String indexName;
126130
private final IndexType type;
127131

128132
public RedisIndexSetting(Serializable keyspace, String path) {
129133
this(keyspace, path, null);
130134
}
131135

132136
public RedisIndexSetting(Serializable keyspace, String path, IndexType type) {
137+
this(keyspace, path, path, type);
138+
}
133139

140+
public RedisIndexSetting(Serializable keyspace, String path, String indexName, IndexType type) {
134141
this.keyspace = keyspace;
135142
this.path = path;
143+
this.indexName = indexName;
136144
this.type = type == null ? IndexType.SIMPLE : type;
137145
}
138146

147+
public String getIndexName() {
148+
return indexName;
149+
}
150+
139151
public Serializable getKeyspace() {
140152
return keyspace;
141153
}
@@ -153,6 +165,7 @@ public int hashCode() {
153165

154166
int result = ObjectUtils.nullSafeHashCode(keyspace);
155167
result += ObjectUtils.nullSafeHashCode(path);
168+
result += ObjectUtils.nullSafeHashCode(indexName);
156169
result += ObjectUtils.nullSafeHashCode(type);
157170
return result;
158171
}
@@ -178,6 +191,9 @@ public boolean equals(Object obj) {
178191
if (!ObjectUtils.nullSafeEquals(this.path, that.path)) {
179192
return false;
180193
}
194+
if (!ObjectUtils.nullSafeEquals(this.indexName, that.indexName)) {
195+
return false;
196+
}
181197
if (!ObjectUtils.nullSafeEquals(this.type, that.type)) {
182198
return false;
183199
}

src/test/java/org/springframework/data/redis/core/IndexWriterUnitTests.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015 the original author or authors.
2+
* Copyright 2015-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -40,6 +40,7 @@
4040

4141
/**
4242
* @author Christoph Strobl
43+
* @auhtor Rob Winch
4344
*/
4445
@RunWith(MockitoJUnitRunner.class)
4546
public class IndexWriterUnitTests {
@@ -145,7 +146,7 @@ public void removeAllIndexesShouldDeleteAllIndexKeys() {
145146
static class StubIndxedData implements IndexedData {
146147

147148
@Override
148-
public String getPath() {
149+
public String getIndexName() {
149150
return "address.city";
150151
}
151152

src/test/java/org/springframework/data/redis/core/convert/IndexResolverImplUnitTests.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ public void resolveIndexShouldRemovePositionIndicatorForValuesInLists() {
296296

297297
IndexedData index = resolve("list.[0].name", "rand");
298298

299-
assertThat(index.getPath(), is("list.name"));
299+
assertThat(index.getIndexName(), is("list.name"));
300300
}
301301

302302
/**
@@ -311,7 +311,7 @@ public void resolveIndexShouldRemoveKeyIndicatorForValuesInMap() {
311311

312312
IndexedData index = resolve("map.[foo].name", "rand");
313313

314-
assertThat(index.getPath(), is("map.foo.name"));
314+
assertThat(index.getIndexName(), is("map.foo.name"));
315315
}
316316

317317
/**
@@ -326,7 +326,7 @@ public void resolveIndexShouldKeepNumericalKeyForValuesInMap() {
326326

327327
IndexedData index = resolve("map.[0].name", "rand");
328328

329-
assertThat(index.getPath(), is("map.0.name"));
329+
assertThat(index.getIndexName(), is("map.0.name"));
330330
}
331331

332332
/**
@@ -405,6 +405,27 @@ public void resolveIndexShouldInspectObjectTypeValuesInListProperties() {
405405
assertThat(indexes, hasItem(new SimpleIndexedPropertyValue(KEYSPACE_PERSON, "items.type", "hat")));
406406
}
407407

408+
/**
409+
* @see DATAREDIS-425
410+
*/
411+
@Test
412+
public void resolveIndexAllowCustomIndexName() {
413+
indexConfig.addIndexDefinition(new RedisIndexSetting(KEYSPACE_PERSON, "items.type", "itemsType", IndexType.SIMPLE));
414+
415+
Item hat = new Item();
416+
hat.type = "hat";
417+
418+
TaVeren mat = new TaVeren();
419+
mat.items = new ArrayList<Object>(2);
420+
mat.items.add(hat);
421+
mat.items.add("foxhead medallion");
422+
423+
Set<IndexedData> indexes = indexResolver.resolveIndexesFor(ClassTypeInformation.from(TaVeren.class), mat);
424+
425+
assertThat(indexes.size(), is(1));
426+
assertThat(indexes, hasItem(new SimpleIndexedPropertyValue(KEYSPACE_PERSON, "itemsType", "hat")));
427+
}
428+
408429
private IndexedData resolve(String path, Object value) {
409430
return indexResolver.resolveIndex(KEYSPACE_PERSON, path, propertyMock, value);
410431
}

0 commit comments

Comments
 (0)