# File lib/tableschema/schema.rb, line 39 def primary_key [self[:primaryKey]].flatten.reject { |k| k.nil? } end
class TableSchema::Schema
Attributes
errors[R]
Public
Public Class Methods
new(descriptor, strict: false, case_insensitive_headers: false)
click to toggle source
# File lib/tableschema/schema.rb, line 11 def initialize(descriptor, strict: false, case_insensitive_headers: false) self.merge! deep_symbolize_keys(parse_schema(descriptor)) @case_insensitive_headers = case_insensitive_headers @strict = strict load_fields! load_validator! expand! @strict == true ? validate! : validate self end
Public Instance Methods
add_field(descriptor)
click to toggle source
# File lib/tableschema/schema.rb, line 61 def add_field(descriptor) self[:fields].push(descriptor) validate! descriptor rescue TableSchema::SchemaException => e self[:fields].pop raise e if @strict nil end
cast_row(row, fail_fast: true)
click to toggle source
# File lib/tableschema/schema.rb, line 78 def cast_row(row, fail_fast: true) errors = Set.new handle_error = lambda { |e| fail_fast == true ? raise(e) : errors << e } row = row.fields if row.class == CSV::Row if row.count != self.fields.count handle_error.call(TableSchema::ConversionError.new("The number of items to convert (#{row.count}) does not match the number of headers in the schema (#{self.fields.count})")) end self.fields.each_with_index do |field, i| begin row[i] = field.cast_value(row[i]) rescue TableSchema::Exception => e handle_error.call(e) end end unless errors.empty? raise(TableSchema::MultipleInvalid.new("There were errors parsing the data", errors)) end row end
descriptor()
click to toggle source
# File lib/tableschema/schema.rb, line 35 def descriptor self.to_h end
field_names()
click to toggle source
# File lib/tableschema/schema.rb, line 51 def field_names fields.map { |f| transform(f[:name]) } rescue NoMethodError [] end
Also aliased as: headers
fields()
click to toggle source
# File lib/tableschema/schema.rb, line 47 def fields self[:fields] end
foreign_keys()
click to toggle source
# File lib/tableschema/schema.rb, line 43 def foreign_keys self[:foreignKeys] || [] end
get_constraints(field_name)
click to toggle source
# File lib/tableschema/schema.rb, line 117 def get_constraints(field_name) get_field(field_name)[:constraints] || {} end
get_field(field_name)
click to toggle source
# File lib/tableschema/schema.rb, line 57 def get_field(field_name) fields.find { |f| f[:name] == field_name } end
get_fields_by_type(type)
click to toggle source
# File lib/tableschema/schema.rb, line 135 def get_fields_by_type(type) fields.select { |f| f[:type] == type } end
get_type(field_name)
click to toggle source
# File lib/tableschema/schema.rb, line 113 def get_type(field_name) get_field(field_name)[:type] end
has_field?(field_name)
click to toggle source
# File lib/tableschema/schema.rb, line 131 def has_field?(field_name) get_field(field_name) != nil end
missing_values()
click to toggle source
# File lib/tableschema/schema.rb, line 109 def missing_values self.fetch(:missingValues, TableSchema::DEFAULTS[:missing_values]) end
primary_key()
click to toggle source
remove_field(field_name)
click to toggle source
# File lib/tableschema/schema.rb, line 71 def remove_field(field_name) field = get_field(field_name) self[:fields].reject!{ |f| f.name == field_name } validate field end
required_headers()
click to toggle source
# File lib/tableschema/schema.rb, line 121 def required_headers fields.select { |f| f.fetch(:constraints, {}).fetch(:required, nil).to_s == 'true' } .map { |f| transform(f[:name]) } end
save(target)
click to toggle source
# File lib/tableschema/schema.rb, line 100 def save(target) File.open(target, "w") { |file| file << JSON.pretty_generate(self.descriptor) } true end
unique_headers()
click to toggle source
# File lib/tableschema/schema.rb, line 126 def unique_headers fields.select { |f| f.fetch(:constraints, {}).fetch(:unique, nil).to_s == 'true' } .map { |f| transform(f[:name]) } end
validate()
click to toggle source
# File lib/tableschema/schema.rb, line 22 def validate @errors = Set.new(JSON::Validator.fully_validate(@profile, self)) check_primary_key check_foreign_keys @errors.empty? end
validate!()
click to toggle source
# File lib/tableschema/schema.rb, line 29 def validate! validate raise SchemaException.new(@errors.first) unless @errors.empty? true end
Private Instance Methods
add_error(error)
click to toggle source
# File lib/tableschema/schema.rb, line 221 def add_error(error) @errors << error end
check_field_value(key, type)
click to toggle source
# File lib/tableschema/schema.rb, line 203 def check_field_value(key, type) if headers.select { |f| key == f }.count == 0 add_error("The TableSchema #{type} value `#{key}` is not found in any of the schema's field names") end end
check_foreign_keys()
click to toggle source
# File lib/tableschema/schema.rb, line 187 def check_foreign_keys return if self[:foreignKeys].nil? self[:foreignKeys].each do |key| if field_type_mismatch?(key) add_error("A TableSchema `foreignKey.fields` value must be the same type as `foreignKey.reference.fields`") end if field_count_mismatch?(key) add_error("A TableSchema `foreignKey.fields` must contain the same number of entries as `foreignKey.reference.fields`") end foreign_key_fields(key).each { |fk| check_field_value(fk, 'foreignKey.fields') } if key.fetch(:reference).fetch(:resource).empty? foreign_key_fields(key.fetch(:reference)).each { |fk| check_field_value(fk, 'foreignKey.reference.fields')} end end end
check_primary_key()
click to toggle source
# File lib/tableschema/schema.rb, line 182 def check_primary_key return if self[:primaryKey].nil? primary_key.each { |pk| check_field_value(pk, 'primaryKey') } end
expand!()
click to toggle source
# File lib/tableschema/schema.rb, line 166 def expand! (self[:fields] || []).each do |f| f[:type] = TableSchema::DEFAULTS[:type] if f[:type] == nil f[:format] = TableSchema::DEFAULTS[:format] if f[:format] == nil end end
field_count_mismatch?(key)
click to toggle source
# File lib/tableschema/schema.rb, line 213 def field_count_mismatch?(key) foreign_key_fields(key).count != foreign_key_fields(key.fetch(:reference)).count end
field_type_mismatch?(key)
click to toggle source
# File lib/tableschema/schema.rb, line 217 def field_type_mismatch?(key) key.fetch(:fields).class.name != key.fetch(:reference).fetch(:fields).class.name end
foreign_key_fields(key)
click to toggle source
# File lib/tableschema/schema.rb, line 209 def foreign_key_fields(key) [key.fetch(:fields)].flatten end
load_fields!()
click to toggle source
# File lib/tableschema/schema.rb, line 173 def load_fields! self[:fields] = (self[:fields] || []).map { |f| TableSchema::Field.new(f, missing_values) } end
load_validator!()
click to toggle source
# File lib/tableschema/schema.rb, line 177 def load_validator! filepath = File.join(File.dirname(__FILE__), '..', 'profiles', 'table-schema.json') @profile ||= JSON.parse(File.read(filepath), symbolize_names: true) end
parse_schema(descriptor)
click to toggle source
Private
# File lib/tableschema/schema.rb, line 143 def parse_schema(descriptor) if descriptor.class == Hash descriptor elsif descriptor.class == String begin JSON.parse(open(descriptor).read, symbolize_names: true) rescue Errno::ENOENT raise SchemaException.new("File not found at `#{descriptor}`") rescue OpenURI::HTTPError => e raise SchemaException.new("URL `#{descriptor}` returned #{e.message}") rescue JSON::ParserError raise SchemaException.new("File at `#{descriptor}` is not valid JSON") end else raise SchemaException.new("A schema must be a hash, path or URL") end end
transform(name)
click to toggle source
# File lib/tableschema/schema.rb, line 161 def transform(name) name.downcase! if @case_insensitive_headers == true name end