[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.

`Target` struct helper

Kasper (Jan 11, 2023, 3:45 PM +0100) 11cede38 195a80f0

+67 -7
+3
CHANGELOG.md
··· 1 1 # Changelog 2 2 3 + ## Next 4 + - Add `Target` struct helper for creating targets, and hide the targets in the `target` module. 5 + 3 6 ## 0.1.0 - 2023 Jan 11 4 7 - Initial release
+29
README.md
··· 5 5 [![Crates.io](https://img.shields.io/crates/v/csv-pipeline.svg)](https://crates.io/crates/csv-pipeline) 6 6 [![Documentation](https://docs.rs/csv-pipeline/badge.svg)](https://docs.rs/csv-pipeline) 7 7 8 + ## Basic Example 9 + ```rs 10 + use csv_pipeline::{Pipeline, Transformer}; 11 + 12 + // First create a pipeline from a CSV file path 13 + let csv = Pipeline::from_path("test/Countries.csv") 14 + .unwrap() 15 + // Add a column with values computed from a closure 16 + .add_col("Language", |headers, row| { 17 + match headers.get_field(row, "Country") { 18 + Some("Norway") => Ok("Norwegian".into()), 19 + _ => Ok("Unknown".into()), 20 + } 21 + }) 22 + // Make the "Country" column uppercase 23 + .rename_col("Country", "COUNTRY") 24 + .map_col("COUNTRY", |id_str| Ok(id_str.to_uppercase())) 25 + // Collect the csv into a string 26 + .collect_into_string() 27 + .unwrap(); 28 + 29 + assert_eq!( 30 + csv, 31 + "ID,COUNTRY,Language\n\ 32 + 1,NORWAY,Norwegian\n\ 33 + 2,TUVALU,Unknown\n" 34 + ); 35 + ``` 36 + 8 37 ## Dev Instructions 9 38 10 39 ### Get started
+1
src/headers.rs
··· 2 2 use csv::StringRecordIter; 3 3 use std::collections::BTreeMap; 4 4 5 + /// The headers of a CSV file 5 6 #[derive(Debug, Clone, PartialEq)] 6 7 pub struct Headers { 7 8 indexes: BTreeMap<String, usize>,
+24 -4
src/lib.rs
··· 1 1 //! CSV processing library inspired by [csvsc](https://crates.io/crates/csvsc) 2 2 //! 3 - //! ## Quickstart 3 + //! ## Get started 4 4 //! 5 5 //! The first thing you need is to create a [`Pipeline`]. This can be done by calling [`Pipeline::from_reader`] with a [`csv::Reader`], or [`Pipeline::from_path`] with a path. 6 6 //! ··· 11 11 //! Finally, you probably want to run the pipeline. There are a few options: 12 12 //! - [`Pipeline::build`] gives you a [`PipelineIter`] which you can iterate through 13 13 //! - [`Pipeline::run`] runs through the pipeline until it finds an error, or the end 14 - //! - [`Pipeline::collect_into_string`] runs the pipeline and returns the csv as a `Result<String, Error>`. Can be a convenient alternative to flushing to a [`StringTarget`]. 14 + //! - [`Pipeline::collect_into_string`] runs the pipeline and returns the csv as a `Result<String, Error>`. Can be a convenient alternative to flushing to a [`StringTarget`](target::StringTarget). 15 15 //! 16 16 //! ## Basic Example 17 17 //! ··· 84 84 //! ``` 85 85 //! 86 86 87 + use std::path::PathBuf; 88 + 87 89 mod headers; 88 90 mod pipeline; 89 91 mod pipeline_iterators; 90 - mod target; 91 92 mod transform; 92 93 93 94 pub use headers::Headers; 94 95 pub use pipeline::{Pipeline, PipelineIter}; 95 - pub use target::{PathTarget, StderrTarget, StdoutTarget, StringTarget, Target}; 96 96 pub use transform::Transformer; 97 97 98 + pub mod target; 99 + /// Helper for building a target to flush data into 100 + pub struct Target {} 101 + impl Target { 102 + pub fn path<P: Into<PathBuf>>(path: P) -> target::PathTarget { 103 + target::PathTarget::new(path) 104 + } 105 + pub fn stdout() -> target::StdoutTarget { 106 + target::StdoutTarget::new() 107 + } 108 + pub fn stderr() -> target::StderrTarget { 109 + target::StderrTarget::new() 110 + } 111 + pub fn string<'a>(s: &'a mut String) -> target::StringTarget { 112 + target::StringTarget::new(s) 113 + } 114 + } 115 + 116 + /// Alias of [`csv::StringRecord`] 98 117 pub type Row = csv::StringRecord; 118 + /// Alias of `Result<Row, Error>` 99 119 pub type RowResult = Result<Row, Error>; 100 120 101 121 #[derive(Debug)]
+4 -2
src/pipeline.rs
··· 2 2 use crate::pipeline_iterators::{ 3 3 AddCol, Flush, MapCol, MapRow, TransformInto, Validate, ValidateCol, 4 4 }; 5 - use crate::target::Target; 5 + use crate::target::{StringTarget, Target}; 6 6 use crate::transform::Transform; 7 - use crate::{Error, Row, RowResult, StringTarget}; 7 + use crate::{Error, Row, RowResult}; 8 8 use csv::{Reader, ReaderBuilder, StringRecordsIntoIter}; 9 9 use std::borrow::BorrowMut; 10 10 use std::collections::BTreeMap; 11 11 use std::io; 12 12 use std::path::Path; 13 13 14 + /// The main thing 14 15 pub struct Pipeline<'a> { 15 16 pub headers: Headers, 16 17 iterator: Box<dyn Iterator<Item = RowResult> + 'a>, ··· 303 304 } 304 305 } 305 306 307 + /// A pipeline you can iterate through. You can get one using [`Pipeline::build`]. 306 308 pub struct PipelineIter<'a> { 307 309 pub headers: Headers, 308 310 pub iterator: Box<dyn Iterator<Item = RowResult> + 'a>,
+6 -1
src/transform.rs
··· 3 3 use std::collections::hash_map::DefaultHasher; 4 4 use std::hash::{Hash, Hasher}; 5 5 6 + /// For grouping and reducing rows. 6 7 pub trait Transform { 7 8 /// Add the row to the hasher to group this row separately from others 8 9 fn hash( ··· 24 25 fn value(&self) -> String; 25 26 } 26 27 28 + /// A struct for building a [`Transform`], which you can use with [`Pipeline::transform_into`](crate::Pipeline::transform_into). 27 29 pub struct Transformer { 28 30 name: String, 29 31 from_col: String, ··· 35 37 from_col: col_name.to_string(), 36 38 } 37 39 } 40 + /// Specify which column the transform should be based on 38 41 pub fn from_col(mut self, col_name: &str) -> Self { 39 42 self.from_col = col_name.to_string(); 40 43 self 41 44 } 45 + /// Keep the unique values from this column 42 46 pub fn keep_unique(self) -> Box<dyn Transform> { 43 47 Box::new(KeepUnique { 44 48 name: self.name, ··· 46 50 value: "".to_string(), 47 51 }) 48 52 } 53 + /// Reduce the values from this column into a single value using a closure 49 54 pub fn reduce<'a, R, V>(self, reduce: R, init: V) -> Box<dyn Transform + 'a> 50 55 where 51 56 R: FnMut(V, &str) -> Result<V, Error> + 'a, ··· 120 125 } 121 126 } 122 127 123 - pub fn compute_hash<'a>( 128 + pub(crate) fn compute_hash<'a>( 124 129 transformers: &Vec<Box<dyn Transform + 'a>>, 125 130 headers: &Headers, 126 131 row: &Row,