From e09294fb31f7ed47f34b6650e689e507153f2fb8 Mon Sep 17 00:00:00 2001 From: Hannes Sandberg Date: Tue, 31 Aug 2021 11:40:50 +0200 Subject: [PATCH] Update constraint syntax, using FOR ... REQUIRE instead of ON ... ASSERT Co-authored-by: Therese Magnusson --- .../advanced-query-tuning-example.asciidoc | 4 +- ...tions-additions-and-compatibility.asciidoc | 25 +++++ .../src/docs/dev/glossary.asciidoc | 8 +- .../ql/administration/security/index.asciidoc | 4 +- .../src/docs/dev/ql/constraints/examples.adoc | 12 +++ .../src/docs/dev/ql/constraints/syntax.adoc | 24 ++--- .../import/import-csv-with-cypher.asciidoc | 4 +- .../src/docs/graphgists/intro/labels.adoc | 2 +- .../neo4j/cypher/export/SubGraphExporter.java | 2 +- .../neo4j/cypher/docgen/ConstraintsTest.scala | 101 +++++++++++------- .../org/neo4j/cypher/docgen/MergeTest.scala | 8 +- .../neo4j/cypher/docgen/QueryPlanTest.scala | 26 ++--- .../docgen/refcard/ConstraintTest.scala | 40 +++---- .../harness/enterprise/doc/JUnitDocIT.java | 2 +- 14 files changed, 164 insertions(+), 98 deletions(-) diff --git a/cypher/cypher-docs/src/docs/dev/advanced-query-tuning-example.asciidoc b/cypher/cypher-docs/src/docs/dev/advanced-query-tuning-example.asciidoc index 92d3255981c..587a4b93d1b 100644 --- a/cypher/cypher-docs/src/docs/dev/advanced-query-tuning-example.asciidoc +++ b/cypher/cypher-docs/src/docs/dev/advanced-query-tuning-example.asciidoc @@ -917,7 +917,7 @@ Predicates that can be used to enable this optimization are: [NOTE] ==== If there is an existence constraint on the property, no predicate is required to trigger the optimization. -For example, `CREATE CONSTRAINT constraint_name ON (p:Person) ASSERT p.name IS NOT NULL`. +For example, `CREATE CONSTRAINT constraint_name FOR (p:Person) REQUIRE p.name IS NOT NULL`. ==== @@ -1142,7 +1142,7 @@ Predicates that will not work: [NOTE] ==== If there is an existence constraint on the property, no predicate is required to trigger the optimization. -For example, `CREATE CONSTRAINT constraint_name ON (p:Person) ASSERT p.name IS NOT NULL` +For example, `CREATE CONSTRAINT constraint_name FOR (p:Person) REQUIRE p.name IS NOT NULL` As of Neo4j {neo4j-version-exact}, predicates with parameters, such as `WHERE n.prop > $param`, can trigger _index-backed order by_. The only exception are queries with parameters of type `Point`. diff --git a/cypher/cypher-docs/src/docs/dev/deprecations-additions-and-compatibility.asciidoc b/cypher/cypher-docs/src/docs/dev/deprecations-additions-and-compatibility.asciidoc index ed361ddd101..41bdc2c15e5 100644 --- a/cypher/cypher-docs/src/docs/dev/deprecations-additions-and-compatibility.asciidoc +++ b/cypher/cypher-docs/src/docs/dev/deprecations-additions-and-compatibility.asciidoc @@ -50,6 +50,31 @@ Replaced by: ---- DROP CONSTRAINT name [IF EXISTS] ---- + + +a| +label:syntax[] +label:added[] +[source, cypher, role="noheader"] +---- +CREATE CONSTRAINT FOR ... REQUIRE ... +---- +a| +New syntax for creating constraints, applicable to all constraint types. + +a| +label:syntax[] +label:deprecated[] +[source, cypher, role="noheader"] +---- +CREATE CONSTRAINT ON ... ASSERT ... +---- +a| +Replaced by: +[source, cypher, role="noheader"] +---- +CREATE CONSTRAINT FOR ... REQUIRE ... +---- |=== diff --git a/cypher/cypher-docs/src/docs/dev/glossary.asciidoc b/cypher/cypher-docs/src/docs/dev/glossary.asciidoc index 8c4e065396d..2c628879749 100644 --- a/cypher/cypher-docs/src/docs/dev/glossary.asciidoc +++ b/cypher/cypher-docs/src/docs/dev/glossary.asciidoc @@ -24,10 +24,10 @@ This section comprises a glossary of all the keywords -- grouped by category and |<> | Reading/Writing | Invoke a procedure deployed in the database. |<> | Reading/Writing | Evaluates a subquery, typically used for post-union processing or aggregations. |<> | Writing | Create nodes and relationships. -|<> | Schema | Create a constraint ensuring that all nodes with a particular label have a certain property. -|<> | Schema | Create a constraint that ensures that all nodes with a particular label have all the specified properties and that the combination of property values is unique; i.e. ensures existence and uniqueness. -|<> | Schema | Create a constraint ensuring that all relationships with a particular type have a certain property. -|<> | Schema | Create a constraint that ensures the uniqueness of the combination of node label and property values for a particular property key combination across all nodes. +|<> | Schema | Create a constraint ensuring that all nodes with a particular label have a certain property. +|<> | Schema | Create a constraint that ensures that all nodes with a particular label have all the specified properties and that the combination of property values is unique; i.e. ensures existence and uniqueness. +|<> | Schema | Create a constraint ensuring that all relationships with a particular type have a certain property. +|<> | Schema | Create a constraint that ensures the uniqueness of the combination of node label and property values for a particular property key combination across all nodes. |<> | Schema | Create an index on all nodes with a particular label and a single property; i.e. create a single-property index. |<> | Schema | Create an index on all relationships with a particular relationship type and a single property; i.e. create a single-property index. |<> | Schema | Create an index on all nodes with a particular label and multiple properties; i.e. create a composite index. diff --git a/cypher/cypher-docs/src/docs/dev/ql/administration/security/index.asciidoc b/cypher/cypher-docs/src/docs/dev/ql/administration/security/index.asciidoc index 2d0c7fa0805..304f4d29662 100644 --- a/cypher/cypher-docs/src/docs/dev/ql/administration/security/index.asciidoc +++ b/cypher/cypher-docs/src/docs/dev/ql/administration/security/index.asciidoc @@ -156,8 +156,8 @@ This is because `(` and `)` are not special characters, and the `[` and `]` indi [source, cypher, role=noplay] ---- CREATE CONSTRAINT [constraint_name] [IF NOT EXISTS] -ON (n:LabelName) -ASSERT n.propertyName IS NOT NULL +FOR (n:LabelName) +REQUIRE n.propertyName IS NOT NULL ---- include::administration-security-users-and-roles.adoc[leveloffset=+1] diff --git a/cypher/cypher-docs/src/docs/dev/ql/constraints/examples.adoc b/cypher/cypher-docs/src/docs/dev/ql/constraints/examples.adoc index 57c74569656..d61d7b70c28 100644 --- a/cypher/cypher-docs/src/docs/dev/ql/constraints/examples.adoc +++ b/cypher/cypher-docs/src/docs/dev/ql/constraints/examples.adoc @@ -127,14 +127,26 @@ include::../administration/constraints/listing-constraints-with-filtering.asciid [[administration-constraints-deprecated-syntax]] == Deprecated syntax +[discrete] +include::../administration/constraints/create-a-unique-constraint-using-deprecated-syntax.asciidoc[leveloffset=+1] + [discrete] include::../administration/constraints/drop-a-unique-constraint.asciidoc[leveloffset=+1] +[discrete] +include::../administration/constraints/create-a-node-property-existence-constraint-using-deprecated-syntax.asciidoc[leveloffset=+1] + [discrete] include::../administration/constraints/drop-a-node-property-existence-constraint.asciidoc[leveloffset=+1] +[discrete] +include::../administration/constraints/create-a-relationship-property-existence-constraint-using-deprecated-syntax.asciidoc[leveloffset=+1] + [discrete] include::../administration/constraints/drop-a-relationship-property-existence-constraint.asciidoc[leveloffset=+1] +[discrete] +include::../administration/constraints/create-a-node-key-constraint-using-deprecated-syntax.asciidoc[leveloffset=+1] + [discrete] include::../administration/constraints/drop-a-node-key-constraint.asciidoc[leveloffset=+1] diff --git a/cypher/cypher-docs/src/docs/dev/ql/constraints/syntax.adoc b/cypher/cypher-docs/src/docs/dev/ql/constraints/syntax.adoc index 63c243b561f..cac34121124 100644 --- a/cypher/cypher-docs/src/docs/dev/ql/constraints/syntax.adoc +++ b/cypher/cypher-docs/src/docs/dev/ql/constraints/syntax.adoc @@ -32,16 +32,16 @@ This command creates a uniqueness constraint on nodes with the specified label a [source, cypher, role=noplay] ---- CREATE CONSTRAINT [constraint_name] [IF NOT EXISTS] -ON (n:LabelName) -ASSERT n.propertyName IS UNIQUE +FOR (n:LabelName) +REQUIRE n.propertyName IS UNIQUE [OPTIONS "{" option: value[, ...] "}"] ---- [source, cypher, role=noplay] ---- CREATE CONSTRAINT [constraint_name] [IF NOT EXISTS] -ON (n:LabelName) -ASSERT (n.propertyName_1, …, n.propertyName_n) IS UNIQUE +FOR (n:LabelName) +REQUIRE (n.propertyName_1, …, n.propertyName_n) IS UNIQUE [OPTIONS "{" option: value[, ...] "}"] ---- @@ -53,8 +53,8 @@ This command creates a property existence constraint on nodes with the specified [source, cypher, role=noplay] ---- CREATE CONSTRAINT [constraint_name] [IF NOT EXISTS] -ON (n:LabelName) -ASSERT n.propertyName IS NOT NULL +FOR (n:LabelName) +REQUIRE n.propertyName IS NOT NULL ---- [discrete] @@ -65,8 +65,8 @@ This command creates a property existence constraint on relationships with the s [source, cypher, role=noplay] ---- CREATE CONSTRAINT [constraint_name] [IF NOT EXISTS] -ON ()-"["R:RELATIONSHIP_TYPE"]"-() -ASSERT R.propertyName IS NOT NULL +FOR ()-"["R:RELATIONSHIP_TYPE"]"-() +REQUIRE R.propertyName IS NOT NULL ---- [discrete] @@ -77,16 +77,16 @@ This command creates a node key constraint on nodes with the specified label and [source, cypher, role=noplay] ---- CREATE CONSTRAINT [constraint_name] [IF NOT EXISTS] -ON (n:LabelName) -ASSERT n.propertyName IS NODE KEY +FOR (n:LabelName) +REQUIRE n.propertyName IS NODE KEY [OPTIONS "{" option: value[, ...] "}"] ---- [source, cypher, role=noplay] ---- CREATE CONSTRAINT [constraint_name] [IF NOT EXISTS] -ON (n:LabelName) -ASSERT (n.propertyName_1, …, n.propertyName_n) IS NODE KEY +FOR (n:LabelName) +REQUIRE (n.propertyName_1, …, n.propertyName_n) IS NODE KEY [OPTIONS "{" option: value[, ...] "}"] ---- diff --git a/cypher/cypher-docs/src/docs/graphgists/import/import-csv-with-cypher.asciidoc b/cypher/cypher-docs/src/docs/graphgists/import/import-csv-with-cypher.asciidoc index 7d56a5a4827..42937c83091 100644 --- a/cypher/cypher-docs/src/docs/graphgists/import/import-csv-with-cypher.asciidoc +++ b/cypher/cypher-docs/src/docs/graphgists/import/import-csv-with-cypher.asciidoc @@ -95,12 +95,12 @@ Creating a unique constraint also creates a unique index (which is faster than a [source, cypher] ---- -CREATE CONSTRAINT person ON (person:Person) ASSERT person.id IS UNIQUE +CREATE CONSTRAINT person FOR (person:Person) REQUIRE person.id IS UNIQUE ---- [source, cypher] ---- -CREATE CONSTRAINT movie ON (movie:Movie) ASSERT movie.id IS UNIQUE +CREATE CONSTRAINT movie FOR (movie:Movie) REQUIRE movie.id IS UNIQUE ---- Now importing the relationships is a matter of finding the nodes and then creating relationships between them. diff --git a/cypher/cypher-docs/src/docs/graphgists/intro/labels.adoc b/cypher/cypher-docs/src/docs/graphgists/intro/labels.adoc index 554ba2a49e0..831f8c82eb4 100644 --- a/cypher/cypher-docs/src/docs/graphgists/intro/labels.adoc +++ b/cypher/cypher-docs/src/docs/graphgists/intro/labels.adoc @@ -14,7 +14,7 @@ Let's start out adding a constraint -- in this case we decided that all `Movie` [source, cypher] ---- -CREATE CONSTRAINT ON (movie:Movie) ASSERT movie.title IS UNIQUE +CREATE CONSTRAINT FOR (movie:Movie) REQUIRE movie.title IS UNIQUE ---- [source, querytest] diff --git a/cypher/cypher-docs/src/test/java/org/neo4j/cypher/export/SubGraphExporter.java b/cypher/cypher-docs/src/test/java/org/neo4j/cypher/export/SubGraphExporter.java index f10cf064aaf..521eae2d47e 100644 --- a/cypher/cypher-docs/src/test/java/org/neo4j/cypher/export/SubGraphExporter.java +++ b/cypher/cypher-docs/src/test/java/org/neo4j/cypher/export/SubGraphExporter.java @@ -173,7 +173,7 @@ private Collection exportConstraints() String name = quote( constraint.getName() ); String key = quote( id ); String label = quote( constraint.getLabel().name() ); - result.add( "create constraint " + name + " on (n:" + label + ") assert n." + key + " is unique" ); + result.add( "create constraint " + name + " for (n:" + label + ") require n." + key + " is unique" ); } Collections.sort( result ); return result; diff --git a/cypher/cypher-docs/src/test/scala/org/neo4j/cypher/docgen/ConstraintsTest.scala b/cypher/cypher-docs/src/test/scala/org/neo4j/cypher/docgen/ConstraintsTest.scala index 44e7431a381..be9576493a5 100644 --- a/cypher/cypher-docs/src/test/scala/org/neo4j/cypher/docgen/ConstraintsTest.scala +++ b/cypher/cypher-docs/src/test/scala/org/neo4j/cypher/docgen/ConstraintsTest.scala @@ -59,15 +59,22 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { title = "Create a unique constraint", text = "When creating a unique constraint, a name can be provided. The constraint ensures that your database " + "will never contain more than one node with a specific label and one property value.", - queryText = "CREATE CONSTRAINT constraint_name ON (book:Book) ASSERT book.isbn IS UNIQUE", + queryText = "CREATE CONSTRAINT constraint_name FOR (book:Book) REQUIRE book.isbn IS UNIQUE", assertions = _ => assertConstraintWithNameExists("constraint_name", "Book", List("isbn")) ) + testQuery( + title = "Create a unique constraint using deprecated syntax", + text = "The unique constraint ensures that your database " + + "will never contain more than one node with a specific label and one property value.", + queryText = "CREATE CONSTRAINT ON (book:Book) ASSERT book.title IS UNIQUE", + assertions = _ => hasNodeConstraint("Book", "title") + ) prepareAndTestQuery( title = "Create a unique constraint only if it does not already exist", text = "If it is unknown if a constraint exists or not but we want to make sure it does, we add the `IF NOT EXISTS`. " + "The uniqueness constraint ensures that your database will never contain more than one node with a specific label and one property value.", prepare = _ => executePreparationQueries(List("DROP CONSTRAINT constraint_name IF EXISTS")), - queryText = "CREATE CONSTRAINT constraint_name IF NOT EXISTS ON (book:Book) ASSERT book.isbn IS UNIQUE", + queryText = "CREATE CONSTRAINT constraint_name IF NOT EXISTS FOR (book:Book) REQUIRE book.isbn IS UNIQUE", optionalResultExplanation = "Note no constraint will be created if any other constraint with that name or another uniqueness constraint on the same schema already exists. " + "Assuming no such constraints existed:", assertions = _ => assertConstraintWithNameExists("constraint_name", "Book", List("isbn")) @@ -81,7 +88,7 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { |`$wgsMin`, `$wgsMax`, `$wgs3dMin`, and `$wgs3dMax`. |Non-specified settings get their respective default values.""".stripMargin, queryText = - s"""CREATE CONSTRAINT constraint_with_options ON (n:Label) ASSERT (n.prop1, n.prop2) IS UNIQUE + s"""CREATE CONSTRAINT constraint_with_options FOR (n:Label) REQUIRE (n.prop1, n.prop2) IS UNIQUE |OPTIONS { | indexProvider: '$nativeLuceneProvider', | indexConfig: {`$wgsMin`: [-100.0, -80.0], `$wgsMax`: [100.0, 80.0]} @@ -101,7 +108,7 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { |To list all constraints with the default output columns, the `SHOW CONSTRAINTS` command can be used. |If all columns are required, use `SHOW CONSTRAINTS YIELD *`.""".stripMargin, queryText = "SHOW CONSTRAINTS", - prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE")), + prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT FOR (book:Book) REQUIRE book.isbn IS UNIQUE")), optionalResultExplanation = """One of the output columns from `SHOW CONSTRAINTS` is the name of the constraint. |This can be used to drop the constraint with the <>.""".stripMargin, @@ -118,7 +125,7 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { |Another more flexible way of filtering the output is to use the `WHERE` clause. |An example is to only show constraints on relationships.""".stripMargin, queryText = "SHOW EXISTENCE CONSTRAINTS WHERE entityType = 'RELATIONSHIP'", - prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT ON ()-[knows:KNOWS]-() ASSERT knows.since IS NOT NULL")), + prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT FOR ()-[knows:KNOWS]-() REQUIRE knows.since IS NOT NULL")), optionalResultExplanation = """This will only return the default output columns. |To get all columns, use `SHOW INDEXES YIELD * WHERE ...`.""".stripMargin, @@ -133,7 +140,7 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { title = "Drop a unique constraint", text = "By using `DROP CONSTRAINT`, you remove a constraint from the database.", queryText = "DROP CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE", - prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE")), + prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT FOR (book:Book) REQUIRE book.isbn IS UNIQUE")), assertions = _ => assertNodeConstraintDoesNotExist("Book", "isbn") ) } @@ -145,14 +152,14 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { title = "Create a node that complies with unique property constraints", text = "Create a `Book` node with an `isbn` that isn't already in the database.", queryText = "CREATE (book:Book {isbn: '1449356265', title: 'Graph Databases'})", - prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE")), + prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT FOR (book:Book) REQUIRE book.isbn IS UNIQUE")), assertions = _ => assertNodeConstraintExist("Book", "isbn") ) } @Test def violate_unique_property_constraint() { generateConsole = false - execute("CREATE CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE") + execute("CREATE CONSTRAINT FOR (book:Book) REQUIRE book.isbn IS UNIQUE") execute("CREATE (book:Book {isbn: '1449356265', title: 'Graph Databases'})") testFailingQuery[CypherExecutionException]( @@ -172,7 +179,7 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { title = "Failure to create a unique property constraint due to conflicting nodes", text = "Create a unique property constraint on the property `isbn` on nodes with the `Book` label when there are two nodes with" + " the same `isbn`.", - queryText = "CREATE CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE", + queryText = "CREATE CONSTRAINT FOR (book:Book) REQUIRE book.isbn IS UNIQUE", optionalResultExplanation = "In this case the constraint can't be created because it is violated by existing " + "data. We may choose to use <> instead or remove the offending nodes and then re-apply the " + "constraint." @@ -184,15 +191,22 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { title = "Create a node property existence constraint", text = "When creating a node property existence constraint, a name can be provided. The constraint ensures that all nodes " + "with a certain label have a certain property.", - queryText = "CREATE CONSTRAINT constraint_name ON (book:Book) ASSERT book.isbn IS NOT NULL", + queryText = "CREATE CONSTRAINT constraint_name FOR (book:Book) REQUIRE book.isbn IS NOT NULL", assertions = _ => assertConstraintWithNameExists("constraint_name", "Book", List("isbn")) ) + testQuery( + title = "Create a node property existence constraint using deprecated syntax", + text = "The node property existence constraint ensures that all nodes " + + "with a certain label have a certain property.", + queryText = "CREATE CONSTRAINT ON (book:Book) ASSERT book.title IS NOT NULL", + assertions = _ => hasNodeConstraint("Book", "title") + ) prepareAndTestQuery( title = "Create a node property existence constraint only if it does not already exist", text = "If it is unknown if a constraint exists or not but we want to make sure it does, we add the `IF NOT EXISTS`. " + "The node property existence constraint ensures that all nodes with a certain label have a certain property.", - prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT constraint_name IF NOT EXISTS ON (book:Book) ASSERT book.isbn IS UNIQUE")), - queryText = "CREATE CONSTRAINT constraint_name IF NOT EXISTS ON (book:Book) ASSERT book.isbn IS NOT NULL", + prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT constraint_name IF NOT EXISTS FOR (book:Book) REQUIRE book.isbn IS UNIQUE")), + queryText = "CREATE CONSTRAINT constraint_name IF NOT EXISTS FOR (book:Book) REQUIRE book.isbn IS NOT NULL", optionalResultExplanation = "Note no constraint will be created if any other constraint with that name or another node property existence constraint on the same schema already exists. " + "Assuming a constraint with the name `constraint_name` already existed:", assertions = _ => assertConstraintWithNameExists("constraint_name", "Book", List("isbn")) @@ -206,7 +220,7 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { title = "Drop a node property existence constraint", text = "By using `DROP CONSTRAINT`, you remove a constraint from the database.", queryText = "DROP CONSTRAINT ON (book:Book) ASSERT exists(book.isbn)", - prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT ON (book:Book) ASSERT book.isbn IS NOT NULL")), + prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT FOR (book:Book) REQUIRE book.isbn IS NOT NULL")), assertions = _ => assertNodeConstraintDoesNotExist("Book", "isbn") ) } @@ -218,14 +232,14 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { title = "Create a node that complies with property existence constraints", text = "Create a `Book` node with an `isbn` property.", queryText = "CREATE (book:Book {isbn: '1449356265', title: 'Graph Databases'})", - prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT ON (book:Book) ASSERT book.isbn IS NOT NULL")), + prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT FOR (book:Book) REQUIRE book.isbn IS NOT NULL")), assertions = _ => assertNodeConstraintExist("Book", "isbn") ) } @Test def violate_node_property_existence_constraint() { generateConsole = false - execute("CREATE CONSTRAINT ON (book:Book) ASSERT book.isbn IS NOT NULL") + execute("CREATE CONSTRAINT FOR (book:Book) REQUIRE book.isbn IS NOT NULL") testFailingQuery[ConstraintViolationException]( title = "Create a node that violates a property existence constraint", text = "Trying to create a `Book` node without an `isbn` property, given a property existence constraint on `:Book(isbn)`.", @@ -236,7 +250,7 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { @Test def violate_node_property_existence_constraint_by_removing_property() { generateConsole = false - execute("CREATE CONSTRAINT ON (book:Book) ASSERT book.isbn IS NOT NULL") + execute("CREATE CONSTRAINT FOR (book:Book) REQUIRE book.isbn IS NOT NULL") execute("CREATE (book:Book {isbn: '1449356265', title: 'Graph Databases'})") testFailingQuery[ConstraintViolationException]( title = "Removing an existence constrained node property", @@ -254,7 +268,7 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { title = "Failure to create a node property existence constraint due to existing node", text = "Create a constraint on the property `isbn` on nodes with the `Book` label when there already exists " + " a node without an `isbn`.", - queryText = "CREATE CONSTRAINT ON (book:Book) ASSERT book.isbn IS NOT NULL", + queryText = "CREATE CONSTRAINT FOR (book:Book) REQUIRE book.isbn IS NOT NULL", optionalResultExplanation = "In this case the constraint can't be created because it is violated by existing " + "data. We may choose to remove the offending nodes and then re-apply the constraint." ) @@ -265,15 +279,22 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { title = "Create a relationship property existence constraint", text = "When creating a relationship property existence constraint, a name can be provided. The constraint ensures all relationships " + "with a certain type have a certain property.", - queryText = "CREATE CONSTRAINT constraint_name ON ()-[like:LIKED]-() ASSERT like.day IS NOT NULL", + queryText = "CREATE CONSTRAINT constraint_name FOR ()-[like:LIKED]-() REQUIRE like.day IS NOT NULL", assertions = _ => assertConstraintWithNameExists("constraint_name", "LIKED", List("day"), forRelationship = true) ) + testQuery( + title = "Create a relationship property existence constraint using deprecated syntax", + text = "The relationship property existence constraint ensures all relationships " + + "with a certain type have a certain property.", + queryText = "CREATE CONSTRAINT ON ()-[like:LIKED]-() ASSERT like.week IS NOT NULL", + assertions = _ => hasRelationshipConstraint("LIKED", "week") + ) prepareAndTestQuery( title = "Create a relationship property existence constraint only if it does not already exist", text = "If it is unknown if a constraint exists or not but we want to make sure it does, we add the `IF NOT EXISTS`. " + "The relationship property existence constraint ensures all relationships with a certain type have a certain property.", - prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT constraint_name IF NOT EXISTS ON ()-[like:LIKED]-() ASSERT like.since IS NOT NULL")), - queryText = "CREATE CONSTRAINT constraint_name IF NOT EXISTS ON ()-[like:LIKED]-() ASSERT like.day IS NOT NULL", + prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT constraint_name IF NOT EXISTS FOR ()-[like:LIKED]-() REQUIRE like.since IS NOT NULL")), + queryText = "CREATE CONSTRAINT constraint_name IF NOT EXISTS FOR ()-[like:LIKED]-() REQUIRE like.day IS NOT NULL", optionalResultExplanation = "Note no constraint will be created if any other constraint with that name or another relationship property existence constraint on the same schema already exists. " + "Assuming a constraint with the name `constraint_name` already existed:", assertions = _ => assertConstraintWithNameExists("constraint_name", "LIKED", List("since"), forRelationship = true) @@ -287,7 +308,7 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { title = "Drop a relationship property existence constraint", text = "To remove a constraint from the database, use `DROP CONSTRAINT`.", queryText = "DROP CONSTRAINT ON ()-[like:LIKED]-() ASSERT exists(like.day)", - prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT ON ()-[like:LIKED]-() ASSERT like.day IS NOT NULL")), + prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT FOR ()-[like:LIKED]-() REQUIRE like.day IS NOT NULL")), assertions = _ => assertRelationshipConstraintDoesNotExist("LIKED", "day") ) } @@ -299,14 +320,14 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { title = "Create a relationship that complies with property existence constraints", text = "Create a `LIKED` relationship with a `day` property.", queryText = "CREATE (user:User)-[like:LIKED {day: 'yesterday'}]->(book:Book)", - prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT ON ()-[like:LIKED]-() ASSERT like.day IS NOT NULL")), + prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT FOR ()-[like:LIKED]-() REQUIRE like.day IS NOT NULL")), assertions = _ => assertRelationshipConstraintExist("LIKED", "day") ) } @Test def violate_relationship_property_existence_constraint() { generateConsole = false - execute("CREATE CONSTRAINT ON ()-[like:LIKED]-() ASSERT like.day IS NOT NULL") + execute("CREATE CONSTRAINT FOR ()-[like:LIKED]-() REQUIRE like.day IS NOT NULL") testFailingQuery[ConstraintViolationException]( title = "Create a relationship that violates a property existence constraint", text = "Trying to create a `LIKED` relationship without a `day` property, given a property existence constraint `:LIKED(day)`.", @@ -317,7 +338,7 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { @Test def violate_relationship_property_existence_constraint_by_removing_property() { generateConsole = false - execute("CREATE CONSTRAINT ON ()-[like:LIKED]-() ASSERT like.day IS NOT NULL") + execute("CREATE CONSTRAINT FOR ()-[like:LIKED]-() REQUIRE like.day IS NOT NULL") execute("CREATE (user:User)-[like:LIKED {day: 'today'}]->(book:Book)") testFailingQuery[ConstraintViolationException]( title = "Removing an existence constrained relationship property", @@ -335,7 +356,7 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { title = "Failure to create a relationship property existence constraint due to existing relationship", text = "Create a constraint on the property `day` on relationships with the `LIKED` type when there already " + "exists a relationship without a property named `day`.", - queryText = "CREATE CONSTRAINT ON ()-[like:LIKED]-() ASSERT like.day IS NOT NULL", + queryText = "CREATE CONSTRAINT FOR ()-[like:LIKED]-() REQUIRE like.day IS NOT NULL", optionalResultExplanation = "In this case the constraint can't be created because it is violated by existing " + "data. We may choose to remove the offending relationships and then re-apply the constraint." ) @@ -347,16 +368,24 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { text = "When creating a node key constraint, a name can be provided. The constraint ensures that all nodes " + "with a particular label have a set of defined properties whose combined value is unique " + "and all properties in the set are present.", - queryText = "CREATE CONSTRAINT constraint_name ON (n:Person) ASSERT (n.firstname, n.surname) IS NODE KEY", + queryText = "CREATE CONSTRAINT constraint_name FOR (n:Person) REQUIRE (n.firstname, n.surname) IS NODE KEY", assertions = _ => assertConstraintWithNameExists("constraint_name", "Person", List("firstname", "surname")) ) + testQuery( + title = "Create a node key constraint using deprecated syntax", + text = "The node key constraint ensures that all nodes " + + "with a particular label have a set of defined properties whose combined value is unique " + + "and all properties in the set are present.", + queryText = "CREATE CONSTRAINT ON (n:Person) ASSERT (n.firstname) IS NODE KEY", + assertions = _ => hasNodeKeyConstraint("Person", List("firstname")) + ) prepareAndTestQuery( title = "Create a node key constraint only if it does not already exist", text = "If it is unknown if a constraint exists or not but we want to make sure it does, we add the `IF NOT EXISTS`. " + "The node key constraint ensures that all nodes with a particular label have a set of defined properties whose combined value is unique " + "and all properties in the set are present.", - prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT old_constraint_name IF NOT EXISTS ON (n:Person) ASSERT (n.firstname, n.surname) IS NODE KEY")), - queryText = "CREATE CONSTRAINT constraint_name IF NOT EXISTS ON (n:Person) ASSERT (n.firstname, n.surname) IS NODE KEY", + prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT old_constraint_name IF NOT EXISTS FOR (n:Person) REQUIRE (n.firstname, n.surname) IS NODE KEY")), + queryText = "CREATE CONSTRAINT constraint_name IF NOT EXISTS FOR (n:Person) REQUIRE (n.firstname, n.surname) IS NODE KEY", optionalResultExplanation = "Note no constraint will be created if any other constraint with that name or another node key constraint on the same schema already exists. " + "Assuming a node key constraint on `(:Person {firstname, surname})` already existed:", assertions = _ => assertConstraintWithNameExists("old_constraint_name", "Person", List("firstname", "surname")) @@ -370,7 +399,7 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { s"""To create a node key constraint with a specific index provider for the backing index, the `OPTIONS` clause is used. |Valid values for the index provider is `$nativeProvider` and `$nativeLuceneProvider`, default if nothing is specified is `$nativeProvider`.""".stripMargin, queryText = - s"""CREATE CONSTRAINT constraint_with_provider ON (n:Label) ASSERT (n.prop1) IS NODE KEY OPTIONS {indexProvider: '$nativeProvider'}""".stripMargin, + s"""CREATE CONSTRAINT constraint_with_provider FOR (n:Label) REQUIRE (n.prop1) IS NODE KEY OPTIONS {indexProvider: '$nativeProvider'}""".stripMargin, optionalResultExplanation = "Can be combined with specifying index configuration.", assertions = _ => assertConstraintWithNameExists("constraint_with_provider", "Label", List("prop1")) ) @@ -385,7 +414,7 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { |`$wgsMin`, `$wgsMax`, `$wgs3dMin`, and `$wgs3dMax`. |Non-specified settings get their respective default values.""".stripMargin, queryText = - s"""CREATE CONSTRAINT constraint_with_config ON (n:Label) ASSERT (n.prop2) IS NODE KEY + s"""CREATE CONSTRAINT constraint_with_config FOR (n:Label) REQUIRE (n.prop2) IS NODE KEY |OPTIONS {indexConfig: {`$cartesianMin`: [-100.0, -100.0], `$cartesianMax`: [100.0, 100.0]}}""".stripMargin, optionalResultExplanation = "Can be combined with specifying index provider.", assertions = _ => assertConstraintWithNameExists("constraint_with_config", "Label", List("prop2")) @@ -399,7 +428,7 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { title = "Drop a node key constraint", text = "Use `DROP CONSTRAINT` to remove a node key constraint from the database.", queryText = "DROP CONSTRAINT ON (n:Person) ASSERT (n.firstname, n.surname) IS NODE KEY", - prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT ON (n:Person) ASSERT (n.firstname, n.surname) IS NODE KEY")), + prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT FOR (n:Person) REQUIRE (n.firstname, n.surname) IS NODE KEY")), assertions = _ => assertNodeKeyConstraintDoesNotExist("Person", "firstname", "surname") ) } @@ -411,14 +440,14 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { title = "Create a node that complies with node key constraints", text = "Create a `Person` node with both a `firstname` and `surname` property.", queryText = "CREATE (p:Person {firstname: 'John', surname: 'Wood', age: 55})", - prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT ON (n:Person) ASSERT (n.firstname, n.surname) IS NODE KEY")), + prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT FOR (n:Person) REQUIRE (n.firstname, n.surname) IS NODE KEY")), assertions = _ => assertNodeKeyConstraintExists("Person", "firstname", "surname") ) } @Test def violate_node_key_constraint() { generateConsole = false - execute("CREATE CONSTRAINT ON (n:Person) ASSERT (n.firstname, n.surname) IS NODE KEY") + execute("CREATE CONSTRAINT FOR (n:Person) REQUIRE (n.firstname, n.surname) IS NODE KEY") testFailingQuery[ConstraintViolationException]( title = "Create a node that violates a node key constraint", text = "Trying to create a `Person` node without a `surname` property, given a node key constraint on `:Person(firstname, surname)`, will fail.", @@ -429,7 +458,7 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { @Test def break_node_key_constraint_by_removing_property() { generateConsole = false - execute("CREATE CONSTRAINT ON (n:Person) ASSERT (n.firstname, n.surname) IS NODE KEY") + execute("CREATE CONSTRAINT FOR (n:Person) REQUIRE (n.firstname, n.surname) IS NODE KEY") execute("CREATE (p:Person {firstname: 'John', surname: 'Wood'})") testFailingQuery[ConstraintViolationException]( title = "Removing a `NODE KEY`-constrained property", @@ -447,7 +476,7 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { title = "Failure to create a node key constraint due to existing node", text = "Trying to create a node key constraint on the property `surname` on nodes with the `Person` label will fail when " + " a node without a `surname` already exists in the database.", - queryText = "CREATE CONSTRAINT ON (n:Person) ASSERT (n.firstname, n.surname) IS NODE KEY", + queryText = "CREATE CONSTRAINT FOR (n:Person) REQUIRE (n.firstname, n.surname) IS NODE KEY", optionalResultExplanation = "In this case the node key constraint can't be created because it is violated by existing " + "data. We may choose to remove the offending nodes and then re-apply the constraint." ) @@ -463,7 +492,7 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { |It is the same command for unique property, property existence and node key constraints. |The name of the constraint can be found using the <>, given in the output column `name`.""".stripMargin, queryText = "DROP CONSTRAINT constraint_name", - prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT constraint_name ON (n:Person) ASSERT (n.firstname, n.surname) IS NODE KEY")), + prepare = _ => executePreparationQueries(List("CREATE CONSTRAINT constraint_name FOR (n:Person) REQUIRE (n.firstname, n.surname) IS NODE KEY")), assertions = _ => assertConstraintWithNameDoesNotExists("constraint_name") ) testQuery( diff --git a/cypher/cypher-docs/src/test/scala/org/neo4j/cypher/docgen/MergeTest.scala b/cypher/cypher-docs/src/test/scala/org/neo4j/cypher/docgen/MergeTest.scala index bda4aeaeddb..4e6b8f3b3c9 100644 --- a/cypher/cypher-docs/src/test/scala/org/neo4j/cypher/docgen/MergeTest.scala +++ b/cypher/cypher-docs/src/test/scala/org/neo4j/cypher/docgen/MergeTest.scala @@ -28,8 +28,8 @@ class MergeTest extends DocumentingTest with QueryStatisticsTestSupport { override def doc = new DocBuilder { doc("MERGE", "query-merge") initQueries( - "CREATE CONSTRAINT ON (person:Person) ASSERT person.name IS UNIQUE", - "CREATE CONSTRAINT ON (movie:Movie) ASSERT movie.title IS UNIQUE", + "CREATE CONSTRAINT FOR (person:Person) REQUIRE person.name IS UNIQUE", + "CREATE CONSTRAINT FOR (movie:Movie) REQUIRE movie.title IS UNIQUE", """CREATE # (charlie:Person {name: 'Charlie Sheen', bornIn: 'New York', chauffeurName: 'John Brown'}), # (martin:Person {name: 'Martin Sheen', bornIn: 'Ohio', chauffeurName: 'Bob Brown'}), @@ -306,8 +306,8 @@ class MergeTest extends DocumentingTest with QueryStatisticsTestSupport { p("Note that the following examples assume the existence of unique constraints that have been created using:") p("""[source,cypher] #---- - #CREATE CONSTRAINT ON (n:Person) ASSERT n.name IS UNIQUE; - #CREATE CONSTRAINT ON (n:Person) ASSERT n.role IS UNIQUE; + #CREATE CONSTRAINT FOR (n:Person) REQUIRE n.name IS UNIQUE; + #CREATE CONSTRAINT FOR (n:Person) REQUIRE n.role IS UNIQUE; #----""".stripMargin('#')) section("Merge using unique constraints creates a new node if no node is found", "merge-merge-using-unique-constraints-creates-a-new-node-if-no-node-is-found") { diff --git a/cypher/cypher-docs/src/test/scala/org/neo4j/cypher/docgen/QueryPlanTest.scala b/cypher/cypher-docs/src/test/scala/org/neo4j/cypher/docgen/QueryPlanTest.scala index ef3c1c58128..9a39d41f46a 100644 --- a/cypher/cypher-docs/src/test/scala/org/neo4j/cypher/docgen/QueryPlanTest.scala +++ b/cypher/cypher-docs/src/test/scala/org/neo4j/cypher/docgen/QueryPlanTest.scala @@ -96,8 +96,8 @@ class QueryPlanTest extends DocumentingTestBase with SoftReset { "CREATE INDEX FOR (n:Person) ON (n.name)", "CREATE INDEX FOR ()-[r:WORKS_IN]-() ON (r.duration)", "CREATE INDEX FOR ()-[r:WORKS_IN]-() ON (r.title)", - "CREATE CONSTRAINT ON (team:Team) ASSERT team.name is UNIQUE", - "CREATE CONSTRAINT ON (team:Team) ASSERT team.id is UNIQUE" + "CREATE CONSTRAINT FOR (team:Team) REQUIRE team.name is UNIQUE", + "CREATE CONSTRAINT FOR (team:Team) REQUIRE team.id is UNIQUE" ) def section = "Query Plan" @@ -119,7 +119,7 @@ class QueryPlanTest extends DocumentingTestBase with SoftReset { text = """The `CreateUniqueConstraint` operator creates a unique constraint on a set of properties for all nodes having a certain label. |The following query will create a unique constraint with the name `uniqueness` on the `name` property of nodes with the `Country` label.""".stripMargin, - queryText = """CREATE CONSTRAINT uniqueness ON (c:Country) ASSERT c.name is UNIQUE""", + queryText = """CREATE CONSTRAINT uniqueness FOR (c:Country) REQUIRE c.name is UNIQUE""", assertions = p => { val plan = p.executionPlanString() assertThat(plan, containsString("CreateConstraint")) @@ -130,7 +130,7 @@ class QueryPlanTest extends DocumentingTestBase with SoftReset { @Test def dropUniqueConstraint() { executePreparationQueries { - List("CREATE CONSTRAINT ON (c:Country) ASSERT c.name is UNIQUE") + List("CREATE CONSTRAINT FOR (c:Country) REQUIRE c.name is UNIQUE") } profileQuery( @@ -152,7 +152,7 @@ class QueryPlanTest extends DocumentingTestBase with SoftReset { |If it finds a constraint with the given name or with the same type and schema it will stop the execution and no new constraint is created. |The following query will create a unique constraint with the name `uniqueness` on the `name` property of nodes with the `Country` label only if |no constraint named `uniqueness` or unique constraint on `(:Country {name})` already exists.""".stripMargin, - queryText = """CREATE CONSTRAINT uniqueness IF NOT EXISTS ON (c:Country) ASSERT c.name is UNIQUE""", + queryText = """CREATE CONSTRAINT uniqueness IF NOT EXISTS FOR (c:Country) REQUIRE c.name is UNIQUE""", assertions = p => { val plan = p.executionPlanString() assertThat(plan, containsString("CreateConstraint")) @@ -169,7 +169,7 @@ class QueryPlanTest extends DocumentingTestBase with SoftReset { """The `CreateNodePropertyExistenceConstraint` operator creates an existence constraint with the name `existence` on a property for all nodes having a certain label. |This will only appear in Enterprise Edition. """.stripMargin, - queryText = """CREATE CONSTRAINT existence ON (p:Person) ASSERT p.name IS NOT NULL""", + queryText = """CREATE CONSTRAINT existence FOR (p:Person) REQUIRE p.name IS NOT NULL""", assertions = p => { val plan = p.executionPlanString() assertThat(plan, containsString("CreateConstraint")) @@ -180,7 +180,7 @@ class QueryPlanTest extends DocumentingTestBase with SoftReset { @Test def dropNodePropertyExistenceConstraint() { executePreparationQueries { - List("CREATE CONSTRAINT ON (p:Person) ASSERT p.name IS NOT NULL") + List("CREATE CONSTRAINT FOR (p:Person) REQUIRE p.name IS NOT NULL") } profileQuery( @@ -202,7 +202,7 @@ class QueryPlanTest extends DocumentingTestBase with SoftReset { |that all nodes with a particular label have a set of defined properties whose combined value is unique, and where all properties in the set are present. |This will only appear in Enterprise Edition. """.stripMargin, - queryText = """CREATE CONSTRAINT node_key ON (e:Employee) ASSERT (e.firstname, e.surname) IS NODE KEY""", + queryText = """CREATE CONSTRAINT node_key FOR (e:Employee) REQUIRE (e.firstname, e.surname) IS NODE KEY""", assertions = p => { val plan = p.executionPlanString() assertThat(plan, containsString("CreateConstraint")) @@ -213,7 +213,7 @@ class QueryPlanTest extends DocumentingTestBase with SoftReset { @Test def dropNodeKeyConstraint() { executePreparationQueries { - List("CREATE CONSTRAINT ON (e:Employee) ASSERT (e.firstname, e.surname) IS NODE KEY") + List("CREATE CONSTRAINT FOR (e:Employee) REQUIRE (e.firstname, e.surname) IS NODE KEY") } profileQuery( @@ -234,7 +234,7 @@ class QueryPlanTest extends DocumentingTestBase with SoftReset { """The `CreateRelationshipPropertyExistenceConstraint` operator creates an existence constraint with the name `existence` on a property for all relationships of a certain type. |This will only appear in Enterprise Edition. """.stripMargin, - queryText = """CREATE CONSTRAINT existence ON ()-[l:LIKED]-() ASSERT l.when IS NOT NULL""", + queryText = """CREATE CONSTRAINT existence FOR ()-[l:LIKED]-() REQUIRE l.when IS NOT NULL""", assertions = p => { val plan = p.executionPlanString() assertThat(plan, containsString("CreateConstraint")) @@ -245,7 +245,7 @@ class QueryPlanTest extends DocumentingTestBase with SoftReset { @Test def dropRelationshipPropertyExistenceConstraint() { executePreparationQueries { - List("CREATE CONSTRAINT ON ()-[l:LIKED]-() ASSERT l.when IS NOT NULL") + List("CREATE CONSTRAINT FOR ()-[l:LIKED]-() REQUIRE l.when IS NOT NULL") } profileQuery( @@ -260,7 +260,7 @@ class QueryPlanTest extends DocumentingTestBase with SoftReset { @Test def dropNamedConstraint() { executePreparationQueries { - List("CREATE CONSTRAINT name ON (c:Country) ASSERT c.name is UNIQUE") + List("CREATE CONSTRAINT name FOR (c:Country) REQUIRE c.name is UNIQUE") } profileQuery( @@ -278,7 +278,7 @@ class QueryPlanTest extends DocumentingTestBase with SoftReset { @Test def showConstraints() { executePreparationQueries { - List("CREATE CONSTRAINT name ON (c:Country) ASSERT c.name is UNIQUE") + List("CREATE CONSTRAINT name FOR (c:Country) REQUIRE c.name is UNIQUE") } profileQuery( diff --git a/cypher/refcard-tests/src/test/scala/org/neo4j/cypher/docgen/refcard/ConstraintTest.scala b/cypher/refcard-tests/src/test/scala/org/neo4j/cypher/docgen/refcard/ConstraintTest.scala index 60eba163f7f..f4aaee8150d 100644 --- a/cypher/refcard-tests/src/test/scala/org/neo4j/cypher/docgen/refcard/ConstraintTest.scala +++ b/cypher/refcard-tests/src/test/scala/org/neo4j/cypher/docgen/refcard/ConstraintTest.scala @@ -80,8 +80,8 @@ class ConstraintTest extends RefcardTest with QueryStatisticsTestSupport { ###assertion=create-unique-property-constraint // -CREATE CONSTRAINT ON (p:Person) - ASSERT p.name IS UNIQUE +CREATE CONSTRAINT FOR (p:Person) + REQUIRE p.name IS UNIQUE ### Create a unique property constraint on the label `Person` and property `name`. @@ -92,8 +92,8 @@ This constraint will create an accompanying index. ###assertion=create-unique-property-constraint // -CREATE CONSTRAINT uniqueness ON (p:Person) - ASSERT (p.firstname, p.age) IS UNIQUE +CREATE CONSTRAINT uniqueness FOR (p:Person) + REQUIRE (p.firstname, p.age) IS UNIQUE ### Create a unique property constraint with the name `uniqueness` on the label `Person` and properties `firstname` and `age`. @@ -104,8 +104,8 @@ This constraint creates an accompanying index. ###assertion=create-unique-property-constraint // -CREATE CONSTRAINT ON (p:Person) - ASSERT p.surname IS UNIQUE +CREATE CONSTRAINT FOR (p:Person) + REQUIRE p.surname IS UNIQUE OPTIONS {indexProvider: '$nativeProvider'} ### @@ -114,8 +114,8 @@ Create a unique property constraint on the label `Person` and property `surname` ###assertion=create-property-existence-constraint // -CREATE CONSTRAINT ON (p:Person) - ASSERT p.name IS NOT NULL +CREATE CONSTRAINT FOR (p:Person) + REQUIRE p.name IS NOT NULL ### (★) Create a node property existence constraint on the label `Person` and property `name`, throws an error if the constraint already exists. @@ -125,8 +125,8 @@ removed from an existing node with the `Person` label, the write operation will ###assertion=create-existing-property-existence-constraint // -CREATE CONSTRAINT node_exists IF NOT EXISTS ON (p:Person) - ASSERT p.name IS NOT NULL +CREATE CONSTRAINT node_exists IF NOT EXISTS FOR (p:Person) + REQUIRE p.name IS NOT NULL ### (★) If a node property existence constraint on the label `Person` and property `name` or any constraint with the name `node_exists` already exist then nothing happens. @@ -135,8 +135,8 @@ If no such constraint exists, then it will be created. ###assertion=create-property-existence-constraint // -CREATE CONSTRAINT ON ()-[l:LIKED]-() - ASSERT l.when IS NOT NULL +CREATE CONSTRAINT FOR ()-[l:LIKED]-() + REQUIRE l.when IS NOT NULL ### (★) Create a relationship property existence constraint on the type `LIKED` and property `when`. @@ -146,8 +146,8 @@ removed from an existing relationship with the `LIKED` type, the write operation ###assertion=create-property-existence-constraint // -CREATE CONSTRAINT relationship_exists ON ()-[l:LIKED]-() - ASSERT l.since IS NOT NULL +CREATE CONSTRAINT relationship_exists FOR ()-[l:LIKED]-() + REQUIRE l.since IS NOT NULL ### (★) Create a relationship property existence constraint with the name `relationship_exists` on the type `LIKED` and property `since`. @@ -166,8 +166,8 @@ List all unique constraints. ###assertion=create-node-key-constraint // -CREATE CONSTRAINT ON (p:Person) - ASSERT (p.firstname, p.surname) IS NODE KEY +CREATE CONSTRAINT FOR (p:Person) + REQUIRE (p.firstname, p.surname) IS NODE KEY ### (★) Create a node key constraint on the label `Person` and properties `firstname` and `surname`. @@ -180,8 +180,8 @@ This constraint creates an accompanying index. ###assertion=create-node-key-constraint // -CREATE CONSTRAINT node_key ON (p:Person) - ASSERT p.firstname IS NODE KEY +CREATE CONSTRAINT node_key FOR (p:Person) + REQUIRE p.firstname IS NODE KEY ### (★) Create a node key constraint with the name `node_key` on the label `Person` and property `firstname`. @@ -194,8 +194,8 @@ This constraint creates an accompanying index. ###assertion=create-node-key-constraint // -CREATE CONSTRAINT node_key_with_config ON (p:Person) - ASSERT (p.name, p.age) IS NODE KEY +CREATE CONSTRAINT node_key_with_config FOR (p:Person) + REQUIRE (p.name, p.age) IS NODE KEY OPTIONS {indexConfig: {`${SPATIAL_WGS84_MIN.getSettingName}`: [-100.0, -100.0], `${SPATIAL_WGS84_MAX.getSettingName}`: [100.0, 100.0]}} ### diff --git a/neo4j-harness-enterprise-test/src/test/java/org/neo4j/harness/enterprise/doc/JUnitDocIT.java b/neo4j-harness-enterprise-test/src/test/java/org/neo4j/harness/enterprise/doc/JUnitDocIT.java index ab0433a4861..27d04f6580c 100644 --- a/neo4j-harness-enterprise-test/src/test/java/org/neo4j/harness/enterprise/doc/JUnitDocIT.java +++ b/neo4j-harness-enterprise-test/src/test/java/org/neo4j/harness/enterprise/doc/JUnitDocIT.java @@ -84,7 +84,7 @@ public void shouldUserEnterpriseFeatures() throws Exception // When I create property existence constraint try ( Transaction tx = db.beginTx() ) { - try ( Result result = tx.execute( "CREATE CONSTRAINT ON (user:User) ASSERT user.name IS NOT NULL" ) ) + try ( Result result = tx.execute( "CREATE CONSTRAINT FOR (user:User) REQUIRE user.name IS NOT NULL" ) ) { // nothing to-do }