1616package org .springframework .data .mongodb .core ;
1717
1818import java .util .ArrayList ;
19- import java .util .Collection ;
2019import java .util .List ;
2120
2221import org .bson .Document ;
2322import org .jspecify .annotations .Nullable ;
24- import org . springframework . dao . DataAccessException ;
23+
2524import org .springframework .data .mongodb .MongoDatabaseFactory ;
26- import org .springframework .data .mongodb .UncategorizedMongoDbException ;
2725import org .springframework .data .mongodb .core .convert .QueryMapper ;
2826import org .springframework .data .mongodb .core .index .IndexDefinition ;
2927import org .springframework .data .mongodb .core .index .IndexInfo ;
3028import 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 ;
3230import 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}.
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}
0 commit comments