use crate::{
diagnostic::RuntimeBoundaryCode,
error::{Error, ErrorOrigin},
traits::Entity,
types::Id,
};
use icydb_core::db::{ResponseError, WriteBatchResponse as CoreWriteBatchResponse};
#[derive(Debug)]
pub enum MutationResult<E: Entity> {
Count { row_count: u32 },
Entity(E),
Entities(Vec<E>),
}
impl<E: Entity> 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(
RuntimeBoundaryCode::MutationResultEntityRequired,
)),
}
}
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(
RuntimeBoundaryCode::MutationResultEntitiesRequired,
)),
}
}
const fn unsupported_shape_error(boundary: RuntimeBoundaryCode) -> Error {
Error::from_runtime_boundary(boundary, ErrorOrigin::Response)
}
}
impl<E: Entity> 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(
RuntimeBoundaryCode::MutationResultIdRequired,
)),
}
}
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(icydb_core::traits::EntityValue::id)
.collect()),
Self::Count { .. } => Err(Self::unsupported_shape_error(
RuntimeBoundaryCode::MutationResultIdsRequired,
)),
}
}
}