dcsv/
virtual_data.rs

1//! Virtual data module
2
3use crate::error::{DcsvError, DcsvResult};
4use crate::value::{Value, ValueLimiter, ValueType};
5use crate::vcont::VCont;
6use std::cmp::Ordering;
7use std::collections::HashMap;
8
9/// Header for csv schema
10pub const SCHEMA_HEADER: &str = "column,type,default,variant,pattern";
11
12/// Virtual data struct which contains csv information
13///
14/// - VirtualData holds row information as hashmap. Therefore modifying data( cell, row or column ) is generally faster than virtual array struct.
15/// - VirtualData cannot have duplicate column name due to previous hashmap implementaiton
16/// - VirtualData allows limiters to confine csv value's possible states.
17#[derive(Clone)]
18pub struct VirtualData {
19    pub columns: Vec<Column>,
20    pub rows: Vec<Row>,
21}
22
23impl Default for VirtualData {
24    fn default() -> Self {
25        Self::new()
26    }
27}
28
29impl VCont for VirtualData {
30    /// Create empty virtual data
31    fn new() -> Self {
32        Self {
33            columns: vec![],
34            rows: vec![],
35        }
36    }
37
38    /// Move given row to a target row index
39    fn move_row(&mut self, src_index: usize, target_index: usize) -> DcsvResult<()> {
40        let row_count = self.get_row_count();
41        if src_index >= row_count || target_index >= row_count {
42            return Err(DcsvError::OutOfRangeError);
43        }
44
45        let move_direction = src_index.cmp(&target_index);
46        match move_direction {
47            // Go left
48            Ordering::Greater => {
49                let mut index = src_index;
50                let mut next = index - 1;
51                while next >= target_index {
52                    self.rows.swap(index, next);
53
54                    // Usize specific check code
55                    if next == 0 {
56                        break;
57                    }
58
59                    // Update index values
60                    index -= 1;
61                    next -= 1;
62                }
63            }
64            Ordering::Less => {
65                // Go right
66                let mut index = src_index;
67                let mut next = index + 1;
68                while next <= target_index {
69                    self.rows.swap(index, next);
70
71                    // Update index values
72                    index += 1;
73                    next += 1;
74                }
75            }
76            Ordering::Equal => (),
77        }
78        Ok(())
79    }
80
81    /// Move a given column to target column index
82    fn move_column(&mut self, src_index: usize, target_index: usize) -> DcsvResult<()> {
83        let column_count = self.get_column_count();
84        if src_index >= column_count || target_index >= column_count {
85            return Err(DcsvError::OutOfRangeError);
86        }
87
88        let move_direction = src_index.cmp(&target_index);
89        match move_direction {
90            // Go left
91            Ordering::Greater => {
92                let mut index = src_index;
93                let mut next = index - 1;
94                while next >= target_index {
95                    self.columns.swap(index, next);
96
97                    // Usize specific check code
98                    if next == 0 {
99                        break;
100                    }
101
102                    // Update index values
103                    index -= 1;
104                    next -= 1;
105                }
106            }
107            Ordering::Less => {
108                // Go right
109                let mut index = src_index;
110                let mut next = index + 1;
111                while next <= target_index {
112                    self.columns.swap(index, next);
113
114                    // Update index values
115                    index += 1;
116                    next += 1;
117                }
118            }
119            Ordering::Equal => (),
120        }
121        Ok(())
122    }
123
124    /// Rename a column
125    ///
126    /// Column's name cannot be an exsiting name
127    ///
128    /// * column   : column_index
129    /// * new_name : New column name
130    fn rename_column(&mut self, column_index: usize, new_name: &str) -> DcsvResult<()> {
131        let next_column_index = self.try_get_column_index(new_name);
132
133        if !self.is_valid_cell_coordinate(0, column_index) {
134            return Err(DcsvError::OutOfRangeError);
135        }
136
137        if next_column_index.is_some() {
138            return Err(DcsvError::InvalidColumn(format!(
139                "Cannot rename to \"{}\" which already exists",
140                &new_name
141            )));
142        }
143
144        let previous = self.columns[column_index].rename(new_name);
145        for row in &mut self.rows {
146            row.rename_column(&previous, new_name);
147        }
148        Ok(())
149    }
150
151    /// Set values to a column
152    ///
153    /// Given value will override every row's value
154    fn set_column(&mut self, column_index: usize, value: Value) -> DcsvResult<()> {
155        if !self.is_valid_cell_coordinate(0, column_index) {
156            return Err(DcsvError::OutOfRangeError);
157        }
158
159        let column = &self.columns[column_index].name;
160
161        for row in &mut self.rows {
162            row.update_cell_value(column, value.clone());
163        }
164        Ok(())
165    }
166
167    /// Edit a row
168    ///
169    /// Only edit row's cell when value is not none
170    fn edit_row(&mut self, row_index: usize, values: &[Option<Value>]) -> DcsvResult<()> {
171        // Row's value doesn't match length of columns
172        if values.len() != self.get_column_count() {
173            return Err(DcsvError::InsufficientRowData);
174        }
175        // Invalid cooridnate
176        if !self.is_valid_cell_coordinate(row_index, 0) {
177            return Err(DcsvError::OutOfRangeError);
178        }
179
180        let col_value_iter = self.columns.iter().zip(values.iter());
181
182        for (col, value) in col_value_iter {
183            if let Some(value) = value {
184                // Early return if doesn't qualify a single element
185                if !col.limiter.qualify(value) {
186                    return Err(DcsvError::InvalidRowData(format!(
187                        "\"{}\" doesn't qualify \"{}\"'s limiter",
188                        value, col.name
189                    )));
190                }
191            }
192        }
193
194        let col_value_iter = self.columns.iter().zip(values.iter());
195
196        // It is safe to unwrap because row_number
197        // was validated by is_valid_cell_coordinate method.
198        let row = self.rows.get_mut(row_index).unwrap();
199        for (col, value) in col_value_iter {
200            if let Some(value) = value {
201                row.update_cell_value(&col.name, value.clone())
202            }
203        }
204
205        Ok(())
206    }
207
208    // TODO
209    // 1. Check limiter
210    // 2. Check if value exists
211    /// Set values to a row
212    ///
213    /// This assumes that given values accord to column's order.
214    /// This method will fail when given value fails to qualify column's limiter.
215    fn set_row(&mut self, row_index: usize, values: &[Value]) -> DcsvResult<()> {
216        // Row's value doesn't match length of columns
217        if values.len() != self.get_column_count() {
218            return Err(DcsvError::InsufficientRowData);
219        }
220        // Invalid cooridnate
221        if !self.is_valid_cell_coordinate(row_index, 0) {
222            return Err(DcsvError::OutOfRangeError);
223        }
224
225        let col_value_iter = self.columns.iter().zip(values.iter());
226
227        for (col, value) in col_value_iter.clone() {
228            // Early return if doesn't qualify a single element
229            if !col.limiter.qualify(value) {
230                return Err(DcsvError::InvalidRowData(format!(
231                    "\"{}\" doesn't qualify \"{}\"'s limiter",
232                    value, col.name
233                )));
234            }
235        }
236
237        // It is safe to unwrap because row_number
238        // was validated by is_valid_cell_coordinate method.
239        let row = self.rows.get_mut(row_index).unwrap();
240        for (col, value) in col_value_iter {
241            row.update_cell_value(&col.name, value.clone())
242        }
243
244        Ok(())
245    }
246
247    /// get cell data by coordinate
248    fn get_cell(&self, x: usize, y: usize) -> Option<&Value> {
249        if let Ok(column) = self.get_column_if_valid(x, y) {
250            self.rows[x].get_cell_value(&column.name)
251        } else {
252            None
253        }
254    }
255
256    /// Set cell value by coordinate
257    fn set_cell(&mut self, x: usize, y: usize, value: Value) -> DcsvResult<()> {
258        let name = self.get_column_if_valid(x, y)?.name.to_owned();
259
260        self.is_valid_column_data(y, &value)?;
261        self.rows[x].update_cell_value(&name, value);
262
263        Ok(())
264    }
265
266    // THis should insert row with given column limiters
267    /// Insert a row to given index
268    ///
269    /// This can yield out of rnage error
270    fn insert_row(&mut self, row_index: usize, source: Option<&[Value]>) -> DcsvResult<()> {
271        if row_index > self.get_row_count() {
272            return Err(DcsvError::InvalidColumn(format!(
273                "Cannot add row to out of range position : {}",
274                row_index
275            )));
276        }
277        let mut new_row = Row::new();
278        if let Some(source) = source {
279            self.check_row_length(source)?;
280            let iter = self.columns.iter().zip(source.iter());
281
282            for (col, value) in iter.clone() {
283                if !col.limiter.qualify(value) {
284                    return Err(DcsvError::InvalidRowData(format!(
285                        "\"{}\" doesn't qualify \"{}\"'s limiter",
286                        value, col.name
287                    )));
288                }
289            }
290
291            iter.for_each(|(col, v)| new_row.insert_cell(&col.name, v.clone()));
292        } else {
293            for col in &self.columns {
294                new_row.insert_cell(&col.name, col.get_default_value());
295            }
296        }
297        self.rows.insert(row_index, new_row);
298        Ok(())
299    }
300
301    fn insert_column(&mut self, column_index: usize, column_name: &str) -> DcsvResult<()> {
302        if column_index > self.get_column_count() {
303            return Err(DcsvError::InvalidColumn(format!(
304                "Cannot add column to out of range position : {}",
305                column_index
306            )));
307        }
308        if self.try_get_column_index(column_name).is_some() {
309            return Err(DcsvError::InvalidColumn(format!(
310                "Cannot add existing column = \"{}\"",
311                column_name
312            )));
313        }
314        let new_column = Column::new(column_name, ValueType::Text, None);
315        let default_value = new_column.get_default_value();
316        for row in &mut self.rows {
317            row.insert_cell(&new_column.name, default_value.clone());
318        }
319        self.columns.insert(column_index, new_column);
320        Ok(())
321    }
322
323    /// Delete a row with given row_index
324    ///
325    /// This doesn't fail but silently do nothing if index is out of range
326    fn delete_row(&mut self, row_index: usize) -> bool {
327        let row_count = self.get_row_count();
328        if row_count == 0 || row_count < row_index {
329            return false;
330        }
331        self.rows.remove(row_index);
332        true
333    }
334
335    /// Delete a column with given column index
336    fn delete_column(&mut self, column_index: usize) -> DcsvResult<()> {
337        let name = self.get_column_if_valid(0, column_index)?.name.to_owned();
338
339        for row in &mut self.rows {
340            row.remove_cell(&name);
341        }
342
343        self.columns.remove(column_index);
344
345        // If column is empty, drop all rows
346        if self.get_column_count() == 0 {
347            self.rows = vec![];
348        }
349
350        Ok(())
351    }
352
353    /// Get total rows count
354    fn get_row_count(&self) -> usize {
355        self.rows.len()
356    }
357
358    /// Get total columns count
359    fn get_column_count(&self) -> usize {
360        self.columns.len()
361    }
362
363    /// Drop all data from virtual data
364    fn drop_data(&mut self) {
365        self.columns.clear();
366        self.rows.clear();
367    }
368
369    /// Apply closure to all values
370    fn apply_all<F: FnMut(&mut Value)>(&mut self, mut f: F) {
371        for row in &mut self.rows {
372            for value in row.values.values_mut() {
373                f(value)
374            }
375        }
376    }
377}
378
379impl VirtualData {
380    /// Get read only data from virtual data
381    ///
382    /// This clones every value into a ReadOnlyData.
383    /// If the purpose is to simply iterate over values, prefer read_only_ref method.
384    pub fn read_only(&self) -> ReadOnlyData {
385        ReadOnlyData::from(self)
386    }
387
388    /// Get read only data from virtual data, but as reference
389    pub fn read_only_ref(&self) -> ReadOnlyDataRef {
390        ReadOnlyDataRef::from(self)
391    }
392
393    /// Set cell's value with given string value
394    ///
395    /// This will fail if the value cannot be converted to column's type
396    pub fn set_cell_from_string(&mut self, x: usize, y: usize, value: &str) -> DcsvResult<()> {
397        let key_column = self.get_column_if_valid(x, y)?;
398        match key_column.column_type {
399            ValueType::Text => self.set_cell(x, y, Value::Text(value.to_string())),
400            ValueType::Number => self.set_cell(
401                x,
402                y,
403                Value::Number(value.parse().map_err(|_| {
404                    DcsvError::InvalidCellData(format!(
405                        "Given value is \"{}\" which is not a number",
406                        value
407                    ))
408                })?),
409            ),
410        }
411    }
412
413    /// Insert a column with given column informations
414    ///
415    /// # Args
416    ///
417    /// * column_index  : Position to put column
418    /// * column_name   : New column name
419    /// * column_type   : Column's type
420    /// * limiter       : Set limiter with
421    /// * placeholder   : Placeholder will be applied to every row
422    pub fn insert_column_with_type(
423        &mut self,
424        column_index: usize,
425        column_name: &str,
426        column_type: ValueType,
427        limiter: Option<ValueLimiter>,
428        placeholder: Option<Value>,
429    ) -> DcsvResult<()> {
430        if column_index > self.get_column_count() {
431            return Err(DcsvError::InvalidColumn(format!(
432                "Cannot add column to out of range position : {}",
433                column_index
434            )));
435        }
436        if self.try_get_column_index(column_name).is_some() {
437            return Err(DcsvError::InvalidColumn(format!(
438                "Cannot add existing column = \"{}\"",
439                column_name
440            )));
441        }
442        let new_column = Column::new(column_name, column_type, limiter);
443        let default_value = new_column.get_default_value();
444        for row in &mut self.rows {
445            row.insert_cell(
446                &new_column.name,
447                placeholder.clone().unwrap_or_else(|| default_value.clone()),
448            );
449        }
450        self.columns.insert(column_index, new_column);
451        Ok(())
452    }
453
454    /// Set a limiter to a column
455    ///
456    /// # Args
457    ///
458    /// * column  : column's index
459    /// * limiter : Target limiter
460    /// * panic   : If true, failed set will occur panic
461    pub fn set_limiter(
462        &mut self,
463        column: usize,
464        limiter: &ValueLimiter,
465        panic: bool,
466    ) -> DcsvResult<()> {
467        let column = &mut self.columns[column];
468        for (index, row) in self.rows.iter_mut().enumerate() {
469            let mut qualified = true;
470            let mut converted = None;
471            let mut convert_to = None;
472            if let Some(value) = row.get_cell_value(&column.name) {
473                // Check if value can be converted at most
474                if let Some(ttype) = limiter.is_convertible(value) {
475                    converted.replace(Value::from_str(&value.to_string(), ttype)?);
476                    convert_to = Some(ttype);
477                }
478
479                // Check if value qualify limiter condition
480                if !limiter.qualify(converted.as_ref().unwrap_or(value)) {
481                    qualified = false;
482                    convert_to = None;
483                    if panic {
484                        return Err(DcsvError::InvalidCellData(format!(
485                            "Cell {},{} doesn't match limiter's qualification",
486                            index, column.name
487                        )));
488                    }
489                }
490            } else {
491                return Err(DcsvError::InvalidRowData(
492                    "Failed to get row data while setting limiter".to_string(),
493                ));
494            }
495
496            if let Some(ttype) = convert_to {
497                row.change_cell_type(&column.name, ttype)?;
498            } else if !qualified && !panic {
499                // Force update to defualt value
500                // It is mostly safe to unwrap because default is required for pattern or variant
501                // but, limiter might only have a single "type" value
502                row.update_cell_value(
503                    &column.name,
504                    limiter
505                        .get_default()
506                        .unwrap_or(&Value::empty(limiter.get_type()))
507                        .clone(),
508                );
509            }
510        }
511        column.set_limiter(limiter.clone());
512        Ok(())
513    }
514
515    /// Qualify data and get reference of qualifed rows.
516    pub fn qualify(&self, column: usize, limiter: &ValueLimiter) -> DcsvResult<Vec<&Row>> {
517        let mut rows = vec![];
518        let column = &self.columns[column];
519        for row in &self.rows {
520            if let Some(value) = row.get_cell_value(&column.name) {
521                // Check if value qualify limiter condition
522                if limiter.qualify(value) {
523                    rows.push(row)
524                }
525            } else {
526                return Err(DcsvError::InvalidRowData(
527                    "Failed to get row data while qualifying".to_string(),
528                ));
529            }
530        }
531        Ok(rows)
532    }
533
534    /// Qualify data with multiple limiters and get reference of qualifed rows.
535    pub fn qualify_multiple(
536        &self,
537        qualifiers: Vec<(usize, &ValueLimiter)>,
538    ) -> DcsvResult<Vec<&Row>> {
539        let mut rows = vec![];
540        // Rows loop
541        'outer: for row in &self.rows {
542            // Values loop in
543            for (column, limiter) in &qualifiers {
544                let column = &self.columns[*column];
545                if let Some(value) = row.get_cell_value(&column.name) {
546                    // Check if value qualify limiter condition
547                    if !limiter.qualify(value) {
548                        continue 'outer;
549                    }
550                } else {
551                    return Err(DcsvError::InvalidRowData(
552                        "Failed to get row data while qualifying".to_string(),
553                    ));
554                }
555            }
556
557            // Only push if all qualifiers suceeded.
558            rows.push(row);
559        }
560        Ok(rows)
561    }
562
563    /// Export virtual data's schema(limiter) as string form
564    ///
565    /// Schema is expressed as csv value. Each line is structured with following order.
566    ///
567    /// - column
568    /// - type
569    /// - default
570    /// - variant
571    /// - pattern
572    pub fn export_schema(&self) -> String {
573        let mut schema = format!("{}\n", SCHEMA_HEADER);
574        for col in &self.columns {
575            let mut line = col.name.clone() + ",";
576            let limiter = &col.limiter;
577            line.push_str(&limiter.get_type().to_string());
578            line.push(',');
579            line.push_str(
580                &limiter
581                    .get_default()
582                    .map(|s| s.to_string())
583                    .unwrap_or_default(),
584            );
585            line.push(',');
586            line.push_str(
587                &limiter
588                    .get_variant()
589                    .map(|s| s.iter().map(|s| s.to_string()).collect::<Vec<String>>())
590                    .unwrap_or_default()
591                    .join(" "),
592            );
593            line.push(',');
594            line.push_str(
595                &limiter
596                    .get_pattern()
597                    .map(|s| s.to_string())
598                    .unwrap_or_default(),
599            );
600
601            schema.push_str(&(line + "\n"));
602        }
603        schema
604    }
605
606    // <DRY>
607    /// Get a column index from src
608    ///
609    /// Src can be either colum name or column index
610    /// If colum index is out of range, it returns none
611    pub fn try_get_column_index(&self, src: &str) -> Option<usize> {
612        let column_index = match src.parse::<usize>() {
613            Err(_) => self.columns.iter().position(|c| c.name == src),
614            Ok(index) => {
615                if index < self.get_column_count() {
616                    Some(index)
617                } else {
618                    None
619                }
620            }
621        };
622        column_index
623    }
624
625    /// Check if cell coordinate is not out of range
626    ///
627    /// # Return
628    ///
629    /// True if given coordinate is within data's boundary, false if not.
630    fn is_valid_cell_coordinate(&self, x: usize, y: usize) -> bool {
631        if x < self.get_row_count() && y < self.get_column_count() {
632            return true;
633        }
634
635        false
636    }
637
638    /// Check if given coordinate exits and return target column
639    fn get_column_if_valid(&self, x: usize, y: usize) -> DcsvResult<&Column> {
640        if !self.is_valid_cell_coordinate(x, y) {
641            return Err(DcsvError::OutOfRangeError);
642        }
643        // It is sfe to uwnrap because
644        // it was validated by prior is_valid_cell_coordinate method
645        let key_column = self.columns.get(y).unwrap();
646        Ok(key_column)
647    }
648
649    /// Check if given value corresponds to column limiter
650    fn is_valid_column_data(&self, column: usize, value: &Value) -> DcsvResult<()> {
651        if let Some(col) = self.columns.get(column) {
652            if col.limiter.qualify(value) {
653                Ok(())
654            } else {
655                Err(DcsvError::InvalidCellData(
656                    "Given cell data failed to match limiter's restriction".to_string(),
657                ))
658            }
659        } else {
660            Err(DcsvError::InvalidRowData(format!(
661                "Given column index \"{}\" doesn't exist",
662                column
663            )))
664        }
665    }
666
667    /// Check if given values' length matches column's legnth
668    fn check_row_length(&self, values: &[Value]) -> DcsvResult<()> {
669        match self.get_column_count().cmp(&values.len()) {
670            Ordering::Equal => (),
671            Ordering::Less | Ordering::Greater => {
672                return Err(DcsvError::InvalidRowData(format!(
673                    r#"Given row length is "{}" while columns length is "{}""#,
674                    values.len(),
675                    self.get_column_count()
676                )))
677            }
678        }
679        Ok(())
680    }
681
682    /// Get iterator.
683    ///
684    /// This methods returns iterator which respects column orders
685    pub fn get_iterator(&self) -> std::vec::IntoIter<&Value> {
686        let columns = &self.columns;
687        let mut iterate = vec![];
688        for row in &self.rows {
689            iterate.extend(row.get_iterator(columns));
690        }
691        iterate.into_iter()
692    }
693
694    /// Get iterator of a row with given index
695    ///
696    /// This respects  columns orders
697    pub fn get_row_iterator(&self, row_index: usize) -> DcsvResult<std::vec::IntoIter<&Value>> {
698        let columns = &self.columns;
699        Ok(self
700            .rows
701            .get(row_index)
702            .ok_or(DcsvError::OutOfRangeError)?
703            .get_iterator(columns))
704    }
705
706    // </DRY>
707}
708
709/// to_string implementation for virtual data
710///
711/// This returns csv value string
712impl std::fmt::Display for VirtualData {
713    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
714        let mut csv_src = String::new();
715        let column_row = self
716            .columns
717            .iter()
718            .map(|c| c.name.as_str())
719            .collect::<Vec<&str>>()
720            .join(",")
721            + "\n";
722        csv_src.push_str(&column_row);
723
724        let columns = self
725            .columns
726            .iter()
727            .map(|col| col.name.as_str())
728            .collect::<Vec<&str>>();
729        for row in &self.rows {
730            let row_value = columns
731                .iter()
732                .map(|name| {
733                    row.get_cell_value(name)
734                        .unwrap_or(&Value::Text(String::new()))
735                        .to_string()
736                })
737                .collect::<Vec<String>>()
738                .join(",")
739                + "\n";
740
741            csv_src.push_str(&row_value);
742        }
743        // Remove trailing newline
744        csv_src.pop();
745        write!(f, "{}", csv_src)
746    }
747}
748
749/// Column of virtual data
750///
751/// Column is "text" type by default but can be further configured with value limiter.
752#[derive(Clone, Debug)]
753pub struct Column {
754    pub name: String,
755    pub column_type: ValueType,
756    pub limiter: ValueLimiter,
757}
758
759impl Column {
760    /// Create empty column with name
761    pub fn empty(name: &str) -> Self {
762        Self {
763            name: name.to_string(),
764            column_type: ValueType::Text,
765            limiter: ValueLimiter::default(),
766        }
767    }
768
769    /// Create new column with properties
770    pub fn new(name: &str, column_type: ValueType, limiter: Option<ValueLimiter>) -> Self {
771        Self {
772            name: name.to_string(),
773            column_type,
774            limiter: limiter.unwrap_or_default(),
775        }
776    }
777
778    /// Get column name
779    pub fn get_name(&self) -> &str {
780        &self.name
781    }
782
783    /// Get column type
784    pub fn get_column_type(&self) -> &ValueType {
785        &self.column_type
786    }
787
788    /// Rename a column and return an original name
789    pub fn rename(&mut self, new_name: &str) -> String {
790        std::mem::replace(&mut self.name, new_name.to_string())
791    }
792
793    /// Apply limiter to a column
794    pub fn set_limiter(&mut self, limiter: ValueLimiter) {
795        self.column_type = limiter.get_type();
796        self.limiter = limiter;
797    }
798
799    /// Get default value by column
800    ///
801    /// Every value type has it's own default value.
802    /// The default value can differ by limiter's variant of patterns and should comply to a
803    /// limter's predicate.
804    pub fn get_default_value(&self) -> Value {
805        // has default
806        if let Some(def) = self.limiter.get_default() {
807            return def.clone();
808        }
809
810        // has variant
811        let variant = self.limiter.get_variant();
812        if let Some(vec) = variant {
813            if !vec.is_empty() {
814                return vec[0].clone();
815            }
816        }
817
818        // Construct new default value
819        match self.column_type {
820            ValueType::Number => Value::Number(0),
821            ValueType::Text => Value::Text(String::new()),
822        }
823    }
824}
825
826/// Row
827///
828/// Row is implementated as a hashmap. You cannot iterate row without column information.
829#[derive(Clone, Debug)]
830pub struct Row {
831    pub values: HashMap<String, Value>,
832}
833
834impl Default for Row {
835    fn default() -> Self {
836        Self::new()
837    }
838}
839
840impl Row {
841    /// Create a new row
842    pub fn new() -> Self {
843        Self {
844            values: HashMap::new(),
845        }
846    }
847
848    /// Convert row to vector with given columns
849    ///
850    /// It is totally valid to give partial columns into a row.
851    pub fn to_vector(&self, columns: &[Column]) -> DcsvResult<Vec<&Value>> {
852        let mut acc = Vec::default();
853        for col in columns {
854            acc.push(self.values.get(&col.name).ok_or_else(|| {
855                DcsvError::InvalidColumn(
856                    "Given column was not present thus cannot construct row vector".to_string(),
857                )
858            })?);
859        }
860        Ok(acc)
861    }
862
863    /// Get comma separated row string
864    ///
865    /// This requires columns because a row is not a linear container. Partial column is not an
866    /// error but valid behaviour.
867    pub fn to_string(&self, columns: &[Column]) -> DcsvResult<String> {
868        let mut acc = String::new();
869        for col in columns {
870            acc.push_str(
871                &self
872                    .values
873                    .get(&col.name)
874                    .ok_or_else(|| {
875                        DcsvError::InvalidColumn(
876                            "Given column was not present thus cannot construct row string"
877                                .to_string(),
878                        )
879                    })?
880                    .to_string(),
881            );
882            acc.push(',');
883        }
884        acc.pop(); // Remove trailing comma
885        Ok(acc)
886    }
887
888    /// Rename column name inside row map
889    ///
890    /// This doesn't validate column's name and should comply with column name rule to avoid
891    /// unintended behaviour.
892    pub fn rename_column(&mut self, name: &str, new_name: &str) {
893        let previous = self.values.remove(name);
894
895        if let Some(prev) = previous {
896            self.values.insert(new_name.to_string(), prev);
897        }
898    }
899
900    /// Insert a new cell(key, value pair) into a row
901    pub fn insert_cell(&mut self, key: &str, value: Value) {
902        self.values.insert(key.to_string(), value);
903    }
904
905    /// Get a cell value by a key
906    pub fn get_cell_value(&self, key: &str) -> Option<&Value> {
907        self.values.get(key)
908    }
909
910    /// Update a cell's value with a given value
911    ///
912    /// This doesn't fail and silently do nothing if key doesn't exist.
913    pub fn update_cell_value(&mut self, key: &str, value: Value) {
914        if let Some(v) = self.values.get_mut(key) {
915            *v = value;
916        }
917    }
918
919    /// Chagnes a cell's value type
920    ///
921    /// This method tries to naturally convert cell's type.
922    /// Empty text value defaults to "0".
923    pub fn change_cell_type(&mut self, key: &str, target_type: ValueType) -> DcsvResult<()> {
924        if let Some(v) = self.values.get_mut(key) {
925            match v {
926                Value::Text(t) => {
927                    if target_type == ValueType::Number {
928                        // Empty text value can be evaluted to 0 value number
929                        if t.is_empty() {
930                            *v = Value::Number(0);
931                            return Ok(());
932                        }
933
934                        *v = Value::Number(t.parse::<isize>().map_err(|_| {
935                            DcsvError::InvalidCellData(format!(
936                                "\"{}\" is not a valid value to be converted to type : \"{}\"",
937                                t, target_type
938                            ))
939                        })?);
940                    }
941                }
942                Value::Number(n) => {
943                    if target_type == ValueType::Text {
944                        *v = Value::Text(n.to_string());
945                    }
946                }
947            }
948        }
949        Ok(())
950    }
951
952    /// Remove a cell by key
953    pub fn remove_cell(&mut self, key: &str) {
954        self.values.remove(key);
955    }
956
957    /// Get iterator with given columns
958    pub fn get_iterator(&self, columns: &[Column]) -> std::vec::IntoIter<&Value> {
959        let mut iterate = vec![];
960        for col in columns {
961            if let Some(value) = self.values.get(&col.name) {
962                iterate.push(value);
963            }
964        }
965        iterate.into_iter()
966    }
967}
968
969/// Read only data
970///
971/// This is a cloned data from virtual_data, thus lifetime independent
972#[derive(Debug)]
973pub struct ReadOnlyData {
974    pub columns: Vec<Column>,
975    pub rows: Vec<Vec<Value>>,
976}
977
978impl From<&VirtualData> for ReadOnlyData {
979    fn from(data: &VirtualData) -> Self {
980        let mut rows: Vec<Vec<Value>> = vec![];
981        for row in &data.rows {
982            let mut static_row: Vec<Value> = vec![];
983            for col in &data.columns {
984                static_row.push(row.get_cell_value(&col.name).unwrap().clone())
985            }
986            rows.push(static_row);
987        }
988        Self {
989            columns: data.columns.clone(),
990            rows,
991        }
992    }
993}
994
995/// Borrowed read only data from virtual_data
996///
997/// * Columns : Vec<&str>
998/// * rows    : Vec<Vec<&Value>>
999#[derive(Debug)]
1000pub struct ReadOnlyDataRef<'data> {
1001    pub columns: Vec<&'data Column>,
1002    pub rows: Vec<Vec<&'data Value>>,
1003}
1004
1005impl<'data> ReadOnlyDataRef<'data> {
1006    /// Get owned ReadOnlyData struct
1007    ///
1008    /// This clones all information into a separate struct
1009    pub fn to_owned(&self) -> ReadOnlyData {
1010        ReadOnlyData {
1011            columns: self.columns.iter().map(|&c| c.clone()).collect::<Vec<_>>(),
1012            rows: self
1013                .rows
1014                .iter()
1015                .map(|vv| vv.iter().map(|&v| v.clone()).collect::<Vec<_>>())
1016                .collect::<Vec<Vec<_>>>(),
1017        }
1018    }
1019}
1020
1021impl<'data> From<&'data VirtualData> for ReadOnlyDataRef<'data> {
1022    fn from(data: &'data VirtualData) -> Self {
1023        let mut rows: Vec<Vec<&'data Value>> = vec![];
1024        for row in &data.rows {
1025            let mut static_row: Vec<&'data Value> = vec![];
1026            for col in &data.columns {
1027                static_row.push(row.get_cell_value(&col.name).unwrap())
1028            }
1029            rows.push(static_row);
1030        }
1031        Self {
1032            columns: data.columns.iter().collect(),
1033            rows,
1034        }
1035    }
1036}