Detect new fields in an ILP batch and expand the memtable schema. Scans all lines for tag keys and field keys not present in the current schema. New columns are added with NULL backfill for existing rows. Must be called BEFORE `ingest_batch` so the batch can map values to the expanded schema.
(memtable: &mut ColumnarMemtable, lines: &[IlpLine<'_>])
| 89 | /// Must be called BEFORE `ingest_batch` so the batch can map values to |
| 90 | /// the expanded schema. |
| 91 | pub fn evolve_schema(memtable: &mut ColumnarMemtable, lines: &[IlpLine<'_>]) { |
| 92 | let existing: std::collections::HashSet<String> = memtable |
| 93 | .schema() |
| 94 | .columns |
| 95 | .iter() |
| 96 | .map(|(n, _)| n.clone()) |
| 97 | .collect(); |
| 98 | |
| 99 | let mut new_columns: Vec<(String, ColumnType)> = Vec::new(); |
| 100 | let mut seen: std::collections::HashSet<String> = std::collections::HashSet::new(); |
| 101 | |
| 102 | for line in lines { |
| 103 | for &(key, _) in &line.tags { |
| 104 | if !existing.contains(key) && seen.insert(key.to_string()) { |
| 105 | new_columns.push((key.to_string(), ColumnType::Symbol)); |
| 106 | } |
| 107 | } |
| 108 | for &(key, ref val) in &line.fields { |
| 109 | if !existing.contains(key) && seen.insert(key.to_string()) { |
| 110 | let col_type = match val { |
| 111 | FieldValue::Float(_) => ColumnType::Float64, |
| 112 | FieldValue::Int(_) | FieldValue::UInt(_) => ColumnType::Int64, |
| 113 | FieldValue::Str(_) => ColumnType::Symbol, |
| 114 | FieldValue::Bool(_) => ColumnType::Float64, |
| 115 | }; |
| 116 | new_columns.push((key.to_string(), col_type)); |
| 117 | } |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | for (name, col_type) in new_columns { |
| 122 | memtable.add_column(name, col_type); |
| 123 | } |
| 124 | } |
no test coverage detected