graphrecords_query/operations/structure/
has_attribute.rs1use crate::{
2 EntityReference, Explain, IndexDomain, Indexed, Mask, Operand, QueryResult, Unit,
3 element::{Pipeline, Preserving},
4 execution::EvaluationCache,
5 index::EntityAttributes,
6 operations::{Apply, ElementKernel, ElementPipeline, Operation, OperationContext, Prepare},
7 optimizer::{OperationInputs, OptimizerHints, PlanIdentity, PlanInputs},
8 registry::operation_manifest,
9 traits::HasAttribute,
10};
11use graphrecords_core::{GraphRecord, graphrecord::GraphRecordAttribute};
12
13#[derive(Clone, Explain, Operation, OperationInputs, OptimizerHints, PlanIdentity, PlanInputs)]
14#[operation(scope = Element)]
15#[explain(label = "HasAttribute")]
16#[plan(optimizer_hints(commutes_with_filter, allows_limit_pushdown, empty = if_any))]
17pub struct HasAttributeOperation {
18 #[explain(label)]
19 attribute: GraphRecordAttribute,
20}
21
22impl Prepare for HasAttributeOperation {
23 type Prepared<'a> = &'a GraphRecordAttribute;
24
25 fn prepare<'a>(
26 &'a self,
27 _graphrecord: &'a GraphRecord,
28 _cache: &'a EvaluationCache<'a>,
29 ) -> QueryResult<Self::Prepared<'a>> {
30 Ok(&self.attribute)
31 }
32}
33
34impl<E: EntityAttributes> ElementKernel<Indexed<E, Unit>> for HasAttributeOperation {
35 type Emission = Preserving;
36 type OutShape = Indexed<E, Mask>;
37
38 fn pipeline<'a>(
39 graphrecord: &'a GraphRecord,
40 prepared: Self::Prepared<'a>,
41 ) -> QueryResult<ElementPipeline<'a, Indexed<E, Unit>, Self>> {
42 Ok(Pipeline::keyed(move |index, membership: QueryResult<_>| {
43 membership.map(|()| {
44 E::attributes(graphrecord, &index)
45 .expect("Entity must exist")
46 .contains_key(prepared)
47 })
48 }))
49 }
50}
51
52impl<E: EntityAttributes, I: IndexDomain> ElementKernel<Indexed<I, EntityReference<E>>>
53 for HasAttributeOperation
54{
55 type Emission = Preserving;
56 type OutShape = Indexed<I, Mask>;
57
58 fn pipeline<'a>(
59 graphrecord: &'a GraphRecord,
60 prepared: Self::Prepared<'a>,
61 ) -> QueryResult<ElementPipeline<'a, Indexed<I, EntityReference<E>>, Self>> {
62 Ok(Pipeline::unkeyed(move |reference: QueryResult<_>| {
63 reference.map(|entity| {
64 E::attributes(graphrecord, &entity)
65 .expect("Entity must exist")
66 .contains_key(prepared)
67 })
68 }))
69 }
70}
71
72impl<O: Apply<HasAttributeOperation>> HasAttribute for O {
73 type ReturnOperand = O::Output;
74
75 fn has_attribute(&self, attribute: GraphRecordAttribute) -> Self::ReturnOperand {
76 Self::ReturnOperand::new(OperationContext::new(
77 self.clone(),
78 HasAttributeOperation { attribute },
79 ))
80 }
81}
82
83operation_manifest! {
84 HasAttributeOperation {
85 method: HasAttribute::has_attribute;
86 scope: element;
87
88 kernel {
89 parameters: <E: EntityAttributes>;
90 field: attribute: GraphRecordAttribute;
91 input: Indexed<E, Unit>;
92 output: Indexed<E, Mask>;
93 emission: Preserving;
94 }
95
96 kernel {
97 parameters: <E: EntityAttributes, I: IndexDomain>;
98 field: attribute: GraphRecordAttribute;
99 input: Indexed<I, EntityReference<E>>;
100 output: Indexed<I, Mask>;
101 emission: Preserving;
102 }
103 }
104}