From 8d9bedbf96b14beb027ebc1338bc6d5750e1feb5 Mon Sep 17 00:00:00 2001 From: Tobias Lindaaker Date: Tue, 23 Jun 2015 15:19:34 +0200 Subject: [PATCH] Enable creation of Mandatory Property Constraints The constraints are not yet validated or enforced. This only supports creating and dropping the constraints, as well as the storage of the constraint metadata. --- .../checking/SchemaRecordCheck.java | 6 +- .../checking/SchemaRuleContent.java | 8 +- .../checking/SchemaRecordCheckTest.java | 23 +- .../checking/SchemaRuleContentTest.java | 2 +- .../full/FullCheckIntegrationTest.java | 5 +- .../compiler/v2_3/spi/PlanContext.scala | 4 +- .../compiler/v2_3/spi/QueryContext.scala | 4 +- .../StartPointChoosingBuilderTest.scala | 2 +- .../planner/LogicalPlanningTestSupport2.scala | 4 +- .../spi/UpdateCountingQueryContextTest.scala | 4 +- .../v2_2/TransactionBoundPlanContext.scala | 6 +- .../v2_2/TransactionBoundQueryContext.scala | 9 +- .../v2_3/TransactionBoundPlanContext.scala | 4 +- .../v2_3/TransactionBoundQueryContext.scala | 23 +- .../neo4j/cypher/ExecutionResultTest.scala | 33 +- .../compiler/v2_3/LabelActionTest.scala | 6 +- .../neo4j/cypher/docgen/ConstraintsTest.scala | 4 +- .../graphdb/schema/ConstraintCreator.java | 8 + .../neo4j/graphdb/schema/ConstraintType.java | 1 + .../java/org/neo4j/graphdb/schema/Schema.java | 2 +- .../java/org/neo4j/kernel/api/SchemaRead.java | 14 +- .../org/neo4j/kernel/api/SchemaWrite.java | 9 +- .../MandatoryPropertyConstraint.java | 55 +++ .../api/constraints/PropertyConstraint.java | 107 +++++ .../api/constraints/UniquenessConstraint.java | 59 +-- .../schema/AlreadyConstrainedException.java | 13 +- ...aintVerificationFailedKernelException.java | 8 +- .../CreateConstraintFailureException.java | 8 +- .../DropConstraintFailureException.java | 8 +- .../schema/NoSuchConstraintException.java | 6 +- .../kernel/api/txstate/ReadableTxState.java | 7 +- .../kernel/api/txstate/TransactionState.java | 8 +- .../kernel/api/txstate/TxStateVisitor.java | 23 +- .../ConstraintEnforcingEntityOperations.java | 22 +- ...ntegrityValidatingStatementOperations.java | 42 +- .../api/KernelTransactionImplementation.java | 38 +- .../impl/api/LockingStatementOperations.java | 22 +- .../kernel/impl/api/OperationsFacade.java | 22 +- .../api/StateHandlingStatementOperations.java | 46 +- .../api/operations/SchemaReadOperations.java | 14 +- .../api/operations/SchemaWriteOperations.java | 11 +- .../api/state/ConstraintIndexCreator.java | 5 +- .../kernel/impl/api/state/LabelState.java | 12 +- .../neo4j/kernel/impl/api/state/TxState.java | 98 +++- .../kernel/impl/api/store/CacheLayer.java | 8 +- .../kernel/impl/api/store/DiskLayer.java | 34 +- .../kernel/impl/api/store/SchemaCache.java | 34 +- .../kernel/impl/api/store/StoreReadLayer.java | 8 +- .../coreapi/schema/BaseConstraintCreator.java | 6 + ...java => PropertyConstraintDefinition.java} | 34 +- .../PropertyUniqueConstraintCreator.java | 6 + .../impl/coreapi/schema/SchemaImpl.java | 24 +- .../MandatoryPropertyConstraintRule.java | 102 +++++ .../impl/store/PropertyConstraintRule.java | 36 ++ .../kernel/impl/store/SchemaStorage.java | 38 +- ...java => UniquePropertyConstraintRule.java} | 25 +- .../kernel/impl/store/record/SchemaRule.java | 18 +- .../command/NeoStoreTransactionApplier.java | 4 +- .../transaction/state/IntegrityValidator.java | 6 +- .../DbStructureArgumentFormatter.java | 5 +- .../dbstructure/DbStructureCollector.java | 10 +- .../util/dbstructure/DbStructureVisitor.java | 4 +- .../dbstructure/GraphDbStructureGuide.java | 6 +- .../unsafe/batchinsert/BatchInserterImpl.java | 16 +- .../api/KernelSchemaStateFlushingTest.java | 10 +- .../org/neo4j/kernel/impl/api/KernelTest.java | 2 +- .../api/LockingStatementOperationsTest.java | 28 +- .../neo4j/kernel/impl/api/index/IndexIT.java | 8 +- .../ConstraintsCreationIT.java | 431 ++++++++++++++---- .../NodeGetUniqueFromIndexSeekIT.java | 2 +- .../UniquenessConstraintCreationIT.java | 3 +- .../UniquenessConstraintValidationIT.java | 2 +- .../state/IndexQueryTransactionStateTest.java | 4 +- .../StateHandlingStatementOperationsTest.java | 39 +- .../kernel/impl/api/state/TxStateTest.java | 14 +- .../kernel/impl/api/store/CacheLayerTest.java | 8 +- .../impl/api/store/SchemaCacheTest.java | 8 +- .../NeoTransactionStoreApplierTest.java | 20 +- .../state/IntegrityValidatorTest.java | 7 +- .../state/NeoStoreTransactionTest.java | 2 +- .../state/SchemaRuleCommandTest.java | 2 +- .../util/dbstructure/CineastsDbStructure.java | 2 - .../DbStructureArgumentFormatterTest.java | 6 +- .../dbstructure/DbStructureCollectorTest.java | 2 - ...uctureInvocationTracingAcceptanceTest.java | 5 +- .../GraphDbStructureGuideTest.java | 8 +- .../unsafe/batchinsert/BatchInsertTest.java | 8 +- .../test/java/org/neo4j/shell/TestApps.java | 45 +- .../kernel/api/UniqueConstraintHaIT.java | 8 +- 89 files changed, 1368 insertions(+), 545 deletions(-) create mode 100644 community/kernel/src/main/java/org/neo4j/kernel/api/constraints/MandatoryPropertyConstraint.java create mode 100644 community/kernel/src/main/java/org/neo4j/kernel/api/constraints/PropertyConstraint.java rename community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/{PropertyUniqueConstraintDefinition.java => PropertyConstraintDefinition.java} (75%) create mode 100644 community/kernel/src/main/java/org/neo4j/kernel/impl/store/MandatoryPropertyConstraintRule.java create mode 100644 community/kernel/src/main/java/org/neo4j/kernel/impl/store/PropertyConstraintRule.java rename community/kernel/src/main/java/org/neo4j/kernel/impl/store/{UniquenessConstraintRule.java => UniquePropertyConstraintRule.java} (77%) diff --git a/community/consistency-check/src/main/java/org/neo4j/consistency/checking/SchemaRecordCheck.java b/community/consistency-check/src/main/java/org/neo4j/consistency/checking/SchemaRecordCheck.java index 0fd1885d094b6..01e6c9a42bbe0 100644 --- a/community/consistency-check/src/main/java/org/neo4j/consistency/checking/SchemaRecordCheck.java +++ b/community/consistency-check/src/main/java/org/neo4j/consistency/checking/SchemaRecordCheck.java @@ -27,7 +27,7 @@ import org.neo4j.consistency.store.RecordAccess; import org.neo4j.kernel.api.exceptions.schema.MalformedSchemaRuleException; import org.neo4j.kernel.impl.store.SchemaRuleAccess; -import org.neo4j.kernel.impl.store.UniquenessConstraintRule; +import org.neo4j.kernel.impl.store.UniquePropertyConstraintRule; import org.neo4j.kernel.impl.store.record.DynamicRecord; import org.neo4j.kernel.impl.store.record.IndexRule; import org.neo4j.kernel.impl.store.record.LabelTokenRecord; @@ -131,7 +131,7 @@ public void check( DynamicRecord record, checkIndexRule( (IndexRule) rule, engine, record, records ); break; case UNIQUENESS_CONSTRAINT: - checkUniquenessConstraintRule( (UniquenessConstraintRule) rule, engine, record, records ); + checkUniquenessConstraintRule( (UniquePropertyConstraintRule) rule, engine, record, records ); break; default: engine.report().unsupportedSchemaRuleKind( kind ); @@ -139,7 +139,7 @@ public void check( DynamicRecord record, } } - private void checkUniquenessConstraintRule( UniquenessConstraintRule rule, + private void checkUniquenessConstraintRule( UniquePropertyConstraintRule rule, CheckerEngine engine, DynamicRecord record, RecordAccess records ) { diff --git a/community/consistency-check/src/main/java/org/neo4j/consistency/checking/SchemaRuleContent.java b/community/consistency-check/src/main/java/org/neo4j/consistency/checking/SchemaRuleContent.java index f04592288022f..db94de191f713 100644 --- a/community/consistency-check/src/main/java/org/neo4j/consistency/checking/SchemaRuleContent.java +++ b/community/consistency-check/src/main/java/org/neo4j/consistency/checking/SchemaRuleContent.java @@ -19,7 +19,7 @@ */ package org.neo4j.consistency.checking; -import org.neo4j.kernel.impl.store.UniquenessConstraintRule; +import org.neo4j.kernel.impl.store.UniquePropertyConstraintRule; import org.neo4j.kernel.impl.store.record.IndexRule; import org.neo4j.kernel.impl.store.record.SchemaRule; @@ -63,8 +63,8 @@ public boolean equals( Object obj ) return indexRulesEquals( (IndexRule) this.schemaRule, (IndexRule) that.schemaRule ); case UNIQUENESS_CONSTRAINT: return this.schemaRule.getKind() == that.schemaRule.getKind() && uniquenessConstraintEquals( - (UniquenessConstraintRule) this.schemaRule, - (UniquenessConstraintRule) that.schemaRule ); + (UniquePropertyConstraintRule) this.schemaRule, + (UniquePropertyConstraintRule) that.schemaRule ); default: throw new IllegalArgumentException( "Invalid SchemaRule kind: " + schemaRule.getKind() ); } @@ -77,7 +77,7 @@ private static boolean indexRulesEquals( IndexRule lhs, IndexRule rhs ) return lhs.getPropertyKey() == rhs.getPropertyKey(); } - private static boolean uniquenessConstraintEquals( UniquenessConstraintRule lhs, UniquenessConstraintRule rhs ) + private static boolean uniquenessConstraintEquals( UniquePropertyConstraintRule lhs, UniquePropertyConstraintRule rhs ) { return lhs.getPropertyKey() == rhs.getPropertyKey(); } diff --git a/community/consistency-check/src/test/java/org/neo4j/consistency/checking/SchemaRecordCheckTest.java b/community/consistency-check/src/test/java/org/neo4j/consistency/checking/SchemaRecordCheckTest.java index 102c013a79b5a..40fad91dee85a 100644 --- a/community/consistency-check/src/test/java/org/neo4j/consistency/checking/SchemaRecordCheckTest.java +++ b/community/consistency-check/src/test/java/org/neo4j/consistency/checking/SchemaRecordCheckTest.java @@ -26,7 +26,7 @@ import org.neo4j.kernel.api.exceptions.schema.MalformedSchemaRuleException; import org.neo4j.kernel.api.index.SchemaIndexProvider; import org.neo4j.kernel.impl.store.SchemaStorage; -import org.neo4j.kernel.impl.store.UniquenessConstraintRule; +import org.neo4j.kernel.impl.store.UniquePropertyConstraintRule; import org.neo4j.kernel.impl.store.record.DynamicRecord; import org.neo4j.kernel.impl.store.record.IndexRule; import org.neo4j.kernel.impl.store.record.LabelTokenRecord; @@ -126,7 +126,8 @@ public void shouldReportInvalidPropertyReferenceFromUniquenessConstraintRule() t DynamicRecord record = inUse( dynamicRecord( schemaRuleId ) ); - UniquenessConstraintRule rule = UniquenessConstraintRule.uniquenessConstraintRule( schemaRuleId, labelId, propertyKeyId, indexRuleId ); + UniquePropertyConstraintRule rule = UniquePropertyConstraintRule + .uniquenessConstraintRule( schemaRuleId, labelId, propertyKeyId, indexRuleId ); when( checker().ruleAccess.loadSingleSchemaRule( schemaRuleId ) ).thenReturn( rule ); @@ -155,7 +156,8 @@ public void shouldReportUniquenessConstraintNotReferencingBack() throws Exceptio SchemaIndexProvider.Descriptor providerDescriptor = new SchemaIndexProvider.Descriptor( "in-memory", "1.0" ); IndexRule rule1 = IndexRule.constraintIndexRule( ruleId1, labelId, propertyKeyId, providerDescriptor, (long) ruleId2 ); - UniquenessConstraintRule rule2 = UniquenessConstraintRule.uniquenessConstraintRule( ruleId2, labelId, propertyKeyId, ruleId2 ); + UniquePropertyConstraintRule rule2 = UniquePropertyConstraintRule + .uniquenessConstraintRule( ruleId2, labelId, propertyKeyId, ruleId2 ); when( checker().ruleAccess.loadSingleSchemaRule( ruleId1 ) ).thenReturn( rule1 ); when( checker().ruleAccess.loadSingleSchemaRule( ruleId2 ) ).thenReturn( rule2 ); @@ -214,8 +216,10 @@ public void shouldReportTwoUniquenessConstraintsReferencingSameIndex() throws Ex DynamicRecord record1 = inUse( dynamicRecord( ruleId1 ) ); DynamicRecord record2 = inUse( dynamicRecord( ruleId2 ) ); - UniquenessConstraintRule rule1 = UniquenessConstraintRule.uniquenessConstraintRule( ruleId1, labelId, propertyKeyId, ruleId2 ); - UniquenessConstraintRule rule2 = UniquenessConstraintRule.uniquenessConstraintRule( ruleId2, labelId, propertyKeyId, ruleId2 ); + UniquePropertyConstraintRule rule1 = UniquePropertyConstraintRule + .uniquenessConstraintRule( ruleId1, labelId, propertyKeyId, ruleId2 ); + UniquePropertyConstraintRule rule2 = UniquePropertyConstraintRule + .uniquenessConstraintRule( ruleId2, labelId, propertyKeyId, ruleId2 ); when( checker().ruleAccess.loadSingleSchemaRule( ruleId1 ) ).thenReturn( rule1 ); when( checker().ruleAccess.loadSingleSchemaRule( ruleId2 ) ).thenReturn( rule2 ); @@ -241,7 +245,8 @@ public void shouldReportUnreferencedUniquenessConstraint() throws Exception DynamicRecord record = inUse( dynamicRecord( ruleId ) ); - UniquenessConstraintRule rule = UniquenessConstraintRule.uniquenessConstraintRule( ruleId, labelId, propertyKeyId, ruleId ); + UniquePropertyConstraintRule rule = UniquePropertyConstraintRule + .uniquenessConstraintRule( ruleId, labelId, propertyKeyId, ruleId ); when( checker().ruleAccess.loadSingleSchemaRule( ruleId ) ).thenReturn( rule ); @@ -271,8 +276,10 @@ public void shouldReportConstraintIndexNotReferencingBack() throws Exception SchemaIndexProvider.Descriptor providerDescriptor = new SchemaIndexProvider.Descriptor( "in-memory", "1.0" ); - IndexRule rule1 = IndexRule.constraintIndexRule( ruleId1, labelId, propertyKeyId, providerDescriptor, (long) ruleId1 ); - UniquenessConstraintRule rule2 = UniquenessConstraintRule.uniquenessConstraintRule( ruleId2, labelId, propertyKeyId, ruleId1 ); + IndexRule rule1 = IndexRule.constraintIndexRule( ruleId1, labelId, propertyKeyId, providerDescriptor, (long) + ruleId1 ); + UniquePropertyConstraintRule rule2 = UniquePropertyConstraintRule + .uniquenessConstraintRule( ruleId2, labelId, propertyKeyId, ruleId1 ); when( checker().ruleAccess.loadSingleSchemaRule( ruleId1 ) ).thenReturn( rule1 ); when( checker().ruleAccess.loadSingleSchemaRule( ruleId2 ) ).thenReturn( rule2 ); diff --git a/community/consistency-check/src/test/java/org/neo4j/consistency/checking/SchemaRuleContentTest.java b/community/consistency-check/src/test/java/org/neo4j/consistency/checking/SchemaRuleContentTest.java index 9e879360e1522..020d8f82b9fb4 100644 --- a/community/consistency-check/src/test/java/org/neo4j/consistency/checking/SchemaRuleContentTest.java +++ b/community/consistency-check/src/test/java/org/neo4j/consistency/checking/SchemaRuleContentTest.java @@ -26,7 +26,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; -import static org.neo4j.kernel.impl.store.UniquenessConstraintRule.uniquenessConstraintRule; +import static org.neo4j.kernel.impl.store.UniquePropertyConstraintRule.uniquenessConstraintRule; import static org.neo4j.kernel.impl.store.record.IndexRule.constraintIndexRule; import static org.neo4j.kernel.impl.store.record.IndexRule.indexRule; diff --git a/community/consistency-check/src/test/java/org/neo4j/consistency/checking/full/FullCheckIntegrationTest.java b/community/consistency-check/src/test/java/org/neo4j/consistency/checking/full/FullCheckIntegrationTest.java index 4a8986482a0d1..f48375be58b34 100644 --- a/community/consistency-check/src/test/java/org/neo4j/consistency/checking/full/FullCheckIntegrationTest.java +++ b/community/consistency-check/src/test/java/org/neo4j/consistency/checking/full/FullCheckIntegrationTest.java @@ -75,7 +75,7 @@ import org.neo4j.kernel.impl.store.RecordStore; import org.neo4j.kernel.impl.store.SchemaStorage; import org.neo4j.kernel.impl.store.StoreAccess; -import org.neo4j.kernel.impl.store.UniquenessConstraintRule; +import org.neo4j.kernel.impl.store.UniquePropertyConstraintRule; import org.neo4j.kernel.impl.store.record.DynamicRecord; import org.neo4j.kernel.impl.store.record.IndexRule; import org.neo4j.kernel.impl.store.record.LabelTokenRecord; @@ -856,7 +856,8 @@ protected void transactionData( GraphStoreFixture.TransactionDataBuilder tx, SchemaIndexProvider.Descriptor providerDescriptor = new SchemaIndexProvider.Descriptor( "lucene", "1.0" ); IndexRule rule1 = IndexRule.constraintIndexRule( ruleId1, labelId, propertyKeyId, providerDescriptor, (long) ruleId2 ); - UniquenessConstraintRule rule2 = UniquenessConstraintRule.uniquenessConstraintRule( ruleId2, labelId, propertyKeyId, ruleId2 ); + UniquePropertyConstraintRule rule2 = UniquePropertyConstraintRule + .uniquenessConstraintRule( ruleId2, labelId, propertyKeyId, ruleId2 ); Collection records1 = serializeRule( rule1, record1 ); diff --git a/community/cypher/cypher-compiler-2.3/src/main/scala/org/neo4j/cypher/internal/compiler/v2_3/spi/PlanContext.scala b/community/cypher/cypher-compiler-2.3/src/main/scala/org/neo4j/cypher/internal/compiler/v2_3/spi/PlanContext.scala index 55a18114fbccb..0a9f13dd537a2 100644 --- a/community/cypher/cypher-compiler-2.3/src/main/scala/org/neo4j/cypher/internal/compiler/v2_3/spi/PlanContext.scala +++ b/community/cypher/cypher-compiler-2.3/src/main/scala/org/neo4j/cypher/internal/compiler/v2_3/spi/PlanContext.scala @@ -19,7 +19,7 @@ */ package org.neo4j.cypher.internal.compiler.v2_3.spi -import org.neo4j.kernel.api.constraints.UniquenessConstraint +import org.neo4j.kernel.api.constraints.PropertyConstraint import org.neo4j.kernel.api.index.IndexDescriptor /** @@ -35,7 +35,7 @@ trait PlanContext extends TokenContext { def getUniqueIndexRule(labelName: String, propertyKey: String): Option[IndexDescriptor] - def getUniquenessConstraint(labelName: String, propertyKey: String): Option[UniquenessConstraint] + def getUniquenessConstraint(labelName: String, propertyKey: String): Option[PropertyConstraint] def checkNodeIndex(idxName: String) diff --git a/community/cypher/cypher-compiler-2.3/src/main/scala/org/neo4j/cypher/internal/compiler/v2_3/spi/QueryContext.scala b/community/cypher/cypher-compiler-2.3/src/main/scala/org/neo4j/cypher/internal/compiler/v2_3/spi/QueryContext.scala index a753810e66fa1..350251a1710eb 100644 --- a/community/cypher/cypher-compiler-2.3/src/main/scala/org/neo4j/cypher/internal/compiler/v2_3/spi/QueryContext.scala +++ b/community/cypher/cypher-compiler-2.3/src/main/scala/org/neo4j/cypher/internal/compiler/v2_3/spi/QueryContext.scala @@ -21,7 +21,7 @@ package org.neo4j.cypher.internal.compiler.v2_3.spi import org.neo4j.cypher.internal.compiler.v2_3.InternalQueryStatistics import org.neo4j.graphdb._ -import org.neo4j.kernel.api.constraints.UniquenessConstraint +import org.neo4j.kernel.api.constraints.{MandatoryPropertyConstraint, UniquenessConstraint} import org.neo4j.kernel.api.index.IndexDescriptor /* @@ -95,7 +95,7 @@ trait QueryContext extends TokenContext { def dropUniqueConstraint(labelId: Int, propertyKeyId: Int) - def createMandatoryConstraint(labelId: Int, propertyKeyId: Int): IdempotentResult[UniquenessConstraint]//TODO add MandatoryConstraint when doing kernel work + def createMandatoryConstraint(labelId: Int, propertyKeyId: Int): IdempotentResult[MandatoryPropertyConstraint] def dropMandatoryConstraint(labelId: Int, propertyKeyId: Int) diff --git a/community/cypher/cypher-compiler-2.3/src/test/scala/org/neo4j/cypher/internal/compiler/v2_3/executionplan/builders/StartPointChoosingBuilderTest.scala b/community/cypher/cypher-compiler-2.3/src/test/scala/org/neo4j/cypher/internal/compiler/v2_3/executionplan/builders/StartPointChoosingBuilderTest.scala index cc8eb97a3fb0b..c75c935d38ce5 100644 --- a/community/cypher/cypher-compiler-2.3/src/test/scala/org/neo4j/cypher/internal/compiler/v2_3/executionplan/builders/StartPointChoosingBuilderTest.scala +++ b/community/cypher/cypher-compiler-2.3/src/test/scala/org/neo4j/cypher/internal/compiler/v2_3/executionplan/builders/StartPointChoosingBuilderTest.scala @@ -33,7 +33,7 @@ import org.neo4j.cypher.internal.compiler.v2_3.pipes.FakePipe import org.neo4j.cypher.internal.compiler.v2_3.spi.PlanContext import org.neo4j.cypher.internal.compiler.v2_3.symbols._ import org.neo4j.graphdb.Direction -import org.neo4j.kernel.api.constraints.UniquenessConstraint +import org.neo4j.kernel.api.constraints.{UniquenessConstraint, PropertyConstraint} import org.neo4j.kernel.api.index.IndexDescriptor class StartPointChoosingBuilderTest extends BuilderTest { diff --git a/community/cypher/cypher-compiler-2.3/src/test/scala/org/neo4j/cypher/internal/compiler/v2_3/planner/LogicalPlanningTestSupport2.scala b/community/cypher/cypher-compiler-2.3/src/test/scala/org/neo4j/cypher/internal/compiler/v2_3/planner/LogicalPlanningTestSupport2.scala index 51acd2e6bad45..42fc03b95a073 100644 --- a/community/cypher/cypher-compiler-2.3/src/test/scala/org/neo4j/cypher/internal/compiler/v2_3/planner/LogicalPlanningTestSupport2.scala +++ b/community/cypher/cypher-compiler-2.3/src/test/scala/org/neo4j/cypher/internal/compiler/v2_3/planner/LogicalPlanningTestSupport2.scala @@ -36,7 +36,7 @@ import org.neo4j.cypher.internal.compiler.v2_3.spi.{GraphStatistics, PlanContext import org.neo4j.cypher.internal.compiler.v2_3.test_helpers.{CypherFunSuite, CypherTestSupport} import org.neo4j.cypher.internal.compiler.v2_3.tracing.rewriters.RewriterStepSequencer import org.neo4j.helpers.collection.Visitable -import org.neo4j.kernel.api.constraints.UniquenessConstraint +import org.neo4j.kernel.api.constraints.{UniquenessConstraint, PropertyConstraint} import org.neo4j.kernel.api.index.IndexDescriptor import org.neo4j.kernel.impl.util.dbstructure.DbStructureVisitor @@ -95,7 +95,7 @@ trait LogicalPlanningTestSupport2 extends CypherTestSupport with AstConstruction else None - def getUniquenessConstraint(labelName: String, propertyKey: String): Option[UniquenessConstraint] = { + def getUniquenessConstraint(labelName: String, propertyKey: String): Option[PropertyConstraint] = { if (config.uniqueIndexes((labelName, propertyKey))) Some(new UniquenessConstraint( semanticTable.resolvedLabelIds(labelName).id, diff --git a/community/cypher/cypher-compiler-2.3/src/test/scala/org/neo4j/cypher/internal/compiler/v2_3/spi/UpdateCountingQueryContextTest.scala b/community/cypher/cypher-compiler-2.3/src/test/scala/org/neo4j/cypher/internal/compiler/v2_3/spi/UpdateCountingQueryContextTest.scala index 442aef0546588..fc320bb237d25 100644 --- a/community/cypher/cypher-compiler-2.3/src/test/scala/org/neo4j/cypher/internal/compiler/v2_3/spi/UpdateCountingQueryContextTest.scala +++ b/community/cypher/cypher-compiler-2.3/src/test/scala/org/neo4j/cypher/internal/compiler/v2_3/spi/UpdateCountingQueryContextTest.scala @@ -26,7 +26,7 @@ import org.mockito.stubbing.Answer import org.neo4j.cypher.internal.compiler.v2_3.InternalQueryStatistics import org.neo4j.cypher.internal.compiler.v2_3.test_helpers.CypherFunSuite import org.neo4j.graphdb.{Node, Relationship} -import org.neo4j.kernel.api.constraints.UniquenessConstraint +import org.neo4j.kernel.api.constraints.{MandatoryPropertyConstraint, UniquenessConstraint} import org.neo4j.kernel.api.index.IndexDescriptor class UpdateCountingQueryContextTest extends CypherFunSuite { @@ -61,7 +61,7 @@ class UpdateCountingQueryContextTest extends CypherFunSuite { .thenReturn(IdempotentResult(mock[UniquenessConstraint])) when( inner.createMandatoryConstraint(anyInt(), anyInt()) ) - .thenReturn(IdempotentResult(mock[UniquenessConstraint])) + .thenReturn(IdempotentResult(mock[MandatoryPropertyConstraint])) when( inner.addIndexRule(anyInt(), anyInt()) ) .thenReturn(IdempotentResult(mock[IndexDescriptor])) diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v2_2/TransactionBoundPlanContext.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v2_2/TransactionBoundPlanContext.scala index 08a1aaae1b7f8..3b52244bdd875 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v2_2/TransactionBoundPlanContext.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v2_2/TransactionBoundPlanContext.scala @@ -61,8 +61,10 @@ class TransactionBoundPlanContext(someStatement: Statement, val gdb: GraphDataba val labelId = statement.readOperations().labelGetForName(labelName) val propertyKeyId = statement.readOperations().propertyKeyGetForName(propertyKey) - val matchingConstraints = statement.readOperations().constraintsGetForLabelAndPropertyKey(labelId, propertyKeyId) - if ( matchingConstraints.hasNext ) Some(matchingConstraints.next()) else None + import scala.collection.JavaConverters._ + statement.readOperations().constraintsGetForLabelAndPropertyKey(labelId, propertyKeyId).asScala.collectFirst { + case unique: UniquenessConstraint => unique + } } catch { case _: KernelException => None } diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v2_2/TransactionBoundQueryContext.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v2_2/TransactionBoundQueryContext.scala index c669c1cb31d91..413aed5417592 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v2_2/TransactionBoundQueryContext.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v2_2/TransactionBoundQueryContext.scala @@ -27,7 +27,6 @@ import org.neo4j.cypher.internal.compiler.v2_3.helpers.JavaConversionSupport._ import org.neo4j.graphdb.DynamicRelationshipType._ import org.neo4j.graphdb._ import org.neo4j.graphdb.factory.GraphDatabaseSettings -import org.neo4j.helpers.collection.IteratorUtil import org.neo4j.kernel.GraphDatabaseAPI import org.neo4j.kernel.api._ import org.neo4j.kernel.api.constraints.UniquenessConstraint @@ -281,12 +280,10 @@ final class TransactionBoundQueryContext(graph: GraphDatabaseAPI, statement.schemaWriteOperations().indexDrop(new IndexDescriptor(labelId, propertyKeyId)) def createUniqueConstraint(labelId: Int, propertyKeyId: Int): IdempotentResult[UniquenessConstraint] = try { - IdempotentResult(statement.schemaWriteOperations().uniquenessConstraintCreate(labelId, propertyKeyId)) + IdempotentResult(statement.schemaWriteOperations().uniquePropertyConstraintCreate(labelId, propertyKeyId)) } catch { - case _: AlreadyConstrainedException => - val readOperations: ReadOperations = statement.readOperations() - val uniquenessConstraints = readOperations.constraintsGetForLabelAndPropertyKey(labelId, propertyKeyId) - IdempotentResult(IteratorUtil.single(uniquenessConstraints), wasCreated = false) + case existing: AlreadyConstrainedException => + IdempotentResult(existing.constraint().asInstanceOf[UniquenessConstraint], wasCreated = false) } def dropUniqueConstraint(labelId: Int, propertyKeyId: Int) = diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v2_3/TransactionBoundPlanContext.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v2_3/TransactionBoundPlanContext.scala index 18ba27d4be89d..be6b2d6c22f43 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v2_3/TransactionBoundPlanContext.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v2_3/TransactionBoundPlanContext.scala @@ -24,7 +24,7 @@ import org.neo4j.cypher.internal.compiler.v2_3.spi._ import org.neo4j.graphdb.GraphDatabaseService import org.neo4j.kernel.GraphDatabaseAPI import org.neo4j.kernel.api.Statement -import org.neo4j.kernel.api.constraints.UniquenessConstraint +import org.neo4j.kernel.api.constraints.PropertyConstraint import org.neo4j.kernel.api.exceptions.KernelException import org.neo4j.kernel.api.exceptions.schema.SchemaRuleNotFoundException import org.neo4j.kernel.api.index.{IndexDescriptor, InternalIndexState} @@ -57,7 +57,7 @@ class TransactionBoundPlanContext(initialStatement: Statement, val gdb: GraphDat case _ => None } - def getUniquenessConstraint(labelName: String, propertyKey: String): Option[UniquenessConstraint] = try { + def getUniquenessConstraint(labelName: String, propertyKey: String): Option[PropertyConstraint] = try { val labelId = statement.readOperations().labelGetForName(labelName) val propertyKeyId = statement.readOperations().propertyKeyGetForName(propertyKey) diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v2_3/TransactionBoundQueryContext.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v2_3/TransactionBoundQueryContext.scala index ed6a4270404c8..98c5715b9027a 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v2_3/TransactionBoundQueryContext.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v2_3/TransactionBoundQueryContext.scala @@ -30,10 +30,9 @@ import org.neo4j.cypher.internal.compiler.v2_3.{EntityNotFoundException, FailedI import org.neo4j.graphdb.DynamicRelationshipType._ import org.neo4j.graphdb._ import org.neo4j.graphdb.factory.GraphDatabaseSettings -import org.neo4j.helpers.collection.IteratorUtil import org.neo4j.kernel.GraphDatabaseAPI import org.neo4j.kernel.api._ -import org.neo4j.kernel.api.constraints.UniquenessConstraint +import org.neo4j.kernel.api.constraints.{MandatoryPropertyConstraint, UniquenessConstraint} import org.neo4j.kernel.api.exceptions.schema.{AlreadyConstrainedException, AlreadyIndexedException} import org.neo4j.kernel.api.index.{IndexDescriptor, InternalIndexState} import org.neo4j.kernel.configuration.Config @@ -297,22 +296,24 @@ final class TransactionBoundQueryContext(graph: GraphDatabaseAPI, statement.schemaWriteOperations().indexDrop(new IndexDescriptor(labelId, propertyKeyId)) def createUniqueConstraint(labelId: Int, propertyKeyId: Int): IdempotentResult[UniquenessConstraint] = try { - IdempotentResult(statement.schemaWriteOperations().uniquenessConstraintCreate(labelId, propertyKeyId)) + IdempotentResult(statement.schemaWriteOperations().uniquePropertyConstraintCreate(labelId, propertyKeyId)) } catch { - case _: AlreadyConstrainedException => - val readOperations: ReadOperations = statement.readOperations() - val uniquenessConstraints = readOperations.constraintsGetForLabelAndPropertyKey(labelId, propertyKeyId) - IdempotentResult(IteratorUtil.single(uniquenessConstraints), wasCreated = false) + case existing: AlreadyConstrainedException => + IdempotentResult(existing.constraint().asInstanceOf[UniquenessConstraint], wasCreated = false) } def dropUniqueConstraint(labelId: Int, propertyKeyId: Int) = statement.schemaWriteOperations().constraintDrop(new UniquenessConstraint(labelId, propertyKeyId)) - //TODO implement - def createMandatoryConstraint(labelId: Int, propertyKeyId: Int): IdempotentResult[UniquenessConstraint] = ??? + def createMandatoryConstraint(labelId: Int, propertyKeyId: Int): IdempotentResult[MandatoryPropertyConstraint] = try { + IdempotentResult(statement.schemaWriteOperations().mandatoryPropertyConstraintCreate(labelId, propertyKeyId)) + } catch { + case existing: AlreadyConstrainedException => + IdempotentResult(existing.constraint().asInstanceOf[MandatoryPropertyConstraint], wasCreated = false) + } - //TODO implement - def dropMandatoryConstraint(labelId: Int, propertyKeyId: Int) = ??? + def dropMandatoryConstraint(labelId: Int, propertyKeyId: Int) = + statement.schemaWriteOperations().constraintDrop(new MandatoryPropertyConstraint(labelId, propertyKeyId)) override def hasLocalFileAccess: Boolean = graph match { case db: GraphDatabaseAPI => db.getDependencyResolver.resolveDependency(classOf[Config]).get(GraphDatabaseSettings.allow_file_urls) diff --git a/community/cypher/cypher/src/test/scala/org/neo4j/cypher/ExecutionResultTest.scala b/community/cypher/cypher/src/test/scala/org/neo4j/cypher/ExecutionResultTest.scala index 7c41ad18390b6..45dfa78dd8e6d 100644 --- a/community/cypher/cypher/src/test/scala/org/neo4j/cypher/ExecutionResultTest.scala +++ b/community/cypher/cypher/src/test/scala/org/neo4j/cypher/ExecutionResultTest.scala @@ -132,8 +132,7 @@ class ExecutionResultTest extends ExecutionEngineFunSuite { assert(stats.uniqueConstraintsRemoved === 0) } - //TODO unignore when implemented spi - ignore("correct statistics for mandatory constraint added ") { + test("correct statistics for mandatory constraint added") { val result = execute("create constraint on (n:Person) assert n.name is not null") val stats = result.queryStatistics() @@ -141,8 +140,7 @@ class ExecutionResultTest extends ExecutionEngineFunSuite { assert(stats.mandatoryConstraintsRemoved === 0) } - //TODO unignore when implemented spi - ignore("correct statistics for mandatory constraint added twice") { + test("correct statistics for mandatory constraint added twice") { execute("create constraint on (n:Person) assert n.name is not null") val result = execute("create constraint on (n:Person) assert n.name is not null") val stats = result.queryStatistics() @@ -151,25 +149,12 @@ class ExecutionResultTest extends ExecutionEngineFunSuite { assert(stats.mandatoryConstraintsRemoved === 0) } - //TODO unignore when implemented spi - ignore("correct statistics for mandatory constraint dropped") { - execute("create constraint on (n:Person) assert n.name is not null") - val result = execute("drop constraint on (n:Person) assert n.name is not null") - val stats = result.queryStatistics() - - assert(stats.mandatoryConstraintsAdded === 0) - assert(stats.mandatoryConstraintsRemoved === 1) - } - - //TODO unignore when implemented spi - ignore("correct statistics for mandatory constraint dropped twice") { - execute("create constraint on (n:Person) assert n.name is not null") - execute("drop constraint on (n:Person) assert n.name is not null") - val result = execute("drop constraint on (n:Person) assert n.name is not null") - val stats = result.queryStatistics() - - assert(stats.mandatoryConstraintsAdded === 0) - assert(stats.mandatoryConstraintsRemoved === 0) - } + test("correct statistics for mandatory constraint dropped") { + execute("create constraint on (n:Person) assert n.name is not null") + val result = execute("drop constraint on (n:Person) assert n.name is not null") + val stats = result.queryStatistics() + assert(stats.mandatoryConstraintsAdded === 0) + assert(stats.mandatoryConstraintsRemoved === 1) + } } diff --git a/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiler/v2_3/LabelActionTest.scala b/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiler/v2_3/LabelActionTest.scala index 32f9b97921fc7..13ce60c6cae52 100644 --- a/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiler/v2_3/LabelActionTest.scala +++ b/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiler/v2_3/LabelActionTest.scala @@ -24,8 +24,8 @@ import org.neo4j.cypher.internal.compiler.v2_3.commands.expressions.Literal import org.neo4j.cypher.internal.compiler.v2_3.commands.values.{KeyToken, TokenType} import org.neo4j.cypher.internal.compiler.v2_3.commands.{LabelAction, LabelSetOp} import org.neo4j.cypher.internal.compiler.v2_3.spi.{IdempotentResult, LockingQueryContext, QueryContext} -import org.neo4j.graphdb.{Relationship, Direction, Node} -import org.neo4j.kernel.api.constraints.UniquenessConstraint +import org.neo4j.graphdb.{Direction, Node, Relationship} +import org.neo4j.kernel.api.constraints.{MandatoryPropertyConstraint, UniquenessConstraint} import org.neo4j.kernel.api.index.IndexDescriptor class LabelActionTest extends GraphDatabaseFunSuite { @@ -141,7 +141,7 @@ class SnitchingQueryContext extends QueryContext { def dropUniqueConstraint(labelId: Int, propertyKeyId: Int) {???} - def createMandatoryConstraint(labelId: Int, propertyKeyId: Int): IdempotentResult[UniquenessConstraint] = ??? + def createMandatoryConstraint(labelId: Int, propertyKeyId: Int): IdempotentResult[MandatoryPropertyConstraint] = ??? def dropMandatoryConstraint(labelId: Int, propertyKeyId: Int) {???} diff --git a/community/cypher/docs/cypher-docs/src/test/scala/org/neo4j/cypher/docgen/ConstraintsTest.scala b/community/cypher/docs/cypher-docs/src/test/scala/org/neo4j/cypher/docgen/ConstraintsTest.scala index e83343d80f78b..7e0ebde3910e6 100644 --- a/community/cypher/docs/cypher-docs/src/test/scala/org/neo4j/cypher/docgen/ConstraintsTest.scala +++ b/community/cypher/docs/cypher-docs/src/test/scala/org/neo4j/cypher/docgen/ConstraintsTest.scala @@ -21,7 +21,7 @@ package org.neo4j.cypher.docgen import org.junit.Test import org.neo4j.cypher.CypherExecutionException -import org.neo4j.kernel.api.constraints.UniquenessConstraint +import org.neo4j.kernel.api.constraints.PropertyConstraint import scala.collection.JavaConverters._ @@ -103,7 +103,7 @@ class ConstraintsTest extends DocumentingTestBase with SoftReset { assert(getConstraintIterator(labelName, propName).size === 1) } - private def getConstraintIterator(labelName: String, propName: String): Iterator[UniquenessConstraint] = { + private def getConstraintIterator(labelName: String, propName: String): Iterator[PropertyConstraint] = { val statement = db.statement val prop = statement.readOperations().propertyKeyGetForName(propName) diff --git a/community/kernel/src/main/java/org/neo4j/graphdb/schema/ConstraintCreator.java b/community/kernel/src/main/java/org/neo4j/graphdb/schema/ConstraintCreator.java index 19c7eac230d55..22f0e7d743a0f 100644 --- a/community/kernel/src/main/java/org/neo4j/graphdb/schema/ConstraintCreator.java +++ b/community/kernel/src/main/java/org/neo4j/graphdb/schema/ConstraintCreator.java @@ -46,6 +46,14 @@ public interface ConstraintCreator */ ConstraintCreator assertPropertyIsUnique( String propertyKey ); + /** + * Imposes an existence constraint for the given property, such that any node with the given label must have a + * value set for the given property key. + * + * @return a {@link ConstraintCreator} instance to be used for further interaction. + */ + ConstraintCreator assertPropertyExists( String propertyKey ); + /** * Creates a constraint with the details specified by the other methods in this interface. * diff --git a/community/kernel/src/main/java/org/neo4j/graphdb/schema/ConstraintType.java b/community/kernel/src/main/java/org/neo4j/graphdb/schema/ConstraintType.java index 6fac723c50c72..884fabb20e58b 100644 --- a/community/kernel/src/main/java/org/neo4j/graphdb/schema/ConstraintType.java +++ b/community/kernel/src/main/java/org/neo4j/graphdb/schema/ConstraintType.java @@ -26,5 +26,6 @@ public enum ConstraintType { UNIQUENESS, + MANDATORY, ; } \ No newline at end of file diff --git a/community/kernel/src/main/java/org/neo4j/graphdb/schema/Schema.java b/community/kernel/src/main/java/org/neo4j/graphdb/schema/Schema.java index df9341a30811b..c1f34fde08690 100644 --- a/community/kernel/src/main/java/org/neo4j/graphdb/schema/Schema.java +++ b/community/kernel/src/main/java/org/neo4j/graphdb/schema/Schema.java @@ -40,7 +40,7 @@ public interface Schema * population of an index, to tell when it is done populating and is online serving * requests. */ - public static enum IndexState + enum IndexState { ONLINE, POPULATING, diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/SchemaRead.java b/community/kernel/src/main/java/org/neo4j/kernel/api/SchemaRead.java index 1db6286eeae34..1ac9a3fd87260 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/SchemaRead.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/SchemaRead.java @@ -21,7 +21,7 @@ import java.util.Iterator; -import org.neo4j.kernel.api.constraints.UniquenessConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.exceptions.index.IndexNotFoundKernelException; import org.neo4j.kernel.api.exceptions.schema.SchemaRuleNotFoundException; import org.neo4j.kernel.api.index.IndexDescriptor; @@ -63,22 +63,22 @@ IndexDescriptor uniqueIndexGetForLabelAndPropertyKey( int labelId, int propertyK /** * Get all constraints applicable to label and propertyKey. There are only {@link - * org.neo4j.kernel.api.constraints.UniquenessConstraint} + * PropertyConstraint} * for the time being. */ - Iterator constraintsGetForLabelAndPropertyKey( int labelId, int propertyKeyId ); + Iterator constraintsGetForLabelAndPropertyKey( int labelId, int propertyKeyId ); /** - * Get all constraints applicable to label. There are only {@link UniquenessConstraint} + * Get all constraints applicable to label. There are only {@link PropertyConstraint} * for the time being. */ - Iterator constraintsGetForLabel( int labelId ); + Iterator constraintsGetForLabel( int labelId ); /** - * Get all constraints. There are only {@link UniquenessConstraint} + * Get all constraints. There are only {@link PropertyConstraint} * for the time being. */ - Iterator constraintsGetAll(); + Iterator constraintsGetAll(); /** * Get the owning constraint for a constraint index. Returns null if the index does not have an owning constraint. diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/SchemaWrite.java b/community/kernel/src/main/java/org/neo4j/kernel/api/SchemaWrite.java index 82a4bf5609401..cbfcc76ceeae2 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/SchemaWrite.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/SchemaWrite.java @@ -19,6 +19,8 @@ */ package org.neo4j.kernel.api; +import org.neo4j.kernel.api.constraints.MandatoryPropertyConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.constraints.UniquenessConstraint; import org.neo4j.kernel.api.exceptions.schema.AddIndexFailureException; import org.neo4j.kernel.api.exceptions.schema.AlreadyConstrainedException; @@ -40,10 +42,13 @@ IndexDescriptor indexCreate( int labelId, int propertyKeyId ) /** Drops a {@link IndexDescriptor} from the database */ void indexDrop( IndexDescriptor descriptor ) throws DropIndexFailureException; - UniquenessConstraint uniquenessConstraintCreate( int labelId, int propertyKeyId ) + UniquenessConstraint uniquePropertyConstraintCreate( int labelId, int propertyKeyId ) throws CreateConstraintFailureException, AlreadyConstrainedException, AlreadyIndexedException; - void constraintDrop( UniquenessConstraint constraint ) throws DropConstraintFailureException; + MandatoryPropertyConstraint mandatoryPropertyConstraintCreate( int labelId, int propertyKeyId ) + throws CreateConstraintFailureException, AlreadyConstrainedException; + + void constraintDrop( PropertyConstraint constraint ) throws DropConstraintFailureException; /** * This should not be used, it is exposed to allow an external job to clean up constraint indexes. diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/constraints/MandatoryPropertyConstraint.java b/community/kernel/src/main/java/org/neo4j/kernel/api/constraints/MandatoryPropertyConstraint.java new file mode 100644 index 0000000000000..3cd88c322e55d --- /dev/null +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/constraints/MandatoryPropertyConstraint.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2002-2015 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.neo4j.kernel.api.constraints; + +import org.neo4j.graphdb.schema.ConstraintType; + +public class MandatoryPropertyConstraint extends PropertyConstraint +{ + public MandatoryPropertyConstraint( int labelId, int propertyKeyId ) + { + super( labelId, propertyKeyId ); + } + + @Override + public void added( ChangeVisitor visitor ) + { + visitor.visitAddedMandatoryPropertyConstraint( this ); + } + + @Override + public void removed( ChangeVisitor visitor ) + { + visitor.visitRemovedMandatoryPropertyConstraint( this ); + } + + @Override + String constraintString() + { + return "NOT NULL"; + } + + @Override + public ConstraintType type() + { + return ConstraintType.MANDATORY; + } +} diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/constraints/PropertyConstraint.java b/community/kernel/src/main/java/org/neo4j/kernel/api/constraints/PropertyConstraint.java new file mode 100644 index 0000000000000..6f4217339d8f3 --- /dev/null +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/constraints/PropertyConstraint.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2002-2015 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.kernel.api.constraints; + +import org.neo4j.graphdb.schema.ConstraintType; +import org.neo4j.kernel.api.TokenNameLookup; + +public abstract class PropertyConstraint +{ + public interface ChangeVisitor + { + void visitAddedUniquePropertyConstraint( UniquenessConstraint constraint ); + + void visitRemovedUniquePropertyConstraint( UniquenessConstraint constraint ); + + void visitAddedMandatoryPropertyConstraint( MandatoryPropertyConstraint constraint ); + + void visitRemovedMandatoryPropertyConstraint( MandatoryPropertyConstraint constraint ); + } + + private final int labelId; + private final int propertyKeyId; + + public PropertyConstraint( int labelId, int propertyKeyId ) + { + this.labelId = labelId; + this.propertyKeyId = propertyKeyId; + } + + public abstract void added( ChangeVisitor visitor ); + + public abstract void removed( ChangeVisitor visitor ); + + @Override + public boolean equals( Object obj ) + { + if ( this == obj ) + { + return true; + } + if ( obj != null && getClass() == obj.getClass() ) + { + PropertyConstraint that = (PropertyConstraint) obj; + return this.equals( type(), that.labelId, that.propertyKeyId ); + } + return false; + } + + @Override + public int hashCode() + { + int result = labelId; + result = 31 * result + propertyKeyId; + return result; + } + + public int label() + { + return labelId; + } + + public int propertyKeyId() + { + return propertyKeyId; + } + + public boolean equals( ConstraintType type, int labelId, int propertyKeyId ) + { + return this.labelId == labelId && this.propertyKeyId == propertyKeyId && type() == type; + } + + @Override + public String toString() + { + return String.format( "CONSTRAINT ON ( n:label[%s] ) ASSERT n.property[%s] IS %s", + labelId, propertyKeyId, constraintString() ); + } + + public String userDescription( TokenNameLookup tokenNameLookup ) + { + String labelName = tokenNameLookup.labelGetName( labelId ); + String boundIdentifier = labelName.toLowerCase(); + return String.format( "CONSTRAINT ON ( %s:%s ) ASSERT %s.%s IS %s", boundIdentifier, labelName, + boundIdentifier, tokenNameLookup.propertyKeyGetName( propertyKeyId ), constraintString() ); + } + + abstract String constraintString(); + + public abstract ConstraintType type(); +} diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/constraints/UniquenessConstraint.java b/community/kernel/src/main/java/org/neo4j/kernel/api/constraints/UniquenessConstraint.java index d484bfcc85ad4..4fde8bc5255c8 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/constraints/UniquenessConstraint.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/constraints/UniquenessConstraint.java @@ -17,72 +17,39 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + package org.neo4j.kernel.api.constraints; -import org.neo4j.kernel.api.TokenNameLookup; +import org.neo4j.graphdb.schema.ConstraintType; -// TODO: When we add other types of constraints, we will either want to create a hierarchy, or... -// TODO: ...rename this to "Constraint" and add a "type" enum (or something like that). -public class UniquenessConstraint +public class UniquenessConstraint extends PropertyConstraint { - private final int labelId; - private final int propertyKeyId; - public UniquenessConstraint( int labelId, int propertyKeyId ) { - this.labelId = labelId; - this.propertyKeyId = propertyKeyId; + super( labelId, propertyKeyId ); } @Override - public boolean equals( Object obj ) + public void added( ChangeVisitor visitor ) { - if ( this == obj ) - { - return true; - } - if ( obj != null && getClass() == obj.getClass() ) - { - UniquenessConstraint that = (UniquenessConstraint) obj; - return this.equals( that.labelId, that.propertyKeyId ); - } - return false; + visitor.visitAddedUniquePropertyConstraint( this ); } @Override - public int hashCode() - { - int result = labelId; - result = 31 * result + propertyKeyId; - return result; - } - - public int label() - { - return labelId; - } - - public int propertyKeyId() - { - return propertyKeyId; - } - - public boolean equals( int labelId, int propertyKeyId ) + public void removed( ChangeVisitor visitor ) { - return this.labelId == labelId && this.propertyKeyId == propertyKeyId; + visitor.visitRemovedUniquePropertyConstraint( this ); } @Override - public String toString() + String constraintString() { - return String.format( "CONSTRAINT ON ( n:label[%s] ) ASSERT n.property[%s] IS UNIQUE", labelId, propertyKeyId ); + return "UNIQUE"; } - public String userDescription( TokenNameLookup tokenNameLookup ) + @Override + public ConstraintType type() { - String labelName = tokenNameLookup.labelGetName( labelId ); - String boundIdentifier = labelName.toLowerCase(); - return String.format( "CONSTRAINT ON ( %s:%s ) ASSERT %s.%s IS UNIQUE", boundIdentifier, labelName, - boundIdentifier, tokenNameLookup.propertyKeyGetName( propertyKeyId ) ); + return ConstraintType.UNIQUENESS; } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/AlreadyConstrainedException.java b/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/AlreadyConstrainedException.java index f17b601881a92..624b1d0976d59 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/AlreadyConstrainedException.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/AlreadyConstrainedException.java @@ -20,7 +20,7 @@ package org.neo4j.kernel.api.exceptions.schema; import org.neo4j.kernel.api.TokenNameLookup; -import org.neo4j.kernel.api.constraints.UniquenessConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.exceptions.Status; import static java.lang.String.format; @@ -33,17 +33,22 @@ public class AlreadyConstrainedException extends SchemaKernelException private static final String INDEX_CONTEXT_FORMAT = "Label '%s' and property '%s' have a unique constraint defined on them, so an index is " + "already created that matches this."; - private final UniquenessConstraint constraint; + private final PropertyConstraint constraint; private final OperationContext context; - public AlreadyConstrainedException( UniquenessConstraint constraint, OperationContext context ) + public AlreadyConstrainedException( PropertyConstraint constraint, OperationContext context ) { super( Status.Schema.ConstraintAlreadyExists, constructUserMessage( context, null, constraint ) ); this.constraint = constraint; this.context = context; } - private static String constructUserMessage( OperationContext context, TokenNameLookup tokenNameLookup, UniquenessConstraint constraint ) + public PropertyConstraint constraint() + { + return constraint; + } + + private static String constructUserMessage( OperationContext context, TokenNameLookup tokenNameLookup, PropertyConstraint constraint ) { switch ( context ) { diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/ConstraintVerificationFailedKernelException.java b/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/ConstraintVerificationFailedKernelException.java index d160a809e40d2..352b59e49a763 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/ConstraintVerificationFailedKernelException.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/ConstraintVerificationFailedKernelException.java @@ -23,7 +23,7 @@ import java.util.Set; import org.neo4j.kernel.api.TokenNameLookup; -import org.neo4j.kernel.api.constraints.UniquenessConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.exceptions.KernelException; import org.neo4j.kernel.api.exceptions.Status; import org.neo4j.kernel.api.index.IndexEntryConflictException; @@ -36,7 +36,7 @@ */ public class ConstraintVerificationFailedKernelException extends KernelException { - private final UniquenessConstraint constraint; + private final PropertyConstraint constraint; public static final class Evidence { @@ -71,14 +71,14 @@ public String toString() private final Set evidence; - public ConstraintVerificationFailedKernelException( UniquenessConstraint constraint, Set evidence ) + public ConstraintVerificationFailedKernelException( PropertyConstraint constraint, Set evidence ) { super( Status.Schema.ConstraintVerificationFailure, "Existing data does not satisfy %s.", constraint ); this.constraint = constraint; this.evidence = evidence; } - public ConstraintVerificationFailedKernelException( UniquenessConstraint constraint, Throwable failure ) + public ConstraintVerificationFailedKernelException( PropertyConstraint constraint, Throwable failure ) { super( Status.Schema.ConstraintVerificationFailure, failure, "Failed to verify constraint %s: %s", constraint, failure.getMessage() ); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/CreateConstraintFailureException.java b/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/CreateConstraintFailureException.java index 6bcea1e3ffcdf..88f89ef01dc13 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/CreateConstraintFailureException.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/CreateConstraintFailureException.java @@ -19,23 +19,23 @@ */ package org.neo4j.kernel.api.exceptions.schema; -import org.neo4j.kernel.api.constraints.UniquenessConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.exceptions.KernelException; import org.neo4j.kernel.api.TokenNameLookup; import org.neo4j.kernel.api.exceptions.Status; public class CreateConstraintFailureException extends SchemaKernelException { - private final UniquenessConstraint constraint; + private final PropertyConstraint constraint; - public CreateConstraintFailureException( UniquenessConstraint constraint, Throwable cause ) + public CreateConstraintFailureException( PropertyConstraint constraint, Throwable cause ) { super( Status.Schema.ConstraintCreationFailure, cause, "Unable to create constraint %s: %s", constraint, cause.getMessage() ); this.constraint = constraint; } - public UniquenessConstraint constraint() + public PropertyConstraint constraint() { return constraint; } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/DropConstraintFailureException.java b/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/DropConstraintFailureException.java index 349b26c3d29aa..d725e94a7ef77 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/DropConstraintFailureException.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/DropConstraintFailureException.java @@ -20,21 +20,21 @@ package org.neo4j.kernel.api.exceptions.schema; import org.neo4j.kernel.api.TokenNameLookup; -import org.neo4j.kernel.api.constraints.UniquenessConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.exceptions.KernelException; import org.neo4j.kernel.api.exceptions.Status; public class DropConstraintFailureException extends SchemaKernelException { - private final UniquenessConstraint constraint; + private final PropertyConstraint constraint; - public DropConstraintFailureException( UniquenessConstraint constraint, Throwable cause ) + public DropConstraintFailureException( PropertyConstraint constraint, Throwable cause ) { super( Status.Schema.ConstraintDropFailure, cause, "Unable to drop constraint %s: %s", constraint, cause.getMessage() ); this.constraint = constraint; } - public UniquenessConstraint constraint() + public PropertyConstraint constraint() { return constraint; } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/NoSuchConstraintException.java b/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/NoSuchConstraintException.java index 493bab9e490e0..df3098ae961a5 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/NoSuchConstraintException.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/exceptions/schema/NoSuchConstraintException.java @@ -20,17 +20,17 @@ package org.neo4j.kernel.api.exceptions.schema; import org.neo4j.kernel.api.TokenNameLookup; -import org.neo4j.kernel.api.constraints.UniquenessConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.exceptions.Status; import static java.lang.String.format; public class NoSuchConstraintException extends SchemaKernelException { - private final UniquenessConstraint constraint; + private final PropertyConstraint constraint; private final static String message = "No such constraint %s."; - public NoSuchConstraintException( UniquenessConstraint constraint ) + public NoSuchConstraintException( PropertyConstraint constraint ) { super( Status.Schema.NoSuchConstraint, format( message, constraint ) ); this.constraint = constraint; diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/ReadableTxState.java b/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/ReadableTxState.java index 17671cb6b9cac..b986386fd3069 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/ReadableTxState.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/ReadableTxState.java @@ -24,6 +24,7 @@ import org.neo4j.collection.primitive.PrimitiveIntIterator; import org.neo4j.collection.primitive.PrimitiveLongIterator; import org.neo4j.graphdb.Direction; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.constraints.UniquenessConstraint; import org.neo4j.kernel.api.cursor.LabelCursor; import org.neo4j.kernel.api.cursor.NodeCursor; @@ -142,11 +143,11 @@ RelationshipIterator augmentRelationships( long nodeId, Direction direction, int Iterable constraintIndexesCreatedInTx(); - ReadableDiffSets constraintsChanges(); + ReadableDiffSets constraintsChanges(); - ReadableDiffSets constraintsChangesForLabel( int labelId ); + ReadableDiffSets constraintsChangesForLabel( int labelId ); - ReadableDiffSets constraintsChangesForLabelAndProperty( int labelId, int propertyKey ); + ReadableDiffSets constraintsChangesForLabelAndProperty( int labelId, int propertyKey ); Long indexCreatedForConstraint( UniquenessConstraint constraint ); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/TransactionState.java b/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/TransactionState.java index 9a5a015e8ad91..c03967dcdd362 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/TransactionState.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/TransactionState.java @@ -21,6 +21,8 @@ import java.util.Map; +import org.neo4j.kernel.api.constraints.MandatoryPropertyConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.constraints.UniquenessConstraint; import org.neo4j.kernel.api.index.IndexDescriptor; import org.neo4j.kernel.api.properties.DefinedProperty; @@ -85,9 +87,11 @@ void relationshipDoReplaceProperty( long relationshipId, void constraintDoAdd( UniquenessConstraint constraint, long indexId ); - void constraintDoDrop( UniquenessConstraint constraint ); + void constraintDoAdd( MandatoryPropertyConstraint constraint ); - boolean constraintDoUnRemove( UniquenessConstraint constraint ); + void constraintDoDrop( PropertyConstraint constraint ); + + boolean constraintDoUnRemove( PropertyConstraint constraint ); boolean constraintIndexDoUnRemove( IndexDescriptor index ); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/TxStateVisitor.java b/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/TxStateVisitor.java index ceb38093e7d6d..0884862a1a050 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/TxStateVisitor.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/TxStateVisitor.java @@ -23,6 +23,7 @@ import java.util.Map; import java.util.Set; +import org.neo4j.kernel.api.constraints.MandatoryPropertyConstraint; import org.neo4j.kernel.api.constraints.UniquenessConstraint; import org.neo4j.kernel.api.index.IndexDescriptor; import org.neo4j.kernel.api.properties.DefinedProperty; @@ -59,9 +60,13 @@ void visitGraphPropertyChanges( Iterator added, Iterator constraints = schemaReadOperations.constraintsGetForLabel( state, labelId ); + Iterator constraints = uniquePropertyConstraints( schemaReadOperations.constraintsGetForLabel( state, labelId ) ); while ( constraints.hasNext() ) { - UniquenessConstraint constraint = constraints.next(); + PropertyConstraint constraint = constraints.next(); int propertyKeyId = constraint.propertyKeyId(); Property property = entityReadOperations.nodeGetProperty( state, nodeId, propertyKeyId ); if ( property.isDefined() ) @@ -90,8 +93,8 @@ public Property nodeSetProperty( KernelStatement state, long nodeId, DefinedProp { int labelId = labelIds.next(); int propertyKeyId = property.propertyKeyId(); - Iterator constraintIterator = - schemaReadOperations.constraintsGetForLabelAndPropertyKey( state, labelId, propertyKeyId ); + Iterator constraintIterator = + uniquePropertyConstraints( schemaReadOperations.constraintsGetForLabelAndPropertyKey( state, labelId, propertyKeyId ) ); if ( constraintIterator.hasNext() ) { validateNoExistingNodeWithLabelAndProperty( state, labelId, property, nodeId ); @@ -136,6 +139,17 @@ private void assertIndexOnline( KernelStatement state, IndexDescriptor indexDesc throw new IndexBrokenKernelException( schemaReadOperations.indexGetFailure( state, indexDescriptor ) ); } } + private Iterator uniquePropertyConstraints( Iterator propertyConstraintIterator) + { + return new FilteringIterator<>( propertyConstraintIterator, new Predicate() + { + @Override + public boolean test( PropertyConstraint constraint ) + { + return constraint instanceof UniquenessConstraint; + } + } ); + } // Simply delegate the rest of the invocations diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/DataIntegrityValidatingStatementOperations.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/DataIntegrityValidatingStatementOperations.java index 91ae37cc36371..c26e7e5f18d4f 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/DataIntegrityValidatingStatementOperations.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/DataIntegrityValidatingStatementOperations.java @@ -22,6 +22,8 @@ import java.util.Iterator; import org.neo4j.kernel.api.Statement; +import org.neo4j.kernel.api.constraints.MandatoryPropertyConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.constraints.UniquenessConstraint; import org.neo4j.kernel.api.exceptions.schema.AddIndexFailureException; import org.neo4j.kernel.api.exceptions.schema.AlreadyConstrainedException; @@ -132,24 +134,46 @@ public void uniqueIndexDrop( KernelStatement state, IndexDescriptor descriptor ) } @Override - public UniquenessConstraint uniquenessConstraintCreate( KernelStatement state, int labelId, int propertyKey ) + public UniquenessConstraint uniquePropertyConstraintCreate( KernelStatement state, int labelId, int propertyKey ) throws AlreadyConstrainedException, CreateConstraintFailureException, AlreadyIndexedException { - Iterator constraints = schemaReadDelegate.constraintsGetForLabelAndPropertyKey( + Iterator constraints = schemaReadDelegate.constraintsGetForLabelAndPropertyKey( state, labelId, propertyKey ); - if ( constraints.hasNext() ) + while ( constraints.hasNext() ) { - throw new AlreadyConstrainedException( constraints.next(), OperationContext.CONSTRAINT_CREATION ); + PropertyConstraint constraint = constraints.next(); + if ( constraint instanceof UniquenessConstraint ) + { + throw new AlreadyConstrainedException( constraint, OperationContext.CONSTRAINT_CREATION ); + } } // It is not allowed to create uniqueness constraints on indexed label/property pairs checkIndexExistence( state, OperationContext.CONSTRAINT_CREATION, labelId, propertyKey ); - return schemaWriteDelegate.uniquenessConstraintCreate( state, labelId, propertyKey ); + return schemaWriteDelegate.uniquePropertyConstraintCreate( state, labelId, propertyKey ); + } + + @Override + public MandatoryPropertyConstraint mandatoryPropertyConstraintCreate( KernelStatement state, int labelId, + int propertyKey ) throws AlreadyConstrainedException, CreateConstraintFailureException + { + Iterator constraints = schemaReadDelegate.constraintsGetForLabelAndPropertyKey( + state, labelId, propertyKey ); + while ( constraints.hasNext() ) + { + PropertyConstraint constraint = constraints.next(); + if ( constraint instanceof MandatoryPropertyConstraint ) + { + throw new AlreadyConstrainedException( constraint, OperationContext.CONSTRAINT_CREATION ); + } + } + + return schemaWriteDelegate.mandatoryPropertyConstraintCreate( state, labelId, propertyKey ); } @Override - public void constraintDrop( KernelStatement state, UniquenessConstraint constraint ) throws DropConstraintFailureException + public void constraintDrop( KernelStatement state, PropertyConstraint constraint ) throws DropConstraintFailureException { try { @@ -219,12 +243,12 @@ private void assertIndexExists( IndexDescriptor descriptor, Iterator constraints ) + private void assertConstraintExists( PropertyConstraint constraint, Iterator constraints ) throws NoSuchConstraintException { - for ( UniquenessConstraint existing : loop( constraints ) ) + for ( PropertyConstraint existing : loop( constraints ) ) { - if ( existing.equals( constraint.label(), constraint.propertyKeyId() ) ) + if ( existing.equals( constraint.type(), constraint.label(), constraint.propertyKeyId() ) ) { return; } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelTransactionImplementation.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelTransactionImplementation.java index ef873678d3f64..c0bac30391d68 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelTransactionImplementation.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelTransactionImplementation.java @@ -31,6 +31,7 @@ import org.neo4j.helpers.ThisShouldNotHappenError; import org.neo4j.kernel.api.KernelTransaction; import org.neo4j.kernel.api.Statement; +import org.neo4j.kernel.api.constraints.MandatoryPropertyConstraint; import org.neo4j.kernel.api.constraints.UniquenessConstraint; import org.neo4j.kernel.api.exceptions.EntityNotFoundException; import org.neo4j.kernel.api.exceptions.InvalidTransactionTypeKernelException; @@ -55,9 +56,10 @@ import org.neo4j.kernel.impl.index.IndexEntityType; import org.neo4j.kernel.impl.locking.LockGroup; import org.neo4j.kernel.impl.locking.Locks; +import org.neo4j.kernel.impl.store.MandatoryPropertyConstraintRule; import org.neo4j.kernel.impl.store.NeoStore; import org.neo4j.kernel.impl.store.SchemaStorage; -import org.neo4j.kernel.impl.store.UniquenessConstraintRule; +import org.neo4j.kernel.impl.store.UniquePropertyConstraintRule; import org.neo4j.kernel.impl.store.record.IndexRule; import org.neo4j.kernel.impl.transaction.TransactionHeaderInformationFactory; import org.neo4j.kernel.impl.transaction.TransactionMonitor; @@ -834,7 +836,7 @@ public void visitRemovedIndex( IndexDescriptor element, boolean isConstraintInde } @Override - public void visitAddedConstraint( UniquenessConstraint element ) + public void visitAddedUniquePropertyConstraint( UniquenessConstraint element ) { clearState = true; long constraintId = schemaStorage.newRuleId(); @@ -842,18 +844,18 @@ public void visitAddedConstraint( UniquenessConstraint element ) element.label(), element.propertyKeyId(), SchemaStorage.IndexRuleKind.CONSTRAINT ); - recordState.createSchemaRule( UniquenessConstraintRule.uniquenessConstraintRule( + recordState.createSchemaRule( UniquePropertyConstraintRule.uniquenessConstraintRule( constraintId, element.label(), element.propertyKeyId(), indexRule.getId() ) ); recordState.setConstraintIndexOwner( indexRule, constraintId ); } @Override - public void visitRemovedConstraint( UniquenessConstraint element ) + public void visitRemovedUniquePropertyConstraint( UniquenessConstraint element ) { try { clearState = true; - UniquenessConstraintRule rule = schemaStorage + UniquePropertyConstraintRule rule = schemaStorage .uniquenessConstraint( element.label(), element.propertyKeyId() ); recordState.dropSchemaRule( rule ); } @@ -868,6 +870,32 @@ public void visitRemovedConstraint( UniquenessConstraint element ) visitRemovedIndex( new IndexDescriptor( element.label(), element.propertyKeyId() ), true ); } + @Override + public void visitAddedMandatoryPropertyConstraint( MandatoryPropertyConstraint element ) + { + clearState = true; + recordState.createSchemaRule( MandatoryPropertyConstraintRule.mandatoryPropertyConstraintRule( + schemaStorage.newRuleId(), element.label(), element.propertyKeyId() ) ); + } + + @Override + public void visitRemovedMandatoryPropertyConstraint( MandatoryPropertyConstraint element ) + { + try + { + clearState = true; + recordState.dropSchemaRule( + schemaStorage.mandatoryPropertyConstraint( element.label(), element.propertyKeyId() ) ); + } + catch ( SchemaRuleNotFoundException e ) + { + throw new ThisShouldNotHappenError( + "Tobias Lindaaker", + "Constraint to be removed should exist, since its existence should " + + "have been validated earlier and the schema should have been locked." ); + } + } + @Override public void visitCreatedLabelToken( String name, int id ) { diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/LockingStatementOperations.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/LockingStatementOperations.java index 781da14d58035..6db003915f7ec 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/LockingStatementOperations.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/LockingStatementOperations.java @@ -23,6 +23,8 @@ import org.neo4j.function.Function; import org.neo4j.kernel.api.Statement; +import org.neo4j.kernel.api.constraints.MandatoryPropertyConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.constraints.UniquenessConstraint; import org.neo4j.kernel.api.exceptions.EntityNotFoundException; import org.neo4j.kernel.api.exceptions.index.IndexNotFoundKernelException; @@ -274,36 +276,44 @@ public void visit( long relId, int type, long startNode, long endNode ) } @Override - public UniquenessConstraint uniquenessConstraintCreate( KernelStatement state, int labelId, int propertyKeyId ) + public UniquenessConstraint uniquePropertyConstraintCreate( KernelStatement state, int labelId, int propertyKeyId ) throws CreateConstraintFailureException, AlreadyConstrainedException, AlreadyIndexedException { state.locks().acquireExclusive( ResourceTypes.SCHEMA, schemaResource() ); - return schemaWriteDelegate.uniquenessConstraintCreate( state, labelId, propertyKeyId ); + return schemaWriteDelegate.uniquePropertyConstraintCreate( state, labelId, propertyKeyId ); } @Override - public Iterator constraintsGetForLabelAndPropertyKey( KernelStatement state, int labelId, int propertyKeyId ) + public MandatoryPropertyConstraint mandatoryPropertyConstraintCreate( KernelStatement state, int labelId, + int propertyKeyId ) throws AlreadyConstrainedException, CreateConstraintFailureException + { + state.locks().acquireExclusive( ResourceTypes.SCHEMA, schemaResource() ); + return schemaWriteDelegate.mandatoryPropertyConstraintCreate( state, labelId, propertyKeyId ); + } + + @Override + public Iterator constraintsGetForLabelAndPropertyKey( KernelStatement state, int labelId, int propertyKeyId ) { state.locks().acquireShared( ResourceTypes.SCHEMA, schemaResource() ); return schemaReadDelegate.constraintsGetForLabelAndPropertyKey( state, labelId, propertyKeyId ); } @Override - public Iterator constraintsGetForLabel( KernelStatement state, int labelId ) + public Iterator constraintsGetForLabel( KernelStatement state, int labelId ) { state.locks().acquireShared( ResourceTypes.SCHEMA, schemaResource() ); return schemaReadDelegate.constraintsGetForLabel( state, labelId ); } @Override - public Iterator constraintsGetAll( KernelStatement state ) + public Iterator constraintsGetAll( KernelStatement state ) { state.locks().acquireShared( ResourceTypes.SCHEMA, schemaResource() ); return schemaReadDelegate.constraintsGetAll( state ); } @Override - public void constraintDrop( KernelStatement state, UniquenessConstraint constraint ) + public void constraintDrop( KernelStatement state, PropertyConstraint constraint ) throws DropConstraintFailureException { state.locks().acquireExclusive( ResourceTypes.SCHEMA, schemaResource() ); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/OperationsFacade.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/OperationsFacade.java index ff6887f6f734a..51d474c5cc777 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/OperationsFacade.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/OperationsFacade.java @@ -32,6 +32,8 @@ import org.neo4j.kernel.api.ReadOperations; import org.neo4j.kernel.api.SchemaWriteOperations; import org.neo4j.kernel.api.StatementConstants; +import org.neo4j.kernel.api.constraints.MandatoryPropertyConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.constraints.UniquenessConstraint; import org.neo4j.kernel.api.cursor.NodeCursor; import org.neo4j.kernel.api.cursor.RelationshipCursor; @@ -518,21 +520,21 @@ public String indexGetFailure( IndexDescriptor descriptor ) throws IndexNotFound } @Override - public Iterator constraintsGetForLabelAndPropertyKey( int labelId, int propertyKeyId ) + public Iterator constraintsGetForLabelAndPropertyKey( int labelId, int propertyKeyId ) { statement.assertOpen(); return schemaRead().constraintsGetForLabelAndPropertyKey( statement, labelId, propertyKeyId ); } @Override - public Iterator constraintsGetForLabel( int labelId ) + public Iterator constraintsGetForLabel( int labelId ) { statement.assertOpen(); return schemaRead().constraintsGetForLabel( statement, labelId ); } @Override - public Iterator constraintsGetAll() + public Iterator constraintsGetAll() { statement.assertOpen(); return schemaRead().constraintsGetAll( statement ); @@ -772,15 +774,23 @@ public void indexDrop( IndexDescriptor descriptor ) throws DropIndexFailureExcep } @Override - public UniquenessConstraint uniquenessConstraintCreate( int labelId, int propertyKeyId ) + public UniquenessConstraint uniquePropertyConstraintCreate( int labelId, int propertyKeyId ) throws CreateConstraintFailureException, AlreadyConstrainedException, AlreadyIndexedException { statement.assertOpen(); - return schemaWrite().uniquenessConstraintCreate( statement, labelId, propertyKeyId ); + return schemaWrite().uniquePropertyConstraintCreate( statement, labelId, propertyKeyId ); } @Override - public void constraintDrop( UniquenessConstraint constraint ) throws DropConstraintFailureException + public MandatoryPropertyConstraint mandatoryPropertyConstraintCreate( int labelId, int propertyKeyId ) + throws CreateConstraintFailureException, AlreadyConstrainedException + { + statement.assertOpen(); + return schemaWrite().mandatoryPropertyConstraintCreate( statement, labelId, propertyKeyId ); + } + + @Override + public void constraintDrop( PropertyConstraint constraint ) throws DropConstraintFailureException { statement.assertOpen(); schemaWrite().constraintDrop( statement, constraint ); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/StateHandlingStatementOperations.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/StateHandlingStatementOperations.java index e64e6484c4540..80befeeb8d53f 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/StateHandlingStatementOperations.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/StateHandlingStatementOperations.java @@ -30,10 +30,13 @@ import org.neo4j.collection.primitive.PrimitiveLongIterator; import org.neo4j.function.Predicate; import org.neo4j.graphdb.Direction; +import org.neo4j.graphdb.schema.ConstraintType; import org.neo4j.kernel.api.EntityType; import org.neo4j.kernel.api.LegacyIndex; import org.neo4j.kernel.api.LegacyIndexHits; import org.neo4j.kernel.api.Statement; +import org.neo4j.kernel.api.constraints.MandatoryPropertyConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.constraints.UniquenessConstraint; import org.neo4j.kernel.api.cursor.LabelCursor; import org.neo4j.kernel.api.cursor.NodeCursor; @@ -389,6 +392,7 @@ public PrimitiveLongIterator nodesGetAll( KernelStatement state ) } @Override + public RelationshipIterator relationshipsGetAll( KernelStatement state ) { return state.txState().augmentRelationshipsGetAll( storeLayer.relationshipsGetAll() ); @@ -465,7 +469,7 @@ public void uniqueIndexDrop( KernelStatement state, IndexDescriptor descriptor ) } @Override - public UniquenessConstraint uniquenessConstraintCreate( KernelStatement state, int labelId, int propertyKeyId ) + public UniquenessConstraint uniquePropertyConstraintCreate( KernelStatement state, int labelId, int propertyKeyId ) throws CreateConstraintFailureException { UniquenessConstraint constraint = new UniquenessConstraint( labelId, propertyKeyId ); @@ -482,10 +486,10 @@ public UniquenessConstraint uniquenessConstraintCreate( KernelStatement state, i } else // *CREATE* { // create from scratch - for ( Iterator it = storeLayer.constraintsGetForLabelAndPropertyKey( + for ( Iterator it = storeLayer.constraintsGetForLabelAndPropertyKey( labelId, propertyKeyId ); it.hasNext(); ) { - if ( it.next().equals( labelId, propertyKeyId ) ) + if ( it.next().equals( ConstraintType.UNIQUENESS, labelId, propertyKeyId ) ) { return constraint; } @@ -504,7 +508,17 @@ public UniquenessConstraint uniquenessConstraintCreate( KernelStatement state, i } @Override - public Iterator constraintsGetForLabelAndPropertyKey( KernelStatement state, + public MandatoryPropertyConstraint mandatoryPropertyConstraintCreate( KernelStatement state, int labelId, + int propertyKeyId ) throws CreateConstraintFailureException + { + MandatoryPropertyConstraint constraint = new MandatoryPropertyConstraint( labelId, propertyKeyId ); + state.txState().constraintDoAdd( constraint ); + // TODO: validate constraint for existing data + return constraint; + } + + @Override + public Iterator constraintsGetForLabelAndPropertyKey( KernelStatement state, int labelId, int propertyKeyId ) { return applyConstraintsDiff( state, storeLayer.constraintsGetForLabelAndPropertyKey( @@ -512,20 +526,21 @@ public Iterator constraintsGetForLabelAndPropertyKey( Kern } @Override - public Iterator constraintsGetForLabel( KernelStatement state, int labelId ) + public Iterator constraintsGetForLabel( KernelStatement state, int labelId ) { return applyConstraintsDiff( state, storeLayer.constraintsGetForLabel( labelId ), labelId ); } @Override - public Iterator constraintsGetAll( KernelStatement state ) + public Iterator constraintsGetAll( KernelStatement state ) { return applyConstraintsDiff( state, storeLayer.constraintsGetAll() ); } - private Iterator applyConstraintsDiff( KernelStatement state, - Iterator constraints, - int labelId, int propertyKeyId ) + + private Iterator applyConstraintsDiff( KernelStatement state, + Iterator constraints, + int labelId, int propertyKeyId ) { if ( state.hasTxStateWithChanges() ) { @@ -534,9 +549,9 @@ private Iterator applyConstraintsDiff( KernelStatement sta return constraints; } - private Iterator applyConstraintsDiff( KernelStatement state, - Iterator constraints, - int labelId ) + private Iterator applyConstraintsDiff( KernelStatement state, + Iterator constraints, + int labelId ) { if ( state.hasTxStateWithChanges() ) { @@ -545,8 +560,9 @@ private Iterator applyConstraintsDiff( KernelStatement sta return constraints; } - private Iterator applyConstraintsDiff( KernelStatement state, - Iterator constraints ) + + private Iterator applyConstraintsDiff( KernelStatement state, + Iterator constraints ) { if ( state.hasTxStateWithChanges() ) { @@ -556,7 +572,7 @@ private Iterator applyConstraintsDiff( KernelStatement sta } @Override - public void constraintDrop( KernelStatement state, UniquenessConstraint constraint ) + public void constraintDrop( KernelStatement state, PropertyConstraint constraint ) { state.txState().constraintDoDrop( constraint ); } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/operations/SchemaReadOperations.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/operations/SchemaReadOperations.java index 63ce76c2dcf4b..fc967412bdd22 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/operations/SchemaReadOperations.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/operations/SchemaReadOperations.java @@ -22,7 +22,7 @@ import java.util.Iterator; import org.neo4j.kernel.api.Statement; -import org.neo4j.kernel.api.constraints.UniquenessConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.exceptions.index.IndexNotFoundKernelException; import org.neo4j.kernel.api.exceptions.schema.SchemaRuleNotFoundException; import org.neo4j.kernel.api.index.IndexDescriptor; @@ -78,22 +78,22 @@ public interface SchemaReadOperations String indexGetFailure( Statement state, IndexDescriptor descriptor ) throws IndexNotFoundKernelException; /** - * Get all constraints applicable to label and propertyKey. There are only {@link UniquenessConstraint} + * Get all constraints applicable to label and propertyKey. There are only {@link PropertyConstraint} * for the time being. */ - Iterator constraintsGetForLabelAndPropertyKey( KernelStatement state, int labelId, int propertyKeyId ); + Iterator constraintsGetForLabelAndPropertyKey( KernelStatement state, int labelId, int propertyKeyId ); /** - * Get all constraints applicable to label. There are only {@link UniquenessConstraint} + * Get all constraints applicable to label. There are only {@link PropertyConstraint} * for the time being. */ - Iterator constraintsGetForLabel( KernelStatement state, int labelId ); + Iterator constraintsGetForLabel( KernelStatement state, int labelId ); /** - * Get all constraints. There are only {@link UniquenessConstraint} + * Get all constraints. There are only {@link PropertyConstraint} * for the time being. */ - Iterator constraintsGetAll( KernelStatement state ); + Iterator constraintsGetAll( KernelStatement state ); /** * Get the owning constraint for a constraint index. Returns null if the index does not have an owning constraint. diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/operations/SchemaWriteOperations.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/operations/SchemaWriteOperations.java index c486fbd18eb97..f6b83bd1725e8 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/operations/SchemaWriteOperations.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/operations/SchemaWriteOperations.java @@ -19,7 +19,8 @@ */ package org.neo4j.kernel.impl.api.operations; -import org.neo4j.kernel.impl.api.KernelStatement; +import org.neo4j.kernel.api.constraints.MandatoryPropertyConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.constraints.UniquenessConstraint; import org.neo4j.kernel.api.exceptions.schema.AddIndexFailureException; import org.neo4j.kernel.api.exceptions.schema.AlreadyConstrainedException; @@ -28,6 +29,7 @@ import org.neo4j.kernel.api.exceptions.schema.DropConstraintFailureException; import org.neo4j.kernel.api.exceptions.schema.DropIndexFailureException; import org.neo4j.kernel.api.index.IndexDescriptor; +import org.neo4j.kernel.impl.api.KernelStatement; public interface SchemaWriteOperations { @@ -47,8 +49,11 @@ IndexDescriptor indexCreate( KernelStatement state, int labelId, int propertyKey */ void uniqueIndexDrop( KernelStatement state, IndexDescriptor descriptor ) throws DropIndexFailureException; - UniquenessConstraint uniquenessConstraintCreate( KernelStatement state, int labelId, int propertyKeyId ) + UniquenessConstraint uniquePropertyConstraintCreate( KernelStatement state, int labelId, int propertyKeyId ) throws AlreadyConstrainedException, CreateConstraintFailureException, AlreadyIndexedException; - void constraintDrop( KernelStatement state, UniquenessConstraint constraint ) throws DropConstraintFailureException; + MandatoryPropertyConstraint mandatoryPropertyConstraintCreate( KernelStatement statement, int labelId, int propertyKeyId ) + throws AlreadyConstrainedException, CreateConstraintFailureException; + + void constraintDrop( KernelStatement state, PropertyConstraint constraint ) throws DropConstraintFailureException; } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/ConstraintIndexCreator.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/ConstraintIndexCreator.java index 43adc280dd42a..c7d256fc5b349 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/ConstraintIndexCreator.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/ConstraintIndexCreator.java @@ -23,6 +23,7 @@ import org.neo4j.kernel.api.KernelAPI; import org.neo4j.kernel.api.KernelTransaction; import org.neo4j.kernel.api.Statement; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.constraints.UniquenessConstraint; import org.neo4j.kernel.api.exceptions.TransactionFailureException; import org.neo4j.kernel.api.exceptions.index.IndexNotFoundKernelException; @@ -60,7 +61,7 @@ public long createUniquenessConstraintIndex( KernelStatement state, SchemaReadOp CreateConstraintFailureException, DropIndexFailureException { IndexDescriptor descriptor = createConstraintIndex( labelId, propertyKeyId ); - UniquenessConstraint constraint = new UniquenessConstraint( labelId, propertyKeyId ); + PropertyConstraint constraint = new UniquenessConstraint( labelId, propertyKeyId ); boolean success = false; try @@ -109,7 +110,7 @@ public void dropUniquenessConstraintIndex( IndexDescriptor descriptor ) } } - private void awaitIndexPopulation( UniquenessConstraint constraint, long indexId ) + private void awaitIndexPopulation( PropertyConstraint constraint, long indexId ) throws InterruptedException, ConstraintVerificationFailedKernelException { try diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/LabelState.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/LabelState.java index 77089609b427a..90caac911b6a4 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/LabelState.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/LabelState.java @@ -19,7 +19,7 @@ */ package org.neo4j.kernel.impl.api.state; -import org.neo4j.kernel.api.constraints.UniquenessConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.index.IndexDescriptor; import org.neo4j.kernel.impl.util.diffsets.DiffSets; import org.neo4j.kernel.impl.util.diffsets.ReadableDiffSets; @@ -45,14 +45,14 @@ public abstract class LabelState public abstract ReadableDiffSets constraintIndexChanges(); - public abstract ReadableDiffSets constraintsChanges(); + public abstract ReadableDiffSets constraintsChanges(); public static class Mutable extends LabelState { private DiffSets nodeDiffSets; private DiffSets indexChanges; private DiffSets constraintIndexChanges; - private DiffSets constraintsChanges; + private DiffSets constraintsChanges; private final int labelId; private Mutable( int labelId ) @@ -111,12 +111,12 @@ public DiffSets getOrCreateConstraintIndexChanges() } @Override - public ReadableDiffSets constraintsChanges() + public ReadableDiffSets constraintsChanges() { return ReadableDiffSets.Empty.ifNull( constraintsChanges ); } - public DiffSets getOrCreateConstraintsChanges() + public DiffSets getOrCreateConstraintsChanges() { if ( constraintsChanges == null ) { @@ -162,7 +162,7 @@ public ReadableDiffSets constraintIndexChanges() } @Override - public ReadableDiffSets constraintsChanges() + public ReadableDiffSets constraintsChanges() { return ReadableDiffSets.Empty.instance(); } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/TxState.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/TxState.java index 40ebdd04d0c2a..858ab4a7e48ba 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/TxState.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/TxState.java @@ -34,6 +34,8 @@ import org.neo4j.function.Predicate; import org.neo4j.graphdb.Direction; import org.neo4j.helpers.collection.Iterables; +import org.neo4j.kernel.api.constraints.MandatoryPropertyConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.constraints.UniquenessConstraint; import org.neo4j.kernel.api.cursor.LabelCursor; import org.neo4j.kernel.api.cursor.NodeCursor; @@ -131,7 +133,7 @@ void setMap( TxState state, Map map ) private GraphState graphState; private DiffSets indexChanges; private DiffSets constraintIndexChanges; - private DiffSets constraintsChanges; + private DiffSets constraintsChanges; private PropertyChanges propertyChangesForNodes; @@ -359,22 +361,55 @@ protected void visitAddedRelationship( long relationshipId, int type, long start }; } - private static DiffSetsVisitor constraintsVisitor( final TxStateVisitor visitor ) + private static DiffSetsVisitor constraintsVisitor( final TxStateVisitor visitor ) { - return new DiffSetsVisitor() + return new ConstraintDiffSetsVisitor( visitor ); + } + + static class ConstraintDiffSetsVisitor implements PropertyConstraint.ChangeVisitor, DiffSetsVisitor + { + private final TxStateVisitor visitor; + + ConstraintDiffSetsVisitor( TxStateVisitor visitor ) { - @Override - public void visitAdded( UniquenessConstraint element ) - { - visitor.visitAddedConstraint( element ); - } + this.visitor = visitor; + } - @Override - public void visitRemoved( UniquenessConstraint element ) - { - visitor.visitRemovedConstraint( element ); - } - }; + @Override + public void visitAdded( PropertyConstraint element ) + { + element.added( this ); + } + + @Override + public void visitRemoved( PropertyConstraint element ) + { + element.removed( this ); + } + + @Override + public void visitAddedUniquePropertyConstraint( UniquenessConstraint constraint ) + { + visitor.visitAddedUniquePropertyConstraint( constraint ); + } + + @Override + public void visitRemovedUniquePropertyConstraint( UniquenessConstraint constraint ) + { + visitor.visitRemovedUniquePropertyConstraint( constraint ); + } + + @Override + public void visitAddedMandatoryPropertyConstraint( MandatoryPropertyConstraint constraint ) + { + visitor.visitAddedMandatoryPropertyConstraint( constraint ); + } + + @Override + public void visitRemovedMandatoryPropertyConstraint( MandatoryPropertyConstraint constraint ) + { + visitor.visitRemovedMandatoryPropertyConstraint( constraint ); + } } private static DiffSetsVisitor indexVisitor( final TxStateVisitor visitor, @@ -1048,14 +1083,22 @@ public void constraintDoAdd( UniquenessConstraint constraint, long indexId ) } @Override - public ReadableDiffSets constraintsChangesForLabelAndProperty( int labelId, + public void constraintDoAdd( MandatoryPropertyConstraint constraint ) + { + constraintsChangesDiffSets().add( constraint ); + getOrCreateLabelState( constraint.label() ).getOrCreateConstraintsChanges().add( constraint ); + hasChanges = true; + } + + @Override + public ReadableDiffSets constraintsChangesForLabelAndProperty( int labelId, final int propertyKey ) { return LABEL_STATE.get( this, labelId ).constraintsChanges().filterAdded( - new Predicate() + new Predicate() { @Override - public boolean test( UniquenessConstraint item ) + public boolean test( PropertyConstraint item ) { return item.propertyKeyId() == propertyKey; } @@ -1063,18 +1106,18 @@ public boolean test( UniquenessConstraint item ) } @Override - public ReadableDiffSets constraintsChangesForLabel( int labelId ) + public ReadableDiffSets constraintsChangesForLabel( int labelId ) { return LABEL_STATE.get( this, labelId ).constraintsChanges(); } @Override - public ReadableDiffSets constraintsChanges() + public ReadableDiffSets constraintsChanges() { return ReadableDiffSets.Empty.ifNull( constraintsChanges ); } - private DiffSets constraintsChangesDiffSets() + private DiffSets constraintsChangesDiffSets() { if ( constraintsChanges == null ) { @@ -1084,17 +1127,21 @@ private DiffSets constraintsChangesDiffSets() } @Override - public void constraintDoDrop( UniquenessConstraint constraint ) + public void constraintDoDrop( PropertyConstraint constraint ) { constraintsChangesDiffSets().remove( constraint ); - constraintIndexDoDrop( new IndexDescriptor( constraint.label(), constraint.propertyKeyId() ) ); + + if ( constraint instanceof UniquenessConstraint ) + { + constraintIndexDoDrop( new IndexDescriptor( constraint.label(), constraint.propertyKeyId() )); + } getOrCreateLabelState( constraint.label() ).getOrCreateConstraintsChanges().remove( constraint ); hasChanges = true; } @Override - public boolean constraintDoUnRemove( UniquenessConstraint constraint ) + public boolean constraintDoUnRemove( PropertyConstraint constraint ) { if ( constraintsChangesDiffSets().unRemove( constraint ) ) { @@ -1120,10 +1167,11 @@ public Iterable constraintIndexesCreatedInTx() { if ( createdConstraintIndexesByConstraint != null && !createdConstraintIndexesByConstraint.isEmpty() ) { - return map( new Function() + + return map( new Function() { @Override - public IndexDescriptor apply( UniquenessConstraint constraint ) + public IndexDescriptor apply( PropertyConstraint constraint ) { return new IndexDescriptor( constraint.label(), constraint.propertyKeyId() ); } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/CacheLayer.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/CacheLayer.java index d4e453c7463f9..b815da970f760 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/CacheLayer.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/CacheLayer.java @@ -45,7 +45,7 @@ import org.neo4j.function.Function; import org.neo4j.function.Predicate; import org.neo4j.graphdb.Direction; -import org.neo4j.kernel.api.constraints.UniquenessConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.cursor.NodeCursor; import org.neo4j.kernel.api.cursor.RelationshipCursor; import org.neo4j.kernel.api.exceptions.EntityNotFoundException; @@ -269,19 +269,19 @@ public Iterator graphGetAllProperties() } @Override - public Iterator constraintsGetForLabelAndPropertyKey( int labelId, int propertyKeyId ) + public Iterator constraintsGetForLabelAndPropertyKey( int labelId, int propertyKeyId ) { return schemaCache.constraintsForLabelAndProperty( labelId, propertyKeyId ); } @Override - public Iterator constraintsGetForLabel( int labelId ) + public Iterator constraintsGetForLabel( int labelId ) { return schemaCache.constraintsForLabel( labelId ); } @Override - public Iterator constraintsGetAll() + public Iterator constraintsGetAll() { return schemaCache.constraints(); } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/DiskLayer.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/DiskLayer.java index 87875914b344b..ebf4ff81ec717 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/DiskLayer.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/DiskLayer.java @@ -36,7 +36,7 @@ import org.neo4j.graphdb.TransactionFailureException; import org.neo4j.kernel.api.EntityType; import org.neo4j.kernel.api.ReadOperations; -import org.neo4j.kernel.api.constraints.UniquenessConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.cursor.LabelCursor; import org.neo4j.kernel.api.cursor.NodeCursor; import org.neo4j.kernel.api.cursor.PropertyCursor; @@ -69,11 +69,12 @@ import org.neo4j.kernel.impl.store.InvalidRecordException; import org.neo4j.kernel.impl.store.NeoStore; import org.neo4j.kernel.impl.store.NodeStore; +import org.neo4j.kernel.impl.store.PropertyConstraintRule; import org.neo4j.kernel.impl.store.RelationshipGroupStore; import org.neo4j.kernel.impl.store.RelationshipStore; import org.neo4j.kernel.impl.store.SchemaStorage; import org.neo4j.kernel.impl.store.UnderlyingStorageException; -import org.neo4j.kernel.impl.store.UniquenessConstraintRule; +import org.neo4j.kernel.impl.store.UniquePropertyConstraintRule; import org.neo4j.kernel.impl.store.record.IndexRule; import org.neo4j.kernel.impl.store.record.NodeRecord; import org.neo4j.kernel.impl.store.record.Record; @@ -96,17 +97,16 @@ */ public class DiskLayer implements StoreReadLayer { - private static final Function UNIQUENESS_CONSTRAINT_TO_RULE = - new Function() + private static final Function RULE_TO_CONSTRAINT = + new Function() { - @Override - public UniquenessConstraint apply( UniquenessConstraintRule rule ) + public PropertyConstraint apply( PropertyConstraintRule rule ) { // We can use propertyKeyId straight up here, without reading from the record, since we have // verified that it has that propertyKeyId in the predicate. And since we currently only support // uniqueness on single properties, there is nothing else to pass in to UniquenessConstraint. - return new UniquenessConstraint( rule.getLabel(), rule.getPropertyKey() ); + return rule.toConstraint(); } }; @@ -662,13 +662,13 @@ public String indexGetFailure( IndexDescriptor descriptor ) throws IndexNotFound } @Override - public Iterator constraintsGetForLabelAndPropertyKey( int labelId, final int propertyKeyId ) + public Iterator constraintsGetForLabelAndPropertyKey( int labelId, final int propertyKeyId ) { - return schemaStorage.schemaRules( UNIQUENESS_CONSTRAINT_TO_RULE, UniquenessConstraintRule.class, - labelId, new Predicate() + return schemaStorage.schemaRules( RULE_TO_CONSTRAINT, PropertyConstraintRule.class, + labelId, new Predicate() { @Override - public boolean test( UniquenessConstraintRule rule ) + public boolean test( PropertyConstraintRule rule ) { return rule.containsPropertyKeyId( propertyKeyId ); } @@ -676,17 +676,17 @@ public boolean test( UniquenessConstraintRule rule ) } @Override - public Iterator constraintsGetForLabel( int labelId ) + public Iterator constraintsGetForLabel( int labelId ) { - return schemaStorage.schemaRules( UNIQUENESS_CONSTRAINT_TO_RULE, UniquenessConstraintRule.class, - labelId, Predicates.alwaysTrue() ); + return schemaStorage.schemaRules( RULE_TO_CONSTRAINT, UniquePropertyConstraintRule.class, + labelId, Predicates.alwaysTrue() ); } @Override - public Iterator constraintsGetAll() + public Iterator constraintsGetAll() { - return schemaStorage.schemaRules( UNIQUENESS_CONSTRAINT_TO_RULE, SchemaRule.Kind.UNIQUENESS_CONSTRAINT, - Predicates.alwaysTrue() ); + return schemaStorage.schemaRules( RULE_TO_CONSTRAINT, SchemaRule.Kind.UNIQUENESS_CONSTRAINT, + Predicates.alwaysTrue() ); } @Override diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/SchemaCache.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/SchemaCache.java index bf71534f985e6..4ae56bcbff1e9 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/SchemaCache.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/SchemaCache.java @@ -29,15 +29,14 @@ import org.neo4j.function.Predicate; import org.neo4j.helpers.collection.Iterables; import org.neo4j.helpers.collection.NestingIterable; -import org.neo4j.kernel.api.constraints.UniquenessConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.exceptions.index.IndexNotFoundKernelException; import org.neo4j.kernel.api.index.IndexDescriptor; -import org.neo4j.kernel.impl.store.UniquenessConstraintRule; +import org.neo4j.kernel.impl.store.PropertyConstraintRule; import org.neo4j.kernel.impl.store.record.IndexRule; import org.neo4j.kernel.impl.store.record.SchemaRule; import static java.util.Collections.unmodifiableCollection; - import static org.neo4j.helpers.collection.Iterables.filter; /** @@ -54,7 +53,7 @@ public class SchemaCache private final Map> rulesByLabelMap = new HashMap<>(); private final Map rulesByIdMap = new HashMap<>(); - private final Collection constraints = new HashSet<>(); + private final Collection constraints = new HashSet<>(); private final Map> indexDescriptors = new HashMap<>(); public SchemaCache( Iterable initialRules ) @@ -100,29 +99,29 @@ public Collection schemaRulesForLabel( int label ) Collections.emptyList(); } - public Iterator constraints() + public Iterator constraints() { return constraints.iterator(); } - public Iterator constraintsForLabel( final int label ) + public Iterator constraintsForLabel( final int label ) { - return filter( new Predicate() + return filter( new Predicate() { @Override - public boolean test( UniquenessConstraint item ) + public boolean test( PropertyConstraint item ) { return item.label() == label; } }, constraints.iterator() ); } - public Iterator constraintsForLabelAndProperty( final int label, final int property ) + public Iterator constraintsForLabelAndProperty( final int label, final int property ) { - return filter( new Predicate() + return filter( new Predicate() { @Override - public boolean test( UniquenessConstraint item ) + public boolean test( PropertyConstraint item ) { return item.label() == label && item.propertyKeyId() == property; } @@ -136,9 +135,9 @@ public void addSchemaRule( SchemaRule rule ) // Note: If you start adding more unmarshalling of other types of things here, // make this into a more generic thing rather than adding more branch statement. - if( rule instanceof UniquenessConstraintRule ) + if( rule instanceof PropertyConstraintRule ) { - constraints.add( ruleToConstraint( (UniquenessConstraintRule) rule ) ); + constraints.add( ((PropertyConstraintRule) rule).toConstraint() ); } else if( rule instanceof IndexRule ) { @@ -212,9 +211,9 @@ public void removeSchemaRule( long id ) rulesByLabelMap.remove( labelId ); } - if( rule instanceof UniquenessConstraintRule ) + if( rule instanceof PropertyConstraintRule ) { - constraints.remove( ruleToConstraint( (UniquenessConstraintRule)rule ) ); + constraints.remove( ((PropertyConstraintRule) rule).toConstraint() ); } else if( rule instanceof IndexRule ) { @@ -245,11 +244,6 @@ public long indexId( IndexDescriptor index ) throws IndexNotFoundKernelException ); } - private UniquenessConstraint ruleToConstraint( UniquenessConstraintRule constraintRule ) - { - return new UniquenessConstraint( constraintRule.getLabel(), constraintRule.getPropertyKey() ); - } - public IndexDescriptor indexDescriptor( int labelId, int propertyKey ) { Map byLabel = indexDescriptors.get( labelId ); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/StoreReadLayer.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/StoreReadLayer.java index e505b972c113d..55df0dc9253bf 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/StoreReadLayer.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/StoreReadLayer.java @@ -24,7 +24,7 @@ import org.neo4j.collection.primitive.PrimitiveIntIterator; import org.neo4j.collection.primitive.PrimitiveLongIterator; import org.neo4j.graphdb.Direction; -import org.neo4j.kernel.api.constraints.UniquenessConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.cursor.NodeCursor; import org.neo4j.kernel.api.cursor.RelationshipCursor; import org.neo4j.kernel.api.exceptions.EntityNotFoundException; @@ -122,12 +122,12 @@ Iterator relationshipGetAllProperties( StoreStatement statement Iterator graphGetAllProperties(); - Iterator constraintsGetForLabelAndPropertyKey( + Iterator constraintsGetForLabelAndPropertyKey( int labelId, int propertyKeyId ); - Iterator constraintsGetForLabel( int labelId ); + Iterator constraintsGetForLabel( int labelId ); - Iterator constraintsGetAll(); + Iterator constraintsGetAll(); PrimitiveLongResourceIterator nodeGetFromUniqueIndexSeek( KernelStatement state, IndexDescriptor index, Object value ) diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/BaseConstraintCreator.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/BaseConstraintCreator.java index 1e891df2bd636..712b2722e6541 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/BaseConstraintCreator.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/BaseConstraintCreator.java @@ -42,6 +42,12 @@ public ConstraintCreator assertPropertyIsUnique( String propertyKey ) return new PropertyUniqueConstraintCreator( actions, label, propertyKey ); } + @Override + public ConstraintCreator assertPropertyExists( String propertyKey ) + { + throw new UnsupportedOperationException( "not implemented" ); + } + @Override public ConstraintDefinition create() { diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/PropertyUniqueConstraintDefinition.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/PropertyConstraintDefinition.java similarity index 75% rename from community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/PropertyUniqueConstraintDefinition.java rename to community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/PropertyConstraintDefinition.java index d6d46c0b51f94..0138a0d403940 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/PropertyUniqueConstraintDefinition.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/PropertyConstraintDefinition.java @@ -25,17 +25,20 @@ import static java.util.Collections.singletonList; -public class PropertyUniqueConstraintDefinition implements ConstraintDefinition +public class PropertyConstraintDefinition implements ConstraintDefinition { private final InternalSchemaActions actions; private final Label label; private final String propertyKey; + private final ConstraintType type; - public PropertyUniqueConstraintDefinition( InternalSchemaActions actions, Label label, String propertyKey ) + public PropertyConstraintDefinition( InternalSchemaActions actions, Label label, String propertyKey, + ConstraintType type ) { this.actions = actions; this.label = label; this.propertyKey = propertyKey; + this.type = type; } @Override @@ -63,7 +66,7 @@ public Label getLabel() public ConstraintType getConstraintType() { assertInUnterminatedTransaction(); - return ConstraintType.UNIQUENESS; + return type; } @Override @@ -85,8 +88,12 @@ public boolean equals( Object o ) return false; } - PropertyUniqueConstraintDefinition that = (PropertyUniqueConstraintDefinition) o; + PropertyConstraintDefinition that = (PropertyConstraintDefinition) o; + if ( type != that.type ) + { + return false; + } if ( !actions.equals( that.actions ) ) { return false; @@ -106,7 +113,7 @@ public boolean equals( Object o ) @Override public int hashCode() { - int result = actions.hashCode(); + int result = type.hashCode(); result = 31 * result + label.name().hashCode(); result = 31 * result + propertyKey.hashCode(); @@ -117,10 +124,23 @@ public int hashCode() public String toString() { // using label name as a good identifier name - return String.format( "%s.%s IS UNIQUE", label.name().toLowerCase(), propertyKey ); + return String.format( "%s.%s IS %s", label.name().toLowerCase(), propertyKey, constraintString() ); + } + + private String constraintString() + { + switch ( type ) + { + case UNIQUENESS: + return "UNIQUE"; + case MANDATORY: + return "NOT NULL"; + default: + throw new UnsupportedOperationException( "Unknown ConstraintType: " + type ); + } } - private final void assertInUnterminatedTransaction() + private void assertInUnterminatedTransaction() { actions.assertInUnterminatedTransaction(); } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/PropertyUniqueConstraintCreator.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/PropertyUniqueConstraintCreator.java index e782ea2f8852a..461af743fc990 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/PropertyUniqueConstraintCreator.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/PropertyUniqueConstraintCreator.java @@ -42,6 +42,12 @@ public final ConstraintCreator assertPropertyIsUnique( String propertyKey ) throw new UnsupportedOperationException( "You can only create one unique constraint at a time." ); } + @Override + public ConstraintCreator assertPropertyExists( String propertyKey ) + { + throw new UnsupportedOperationException( "You are already creating a unique constraint." ); + } + @Override public final ConstraintDefinition create() { diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/SchemaImpl.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/SchemaImpl.java index 56682e4c8a688..781c7718a1585 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/SchemaImpl.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/SchemaImpl.java @@ -32,6 +32,7 @@ import org.neo4j.graphdb.NotFoundException; import org.neo4j.graphdb.schema.ConstraintCreator; import org.neo4j.graphdb.schema.ConstraintDefinition; +import org.neo4j.graphdb.schema.ConstraintType; import org.neo4j.graphdb.schema.IndexCreator; import org.neo4j.graphdb.schema.IndexDefinition; import org.neo4j.graphdb.schema.Schema; @@ -39,6 +40,7 @@ import org.neo4j.kernel.api.ReadOperations; import org.neo4j.kernel.api.Statement; import org.neo4j.kernel.api.StatementTokenNameLookup; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.constraints.UniquenessConstraint; import org.neo4j.kernel.api.exceptions.InvalidTransactionTypeKernelException; import org.neo4j.kernel.api.exceptions.KernelException; @@ -125,7 +127,7 @@ public Iterable getIndexes() private void addDefinitions( List definitions, final ReadOperations statement, Iterator indexes, final boolean constraintIndex ) { - addToCollection( map( new Function() + addToCollection( map( new Function() { @Override public IndexDefinition apply( IndexDescriptor rule ) @@ -287,7 +289,7 @@ public Iterable getConstraints() try ( Statement statement = statementContextSupplier.get() ) { - Iterator constraints = statement.readOperations().constraintsGetAll(); + Iterator constraints = statement.readOperations().constraintsGetAll(); return asConstraintDefinitions( statement.readOperations(), constraints ); } } @@ -304,26 +306,26 @@ public Iterable getConstraints( final Label label ) { return emptyList(); } - Iterator constraints = statement.readOperations().constraintsGetForLabel( labelId ); + Iterator constraints = statement.readOperations().constraintsGetForLabel( labelId ); return asConstraintDefinitions( statement.readOperations(), constraints ); } } private Iterable asConstraintDefinitions( - final ReadOperations readOperations, Iterator constraints ) + final ReadOperations readOperations, Iterator constraints ) { Iterator definitions = - map( new Function() + map( new Function() { @Override - public ConstraintDefinition apply( UniquenessConstraint constraint ) + public ConstraintDefinition apply( PropertyConstraint constraint ) { int labelId = constraint.label(); try { Label label = label( readOperations.labelGetName( labelId ) ); - return new PropertyUniqueConstraintDefinition( actions, label, - readOperations.propertyKeyGetName( constraint.propertyKeyId() ) ); + return new PropertyConstraintDefinition( actions, label, + readOperations.propertyKeyGetName( constraint.propertyKeyId() ), constraint.type() ); } catch ( PropertyKeyIdNotFoundKernelException e ) { @@ -428,8 +430,8 @@ public ConstraintDefinition createPropertyUniquenessConstraint( Label label, Str { int labelId = statement.schemaWriteOperations().labelGetOrCreateForName( label.name() ); int propertyKeyId = statement.schemaWriteOperations().propertyKeyGetOrCreateForName( propertyKey ); - statement.schemaWriteOperations().uniquenessConstraintCreate( labelId, propertyKeyId ); - return new PropertyUniqueConstraintDefinition( this, label, propertyKey ); + statement.schemaWriteOperations().uniquePropertyConstraintCreate( labelId, propertyKeyId ); + return new PropertyConstraintDefinition( this, label, propertyKey, ConstraintType.UNIQUENESS ); } catch ( AlreadyConstrainedException e ) { @@ -468,7 +470,7 @@ public void dropPropertyUniquenessConstraint( Label label, String propertyKey ) { int labelId = statement.schemaWriteOperations().labelGetOrCreateForName( label.name() ); int propertyKeyId = statement.schemaWriteOperations().propertyKeyGetOrCreateForName( propertyKey ); - UniquenessConstraint constraint = new UniquenessConstraint( labelId, propertyKeyId ); + PropertyConstraint constraint = new UniquenessConstraint( labelId, propertyKeyId ); statement.schemaWriteOperations().constraintDrop( constraint ); } catch ( IllegalTokenNameException | TooManyLabelsException | DropConstraintFailureException e ) diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/store/MandatoryPropertyConstraintRule.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/store/MandatoryPropertyConstraintRule.java new file mode 100644 index 0000000000000..1e9f5f988ea14 --- /dev/null +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/store/MandatoryPropertyConstraintRule.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2002-2015 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.neo4j.kernel.impl.store; + +import java.nio.ByteBuffer; + +import org.neo4j.kernel.api.constraints.MandatoryPropertyConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; + +public class MandatoryPropertyConstraintRule extends PropertyConstraintRule +{ + private final int propertyKeyId; + + /** We currently only support uniqueness constraints on a single property. */ + public static MandatoryPropertyConstraintRule mandatoryPropertyConstraintRule( long id, int labelId, int propertyKeyId ) + { + return new MandatoryPropertyConstraintRule( id, labelId, propertyKeyId ); + } + + public static MandatoryPropertyConstraintRule readMandatoryPropertyConstraintRule( long id, int labelId, ByteBuffer buffer ) + { + return new MandatoryPropertyConstraintRule( id, labelId, readPropertyKey( buffer ) ); + } + + private MandatoryPropertyConstraintRule( long id, int labelId, int propertyKeyId ) + { + super( id, labelId, Kind.MANDATORY_PROPERTY_CONSTRAINT ); + this.propertyKeyId = propertyKeyId; + } + + @Override + public int hashCode() + { + return super.hashCode() | propertyKeyId; + } + + @Override + public boolean equals( Object obj ) + { + return super.equals( obj ) && propertyKeyId == ((MandatoryPropertyConstraintRule) obj).propertyKeyId; + } + + @Override + protected String innerToString() + { + return ", propertyKey=" + propertyKeyId; + } + + @Override + public int length() + { + return super.length() + + 4; /* propertyKeyId */ + } + + @Override + public void serialize( ByteBuffer target ) + { + super.serialize( target ); + target.putInt( propertyKeyId ); + } + + private static int readPropertyKey( ByteBuffer buffer ) + { + return buffer.getInt(); + } + + public int getPropertyKey() + { + return propertyKeyId; + } + + @Override + public PropertyConstraint toConstraint() + { + return new MandatoryPropertyConstraint( getLabel(), getPropertyKey() ); + } + + @Override + public boolean containsPropertyKeyId( int propertyKeyId ) + { + return propertyKeyId == this.propertyKeyId; + } +} diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/store/PropertyConstraintRule.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/store/PropertyConstraintRule.java new file mode 100644 index 0000000000000..521ac373d0f05 --- /dev/null +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/store/PropertyConstraintRule.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2002-2015 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.neo4j.kernel.impl.store; + +import org.neo4j.kernel.api.constraints.PropertyConstraint; +import org.neo4j.kernel.impl.store.record.AbstractSchemaRule; + +public abstract class PropertyConstraintRule extends AbstractSchemaRule +{ + PropertyConstraintRule( long id, int label, Kind kind ) + { + super( id, label, kind ); + } + + public abstract PropertyConstraint toConstraint(); + + public abstract boolean containsPropertyKeyId( int propertyKeyId ); +} diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/store/SchemaStorage.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/store/SchemaStorage.java index 5a4f303abe824..3cc67a3b4ce0c 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/store/SchemaStorage.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/store/SchemaStorage.java @@ -139,12 +139,12 @@ public Iterator schemaRules( Function ruleConversion = (Function) conversion; return map( ruleConversion, filter( new Predicate() { - @SuppressWarnings("unchecked") + @SuppressWarnings( "unchecked" ) @Override public boolean test( SchemaRule rule ) { return rule.getLabel() == labelId && - rule.getKind().getRuleClass() == ruleType && + ruleType.isAssignableFrom( rule.getKind().getRuleClass() ) && predicate.test( (R) rule ); } }, loadAllSchemaRules() ) ); @@ -245,25 +245,35 @@ public long newRuleId() return schemaStore.nextId(); } - public UniquenessConstraintRule uniquenessConstraint( int labelId, final int propertyKeyId ) + public MandatoryPropertyConstraintRule mandatoryPropertyConstraint( int labelId, final int propertyKeyId ) throws SchemaRuleNotFoundException { - Iterator rules = schemaRules( - UniquenessConstraintRule.class, labelId, - new Predicate() - { - @Override - public boolean test( UniquenessConstraintRule item ) - { - return item.containsPropertyKeyId( propertyKeyId ); - } - } ); + return propertyConstraint( MandatoryPropertyConstraintRule.class, labelId, propertyKeyId ); + } + + public UniquePropertyConstraintRule uniquenessConstraint( int labelId, final int propertyKeyId ) + throws SchemaRuleNotFoundException + { + return propertyConstraint( UniquePropertyConstraintRule.class, labelId, propertyKeyId ); + } + + private Rule propertyConstraint( Class type, + final int labelId, final int propertyKeyId ) throws SchemaRuleNotFoundException + { + Iterator rules = schemaRules( type, labelId, new Predicate() + { + @Override + public boolean test( Rule item ) + { + return item.containsPropertyKeyId( propertyKeyId ); + } + } ); if ( !rules.hasNext() ) { throw new SchemaRuleNotFoundException( labelId, propertyKeyId, "not found" ); } - UniquenessConstraintRule rule = rules.next(); + Rule rule = rules.next(); if ( rules.hasNext() ) { diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/store/UniquenessConstraintRule.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/store/UniquePropertyConstraintRule.java similarity index 77% rename from community/kernel/src/main/java/org/neo4j/kernel/impl/store/UniquenessConstraintRule.java rename to community/kernel/src/main/java/org/neo4j/kernel/impl/store/UniquePropertyConstraintRule.java index 0ac642f86d324..508891cdea87d 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/store/UniquenessConstraintRule.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/store/UniquePropertyConstraintRule.java @@ -22,28 +22,29 @@ import java.nio.ByteBuffer; import java.util.Arrays; -import org.neo4j.kernel.impl.store.record.AbstractSchemaRule; +import org.neo4j.kernel.api.constraints.PropertyConstraint; +import org.neo4j.kernel.api.constraints.UniquenessConstraint; import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.safeCastLongToInt; -public class UniquenessConstraintRule extends AbstractSchemaRule +public class UniquePropertyConstraintRule extends PropertyConstraintRule { private final int[] propertyKeyIds; private final long ownedIndexRule; /** We currently only support uniqueness constraints on a single property. */ - public static UniquenessConstraintRule uniquenessConstraintRule( long id, int labelId, int propertyKeyId, - long ownedIndexRule ) + public static UniquePropertyConstraintRule uniquenessConstraintRule( long id, int labelId, int propertyKeyId, + long ownedIndexRule ) { - return new UniquenessConstraintRule( id, labelId, new int[] {propertyKeyId}, ownedIndexRule ); + return new UniquePropertyConstraintRule( id, labelId, new int[] {propertyKeyId}, ownedIndexRule ); } - public static UniquenessConstraintRule readUniquenessConstraintRule( long id, int labelId, ByteBuffer buffer ) + public static UniquePropertyConstraintRule readUniquenessConstraintRule( long id, int labelId, ByteBuffer buffer ) { - return new UniquenessConstraintRule( id, labelId, readPropertyKeys( buffer ), readOwnedIndexRule( buffer ) ); + return new UniquePropertyConstraintRule( id, labelId, readPropertyKeys( buffer ), readOwnedIndexRule( buffer ) ); } - private UniquenessConstraintRule( long id, int labelId, int[] propertyKeyIds, long ownedIndexRule ) + private UniquePropertyConstraintRule( long id, int labelId, int[] propertyKeyIds, long ownedIndexRule ) { super( id, labelId, Kind.UNIQUENESS_CONSTRAINT ); this.ownedIndexRule = ownedIndexRule; @@ -60,7 +61,7 @@ public int hashCode() @Override public boolean equals( Object obj ) { - return super.equals( obj ) && Arrays.equals( propertyKeyIds, ((UniquenessConstraintRule) obj).propertyKeyIds ); + return super.equals( obj ) && Arrays.equals( propertyKeyIds, ((UniquePropertyConstraintRule) obj).propertyKeyIds ); } @Override @@ -128,4 +129,10 @@ public long getOwnedIndex() { return ownedIndexRule; } + + @Override + public PropertyConstraint toConstraint() + { + return new UniquenessConstraint( getLabel(), getPropertyKey() ); + } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/store/record/SchemaRule.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/store/record/SchemaRule.java index 90704ee41ae8f..acd811854ee9d 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/store/record/SchemaRule.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/store/record/SchemaRule.java @@ -22,7 +22,8 @@ import java.nio.ByteBuffer; import org.neo4j.kernel.api.exceptions.schema.MalformedSchemaRuleException; -import org.neo4j.kernel.impl.store.UniquenessConstraintRule; +import org.neo4j.kernel.impl.store.MandatoryPropertyConstraintRule; +import org.neo4j.kernel.impl.store.UniquePropertyConstraintRule; public interface SchemaRule extends RecordSerializable { @@ -41,7 +42,7 @@ public interface SchemaRule extends RecordSerializable */ Kind getKind(); - public static enum Kind + enum Kind { INDEX_RULE( 1, IndexRule.class ) { @@ -59,12 +60,20 @@ protected SchemaRule newRule( long id, int labelId, ByteBuffer buffer ) return IndexRule.readIndexRule( id, true, labelId, buffer ); } }, - UNIQUENESS_CONSTRAINT( 3, UniquenessConstraintRule.class ) + UNIQUENESS_CONSTRAINT( 3, UniquePropertyConstraintRule.class ) { @Override protected SchemaRule newRule( long id, int labelId, ByteBuffer buffer ) { - return UniquenessConstraintRule.readUniquenessConstraintRule( id, labelId, buffer ); + return UniquePropertyConstraintRule.readUniquenessConstraintRule( id, labelId, buffer ); + } + }, + MANDATORY_PROPERTY_CONSTRAINT( 4, MandatoryPropertyConstraintRule.class ) + { + @Override + protected SchemaRule newRule( long id, int labelId, ByteBuffer buffer ) + { + return MandatoryPropertyConstraintRule.readMandatoryPropertyConstraintRule( id, labelId, buffer ); } }; @@ -118,6 +127,7 @@ public static Kind kindForId( byte id ) throws MalformedSchemaRuleException case 1: return INDEX_RULE; case 2: return CONSTRAINT_INDEX_RULE; case 3: return UNIQUENESS_CONSTRAINT; + case 4: return MANDATORY_PROPERTY_CONSTRAINT; default: throw new MalformedSchemaRuleException( null, "Unknown kind id %d", id ); } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/transaction/command/NeoStoreTransactionApplier.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/transaction/command/NeoStoreTransactionApplier.java index 22360596a0a83..c997f72e5c3e6 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/transaction/command/NeoStoreTransactionApplier.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/transaction/command/NeoStoreTransactionApplier.java @@ -27,7 +27,7 @@ import org.neo4j.kernel.impl.store.NeoStore; import org.neo4j.kernel.impl.store.NodeStore; import org.neo4j.kernel.impl.store.SchemaStore; -import org.neo4j.kernel.impl.store.UniquenessConstraintRule; +import org.neo4j.kernel.impl.store.UniquePropertyConstraintRule; import org.neo4j.kernel.impl.store.record.DynamicRecord; import org.neo4j.kernel.impl.store.record.RelationshipRecord; @@ -144,7 +144,7 @@ public boolean visitSchemaRuleCommand( Command.SchemaRuleCommand command ) throw schemaStore.updateRecord( record ); } - if ( command.getSchemaRule() instanceof UniquenessConstraintRule ) + if ( command.getSchemaRule() instanceof UniquePropertyConstraintRule ) { switch ( command.getMode() ) { diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/transaction/state/IntegrityValidator.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/transaction/state/IntegrityValidator.java index 5a63333e850ac..ebe1a2c3e4671 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/transaction/state/IntegrityValidator.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/transaction/state/IntegrityValidator.java @@ -26,7 +26,7 @@ import org.neo4j.kernel.api.exceptions.schema.ConstraintVerificationFailedKernelException; import org.neo4j.kernel.impl.api.index.IndexingService; import org.neo4j.kernel.impl.store.NeoStore; -import org.neo4j.kernel.impl.store.UniquenessConstraintRule; +import org.neo4j.kernel.impl.store.UniquePropertyConstraintRule; import org.neo4j.kernel.impl.store.record.NodeRecord; import org.neo4j.kernel.impl.store.record.Record; import org.neo4j.kernel.impl.store.record.SchemaRule; @@ -76,11 +76,11 @@ public void validateTransactionStartKnowledge( long lastCommittedTxWhenTransacti public void validateSchemaRule( SchemaRule schemaRule ) throws TransactionFailureException { - if ( schemaRule instanceof UniquenessConstraintRule ) + if ( schemaRule instanceof UniquePropertyConstraintRule ) { try { - indexes.validateIndex( ((UniquenessConstraintRule)schemaRule).getOwnedIndex() ); + indexes.validateIndex( ((UniquePropertyConstraintRule)schemaRule).getOwnedIndex() ); } catch ( ConstraintVerificationFailedKernelException e ) { diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureArgumentFormatter.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureArgumentFormatter.java index 6f79346269d10..6ab0a9bdc6981 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureArgumentFormatter.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureArgumentFormatter.java @@ -25,6 +25,7 @@ import java.util.List; import org.neo4j.helpers.Strings; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.constraints.UniquenessConstraint; import org.neo4j.kernel.api.index.IndexDescriptor; @@ -85,9 +86,9 @@ else if ( arg instanceof IndexDescriptor ) int propertyKeyId = descriptor.getPropertyKeyId(); builder.append( format( "new IndexDescriptor( %s, %s )", labelId, propertyKeyId ) ); } - else if ( arg instanceof UniquenessConstraint ) + else if ( arg instanceof PropertyConstraint ) { - UniquenessConstraint constraint = (UniquenessConstraint) arg; + PropertyConstraint constraint = (PropertyConstraint) arg; int labelId = constraint.label(); int propertyKeyId = constraint.propertyKeyId(); builder.append( format( "new UniquenessConstraint( %s, %s )", labelId, propertyKeyId ) ); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureCollector.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureCollector.java index 2552e1c8dd1eb..bea9bf19b216c 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureCollector.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureCollector.java @@ -22,7 +22,7 @@ import org.neo4j.function.Function; import org.neo4j.helpers.Pair; import org.neo4j.helpers.collection.Iterables; -import org.neo4j.kernel.api.constraints.UniquenessConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.index.IndexDescriptor; import java.util.*; @@ -36,7 +36,7 @@ public class DbStructureCollector implements DbStructureVisitor private final TokenMap relationshipTypes = new TokenMap( "relationship types" ); private final IndexDescriptorMap regularIndices = new IndexDescriptorMap( "regular" ); private final IndexDescriptorMap uniqueIndices = new IndexDescriptorMap( "unique" ); - private final Set uniquenessConstraint = new HashSet<>(); + private final Set uniquenessConstraint = new HashSet<>(); private final Map nodeCounts = new HashMap<>(); private final Map relCounts = new HashMap<>(); private long allNodesCount = -1l; @@ -78,10 +78,10 @@ public Iterator> knownUniqueIndices() @Override public Iterator> knownUniqueConstraints() { - return Iterables.map( new Function>() + return Iterables.map( new Function>() { @Override - public Pair apply( UniquenessConstraint uniquenessConstraint ) throws RuntimeException + public Pair apply( PropertyConstraint uniquenessConstraint ) throws RuntimeException { String label = labels.byIdOrFail( uniquenessConstraint.label() ); String propertyKey = propertyKeys.byIdOrFail( uniquenessConstraint.propertyKeyId() ); @@ -154,7 +154,7 @@ public void visitUniqueIndex( IndexDescriptor descriptor, String userDescription } @Override - public void visitUniqueConstraint( UniquenessConstraint constraint, String userDescription ) + public void visitUniqueConstraint( PropertyConstraint constraint, String userDescription ) { if ( !uniquenessConstraint.add( constraint ) ) { diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureVisitor.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureVisitor.java index 81414ef38cc2f..9479d28f06814 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureVisitor.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureVisitor.java @@ -19,7 +19,7 @@ */ package org.neo4j.kernel.impl.util.dbstructure; -import org.neo4j.kernel.api.constraints.UniquenessConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.index.IndexDescriptor; public interface DbStructureVisitor @@ -30,7 +30,7 @@ public interface DbStructureVisitor void visitIndex( IndexDescriptor descriptor, String userDescription, double uniqueValuesPercentage, long size ); void visitUniqueIndex( IndexDescriptor descriptor, String userDescription, double uniqueValuesPercentage, long size ); - void visitUniqueConstraint( UniquenessConstraint constraint, String userDescription ); + void visitUniqueConstraint( PropertyConstraint constraint, String userDescription ); void visitAllNodesCount( long nodeCount ); void visitNodeCount( int labelId, String labelName, long nodeCount ); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/util/dbstructure/GraphDbStructureGuide.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/util/dbstructure/GraphDbStructureGuide.java index ade26023e93be..80e16a1532ef8 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/util/dbstructure/GraphDbStructureGuide.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/util/dbstructure/GraphDbStructureGuide.java @@ -32,7 +32,7 @@ import org.neo4j.kernel.api.Statement; import org.neo4j.kernel.api.StatementTokenNameLookup; import org.neo4j.kernel.api.TokenNameLookup; -import org.neo4j.kernel.api.constraints.UniquenessConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.exceptions.KernelException; import org.neo4j.kernel.api.exceptions.index.IndexNotFoundKernelException; import org.neo4j.kernel.api.index.IndexDescriptor; @@ -167,10 +167,10 @@ private void showUniqueIndices( DbStructureVisitor visitor, ReadOperations read, private void showUniqueConstraints( DbStructureVisitor visitor, ReadOperations read, TokenNameLookup nameLookup ) { - Iterator constraints = read.constraintsGetAll(); + Iterator constraints = read.constraintsGetAll(); while ( constraints.hasNext() ) { - UniquenessConstraint constraint = constraints.next(); + PropertyConstraint constraint = constraints.next(); String userDescription = constraint.userDescription( nameLookup ); visitor.visitUniqueConstraint( constraint, userDescription ); } diff --git a/community/kernel/src/main/java/org/neo4j/unsafe/batchinsert/BatchInserterImpl.java b/community/kernel/src/main/java/org/neo4j/unsafe/batchinsert/BatchInserterImpl.java index 8c19387b00518..c53a8bae3f4a5 100644 --- a/community/kernel/src/main/java/org/neo4j/unsafe/batchinsert/BatchInserterImpl.java +++ b/community/kernel/src/main/java/org/neo4j/unsafe/batchinsert/BatchInserterImpl.java @@ -40,6 +40,7 @@ import org.neo4j.graphdb.factory.GraphDatabaseSettings; import org.neo4j.graphdb.schema.ConstraintCreator; import org.neo4j.graphdb.schema.ConstraintDefinition; +import org.neo4j.graphdb.schema.ConstraintType; import org.neo4j.graphdb.schema.IndexCreator; import org.neo4j.graphdb.schema.IndexDefinition; import org.neo4j.helpers.collection.IteratorUtil; @@ -55,6 +56,7 @@ import org.neo4j.kernel.IdGeneratorFactory; import org.neo4j.kernel.IdType; import org.neo4j.kernel.StoreLocker; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.constraints.UniquenessConstraint; import org.neo4j.kernel.api.exceptions.KernelException; import org.neo4j.kernel.api.exceptions.index.IndexCapacityExceededException; @@ -85,7 +87,7 @@ import org.neo4j.kernel.impl.coreapi.schema.IndexCreatorImpl; import org.neo4j.kernel.impl.coreapi.schema.IndexDefinitionImpl; import org.neo4j.kernel.impl.coreapi.schema.InternalSchemaActions; -import org.neo4j.kernel.impl.coreapi.schema.PropertyUniqueConstraintDefinition; +import org.neo4j.kernel.impl.coreapi.schema.PropertyConstraintDefinition; import org.neo4j.kernel.impl.index.IndexConfigStore; import org.neo4j.kernel.impl.locking.LockService; import org.neo4j.kernel.impl.locking.ReentrantLockService; @@ -104,7 +106,7 @@ import org.neo4j.kernel.impl.store.SchemaStore; import org.neo4j.kernel.impl.store.StoreFactory; import org.neo4j.kernel.impl.store.UnderlyingStorageException; -import org.neo4j.kernel.impl.store.UniquenessConstraintRule; +import org.neo4j.kernel.impl.store.UniquePropertyConstraintRule; import org.neo4j.kernel.impl.store.counts.CountsTracker; import org.neo4j.kernel.impl.store.id.IdGeneratorImpl; import org.neo4j.kernel.impl.store.record.DynamicRecord; @@ -138,7 +140,6 @@ import org.neo4j.logging.NullLog; import static java.lang.Boolean.parseBoolean; - import static org.neo4j.collection.primitive.PrimitiveLongCollections.map; import static org.neo4j.graphdb.DynamicLabel.label; import static org.neo4j.helpers.collection.IteratorUtil.first; @@ -418,7 +419,7 @@ private void checkSchemaCreationConstraints( int labelId, int propertyKeyId ) otherPropertyKeyId = ((IndexRule) rule).getPropertyKey(); break; case UNIQUENESS_CONSTRAINT: - otherPropertyKeyId = ((UniquenessConstraintRule) rule).getPropertyKey(); + otherPropertyKeyId = ((UniquePropertyConstraintRule) rule).getPropertyKey(); break; default: throw new IllegalStateException( "Case not handled."); @@ -589,7 +590,7 @@ public ConstraintCreator createDeferredConstraint( Label label ) return new BaseConstraintCreator( new BatchSchemaActions(), label ); } - private void createConstraintRule( UniquenessConstraint constraint ) + private void createConstraintRule( PropertyConstraint constraint ) { // TODO: Do not create duplicate index @@ -602,7 +603,8 @@ private void createConstraintRule( UniquenessConstraint constraint ) indexRuleId, constraint.label(), constraint.propertyKeyId(), this.schemaIndexProviders.getDefaultProvider().getProviderDescriptor(), constraintRuleId ); - UniquenessConstraintRule constraintRule = UniquenessConstraintRule.uniquenessConstraintRule( + UniquePropertyConstraintRule + constraintRule = UniquePropertyConstraintRule.uniquenessConstraintRule( constraintRuleId, constraint.label(), constraint.propertyKeyId(), indexRuleId ); for ( DynamicRecord record : schemaStore.allocateFrom( constraintRule ) ) @@ -1148,7 +1150,7 @@ public ConstraintDefinition createPropertyUniquenessConstraint( Label label, Str checkSchemaCreationConstraints( labelId, propertyKeyId ); createConstraintRule( new UniquenessConstraint( labelId, propertyKeyId ) ); - return new PropertyUniqueConstraintDefinition( this, label, propertyKey ); + return new PropertyConstraintDefinition( this, label, propertyKey, ConstraintType.UNIQUENESS ); } @Override diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelSchemaStateFlushingTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelSchemaStateFlushingTest.java index 3b839fb1b5416..a61ea403b28da 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelSchemaStateFlushingTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelSchemaStateFlushingTest.java @@ -30,7 +30,7 @@ import org.neo4j.kernel.api.KernelAPI; import org.neo4j.kernel.api.KernelTransaction; import org.neo4j.kernel.api.Statement; -import org.neo4j.kernel.api.constraints.UniquenessConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.exceptions.KernelException; import org.neo4j.kernel.api.exceptions.TransactionFailureException; import org.neo4j.kernel.api.exceptions.index.IndexNotFoundKernelException; @@ -115,7 +115,7 @@ public void shouldInvalidateSchemaStateOnCreateConstraint() throws Exception public void shouldInvalidateSchemaStateOnDropConstraint() throws Exception { // given - UniquenessConstraint descriptor = createConstraint(); + PropertyConstraint descriptor = createConstraint(); commitToSchemaState( "test", "before" ); @@ -128,19 +128,19 @@ public void shouldInvalidateSchemaStateOnDropConstraint() throws Exception assertEquals( "after", after ); } - private UniquenessConstraint createConstraint() throws KernelException + private PropertyConstraint createConstraint() throws KernelException { try ( KernelTransaction transaction = kernel.newTransaction(); Statement statement = transaction.acquireStatement() ) { - UniquenessConstraint descriptor = statement.schemaWriteOperations().uniquenessConstraintCreate( 1, 1 ); + PropertyConstraint descriptor = statement.schemaWriteOperations().uniquePropertyConstraintCreate( 1, 1 ); transaction.success(); return descriptor; } } - private void dropConstraint( UniquenessConstraint descriptor ) throws KernelException + private void dropConstraint( PropertyConstraint descriptor ) throws KernelException { try ( KernelTransaction transaction = kernel.newTransaction(); Statement statement = transaction.acquireStatement() ) diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelTest.java index 0456a23fc79aa..ac37b8f8efcba 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelTest.java @@ -57,7 +57,7 @@ public void shouldNotAllowCreationOfConstraintsWhenInHA() throws Exception try { - statement.schemaWriteOperations().uniquenessConstraintCreate( 1, 1 ); + statement.schemaWriteOperations().uniquePropertyConstraintCreate( 1, 1 ); fail( "expected exception here" ); } catch ( InvalidTransactionTypeKernelException e ) diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/LockingStatementOperationsTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/LockingStatementOperationsTest.java index 9b5c069bcfd52..bd9ef3d792b49 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/LockingStatementOperationsTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/LockingStatementOperationsTest.java @@ -19,13 +19,14 @@ */ package org.neo4j.kernel.impl.api; -import java.util.Collections; -import java.util.Iterator; - import org.junit.Test; import org.mockito.InOrder; +import java.util.Collections; +import java.util.Iterator; + import org.neo4j.function.Function; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.constraints.UniquenessConstraint; import org.neo4j.kernel.api.exceptions.EntityNotFoundException; import org.neo4j.kernel.api.index.IndexDescriptor; @@ -43,7 +44,6 @@ import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; - import static org.neo4j.function.Functions.constant; import static org.neo4j.kernel.impl.locking.ResourceTypes.schemaResource; @@ -197,22 +197,22 @@ public void shouldAcquireSchemaWriteLockBeforeCreatingUniquenessConstraint() thr { // given UniquenessConstraint constraint = new UniquenessConstraint( 0, 0 ); - when( schemaWriteOps.uniquenessConstraintCreate( state, 123, 456 ) ).thenReturn( constraint ); + when( schemaWriteOps.uniquePropertyConstraintCreate( state, 123, 456 ) ).thenReturn( constraint ); // when - UniquenessConstraint result = lockingOps.uniquenessConstraintCreate( state, 123, 456 ); + PropertyConstraint result = lockingOps.uniquePropertyConstraintCreate( state, 123, 456 ); // then assertSame( constraint, result ); order.verify( locks ).acquireExclusive( ResourceTypes.SCHEMA, schemaResource() ); - order.verify( schemaWriteOps ).uniquenessConstraintCreate( state, 123, 456 ); + order.verify( schemaWriteOps ).uniquePropertyConstraintCreate( state, 123, 456 ); } @Test public void shouldAcquireSchemaWriteLockBeforeDroppingConstraint() throws Exception { // given - UniquenessConstraint constraint = new UniquenessConstraint( 1, 2 ); + PropertyConstraint constraint = new UniquenessConstraint( 1, 2 ); // when lockingOps.constraintDrop( state, constraint ); @@ -226,11 +226,11 @@ public void shouldAcquireSchemaWriteLockBeforeDroppingConstraint() throws Except public void shouldAcquireSchemaReadLockBeforeGettingConstraintsByLabelAndProperty() throws Exception { // given - Iterator constraints = Collections.emptyIterator(); + Iterator constraints = Collections.emptyIterator(); when( schemaReadOps.constraintsGetForLabelAndPropertyKey( state, 123, 456 ) ).thenReturn( constraints ); // when - Iterator result = lockingOps.constraintsGetForLabelAndPropertyKey( state, 123, 456 ); + Iterator result = lockingOps.constraintsGetForLabelAndPropertyKey( state, 123, 456 ); // then assertSame( constraints, result ); @@ -242,11 +242,11 @@ public void shouldAcquireSchemaReadLockBeforeGettingConstraintsByLabelAndPropert public void shouldAcquireSchemaReadLockBeforeGettingConstraintsByLabel() throws Exception { // given - Iterator constraints = Collections.emptyIterator(); + Iterator constraints = Collections.emptyIterator(); when( schemaReadOps.constraintsGetForLabel( state, 123 ) ).thenReturn( constraints ); // when - Iterator result = lockingOps.constraintsGetForLabel( state, 123 ); + Iterator result = lockingOps.constraintsGetForLabel( state, 123 ); // then assertSame( constraints, result ); @@ -258,11 +258,11 @@ public void shouldAcquireSchemaReadLockBeforeGettingConstraintsByLabel() throws public void shouldAcquireSchemaReadLockBeforeGettingAllConstraints() throws Exception { // given - Iterator constraints = Collections.emptyIterator(); + Iterator constraints = Collections.emptyIterator(); when( schemaReadOps.constraintsGetAll( state ) ).thenReturn( constraints ); // when - Iterator result = lockingOps.constraintsGetAll( state ); + Iterator result = lockingOps.constraintsGetAll( state ); // then assertSame( constraints, result ); diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/index/IndexIT.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/index/IndexIT.java index ab87e3c4d03c3..0dffc11f46171 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/index/IndexIT.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/index/IndexIT.java @@ -164,7 +164,7 @@ public void shouldFailToCreateIndexWhereAConstraintAlreadyExists() throws Except // given { SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); - statement.uniquenessConstraintCreate( labelId, propertyKey ); + statement.uniquePropertyConstraintCreate( labelId, propertyKey ); commit(); } @@ -191,8 +191,8 @@ public void shouldListConstraintIndexesInTheBeansAPI() throws Exception // given { SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); - statement.uniquenessConstraintCreate( statement.labelGetOrCreateForName( "Label1" ), - statement.propertyKeyGetOrCreateForName( "property1" ) ); + statement.uniquePropertyConstraintCreate( statement.labelGetOrCreateForName( "Label1" ), + statement.propertyKeyGetOrCreateForName( "property1" ) ); commit(); } @@ -232,7 +232,7 @@ public void shouldNotListConstraintIndexesAmongIndexes() throws Exception // given { SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); - statement.uniquenessConstraintCreate( labelId, propertyKey ); + statement.uniquePropertyConstraintCreate( labelId, propertyKey ); commit(); } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/integrationtest/ConstraintsCreationIT.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/integrationtest/ConstraintsCreationIT.java index b294b27064b70..7aa1483a81254 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/integrationtest/ConstraintsCreationIT.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/integrationtest/ConstraintsCreationIT.java @@ -19,14 +19,14 @@ */ package org.neo4j.kernel.impl.api.integrationtest; +import org.junit.Before; +import org.junit.Test; + import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; -import org.junit.Before; -import org.junit.Test; - import org.neo4j.function.Function; import org.neo4j.graphdb.ConstraintViolationException; import org.neo4j.graphdb.Node; @@ -35,6 +35,8 @@ import org.neo4j.graphdb.schema.Schema; import org.neo4j.kernel.api.ReadOperations; import org.neo4j.kernel.api.SchemaWriteOperations; +import org.neo4j.kernel.api.constraints.MandatoryPropertyConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.constraints.UniquenessConstraint; import org.neo4j.kernel.api.exceptions.KernelException; import org.neo4j.kernel.api.exceptions.TransactionFailureException; @@ -43,18 +45,16 @@ import org.neo4j.kernel.api.exceptions.schema.NoSuchConstraintException; import org.neo4j.kernel.api.index.IndexDescriptor; import org.neo4j.kernel.impl.store.SchemaStorage; -import org.neo4j.kernel.impl.store.UniquenessConstraintRule; +import org.neo4j.kernel.impl.store.UniquePropertyConstraintRule; import org.neo4j.kernel.impl.store.record.IndexRule; import static java.util.Collections.singletonList; - import static org.hamcrest.CoreMatchers.instanceOf; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; - import static org.neo4j.graphdb.DynamicLabel.label; import static org.neo4j.helpers.collection.IteratorUtil.asCollection; import static org.neo4j.helpers.collection.IteratorUtil.asList; @@ -65,15 +65,15 @@ public class ConstraintsCreationIT extends KernelIntegrationTest { @Test - public void shouldBeAbleToStoreAndRetrieveUniquenessConstraintRule() throws Exception + public void shouldBeAbleToStoreAndRetrieveUniquePropertyConstraintRule() throws Exception { // given - UniquenessConstraint constraint; + PropertyConstraint constraint; { SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); // when - constraint = statement.uniquenessConstraintCreate( labelId, propertyKeyId ); + constraint = statement.uniquePropertyConstraintCreate( labelId, propertyKeyId ); // then assertEquals( constraint, single( statement.constraintsGetForLabelAndPropertyKey( labelId,propertyKeyId ) ) ); @@ -82,11 +82,41 @@ public void shouldBeAbleToStoreAndRetrieveUniquenessConstraintRule() throws Exce // given commit(); } + { + ReadOperations statement = readOperationsInNewTransaction(); + + // when + Iterator constraints = statement + .constraintsGetForLabelAndPropertyKey( labelId, propertyKeyId ); + + // then + assertEquals( constraint, single( constraints ) ); + } + } + + @Test + public void shouldCreateAndRetrieveMandatoryPropertyConstraint() throws Exception + { + // given + PropertyConstraint constraint; { SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); // when - Iterator constraints = statement + constraint = statement.mandatoryPropertyConstraintCreate( labelId, propertyKeyId ); + + // then + assertEquals( constraint, single( statement.constraintsGetForLabelAndPropertyKey( labelId,propertyKeyId ) ) ); + assertEquals( constraint, single( statement.constraintsGetForLabel( labelId ) ) ); + + // given + commit(); + } + { + ReadOperations statement = readOperationsInNewTransaction(); + + // when + Iterator constraints = statement .constraintsGetForLabelAndPropertyKey( labelId, propertyKeyId ); // then @@ -95,59 +125,138 @@ public void shouldBeAbleToStoreAndRetrieveUniquenessConstraintRule() throws Exce } @Test - public void shouldNotPersistUniquenessConstraintsCreatedInAbortedTransaction() throws Exception + public void shouldNotPersistUniquePropertyConstraintsCreatedInAbortedTransaction() throws Exception { // given { SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); - statement.uniquenessConstraintCreate( labelId, propertyKeyId ); + statement.uniquePropertyConstraintCreate( labelId, propertyKeyId ); // when rollback(); } + { + ReadOperations statement = readOperationsInNewTransaction(); + + // then + Iterator constraints = statement.constraintsGetForLabelAndPropertyKey( labelId, propertyKeyId ); + assertFalse( "should not have any constraints", constraints.hasNext() ); + } + } + + @Test + public void shouldNotPersistMandatoryPropertyConstraintsCreatedInAbortedTransaction() throws Exception + { + // given { SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); + statement.mandatoryPropertyConstraintCreate( labelId, propertyKeyId ); + + // when + rollback(); + } + { + ReadOperations statement = readOperationsInNewTransaction(); + // then - Iterator constraints = statement.constraintsGetForLabelAndPropertyKey( labelId, propertyKeyId ); + Iterator constraints = statement.constraintsGetForLabelAndPropertyKey( labelId, propertyKeyId ); assertFalse( "should not have any constraints", constraints.hasNext() ); } } @Test - public void shouldNotStoreUniquenessConstraintThatIsRemovedInTheSameTransaction() throws Exception + public void shouldNotStoreUniquePropertyConstraintThatIsRemovedInTheSameTransaction() throws Exception { // given { SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); - UniquenessConstraint constraint = statement.uniquenessConstraintCreate( labelId, propertyKeyId ); + PropertyConstraint constraint = statement.uniquePropertyConstraintCreate( labelId, propertyKeyId ); // when statement.constraintDrop( constraint ); // then - assertFalse( "should not have any constraints", statement.constraintsGetForLabelAndPropertyKey( labelId, propertyKeyId ).hasNext() ); + assertFalse( "should not have any constraints", + statement.constraintsGetForLabelAndPropertyKey( labelId, propertyKeyId ).hasNext() ); // when commit(); } + { + ReadOperations statement = readOperationsInNewTransaction(); + + // then + assertFalse( "should not have any constraints", + statement.constraintsGetForLabelAndPropertyKey( labelId, propertyKeyId ).hasNext() ); + } + } + + @Test + public void shouldNotStoreMandatoryPropertyConstraintThatIsRemovedInTheSameTransaction() throws Exception + { + // given { SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); + PropertyConstraint constraint = statement.mandatoryPropertyConstraintCreate( labelId, propertyKeyId ); + + // when + statement.constraintDrop( constraint ); + + // then + assertFalse( "should not have any constraints", + statement.constraintsGetForLabelAndPropertyKey( labelId, propertyKeyId ).hasNext() ); + + // when + commit(); + } + { + ReadOperations statement = readOperationsInNewTransaction(); + + // then + assertFalse( "should not have any constraints", + statement.constraintsGetForLabelAndPropertyKey( labelId, propertyKeyId ).hasNext() ); + } + } + + @Test + public void shouldDropMandatoryPropertyConstraint() throws Exception + { + // given + PropertyConstraint constraint; + { + SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); + constraint = statement.mandatoryPropertyConstraintCreate( labelId, propertyKeyId ); + commit(); + } + + // when + { + SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); + statement.constraintDrop( constraint ); + commit(); + } + + // then + { + ReadOperations statement = readOperationsInNewTransaction(); + // then - assertFalse( "should not have any constraints", statement.constraintsGetForLabelAndPropertyKey( labelId, propertyKeyId ).hasNext() ); + assertFalse( "should not have any constraints", + statement.constraintsGetForLabelAndPropertyKey( labelId, propertyKeyId ).hasNext() ); } } @Test - public void shouldNotCreateUniquenessConstraintThatAlreadyExists() throws Exception + public void shouldNotCreateUniquePropertyConstraintThatAlreadyExists() throws Exception { // given { SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); - statement.uniquenessConstraintCreate( labelId, propertyKeyId ); + statement.uniquePropertyConstraintCreate( labelId, propertyKeyId ); commit(); } @@ -156,7 +265,7 @@ public void shouldNotCreateUniquenessConstraintThatAlreadyExists() throws Except { SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); - statement.uniquenessConstraintCreate( labelId, propertyKeyId ); + statement.uniquePropertyConstraintCreate( labelId, propertyKeyId ); fail( "Should not have validated" ); } @@ -168,13 +277,39 @@ public void shouldNotCreateUniquenessConstraintThatAlreadyExists() throws Except } @Test - public void shouldNotRemoveConstraintThatGetsReAdded() throws Exception + public void shouldNotCreateMandatoryPropertyConstraintThatAlreadyExists() throws Exception { // given - UniquenessConstraint constraint; { SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); - constraint = statement.uniquenessConstraintCreate( labelId, propertyKeyId ); + statement.mandatoryPropertyConstraintCreate( labelId, propertyKeyId ); + commit(); + } + + // when + try + { + SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); + + statement.mandatoryPropertyConstraintCreate( labelId, propertyKeyId ); + + fail( "Should not have validated" ); + } + // then + catch ( AlreadyConstrainedException e ) + { + // good + } + } + + @Test + public void shouldNotRemoveUniquePropertyConstraintThatGetsReAdded() throws Exception + { + // given + PropertyConstraint constraint; + { + SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); + constraint = statement.uniquePropertyConstraintCreate( labelId, propertyKeyId ); commit(); } SchemaStateCheck schemaState = new SchemaStateCheck().setUp(); @@ -183,75 +318,123 @@ public void shouldNotRemoveConstraintThatGetsReAdded() throws Exception // when statement.constraintDrop( constraint ); - statement.uniquenessConstraintCreate( labelId, propertyKeyId ); + statement.uniquePropertyConstraintCreate( labelId, propertyKeyId ); commit(); } { - SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); + ReadOperations statement = readOperationsInNewTransaction(); // then assertEquals( singletonList( constraint ), asCollection( statement.constraintsGetForLabelAndPropertyKey( labelId, propertyKeyId ) ) ); - schemaState.assertNotCleared(); + schemaState.assertNotCleared(statement); } } @Test - public void shouldClearSchemaStateWhenConstraintIsCreated() throws Exception + public void shouldNotRemoveMandatoryPropertyConstraintThatGetsReAdded() throws Exception { // given + PropertyConstraint constraint; + { + SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); + constraint = statement.mandatoryPropertyConstraintCreate( labelId, propertyKeyId ); + commit(); + } SchemaStateCheck schemaState = new SchemaStateCheck().setUp(); + { + SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); - SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); - - // when - statement.uniquenessConstraintCreate( labelId, propertyKeyId ); - commit(); + // when + statement.constraintDrop( constraint ); + statement.mandatoryPropertyConstraintCreate( labelId, propertyKeyId ); + commit(); + } + { + ReadOperations statement = readOperationsInNewTransaction(); - // then - schemaWriteOperationsInNewTransaction(); - schemaState.assertCleared(); + // then + assertEquals( singletonList( constraint ), asCollection( statement.constraintsGetForLabelAndPropertyKey( labelId, propertyKeyId ) ) ); + schemaState.assertNotCleared(statement); + } } @Test - public void shouldClearSchemaStateWhenConstraintIsDropped() throws Exception + public void shouldClearSchemaStateWhenConstraintIsCreated() throws Exception { - // given - UniquenessConstraint constraint; - SchemaStateCheck schemaState; + for ( int i = 0; i < 2; i++ ) { + // given + SchemaStateCheck schemaState = new SchemaStateCheck().setUp(); + SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); - constraint = statement.uniquenessConstraintCreate( labelId, propertyKeyId ); + + // when + if ( i == 0 ) + { + statement.uniquePropertyConstraintCreate( labelId, propertyKeyId ); + } + else + { + statement.mandatoryPropertyConstraintCreate( labelId, propertyKeyId ); + } commit(); - schemaState = new SchemaStateCheck().setUp(); + // then + schemaState.assertCleared(readOperationsInNewTransaction()); + rollback(); } + } + @Test + public void shouldClearSchemaStateWhenConstraintIsDropped() throws Exception + { + for ( int i = 0; i < 2; i++ ) { - SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); + // given + PropertyConstraint constraint; + SchemaStateCheck schemaState; + { + SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); + if ( i == 0 ) + { + constraint = statement.uniquePropertyConstraintCreate( labelId, propertyKeyId ); + } + else + { + constraint = statement.mandatoryPropertyConstraintCreate( labelId, propertyKeyId ); + } + commit(); + + schemaState = new SchemaStateCheck().setUp(); + } - // when - statement.constraintDrop( constraint ); - commit(); - } + { + SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); - // then - schemaWriteOperationsInNewTransaction(); - schemaState.assertCleared(); + // when + statement.constraintDrop( constraint ); + commit(); + } + + // then + schemaState.assertCleared( readOperationsInNewTransaction() ); + rollback(); + } } @Test - public void shouldCreateAnIndexToGoAlongWithAUniquenessConstraint() throws Exception + public void shouldCreateAnIndexToGoAlongWithAUniquePropertyConstraint() throws Exception { // when { SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); - statement.uniquenessConstraintCreate( labelId, propertyKeyId ); + statement.uniquePropertyConstraintCreate( labelId, propertyKeyId ); commit(); } // then { - SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); + ReadOperations statement = readOperationsInNewTransaction(); assertEquals( asSet( new IndexDescriptor( labelId, propertyKeyId ) ), asSet( statement.uniqueIndexesGetAll() ) ); } @@ -263,9 +446,9 @@ public void shouldDropCreatedConstraintIndexWhenRollingBackConstraintCreation() // given { SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); - statement.uniquenessConstraintCreate( labelId, propertyKeyId ); + statement.uniquePropertyConstraintCreate( labelId, propertyKeyId ); assertEquals( asSet( new IndexDescriptor( labelId, propertyKeyId ) ), - asSet( statement.uniqueIndexesGetAll() ) ); + asSet( statement.uniqueIndexesGetAll() ) ); } // when @@ -273,7 +456,7 @@ public void shouldDropCreatedConstraintIndexWhenRollingBackConstraintCreation() // then { - SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); + ReadOperations statement = readOperationsInNewTransaction(); assertEquals( emptySetOf( IndexDescriptor.class ), asSet( statement.uniqueIndexesGetAll() ) ); commit(); } @@ -283,11 +466,12 @@ public void shouldDropCreatedConstraintIndexWhenRollingBackConstraintCreation() public void shouldDropConstraintIndexWhenDroppingConstraint() throws Exception { // given - UniquenessConstraint constraint; + PropertyConstraint constraint; { SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); - constraint = statement.uniquenessConstraintCreate( labelId, propertyKeyId ); - assertEquals( asSet( new IndexDescriptor( labelId, propertyKeyId ) ), asSet( statement.uniqueIndexesGetAll() ) ); + constraint = statement.uniquePropertyConstraintCreate( labelId, propertyKeyId ); + assertEquals( asSet( new IndexDescriptor( labelId, propertyKeyId ) ), + asSet( statement.uniqueIndexesGetAll() ) ); commit(); } @@ -300,7 +484,7 @@ public void shouldDropConstraintIndexWhenDroppingConstraint() throws Exception // then { - SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); + ReadOperations statement = readOperationsInNewTransaction(); assertEquals( emptySetOf( IndexDescriptor.class ), asSet( statement.uniqueIndexesGetAll( ) ) ); commit(); } @@ -309,28 +493,116 @@ public void shouldDropConstraintIndexWhenDroppingConstraint() throws Exception @Test public void shouldNotDropConstraintThatDoesNotExist() throws Exception { - // when + for ( PropertyConstraint constraint : new PropertyConstraint[]{ + new UniquenessConstraint( labelId, propertyKeyId ), + new MandatoryPropertyConstraint( labelId, propertyKeyId ), + } ) { - SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); - - try + // when { - statement.constraintDrop( new UniquenessConstraint( labelId, propertyKeyId ) ); - fail( "Should not have dropped constraint" ); + SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); + + try + { + statement.constraintDrop( constraint ); + fail( "Should not have dropped constraint" ); + } + catch ( DropConstraintFailureException e ) + { + assertThat( e.getCause(), instanceOf( NoSuchConstraintException.class ) ); + } + commit(); } - catch ( DropConstraintFailureException e ) + + // then { - assertThat( e.getCause(), instanceOf( NoSuchConstraintException.class ) ); + ReadOperations statement = readOperationsInNewTransaction(); + assertEquals( emptySetOf( IndexDescriptor.class ), asSet( statement.uniqueIndexesGetAll() ) ); + commit(); } + } + } + + @Test + public void shouldNotDropMandatoryPropertyConstraintThatDoesNotExistWhenThereIsAUniquePropertyConstraint() + throws Exception + { + // given + PropertyConstraint constraint; + { + SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); + constraint = statement.uniquePropertyConstraintCreate( labelId, propertyKeyId ); commit(); } + // when + try + { + SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); + statement.constraintDrop( new MandatoryPropertyConstraint( constraint.label(), constraint.propertyKeyId() ) ); + + fail( "expected exception" ); + } + // then + catch ( DropConstraintFailureException e ) + { + assertThat( e.getCause(), instanceOf( NoSuchConstraintException.class ) ); + } + finally + { + rollback(); + } + // then + { + ReadOperations statement = readOperationsInNewTransaction(); + + Iterator constraints = statement + .constraintsGetForLabelAndPropertyKey( labelId, propertyKeyId ); + + assertEquals( constraint, single( constraints ) ); + } + } + + @Test + public void shouldNotDropUniquePropertyConstraintThatDoesNotExistWhenThereIsAMandatoryPropertyConstraint() + throws Exception + { + // given + PropertyConstraint constraint; { SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); - assertEquals( emptySetOf( IndexDescriptor.class ), asSet( statement.uniqueIndexesGetAll() ) ); + constraint = statement.mandatoryPropertyConstraintCreate( labelId, propertyKeyId ); commit(); } + + // when + try + { + SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); + statement.constraintDrop( new UniquenessConstraint( constraint.label(), constraint.propertyKeyId() ) ); + + fail( "expected exception" ); + } + // then + catch ( DropConstraintFailureException e ) + { + assertThat( e.getCause(), instanceOf( NoSuchConstraintException.class ) ); + } + finally + { + rollback(); + } + + // then + { + ReadOperations statement = readOperationsInNewTransaction(); + + Iterator constraints = statement + .constraintsGetForLabelAndPropertyKey( labelId, propertyKeyId ); + + assertEquals( constraint, single( constraints ) ); + } } @Test @@ -338,19 +610,19 @@ public void committedConstraintRuleShouldCrossReferenceTheCorrespondingIndexRule { // when SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); - statement.uniquenessConstraintCreate( labelId, propertyKeyId ); + statement.uniquePropertyConstraintCreate( labelId, propertyKeyId ); commit(); // then SchemaStorage schema = new SchemaStorage( neoStore().getSchemaStore() ); IndexRule indexRule = schema.indexRule( labelId, propertyKeyId ); - UniquenessConstraintRule constraintRule = schema.uniquenessConstraint( labelId, propertyKeyId ); + UniquePropertyConstraintRule constraintRule = schema.uniquenessConstraint( labelId, propertyKeyId ); assertEquals( constraintRule.getId(), indexRule.getOwningConstraint().longValue() ); assertEquals( indexRule.getId(), constraintRule.getOwnedIndex() ); } @Test - public void shouldNotLeaveAnyStateBehindAfterFailingToCreateConstraint() throws Exception + public void shouldNotLeaveAnyStateBehindAfterFailingToCreateUniquePropertyConstraint() throws Exception { // given try ( org.neo4j.graphdb.Transaction tx = db.beginTx() ) @@ -390,7 +662,7 @@ public void shouldNotLeaveAnyStateBehindAfterFailingToCreateConstraint() throws } @Test - public void shouldBeAbleToResolveConflictsAndRecreateConstraintAfterFailingToCreateConstraintDueToConflict() + public void shouldBeAbleToResolveConflictsAndRecreateConstraintAfterFailingToCreateUniquePropertyConstraintDueToConflict() throws Exception { // given @@ -459,7 +731,6 @@ public void createKeys() throws KernelException private class SchemaStateCheck implements Function { int invocationCount; - private ReadOperations readOperations; @Override public Integer apply( String s ) @@ -470,27 +741,27 @@ public Integer apply( String s ) public SchemaStateCheck setUp() throws TransactionFailureException { - this.readOperations = readOperationsInNewTransaction(); - checkState(); + ReadOperations readOperations = readOperationsInNewTransaction(); + checkState(readOperations); commit(); return this; } - public void assertCleared() + public void assertCleared(ReadOperations readOperations) { int count = invocationCount; - checkState(); + checkState( readOperations ); assertEquals( "schema state should have been cleared.", count + 1, invocationCount ); } - public void assertNotCleared() + public void assertNotCleared(ReadOperations readOperations) { int count = invocationCount; - checkState(); + checkState( readOperations ); assertEquals( "schema state should not have been cleared.", count, invocationCount ); } - private SchemaStateCheck checkState() + private SchemaStateCheck checkState( ReadOperations readOperations ) { assertEquals( Integer.valueOf( 7 ), readOperations.schemaStateGetOrCreate( "7", this ) ); return this; diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/integrationtest/NodeGetUniqueFromIndexSeekIT.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/integrationtest/NodeGetUniqueFromIndexSeekIT.java index dee3687f99993..ce37b2d6ba20a 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/integrationtest/NodeGetUniqueFromIndexSeekIT.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/integrationtest/NodeGetUniqueFromIndexSeekIT.java @@ -195,7 +195,7 @@ private long createNodeWithValue( String value ) throws KernelException private IndexDescriptor createUniquenessConstraint() throws Exception { SchemaWriteOperations schemaStatement = schemaWriteOperationsInNewTransaction(); - schemaStatement.uniquenessConstraintCreate( labelId, propertyKeyId ); + schemaStatement.uniquePropertyConstraintCreate( labelId, propertyKeyId ); IndexDescriptor result = schemaStatement.uniqueIndexGetForLabelAndPropertyKey( labelId, propertyKeyId ); commit(); return result; diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/integrationtest/UniquenessConstraintCreationIT.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/integrationtest/UniquenessConstraintCreationIT.java index d909e154355e4..b1636368a4129 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/integrationtest/UniquenessConstraintCreationIT.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/integrationtest/UniquenessConstraintCreationIT.java @@ -36,7 +36,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; - import static org.neo4j.helpers.collection.IteratorUtil.asSet; public class UniquenessConstraintCreationIT extends KernelIntegrationTest @@ -76,7 +75,7 @@ public void shouldAbortConstraintCreationWhenDuplicatesExist() throws Exception try { SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); - statement.uniquenessConstraintCreate( foo, name ); + statement.uniquePropertyConstraintCreate( foo, name ); fail( "expected exception" ); } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/integrationtest/UniquenessConstraintValidationIT.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/integrationtest/UniquenessConstraintValidationIT.java index ba7bdf603df94..dcbf4e43897bb 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/integrationtest/UniquenessConstraintValidationIT.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/integrationtest/UniquenessConstraintValidationIT.java @@ -328,7 +328,7 @@ private void createConstraint( String label, String propertyKey ) throws KernelE { SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction(); - statement.uniquenessConstraintCreate( labelId, propertyKeyId ); + statement.uniquePropertyConstraintCreate( labelId, propertyKeyId ); commit(); } } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/IndexQueryTransactionStateTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/IndexQueryTransactionStateTest.java index 3d4a7c0ad0355..aa2a7052f8406 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/IndexQueryTransactionStateTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/IndexQueryTransactionStateTest.java @@ -30,6 +30,8 @@ import org.neo4j.kernel.api.constraints.UniquenessConstraint; import org.neo4j.kernel.api.cursor.LabelCursor; import org.neo4j.kernel.api.cursor.PropertyCursor; +import org.neo4j.helpers.collection.IteratorUtil; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.index.IndexDescriptor; import org.neo4j.kernel.api.index.InternalIndexState; import org.neo4j.kernel.api.properties.Property; @@ -331,7 +333,7 @@ public void before() throws Exception when( store.indexesGetForLabel( labelId2 ) ).then( answerAsIteratorFrom( Collections .emptyList() ) ); when( store.indexesGetAll() ).then( answerAsIteratorFrom( Collections.emptyList() ) ); - when( store.constraintsGetForLabel( labelId ) ).thenReturn( Collections.emptyIterator() ); + when( store.constraintsGetForLabel( labelId ) ).thenReturn( Collections.emptyIterator() ); when( store.nodeExists( anyLong() ) ).thenReturn( true ); when( store.indexesGetForLabelAndPropertyKey( labelId, propertyKeyId ) ) .thenReturn( new IndexDescriptor( labelId, propertyKeyId ) ); diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/StateHandlingStatementOperationsTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/StateHandlingStatementOperationsTest.java index df31e05e9017a..0ae0ef6db3d47 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/StateHandlingStatementOperationsTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/StateHandlingStatementOperationsTest.java @@ -19,18 +19,19 @@ */ package org.neo4j.kernel.impl.api.state; -import java.util.Collections; -import java.util.Iterator; -import java.util.Set; - import org.junit.Test; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import java.util.Collections; +import java.util.Iterator; +import java.util.Set; + import org.neo4j.collection.primitive.PrimitiveLongCollections; import org.neo4j.collection.primitive.PrimitiveLongIterator; import org.neo4j.helpers.collection.IteratorUtil; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.constraints.UniquenessConstraint; import org.neo4j.kernel.api.cursor.LabelCursor; import org.neo4j.kernel.api.cursor.PropertyCursor; @@ -47,7 +48,6 @@ import org.neo4j.kernel.impl.util.diffsets.DiffSets; import static java.util.Arrays.asList; - import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; @@ -57,7 +57,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; - import static org.neo4j.helpers.collection.IteratorUtil.asIterable; import static org.neo4j.helpers.collection.IteratorUtil.asSet; import static org.neo4j.kernel.impl.api.StatementOperationsTestHelper.mockedState; @@ -107,7 +106,7 @@ public void shouldNeverDelegateWrites() throws Exception public void shouldNotAddConstraintAlreadyExistsInTheStore() throws Exception { // given - UniquenessConstraint constraint = new UniquenessConstraint( 10, 66 ); + PropertyConstraint constraint = new UniquenessConstraint( 10, 66 ); TransactionState txState = mock( TransactionState.class ); when( txState.nodesWithLabelChanged( anyInt() ) ).thenReturn( new DiffSets() ); KernelStatement state = mockedState( txState ); @@ -116,7 +115,7 @@ public void shouldNotAddConstraintAlreadyExistsInTheStore() throws Exception StateHandlingStatementOperations context = newTxStateOps( inner ); // when - context.uniquenessConstraintCreate( state, 10, 66 ); + context.uniquePropertyConstraintCreate( state, 10, 66 ); // then verify( txState ).constraintIndexDoUnRemove( any( IndexDescriptor.class ) ); @@ -126,16 +125,16 @@ public void shouldNotAddConstraintAlreadyExistsInTheStore() throws Exception public void shouldGetConstraintsByLabelAndProperty() throws Exception { // given - UniquenessConstraint constraint = new UniquenessConstraint( 10, 66 ); + PropertyConstraint constraint = new UniquenessConstraint( 10, 66 ); TransactionState txState = new TxState(); KernelStatement state = mockedState( txState ); when( inner.constraintsGetForLabelAndPropertyKey( 10, 66 ) ) .thenAnswer( asAnswer( Collections.emptyList() ) ); StateHandlingStatementOperations context = newTxStateOps( inner ); - context.uniquenessConstraintCreate( state, 10, 66 ); + context.uniquePropertyConstraintCreate( state, 10, 66 ); // when - Set result = asSet( + Set result = asSet( asIterable( context.constraintsGetForLabelAndPropertyKey( state, 10, 66 ) ) ); // then @@ -146,8 +145,8 @@ public void shouldGetConstraintsByLabelAndProperty() throws Exception public void shouldGetConstraintsByLabel() throws Exception { // given - UniquenessConstraint constraint1 = new UniquenessConstraint( 11, 66 ); - UniquenessConstraint constraint2 = new UniquenessConstraint( 11, 99 ); + PropertyConstraint constraint2 = new UniquenessConstraint( 11, 99 ); + PropertyConstraint constraint1 = new UniquenessConstraint( 11, 66 ); TransactionState txState = new TxState(); KernelStatement state = mockedState( txState ); @@ -160,11 +159,11 @@ public void shouldGetConstraintsByLabel() throws Exception when( inner.constraintsGetForLabel( 11 ) ) .thenAnswer( asAnswer( asIterable( constraint1 ) ) ); StateHandlingStatementOperations context = newTxStateOps( inner ); - context.uniquenessConstraintCreate( state, 10, 66 ); - context.uniquenessConstraintCreate( state, 11, 99 ); + context.uniquePropertyConstraintCreate( state, 10, 66 ); + context.uniquePropertyConstraintCreate( state, 11, 99 ); // when - Set result = asSet( asIterable( context.constraintsGetForLabel( state, 11 ) ) ); + Set result = asSet( asIterable( context.constraintsGetForLabel( state, 11 ) ) ); // then assertEquals( asSet( constraint1, constraint2 ), result ); @@ -174,8 +173,8 @@ public void shouldGetConstraintsByLabel() throws Exception public void shouldGetAllConstraints() throws Exception { // given - UniquenessConstraint constraint1 = new UniquenessConstraint( 10, 66 ); - UniquenessConstraint constraint2 = new UniquenessConstraint( 11, 99 ); + PropertyConstraint constraint1 = new UniquenessConstraint( 10, 66 ); + PropertyConstraint constraint2 = new UniquenessConstraint( 11, 99 ); TransactionState txState = new TxState(); KernelStatement state = mockedState( txState ); @@ -185,10 +184,10 @@ public void shouldGetAllConstraints() throws Exception .thenAnswer( asAnswer( Collections.emptyList() ) ); when( inner.constraintsGetAll() ).thenAnswer( asAnswer( asIterable( constraint2 ) ) ); StateHandlingStatementOperations context = newTxStateOps( inner ); - context.uniquenessConstraintCreate( state, 10, 66 ); + context.uniquePropertyConstraintCreate( state, 10, 66 ); // when - Set result = asSet( asIterable( context.constraintsGetAll( state ) ) ); + Set result = asSet( asIterable( context.constraintsGetAll( state ) ) ); // then assertEquals( asSet( constraint1, constraint2 ), result ); diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/TxStateTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/TxStateTest.java index 0c15e4c0737c0..bcb17a68025f3 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/TxStateTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/TxStateTest.java @@ -19,20 +19,22 @@ */ package org.neo4j.kernel.impl.api.state; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.RuleChain; +import org.junit.rules.TestRule; + import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.RuleChain; -import org.junit.rules.TestRule; import org.neo4j.collection.primitive.PrimitiveLongIterator; import org.neo4j.graphdb.Direction; import org.neo4j.helpers.collection.IteratorUtil; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.constraints.UniquenessConstraint; import org.neo4j.kernel.api.index.IndexDescriptor; import org.neo4j.kernel.api.properties.DefinedProperty; @@ -313,7 +315,7 @@ public void shouldAddUniquenessConstraint() throws Exception state.constraintDoAdd( constraint, 7 ); // then - ReadableDiffSets diff = state.constraintsChangesForLabel( 1 ); + ReadableDiffSets diff = state.constraintsChangesForLabel( 1 ); assertEquals( Collections.singleton( constraint ), diff.getAdded() ); assertTrue( diff.getRemoved().isEmpty() ); diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/CacheLayerTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/CacheLayerTest.java index 0fa856ee67d89..1814188267943 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/CacheLayerTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/CacheLayerTest.java @@ -23,13 +23,13 @@ import java.util.Set; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.constraints.UniquenessConstraint; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; - import static org.neo4j.helpers.collection.IteratorUtil.asSet; public class CacheLayerTest @@ -42,7 +42,7 @@ public class CacheLayerTest public void shouldLoadAllConstraintsFromCache() throws Exception { // Given - Set constraints = asSet( new UniquenessConstraint( 0, 1 ) ); + Set constraints = asSet( (PropertyConstraint)new UniquenessConstraint( 0, 1 ) ); when(schemaCache.constraints()).thenReturn( constraints.iterator() ); // When & Then @@ -54,7 +54,7 @@ public void shouldLoadConstraintsByLabelFromCache() throws Exception { // Given int labelId = 0; - Set constraints = asSet( new UniquenessConstraint( labelId, 1 ) ); + Set constraints = asSet( (PropertyConstraint)new UniquenessConstraint( labelId, 1 ) ); when(schemaCache.constraintsForLabel(labelId)).thenReturn( constraints.iterator() ); // When & Then @@ -66,7 +66,7 @@ public void shouldLoadConstraintsByLabelAndPropertyFromCache() throws Exception { // Given int labelId = 0, propertyId = 1; - Set constraints = asSet( new UniquenessConstraint( labelId, propertyId ) ); + Set constraints = asSet( (PropertyConstraint)new UniquenessConstraint( labelId, propertyId ) ); when(schemaCache.constraintsForLabelAndProperty(labelId, propertyId)).thenReturn( constraints.iterator() ); // When & Then diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/SchemaCacheTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/SchemaCacheTest.java index cddcf514f9744..98d8464337e10 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/SchemaCacheTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/SchemaCacheTest.java @@ -19,10 +19,10 @@ */ package org.neo4j.kernel.impl.api.store; -import java.util.Collection; - import org.junit.Test; +import java.util.Collection; + import org.neo4j.helpers.collection.Iterables; import org.neo4j.helpers.collection.IteratorUtil; import org.neo4j.kernel.api.constraints.UniquenessConstraint; @@ -31,15 +31,13 @@ import org.neo4j.kernel.impl.store.record.SchemaRule; import static java.util.Arrays.asList; - import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; - import static org.neo4j.helpers.collection.IteratorUtil.asSet; import static org.neo4j.kernel.impl.api.index.TestSchemaIndexProviderDescriptor.PROVIDER_DESCRIPTOR; -import static org.neo4j.kernel.impl.store.UniquenessConstraintRule.uniquenessConstraintRule; +import static org.neo4j.kernel.impl.store.UniquePropertyConstraintRule.uniquenessConstraintRule; public class SchemaCacheTest { diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/command/NeoTransactionStoreApplierTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/command/NeoTransactionStoreApplierTest.java index 68a4818f73d99..fe764216df8fa 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/command/NeoTransactionStoreApplierTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/command/NeoTransactionStoreApplierTest.java @@ -51,7 +51,7 @@ import org.neo4j.kernel.impl.store.RelationshipStore; import org.neo4j.kernel.impl.store.RelationshipTypeTokenStore; import org.neo4j.kernel.impl.store.SchemaStore; -import org.neo4j.kernel.impl.store.UniquenessConstraintRule; +import org.neo4j.kernel.impl.store.UniquePropertyConstraintRule; import org.neo4j.kernel.impl.store.record.DynamicRecord; import org.neo4j.kernel.impl.store.record.IndexRule; import org.neo4j.kernel.impl.store.record.LabelTokenRecord; @@ -747,7 +747,8 @@ public void shouldApplyCreateUniquenessConstraintRuleSchemaRuleCommandToTheStore final DynamicRecord record = DynamicRecord.dynamicRecord( 21, true ); record.setCreated(); final Collection recordsAfter = Arrays.asList( record ); - final UniquenessConstraintRule rule = UniquenessConstraintRule.uniquenessConstraintRule( 0l, 1, 2, 3l ); + final UniquePropertyConstraintRule + rule = UniquePropertyConstraintRule.uniquenessConstraintRule( 0l, 1, 2, 3l ); final Command.SchemaRuleCommand command = new Command.SchemaRuleCommand().init( Collections.emptyList(), recordsAfter, rule ); @@ -770,7 +771,8 @@ public void shouldApplyCreateUniquenessConstraintRuleSchemaRuleCommandToTheStore final DynamicRecord record = DynamicRecord.dynamicRecord( 21, true ); record.setCreated(); final Collection recordsAfter = Arrays.asList( record ); - final UniquenessConstraintRule rule = UniquenessConstraintRule.uniquenessConstraintRule( 0l, 1, 2, 3l ); + final UniquePropertyConstraintRule + rule = UniquePropertyConstraintRule.uniquenessConstraintRule( 0l, 1, 2, 3l ); final Command.SchemaRuleCommand command = new Command.SchemaRuleCommand().init( Collections.emptyList(), recordsAfter, rule ); @@ -794,7 +796,8 @@ public void shouldApplyUpdateUniquenessConstraintRuleSchemaRuleCommandToTheStore final NeoCommandHandler applier = newApplier( false ); final DynamicRecord record = DynamicRecord.dynamicRecord( 21, true ); final Collection recordsAfter = Arrays.asList( record ); - final UniquenessConstraintRule rule = UniquenessConstraintRule.uniquenessConstraintRule( 0l, 1, 2, 3l ); + final UniquePropertyConstraintRule + rule = UniquePropertyConstraintRule.uniquenessConstraintRule( 0l, 1, 2, 3l ); final Command.SchemaRuleCommand command = new Command.SchemaRuleCommand().init( Collections.emptyList(), recordsAfter, rule ); @@ -816,7 +819,8 @@ public void shouldApplyUpdateUniquenessConstraintRuleSchemaRuleCommandToTheStore final NeoCommandHandler applier = newApplier( true ); final DynamicRecord record = DynamicRecord.dynamicRecord( 21, true ); final Collection recordsAfter = Arrays.asList( record ); - final UniquenessConstraintRule rule = UniquenessConstraintRule.uniquenessConstraintRule( 0l, 1, 2, 3l ); + final UniquePropertyConstraintRule + rule = UniquePropertyConstraintRule.uniquenessConstraintRule( 0l, 1, 2, 3l ); final Command.SchemaRuleCommand command = new Command.SchemaRuleCommand().init( Collections.emptyList(), recordsAfter, rule ); @@ -841,7 +845,8 @@ public void shouldApplyDeleteUniquenessConstraintRuleSchemaRuleCommandToTheStore final DynamicRecord record = DynamicRecord.dynamicRecord( 21, true ); record.setInUse( false ); final Collection recordsAfter = Arrays.asList( record ); - final UniquenessConstraintRule rule = UniquenessConstraintRule.uniquenessConstraintRule( 0l, 1, 2, 3l ); + final UniquePropertyConstraintRule + rule = UniquePropertyConstraintRule.uniquenessConstraintRule( 0l, 1, 2, 3l ); final Command.SchemaRuleCommand command = new Command.SchemaRuleCommand().init( Collections.emptyList(), recordsAfter, rule ); @@ -864,7 +869,8 @@ public void shouldApplyDeleteUniquenessConstraintRuleSchemaRuleCommandToTheStore final DynamicRecord record = DynamicRecord.dynamicRecord( 21, true ); record.setInUse( false ); final Collection recordsAfter = Arrays.asList( record ); - final UniquenessConstraintRule rule = UniquenessConstraintRule.uniquenessConstraintRule( 0l, 1, 2, 3l ); + final UniquePropertyConstraintRule + rule = UniquePropertyConstraintRule.uniquenessConstraintRule( 0l, 1, 2, 3l ); final Command.SchemaRuleCommand command = new Command.SchemaRuleCommand().init( Collections.emptyList(), recordsAfter, rule ); diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/state/IntegrityValidatorTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/state/IntegrityValidatorTest.java index fd85694f405c4..27b7d9f541ad5 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/state/IntegrityValidatorTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/state/IntegrityValidatorTest.java @@ -23,7 +23,7 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.when; -import static org.neo4j.kernel.impl.store.UniquenessConstraintRule.uniquenessConstraintRule; +import static org.neo4j.kernel.impl.store.UniquePropertyConstraintRule.uniquenessConstraintRule; import static org.powermock.api.mockito.PowerMockito.mock; import org.junit.Test; @@ -31,9 +31,8 @@ import org.neo4j.kernel.api.exceptions.schema.ConstraintVerificationFailedKernelException; import org.neo4j.kernel.impl.api.index.IndexingService; import org.neo4j.kernel.impl.store.NeoStore; -import org.neo4j.kernel.impl.store.UniquenessConstraintRule; +import org.neo4j.kernel.impl.store.UniquePropertyConstraintRule; import org.neo4j.kernel.impl.store.record.NodeRecord; -import org.neo4j.kernel.impl.transaction.state.IntegrityValidator; public class IntegrityValidatorTest { @@ -48,7 +47,7 @@ public void shouldValidateUniquenessIndexes() throws Exception doThrow( new ConstraintVerificationFailedKernelException( null, new RuntimeException() )) .when( indexes ).validateIndex( 2l ); - UniquenessConstraintRule record = uniquenessConstraintRule( 1l, 1, 1, 2l ); + UniquePropertyConstraintRule record = uniquenessConstraintRule( 1l, 1, 1, 2l ); // When try diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/state/NeoStoreTransactionTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/state/NeoStoreTransactionTest.java index b5e8e757cb96f..192638da9cbf3 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/state/NeoStoreTransactionTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/state/NeoStoreTransactionTest.java @@ -143,7 +143,7 @@ import static org.neo4j.kernel.api.index.SchemaIndexProvider.NO_INDEX_PROVIDER; import static org.neo4j.kernel.impl.api.TransactionApplicationMode.INTERNAL; import static org.neo4j.kernel.impl.api.index.TestSchemaIndexProviderDescriptor.PROVIDER_DESCRIPTOR; -import static org.neo4j.kernel.impl.store.UniquenessConstraintRule.uniquenessConstraintRule; +import static org.neo4j.kernel.impl.store.UniquePropertyConstraintRule.uniquenessConstraintRule; import static org.neo4j.kernel.impl.store.record.IndexRule.indexRule; import static org.neo4j.kernel.impl.transaction.log.TransactionIdStore.BASE_TX_ID; diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/state/SchemaRuleCommandTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/state/SchemaRuleCommandTest.java index 7cdae729b029f..baf1d73cee144 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/state/SchemaRuleCommandTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/state/SchemaRuleCommandTest.java @@ -55,7 +55,7 @@ import static org.neo4j.helpers.collection.IteratorUtil.first; import static org.neo4j.kernel.impl.api.index.TestSchemaIndexProviderDescriptor.PROVIDER_DESCRIPTOR; -import static org.neo4j.kernel.impl.store.UniquenessConstraintRule.uniquenessConstraintRule; +import static org.neo4j.kernel.impl.store.UniquePropertyConstraintRule.uniquenessConstraintRule; public class SchemaRuleCommandTest { diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/util/dbstructure/CineastsDbStructure.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/util/dbstructure/CineastsDbStructure.java index cb05228355047..c11905d9a1c80 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/util/dbstructure/CineastsDbStructure.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/util/dbstructure/CineastsDbStructure.java @@ -20,8 +20,6 @@ package org.neo4j.kernel.impl.util.dbstructure; import org.neo4j.helpers.collection.Visitable; -import org.neo4j.kernel.impl.util.dbstructure.DbStructureVisitor; - import org.neo4j.kernel.api.constraints.UniquenessConstraint; import org.neo4j.kernel.api.index.IndexDescriptor; diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureArgumentFormatterTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureArgumentFormatterTest.java index 12dd68309319a..d7f8931e10eeb 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureArgumentFormatterTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureArgumentFormatterTest.java @@ -19,14 +19,14 @@ */ package org.neo4j.kernel.impl.util.dbstructure; -import java.io.IOException; - import org.junit.Test; +import java.io.IOException; + import org.neo4j.kernel.api.constraints.UniquenessConstraint; import org.neo4j.kernel.api.index.IndexDescriptor; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; public class DbStructureArgumentFormatterTest { diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureCollectorTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureCollectorTest.java index 1c84468387e4e..acd527a8c0dcc 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureCollectorTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureCollectorTest.java @@ -25,9 +25,7 @@ import org.neo4j.kernel.api.index.IndexDescriptor; import static java.util.Arrays.asList; - import static org.junit.Assert.assertEquals; - import static org.neo4j.helpers.Pair.of; import static org.neo4j.helpers.collection.Iterables.toList; diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureInvocationTracingAcceptanceTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureInvocationTracingAcceptanceTest.java index 63bd02d3dee8d..632d9fafe2b23 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureInvocationTracingAcceptanceTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/util/dbstructure/DbStructureInvocationTracingAcceptanceTest.java @@ -19,6 +19,8 @@ */ package org.neo4j.kernel.impl.util.dbstructure; +import org.junit.Test; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; @@ -41,8 +43,6 @@ import javax.tools.StandardLocation; import javax.tools.ToolProvider; -import org.junit.Test; - import org.neo4j.function.Function; import org.neo4j.helpers.collection.Visitable; import org.neo4j.kernel.api.constraints.UniquenessConstraint; @@ -52,7 +52,6 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; - import static org.neo4j.function.Functions.constant; public class DbStructureInvocationTracingAcceptanceTest diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/util/dbstructure/GraphDbStructureGuideTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/util/dbstructure/GraphDbStructureGuideTest.java index 1f405b7443cc7..dad44521e2d8d 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/util/dbstructure/GraphDbStructureGuideTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/util/dbstructure/GraphDbStructureGuideTest.java @@ -34,7 +34,7 @@ import org.neo4j.kernel.api.ReadOperations; import org.neo4j.kernel.api.SchemaWriteOperations; import org.neo4j.kernel.api.Statement; -import org.neo4j.kernel.api.constraints.UniquenessConstraint; +import org.neo4j.kernel.api.constraints.PropertyConstraint; import org.neo4j.kernel.api.exceptions.InvalidTransactionTypeKernelException; import org.neo4j.kernel.api.index.IndexDescriptor; import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; @@ -129,7 +129,7 @@ public void visitsUniqueConstraintsAndIndices() throws Exception commitAndReOpen(); - UniquenessConstraint constraint = createUniqueConstraint( labelId, pkId ); + PropertyConstraint constraint = createUniqueConstraint( labelId, pkId ); IndexDescriptor descriptor = new IndexDescriptor( labelId, pkId ); // WHEN @@ -214,9 +214,9 @@ private IndexDescriptor createSchemaIndex( int labelId, int pkId ) throws Except return schemaWrite().indexCreate( labelId, pkId ); } - private UniquenessConstraint createUniqueConstraint( int labelId, int pkId ) throws Exception + private PropertyConstraint createUniqueConstraint( int labelId, int pkId ) throws Exception { - return schemaWrite().uniquenessConstraintCreate( labelId, pkId ); + return schemaWrite().uniquePropertyConstraintCreate( labelId, pkId ); } private int createLabeledNodes( String labelName, int amount ) throws Exception diff --git a/community/kernel/src/test/java/org/neo4j/unsafe/batchinsert/BatchInsertTest.java b/community/kernel/src/test/java/org/neo4j/unsafe/batchinsert/BatchInsertTest.java index dd3e0257d69db..be9c74fc5b271 100644 --- a/community/kernel/src/test/java/org/neo4j/unsafe/batchinsert/BatchInsertTest.java +++ b/community/kernel/src/test/java/org/neo4j/unsafe/batchinsert/BatchInsertTest.java @@ -82,7 +82,7 @@ import org.neo4j.kernel.impl.store.SchemaStore; import org.neo4j.kernel.impl.store.StoreFactory; import org.neo4j.kernel.impl.store.UnderlyingStorageException; -import org.neo4j.kernel.impl.store.UniquenessConstraintRule; +import org.neo4j.kernel.impl.store.UniquePropertyConstraintRule; import org.neo4j.kernel.impl.store.record.DynamicRecord; import org.neo4j.kernel.impl.store.record.IndexRule; import org.neo4j.kernel.impl.store.record.NodeRecord; @@ -910,15 +910,15 @@ public void shouldCreateConsistentUniquenessConstraint() throws Exception SchemaRule rule0 = storage.loadSingleSchemaRule( inUse.get( 0 ) ); SchemaRule rule1 = storage.loadSingleSchemaRule( inUse.get( 1 ) ); IndexRule indexRule; - UniquenessConstraintRule constraintRule; + UniquePropertyConstraintRule constraintRule; if ( rule0 instanceof IndexRule ) { indexRule = (IndexRule) rule0; - constraintRule = (UniquenessConstraintRule) rule1; + constraintRule = (UniquePropertyConstraintRule) rule1; } else { - constraintRule = (UniquenessConstraintRule) rule0; + constraintRule = (UniquePropertyConstraintRule) rule0; indexRule = (IndexRule) rule1; } assertEquals( "index should reference constraint", diff --git a/community/shell/src/test/java/org/neo4j/shell/TestApps.java b/community/shell/src/test/java/org/neo4j/shell/TestApps.java index 55a2ca935c38a..6fbbf3fdc342a 100644 --- a/community/shell/src/test/java/org/neo4j/shell/TestApps.java +++ b/community/shell/src/test/java/org/neo4j/shell/TestApps.java @@ -856,7 +856,7 @@ public void canListIndexesWhenNoOptionGiven() throws Exception } @Test - public void canListConstraints() throws Exception + public void canListUniquePropertyConstraints() throws Exception { // GIVEN Label label = label( "Person" ); @@ -869,7 +869,20 @@ public void canListConstraints() throws Exception } @Test - public void canListConstraintsByLabel() throws Exception + public void canListMandatoryPropertyConstraints() throws Exception + { + // GIVEN + Label label = label( "Person" ); + beginTx(); + db.schema().constraintFor( label ).assertPropertyExists( "name" ).create(); + finishTx(); + + // WHEN / THEN + executeCommand( "schema ls", "ON \\(person:Person\\) ASSERT person.name IS NOT NULL" ); + } + + @Test + public void canListUniquePropertyConstraintsByLabel() throws Exception { // GIVEN Label label1 = label( "Person" ); @@ -882,7 +895,20 @@ public void canListConstraintsByLabel() throws Exception } @Test - public void canListConstraintsByLabelAndProperty() throws Exception + public void canListMandatoryPropertyConstraintsByLabel() throws Exception + { + // GIVEN + Label label1 = label( "Person" ); + beginTx(); + db.schema().constraintFor( label1 ).assertPropertyExists( "name" ).create(); + finishTx(); + + // WHEN / THEN + executeCommand( "schema ls -l :Person", "ON \\(person:Person\\) ASSERT person.name IS NOT NULL" ); + } + + @Test + public void canListUniquePropertyConstraintsByLabelAndProperty() throws Exception { // GIVEN Label label1 = label( "Person" ); @@ -894,6 +920,19 @@ public void canListConstraintsByLabelAndProperty() throws Exception executeCommand( "schema ls -l :Person -p name", "ON \\(person:Person\\) ASSERT person.name IS UNIQUE" ); } + @Test + public void canListMandatoryPropertyConstraintsByLabelAndProperty() throws Exception + { + // GIVEN + Label label1 = label( "Person" ); + beginTx(); + db.schema().constraintFor( label1 ).assertPropertyExists( "name" ).create(); + finishTx(); + + // WHEN / THEN + executeCommand( "schema ls -l :Person -p name", "ON \\(person:Person\\) ASSERT person.name IS NOT NULL" ); + } + @Test public void failSampleWhenNoOptionGiven() throws Exception { diff --git a/enterprise/ha/src/test/java/org/neo4j/kernel/api/UniqueConstraintHaIT.java b/enterprise/ha/src/test/java/org/neo4j/kernel/api/UniqueConstraintHaIT.java index fbb3da5e5f45e..82087123c5928 100644 --- a/enterprise/ha/src/test/java/org/neo4j/kernel/api/UniqueConstraintHaIT.java +++ b/enterprise/ha/src/test/java/org/neo4j/kernel/api/UniqueConstraintHaIT.java @@ -32,7 +32,7 @@ import org.neo4j.kernel.ha.HaSettings; import org.neo4j.kernel.ha.HighlyAvailableGraphDatabase; import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; -import org.neo4j.kernel.impl.coreapi.schema.PropertyUniqueConstraintDefinition; +import org.neo4j.kernel.impl.coreapi.schema.PropertyConstraintDefinition; import org.neo4j.test.ha.ClusterManager; import org.neo4j.test.ha.ClusterRule; @@ -216,9 +216,9 @@ public void newSlaveJoiningClusterShouldNotAcceptOperationsUntilConstraintIsOnli // Then try( Transaction ignored = slave.beginTx() ) { - assertThat(single( slave.schema().getConstraints() ), instanceOf(PropertyUniqueConstraintDefinition.class)); - PropertyUniqueConstraintDefinition constraint = - (PropertyUniqueConstraintDefinition)single(slave.schema().getConstraints()); + assertThat(single( slave.schema().getConstraints() ), instanceOf(PropertyConstraintDefinition.class)); + PropertyConstraintDefinition constraint = + (PropertyConstraintDefinition)single(slave.schema().getConstraints()); assertThat(single(constraint.getPropertyKeys()), equalTo("name")); assertThat(constraint.getLabel(), equalTo(label("User"))); }