module Sequel::Plugins::PgAutoConstraintValidations::InstanceMethods

Private Instance Methods

_insert_raw(ds) click to toggle source

Convert PostgreSQL constraint errors when inserting.

Calls superclass method
# File lib/sequel/plugins/pg_auto_constraint_validations.rb, line 243
def _insert_raw(ds)
  check_pg_constraint_error(ds){super}
end
_insert_select_raw(ds) click to toggle source

Convert PostgreSQL constraint errors when inserting.

Calls superclass method
# File lib/sequel/plugins/pg_auto_constraint_validations.rb, line 248
def _insert_select_raw(ds)
  check_pg_constraint_error(ds){super}
end
_update_without_checking(_) click to toggle source

Convert PostgreSQL constraint errors when updating.

Calls superclass method
# File lib/sequel/plugins/pg_auto_constraint_validations.rb, line 253
def _update_without_checking(_)
  check_pg_constraint_error(_update_dataset){super}
end
add_pg_constraint_validation_error(column, message) click to toggle source

If there is a single column instead of an array of columns, add the error for the column, otherwise add the error for the array of columns.

# File lib/sequel/plugins/pg_auto_constraint_validations.rb, line 237
def add_pg_constraint_validation_error(column, message)
  column = column.first if column.length == 1 
  errors.add(column, message)
end
check_pg_constraint_error(ds) { || ... } click to toggle source

Yield to the given block, and if a Sequel::ConstraintViolation is raised, try to convert it to a Sequel::ValidationFailed error using the PostgreSQL error metadata.

# File lib/sequel/plugins/pg_auto_constraint_validations.rb, line 148
def check_pg_constraint_error(ds)
  yield
rescue Sequel::ConstraintViolation => e
  begin
    unless cv_info = model.pg_auto_constraint_validations
      # Necessary metadata does not exist, just reraise the exception.
      raise e
    end

    info = ds.db.error_info(e)
    m = ds.method(:output_identifier)
    schema = info[:schema]
    table = info[:table]
    if constraint = info[:constraint]
      constraint = m.call(constraint)
    end
    messages = model.pg_auto_constraint_validations_messages

    case e
    when Sequel::NotNullConstraintViolation
      if column = info[:column]
        add_pg_constraint_validation_error([m.call(column)], messages[:not_null])
      end
    when Sequel::CheckConstraintViolation
      if columns = cv_info[:check][constraint]
        add_pg_constraint_validation_error(columns, messages[:check])
      end
    when Sequel::UniqueConstraintViolation
      if columns = cv_info[:unique][constraint]
        add_pg_constraint_validation_error(columns, messages[:unique])
      end
    when Sequel::ForeignKeyConstraintViolation
      message_primary = info[:message_primary]
      if message_primary.start_with?('update')
        # This constraint violation is different from the others, because the constraint
        # referenced is a constraint for a different table, not for this table.  This
        # happens when another table references the current table, and the referenced
        # column in the current update is modified such that referential integrity
        # would be broken.  Use the reverse foreign key information to figure out
        # which column is affected in that case.
        skip_schema_table_check = true
        if columns = cv_info[:referenced_by][[m.call(schema), m.call(table), constraint]]
          add_pg_constraint_validation_error(columns, messages[:referenced_by])
        end
      elsif message_primary.start_with?('insert')
        if columns = cv_info[:foreign_key][constraint]
          add_pg_constraint_validation_error(columns, messages[:foreign_key])
        end
      end
    end
  rescue => e2
    # If there is an error trying to conver the constraint violation
    # into a validation failure, it's best to just raise the constraint
    # violation.  This can make debugging the above block of code more
    # difficult.
    raise e
  else
    unless skip_schema_table_check
      # The constraint violation could be caused by a trigger modifying
      # a different table.  Check that the error schema and table
      # match the model's schema and table, or clear the validation error
      # that was set above.
      if schema != cv_info[:schema] || table != cv_info[:table]
        errors.clear
      end
    end

    if errors.empty?
      # If we weren't able to parse the constraint violation metadata and
      # convert it to an appropriate validation failure, or the schema/table
      # didn't match, then raise the constraint violation.
      raise e
    end

    # Integrate with error_splitter plugin to split any multi-column errors
    # and add them as separate single column errors
    if respond_to?(:split_validation_errors, true)
      split_validation_errors(errors)
    end

    vf = ValidationFailed.new(self)
    vf.set_backtrace(e.backtrace)
    vf.wrapped_exception = e
    raise vf
  end
end