Skip to content

Commit 8772742

Browse files
committed
Revise index operations to remove redundant code.
Refactored code duplications between DefaultIndexOperations and DefaultReactiveIndexOperations into IndexOperationsSupport. Added indexOps() overload to ReactiveMongoOperations accepting the entity class and collection name for consistency with MongoOperations. IndexOperationsSupport provides template methods for various mapping stages of index information.
1 parent f0d7c8a commit 8772742

11 files changed

Lines changed: 369 additions & 235 deletions

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/DefaultIndexOperations.java

Lines changed: 47 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,18 @@
1616
package org.springframework.data.mongodb.core;
1717

1818
import java.util.ArrayList;
19-
import java.util.Collection;
2019
import java.util.List;
2120

2221
import org.bson.Document;
2322
import org.jspecify.annotations.Nullable;
24-
import org.springframework.dao.DataAccessException;
23+
2524
import org.springframework.data.mongodb.MongoDatabaseFactory;
26-
import org.springframework.data.mongodb.UncategorizedMongoDbException;
2725
import org.springframework.data.mongodb.core.convert.QueryMapper;
2826
import org.springframework.data.mongodb.core.index.IndexDefinition;
2927
import org.springframework.data.mongodb.core.index.IndexInfo;
3028
import org.springframework.data.mongodb.core.index.IndexOperations;
31-
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
29+
import org.springframework.data.mongodb.core.mapping.CollectionName;
3230
import org.springframework.util.Assert;
33-
import org.springframework.util.NumberUtils;
34-
35-
import com.mongodb.MongoException;
36-
import com.mongodb.client.MongoCollection;
37-
import com.mongodb.client.MongoCursor;
38-
import com.mongodb.client.model.IndexOptions;
3931

4032
/**
4133
* Default implementation of {@link IndexOperations}.
@@ -46,133 +38,111 @@
4638
* @author Christoph Strobl
4739
* @author Mark Paluch
4840
*/
49-
public class DefaultIndexOperations implements IndexOperations {
50-
51-
private static final String PARTIAL_FILTER_EXPRESSION_KEY = "partialFilterExpression";
52-
53-
private final String collectionName;
54-
private final QueryMapper mapper;
55-
private final @Nullable Class<?> type;
41+
public class DefaultIndexOperations extends IndexOperationsSupport implements IndexOperations {
5642

5743
private final MongoOperations mongoOperations;
5844

5945
/**
60-
* Creates a new {@link DefaultIndexOperations}.
46+
* Creates a new {@code DefaultIndexOperations}.
6147
*
6248
* @param mongoDbFactory must not be {@literal null}.
6349
* @param collectionName must not be {@literal null}.
6450
* @param queryMapper must not be {@literal null}.
6551
* @deprecated since 2.1. Please use
66-
* {@link DefaultIndexOperations#DefaultIndexOperations(MongoOperations, String, Class)}.
52+
* {@code DefaultIndexOperations#DefaultIndexOperations(MongoOperations, String, Class)}.
6753
*/
6854
@Deprecated
6955
public DefaultIndexOperations(MongoDatabaseFactory mongoDbFactory, String collectionName, QueryMapper queryMapper) {
7056
this(mongoDbFactory, collectionName, queryMapper, null);
7157
}
7258

7359
/**
74-
* Creates a new {@link DefaultIndexOperations}.
60+
* Creates a new {@code DefaultIndexOperations}.
7561
*
7662
* @param mongoDbFactory must not be {@literal null}.
7763
* @param collectionName must not be {@literal null}.
7864
* @param queryMapper must not be {@literal null}.
7965
* @param type Type used for mapping potential partial index filter expression. Can be {@literal null}.
8066
* @since 1.10
8167
* @deprecated since 2.1. Please use
82-
* {@link DefaultIndexOperations#DefaultIndexOperations(MongoOperations, String, Class)}.
68+
* {@code DefaultIndexOperations#DefaultIndexOperations(MongoOperations, String, Class)}.
8369
*/
8470
@Deprecated
8571
public DefaultIndexOperations(MongoDatabaseFactory mongoDbFactory, String collectionName, QueryMapper queryMapper,
8672
@Nullable Class<?> type) {
87-
88-
Assert.notNull(mongoDbFactory, "MongoDbFactory must not be null");
89-
Assert.notNull(collectionName, "Collection name can not be null");
90-
Assert.notNull(queryMapper, "QueryMapper must not be null");
91-
92-
this.collectionName = collectionName;
93-
this.mapper = queryMapper;
94-
this.type = type;
95-
this.mongoOperations = new MongoTemplate(mongoDbFactory);
73+
this(new MongoTemplate(mongoDbFactory), collectionName, queryMapper, type);
9674
}
9775

9876
/**
99-
* Creates a new {@link DefaultIndexOperations}.
77+
* Creates a new {@code DefaultIndexOperations}.
10078
*
10179
* @param mongoOperations must not be {@literal null}.
10280
* @param collectionName must not be {@literal null} or empty.
10381
* @param type can be {@literal null}.
10482
* @since 2.1
10583
*/
10684
public DefaultIndexOperations(MongoOperations mongoOperations, String collectionName, @Nullable Class<?> type) {
85+
this(mongoOperations, CollectionName.just(collectionName), new QueryMapper(mongoOperations.getConverter()), type);
86+
}
10787

108-
Assert.notNull(mongoOperations, "MongoOperations must not be null");
109-
Assert.hasText(collectionName, "Collection name must not be null or empty");
88+
/**
89+
* Creates a new {@code DefaultIndexOperations}.
90+
*
91+
* @param mongoOperations must not be {@literal null}.
92+
* @param collectionName must not be {@literal null}.
93+
* @param queryMapper must not be {@literal null}.
94+
* @param type used for mapping potential partial index filter expression.
95+
* @since 5.1
96+
*/
97+
public DefaultIndexOperations(MongoOperations mongoOperations, String collectionName, QueryMapper queryMapper,
98+
@Nullable Class<?> type) {
99+
this(mongoOperations, CollectionName.just(collectionName), queryMapper, type);
100+
}
101+
102+
/**
103+
* Creates a new {@code DefaultIndexOperations}.
104+
*
105+
* @param mongoOperations must not be {@literal null}.
106+
* @param collectionName must not be {@literal null} or empty.
107+
* @param type can be {@literal null}.
108+
* @since 5.1
109+
*/
110+
protected DefaultIndexOperations(MongoOperations mongoOperations, CollectionName collectionName,
111+
QueryMapper queryMapper, @Nullable Class<?> type) {
112+
113+
super(collectionName, queryMapper, type);
110114

115+
Assert.notNull(mongoOperations, "MongoOperations must not be null");
111116
this.mongoOperations = mongoOperations;
112-
this.mapper = new QueryMapper(mongoOperations.getConverter());
113-
this.collectionName = collectionName;
114-
this.type = type;
115117
}
116118

117119
@Override
118-
@SuppressWarnings("NullAway")
119120
public String createIndex(IndexDefinition indexDefinition) {
120121

121122
return execute(collection -> {
122123

123-
MongoPersistentEntity<?> entity = lookupPersistentEntity(type, collectionName);
124-
125-
IndexOptions indexOptions = IndexConverters.toIndexOptions(indexDefinition);
126-
127-
indexOptions = addPartialFilterIfPresent(indexOptions, indexDefinition.getIndexOptions(), entity);
128-
indexOptions = addDefaultCollationIfRequired(indexOptions, entity);
129-
130-
Document mappedKeys = mapper.getMappedSort(indexDefinition.getIndexKeys(), entity);
131-
return collection.createIndex(mappedKeys, indexOptions);
124+
CreateIndexCommand command = toCreateIndexCommand(indexDefinition);
125+
return collection.createIndexes(command.toIndexModels(), command.createIndexOptions()).get(0);
132126
});
133127
}
134128

135-
private @Nullable MongoPersistentEntity<?> lookupPersistentEntity(@Nullable Class<?> entityType, String collection) {
136-
137-
if (entityType != null) {
138-
return mapper.getMappingContext().getRequiredPersistentEntity(entityType);
139-
}
140-
141-
Collection<? extends MongoPersistentEntity<?>> entities = mapper.getMappingContext().getPersistentEntities();
142-
143-
for (MongoPersistentEntity<?> entity : entities) {
144-
if (entity.getCollection().equals(collection)) {
145-
return entity;
146-
}
147-
}
148-
149-
return null;
150-
}
151-
152129
@Override
153130
public void dropIndex(String name) {
154131

155132
execute(collection -> {
156133
collection.dropIndex(name);
157134
return null;
158135
});
159-
160136
}
161137

162138
@Override
163139
@SuppressWarnings("NullAway")
164140
public void alterIndex(String name, org.springframework.data.mongodb.core.index.IndexOptions options) {
165141

166-
Document indexOptions = new Document("name", name);
167-
indexOptions.putAll(options.toDocument());
168-
169142
Document result = mongoOperations
170-
.execute(db -> db.runCommand(new Document("collMod", collectionName).append("index", indexOptions)));
143+
.execute(db -> db.runCommand(alterIndexCommand(name, options), Document.class));
171144

172-
if (NumberUtils.convertNumberToTargetClass(result.get("ok", (Number) 0), Integer.class) != 1) {
173-
throw new UncategorizedMongoDbException(
174-
"Index '%s' could not be modified. Response was %s".formatted(name, result.toJson()), null);
175-
}
145+
validateAlterIndexResponse(name, result);
176146
}
177147

178148
@Override
@@ -181,62 +151,15 @@ public void dropAllIndexes() {
181151
}
182152

183153
@Override
184-
@SuppressWarnings("NullAway")
185154
public List<IndexInfo> getIndexInfo() {
186-
187-
return execute(new CollectionCallback<List<IndexInfo>>() {
188-
189-
public List<IndexInfo> doInCollection(MongoCollection<Document> collection)
190-
throws MongoException, DataAccessException {
191-
192-
MongoCursor<Document> cursor = collection.listIndexes(Document.class).iterator();
193-
return getIndexData(cursor);
194-
}
195-
196-
private List<IndexInfo> getIndexData(MongoCursor<Document> cursor) {
197-
198-
int available = cursor.available();
199-
List<IndexInfo> indexInfoList = available > 0 ? new ArrayList<>(available) : new ArrayList<>();
200-
201-
while (cursor.hasNext()) {
202-
203-
Document ix = cursor.next();
204-
IndexInfo indexInfo = IndexInfo.indexInfoOf(ix);
205-
indexInfoList.add(indexInfo);
206-
}
207-
208-
return indexInfoList;
209-
}
210-
});
211-
}
212-
213-
public <T> @Nullable T execute(CollectionCallback<T> callback) {
214-
215-
Assert.notNull(callback, "CollectionCallback must not be null");
216-
217-
return mongoOperations.execute(collectionName, callback);
218-
}
219-
220-
private IndexOptions addPartialFilterIfPresent(IndexOptions ops, Document sourceOptions,
221-
@Nullable MongoPersistentEntity<?> entity) {
222-
223-
if (!sourceOptions.containsKey(PARTIAL_FILTER_EXPRESSION_KEY)) {
224-
return ops;
225-
}
226-
227-
Assert.isInstanceOf(Document.class, sourceOptions.get(PARTIAL_FILTER_EXPRESSION_KEY));
228-
return ops.partialFilterExpression(
229-
mapper.getMappedSort((Document) sourceOptions.get(PARTIAL_FILTER_EXPRESSION_KEY), entity));
155+
return execute(
156+
collection -> collection.listIndexes(Document.class).map(IndexInfo::indexInfoOf).into(new ArrayList<>()));
230157
}
231158

232159
@SuppressWarnings("NullAway")
233-
private static IndexOptions addDefaultCollationIfRequired(IndexOptions ops,
234-
@Nullable MongoPersistentEntity<?> entity) {
235-
236-
if (ops.getCollation() != null || entity == null || !entity.hasCollation()) {
237-
return ops;
238-
}
160+
public <T> T execute(CollectionCallback<T> callback) {
239161

240-
return ops.collation(entity.getCollation().toMongoCollation());
162+
Assert.notNull(callback, "CollectionCallback must not be null");
163+
return mongoOperations.execute(getCollectionName(), callback);
241164
}
242165
}

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/DefaultIndexOperationsProvider.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class DefaultIndexOperationsProvider implements IndexOperationsProvider {
4444
}
4545

4646
@Override
47-
public IndexOperations indexOps(String collectionName, @Nullable Class<?> type) {
48-
return new DefaultIndexOperations(mongoDbFactory, collectionName, mapper, type);
47+
public IndexOperations indexOps(String collectionName, @Nullable Class<?> entityClass) {
48+
return new DefaultIndexOperations(mongoDbFactory, collectionName, mapper, entityClass);
4949
}
5050
}

0 commit comments

Comments
 (0)