Skip to content

Commit 034c6e8

Browse files
authored
GH-2575 - Provide ReactiveCypherdslConditionExecutor. (#2577)
Closes #2575 (Original PR was #2577).
1 parent cc96944 commit 034c6e8

File tree

7 files changed

+378
-11
lines changed

7 files changed

+378
-11
lines changed

src/main/asciidoc/object-mapping/sdn-extensions.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ Additional mixins provided are:
1919
* `QuerydslPredicateExecutor`
2020
* `CypherdslConditionExecutor`
2121
* `CypherdslStatementExecutor`
22+
* `ReactiveQuerydslPredicateExecutor`
23+
* `ReactiveCypherdslConditionExecutor`
2224
* `ReactiveCypherdslStatementExecutor`
2325

2426
[[sdn-mixins.dynamic-conditions]]

src/main/java/org/springframework/data/neo4j/repository/query/CypherdslConditionExecutorImpl.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,6 @@ public long count(Condition condition) {
131131

132132
@Override
133133
public boolean exists(Condition condition) {
134-
Statement statement = CypherGenerator.INSTANCE.prepareMatchOf(this.metaData, condition)
135-
.returning(Functions.count(asterisk())).build();
136-
return this.neo4jOperations.count(statement, statement.getParameters()) > 0;
134+
return count(condition) > 0;
137135
}
138136
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
* Copyright 2011-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.neo4j.repository.query;
17+
18+
import static org.neo4j.cypherdsl.core.Cypher.asterisk;
19+
20+
import java.util.Arrays;
21+
22+
import org.apiguardian.api.API;
23+
import org.neo4j.cypherdsl.core.Condition;
24+
import org.neo4j.cypherdsl.core.Conditions;
25+
import org.neo4j.cypherdsl.core.Functions;
26+
import org.neo4j.cypherdsl.core.SortItem;
27+
import org.neo4j.cypherdsl.core.Statement;
28+
import org.springframework.data.domain.Sort;
29+
import org.springframework.data.neo4j.core.ReactiveNeo4jOperations;
30+
import org.springframework.data.neo4j.core.mapping.CypherGenerator;
31+
import org.springframework.data.neo4j.core.mapping.Neo4jPersistentEntity;
32+
import org.springframework.data.neo4j.repository.support.ReactiveCypherdslConditionExecutor;
33+
import org.springframework.data.neo4j.repository.support.Neo4jEntityInformation;
34+
35+
import reactor.core.publisher.Flux;
36+
import reactor.core.publisher.Mono;
37+
38+
/**
39+
* @author Niklas Krieger
40+
* @author Michael J. Simons
41+
* @param <T> The returned domain type.
42+
* @since 6.3.3
43+
*/
44+
@API(status = API.Status.INTERNAL, since = "6.3.3")
45+
public final class ReactiveCypherdslConditionExecutorImpl<T> implements ReactiveCypherdslConditionExecutor<T> {
46+
47+
private final Neo4jEntityInformation<T, Object> entityInformation;
48+
49+
private final ReactiveNeo4jOperations neo4jOperations;
50+
51+
private final Neo4jPersistentEntity<T> metaData;
52+
53+
public ReactiveCypherdslConditionExecutorImpl(Neo4jEntityInformation<T, Object> entityInformation,
54+
ReactiveNeo4jOperations neo4jOperations) {
55+
56+
this.entityInformation = entityInformation;
57+
this.neo4jOperations = neo4jOperations;
58+
this.metaData = this.entityInformation.getEntityMetaData();
59+
}
60+
61+
@Override
62+
public Mono<T> findOne(Condition condition) {
63+
64+
return this.neo4jOperations.toExecutableQuery(
65+
this.metaData.getType(),
66+
QueryFragmentsAndParameters.forCondition(this.metaData, condition, null, null)
67+
).flatMap(ReactiveNeo4jOperations.ExecutableQuery::getSingleResult);
68+
}
69+
70+
@Override
71+
public Flux<T> findAll(Condition condition) {
72+
73+
return this.neo4jOperations.toExecutableQuery(
74+
this.metaData.getType(),
75+
QueryFragmentsAndParameters.forCondition(this.metaData, condition, null, null)
76+
).flatMapMany(ReactiveNeo4jOperations.ExecutableQuery::getResults);
77+
}
78+
79+
@Override
80+
public Flux<T> findAll(Condition condition, Sort sort) {
81+
82+
return this.neo4jOperations.toExecutableQuery(
83+
metaData.getType(),
84+
QueryFragmentsAndParameters.forCondition(
85+
this.metaData, condition, null, CypherAdapterUtils.toSortItems(this.metaData, sort)
86+
)
87+
).flatMapMany(ReactiveNeo4jOperations.ExecutableQuery::getResults);
88+
}
89+
90+
@Override
91+
public Flux<T> findAll(Condition condition, SortItem... sortItems) {
92+
93+
return this.neo4jOperations.toExecutableQuery(
94+
this.metaData.getType(),
95+
QueryFragmentsAndParameters.forCondition(
96+
this.metaData, condition, null, Arrays.asList(sortItems)
97+
)
98+
).flatMapMany(ReactiveNeo4jOperations.ExecutableQuery::getResults);
99+
}
100+
101+
@Override
102+
public Flux<T> findAll(SortItem... sortItems) {
103+
104+
return this.neo4jOperations.toExecutableQuery(
105+
this.metaData.getType(),
106+
QueryFragmentsAndParameters.forCondition(this.metaData, Conditions.noCondition(), null,
107+
Arrays.asList(sortItems))
108+
).flatMapMany(ReactiveNeo4jOperations.ExecutableQuery::getResults);
109+
}
110+
111+
@Override
112+
public Mono<Long> count(Condition condition) {
113+
114+
Statement statement = CypherGenerator.INSTANCE.prepareMatchOf(this.metaData, condition)
115+
.returning(Functions.count(asterisk())).build();
116+
return this.neo4jOperations.count(statement, statement.getParameters());
117+
}
118+
119+
@Override
120+
public Mono<Boolean> exists(Condition condition) {
121+
return count(condition).map(count -> count > 0);
122+
}
123+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2011-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.neo4j.repository.support;
17+
18+
import org.apiguardian.api.API;
19+
import org.neo4j.cypherdsl.core.Condition;
20+
import org.neo4j.cypherdsl.core.SortItem;
21+
import org.springframework.data.domain.Sort;
22+
23+
import reactor.core.publisher.Flux;
24+
import reactor.core.publisher.Mono;
25+
26+
/**
27+
* An interface that can be added to any repository so that queries can be enriched by {@link Condition conditions} of the
28+
* Cypher-DSL. This interface behaves the same as the {@link org.springframework.data.querydsl.ReactiveQuerydslPredicateExecutor}.
29+
*
30+
* @author Niklas Krieger
31+
* @author Michael J. Simons
32+
* @param <T> Type of the domain
33+
* @since 6.3.3
34+
*/
35+
@API(status = API.Status.STABLE, since = "6.3.3")
36+
public interface ReactiveCypherdslConditionExecutor<T> {
37+
38+
Mono<T> findOne(Condition condition);
39+
40+
Flux<T> findAll(Condition condition);
41+
42+
Flux<T> findAll(Condition condition, Sort sort);
43+
44+
Flux<T> findAll(Condition condition, SortItem... sortItems);
45+
46+
Flux<T> findAll(SortItem... sortItems);
47+
48+
Mono<Long> count(Condition condition);
49+
50+
Mono<Boolean> exists(Condition condition);
51+
}
52+

src/main/java/org/springframework/data/neo4j/repository/support/ReactiveNeo4jRepositoryFactory.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.data.neo4j.repository.query.ReactiveNeo4jQueryLookupStrategy;
2828
import org.springframework.data.neo4j.repository.query.ReactiveQuerydslNeo4jPredicateExecutor;
2929
import org.springframework.data.neo4j.repository.query.SimpleReactiveQueryByExampleExecutor;
30+
import org.springframework.data.neo4j.repository.query.ReactiveCypherdslConditionExecutorImpl;
3031
import org.springframework.data.projection.ProjectionFactory;
3132
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
3233
import org.springframework.data.querydsl.QuerydslUtils;
@@ -45,6 +46,7 @@
4546
*
4647
* @author Gerrit Meier
4748
* @author Michael J. Simons
49+
* @author Niklas Krieger
4850
* @since 6.0
4951
*/
5052
final class ReactiveNeo4jRepositoryFactory extends ReactiveRepositoryFactorySupport {
@@ -93,6 +95,11 @@ protected RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata
9395
fragments = fragments.append(createDSLExecutorFragment(metadata, ReactiveQuerydslNeo4jPredicateExecutor.class));
9496
}
9597

98+
if (ReactiveCypherdslConditionExecutor.class.isAssignableFrom(metadata.getRepositoryInterface())) {
99+
100+
fragments = fragments.append(createDSLExecutorFragment(metadata, ReactiveCypherdslConditionExecutorImpl.class));
101+
}
102+
96103
return fragments;
97104
}
98105

src/test/java/org/springframework/data/neo4j/integration/imperative/CypherdslConditionExecutorIT.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,11 @@ class CypherdslConditionExecutorIT {
5858

5959
protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport;
6060

61-
private final Driver driver;
62-
private final BookmarkCapture bookmarkCapture;
63-
private final Node person;
6461
private final Property firstName;
6562
private final Property lastName;
6663

6764
@Autowired
68-
CypherdslConditionExecutorIT(Driver driver, BookmarkCapture bookmarkCapture) {
69-
70-
this.driver = driver;
71-
this.bookmarkCapture = bookmarkCapture;
65+
CypherdslConditionExecutorIT() {
7266

7367
//CHECKSTYLE:OFF
7468
// tag::sdn-mixins.dynamic-conditions.usage[]
@@ -78,7 +72,6 @@ class CypherdslConditionExecutorIT {
7872
// end::sdn-mixins.dynamic-conditions.usage[]
7973
//CHECKSTYLE:ON
8074

81-
this.person = person;
8275
this.firstName = firstName;
8376
this.lastName = lastName;
8477
}

0 commit comments

Comments
 (0)