Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 136 additions & 0 deletions cip/CIP2015-10-12-CREATE.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
= CIP2015-10-12 - CREATE
:numbered:
:toc:
:toc-placement: macro
:source-highlighter: codemirror

*Authors:* Pontus Melke pontus.melke@neotechnology.com, Mats Rydberg mats@neotechnology.com

[abstract]
.Abstract
--
This proposal formalizes `CREATE` which is used in Cypher to create nodes and relationships.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does/should this cover CREATE UNIQUE as well (which is part of the same parser rule in the Neo4j implementation)? Similarly, might be also worth mentioning that CREATE is used in other contexts within Cypher, such as CREATE CONSTRAINT, for clarity.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll mention that these two things, CREATE UNIQUE and CREATE CONSTRAINT, are not included.

--

toc::[]

== Motivation & Background
`CREATE` is how nodes and relationships are created in Cypher.
The syntax has been around since Cypher 1.7 but never properly formalized.

== Proposal

`CREATE` is used to create new nodes and relationships into the graph, as well as set initial labels, type, and properties on the new entities.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"create new nodes and relationships into the graph" -> "add new nodes and relationships to the graph"

The idea is to let each `CREATE` represent exactly one creation of either a node or a relationship, but allow a few variations on how to structure the query for convenience.
`CREATE` will be allowed to both start and end a query, requiring an additional `WITH` clause to allow further `MATCH` reads after it, and producing an empty result if it ends the query.
`MATCH` clauses that come after a `CREATE` clause must be able to see and possibly match _all_ entities created by the `CREATE`; not only those created for the same row.

A `CREATE` will always succeed unless it specifically violates some constraint already present in the database.

=== Examples

[source, cypher]
.Create a single node.
----
CREATE ()
----

[source, cypher]
.Create a node and set two labels and one property on it.
----
CREATE (:Person:Administrator { email: 'mats@neotechnology.com' })
----

[source, cypher]
.Create a relationship of type `KNOWS` between all `:Person` nodes.
----
MATCH (a:Person), (b:Person)
CREATE (a)-[:KNOWS]->(b)
----

[source, cypher]
.Create two nodes, one relationship between them, and sets one property on the relationship.
----
CREATE (me:Source), (you:Destination), (you)<-[:LOVES { dearly: true }]-(me)
----

[source, cypher]
.Create multiple nodes with properties from a parameter list of maps.
----
UNWIND { mapList } AS map
CREATE (n:Node)
SET n = map
----

[source, cypher]
// It seems the . operator doesn't allow multiple lines, and we want two sentences here.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest deleting the comment "// It seems...."

.Create two nodes with properties from two parameter maps. Parameter keys and values will be the same as those of the map.
----
CREATE (:Cat {catProps})
CREATE (:Dog {dogProps})
----

[source, cypher]
.Create three nodes, connect them with two relationships and return the whole pattern as a path.
----
CREATE (andres { name: 'Andres' })
CREATE (neo)
CREATE (michael { name: 'Michael' })
CREATE (andres)-[r1:WORKS_AT]->(neo)
CREATE (michael)-[r2:WORKS_AT]->(neo)
RETURN (andres)-[r1]->(neo)<-[r2]-(michael) AS p
----

=== Syntax
[source, ebnf]
----
create = "CREATE", {pattern}, [{",", pattern}] ;
pattern = node-pattern | rel-pattern ;
node-pattern = "(", [identifier], [{label}], [property], ")" ;
rel-pattern = "(", identifier, ")", in-rel | out-rel, "(", identifier, ")" ;
out-rel = "-[", [identifier], type, [property], "]->" ;
in-rel = "<-[", [identifier], type, [property], "]-" ;
label = ":", identifier ;
type = label ;
property = "{", param | {identifier, ":", literal | param}, "}" ;
param = "{", identifier, "}" ;
literal = string | number ;
----

=== Semantics

`CREATE` is used to create new nodes and relationships in the graph.
Each `CREATE` will create exactly one node or one relationship between two pre-existing nodes per row.
`CREATE` has no return value, and ending a query with a `CREATE` clause will yield an empty result.

=== Interaction with existing features

`CREATE` on a node pattern will cause the query to fail in the commit phase if the to-be-created node would violate a uniqueness constraint in the database.

This proposal drops some functionality around how we handle creating nodes and relationships:

- `CREATE (a {param})` where `{param}` is a list of maps where one node is created for each item in the list.
See the example with `UNWIND` above for a way to achieve the same behavior.

- `CREATE (a:L {prop: 42})-[:R]->(b:B)` where both nodes and relationships are created from the same pattern.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The - > combo seems to render as a single arrow symbol, at least on GitHub. Can we escape this?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no idea. Asciidoc is difficult.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strange, typically the backticks are enough to make such things escaped. The asciidoc tools I use locally don't render that as an arrow symbol.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding backticks should be enough, I see the arrow on github using the asciidoctor.js extension but not on other places.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's only a problem on GitHub, let's not worry too much.

With this proposal one would have to be more specific and write `CREATE (a:L {prop:42}), (b:B), (a)-[:R]->(b)`.

- `CREATE p = (andres { name: 'Andres' })-[:WORKS_AT]->(neo)<-[:WORKS_AT]-(michael { name:'Michael' }) RETURN p`, where a full path is created and returned.
See the final example above for how to achieve the same behaviour.

We believe that the implicit creation of nodes when specifying a relationship pattern is causing more complexity than whatever benefit it provides to the user, and thus forcing the user to be specific about what to create will benefit both users and implementors of Cypher.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"more complexity than whatever benefit it provides to the user" -> "more complexity than any benefit provided to the user"


=== Alternatives
This is a retroactive CIP.
`CREATE` already exists in the language.

== What others do

- SQL has `CREATE TABLE` for creating tables and `INSERT` for creating new records in a table.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CREATE TABLE isn't an equivalent here. It would be closer to label creation, if anything.
INSERT is the equivalent in SQL.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CREATE does have the ability to set labels and properties, too. And we do mention INSERT here.

- MongoDB has `create: <collection_name>` for creating documents.
- In SPARQL, you use `INSERT DATA` to add triples.

== Benefits to this proposal

This is a retroactive CIP, and proposes no new features.
The purpose of this proposal is this very CIP, formalizing what we want `CREATE` to be.