From 7db5b3842381227f777d20e44634c0e3463daf5f Mon Sep 17 00:00:00 2001 From: cyr Date: Sun, 10 Sep 2023 10:29:23 +0200 Subject: [PATCH] Added ReaderBuilder, useful for when you when you have access to the database file and the memo file as Read+Seek objects, instead of requiring them to be from path. --- src/lib.rs | 4 +-- src/reading.rs | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 80d638d..802dd75 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -298,8 +298,8 @@ pub use crate::field::types::{Date, DateTime, FieldType, FieldValue, Time, TrimO pub use crate::field::{FieldConversionError, FieldInfo, FieldName}; pub use crate::header::CodePageMark; pub use crate::reading::{ - read, FieldIterator, NamedValue, ReadableRecord, Reader, ReadingOptions, RecordIterator, - TableInfo, + read, FieldIterator, NamedValue, ReadableRecord, Reader, ReaderBuilder, ReadingOptions, + RecordIterator, TableInfo, }; pub use crate::record::Record; pub use crate::writing::{FieldWriter, TableWriter, TableWriterBuilder, WritableRecord}; diff --git a/src/reading.rs b/src/reading.rs index e8f23e8..70e75f3 100644 --- a/src/reading.rs +++ b/src/reading.rs @@ -73,6 +73,94 @@ impl ReadingOptions { } } +/// Convenience builder to create a reader directly from file sources +/// +/// # Example +/// +/// ``` +/// use std::fs::File; +/// +/// # fn main() -> Result<(), dbase::Error> { +/// let dbf_file = File::open("tests/data/line.dbf").unwrap(); +/// let options = dbase::ReadingOptions::default() +/// .character_trim(dbase::TrimOption::BeginEnd); +/// +/// let mut reader = dbase::ReaderBuilder::new(dbf_file) +/// .with_options(options) +/// .with_encoding(dbase::encoding::UnicodeLossy) +/// .build() +/// .unwrap(); +/// +/// let records = reader.read()?; +/// assert_eq!(records.len(), 1); +/// # Ok(()) +/// # } +/// ``` +pub struct ReaderBuilder { + source: T, + memo_source: Option, + encoding: Option, + options: Option, +} + +impl ReaderBuilder { + pub fn new(source: T) -> Self { + Self { + source, + memo_source: None, + encoding: None, + options: None, + } + } + + pub fn with_memo(mut self, memo_source: T) -> Self { + self.memo_source = Some(memo_source); + + self + } + + pub fn with_encoding(mut self, encoding: E) -> Self { + self.encoding = Some(encoding); + + self + } + + pub fn with_options(mut self, options: ReadingOptions) -> Self { + self.options = Some(options); + + self + } + + pub fn build(self) -> Result, Error> { + let file = crate::File::open(self.source)?; + + let memo_reader = if let Some(memo_source) = self.memo_source { + let memo_type = file.header.file_type.supported_memo_type(); + if let Some(mt) = memo_type { + let memo_reader = + MemoReader::new(mt, memo_source).map_err(|error| Error::io_error(error, 0))?; + + Some(memo_reader) + } else { + None + } + } else { + None + }; + + Ok(Reader { + source: file.inner, + memo_reader, + header: file.header, + fields_info: file.fields_info, + encoding: self + .encoding + .map_or_else(|| file.encoding, DynEncoding::new), + options: self.options.unwrap_or_default(), + }) + } +} + /// Struct with the handle to the source .dbf file /// Responsible for reading the content // TODO Debug impl