Skip to content

Commit

Permalink
csv
Browse files Browse the repository at this point in the history
  • Loading branch information
jrouaix committed Apr 27, 2024
1 parent e38ca98 commit d5d6a44
Show file tree
Hide file tree
Showing 8 changed files with 256 additions and 56 deletions.
236 changes: 189 additions & 47 deletions Cargo.lock

Large diffs are not rendered by default.

11 changes: 7 additions & 4 deletions codegenr/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "codegenr"
version = "0.0.4"
version = "0.0.5"
edition = "2021"
authors = ["Jérôme Rx & contributors <[email protected]>"]
description = "Fast json/yaml/openapi code generator based on handlebars templating."
Expand Down Expand Up @@ -35,6 +35,7 @@ structopt = { version = "0.3", optional = true }
anyhow = { version = "1.0", optional = true }
toml = { version = "0.8", optional = true }


# ========================================================================================
# Common dependencies
# ========================================================================================
Expand All @@ -45,17 +46,19 @@ thiserror = "1.0"
# File loading & path manipulations
url = "2.4"
path-dedot = "3.1"
reqwest = { version = "0.11", features = ["blocking"] }
reqwest = { version = "0.12", features = ["blocking"] }
walkdir = "2"
glob = "0.3"
# Json / Yaml / OpenApi / Graphql manipulation

# file formats manipulation
serde_json = { version = "1.0", features = ["preserve_order"] }
serde_yaml = "0.8" # 0.9 failing with deserializing from YAML containing more than one document is not supported on most files
serde = "1.0"
graphql-parser = "0.4"
quick-xml = { version = "0.31", features = ["serialize"] }
quickxml_to_serde = "0.5"
quickxml_to_serde = "0.6"
minidom = "0.12"
csv = "1.2"

# Templating
handlebars = { version = "4.4", features = ["script_helper"] }
Expand Down
7 changes: 7 additions & 0 deletions codegenr/_samples/username.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Username, Identifier,First name,Last name
booker12,9012,Rachel,Booker
grey07,2070,Laura,Grey
johnson81,4081,Craig,Johnson
jenkins46,9346,Mary,Jenkins
smith79,5079,Jamie,Smith

24 changes: 24 additions & 0 deletions codegenr/src/loaders/csv.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use super::DocumentLoader;
use serde_json::Value;

pub struct CsvLoader {}
impl DocumentLoader for CsvLoader {
type Error = csv::Error;
fn json_from_str(content: &str) -> Result<Value, Self::Error> {
let mut rdr = csv::Reader::from_reader(content.as_bytes());
let lines = rdr
.records()
.map(|result| {
let record = result?;
Ok(Value::Object(
record
.into_iter()
.enumerate()
.map(|(i, field)| (format!("field_{i}"), Value::String(field.into())))
.collect(),
))
})
.collect::<Result<Vec<_>, Self::Error>>()?;
Ok(Value::Array(lines))
}
}
3 changes: 3 additions & 0 deletions codegenr/src/loaders/document_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ impl DocumentPath {
DocumentPath::FileName(s) => s,
DocumentPath::None => return FormatHint::NoIdea,
};
let s = s.to_lowercase();
if s.ends_with(".json") {
FormatHint::Json
} else if s.ends_with(".yaml") || s.ends_with(".yml") {
Expand All @@ -84,6 +85,8 @@ impl DocumentPath {
FormatHint::Graphql
} else if s.ends_with(".xml") || s.ends_with(".xaml") || s.ends_with(".wsdl") || s.ends_with(".xsd") || s.ends_with(".xul") {
FormatHint::Xml
} else if s.ends_with(".csv") {
FormatHint::Csv
} else {
FormatHint::NoIdea
}
Expand Down
27 changes: 24 additions & 3 deletions codegenr/src/loaders/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use url::Url;

pub mod document_path;
pub use document_path::*;
pub mod csv;
pub mod graphql;
pub mod json;
pub mod toml;
Expand Down Expand Up @@ -50,6 +51,7 @@ pub enum LoaderError {
yaml_error: serde_yaml::Error,
toml_error: ::toml::de::Error,
xml_error: minidom::Error,
csv_error: ::csv::Error,
graphql_error: graphql_parser::schema::ParseError,
},
#[error("Yaml error: `{0}`.")]
Expand All @@ -74,6 +76,8 @@ pub(crate) enum FormatHint {
Toml,
/// The content should be xml
Xml,
/// The content should be csv
Csv,
/// The content should be a graphql schema
Graphql,
/// We have no f.....g idea
Expand All @@ -85,9 +89,10 @@ fn json_from_string(content: &str, hint: FormatHint) -> Result<Value, LoaderErro
use FormatHint::*;
match hint {
FormatHint::Json | FormatHint::NoIdea => try_loaders(content, &[Json, Yaml, Toml, Graphql]),
FormatHint::Yaml => try_loaders(content, &[Yaml, Json, Toml, Xml, Graphql]),
FormatHint::Toml => try_loaders(content, &[Toml, Json, Yaml, Xml, Graphql]),
FormatHint::Xml => try_loaders(content, &[Xml, Json, Yaml, Toml, Graphql]),
FormatHint::Yaml => try_loaders(content, &[Yaml, Json]),
FormatHint::Toml => try_loaders(content, &[Toml]),
FormatHint::Xml => try_loaders(content, &[Xml]),
FormatHint::Csv => try_loaders(content, &[Csv]),
FormatHint::Graphql => try_loaders(content, &[Graphql, Json, Yaml, Toml, Xml]),
}
}
Expand All @@ -98,6 +103,7 @@ fn try_loaders(content: &str, formats: &[FormatHint]) -> Result<Value, LoaderErr
let mut yaml_error: Option<serde_yaml::Error> = None;
let mut toml_error: Option<::toml::de::Error> = None;
let mut xml_error: Option<::minidom::Error> = None;
let mut csv_error: Option<::csv::Error> = None;
let mut graphql_error: Option<graphql_parser::schema::ParseError> = None;

for hint in formats {
Expand Down Expand Up @@ -126,6 +132,12 @@ fn try_loaders(content: &str, formats: &[FormatHint]) -> Result<Value, LoaderErr
Err(e) => e,
});
}
FormatHint::Csv => {
csv_error = Some(match csv::CsvLoader::json_from_str(content) {
Ok(json) => return Ok(json),
Err(e) => e,
});
}
FormatHint::Graphql => {
graphql_error = Some(match graphql::GraphqlLoader::json_from_str(content) {
Ok(json) => return Ok(json),
Expand All @@ -144,6 +156,7 @@ fn try_loaders(content: &str, formats: &[FormatHint]) -> Result<Value, LoaderErr
yaml_error: yaml_error.ok_or(LoaderError::DidNotTryAllFormats)?,
toml_error: toml_error.ok_or(LoaderError::DidNotTryAllFormats)?,
xml_error: xml_error.ok_or(LoaderError::DidNotTryAllFormats)?,
csv_error: csv_error.ok_or(LoaderError::DidNotTryAllFormats)?,
graphql_error: graphql_error.ok_or(LoaderError::DidNotTryAllFormats)?,
})
}
Expand Down Expand Up @@ -221,6 +234,14 @@ mod tests {
Ok(())
}

#[allow(clippy::result_large_err)]
#[test]
fn read_csv_file_test() -> Result<(), LoaderError> {
let _result = DocumentPath::parse("./_samples/username.csv")?.load_raw()?;
dbg!(_result);
Ok(())
}

#[allow(clippy::result_large_err)]
#[test]
#[ignore]
Expand Down
2 changes: 1 addition & 1 deletion codegenr/src/loaders/xml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use quickxml_to_serde::xml_str_to_json;

pub struct XmlLoader {}
impl DocumentLoader for XmlLoader {
type Error = minidom::Error;
type Error = minidom::error::Error;
fn json_from_str(content: &str) -> Result<serde_json::Value, Self::Error> {
let config = quickxml_to_serde::Config::default();
xml_str_to_json(content, &config)
Expand Down
2 changes: 1 addition & 1 deletion codegenr/src/processor/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ impl Instruction for FileInstruction {
}
fn start(&self, params: Vec<String>) -> Result<Box<dyn InstructionLineHandler>, ProcessorError> {
let file_path = params
.get(0)
.first()
.ok_or(ProcessorError::InstructionParameterMissing(FILE, "file_name"))?;
Ok(Box::new(FileLineHandler::new(&self.output_folder, file_path)?) as Box<dyn InstructionLineHandler>)
}
Expand Down

0 comments on commit d5d6a44

Please sign in to comment.