-
Notifications
You must be signed in to change notification settings - Fork 19
Add type-safe accessors for primitive types in Row #86
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great! Thank you very much!
I left a comment and I have several general suggestions/questions:
- Would it be useful to add method
is_primitive
that returns true if type is not Group/List/Map, and false otherwise? - Would it be possible to add tests to cover all value conversions, e.g. Byte, Short, Int, Long, etc.?
- Would you mind changing line width to 90? We normally follow this style rule. Thanks.
src/record/api.rs
Outdated
pub fn $METHOD(&self) -> Result<$TY, ParquetError> { | ||
match *self { | ||
Row::$VARIANT(v) => Ok(v), | ||
_ => Err(ParquetError::General(format!("Cannot access {} as {}", self.get_type_name(), stringify!($VARIANT)))) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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!
This should fix #85. |
I've added the remaining accessors as requested, and |
Looks like I need to add tests for the error condition for each type to keep code coverage up. I'll get that done either tonight or tomorrow. |
Well, I think it is okay, but if you want to then it is even better! @sunchao what do you think? |
It was actually not much work after all.. I think it's great you have code coverage set up and I'll be learning from you and applying this to DataFusion soon |
Yes it would be great if we can cover those too but not a must. |
src/record/api.rs
Outdated
macro_rules! row_primitive_accessor { | ||
($METHOD:ident, $VARIANT:ident, $TY:ty) => { | ||
pub fn $METHOD(&self) -> Result<$TY, ParquetError> { | ||
match *self { |
There was a problem hiding this comment.
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.
src/record/api.rs
Outdated
pub fn $METHOD(&self) -> Result<$TY, ParquetError> { | ||
match *self { | ||
Row::$VARIANT(v) => Ok(v), | ||
_ => Err(ParquetError::General(format!("Cannot access {} as {}", self.get_type_name(), stringify!($VARIANT)))) |
There was a problem hiding this comment.
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.
src/record/api.rs
Outdated
// 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> { |
There was a problem hiding this comment.
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>
src/record/api.rs
Outdated
fn test_row_accessors_invalid_message() { | ||
assert_eq!(ParquetError::General("Cannot access Float as Bool".to_string()), | ||
Row::Float(1.2).get_bool().unwrap_err()); | ||
assert_eq!(ParquetError::General("Cannot access Float as Str".to_string()), Row::Float(1.2).get_string().unwrap_err()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: line too long.
src/record/api.rs
Outdated
row_primitive_accessor!(get_timestamp, Timestamp, u64); | ||
|
||
/// Type-safe accessor for Str type | ||
pub fn get_string(&self) -> Result<&String, ParquetError> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing I'm not quite sure is whether it's better to just panic here, instead of returning Result
. It seems pretty rare that the error case would happen, given that one always (I think?) will hold the schema of the row before calling these methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think panic is pretty extreme. I think the user should decide if they want to panic or not. In non-test code they just need to add a ?
at the end of the line, so it doesn't make much difference to code verbosity.
Hi @andygrove , sorry for the delay! We just refactored the |
Cool. I am working on it this morning. |
@sunchao This is ready for review (as long as you are OK with the 0.009% decrease in code coverage!) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @andygrove. Appreciate you making changes. I left some minor comments, hope you could have a look. Thanks!
src/record/api.rs
Outdated
@@ -41,6 +42,79 @@ pub struct Row { | |||
fields: Vec<(String, Field)> | |||
} | |||
|
|||
impl Row { | |||
/// Get then number of fields in this row |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it be the
?
src/record/api.rs
Outdated
} | ||
|
||
impl RowAccessor for Row { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you remove empty line?
src/record/api.rs
Outdated
row_complex_accessor!(get_group, Group, Row); | ||
row_complex_accessor!(get_list, ListInternal, List); | ||
row_complex_accessor!(get_map, MapInternal, Map); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you remove empty line?
src/record/api.rs
Outdated
@@ -71,6 +145,13 @@ pub struct List { | |||
elements: Vec<Field> | |||
} | |||
|
|||
impl List { | |||
/// Get then number of fields in this row |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it be the
?
src/record/api.rs
Outdated
@@ -86,6 +167,13 @@ pub struct Map { | |||
entries: Vec<(Field, Field)> | |||
} | |||
|
|||
impl Map { | |||
/// Get then number of fields in this row |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
@sadikovi I pushed the formatting changes. Have you thought about adopting cargo fmt? Then you can just have the build fail if the formatting is off and this will no longer be a manual process. |
Thanks for making changes. Looks good, we should merge it! Yes, we discussed that and at the time, and we needed to apply only a subset of the rules, but I could not manage to configure it that way. So we decided to review manually and periodically do clean up with rustfmt. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @andygrove ! PR looks good. Just one minor comment.
src/record/api.rs
Outdated
} | ||
|
||
/// Trait for type-safe convenient access to fields within a Row | ||
trait RowAccessor { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be public and be exported in mod.rs
, otherwise these methods will not be available.
@sunchao Good catch! Fixed. |
Thanks @andygrove . Merged. |
No description provided.