ruby-rdf/rdf

View on GitHub
lib/rdf/mixin/transactable.rb

Summary

Maintainability
A
0 mins
Test Coverage
module RDF
  ##
  # A transaction application mixin.
  # 
  # Classes that include this module must provide a `#begin_transaction` method
  # returning an {RDF::Transaction}.
  #
  # @example running a read/write transaction with block syntax
  #   repository = RDF::Repository.new # or other transactable
  #
  #   repository.transaction(mutable: true) do |tx|
  #     tx.insert [:node, RDF.type, RDF::OWL.Thing]
  #     # ...
  #   end
  #
  # @see RDF::Transaction
  # @since 2.0.0
  module Transactable
    ##
    # Executes the given block in a transaction.
    #
    # @example running a transaction
    #   repository.transaction(mutable: true) do |tx|
    #     tx.insert [RDF::URI("https://rubygems.org/gems/rdf"), RDF::RDFS.label, "RDF.rb"]
    #   end
    #
    # Raising an error within the transaction block causes automatic rollback.
    #
    # @example manipulating a live transaction
    #   tx = repository.transaction(mutable: true)
    #   tx.insert [RDF::URI("https://rubygems.org/gems/rdf"), RDF::RDFS.label, "RDF.rb"]
    #   tx.execute
    #
    # @overload transaction(mutable: false)
    #   @param mutable [Boolean]
    #   @return [RDF::Transaction] an open transaction; the client is 
    #     responsible for closing the transaction via #execute or #rollback
    #
    # @overload transaction(mutable: false, &block)
    #   @param mutable [Boolean] 
    #     allows changes to the transaction, otherwise it is a read-only 
    #     snapshot of the underlying repository.
    #   @yield  [tx]
    #   @yieldparam  [RDF::Transaction] tx
    #   @yieldreturn [void] ignored
    #   @return [self]
    #
    # @see    RDF::Transaction
    # @since  0.3.0
    def transaction(mutable: false, &block)
      tx = begin_transaction(mutable: mutable)
      return tx unless block_given?

      begin
        case block.arity
          when 1 then block.call(tx)
          else tx.instance_eval(&block)
        end
      rescue => error
        rollback_transaction(tx)
        raise error
      end
      commit_transaction(tx)
      self
    end
    alias_method :transact, :transaction

  protected

    ##
    # Begins a new transaction.
    #
    # Subclasses implementing transaction-capable storage adapters may wish
    # to override this method in order to begin a transaction against the
    # underlying storage.
    #
    # @param mutable [Boolean] Create a mutable or immutable transaction.
    # @param graph_name [Boolean] A default graph name for statements inserted
    #   or deleted (default: nil)
    # @return [RDF::Transaction]
    def begin_transaction(mutable: false, graph_name: nil)
      raise NotImplementedError
    end

    ##
    # Rolls back the given transaction.
    #
    # @param  [RDF::Transaction] tx
    # @return [void] ignored
    # @since  0.3.0
    def rollback_transaction(tx)
      tx.rollback
    end

    ##
    # Commits the given transaction.
    #
    # Subclasses implementing transaction-capable storage adapters may wish
    # to override this method in order to commit the given transaction to
    # the underlying storage.
    #
    # @param  [RDF::Transaction] tx
    # @return [void] ignored
    # @since  0.3.0
    def commit_transaction(tx)
      tx.execute
    end
  end
end