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 @@ -24,6 +24,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import org.bson.Document;
Expand All @@ -41,6 +42,7 @@
* @author Oliver Gierke
* @author Christoph Strobl
* @author Mark Paluch
* @author dragonfsky
*/
public class IndexInfo {

Expand Down Expand Up @@ -182,16 +184,80 @@ public List<IndexField> getIndexFields() {
}

/**
* Returns whether the index is covering exactly the fields given independently of the order.
* Returns whether the index contains all given field keys independently of their position. Field keys are compared as
* a set and therefore repeated input keys are ignored.
*
* @param keys must not be {@literal null}.
* @return
* @since 5.1
*/
public boolean containsAllFields(Collection<String> keys) {

Assert.notNull(keys, "Collection of keys must not be null");

return getIndexFieldKeys().containsAll(keys);
}

/**
* Returns whether the index contains all given field keys independently of their position. Field keys are compared as
* a set and therefore repeated input keys are ignored.
*
* @param keys must not be {@literal null}.
* @return
* @deprecated since 5.1. Use {@link #containsAllFields(Collection)}, {@link #isIndexForFieldsExactly(Collection)}, or
* {@link #coversFields(Collection)} to express the intended index field matching semantics.
*/
@Deprecated(since = "5.1")
public boolean isIndexForFields(Collection<String> keys) {
return containsAllFields(keys);
}

/**
* Returns whether the index matches exactly the given field keys independently of their order. Field keys are compared
* as a set and therefore repeated input keys are ignored.
*
* @param keys must not be {@literal null}.
* @return
* @since 5.1
*/
public boolean isIndexForFieldsExactly(Collection<String> keys) {

Assert.notNull(keys, "Collection of keys must not be null");

return this.indexFields.stream().map(IndexField::getKey).collect(Collectors.toSet()).containsAll(keys);
Set<String> indexFieldKeys = getIndexFieldKeys();
Set<String> keysToCheck = keys.stream().collect(Collectors.toSet());

return indexFieldKeys.size() == keysToCheck.size() && indexFieldKeys.containsAll(keysToCheck);
}

/**
* Returns whether the given field keys are covered by this index according to compound-index prefix field matching.
* Field keys are compared as a set and therefore repeated input keys are ignored. This method matches
* {@link IndexField#getKey() index field keys} only and does not evaluate special query semantics of text, geo, or
* wildcard indexes.
*
* @param keys must not be {@literal null}.
* @return
* @since 5.1
*/
public boolean coversFields(Collection<String> keys) {

Assert.notNull(keys, "Collection of keys must not be null");

Set<String> keysToCheck = keys.stream().collect(Collectors.toSet());

if (keysToCheck.size() > indexFields.size()) {
return false;
}

Set<String> indexFieldPrefix = indexFields.stream().limit(keysToCheck.size()).map(IndexField::getKey)
.collect(Collectors.toSet());

return indexFieldPrefix.containsAll(keysToCheck);
}

private Set<String> getIndexFieldKeys() {
return this.indexFields.stream().map(IndexField::getKey).collect(Collectors.toSet());
}

public String getName() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
* @author Oliver Gierke
* @author Christoph Strobl
* @author Stefan Tirea
* @author dragonfsky
*/
class IndexInfoUnitTests {

Expand All @@ -50,14 +51,52 @@ class IndexInfoUnitTests {
}
""";

@Test
void isIndexForFieldsCorrectly() {
@Test // GH-5187
@SuppressWarnings("deprecation")
void isIndexForFieldsRetainsContainsAllBehavior() {

IndexField fooField = IndexField.create("foo", Direction.ASC);
IndexField barField = IndexField.create("bar", Direction.DESC);

IndexInfo info = new IndexInfo(Arrays.asList(fooField, barField), "myIndex", false, false, "");
assertThat(info.isIndexForFields(Arrays.asList("foo", "bar"))).isTrue();
assertThat(info.isIndexForFields(Arrays.asList("foo"))).isTrue();
}

@Test // GH-5187
void containsAllFieldsReturnsTrueForFieldSubset() {

IndexInfo info = new IndexInfo(Arrays.asList(IndexField.create("foo", Direction.ASC),
IndexField.create("bar", Direction.DESC)), "myIndex", false, false, "");

assertThat(info.containsAllFields(Arrays.asList("foo"))).isTrue();
assertThat(info.containsAllFields(Arrays.asList("bar", "foo"))).isTrue();
assertThat(info.containsAllFields(Arrays.asList("foo", "baz"))).isFalse();
}

@Test // GH-5187
void isIndexForFieldsExactlyRequiresSameFields() {

IndexInfo info = new IndexInfo(Arrays.asList(IndexField.create("foo", Direction.ASC),
IndexField.create("bar", Direction.DESC)), "myIndex", false, false, "");

assertThat(info.isIndexForFieldsExactly(Arrays.asList("foo", "bar"))).isTrue();
assertThat(info.isIndexForFieldsExactly(Arrays.asList("bar", "foo"))).isTrue();
assertThat(info.isIndexForFieldsExactly(Arrays.asList("foo"))).isFalse();
assertThat(info.isIndexForFieldsExactly(Arrays.asList("foo", "bar", "baz"))).isFalse();
}

@Test // GH-5187
void coversFieldsOnlyMatchesIndexPrefixes() {

IndexInfo info = new IndexInfo(Arrays.asList(IndexField.create("foo", Direction.ASC),
IndexField.create("bar", Direction.DESC), IndexField.create("baz", Direction.ASC)), "myIndex", false,
false, "");

assertThat(info.coversFields(Arrays.asList("foo"))).isTrue();
assertThat(info.coversFields(Arrays.asList("bar", "foo"))).isTrue();
assertThat(info.coversFields(Arrays.asList("bar"))).isFalse();
assertThat(info.coversFields(Arrays.asList("foo", "baz"))).isFalse();
}

@Test // DATAMONGO-2170
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
* Integration test for index creation for query methods.
*
* @author Oliver Gierke
* @author dragonfsky
*/
@RunWith(SpringRunner.class)
@ContextConfiguration
Expand Down Expand Up @@ -84,7 +85,7 @@ public void testname() {
private static void assertHasIndexForField(List<IndexInfo> indexInfo, String... fields) {

for (IndexInfo info : indexInfo) {
if (info.isIndexForFields(Arrays.asList(fields))) {
if (info.containsAllFields(Arrays.asList(fields))) {
return;
}
}
Expand Down