Skip to content

Commit 5909008

Browse files
committed
Improve docs on call subqueries
1 parent c53836f commit 5909008

File tree

5 files changed

+143
-27
lines changed

5 files changed

+143
-27
lines changed

docs/modules/ROOT/pages/getting-started/relationships-and-advanced-filtering.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ It also adds the property `roles` from the relationship to the projection, alias
1919
Querying it on the Movies Dataset should prompt this result:
2020

2121
.Result
22-
[role="queryresult",options="header,footer",cols="4*<m"]
22+
[role="queryresult",options="header",cols="4*<m"]
2323
|===
2424
| m.title | m.tagline | m.released | actingRoles
2525
| "The Matrix" | "Welcome to the Real World" | 1999 | ["Neo"]

docs/modules/ROOT/pages/index.adoc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,30 @@
44

55
Cypher Builder is a programmatic API for building link:https://neo4j.com/docs/cypher-manual/[Cypher] queries for Neo4j in JavaScript and TypeScript.
66

7+
For example, the following code:
8+
9+
[source, javascript]
10+
----
11+
const movieNode = new Cypher.Node();
12+
const pattern = new Cypher.Pattern(movieNode, { labels: ["Movie"] });
13+
14+
const matchQuery = new Cypher.Match(pattern)
15+
.where(movieNode, {
16+
title: new Cypher.Param("The Matrix"),
17+
})
18+
.return(movieNode.property("title"));
19+
----
20+
21+
Generates the following Cypher query:
22+
23+
[source, cypher]
24+
----
25+
MATCH (this0:Movie)
26+
WHERE this0.title = $param0
27+
RETURN this0.title
28+
----
29+
30+
731

832

933
If you are using Java, check link:https://neo4j.github.io/cypher-dsl[Neo4j Cypher-DSL].

docs/modules/ROOT/pages/subqueries/call.adoc

Lines changed: 116 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,30 @@
22
:description: This page describes how to create CALL subqueries with the Cypher Builder.
33
= `Call`
44

5-
Cypher link:https://neo4j.com/docs/cypher-manual/current/subqueries/call-subquery/[`CALL` subqueries] can be created with `new Cypher.Call()` in Cypher Builder.
6-
To do this, a valid query needs to be passed to `Call`, for example:
5+
`Cypher.Call` generates Cypher link:https://neo4j.com/docs/cypher-manual/current/subqueries/call-subquery/[`CALL` subqueries]. To do this, instantiate `Cypher.Call` with a valid subquery as parameter in the constructor.
6+
7+
[source, javascript]
8+
----
9+
new Cypher.Call(subquery);
10+
----
11+
12+
In the following example, `Cypher.Call` receives a `Cypher.Match` clause.
713

814
[source, javascript]
915
----
1016
const dog = new Cypher.Node({ labels: ["Dog"] });
1117
const person = new Cypher.Node({ labels: ["Person"] });
18+
const dogName = new Cypher.NamedVariable("dogName");
1219
13-
const dogName = new Cypher.NamedVariable("dogName")
14-
15-
const subquery = new Cypher.Match(
16-
new Cypher.Pattern(person).related(new Cypher.Relationship({ type: "HAS_DOG" })).to(dog)
17-
).return([dog.property("name"), dogName]);
20+
const pattern = new Cypher.Pattern(person).related(new Cypher.Relationship({ type: "HAS_DOG" })).to(dog)
21+
const subquery = new Cypher.Match(pattern).return([dog.property("name"), dogName]);
1822
19-
const classClause = new Cypher.Call(subquery).return(dogName);
23+
const callClause = new Cypher.Call(subquery).return(dogName);
24+
const { cypher, params } = callClause.build();
2025
----
2126

27+
This example builds a `CALL` clause with the `MATCH` subquery inside.
28+
2229
[source, cypher]
2330
----
2431
CALL {
@@ -30,20 +37,29 @@ RETURN dogName
3037

3138
== Variable scope
3239

33-
The variable scope can be set with the second parameter of `new Cypher.Call()`, by passing an array of variables:
40+
`Call` clauses accept an array of xref:../variables-and-params/variables.adoc[Cypher Variables] as the second parameter of its constructor. These variables will be available within the scope of the subquery in the generated Cypher.
41+
42+
[source, javascript]
43+
----
44+
new Cypher.Call(subquery, [var1, var2]);
45+
----
46+
47+
For example, the following code will make two node variables available in the `CREATE` statement inside `CALL`.
3448

3549
[source, javascript]
3650
----
3751
const movieNode = new Cypher.Node();
3852
const actorNode = new Cypher.Node();
3953
40-
const clause = new Cypher.Call(new Cypher.Create(new Cypher.Pattern(movieNode).related().to(actorNode)), [
54+
const createSubquery = new Cypher.Create(new Cypher.Pattern(movieNode).related().to(actorNode));
55+
56+
const clause = new Cypher.Call(createSubquery, [
4157
movieNode,
4258
actorNode,
4359
]);
4460
----
4561

46-
This will add the two variables `movieNode` and `actorNode` to the `CALL` scope:
62+
The resulting Cypher adds the two variables `movieNode` (`this0`) and `actorNode` (`this1`) to the `CALL` scope:
4763

4864
[source, cypher]
4965
----
@@ -52,14 +68,16 @@ CALL (this0, this1) {
5268
}
5369
----
5470

55-
To import all variables from the outer scope, the second parameter can be set to the string `"*"`:
71+
To import all variables from the outer scope, set the second parameter to the string `"*"`:
5672

5773
[source, javascript]
5874
----
5975
const movieNode = new Cypher.Node();
6076
const actorNode = new Cypher.Node();
6177
62-
const clause = new Cypher.Call(new Cypher.Create(new Cypher.Pattern(movieNode).related().to(actorNode)), "*");
78+
const createSubquery = new Cypher.Create(new Cypher.Pattern(movieNode).related().to(actorNode));
79+
80+
const clause = new Cypher.Call(createSubquery, "*");
6381
----
6482

6583
[source, cypher]
@@ -73,7 +91,12 @@ CALL (*) {
7391

7492
[WARNING]
7593
====
76-
Import with cannot be used if scope variables are defined and will throw an error
94+
This method is deprecated in favor of <<_variable_scope>>.
95+
====
96+
97+
[WARNING]
98+
====
99+
ImportWith cannot be used if scope variables are defined and will throw an error.
77100
====
78101

79102

@@ -109,11 +132,11 @@ Note how the previous example uses `.concat` to concatenate the first `MATCH` st
109132

110133
== `.inTransactions`
111134

112-
A `CALL` subquery can be executed in separate transactions by using the `inTransaction` method:
135+
The method `.inTransactions` appends the modifier `IN TRANSACTIONS` at the end of the `CALL` subquery, this way subqueries will link:https://neo4j.com/docs/cypher-manual/current/subqueries/subqueries-in-transactions/[execute in separate transactions]:
113136

114137
[source, javascript]
115138
----
116-
new Cypher.Match(node).call(deleteSubquery).inTransactions();
139+
new Call(subquery).inTransactions();
117140
----
118141

119142
[source, cypher]
@@ -123,30 +146,98 @@ CALL {
123146
} IN TRANSACTIONS
124147
----
125148

126-
The method `inTransaction` accepts an object with the following options:
149+
The method `inTransactions` accepts multiple settings to change the behaviour of the transactions, such as, error handling, rows per transaction, or concurrency. You can pass one or more settings, as an object, to `.inTransaction`.
150+
151+
[source, javascript]
152+
----
153+
new Call(subquery).inTransactions({
154+
ofRows: 10
155+
});
156+
----
157+
158+
`inTransactions` supports the following settings:
159+
160+
[cols="1,1,1",options="header"]
161+
|===
162+
| Setting | Description | Cypher
163+
| `ofRows` | Define the number of rows per transaction | link:https://neo4j.com/docs/cypher-manual/current/subqueries/subqueries-in-transactions/#batching[`IN TRANSACTIONS OF [n\] ROWS`]
164+
| `onError` | Error handling behaviour, can be `continue`, `break` or `fail` | link:https://neo4j.com/docs/cypher-manual/current/subqueries/subqueries-in-transactions/#error-behavior[`ON ERROR [CONTINUE \| BREAK \| FAIL\]`]
165+
| `concurrentTransactions` | The maximum number of transactions to execute concurrently | link:https://neo4j.com/docs/cypher-manual/current/subqueries/subqueries-in-transactions/#concurrent-transactions[`IN [n\] CONCURRENT TRANSACTIONS`]
166+
| `retry` | If set to `true`, retries failing transactions. Can be a number to define the maximum duration, in seconds. | link:https://neo4j.com/docs/cypher-manual/current/subqueries/subqueries-in-transactions/#on-error-retry[`ON ERROR RETRY [FOR x SECONDS\]`]
167+
|===
168+
169+
170+
**Example 1: Concurrent transaction of rows**
171+
172+
[source, javascript]
173+
----
174+
const clause = new Cypher.Call(subquery).inTransactions({
175+
ofRows: 10,
176+
concurrentTransactions: 5
177+
});
178+
----
179+
180+
181+
[source, cypher]
182+
----
183+
CALL {
184+
// subquery
185+
} IN 5 CONCURRENT TRANSACTIONS OF 10 ROWS
186+
----
187+
188+
**Example 2: Retry with maximum duration**
189+
190+
[source, javascript]
191+
----
192+
const clause = new Cypher.Call(subquery).inTransactions({
193+
retry: 10
194+
});
195+
----
196+
197+
198+
[source, cypher]
199+
----
200+
CALL {
201+
// subquery
202+
} TRANSACTIONS ON ERROR RETRY FOR 10 SECONDS
203+
----
204+
205+
**Example 3: Retry error fallback**
206+
207+
[source, javascript]
208+
----
209+
const clause = new Cypher.Call(subquery).inTransactions({
210+
retry: true,
211+
onError: "continue"
212+
});
213+
----
214+
215+
216+
[source, cypher]
217+
----
218+
CALL {
219+
// subquery
220+
} TRANSACTIONS ON ERROR RETRY THEN CONTINUE
221+
----
127222

128-
* `ofRows`: A number to define the batch of rows. Translates to `IN TRANSACTIONS OF 10 ROWS`.
129-
* `onError`: A behavior for error handling. This can be `continue`, `break` or `fail`. Translates to `ON ERROR CONTINUE`.
130-
* `concurrentTransactions`: A number to execute concurrent transactions. Translates to `IN x CONCURRENT TRANSACTIONS`.
131-
* `retry`: Either a boolean or a number. Translates to `ON ERROR RETRY [FOR x SECONDS]`. If `onError` is also defined, it will add `THEN [error]`.
132223

133224
== Optional Call
134225

135-
A `CALL` subquery can be converted to an `OPTIONAL CALL` by using the `.optional` method:
226+
The method `.optional()` transforms a `CALL` subquery into link:https://neo4j.com/docs/cypher-manual/current/subqueries/call-subquery/#optional-call[`OPTIONAL CALL`] subquery.
136227

137228
[source, javascript]
138229
----
139-
new Cypher.Call(deleteSubquery).optional();
230+
new Cypher.Call(subquery).optional();
140231
----
141232

142-
Alternatively, the clause `OptionalCall` can be used to create an `OPTIONAL CALL` directly:
233+
Alternatively, the clause `OptionalCall` creates an `OPTIONAL CALL` directly:
143234

144235
[source, javascript]
145236
----
146237
new Cypher.OptionalCall(deleteSubquery);
147238
----
148239

149-
Both will generate the Cypher:
240+
Both generate the Cypher:
150241

151242
[source, cypher]
152243
----

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
"jest-extended": "^6.0.0",
5959
"prettier": "^3.4.1",
6060
"ts-jest": "^29.2.5",
61-
"typedoc": "^0.28.7",
61+
"typedoc": "^0.28.8",
6262
"typescript": "^5.6.3"
6363
}
6464
}

src/clauses/Call.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ export class Call extends Clause {
201201
/**
202202
* @see {@link https://neo4j.com/docs/cypher-manual/current/subqueries/call-subquery/#optional-call | Cypher Documentation}
203203
* @group Subqueries
204+
* @since Neo4j 5.24
204205
*/
205206
export class OptionalCall extends Call {
206207
constructor(subquery: Clause, variableScope?: Variable[] | "*") {

0 commit comments

Comments
 (0)