graphrecords-query 0.5.0

High-performance graph-based data records
Documentation
use crate::{
    AttributeName, Failure, IndexValue, Positional, QueryResult, Scalar, ValueDomain,
    error::{
        comparison::IncomparableValues,
        numeric::{InvalidClipBounds, NonNumericValue},
    },
};
use graphrecords_core::graphrecord::{
    EdgeIndex, GraphRecordAttribute, GraphRecordValue, NodeIndex,
};
use std::{
    cmp::Ordering,
    fmt::{Debug, Display},
};

pub trait ValueClip: ValueDomain {
    fn clip<'a>(
        label: &'static str,
        value: Self::Value<'a>,
        lower: Self::Value<'a>,
        upper: Self::Value<'a>,
    ) -> QueryResult<Self::Value<'a>>;
}

fn clip_ordered<T>(label: &'static str, value: T, lower: T, upper: T) -> QueryResult<T>
where
    T: Debug + Display + PartialOrd + Send + Sync + 'static,
{
    match lower.partial_cmp(&upper) {
        Some(Ordering::Greater) => {
            return Err(Failure::new(label, InvalidClipBounds::new(lower, upper)));
        }
        None => {
            return Err(Failure::new(label, IncomparableValues::new(lower, upper)));
        }
        Some(Ordering::Less | Ordering::Equal) => {}
    }

    match value.partial_cmp(&lower) {
        Some(Ordering::Less) => return Ok(lower),
        None => {
            return Err(Failure::new(label, IncomparableValues::new(value, lower)));
        }
        Some(Ordering::Equal | Ordering::Greater) => {}
    }

    match value.partial_cmp(&upper) {
        Some(Ordering::Greater) => Ok(upper),
        Some(Ordering::Less | Ordering::Equal) => Ok(value),
        None => Err(Failure::new(label, IncomparableValues::new(value, upper))),
    }
}

fn clip_graphrecord_attribute(
    label: &'static str,
    value: GraphRecordAttribute,
    lower: GraphRecordAttribute,
    upper: GraphRecordAttribute,
) -> QueryResult<GraphRecordAttribute> {
    let value = match value {
        GraphRecordAttribute::Int(_) => value,
        value @ GraphRecordAttribute::String(_) => {
            return Err(Failure::new(label, NonNumericValue::new(value)));
        }
    };
    let lower = match lower {
        GraphRecordAttribute::Int(_) => lower,
        lower @ GraphRecordAttribute::String(_) => {
            return Err(Failure::new(label, NonNumericValue::new(lower)));
        }
    };
    let upper = match upper {
        GraphRecordAttribute::Int(_) => upper,
        upper @ GraphRecordAttribute::String(_) => {
            return Err(Failure::new(label, NonNumericValue::new(upper)));
        }
    };

    clip_ordered(label, value, lower, upper)
}

fn clip_graphrecord_value(
    label: &'static str,
    value: GraphRecordValue,
    lower: GraphRecordValue,
    upper: GraphRecordValue,
) -> QueryResult<GraphRecordValue> {
    let value = match value {
        GraphRecordValue::Int(_)
        | GraphRecordValue::Float(_)
        | GraphRecordValue::DateTime(_)
        | GraphRecordValue::Duration(_) => value,
        value => return Err(Failure::new(label, NonNumericValue::new(value))),
    };
    let lower = match lower {
        GraphRecordValue::Int(_)
        | GraphRecordValue::Float(_)
        | GraphRecordValue::DateTime(_)
        | GraphRecordValue::Duration(_) => lower,
        lower => return Err(Failure::new(label, NonNumericValue::new(lower))),
    };
    let upper = match upper {
        GraphRecordValue::Int(_)
        | GraphRecordValue::Float(_)
        | GraphRecordValue::DateTime(_)
        | GraphRecordValue::Duration(_) => upper,
        upper => return Err(Failure::new(label, NonNumericValue::new(upper))),
    };

    clip_ordered(label, value, lower, upper)
}

impl ValueClip for Scalar {
    fn clip<'a>(
        label: &'static str,
        value: Self::Value<'a>,
        lower: Self::Value<'a>,
        upper: Self::Value<'a>,
    ) -> QueryResult<Self::Value<'a>> {
        clip_graphrecord_value(label, value, lower, upper)
    }
}

impl ValueClip for AttributeName {
    fn clip<'a>(
        label: &'static str,
        value: Self::Value<'a>,
        lower: Self::Value<'a>,
        upper: Self::Value<'a>,
    ) -> QueryResult<Self::Value<'a>> {
        clip_graphrecord_attribute(label, value, lower, upper)
    }
}

impl ValueClip for IndexValue<Positional> {
    fn clip<'a>(
        label: &'static str,
        value: Self::Value<'a>,
        lower: Self::Value<'a>,
        upper: Self::Value<'a>,
    ) -> QueryResult<Self::Value<'a>> {
        clip_ordered(label, value, lower, upper)
    }
}

impl ValueClip for IndexValue<NodeIndex> {
    fn clip<'a>(
        label: &'static str,
        value: Self::Value<'a>,
        lower: Self::Value<'a>,
        upper: Self::Value<'a>,
    ) -> QueryResult<Self::Value<'a>> {
        clip_graphrecord_attribute(label, value, lower, upper)
    }
}

impl ValueClip for IndexValue<AttributeName> {
    fn clip<'a>(
        label: &'static str,
        value: Self::Value<'a>,
        lower: Self::Value<'a>,
        upper: Self::Value<'a>,
    ) -> QueryResult<Self::Value<'a>> {
        clip_graphrecord_attribute(label, value, lower, upper)
    }
}

impl ValueClip for IndexValue<EdgeIndex> {
    fn clip<'a>(
        label: &'static str,
        value: Self::Value<'a>,
        lower: Self::Value<'a>,
        upper: Self::Value<'a>,
    ) -> QueryResult<Self::Value<'a>> {
        clip_ordered(label, value, lower, upper)
    }
}

impl ValueClip for IndexValue<GraphRecordValue> {
    fn clip<'a>(
        label: &'static str,
        value: Self::Value<'a>,
        lower: Self::Value<'a>,
        upper: Self::Value<'a>,
    ) -> QueryResult<Self::Value<'a>> {
        clip_graphrecord_value(label, value, lower, upper)
    }
}