trailblazerneo4jrb

Using the Neo4jrb gem, is it possible to use one transaction across multiple blocks


Using the neo4jrb/neo4j gem (8.x), I know it is possible to run multiple queries inside a single transaction like so

person = Person.find_by(id: person_id)

Neo4j::ActiveBase.run_transaction do |tx|
  person.update(name: 'New name')
  person.update(number: 1)
end

But it possible to open a transaction, and then use that same transaction across multiple blocks. Something like:

person = Person.find_by(id: person_id)

transaction = Neo4j::ActiveBase.new_transaction

transaction.run do |tx|
  person.update(name: 'New name')
end

transaction.run do |tx|
  person.update(number: 1)
end

transaction.close

The reason why this functionality is desirable is because I'm using Neo4jrb inside of a Trailblazer-Operation. The trailblazer operation is broken up into discrete steps which are themselves written as separate methods. I want several of the steps wrapped in a transaction, but, without monkey patching the operation, I don't have the ability to execute some steps inside one transaction block.

Thanks!


Solution

  • So it turns out that my problem has multiple solutions.

    While it wasn't immediately apparent to me that this was the case, after a new transaction is created in Neo4jrb, any subsequent queries in that same session are automatically associated with the transaction as long as it remains open.

    person = Person.find_by(id: person_id)
    
    transaction = Neo4j::ActiveBase.new_transaction
    
    one = person.update(name: 'New name')
    
    two = person.update(number: 1)
    
    transaction.close
    

    In the above example, both one and two are committed as part of transaction. So this solves my problem.

    Another solution to my problem, is that trailblazer-operation has a specific method for wrapping steps in a db transaction block, as documented on Trailblazer's website.

    step Wrap ->(*, &block) { Sequel.transaction do block.call end } {
      step Model( Song, :new )
      step Contract::Build( constant: MyContract )
      step Contract::Validate( )
      step Contract::Persist( method: :sync )
    }
    

    In the above example, all of the step methods inside step Wrap are called within the scope of the Sequel.transaction block.