Class: Boltless::Transaction

Inherits:
Object
  • Object
show all
Defined in:
lib/boltless/transaction.rb

Overview

A single neo4j transaction representation.

When passing Cypher statements you can tweak some HTTP API result options while passing the following keys to the Cypher parameters (they wont be sent to neo4j):

* +with_stats: true|false+: whenever to include statement
  statistics, or not (see: https://bit.ly/3SKXfC8)
* +result_as_graph: true|false+: whenever to return the result as a graph
  structure that can be visualized (see: https://bit.ly/3doJw3Z)

Error handling details (see: bit.ly/3pdqTCy):

> If there is an error in a request, the server will roll back the > transaction. You can tell if the transaction is still open by inspecting > the response for the presence/absence of the transaction key.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(connection, database: Boltless.configuration.default_db, access_mode: :write, raw_results: false) ⇒ Transaction

Setup a new neo4j transaction management instance.

Parameters:

  • connection (HTTP::Client)

    a ready to use persistent connection object

  • database (String, Symbol) (defaults to: Boltless.configuration.default_db)

    the neo4j database to use

  • access_mode (String, Symbol) (defaults to: :write)

    the neo4j transaction mode (:read, or :write)

  • raw_results (Boolean) (defaults to: false)

    whenever to return the plain HTTP API JSON results (as plain Hash{Symbol => Mixed}/Array data), or not (then we return Array<Boltless::Result> structs



39
40
41
42
43
44
45
46
# File 'lib/boltless/transaction.rb', line 39

def initialize(connection, database: Boltless.configuration.default_db,
               access_mode: :write, raw_results: false)
  @request = Request.new(connection, access_mode: access_mode,
                                     database: database,
                                     raw_results: raw_results)
  @access_mode = access_mode
  @raw_state = :not_yet_started
end

Instance Attribute Details

#access_modeObject (readonly)

We allow to read some internal configurations



22
23
24
# File 'lib/boltless/transaction.rb', line 22

def access_mode
  @access_mode
end

#idObject (readonly)

We allow to read some internal configurations



22
23
24
# File 'lib/boltless/transaction.rb', line 22

def id
  @id
end

#raw_stateObject (readonly)

We allow to read some internal configurations



22
23
24
# File 'lib/boltless/transaction.rb', line 22

def raw_state
  @raw_state
end

Instance Method Details

#beginBoolean

Begin a new transaction. We rescue all errors transparently.

Returns:

  • (Boolean)

    whenever the transaction was successfully started, or not



78
79
80
# File 'lib/boltless/transaction.rb', line 78

def begin
  handle_errors(false) { begin! }
end

#begin!TrueClass

Begin a new transaction. No exceptions will be rescued.

Returns:

  • (TrueClass)

    when the transaction was successfully started

Raises:



62
63
64
65
66
67
68
69
70
71
72
# File 'lib/boltless/transaction.rb', line 62

def begin!
  # We do not allow messing around in wrong states
  unless @raw_state == :not_yet_started
    raise Errors::TransactionInBadStateError,
          "Transaction already #{@raw_state}"
  end

  @id = @request.begin_transaction
  @raw_state = :open
  true
end

#cleanupObject

Clean the transaction, in order to make it unusable for further interaction. This prevents users from leaking the transaction context and mess around with the connection pool.



229
230
231
232
# File 'lib/boltless/transaction.rb', line 229

def cleanup
  @request = nil
  @raw_state = :cleaned
end

#commit(*statements) ⇒ Array<Hash{Symbol => Mixed}>?

Commit the transaction, while also sending finalizing Cypher statement(s). This results in a single HTTP API request for all the statement(s). You can also omit the statement(s) in order to just commit the transaction. We rescue all errors transparently.

Parameters:

  • statements (Array<Hash>)

    the Cypher statements to run

Returns:

  • (Array<Hash{Symbol => Mixed}>, nil)

    the raw neo4j results, or nil in case of errors

Raises:



173
174
175
# File 'lib/boltless/transaction.rb', line 173

def commit(*statements)
  handle_errors { commit!(*statements) }
end

#commit!(*statements) ⇒ Array<Hash{Symbol => Mixed}>

Commit the transaction, while also sending finalizing Cypher statement(s). This results in a single HTTP API request for all the statement(s). You can also omit the statement(s) in order to just commit the transaction.

Parameters:

  • statements (Array<Hash>)

    the Cypher statements to run

Returns:

  • (Array<Hash{Symbol => Mixed}>)

    the raw neo4j results

Raises:



151
152
153
154
155
156
157
158
159
160
# File 'lib/boltless/transaction.rb', line 151

def commit!(*statements)
  # We do not allow messing around in wrong states
  raise Errors::TransactionInBadStateError, 'Transaction not open' \
    unless @raw_state == :open

  @request.commit_transaction(
    @id,
    *Request.statement_payloads(*statements)
  ).tap { @raw_state = :closed }
end

#handle_errors(error_result = nil) { ... } ⇒ Mixed

Handle all request/response errors of the low-level connection for our non-bang methods in a generic way.

Parameters:

  • error_result (Proc, Mixed) (defaults to: nil)

    the object to return on errors, when a proc is given, we call it with the actual exception object as parameter and use the result of the proc as return value

Yields:

  • the given block

Returns:

  • (Mixed)

    the result of the block, or on exceptions the given error_result



210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/boltless/transaction.rb', line 210

def handle_errors(error_result = nil)
  yield
rescue Errors::RequestError, Errors::ResponseError,
       Errors::TransactionInBadStateError => e
  # When an error occured, the transaction is automatically rolled back by
  # neo4j, so we cannot handle any further interaction
  cleanup
  @raw_state = :closed

  # When we got a proc/lambda as error result, call it
  return error_result.call(e) if error_result.is_a? Proc

  # Otherwise use the error result as it is
  error_result
end

#rollbackBoolean

Rollback this transaction. We rescue all errors transparently.

Returns:

  • (Boolean)

    whenever the transaction was successfully rolled back, or not



197
198
199
# File 'lib/boltless/transaction.rb', line 197

def rollback
  handle_errors(false) { rollback! }
end

#rollback!TrueClass

Rollback this transaction. No exceptions will be rescued.

Returns:

  • (TrueClass)

    when the transaction was successfully rolled back

Raises:



183
184
185
186
187
188
189
190
191
# File 'lib/boltless/transaction.rb', line 183

def rollback!
  # We do not allow messing around in wrong states
  raise Errors::TransactionInBadStateError, 'Transaction not open' \
    unless @raw_state == :open

  @request.rollback_transaction(@id)
  @raw_state = :closed
  true
end

#run(cypher, **args) ⇒ Array<Hash{Symbol => Mixed}>?

Run a single Cypher statement inside the transaction. This results in a single HTTP API request for the statement. We rescue all errors transparently.

Parameters:

  • cypher (String)

    the Cypher statement to run

  • args (Hash{Symbol => Mixed})

    the additional Cypher parameters

Returns:

  • (Array<Hash{Symbol => Mixed}>, nil)

    the raw neo4j results, or nil in case of errors



107
108
109
# File 'lib/boltless/transaction.rb', line 107

def run(cypher, **args)
  handle_errors { run!(cypher, **args) }
end

#run!(cypher, **args) ⇒ Hash{Symbol => Mixed}

Run a single Cypher statement inside the transaction. This results in a single HTTP API request for the statement.

Parameters:

  • cypher (String)

    the Cypher statement to run

  • args (Hash{Symbol => Mixed})

    the additional Cypher parameters

Returns:

  • (Hash{Symbol => Mixed})

    the raw neo4j results

Raises:



91
92
93
94
95
96
97
# File 'lib/boltless/transaction.rb', line 91

def run!(cypher, **args)
  # We do not allow messing around in wrong states
  raise Errors::TransactionInBadStateError, 'Transaction not open' \
    unless @raw_state == :open

  @request.run_query(@id, Request.statement_payload(cypher, **args)).first
end

#run_in_batch(*statements) ⇒ Array<Hash{Symbol => Mixed}>?

Run a multiple Cypher statement inside the transaction. This results in a single HTTP API request for all the statements. We rescue all errors transparently.

Parameters:

  • statements (Array<Hash>)

    the Cypher statements to run

Returns:

  • (Array<Hash{Symbol => Mixed}>, nil)

    the raw neo4j results, or nil in case of errors

Raises:



137
138
139
# File 'lib/boltless/transaction.rb', line 137

def run_in_batch(*statements)
  handle_errors { run_in_batch!(*statements) }
end

#run_in_batch!(*statements) ⇒ Array<Hash{Symbol => Mixed}>

Run a multiple Cypher statement inside the transaction. This results in a single HTTP API request for all the statements.

Parameters:

  • statements (Array<Hash>)

    the Cypher statements to run

Returns:

  • (Array<Hash{Symbol => Mixed}>)

    the raw neo4j results

Raises:



119
120
121
122
123
124
125
# File 'lib/boltless/transaction.rb', line 119

def run_in_batch!(*statements)
  # We do not allow messing around in wrong states
  raise Errors::TransactionInBadStateError, 'Transaction not open' \
    unless @raw_state == :open

  @request.run_query(@id, *Request.statement_payloads(*statements))
end

#stateActiveSupport::StringInquirer

Return the transaction state as ActiveSupport::StringInquirer for convenience.

Returns:

  • (ActiveSupport::StringInquirer)

    the transaction state



52
53
54
# File 'lib/boltless/transaction.rb', line 52

def state
  ActiveSupport::StringInquirer.new(@raw_state.to_s)
end