mech_core/structures/
record.rs

1use crate::*;
2use indexmap::map::*;
3
4// Record ------------------------------------------------------------------
5
6#[cfg(feature = "record")]
7#[derive(Clone, Debug, PartialEq, Eq)]
8pub struct MechRecord {
9  pub cols: usize,
10  pub kinds: Vec<ValueKind>,
11  pub data: IndexMap<u64,Value>,
12  pub field_names: HashMap<u64,String>,
13}
14
15#[cfg(feature = "record")]
16impl MechRecord {
17
18  pub fn check_record_schema(&self, record: &MechRecord) -> MResult<()> {
19    for (&field_id, _value) in &self.data {
20      // Check field existence
21      if !record.data.contains_key(&field_id) {
22        return Err(MechError2::new(MissingFieldInRecordError { field_id }, None).with_compiler_loc());
23      }
24      // Get expected kind
25      let expected_kind = self.kinds.get(self.key_index(field_id)?)
26        .ok_or_else(|| MechError2::new(MissingKindForFieldError { field_id }, None).with_compiler_loc())?;
27      // Get actual kind
28      let actual_kind = record.kinds.get(record.key_index(field_id)?)
29        .ok_or_else(|| MechError2::new(MissingKindInComparedRecordError { field_id }, None).with_compiler_loc())?;
30      // Compare kinds
31      if expected_kind != actual_kind {
32        return Err(MechError2::new(
33          RecordFieldKindMismatchError {
34            field_id,
35            expected_kind: expected_kind.clone(),
36            actual_kind: actual_kind.clone(),
37          },
38          None
39        ).with_compiler_loc());
40      }
41      // Check field names
42      if self.field_names.get(&field_id) != record.field_names.get(&field_id) {
43        return Err(MechError2::new(
44          RecordFieldNameMismatchError {
45            field_id,
46            expected_name: self.field_names.get(&field_id).cloned(),
47            actual_name: record.field_names.get(&field_id).cloned(),
48          },
49          None
50        ).with_compiler_loc());
51      }
52    }
53    Ok(())
54  }
55
56  fn key_index(&self, field_id: u64) -> MResult<usize> {
57    self.data.keys().position(|&id| id == field_id).ok_or_else(|| {
58      MechError2::new(
59        KeyNotFoundInKeyIndexError { field_id },
60        None
61      ).with_compiler_loc()
62    })
63  }
64
65  #[cfg(feature = "pretty_print")]
66  pub fn to_html(&self) -> String {
67    let mut bindings = Vec::new();
68
69    for (key, value) in &self.data {
70      let name = self.field_names.get(key).unwrap();
71
72      let binding_html = format!(
73        "<span class=\"mech-binding\">\
74          <span class=\"mech-binding-name\">{}</span>\
75          <span class=\"mech-binding-colon-op\">:</span>\
76          <span class=\"mech-binding-value\">{}</span>\
77        </span>",
78        name,
79        value.to_html(),
80      );
81
82      bindings.push(binding_html);
83    }
84
85    format!(
86      "<span class=\"mech-record\">\
87        <span class=\"mech-start-brace\">{{</span>{}<span class=\"mech-end-brace\">}}</span>\
88      </span>",
89      bindings.join("<span class=\"mech-separator\">, </span>")
90    )
91  }
92
93  pub fn get(&self, key: &u64) -> Option<&Value> {
94    self.data.get(key)
95  }
96
97  pub fn new(vec: Vec<(&str, Value)>) -> MechRecord {
98    let mut data = IndexMap::new();
99    let mut field_names = HashMap::new();
100
101    for (name, value) in vec {
102      let col_id = hash_str(name);
103
104      field_names.insert(col_id, name.to_string());
105      data.insert(col_id, value);
106    }
107
108    let kinds = data.iter().map(|(_, v)| v.kind()).collect();
109
110    MechRecord {
111      cols: data.len(),
112      kinds,
113      data,
114      field_names,
115    }
116  }
117
118  pub fn from_vec(vec: Vec<((u64,String),Value)>) -> MechRecord {
119    let mut data = IndexMap::new();
120    let mut field_names = HashMap::new();
121    for ((k,s),v) in vec {
122      field_names.insert(k,s);
123      data.insert(k,v);
124    }
125    let kinds = data.iter().map(|(_,v)| v.kind()).collect();
126    MechRecord{cols: data.len(), kinds, data, field_names}
127  }
128
129  pub fn from_kind(fields: &Vec<(String,ValueKind)>) -> MResult<MechRecord> {
130    let mut data = IndexMap::new();
131    let mut field_names = HashMap::new();
132    for (name, knd) in fields {
133      let col_id = hash_str(name);
134      field_names.insert(col_id, name.to_string());
135      data.insert(col_id, Value::from_kind(knd));
136    }
137    let kinds = data.iter().map(|(_,v)| v.kind()).collect();
138    Ok(MechRecord{cols: data.len(), kinds, data, field_names})
139  }
140
141  pub fn insert_field(&mut self, key: u64, value: Value) {
142    self.cols += 1;
143    self.kinds.push(value.kind());
144    self.data.insert(key, value);
145  }
146
147  pub fn kind(&self) -> ValueKind {
148    ValueKind::Record(self.data.iter()
149      .map(|(k,v)| (self.field_names.get(k).unwrap().to_string(), v.kind()))
150      .collect())
151  }
152
153  pub fn size_of(&self) -> usize {
154    self.data.iter().map(|(_,v)| v.size_of()).sum()
155  }
156
157  pub fn shape(&self) -> Vec<usize> {
158    vec![1,self.cols]
159  }
160}
161
162#[cfg(feature = "pretty_print")]
163impl PrettyPrint for MechRecord {
164  fn pretty_print(&self) -> String {
165    let mut lines = Vec::new();
166
167    for (k, v) in &self.data {
168      let field_name = self.field_names.get(k).unwrap();
169      lines.push(format!(
170        "  {}<{}>: {}",
171        field_name,
172        v.kind(),
173        v.pretty_print()
174      ));
175    }
176
177    format!("{{\n{}\n}}", lines.join("\n"))
178  }
179}
180
181#[cfg(feature = "record")]
182impl Hash for MechRecord {
183  fn hash<H: Hasher>(&self, state: &mut H) {
184    for (k,v) in self.data.iter() {
185      k.hash(state);
186      v.hash(state);
187    }
188  }
189}
190
191#[derive(Debug, Clone)]
192pub struct MissingFieldInRecordError {
193  pub field_id: u64,
194}
195
196impl MechErrorKind2 for MissingFieldInRecordError {
197  fn name(&self) -> &str {
198    "MissingFieldInRecord"
199  }
200  fn message(&self) -> String {
201    format!("Record is missing required field `{}`.", self.field_id)
202  }
203}
204
205#[derive(Debug, Clone)]
206pub struct MissingKindForFieldError {
207  pub field_id: u64,
208}
209
210impl MechErrorKind2 for MissingKindForFieldError {
211  fn name(&self) -> &str {
212    "MissingKindForField"
213  }
214  fn message(&self) -> String {
215    format!("Missing expected kind for field `{}` in schema.", self.field_id)
216  }
217}
218
219#[derive(Debug, Clone)]
220pub struct MissingKindInComparedRecordError {
221  pub field_id: u64,
222}
223
224impl MechErrorKind2 for MissingKindInComparedRecordError {
225  fn name(&self) -> &str {
226    "MissingKindInComparedRecord"
227  }
228  fn message(&self) -> String {
229    format!("Missing kind for field `{}` in the compared record.", self.field_id)
230  }
231}
232
233#[derive(Debug, Clone)]
234pub struct RecordFieldKindMismatchError {
235  pub field_id: u64,
236  pub expected_kind: ValueKind,
237  pub actual_kind: ValueKind,
238}
239
240impl MechErrorKind2 for RecordFieldKindMismatchError {
241  fn name(&self) -> &str {
242    "RecordFieldKindMismatch"
243  }
244  fn message(&self) -> String {
245    format!(
246      "Kind mismatch for column `{}` (expected `{}`, found `{}`).",
247      self.field_id, self.expected_kind, self.actual_kind
248    )
249  }
250}
251
252#[derive(Debug, Clone)]
253pub struct RecordFieldNameMismatchError {
254  pub field_id: u64,
255  pub expected_name: Option<String>,
256  pub actual_name: Option<String>,
257}
258
259impl MechErrorKind2 for RecordFieldNameMismatchError {
260  fn name(&self) -> &str {
261    "RecordFieldNameMismatch"
262  }
263  fn message(&self) -> String {
264    match (&self.expected_name, &self.actual_name) {
265      (Some(e), Some(a)) => format!(
266        "Field name mismatch for field `{}` (expected `{}`, found `{}`).",
267        self.field_id, e, a
268      ),
269      (Some(e), None) => format!(
270        "Field name mismatch for field `{}` (expected `{}`, but no field found).",
271        self.field_id, e
272      ),
273      _ => format!("Field name mismatch for field `{}`.", self.field_id),
274    }
275  }
276}
277
278#[derive(Debug, Clone)]
279pub struct KeyNotFoundInKeyIndexError {
280  pub field_id: u64,
281}
282
283impl MechErrorKind2 for KeyNotFoundInKeyIndexError {
284  fn name(&self) -> &str {
285    "KeyNotFoundInKeyIndex"
286  }
287  fn message(&self) -> String {
288    format!("Key id `{}` not found in key_index.", self.field_id)
289  }
290}