Class: MarkdownServer::CsvBrowser::TableReader
- Inherits:
-
Object
- Object
- MarkdownServer::CsvBrowser::TableReader
- Defined in:
- lib/markdown_server/csv_browser/table_reader.rb
Overview
Reads CSV files and applies view filtering (column subsets). Coerces values to match schema types (integer, number, string).
Instance Method Summary collapse
-
#delete_row(row_index) ⇒ Object
Deletes a row from the CSV file.
-
#duplicate_row(row_index) ⇒ Object
Duplicates a row by inserting an identical copy immediately after it.
-
#initialize(table) ⇒ TableReader
constructor
A new instance of TableReader.
-
#insert_row(values, at: nil) ⇒ Object
Inserts a new row.
-
#read(view_key = nil) ⇒ Object
Returns { columns: [title, type], rows: [[idx, val, …]] } for the given view.
-
#update_row(row_index, changes) ⇒ Object
Updates a row in the CSV file.
-
#validate_all ⇒ Object
Validates all rows against the table schema.
-
#validate_cells(row_index, changes) ⇒ Object
Validates changed cells against the table schema.
Constructor Details
#initialize(table) ⇒ TableReader
Returns a new instance of TableReader.
10 11 12 |
# File 'lib/markdown_server/csv_browser/table_reader.rb', line 10 def initialize(table) @table = table end |
Instance Method Details
#delete_row(row_index) ⇒ Object
Deletes a row from the CSV file. Returns { deleted: true } or { deleted: false, error: “…” }.
70 71 72 73 74 75 76 77 |
# File 'lib/markdown_server/csv_browser/table_reader.rb', line 70 def delete_row(row_index) rows = read_csv_raw return { deleted: false, error: "Row not found" } if row_index < 0 || row_index >= rows.length rows.delete_at(row_index) write_csv(rows) { deleted: true } end |
#duplicate_row(row_index) ⇒ Object
Duplicates a row by inserting an identical copy immediately after it. Returns { duplicated: true, new_index: row_index + 1 } or { duplicated: false, error: “…” }.
113 114 115 116 117 118 119 120 121 122 |
# File 'lib/markdown_server/csv_browser/table_reader.rb', line 113 def duplicate_row(row_index) rows = read_csv_raw return { duplicated: false, error: "Row not found" } if row_index < 0 || row_index >= rows.length source = rows[row_index] copy = CSV::Row.new(source.headers, source.fields) rows.insert(row_index + 1, copy) write_csv(rows) { duplicated: true, new_index: row_index + 1 } end |
#insert_row(values, at: nil) ⇒ Object
Inserts a new row. ‘values` is { col_key => string_value }. When `at` is nil the row is appended; otherwise it’s inserted at that index. Returns { valid: true, new_index: i } or { valid: false, errors: […] }.
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 |
# File 'lib/markdown_server/csv_browser/table_reader.rb', line 82 def insert_row(values, at: nil) string_values = values.each_with_object({}) { |(k, v), h| h[k.to_s] = v.nil? ? nil : v.to_s } coerced = {} @table.columns.each do |col| val = coerce_for_validation(string_values[col.key], col.type) coerced[col.key] = val unless val.nil? end errors = @table.schema.validate(coerced).map { |e| format_error(e) } return { valid: false, errors: errors } unless errors.empty? rows = read_csv_raw headers = @table.columns.map(&:key) new_row = CSV::Row.new(headers, headers.map { |h| string_values[h] }) if at.nil? || at >= rows.length rows << new_row new_index = rows.length - 1 else at = 0 if at < 0 rows.insert(at, new_row) new_index = at end write_csv(rows) { valid: true, new_index: new_index } end |
#read(view_key = nil) ⇒ Object
Returns { columns: [title, type], rows: [[idx, val, …]] } for the given view. Each row’s first element is its original file index.
16 17 18 19 20 |
# File 'lib/markdown_server/csv_browser/table_reader.rb', line 16 def read(view_key = nil) view = find_view(view_key) all_data = read_csv apply_view(all_data, view) end |
#update_row(row_index, changes) ⇒ Object
Updates a row in the CSV file. changes is { col_key => new_string_value }. Returns { valid: true } or { valid: false, errors: […] }.
126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/markdown_server/csv_browser/table_reader.rb', line 126 def update_row(row_index, changes) result = validate_cells(row_index, changes) return result unless result[:valid] rows = read_csv_raw row = rows[row_index] changes.each { |k, v| row[k] = v } write_csv(rows) { valid: true } end |
#validate_all ⇒ Object
Validates all rows against the table schema. Returns { row_index => [error_strings, …], … } for failing rows only.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/markdown_server/csv_browser/table_reader.rb', line 49 def validate_all rows = read_csv_raw errors_by_row = {} rows.each_with_index do |row, idx| coerced = {} @table.columns.each do |col| val = coerce_for_validation(row[col.key], col.type) coerced[col.key] = val unless val.nil? end errors = @table.schema.validate(coerced).map { |e| format_error(e) } errors_by_row[idx] = errors unless errors.empty? end errors_by_row end |
#validate_cells(row_index, changes) ⇒ Object
Validates changed cells against the table schema. changes is a hash of { col_key => new_string_value }. Returns { valid: true } or { valid: false, errors: […] }.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/markdown_server/csv_browser/table_reader.rb', line 25 def validate_cells(row_index, changes) rows = read_csv_raw if row_index < 0 || row_index >= rows.length return { valid: false, errors: [{ "message" => "Row not found", "fields" => [] }] } end row = rows[row_index] merged = row.to_h.merge(changes) # Coerce to schema types for validation (skip blank optional fields # so json_schemer doesn't reject nil as non-string) coerced = {} @table.columns.each do |col| val = coerce_for_validation(merged[col.key], col.type) coerced[col.key] = val unless val.nil? end errors = @table.schema.validate(coerced).map { |e| format_error(e) } errors.empty? ? { valid: true } : { valid: false, errors: errors } end |