Class: Csvlint::Csvw::TableGroup

Inherits:
Object
  • Object
show all
Includes:
ErrorCollector
Defined in:
lib/csvlint/csvw/table_group.rb

Instance Attribute Summary collapse

Attributes included from ErrorCollector

#errors, #info_messages, #warnings

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ErrorCollector

#build_errors, #build_info_messages, #build_warnings, #reset, #valid?

Constructor Details

#initialize(url, id: nil, tables: {}, notes: [], annotations: {}, warnings: []) ⇒ TableGroup

Returns a new instance of TableGroup.



8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/csvlint/csvw/table_group.rb', line 8

def initialize(url, id: nil, tables: {}, notes: [], annotations: {}, warnings: [])
  @url = url
  @id = id
  @tables = tables
  @notes = notes
  @annotations = annotations
  @validated_tables = {}
  @tables.each { |t, v| @validated_tables[t] = false }
  reset
  @warnings += warnings
  @errors += @tables.map { |url, table| table.errors }.flatten
  @warnings += @tables.map { |url, table| table.warnings }.flatten
end

Instance Attribute Details

#annotationsObject (readonly)

Returns the value of attribute annotations.



6
7
8
# File 'lib/csvlint/csvw/table_group.rb', line 6

def annotations
  @annotations
end

#idObject (readonly)

Returns the value of attribute id.



6
7
8
# File 'lib/csvlint/csvw/table_group.rb', line 6

def id
  @id
end

#notesObject (readonly)

Returns the value of attribute notes.



6
7
8
# File 'lib/csvlint/csvw/table_group.rb', line 6

def notes
  @notes
end

#tablesObject (readonly)

Returns the value of attribute tables.



6
7
8
# File 'lib/csvlint/csvw/table_group.rb', line 6

def tables
  @tables
end

#urlObject (readonly)

Returns the value of attribute url.



6
7
8
# File 'lib/csvlint/csvw/table_group.rb', line 6

def url
  @url
end

Class Method Details

.from_json(url, json) ⇒ Object

Raises:



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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/csvlint/csvw/table_group.rb', line 55

def self.from_json(url, json)
  warnings = []
  tables = {}
  annotations = {}
  inherited_properties = {}
  common_properties = {}
  base_url = URI(url.to_s.strip)
  lang = "und"

  context = json["@context"]
  if context.instance_of?(Array) && context[1]
    context[1].each do |property, value|
      v, warning, type = Csvw::PropertyChecker.check_property(property, value, base_url, lang)
      if warning.nil? || warning.empty?
        if type == :context
          base_url = v if property == "@base"
          lang = v if property == "@language"
        else
          raise Csvlint::Csvw::MetadataError.new("$.@context"), "@context contains properties other than @base or @language (#{property})"
        end
      else
        raise Csvlint::Csvw::MetadataError.new("$.@context"), "@context contains properties other than @base or @language (#{property})" unless ["@base", "@language"].include?(property)
        warnings += Array(warning).map { |w| Csvlint::ErrorMessage.new(w, :metadata, nil, nil, "@context: #{property}: #{value}", nil) }
      end
    end
  end
  json.delete("@context")

  unless json["tables"]
    if json["url"]
      json = {"tables" => [json]}
    end
  end

  json.each do |property, value|
    unless VALID_PROPERTIES.include? property
      v, warning, type = Csvw::PropertyChecker.check_property(property, value, base_url, lang)
      warnings += Array(warning).map { |w| Csvlint::ErrorMessage.new(w, :metadata, nil, nil, "#{property}: #{value}", nil) } unless warning.nil? || warning.empty?
      if type == :annotation
        annotations[property] = v
      elsif type == :common
        common_properties[property] = v
      elsif type == :inherited
        inherited_properties[property] = v
      else
        warnings << Csvlint::ErrorMessage.new(:invalid_property, :metadata, nil, nil, property.to_s, nil)
      end
    end
  end

  id = common_properties["@id"]

  raise Csvlint::Csvw::MetadataError.new("$.@type"), "@type of table group is not 'TableGroup'" if json["@type"] && json["@type"] != "TableGroup"

  raise Csvlint::Csvw::MetadataError.new("$"), "no tables property" unless json["tables"]
  raise Csvlint::Csvw::MetadataError.new("$.tables"), "empty tables property" if json["tables"].empty?
  raise Csvlint::Csvw::MetadataError.new("$.tables"), "tables property is not an array" unless json["tables"].instance_of? Array

  json["tables"].each do |table_desc|
    if table_desc.instance_of? Hash
      table_url = table_desc["url"]
      unless table_url.instance_of? String
        warnings << Csvlint::ErrorMessage.new(:invalid_url, :metadata, nil, nil, "url: #{table_url}", nil)
        table_url = ""
      end
      table_url = URI.join(base_url, table_url).to_s
      table_desc["url"] = table_url
      table = Csvlint::Csvw::Table.from_json(table_desc, base_url, lang, common_properties, inherited_properties)
      tables[table_url] = table
    else
      warnings << Csvlint::ErrorMessage.new(:invalid_table_description, :metadata, nil, nil, table_desc.to_s, nil)
    end
  end

  tables.each do |table_url, table|
    table.foreign_keys.each_with_index do |foreign_key, i|
      reference = foreign_key["reference"]
      if reference["resource"]
        resource = URI.join(base_url, reference["resource"]).to_s
        referenced_table = tables[resource]
        raise Csvlint::Csvw::MetadataError.new("$.tables[?(@.url = '#{table_url}')].tableSchema.foreign_keys[#{i}].reference.resource"), "foreign key references table that does not exist (#{resource})" if referenced_table.nil?
      else
        schema_url = URI.join(base_url, reference["schemaReference"]).to_s
        referenced_tables = tables.values.select { |table| table.schema == schema_url }
        referenced_table = referenced_tables[0]
        raise Csvlint::Csvw::MetadataError.new("$.tables[?(@.url = '#{table_url}')].tableSchema.foreign_keys[#{i}].reference.schemaReference"), "foreign key references schema that is not used (#{schema_url})" if referenced_table.nil?
      end
      foreign_key["referenced_table"] = referenced_table
      table_columns = {}
      referenced_table.columns.each do |column|
        table_columns[column.name] = column if column.name
      end
      referenced_columns = []
      Array(reference["columnReference"]).each do |column_reference|
        column = table_columns[column_reference]
        raise Csvlint::Csvw::MetadataError.new("$.tables[?(@.url = '#{table_url}')].tableSchema.foreign_keys[#{i}].reference.columnReference"), "column named #{column_reference} does not exist in #{resource}" if column.nil?
        referenced_columns << column
      end
      foreign_key["referenced_columns"] = referenced_columns
      referenced_table.foreign_key_references << foreign_key
    end
  end

  new(base_url, id: id, tables: tables, notes: common_properties["notes"] || [], annotations: annotations, warnings: warnings)
end

Instance Method Details

#validate_foreign_keysObject



43
44
45
46
47
48
49
50
51
52
53
# File 'lib/csvlint/csvw/table_group.rb', line 43

def validate_foreign_keys
  reset
  unless @validated_tables.has_value?(false)
    @tables.each do |table_url, table|
      table.validate_foreign_keys
      @errors += table.errors
      @warnings += table.warnings
    end
  end
  valid?
end

#validate_header(header, table_url, strict) ⇒ Object



22
23
24
25
26
27
28
29
30
# File 'lib/csvlint/csvw/table_group.rb', line 22

def validate_header(header, table_url, strict)
  reset
  table_url = "file:#{File.absolute_path(table_url)}" if table_url.instance_of? File
  table = tables[table_url]
  table.validate_header(header, strict)
  @errors += table.errors
  @warnings += table.warnings
  valid?
end

#validate_row(values, row = nil, all_errors = [], table_url, validate) ⇒ Object



32
33
34
35
36
37
38
39
40
41
# File 'lib/csvlint/csvw/table_group.rb', line 32

def validate_row(values, row = nil, all_errors = [], table_url, validate)
  reset
  table_url = "file:#{File.absolute_path(table_url)}" if table_url.instance_of? File
  @validated_tables[table_url] = true
  table = tables[table_url]
  table.validate_row(values, row, validate)
  @errors += table.errors
  @warnings += table.warnings
  valid?
end