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.



442
443
444
445
446
447
448
449
# File 'lib/view_model/deserialization_error.rb', line 442

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.



360
361
362
# File 'lib/view_model/deserialization_error.rb', line 360

def columns
  @columns
end

#conflictsObject (readonly)

Returns the value of attribute conflicts.



360
361
362
# File 'lib/view_model/deserialization_error.rb', line 360

def conflicts
  @conflicts
end

#constraintObject (readonly)

Returns the value of attribute constraint.



360
361
362
# File 'lib/view_model/deserialization_error.rb', line 360

def constraint
  @constraint
end

#detailObject (readonly)

Returns the value of attribute detail.



360
361
362
# File 'lib/view_model/deserialization_error.rb', line 360

def detail
  @detail
end

#valuesObject (readonly)

Returns the value of attribute values.



360
361
362
# File 'lib/view_model/deserialization_error.rb', line 360

def values
  @values
end

Class Method Details

.from_postgres_error(err, nodes) ⇒ Object



362
363
364
365
366
367
368
369
370
371
372
373
374
375
# File 'lib/view_model/deserialization_error.rb', line 362

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



382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
# File 'lib/view_model/deserialization_error.rb', line 382

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



451
452
453
# File 'lib/view_model/deserialization_error.rb', line 451

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