Skip to content

Commit

Permalink
Make sure it only has Cypher 25 support
Browse files Browse the repository at this point in the history
  • Loading branch information
gem-neo4j committed Jan 21, 2025
1 parent 1c3592d commit bb9f69d
Show file tree
Hide file tree
Showing 5 changed files with 1,251 additions and 977 deletions.
16 changes: 16 additions & 0 deletions core/src/main/java/apoc/cypher/Timeboxed.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
import org.neo4j.graphdb.Result;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.TransactionTerminatedException;
import org.neo4j.kernel.api.QueryLanguage;
import org.neo4j.kernel.api.procedure.QueryLanguageScope;
import org.neo4j.logging.Log;
import org.neo4j.procedure.Context;
import org.neo4j.procedure.Description;
Expand Down Expand Up @@ -65,6 +67,20 @@ public class Timeboxed {

@NotThreadSafe
@Procedure("apoc.cypher.runTimeboxed")
@QueryLanguageScope(scope = {QueryLanguage.CYPHER_5})
@Description("Terminates a Cypher statement if it has not finished before the set timeout (ms).")
public Stream<CypherStatementMapResult> runTimeboxedCypher5(
@Name(value = "statement", description = "The Cypher statement to run.") String cypher,
@Name(value = "params", description = "The parameters for the given Cypher statement.")
Map<String, Object> params,
@Name(value = "timeout", description = "The maximum time, in milliseconds, the statement can run for.")
long timeout) {
return runTimeboxed(cypher, params, timeout, new HashMap<>());
}

@NotThreadSafe
@Procedure("apoc.cypher.runTimeboxed")
@QueryLanguageScope(scope = {QueryLanguage.CYPHER_25})
@Description("Terminates a Cypher statement if it has not finished before the set timeout (ms).")
public Stream<CypherStatementMapResult> runTimeboxed(
@Name(value = "statement", description = "The Cypher statement to run.") String cypher,
Expand Down
18 changes: 12 additions & 6 deletions core/src/test/java/apoc/cypher/CypherTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.neo4j.configuration.GraphDatabaseInternalSettings;
import org.neo4j.configuration.GraphDatabaseSettings;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.QueryExecutionException;
Expand All @@ -80,6 +81,7 @@ public class CypherTest {
@ClassRule
public static DbmsRule db = new ImpermanentDbmsRule()
.withSetting(GraphDatabaseSettings.allow_file_urls, true)
.withSetting(GraphDatabaseInternalSettings.enable_experimental_cypher_versions, true)
.withSetting(
GraphDatabaseSettings.load_csv_file_url_root,
new File("src/test/resources").toPath().toAbsolutePath());
Expand Down Expand Up @@ -220,7 +222,7 @@ public void testWithTimeout() {

@Test
public void testRunTimeboxedWithInvalidQuerySyntax() {
final String query = "CALL apoc.cypher.runTimeboxed('RETUN 0', null, 20000, {failOnError: true})";
final String query = "CYPHER 25 CALL apoc.cypher.runTimeboxed('RETUN 0', null, 20000, {failOnError: true})";
QueryExecutionException e = assertThrows(QueryExecutionException.class, () -> testCall(db, query, (r) -> {}));
Throwable except = ExceptionUtils.getRootCause(e);
TestCase.assertTrue(except instanceof RuntimeException);
Expand All @@ -229,7 +231,7 @@ public void testRunTimeboxedWithInvalidQuerySyntax() {

@Test
public void testRunTimeboxedWithInvalidQueries() {
final String query = "CALL apoc.cypher.runTimeboxed('RETURN 1/0', null, 20000, {failOnError: true})";
final String query = "CYPHER 25 CALL apoc.cypher.runTimeboxed('RETURN 1/0', null, 20000, {failOnError: true})";
QueryExecutionException e = assertThrows(QueryExecutionException.class, () -> testCall(db, query, (r) -> {}));
Throwable except = ExceptionUtils.getRootCause(e);
TestCase.assertTrue(except instanceof RuntimeException);
Expand All @@ -240,7 +242,8 @@ public void testRunTimeboxedWithInvalidQueries() {
public void testRunTimeboxedWithSuccessStatus() {
// this query throws an error because 1/0
final String innerQuery = "RETURN 1 AS a";
final String query = "CALL apoc.cypher.runTimeboxed($innerQuery, null, $timeout, {appendStatusRow: true})";
final String query =
"CYPHER 25 CALL apoc.cypher.runTimeboxed($innerQuery, null, $timeout, {appendStatusRow: true})";

// check that the query returns nothing and terminate before `timeout`
long timeout = 50000L;
Expand All @@ -261,7 +264,8 @@ public void testRunTimeboxedWithSuccessStatus() {
public void testRunTimeboxedWithErrorReported() {
// this query throws an error because 1/0
final String innerQuery = "RETURN 1/0 AS a";
final String query = "CALL apoc.cypher.runTimeboxed($innerQuery, null, $timeout, {appendStatusRow: true})";
final String query =
"CYPHER 25 CALL apoc.cypher.runTimeboxed($innerQuery, null, $timeout, {appendStatusRow: true})";

// check that the query returns nothing and terminate before `timeout`
long timeout = 50000L;
Expand All @@ -278,7 +282,8 @@ public void testRunTimeboxedWithErrorReported() {
public void testRunTimeboxedWithErrorReportedAfterSomeSuccesses() {
// this query throws an error because 1/0
final String innerQuery = "UNWIND [1, 1, 0] AS i RETURN 1/i AS a";
final String query = "CALL apoc.cypher.runTimeboxed($innerQuery, null, $timeout, {appendStatusRow: true})";
final String query =
"CYPHER 25 CALL apoc.cypher.runTimeboxed($innerQuery, null, $timeout, {appendStatusRow: true})";

// check that the query returns nothing and terminate before `timeout`
long timeout = 50000L;
Expand All @@ -304,7 +309,8 @@ public void testRunTimeboxedWithErrorReportedAfterSomeSuccesses() {
@Test
public void testRunTimeboxedWithTerminationReported() {
final String innerQuery = "CALL apoc.util.sleep(10999) RETURN 0";
final String query = "CALL apoc.cypher.runTimeboxed($innerQuery, null, $timeout, {appendStatusRow: true})";
final String query =
"CYPHER 25 CALL apoc.cypher.runTimeboxed($innerQuery, null, $timeout, {appendStatusRow: true})";

// check that the query returns the status row that it was terminated
long timeout = 500L;
Expand Down
35 changes: 0 additions & 35 deletions core/src/test/resources/procedures/common/procedures.json
Original file line number Diff line number Diff line change
Expand Up @@ -1770,41 +1770,6 @@
"isDeprecated" : false,
"type" : "MAP"
} ]
}, {
"isDeprecated" : false,
"signature" : "apoc.cypher.runTimeboxed(statement :: STRING, params :: MAP, timeout :: INTEGER, config = {} :: MAP) :: (value :: MAP)",
"name" : "apoc.cypher.runTimeboxed",
"description" : "Terminates a Cypher statement if it has not finished before the set timeout (ms).",
"returnDescription" : [ {
"name" : "value",
"description" : "The result returned from the Cypher statement.",
"isDeprecated" : false,
"type" : "MAP"
} ],
"deprecatedBy" : null,
"argumentDescription" : [ {
"name" : "statement",
"description" : "The Cypher statement to run.",
"isDeprecated" : false,
"type" : "STRING"
}, {
"name" : "params",
"description" : "The parameters for the given Cypher statement.",
"isDeprecated" : false,
"type" : "MAP"
}, {
"name" : "timeout",
"description" : "The maximum time, in milliseconds, the statement can run for.",
"isDeprecated" : false,
"type" : "INTEGER"
},
{
"name" : "config",
"description" : "{ failOnError = false :: BOOLEAN, appendStatusRow = false :: BOOLEAN }",
"isDeprecated" : false,
"default" : "DefaultParameterValue{value={}, type=MAP}",
"type" : "MAP"
}]
}, {
"isDeprecated" : false,
"signature" : "apoc.cypher.runWrite(statement :: STRING, params :: MAP) :: (value :: MAP)",
Expand Down
42 changes: 42 additions & 0 deletions core/src/test/resources/procedures/cypher25/procedures.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,46 @@
[
{
"isDeprecated": false,
"signature": "apoc.cypher.runTimeboxed(statement :: STRING, params :: MAP, timeout :: INTEGER, config = {} :: MAP) :: (value :: MAP)",
"name": "apoc.cypher.runTimeboxed",
"description": "Terminates a Cypher statement if it has not finished before the set timeout (ms).",
"returnDescription": [
{
"name": "value",
"description": "The result returned from the Cypher statement.",
"isDeprecated": false,
"type": "MAP"
}
],
"deprecatedBy": null,
"argumentDescription": [
{
"name": "statement",
"description": "The Cypher statement to run.",
"isDeprecated": false,
"type": "STRING"
},
{
"name": "params",
"description": "The parameters for the given Cypher statement.",
"isDeprecated": false,
"type": "MAP"
},
{
"name": "timeout",
"description": "The maximum time, in milliseconds, the statement can run for.",
"isDeprecated": false,
"type": "INTEGER"
},
{
"name": "config",
"description": "{ failOnError = false :: BOOLEAN, appendStatusRow = false :: BOOLEAN }",
"isDeprecated": false,
"default": "DefaultParameterValue{value={}, type=MAP}",
"type": "MAP"
}
]
},
{
"isDeprecated": true,
"signature": "apoc.refactor.deleteAndReconnect(path :: PATH, nodes :: LIST<NODE>, config = {} :: MAP) :: (nodes :: LIST<NODE>, relationships :: LIST<RELATIONSHIP>)",
Expand Down
Loading

0 comments on commit bb9f69d

Please sign in to comment.