30
30
import java .util .Map ;
31
31
import java .util .Optional ;
32
32
import java .util .Set ;
33
+ import java .util .function .BiFunction ;
33
34
import java .util .function .Consumer ;
34
35
import java .util .function .Function ;
35
36
import java .util .function .Predicate ;
47
48
import org .neo4j .driver .summary .ResultSummary ;
48
49
import org .neo4j .driver .summary .SummaryCounters ;
49
50
import org .neo4j .driver .types .Entity ;
51
+ import org .neo4j .driver .types .MapAccessor ;
52
+ import org .neo4j .driver .types .TypeSystem ;
50
53
import org .springframework .beans .BeansException ;
51
54
import org .springframework .beans .factory .BeanClassLoaderAware ;
52
55
import org .springframework .beans .factory .BeanFactory ;
61
64
import org .springframework .data .neo4j .core .mapping .Constants ;
62
65
import org .springframework .data .neo4j .core .mapping .CreateRelationshipStatementHolder ;
63
66
import org .springframework .data .neo4j .core .mapping .CypherGenerator ;
67
+ import org .springframework .data .neo4j .core .mapping .DtoInstantiatingConverter ;
68
+ import org .springframework .data .neo4j .core .mapping .EntityInstanceWithSource ;
64
69
import org .springframework .data .neo4j .core .mapping .MappingSupport ;
65
70
import org .springframework .data .neo4j .core .mapping .Neo4jMappingContext ;
66
71
import org .springframework .data .neo4j .core .mapping .Neo4jPersistentEntity ;
@@ -190,24 +195,29 @@ public long count(String cypherQuery, Map<String, Object> parameters) {
190
195
191
196
@ Override
192
197
public <T > List <T > findAll (Class <T > domainType ) {
198
+
199
+ return doFindAll (domainType , null );
200
+ }
201
+
202
+ private <T > List <T > doFindAll (Class <T > domainType , Class <?> resultType ) {
193
203
Neo4jPersistentEntity <?> entityMetaData = neo4jMappingContext .getPersistentEntity (domainType );
194
- return createExecutableQuery (domainType , QueryFragmentsAndParameters .forFindAll (entityMetaData ))
204
+ return createExecutableQuery (domainType , resultType , QueryFragmentsAndParameters .forFindAll (entityMetaData ))
195
205
.getResults ();
196
206
}
197
207
198
208
@ Override
199
209
public <T > List <T > findAll (Statement statement , Class <T > domainType ) {
200
- return createExecutableQuery (domainType , statement , Collections . emptyMap () ).getResults ();
210
+ return createExecutableQuery (domainType , statement ).getResults ();
201
211
}
202
212
203
213
@ Override
204
214
public <T > List <T > findAll (Statement statement , Map <String , Object > parameters , Class <T > domainType ) {
205
- return createExecutableQuery (domainType , statement , parameters ).getResults ();
215
+ return createExecutableQuery (domainType , null , statement , parameters ).getResults ();
206
216
}
207
217
208
218
@ Override
209
219
public <T > Optional <T > findOne (Statement statement , Map <String , Object > parameters , Class <T > domainType ) {
210
- return createExecutableQuery (domainType , statement , parameters ).getSingleResult ();
220
+ return createExecutableQuery (domainType , null , statement , parameters ).getSingleResult ();
211
221
}
212
222
213
223
@ Override
@@ -217,26 +227,27 @@ public <T> List<T> findAll(String cypherQuery, Class<T> domainType) {
217
227
218
228
@ Override
219
229
public <T > List <T > findAll (String cypherQuery , Map <String , Object > parameters , Class <T > domainType ) {
220
- return createExecutableQuery (domainType , cypherQuery , parameters ).getResults ();
230
+ return createExecutableQuery (domainType , null , cypherQuery , parameters ).getResults ();
221
231
}
222
232
223
233
@ Override
224
234
public <T > Optional <T > findOne (String cypherQuery , Map <String , Object > parameters , Class <T > domainType ) {
225
- return createExecutableQuery (domainType , cypherQuery , parameters ).getSingleResult ();
235
+ return createExecutableQuery (domainType , null , cypherQuery , parameters ).getSingleResult ();
226
236
}
227
237
228
238
@ Override
229
239
public <T > ExecutableFind <T > find (Class <T > domainType ) {
230
240
return new FluentFindOperationSupport (this ).find (domainType );
231
241
}
232
242
233
- <T , R > List <R > doFind (String cypherQuery , Map <String , Object > parameters , Class <T > domainType , Class <R > resultType , TemplateSupport .FetchType fetchType ) {
243
+ @ SuppressWarnings ("unchecked" )
244
+ <T , R > List <R > doFind (@ Nullable String cypherQuery , @ Nullable Map <String , Object > parameters , Class <T > domainType , Class <R > resultType , TemplateSupport .FetchType fetchType ) {
234
245
235
246
List <T > intermediaResults = Collections .emptyList ();
236
247
if (cypherQuery == null && fetchType == TemplateSupport .FetchType .ALL ) {
237
- intermediaResults = findAll (domainType );
248
+ intermediaResults = doFindAll (domainType , resultType );
238
249
} else {
239
- ExecutableQuery <T > executableQuery = createExecutableQuery (domainType , cypherQuery ,
250
+ ExecutableQuery <T > executableQuery = createExecutableQuery (domainType , resultType , cypherQuery ,
240
251
parameters == null ? Collections .emptyMap () : parameters );
241
252
switch (fetchType ) {
242
253
case ALL :
@@ -253,16 +264,25 @@ <T, R> List<R> doFind(String cypherQuery, Map<String, Object> parameters, Class<
253
264
return (List <R >) intermediaResults ;
254
265
}
255
266
267
+ if (resultType .isInterface ()) {
268
+ return intermediaResults .stream ()
269
+ .map (instance -> projectionFactory .createProjection (resultType , instance ))
270
+ .collect (Collectors .toList ());
271
+ }
272
+
273
+ DtoInstantiatingConverter converter = new DtoInstantiatingConverter (resultType , neo4jMappingContext );
256
274
return intermediaResults .stream ()
257
- .map (instance -> projectionFactory .createProjection (resultType , instance ))
275
+ .map (EntityInstanceWithSource .class ::cast )
276
+ .map (converter ::convert )
277
+ .map (v -> (R ) v )
258
278
.collect (Collectors .toList ());
259
279
}
260
280
261
281
@ Override
262
282
public <T > Optional <T > findById (Object id , Class <T > domainType ) {
263
283
Neo4jPersistentEntity <?> entityMetaData = neo4jMappingContext .getPersistentEntity (domainType );
264
284
265
- return createExecutableQuery (domainType ,
285
+ return createExecutableQuery (domainType , null ,
266
286
QueryFragmentsAndParameters .forFindById (entityMetaData ,
267
287
convertIdValues (entityMetaData .getRequiredIdProperty (), id )))
268
288
.getSingleResult ();
@@ -272,7 +292,7 @@ public <T> Optional<T> findById(Object id, Class<T> domainType) {
272
292
public <T > List <T > findAllById (Iterable <?> ids , Class <T > domainType ) {
273
293
Neo4jPersistentEntity <?> entityMetaData = neo4jMappingContext .getPersistentEntity (domainType );
274
294
275
- return createExecutableQuery (domainType ,
295
+ return createExecutableQuery (domainType , null ,
276
296
QueryFragmentsAndParameters .forFindByAllId (
277
297
entityMetaData , convertIdValues (entityMetaData .getRequiredIdProperty (), ids )))
278
298
.getResults ();
@@ -520,7 +540,7 @@ public <T> void deleteByIdWithVersion(Object id, Class<T> domainType, Neo4jPersi
520
540
parameters .put (nameOfParameter , convertIdValues (entityMetaData .getRequiredIdProperty (), id ));
521
541
parameters .put (Constants .NAME_OF_VERSION_PARAM , versionValue );
522
542
523
- createExecutableQuery (domainType , statement , parameters ).getSingleResult ().orElseThrow (
543
+ createExecutableQuery (domainType , null , statement , parameters ).getSingleResult ().orElseThrow (
524
544
() -> new OptimisticLockingFailureException (OPTIMISTIC_LOCKING_ERROR_MESSAGE )
525
545
);
526
546
@@ -558,23 +578,28 @@ public void deleteAll(Class<?> domainType) {
558
578
summary .counters ().relationshipsDeleted ()));
559
579
}
560
580
561
- private <T > ExecutableQuery <T > createExecutableQuery (Class <T > domainType , String cypherStatement ) {
562
- return createExecutableQuery (domainType , cypherStatement , Collections .emptyMap ());
581
+ private <T > ExecutableQuery <T > createExecutableQuery (Class <T > domainType , Statement statement ) {
582
+ return createExecutableQuery (domainType , null , statement , Collections .emptyMap ());
583
+ }
584
+
585
+ private <T > ExecutableQuery <T > createExecutableQuery (Class <T > domainType , String cyperQuery ) {
586
+ return createExecutableQuery (domainType , null , cyperQuery , Collections .emptyMap ());
563
587
}
564
588
565
- private <T > ExecutableQuery <T > createExecutableQuery (Class <T > domainType , Statement statement , Map <String , Object > parameters ) {
589
+ private <T > ExecutableQuery <T > createExecutableQuery (Class <T > domainType , @ Nullable Class <?> resultType , Statement statement , Map <String , Object > parameters ) {
566
590
567
- return createExecutableQuery (domainType , renderer .render (statement ), TemplateSupport .mergeParameters (statement , parameters ));
591
+ return createExecutableQuery (domainType , resultType , renderer .render (statement ), TemplateSupport .mergeParameters (statement , parameters ));
568
592
}
569
593
570
- private <T > ExecutableQuery <T > createExecutableQuery (Class <T > domainType , String cypherStatement ,
594
+ private <T > ExecutableQuery <T > createExecutableQuery (Class <T > domainType , @ Nullable Class <?> resultType , @ Nullable String cypherStatement ,
571
595
Map <String , Object > parameters ) {
572
596
573
- Assert .notNull (neo4jMappingContext .getPersistentEntity (domainType ), "Cannot get or create persistent entity." );
597
+ BiFunction <TypeSystem , MapAccessor , ?> mappingFunction = TemplateSupport
598
+ .getAndDecorateMappingFunction (neo4jMappingContext , domainType , resultType );
574
599
PreparedQuery <T > preparedQuery = PreparedQuery .queryFor (domainType )
575
600
.withCypherQuery (cypherStatement )
576
601
.withParameters (parameters )
577
- .usingMappingFunction (neo4jMappingContext . getRequiredMappingFunctionFor ( domainType ) )
602
+ .usingMappingFunction (mappingFunction )
578
603
.build ();
579
604
580
605
return toExecutableQuery (preparedQuery );
@@ -796,15 +821,18 @@ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
796
821
public <T > ExecutableQuery <T > toExecutableQuery (Class <T > domainType ,
797
822
QueryFragmentsAndParameters queryFragmentsAndParameters ) {
798
823
799
- return createExecutableQuery (domainType , queryFragmentsAndParameters );
824
+ return createExecutableQuery (domainType , null , queryFragmentsAndParameters );
800
825
}
801
826
802
- private <T > ExecutableQuery <T > createExecutableQuery (Class <T > domainType ,
803
- QueryFragmentsAndParameters queryFragmentsAndParameters ) {
804
827
828
+ private <T > ExecutableQuery <T > createExecutableQuery (Class <T > domainType , Class <?> resultType ,
829
+ QueryFragmentsAndParameters queryFragmentsAndParameters ) {
830
+
831
+ BiFunction <TypeSystem , MapAccessor , ?> mappingFunction = TemplateSupport
832
+ .getAndDecorateMappingFunction (neo4jMappingContext , domainType , resultType );
805
833
PreparedQuery <T > preparedQuery = PreparedQuery .queryFor (domainType )
806
834
.withQueryFragmentsAndParameters (queryFragmentsAndParameters )
807
- .usingMappingFunction (neo4jMappingContext . getRequiredMappingFunctionFor ( domainType ) )
835
+ .usingMappingFunction (mappingFunction )
808
836
.build ();
809
837
return toExecutableQuery (preparedQuery );
810
838
}
0 commit comments