class ViewModel::DeserializationError::UniqueViolation
def self.from_postgres_error(err, nodes)
def self.from_postgres_error(err, nodes) result = err.result constraint = result.error_field(PG_ERROR_FIELD_CONSTRAINT_NAME) message_detail = result.error_field(PG::Result::PG_DIAG_MESSAGE_DETAIL) columns, values = 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, nodes) end
def initialize(detail, constraint, columns, values, nodes = [])
def initialize(detail, constraint, columns, values, nodes = []) @detail = detail @constraint = constraint @columns = columns @values = values super(nodes) end
def meta
def meta super.merge(constraint: @constraint, columns: @columns, values: @values) end
def parse_identifier(stream)
def parse_identifier(stream) if (identifier = stream.slice!(UNQUOTED_IDENTIFIER)) identifier elsif (quoted_identifier = stream.slice!(QUOTED_IDENTIFIER)) quoted_identifier[1..-2].gsub('""', '"') else nil end end
def parse_message_detail(detail)
def parse_message_detail(detail) stream = detail.dup return nil unless stream.delete_prefix!(DETAIL_PREFIX) return nil unless stream.delete_suffix!(DETAIL_SUFFIX) # The message should start with an identifier list: pop off identifier # tokens while we can. identifiers = [] identifier = parse_identifier(stream) return nil unless identifier identifiers << identifier while stream.delete_prefix!(', ') identifier = parse_identifier(stream) return nil unless identifier identifiers << identifier end # The message should now contain ")=(" followed by the (unparseable) # value list. return nil unless stream.delete_prefix!(DETAIL_INFIX) [identifiers, stream] end