1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 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
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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
use std::{
    vec,
    collections::HashMap,
};

use crate::{
    add, col, add_with, error, reduce,

    Add, ColSpec, Flush, Headers, Inspect, Reduce, Row, RowResult, AddWith,
    Del, Group, AdjacentGroup, MockStream, Rename, GroupBuildError, MapRow, MapCol,

    aggregate::Aggregate,
    flush::FlushTarget,
};

/// This trait describes de behaviour of every component in the CSV transformation
/// chain. Functions provided by this trait help construct the chain and can be
/// _chained_.
///
/// Implement this trait to extend `csvsc` with your own processors.
pub trait RowStream: IntoIterator<Item = RowResult> {

    /// Must return headers as they are in this point of the chain. For example
    /// if implementor adds a column, its `headers()` function must return the
    /// new headers including the one just added.
    fn headers(&self) -> &Headers;

    /// Allows adding columns to each row of the stream.
    fn add(self, column: ColSpec) -> Result<Add<Self>, add::BuildError>
    where
        Self: Sized,
    {
        Add::new(self, column)
    }

    /// Deletes the specified columns from each row of the stream
    fn del(self, columns: Vec<&str>) -> Del<Self>
    where
        Self: Sized,
    {
        Del::new(self, columns)
    }

    /// Adds a column to each row of the stream using a closure to compute its
    /// value
    fn add_with<F>(self, colname: &str, f: F) -> Result<AddWith<Self, F>, add_with::BuildError>
    where
        Self: Sized,
        F: FnMut(&Headers, &Row) -> Result<String, col::BuildError>,
    {
        AddWith::new(self, colname, f)
    }

    /// Group by one or more columns, compute aggregates and output the
    /// resulting columns
    fn reduce(
        self,
        columns: Vec<Box<dyn Aggregate>>,
    ) -> Result<Reduce<Self>, reduce::BuildError>
    where
        Self: Sized,
    {
        Reduce::new(self, columns)
    }

    fn adjacent_group<H, F, R>(
        self,
        header_map: H,
        f: F,
        grouping: &[&str],
    ) -> Result<AdjacentGroup<Self, F>, GroupBuildError>
    where
        H: FnMut(Headers) -> Headers,
        F: FnMut(MockStream<vec::IntoIter<RowResult>>) -> R,
        R: RowStream,
        Self: Sized,
    {
        AdjacentGroup::new(self, header_map, f, grouping)
    }

    fn group<H, F, R>(
        self,
        header_map: H,
        f: F,
        grouping: &[&str],
    ) -> Result<Group<Self, F>, GroupBuildError>
    where
        H: FnMut(Headers) -> Headers,
        F: FnMut(MockStream<vec::IntoIter<RowResult>>) -> R,
        R: RowStream,
        Self: Sized,
    {
        Group::new(self, header_map, f, grouping)
    }

    /// When consumed, writes to destination specified by the column given in
    /// the first argument. Other than that this behaves like an `id(x)`
    /// function so you can specify more links in the chain and even more
    /// flushers.
    fn flush(self, target: FlushTarget) -> error::Result<Flush<Self>>
    where
        Self: Sized,
    {
        Ok(Flush::new(self, target)?)
    }

    /// Mostly for debugging, calls a closure on each element. Behaves like the
    /// identity function on the stream returning each row untouched.
    fn inspect<F>(self, f: F) -> Inspect<Self, F>
    where
        Self: Sized,
        F: FnMut(&Headers, &RowResult),
    {
        Inspect::new(self, f)
    }

    /// Renames some columns
    fn rename(self, name_map: &HashMap<&str, &str>) -> Rename<Self>
    where
        Self: Sized,
    {
        Rename::new(self, name_map)
    }

    /// Apply a function to an entire row
    fn map_row<F>(self, f: F) -> MapRow<Self, F>
    where
        Self: Sized,
        F: Fn(&Headers, &Row) -> RowResult,
    {
        MapRow::new(self, f)
    }

    /// Apply a function to a single column of the stream, this function dones't fail
    /// if the column dones't exist.
    fn map_col<F>(self, col: String, f: F) -> MapCol<Self, F>
    where
        Self: Sized,
        F: Fn(&str) -> Result<String, col::BuildError>,
    {
        MapCol::new(self, col, f)
    }
}