47
47
import org .jspecify .annotations .Nullable ;
48
48
import org .reactivestreams .Publisher ;
49
49
import org .reactivestreams .Subscriber ;
50
-
51
50
import org .springframework .beans .BeansException ;
52
51
import org .springframework .context .ApplicationContext ;
53
52
import org .springframework .context .ApplicationContextAware ;
114
113
import org .springframework .data .mongodb .core .mapreduce .MapReduceOptions ;
115
114
import org .springframework .data .mongodb .core .query .BasicQuery ;
116
115
import org .springframework .data .mongodb .core .query .Collation ;
116
+ import org .springframework .data .mongodb .core .query .Criteria ;
117
117
import org .springframework .data .mongodb .core .query .Meta ;
118
118
import org .springframework .data .mongodb .core .query .NearQuery ;
119
119
import org .springframework .data .mongodb .core .query .Query ;
@@ -1137,9 +1137,8 @@ public <T> Mono<T> findAndModify(Query query, UpdateDefinition update, FindAndMo
1137
1137
return findAndModify (query , update , options , entityClass , getCollectionName (entityClass ));
1138
1138
}
1139
1139
1140
- @ Override
1141
- public <T > Mono <T > findAndModify (Query query , UpdateDefinition update , FindAndModifyOptions options ,
1142
- Class <T > entityClass , String collectionName ) {
1140
+ public <S , T > Mono <T > findAndModify (Query query , UpdateDefinition update , FindAndModifyOptions options ,
1141
+ Class <S > entityClass , String collectionName , QueryResultConverter <? super S , ? extends T > resultConverter ) {
1143
1142
1144
1143
Assert .notNull (options , "Options must not be null " );
1145
1144
Assert .notNull (entityClass , "Entity class must not be null" );
@@ -1156,13 +1155,27 @@ public <T> Mono<T> findAndModify(Query query, UpdateDefinition update, FindAndMo
1156
1155
}
1157
1156
1158
1157
return doFindAndModify (collectionName , ReactiveCollectionPreparerDelegate .of (query ), query .getQueryObject (),
1159
- query .getFieldsObject (), getMappedSortObject (query , entityClass ), entityClass , update , optionsToUse );
1158
+ query .getFieldsObject (), getMappedSortObject (query , entityClass ), entityClass , update , optionsToUse ,
1159
+ resultConverter );
1160
+ }
1161
+
1162
+ @ Override
1163
+ public <T > Mono <T > findAndModify (Query query , UpdateDefinition update , FindAndModifyOptions options ,
1164
+ Class <T > entityClass , String collectionName ) {
1165
+ return findAndModify (query , update , options , entityClass , collectionName , QueryResultConverter .entity ());
1160
1166
}
1161
1167
1162
1168
@ Override
1163
- @ SuppressWarnings ("NullAway" )
1164
1169
public <S , T > Mono <T > findAndReplace (Query query , S replacement , FindAndReplaceOptions options , Class <S > entityType ,
1165
1170
String collectionName , Class <T > resultType ) {
1171
+ return findAndReplace (query , replacement , options , entityType , collectionName , resultType ,
1172
+ QueryResultConverter .entity ());
1173
+ }
1174
+
1175
+ @ SuppressWarnings ("NullAway" )
1176
+ public <S , T , R > Mono <R > findAndReplace (Query query , S replacement , FindAndReplaceOptions options ,
1177
+ Class <S > entityType , String collectionName , Class <T > resultType ,
1178
+ QueryResultConverter <? super T , ? extends R > resultConverter ) {
1166
1179
1167
1180
Assert .notNull (query , "Query must not be null" );
1168
1181
Assert .notNull (replacement , "Replacement must not be null" );
@@ -1199,9 +1212,9 @@ public <S, T> Mono<T> findAndReplace(Query query, S replacement, FindAndReplaceO
1199
1212
mapped .getCollection ()));
1200
1213
}).flatMap (it -> {
1201
1214
1202
- Mono <T > afterFindAndReplace = doFindAndReplace (it .getCollection (), collectionPreparer , mappedQuery ,
1215
+ Mono <R > afterFindAndReplace = doFindAndReplace (it .getCollection (), collectionPreparer , mappedQuery ,
1203
1216
mappedFields , mappedSort , queryContext .getCollation (entityType ).orElse (null ), entityType , it .getTarget (),
1204
- options , projection );
1217
+ options , projection , resultConverter );
1205
1218
return afterFindAndReplace .flatMap (saved -> {
1206
1219
maybeEmitEvent (new AfterSaveEvent <>(saved , it .getTarget (), it .getCollection ()));
1207
1220
return maybeCallAfterSave (saved , it .getTarget (), it .getCollection ());
@@ -2280,6 +2293,43 @@ protected <T> Flux<T> doFindAndDelete(String collectionName, Query query, Class<
2280
2293
.flatMapSequential (deleteResult -> Flux .fromIterable (list )));
2281
2294
}
2282
2295
2296
+ <S , T > Flux <T > doFindAndDelete (String collectionName , Query query , Class <S > entityClass ,
2297
+ QueryResultConverter <? super S , ? extends T > resultConverter ) {
2298
+
2299
+ List <Object > ids = new ArrayList <>();
2300
+ ProjectingReadCallback readCallback = new ProjectingReadCallback (getConverter (),
2301
+ EntityProjection .nonProjecting (entityClass ), collectionName );
2302
+
2303
+ QueryResultConverterCallback <S , T > callback = new QueryResultConverterCallback <>(resultConverter , readCallback ) {
2304
+
2305
+ @ Override
2306
+ public Mono <T > doWith (Document object ) {
2307
+ ids .add (object .get ("_id" ));
2308
+ return super .doWith (object );
2309
+ }
2310
+ };
2311
+
2312
+ Flux <T > flux = doFind (collectionName , ReactiveCollectionPreparerDelegate .of (query ), query .getQueryObject (),
2313
+ query .getFieldsObject (), entityClass ,
2314
+ new QueryFindPublisherPreparer (query , query .getSortObject (), query .getLimit (), query .getSkip (), entityClass ),
2315
+ callback );
2316
+
2317
+ return Flux .from (flux ).collectList ().filter (it -> !it .isEmpty ()).flatMapMany (list -> {
2318
+
2319
+ Criteria [] criterias = ids .stream () //
2320
+ .map (it -> Criteria .where ("_id" ).is (it )) //
2321
+ .toArray (Criteria []::new );
2322
+
2323
+ Query removeQuery = new Query (criterias .length == 1 ? criterias [0 ] : new Criteria ().orOperator (criterias ));
2324
+ if (query .hasReadPreference ()) {
2325
+ removeQuery .withReadPreference (query .getReadPreference ());
2326
+ }
2327
+
2328
+ return Flux .from (remove (removeQuery , entityClass , collectionName ))
2329
+ .flatMapSequential (deleteResult -> Flux .fromIterable (list ));
2330
+ });
2331
+ }
2332
+
2283
2333
/**
2284
2334
* Create the specified collection using the provided options
2285
2335
*
@@ -2487,9 +2537,10 @@ protected <T> Mono<T> doFindAndRemove(String collectionName,
2487
2537
new ReadDocumentCallback <>(this .mongoConverter , entityClass , collectionName ), collectionName );
2488
2538
}
2489
2539
2490
- protected < T > Mono <T > doFindAndModify (String collectionName ,
2540
+ < S , T > Mono <T > doFindAndModify (String collectionName ,
2491
2541
CollectionPreparer <MongoCollection <Document >> collectionPreparer , Document query , Document fields ,
2492
- @ Nullable Document sort , Class <T > entityClass , UpdateDefinition update , FindAndModifyOptions options ) {
2542
+ @ Nullable Document sort , Class <S > entityClass , UpdateDefinition update , FindAndModifyOptions options ,
2543
+ QueryResultConverter <? super S , ? extends T > resultConverter ) {
2493
2544
2494
2545
MongoPersistentEntity <?> entity = mappingContext .getPersistentEntity (entityClass );
2495
2546
UpdateContext updateContext = queryOperations .updateSingleContext (update , query , false );
@@ -2508,10 +2559,13 @@ protected <T> Mono<T> doFindAndModify(String collectionName,
2508
2559
serializeToJsonSafely (mappedUpdate ), collectionName ));
2509
2560
}
2510
2561
2562
+ EntityProjection <S , ?> projection = EntityProjection .nonProjecting (entityClass );
2563
+ DocumentCallback <T > callback = getResultReader (projection , collectionName , resultConverter );
2564
+
2511
2565
return executeFindOneInternal (
2512
2566
new FindAndModifyCallback (collectionPreparer , mappedQuery , fields , sort , mappedUpdate ,
2513
2567
update .getArrayFilters ().stream ().map (ArrayFilter ::asDocument ).collect (Collectors .toList ()), options ),
2514
- new ReadDocumentCallback <>( this . mongoConverter , entityClass , collectionName ) , collectionName );
2568
+ callback , collectionName );
2515
2569
});
2516
2570
}
2517
2571
@@ -2540,7 +2594,7 @@ protected <T> Mono<T> doFindAndReplace(String collectionName,
2540
2594
EntityProjection <T , ?> projection = operations .introspectProjection (resultType , entityType );
2541
2595
2542
2596
return doFindAndReplace (collectionName , collectionPreparer , mappedQuery , mappedFields , mappedSort , collation ,
2543
- entityType , replacement , options , projection );
2597
+ entityType , replacement , options , projection , QueryResultConverter . entity () );
2544
2598
}
2545
2599
2546
2600
/**
@@ -2560,10 +2614,11 @@ protected <T> Mono<T> doFindAndReplace(String collectionName,
2560
2614
* {@literal false} and {@link FindAndReplaceOptions#isUpsert() upsert} is {@literal false}.
2561
2615
* @since 3.4
2562
2616
*/
2563
- private <T > Mono <T > doFindAndReplace (String collectionName ,
2617
+ private <S , T > Mono <T > doFindAndReplace (String collectionName ,
2564
2618
CollectionPreparer <MongoCollection <Document >> collectionPreparer , Document mappedQuery , Document mappedFields ,
2565
2619
Document mappedSort , com .mongodb .client .model .Collation collation , Class <?> entityType , Document replacement ,
2566
- FindAndReplaceOptions options , EntityProjection <T , ?> projection ) {
2620
+ FindAndReplaceOptions options , EntityProjection <S , ?> projection ,
2621
+ QueryResultConverter <? super S , ? extends T > resultConverter ) {
2567
2622
2568
2623
return Mono .defer (() -> {
2569
2624
@@ -2575,9 +2630,10 @@ private <T> Mono<T> doFindAndReplace(String collectionName,
2575
2630
serializeToJsonSafely (replacement ), collectionName ));
2576
2631
}
2577
2632
2633
+ DocumentCallback <T > resultReader = getResultReader (projection , collectionName , resultConverter );
2634
+
2578
2635
return executeFindOneInternal (new FindAndReplaceCallback (collectionPreparer , mappedQuery , mappedFields ,
2579
- mappedSort , replacement , collation , options ),
2580
- new ProjectingReadCallback <>(this .mongoConverter , projection , collectionName ), collectionName );
2636
+ mappedSort , replacement , collation , options ), resultReader , collectionName );
2581
2637
2582
2638
});
2583
2639
}
@@ -3124,7 +3180,7 @@ interface ReactiveCollectionQueryCallback<T> extends ReactiveCollectionCallback<
3124
3180
FindPublisher <T > doInCollection (MongoCollection <Document > collection ) throws MongoException , DataAccessException ;
3125
3181
}
3126
3182
3127
- static final class QueryResultConverterCallback <T , R > implements DocumentCallback <R > {
3183
+ static class QueryResultConverterCallback <T , R > implements DocumentCallback <R > {
3128
3184
3129
3185
private final QueryResultConverter <? super T , ? extends R > converter ;
3130
3186
private final DocumentCallback <T > delegate ;
0 commit comments