graphrecords-query 0.5.0

High-performance graph-based data records
Documentation
use crate::{
    EntityReference, Explain, IndexDomain, Indexed, Mask, Operand, QueryResult, Unit,
    element::{Pipeline, Preserving},
    execution::EvaluationCache,
    index::EntityAttributes,
    operations::{Apply, ElementKernel, ElementPipeline, Operation, OperationContext, Prepare},
    optimizer::{OperationInputs, OptimizerHints, PlanIdentity, PlanInputs},
    registry::operation_manifest,
    traits::HasAttribute,
};
use graphrecords_core::{GraphRecord, graphrecord::GraphRecordAttribute};

#[derive(Clone, Explain, Operation, OperationInputs, OptimizerHints, PlanIdentity, PlanInputs)]
#[operation(scope = Element)]
#[explain(label = "HasAttribute")]
#[plan(optimizer_hints(commutes_with_filter, allows_limit_pushdown, empty = if_any))]
pub struct HasAttributeOperation {
    #[explain(label)]
    attribute: GraphRecordAttribute,
}

impl Prepare for HasAttributeOperation {
    type Prepared<'a> = &'a GraphRecordAttribute;

    fn prepare<'a>(
        &'a self,
        _graphrecord: &'a GraphRecord,
        _cache: &'a EvaluationCache<'a>,
    ) -> QueryResult<Self::Prepared<'a>> {
        Ok(&self.attribute)
    }
}

impl<E: EntityAttributes> ElementKernel<Indexed<E, Unit>> for HasAttributeOperation {
    type Emission = Preserving;
    type OutShape = Indexed<E, Mask>;

    fn pipeline<'a>(
        graphrecord: &'a GraphRecord,
        prepared: Self::Prepared<'a>,
    ) -> QueryResult<ElementPipeline<'a, Indexed<E, Unit>, Self>> {
        Ok(Pipeline::keyed(move |index, membership: QueryResult<_>| {
            membership.map(|()| {
                E::attributes(graphrecord, &index)
                    .expect("Entity must exist")
                    .contains_key(prepared)
            })
        }))
    }
}

impl<E: EntityAttributes, I: IndexDomain> ElementKernel<Indexed<I, EntityReference<E>>>
    for HasAttributeOperation
{
    type Emission = Preserving;
    type OutShape = Indexed<I, Mask>;

    fn pipeline<'a>(
        graphrecord: &'a GraphRecord,
        prepared: Self::Prepared<'a>,
    ) -> QueryResult<ElementPipeline<'a, Indexed<I, EntityReference<E>>, Self>> {
        Ok(Pipeline::unkeyed(move |reference: QueryResult<_>| {
            reference.map(|entity| {
                E::attributes(graphrecord, &entity)
                    .expect("Entity must exist")
                    .contains_key(prepared)
            })
        }))
    }
}

impl<O: Apply<HasAttributeOperation>> HasAttribute for O {
    type ReturnOperand = O::Output;

    fn has_attribute(&self, attribute: GraphRecordAttribute) -> Self::ReturnOperand {
        Self::ReturnOperand::new(OperationContext::new(
            self.clone(),
            HasAttributeOperation { attribute },
        ))
    }
}

operation_manifest! {
    HasAttributeOperation {
        method: HasAttribute::has_attribute;
        scope: element;

        kernel {
            parameters: <E: EntityAttributes>;
            field: attribute: GraphRecordAttribute;
            input: Indexed<E, Unit>;
            output: Indexed<E, Mask>;
            emission: Preserving;
        }

        kernel {
            parameters: <E: EntityAttributes, I: IndexDomain>;
            field: attribute: GraphRecordAttribute;
            input: Indexed<I, EntityReference<E>>;
            output: Indexed<I, Mask>;
            emission: Preserving;
        }
    }
}