Skip to content

Commit

Permalink
Merge pull request #104 from niklasmueboe/main
Browse files Browse the repository at this point in the history
functions to get children of Group
  • Loading branch information
LDeakin authored Dec 25, 2024
2 parents 9151ab2 + cee7dda commit 3c6e041
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 63 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Added
- Add `Node::[async_]get_direct_child_nodes`
- [#104](https://github.com/LDeakin/zarrs/pull/104) functions to get children of Group by [@niklasmueboe]
- adds `Group::[async_]children`, `Group::[async_]child_groups`, `Group::[async_]child_arrays`
- Impl `From<Node>` for `NodeMetadata`

### Changed
- Reduce metadata code duplication in the `Node` module
Expand Down Expand Up @@ -1213,3 +1215,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[@lorenzocerrone]: https://github.com/lorenzocerrone
[@dustinlagoy]: https://github.com/dustinlagoy
[@sk1p]: https://github.com/sk1p
[@niklasmueboe]: https://github.com/niklasmueboe
130 changes: 128 additions & 2 deletions zarrs/src/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@ use std::sync::Arc;

use derive_more::Display;
use thiserror::Error;
use zarrs_metadata::NodeMetadata;
use zarrs_storage::ListableStorageTraits;

use crate::{
array::{Array, ArrayCreateError},
config::{
global_config, MetadataConvertVersion, MetadataEraseVersion, MetadataRetrieveVersion,
},
Expand All @@ -40,12 +43,19 @@ use crate::{
v2_to_v3::group_metadata_v2_to_v3,
v3::{AdditionalFields, UnsupportedAdditionalFieldError},
},
node::{meta_key_v2_attributes, meta_key_v2_group, meta_key_v3, NodePath, NodePathError},
node::{
_get_child_nodes, meta_key_v2_attributes, meta_key_v2_group, meta_key_v3, Node, NodePath,
NodePathError,
},
storage::{ReadableStorageTraits, StorageError, StorageHandle, WritableStorageTraits},
};

#[cfg(feature = "async")]
use crate::storage::{AsyncReadableStorageTraits, AsyncWritableStorageTraits};
use crate::node::_async_get_child_nodes;
#[cfg(feature = "async")]
use crate::storage::{
AsyncListableStorageTraits, AsyncReadableStorageTraits, AsyncWritableStorageTraits,
};

pub use self::group_builder::GroupBuilder;
pub use crate::metadata::{v3::GroupMetadataV3, GroupMetadata};
Expand Down Expand Up @@ -223,6 +233,61 @@ impl<TStorage: ?Sized + ReadableStorageTraits> Group<TStorage> {
}
}

impl<TStorage: ?Sized + ReadableStorageTraits + ListableStorageTraits> Group<TStorage> {
/// Return the children of the group
///
/// # Errors
/// Returns [`StorageError`] if there is an underlying error with the store.
pub fn children(&self, recursive: bool) -> Result<Vec<Node>, StorageError> {
#[allow(clippy::used_underscore_items)]
_get_child_nodes(&self.storage, &self.path, recursive)
}

/// Return the children of the group that are [`Group`]s
///
/// # Errors
/// Returns [`GroupCreateError`] if there is a storage error or any metadata is invalid.
pub fn child_groups(&self, recursive: bool) -> Result<Vec<Self>, GroupCreateError> {
self.children(recursive)?
.into_iter()
.filter_map(|node| {
let name = node.name();
let metadata: NodeMetadata = node.into();
match metadata {
NodeMetadata::Group(metadata) => Some(Group::new_with_metadata(
self.storage.clone(),
name.as_str(),
metadata,
)),
NodeMetadata::Array(_) => None,
}
})
.collect()
}

/// Return the children of the group that are [`Array`]s
///
/// # Errors
/// Returns [`ArrayCreateError`] if there is a storage error or any metadata is invalid.
pub fn child_arrays(&self, recursive: bool) -> Result<Vec<Array<TStorage>>, ArrayCreateError> {
self.children(recursive)?
.into_iter()
.filter_map(|node| {
let name = node.name();
let metadata: NodeMetadata = node.into();
match metadata {
NodeMetadata::Array(metadata) => Some(Array::new_with_metadata(
self.storage.clone(),
name.as_str(),
metadata.clone(),
)),
NodeMetadata::Group(_) => None,
}
})
.collect()
}
}

#[cfg(feature = "async")]
impl<TStorage: ?Sized + AsyncReadableStorageTraits> Group<TStorage> {
/// Async variant of [`open`](Group::open).
Expand Down Expand Up @@ -272,6 +337,67 @@ impl<TStorage: ?Sized + AsyncReadableStorageTraits> Group<TStorage> {
}
}

#[cfg(feature = "async")]
impl<TStorage: ?Sized + AsyncReadableStorageTraits + AsyncListableStorageTraits> Group<TStorage> {
/// Return the children of the group
///
/// # Errors
/// Returns [`StorageError`] if there is an underlying error with the store.
pub async fn async_children(&self, recursive: bool) -> Result<Vec<Node>, StorageError> {
#[allow(clippy::used_underscore_items)]
_async_get_child_nodes(&self.storage, &self.path, recursive).await
}

/// Return the children of the group that are [`Group`]s
///
/// # Errors
/// Returns [`GroupCreateError`] if there is a storage error or any metadata is invalid.
pub async fn async_child_groups(&self, recursive: bool) -> Result<Vec<Self>, GroupCreateError> {
self.async_children(recursive)
.await?
.into_iter()
.filter_map(|node| {
let name = node.name();
let metadata: NodeMetadata = node.into();
match metadata {
NodeMetadata::Group(metadata) => Some(Group::new_with_metadata(
self.storage.clone(),
name.as_str(),
metadata,
)),
NodeMetadata::Array(_) => None,
}
})
.collect()
}

/// Return the children of the group that are [`Array`]s
///
/// # Errors
/// Returns [`ArrayCreateError`] if there is a storage error or any metadata is invalid.
pub async fn async_child_arrays(
&self,
recursive: bool,
) -> Result<Vec<Array<TStorage>>, ArrayCreateError> {
self.async_children(recursive)
.await?
.into_iter()
.filter_map(|node| {
let name = node.name();
let metadata: NodeMetadata = node.into();
match metadata {
NodeMetadata::Array(metadata) => Some(Array::new_with_metadata(
self.storage.clone(),
name.as_str(),
metadata.clone(),
)),
NodeMetadata::Group(_) => None,
}
})
.collect()
}
}

/// A group creation error.
#[derive(Debug, Error)]
pub enum GroupCreateError {
Expand Down
16 changes: 11 additions & 5 deletions zarrs/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ mod node_path;
pub use node_path::{NodePath, NodePathError};

mod node_sync;
pub use node_sync::{get_child_nodes, get_direct_child_nodes, node_exists, node_exists_listable};
pub(crate) use node_sync::_get_child_nodes;
pub use node_sync::{get_child_nodes, node_exists, node_exists_listable};

mod key;
pub use key::{
Expand All @@ -23,10 +24,9 @@ pub use key::{
#[cfg(feature = "async")]
mod node_async;
#[cfg(feature = "async")]
pub use node_async::{
async_get_child_nodes, async_get_direct_child_nodes, async_node_exists,
async_node_exists_listable,
};
pub(crate) use node_async::_async_get_child_nodes;
#[cfg(feature = "async")]
pub use node_async::{async_get_child_nodes, async_node_exists, async_node_exists_listable};

use std::sync::Arc;

Expand Down Expand Up @@ -61,6 +61,12 @@ pub struct Node {
children: Vec<Node>,
}

impl From<Node> for NodeMetadata {
fn from(value: Node) -> Self {
value.metadata
}
}

/// A node creation error.
#[derive(Debug, Error)]
pub enum NodeCreateError {
Expand Down
42 changes: 15 additions & 27 deletions zarrs/src/node/node_async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,12 @@ use super::{
meta_key_v2_array, meta_key_v2_group, meta_key_v3, Node, NodeMetadata, NodePath, NodePathError,
};

/// Asynchronously get the child nodes.
///
/// # Errors
/// Returns a [`StorageError`] if there is an underlying error with the store.
// FIXME: Change to NodeCreateError in the next breaking release
pub async fn async_get_child_nodes<TStorage>(
// TODO: Replace async_get_child_nodes with this method in the next breaking release
// TODO: Change to NodeCreateError in the next breaking release
pub(crate) async fn _async_get_child_nodes<TStorage>(
storage: &Arc<TStorage>,
path: &NodePath,
recursive: bool,
) -> Result<Vec<Node>, StorageError>
where
TStorage: ?Sized + AsyncReadableStorageTraits + AsyncListableStorageTraits,
Expand All @@ -35,43 +33,33 @@ where
let child_metadata =
Node::async_get_metadata(storage, &path, &MetadataRetrieveVersion::Default).await?;

let children = match child_metadata {
NodeMetadata::Array(_) => Vec::default(),
NodeMetadata::Group(_) => Box::pin(async_get_child_nodes(storage, &path)).await?,
let children = if recursive {
match child_metadata {
NodeMetadata::Array(_) => Vec::default(),
NodeMetadata::Group(_) => Box::pin(async_get_child_nodes(storage, &path)).await?,
}
} else {
vec![]
};
nodes.push(Node::new_with_metadata(path, child_metadata, children));
}
Ok(nodes)
}

/// Get the direct child nodes.
///
/// Unlike [`async_get_child_nodes`], this does not fully resolve the node hierarchy and the nodes returned will not have any children.
/// Asynchronously get the child nodes.
///
/// # Errors
/// Returns a [`StorageError`] if there is an underlying error with the store.
// FIXME: Change to NodeCreateError in the next breaking release
pub async fn async_get_direct_child_nodes<TStorage>(
pub async fn async_get_child_nodes<TStorage>(
storage: &Arc<TStorage>,
path: &NodePath,
) -> Result<Vec<Node>, StorageError>
where
TStorage: ?Sized + AsyncReadableStorageTraits + AsyncListableStorageTraits,
{
let prefix: StorePrefix = path.try_into()?;
let prefixes = async_discover_children(storage, &prefix).await?;
let mut nodes: Vec<Node> = Vec::new();
// TODO: Asynchronously get metadata of all prefixes
for prefix in &prefixes {
let path: NodePath = prefix
.try_into()
.map_err(|err: NodePathError| StorageError::Other(err.to_string()))?;
let child_metadata =
Node::async_get_metadata(storage, &path, &MetadataRetrieveVersion::Default).await?;

nodes.push(Node::new_with_metadata(path, child_metadata, vec![]));
}
Ok(nodes)
#[allow(clippy::used_underscore_items)]
_async_get_child_nodes(storage, path, true).await
}

/// Asynchronously check if a node exists.
Expand Down
43 changes: 15 additions & 28 deletions zarrs/src/node/node_sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,12 @@ use super::{
meta_key_v2_array, meta_key_v2_group, meta_key_v3, Node, NodeMetadata, NodePath, NodePathError,
};

/// Get the child nodes.
///
/// # Errors
/// Returns a [`StorageError`] if there is an underlying error with the store.
// FIXME: Change to NodeCreateError in the next breaking release
pub fn get_child_nodes<TStorage: ?Sized + ReadableStorageTraits + ListableStorageTraits>(
// TODO: Replace get_child_nodes with this method in the next breaking release
// TODO: Change to NodeCreateError in the next breaking release
pub(crate) fn _get_child_nodes<TStorage: ?Sized + ReadableStorageTraits + ListableStorageTraits>(
storage: &Arc<TStorage>,
path: &NodePath,
recursive: bool,
) -> Result<Vec<Node>, StorageError> {
let prefix: StorePrefix = path.try_into()?;
let prefixes = discover_children(storage, &prefix)?;
Expand All @@ -32,41 +30,30 @@ pub fn get_child_nodes<TStorage: ?Sized + ReadableStorageTraits + ListableStorag
let path: NodePath = prefix
.try_into()
.map_err(|err: NodePathError| StorageError::Other(err.to_string()))?;
let children = match child_metadata {
NodeMetadata::Array(_) => Vec::default(),
NodeMetadata::Group(_) => get_child_nodes(storage, &path)?,
let children = if recursive {
match child_metadata {
NodeMetadata::Array(_) => Vec::default(),
NodeMetadata::Group(_) => get_child_nodes(storage, &path)?,
}
} else {
vec![]
};
nodes.push(Node::new_with_metadata(path, child_metadata, children));
}
Ok(nodes)
}

/// Get the direct child nodes.
///
/// Unlike [`get_child_nodes`], this does not fully resolve the node hierarchy and the nodes returned will not have any children.
/// Get the child nodes.
///
/// # Errors
/// Returns a [`StorageError`] if there is an underlying error with the store.
// FIXME: Change to NodeCreateError in the next breaking release
pub fn get_direct_child_nodes<TStorage: ?Sized + ReadableStorageTraits + ListableStorageTraits>(
pub fn get_child_nodes<TStorage: ?Sized + ReadableStorageTraits + ListableStorageTraits>(
storage: &Arc<TStorage>,
path: &NodePath,
) -> Result<Vec<Node>, StorageError> {
let prefix: StorePrefix = path.try_into()?;
let prefixes = discover_children(storage, &prefix)?;
let mut nodes: Vec<Node> = Vec::new();
for prefix in &prefixes {
let path: NodePath = prefix
.try_into()
.map_err(|err: NodePathError| StorageError::Other(err.to_string()))?;
let child_metadata = Node::get_metadata(storage, &path, &MetadataRetrieveVersion::Default)?;

let path: NodePath = prefix
.try_into()
.map_err(|err: NodePathError| StorageError::Other(err.to_string()))?;
nodes.push(Node::new_with_metadata(path, child_metadata, vec![]));
}
Ok(nodes)
#[allow(clippy::used_underscore_items)]
_get_child_nodes(storage, path, true)
}

/// Check if a node exists.
Expand Down

0 comments on commit 3c6e041

Please sign in to comment.