lib/cocina/models/validators/description_values_validator.rb in cocina-models-0.94.2 vs lib/cocina/models/validators/description_values_validator.rb in cocina-models-0.95.0

- old
+ new

@@ -12,32 +12,35 @@ def initialize(clazz, attributes) @clazz = clazz @attributes = attributes @error_paths_multiple = [] @error_paths_blank = [] + @error_paths_missing_title_type = [] end def validate return unless meets_preconditions? validate_obj(attributes, []) raise ValidationError, "Multiple value, groupedValue, structuredValue, and parallelValue in description: #{error_paths_multiple.join(', ')}" unless error_paths_multiple.empty? raise ValidationError, "Blank value in description: #{error_paths_blank.join(', ')}" unless error_paths_blank.empty? + raise ValidationError, "Missing type for value in description: #{error_paths_missing_title_type.join(', ')}" unless error_paths_missing_title_type.empty? end private - attr_reader :clazz, :attributes, :error_paths_blank, :error_paths_multiple + attr_reader :clazz, :attributes, :error_paths_blank, :error_paths_multiple, :error_paths_missing_title_type def meets_preconditions? [Cocina::Models::Description, Cocina::Models::RequestDescription].include?(clazz) end def validate_hash(hash, path) validate_values_for_blanks(hash, path) validate_values_for_multiples(hash, path) + validate_title_type(hash, path) hash.each do |key, obj| validate_obj(obj, path + [key]) end end @@ -60,9 +63,22 @@ def validate_values_for_multiples(hash, path) return unless hash.count { |key, value| %i[value groupedValue structuredValue parallelValue].include?(key) && value.present? } > 1 error_paths_multiple << path_to_s(path) + end + + def validate_title_type(hash, path) + # only apply to title.structuredValue, title.parallelValue.structuredValue, or relatedResource.title with a value + return unless hash[:value] && (path.first == :title || related_resource_title?(path)) && path.include?(:structuredValue) + + # if there is a "value" key, make sure there is also a "type" key, only for title.structuredValue + error_paths_missing_title_type << path_to_s(path) unless hash[:type] + end + + def related_resource_title?(path) + # title is directly within relatedResource, e.g [:relatedResource, 0, :title, 0, :structuredValue, 0]) + path.first == :relatedResource && path[2] == :title end def path_to_s(path) # This matches the format used by descriptive spreadsheets path_str = ''