Class: Csvlint::Csvw::Table
- Inherits:
-
Object
- Object
- Csvlint::Csvw::Table
- Includes:
- ErrorCollector
- Defined in:
- lib/csvlint/csvw/table.rb
Instance Attribute Summary collapse
-
#annotations ⇒ Object
readonly
Returns the value of attribute annotations.
-
#columns ⇒ Object
readonly
Returns the value of attribute columns.
-
#dialect ⇒ Object
readonly
Returns the value of attribute dialect.
-
#foreign_key_references ⇒ Object
readonly
Returns the value of attribute foreign_key_references.
-
#foreign_keys ⇒ Object
readonly
Returns the value of attribute foreign_keys.
-
#id ⇒ Object
readonly
Returns the value of attribute id.
-
#notes ⇒ Object
readonly
Returns the value of attribute notes.
-
#primary_key ⇒ Object
readonly
Returns the value of attribute primary_key.
-
#row_title_columns ⇒ Object
readonly
Returns the value of attribute row_title_columns.
-
#schema ⇒ Object
readonly
Returns the value of attribute schema.
-
#suppress_output ⇒ Object
readonly
Returns the value of attribute suppress_output.
-
#table_direction ⇒ Object
readonly
Returns the value of attribute table_direction.
-
#transformations ⇒ Object
readonly
Returns the value of attribute transformations.
-
#url ⇒ Object
readonly
Returns the value of attribute url.
Attributes included from ErrorCollector
#errors, #info_messages, #warnings
Class Method Summary collapse
Instance Method Summary collapse
-
#initialize(url, columns: [], dialect: {}, table_direction: :auto, foreign_keys: [], id: nil, notes: [], primary_key: nil, row_title_columns: [], schema: nil, suppress_output: false, transformations: [], annotations: [], warnings: []) ⇒ Table
constructor
A new instance of Table.
- #validate_foreign_key_references(foreign_key, remote_url, remote) ⇒ Object
- #validate_foreign_keys ⇒ Object
- #validate_header(headers, strict) ⇒ Object
- #validate_row(values, row = nil, validate = false) ⇒ Object
Methods included from ErrorCollector
#build_errors, #build_info_messages, #build_warnings, #reset, #valid?
Constructor Details
#initialize(url, columns: [], dialect: {}, table_direction: :auto, foreign_keys: [], id: nil, notes: [], primary_key: nil, row_title_columns: [], schema: nil, suppress_output: false, transformations: [], annotations: [], warnings: []) ⇒ Table
Returns a new instance of Table.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/csvlint/csvw/table.rb', line 8 def initialize(url, columns: [], dialect: {}, table_direction: :auto, foreign_keys: [], id: nil, notes: [], primary_key: nil, row_title_columns: [], schema: nil, suppress_output: false, transformations: [], annotations: [], warnings: []) @url = url @columns = columns @dialect = dialect @table_direction = table_direction @foreign_keys = foreign_keys @foreign_key_values = {} @foreign_key_references = [] @foreign_key_reference_values = {} @id = id @notes = notes @primary_key = primary_key @primary_key_values = {} @row_title_columns = row_title_columns @schema = schema @suppress_output = suppress_output @transformations = transformations @annotations = annotations reset @warnings += warnings @errors += columns.map { |c| c.errors }.flatten @warnings += columns.map { |c| c.warnings }.flatten end |
Instance Attribute Details
#annotations ⇒ Object (readonly)
Returns the value of attribute annotations.
6 7 8 |
# File 'lib/csvlint/csvw/table.rb', line 6 def annotations @annotations end |
#columns ⇒ Object (readonly)
Returns the value of attribute columns.
6 7 8 |
# File 'lib/csvlint/csvw/table.rb', line 6 def columns @columns end |
#dialect ⇒ Object (readonly)
Returns the value of attribute dialect.
6 7 8 |
# File 'lib/csvlint/csvw/table.rb', line 6 def dialect @dialect end |
#foreign_key_references ⇒ Object (readonly)
Returns the value of attribute foreign_key_references.
6 7 8 |
# File 'lib/csvlint/csvw/table.rb', line 6 def foreign_key_references @foreign_key_references end |
#foreign_keys ⇒ Object (readonly)
Returns the value of attribute foreign_keys.
6 7 8 |
# File 'lib/csvlint/csvw/table.rb', line 6 def foreign_keys @foreign_keys end |
#id ⇒ Object (readonly)
Returns the value of attribute id.
6 7 8 |
# File 'lib/csvlint/csvw/table.rb', line 6 def id @id end |
#notes ⇒ Object (readonly)
Returns the value of attribute notes.
6 7 8 |
# File 'lib/csvlint/csvw/table.rb', line 6 def notes @notes end |
#primary_key ⇒ Object (readonly)
Returns the value of attribute primary_key.
6 7 8 |
# File 'lib/csvlint/csvw/table.rb', line 6 def primary_key @primary_key end |
#row_title_columns ⇒ Object (readonly)
Returns the value of attribute row_title_columns.
6 7 8 |
# File 'lib/csvlint/csvw/table.rb', line 6 def row_title_columns @row_title_columns end |
#schema ⇒ Object (readonly)
Returns the value of attribute schema.
6 7 8 |
# File 'lib/csvlint/csvw/table.rb', line 6 def schema @schema end |
#suppress_output ⇒ Object (readonly)
Returns the value of attribute suppress_output.
6 7 8 |
# File 'lib/csvlint/csvw/table.rb', line 6 def suppress_output @suppress_output end |
#table_direction ⇒ Object (readonly)
Returns the value of attribute table_direction.
6 7 8 |
# File 'lib/csvlint/csvw/table.rb', line 6 def table_direction @table_direction end |
#transformations ⇒ Object (readonly)
Returns the value of attribute transformations.
6 7 8 |
# File 'lib/csvlint/csvw/table.rb', line 6 def transformations @transformations end |
#url ⇒ Object (readonly)
Returns the value of attribute url.
6 7 8 |
# File 'lib/csvlint/csvw/table.rb', line 6 def url @url end |
Class Method Details
.from_json(table_desc, base_url = nil, lang = "und", common_properties = {}, inherited_properties = {}) ⇒ Object
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 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/csvlint/csvw/table.rb', line 119 def self.from_json(table_desc, base_url = nil, lang = "und", common_properties = {}, inherited_properties = {}) annotations = {} warnings = [] columns = [] table_properties = common_properties.clone inherited_properties = inherited_properties.clone table_desc.each do |property, value| if property == "@type" raise Csvlint::Csvw::MetadataError.new("$.tables[?(@.url = '#{table_desc["url"]}')].@type"), "@type of table is not 'Table'" unless value == "Table" else 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 == :table || type == :common table_properties[property] = v elsif type == :column warnings << Csvlint::ErrorMessage.new(:invalid_property, :metadata, nil, nil, property.to_s, nil) else inherited_properties[property] = v end end end table_schema = table_properties["tableSchema"] || inherited_properties["tableSchema"] column_names = [] foreign_keys = [] if table_schema unless table_schema["columns"].instance_of? Array table_schema["columns"] = [] warnings << Csvlint::ErrorMessage.new(:invalid_value, :metadata, nil, nil, "columns", nil) end table_schema.each do |p, v| unless ["columns", "primaryKey", "foreignKeys", "rowTitles"].include? p inherited_properties[p] = v end end virtual_columns = false table_schema["columns"].each_with_index do |column_desc, i| if column_desc.instance_of? Hash column = Csvlint::Csvw::Column.from_json(i + 1, column_desc, base_url, lang, inherited_properties) raise Csvlint::Csvw::MetadataError.new("$.tables[?(@.url = '#{table_desc["url"]}')].tableSchema.columns[#{i}].virtual"), "virtual columns before non-virtual column #{column.name || i}" if virtual_columns && !column.virtual virtual_columns ||= column.virtual raise Csvlint::Csvw::MetadataError.new("$.tables[?(@.url = '#{table_desc["url"]}')].tableSchema.columns"), "multiple columns named #{column.name}" if column_names.include? column.name column_names << column.name unless column.name.nil? columns << column else warnings << Csvlint::ErrorMessage.new(:invalid_column_description, :metadata, nil, nil, column_desc.to_s, nil) end end primary_key_columns = [] primary_key_valid = true table_schema["primaryKey"]&.each do |reference| i = column_names.index(reference) if i primary_key_columns << columns[i] else warnings << Csvlint::ErrorMessage.new(:invalid_column_reference, :metadata, nil, nil, "primaryKey: #{reference}", nil) primary_key_valid = false end end foreign_keys = table_schema["foreignKeys"] foreign_keys&.each_with_index do |foreign_key, i| foreign_key_columns = [] foreign_key["columnReference"].each do |reference| i = column_names.index(reference) raise Csvlint::Csvw::MetadataError.new("$.tables[?(@.url = '#{table_desc["url"]}')].tableSchema.foreignKeys[#{i}].columnReference"), "foreignKey references non-existant column" unless i foreign_key_columns << columns[i] end foreign_key["referencing_columns"] = foreign_key_columns end row_titles = table_schema["rowTitles"] row_title_columns = [] row_titles&.each do |row_title| i = column_names.index(row_title) raise Csvlint::Csvw::MetadataError.new("$.tables[?(@.url = '#{table_desc["url"]}')].tableSchema.rowTitles[#{i}]"), "rowTitles references non-existant column" unless i row_title_columns << columns[i] end end new(table_properties["url"], id: table_properties["@id"], columns: columns, dialect: table_properties["dialect"], foreign_keys: foreign_keys || [], notes: table_properties["notes"] || [], primary_key: (primary_key_valid && !primary_key_columns.empty?) ? primary_key_columns : nil, row_title_columns: row_title_columns, schema: table_schema ? table_schema["@id"] : nil, suppress_output: table_properties["suppressOutput"] || false, annotations: annotations, warnings: warnings) end |
Instance Method Details
#validate_foreign_key_references(foreign_key, remote_url, remote) ⇒ Object
104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/csvlint/csvw/table.rb', line 104 def validate_foreign_key_references(foreign_key, remote_url, remote) reset local = @foreign_key_reference_values[foreign_key] context = {"from" => {"url" => remote_url.to_s.split("/")[-1], "columns" => foreign_key["columnReference"]}, "to" => {"url" => @url.to_s.split("/")[-1], "columns" => foreign_key["reference"]["columnReference"]}} colnum = (foreign_key["referencing_columns"].length == 1) ? foreign_key["referencing_columns"][0].number : nil remote.each_with_index do |r, i| if local[r] build_errors(:multiple_matched_rows, :schema, i + 1, colnum, r, context) if local[r].length > 1 else build_errors(:unmatched_foreign_key_reference, :schema, i + 1, colnum, r, context) end end valid? end |
#validate_foreign_keys ⇒ Object
92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/csvlint/csvw/table.rb', line 92 def validate_foreign_keys reset @foreign_keys.each do |foreign_key| local = @foreign_key_values[foreign_key] remote_table = foreign_key["referenced_table"] remote_table.validate_foreign_key_references(foreign_key, @url, local) @errors += remote_table.errors unless remote_table == self @warnings += remote_table.warnings unless remote_table == self end valid? end |
#validate_header(headers, strict) ⇒ Object
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/csvlint/csvw/table.rb', line 32 def validate_header(headers, strict) reset headers.each_with_index do |header, i| if columns[i] columns[i].validate_header(header, strict) @errors += columns[i].errors @warnings += columns[i].warnings elsif strict build_errors(:malformed_header, :schema, 1, nil, header, nil) else build_warnings(:malformed_header, :schema, 1, nil, header, nil) end end # unless columns.empty? valid? end |
#validate_row(values, row = nil, validate = false) ⇒ Object
48 49 50 51 52 53 54 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 |
# File 'lib/csvlint/csvw/table.rb', line 48 def validate_row(values, row = nil, validate = false) reset unless columns.empty? values.each_with_index do |value, i| column = columns[i] if column v = column.validate(value, row) values[i] = v @errors += column.errors @warnings += column.warnings else build_errors(:too_many_values, :schema, row, nil, value, nil) end end end if validate unless @primary_key.nil? key = @primary_key.map { |column| column.validate(values[column.number - 1], row) } colnum = (primary_key.length == 1) ? primary_key[0].number : nil build_errors(:duplicate_key, :schema, row, colnum, key.join(","), @primary_key_values[key]) if @primary_key_values.include?(key) @primary_key_values[key] = row end # build a record of the unique values that are referenced by foreign keys from other tables # so that later we can check whether those foreign keys reference these values @foreign_key_references.each do |foreign_key| referenced_columns = foreign_key["referenced_columns"] key = referenced_columns.map { |column| column.validate(values[column.number - 1], row) } known_values = @foreign_key_reference_values[foreign_key] = @foreign_key_reference_values[foreign_key] || {} known_values[key] = known_values[key] || [] known_values[key] << row end # build a record of the references from this row to other tables # we can't check yet whether these exist in the other tables because # we might not have parsed those other tables @foreign_keys.each do |foreign_key| referencing_columns = foreign_key["referencing_columns"] key = referencing_columns.map { |column| column.validate(values[column.number - 1], row) } known_values = @foreign_key_values[foreign_key] = @foreign_key_values[foreign_key] || [] known_values << key unless known_values.include?(key) end end valid? end |