class ViewModel::ActiveRecord::AbstractCollectionUpdate::Parser

Attributes

association_data[R]
blame_reference[R]
valid_reference_keys[R]

Public Class Methods

new(association_data, blame_reference, valid_reference_keys) click to toggle source
# File lib/view_model/active_record/update_data.rb, line 111
def initialize(association_data, blame_reference, valid_reference_keys)
  @association_data     = association_data
  @blame_reference      = blame_reference
  @valid_reference_keys = valid_reference_keys
end

Public Instance Methods

parse(value) click to toggle source
# File lib/view_model/active_record/update_data.rb, line 117
def parse(value)
  case value
  when Array
    replace_update_type.new(parse_contents(value))

  when Hash
    ViewModel::Schemas.verify_schema!(functional_update_schema, value)
    functional_updates = value[ACTIONS_ATTRIBUTE].map { |action| parse_action(action) }
    functional_update_type.new(functional_updates)

  else
    raise ViewModel::DeserializationError::InvalidSyntax.new(
            "Could not parse non-array value for collection association '#{association_data}'",
            blame_reference)
  end
end

Private Instance Methods

append_action_schema() click to toggle source
# File lib/view_model/active_record/update_data.rb, line 225
def append_action_schema # abstract
  raise 'abstract'
end
functional_update_schema() click to toggle source
Action contents

The contents of the actions are determined by the subclasses

# File lib/view_model/active_record/update_data.rb, line 221
def functional_update_schema # abstract
  raise 'abstract'
end
functional_update_type() click to toggle source
# File lib/view_model/active_record/update_data.rb, line 265
def functional_update_type # abstract
  raise 'abstract'
end
parse_action(action) click to toggle source
# File lib/view_model/active_record/update_data.rb, line 140
def parse_action(action)
  type = action[ViewModel::TYPE_ATTRIBUTE]

  case type
  when FunctionalUpdate::Remove::NAME
    parse_remove_action(action)
  when FunctionalUpdate::Append::NAME
    parse_append_action(action)
  when FunctionalUpdate::Update::NAME
    parse_update_action(action)
  else
    raise ViewModel::DeserializationError::InvalidSyntax.new(
            "Unknown action type '#{type}'",
            blame_reference)
  end
end
parse_anchor(child_hash) click to toggle source

Parse an anchor for a functional_update, before/after May only contain type and id fields, is never a reference even for referenced associations.

# File lib/view_model/active_record/update_data.rb, line 164
def parse_anchor(child_hash) # final
  child_metadata = ViewModel.extract_reference_only_metadata(child_hash)

  child_viewmodel_class =
    association_data.viewmodel_class_for_name(child_metadata.view_name)

  if child_viewmodel_class.nil?
    raise ViewModel::DeserializationError::InvalidAssociationType.new(
            association_data.association_name.to_s,
            child_metadata.view_name,
            blame_reference)
  end

  ViewModel::Reference.new(child_viewmodel_class, child_metadata.id)
end
parse_append_action(action) click to toggle source
# File lib/view_model/active_record/update_data.rb, line 180
def parse_append_action(action) # final
  ViewModel::Schemas.verify_schema!(append_action_schema, action)

  values = action[VALUES_ATTRIBUTE]
  update = FunctionalUpdate::Append.new(parse_contents(values))

  if (before = action[BEFORE_ATTRIBUTE])
    update.before = parse_anchor(before)
  end

  if (after = action[AFTER_ATTRIBUTE])
    update.after = parse_anchor(after)
  end

  if before && after
    raise ViewModel::DeserializationError::InvalidSyntax.new(
            "Append may not specify both 'after' and 'before'",
            blame_reference)
  end

  update
end
parse_contents(_values) click to toggle source
# File lib/view_model/active_record/update_data.rb, line 237
def parse_contents(_values) # abstract
  raise 'abstract'
end
parse_remove_action(action) click to toggle source
# File lib/view_model/active_record/update_data.rb, line 210
def parse_remove_action(action) # final
  ViewModel::Schemas.verify_schema!(remove_action_schema, action)

  values = action[VALUES_ATTRIBUTE]
  FunctionalUpdate::Remove.new(parse_remove_values(values))
end
parse_remove_values(values) click to toggle source

Remove values are always anchors

# File lib/view_model/active_record/update_data.rb, line 242
def parse_remove_values(values)
  # There's no reasonable interpretation of a remove update that includes data.
  # Report it as soon as we detect it.
  invalid_entries = values.reject { |h| UpdateData.reference_only_hash?(h) }
  if invalid_entries.present?
    raise ViewModel::DeserializationError::InvalidSyntax.new(
            "Removed entities must have only #{ViewModel::TYPE_ATTRIBUTE} and #{ViewModel::ID_ATTRIBUTE} fields. " \
            "Invalid entries: #{invalid_entries}",
            blame_reference)
  end

  values.map { |value| parse_anchor(value) }
end
parse_update_action(action) click to toggle source
# File lib/view_model/active_record/update_data.rb, line 203
def parse_update_action(action) # final
  ViewModel::Schemas.verify_schema!(update_action_schema, action)

  values = action[VALUES_ATTRIBUTE]
  FunctionalUpdate::Update.new(parse_contents(values))
end
remove_action_schema() click to toggle source
# File lib/view_model/active_record/update_data.rb, line 229
def remove_action_schema # abstract
  raise 'abstract'
end
replace_update_type() click to toggle source
Value constructors

ReferencedCollectionUpdates and OwnedCollectionUpdates have different behaviour, so we parameterise the result type as well.

# File lib/view_model/active_record/update_data.rb, line 261
def replace_update_type # abstract
  raise 'abstract'
end
update_action_schema() click to toggle source
# File lib/view_model/active_record/update_data.rb, line 233
def update_action_schema # abstract
  raise 'abstract'
end