Class: ArchivesSpaceTypeAttribute

Inherits:
JSON::Schema::TypeAttribute
  • Object
show all
Extended by:
JSONModel
Defined in:
common/archivesspace_json_schema.rb

Class Method Summary (collapse)

Methods included from JSONModel

JSONModel, JSONModel, add_error_handler, all, allow_unmapped_enum_value, backend_url, client_mode?, custom_validations, destroy_model, enum_default_value, enum_values, handle_error, init, load_schema, models, models, parse_jsonmodel_ref, parse_reference, repository, repository_for, schema_src, set_repository, strict_mode, strict_mode?, with_repository

Class Method Details

+ (Object) validate(current_schema, data, fragments, validator, options = {})



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'common/archivesspace_json_schema.rb', line 55

def self.validate(current_schema, data, fragments, validator, options = {})
  types = current_schema.schema['type']

  if types == 'date'
    begin
      Date.parse(data)
      return
    rescue
      validation_error("The property '#{build_fragment(fragments)}' was not " +
                       "a well-formed date (value: #{data})",
                       fragments, current_schema, self, options[:record_errors])
    end
  end


  if types == 'object' && data.is_a?(Hash) && data.has_key?('ref') && current_schema.schema['subtype'] != 'ref'
    # Provide a helpful warning about potentially missing subtype definitions
    $stderr.puts("WARNING: Schema #{current_schema.inspect} appears to be missing a subtype definition of 'ref'")
  end

  # A bit crazy, sorry.  If we're being asked to validate a hash whose
  # jsonmodel_type is marked against a different JSONModel schema, we're
  # wasting our time.  Just stop straight away.
  if (data.is_a?(Hash) && data["jsonmodel_type"]) &&
      (current_schema.schema.is_a?(Hash) &&
       "#{current_schema.schema["type"]}".include?("JSONModel") &&
       !"#{current_schema.schema["type"]}".include?("JSONModel(:#{data['jsonmodel_type']})"))

    raise validation_error_for(data['jsonmodel_type'], fragments, current_schema)
  end

  if JSONModel.parse_jsonmodel_ref(types)
    (model, qualifier) = JSONModel.parse_jsonmodel_ref(types)

    if qualifier == 'uri' || (qualifier == 'uri_or_object' && data.is_a?(String))
      if JSONModel(model).id_for(data, {}, true).nil?
        validation_error("The property '#{build_fragment(fragments)}' of type " +
                         "#{data.class} did not match the following type: #{types} in schema",
                         fragments, current_schema, self, options[:record_errors])
      end

    elsif qualifier == 'uri_or_object' || qualifier == 'object'
      if data.is_a?(Hash)
        data["jsonmodel_type"] ||= model.to_s

        ValidatorCache.with_validator_for(JSONModel(model), data) do |subvalidator|
          # Urk.  Validate the subrecord but pass in the fragments of the point
          # we're at in the parent record.
          subvalidator.instance_eval do
            @base_schema.validate(@data, fragments, @validation_options)
          end
        end

      else
        validation_error("The property '#{build_fragment(fragments)}' of type " +
                         "#{data.class} did not match the following type: #{types} in schema",
                         fragments, current_schema, self, options[:record_errors])
      end
    end
  else
    super
  end
end

+ (Object) validation_error_for(expected_type, fragments, current_schema)

This reuse business is a bit of a pain. The story here: JRuby backtraces are relatively expensive to create (relative to MRI Ruby), and JSON Schema validation is using exceptions as control flow here (sigh). During imports, these validation error are hit a lot, and calculating a backtrace every time is expensive.

So, we recycle.



43
44
45
46
47
48
49
50
51
52
# File 'common/archivesspace_json_schema.rb', line 43

def self.validation_error_for(expected_type, fragments, current_schema)
  Thread.current[:json_validation_cached_errors] ||= {}
  if !Thread.current[:json_validation_cached_errors][expected_type]
    msg = "ERROR: Schema type mismatch.  Expected type: #{expected_type}"
    Thread.current[:json_validation_cached_errors][expected_type] = JSON::Schema::ValidationError.new(msg, fragments, self, current_schema)
  end

  Thread.current[:json_validation_cached_errors][expected_type].fragments = fragments
  Thread.current[:json_validation_cached_errors][expected_type]
end