diff --git a/driver/src/main/java/org/neo4j/driver/internal/summary/InternalSummaryCounters.java b/driver/src/main/java/org/neo4j/driver/internal/summary/InternalSummaryCounters.java index 33e686902b..37554439c4 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/summary/InternalSummaryCounters.java +++ b/driver/src/main/java/org/neo4j/driver/internal/summary/InternalSummaryCounters.java @@ -23,7 +23,7 @@ public class InternalSummaryCounters implements SummaryCounters { public static final InternalSummaryCounters EMPTY_STATS = - new InternalSummaryCounters( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); + new InternalSummaryCounters( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); private final int nodesCreated; private final int nodesDeleted; private final int relationshipsCreated; @@ -35,6 +35,7 @@ public class InternalSummaryCounters implements SummaryCounters private final int indexesRemoved; private final int constraintsAdded; private final int constraintsRemoved; + private final int systemUpdates; public InternalSummaryCounters( int nodesCreated, int nodesDeleted, @@ -42,7 +43,7 @@ public InternalSummaryCounters( int propertiesSet, int labelsAdded, int labelsRemoved, int indexesAdded, int indexesRemoved, - int constraintsAdded, int constraintsRemoved ) + int constraintsAdded, int constraintsRemoved, int systemUpdates ) { this.nodesCreated = nodesCreated; this.nodesDeleted = nodesDeleted; @@ -55,6 +56,7 @@ public InternalSummaryCounters( this.indexesRemoved = indexesRemoved; this.constraintsAdded = constraintsAdded; this.constraintsRemoved = constraintsRemoved; + this.systemUpdates = systemUpdates; } @Override @@ -140,6 +142,18 @@ public int constraintsRemoved() return constraintsRemoved; } + @Override + public boolean containsSystemUpdates() + { + return isPositive( systemUpdates ); + } + + @Override + public int systemUpdates() + { + return systemUpdates; + } + @Override public boolean equals( Object o ) { @@ -164,7 +178,8 @@ public boolean equals( Object o ) && indexesAdded == that.indexesAdded && indexesRemoved == that.indexesRemoved && constraintsAdded == that.constraintsAdded - && constraintsRemoved == that.constraintsRemoved; + && constraintsRemoved == that.constraintsRemoved + && systemUpdates == that.systemUpdates; } @Override @@ -181,6 +196,7 @@ public int hashCode() result = 31 * result + indexesRemoved; result = 31 * result + constraintsAdded; result = 31 * result + constraintsRemoved; + result = 31 * result + systemUpdates; return result; } diff --git a/driver/src/main/java/org/neo4j/driver/internal/util/MetadataExtractor.java b/driver/src/main/java/org/neo4j/driver/internal/util/MetadataExtractor.java index e708bf44e1..c7d4ce29d6 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/util/MetadataExtractor.java +++ b/driver/src/main/java/org/neo4j/driver/internal/util/MetadataExtractor.java @@ -178,7 +178,8 @@ private static InternalSummaryCounters extractCounters( Map metada counterValue( countersValue, "indexes-added" ), counterValue( countersValue, "indexes-removed" ), counterValue( countersValue, "constraints-added" ), - counterValue( countersValue, "constraints-removed" ) + counterValue( countersValue, "constraints-removed" ), + counterValue( countersValue, "system-updates" ) ); } return null; diff --git a/driver/src/main/java/org/neo4j/driver/summary/SummaryCounters.java b/driver/src/main/java/org/neo4j/driver/summary/SummaryCounters.java index 291755ea25..76e82e9c7e 100644 --- a/driver/src/main/java/org/neo4j/driver/summary/SummaryCounters.java +++ b/driver/src/main/java/org/neo4j/driver/summary/SummaryCounters.java @@ -87,4 +87,15 @@ public interface SummaryCounters * @return number of constraints removed from the schema. */ int constraintsRemoved(); + + /** + * If the query updated the system graph in any way, this method will return true, + * @return true if the system graph has been updated. + */ + boolean containsSystemUpdates(); + + /** + * @return the number of system updates performed by this query. + */ + int systemUpdates(); } diff --git a/driver/src/test/java/org/neo4j/driver/integration/SummaryIT.java b/driver/src/test/java/org/neo4j/driver/integration/SummaryIT.java index 75733d3a6e..bd62e60beb 100644 --- a/driver/src/test/java/org/neo4j/driver/integration/SummaryIT.java +++ b/driver/src/test/java/org/neo4j/driver/integration/SummaryIT.java @@ -18,22 +18,27 @@ */ package org.neo4j.driver.integration; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import java.util.List; import java.util.concurrent.TimeUnit; +import org.neo4j.driver.Session; import org.neo4j.driver.StatementResult; import org.neo4j.driver.Value; import org.neo4j.driver.Values; +import org.neo4j.driver.internal.util.EnabledOnNeo4jWith; +import org.neo4j.driver.internal.util.Neo4jFeature; import org.neo4j.driver.summary.Notification; import org.neo4j.driver.summary.Plan; import org.neo4j.driver.summary.ProfiledPlan; import org.neo4j.driver.summary.ResultSummary; import org.neo4j.driver.summary.StatementType; +import org.neo4j.driver.util.DatabaseExtension; import org.neo4j.driver.util.ParallelizableIT; -import org.neo4j.driver.util.SessionExtension; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThan; @@ -44,12 +49,30 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.neo4j.driver.SessionConfig.forDatabase; @ParallelizableIT class SummaryIT { @RegisterExtension - static final SessionExtension session = new SessionExtension(); + static final DatabaseExtension neo4j = new DatabaseExtension(); + private Session session; + + @BeforeEach + void setup() + { + session = neo4j.driver().session(); + } + + @AfterEach + void tearDown() + { + if ( session != null && session.isOpen() ) + { + session.close(); + } + session = null; + } @Test void shouldContainBasicMetadata() @@ -112,6 +135,18 @@ void shouldContainCorrectStatistics() .summary().counters().constraintsRemoved(), equalTo( 1 ) ); } + @Test + @EnabledOnNeo4jWith( Neo4jFeature.BOLT_V4 ) + void shouldGetSystemUpdates() throws Throwable + { + try ( Session session = neo4j.driver().session( forDatabase( "system" ) ) ) + { + StatementResult result = session.run( "CREATE USER foo SET PASSWORD 'bar'" ); + assertThat( result.summary().counters().containsUpdates(), equalTo( false ) ); + assertThat( result.summary().counters().containsSystemUpdates(), equalTo( true ) ); + } + } + @Test void shouldContainCorrectStatementType() { diff --git a/driver/src/test/java/org/neo4j/driver/internal/async/AsyncStatementResultCursorImplTest.java b/driver/src/test/java/org/neo4j/driver/internal/async/AsyncStatementResultCursorImplTest.java index 8c11556974..ab68480607 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/async/AsyncStatementResultCursorImplTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/async/AsyncStatementResultCursorImplTest.java @@ -88,7 +88,8 @@ void shouldReturnSummary() ResultSummary summary = new InternalResultSummary( new Statement( "RETURN 42" ), new InternalServerInfo( BoltServerAddress.LOCAL_DEFAULT, anyServerVersion() ), DEFAULT_DATABASE_INFO, StatementType.SCHEMA_WRITE, - new InternalSummaryCounters( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ), null, null, emptyList(), 42, 42 ); + new InternalSummaryCounters( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0 ), + null, null, emptyList(), 42, 42 ); when( pullAllHandler.summaryAsync() ).thenReturn( completedFuture( summary ) ); AsyncStatementResultCursorImpl cursor = newCursor( pullAllHandler );