Skip to content

Commit

Permalink
Add callbacks for variable creation.
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-simons committed Jul 6, 2021
1 parent 2870c46 commit 955a77f
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 65 deletions.
23 changes: 22 additions & 1 deletion docs/cypher-parser/cypher-parser.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -232,4 +232,25 @@ include::../../neo4j-cypher-dsl-examples/neo4j-cypher-dsl-examples-sdn6/src/main
----
<.> The condition that only people born later than 1980 is hard coded in the service.
An arbitrary String is than parsed into a condition and attached via `AND`.
Thus only valid cypher can go in there and with filters and callbacks, preconditions of that Cypher can be asserted.
Thus, only valid cypher can go in there and with filters and callbacks, preconditions of that Cypher can be asserted.

The downside to the above solution is that the query fragment passed to the service and eventually the repository must
know the root node (which is `n` in case of SDN 6) and the caller code might look like this:

[source,java,indent=0,tabsize=4]
----
include::../../neo4j-cypher-dsl-examples/neo4j-cypher-dsl-examples-sdn6/src/test/java/org/neo4j/cypherdsl/examples/sdn6/ApplicationIT.java[tag=exchange1]
----

Notice `n.name` etc.
We could change the service method slightly and apply a callback like this:

[source,java,indent=0,tabsize=4]
----
include::../../neo4j-cypher-dsl-examples/neo4j-cypher-dsl-examples-sdn6/src/main/java/org/neo4j/cypherdsl/examples/sdn6/movies/PeopleService.java[tag=using-parser-with-spring2]
----
<.> Create a function that takes the value of a variable created in the fragment and use it to look up a property on the
SDN root node.
<.> Create an instance of parsing options. It's probably a good idea todo this once and store them away in an instance variable.
Options are thread safe.
<.> Apply them when calling the corresponding parse method
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,15 @@ Iterable<Person> findPeopleBornInThe70tiesOr(@RequestParam(name = "name") Option
return peopleService.findPeopleBornInThe70tiesOr(optionalName);
}

@GetMapping("/findPeopleBornAfterThe70ties")
@GetMapping("/v1/findPeopleBornAfterThe70ties")
Iterable<Person> findPeopleBornAfterThe70ties(@RequestParam(name = "conditions") String additionalConditions) {

return peopleService.findPeopleBornAfterThe70tiesAnd(additionalConditions);
}

@GetMapping("/v2/findPeopleBornAfterThe70ties")
Iterable<Person> findPeopleBornAfterThe70tiesV2(@RequestParam(name = "conditions") String additionalConditions) {

return peopleService.findPeopleBornAfterThe70tiesAndV2(additionalConditions);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,20 @@

// tag::using-person-repo[]
import java.util.Optional;
import java.util.function.Function;

import org.neo4j.cypherdsl.core.Conditions;
import org.neo4j.cypherdsl.core.Cypher;
import org.neo4j.cypherdsl.core.Expression;
import org.neo4j.cypherdsl.core.Functions;
// end::using-person-repo[]
import org.neo4j.cypherdsl.core.SymbolicName;
import org.neo4j.cypherdsl.parser.CypherParser;
import org.neo4j.cypherdsl.parser.ExpressionCreatedEventType;
import org.neo4j.cypherdsl.parser.Options;
import org.springframework.data.domain.Example;
// tag::using-person-repo[]
import org.springframework.data.neo4j.core.mapping.Constants;
import org.springframework.stereotype.Service;

// end::using-person-repo[]
Expand Down Expand Up @@ -63,6 +69,30 @@ Iterable<Person> findPeopleBornAfterThe70tiesAnd(String additionalConditions) {
}
// end::using-parser-with-spring[]

// tag::using-parser-with-spring2[]
Iterable<Person> findPeopleBornAfterThe70tiesAndV2(String additionalConditions) {

Function<Expression, Expression> enforceReference =
e -> Constants.NAME_OF_ROOT_NODE.property(((SymbolicName) e).getValue()); // <.>
var parserOptions = Options.newOptions()
.withCallback(
ExpressionCreatedEventType.ON_NEW_VARIABLE,
Expression.class,
enforceReference
) // <.>
.build();

return peopleRepository.findAll(
PERSON.BORN.gte(Cypher.literalOf(1980)).and(
CypherParser.parseExpression(
additionalConditions,
parserOptions // <.>
).asCondition()
)
);
}
// end::using-parser-with-spring2[]

// tag::using-person-repo[]
Iterable<Person> findPeopleBornInThe70tiesOr(Optional<String> optionalName) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,26 @@ void findPeopleBornInThe70tiesOrShouldWork2(@Autowired TestRestTemplate restTemp
@DisplayName("Using conditions pt3.")
void findPeopleBornAfterThe70tiesShouldWork(@Autowired TestRestTemplate restTemplate) {

// tag::exchange1[]
var exchange = restTemplate.exchange(
"/api/people/v1/findPeopleBornAfterThe70ties?conditions={conditions}",
HttpMethod.GET,
null, new ParameterizedTypeReference<List<Person>>() { },
"n.name contains \"Ricci\" OR n.name ends with 'Hirsch'"
);
// end::exchange1[]
assertThat(exchange.getStatusCode()).isEqualTo(HttpStatus.OK);
var people = exchange.getBody();
assertThat(people).hasSize(2);
}

@Test
@DisplayName("Using conditions pt4.")
void findPeopleBornAfterThe70tiesV2ShouldWork(@Autowired TestRestTemplate restTemplate) {

var exchange = restTemplate
.exchange("/api/people/findPeopleBornAfterThe70ties?conditions={conditions}", HttpMethod.GET, null, new ParameterizedTypeReference<List<Person>>() {
}, "n.name contains \"Ricci\" OR n.name ends with 'Hirsch'");
.exchange("/api/people/v2/findPeopleBornAfterThe70ties?conditions={conditions}", HttpMethod.GET, null, new ParameterizedTypeReference<List<Person>>() {
}, "name contains \"Ricci\" OR name ends with 'Hirsch'");
assertThat(exchange.getStatusCode()).isEqualTo(HttpStatus.OK);
var people = exchange.getBody();
assertThat(people).hasSize(2);
Expand Down
Loading

0 comments on commit 955a77f

Please sign in to comment.