Skip to content

Commit 8ee7040

Browse files
committed
Upgrade to Neo4j 3.1.1
* updated dependencies * added function scripts.run(name [,args]) * made arguments optional * added prefix for graph properties
1 parent 67888fd commit 8ee7040

File tree

4 files changed

+67
-91
lines changed

4 files changed

+67
-91
lines changed

README.adoc

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ The operations are:
1818
CALL scripts.function({name}, {code})
1919
2020
{"name" : "users",
21-
"code" : "function users() collection(db.findNodes(label('User')))"}
21+
"code" : "function users() { return collection(db.findNodes(label('User'))) }"}
2222
----
2323

24-
.run function
24+
.run function as procedure
2525
[source,cypher]
2626
----
2727
CALL scripts.run({name}, {params})
@@ -31,6 +31,16 @@ CALL scripts.run('users', null)
3131
-> returns one user per row
3232
----
3333

34+
.run function as function
35+
[source,cypher]
36+
----
37+
RETURN scripts.run({name}, {params})
38+
39+
RETURN scripts.run('users', null)
40+
41+
-> returns a list of users
42+
----
43+
3444
.list functions
3545
[source,cypher]
3646
----

pom.xml

Lines changed: 8 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,25 @@
33
http://maven.apache.org/xsd/maven-4.0.0.xsd">
44
<modelVersion>4.0.0</modelVersion>
55

6-
<groupId>org.neo4j.example</groupId>
7-
<artifactId>js-procs</artifactId>
6+
<groupId>org.neo4j.procedures</groupId>
7+
<artifactId>neo4j-script-procedures</artifactId>
88
<version>1.0.0-SNAPSHOT</version>
99

1010
<packaging>jar</packaging>
11-
<name>Neo4j Javascript Procedures</name>
11+
<name>Neo4j Script Procedures</name>
1212

1313
<properties>
1414
<encoding>UTF-8</encoding>
15-
<!-- Neo4j procedures require Java 8 -->
1615
<java.version>1.8</java.version>
1716
<project.build.sourceEncoding>${encoding}</project.build.sourceEncoding>
1817
<project.reporting.outputEncoding>${encoding}</project.reporting.outputEncoding>
1918
<maven.compiler.source>${java.version}</maven.compiler.source>
2019
<maven.compiler.target>${java.version}</maven.compiler.target>
21-
<neo4j.version>3.0.3</neo4j.version>
20+
<neo4j.version>3.1.1</neo4j.version>
2221
</properties>
2322

2423
<dependencies>
2524
<dependency>
26-
<!-- This gives us the Procedure API our runtime code uses.
27-
We have a `provided` scope on it, because when this is
28-
deployed in a Neo4j Instance, the API will be provided
29-
by Neo4j. If you add non-Neo4j dependencies to this
30-
project, their scope should normally be `compile` -->
3125
<groupId>org.neo4j</groupId>
3226
<artifactId>neo4j</artifactId>
3327
<version>${neo4j.version}</version>
@@ -37,25 +31,22 @@
3731
<dependency>
3832
<groupId>net.biville.florent</groupId>
3933
<artifactId>neo4j-sproc-compiler</artifactId>
40-
<version>1.0-M01</version>
34+
<version>1.1</version>
4135
<optional>true</optional>
36+
<scope>provided</scope>
4237
</dependency>
4338

44-
<!-- Test Dependencies -->
4539
<dependency>
46-
<!-- This is used for a utility that lets us start Neo4j with
47-
a specific Procedure, which is nice for writing tests. -->
4840
<groupId>org.neo4j.test</groupId>
4941
<artifactId>neo4j-harness</artifactId>
5042
<version>${neo4j.version}</version>
5143
<scope>test</scope>
5244
</dependency>
5345

5446
<dependency>
55-
<!-- Used to send cypher statements to our procedure. -->
5647
<groupId>org.neo4j.driver</groupId>
5748
<artifactId>neo4j-java-driver</artifactId>
58-
<version>1.0.3</version>
49+
<version>1.2.1</version>
5950
<scope>test</scope>
6051
</dependency>
6152

@@ -70,14 +61,9 @@
7061
<build>
7162
<plugins>
7263
<plugin>
73-
<!-- This generates a jar-file with our procedure code,
74-
plus any dependencies marked as `compile` scope.
75-
This should then be deployed in the `plugins` directory
76-
of each Neo4j instance in your deployment.
77-
After a restart, the procedure is available for calling. -->
7864
<artifactId>maven-shade-plugin</artifactId>
7965
<version>2.4.3</version>
80-
<executions>
66+
<executions>
8167
<execution>
8268
<phase>package</phase>
8369
<goals>
@@ -88,20 +74,4 @@
8874
</plugin>
8975
</plugins>
9076
</build>
91-
92-
<!-- Since there is no stable release of Procedures at the time this
93-
is written, we depend on Neo4j Snapshot releases for now. If there
94-
is a stable Neo4j release when you read this, this repository has
95-
not been properly updated. Please use stable versions for production
96-
code - and do consider sending a pull-request bringing this project
97-
up to date! -->
98-
<repositories>
99-
<repository>
100-
<id>neo4j-snapshot-repository</id>
101-
<name>Maven 2 snapshot repository for Neo4j</name>
102-
<url>http://m2.neo4j.org/content/repositories/snapshots</url>
103-
<snapshots><enabled>true</enabled></snapshots>
104-
<releases><enabled>false</enabled></releases>
105-
</repository>
106-
</repositories>
10777
</project>

src/main/java/scripts/Scripts.java

Lines changed: 39 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
import org.neo4j.logging.Log;
1313
import org.neo4j.procedure.Context;
1414
import org.neo4j.procedure.Name;
15+
import org.neo4j.procedure.Mode;
1516
import org.neo4j.procedure.PerformsWrites;
1617
import org.neo4j.procedure.Procedure;
18+
import org.neo4j.procedure.UserFunction;
1719

1820
import javax.script.Invocable;
1921
import javax.script.ScriptEngine;
@@ -22,21 +24,14 @@
2224

2325
import static org.neo4j.helpers.collection.MapUtil.stringMap;
2426

25-
/**
26-
* This is an example showing how you could expose Neo4j's full text indexes as
27-
* two procedures - one for updating indexes, and one for querying by label and
28-
* the lucene query language.
29-
*/
3027
public class Scripts {
3128

29+
private static String PREFIX = "script.function.";
3230
public static final Object[] NO_OBJECTS = new Object[0];
33-
// This field declares that we need a GraphDatabaseService
34-
// as context when any procedure in this class is invoked
31+
3532
@Context
36-
public GraphDatabaseService db;
33+
public GraphDatabaseAPI db;
3734

38-
// This gives us a log instance that outputs messages to the
39-
// standard log, normally found under `data/log/console.log`
4035
@Context
4136
public Log log;
4237

@@ -47,7 +42,7 @@ public class Scripts {
4742

4843
private GraphProperties graphProperties() {
4944
if (graphProperties == NO_GRAPH_PROPERTIES)
50-
graphProperties = ((GraphDatabaseAPI) db).getDependencyResolver().resolveDependency(NodeManager.class).newGraphProperties();
45+
graphProperties = db.getDependencyResolver().resolveDependency(NodeManager.class).newGraphProperties();
5146
return graphProperties;
5247
}
5348
private ScriptEngine getEngine() {
@@ -70,57 +65,52 @@ private void addFunctions(ScriptEngine js, String...script) {
7065
}
7166
}
7267

73-
@Procedure
74-
public Stream<Result> run(@Name("name") String name, @Name("params") List params) {
75-
try {
76-
ScriptEngine js = getEngine();
77-
String code = (String) graphProperties().getProperty(name, null);
78-
if (code == null)
79-
throw new RuntimeException("Function " + name + " not defined, use CALL function('name','code') ");
80-
81-
js.put("db", db);
82-
js.put("log", log);
83-
js.eval(String.format("function %s(){ return (%s).apply(this, arguments) }", name, code));
84-
Object value = ((Invocable) js).invokeFunction(name, params == null ? NO_OBJECTS : params.toArray());
85-
if (value instanceof Object[]) {
86-
return Stream.of((Object[]) value).map(Result::new);
87-
}
88-
if (value instanceof Iterable) {
89-
return StreamSupport.stream(((Iterable<?>)value).spliterator(),false).map(Result::new);
90-
}
91-
return Stream.of(new Result(value));
92-
} catch (ScriptException | NoSuchMethodException e) {
93-
throw new RuntimeException(e);
94-
}
68+
@UserFunction("scripts.run")
69+
public Object runFunction(@Name("name") String name, @Name(value="params",defaultValue="[]") List<Object> params) throws ScriptException, NoSuchMethodException {
70+
ScriptEngine js = getEngine();
71+
String code = (String) graphProperties().getProperty(PREFIX + name, null);
72+
if (code == null)
73+
throw new RuntimeException("Function " + name + " not defined, use CALL function('name','code') ");
74+
75+
js.put("db", db);
76+
js.put("log", log);
77+
js.eval(String.format("function %s(){ return (%s).apply(this, arguments) }", name, code));
78+
return ((Invocable) js).invokeFunction(name, params == null ? NO_OBJECTS : params.toArray());
9579
}
9680

9781
@Procedure
98-
@PerformsWrites
99-
public Stream<Result> function(@Name("name") String name, @Name("code") String code) {
100-
try {
101-
ScriptEngine js = getEngine();
102-
js.eval("function(){" + code + "}");
103-
GraphProperties props = graphProperties();
104-
boolean replaced = props.hasProperty(name);
105-
props.setProperty(name, code);
106-
return Stream.of(new Result(String.format("%s Function %s", replaced ? "Updated" : "Added", name)));
107-
} catch (ScriptException e) {
108-
throw new RuntimeException(e);
109-
}
82+
public Stream<Result> run(@Name("name") String name, @Name(value="params",defaultValue="[]") List<Object> params) throws ScriptException, NoSuchMethodException {
83+
Object value = runFunction(name, params);
84+
if (value instanceof Object[]) {
85+
return Stream.of((Object[]) value).map(Result::new);
86+
}
87+
if (value instanceof Iterable) {
88+
return StreamSupport.stream(((Iterable<?>)value).spliterator(),false).map(Result::new);
89+
}
90+
return Stream.of(new Result(value));
11091
}
11192

112-
@Procedure
113-
@PerformsWrites
93+
@Procedure(mode=Mode.WRITE)
94+
public Stream<Result> function(@Name("name") String name, @Name("code") String code) throws ScriptException {
95+
ScriptEngine js = getEngine();
96+
js.eval("function(){" + code + "}");
97+
GraphProperties props = graphProperties();
98+
boolean replaced = props.hasProperty(PREFIX + name);
99+
props.setProperty(PREFIX + name, code);
100+
return Stream.of(new Result(String.format("%s Function %s", replaced ? "Updated" : "Added", name)));
101+
}
102+
103+
@Procedure(mode=Mode.WRITE)
114104
public Stream<Result> delete(@Name("name") String name) {
115105
GraphProperties props = graphProperties();
116-
props.removeProperty(name);
106+
props.removeProperty(PREFIX + name);
117107
return Stream.of(new Result(String.format("Function '%s' removed", name)));
118108
}
119109

120110

121111
@Procedure
122112
public Stream<Result> list() {
123-
return StreamSupport.stream(graphProperties.getPropertyKeys().spliterator(), false).map(Result::new);
113+
return StreamSupport.stream(graphProperties.getPropertyKeys().spliterator(), false).filter(s -> s.startsWith(PREFIX )).map(Result::new);
124114
}
125115

126116
public static class Result {

src/test/java/scripts/ScriptsTest.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,16 @@
66
import org.neo4j.driver.v1.*;
77
import org.neo4j.harness.junit.Neo4jRule;
88

9+
import static java.util.Arrays.asList;
10+
911
import static org.hamcrest.MatcherAssert.assertThat;
1012
import static org.hamcrest.core.IsEqual.equalTo;
1113
import static org.neo4j.driver.v1.Values.parameters;
1214

1315
public class ScriptsTest
1416
{
1517
@Rule
16-
public Neo4jRule neo4j = new Neo4jRule().withProcedure( Scripts.class );
18+
public Neo4jRule neo4j = new Neo4jRule().withProcedure( Scripts.class ).withFunction( Scripts.class );
1719

1820
@Test
1921
public void shouldAllowCreatingAndRunningJSProcedures() throws Throwable
@@ -29,12 +31,16 @@ public void shouldAllowCreatingAndRunningJSProcedures() throws Throwable
2931
.get(0).asLong();
3032

3133

32-
session.run("CALL scripts.function({name}, {code})", parameters("name", "users", "code", "function users() collection(db.findNodes(label('User')))"));
34+
session.run("CALL scripts.function({name}, {code})", parameters("name", "users", "code", "function users() { return collection(db.findNodes(label('User'))); }"));
3335

3436
StatementResult result = session.run("CALL scripts.run('users',null)");
3537
Value value = result.single().get("value");
3638
System.out.println(value.asObject());
3739
assertThat(value.asNode().id(), equalTo(nodeId));
40+
result = session.run("RETURN scripts.run('users') AS value");
41+
value = result.single().get("value");
42+
System.out.println(value.asObject());
43+
assertThat(value.get(0).asNode().id(), equalTo(nodeId));
3844
}
3945
}
4046
}

0 commit comments

Comments
 (0)