This is an automated email from the ASF dual-hosted git repository.
liurenjie1024 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-rust.git
The following commit(s) were added to refs/heads/main by this push:
new f1ea6e1 feat: `StructAccessor.get` returns `Result<Option<Datum>>`
instead of `Result<Datum>` (#390)
f1ea6e1 is described below
commit f1ea6e137eaabf22ff7d091bfafa0a05739a6516
Author: Scott Donnelly <[email protected]>
AuthorDate: Fri Jun 7 08:25:27 2024 +0100
feat: `StructAccessor.get` returns `Result<Option<Datum>>` instead of
`Result<Datum>` (#390)
This is so that the accessor's result can represent null field values.
Fixes: #379
---
crates/iceberg/src/expr/accessor.rs | 48 +++++++++++++++++++++++++++++++------
crates/iceberg/src/spec/schema.rs | 10 ++++----
crates/iceberg/src/spec/values.rs | 5 ++++
3 files changed, 51 insertions(+), 12 deletions(-)
diff --git a/crates/iceberg/src/expr/accessor.rs
b/crates/iceberg/src/expr/accessor.rs
index f002539..2e2258f 100644
--- a/crates/iceberg/src/expr/accessor.rs
+++ b/crates/iceberg/src/expr/accessor.rs
@@ -15,11 +15,12 @@
// specific language governing permissions and limitations
// under the License.
-use crate::spec::{Datum, Literal, PrimitiveType, Struct};
-use crate::{Error, ErrorKind};
use serde_derive::{Deserialize, Serialize};
use std::sync::Arc;
+use crate::spec::{Datum, Literal, PrimitiveType, Struct};
+use crate::{Error, ErrorKind, Result};
+
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct StructAccessor {
position: usize,
@@ -54,11 +55,13 @@ impl StructAccessor {
&self.r#type
}
- pub(crate) fn get<'a>(&'a self, container: &'a Struct) ->
crate::Result<Datum> {
+ pub(crate) fn get<'a>(&'a self, container: &'a Struct) ->
Result<Option<Datum>> {
match &self.inner {
None => {
- if let Literal::Primitive(literal) = &container[self.position]
{
- Ok(Datum::new(self.r#type().clone(), literal.clone()))
+ if container.is_null_at_index(self.position) {
+ Ok(None)
+ } else if let Literal::Primitive(literal) =
&container[self.position] {
+ Ok(Some(Datum::new(self.r#type().clone(),
literal.clone())))
} else {
Err(Error::new(
ErrorKind::Unexpected,
@@ -95,7 +98,19 @@ mod tests {
let test_struct =
Struct::from_iter(vec![Some(Literal::bool(false)),
Some(Literal::bool(true))]);
- assert_eq!(accessor.get(&test_struct).unwrap(), Datum::bool(true));
+ assert_eq!(accessor.get(&test_struct).unwrap(),
Some(Datum::bool(true)));
+ }
+
+ #[test]
+ fn test_single_level_accessor_null() {
+ let accessor = StructAccessor::new(1, PrimitiveType::Boolean);
+
+ assert_eq!(accessor.r#type(), &PrimitiveType::Boolean);
+ assert_eq!(accessor.position(), 1);
+
+ let test_struct = Struct::from_iter(vec![Some(Literal::bool(false)),
None]);
+
+ assert_eq!(accessor.get(&test_struct).unwrap(), None);
}
#[test]
@@ -115,6 +130,25 @@ mod tests {
Some(Literal::Struct(nested_test_struct)),
]);
- assert_eq!(accessor.get(&test_struct).unwrap(), Datum::bool(true));
+ assert_eq!(accessor.get(&test_struct).unwrap(),
Some(Datum::bool(true)));
+ }
+
+ #[test]
+ fn test_nested_accessor_null() {
+ let nested_accessor = StructAccessor::new(0, PrimitiveType::Boolean);
+ let accessor = StructAccessor::wrap(2, Box::new(nested_accessor));
+
+ assert_eq!(accessor.r#type(), &PrimitiveType::Boolean);
+ //assert_eq!(accessor.position(), 1);
+
+ let nested_test_struct = Struct::from_iter(vec![None,
Some(Literal::bool(true))]);
+
+ let test_struct = Struct::from_iter(vec![
+ Some(Literal::bool(false)),
+ Some(Literal::bool(false)),
+ Some(Literal::Struct(nested_test_struct)),
+ ]);
+
+ assert_eq!(accessor.get(&test_struct).unwrap(), None);
}
}
diff --git a/crates/iceberg/src/spec/schema.rs
b/crates/iceberg/src/spec/schema.rs
index 4302e3b..acdcae6 100644
--- a/crates/iceberg/src/spec/schema.rs
+++ b/crates/iceberg/src/spec/schema.rs
@@ -1683,7 +1683,7 @@ table {
.unwrap()
.get(&test_struct)
.unwrap(),
- Datum::string("foo value")
+ Some(Datum::string("foo value"))
);
assert_eq!(
schema
@@ -1691,7 +1691,7 @@ table {
.unwrap()
.get(&test_struct)
.unwrap(),
- Datum::int(1002)
+ Some(Datum::int(1002))
);
assert_eq!(
schema
@@ -1699,7 +1699,7 @@ table {
.unwrap()
.get(&test_struct)
.unwrap(),
- Datum::bool(true)
+ Some(Datum::bool(true))
);
assert_eq!(
schema
@@ -1707,7 +1707,7 @@ table {
.unwrap()
.get(&test_struct)
.unwrap(),
- Datum::string("Testy McTest")
+ Some(Datum::string("Testy McTest"))
);
assert_eq!(
schema
@@ -1715,7 +1715,7 @@ table {
.unwrap()
.get(&test_struct)
.unwrap(),
- Datum::int(33)
+ Some(Datum::int(33))
);
}
diff --git a/crates/iceberg/src/spec/values.rs
b/crates/iceberg/src/spec/values.rs
index 57eecdc..567a847 100644
--- a/crates/iceberg/src/spec/values.rs
+++ b/crates/iceberg/src/spec/values.rs
@@ -1440,6 +1440,11 @@ impl Struct {
},
)
}
+
+ /// returns true if the field at position `index` is null
+ pub fn is_null_at_index(&self, index: usize) -> bool {
+ self.null_bitmap[index]
+ }
}
impl Index<usize> for Struct {