use crate::{
error::{Error, ErrorKind, ErrorOrigin, RuntimeErrorKind},
traits::{EntityKind, EntityValue},
types::Id,
};
use icydb_core::db::{ResponseError, WriteBatchResponse as CoreWriteBatchResponse};
#[derive(Debug)]
pub enum MutationResult<E: EntityKind> {
Count { row_count: u32 },
Entity(E),
Entities(Vec<E>),
}
impl<E: EntityKind> MutationResult<E> {
#[must_use]
pub const fn from_count(row_count: u32) -> Self {
Self::Count { row_count }
}
#[must_use]
pub const fn from_entity(entity: E) -> Self {
Self::Entity(entity)
}
#[must_use]
pub const fn from_entities(entities: Vec<E>) -> Self {
Self::Entities(entities)
}
#[must_use]
pub fn from_core_batch(inner: CoreWriteBatchResponse<E>) -> Self {
Self::from_entities(inner.into_iter().collect())
}
#[must_use]
pub fn row_count(&self) -> u32 {
match self {
Self::Count { row_count } => *row_count,
Self::Entity(_) => 1,
Self::Entities(entities) => u32::try_from(entities.len()).unwrap_or(u32::MAX),
}
}
#[must_use]
pub fn count(&self) -> u32 {
self.row_count()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.row_count() == 0
}
#[must_use]
pub fn exists(&self) -> bool {
!self.is_empty()
}
pub fn entity(self) -> Result<E, Error> {
match self {
Self::Entity(entity) => Ok(entity),
Self::Entities(mut entities) => match entities.len() {
0 => Err(Error::from(ResponseError::not_found(E::PATH))),
1 => Ok(entities.remove(0)),
count => Err(Error::from(ResponseError::not_unique(
E::PATH,
u32::try_from(count).unwrap_or(u32::MAX),
))),
},
Self::Count { .. } => Err(Self::unsupported_shape_error("entity", "count")),
}
}
pub fn entities(self) -> Result<Vec<E>, Error> {
match self {
Self::Entity(entity) => Ok(vec![entity]),
Self::Entities(entities) => Ok(entities),
Self::Count { .. } => Err(Self::unsupported_shape_error("entities", "count")),
}
}
fn unsupported_shape_error(expected: &str, actual: &str) -> Error {
Error::new(
ErrorKind::Runtime(RuntimeErrorKind::Unsupported),
ErrorOrigin::Response,
format!("mutation result does not contain {expected}; actual shape={actual}"),
)
}
}
impl<E: EntityKind + EntityValue> MutationResult<E> {
pub fn id(&self) -> Result<Id<E>, Error> {
match self {
Self::Entity(entity) => Ok(entity.id()),
Self::Entities(entities) => match entities.as_slice() {
[] => Err(Error::from(ResponseError::not_found(E::PATH))),
[entity] => Ok(entity.id()),
many => Err(Error::from(ResponseError::not_unique(
E::PATH,
u32::try_from(many.len()).unwrap_or(u32::MAX),
))),
},
Self::Count { .. } => Err(Self::unsupported_shape_error("id", "count")),
}
}
pub fn ids(&self) -> Result<Vec<Id<E>>, Error> {
match self {
Self::Entity(entity) => Ok(vec![entity.id()]),
Self::Entities(entities) => Ok(entities.iter().map(EntityValue::id).collect()),
Self::Count { .. } => Err(Self::unsupported_shape_error("ids", "count")),
}
}
}