Skip to content
This repository has been archived by the owner on Jan 11, 2021. It is now read-only.

Add type-safe accessors for primitive types in Row #86

Merged
merged 10 commits into from
Apr 21, 2018
66 changes: 66 additions & 0 deletions src/record/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use std::fmt;

use basic::{LogicalType, Type as PhysicalType};
use data_type::{ByteArray, Int96};
use errors::ParquetError;

/// Macro as a shortcut to generate 'not yet implemented' panic error.
macro_rules! nyi {
Expand Down Expand Up @@ -55,7 +56,59 @@ pub enum Row {
Map(Vec<(Row, Row)>) // List of key-value pairs
}

// Macro to generate type-safe get_xxx methods e.g. get_bool, get_short
macro_rules! row_primitive_accessor {
($METHOD:ident, $VARIANT:ident, $TY:ty) => {
pub fn $METHOD(&self) -> Result<$TY, ParquetError> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: you can import errors::Result and replace Result<$TY, ParquetError> with Result<$TY>

match *self {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we use 2-space indent.

Row::$VARIANT(v) => Ok(v),
_ => Err(ParquetError::General(format!("Cannot access {} as {}", self.get_type_name(), stringify!($VARIANT))))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking if it would be easier to just print self instead of self.get_type_name? One of the pros is that we need not maintain the mapping to string values, but I am happy either way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we print self, we would have a message like Cannot access 1.2 as Bool which makes debugging harder?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough, let's keep type names!

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: maybe we can use general_err! here - a little less verbose
also we limit line width to 90 characters.

}
}
}
}

impl Row {
/// Get the type name
fn get_type_name(&self) -> &'static str {
match *self {
Row::Null => "Null",
Row::Bool(_) => "Bool",
Row::Byte(_) => "Byte",
Row::Short(_) => "Short",
Row::Int(_) => "Int",
Row::Long(_) => "Long",
Row::Float(_) => "Float",
Row::Double(_) => "Double",
Row::Str(_) => "Str",
Row::Bytes(_) => "Bytes",
Row::Timestamp(_) => "Timestamp",
Row::Group(_) => "Group",
Row::List(_) => "List",
Row::Map(_) => "Map",
}
}

row_primitive_accessor!(get_bool, Bool, bool);
row_primitive_accessor!(get_byte, Byte, i8);
row_primitive_accessor!(get_short, Short, i16);
row_primitive_accessor!(get_int, Int, i32);
row_primitive_accessor!(get_long, Long, i64);
row_primitive_accessor!(get_float, Float, f32);
row_primitive_accessor!(get_double, Double, f64);
row_primitive_accessor!(get_timestamp, Timestamp, u64);

/// Type-safe accessor for Str type
pub fn get_string(&self) -> Result<String, ParquetError> {
match *self {
Row::Str(ref v) => Ok(v.clone()),
_ => Err(ParquetError::General(format!(
"Cannot access {} as Str",
self.get_type_name()
))),
}
}

/// Converts Parquet BOOLEAN type with logical type into `bool` value.
pub fn convert_bool(
_physical_type: PhysicalType,
Expand Down Expand Up @@ -343,4 +396,17 @@ mod tests {
]);
assert_eq!(format!("{}", row), "{1 -> 1.2, 2 -> 4.5, 3 -> 2.3}");
}

#[test]
fn test_row_bool_accessors() {
assert_eq!(true, Row::Bool(true).get_bool().unwrap());
assert_eq!(false, Row::Bool(false).get_bool().unwrap());
assert_eq!(ParquetError::General("Cannot access Float as Bool".to_string()), Row::Float(1.2).get_bool().unwrap_err());
}

#[test]
fn test_row_string_accessors() {
assert_eq!("Hello".to_string(), Row::Str("Hello".to_string()).get_string().unwrap());
assert_eq!(ParquetError::General("Cannot access Float as Str".to_string()), Row::Float(1.2).get_string().unwrap_err());
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: line too long.

}
}