memgraphdbneo4j-java-api

How to know if CREATE query failed in Memgraph through Neo4j Java driver?


Description

I'm attempting to use Memgraph in my application by connecting to it using the Neo4j Java driver. I have a constraint that nodes of a certain label must have a certain property. When I try to create a node without that property, the create fails (as verified by a separate read query); however, the query and transaction in which I attempt to create the node give no indication of failure. Running the same create query in Memgraph Lab gives a clear error message. Is there a way for me to get a similar message using the driver, so that I can know if the create failed without needing to do a separate read?

Example

Here is a straightforward Kotlin main function that demonstrates the problem. I know Kotlin isn't the most common of languages, but hopefully it's legible enough.

import org.neo4j.driver.AuthTokens
import org.neo4j.driver.GraphDatabase
import org.neo4j.driver.Query
import org.neo4j.driver.Record
import org.neo4j.driver.Session
import org.neo4j.driver.summary.ResultSummary

fun main() {
    // setup: delete all nodes (so that I can run this repeatedly) and create a constraint on n:Foo
    val driver = GraphDatabase.driver("bolt://localhost:7687", AuthTokens.basic("myUsername", "myPassword")) // replace with the correct auth for your Memgraph database.
    driver.session().run("MATCH (n) \n DETACH DELETE n;")
    driver.session().run("CREATE CONSTRAINT ON (n:Foo) ASSERT EXISTS (n.bar);").consume()

    // attempt to create n:Foo with bar so that I know what a success looks like
    lateinit var successfulRecord: Record
    lateinit var successfulSummary: ResultSummary
    driver.session().use { session: Session ->
        session.beginTransaction().run {
            val query = Query("CREATE (node:Foo {bar: 3}) \n RETURN node")
            val result = run(query)
            successfulRecord = result.single()
            successfulSummary = result.consume()
            commit()
            close()
        }
    }

    // attempt to create n:Foo without bar. I want this to throw an error or give me a result indicating failure
    lateinit var failureRecord: Record
    lateinit var failureSummary: ResultSummary
    driver.session().use { session: Session ->
        session.beginTransaction().run {
            val query = Query("CREATE (node:Foo) \n RETURN node")
            val result = run(query)
            failureRecord = result.single()
            failureSummary = result.consume()
            commit() //commit() doesn't return anything
            close()
        }
        // I know of no way to get info from the session on whether the CREATE succeeded or not
    }

    // This is where I would like to see a piece of information that is meaningfully different between the two
    println(successfulRecord)
    println(failureRecord)
    println()
    println(successfulSummary)
    println(failureSummary)

    // Read from the db to make sure that the successful one was successful and the bad one failed.
    driver.session().use { session: Session ->
        session.beginTransaction().run {
            val query = Query("MATCH (node:Foo) \n RETURN node")
            val result = run(query)
            val nodeList = result.list()
            // These assertions correctly pass; the node without bar was not created and the node with bar was created
            assert(nodeList.size == 1)
            assert(nodeList[0].get(0).asMap()["bar"] == 3L)
        }
    }
}

It prints the following:

Record<{node: node<59>}>
Record<{node: node<60>}>

InternalResultSummary{query=Query{text='CREATE (node:Foo {bar: 3}) 
 RETURN node', parameters={}}, serverInfo=InternalServerInfo{address='localhost:7687', version='Neo4j/4.3.0'}, databaseInfo=InternalDatabaseInfo{name='null'}, queryType=WRITE_ONLY, counters=InternalSummaryCounters{nodesCreated=1, nodesDeleted=0, relationshipsCreated=0, relationshipsDeleted=0, propertiesSet=0, labelsAdded=1, labelsRemoved=0, indexesAdded=0, indexesRemoved=0, constraintsAdded=0, constraintsRemoved=0, systemUpdates=0}, plan=null, profile=null, notifications=[], resultAvailableAfter=-1, resultConsumedAfter=-1}
InternalResultSummary{query=Query{text='CREATE (node:Foo) 
 RETURN node', parameters={}}, serverInfo=InternalServerInfo{address='localhost:7687', version='Neo4j/4.3.0'}, databaseInfo=InternalDatabaseInfo{name='null'}, queryType=WRITE_ONLY, counters=InternalSummaryCounters{nodesCreated=1, nodesDeleted=0, relationshipsCreated=0, relationshipsDeleted=0, propertiesSet=0, labelsAdded=1, labelsRemoved=0, indexesAdded=0, indexesRemoved=0, constraintsAdded=0, constraintsRemoved=0, systemUpdates=0}, plan=null, profile=null, notifications=[], resultAvailableAfter=-1, resultConsumedAfter=-1}

Process finished with exit code 0

which does not show any difference between the successful creation and the failed creation.

I have tried the following

Versions:


Solution

  • This was indeed a bug with Memgraph, not with my code. The Memgraph team has worked on it, and I have confirmed that this bug is fixed in version 2.13.0 of Memgraph.