class ViewModel::ActiveRecord::AbstractCollectionUpdate::Parser
def append_action_schema # abstract
def append_action_schema # abstract raise 'abstract' end
def functional_update_schema # abstract
def functional_update_schema # abstract raise 'abstract' end
def functional_update_type # abstract
def functional_update_type # abstract raise 'abstract' end
def initialize(association_data, blame_reference, valid_reference_keys)
def initialize(association_data, blame_reference, valid_reference_keys) @association_data = association_data @blame_reference = blame_reference @valid_reference_keys = valid_reference_keys end
def parse(value)
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
def parse_action(action)
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
def parse_anchor(child_hash) # final
referenced associations.
May only contain type and id fields, is never a reference even for
Parse an anchor for a functional_update, before/after
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
def parse_append_action(action) # final
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
def parse_contents(_values) # abstract
def parse_contents(_values) # abstract raise 'abstract' end
def parse_remove_action(action) # final
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
def parse_remove_values(values)
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
def parse_update_action(action) # final
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
def remove_action_schema # abstract
def remove_action_schema # abstract raise 'abstract' end
def replace_update_type # abstract
def replace_update_type # abstract raise 'abstract' end
def update_action_schema # abstract
def update_action_schema # abstract raise 'abstract' end