zeppelin-embed 0.7.0

In-process vector, lexical, and hybrid search for macOS and Apple silicon
Documentation
use super::*;
fn expression_inner(
    description: PlanDescription<'_>,
    id: ExprId,
    scope: &NodeFacts,
    seen: &mut [bool; MAX_PLAN_NODES],
    context: &mut ValueContext<'_>,
    active: &mut [ExprId; MAX_PLAN_DEPTH],
    depth: usize,
) -> Result<ValueKinds, PlanError> {
    context.step()?;
    if active.get(..depth).ok_or(PlanError::Limit)?.contains(&id) {
        return Err(PlanError::Cycle);
    }
    *active.get_mut(depth).ok_or(PlanError::Limit)? = id;
    let expression = description
        .expressions
        .get(id.0 as usize)
        .ok_or(PlanError::Reference)?;
    *seen.get_mut(id.0 as usize).ok_or(PlanError::Reference)? = true;
    Ok(match *expression {
        Expression::Aggregate { .. } => return Err(PlanError::Aggregate),
        Expression::Unary { operation, operand } => {
            let kinds = expression_inner(
                description,
                operand,
                scope,
                seen,
                context,
                active,
                depth + 1,
            )?;
            unary(operation, kinds)?
        }
        Expression::Binary {
            operation,
            left,
            right,
        } => {
            let left =
                expression_inner(description, left, scope, seen, context, active, depth + 1)?;
            let right =
                expression_inner(description, right, scope, seen, context, active, depth + 1)?;
            binary(operation, left, right)?
        }
        Expression::List(items) => {
            for item in items {
                expression_inner(description, *item, scope, seen, context, active, depth + 1)?;
            }
            ValueKinds::LIST
        }
        Expression::Property { entity, .. } => {
            require(
                expression_inner(description, entity, scope, seen, context, active, depth + 1)?,
                ValueKinds::NODE.union(ValueKinds::REL),
            )?;
            ValueKinds::NULL
                .union(ValueKinds::BOOL)
                .union(ValueKinds::I64)
                .union(ValueKinds::F64)
                .union(ValueKinds::STRING)
                .union(ValueKinds::LIST)
        }
        Expression::HasLabel { entity, .. } => {
            let receiver =
                expression_inner(description, entity, scope, seen, context, active, depth + 1)?;
            require(receiver, ValueKinds::NODE)?;
            nullable(ValueKinds::BOOL, receiver)
        }
        Expression::Literal(Literal::Null) => ValueKinds::NULL,
        Expression::Literal(Literal::Bool(_)) => ValueKinds::BOOL,
        Expression::Literal(Literal::I64(_)) => ValueKinds::I64,
        Expression::Literal(Literal::F64(_)) => ValueKinds::F64,
        Expression::Literal(Literal::String(_)) => ValueKinds::STRING,
        Expression::Slot(id) => scope.slot(id).ok_or(PlanError::Scope)?,
        Expression::Parameter(id) => {
            description
                .parameters
                .get(id.0 as usize)
                .ok_or(PlanError::Parameter)?
                .kinds
        }
    })
}

pub(super) fn expression(
    description: PlanDescription<'_>,
    id: ExprId,
    scope: &NodeFacts,
    seen: &mut [bool; MAX_PLAN_NODES],
    context: &mut ValueContext<'_>,
) -> Result<ValueKinds, PlanError> {
    expression_inner(
        description,
        id,
        scope,
        seen,
        context,
        &mut [ExprId(0); MAX_PLAN_DEPTH],
        0,
    )
}

fn require(actual: ValueKinds, allowed: ValueKinds) -> Result<(), PlanError> {
    if !actual.overlaps(allowed.union(ValueKinds::NULL)) {
        return Err(PlanError::Type);
    }
    Ok(())
}
fn nullable(result: ValueKinds, input: ValueKinds) -> ValueKinds {
    if input.overlaps(ValueKinds::NULL) {
        result.union(ValueKinds::NULL)
    } else {
        result
    }
}
fn unary(operation: UnaryExpression, input: ValueKinds) -> Result<ValueKinds, PlanError> {
    let (allowed, result) = match operation {
        UnaryExpression::Not => (ValueKinds::BOOL, ValueKinds::BOOL),
        UnaryExpression::Positive | UnaryExpression::Negate => (
            ValueKinds::I64.union(ValueKinds::F64),
            ValueKinds(input.0 & 12),
        ),
        UnaryExpression::IsNull | UnaryExpression::IsNotNull => return Ok(ValueKinds::BOOL),
        UnaryExpression::Size => (ValueKinds::LIST.union(ValueKinds::STRING), ValueKinds::I64),
        UnaryExpression::Labels => (ValueKinds::NODE, ValueKinds::LIST),
        UnaryExpression::RelType | UnaryExpression::RelIdText => {
            (ValueKinds::REL, ValueKinds::STRING)
        }
        UnaryExpression::NodeIdText => (ValueKinds::NODE, ValueKinds::STRING),
        UnaryExpression::StoredText => {
            (ValueKinds::NODE, ValueKinds::STRING.union(ValueKinds::NULL))
        }
    };
    require(input, allowed)?;
    Ok(nullable(result, input))
}
fn binary(
    operation: BinaryExpression,
    left: ValueKinds,
    right: ValueKinds,
) -> Result<ValueKinds, PlanError> {
    let result = match operation {
        BinaryExpression::And | BinaryExpression::Or | BinaryExpression::Xor => {
            require(left, ValueKinds::BOOL)?;
            require(right, ValueKinds::BOOL)?;
            ValueKinds::BOOL
        }
        BinaryExpression::Comparison(_) => ValueKinds::BOOL.union(ValueKinds::NULL),
        BinaryExpression::Arithmetic(_) => {
            let number = ValueKinds::I64.union(ValueKinds::F64);
            require(left, number)?;
            require(right, number)?;
            let mut result = ValueKinds::default();
            if left.overlaps(ValueKinds::I64) && right.overlaps(ValueKinds::I64) {
                result = result.union(ValueKinds::I64);
            }
            if left.overlaps(ValueKinds::F64) || right.overlaps(ValueKinds::F64) {
                result = result.union(ValueKinds::F64);
            }
            result
        }
        BinaryExpression::String(_) => {
            require(left, ValueKinds::STRING)?;
            require(right, ValueKinds::STRING)?;
            ValueKinds::BOOL
        }
        BinaryExpression::In => {
            require(right, ValueKinds::LIST)?;
            ValueKinds::BOOL.union(ValueKinds::NULL)
        }
        BinaryExpression::Index => {
            require(left, ValueKinds::LIST)?;
            require(right, ValueKinds::I64)?;
            ValueKinds::ANY
        }
    };
    Ok(nullable(result, left.union(right)))
}

pub(super) fn aggregate(
    description: PlanDescription<'_>,
    id: ExprId,
    scope: &NodeFacts,
    seen: &mut [bool; MAX_PLAN_NODES],
    context: &mut ValueContext<'_>,
) -> Result<ValueKinds, PlanError> {
    context.step()?;
    let Expression::Aggregate { operation, operand } = description
        .expressions
        .get(id.0 as usize)
        .ok_or(PlanError::Reference)?
    else {
        return Err(PlanError::Aggregate);
    };
    *seen.get_mut(id.0 as usize).ok_or(PlanError::Reference)? = true;
    if let Some(operand) = operand {
        expression(description, *operand, scope, seen, context)?;
    }
    Ok(match operation {
        AggregateExpression::Count { distinct: false } => ValueKinds::I64,
        AggregateExpression::Count { distinct: true } if operand.is_some() => ValueKinds::I64,
        AggregateExpression::Collect { .. } if operand.is_some() => ValueKinds::LIST,
        AggregateExpression::Sum { .. } if operand.is_some() => {
            ValueKinds::I64.union(ValueKinds::F64)
        }
        AggregateExpression::Min | AggregateExpression::Max if operand.is_some() => expression(
            description,
            operand.ok_or(PlanError::Aggregate)?,
            scope,
            seen,
            context,
        )?
        .union(ValueKinds::NULL),
        _ => return Err(PlanError::Aggregate),
    })
}