Re-adding a relationship after deleting, doesn't work

I'm having trouble with a complex query and large dataset. For a given dataset a batch query might add, remove and re-add the same relationship between the same two nodes. This is not working for me, given my query and I can't figure out why.

Here's a whittled down query that reproduces the problem.

WITH [
    {
        entity_id: 'e41',
        component_id: 'SceneNodeChildOf',
        has_parent: true,
        parent: 'f5'
    },
    {
        entity_id: 'c57',
        component_id: 'SceneNodeChildOf',
        has_parent: true,
        parent: 'e41'
    },
    {
        entity_id: 'c57',
        component_id: 'SceneNodeChildOf',
        value: '',
        has_parent: true,
        parent: ''
    },
    {
        entity_id: 'c57',
        component_id: 'SceneNodeChildOf',
        has_parent: true,
        parent: 'e41'
    }
] AS batch
UNWIND batch as row
MERGE (e:Entity {id: row.entity_id})
WITH e as child, row
CALL {
    WITH child, row
    WITH child, row WHERE row.has_parent=True AND row.parent <> ''
    MERGE (parent:Entity {id: row.parent})
    MERGE (parent)<-[:CHILD_OF]-(child)
}
WITH child, row
CALL {
    WITH child, row
    WITH child, row WHERE row.has_parent = True AND row.parent = ''
    MATCH (child:Entity {id: row.entity_id})-[r:CHILD_OF]->(:Entity)
        DELETE r
}

I expect that the first item in the batch would create two nodes e41 and f5, and one CHILD_OF relationship e41 being a child of f5.

The second item in the batch would create one new node, c57 that is a child of e41.

The third item in the batch creates no new nodes, and removes the child of relationship between c57 and e41. i.e. c57 is no longer a child of e41.

The last item in the batch should re-add the child of relationship just previously removed. But it does not. I end up with the following graph after running this query:

If I run the same query but without the last two items in the batch, I end up with the following graph:

This is what I was expecting after deleting and re-adding the relationship.

I don't understand this behavior and what is wrong with my query. Can someone give me a hand?

After being pointed in the direction of apoc procedures to make my query cleaner, I've come up with the following query which does work as expected.

WITH [
    {
        entity_id: 'e41',
        component_id: 'SceneNodeChildOf',
        has_parent: true,
        parent: 'f5'
    },
    {
        entity_id: 'c57',
        component_id: 'SceneNodeChildOf',
        has_parent: true,
        parent: 'e41'
    },
    {
        entity_id: 'c57',
        component_id: 'SceneNodeChildOf',
        value: '',
        has_parent: true,
        parent: ''
    },
    {
        entity_id: 'c57',
        component_id: 'SceneNodeChildOf',
        has_parent: true,
        parent: 'e41'
    }
] AS batch
UNWIND batch as row
MERGE (e:Entity {id: row.entity_id})
WITH e as child, row
CALL {
    WITH child, row
    CALL apoc.do.case([
        row.has_parent = True AND row.parent <> '',
        'MERGE (parent:Entity {id: row.parent})
         MERGE (parent)<-[:CHILD_OF]-(child)
         RETURN child',
        row.has_parent = True AND row.parent = '',
        'MATCH (child:Entity {id: row.entity_id})-[r:CHILD_OF]->(:Entity)
         DELETE r
         RETURN child'
    ],
    'RETURN child', {child:child, row:row})
    YIELD value as entity
}

Though I would still like to understand why my original query didn't work as expected. I'm using a sub-query here because there is more to my query, when it is not whittled down to this reproducible example.

Hi @mburbidg1 getting back to this

Cypher always executes each clause completely, before going to the next.UNWIND produces a table with a row column. Each row of that table is fed into MERGE clause, which performs side effects and introduces e column to the intermediate results table.

That table is then fully processed by they first CALL {} clause, which also performs updates.

Then the intermediate results table is processed by the next CALL {} clause.

There is no going back and forth between clauses, it's all linear. The rule to remember is that preceding clauses can never see updates made by later clauses. In this case, the first CALL {} clause cannot possibly see and DELETE performed by the second CALL {} .

More on clause composition