[READ-ONLY] Mirror of https://github.com/probablykasper/csv-pipeline.
0

Configure Feed

Select the types of activity you want to include in your feed.

Add `filter_col` method

Kasper (Jan 18, 2023, 6:14 AM +0100) b9cb9e91 6b365127

+80 -13
+2 -2
CHANGELOG.md
··· 1 1 # Changelog 2 2 3 3 ## Next 4 - - Add Pipeline select method 5 - - Add Pipeline filter method 4 + - Add Pipeline `select` method 5 + - Add Pipeline `filter` & `filter_col` methods 6 6 - Add Pipeline `from_pipelines` constructor for merging pipelines together 7 7 - Remember row order in transform_into 8 8 - Include source index in errors
+37 -4
src/pipeline.rs
··· 1 1 use super::headers::Headers; 2 2 use crate::pipeline_iterators::{ 3 - AddCol, Filter, Flush, MapCol, MapRow, PipelinesChain, Select, TransformInto, Validate, 4 - ValidateCol, 3 + AddCol, Filter, FilterCol, Flush, MapCol, MapRow, PipelinesChain, Select, TransformInto, 4 + Validate, ValidateCol, 5 5 }; 6 6 use crate::target::{StringTarget, Target}; 7 7 use crate::transform::Transform; ··· 192 192 /// .unwrap() 193 193 /// .filter(|headers, row| { 194 194 /// let country = headers.get_field(&row, "Country").unwrap(); 195 - /// Ok(country == "Tuvalu") 195 + /// country == "Tuvalu" 196 196 /// }) 197 197 /// .collect_into_string() 198 198 /// .unwrap(); ··· 205 205 /// ``` 206 206 pub fn filter<F>(mut self, get_row: F) -> Self 207 207 where 208 - F: FnMut(&Headers, &Row) -> Result<bool, Error> + 'a, 208 + F: FnMut(&Headers, &Row) -> bool + 'a, 209 209 { 210 210 self.iterator = Box::new(Filter { 211 + iterator: self.iterator, 212 + f: get_row, 213 + source: self.source, 214 + headers: self.headers.clone(), 215 + }); 216 + self 217 + } 218 + 219 + /// Filter rows based on the field of the specified column, using the provided closure. 220 + /// 221 + /// ## Example 222 + /// 223 + /// ``` 224 + /// use csv_pipeline::Pipeline; 225 + /// 226 + /// let csv = Pipeline::from_path("test/Countries.csv") 227 + /// .unwrap() 228 + /// .filter_col("Country", |country| country == "Tuvalu") 229 + /// .collect_into_string() 230 + /// .unwrap(); 231 + /// 232 + /// assert_eq!( 233 + /// csv, 234 + /// "ID,Country\n\ 235 + /// 2,Tuvalu\n" 236 + /// ); 237 + /// ``` 238 + pub fn filter_col<F>(mut self, name: &str, get_row: F) -> Self 239 + where 240 + F: FnMut(&str) -> bool + 'a, 241 + { 242 + self.iterator = Box::new(FilterCol { 243 + name: name.to_string(), 211 244 iterator: self.iterator, 212 245 f: get_row, 213 246 source: self.source,
+41 -7
src/pipeline_iterators.rs
··· 148 148 } 149 149 } 150 150 151 - pub struct Filter<I, F: FnMut(&Headers, &Row) -> Result<bool, Error>> { 151 + pub struct Filter<I, F: FnMut(&Headers, &Row) -> bool> { 152 152 pub iterator: I, 153 153 pub f: F, 154 154 pub source: usize, ··· 157 157 impl<I, F> Iterator for Filter<I, F> 158 158 where 159 159 I: Iterator<Item = RowResult>, 160 - F: FnMut(&Headers, &Row) -> Result<bool, Error>, 160 + F: FnMut(&Headers, &Row) -> bool, 161 161 { 162 162 type Item = RowResult; 163 163 ··· 167 167 Ok(row) => row, 168 168 Err(e) => return Some(Err(e)), 169 169 }; 170 - let filter = (self.f)(&self.headers, &row); 171 - match filter { 172 - Ok(true) => return Some(Ok(row)), 173 - Ok(false) => continue, 174 - Err(e) => return Some(Err(e.at_source(self.source))), 170 + let pass_filter = (self.f)(&self.headers, &row); 171 + if pass_filter { 172 + return Some(Ok(row)); 173 + } 174 + } 175 + } 176 + } 177 + 178 + pub struct FilterCol<I, F: FnMut(&str) -> bool> { 179 + pub name: String, 180 + pub iterator: I, 181 + pub f: F, 182 + pub source: usize, 183 + pub headers: Headers, 184 + } 185 + impl<I, F> Iterator for FilterCol<I, F> 186 + where 187 + I: Iterator<Item = RowResult>, 188 + F: FnMut(&str) -> bool, 189 + { 190 + type Item = RowResult; 191 + 192 + fn next(&mut self) -> Option<Self::Item> { 193 + loop { 194 + let row = match self.iterator.next()? { 195 + Ok(row) => row, 196 + Err(e) => return Some(Err(e)), 197 + }; 198 + let field = match self.headers.get_field(&row, &self.name) { 199 + Some(field) => field, 200 + None => { 201 + return Some(Err( 202 + Error::MissingColumn(self.name.clone()).at_source(self.source) 203 + )) 204 + } 205 + }; 206 + let pass_filter = (self.f)(field); 207 + if pass_filter { 208 + return Some(Ok(row)); 175 209 } 176 210 } 177 211 }