Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
jsonapi-resources / lib / jsonapi / operations_processor.rb
Size: Mime:
module JSONAPI
  class OperationsProcessor
    include Callbacks
    define_jsonapi_resources_callbacks :operation,
                                       :operations,
                                       :find_operation,
                                       :show_operation,
                                       :show_relationship_operation,
                                       :show_related_resource_operation,
                                       :show_related_resources_operation,
                                       :create_resource_operation,
                                       :remove_resource_operation,
                                       :replace_fields_operation,
                                       :replace_to_one_relationship_operation,
                                       :replace_polymorphic_to_one_relationship_operation,
                                       :create_to_many_relationship_operation,
                                       :replace_to_many_relationship_operation,
                                       :remove_to_many_relationship_operation,
                                       :remove_to_one_relationship_operation

    class << self
      def operations_processor_for(operations_processor)
        operations_processor_class_name = "#{operations_processor.to_s.camelize}OperationsProcessor"
        operations_processor_class_name.safe_constantize
      end
    end

    def process(request)
      @results = JSONAPI::OperationResults.new
      @request = request
      @operations = request.operations

      # Use transactions if more than one operation and if one of the operations can be transactional
      # Even if transactional transactions won't be used unless the derived OperationsProcessor supports them.
      @transactional = false
      @operations.each do |operation|
        @transactional |= operation.transactional
      end

      run_callbacks :operations do
        transaction do
          # Links and meta data global to the set of operations
          @operations_meta = {}
          @operations_links = {}
          @operations.each do |operation|
            @operation = operation
            # Links and meta data for each operation
            @operation_meta = {}
            @operation_links = {}
            run_callbacks :operation do
              @result = nil
              run_callbacks @operation.class.name.demodulize.underscore.to_sym do
                @result = process_operation(@operation)
              end
              @result.meta.merge!(@operation_meta)
              @result.links.merge!(@operation_links)
              @results.add_result(@result)
              rollback if @results.has_errors?
            end
          end
          @results.meta = @operations_meta
          @results.links = @operations_links
        end
      end
      @results
    end

    private

    # The base OperationsProcessor provides no transaction support
    # Override the transaction and rollback methods to provide transaction support.
    # For ActiveRecord transactions you can use the ActiveRecordOperationsProcessor
    def transaction
      yield
    end

    def rollback
    end

    # If overriding in child operation processors, call operation.apply and 
    # catch errors that should be handled before JSONAPI::Exceptions::Error
    # and other unprocessed exceptions
    def process_operation(operation)
      with_default_handling do 
        operation.apply
      end        
    end

    def with_default_handling(&block)
      yield
    rescue JSONAPI::Exceptions::Error => e
      raise e

    rescue => e
      if JSONAPI.configuration.exception_class_whitelisted?(e)
        raise e
      else
        @request.server_error_callbacks.each { |callback| safe_run_callback(callback, e) }

        internal_server_error = JSONAPI::Exceptions::InternalServerError.new(e)
        Rails.logger.error { "Internal Server Error: #{e.message} #{e.backtrace.join("\n")}" }
        return JSONAPI::ErrorsOperationResult.new(internal_server_error.errors[0].code, internal_server_error.errors)
      end
    end

    def safe_run_callback(callback, error)
      begin 
        callback.call(error)
      rescue => e
        Rails.logger.error { "Error in error handling callback: #{e.message} #{e.backtrace.join("\n")}" }
        internal_server_error = JSONAPI::Exceptions::InternalServerError.new(e)
        return JSONAPI::ErrorsOperationResult.new(internal_server_error.errors[0].code, internal_server_error.errors)
      end
    end

  end
end

class BasicOperationsProcessor < JSONAPI::OperationsProcessor
end