|
| 1 | +[[sdn-mixins]] |
| 2 | +== Spring Data Neo4j Extensions |
| 3 | + |
| 4 | +=== Available extensions for Spring Data Neo4j repositories |
| 5 | + |
| 6 | +Spring Data Neo4j offers a couple of extensions or "mixins" that can be added to repositories. What is a mixin? According to |
| 7 | +https://en.wikipedia.org/wiki/Mixin[Wikipedia] mixins are a language concept that allows a programmer to inject some code |
| 8 | +into a class. Mixin programming is a style of software development, in which units of functionality are created in a class |
| 9 | +and then mixed in with other classes. |
| 10 | + |
| 11 | +Java does not support that concept on the language level, but we do emulate it via a couple of interfaces and a runtime |
| 12 | +that adds appropriate implementations and interceptors for. |
| 13 | + |
| 14 | +Mixins added by default are `QueryByExampleExecutor` and `ReactiveQueryByExampleExecutor` respectively. Those interfaces are |
| 15 | +explained in detail in <<query-by-example>>. |
| 16 | + |
| 17 | +Additional mixins provided are: |
| 18 | + |
| 19 | +* `QuerydslPredicateExecutor` |
| 20 | +* `CypherdslConditionExecutor` |
| 21 | +* `CypherdslStatementExecutor` |
| 22 | +* `ReactiveCypherdslStatementExecutor` |
| 23 | + |
| 24 | +[[sdn-mixins.dynamic-conditions]] |
| 25 | +==== Add dynamic conditions to generated queries |
| 26 | + |
| 27 | +Both the `QuerydslPredicateExecutor` and `CypherdslConditionExecutor` provide the same concept: SDN generates a query, you |
| 28 | +provide "predicates" (Query DSL) or "conditions" (Cypher DSL) that will be added. We recommend the Cypher DSL, as this is |
| 29 | +what SDN 6 uses natively. You might even want to consider using the |
| 30 | +http://neo4j-contrib.github.io/cypher-dsl/2021.1.1/#thespringdataneo4j6annotationprocessor[annotation processor] that generates |
| 31 | +a static meta model for you. |
| 32 | + |
| 33 | +How does that work? Declare your repository as described above and add *one* of the following interfaces: |
| 34 | + |
| 35 | +[source,java,indent=0,tabsize=4] |
| 36 | +---- |
| 37 | +include::../../../../src/test/java/org/springframework/data/neo4j/integration/imperative/QuerydslNeo4jPredicateExecutorIT.java[tags=sdn-mixins.dynamic-conditions.add-mixin] |
| 38 | +---- |
| 39 | +<.> Standard repository declaration |
| 40 | +<.> The Query DSL mixin |
| 41 | + |
| 42 | +*OR* |
| 43 | + |
| 44 | +[source,java,indent=0,tabsize=4] |
| 45 | +---- |
| 46 | +include::../../../../src/test/java/org/springframework/data/neo4j/integration/imperative/CypherdslConditionExecutorIT.java[tags=sdn-mixins.dynamic-conditions.add-mixin] |
| 47 | +---- |
| 48 | +<.> Standard repository declaration |
| 49 | +<.> The Cypher DSL mixin |
| 50 | + |
| 51 | +Exemplary usage is shown with the Cypher DSL condition executor: |
| 52 | + |
| 53 | +[source,java,indent=0,tabsize=4] |
| 54 | +---- |
| 55 | +include::../../../../src/test/java/org/springframework/data/neo4j/integration/imperative/CypherdslConditionExecutorIT.java[tags=sdn-mixins.dynamic-conditions.usage] |
| 56 | +---- |
| 57 | +<.> Define a named `Node` object, targeting the root of the query |
| 58 | +<.> Derive some properties from it |
| 59 | +<.> Create an `or` condition. An anonymous parameter is used for the first name, a named parameter for |
| 60 | +the last name. This is how you define parameters in those fragments and one of the advantages over the Query-DSL |
| 61 | +mixin which can't do that. |
| 62 | +Literals can be expressed with `Cypher.literalOf`. |
| 63 | +<.> Define a `SortItem` from one of the properties |
| 64 | + |
| 65 | +The code looks pretty similar for the Query-DSL mixin. Reasons for the Query-DSL mixin can be familiarity of the API and |
| 66 | +that it works with other stores, too. Reasons against it are the fact that you need an additional library on the class path, |
| 67 | +it's missing support for traversing relationships and the above mentioned fact that it doesn't support parameters in its |
| 68 | +predicates (it technically does, but there are no API methods to actually pass them to the query being executed). |
| 69 | + |
| 70 | +[[sdn-mixins.using-cypher-dsl-statements]] |
| 71 | +==== Using (dynamic) Cypher-DSL statements for entities and projections |
| 72 | + |
| 73 | +Adding the corresponding mixin is not different than using the <<sdn-mixins.dynamic-conditions, condition excecutor>>: |
| 74 | + |
| 75 | +[source,java,indent=0,tabsize=4] |
| 76 | +---- |
| 77 | +include::../../../../src/test/java/org/springframework/data/neo4j/integration/imperative/CypherdslStatementExecutorIT.java[tags=sdn-mixins.using-cypher-dsl-statements.add-mixin] |
| 78 | +---- |
| 79 | + |
| 80 | +Please use the `ReactiveCypherdslStatementExecutor` when extending the `ReactiveNeo4jRepository`. |
| 81 | + |
| 82 | +The `CypherdslStatementExecutor` comes with several overloads for `findOne` and `findAll`. They all take a Cypher-DSL |
| 83 | +statement respectively an ongoing definition of that as a first parameter and in case of the projecting methods, a type. |
| 84 | + |
| 85 | +If a query requires parameters, they must be defined via the Cypher-DSL itself and also populated by it, as the following listing shows: |
| 86 | + |
| 87 | +[source,java,indent=0,tabsize=4] |
| 88 | +---- |
| 89 | +include::../../../../src/test/java/org/springframework/data/neo4j/integration/imperative/CypherdslStatementExecutorIT.java[tags=sdn-mixins.using-cypher-dsl-statements.using] |
| 90 | +---- |
| 91 | +<.> The dynamic query is build in a type safe way in a helper method |
| 92 | +<.> We already saw this in <<sdn-mixins.dynamic-conditions,here>>, where we also defined some variables holding the model |
| 93 | +<.> We define an anonymous parameter, filled by the actual value of `name`, which was passed to the method |
| 94 | +<.> The statement returned from the helper method is used to find an entity |
| 95 | +<.> Or a projection. |
| 96 | + |
| 97 | +The `findAll` methods works similar. |
| 98 | +The imperative Cypher-DSL statement executor also provides an overload returning paged results. |
0 commit comments