Exception: ViewModel::DeserializationError::UniqueViolation

Inherits:
ViewModel::DeserializationError show all
Defined in:
lib/view_model/deserialization_error.rb

Constant Summary collapse

DETAIL_PREFIX =
'Key ('
UNIQUE_SUFFIX_TEMPLATE =
/\A\)=\((?<values>.*)\) already exists\.\z/
EXCLUSION_SUFFIX_TEMPLATE =
/\A\)=\((?<values>.*)\) conflicts with existing key \(.*\)=\((?<conflicts>.*)\)\.\z/

Instance Attribute Summary collapse

Attributes inherited from AbstractErrorWithBlame

#nodes

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from ViewModel::DeserializationError

#code

Methods inherited from AbstractError

#aggregation?, #causes, #code, #exception, #status, #title, #to_s, #view

Constructor Details

#initialize(detail, constraint, columns, values, conflicts, nodes = []) ⇒ UniqueViolation

Returns a new instance of UniqueViolation.



459
460
461
462
463
464
465
466
# File 'lib/view_model/deserialization_error.rb', line 459

def initialize(detail, constraint, columns, values, conflicts, nodes = [])
  @detail     = detail
  @constraint = constraint
  @columns    = columns
  @values     = values
  @conflicts  = conflicts
  super(nodes)
end

Instance Attribute Details

#columnsObject (readonly)

Returns the value of attribute columns.



377
378
379
# File 'lib/view_model/deserialization_error.rb', line 377

def columns
  @columns
end

#conflictsObject (readonly)

Returns the value of attribute conflicts.



377
378
379
# File 'lib/view_model/deserialization_error.rb', line 377

def conflicts
  @conflicts
end

#constraintObject (readonly)

Returns the value of attribute constraint.



377
378
379
# File 'lib/view_model/deserialization_error.rb', line 377

def constraint
  @constraint
end

#detailObject (readonly)

Returns the value of attribute detail.



377
378
379
# File 'lib/view_model/deserialization_error.rb', line 377

def detail
  @detail
end

#valuesObject (readonly)

Returns the value of attribute values.



377
378
379
# File 'lib/view_model/deserialization_error.rb', line 377

def values
  @values
end

Class Method Details

.from_postgres_error(err, nodes) ⇒ Object



379
380
381
382
383
384
385
386
387
388
389
390
391
392
# File 'lib/view_model/deserialization_error.rb', line 379

def self.from_postgres_error(err, nodes)
  result         = err.result
  constraint     = result.error_field(PG::PG_DIAG_CONSTRAINT_NAME)
  message_detail = result.error_field(PG::PG_DIAG_MESSAGE_DETAIL)

  columns, values, conflicts = parse_message_detail(message_detail)

  unless columns
    # Couldn't parse the detail message, fall back on an unparsed error
    return DatabaseConstraint.new(err.message, nodes)
  end

  self.new(err.message, constraint, columns, values, conflicts, nodes)
end

.parse_message_detail(detail) ⇒ Object



399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
# File 'lib/view_model/deserialization_error.rb', line 399

def parse_message_detail(detail)
  stream = detail.dup
  return nil unless stream.delete_prefix!(DETAIL_PREFIX)

  # The message should start with an identifier list: pop off identifier
  # tokens while we can.
  identifiers = parse_identifiers(stream)
  return nil if identifiers.nil?

  # The message should now contain ")=(" followed by the value list and
  # the suffix, potentially including a conflict list. We consider the
  # value and conflict lists to be essentially unparseable because they
  # are free to contain commas and no escaping is used. We make a best
  # effort to extract them anyway.
  values, conflicts =
    if (m = UNIQUE_SUFFIX_TEMPLATE.match(stream))
      m.values_at(:values)
    elsif (m = EXCLUSION_SUFFIX_TEMPLATE.match(stream))
      m.values_at(:values, :conflicts)
    else
      return nil
    end

  return identifiers, values, conflicts
end

Instance Method Details

#metaObject



468
469
470
# File 'lib/view_model/deserialization_error.rb', line 468

def meta
  super.merge(constraint: @constraint, columns: @columns, values: @values, conflicts: @conflicts)
end