class ArchivesSpaceTypeAttribute

Public Class Methods

validate(current_schema, data, fragments, validator, options = {}) click to toggle source
Calls superclass method
# File lib/aspace_client/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
validation_error_for(expected_type, fragments, current_schema) click to toggle source

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.

# File lib/aspace_client/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