neo4j-contrib / cypher-dsl Goto Github PK
View Code? Open in Web Editor NEWA Java DSL (Builder) for the Cypher Query Language
Home Page: http://neo4j.github.io/cypher-dsl
License: Apache License 2.0
A Java DSL (Builder) for the Cypher Query Language
Home Page: http://neo4j.github.io/cypher-dsl
License: Apache License 2.0
The RELATE
command has been renamed to CREATE UNIQUE
in cypher.
RELATE has been removed with #15 from cypher-dsl, but CREATE UNIQUE is not supported yet.
Support for the following temporal functions supported by Neo4j:
Reference: https://neo4j.com/docs/cypher-manual/current/functions/temporal/
Example:
Renderer.getDefaultRenderer().render(
.............
.call("apoc.create.relationship")
.withArgs(
parent.getRequiredSymbolicName(),
literalOf(type.name()),
mapOf(
"score", literalOf(0.33),
"weight", literalOf(1.7)
),
child.getRequiredSymbolicName()
)
.yield(createdRelationship)
.............
)
where
parent - named org.neo4j.cypherdsl.core.Node
child - named org.neo4j.cypherdsl.core.Node
type - Enum
mapOf - org.neo4j.cypherdsl.core.Cypher#mapOf
literalOf - org.neo4j.cypherdsl.core.Cypher#literalOf
Renderer returns:
CALL apoc.create.relationship(parent, 'ChildEdge'{score: 0.33, weight: 1.7}child) YIELD rel
But expected:
CALL apoc.create.relationship(parent, 'ChildEdge', {score: 0.33, weight: 1.7}, child) YIELD rel
It would be convenient if there was an option or automatic feature to generate a random symbolic name, so that a node could be referred to multiple times in a query without needing to explicitly name it (i.e, reusing a variable of type Node)
Node strawberry = node("Fruit", mapOf("kind", literalOf("strawberry")));
RENDERER.render(match(strawberry).set(strawberry.property("color").to(literalOf("red"))));
Right now, this will fail, because a SymbolicName needs to be added to 'strawberry' for it to be able to be referenced in the 'set' clause. Instead of setting the name that will never actually need to be referenced by the author, it could be automatically set to a random UUID or something else so that the variable of type Node can be reused throughout the query
The Querydsl version referred to (2.2.3) is almost a year old. Recent ones (2.7.3) have breaking changes that cause errors when executing. I've stumbled over Ops.EQ_PRIMITIVE
and Ops.EQ_OBJECT
being unified to Ops.EQ
only.
if we add multiple WhereClause to a Query the new additions are merged with the previous WhereClause to create a compound. This doesn't happen for WithClause which I can't determine any rationale behind. There may also be other clauses that could usefully be merged.
Suggestion for implementing is to change check in Query.add
to use instanceOf MergeClause
instead of instanceof WhereClause
and create MergeClause
with the single merge
method. Happy to provide pull request if helpful
I upgraded to 1.8 from 1.7 yesterday and noticed the following new rules made in 1.8.RC1 have not been incorporated in the latest Cypher DSL 1.8
The legal cypher query
collect(distinct("id"))
can't be written as
collect(distinct(identifier("id")))
without a cast to make it
collect((ScalarExpression)distinct(identifier("id"))))
Currently there is no way to create a cypher query like:
MATCH (person:`Person`)
WHERE distance(person.location, point($point.point)) = $point.distance
WITH person
RETURN person { .name } AS person
Execute query = CypherQuery
.match(node("n").label("Label"))
.set(node("n").eq(param("key")))
.returns(identifier("n"));
throws compilation error because set
method requires SetProperty...
while eq(...)
method returns BooleanExpression
When trying to execute a Cypher query 1.8.0_M06 web console, the following exception puts an end to the attempt:
2012-08-14 19:33:12,597 [2138463779@qtp-816829837-2] ERROR org.mortbay.log - /db/data/cypher
java.lang.NoSuchMethodError: scala.Predef$.augmentString(Ljava/lang/String;)Lscala/collection/immutable/StringOps;
at org.neo4j.cypher.CypherParser.(CypherParser.scala:27) ~[neo4j-cypher-1.8.M06.jar:1.8.M06]
at org.neo4j.cypher.CypherParser.(CypherParser.scala:25) ~[neo4j-cypher-1.8.M06.jar:1.8.M06]
at org.neo4j.cypher.ExecutionEngine.createCorrectParser(ExecutionEngine.scala:47) ~[neo4j-cypher-1.8.M06.jar:1.8.M06]
at org.neo4j.cypher.ExecutionEngine.(ExecutionEngine.scala:37) ~[neo4j-cypher-1.8.M06.jar:1.8.M06]
at org.neo4j.cypher.javacompat.ExecutionEngine.(ExecutionEngine.java:41) ~[neo4j-cypher-1.8.M06.jar:1.8.M06]
at org.neo4j.server.rest.web.CypherService.(CypherService.java:50) ~[neo4j-server-1.8.M06.jar:1.8.M06]
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.7.0_04]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57) ~[na:1.7.0_04]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.7.0_04]
at java.lang.reflect.Constructor.newInstance(Constructor.java:525) ~[na:1.7.0_04]
at com.sun.jersey.server.spi.component.ResourceComponentConstructor._construct(ResourceComponentConstructor.java:198) ~[jersey-server-1.9.jar:1.9]
at com.sun.jersey.server.spi.component.ResourceComponentConstructor.construct(ResourceComponentConstructor.java:179) ~[jersey-server-1.9.jar:1.9]
at com.sun.jersey.server.impl.resource.PerRequestFactory$PerRequest._getInstance(PerRequestFactory.java:182) ~[jersey-server-1.9.jar:1.9]
at com.sun.jersey.server.impl.resource.PerRequestFactory$AbstractPerRequest.getInstance(PerRequestFactory.java:144) ~[jersey-server-1.9.jar:1.9]
at com.sun.jersey.server.impl.application.WebApplicationContext.getResource(WebApplicationContext.java:238) ~[jersey-server-1.9.jar:1.9]
at com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:83) ~[jersey-server-1.9.jar:1.9]
at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147) ~[jersey-server-1.9.jar:1.9]
at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84) ~[jersey-server-1.9.jar:1.9]
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1469) ~[jersey-server-1.9.jar:1.9]
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1400) ~[jersey-server-1.9.jar:1.9]
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1349) ~[jersey-server-1.9.jar:1.9]
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1339) ~[jersey-server-1.9.jar:1.9]
at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416) ~[jersey-server-1.9.jar:1.9]
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537) ~[jersey-server-1.9.jar:1.9]
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:699) ~[jersey-server-1.9.jar:1.9]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820) ~[servlet-api-2.5-20081211.jar:na]
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511) ~[jetty-6.1.25.jar:6.1.25]
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166) ~[jetty-6.1.25.jar:6.1.25]
at org.neo4j.server.statistic.StatisticFilter.doFilter(StatisticFilter.java:62) ~[neo4j-server-1.8.M06.jar:1.8.M06]
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157) ~[jetty-6.1.25.jar:6.1.25]
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388) ~[jetty-6.1.25.jar:6.1.25]
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182) [jetty-6.1.25.jar:6.1.25]
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765) [jetty-6.1.25.jar:6.1.25]
at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114) [jetty-6.1.25.jar:6.1.25]
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152) [jetty-6.1.25.jar:6.1.25]
at org.mortbay.jetty.Server.handle(Server.java:326) [jetty-6.1.25.jar:6.1.25]
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542) [jetty-6.1.25.jar:6.1.25]
at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:943) [jetty-6.1.25.jar:6.1.25]
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756) [jetty-6.1.25.jar:6.1.25]
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218) [jetty-6.1.25.jar:6.1.25]
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404) [jetty-6.1.25.jar:6.1.25]
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:410) [jetty-6.1.25.jar:6.1.25]
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582) [jetty-util-6.1.25.jar:6.1.25]
Two bugs in cypher-dsl:
Neo4j does not use the slash as a regexp delimiter, which is still used by cypher-dsl.
Cypher dsl generates queries with the ! operator like WHERE n.prop!="foo"
which is now treated as an error in cypher:
Error: Cypher does not support != for inequality comparisons. It's used for nullable properties instead. You probably meant <> instead. Read more about this in the operators chapter in the manual.
Adding a space fixes this problem: WHERE n.prop! ="foo"
It's not possible to use statement builder's methods
org.neo4j.cypherdsl.core.Cypher#call + org.neo4j.cypherdsl.core.ExposesCall.ExposesWithArgs#withArgs
because "call" returns package-private interface org.neo4j.cypherdsl.core.ProcedureCall.OngoingStandaloneCallWithoutArguments
Example:
Statement call = Cypher
.call("dbms.listConfig")
.withArgs(Cypher.literalOf("browser"))
.yield("name")
.build();
P.S.
Test org.neo4j.cypherdsl.core.ProcedureCallsIT#withArgsAndYield passes because of the same package
PPS
May be possible to use something like
org.neo4j.cypherdsl.core.StatementBuilder.OngoingReadingWithoutWhere as return to continue the builder chain ?
The Query and CypherQueryTest classes should generate 2.1 statements instead of 2.0.
I would have contributed but I'm struggling getting my old fork up to date with the 2.1.4 tag.
Is it possible to publish a daily SNAPSHOT build to http://m2.neo4j.org/content/repositories/snapshots/org/neo4j/neo4j-cypher-dsl/?
Other Neo4j modules seem to have this.
Thanks!
Timmy
Hi Michael,
Current snapshot of version 2.0.2 add quite a useful feature of using labels. This is something that I want to make use of but in order to do so I have to copy Cypher-DSL to my project with a different version label so that it can be built and installed.
Please release version 2.0.2.
Thank you,
Alex
i'm not very experienced in creating gradle scripts, would you please create sample gradle script for generating Q classes?
start(... ).. ..orderBy( identifier("node").property("start") )
results as
start... order by node.start
but should be
start... order by node.`start`
version neo4j-cypher-dsl 1.7
The current codebase is incompatible with Querydsl 3.x due to some incompatible changes in Querydsl. Currently this is blocking the Spring Data Neo4j snapshots from building as Spring Data has already upgraded to 3.x.
It would be nice to be able to change the cypher version. Right now, "CYPHER 1.8" seems to be hardcoded in the Query#asString() method.
is it possible to change all jackson references from codehaus to fasterxml namespace?
This includes
README.adoc
so that the GH-Action uses the correct version when the documentation is generated and "current" http://neo4j-contrib.github.io/cypher-dsl/current points to that (PREPARE)The snapshot version of the POM should be changed to something unrealistic which doesn't indicate a next release date or something.
The corresponding targets should than be called from Team City.
getContent() return provided type and not literal so toString() method failed with cast exception
It would be nice to add CALL method to statement builder.
functionality to call APOC and GDS methods
Please provide proper Javadoc for all public APIs, esp. within the org.neo4j.cypherdsl.query package.
Similar to the support just added in Remove. Allows for renaming of labels for example:
MATCH (n:oldLabel) SET n :newLabel REMOVE n:oldLabel
I will work on this when I get some time and submit a PR. This issue is so I don't lose track of it.
The licensing of the project is not obvious for me:
As far as I can see, the project only uses Neo4j optionally or with a test
scope, so in theory, it could be distributed under the Apache license. I believe the fluent API for building queries would be very useful for a lot of openCypher applications.
Cannot construct the following query:
MATCH (change:Change)-[codeRelation:CODE]-(code) WHERE id(code)=147 OPTIONAL MATCH (change)-[changeDetailsRelation:CHANGE_DETAILS]-(changeDetail) WHERE id(code)=147 RETURN change,codeRelation,changeDetailsRelation,changeDetail
Cannot put a 2nd match-clause after the first where.
CypherQueryDSL
.match(node("change").label("Change")
.both("CODE").as("codeRelation")
.node("code"))
.where(id("code").eq(codeId))
.match(node("change").label("Change") // not allowed after where
.both("CHANGE_DETAILS").as("changeDetailsRelation")
.node("changeDetail"))
.where(id("code").eq(codeId))
.returns(identifiers("change", "codeRelation", "changeDetailsRelation", "changeDetail"));
including the latest stable version by using
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-cypher-dsl</artifactId>
<version>1.6</version>
</dependency>
it failes in missing dependencies
java.lang.NoClassDefFoundError: com/mysema/query/types/Path
the dependency
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-core</artifactId>
<version>2.2.3</version>
</dependency>
should not be optional !!
Current version of cypher-dsl don't support CONTAINS keyword
Much of the code in the src directory is licensed by Neo technologies under the GPL license on the *.java files. The only clue otherwise is the file asl-2-header.txt which says this code is licensed to Neo under the Apache 2 license. How can I be certain about the license?
The commit 04c0eee (Restructured packages) breaks compatibility with Spring Data Neo4j. SDN expects to find Execute in org.neo4j.cypherdsl.
I have an string array over relation and unable to generate predicate with querydsl.
Consider the following scenario,
NODE {id: 10} --- [LINKS_WITH {markets: ['US', 'France']}] ---> NODE {id: 21}
NODE {id: 10} --- [LINKS_WITH {markets: ['UK']}] ---> NODE {id: 22}
NODE {id: 10} --- [LINKS_WITH {markets: ['Canada']}] ---> NODE {id: 23}
NODE {id: 10} --- [LINKS_WITH {markets: ['Germany']}] ---> NODE {id: 24}
Now I have to get all nodes associated with the node having id 10 if the relation contains France
in it.
I am unable to generate its predicate. Any help would be highly appreciated.
Hi,
Is it possible to get snapshot builds of cypher-dsl made (and published via maven) whenever a new snapshot of neo4j is released? Likewise for milestone and stable releases of neo4j?
Thanks!
Chris
I found I cannot remove labels. I see that remove currently only takes reference expressions:
UpdateNext remove(ReferenceExpression... expressions);
UpdateNext remove(Iterable<ReferenceExpression> expressions);
Perhaps the easiest way would be to add two more that take LabelValue s
UpdateNext remove(LabelValue... labelValues);
UpdateNext remove(Iterable<LabelValue> labelValues);
This would works since cypher allows you to have multiple remove clauses. It is a little icky though in that LabelValue is not an interface but short of adding a new one just for this I don't see a better way. Do you have an opinion on this?
It would be nice to add endNode() and startNode() scalar functions
This project should be in the neo4j-contrib github group. The neo4j group should only contain repositories that are part of (or support) the official Neo4j distribution.
I've tried to get the following query to work, but without success:
start(nodesById("s", 1), nodesById("e", 2))
.match(path("path", node("s").both().hops(2, 6).node("e")))
.createUnique(node("s").both(identifier("NEAR")).as("r").node(identifier("e")))
.set(property(identifier("r").property("nearness"), avg(length(identifier("path")))))
gives:
CYPHER 1.8
START s=node(1),e=node(2)
MATCH path=(s)-[*2..6]-(e)
CREATE UNIQUE (s)-[r:NEAR]-(e)
SET r.nearness=avg(length(path))
What I'm trying to accomplish here, is to create a relationship between two given nodes. This relationship should contain a property "nearness" that represents the average length of all paths between the given nodes with a length between 2 and 6.
Although no exception is thrown, the property nearness isn't created and thus I suppose that "avg(length(path))" isn't evaluated. If I use a fixed value (e.g. r.nearness=1), the query works as expected.
Another side question. I'm using this in a the context of Spring Data Neo4j. When I try to retrieve a "NEAR" relationship, an exception is thrown stating that the "type" property could not be found. This makes sense because I'm using the ExcecutionEngine which is part of the native API. Is there a way that this property is automagically created, or should I do this myself (which actually works)?
Currently it is not possible to model queries like:
RETURN range(0, 10)[3]
or
RETURN range(0, 10)[..3]
or
RETURN range(0, 10)[-3..]
or
RETURN range(0, 10)[2..4]
or
MATCH (person: Person) RETURN person { livesIn: [(person)-[: LIVES_IN]->(personLivesIn: Location) | personLivesIn { .name }][0] }
It's unclear whether it is appropriate for client code to use org.neo4j.cypherdsl.core.renderer.Renderer
directly, because it is annotated as an internal API, however it is shown being used in the README.md example
Accept QueryDSL types in all sensible places and convert them internally.
CypherQuery.ExecuteWithParams.parameters(Map<String, Object> parameters) erroneously does a putAll on the same object it passes as a parameter. Needs to be this.parameters.putAll( parameters). Not sure if this code is even being used since Grammer.parameters has its own implementation. Grammar should probably delegate to ExecuteWithParams instead.
protected class ExecuteWithParams
implements ExecuteWithParameters
{
private final Query query;
private final Map<String, Object> parameters = new HashMap<String, Object>();
...
@Override
public ExecuteWithParameters parameters( Map<String, Object> parameters )
{
parameters.putAll( parameters );
return this;
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.